42 using namespace Utilities;
46 namespace SubductingPlateModels
52 min_depth(NaN::
DSNAN),
53 max_depth(NaN::
DSNAN),
55 mantle_coupling_depth(NaN::
DSNAN),
56 forearc_cooling_factor(NaN::
DSNAN),
57 thermal_conductivity(NaN::
DSNAN),
58 thermal_expansion_coefficient(NaN::
DSNAN),
59 specific_heat(NaN::
DSNAN),
60 thermal_diffusivity(NaN::
DSNAN),
61 potential_mantle_temperature(NaN::
DSNAN),
62 surface_temperature(NaN::
DSNAN),
63 taper_distance(NaN::
DSNAN),
64 adiabatic_heating(true),
68 this->
name =
"mass conserving";
79 "Mass conserving temperature model. The temperature " 80 "model uses the heat content (proportional to to thermal mass anomaly) to " 81 "define a smooth temperature profile that conserves mass along the slab length. " 82 "An empirical model, using error functions for smooth transitions, is used to " 83 " define how the minimum temperature increases with depth and how the location of " 84 "the minimum temperature shifts into the slab interior. The slab is divided into top " 85 "and bottom parts, which meet at the location where the minimum temperature occurs in the slab. " 86 "For the bottom slab, the temperature is defined by a half-space cooling model. " 87 "For the top of the slab the temperature is defined by one side of a 1D infinite " 88 "space cooling model: this function was chosen to have a smoother temperature function across " 89 "the minimum temperature position. The age of the overriding plate is used so the slab temperature " 90 "at shallow depth smoothly transitions to the temperature of the overriding plate: " 91 "this is not perfect, and is affected by the value of \"top truncation\" parameter " 92 "subducting plate. Notes:" 93 "1) the parameter \"thickness\" for the subducting plate segments needs to be defined but is not used. " 94 "2) because we use a negative truncation for distance above the slab, it is recommended to use" 95 "depth method:begin at end segment, in the main part of the world-builder file." 96 "Other methods may lead to gpas in temperatures at the segment boundaries." 97 "3)the empirical model used to define how Tmin increases with depth " 98 "and how the position of Tmin shift with depth is expected to change somewhat " 99 "after better calibrating with further tests.");
103 "The distance in meters from the top surface of the slab over which the temperature is " 104 "determined by this feature. This parameter should be negative and should be 1.5-2 times " 105 "larger than the nominal slab thickness to allow the diffusion of cold " 106 "temperatures from in the slab into the mantle above the slab surface. " 107 "Also note that the top truncation value for the slab segment needs to have a value " 108 "of -1, otherwise the temperature above the slab will be cut off at a distance less than " 109 "the value set here.");
112 "The distance in meters from the top surface of the slab over which the temperature is " 113 "determined by this feature. This parameter should be positive and approximately 2.5-3.0 times " 114 "larger than the nominal slab thickness to allow the diffusion of cold" 115 "temperatures from in the slab into the mantle below the slab surface." 116 "For example if the slab starts with cold temperatures over a 100 km wide region, this" 117 "parameters should be about 250 km.");
120 "The reference density of the subducting plate in $kg/m^3$");
123 "The velocity with which the ridge spreads and create the plate in meters per year. Default is 5 cm/yr");
126 "The velocity with which the slab is subducting through time. Default is 5 cm/yr");
129 "The depth at which the slab surface first comes in contact with the hot mantle wedge " 130 "in meters. Default is 100 km.");
133 "Increase the value to create thin (~2 km) cold thermal boundary layer above the slab." 134 "Any value greater than 1 does NOT meet the instantaneous conservation of mass, but does allow " 135 "one to account for the history of insulating the forearc from heating up to this point in time. " 136 "Note younger subducting lithosphere provides less insulation, while thicker, older slabs " 137 "provide more insulation. Values up to 10 to 30 have been tested and don't cause any other " 138 "extraneous effects. The larger th value the more you are not meeting the mass conserving criteria, " 139 "so you don't want to see this affecting the temperature beyond the coupling depth as it will " 140 "increase the mass of the slab and affect how it sinks. If you use higher values, you will start to " 141 "see that this creates a very thick cool layer above the entire slab - if you see this extending beyond " 142 "the coupling zone reduce the value. You should use a value of 1 first and then " 143 "only increase as little as possible to cool just the forearc region. " 144 "Please examine the output temperature carefully. ");
147 "The thermal conductivity of the subducting plate material in $W m^{-1} K^{-1}$.");
150 "The thermal expansivity of the subducting plate material in $K^{-1}$. If smaller than zero, the global value is used.");
153 "The specific heat of the subducting plate material in $J kg^{-1} K^{-1}$. If smaller than zero, the global value is used.");
156 "The thermal conductivity of the subducting plate material in $W m^{-1} K^{-1}$.");
159 "Whether adiabatic heating should be used for the slab.");
162 "Distance over which to taper the slab tip." 163 "tapers the initial heat content to zero and the minimum temperature to the background temperature.");
166 "The potential temperature of the mantle at the surface in Kelvin. If smaller than zero, the global value is used.");
169 "An list of ridges. Each ridge is a lists of at least 2 2d points which " 170 "define the location of the ridge. You need to define at least one ridge." 171 "So the an example with two ridges is " 172 "[[[10,20],[20,30],[10,40]],[[50,10],[60,10]]].");
175 "The type of thermal model to use in the mass conserving model of slab temperature. " 176 "Options are half space model and plate model");
179 "Whether a spline should be applied on the mass conserving model.");
182 "The number of points in the spline");
205 if (thermal_expansion_coefficient < 0)
222 prm.
get<
double>(
"potential mantle temperature");
229 for (
auto &ridge_coordinate : ridge_coordinates)
231 ridge_coordinate *= dtr;
234 unsigned int ridge_point_index = 0;
235 for (
const auto &mid_oceanic_ridge : mid_oceanic_ridges)
237 std::vector<double> ridge_spreading_velocities_for_ridge;
238 for (
unsigned int index_y = 0; index_y < mid_oceanic_ridge.size(); index_y++)
240 if (ridge_spreading_velocities.second.size() == 1)
242 ridge_spreading_velocities_for_ridge.push_back(ridge_spreading_velocities.second[0]);
246 ridge_spreading_velocities_for_ridge.push_back(ridge_spreading_velocities.second[ridge_point_index]);
248 ridge_point_index += 1;
253 std::string reference_model_name_str = prm.
get<std::string>(
"reference model name");
254 if (reference_model_name_str==
"plate model")
256 else if (reference_model_name_str==
"half space model")
264 for (
unsigned int ridge_index = 0; ridge_index < mid_oceanic_ridges.size(); ridge_index++)
268 "subducting velocity must have the same dimension as the ridge coordinates parameter.");
269 for (
unsigned int point_index = 0; point_index < mid_oceanic_ridges[ridge_index].size(); point_index++)
273 "Currently, subducting velocity must equal the spreading velocity to satisfy conservation of mass. " 274 "This will be changed in the future to allow for the spreading center to move depending on the relative " 275 "difference between the spreading velocity and the subducting velocity, thereby conserving mass.");
284 const double gravity_norm,
292 const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25;
296 if (distance_from_plane <= max_depth && distance_from_plane >=
min_depth)
306 trench_point_natural,
310 constexpr
double km2m = 1.0e3;
311 constexpr
double cm2m = 100;
312 constexpr
double my = 1.0e6;
318 const double average_angle = distance_from_planes.
average_angle;
322 const double spreading_velocity = ridge_parameters[0] * seconds_in_year;
323 double subducting_velocity = ridge_parameters[2] * seconds_in_year;
325 const double age_at_trench = slab_ages[0];
326 const double plate_age_sec = age_at_trench * seconds_in_year;
331 double initial_heat_content;
341 const double subducting_velocity_UI = subducting_velocity / seconds_in_year;
348 subducting_velocity * age_at_trench /
max_depth);
349 initial_heat_content -= temp_heat_content;
359 double effective_plate_age_sec = slab_ages[1] * seconds_in_year;
366 WBAssert(!std::isnan(background_temperature),
"Internal error: temp is not a number: " << background_temperature <<
". In exponent: " 369 <<
", specific_heat = " <<
specific_heat <<
", depth = " << depth);
381 const double max_plate_vel = 20/cm2m;
382 const double vsubfact = std::min( std::max( 0.35 + ((0.1-0.35) / max_plate_vel) * subducting_velocity, 0.1), 0.35);
386 const double max_plate_age = 100*my;
387 const double max_age_fact = 1.0;
388 const double agefact = std::min( std::max( max_age_fact + ((0.1-max_age_fact) / max_plate_age) * age_at_trench, 0.1), max_age_fact);
392 const double agefact2 = std::max( std::min( 0.1 + ((0.35-0.1) / max_plate_age) * age_at_trench, 0.35), 0.1);
395 const double subfact = 0.3 + vsubfact + agefact;
397 const double subfact2 = 0.3 + vsubfact + agefact2;
400 const double min_Tcoup = 10;
401 const double max_Tcoup = 350;
402 const double Tcoup = min_Tcoup + (subfact - 0.5)*(max_Tcoup - min_Tcoup);
404 const double min_Tmin660 = 300;
405 const double max_Tmin660 = 900;
406 const double Tmin660 = min_Tmin660 + (subfact - 0.5)*(max_Tmin660 - min_Tmin660);
409 const double min_offset_coup = 2*km2m;
410 const double max_offset_coup = 10*km2m;
411 const double offset_coup = min_offset_coup + (subfact2)*(max_offset_coup - min_offset_coup);
413 const double min_offset660 = 15*km2m;
414 const double max_offset660 = 25*km2m;
415 const double offset660 = min_offset660 + (subfact2)*(max_offset660 - min_offset660);
418 const double start_taper_distance = total_segment_length -
taper_distance;
423 const double taper_con = 0.8;
425 double min_temperature = 0;
428 if (depth_to_reference_surface < mantle_coupling_depth)
431 theta = (mantle_coupling_depth - depth_to_reference_surface) / (subfact * mantle_coupling_depth);
432 min_temperature = Tcoup * std::erfc(theta);
433 offset = offset_coup * std::erfc(theta);
435 else if (distance_along_plane >= start_taper_distance)
439 const double depth_start_taper = depth_to_reference_surface - (distance_along_plane - start_taper_distance)
441 const double theta_start = (mantle_coupling_depth - depth_start_taper) / (subfact * upper_mantle_lengthscale);
442 const double Tmin_start_taper = Tcoup + Tmin660 * (std::erfc(theta_start)) - Tmin660;
444 const double offset_start_taper = offset_coup + (offset660) * std::erfc(theta_start) - offset660;
447 theta = (distance_along_plane - start_taper_distance) / (taper_distance);
449 offset = offset_start_taper + (2*max_offset660 - offset_start_taper) * (1-std::erfc(taper_con*theta));
452 initial_heat_content = initial_heat_content * std::erfc(1.5*taper_con*theta);
453 effective_plate_age_sec = effective_plate_age_sec * std::erfc(1.5*taper_con*theta);
458 theta = (mantle_coupling_depth - depth_to_reference_surface) / (subfact * upper_mantle_lengthscale);
459 min_temperature = Tcoup + Tmin660 * std::erfc(theta) - Tmin660;
460 offset = offset_coup + offset660 * std::erfc(theta) - offset660;
466 const double adjusted_distance = distance_from_plane - offset;
472 double temperature = 0.0;
474 if (min_temperature < background_temperature)
481 double bottom_heat_content;
489 const double subducting_velocity_UI = subducting_velocity / seconds_in_year;
496 subducting_velocity_UI * effective_plate_age_sec /
max_depth);
497 bottom_heat_content -= temp_heat_content;
510 double top_heat_content = std::min(max_top_heat_content, (initial_heat_content - bottom_heat_content) );
514 if (distance_along_plane > start_taper_distance)
516 top_heat_content = top_heat_content * std::erfc(taper_con*theta);
519 double nondimensional_adjusted_distance = adjusted_distance /
max_depth;
533 const double i_adjusted_distance = (
static_cast<double>(i) * interval_spline_distance - 1.0) *
max_depth;
534 const double i_temperature =
get_temperature_analytic(top_heat_content, min_temperature, background_temperature, temperature_, spreading_velocity, effective_plate_age_sec, i_adjusted_distance);
535 i_temperatures[i] = i_temperature;
538 monotone_cubic_spline.
set_points(i_temperatures);
540 const double index_distance = (nondimensional_adjusted_distance + 1.0) / interval_spline_distance;
541 temperature = monotone_cubic_spline(index_distance);
546 temperature =
get_temperature_analytic(top_heat_content, min_temperature, background_temperature, temperature_, spreading_velocity, effective_plate_age_sec, adjusted_distance);
552 temperature = temperature_;
555 WBAssert(!std::isnan(temperature),
"Internal error: temperature is not a number: " << temperature <<
'.');
556 WBAssert(std::isfinite(temperature),
"Internal error: temperature is not finite: " << temperature <<
'.');
566 const double min_temperature,
567 const double background_temperature,
568 const double temperature_,
569 const double subducting_velocity,
570 const double effective_plate_age_sec,
571 const double adjusted_distance)
const 573 const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25;
575 double temperature = 0.0;
578 if (adjusted_distance < 0)
583 pow(((2 * top_heat_content) / (2 *
density *
specific_heat * (min_temperature - temperature_ + 1e-16))),2) + 1e-16;
587 if (temperature_ < min_temperature)
589 temperature = temperature_;
593 temperature = temperature_ + (2 * top_heat_content /
605 const double subducting_velocity_UI = subducting_velocity / seconds_in_year;
606 temperature = background_temperature + (min_temperature - background_temperature) * (1 - adjusted_distance /
max_depth);
609 temperature = temperature - (min_temperature - background_temperature) *
612 std::sqrt(((subducting_velocity_UI*subducting_velocity_UI*max_depth*max_depth) /
614 ((subducting_velocity_UI * effective_plate_age_sec) / max_depth)));
619 temperature = background_temperature;
624 temperature = background_temperature + (min_temperature - background_temperature) *
625 std::erfc(adjusted_distance / (2 * std::sqrt(
thermal_diffusivity * effective_plate_age_sec)));
std::vector< std::vector< double > > ridge_spreading_velocities_at_each_ridge_point
static void declare_entries(Parameters &prm, const std::string &parent_name="")
WorldBuilder::World * world
double total_local_segment_length
double mantle_coupling_depth
const int plate_model_summation_number
std::vector< std::vector< Point< 2 > > > mid_oceanic_ridges
bool approx(double a, double b, double error_factor=1e4)
double potential_mantle_temperature
unsigned int spline_n_points
ReferenceModelName reference_model_name
double surface_temperature
double potential_mantle_temperature
double get_temperature(const Point< 3 > &position, const double depth, const double gravity, double temperature, const double feature_min_depth, const double feature_max_depth, const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, const AdditionalParameters &additional_parameters) const override final
Operations string_operations_to_enum(const std::string &operation)
std::vector< double > calculate_ridge_distance_and_spreading(std::vector< std::vector< Point< 2 >>> mid_oceanic_ridges, std::vector< std::vector< double >> mid_oceanic_spreading_velocities, const std::unique_ptr< WorldBuilder::CoordinateSystems::Interface > &coordinate_system, const Objects::NaturalCoordinate &position_in_natural_coordinates_at_min_depth, const std::vector< std::vector< double >> &subducting_plate_velocities, const std::vector< double > &ridge_migration_times)
#define WBAssert(condition, message)
double thermal_conductivity
double distance_from_plane
void set_points(const std::vector< double > &y)
double distance_along_plane
Point< 3 > closest_trench_point
double thermal_diffusivity
std::pair< std::vector< double >, std::vector< double > > ridge_spreading_velocities
double depth_reference_surface
double surface_temperature
#define WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(classname, name)
#define WBAssertThrow(condition, message)
~MassConserving() override final
std::vector< std::vector< double > > subducting_velocities
std::unique_ptr< WorldBuilder::CoordinateSystems::Interface > coordinate_system
std::vector< double > calculate_effective_trench_and_plate_ages(std::vector< double > ridge_parameters, double distance_along_plane)
void parse_entries(Parameters &prm) override final
double thermal_expansion_coefficient
std::pair< std::vector< double >, std::vector< double > > get_value_at_array(const std::string &name)
std::vector< std::vector< double > > get_vector_or_double(const std::string &name)
double thermal_diffusivity
double apply_operation(const Operations operation, const double old_value, const double new_value)
double sin(const double raw_angle)
double get_temperature_analytic(const double top_heat_content, const double min_temperature, const double background_temperature, const double temperature_, const double plate_velocity, const double effective_plate_age, const double adjusted_distance) const
void declare_entry(const std::string &name, const Types::Interface &type, const std::string &documentation)
double forearc_cooling_factor
std::vector< T > get_vector(const std::string &name)
T get(const std::string &name)
double thermal_expansion_coefficient