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