World Builder  1.1.0-pre
A geodynamic initial conditions generator
main.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2018 - 2021 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 
20 
21 #include "app/main.h"
22 
23 #include "world_builder/assert.h"
24 #include "world_builder/consts.h"
25 #include "world_builder/point.h"
27 #include "world_builder/world.h"
28 
29 #ifdef WB_WITH_MPI
30 // we don't need the c++ MPI wrappers
31 #define OMPI_SKIP_MPICXX 1
32 #define MPICH_SKIP_MPICXX
33 #include <mpi.h>
34 #endif
35 
36 #include <algorithm>
37 #include <fstream>
38 #include <iostream>
39 #include <memory>
40 
41 #ifndef NDEBUG
42 #ifdef WB_USE_FP_EXCEPTIONS
43 #include <cfenv>
44 #endif
45 #endif
46 
47 using namespace WorldBuilder::Utilities;
48 
49 bool find_command_line_option(char **begin, char **end, const std::string &option)
50 {
51  return std::find(begin, end, option) != end;
52 }
53 
54 int main(int argc, char **argv)
55 {
56 
57 #ifndef NDEBUG
58 #ifdef WB_USE_FP_EXCEPTIONS
59  // Some implementations seem to not initialize the floating point exception
60  // bits to zero. Make sure we start from a clean state.
61  feclearexcept(FE_DIVBYZERO|FE_INVALID);
62 
63  // enable floating point exceptions
64  feenableexcept(FE_DIVBYZERO|FE_INVALID);
65 #endif
66 #endif
67 
71  std::string wb_file;
72  std::string data_file;
73 
74  unsigned int dim = 3;
75  unsigned int compositions = 0;
76  unsigned int grain_compositions = 0;
77  size_t n_grains = 0;
78  bool convert_spherical = false;
79  bool limit_debug_consistency_checks = false;
80  bool output_json_files = false;
81 
82  if (find_command_line_option(argv, argv+argc, "-h") || find_command_line_option(argv, argv+argc, "--help"))
83  {
84  std::cout << "This program allows to use the world builder library directly with a world builder file and a data file. "
85  "The data file will be filled with initial conditions from the world as set by the world builder file." << std::endl
86  << "Besides providing two files, where the first is the world builder file and the second is the data file, the available options are: " << std::endl
87  << "-h or --help to get this help screen." << std::endl;
88  return 0;
89  }
90 
91  if (find_command_line_option(argv, argv+argc, "-ldcc") || find_command_line_option(argv, argv+argc, "--limit-debug-consistency-checks"))
92  limit_debug_consistency_checks = true;
93 
94  if (find_command_line_option(argv, argv+argc, "--output-json-files"))
95  output_json_files = true;
96 
97  if (argc == 1)
98  {
99  std::cout << "Error: There where no files passed to the World Builder, use --help for more " << std::endl
100  << "information on how to use the World Builder app." << std::endl;
101  return 0;
102  }
103 
104 
105  if (argc == 2)
106  {
107  std::cout << "Error: The World Builder app requires at least two files, a World Builder file " << std::endl
108  << "and a data file to convert." << std::endl;
109  return 0;
110  }
111 
112  if ((argc == 3 && limit_debug_consistency_checks && output_json_files) || (argc == 4 && !(!limit_debug_consistency_checks != !output_json_files)) || (argc == 5 && (!limit_debug_consistency_checks && !output_json_files)) || argc > 5)
113  {
114  std::cout << "Only exactly two command line arguments may be given, which should be the world builder file location and the data file location (in that order) "
115  << "or exactly three command line arguments, which should be the world builder file location, the data file location and --limit-debug-consistency-checks or --output-json-files (in that order),"
116  "or exactly four command line arguments, which should be the world builder file location, the data file location and --limit-debug-consistency-checks and --output-json-files (in that order),"
117  << ", argc = " << argc << ", limit_debug_consistency_checks = " << (limit_debug_consistency_checks ? "true" : "false") << ", output_json_files = " << (output_json_files ? "true" : "false") << std::endl;
118  return 0;
119  }
120 
121  int MPI_RANK = 0;
122 #ifdef WB_WITH_MPI
123  int MPI_SIZE = 1;
124  MPI_Init(&argc,&argv);
125  MPI_Comm_rank(MPI_COMM_WORLD, &MPI_RANK);
126  MPI_Comm_size(MPI_COMM_WORLD, &MPI_SIZE);
127 #endif
128 
129  if (MPI_RANK == 0)
130  {
131  wb_file = argv[1];
132  data_file = argv[2];
133 
137  std::unique_ptr<WorldBuilder::World> world;
138  //try
139  {
140  const std::string output_dir = wb_file.substr(0,wb_file.find_last_of("/\\") + 1);
141  world = std::make_unique<WorldBuilder::World>(wb_file, output_json_files, output_dir,1,limit_debug_consistency_checks);
142  }
143  /*catch (std::exception &e)
144  {
145  std::cerr << "Could not start the World builder, error: " << e.what() << "\n";
146  return 1;
147  }
148  catch (...)
149  {
150  std::cerr << "Exception of unknown type!\n";
151  return 1;
152  }*/
153 
154 
158  std::ifstream data_stream(data_file);
159 
160  // move the data into a vector of strings
161  std::vector<std::vector<std::string> > data;
162  std::string temp;
163 
164  while (std::getline(data_stream, temp))
165  {
166  std::istringstream buffer(temp);
167  std::vector<std::string> line((std::istream_iterator<std::string>(buffer)),
168  std::istream_iterator<std::string>());
169 
170  // remove the comma's in case it is a comma separated file.
171  // TODO: make it split for comma's and/or spaces
172  for (auto &line_i : line)
173  line_i.erase(std::remove(line_i.begin(), line_i.end(), ','), line_i.end());
174 
175  data.push_back(line);
176  }
177 
178  // Read config from data if present
179  for (auto &line_i : data)
180  {
181  if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "dim" && line_i[2] == "=")
182  {
183  dim = string_to_unsigned_int(line_i[3]);
184  }
185 
186  if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "compositions" && line_i[2] == "=")
187  compositions = string_to_unsigned_int(line_i[3]);
188 
189  if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "grain" && line_i[2] == "compositions" && line_i[3] == "=")
190  grain_compositions = string_to_unsigned_int(line_i[4]);
191 
192  if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "number" && line_i[2] == "of" && line_i[3] == "grains" && line_i[4] == "=")
193  n_grains = string_to_unsigned_int(line_i[5]);
194 
195  if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "convert" && line_i[2] == "spherical" && line_i[3] == "=" && line_i[4] == "true")
196  convert_spherical = true;
197  }
198 
199  // set properties
200  std::vector<std::array<unsigned ,3>> properties;
201  properties.push_back({{1,0,0}}); // temperature
202 
203  properties.push_back({{5,0,0}}); // velocity x
204 
205  for (size_t c = 0; c < compositions; ++c)
206  properties.push_back({{2,static_cast<unsigned int>(c),0}}); // composition c
207 
208 
209  for (size_t gc = 0; gc < grain_compositions; ++gc)
210  properties.push_back({{3,static_cast<unsigned int>(gc),static_cast<unsigned int>(n_grains)}}); // grains gc
211 
212  properties.push_back({{4,0,0}}); // tag
213 
214 
215  switch (dim)
216  {
217  case 2:
218  WBAssertThrow(!convert_spherical, "Converting to spherical values is only available in 3D.");
219  // set the header
220  std::cout << "# x z d T vx vz ";
221 
222  for (unsigned int c = 0; c < compositions; ++c)
223  std::cout << 'c' << c << ' ';
224 
225  for (unsigned int gc = 0; gc < grain_compositions; ++gc)
226  for (size_t g = 0; g < n_grains; g++)
227  std::cout << "gs" << gc << '-' << g << ' ' // gs = grain size, gm = grain rotation matrix
228  << "gm" << gc << '-' << g << "[0:0] " << "gm" << gc << '-' << g << "[0:1] " << "gm" << gc << '-' << g << "[0:2] "
229  << "gm" << gc << '-' << g << "[1:0] " << "gm" << gc << '-' << g << "[1:1] " << "gm" << gc << '-' << g << "[1:2] "
230  << "gm" << gc << '-' << g << "[2:0] " << "gm" << gc << '-' << g << "[2:1] " << "gm" << gc << '-' << g << "[2:2] ";
231 
232  std::cout << "tag ";
233  std::cout <<std::endl;
234 
235  // set the values
236  for (unsigned int i = 0; i < data.size(); ++i)
237  if (data[i].size() > 0 && data[i][0] != "#")
238  {
239 
240  WBAssertThrow(data[i].size() == dim + 1, "The file needs to contain dim + 1 entries, but contains " << data[i].size() << " entries "
241  " on line " << i+1 << " of the data file (" << data_file << "). Dim is " << dim << '.');
242  const std::array<double,2> coords = {{
243  string_to_double(data[i][0]),
244  string_to_double(data[i][1])
245  }
246  };
247  std::cout << data[i][0] << ' ' << data[i][1] << ' ' << data[i][2] << ' ';
248  std::vector<double> output = world->properties(coords, string_to_double(data[i][2]),properties);
249  std::cout << output[0] << ' ';
250 
251  std::cout << output[1] << ' ' << output[2] << ' ';
252 
253  for (unsigned int c = 0; c < compositions; ++c)
254  {
255  std::cout << output[3+c] << ' ';
256  }
257 
258  for (unsigned int gc = 0; gc < grain_compositions; ++gc)
259  {
260  const size_t start = 3+compositions+gc*n_grains*10;
261  for (unsigned int g = 0; g < n_grains; ++g)
262  {
263  std::cout << output[start+g] << ' '
264  << output[start+n_grains+g*9] << ' ' << output[start+n_grains+g*9+1] << ' ' << output[start+n_grains+g*9+2] << ' '
265  << output[start+n_grains+g*9+3] << ' ' << output[start+n_grains+g*9+4] << ' ' << output[start+n_grains+g*9+5] << ' '
266  << output[start+n_grains+g*9+6] << ' ' << output[start+n_grains+g*9+7] << ' ' << output[start+n_grains+g*9+8] << ' ';
267 
268  }
269  }
270  std::cout << " " << output[output.size()-1] << std::endl;
271 
272  }
273  break;
274  case 3:
275  // set the header
276  std::cout << "# x y z d g T vx vy vz ";
277 
278  for (unsigned int c = 0; c < compositions; ++c)
279  std::cout << 'c' << c << ' ';
280 
281  for (unsigned int gc = 0; gc < grain_compositions; ++gc)
282  for (size_t g = 0; g < n_grains; g++)
283  std::cout << "gs" << gc << '-' << g << ' ' // gs = grain size, gm = grain rotation matrix
284  << "gm" << gc << '-' << g << "[0:0] " << "gm" << gc << '-' << g << "[0:1] " << "gm" << gc << '-' << g << "[0:2] "
285  << "gm" << gc << '-' << g << "[1:0] " << "gm" << gc << '-' << g << "[1:1] " << "gm" << gc << '-' << g << "[1:2] "
286  << "gm" << gc << '-' << g << "[2:0] " << "gm" << gc << '-' << g << "[2:1] " << "gm" << gc << '-' << g << "[2:2] ";
287 
288  std::cout << "tag ";
289  std::cout <<std::endl;
290 
291  // set the values
292  for (unsigned int i = 0; i < data.size(); ++i)
293  if (data[i].size() > 0 && data[i][0] != "#")
294  {
295  WBAssertThrow(data[i].size() == dim + 1, "The file needs to contain dim + 1 entries, but contains " << data[i].size() << " entries "
296  " on line " << i+1 << " of the data file (" << data_file << "). Dim is " << dim << '.');
297  std::array<double,3> coords = {{
298  string_to_double(data[i][0]), // x or R
299  string_to_double(data[i][1]) *(convert_spherical ? (WorldBuilder::Consts::PI/180.): 1.), // y or long
300  string_to_double(data[i][2]) *(convert_spherical ? (WorldBuilder::Consts::PI/180.): 1.) // z or lat
301  }
302  };
303 
304  if (convert_spherical)
305  {
307  }
308 
309  std::cout << data[i][0] << ' ' << data[i][1] << ' ' << data[i][2] << ' ' << data[i][3] << ' ';
310  std::vector<double> output = world->properties(coords, string_to_double(data[i][3]),properties);
311  std::cout << output[0] << ' ';
312 
313  std::cout << output[1] << ' ' << output[2] << ' ' << output[3] << ' ';
314 
315  for (unsigned int c = 0; c < compositions; ++c)
316  {
317  std::cout << output[4+c] << ' ';
318  }
319 
320  for (unsigned int gc = 0; gc < grain_compositions; ++gc)
321  {
322  const size_t start = 4+compositions+gc*n_grains*10;
323  for (unsigned int g = 0; g < n_grains; ++g)
324  {
325  std::cout << output[start+g] << ' '
326  << output[start+n_grains+g*9] << ' ' << output[start+n_grains+g*9+1] << ' ' << output[start+n_grains+g*9+2] << ' '
327  << output[start+n_grains+g*9+3] << ' ' << output[start+n_grains+g*9+4] << ' ' << output[start+n_grains+g*9+5] << ' '
328  << output[start+n_grains+g*9+6] << ' ' << output[start+n_grains+g*9+7] << ' ' << output[start+n_grains+g*9+8] << ' ';
329 
330  }
331  }
332  std::cout << output[output.size()-1] << std::endl;
333 
334  }
335  break;
336  default:
337  std::cout << "The World Builder can only be run in 2d and 3d but a different space dimension " << std::endl
338  << "is given: dim = " << dim << '.';
339 
340 #ifdef WB_WITH_MPI
341  MPI_Finalize();
342 #endif
343  return 0;
344  }
345  }
346 #ifdef WB_WITH_MPI
347  MPI_Finalize();
348 #endif
349  return 0;
350 }
Point< 3 > spherical_to_cartesian_coordinates(const std::array< double, 3 > &scoord)
Definition: utilities.cc:274
const std::array< double, dim > & get_array() const
Definition: point.h:393
bool find_command_line_option(char **begin, char **end, const std::string &option)
Definition: main.cc:49
int main(int argc, char **argv)
Definition: main.cc:54
#define WBAssertThrow(condition, message)
Definition: assert.h:40
double string_to_double(const std::string &string)
Definition: utilities.cc:310
unsigned int string_to_unsigned_int(const std::string &string)
Definition: utilities.cc:349
constexpr double PI
Definition: consts.h:30