World Builder  1.1.0-pre
A geodynamic initial conditions generator
random_uniform_distribution.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 #include <algorithm>
23 
24 #include "world_builder/nan.h"
32 #include "world_builder/world.h"
33 
34 namespace WorldBuilder
35 {
36  using namespace Utilities;
37 
38  namespace Features
39  {
40  namespace MantleLayerModels
41  {
42  namespace Grains
43  {
44  RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_)
45  :
46  min_depth(NaN::DSNAN),
47  max_depth(NaN::DSNAN)
48 
49  {
50  this->world = world_;
51  this->name = "random uniform distribution";
52  }
53 
55  = default;
56 
57  void
58  RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/)
59  {
60  // Document plugin and require entries if needed.
61  // Add compositions the required parameters.
62  prm.declare_entry("", Types::Object({"compositions"}),
63  "Random uniform distribution grains model. The size of the grains can be independently set "
64  "to a single value or to a random distribution.");
65 
66  // Declare entries of this plugin
68  "The depth in meters from which the composition of this feature is present.");
69  prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits<double>::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits<double>::max(), 2.))),
70  "The depth in meters to which the composition of this feature is present.");
71 
72  prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0),
73  "A list with the integer labels of the composition which are present there.");
74 
75  prm.declare_entry("orientation operation", Types::String("replace", std::vector<std::string> {"replace"}),
76  "Whether the value should replace any value previously defined at this location (replace) or "
77  "add the value to the previously define value (add, not implemented). Replacing implies that all values not "
78  "explicitly defined are set to zero.");
79 
80  prm.declare_entry("grain sizes",
82  "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1.");
83 
84  prm.declare_entry("normalize grain sizes",
85  Types::Array(Types::Bool(true),0),
86  "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1.");
87 
88 
89 
90  }
91 
92  void
93  RandomUniformDistribution::parse_entries(Parameters &prm, const std::vector<Point<2>> &coordinates)
94  {
95  min_depth_surface = Objects::Surface(prm.get("min depth",coordinates));
97  max_depth_surface = Objects::Surface(prm.get("max depth",coordinates));
99  compositions = prm.get_vector<unsigned int>("compositions");
100 
101  operation = prm.get<std::string>("orientation operation");
102  grain_sizes = prm.get_vector<double>("grain sizes");
103  normalize_grain_sizes = prm.get_vector<bool>("normalize grain sizes");
104 
105 
106  WBAssertThrow(compositions.size() == grain_sizes.size(),
107  "There are not the same amount of compositions (" << compositions.size()
108  << ") and grain_sizes (" << grain_sizes.size() << ").");
109  WBAssertThrow(compositions.size() == normalize_grain_sizes.size(),
110  "There are not the same amount of compositions (" << compositions.size()
111  << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ").");
112  }
113 
114 
116  RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/,
117  const Objects::NaturalCoordinate &position_in_natural_coordinates,
118  const double depth,
119  const unsigned int composition_number,
120  WorldBuilder::grains grains_,
121  const double /*feature_min_depth*/,
122  const double /*feature_max_depth*/) const
123  {
124  WorldBuilder::grains grains_local = grains_;
125  if (depth <= max_depth && depth >= min_depth)
126  {
127  const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value;
128  const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value;
129  if (depth <= max_depth_local && depth >= min_depth_local)
130  {
131  for (unsigned int i =0; i < compositions.size(); ++i)
132  {
133  if (compositions[i] == composition_number)
134  {
135  std::uniform_real_distribution<> dist(0.0,1.0);
136  for (auto &&it_rotation_matrices : grains_local.rotation_matrices)
137  {
138  // set a uniform random a_cosine_matrix per grain
139  // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120).
140  // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c
141  // and is licenend accourding to this website with the following licence:
142  //
143  // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and
144  // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit
145  // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems
146  // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically,
147  // don't be a jerk, and remember that anything free comes with no guarantee.""
148  //
149  // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in
150  // the public domain, and is yours to study, modify, and use."
151 
152  // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2.
153  const double one = dist(world->get_random_number_engine());
154  const double two = dist(world->get_random_number_engine());
155  const double three = dist(world->get_random_number_engine());
156 
157  const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z)
158  const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection.
159  const double z = 2.0* three; //For magnitude of pole deflection.
160 
161  // Compute a vector V used for distributing points over the sphere
162  // via the reflection I - V Transpose(V). This formulation of V
163  // will guarantee that if x[1] and x[2] are uniformly distributed,
164  // the reflected points will be uniform on the sphere. Note that V
165  // has length sqrt(2) to eliminate the 2 in the Householder matrix.
166 
167  const double r = std::sqrt( z );
168  const double Vx = std::sin( phi ) * r;
169  const double Vy = std::cos( phi ) * r;
170  const double Vz = std::sqrt( 2.F - z );
171 
172  // Compute the row vector S = Transpose(V) * R, where R is a simple
173  // rotation by theta about the z-axis. No need to compute Sz since
174  // it's just Vz.
175 
176  const double st = std::sin( theta );
177  const double ct = std::cos( theta );
178  const double Sx = Vx * ct - Vy * st;
179  const double Sy = Vx * st + Vy * ct;
180 
181  // Construct the rotation matrix ( V Transpose(V) - I ) R, which
182  // is equivalent to V S - R.
183 
184  it_rotation_matrices[0][0] = Vx * Sx - ct;
185  it_rotation_matrices[0][1] = Vx * Sy - st;
186  it_rotation_matrices[0][2] = Vx * Vz;
187 
188  it_rotation_matrices[1][0] = Vy * Sx + st;
189  it_rotation_matrices[1][1] = Vy * Sy - ct;
190  it_rotation_matrices[1][2] = Vy * Vz;
191 
192  it_rotation_matrices[2][0] = Vz * Sx;
193  it_rotation_matrices[2][1] = Vz * Sy;
194  it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0
195  }
196 
197  double total_size = 0;
198  for (auto &&it_sizes : grains_local.sizes)
199  {
200  it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i];
201  total_size += it_sizes;
202  }
203 
204  if (normalize_grain_sizes[i])
205  {
206  const double one_over_total_size = 1/total_size;
207  std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(),
208  [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; });
209  }
210 
211  return grains_local;
212  }
213  }
214  }
215  }
216  return grains_local;
217  }
219  } // namespace Grains
220  } // namespace MantleLayerModels
221  } // namespace Features
222 } // namespace WorldBuilder
223 
224 
#define WB_REGISTER_FEATURE_MANTLE_LAYER_GRAINS_MODEL(classname, name)
Definition: interface.h:152
const double DSNAN
Definition: nan.h:41
void parse_entries(Parameters &prm, const std::vector< Point< 2 >> &coordinates) override final
std::mt19937 & get_random_number_engine()
Definition: world.cc:556
std::vector< double > sizes
Definition: grains.h:47
double cos(const double angle)
Definition: point.h:97
WorldBuilder::grains get_grains(const Point< 3 > &position, const Objects::NaturalCoordinate &position_in_natural_coordinates, const double depth, const unsigned int composition_number, WorldBuilder::grains grains, const double feature_min_depth, const double feature_max_depth) const override final
#define WBAssertThrow(condition, message)
Definition: assert.h:40
SurfaceValueInfo local_value(const Point< 2 > &check_point) const
Definition: surface.cc:149
double sin(const double raw_angle)
Definition: point.h:81
static void declare_entries(Parameters &prm, const std::string &parent_name="")
std::vector< std::array< std::array< double, 3 >, 3 > > rotation_matrices
Definition: grains.h:51
constexpr double PI
Definition: consts.h:30
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)