World Builder  1.1.0-pre
A geodynamic initial conditions generator
random_uniform_distribution_deflected.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 "world_builder/nan.h"
29 #include "world_builder/world.h"
30 
31 namespace WorldBuilder
32 {
33  using namespace Utilities;
34 
35  namespace Features
36  {
37  namespace FaultModels
38  {
39  namespace Grains
40  {
41  RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_)
42  :
43  min_depth(NaN::DSNAN),
44  max_depth(NaN::DSNAN)
45 
46  {
47  this->world = world_;
48  this->name = "random uniform distribution deflected";
49  }
50 
52  = default;
53 
54  void
56  {
57  // Document plugin and require entries if needed.
58  // Add compositions to the required parameters.
59  prm.declare_entry("", Types::Object({"compositions"}),
60  "Random uniform distribution grains model. The size of the grains can be independently set "
61  "to a single value or to a random distribution.");
62 
63  // Declare entries of this plugin
64  prm.declare_entry("min distance fault center", Types::Double(0),
65  "The distance from the fault center in meters from which the composition of this feature is present.");
66  prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits<double>::max()),
67  "The distance from the fault in meters to which the composition of this feature is present.");
68 
69  prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0),
70  "A list with the integer labels of the composition which are present there.");
71 
72  prm.declare_entry("orientation operation", Types::String("replace", std::vector<std::string> {"replace"}),
73  "Whether the value should replace any value previously defined at this location (replace) or "
74  "add the value to the previously define value (add, not implemented). Replacing implies that all values not "
75  "explicitly defined are set to zero.");
76 
77  prm.declare_entry("grain sizes",
79  "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.");
80 
81  prm.declare_entry("normalize grain sizes",
82  Types::Array(Types::Bool(true),0),
83  "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.");
84 
85  prm.declare_entry("deflections",
87  "A list of the deflections of all of the grains in each composition between 0 and 1.");
88 
89  prm.declare_entry("basis rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0),
90  "A list with the rotation matrices of the grains which are present there for each compositions.");
91 
92  prm.declare_entry("basis Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0),
93  "A list with the z-x-z Euler angles of the grains which are present there for each compositions.");
94 
95 
96 
97  }
98 
99  void
101  {
102  min_depth = prm.get<double>("min distance fault center");
103  max_depth = prm.get<double>("max distance fault center");
104  compositions = prm.get_vector<unsigned int>("compositions");
105 
106  const bool set_euler_angles = prm.check_entry("basis Euler angles z-x-z");
107  const bool set_rotation_matrices = prm.check_entry("basis rotation matrices");
108 
109  WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true),
110  "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path());
111 
112 
113  WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false),
114  "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path());
115 
116  if (set_euler_angles)
117  {
118  std::vector<std::array<double,3> > basis_euler_angles_vector = prm.get_vector<std::array<double,3> >("basis Euler angles z-x-z");
119  basis_rotation_matrices.resize(basis_euler_angles_vector.size());
120  for (size_t i = 0; i<basis_euler_angles_vector.size(); ++i)
121  {
122  basis_rotation_matrices[i] = Utilities::euler_angles_to_rotation_matrix(basis_euler_angles_vector[i][0],basis_euler_angles_vector[i][1],basis_euler_angles_vector[i][2]);
123  }
124 
125  }
126  else
127  {
128  basis_rotation_matrices = prm.get_vector<std::array<std::array<double,3>,3> >("basis rotation matrices");
129  }
130 
131  operation = prm.get<std::string>("orientation operation");
132  grain_sizes = prm.get_vector<double>("grain sizes");
133  normalize_grain_sizes = prm.get_vector<bool>("normalize grain sizes");
134  deflections = prm.get_vector<double>("deflections");
135 
136  WBAssertThrow(compositions.size() == grain_sizes.size(),
137  "There are not the same amount of compositions (" << compositions.size()
138  << ") and grain_sizes (" << grain_sizes.size() << ").");
139  WBAssertThrow(compositions.size() == normalize_grain_sizes.size(),
140  "There are not the same amount of compositions (" << compositions.size()
141  << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ").");
142  WBAssertThrow(compositions.size() == deflections.size(),
143  "There are not the same amount of compositions (" << compositions.size()
144  << ") and deflections (" << deflections.size() << ").");
145  WBAssertThrow(compositions.size() == basis_rotation_matrices.size(),
146  "There are not the same amount of compositions (" << compositions.size()
147  << ") and rotation_matrices (" << basis_rotation_matrices.size() << ").");
148  }
149 
151  RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/,
152  const double /*depth*/,
153  const unsigned int composition_number,
154  WorldBuilder::grains grains_,
155  const double /*feature_min_depth*/,
156  const double /*feature_max_depth*/,
157  const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes,
158  const AdditionalParameters & /*additional_parameters*/) const
159  {
160  WorldBuilder::grains grains_local = grains_;
161  if (std::fabs(distance_from_planes.distance_from_plane) <= max_depth && std::fabs(distance_from_planes.distance_from_plane) >= min_depth)
162  {
163  for (unsigned int i =0; i < compositions.size(); ++i)
164  {
165  if (compositions[i] == composition_number)
166  {
167  std::uniform_real_distribution<> dist(0.0,1.0);
168  for (auto &&it_rotation_matrices : grains_local.rotation_matrices)
169  {
170  // set a uniform random a_cosine_matrix per grain
171  // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120).
172  // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c
173  // and is licenend accourding to this website with the following licence:
174  //
175  // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and
176  // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit
177  // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems
178  // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically,
179  // don't be a jerk, and remember that anything free comes with no guarantee.""
180  //
181  // 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
182  // the public domain, and is yours to study, modify, and use."
183 
184  // 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.
185  const double one = dist(world->get_random_number_engine());
186  const double two = dist(world->get_random_number_engine());
187  const double three = dist(world->get_random_number_engine());
188 
189  const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z).
190  const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection.
191  const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection.
192 
193  // Compute a vector V used for distributing points over the sphere
194  // via the reflection I - V Transpose(V). This formulation of V
195  // will guarantee that if x[1] and x[2] are uniformly distributed,
196  // the reflected points will be uniform on the sphere. Note that V
197  // has length sqrt(2) to eliminate the 2 in the Householder matrix.
198 
199  const double r = std::sqrt( z );
200  const double Vx = std::sin( phi ) * r;
201  const double Vy = std::cos( phi ) * r;
202  const double Vz = std::sqrt( 2.F - z );
203 
204  // Compute the row vector S = Transpose(V) * R, where R is a simple
205  // rotation by theta about the z-axis. No need to compute Sz since
206  // it's just Vz.
207 
208  const double st = std::sin( theta );
209  const double ct = std::cos( theta );
210  const double Sx = Vx * ct - Vy * st;
211  const double Sy = Vx * st + Vy * ct;
212 
213  // Construct the rotation matrix ( V Transpose(V) - I ) R, which
214  // is equivalent to V S - R.
215 
216  std::array<std::array<double,3>,3> rotation_matrices;
217  rotation_matrices[0][0] = (Vx * Sx - ct);
218  rotation_matrices[0][1] = (Vx * Sy - st);
219  rotation_matrices[0][2] = Vx * Vz;
220 
221  rotation_matrices[1][0] = (Vy * Sx + st);
222  rotation_matrices[1][1] = (Vy * Sy - ct);
223  rotation_matrices[1][2] = Vy * Vz;
224 
225  rotation_matrices[2][0] = Vz * Sx;
226  rotation_matrices[2][1] = Vz * Sy;
227  rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0
228 
229  // Rotate the basis rotation matrix with the random uniform distribution rotation matrix
230  // First get the transpose of the rotation matrix
231  std::array<std::array<double, 3>, 3> rot_T= rotation_matrices;
232  rot_T[0][1] = rotation_matrices[1][0];
233  rot_T[1][0] = rotation_matrices[0][1];
234  rot_T[1][2] = rotation_matrices[2][1];
235  rot_T[2][1] = rotation_matrices[1][2];
236  rot_T[0][2] = rotation_matrices[2][0];
237  rot_T[2][0] = rotation_matrices[0][2];
238 
239  // Then U' = R * U * R^T
240  std::array<std::array<double,3>,3> result1 = multiply_3x3_matrices(rotation_matrices, basis_rotation_matrices[i]);
241 
242  it_rotation_matrices = result1;
243  }
244 
245  double total_size = 0;
246  for (auto &&it_sizes : grains_local.sizes)
247  {
248  it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i];
249  total_size += it_sizes;
250  }
251 
252  if (normalize_grain_sizes[i])
253  {
254  const double one_over_total_size = 1/total_size;
255  // std::transform is a c++17 feature, while current GWB is c++14
256  // update this after switching to c+=17
257  // std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(),
258  // [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; });
259  // Apply the transformation using a loop
260  for (auto &&size : grains_local.sizes)
261  {
262  size = size*one_over_total_size;
263  }
264  }
265 
266  return grains_local;
267  }
268  }
269  }
270  return grains_local;
271  }
272  WB_REGISTER_FEATURE_FAULT_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected)
273  } // namespace Grains
274  } // namespace FaultModels
275  } // namespace Features
276 } // namespace WorldBuilder
277 
bool check_entry(const std::string &name) const
Definition: parameters.cc:205
const double DSNAN
Definition: nan.h:41
std::array< std::array< double, 3 >, 3 > multiply_3x3_matrices(const std::array< std::array< double, 3 >, 3 > mat1, const std::array< std::array< double, 3 >, 3 > mat2)
Definition: utilities.cc:1510
std::mt19937 & get_random_number_engine()
Definition: world.cc:556
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
std::string get_full_json_path(size_t max_size=std::numeric_limits< size_t >::max()) const
Definition: parameters.cc:1933
#define WB_REGISTER_FEATURE_FAULT_GRAINS_MODEL(classname, name)
Definition: interface.h:155
double cos(const double angle)
Definition: point.h:97
#define WBAssertThrow(condition, message)
Definition: assert.h:40
std::array< std::array< double, 3 >, 3 > euler_angles_to_rotation_matrix(double phi1_d, double theta_d, double phi2_d)
Definition: utilities.cc:1147
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)