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