World Builder  1.1.0-pre
A geodynamic initial conditions generator
gaussian.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2018-2024 by the authors of the World Builder code.
3 
4  This file is part of the World Builder.
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19 
21 
22 
26 #include "world_builder/world.h"
27 
28 #include <algorithm>
29 
30 
31 namespace WorldBuilder
32 {
33  using namespace Utilities;
34 
35  namespace Features
36  {
37  namespace PlumeModels
38  {
39  namespace Temperature
40  {
41  Gaussian::Gaussian(WorldBuilder::World *world_)
42  :
43  operation(Operations::REPLACE)
44  {
45  this->world = world_;
46  this->name = "gaussian";
47  }
48 
50  = default;
51 
52  void
53  Gaussian::declare_entries(Parameters &prm, const std::string & /*unused*/)
54  {
55  // Document plugin and require entries if needed.
56  // Add `max distance fault` center to the required parameters.
57  prm.declare_entry("", Types::Object({"centerline temperatures"}),
58  "Gaussian temperature model. The temperature is interpolated between the plume center "
59  "and margin (as defined by the plume feature) using a Gaussian function: "
60  "T(r) = T_center(z) exp(-r^2/(2 sigma^2). "
61  "The temperature at the plume centerline T_center can be changed with depth by defining "
62  "an array of depths and centerline temperatures, and temperature is interpolated linearly "
63  "with depth. Similarly, the sigma of the Gaussian function (relative to the width of "
64  "the plume as given by the plume feature) can be changed with depth. "
65  "Temperature is always interpolated in a horizonzal/radial plane, except for the plume "
66  "head: If the first depth of the plume centerline and the minimum depth of the plume "
67  "feature are different, an ellipsoidal plume head is created in this depth range. "
68  "Within this plume head, temperature is interpolated radially, i.e., depending on the "
69  "distance from the center of the ellipsoid.");
70 
71  prm.declare_entry("depths", Types::Array(Types::Double(0)),
72  "The list of depths where both the temperature in the center of the plume "
73  "and the width of the temperature anomaly in terms of the sigma of a Gaussian "
74  "function can be provided. Temperature is interpolated linearly in vertical "
75  "direction between these depths. Units: m.");
76  prm.declare_entry("centerline temperatures", Types::Array(Types::Double(0)),
77  "The temperature at the center of this feature in degree Kelvin."
78  "If the value is below zero, then an adiabatic temperature is used.");
79  prm.declare_entry("gaussian sigmas", Types::Array(Types::Double(0.3)),
80  "The sigma (standard deviation) of the Gaussian function used to compute the "
81  "temperature distribution within the plume. This sigma is non-dimensional, i.e. "
82  "it is defined relative to the distance between the plume center and margin as "
83  "defined by the plume feature. Choosing a sigma of 1 therefore means that the "
84  "temperature at the plume margin is set to a fraction of 1/sqrt(e) (approx. 0.61) "
85  "of the centerline temperature. To achieve a smoother transition between the "
86  "plume temperature and the outside temperature a smaller values has to be chosen "
87  "for the gaussian sigmas.");
88  }
89 
90  void
92  {
93  operation = string_operations_to_enum(prm.get<std::string>("operation"));
94 
95  depths = prm.get_vector<double>("depths");
96  center_temperatures = prm.get_vector<double>("centerline temperatures");
97  gaussian_sigmas = prm.get_vector<double>("gaussian sigmas");
98 
99  WBAssert(center_temperatures.size() == depths.size() && gaussian_sigmas.size() == depths.size(),
100  "The depths, center_temperatures and gaussian_sigmas arrays need to have the same number of entries. "
101  "At the moment there are: "
102  << depths.size() << " depth entries, "
103  << center_temperatures.size() << " centerline temperature entries, and "
104  << gaussian_sigmas.size() << " gaussian sigma entries!");
105  }
106 
107 
108  double
109  Gaussian::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/,
110  const Objects::NaturalCoordinate & /*position_in_natural_coordinates*/,
111  const double depth,
112  const double gravity_norm,
113  double temperature_,
114  const double feature_min_depth,
115  const double feature_max_depth,
116  const double relative_distance_from_center) const
117  {
118  if (depth <= feature_max_depth && depth >= feature_min_depth && relative_distance_from_center <= 1.)
119  {
120  // Figure out if the point is within the plume
121  auto upper = std::upper_bound(depths.begin(), depths.end(), depth);
122 
123  double center_temperature_local;
124  double gaussian_sigma;
125 
126  if (upper - depths.begin() == 0)
127  {
128  center_temperature_local = center_temperatures.front();
129  gaussian_sigma = gaussian_sigmas.front();
130  }
131  else if (upper - depths.end() == 0)
132  {
133  center_temperature_local = center_temperatures.back();
134  gaussian_sigma = gaussian_sigmas.back();
135  }
136  else
137  {
138  const unsigned int index = static_cast<unsigned int>(std::distance(depths.begin(), upper));
139  const double fraction = (depth - depths[index-1]) / (depths[index] - depths[index-1]);
140 
141  center_temperature_local = (1-fraction) * center_temperatures[index-1] + fraction * center_temperatures[index];
142  gaussian_sigma = (1-fraction) * gaussian_sigmas[index-1] + fraction * gaussian_sigmas[index];
143  }
144 
145  if (center_temperature_local < 0)
146  {
147  center_temperature_local = this->world->potential_mantle_temperature *
148  std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) /
149  this->world->specific_heat) * depth);
150  }
151 
152  const double new_temperature = center_temperature_local * std::exp(-relative_distance_from_center/(2.*std::pow(gaussian_sigma, 2)));
153 
154  return apply_operation(operation,temperature_,new_temperature);
155 
156  }
157 
158  return temperature_;
159  }
160 
162  } // namespace Temperature
163  } // namespace PlumeModels
164  } // namespace Features
165 } // namespace WorldBuilder
166 
double potential_mantle_temperature
Definition: world.h:268
Operations string_operations_to_enum(const std::string &operation)
static void declare_entries(Parameters &prm, const std::string &parent_name="")
Definition: gaussian.cc:53
#define WBAssert(condition, message)
Definition: assert.h:27
#define WB_REGISTER_FEATURE_PLUME_TEMPERATURE_MODEL(classname, name)
Definition: interface.h:155
double get_temperature(const Point< 3 > &position, const Objects::NaturalCoordinate &position_in_natural_coordinates, const double depth, const double gravity, double temperature, const double feature_min_depth, const double feature_max_depth, const double relative_distance_from_center) const override final
Definition: gaussian.cc:109
void parse_entries(Parameters &prm) override final
Definition: gaussian.cc:91
double thermal_expansion_coefficient
Definition: world.h:283
double apply_operation(const Operations operation, const double old_value, const double new_value)
void declare_entry(const std::string &name, const Types::Interface &type, const std::string &documentation)
Definition: parameters.cc:197
std::vector< T > get_vector(const std::string &name)
T get(const std::string &name)