Reference documentation for deal.II version Git 3f1f337db3 2021-10-23 13:19:02 -0600
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
parameter_handler.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2021 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/logstream.h>
21 #include <deal.II/base/utilities.h>
22 
24 #define BOOST_BIND_GLOBAL_PLACEHOLDERS
25 #include <boost/algorithm/string.hpp>
26 #include <boost/io/ios_state.hpp>
27 #include <boost/property_tree/json_parser.hpp>
28 #include <boost/property_tree/ptree.hpp>
29 #include <boost/property_tree/xml_parser.hpp>
30 #undef BOOST_BIND_GLOBAL_PLACEHOLDERS
32 
33 #include <algorithm>
34 #include <cctype>
35 #include <cstdlib>
36 #include <cstring>
37 #include <fstream>
38 #include <iomanip>
39 #include <iostream>
40 #include <limits>
41 #include <sstream>
42 
43 
45 
46 
48  : entries(new boost::property_tree::ptree())
49 {}
50 
51 
52 namespace
53 {
54  std::string
55  mangle(const std::string &s)
56  {
57  std::string u;
58 
59  // reserve the minimum number of characters we will need. it may
60  // be more but this is the least we can do
61  u.reserve(s.size());
62 
63  // see if the name is special and if so mangle the whole thing
64  const bool mangle_whole_string = (s == "value");
65 
66  // for all parts of the string, see if it is an allowed character or not
67  for (const char c : s)
68  {
69  static const std::string allowed_characters(
70  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
71 
72  if ((!mangle_whole_string) &&
73  (allowed_characters.find(c) != std::string::npos))
74  u.push_back(c);
75  else
76  {
77  u.push_back('_');
78  static const char hex[16] = {'0',
79  '1',
80  '2',
81  '3',
82  '4',
83  '5',
84  '6',
85  '7',
86  '8',
87  '9',
88  'a',
89  'b',
90  'c',
91  'd',
92  'e',
93  'f'};
94  u.push_back(hex[static_cast<unsigned char>(c) / 16]);
95  u.push_back(hex[static_cast<unsigned char>(c) % 16]);
96  }
97  }
98 
99  return u;
100  }
101 
102 
103 
104  std::string
105  demangle(const std::string &s)
106  {
107  std::string u;
108  u.reserve(s.size());
109 
110  for (unsigned int i = 0; i < s.size(); ++i)
111  if (s[i] != '_')
112  u.push_back(s[i]);
113  else
114  {
115  Assert(i + 2 < s.size(),
116  ExcMessage("Trying to demangle an invalid string."));
117 
118  unsigned char c = 0;
119  switch (s[i + 1])
120  {
121  case '0':
122  c = 0 * 16;
123  break;
124  case '1':
125  c = 1 * 16;
126  break;
127  case '2':
128  c = 2 * 16;
129  break;
130  case '3':
131  c = 3 * 16;
132  break;
133  case '4':
134  c = 4 * 16;
135  break;
136  case '5':
137  c = 5 * 16;
138  break;
139  case '6':
140  c = 6 * 16;
141  break;
142  case '7':
143  c = 7 * 16;
144  break;
145  case '8':
146  c = 8 * 16;
147  break;
148  case '9':
149  c = 9 * 16;
150  break;
151  case 'a':
152  c = 10 * 16;
153  break;
154  case 'b':
155  c = 11 * 16;
156  break;
157  case 'c':
158  c = 12 * 16;
159  break;
160  case 'd':
161  c = 13 * 16;
162  break;
163  case 'e':
164  c = 14 * 16;
165  break;
166  case 'f':
167  c = 15 * 16;
168  break;
169  default:
170  Assert(false, ExcInternalError());
171  }
172  switch (s[i + 2])
173  {
174  case '0':
175  c += 0;
176  break;
177  case '1':
178  c += 1;
179  break;
180  case '2':
181  c += 2;
182  break;
183  case '3':
184  c += 3;
185  break;
186  case '4':
187  c += 4;
188  break;
189  case '5':
190  c += 5;
191  break;
192  case '6':
193  c += 6;
194  break;
195  case '7':
196  c += 7;
197  break;
198  case '8':
199  c += 8;
200  break;
201  case '9':
202  c += 9;
203  break;
204  case 'a':
205  c += 10;
206  break;
207  case 'b':
208  c += 11;
209  break;
210  case 'c':
211  c += 12;
212  break;
213  case 'd':
214  c += 13;
215  break;
216  case 'e':
217  c += 14;
218  break;
219  case 'f':
220  c += 15;
221  break;
222  default:
223  Assert(false, ExcInternalError());
224  }
225 
226  u.push_back(static_cast<char>(c));
227 
228  // skip the two characters
229  i += 2;
230  }
231 
232  return u;
233  }
234 
239  bool
240  is_parameter_node(const boost::property_tree::ptree &p)
241  {
242  return static_cast<bool>(p.get_optional<std::string>("value"));
243  }
244 
245 
250  bool
251  is_alias_node(const boost::property_tree::ptree &p)
252  {
253  return static_cast<bool>(p.get_optional<std::string>("alias"));
254  }
255 
262  std::string
263  collate_path_string(const char separator,
264  const std::vector<std::string> &subsection_path)
265  {
266  if (subsection_path.size() > 0)
267  {
268  std::string p = mangle(subsection_path[0]);
269  for (unsigned int i = 1; i < subsection_path.size(); ++i)
270  {
271  p += separator;
272  p += mangle(subsection_path[i]);
273  }
274  return p;
275  }
276  else
277  return "";
278  }
279 
285  void
286  recursively_sort_parameters(
287  const char separator,
288  const std::vector<std::string> &target_subsection_path,
289  boost::property_tree::ptree & tree)
290  {
291  boost::property_tree::ptree &current_section =
292  tree.get_child(collate_path_string(separator, target_subsection_path));
293 
294  // Custom comparator to ensure that the order of sorting is:
295  // - sorted parameters and aliases;
296  // - sorted subsections.
297  static auto compare =
298  [](const std::pair<std::string, boost::property_tree::ptree> &a,
299  const std::pair<std::string, boost::property_tree::ptree> &b) {
300  bool a_is_param =
301  (is_parameter_node(a.second) || is_alias_node(a.second));
302 
303  bool b_is_param =
304  (is_parameter_node(b.second) || is_alias_node(b.second));
305 
306  // If a is a parameter/alias and b is a subsection,
307  // a should go first, and viceversa.
308  if (a_is_param && !b_is_param)
309  return true;
310 
311  if (!a_is_param && b_is_param)
312  return false;
313 
314  // Otherwise, compare a and b.
315  return a.first < b.first;
316  };
317 
318  current_section.sort(compare);
319 
320  // Now transverse subsections tree recursively.
321  for (auto &p : current_section)
322  {
323  if ((is_parameter_node(p.second) == false) &&
324  (is_alias_node(p.second) == false))
325  {
326  const std::string subsection = demangle(p.first);
327 
328  std::vector<std::string> subsection_path = target_subsection_path;
329  subsection_path.emplace_back(subsection);
330 
331  recursively_sort_parameters(separator, subsection_path, tree);
332  }
333  }
334  }
335 
339  void
340  assert_validity_of_output_style(const ParameterHandler::OutputStyle style)
341  {
342  AssertThrow(
343  (((style & ParameterHandler::XML) != 0) +
344  ((style & ParameterHandler::JSON) != 0) +
345  ((style & ParameterHandler::PRM) != 0) +
346  ((style & ParameterHandler::Description) != 0) +
347  ((style & ParameterHandler::LaTeX) != 0)) == 1,
348  ExcMessage(
349  "You have chosen either no or multiple style formats. You can choose "
350  "between: PRM, Description, LaTeX, XML, JSON."));
351  }
352 
353 } // namespace
354 
355 
356 
357 std::string
359 {
360  return collate_path_string(path_separator, subsection_path);
361 }
362 
363 
364 
365 std::string
366 ParameterHandler::get_current_full_path(const std::string &name) const
367 {
368  std::string path = get_current_path();
369  if (path.empty() == false)
370  path += path_separator;
371 
372  path += mangle(name);
373 
374  return path;
375 }
376 
377 
378 
379 std::string
381  const std::vector<std::string> &sub_path,
382  const std::string & name) const
383 {
384  std::string path = get_current_path();
385  if (path.empty() == false)
386  path += path_separator;
387 
388  if (sub_path.empty() == false)
389  path += collate_path_string(path_separator, sub_path) + path_separator;
390 
391  path += mangle(name);
392 
393  return path;
394 }
395 
396 
397 
398 void
399 ParameterHandler::parse_input(std::istream & input,
400  const std::string &filename,
401  const std::string &last_line,
402  const bool skip_undefined)
403 {
404  AssertThrow(input, ExcIO());
405 
406  // store subsections we are currently in
407  const std::vector<std::string> saved_path = subsection_path;
408 
409  std::string input_line;
410  std::string fully_concatenated_line;
411  bool is_concatenated = false;
412  // Maintain both the current line number and the current logical line
413  // number, where the latter refers to the line number where (possibly) the
414  // current line continuation started.
415  unsigned int current_line_n = 0;
416  unsigned int current_logical_line_n = 0;
417 
418  // define an action that tries to scan a line.
419  //
420  // if that fails, i.e., if scan_line throws
421  // an exception either because a parameter doesn't match its
422  // pattern or because an associated action throws an exception,
423  // then try to rewind the set of subsections to the same
424  // point where we were when the current function was called.
425  // this at least allows to read parameters from a predictable
426  // state, rather than leave the subsection stack in some
427  // unknown state.
428  //
429  // after unwinding the subsection stack, just re-throw the exception
430  auto scan_line_or_cleanup = [this,
431  &skip_undefined,
432  &saved_path](const std::string &line,
433  const std::string &filename,
434  const unsigned int line_number) {
435  try
436  {
437  scan_line(line, filename, line_number, skip_undefined);
438  }
439  catch (...)
440  {
441  while ((saved_path != subsection_path) && (subsection_path.size() > 0))
443 
444  throw;
445  }
446  };
447 
448 
449  while (std::getline(input, input_line))
450  {
451  ++current_line_n;
452  if (!is_concatenated)
453  current_logical_line_n = current_line_n;
454  // Trim the whitespace at the ends of the line here instead of in
455  // scan_line. This makes the continuation line logic a lot simpler.
456  input_line = Utilities::trim(input_line);
457 
458  // If we see the line which is the same as @p last_line ,
459  // terminate the parsing.
460  if (last_line.length() != 0 && input_line == last_line)
461  break;
462 
463  // Check whether or not the current line should be joined with the next
464  // line before calling scan_line.
465  if (input_line.length() != 0 &&
466  input_line.find_last_of('\\') == input_line.length() - 1)
467  {
468  input_line.erase(input_line.length() - 1); // remove the last '\'
469  is_concatenated = true;
470 
471  fully_concatenated_line += input_line;
472  }
473  // If the previous line ended in a '\' but the current did not, then we
474  // should proceed to scan_line.
475  else if (is_concatenated)
476  {
477  fully_concatenated_line += input_line;
478  is_concatenated = false;
479  }
480  // Finally, if neither the previous nor current lines are continuations,
481  // then the current input line is entirely concatenated.
482  else
483  {
484  fully_concatenated_line = input_line;
485  }
486 
487  if (!is_concatenated)
488  {
489  scan_line_or_cleanup(fully_concatenated_line,
490  filename,
491  current_logical_line_n);
492 
493  fully_concatenated_line.clear();
494  }
495  }
496 
497  // While it does not make much sense for anyone to actually do this, allow
498  // the last line to end in a backslash. To do so, we need to parse
499  // whatever was left in the stash of concatenated lines
500  if (is_concatenated)
501  scan_line_or_cleanup(fully_concatenated_line, filename, current_line_n);
502 
503  if (saved_path != subsection_path)
504  {
505  std::stringstream paths_message;
506  if (saved_path.size() > 0)
507  {
508  paths_message << "Path before loading input:\n";
509  for (unsigned int i = 0; i < subsection_path.size(); ++i)
510  {
511  paths_message << std::setw(i * 2 + 4) << " "
512  << "subsection " << saved_path[i] << '\n';
513  }
514  paths_message << "Current path:\n";
515  for (unsigned int i = 0; i < subsection_path.size(); ++i)
516  {
517  paths_message << std::setw(i * 2 + 4) << " "
518  << "subsection " << subsection_path[i]
519  << (i == subsection_path.size() - 1 ? "" : "\n");
520  }
521  }
522  // restore subsection we started with before throwing the exception:
523  subsection_path = saved_path;
524  AssertThrow(false,
525  ExcUnbalancedSubsections(filename, paths_message.str()));
526  }
527 }
528 
529 
530 
531 void
532 ParameterHandler::parse_input(const std::string &filename,
533  const std::string &last_line,
534  const bool skip_undefined,
535  const bool assert_mandatory_entries_are_found)
536 {
537  std::ifstream is(filename);
538  AssertThrow(is, PathSearch::ExcFileNotFound(filename, "ParameterHandler"));
539 
540  std::string file_ending = filename.substr(filename.find_last_of('.') + 1);
541  boost::algorithm::to_lower(file_ending);
542  if (file_ending == "prm")
543  parse_input(is, filename, last_line, skip_undefined);
544  else if (file_ending == "xml")
545  parse_input_from_xml(is, skip_undefined);
546  else if (file_ending == "json")
547  parse_input_from_json(is, skip_undefined);
548  else
549  AssertThrow(false,
550  ExcMessage("Unknown input file name extension. Supported types "
551  "are .prm, .xml, and .json."));
552 
553  if (assert_mandatory_entries_are_found)
555 }
556 
557 
558 
559 void
561  const std::string &last_line,
562  const bool skip_undefined)
563 {
564  std::istringstream input_stream(s);
565  parse_input(input_stream, "input string", last_line, skip_undefined);
566 }
567 
568 
569 
570 namespace
571 {
572  // Recursively go through the 'source' tree and see if we can find
573  // corresponding entries in the 'destination' tree. If not, error out
574  // (i.e. we have just read an XML file that has entries that weren't
575  // declared in the ParameterHandler object); if so, copy the value of these
576  // nodes into the destination object
577  void
578  read_xml_recursively(
579  const boost::property_tree::ptree &source,
580  const std::string & current_path,
581  const char path_separator,
582  const std::vector<std::unique_ptr<const Patterns::PatternBase>> &patterns,
583  const bool skip_undefined,
584  ParameterHandler &prm)
585  {
586  for (const auto &p : source)
587  {
588  // a sub-tree must either be a parameter node or a subsection
589  if (p.second.empty())
590  {
591  // set the found parameter in the destination argument
592  if (skip_undefined)
593  {
594  try
595  {
596  prm.set(demangle(p.first), p.second.data());
597  }
599  {
600  // ignore undeclared entry assert
601  }
602  }
603  else
604  prm.set(demangle(p.first), p.second.data());
605  }
606  else if (p.second.get_optional<std::string>("value"))
607  {
608  // set the found parameter in the destination argument
609  if (skip_undefined)
610  {
611  try
612  {
613  prm.set(demangle(p.first),
614  p.second.get<std::string>("value"));
615  }
617  {
618  // ignore undeclared entry assert
619  }
620  }
621  else
622  prm.set(demangle(p.first), p.second.get<std::string>("value"));
623 
624  // this node might have sub-nodes in addition to "value", such as
625  // "default_value", "documentation", etc. we might at some point
626  // in the future want to make sure that if they exist that they
627  // match the ones in the 'destination' tree
628  }
629  else if (p.second.get_optional<std::string>("alias"))
630  {
631  // it is an alias node. alias nodes are static and there is
632  // nothing to do here (but the same applies as mentioned in the
633  // comment above about the static nodes inside parameter nodes
634  }
635  else
636  {
637  // it must be a subsection
638  prm.enter_subsection(demangle(p.first));
639  read_xml_recursively(p.second,
640  (current_path.empty() ?
641  p.first :
642  current_path + path_separator + p.first),
643  path_separator,
644  patterns,
645  skip_undefined,
646  prm);
647  prm.leave_subsection();
648  }
649  }
650  }
651 
652  // Recursively go through the @p source tree and collapse the nodes of the
653  // format:
654  //
655  //"key":
656  // {
657  // "value" : "val",
658  // "default_value" : "...",
659  // "documentation" : "...",
660  // "pattern" : "...",
661  // "pattern_description": "..."
662  // },
663  //
664  // to
665  //
666  // "key" : "val";
667  //
668  // As an example a JSON file is shown. However, this function also works for
669  // XML since both formats are build around the same BOOST data structures.
670  //
671  // This function is strongly based on read_xml_recursively().
672  void
673  recursively_compress_tree(boost::property_tree::ptree &source)
674  {
675  for (auto &p : source)
676  {
677  if (p.second.get_optional<std::string>("value"))
678  {
679  // save the value in a temporal variable
680  const auto temp = p.second.get<std::string>("value");
681  // clear node (children and value)
682  p.second.clear();
683  // set the correct value
684  p.second.put_value<std::string>(temp);
685  }
686  else if (p.second.get_optional<std::string>("alias"))
687  {}
688  else
689  {
690  // it must be a subsection
691  recursively_compress_tree(p.second);
692  }
693  }
694  }
695 } // namespace
696 
697 
698 
699 void
701  const bool skip_undefined)
702 {
703  AssertThrow(in, ExcIO());
704  // read the XML tree assuming that (as we
705  // do in print_parameters(XML) it has only
706  // a single top-level node called
707  // "ParameterHandler"
708  boost::property_tree::ptree single_node_tree;
709  // This boost function will raise an exception if this is not a valid XML
710  // file.
711  read_xml(in, single_node_tree);
712 
713  // make sure there is a single top-level element
714  // called "ParameterHandler"
715  AssertThrow(single_node_tree.get_optional<std::string>("ParameterHandler"),
716  ExcInvalidXMLParameterFile("There is no top-level XML element "
717  "called \"ParameterHandler\"."));
718 
719  const std::size_t n_top_level_elements =
720  std::distance(single_node_tree.begin(), single_node_tree.end());
721  if (n_top_level_elements != 1)
722  {
723  std::ostringstream top_level_message;
724  top_level_message << "The ParameterHandler input parser found "
725  << n_top_level_elements
726  << " top level elements while reading\n "
727  << " an XML format input file, but there should be"
728  << " exactly one top level element.\n"
729  << " The top level elements are:\n";
730 
731  unsigned int entry_n = 0;
732  for (boost::property_tree::ptree::iterator it = single_node_tree.begin();
733  it != single_node_tree.end();
734  ++it, ++entry_n)
735  {
736  top_level_message
737  << " " << it->first
738  << (entry_n != n_top_level_elements - 1 ? "\n" : "");
739  }
740 
741  // repeat assertion condition to make the printed version easier to read
742  AssertThrow(n_top_level_elements == 1,
743  ExcInvalidXMLParameterFile(top_level_message.str()));
744  }
745 
746  // read the child elements recursively
747  const boost::property_tree::ptree &my_entries =
748  single_node_tree.get_child("ParameterHandler");
749 
750  read_xml_recursively(
751  my_entries, "", path_separator, patterns, skip_undefined, *this);
752 }
753 
754 
755 void
757  const bool skip_undefined)
758 {
759  AssertThrow(in, ExcIO());
760 
761  boost::property_tree::ptree node_tree;
762  // This boost function will raise an exception if this is not a valid JSON
763  // file.
764  try
765  {
766  read_json(in, node_tree);
767  }
768  catch (const std::exception &e)
769  {
770  AssertThrow(
771  false,
772  ExcMessage(
773  "The provided JSON file is not valid. Boost aborted with the "
774  "following assert message: \n\n" +
775  std::string(e.what())));
776  }
777 
778  // The xml function is reused to read in the xml into the parameter file.
779  // This means that only mangled files can be read.
780  read_xml_recursively(
781  node_tree, "", path_separator, patterns, skip_undefined, *this);
782 }
783 
784 
785 
786 void
788 {
789  entries = std::make_unique<boost::property_tree::ptree>();
790  entries_set_status.clear();
791 }
792 
793 
794 
795 void
796 ParameterHandler::declare_entry(const std::string & entry,
797  const std::string & default_value,
798  const Patterns::PatternBase &pattern,
799  const std::string & documentation,
800  const bool has_to_be_set)
801 {
802  entries->put(get_current_full_path(entry) + path_separator + "value",
803  default_value);
804  entries->put(get_current_full_path(entry) + path_separator + "default_value",
805  default_value);
806  entries->put(get_current_full_path(entry) + path_separator + "documentation",
807  documentation);
808 
809  // initialize with false
810  const std::pair<bool, bool> set_status =
811  std::pair<bool, bool>(has_to_be_set, false);
812  entries_set_status.insert(
813  std::pair<std::string, std::pair<bool, bool>>(get_current_full_path(entry),
814  set_status));
815 
816  patterns.reserve(patterns.size() + 1);
817  patterns.emplace_back(pattern.clone());
818  entries->put(get_current_full_path(entry) + path_separator + "pattern",
819  static_cast<unsigned int>(patterns.size() - 1));
820  // also store the description of
821  // the pattern. we do so because we
822  // may wish to export the whole
823  // thing as XML or any other format
824  // so that external tools can work
825  // on the parameter file; in that
826  // case, they will have to be able
827  // to re-create the patterns as far
828  // as possible
830  "pattern_description",
831  patterns.back()->description());
832 
833  // as documented, do the default value checking at the very end
834  AssertThrow(pattern.match(default_value),
835  ExcValueDoesNotMatchPattern(default_value,
836  pattern.description()));
837 }
838 
839 
840 
841 void
843  const std::string & entry,
844  const std::function<void(const std::string &)> &action)
845 {
846  actions.push_back(action);
847 
848  // get the current list of actions, if any
849  boost::optional<std::string> current_actions =
850  entries->get_optional<std::string>(get_current_full_path(entry) +
851  path_separator + "actions");
852 
853  // if there were actions already associated with this parameter, add
854  // the current one to it; otherwise, create a one-item list and use
855  // that
856  if (current_actions)
857  {
858  const std::string all_actions =
859  current_actions.get() + "," +
860  Utilities::int_to_string(actions.size() - 1);
861  entries->put(get_current_full_path(entry) + path_separator + "actions",
862  all_actions);
863  }
864  else
865  entries->put(get_current_full_path(entry) + path_separator + "actions",
866  Utilities::int_to_string(actions.size() - 1));
867 
868 
869  // as documented, run the action on the default value at the very end
870  const std::string default_value = entries->get<std::string>(
871  get_current_full_path(entry) + path_separator + "default_value");
872  action(default_value);
873 }
874 
875 
876 
877 void
878 ParameterHandler::declare_alias(const std::string &existing_entry_name,
879  const std::string &alias_name,
880  const bool alias_is_deprecated)
881 {
882  // see if there is anything to refer to already
883  Assert(entries->get_optional<std::string>(
884  get_current_full_path(existing_entry_name)),
885  ExcMessage("You are trying to declare an alias entry <" + alias_name +
886  "> that references an entry <" + existing_entry_name +
887  ">, but the latter does not exist."));
888  // then also make sure that what is being referred to is in
889  // fact a parameter (not an alias or subsection)
890  Assert(entries->get_optional<std::string>(
891  get_current_full_path(existing_entry_name) + path_separator +
892  "value"),
893  ExcMessage("You are trying to declare an alias entry <" + alias_name +
894  "> that references an entry <" + existing_entry_name +
895  ">, but the latter does not seem to be a "
896  "parameter declaration."));
897 
898 
899  // now also make sure that if the alias has already been
900  // declared, that it is also an alias and refers to the same
901  // entry
902  if (entries->get_optional<std::string>(get_current_full_path(alias_name)))
903  {
904  Assert(entries->get_optional<std::string>(
905  get_current_full_path(alias_name) + path_separator + "alias"),
906  ExcMessage("You are trying to declare an alias entry <" +
907  alias_name +
908  "> but a non-alias entry already exists in this "
909  "subsection (i.e., there is either a preexisting "
910  "further subsection, or a parameter entry, with "
911  "the same name as the alias)."));
912  Assert(entries->get<std::string>(get_current_full_path(alias_name) +
913  path_separator + "alias") ==
914  existing_entry_name,
915  ExcMessage(
916  "You are trying to declare an alias entry <" + alias_name +
917  "> but an alias entry already exists in this "
918  "subsection and this existing alias references a "
919  "different parameter entry. Specifically, "
920  "you are trying to reference the entry <" +
921  existing_entry_name +
922  "> whereas the existing alias references "
923  "the entry <" +
924  entries->get<std::string>(get_current_full_path(alias_name) +
925  path_separator + "alias") +
926  ">."));
927  }
928 
929  entries->put(get_current_full_path(alias_name) + path_separator + "alias",
930  existing_entry_name);
931  entries->put(get_current_full_path(alias_name) + path_separator +
932  "deprecation_status",
933  (alias_is_deprecated ? "true" : "false"));
934 }
935 
936 
937 
938 void
939 ParameterHandler::enter_subsection(const std::string &subsection)
940 {
941  // if necessary create subsection
942  if (!entries->get_child_optional(get_current_full_path(subsection)))
943  entries->add_child(get_current_full_path(subsection),
944  boost::property_tree::ptree());
945 
946  // then enter it
947  subsection_path.push_back(subsection);
948 }
949 
950 
951 
952 void
954 {
955  // assert there is a subsection that
956  // we may leave
958 
959  if (subsection_path.size() > 0)
960  subsection_path.pop_back();
961 }
962 
963 
964 
965 bool
967  const std::vector<std::string> &sub_path) const
968 {
969  // Get full path to sub_path (i.e. prepend subsection_path to sub_path).
970  std::vector<std::string> full_path(subsection_path);
971  full_path.insert(full_path.end(), sub_path.begin(), sub_path.end());
972 
973  boost::optional<const boost::property_tree::ptree &> subsection(
974  entries->get_child_optional(
975  collate_path_string(path_separator, full_path)));
976 
977  // If subsection is boost::null (i.e. it does not exist)
978  // or it exists as a parameter/alias node, return false.
979  // Otherwise (i.e. it exists as a subsection node), return true.
980  return !(!subsection || is_parameter_node(subsection.get()) ||
981  is_alias_node(subsection.get()));
982 }
983 
984 
985 
986 std::string
987 ParameterHandler::get(const std::string &entry_string) const
988 {
989  // assert that the entry is indeed
990  // declared
991  if (boost::optional<std::string> value = entries->get_optional<std::string>(
992  get_current_full_path(entry_string) + path_separator + "value"))
993  return value.get();
994  else
995  {
996  Assert(false, ExcEntryUndeclared(entry_string));
997  return "";
998  }
999 }
1000 
1001 
1002 
1003 std::string
1004 ParameterHandler::get(const std::vector<std::string> &entry_subsection_path,
1005  const std::string & entry_string) const
1006 {
1007  // assert that the entry is indeed
1008  // declared
1009  if (boost::optional<std::string> value = entries->get_optional<std::string>(
1010  get_current_full_path(entry_subsection_path, entry_string) +
1011  path_separator + "value"))
1012  return value.get();
1013  else
1014  {
1015  Assert(false,
1016  ExcEntryUndeclared(demangle(
1017  get_current_full_path(entry_subsection_path, entry_string))));
1018  return "";
1019  }
1020 }
1021 
1022 
1023 
1024 long int
1025 ParameterHandler::get_integer(const std::string &entry_string) const
1026 {
1027  try
1028  {
1029  return Utilities::string_to_int(get(entry_string));
1030  }
1031  catch (...)
1032  {
1033  AssertThrow(false,
1034  ExcMessage("Can't convert the parameter value <" +
1035  get(entry_string) + "> for entry <" +
1036  entry_string + "> to an integer."));
1037  return 0;
1038  }
1039 }
1040 
1041 
1042 
1043 long int
1045  const std::vector<std::string> &entry_subsection_path,
1046  const std::string & entry_string) const
1047 {
1048  try
1049  {
1050  return Utilities::string_to_int(get(entry_subsection_path, entry_string));
1051  }
1052  catch (...)
1053  {
1054  AssertThrow(false,
1055  ExcMessage(
1056  "Can't convert the parameter value <" +
1057  get(entry_subsection_path, entry_string) + "> for entry <" +
1058  demangle(get_current_full_path(entry_subsection_path,
1059  entry_string)) +
1060  "> to an integer."));
1061  return 0;
1062  }
1063 }
1064 
1065 
1066 
1067 double
1068 ParameterHandler::get_double(const std::string &entry_string) const
1069 {
1070  try
1071  {
1072  return Utilities::string_to_double(get(entry_string));
1073  }
1074  catch (...)
1075  {
1076  AssertThrow(false,
1077  ExcMessage("Can't convert the parameter value <" +
1078  get(entry_string) + "> for entry <" +
1079  entry_string +
1080  "> to a double precision variable."));
1081  return 0;
1082  }
1083 }
1084 
1085 
1086 
1087 double
1089  const std::vector<std::string> &entry_subsection_path,
1090  const std::string & entry_string) const
1091 {
1092  try
1093  {
1095  get(entry_subsection_path, entry_string));
1096  }
1097  catch (...)
1098  {
1099  AssertThrow(false,
1100  ExcMessage(
1101  "Can't convert the parameter value <" +
1102  get(entry_subsection_path, entry_string) + "> for entry <" +
1103  demangle(get_current_full_path(entry_subsection_path,
1104  entry_string)) +
1105  "> to a double precision variable."));
1106  return 0;
1107  }
1108 }
1109 
1110 
1111 
1112 bool
1113 ParameterHandler::get_bool(const std::string &entry_string) const
1114 {
1115  const std::string s = get(entry_string);
1116 
1117  AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1118  ExcMessage("Can't convert the parameter value <" +
1119  get(entry_string) + "> for entry <" + entry_string +
1120  "> to a boolean."));
1121  if (s == "true" || s == "yes")
1122  return true;
1123  else
1124  return false;
1125 }
1126 
1127 
1128 
1129 bool
1131  const std::vector<std::string> &entry_subsection_path,
1132  const std::string & entry_string) const
1133 {
1134  const std::string s = get(entry_subsection_path, entry_string);
1135 
1136  AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1137  ExcMessage("Can't convert the parameter value <" +
1138  get(entry_subsection_path, entry_string) +
1139  "> for entry <" +
1140  demangle(get_current_full_path(entry_subsection_path,
1141  entry_string)) +
1142  "> to a boolean."));
1143  if (s == "true" || s == "yes")
1144  return true;
1145  else
1146  return false;
1147 }
1148 
1149 
1150 
1151 void
1152 ParameterHandler::set(const std::string &entry_string,
1153  const std::string &new_value)
1154 {
1155  // resolve aliases before looking up the correct entry
1156  std::string path = get_current_full_path(entry_string);
1157  if (entries->get_optional<std::string>(path + path_separator + "alias"))
1158  path = get_current_full_path(
1159  entries->get<std::string>(path + path_separator + "alias"));
1160 
1161  // get the node for the entry. if it doesn't exist, then we end up
1162  // in the else-branch below, which asserts that the entry is indeed
1163  // declared
1164  if (entries->get_optional<std::string>(path + path_separator + "value"))
1165  {
1166  // verify that the new value satisfies the provided pattern
1167  const unsigned int pattern_index =
1168  entries->get<unsigned int>(path + path_separator + "pattern");
1169  AssertThrow(patterns[pattern_index]->match(new_value),
1170  ExcValueDoesNotMatchPattern(new_value,
1171  entries->get<std::string>(
1172  path + path_separator +
1173  "pattern_description")));
1174 
1175  // then also execute the actions associated with this
1176  // parameter (if any have been provided)
1177  const boost::optional<std::string> action_indices_as_string =
1178  entries->get_optional<std::string>(path + path_separator + "actions");
1179  if (action_indices_as_string)
1180  {
1181  std::vector<int> action_indices = Utilities::string_to_int(
1182  Utilities::split_string_list(action_indices_as_string.get()));
1183  for (const unsigned int index : action_indices)
1184  if (actions.size() >= index + 1)
1185  actions[index](new_value);
1186  }
1187 
1188  // finally write the new value into the database
1189  entries->put(path + path_separator + "value", new_value);
1190 
1191  auto map_iter = entries_set_status.find(path);
1192  if (map_iter != entries_set_status.end())
1193  map_iter->second = std::pair<bool, bool>(map_iter->second.first, true);
1194  else
1195  AssertThrow(false,
1196  ExcMessage("Could not find parameter " + path +
1197  " in map entries_set_status."));
1198  }
1199  else
1200  AssertThrow(false, ExcEntryUndeclared(entry_string));
1201 }
1202 
1203 
1204 void
1205 ParameterHandler::set(const std::string &entry_string, const char *new_value)
1206 {
1207  // simply forward
1208  set(entry_string, std::string(new_value));
1209 }
1210 
1211 
1212 void
1213 ParameterHandler::set(const std::string &entry_string, const double new_value)
1214 {
1215  std::ostringstream s;
1216  s << std::setprecision(16);
1217  s << new_value;
1218 
1219  // hand this off to the function that
1220  // actually sets the value as a string
1221  set(entry_string, s.str());
1222 }
1223 
1224 
1225 
1226 void
1227 ParameterHandler::set(const std::string &entry_string, const long int new_value)
1228 {
1229  std::ostringstream s;
1230  s << new_value;
1231 
1232  // hand this off to the function that
1233  // actually sets the value as a string
1234  set(entry_string, s.str());
1235 }
1236 
1237 
1238 
1239 void
1240 ParameterHandler::set(const std::string &entry_string, const bool new_value)
1241 {
1242  // hand this off to the function that
1243  // actually sets the value as a string
1244  set(entry_string, (new_value ? "true" : "false"));
1245 }
1246 
1247 
1248 
1249 std::ostream &
1251  const OutputStyle style) const
1252 {
1253  AssertThrow(out, ExcIO());
1254 
1255  assert_validity_of_output_style(style);
1256 
1257  // Create entries copy and sort it, if needed.
1258  // In this way we ensure that the class state is never
1259  // modified by this function.
1260  boost::property_tree::ptree current_entries = *entries.get();
1261 
1262  // Sort parameters alphabetically, if needed.
1263  if (!(style & KeepDeclarationOrder))
1264  {
1265  // Dive recursively into the subsections,
1266  // starting from the top level.
1267  recursively_sort_parameters(path_separator,
1268  std::vector<std::string>(),
1269  current_entries);
1270  }
1271 
1272  // we'll have to print some text that is padded with spaces;
1273  // set the appropriate fill character, but also make sure that
1274  // we will restore the previous setting (and all other stream
1275  // flags) when we exit this function
1276  boost::io::ios_flags_saver restore_flags(out);
1277  boost::io::basic_ios_fill_saver<char> restore_fill_state(out);
1278  out.fill(' ');
1279 
1280  // we treat XML and JSON is one step via BOOST, whereas all of the others are
1281  // done recursively in our own code. take care of the two special formats
1282  // first
1283 
1284  // explicitly compress the tree if requested
1285  if ((style & Short) && (style & (XML | JSON)))
1286  {
1287  // modify the copy of the tree
1288  recursively_compress_tree(current_entries);
1289  }
1290 
1291  if (style & XML)
1292  {
1293  // call the writer function and exit as there is nothing
1294  // further to do down in this function
1295  //
1296  // XML has a requirement that there can only be one
1297  // single top-level entry, but we may have multiple
1298  // entries and sections. we work around this by
1299  // creating a tree just for this purpose with the
1300  // single top-level node "ParameterHandler" and
1301  // assign the existing tree under it
1302  boost::property_tree::ptree single_node_tree;
1303  single_node_tree.add_child("ParameterHandler", current_entries);
1304 
1305  write_xml(out, single_node_tree);
1306  return out;
1307  }
1308 
1309  if (style & JSON)
1310  {
1311  write_json(out, current_entries);
1312  return out;
1313  }
1314 
1315  // for all of the other formats, print a preamble:
1316  if ((style & Short) && (style & Text))
1317  {
1318  // nothing to do
1319  }
1320  else if (style & Text)
1321  {
1322  out << "# Listing of Parameters" << std::endl
1323  << "# ---------------------" << std::endl;
1324  }
1325  else if (style & LaTeX)
1326  {
1327  out << "\\subsection{Global parameters}" << std::endl;
1328  out << "\\label{parameters:global}" << std::endl;
1329  out << std::endl << std::endl;
1330  }
1331  else if (style & Description)
1332  {
1333  out << "Listing of Parameters:" << std::endl << std::endl;
1334  }
1335  else
1336  {
1337  Assert(false, ExcNotImplemented());
1338  }
1339 
1340  // dive recursively into the subsections
1342  current_entries,
1343  std::vector<std::string>(), // start at the top level
1344  style,
1345  0,
1346  out);
1347 
1348  return out;
1349 }
1350 
1351 
1352 
1353 void
1355  const std::string & filename,
1356  const ParameterHandler::OutputStyle style) const
1357 {
1358  std::string extension = filename.substr(filename.find_last_of('.') + 1);
1359  boost::algorithm::to_lower(extension);
1360 
1361  ParameterHandler::OutputStyle output_style = style;
1362  if (extension == "prm")
1363  output_style = style | PRM;
1364  else if (extension == "xml")
1365  output_style = style | XML;
1366  else if (extension == "json")
1367  output_style = style | JSON;
1368  else if (extension == "tex")
1369  output_style = style | LaTeX;
1370 
1371  std::ofstream out(filename);
1372  AssertThrow(out, ExcIO());
1373  print_parameters(out, output_style);
1374 }
1375 
1376 
1377 
1378 void
1380  const boost::property_tree::ptree &tree,
1381  const std::vector<std::string> & target_subsection_path,
1382  const OutputStyle style,
1383  const unsigned int indent_level,
1384  std::ostream & out) const
1385 {
1386  AssertThrow(out, ExcIO());
1387 
1388  // this function should not be necessary for XML or JSON output...
1389  Assert(!(style & (XML | JSON)), ExcInternalError());
1390 
1391  const boost::property_tree::ptree &current_section =
1392  tree.get_child(collate_path_string(path_separator, target_subsection_path));
1393 
1394  unsigned int overall_indent_level = indent_level;
1395 
1396  const bool is_short = style & Short;
1397 
1398  if (style & Text)
1399  {
1400  // first find out the longest entry name to be able to align the
1401  // equal signs to do this loop over all nodes of the current
1402  // tree, select the parameter nodes (and discard sub-tree nodes)
1403  // and take the maximum of their lengths
1404  //
1405  // likewise find the longest actual value string to make sure we
1406  // can align the default and documentation strings
1407  std::size_t longest_name = 0;
1408  std::size_t longest_value = 0;
1409  for (const auto &p : current_section)
1410  if (is_parameter_node(p.second) == true)
1411  {
1412  longest_name = std::max(longest_name, demangle(p.first).length());
1413  longest_value =
1414  std::max(longest_value,
1415  p.second.get<std::string>("value").length());
1416  }
1417 
1418  // print entries one by one
1419  bool first_entry = true;
1420  for (const auto &p : current_section)
1421  if (is_parameter_node(p.second) == true)
1422  {
1423  const std::string value = p.second.get<std::string>("value");
1424 
1425  // if there is documentation, then add an empty line
1426  // (unless this is the first entry in a subsection), print
1427  // the documentation, and then the actual entry; break the
1428  // documentation into readable chunks such that the whole
1429  // thing is at most 78 characters wide
1430  if (!is_short &&
1431  !p.second.get<std::string>("documentation").empty())
1432  {
1433  if (first_entry == false)
1434  out << '\n';
1435  else
1436  first_entry = false;
1437 
1438  const std::vector<std::string> doc_lines =
1440  p.second.get<std::string>("documentation"),
1441  78 - overall_indent_level * 2 - 2);
1442 
1443  for (const auto &doc_line : doc_lines)
1444  out << std::setw(overall_indent_level * 2) << ""
1445  << "# " << doc_line << '\n';
1446  }
1447 
1448  // print name and value of this entry
1449  out << std::setw(overall_indent_level * 2) << ""
1450  << "set " << demangle(p.first)
1451  << std::setw(longest_name - demangle(p.first).length() + 1)
1452  << " "
1453  << "= " << value;
1454 
1455  // finally print the default value, but only if it differs
1456  // from the actual value
1457  if (!is_short &&
1458  value != p.second.get<std::string>("default_value"))
1459  {
1460  out << std::setw(longest_value - value.length() + 1) << ' '
1461  << "# ";
1462  out << "default: "
1463  << p.second.get<std::string>("default_value");
1464  }
1465 
1466  out << '\n';
1467  }
1468  }
1469  else if (style & LaTeX)
1470  {
1471  auto escape = [](const std::string &input) {
1473  };
1474 
1475  // if there are any parameters in this section then print them
1476  // as an itemized list
1477  const bool parameters_exist_here =
1478  std::any_of(current_section.begin(),
1479  current_section.end(),
1480  [](const boost::property_tree::ptree::value_type &p) {
1481  return is_parameter_node(p.second) ||
1482  is_alias_node(p.second);
1483  });
1484  if (parameters_exist_here)
1485  {
1486  out << "\\begin{itemize}" << '\n';
1487 
1488  // print entries one by one
1489  for (const auto &p : current_section)
1490  if (is_parameter_node(p.second) == true)
1491  {
1492  const std::string value = p.second.get<std::string>("value");
1493 
1494  // print name
1495  out << "\\item {\\it Parameter name:} {\\tt "
1496  << escape(demangle(p.first)) << "}\n"
1497  << "\\phantomsection";
1498  {
1499  // create label: labels are not to be escaped but
1500  // mangled
1501  std::string label = "parameters:";
1502  for (const auto &path : target_subsection_path)
1503  {
1504  label.append(mangle(path));
1505  label.append("/");
1506  }
1507  label.append(p.first);
1508  // Backwards-compatibility. Output the label with and
1509  // without escaping whitespace:
1510  if (label.find("_20") != std::string::npos)
1511  out << "\\label{"
1512  << Utilities::replace_in_string(label, "_20", " ")
1513  << "}\n";
1514  out << "\\label{" << label << "}\n";
1515  }
1516  out << "\n\n";
1517 
1518  out << "\\index[prmindex]{" << escape(demangle(p.first))
1519  << "}\n";
1520  out << "\\index[prmindexfull]{";
1521  for (const auto &path : target_subsection_path)
1522  out << escape(path) << "!";
1523  out << escape(demangle(p.first)) << "}\n";
1524 
1525  // finally print value and default
1526  out << "{\\it Value:} " << escape(value) << "\n\n"
1527  << '\n'
1528  << "{\\it Default:} "
1529  << escape(p.second.get<std::string>("default_value"))
1530  << "\n\n"
1531  << '\n';
1532 
1533  // if there is a documenting string, print it as well but
1534  // don't escape to allow formatting/formulas
1535  if (!is_short &&
1536  !p.second.get<std::string>("documentation").empty())
1537  out << "{\\it Description:} "
1538  << p.second.get<std::string>("documentation") << "\n\n"
1539  << '\n';
1540  if (!is_short)
1541  {
1542  // also output possible values, do not escape because the
1543  // description internally will use LaTeX formatting
1544  const unsigned int pattern_index =
1545  p.second.get<unsigned int>("pattern");
1546  const std::string desc_str =
1547  patterns[pattern_index]->description(
1549  out << "{\\it Possible values:} " << desc_str << '\n';
1550  }
1551  }
1552  else if (is_alias_node(p.second) == true)
1553  {
1554  const std::string alias = p.second.get<std::string>("alias");
1555 
1556  // print name
1557  out << "\\item {\\it Parameter name:} {\\tt "
1558  << escape(demangle(p.first)) << "}\n"
1559  << "\\phantomsection";
1560  {
1561  // create label: labels are not to be escaped but
1562  // mangled
1563  std::string label = "parameters:";
1564  for (const auto &path : target_subsection_path)
1565  {
1566  label.append(mangle(path));
1567  label.append("/");
1568  }
1569  label.append(p.first);
1570  // Backwards-compatibility. Output the label with and
1571  // without escaping whitespace:
1572  if (label.find("_20") != std::string::npos)
1573  out << "\\label{"
1574  << Utilities::replace_in_string(label, "_20", " ")
1575  << "}\n";
1576  out << "\\label{" << label << "}\n";
1577  }
1578  out << "\n\n";
1579 
1580  out << "\\index[prmindex]{" << escape(demangle(p.first))
1581  << "}\n";
1582  out << "\\index[prmindexfull]{";
1583  for (const auto &path : target_subsection_path)
1584  out << escape(path) << "!";
1585  out << escape(demangle(p.first)) << "}\n";
1586 
1587  // finally print alias and indicate if it is deprecated
1588  out
1589  << "This parameter is an alias for the parameter ``\\texttt{"
1590  << escape(alias) << "}''."
1591  << (p.second.get<std::string>("deprecation_status") ==
1592  "true" ?
1593  " Its use is deprecated." :
1594  "")
1595  << "\n\n"
1596  << '\n';
1597  }
1598  out << "\\end{itemize}" << '\n';
1599  }
1600  }
1601  else if (style & Description)
1602  {
1603  // first find out the longest entry name to be able to align the
1604  // equal signs
1605  std::size_t longest_name = 0;
1606  for (const auto &p : current_section)
1607  if (is_parameter_node(p.second) == true)
1608  longest_name = std::max(longest_name, demangle(p.first).length());
1609 
1610  // print entries one by one
1611  for (const auto &p : current_section)
1612  if (is_parameter_node(p.second) == true)
1613  {
1614  // print name and value
1615  out << std::setw(overall_indent_level * 2) << ""
1616  << "set " << demangle(p.first)
1617  << std::setw(longest_name - demangle(p.first).length() + 1)
1618  << " "
1619  << " = ";
1620 
1621  // print possible values:
1622  const unsigned int pattern_index =
1623  p.second.get<unsigned int>("pattern");
1624  const std::string full_desc_str =
1625  patterns[pattern_index]->description(Patterns::PatternBase::Text);
1626  const std::vector<std::string> description_str =
1628  full_desc_str, 78 - overall_indent_level * 2 - 2, '|');
1629  if (description_str.size() > 1)
1630  {
1631  out << '\n';
1632  for (const auto &description : description_str)
1633  out << std::setw(overall_indent_level * 2 + 6) << ""
1634  << description << '\n';
1635  }
1636  else if (description_str.empty() == false)
1637  out << " " << description_str[0] << '\n';
1638  else
1639  out << '\n';
1640 
1641  // if there is a documenting string, print it as well
1642  if (!is_short &&
1643  p.second.get<std::string>("documentation").length() != 0)
1644  out << std::setw(overall_indent_level * 2 + longest_name + 10)
1645  << ""
1646  << "(" << p.second.get<std::string>("documentation") << ")"
1647  << '\n';
1648  }
1649  }
1650  else
1651  {
1652  Assert(false, ExcNotImplemented());
1653  }
1654 
1655 
1656  // if there was text before and there are sections to come, put two
1657  // newlines between the last entry and the first subsection
1658  {
1659  unsigned int n_parameters = 0;
1660  unsigned int n_sections = 0;
1661  for (const auto &p : current_section)
1662  if (is_parameter_node(p.second) == true)
1663  ++n_parameters;
1664  else if (is_alias_node(p.second) == false)
1665  ++n_sections;
1666 
1667  if (!(style & Description) && (!((style & Text) && is_short)) &&
1668  (n_parameters != 0) && (n_sections != 0))
1669  out << "\n\n";
1670  }
1671 
1672  // now transverse subsections tree
1673  for (const auto &p : current_section)
1674  if ((is_parameter_node(p.second) == false) &&
1675  (is_alias_node(p.second) == false))
1676  {
1677  // first print the subsection header
1678  if ((style & Text) || (style & Description))
1679  {
1680  out << std::setw(overall_indent_level * 2) << ""
1681  << "subsection " << demangle(p.first) << '\n';
1682  }
1683  else if (style & LaTeX)
1684  {
1685  auto escape = [](const std::string &input) {
1686  return Patterns::internal::escape(input,
1688  };
1689 
1690  out << '\n' << "\\subsection{Parameters in section \\tt ";
1691 
1692  // find the path to the current section so that we can
1693  // print it in the \subsection{...} heading
1694  for (const auto &path : target_subsection_path)
1695  out << escape(path) << "/";
1696  out << escape(demangle(p.first));
1697 
1698  out << "}" << '\n';
1699  out << "\\label{parameters:";
1700  for (const auto &path : target_subsection_path)
1701  out << mangle(path) << "/";
1702  out << p.first << "}";
1703  out << '\n';
1704 
1705  out << '\n';
1706  }
1707  else
1708  {
1709  Assert(false, ExcNotImplemented());
1710  }
1711 
1712  // then the contents of the subsection
1713  const std::string subsection = demangle(p.first);
1714  std::vector<std::string> directory_path = target_subsection_path;
1715  directory_path.emplace_back(subsection);
1716 
1718  tree, directory_path, style, overall_indent_level + 1, out);
1719 
1720  if (is_short && (style & Text))
1721  {
1722  // write end of subsection.
1723  out << std::setw(overall_indent_level * 2) << ""
1724  << "end" << '\n';
1725  }
1726  else if (style & Text)
1727  {
1728  // write end of subsection. one blank line after each
1729  // subsection
1730  out << std::setw(overall_indent_level * 2) << ""
1731  << "end" << '\n'
1732  << '\n';
1733 
1734  // if this is a toplevel subsection, then have two
1735  // newlines
1736  if (overall_indent_level == 0)
1737  out << '\n';
1738  }
1739  else if (style & Description)
1740  {
1741  // nothing to do
1742  }
1743  else if (style & LaTeX)
1744  {
1745  // nothing to do
1746  }
1747  else
1748  {
1749  Assert(false, ExcNotImplemented());
1750  }
1751  }
1752 }
1753 
1754 
1755 
1756 void
1758 {
1759  out.push("parameters");
1760  // dive recursively into the subsections
1761  log_parameters_section(out, style);
1762 
1763  out.pop();
1764 }
1765 
1766 
1767 void
1769  const OutputStyle style)
1770 {
1771  // Create entries copy and sort it, if needed.
1772  // In this way we ensure that the class state is never
1773  // modified by this function.
1774  boost::property_tree::ptree sorted_entries;
1775  boost::property_tree::ptree *current_entries = entries.get();
1776 
1777  // Sort parameters alphabetically, if needed.
1778  if (!(style & KeepDeclarationOrder))
1779  {
1780  sorted_entries = *entries;
1781  current_entries = &sorted_entries;
1782 
1783  // Dive recursively into the subsections,
1784  // starting from the current level.
1785  recursively_sort_parameters(path_separator,
1787  sorted_entries);
1788  }
1789 
1790  const boost::property_tree::ptree &current_section =
1791  current_entries->get_child(get_current_path());
1792 
1793  // print entries one by one
1794  for (const auto &p : current_section)
1795  if (is_parameter_node(p.second) == true)
1796  out << demangle(p.first) << ": " << p.second.get<std::string>("value")
1797  << std::endl;
1798 
1799  // now transverse subsections tree
1800  for (const auto &p : current_section)
1801  if (is_parameter_node(p.second) == false)
1802  {
1803  out.push(demangle(p.first));
1804  enter_subsection(demangle(p.first));
1805  log_parameters_section(out, style);
1806  leave_subsection();
1807  out.pop();
1808  }
1809 }
1810 
1811 
1812 
1813 void
1815  const std::string &input_filename,
1816  const unsigned int current_line_n,
1817  const bool skip_undefined)
1818 {
1819  // save a copy for some error messages
1820  const std::string original_line = line;
1821 
1822  // if there is a comment, delete it
1823  if (line.find('#') != std::string::npos)
1824  line.erase(line.find('#'), std::string::npos);
1825 
1826  // replace \t by space:
1827  while (line.find('\t') != std::string::npos)
1828  line.replace(line.find('\t'), 1, " ");
1829 
1830  // trim start and end:
1831  line = Utilities::trim(line);
1832 
1833  // if line is now empty: leave
1834  if (line.length() == 0)
1835  {
1836  return;
1837  }
1838  // enter subsection
1839  else if (Utilities::match_at_string_start(line, "SUBSECTION ") ||
1840  Utilities::match_at_string_start(line, "subsection "))
1841  {
1842  // delete this prefix
1843  line.erase(0, std::string("subsection").length() + 1);
1844 
1845  const std::string subsection = Utilities::trim(line);
1846 
1847  // check whether subsection exists
1848  AssertThrow(skip_undefined || entries->get_child_optional(
1849  get_current_full_path(subsection)),
1850  ExcNoSubsection(current_line_n,
1851  input_filename,
1852  demangle(get_current_full_path(subsection))));
1853 
1854  // subsection exists
1855  subsection_path.push_back(subsection);
1856  }
1857  // exit subsection
1858  else if (Utilities::match_at_string_start(line, "END") ||
1859  Utilities::match_at_string_start(line, "end"))
1860  {
1861  line.erase(0, 3);
1862  while ((line.size() > 0) && (std::isspace(line[0])))
1863  line.erase(0, 1);
1864 
1865  AssertThrow(
1866  line.size() == 0,
1867  ExcCannotParseLine(current_line_n,
1868  input_filename,
1869  "Invalid content after 'end' or 'END' statement."));
1870  AssertThrow(subsection_path.size() != 0,
1871  ExcCannotParseLine(current_line_n,
1872  input_filename,
1873  "There is no subsection to leave here."));
1874  leave_subsection();
1875  }
1876  // regular entry
1877  else if (Utilities::match_at_string_start(line, "SET ") ||
1878  Utilities::match_at_string_start(line, "set "))
1879  {
1880  // erase "set" statement
1881  line.erase(0, 4);
1882 
1883  std::string::size_type pos = line.find('=');
1884  AssertThrow(
1885  pos != std::string::npos,
1886  ExcCannotParseLine(current_line_n,
1887  input_filename,
1888  "Invalid format of 'set' or 'SET' statement."));
1889 
1890  // extract entry name and value and trim
1891  std::string entry_name = Utilities::trim(std::string(line, 0, pos));
1892  std::string entry_value =
1893  Utilities::trim(std::string(line, pos + 1, std::string::npos));
1894 
1895  // resolve aliases before we look up the entry. if necessary, print
1896  // a warning that the alias is deprecated
1897  std::string path = get_current_full_path(entry_name);
1898  if (entries->get_optional<std::string>(path + path_separator + "alias"))
1899  {
1900  if (entries->get<std::string>(path + path_separator +
1901  "deprecation_status") == "true")
1902  {
1903  std::cerr << "Warning in line <" << current_line_n
1904  << "> of file <" << input_filename
1905  << ">: You are using the deprecated spelling <"
1906  << entry_name << "> of the parameter <"
1907  << entries->get<std::string>(path + path_separator +
1908  "alias")
1909  << ">." << std::endl;
1910  }
1911  path = get_current_full_path(
1912  entries->get<std::string>(path + path_separator + "alias"));
1913  }
1914 
1915  // get the node for the entry. if it doesn't exist, then we end up
1916  // in the else-branch below, which asserts that the entry is indeed
1917  // declared
1918  if (entries->get_optional<std::string>(path + path_separator + "value"))
1919  {
1920  // if entry was declared: does it match the regex? if not, don't enter
1921  // it into the database exception: if it contains characters which
1922  // specify it as a multiple loop entry, then ignore content
1923  if (entry_value.find('{') == std::string::npos)
1924  {
1925  // verify that the new value satisfies the provided pattern
1926  const unsigned int pattern_index =
1927  entries->get<unsigned int>(path + path_separator + "pattern");
1928  AssertThrow(patterns[pattern_index]->match(entry_value),
1930  current_line_n,
1931  input_filename,
1932  entry_value,
1933  entry_name,
1934  patterns[pattern_index]->description()));
1935 
1936  // then also execute the actions associated with this
1937  // parameter (if any have been provided)
1938  const boost::optional<std::string> action_indices_as_string =
1939  entries->get_optional<std::string>(path + path_separator +
1940  "actions");
1941  if (action_indices_as_string)
1942  {
1943  std::vector<int> action_indices =
1945  action_indices_as_string.get()));
1946  for (const unsigned int index : action_indices)
1947  if (actions.size() >= index + 1)
1948  actions[index](entry_value);
1949  }
1950  }
1951 
1952  // finally write the new value into the database
1953  entries->put(path + path_separator + "value", entry_value);
1954 
1955  auto map_iter = entries_set_status.find(path);
1956  if (map_iter != entries_set_status.end())
1957  map_iter->second =
1958  std::pair<bool, bool>(map_iter->second.first, true);
1959  else
1960  AssertThrow(false,
1961  ExcMessage("Could not find parameter " + path +
1962  " in map entries_set_status."));
1963  }
1964  else
1965  {
1966  AssertThrow(
1967  skip_undefined,
1968  ExcCannotParseLine(current_line_n,
1969  input_filename,
1970  ("No entry with name <" + entry_name +
1971  "> was declared in the current subsection.")));
1972  }
1973  }
1974  // an include statement?
1975  else if (Utilities::match_at_string_start(line, "include ") ||
1976  Utilities::match_at_string_start(line, "INCLUDE "))
1977  {
1978  // erase "include " statement and eliminate spaces
1979  line.erase(0, 7);
1980  while ((line.size() > 0) && (line[0] == ' '))
1981  line.erase(0, 1);
1982 
1983  // the remainder must then be a filename
1984  AssertThrow(line.size() != 0,
1985  ExcCannotParseLine(current_line_n,
1986  input_filename,
1987  "The current line is an 'include' or "
1988  "'INCLUDE' statement, but it does not "
1989  "name a file for inclusion."));
1990 
1991  std::ifstream input(line.c_str());
1992  AssertThrow(input,
1993  ExcCannotOpenIncludeStatementFile(current_line_n,
1994  input_filename,
1995  line));
1996  parse_input(input, line, "", skip_undefined);
1997  }
1998  else
1999  {
2000  AssertThrow(
2001  false,
2002  ExcCannotParseLine(current_line_n,
2003  input_filename,
2004  "The line\n\n"
2005  " <" +
2006  original_line +
2007  ">\n\n"
2008  "could not be parsed: please check to "
2009  "make sure that the file is not missing a "
2010  "'set', 'include', 'subsection', or 'end' "
2011  "statement."));
2012  }
2013 }
2014 
2015 
2016 
2017 std::size_t
2019 {
2020  // TODO: add to this an estimate of the memory in the property_tree
2022 }
2023 
2024 
2025 
2026 bool
2028 {
2029  if (patterns.size() != prm2.patterns.size())
2030  return false;
2031 
2032  for (unsigned int j = 0; j < patterns.size(); ++j)
2033  if (patterns[j]->description() != prm2.patterns[j]->description())
2034  return false;
2035 
2036  // instead of walking through all
2037  // the nodes of the two trees
2038  // entries and prm2.entries and
2039  // comparing them for equality,
2040  // simply dump the content of the
2041  // entire structure into a string
2042  // and compare those for equality
2043  std::ostringstream o1, o2;
2044  write_json(o1, *entries);
2045  write_json(o2, *prm2.entries);
2046  return (o1.str() == o2.str());
2047 }
2048 
2049 
2050 
2051 std::set<std::string>
2053 {
2054  std::set<std::string> entries_wrongly_not_set;
2055 
2056  for (const auto &it : entries_set_status)
2057  if (it.second.first == true && it.second.second == false)
2058  entries_wrongly_not_set.insert(it.first);
2059 
2060  return entries_wrongly_not_set;
2061 }
2062 
2063 
2064 
2065 void
2067 {
2068  const std::set<std::string> entries_wrongly_not_set =
2070 
2071  if (entries_wrongly_not_set.size() > 0)
2072  {
2073  std::string list_of_missing_parameters = "\n\n";
2074  for (const auto &it : entries_wrongly_not_set)
2075  list_of_missing_parameters += " " + it + "\n";
2076  list_of_missing_parameters += "\n";
2077 
2078  AssertThrow(
2079  entries_wrongly_not_set.size() == 0,
2080  ExcMessage(
2081  "Not all entries of the parameter handler that were declared with "
2082  "`has_to_be_set = true` have been set. The following parameters " +
2083  list_of_missing_parameters +
2084  " have not been set. "
2085  "A possible reason might be that you did not add these parameter to "
2086  "the input file or that their spelling is not correct."));
2087  }
2088 }
2089 
2090 
2091 
2093  : n_branches(0)
2094 {}
2095 
2096 
2097 
2098 void
2100  const std::string &filename,
2101  const std::string &last_line,
2102  const bool skip_undefined)
2103 {
2104  AssertThrow(input, ExcIO());
2105 
2106  // Note that (to avoid infinite recursion) we have to explicitly call the
2107  // base class version of parse_input and *not* a wrapper (which may be
2108  // virtual and lead us back here)
2109  ParameterHandler::parse_input(input, filename, last_line, skip_undefined);
2110  init_branches();
2111 }
2112 
2113 
2114 
2115 void
2117 {
2118  for (unsigned int run_no = 0; run_no < n_branches; ++run_no)
2119  {
2120  // give create_new one-based numbers
2121  uc.create_new(run_no + 1);
2122  fill_entry_values(run_no);
2123  uc.run(*this);
2124  }
2125 }
2126 
2127 
2128 
2129 void
2131 {
2132  multiple_choices.clear();
2134 
2135  // split up different values
2136  for (auto &multiple_choice : multiple_choices)
2137  multiple_choice.split_different_values();
2138 
2139  // finally calculate number of branches
2140  n_branches = 1;
2141  for (const auto &multiple_choice : multiple_choices)
2142  if (multiple_choice.type == Entry::variant)
2143  n_branches *= multiple_choice.different_values.size();
2144 
2145  // check whether array entries have the correct
2146  // number of entries
2147  for (const auto &multiple_choice : multiple_choices)
2148  if (multiple_choice.type == Entry::array)
2149  if (multiple_choice.different_values.size() != n_branches)
2150  std::cerr << " The entry value" << std::endl
2151  << " " << multiple_choice.entry_value << std::endl
2152  << " for the entry named" << std::endl
2153  << " " << multiple_choice.entry_name << std::endl
2154  << " does not have the right number of entries for the "
2155  << std::endl
2156  << " " << n_branches
2157  << " variant runs that will be performed." << std::endl;
2158 
2159 
2160  // do a first run on filling the values to
2161  // check for the conformance with the regexp
2162  // (later on, this will be lost in the whole
2163  // other output)
2164  for (unsigned int i = 0; i < n_branches; ++i)
2165  fill_entry_values(i);
2166 }
2167 
2168 
2169 
2170 void
2172 {
2173  const boost::property_tree::ptree &current_section =
2174  entries->get_child(get_current_path());
2175 
2176  // check all entries in the present
2177  // subsection whether they are
2178  // multiple entries
2179  for (const auto &p : current_section)
2180  if (is_parameter_node(p.second) == true)
2181  {
2182  const std::string value = p.second.get<std::string>("value");
2183  if (value.find('{') != std::string::npos)
2184  multiple_choices.emplace_back(subsection_path,
2185  demangle(p.first),
2186  value);
2187  }
2188 
2189  // then loop over all subsections
2190  for (const auto &p : current_section)
2191  if (is_parameter_node(p.second) == false)
2192  {
2193  enter_subsection(demangle(p.first));
2195  leave_subsection();
2196  }
2197 }
2198 
2199 
2200 
2201 void
2203 {
2204  unsigned int possibilities = 1;
2205 
2206  std::vector<Entry>::iterator choice;
2207  for (choice = multiple_choices.begin(); choice != multiple_choices.end();
2208  ++choice)
2209  {
2210  const unsigned int selection =
2211  (run_no / possibilities) % choice->different_values.size();
2212  std::string entry_value;
2213  if (choice->type == Entry::variant)
2214  entry_value = choice->different_values[selection];
2215  else
2216  {
2217  if (run_no >= choice->different_values.size())
2218  {
2219  std::cerr
2220  << "The given array for entry <" << choice->entry_name
2221  << "> does not contain enough elements! Taking empty string instead."
2222  << std::endl;
2223  entry_value = "";
2224  }
2225  else
2226  entry_value = choice->different_values[run_no];
2227  }
2228 
2229  // temporarily enter the
2230  // subsection tree of this
2231  // multiple entry, set the
2232  // value, and get out
2233  // again. the set() operation
2234  // also tests for the
2235  // correctness of the value
2236  // with regard to the pattern
2237  subsection_path.swap(choice->subsection_path);
2238  set(choice->entry_name, entry_value);
2239  subsection_path.swap(choice->subsection_path);
2240 
2241  // move ahead if it was a variant entry
2242  if (choice->type == Entry::variant)
2243  possibilities *= choice->different_values.size();
2244  }
2245 }
2246 
2247 
2248 
2249 std::size_t
2251 {
2252  std::size_t mem = ParameterHandler::memory_consumption();
2253  for (const auto &multiple_choice : multiple_choices)
2254  mem += multiple_choice.memory_consumption();
2255 
2256  return mem;
2257 }
2258 
2259 
2260 
2261 MultipleParameterLoop::Entry::Entry(const std::vector<std::string> &ssp,
2262  const std::string & Name,
2263  const std::string & Value)
2264  : subsection_path(ssp)
2265  , entry_name(Name)
2266  , entry_value(Value)
2267  , type(Entry::array)
2268 {}
2269 
2270 
2271 
2272 void
2274 {
2275  // split string into three parts:
2276  // part before the opening "{",
2277  // the selection itself, final
2278  // part after "}"
2279  std::string prefix(entry_value, 0, entry_value.find('{'));
2280  std::string multiple(entry_value,
2281  entry_value.find('{') + 1,
2282  entry_value.rfind('}') - entry_value.find('{') - 1);
2283  std::string postfix(entry_value,
2284  entry_value.rfind('}') + 1,
2285  std::string::npos);
2286  // if array entry {{..}}: delete inner
2287  // pair of braces
2288  if (multiple[0] == '{')
2289  multiple.erase(0, 1);
2290  if (multiple[multiple.size() - 1] == '}')
2291  multiple.erase(multiple.size() - 1, 1);
2292  // erase leading and trailing spaces
2293  // in multiple
2294  while (std::isspace(multiple[0]))
2295  multiple.erase(0, 1);
2296  while (std::isspace(multiple[multiple.size() - 1]))
2297  multiple.erase(multiple.size() - 1, 1);
2298 
2299  // delete spaces around '|'
2300  while (multiple.find(" |") != std::string::npos)
2301  multiple.replace(multiple.find(" |"), 2, "|");
2302  while (multiple.find("| ") != std::string::npos)
2303  multiple.replace(multiple.find("| "), 2, "|");
2304 
2305  while (multiple.find('|') != std::string::npos)
2306  {
2307  different_values.push_back(
2308  prefix + std::string(multiple, 0, multiple.find('|')) + postfix);
2309  multiple.erase(0, multiple.find('|') + 1);
2310  }
2311  // make up the last selection ("while" broke
2312  // because there was no '|' any more
2313  different_values.push_back(prefix + multiple + postfix);
2314  // finally check whether this was a variant
2315  // entry ({...}) or an array ({{...}})
2316  if ((entry_value.find("{{") != std::string::npos) &&
2317  (entry_value.find("}}") != std::string::npos))
2318  type = Entry::array;
2319  else
2320  type = Entry::variant;
2321 }
2322 
2323 
2324 std::size_t
2326 {
2331  sizeof(type));
2332 }
2333 
std::vector< std::string > split_string_list(const std::string &s, const std::string &delimiter=",")
Definition: utilities.cc:704
std::vector< Entry > multiple_choices
long int get_integer(const std::string &entry_string) const
void pop()
Definition: logstream.cc:317
static const char path_separator
std::string escape(const std::string &input, const PatternBase::OutputStyle style)
Definition: patterns.cc:55
void assert_that_entries_have_been_set() const
void loop(UserClass &uc)
types::global_dof_index size_type
Definition: cuda_kernels.h:45
static ::ExceptionBase & ExcCannotOpenIncludeStatementFile(int arg1, std::string arg2, std::string arg3)
static ::ExceptionBase & ExcIO()
virtual void run(ParameterHandler &prm)=0
std::string get_current_path() const
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
static ::ExceptionBase & ExcEntryUndeclared(std::string arg1)
std::string trim(const std::string &input)
Definition: utilities.cc:531
std::string get(const std::string &entry_string) const
static ::ExceptionBase & ExcUnbalancedSubsections(std::string arg1, std::string arg2)
std::ostream & print_parameters(std::ostream &out, const OutputStyle style) const
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:758
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="", const bool skip_undefined=false) override
virtual void parse_input_from_string(const std::string &s, const std::string &last_line="", const bool skip_undefined=false)
virtual std::unique_ptr< PatternBase > clone() const =0
void set(const std::string &entry_name, const std::string &new_value)
void log_parameters(LogStream &out, const OutputStyle style=DefaultStyle)
std::vector< std::string > subsection_path
#define AssertThrow(cond, exc)
Definition: exceptions.h:1571
void scan_line(std::string line, const std::string &input_filename, const unsigned int current_line_n, const bool skip_undefined)
static ::ExceptionBase & ExcValueDoesNotMatchPattern(std::string arg1, std::string arg2)
std::vector< std::string > subsection_path
double string_to_double(const std::string &s)
Definition: utilities.cc:656
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
Definition: config.h:414
bool subsection_path_exists(const std::vector< std::string > &sub_path) const
void enter_subsection(const std::string &subsection)
static ::ExceptionBase & ExcFileNotFound(std::string arg1, std::string arg2)
static ::ExceptionBase & ExcInvalidXMLParameterFile()
static ::ExceptionBase & ExcMessage(std::string arg1)
virtual void create_new(const unsigned int run_no)=0
static ::ExceptionBase & ExcCannotParseLine(int arg1, std::string arg2, std::string arg3)
double get_double(const std::string &entry_name) const
std::size_t memory_consumption() const
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation="", const bool has_to_be_set=false)
virtual void parse_input_from_xml(std::istream &input, const bool skip_undefined=false)
#define Assert(cond, exc)
Definition: exceptions.h:1461
std::string get_current_full_path(const std::string &name) const
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:401
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition: utilities.cc:838
std::unique_ptr< boost::property_tree::ptree > entries
void fill_entry_values(const unsigned int run_no)
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="", const bool skip_undefined=false)
bool get_bool(const std::string &entry_name) const
static ::ExceptionBase & ExcAlreadyAtTopLevel()
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:473
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition: utilities.cc:512
std::vector< std::unique_ptr< const Patterns::PatternBase > > patterns
virtual bool match(const std::string &test_string) const =0
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
bool operator==(const ParameterHandler &prm2) const
void log_parameters_section(LogStream &out, const OutputStyle style=DefaultStyle)
virtual void parse_input_from_json(std::istream &input, const bool skip_undefined=false)
std::set< std::string > get_entries_wrongly_not_set() const
std::size_t memory_consumption() const
void push(const std::string &text)
Definition: logstream.cc:303
virtual std::string description(const OutputStyle style=Machine) const =0
void add_action(const std::string &entry, const std::function< void(const std::string &value)> &action)
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
Definition: config.h:452
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:400
int string_to_int(const std::string &s)
Definition: utilities.cc:608
static ::ExceptionBase & ExcNotImplemented()
std::vector< std::string > different_values
std::size_t memory_consumption() const
static ::ExceptionBase & ExcInvalidEntryForPattern(int arg1, std::string arg2, std::string arg3, std::string arg4, std::string arg5)
void recursively_print_parameters(const boost::property_tree::ptree &tree, const std::vector< std::string > &target_subsection_path, const ParameterHandler::OutputStyle style, const unsigned int indent_level, std::ostream &out) const
std::vector< std::function< void(const std::string &)> > actions
static ::ExceptionBase & ExcNoSubsection(int arg1, std::string arg2, std::string arg3)
void declare_alias(const std::string &existing_entry_name, const std::string &alias_name, const bool alias_is_deprecated=false)
std::map< std::string, std::pair< bool, bool > > entries_set_status
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
static ::ExceptionBase & ExcInternalError()