World Builder  1.1.0-pre
A geodynamic initial conditions generator
parameters.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 
20 
43 
44 #include "rapidjson/error/en.h"
45 #include "rapidjson/istreamwrapper.h"
46 #include "rapidjson/latexwriter.h"
47 #include "rapidjson/mystwriter.h"
48 #include "rapidjson/prettywriter.h"
49 
50 #include <fstream>
51 #include <memory>
52 
53 using namespace rapidjson;
54 
55 namespace
56 {
57  void remove_key(rapidjson::Value &value, const char *key)
58  {
59  if (value.IsObject())
60  {
61  auto it = value.FindMember(key);
62  if (it != value.MemberEnd())
63  value.RemoveMember(it);
64 
65  for (auto &member : value.GetObject())
66  remove_key(member.value, key);
67 
68  }
69  else if (value.IsArray())
70  {
71  for (auto &element : value.GetArray())
72  remove_key(element, key);
73  }
74  }
75 }
76 
77 namespace WorldBuilder
78 {
79  Parameters::Parameters(World &world_)
80  :
81  world(world_)
82  {
83  }
84 
86  = default;
87 
88  void Parameters::initialize(std::string &filename, bool has_output_dir, const std::string &output_dir)
89  {
90 
91  if (has_output_dir)
92  {
93  StringBuffer buffer;
94  std::ofstream file;
95 
96  // write out json schema
97  file.open (output_dir + "world_builder_declarations.schema.json");
98  WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations.schema.json' for string the json declarations.");
99  PrettyWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> json_writer(buffer);
100  declarations.Accept(json_writer);
101  file << buffer.GetString();
102  file.close();
103  buffer.Clear();
104 
105  // remove Snippets so they don't appear in the documentation:
106  remove_key(declarations, "defaultSnippets");
107 
108  // write out declarations
109  file.open (output_dir + "world_builder_declarations.tex");
110  WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations.tex' for string the tex declarations.");
111 
112  LatexWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> tex_writer(buffer);
113  declarations.Accept(tex_writer);
114  file << buffer.GetString();
115  file.close();
116  buffer.Clear();
117 
118  // write out declarations (open)
119  file.open (output_dir + "world_builder_declarations_open.md");
120  WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations_open.md' for string the tex declarations.");
121 
122  MySTWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> myst_writer_open(buffer, true);
123  declarations.Accept(myst_writer_open);
124  file << buffer.GetString();
125  file.close();
126  buffer.Clear();
127 
128  // write out declarations (closed)
129  file.open (output_dir + "world_builder_declarations_closed.md");
130  WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations_closed.md' for string the tex declarations.");
131 
132  MySTWriter<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> myst_writer_closed(buffer, false);
133  declarations.Accept(myst_writer_closed);
134  file << buffer.GetString();
135  file.close();
136  buffer.Clear();
137  }
138 
139  path_level =0;
140  // Now read in the world builder file into a stringstream and
141  // put it into a the rapidjson document
142  std::stringstream json_input_stream(WorldBuilder::Utilities::read_and_distribute_file_content(filename));
143  rapidjson::IStreamWrapper isw(json_input_stream);
144 
145  // relaxing syntax by allowing comments () for now, maybe also allow trailing commas and (kParseTrailingCommasFlag) and nan's, inf etc (kParseNanAndInfFlag)?
146  //WBAssertThrow(!parameters.ParseStream<kParseCommentsFlag>(isw).HasParseError(), "Parsing errors world builder file");
147 
148  WBAssertThrowExc(!(parameters.ParseStream<kParseCommentsFlag | kParseNanAndInfFlag>(isw).HasParseError()), std::ifstream json_input_stream_error(filename.c_str()); ,
149  "Parsing errors world builder file: Error(offset " << static_cast<unsigned>(parameters.GetErrorOffset())
150  << "): " << GetParseError_En(parameters.GetParseError()) << std::endl << std::endl
151  << " Showing 50 chars before and after: "
152  << std::string((std::istreambuf_iterator<char>(json_input_stream_error.seekg(0, json_input_stream_error.beg))),
153  std::istreambuf_iterator<char>()).substr(static_cast<unsigned>(parameters.GetErrorOffset()) <= 50
154  ?
155  0
156  :
157  static_cast<unsigned>(parameters.GetErrorOffset()) - 50, 100
158  ) << std::endl << std::endl
159  << " Showing 5 chars before and after: "
160  << std::string((std::istreambuf_iterator<char>(json_input_stream_error.seekg(0, json_input_stream_error.beg))),
161  std::istreambuf_iterator<char>()).substr(static_cast<unsigned>(parameters.GetErrorOffset()) <= 5
162  ? 0
163  :
164  static_cast<unsigned>(parameters.GetErrorOffset())-5,
165  (static_cast<unsigned>(parameters.GetErrorOffset()) + 10 > json_input_stream_error.seekg(0,std::ios::end).tellg()
166  ?
167  static_cast<unsigned>(json_input_stream.tellg())-static_cast<unsigned>(parameters.GetErrorOffset())
168  :
169  10)
170  ));
171 
172  WBAssertThrow(parameters.IsObject(), "World builder file is is not an object.");
173 
174 
175  const SchemaDocument schema(declarations);
176  SchemaValidator validator(schema);
177 
178  if (!parameters.Accept(validator))
179  {
180  // Input JSON is invalid according to the schema
181  // Output diagnostic information
182  StringBuffer buffer;
183  std::stringstream string;
184  validator.GetInvalidSchemaPointer().StringifyUriFragment(buffer);
185  string << "Invalid schema: " << buffer.GetString() << std::endl;
186  string << "Invalid keyword: " << validator.GetInvalidSchemaKeyword();
187  buffer.Clear();
188  validator.GetInvalidDocumentPointer().StringifyUriFragment(buffer);
189  string << "Invalid schema: " << buffer.GetString() << std::endl;
190  PrettyWriter<StringBuffer> writer(buffer);
191  validator.GetError().Accept(writer);
192  WBAssertThrow(false, string.str() << "Error document: " << std::endl << buffer.GetString());
193  }
194  }
195 
196  void
197  Parameters::declare_entry(const std::string &name,
198  const Types::Interface &type,
199  const std::string &documentation)
200  {
201  type.write_schema(*this,name,documentation);
202  }
203 
204  bool
205  Parameters::check_entry(const std::string &name) const
206  {
207  return Pointer((this->get_full_json_path() + "/" + name).c_str()).Get(parameters) != nullptr;
208  }
209 
210 
211  template<>
212  std::string
213  Parameters::get(const std::string &name)
214  {
215  const std::string base = this->get_full_json_path();
216  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
217 
218 #ifdef debug
219  bool required = false;
220  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
221  {
222  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
223  {
224  if (v.GetString() == name)
225  {
226  required = true;
227  }
228  }
229  }
230 
231  WBAssert(value != NULL || required == false,
232  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
233 #endif
234  if (value == nullptr)
235  {
236  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
237  WBAssertThrow(value != nullptr,
238  "internal error: could not retrieve the default value at: "
239  << base + "/" + name + "/default value");
240  }
241 
242  return value->GetString();
243  }
244 
245  template<>
246  double
247  Parameters::get(const std::string &name)
248  {
249  const std::string base = this->get_full_json_path();
250  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
251 
252 #ifdef debug
253  bool required = false;
254  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
255  {
256  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
257  {
258  if (v.GetString() == name)
259  {
260  required = true;
261  }
262  }
263  }
264 
265  WBAssert(value != NULL || required == false,
266  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
267 #endif
268  if (value == nullptr)
269  {
270  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
271  WBAssertThrow(value != nullptr,
272  "internal error: could not retrieve the default value at: "
273  << get_full_json_schema_path() + "/" + name + "/default value, for value: " << base + "/" + name);
274  }
275 
276  double return_value;
277  try
278  {
279  return_value = value->GetDouble();
280  }
281  catch (...)
282  {
283  WBAssertThrow(false, "Could not convert values of " << base << " into doubles.");
284  }
285  return return_value;
286  }
287 
288  template<>
289  size_t
290  Parameters::get(const std::string &name)
291  {
292  const std::string base = this->get_full_json_path();
293  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
294 
295 #ifdef debug
296  bool required = false;
297  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
298  {
299  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
300  {
301  if (v.GetString() == name)
302  {
303  required = true;
304  }
305  }
306  }
307 
308  WBAssert(value != NULL || required == false,
309  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
310 #endif
311  if (value == nullptr)
312  {
313  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
314  WBAssertThrow(value != nullptr,
315  "internal error: could not retrieve the default value at: "
316  << base + "/" + name + "/default value");
317  }
318 
319  return value->GetUint();
320  }
321 
322  template<>
323  unsigned int
324  Parameters::get(const std::string &name)
325  {
326  const std::string base = this->get_full_json_path();
327  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
328 
329 #ifdef debug
330  bool required = false;
331  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
332  {
333  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
334  {
335  if (v.GetString() == name)
336  {
337  required = true;
338  }
339  }
340  }
341 
342  WBAssert(value != NULL || required == false,
343  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
344 #endif
345  if (value == nullptr)
346  {
347  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
348  WBAssertThrow(value != nullptr,
349  "internal error: could not retrieve the default value at: "
350  << base + "/" + name + "/default value");
351  }
352 
353  return value->GetUint();
354  }
355 
356  template<>
357  int
358  Parameters::get(const std::string &name)
359  {
360  const std::string base = this->get_full_json_path();
361  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
362 
363 #ifdef debug
364  bool required = false;
365  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
366  {
367  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
368  {
369  if (v.GetString() == name)
370  {
371  required = true;
372  }
373  }
374  }
375 
376  WBAssert(value != NULL || required == false,
377  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
378 #endif
379  if (value == nullptr)
380  {
381  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
382  WBAssertThrow(value != nullptr,
383  "internal error: could not retrieve the default value at: "
384  << base + "/" + name + "/default value");
385  }
386 
387  return value->GetInt();
388  }
389 
390  template<>
391  bool
392  Parameters::get(const std::string &name)
393  {
394  const std::string base = this->get_full_json_path();
395  const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters);
396 
397 #ifdef debug
398  bool required = false;
399  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
400  {
401  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
402  {
403  if (v.GetString() == name)
404  {
405  required = true;
406  }
407  }
408  }
409 
410  WBAssert(value != NULL || required == false,
411  "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required.");
412 #endif
413  if (value == nullptr)
414  {
415  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
416  WBAssertThrow(value != nullptr,
417  "internal error: could not retrieve the default value at: "
418  << base + "/" + name + "/default value");
419  }
420 
421  return value->GetBool();
422  }
423 
424 
425  template<>
426  Point<2>
427  Parameters::get(const std::string &name)
428  {
429 
430  const std::string strict_base = this->get_full_json_path();
431  const Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
432 
433 #ifdef debug
434  bool required = false;
435  if (Pointer((strict_base + "/required").c_str()).Get(declarations) != NULL)
436  {
437  for (auto &v : Pointer((strict_base + "/required").c_str()).Get(declarations)->GetArray())
438  {
439  if (v.GetString() == name)
440  {
441  required = true;
442  }
443  }
444  }
445 
446  WBAssert(array != NULL || required == false,
447  "Internal error: Value \"" << strict_base << '/' << name << "/type\" not found in the input file, while it was set as required.");
448 #endif
449  if (array != nullptr)
450  {
451  const std::string base = strict_base + "/" + name;
452  //let's assume that the file is correct, because it has been checked with the json schema.
453  // So there are exactly two values.
454  double value1;
455  double value2;
456 
457  try
458  {
459  value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble();
460  value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble();
461  }
462  catch (...)
463  {
464  WBAssertThrow(false, "Could not convert values of " << base << " into Point<2>, because it could not convert the sub-elements into doubles.");
465  }
466  return Point<2>(value1,value2,this->coordinate_system->natural_coordinate_system());
467  }
468  WBAssertThrow(false, "default values not implemented in get<Point<2> >. Looked in: " + strict_base + "/" << name);
469 
470  return {invalid};;
471  }
472 
473  template<>
474  std::vector<bool>
475  Parameters::get_vector(const std::string &name)
476  {
477  std::vector<bool> vector;
478  const std::string strict_base = this->get_full_json_path();
479  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
480  {
481  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
482 
483  for (size_t i = 0; i < array->Size(); ++i )
484  {
485  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
486 
487  vector.push_back(Pointer(base.c_str()).Get(parameters)->GetBool());
488  }
489  }
490  else
491  {
492  const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations);
493  WBAssertThrow(value != nullptr,
494  "internal error: could not retrieve the minItems value at: "
495  << this->get_full_json_schema_path() + "/" + name + "/minItems value");
496 
497  const size_t min_size = value->GetUint();
498 
499  const bool default_value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations)->GetBool();
500 
501  // set to min size
502  for (size_t i = 0; i < min_size; ++i)
503  {
504  vector.push_back(default_value);
505  }
506  }
507  return vector;
508  }
509 
510 
511  std::pair<std::vector<double>,std::vector<double>>
512  Parameters::get(const std::string &name,
513  const std::vector<Point<2> > &addition_points)
514  {
515  // There are four cases:
516  // 1. No value provided: use the default value everywhere. Return first with one value and second with size 0.
517  // 2. One double provided: use the default value everywhere. Return first with one value and second with size 0.
518  // 3. One value in a double array and no points provided: use that value everywhere. Return first with one value and second with size 0.
519  // 4. Other: fill the vectors with the default value and addition points and then add new point.
520  // If a value without points is encountered, the additional points are used.
521  std::pair<std::vector<double>,std::vector<double>> result;
522 
523  const std::string strict_base = this->get_full_json_path();
524 
525  // start with adding the additional points with the default value
526  // to do this we need the default value
527  double default_value = 0;
528  bool is_array = true;
529  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray())
530  {
531  const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/anyOf/0/default value";
532  Value *value_def = Pointer(value_def_path.c_str()).Get(declarations);
533  WBAssertThrow(value_def != nullptr,
534  "internal error: could not retrieve the default value at: "
535  << value_def_path);
536 
537  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
538  // So no try/catch needed.
539  default_value = value_def->GetDouble();
540  }
541  else
542  {
543  is_array = false;
544  Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations);
545  WBAssertThrow(value_def != nullptr,
546  "internal error: could not retrieve the default value at: "
547  <<get_full_json_schema_path() + "/" + name + "/oneOf/0/default value");
548 
549 
550  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
551  // So no try/catch needed.
552  default_value = value_def->GetDouble();
553  }
554 
555 
556  // check if there is a user defined value
557  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
558  {
559  // there is a user defined value, so either case 2, 3 or 4.
560  if (is_array)
561  {
562  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
563 
564  if (array->Size() == 1
565  && Pointer((strict_base + "/" + name + "/0/1").c_str()).Get(parameters) == nullptr)
566  {
567  // case 2: Return first with one value and second with size 0.
568  double value = 0;
569  try
570  {
571  value = Pointer((strict_base + "/" + name + "/0/0").c_str()).Get(parameters)->GetDouble();
572  }
573  catch (...)
574  {
575  WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << "/0/0 into a double. "
576  << "The provided value was \"" << Pointer((strict_base + "/" + name + "/0/0").c_str()).Get(parameters)->GetString() << "\".");
577  }
578  result.first.emplace_back(value);
579  }
580  else
581  {
582  // case 3: fill the vectors with the default value and addition points and then add new point.
583  // If a value without points is encountered, the additional points are used.
584 
585  // first fill with additional points at default value
586  for (const auto &addition_point : addition_points)
587  {
588  result.first.emplace_back(default_value);
589  result.second.emplace_back(addition_point[0]);
590  result.second.emplace_back(addition_point[1]);
591  }
592 
593  // second, go through all the points in order
594  for (size_t i = 0; i < array->Size(); ++i )
595  {
596  // now parse a single value_at_point.
597  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
598  // Let's assume that the file is correct, because it has been checked with the json schema.
599  // So there are exactly two values, the first value is a double, the second an array of 2d arrays (points).
600 
601  // Get the double
602  double value;
603  Value *value_pointer = Pointer((base + "/0").c_str()).Get(parameters);
604 
605  WBAssertThrow(value_pointer != nullptr, "internal error: this should not happen.");
606 
607  try
608  {
609  value = value_pointer->GetDouble();
610  }
611  catch (...)
612  {
613  WBAssertThrow(false, "Could not convert values of " << base << "/0 into doubles. "
614  << "The provided value was \"" << Pointer((base + "/0").c_str()).Get(parameters)->GetString() << "\".");
615  }
616 
617  // now get the array of points.
618  Value *coordinates_array = Pointer((base + "/1").c_str()).Get(parameters);
619  if (coordinates_array != nullptr)
620  {
621  for (size_t coordinate_i = 0; coordinate_i < coordinates_array->Size(); ++coordinate_i )
622  {
623  // Let's assume that the file is correct, because it has been checked with the json schema.
624  // That means that there are exactly two values per item
625  double coordinate_0;
626  double coordinate_1;
627  try
628  {
629  coordinate_0 = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/0").c_str()).Get(parameters)->GetDouble();
630  }
631  catch (...)
632  {
633  WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/0"
634  << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. "
635  << "The provided value was \""
636  << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/0").c_str()).Get(parameters)->GetString()
637  << "\".");
638  }
639  try
640  {
641  coordinate_1 = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/1").c_str()).Get(parameters)->GetDouble();
642  }
643  catch (...)
644  {
645  WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/1"
646  << " into a Point<2> array, because it could not convert the 2nd sub-elements into doubles. "
647  << "The provided value was \""
648  << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/1").c_str()).Get(parameters)->GetString()
649  << "\".");
650  }
651 
652  coordinate_0 *= (coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical ? Consts::PI / 180.0 : 1.);
653  coordinate_1 *= (coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical ? Consts::PI / 180.0 : 1.);
654 
655  bool found_same_point = false;
656  unsigned int coordinate_pair_i = 0;
657  for (; coordinate_pair_i < result.second.size(); coordinate_pair_i+=2)
658  {
659  if (Utilities::approx(result.second[coordinate_pair_i],coordinate_0) && Utilities::approx(result.second[coordinate_pair_i+1],coordinate_1))
660  {
661  found_same_point = true;
662  break;
663  }
664  }
665  if (found_same_point)
666  {
667  // set the value to the new value
668  result.first[coordinate_pair_i/2] = value;
669  }
670  else
671  {
672  // add a new point
673  result.first.emplace_back(value);
674  result.second.emplace_back(coordinate_0);
675  result.second.emplace_back(coordinate_1);
676  }
677  }
678 
679  }
680  else
681  {
682  // no points are provided, so use the value to fill put in the additional points
683  // at that value. Since we know that all the additional points are at the start
684  // we can easily overwrite the values.
685  for (unsigned int addition_point_i = 0; addition_point_i < addition_points.size(); ++addition_point_i)
686  {
687  result.first[addition_point_i] = value;
688  }
689  }
690  }
691  }
692  }
693  else
694  {
695  // case 2: there one value, not an array
696  double value = 0;
697  try
698  {
699  value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble();
700  }
701  catch (...)
702  {
703  WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. "
704  << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\".");
705  }
706  result.first.emplace_back(value);
707  }
708  }
709  else
710  {
711  // there is no user defined value. Case one: return the default value and no points
712  result.first.emplace_back(default_value);
713  }
714 
715  return result;
716  }
717 
718 
719  std::pair<std::vector<double>,std::vector<double>> Parameters::get_value_at_array(const std::string &name)
720  {
721  // There are two cases:
722  // 1. One double provided: use the default value everywhere. Return first with one value and second with size 0.
723  // 2. Other: fill the vectors with the default value and addition points and then add new point.
724  // If a value without points is encountered, the additional points are used.
725  std::pair<std::vector<double>,std::vector<double>> result;
726 
727  const std::string strict_base = this->get_full_json_path();
728 
729  // start with adding the additional points with the default value
730  // to do this we need the default value
731  double default_value = 0;
732  bool is_array = true;
733  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray())
734  {
735  const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/anyOf/0/default value";
736  Value *value_def = Pointer(value_def_path.c_str()).Get(declarations);
737  WBAssertThrow(value_def != nullptr,
738  "internal error: could not retrieve the default value at: "
739  << value_def_path);
740 
741  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
742  // So no try/catch needed.
743  default_value = value_def->GetDouble();
744  }
745  else
746  {
747  is_array = false;
748  Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations);
749  WBAssertThrow(value_def != nullptr,
750  "internal error: could not retrieve the default value at: "
751  <<get_full_json_schema_path() + "/" + name + "/oneOf/0/default value");
752 
753 
754  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
755  // So no try/catch needed.
756  default_value = value_def->GetDouble();
757  }
758 
759 
760  // check if there is a user defined value
761  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
762  {
763  // there is a user defined value, so either case 2, 3 or 4.
764  if (is_array)
765  {
766  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
767 
768  // go through all the points in order
769  for (size_t i = 0; i < array->Size(); ++i )
770  {
771  // now parse a single value_at_point.
772  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
773  // Let's assume that the file is correct, because it has been checked with the json schema.
774  // So there are exactly two values, the first value is a double, the second an array of 2d arrays (points).
775 
776  // Get the double
777  double value;
778  Value *value_pointer = Pointer((base + "/0").c_str()).Get(parameters);
779 
780  WBAssertThrow(value_pointer != nullptr, "internal error: this should not happen.");
781 
782  try
783  {
784  value = value_pointer->GetDouble();
785  }
786  catch (...)
787  {
788  WBAssertThrow(false, "Could not convert values of " << base << "/0 into doubles. "
789  << "The provided value was \"" << Pointer((base + "/0").c_str()).Get(parameters)->GetString() << "\".");
790  }
791 
792  // now get the array of points.
793  Value *array_of_doubles = Pointer((base + "/1").c_str()).Get(parameters);
794  double value_in_array;
795  if (array_of_doubles != nullptr)
796  {
797  for (size_t coordinate_i = 0; coordinate_i < array_of_doubles->Size(); ++coordinate_i )
798  {
799  Value *coordinate_j_array = Pointer((base + "/1/" + std::to_string(coordinate_i)).c_str()).Get(parameters);
800  for (size_t coordinate_j = 0; coordinate_j < coordinate_j_array->Size(); ++coordinate_j)
801  {
802  // Let's assume that the file is correct, because it has been checked with the json schema.
803  // That means that there are exactly two values per item
804  try
805  {
806  value_in_array = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j)).c_str()).Get(parameters)->GetDouble();
807  }
808  catch (...)
809  {
810  WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j)
811  << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. "
812  << "The provided value was \""
813  << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j)).c_str()).Get(parameters)->GetString()
814  << "\".");
815  }
816 
817  result.second.emplace_back(value_in_array);
818  }
819  }
820  result.first.emplace_back(value);
821  }
822  }
823  }
824  else
825  {
826  // case 1: there one value, not an array
827  double value = 0;
828  try
829  {
830  value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble();
831  }
832  catch (...)
833  {
834  WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. "
835  << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\".");
836  }
837  result.first.emplace_back(0.0);
838  result.second.emplace_back(value);
839  }
840  }
841  else
842  {
843  // there is no user defined value. Case one: return the default value and no points
844  result.first.emplace_back(0.0);
845  result.second.emplace_back(default_value);
846  }
847 
848  return result;
849  }
850 
851 
852  template<>
853  std::vector<Point<2> >
854  Parameters::get_vector(const std::string &name)
855  {
856  std::vector<Point<2> > vector;
857  const std::string strict_base = this->get_full_json_path();
858  WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name
859  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
860 
861  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
862 
863  for (size_t i = 0; i < array->Size(); ++i )
864  {
865  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
866  //let's assume that the file is correct, because it has been checked with the json schema.
867  // So there are exactly two values.
868  double value1;
869  double value2;
870 
871  try
872  {
873  value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble();
874  value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble();
875  }
876  catch (...)
877  {
878  WBAssertThrow(false, "Could not convert values of " << base << " into a Point<2> array, because it could not convert the sub-elements into doubles.");
879  }
880  vector.emplace_back(value1,value2,this->coordinate_system->natural_coordinate_system());
881  }
882 
883  return vector;
884  }
885 
886  template<>
887  std::vector<std::array<double,3> >
888  Parameters::get_vector(const std::string &name)
889  {
890  std::vector<std::array<double,3> > vector;
891  const std::string strict_base = this->get_full_json_path();
892  WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name
893  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
894 
895  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
896 
897  for (size_t i = 0; i < array->Size(); ++i )
898  {
899  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
900  //let's assume that the file is correct, because it has been checked with the json schema.
901  // So there are exactly three values.
902  try
903  {
904  const double value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble();
905  const double value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble();
906  const double value3 = Pointer((base + "/2").c_str()).Get(parameters)->GetDouble();
907  vector.push_back({{value1,value2,value3}});
908  }
909  catch (...)
910  {
911  WBAssertThrow(false, "Could not convert values of " << base << " into doubles.");
912  }
913  }
914 
915 
916  return vector;
917  }
918 
919  std::vector<std::vector<double>>
920  Parameters::get_vector_or_double(const std::string &name)
921  {
922  // There are two cases:
923  // 1. One double provided: use the default value everywhere. Return first with one value and second with size 0.
924  // 2. std::vector<std::vector<double>> provided: output this array.
925  std::vector<std::vector<double>> result;
926 
927  const std::string strict_base = this->get_full_json_path();
928 
929  // start with adding the additional points with the default value
930  // to do this we need the default value
931  double default_value = 0;
932  bool is_array = true;
933  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray())
934  {
935  const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/default value";
936  Value *value_def = Pointer(value_def_path.c_str()).Get(declarations);
937  WBAssertThrow(value_def != nullptr,
938  "internal error: could not retrieve the default value at: "
939  << value_def_path);
940 
941  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
942  // So no try/catch needed.
943  default_value = value_def->GetDouble();
944  }
945  else
946  {
947  is_array = false;
948  Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations);
949  WBAssertThrow(value_def != nullptr,
950  "internal error: could not retrieve the default value at: "
951  <<get_full_json_schema_path() + "/" + name + "/oneOf/0/default value");
952 
953 
954  // Since the default value is set in the code, if it fails it is an internal error, not a user error.
955  // So no try/catch needed.
956  default_value = value_def->GetDouble();
957  }
958 
959 
960  // check if there is a user defined value
961  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
962  {
963  // there is a user defined value, so either case 2, 3 or 4.
964  if (is_array)
965  {
966  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
967 
968  // go through all the 1d-arrays within the 2d-array
969  for (size_t i = 0; i < array->Size(); ++i )
970  {
971  // now parse a single value_at_point.
972  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
973 
974  // now get the array of points.
975  // Value *coordinates_array = Pointer((base + "/0").c_str()).Get(parameters);
976  Value *coordinates_array = Pointer((base).c_str()).Get(parameters);
977  double value_in_array;
978  std::vector<double> array_of_values;
979  if (coordinates_array != nullptr)
980  {
981  for (size_t coordinate_i = 0; coordinate_i < coordinates_array->Size(); ++coordinate_i )
982  {
983  // Let's assume that the file is correct, because it has been checked with the json schema.
984  // That means that there are exactly two values per item
985  try
986  {
987  value_in_array = Pointer(((base + "/") + std::to_string(coordinate_i)).c_str()).Get(parameters)->GetDouble();
988  }
989  catch (...)
990  {
991  WBAssertThrow(false, "Could not convert values of " << base + "/" + std::to_string(i) + "/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_i)
992  << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. "
993  << "The provided value was \""
994  << Pointer((base + "/" + std::to_string(i) + "/" + std::to_string(coordinate_i)).c_str()).Get(parameters)->GetString()
995  << "\".");
996  }
997  array_of_values.emplace_back(value_in_array);
998  }
999  result.emplace_back(array_of_values);
1000 
1001  }
1002  }
1003  }
1004  else
1005  {
1006  // case 1: there's one value, not an array
1007  double value = 0;
1008  try
1009  {
1010  value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble();
1011  }
1012  catch (...)
1013  {
1014  WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. "
1015  << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\".");
1016  }
1017  result.emplace_back(std::vector<double> {value});
1018  }
1019  }
1020  else
1021  {
1022  // there is no user defined value. Case one: return the default value and no points
1023  result.emplace_back(std::vector<double> {default_value});
1024  }
1025 
1026  return result;
1027  }
1028 
1029 
1030 
1031  template<>
1032  std::vector<std::array<std::array<double,3>,3> >
1033  Parameters::get_vector(const std::string &name)
1034  {
1035  std::vector<std::array<std::array<double,3>,3> > vector;
1036  const std::string strict_base = this->get_full_json_path();
1037  WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name
1038  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
1039 
1040  Value *array1 = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1041 
1042  for (size_t i = 0; i < array1->Size(); ++i )
1043  {
1044  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1045  Value *array2 = Pointer((base).c_str()).Get(parameters);
1046 
1047  // Not sure why cppcheck it is generating the warning
1048  // Filed a question at: https://sourceforge.net/p/cppcheck/discussion/general/thread/429759f85e/
1049  // cppcheck-suppress constStatement
1050  std::array<std::array<double,3>,3> array;
1051  WBAssertThrow(array2->Size() == 3, "Array " << i << " is supposed to be a 3x3 array, but the outer array dimensions is "
1052  << array2->Size() << '.');
1053  for (size_t j = 0; j < array2->Size(); ++j )
1054  {
1055  const std::string base_extended = base + "/" + std::to_string(j);
1056 
1057  WBAssertThrow(Pointer((base_extended).c_str()).Get(parameters)->Size() == 3,
1058  "Array " << i << " is supposed to be a 3x3 array, but the inner array dimensions of "
1059  << j << " is " << Pointer((base_extended).c_str()).Get(parameters)->Size() << '.');
1060  double value1;
1061  double value2;
1062  double value3;
1063 
1064  try
1065  {
1066  value1 = Pointer((base_extended + "/0").c_str()).Get(parameters)->GetDouble();
1067  value2 = Pointer((base_extended + "/1").c_str()).Get(parameters)->GetDouble();
1068  value3 = Pointer((base_extended + "/2").c_str()).Get(parameters)->GetDouble();
1069  }
1070  catch (...)
1071  {
1072  WBAssertThrow(false, "Could not convert values of " << base << " into doubles.");
1073  }
1074  array[j][0] = value1;
1075  array[j][1] = value2;
1076  array[j][2] = value3;
1077  }
1078  vector.push_back(array);
1079  }
1080 
1081  return vector;
1082  }
1083 
1084 
1085  template<>
1086  std::vector<std::vector<Point<2> > >
1087  Parameters::get_vector(const std::string &name)
1088  {
1089  std::vector<std::vector<Point<2> > > vector;
1090  const std::string strict_base = this->get_full_json_path();
1091  WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name
1092  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
1093 
1094  Value *array1 = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1095 
1096  for (size_t i = 0; i < array1->Size(); ++i )
1097  {
1098  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1099  Value *array2 = Pointer((base).c_str()).Get(parameters);
1100 
1101  // Not sure why cppcheck it is generating the warning
1102  // Filed a question at: https://sourceforge.net/p/cppcheck/discussion/general/thread/429759f85e/
1103  // cppcheck-suppress constStatement
1104  std::vector<Point<2> > sub_vector(array2->Size(),Point<2>(NaN::DSNAN,NaN::DSNAN,coordinate_system->natural_coordinate_system()));
1105  for (size_t j = 0; j < array2->Size(); ++j )
1106  {
1107  const std::string base_extended = base + "/" + std::to_string(j);
1108 
1109  WBAssertThrow(Pointer((base_extended).c_str()).Get(parameters)->Size() == 2,
1110  "Array " << i << " is supposed to be a 2d point, but the inner array dimensions of "
1111  << j << " is " << Pointer((base_extended).c_str()).Get(parameters)->Size() << '.');
1112  double value1;
1113  double value2;
1114 
1115  try
1116  {
1117  value1 = Pointer((base_extended + "/0").c_str()).Get(parameters)->GetDouble();
1118  value2 = Pointer((base_extended + "/1").c_str()).Get(parameters)->GetDouble();
1119  }
1120  catch (...)
1121  {
1122  WBAssertThrow(false, "Could not convert values of " << base << " into doubles, because it could not covert the sub-elements into doubles.");
1123  }
1124  sub_vector[j][0] = value1;
1125  sub_vector[j][1] = value2;
1126  }
1127  vector.push_back(sub_vector);
1128  }
1129 
1130  return vector;
1131  }
1132 
1133 
1134  template<>
1139  Parameters::get_vector(const std::string &name,
1140  std::vector<std::shared_ptr<Features::SubductingPlateModels::Temperature::Interface> > &default_temperature_models,
1141  std::vector<std::shared_ptr<Features::SubductingPlateModels::Composition::Interface> > &default_composition_models,
1142  std::vector<std::shared_ptr<Features::SubductingPlateModels::Grains::Interface> > &default_grains_models,
1143  std::vector<std::shared_ptr<Features::SubductingPlateModels::Velocity::Interface> > &default_velocity_models)
1144  {
1145  using namespace Features::SubductingPlateModels;
1146  std::vector<Objects::Segment<Temperature::Interface,Composition::Interface,Grains::Interface,Velocity::Interface> > vector;
1147  this->enter_subsection(name);
1148  const std::string strict_base = this->get_full_json_path();
1149  WBAssertThrow(Pointer((strict_base).c_str()).Get(parameters) != nullptr,"Error: " << name
1150  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
1151 
1152  // get the array of segments
1153  Value *array = Pointer((strict_base).c_str()).Get(parameters);
1154 
1155  for (size_t i = 0; i < array->Size(); ++i )
1156  {
1157  this->enter_subsection(std::to_string(i));
1158  const std::string base = this->get_full_json_path();
1159  // get one segment
1160  // length
1161  const double length = Pointer((base + "/length").c_str()).Get(parameters)->GetDouble();
1162 
1163  // get thickness
1164  Value *point_array = Pointer((base + "/thickness").c_str()).Get(parameters);
1165  Point<2> thickness(invalid);
1166  WBAssertThrow(point_array != nullptr,"error: " << name
1167  << " was not defined in " << strict_base << "/thickness, schema path: " << this->get_full_json_schema_path() << "/thickness.");
1168 
1169  if (point_array->Size() == 1)
1170  {
1171  // There is only one value, set it for both elements
1172  const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble();
1173  thickness = Point<2>(local0,local0,invalid);
1174  }
1175  else
1176  {
1177  const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble();
1178  const double local1 = Pointer((base + "/thickness/1").c_str()).Get(parameters)->GetDouble();
1179  thickness = Point<2>(local0,local1,invalid);
1180  }
1181 
1182 
1183  // get top truncation (default is 0,0)
1184  point_array = Pointer((base + "/top truncation").c_str()).Get(parameters);
1185  Point<2> top_truncation(invalid);
1186  if (point_array != nullptr)
1187  {
1188  if (point_array->Size() == 1)
1189  {
1190  // There is only one value, set it for both elements
1191  const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble();
1192  top_truncation = Point<2>(local0,local0,invalid);
1193  }
1194  else
1195  {
1196  const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble();
1197  const double local1 = Pointer((base + "/top truncation/1").c_str()).Get(parameters)->GetDouble();
1198  top_truncation = Point<2>(local0,local1,invalid);
1199  }
1200  }
1201  // get thickness
1202  point_array = Pointer((base + "/angle").c_str()).Get(parameters);
1203  Point<2> angle(invalid);
1204  WBAssertThrow(point_array != nullptr,"error: " << name
1205  << " was not defined in " << strict_base << "/angle, schema path: " << this->get_full_json_schema_path() << "/angle.");
1206 
1207  if (point_array->Size() == 1)
1208  {
1209  // There is only one value, set it for both elements
1210  const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble();
1211  angle = Point<2>(local0,local0,invalid);
1212  }
1213  else
1214  {
1215  const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble();
1216  const double local1 = Pointer((base + "/angle/1").c_str()).Get(parameters)->GetDouble();
1217  angle = Point<2>(local0,local1,invalid);
1218  }
1219 
1220 
1221  // Get temperature models
1222  std::vector<std::shared_ptr<Temperature::Interface> > temperature_models;
1223 
1224  //This is a value to look back in the path elements.
1225  size_t searchback = 0;
1226  if (!this->get_shared_pointers<Temperature::Interface>("temperature models", temperature_models) ||
1227  Pointer((base + "/temperature model default entry").c_str()).Get(parameters) != nullptr)
1228  {
1229  temperature_models = default_temperature_models;
1230 
1231  // find the default value, which is the closest to the current path
1232  for (searchback = 0; searchback < path.size(); ++searchback)
1233  {
1234  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters) != nullptr)
1235  {
1236  break;
1237  }
1238  }
1239 
1240  // if we can not find default value for the temperature model, skip it
1241  if (searchback < path.size())
1242  {
1243 
1244  // copy the value, this unfortunately removes it.
1245  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters)->GetArray());
1246 
1247  // now copy it
1248  Value value2;
1249  value2.CopyFrom(value1, parameters.GetAllocator());
1250 
1251  // now we should have 2x the same value, so put it back and place it in the correct location.
1252  Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1253 
1254  Pointer((base).c_str()).Get(parameters)->AddMember("temperature models", value2, parameters.GetAllocator());
1255  Pointer((base + "/temperature model default entry").c_str()).Set(parameters,true);
1256  }
1257  }
1258 
1259  // now do the same for compositions
1260  std::vector<std::shared_ptr<Composition::Interface> > composition_models;
1261  if (!this->get_shared_pointers<Composition::Interface>("composition models", composition_models) ||
1262  Pointer((base + "/composition model default entry").c_str()).Get(parameters) != nullptr)
1263  {
1264  composition_models = default_composition_models;
1265 
1266 
1267  // find the default value, which is the closest to the current path
1268  for (searchback = 0; searchback < path.size(); ++searchback)
1269  {
1270  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters) != nullptr)
1271  {
1272  break;
1273  }
1274  }
1275 
1276  // if we can not find default value for the temperature model, skip it
1277  if (searchback < path.size())
1278  {
1279 
1280  // copy the value, this unfortunately removes it.
1281  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters)->GetArray());
1282 
1283  // now copy it
1284  Value value2;
1285  value2.CopyFrom(value1, parameters.GetAllocator());
1286 
1287  // now we should have 2x the same value, so put it back and place it in the correct location.
1288  Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1289 
1290  Pointer((base).c_str()).Get(parameters)->AddMember("composition models", value2, parameters.GetAllocator());
1291  Pointer((base + "/composition model default entry").c_str()).Set(parameters,true);
1292  }
1293  }
1294 
1295  // now do the same for grains
1296  std::vector<std::shared_ptr<Grains::Interface> > grains_models;
1297  if (!this->get_shared_pointers<Grains::Interface>("grains models", grains_models) ||
1298  Pointer((base + "/grains model default entry").c_str()).Get(parameters) != nullptr)
1299  {
1300  grains_models = default_grains_models;
1301 
1302 
1303  // find the default value, which is the closest to the current path
1304  for (searchback = 0; searchback < path.size(); ++searchback)
1305  {
1306  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters) != nullptr)
1307  {
1308  break;
1309  }
1310  }
1311 
1312  // if we can not find default value for the temperature model, skip it
1313  if (searchback < path.size())
1314  {
1315 
1316  // copy the value, this unfortunately removes it.
1317  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters)->GetArray());
1318 
1319  // now copy it
1320  Value value2;
1321  value2.CopyFrom(value1, parameters.GetAllocator());
1322 
1323  // now we should have 2x the same value, so put it back and place it in the correct location.
1324  Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1325 
1326  Pointer((base).c_str()).Get(parameters)->AddMember("grains models", value2, parameters.GetAllocator());
1327  Pointer((base + "/grains model default entry").c_str()).Set(parameters,true);
1328  }
1329  }
1330 
1331  // now do the same for velocities
1332  std::vector<std::shared_ptr<Velocity::Interface> > velocity_models;
1333  if (!this->get_shared_pointers<Velocity::Interface>("velocity models", velocity_models) ||
1334  Pointer((base + "/velocity model default entry").c_str()).Get(parameters) != nullptr)
1335  {
1336  velocity_models = default_velocity_models;
1337 
1338 
1339  // find the default value, which is the closest to the current path
1340  for (searchback = 0; searchback < path.size(); ++searchback)
1341  {
1342  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Get(parameters) != nullptr)
1343  {
1344  break;
1345  }
1346  }
1347 
1348  // if we can not find default value for the temperature model, skip it
1349  if (searchback < path.size())
1350  {
1351 
1352  // copy the value, this unfortunately removes it.
1353  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Get(parameters)->GetArray());
1354 
1355  // now copy it
1356  Value value2;
1357  value2.CopyFrom(value1, parameters.GetAllocator());
1358 
1359  // now we should have 2x the same value, so put it back and place it in the correct location.
1360  Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1361 
1362  Pointer((base).c_str()).Get(parameters)->AddMember("velocity models", value2, parameters.GetAllocator());
1363  Pointer((base + "/velocity model default entry").c_str()).Set(parameters,true);
1364  }
1365  }
1366  vector.emplace_back(length, thickness, top_truncation, angle, temperature_models, composition_models, grains_models, velocity_models);
1367 
1368  this->leave_subsection();
1369  }
1370 
1371  this->leave_subsection();
1372  return vector;
1373  }
1374 
1375 
1376  template<>
1377  std::vector<Objects::Segment<Features::FaultModels::Temperature::Interface,Features::FaultModels::Composition::Interface, Features::FaultModels::Grains::Interface, Features::FaultModels::Velocity::Interface> >
1378  Parameters::get_vector(const std::string &name,
1379  std::vector<std::shared_ptr<Features::FaultModels::Temperature::Interface> > &default_temperature_models,
1380  std::vector<std::shared_ptr<Features::FaultModels::Composition::Interface> > &default_composition_models,
1381  std::vector<std::shared_ptr<Features::FaultModels::Grains::Interface> > &default_grains_models,
1382  std::vector<std::shared_ptr<Features::FaultModels::Velocity::Interface> > &default_velocity_models)
1383  {
1384  using namespace Features::FaultModels;
1385  std::vector<Objects::Segment<Temperature::Interface,Composition::Interface,Grains::Interface,Velocity::Interface> > vector;
1386  this->enter_subsection(name);
1387  const std::string strict_base = this->get_full_json_path();
1388  WBAssertThrow(Pointer((strict_base).c_str()).Get(parameters) != nullptr,"error: " << name
1389  << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << ".");
1390 
1391  // get the array of segments
1392  Value *array = Pointer((strict_base).c_str()).Get(parameters);
1393 
1394  for (size_t i = 0; i < array->Size(); ++i )
1395  {
1396  this->enter_subsection(std::to_string(i));
1397  const std::string base = this->get_full_json_path();
1398  // get one segment
1399  // length
1400  const double length = Pointer((base + "/length").c_str()).Get(parameters)->GetDouble();
1401 
1402  // get thickness
1403  Value *point_array = Pointer((base + "/thickness").c_str()).Get(parameters);
1404  Point<2> thickness(invalid);
1405  WBAssertThrow(point_array != nullptr,"error: " << name
1406  << " was not defined in " << strict_base << "/thickness, schema path: " << this->get_full_json_schema_path() << "/thickness.");
1407 
1408  if (point_array->Size() == 1)
1409  {
1410  // There is only one value, set it for both elements
1411  const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble();
1412  thickness = Point<2>(local0,local0,invalid);
1413  }
1414  else
1415  {
1416  const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble();
1417  const double local1 = Pointer((base + "/thickness/1").c_str()).Get(parameters)->GetDouble();
1418  thickness = Point<2>(local0,local1,invalid);
1419  }
1420 
1421 
1422  // get top truncation (default is 0,0)
1423  point_array = Pointer((base + "/top truncation").c_str()).Get(parameters);
1424  Point<2> top_truncation(invalid);
1425  if (point_array != nullptr)
1426  {
1427  if (point_array->Size() == 1)
1428  {
1429  // There is only one value, set it for both elements
1430  const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble();
1431  top_truncation = Point<2>(local0,local0,invalid);
1432  }
1433  else
1434  {
1435  const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble();
1436  const double local1 = Pointer((base + "/top truncation/1").c_str()).Get(parameters)->GetDouble();
1437  top_truncation = Point<2>(local0,local1,invalid);
1438  }
1439  }
1440  // get thickness
1441  point_array = Pointer((base + "/angle").c_str()).Get(parameters);
1442  Point<2> angle(invalid);
1443  WBAssertThrow(point_array != nullptr,"error: " << name
1444  << " was not defined in " << strict_base << "/angle, schema path: " << this->get_full_json_schema_path() << "/angle.");
1445 
1446  if (point_array->Size() == 1)
1447  {
1448  // There is only one value, set it for both elements
1449  const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble();
1450  angle = Point<2>(local0,local0,invalid);
1451  }
1452  else
1453  {
1454  const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble();
1455  const double local1 = Pointer((base + "/angle/1").c_str()).Get(parameters)->GetDouble();
1456  angle = Point<2>(local0,local1,invalid);
1457  }
1458 
1459 
1460  // Get temperature models
1461  std::vector<std::shared_ptr<Temperature::Interface> > temperature_models;
1462 
1463  //This is a value to look back in the path elements.
1464  size_t searchback = 0;
1465  if (!this->get_shared_pointers<Temperature::Interface>("temperature models", temperature_models) ||
1466  Pointer((base + "/temperature model default entry").c_str()).Get(parameters) != nullptr)
1467  {
1468  temperature_models = default_temperature_models;
1469 
1470  // find the default value, which is the closest to the current path
1471  for (searchback = 0; searchback < path.size(); ++searchback)
1472  {
1473  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters) != nullptr)
1474  {
1475  break;
1476  }
1477  }
1478 
1479  // if we can not find default value for the temperature model, skip it
1480  if (searchback < path.size())
1481  {
1482 
1483  // copy the value, this unfortunately removes it.
1484  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters)->GetArray());
1485 
1486  // now copy it
1487  Value value2;
1488  value2.CopyFrom(value1, parameters.GetAllocator());
1489 
1490  // now we should have 2x the same value, so put it back and place it in the correct location.
1491  Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1492 
1493  Pointer((base).c_str()).Get(parameters)->AddMember("temperature models", value2, parameters.GetAllocator());
1494  Pointer((base + "/temperature model default entry").c_str()).Set(parameters,true);
1495  }
1496  }
1497 
1498  // now do the same for compositions
1499  std::vector<std::shared_ptr<Composition::Interface> > composition_models;
1500  if (!this->get_shared_pointers<Composition::Interface>("composition models", composition_models) ||
1501  Pointer((base + "/composition model default entry").c_str()).Get(parameters) != nullptr)
1502  {
1503  composition_models = default_composition_models;
1504 
1505 
1506  // find the default value, which is the closest to the current path
1507  for (searchback = 0; searchback < path.size(); ++searchback)
1508  {
1509  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters) != nullptr)
1510  {
1511  break;
1512  }
1513  }
1514 
1515  // if we can not find default value for the temperature model, skip it
1516  if (searchback < path.size())
1517  {
1518 
1519  // copy the value, this unfortunately removes it.
1520  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters)->GetArray());
1521 
1522  // now copy it
1523  Value value2;
1524  value2.CopyFrom(value1, parameters.GetAllocator());
1525 
1526  // now we should have 2x the same value, so put it back and place it in the correct location.
1527  Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1528 
1529  Pointer((base).c_str()).Get(parameters)->AddMember("composition models", value2, parameters.GetAllocator());
1530  Pointer((base + "/composition model default entry").c_str()).Set(parameters,true);
1531  }
1532  }
1533 
1534  // now do the same for grains
1535  std::vector<std::shared_ptr<Grains::Interface> > grains_models;
1536  if (!this->get_shared_pointers<Grains::Interface>("grains models", grains_models) ||
1537  Pointer((base + "/grains model default entry").c_str()).Get(parameters) != nullptr)
1538  {
1539  grains_models = default_grains_models;
1540 
1541 
1542  // find the default value, which is the closest to the current path
1543  for (searchback = 0; searchback < path.size(); ++searchback)
1544  {
1545  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters) != nullptr)
1546  {
1547  break;
1548  }
1549  }
1550 
1551  // if we can not find default value for the temperature model, skip it
1552  if (searchback < path.size())
1553  {
1554 
1555  // copy the value, this unfortunately removes it.
1556  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters)->GetArray());
1557 
1558  // now copy it
1559  Value value2;
1560  value2.CopyFrom(value1, parameters.GetAllocator());
1561 
1562  // now we should have 2x the same value, so put it back and place it in the correct location.
1563  Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1564 
1565  Pointer((base).c_str()).Get(parameters)->AddMember("grains models", value2, parameters.GetAllocator());
1566  Pointer((base + "/grains model default entry").c_str()).Set(parameters,true);
1567  }
1568  }
1569 
1570  // now do the same for velocitys
1571  std::vector<std::shared_ptr<Velocity::Interface> > velocity_models;
1572  if (!this->get_shared_pointers<Velocity::Interface>("velocity models", velocity_models) ||
1573  Pointer((base + "/velocity model default entry").c_str()).Get(parameters) != nullptr)
1574  {
1575  velocity_models = default_velocity_models;
1576 
1577 
1578  // find the default value, which is the closest to the current path
1579  for (searchback = 0; searchback < path.size(); ++searchback)
1580  {
1581  if (Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Get(parameters) != nullptr)
1582  {
1583  break;
1584  }
1585  }
1586 
1587  // if we can not find default value for the temperature model, skip it
1588  if (searchback < path.size())
1589  {
1590 
1591  // copy the value, this unfortunately removes it.
1592  Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Get(parameters)->GetArray());
1593 
1594  // now copy it
1595  Value value2;
1596  value2.CopyFrom(value1, parameters.GetAllocator());
1597 
1598  // now we should have 2x the same value, so put it back and place it in the correct location.
1599  Pointer((this->get_full_json_path(path.size()-searchback) + "/velocity models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator());
1600 
1601  Pointer((base).c_str()).Get(parameters)->AddMember("velocity models", value2, parameters.GetAllocator());
1602  Pointer((base + "/velocity model default entry").c_str()).Set(parameters,true);
1603  }
1604  }
1605 
1606  vector.emplace_back(length, thickness, top_truncation, angle, temperature_models, composition_models, grains_models, velocity_models);
1607 
1608  this->leave_subsection();
1609  }
1610 
1611  this->leave_subsection();
1612  return vector;
1613  }
1614 
1615  template<>
1616  std::vector<double>
1617  Parameters::get_vector(const std::string &name)
1618  {
1619  std::vector<double> vector;
1620  const std::string strict_base = this->get_full_json_path();
1621  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1622  {
1623  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1624 
1625  for (size_t i = 0; i < array->Size(); ++i )
1626  {
1627  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1628 
1629  vector.push_back(Pointer(base.c_str()).Get(parameters)->GetDouble());
1630  }
1631  }
1632  else
1633  {
1634  const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations);
1635  WBAssertThrow(value != nullptr,
1636  "internal error: could not retrieve the minItems value at: "
1637  << this->get_full_json_schema_path() + "/" + name + "/minItems");
1638 
1639  const size_t min_size = value->GetUint();
1640 
1641  value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations);
1642  WBAssertThrow(value != nullptr,
1643  "internal error: could not retrieve the default value at: "
1644  << this->get_full_json_schema_path() + "/" + name + "/default value");
1645 
1646  const double default_value = value->GetDouble();
1647 
1648  // set to min size
1649  for (size_t i = 0; i < min_size; ++i)
1650  {
1651  vector.push_back(default_value);
1652  }
1653  }
1654  return vector;
1655  }
1656 
1657  template<>
1658  std::vector<size_t>
1659  Parameters::get_vector(const std::string &name)
1660  {
1661  std::vector<size_t> vector;
1662  const std::string strict_base = this->get_full_json_path();
1663  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1664  {
1665  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1666 
1667  for (size_t i = 0; i < array->Size(); ++i )
1668  {
1669  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1670 
1671  vector.push_back(Pointer(base.c_str()).Get(parameters)->GetUint());
1672  }
1673  }
1674  else
1675  {
1676  const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations);
1677  WBAssertThrow(value != nullptr,
1678  "internal error: could not retrieve the minItems value at: "
1679  << this->get_full_json_schema_path() + "/" + name + "/minItems");
1680 
1681  const size_t min_size = value->GetUint();
1682 
1683  value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations);
1684  WBAssertThrow(value != nullptr,
1685  "internal error: could not retrieve the default value at: "
1686  << this->get_full_json_schema_path() + "/" + name + "/default value");
1687 
1688  const size_t default_value = value->GetUint();
1689 
1690  // set to min size
1691  for (size_t i = 0; i < min_size; ++i)
1692  {
1693  vector.push_back(default_value);
1694  }
1695  }
1696  return vector;
1697  }
1698 
1699  template<>
1700  std::vector<unsigned int>
1701  Parameters::get_vector(const std::string &name)
1702  {
1703  std::vector<unsigned int> vector;
1704  const std::string strict_base = this->get_full_json_path();
1705  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1706  {
1707  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1708 
1709  for (size_t i = 0; i < array->Size(); ++i )
1710  {
1711  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1712 
1713  vector.push_back(Pointer(base.c_str()).Get(parameters)->GetUint());
1714  }
1715  }
1716  else
1717  {
1718  const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations);
1719  WBAssertThrow(value != nullptr,
1720  "internal error: could not retrieve the minItems value at: "
1721  << this->get_full_json_schema_path() + "/" + name + "/minItems value");
1722 
1723  const size_t min_size = value->GetUint();
1724 
1725  const unsigned int default_value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations)->GetUint();
1726 
1727  // set to min size
1728  for (size_t i = 0; i < min_size; ++i)
1729  {
1730  vector.push_back(default_value);
1731  }
1732  }
1733  return vector;
1734  }
1735 
1736  template<class T>
1737  std::unique_ptr<T>
1738  Parameters::get_unique_pointer(const std::string &name)
1739  {
1740  const std::string base = this->get_full_json_path();
1741  Value *value = Pointer((base + "/" + name + "/model").c_str()).Get(parameters);
1742 
1743 #ifdef debug
1744  bool required = false;
1745  if (Pointer((base + "/required").c_str()).Get(declarations) != NULL)
1746  for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray())
1747  {
1748  if (v.GetString() == name)
1749  {
1750  required = true;
1751  }
1752  }
1753 
1754  WBAssert(value != NULL || required == false,
1755  "Internal error: Value \"" << base << '/' << name << "/model\" not found in the input file, while it was set as required.");
1756 #endif
1757  if (value == nullptr)
1758  {
1759  value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations);
1760  WBAssertThrow(value != nullptr,
1761  "internal error: could not retrieve the default value at: "
1762  << base + "/" + name + "/default value. Make sure the value has been declared.");
1763  }
1764 
1765  return T::create(value->GetString(),&world);
1766  }
1767 
1768  template<class T>
1769  bool
1770  Parameters::get_unique_pointers(const std::string &name, std::vector<std::unique_ptr<T> > &vector)
1771  {
1772  vector.resize(0);
1773  const std::string strict_base = this->get_full_json_path();
1774  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1775  {
1776  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1777 
1778  for (size_t i = 0; i < array->Size(); ++i )
1779  {
1780  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1781 
1782  const std::string value = Pointer((base + "/model").c_str()).Get(parameters)->GetString();
1783 
1784  vector.push_back(std::move(T::create(value, &world)));
1785  }
1786  }
1787  else
1788  {
1789  return false;
1790  }
1791 
1792  return true;
1793  }
1794 
1795  template<>
1796  bool
1797  Parameters::get_unique_pointers(const std::string &name, std::vector<std::unique_ptr<Features::SubductingPlate> > &vector)
1798  {
1799  vector.resize(0);
1800  const std::string strict_base = this->get_full_json_path();
1801  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1802  {
1803  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1804 
1805  for (size_t i = 0; i < array->Size(); ++i )
1806  {
1807  vector.push_back(std::make_unique<Features::SubductingPlate>(&world));
1808  }
1809  }
1810  else
1811  {
1812  return false;
1813  }
1814 
1815  return true;
1816  }
1817 
1818  template<>
1819  bool
1820  Parameters::get_unique_pointers(const std::string &name, std::vector<std::unique_ptr<Features::Fault> > &vector)
1821  {
1822  vector.resize(0);
1823  const std::string strict_base = this->get_full_json_path();
1824  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1825  {
1826  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1827 
1828  for (size_t i = 0; i < array->Size(); ++i )
1829  {
1830  vector.push_back(std::make_unique<Features::Fault>(&world));
1831  }
1832  }
1833  else
1834  {
1835  return false;
1836  }
1837 
1838  return true;
1839  }
1840 
1841 
1842 
1843  template<class T>
1844  bool
1845  Parameters::get_shared_pointers(const std::string &name, std::vector<std::shared_ptr<T> > &vector)
1846  {
1847  vector.resize(0);
1848  const std::string strict_base = this->get_full_json_path();
1849  if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr)
1850  {
1851  Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters);
1852 
1853  for (size_t i = 0; i < array->Size(); ++i )
1854  {
1855  const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i));
1856 
1857  const std::string value = Pointer((base + "/model").c_str()).Get(parameters)->GetString();
1858 
1859  vector.push_back(std::move(T::create(value, &world)));
1860  }
1861  }
1862  else
1863  {
1864  return false;
1865  }
1866 
1867  return true;
1868  }
1869 
1870  void
1871  Parameters::enter_subsection(const std::string &name)
1872  {
1873  path.push_back(name);
1874  //TODO: WBAssert(is path valid?)
1875  }
1876 
1877  void
1879  {
1880  path.pop_back();
1881  }
1882 
1883 
1884 
1885  void
1886  Parameters::declare_model_entries(const std::string &model_group_name,
1887  const std::string &parent_name,
1888  const std::map<std::string, void ( *)(Parameters &,const std::string &)> &declare_map,
1889  const std::vector<std::string> &required_entries,
1890  const std::vector<std::tuple<std::string,const WorldBuilder::Types::Interface &, std::string> > &extra_declarations)
1891  {
1892  unsigned int counter = 0;
1893  for (const auto &it : declare_map)
1894  {
1895  typedef std::tuple<std::string,const WorldBuilder::Types::Interface &, std::string> DeclareEntry;
1896  // prevent infinite recursion
1897  if (it.first != parent_name)
1898  {
1899  enter_subsection("oneOf");
1900  {
1901  enter_subsection(std::to_string(counter));
1902  {
1903  enter_subsection("properties");
1904  {
1905  declare_entry("", Types::Object(required_entries), model_group_name + " object");
1906 
1907  declare_entry("model", Types::String("",it.first),
1908  "The name of the " + model_group_name + " model.");
1909 
1910  for (DeclareEntry extra_declaration : extra_declarations)
1911  {
1912  declare_entry(std::get<0>(extra_declaration),std::get<1>(extra_declaration),std::get<2>(extra_declaration));
1913  }
1914 
1915 
1916  it.second(*this, parent_name);
1917  }
1918  leave_subsection();
1919  }
1920  leave_subsection();
1921  }
1922  leave_subsection();
1923 
1924  counter++;
1925 
1926  }
1927  }
1928  }
1929 
1930 
1931 
1932  std::string
1933  Parameters::get_full_json_path(size_t max_size) const
1934  {
1935  std::string collapse;
1936  for (size_t i = 0; i < path.size() && i < max_size; i++)
1937  {
1938  collapse += "/" + path[i];
1939  }
1940  return collapse;
1941  }
1942 
1943  std::string
1945  {
1946  std::string collapse = "/properties";
1947  for (size_t i = 0; i < path.size(); i++)
1948  {
1949  // first get the type
1950  //WBAssert(Pointer((collapse + "/" + path[i] + "/type").c_str()).Get(declarations) != NULL, "Internal error: could not find " << collapse + "/" + path[i] + "/type");
1951 
1952  const std::string base_path = Pointer((collapse + "/" + path[i] + "/type").c_str()).Get(declarations) != nullptr
1953  ?
1954  collapse + "/" + path[i]
1955  :
1956  collapse;
1957 
1958  const std::string type = Pointer((base_path + "/type").c_str()).Get(declarations)->GetString();
1959 
1960  if (type == "array")
1961  {
1962  // the type is an array. Arrays always have an items, but can also
1963  // have a oneOf (todo: or anyOf ...). Find out whether this is the case
1964  //collapse += path[i] + "/items";
1965  if (Pointer((base_path + "/items/oneOf").c_str()).Get(declarations) != nullptr)
1966  {
1967  // it has a structure with oneOf. Find out which of the entries is needed.
1968  // This means we have to take a sneak peak to figure out how to get to the
1969  // next value.
1970  const size_t size = Pointer((base_path + "/items/oneOf").c_str()).Get(declarations)->Size();
1971 #ifdef debug
1972  bool found = false;
1973 #endif
1974  size_t index = 0;
1975  for (; index < size; ++index)
1976  {
1977  const std::string declarations_string = Pointer((base_path + "/items/oneOf/" + std::to_string(index)
1978  + "/properties/model/enum/0").c_str()).Get(declarations)->GetString();
1979 
1980  // we need to get the json path relevant for the current declaration string
1981  // we are interested in, which requires an offset of 2.
1982  WBAssert(Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters) != nullptr, "Could not find model in: " << get_full_json_path(i+2) + "/model");
1983  const std::string parameters_string = Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters)->GetString();
1984 
1985  // currently in our case these are always objects, so go directly to find the option we need.
1986  if (declarations_string == parameters_string)
1987  {
1988  // found it for index i;
1989 #ifdef debug
1990  found = true;
1991 #endif
1992  break;
1993  }
1994  }
1995 #ifdef debug
1996  WBAssert(found == true,
1997  "Internal error: This is an array with several possible values, "
1998  "but could not find the correct value " << collapse + "/" + path[i] + "/items/oneOf");
1999 #endif
2000  collapse += "/" + path[i] + "/items/oneOf/" + std::to_string(index) + "/properties";
2001  // add one to i, to skip the array
2002  ++i;
2003  }
2004  else
2005  {
2006  collapse = base_path + "/items";
2007  }
2008  }
2009  else if (type == "object")
2010  {
2011  // normal objects just have properties, but some have oneOf
2012  if (Pointer((base_path + "/oneOf").c_str()).Get(declarations) != nullptr)
2013  {
2014  // it has a structure with oneOf. Find out which of the entries is needed.
2015  // This means we have to take a sneak peak to figure out how to get to the
2016  // next value.
2017  const size_t size = Pointer((base_path + "/oneOf").c_str()).Get(declarations)->Size();
2018 #ifdef debug
2019  bool found = false;
2020 #endif
2021  size_t index = 0;
2022  for (; index < size; ++index)
2023  {
2024  const std::string declarations_string = Pointer((base_path + "/oneOf/" + std::to_string(index)
2025  + "/properties/model/enum/0").c_str()).Get(declarations)->GetString();
2026 
2027  // we need to get the json path relevant for the current declaration string
2028  // we are interested in, which requires an offset of 2.
2029  const Value *value = Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters);
2030 
2031 
2032  if (value == nullptr)
2033  {
2034  value = Pointer((collapse + "/" + path[i] + "/default value").c_str()).Get(declarations);
2035  WBAssertThrow(value != nullptr,
2036  "internal error: could not retrieve the default value at: "
2037  << collapse + "/" + path[i] + "/default value, for value: ");
2038  }
2039 
2040  const std::string parameters_string = value->GetString();
2041 
2042  // currently in our case these are always objects, so go directly to find the option we need.
2043  if (declarations_string == parameters_string)
2044  {
2045  // found it for index i;
2046 #ifdef debug
2047  found = true;
2048 #endif
2049  break;
2050  }
2051  }
2052 #ifdef debug
2053  WBAssert(found == true,
2054  "Internal error: This is an array with several possible values, "
2055  "but could not find the correct value " << collapse + "/" + path[i] + "/items/oneOf");
2056 #endif
2057  collapse += "/" + path[i] + "/oneOf/" + std::to_string(index) + "/properties";
2058  // add one to i, to skip the array
2059  ++i;
2060 
2061  }
2062  else
2063  {
2064  collapse += "/properties";
2065  }
2066  }
2067  else
2068  {
2069  collapse += "/" + path[i];
2070  }
2071  }
2072  return collapse;
2073  }
2074 
2075 
2076 
2077 
2078 
2083  template std::unique_ptr<CoordinateSystems::Interface> Parameters::get_unique_pointer<CoordinateSystems::Interface>(const std::string &name);
2084 
2085 
2090  template std::unique_ptr<GravityModel::Interface> Parameters::get_unique_pointer<GravityModel::Interface>(const std::string &name);
2091 
2092 
2093 
2098  template bool
2099  Parameters::get_unique_pointers<Features::Interface>(const std::string &name,
2100  std::vector<std::unique_ptr<Features::Interface> > &vector);
2101 
2102 
2107  template bool
2108  Parameters::get_unique_pointers<Features::ContinentalPlateModels::Temperature::Interface>(const std::string &name,
2109  std::vector<std::unique_ptr<Features::ContinentalPlateModels::Temperature::Interface> > &vector);
2110 
2115  template bool
2116  Parameters::get_unique_pointers<Features::ContinentalPlateModels::Composition::Interface>(const std::string &name,
2117  std::vector<std::unique_ptr<Features::ContinentalPlateModels::Composition::Interface> > &vector);
2118 
2123  template bool
2124  Parameters::get_unique_pointers<Features::ContinentalPlateModels::Grains::Interface>(const std::string &name,
2125  std::vector<std::unique_ptr<Features::ContinentalPlateModels::Grains::Interface> > &vector);
2126 
2131  template bool
2132  Parameters::get_unique_pointers<Features::ContinentalPlateModels::Velocity::Interface>(const std::string &name,
2133  std::vector<std::unique_ptr<Features::ContinentalPlateModels::Velocity::Interface> > &vector);
2134 
2135 
2140  template bool
2141  Parameters::get_unique_pointers<Features::PlumeModels::Temperature::Interface>(const std::string &name,
2142  std::vector<std::unique_ptr<Features::PlumeModels::Temperature::Interface> > &vector);
2143 
2148  template bool
2149  Parameters::get_unique_pointers<Features::PlumeModels::Composition::Interface>(const std::string &name,
2150  std::vector<std::unique_ptr<Features::PlumeModels::Composition::Interface> > &vector);
2151 
2156  template bool
2157  Parameters::get_unique_pointers<Features::PlumeModels::Grains::Interface>(const std::string &name,
2158  std::vector<std::unique_ptr<Features::PlumeModels::Grains::Interface> > &vector);
2159 
2164  template bool
2165  Parameters::get_unique_pointers<Features::PlumeModels::Velocity::Interface>(const std::string &name,
2166  std::vector<std::unique_ptr<Features::PlumeModels::Velocity::Interface> > &vector);
2167 
2168 
2169 
2174  template bool
2175  Parameters::get_unique_pointers<Features::OceanicPlateModels::Temperature::Interface>(const std::string &name,
2176  std::vector<std::unique_ptr<Features::OceanicPlateModels::Temperature::Interface> > &vector);
2177 
2182  template bool
2183  Parameters::get_unique_pointers<Features::OceanicPlateModels::Composition::Interface>(const std::string &name,
2184  std::vector<std::unique_ptr<Features::OceanicPlateModels::Composition::Interface> > &vector);
2185 
2190  template bool
2191  Parameters::get_unique_pointers<Features::OceanicPlateModels::Grains::Interface>(const std::string &name,
2192  std::vector<std::unique_ptr<Features::OceanicPlateModels::Grains::Interface> > &vector);
2193 
2198  template bool
2199  Parameters::get_unique_pointers<Features::OceanicPlateModels::Velocity::Interface>(const std::string &name,
2200  std::vector<std::unique_ptr<Features::OceanicPlateModels::Velocity::Interface> > &vector);
2201 
2202 
2203 
2208  template bool
2209  Parameters::get_unique_pointers<Features::MantleLayerModels::Temperature::Interface>(const std::string &name,
2210  std::vector<std::unique_ptr<Features::MantleLayerModels::Temperature::Interface> > &vector);
2211 
2216  template bool
2217  Parameters::get_unique_pointers<Features::MantleLayerModels::Composition::Interface>(const std::string &name,
2218  std::vector<std::unique_ptr<Features::MantleLayerModels::Composition::Interface> > &vector);
2219 
2224  template bool
2225  Parameters::get_unique_pointers<Features::MantleLayerModels::Grains::Interface>(const std::string &name,
2226  std::vector<std::unique_ptr<Features::MantleLayerModels::Grains::Interface> > &vector);
2227 
2232  template bool
2233  Parameters::get_unique_pointers<Features::MantleLayerModels::Velocity::Interface>(const std::string &name,
2234  std::vector<std::unique_ptr<Features::MantleLayerModels::Velocity::Interface> > &vector);
2235 
2236 
2237 
2242  template bool
2243  Parameters::get_unique_pointers<Features::SubductingPlateModels::Temperature::Interface>(const std::string &name,
2244  std::vector<std::unique_ptr<Features::SubductingPlateModels::Temperature::Interface> > &vector);
2245 
2250  template bool
2251  Parameters::get_unique_pointers<Features::SubductingPlateModels::Composition::Interface>(const std::string &name,
2252  std::vector<std::unique_ptr<Features::SubductingPlateModels::Composition::Interface> > &vector);
2253 
2258  template bool
2259  Parameters::get_unique_pointers<Features::SubductingPlateModels::Grains::Interface>(const std::string &name,
2260  std::vector<std::unique_ptr<Features::SubductingPlateModels::Grains::Interface> > &vector);
2261 
2266  template bool
2267  Parameters::get_unique_pointers<Features::SubductingPlateModels::Velocity::Interface>(const std::string &name,
2268  std::vector<std::unique_ptr<Features::SubductingPlateModels::Velocity::Interface> > &vector);
2269 
2270 
2271 
2276  template bool
2277  Parameters::get_unique_pointers<Features::FaultModels::Temperature::Interface>(const std::string &name,
2278  std::vector<std::unique_ptr<Features::FaultModels::Temperature::Interface> > &vector);
2279 
2284  template bool
2285  Parameters::get_unique_pointers<Features::FaultModels::Composition::Interface>(const std::string &name,
2286  std::vector<std::unique_ptr<Features::FaultModels::Composition::Interface> > &vector);
2291  template bool
2292  Parameters::get_unique_pointers<Features::FaultModels::Grains::Interface>(const std::string &name,
2293  std::vector<std::unique_ptr<Features::FaultModels::Grains::Interface> > &vector);
2298  template bool
2299  Parameters::get_unique_pointers<Features::FaultModels::Velocity::Interface>(const std::string &name,
2300  std::vector<std::unique_ptr<Features::FaultModels::Velocity::Interface> > &vector);
2301 
2302 
2303 
2308  template bool
2309  Parameters::get_shared_pointers<Features::SubductingPlateModels::Temperature::Interface>(const std::string &name,
2310  std::vector<std::shared_ptr<Features::SubductingPlateModels::Temperature::Interface> > &vector);
2311 
2316  template bool
2317  Parameters::get_shared_pointers<Features::SubductingPlateModels::Composition::Interface>(const std::string &name,
2318  std::vector<std::shared_ptr<Features::SubductingPlateModels::Composition::Interface> > &vector);
2319 
2324  template bool
2325  Parameters::get_shared_pointers<Features::SubductingPlateModels::Grains::Interface>(const std::string &name,
2326  std::vector<std::shared_ptr<Features::SubductingPlateModels::Grains::Interface> > &vector);
2327 
2332  template bool
2333  Parameters::get_shared_pointers<Features::SubductingPlateModels::Velocity::Interface>(const std::string &name,
2334  std::vector<std::shared_ptr<Features::SubductingPlateModels::Velocity::Interface> > &vector);
2335 
2336 
2341  template bool
2342  Parameters::get_shared_pointers<Features::FaultModels::Temperature::Interface>(const std::string &name,
2343  std::vector<std::shared_ptr<Features::FaultModels::Temperature::Interface> > &vector);
2344 
2349  template bool
2350  Parameters::get_shared_pointers<Features::FaultModels::Composition::Interface>(const std::string &name,
2351  std::vector<std::shared_ptr<Features::FaultModels::Composition::Interface> > &vector);
2356  template bool
2357  Parameters::get_shared_pointers<Features::FaultModels::Grains::Interface>(const std::string &name,
2358  std::vector<std::shared_ptr<Features::FaultModels::Grains::Interface> > &vector);
2363  template bool
2364  Parameters::get_shared_pointers<Features::FaultModels::Velocity::Interface>(const std::string &name,
2365  std::vector<std::shared_ptr<Features::FaultModels::Velocity::Interface> > &vector);
2366 
2367 
2368 
2369 
2370 
2371 } // namespace WorldBuilder
2372 
bool check_entry(const std::string &name) const
Definition: parameters.cc:205
#define WBAssertThrowExc(condition, exc, message)
Definition: assert.h:51
const double DSNAN
Definition: nan.h:41
bool approx(double a, double b, double error_factor=1e4)
Definition: utilities.h:48
void enter_subsection(const std::string &name)
Definition: parameters.cc:1871
rapidjson::Document parameters
Definition: parameters.h:249
std::unique_ptr< T > get_unique_pointer(const std::string &name)
Definition: parameters.cc:1738
bool get_shared_pointers(const std::string &name, std::vector< std::shared_ptr< T > > &)
Definition: parameters.cc:1845
void initialize(std::string &filename, bool has_output_dir=false, const std::string &output_dir="")
Definition: parameters.cc:88
virtual void write_schema(Parameters &prm, const std::string &name, const std::string &documentation) const =0
std::string read_and_distribute_file_content(const std::string &filename)
Definition: utilities.cc:1172
#define WBAssert(condition, message)
Definition: assert.h:27
std::string get_full_json_path(size_t max_size=std::numeric_limits< size_t >::max()) const
Definition: parameters.cc:1933
std::string get_full_json_schema_path() const
Definition: parameters.cc:1944
#define WBAssertThrow(condition, message)
Definition: assert.h:40
bool get_unique_pointers(const std::string &name, std::vector< std::unique_ptr< T > > &vector)
Definition: parameters.cc:1770
std::unique_ptr< WorldBuilder::CoordinateSystems::Interface > coordinate_system
Definition: parameters.h:268
std::pair< std::vector< double >, std::vector< double > > get_value_at_array(const std::string &name)
Definition: parameters.cc:719
std::vector< std::vector< double > > get_vector_or_double(const std::string &name)
Definition: parameters.cc:920
void declare_model_entries(const std::string &model_group_name, const std::string &parent_name, const std::map< std::string, void(*)(Parameters &, const std::string &)> &declare_map, const std::vector< std::string > &required_entries={}, const std::vector< std::tuple< std::string, const WorldBuilder::Types::Interface &, std::string > > &extra_declarations={})
Definition: parameters.cc:1886
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< std::string > path
Definition: parameters.h:246
std::vector< T > get_vector(const std::string &name)
T get(const std::string &name)
rapidjson::Document declarations
Definition: parameters.h:248