Reference documentation for deal.II version GIT b8135fa6eb 2023-03-25 15:55: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 
23 #define BOOST_BIND_GLOBAL_PLACEHOLDERS
24 #include <boost/algorithm/string.hpp>
25 #include <boost/io/ios_state.hpp>
26 #include <boost/property_tree/json_parser.hpp>
27 #include <boost/property_tree/ptree.hpp>
28 #include <boost/property_tree/xml_parser.hpp>
29 #undef BOOST_BIND_GLOBAL_PLACEHOLDERS
30 
31 #include <algorithm>
32 #include <cctype>
33 #include <cstdlib>
34 #include <cstring>
35 #include <fstream>
36 #include <iomanip>
37 #include <iostream>
38 #include <limits>
39 #include <sstream>
40 
41 
43 
44 
46  : entries(new boost::property_tree::ptree())
47 {}
48 
49 
50 namespace
51 {
52  std::string
53  mangle(const std::string &s)
54  {
55  std::string u;
56 
57  // reserve the minimum number of characters we will need. it may
58  // be more but this is the least we can do
59  u.reserve(s.size());
60 
61  // see if the name is special and if so mangle the whole thing
62  const bool mangle_whole_string = (s == "value");
63 
64  // for all parts of the string, see if it is an allowed character or not
65  for (const char c : s)
66  {
67  static const std::string allowed_characters(
68  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
69 
70  if ((!mangle_whole_string) &&
71  (allowed_characters.find(c) != std::string::npos))
72  u.push_back(c);
73  else
74  {
75  u.push_back('_');
76  static const char hex[16] = {'0',
77  '1',
78  '2',
79  '3',
80  '4',
81  '5',
82  '6',
83  '7',
84  '8',
85  '9',
86  'a',
87  'b',
88  'c',
89  'd',
90  'e',
91  'f'};
92  u.push_back(hex[static_cast<unsigned char>(c) / 16]);
93  u.push_back(hex[static_cast<unsigned char>(c) % 16]);
94  }
95  }
96 
97  return u;
98  }
99 
100 
101 
102  std::string
103  demangle(const std::string &s)
104  {
105  std::string u;
106  u.reserve(s.size());
107 
108  for (unsigned int i = 0; i < s.size(); ++i)
109  if (s[i] != '_')
110  u.push_back(s[i]);
111  else
112  {
113  Assert(i + 2 < s.size(),
114  ExcMessage("Trying to demangle an invalid string."));
115 
116  unsigned char c = 0;
117  switch (s[i + 1])
118  {
119  case '0':
120  c = 0 * 16;
121  break;
122  case '1':
123  c = 1 * 16;
124  break;
125  case '2':
126  c = 2 * 16;
127  break;
128  case '3':
129  c = 3 * 16;
130  break;
131  case '4':
132  c = 4 * 16;
133  break;
134  case '5':
135  c = 5 * 16;
136  break;
137  case '6':
138  c = 6 * 16;
139  break;
140  case '7':
141  c = 7 * 16;
142  break;
143  case '8':
144  c = 8 * 16;
145  break;
146  case '9':
147  c = 9 * 16;
148  break;
149  case 'a':
150  c = 10 * 16;
151  break;
152  case 'b':
153  c = 11 * 16;
154  break;
155  case 'c':
156  c = 12 * 16;
157  break;
158  case 'd':
159  c = 13 * 16;
160  break;
161  case 'e':
162  c = 14 * 16;
163  break;
164  case 'f':
165  c = 15 * 16;
166  break;
167  default:
168  Assert(false, ExcInternalError());
169  }
170  switch (s[i + 2])
171  {
172  case '0':
173  c += 0;
174  break;
175  case '1':
176  c += 1;
177  break;
178  case '2':
179  c += 2;
180  break;
181  case '3':
182  c += 3;
183  break;
184  case '4':
185  c += 4;
186  break;
187  case '5':
188  c += 5;
189  break;
190  case '6':
191  c += 6;
192  break;
193  case '7':
194  c += 7;
195  break;
196  case '8':
197  c += 8;
198  break;
199  case '9':
200  c += 9;
201  break;
202  case 'a':
203  c += 10;
204  break;
205  case 'b':
206  c += 11;
207  break;
208  case 'c':
209  c += 12;
210  break;
211  case 'd':
212  c += 13;
213  break;
214  case 'e':
215  c += 14;
216  break;
217  case 'f':
218  c += 15;
219  break;
220  default:
221  Assert(false, ExcInternalError());
222  }
223 
224  u.push_back(static_cast<char>(c));
225 
226  // skip the two characters
227  i += 2;
228  }
229 
230  return u;
231  }
232 
237  bool
238  is_parameter_node(const boost::property_tree::ptree &p)
239  {
240  return static_cast<bool>(p.get_optional<std::string>("value"));
241  }
242 
243 
248  bool
249  is_alias_node(const boost::property_tree::ptree &p)
250  {
251  return static_cast<bool>(p.get_optional<std::string>("alias"));
252  }
253 
260  std::string
261  collate_path_string(const char separator,
262  const std::vector<std::string> &subsection_path)
263  {
264  if (subsection_path.size() > 0)
265  {
266  std::string p = mangle(subsection_path[0]);
267  for (unsigned int i = 1; i < subsection_path.size(); ++i)
268  {
269  p += separator;
270  p += mangle(subsection_path[i]);
271  }
272  return p;
273  }
274  else
275  return "";
276  }
277 
283  void
284  recursively_sort_parameters(
285  const char separator,
286  const std::vector<std::string> &target_subsection_path,
287  boost::property_tree::ptree & tree)
288  {
289  boost::property_tree::ptree &current_section =
290  tree.get_child(collate_path_string(separator, target_subsection_path));
291 
292  // Custom comparator to ensure that the order of sorting is:
293  // - sorted parameters and aliases;
294  // - sorted subsections.
295  static auto compare =
296  [](const std::pair<std::string, boost::property_tree::ptree> &a,
297  const std::pair<std::string, boost::property_tree::ptree> &b) {
298  bool a_is_param =
299  (is_parameter_node(a.second) || is_alias_node(a.second));
300 
301  bool b_is_param =
302  (is_parameter_node(b.second) || is_alias_node(b.second));
303 
304  // If a is a parameter/alias and b is a subsection,
305  // a should go first, and vice-versa.
306  if (a_is_param && !b_is_param)
307  return true;
308 
309  if (!a_is_param && b_is_param)
310  return false;
311 
312  // Otherwise, compare a and b.
313  return a.first < b.first;
314  };
315 
316  current_section.sort(compare);
317 
318  // Now transverse subsections tree recursively.
319  for (auto &p : current_section)
320  {
321  if ((is_parameter_node(p.second) == false) &&
322  (is_alias_node(p.second) == false))
323  {
324  const std::string subsection = demangle(p.first);
325 
326  std::vector<std::string> subsection_path = target_subsection_path;
327  subsection_path.emplace_back(subsection);
328 
329  recursively_sort_parameters(separator, subsection_path, tree);
330  }
331  }
332  }
333 
340  void
341  recursively_demangle(const boost::property_tree::ptree &tree_in,
342  boost::property_tree::ptree & tree_out,
343  const bool is_parameter_or_alias_node = false)
344  {
345  for (const auto &p : tree_in)
346  {
347  if (is_parameter_or_alias_node)
348  {
349  tree_out.put_child(p.first, p.second);
350  }
351  else
352  {
353  boost::property_tree::ptree temp;
354 
355  if (const auto val = p.second.get_value_optional<std::string>())
356  temp.put_value<std::string>(*val);
357 
358  recursively_demangle(p.second,
359  temp,
360  is_parameter_node(p.second) ||
361  is_alias_node(p.second));
362  tree_out.put_child(demangle(p.first), temp);
363  }
364  }
365  }
366 
370  void
371  assert_validity_of_output_style(const ParameterHandler::OutputStyle style)
372  {
373  AssertThrow(
374  (((style & ParameterHandler::XML) != 0) +
375  ((style & ParameterHandler::JSON) != 0) +
376  ((style & ParameterHandler::PRM) != 0) +
377  ((style & ParameterHandler::Description) != 0) +
378  ((style & ParameterHandler::LaTeX) != 0)) == 1,
379  ExcMessage(
380  "You have chosen either no or multiple style formats. You can choose "
381  "between: PRM, Description, LaTeX, XML, JSON."));
382  }
383 
384 } // namespace
385 
386 
387 
388 std::string
390 {
391  return collate_path_string(path_separator, subsection_path);
392 }
393 
394 
395 
396 std::string
397 ParameterHandler::get_current_full_path(const std::string &name) const
398 {
399  std::string path = get_current_path();
400  if (path.empty() == false)
401  path += path_separator;
402 
403  path += mangle(name);
404 
405  return path;
406 }
407 
408 
409 
410 std::string
412  const std::vector<std::string> &sub_path,
413  const std::string & name) const
414 {
415  std::string path = get_current_path();
416  if (path.empty() == false)
417  path += path_separator;
418 
419  if (sub_path.empty() == false)
420  path += collate_path_string(path_separator, sub_path) + path_separator;
421 
422  path += mangle(name);
423 
424  return path;
425 }
426 
427 
428 
429 void
430 ParameterHandler::parse_input(std::istream & input,
431  const std::string &filename,
432  const std::string &last_line,
433  const bool skip_undefined)
434 {
435  AssertThrow(input.fail() == false, ExcIO());
436 
437  // store subsections we are currently in
438  const std::vector<std::string> saved_path = subsection_path;
439 
440  std::string input_line;
441  std::string fully_concatenated_line;
442  bool is_concatenated = false;
443  // Maintain both the current line number and the current logical line
444  // number, where the latter refers to the line number where (possibly) the
445  // current line continuation started.
446  unsigned int current_line_n = 0;
447  unsigned int current_logical_line_n = 0;
448 
449  // define an action that tries to scan a line.
450  //
451  // if that fails, i.e., if scan_line throws
452  // an exception either because a parameter doesn't match its
453  // pattern or because an associated action throws an exception,
454  // then try to rewind the set of subsections to the same
455  // point where we were when the current function was called.
456  // this at least allows to read parameters from a predictable
457  // state, rather than leave the subsection stack in some
458  // unknown state.
459  //
460  // after unwinding the subsection stack, just re-throw the exception
461  auto scan_line_or_cleanup = [this,
462  &skip_undefined,
463  &saved_path](const std::string &line,
464  const std::string &filename,
465  const unsigned int line_number) {
466  try
467  {
468  scan_line(line, filename, line_number, skip_undefined);
469  }
470  catch (...)
471  {
472  while ((saved_path != subsection_path) && (subsection_path.size() > 0))
474 
475  throw;
476  }
477  };
478 
479 
480  while (std::getline(input, input_line))
481  {
482  ++current_line_n;
483  if (!is_concatenated)
484  current_logical_line_n = current_line_n;
485  // Trim the whitespace at the ends of the line here instead of in
486  // scan_line. This makes the continuation line logic a lot simpler.
487  input_line = Utilities::trim(input_line);
488 
489  // If we see the line which is the same as @p last_line ,
490  // terminate the parsing.
491  if (last_line.size() != 0 && input_line == last_line)
492  break;
493 
494  // Check whether or not the current line should be joined with the next
495  // line before calling scan_line.
496  if (input_line.size() != 0 &&
497  input_line.find_last_of('\\') == input_line.size() - 1)
498  {
499  input_line.erase(input_line.size() - 1); // remove the last '\'
500  is_concatenated = true;
501 
502  fully_concatenated_line += input_line;
503  }
504  // If the previous line ended in a '\' but the current did not, then we
505  // should proceed to scan_line.
506  else if (is_concatenated)
507  {
508  fully_concatenated_line += input_line;
509  is_concatenated = false;
510  }
511  // Finally, if neither the previous nor current lines are continuations,
512  // then the current input line is entirely concatenated.
513  else
514  {
515  fully_concatenated_line = input_line;
516  }
517 
518  if (!is_concatenated)
519  {
520  scan_line_or_cleanup(fully_concatenated_line,
521  filename,
522  current_logical_line_n);
523 
524  fully_concatenated_line.clear();
525  }
526  }
527 
528  // While it does not make much sense for anyone to actually do this, allow
529  // the last line to end in a backslash. To do so, we need to parse
530  // whatever was left in the stash of concatenated lines
531  if (is_concatenated)
532  scan_line_or_cleanup(fully_concatenated_line, filename, current_line_n);
533 
534  if (saved_path != subsection_path)
535  {
536  std::stringstream paths_message;
537  if (saved_path.size() > 0)
538  {
539  paths_message << "Path before loading input:\n";
540  for (unsigned int i = 0; i < subsection_path.size(); ++i)
541  {
542  paths_message << std::setw(i * 2 + 4) << " "
543  << "subsection " << saved_path[i] << '\n';
544  }
545  paths_message << "Current path:\n";
546  for (unsigned int i = 0; i < subsection_path.size(); ++i)
547  {
548  paths_message << std::setw(i * 2 + 4) << " "
549  << "subsection " << subsection_path[i]
550  << (i == subsection_path.size() - 1 ? "" : "\n");
551  }
552  }
553  // restore subsection we started with before throwing the exception:
554  subsection_path = saved_path;
555  AssertThrow(false,
556  ExcUnbalancedSubsections(filename, paths_message.str()));
557  }
558 }
559 
560 
561 
562 void
563 ParameterHandler::parse_input(const std::string &filename,
564  const std::string &last_line,
565  const bool skip_undefined,
566  const bool assert_mandatory_entries_are_found)
567 {
568  std::ifstream is(filename);
569  AssertThrow(is, PathSearch::ExcFileNotFound(filename, "ParameterHandler"));
570 
571  std::string file_ending = filename.substr(filename.find_last_of('.') + 1);
572  boost::algorithm::to_lower(file_ending);
573  if (file_ending == "prm")
574  parse_input(is, filename, last_line, skip_undefined);
575  else if (file_ending == "xml")
576  parse_input_from_xml(is, skip_undefined);
577  else if (file_ending == "json")
578  parse_input_from_json(is, skip_undefined);
579  else
580  AssertThrow(false,
581  ExcMessage("Unknown input file name extension. Supported types "
582  "are .prm, .xml, and .json."));
583 
584  if (assert_mandatory_entries_are_found)
586 }
587 
588 
589 
590 void
592  const std::string &last_line,
593  const bool skip_undefined)
594 {
595  std::istringstream input_stream(s);
596  parse_input(input_stream, "input string", last_line, skip_undefined);
597 }
598 
599 
600 
601 namespace
602 {
603  // Recursively go through the 'source' tree and see if we can find
604  // corresponding entries in the 'destination' tree. If not, error out
605  // (i.e. we have just read an XML file that has entries that weren't
606  // declared in the ParameterHandler object); if so, copy the value of these
607  // nodes into the destination object
608  void
609  read_xml_recursively(
610  const boost::property_tree::ptree &source,
611  const std::string & current_path,
612  const char path_separator,
613  const std::vector<std::unique_ptr<const Patterns::PatternBase>> &patterns,
614  const bool skip_undefined,
615  ParameterHandler &prm)
616  {
617  for (const auto &p : source)
618  {
619  // a sub-tree must either be a parameter node or a subsection
620  if (p.second.empty())
621  {
622  // set the found parameter in the destination argument
623  if (skip_undefined)
624  {
625  try
626  {
627  prm.set(demangle(p.first), p.second.data());
628  }
630  {
631  // ignore undeclared entry assert
632  }
633  }
634  else
635  prm.set(demangle(p.first), p.second.data());
636  }
637  else if (p.second.get_optional<std::string>("value"))
638  {
639  // set the found parameter in the destination argument
640  if (skip_undefined)
641  {
642  try
643  {
644  prm.set(demangle(p.first),
645  p.second.get<std::string>("value"));
646  }
648  {
649  // ignore undeclared entry assert
650  }
651  }
652  else
653  prm.set(demangle(p.first), p.second.get<std::string>("value"));
654 
655  // this node might have sub-nodes in addition to "value", such as
656  // "default_value", "documentation", etc. we might at some point
657  // in the future want to make sure that if they exist that they
658  // match the ones in the 'destination' tree
659  }
660  else if (p.second.get_optional<std::string>("alias"))
661  {
662  // it is an alias node. alias nodes are static and there is
663  // nothing to do here (but the same applies as mentioned in the
664  // comment above about the static nodes inside parameter nodes
665  }
666  else
667  {
668  // it must be a subsection
669  prm.enter_subsection(demangle(p.first));
670  read_xml_recursively(p.second,
671  (current_path.empty() ?
672  p.first :
673  current_path + path_separator + p.first),
674  path_separator,
675  patterns,
676  skip_undefined,
677  prm);
678  prm.leave_subsection();
679  }
680  }
681  }
682 
683  // Recursively go through the @p source tree and collapse the nodes of the
684  // format:
685  //
686  //"key":
687  // {
688  // "value" : "val",
689  // "default_value" : "...",
690  // "documentation" : "...",
691  // "pattern" : "...",
692  // "pattern_description": "..."
693  // },
694  //
695  // to
696  //
697  // "key" : "val";
698  //
699  // As an example a JSON file is shown. However, this function also works for
700  // XML since both formats are build around the same BOOST data structures.
701  //
702  // This function is strongly based on read_xml_recursively().
703  void
704  recursively_compress_tree(boost::property_tree::ptree &source)
705  {
706  for (auto &p : source)
707  {
708  if (p.second.get_optional<std::string>("value"))
709  {
710  // save the value in a temporal variable
711  const auto temp = p.second.get<std::string>("value");
712  // clear node (children and value)
713  p.second.clear();
714  // set the correct value
715  p.second.put_value<std::string>(temp);
716  }
717  else if (p.second.get_optional<std::string>("alias"))
718  {}
719  else
720  {
721  // it must be a subsection
722  recursively_compress_tree(p.second);
723  }
724  }
725  }
726 } // namespace
727 
728 
729 
730 void
732  const bool skip_undefined)
733 {
734  AssertThrow(in.fail() == false, ExcIO());
735  // read the XML tree assuming that (as we
736  // do in print_parameters(XML) it has only
737  // a single top-level node called
738  // "ParameterHandler"
739  boost::property_tree::ptree single_node_tree;
740  // This boost function will raise an exception if this is not a valid XML
741  // file.
742  read_xml(in, single_node_tree);
743 
744  // make sure there is a single top-level element
745  // called "ParameterHandler"
746  AssertThrow(single_node_tree.get_optional<std::string>("ParameterHandler"),
747  ExcInvalidXMLParameterFile("There is no top-level XML element "
748  "called \"ParameterHandler\"."));
749 
750  const std::size_t n_top_level_elements =
751  std::distance(single_node_tree.begin(), single_node_tree.end());
752  if (n_top_level_elements != 1)
753  {
754  std::ostringstream top_level_message;
755  top_level_message << "The ParameterHandler input parser found "
756  << n_top_level_elements
757  << " top level elements while reading\n "
758  << " an XML format input file, but there should be"
759  << " exactly one top level element.\n"
760  << " The top level elements are:\n";
761 
762  unsigned int entry_n = 0;
763  for (boost::property_tree::ptree::iterator it = single_node_tree.begin();
764  it != single_node_tree.end();
765  ++it, ++entry_n)
766  {
767  top_level_message
768  << " " << it->first
769  << (entry_n != n_top_level_elements - 1 ? "\n" : "");
770  }
771 
772  // repeat assertion condition to make the printed version easier to read
773  AssertThrow(n_top_level_elements == 1,
774  ExcInvalidXMLParameterFile(top_level_message.str()));
775  }
776 
777  // read the child elements recursively
778  const boost::property_tree::ptree &my_entries =
779  single_node_tree.get_child("ParameterHandler");
780 
781  read_xml_recursively(
782  my_entries, "", path_separator, patterns, skip_undefined, *this);
783 }
784 
785 
786 void
788  const bool skip_undefined)
789 {
790  AssertThrow(in.fail() == false, ExcIO());
791 
792  boost::property_tree::ptree node_tree;
793  // This boost function will raise an exception if this is not a valid JSON
794  // file.
795  try
796  {
797  read_json(in, node_tree);
798  }
799  catch (const std::exception &e)
800  {
801  AssertThrow(
802  false,
803  ExcMessage(
804  "The provided JSON file is not valid. Boost aborted with the "
805  "following assert message: \n\n" +
806  std::string(e.what())));
807  }
808 
809  // The xml function is reused to read in the xml into the parameter file.
810  // This means that only mangled files can be read.
811  read_xml_recursively(
812  node_tree, "", path_separator, patterns, skip_undefined, *this);
813 }
814 
815 
816 
817 void
819 {
820  entries = std::make_unique<boost::property_tree::ptree>();
821  entries_set_status.clear();
822 }
823 
824 
825 
826 void
827 ParameterHandler::declare_entry(const std::string & entry,
828  const std::string & default_value,
829  const Patterns::PatternBase &pattern,
830  const std::string & documentation,
831  const bool has_to_be_set)
832 {
833  entries->put(get_current_full_path(entry) + path_separator + "value",
834  default_value);
835  entries->put(get_current_full_path(entry) + path_separator + "default_value",
836  default_value);
837  entries->put(get_current_full_path(entry) + path_separator + "documentation",
838  documentation);
839 
840  // initialize with false
841  const std::pair<bool, bool> set_status =
842  std::pair<bool, bool>(has_to_be_set, false);
843  entries_set_status.insert(
844  std::pair<std::string, std::pair<bool, bool>>(get_current_full_path(entry),
845  set_status));
846 
847  patterns.reserve(patterns.size() + 1);
848  patterns.emplace_back(pattern.clone());
849  entries->put(get_current_full_path(entry) + path_separator + "pattern",
850  static_cast<unsigned int>(patterns.size() - 1));
851  // also store the description of
852  // the pattern. we do so because we
853  // may wish to export the whole
854  // thing as XML or any other format
855  // so that external tools can work
856  // on the parameter file; in that
857  // case, they will have to be able
858  // to re-create the patterns as far
859  // as possible
861  "pattern_description",
862  patterns.back()->description());
863 
864  // as documented, do the default value checking at the very end
865  AssertThrow(pattern.match(default_value),
866  ExcValueDoesNotMatchPattern(default_value,
867  pattern.description()));
868 }
869 
870 
871 
872 void
874  const std::string & entry,
875  const std::function<void(const std::string &)> &action,
876  const bool execute_action)
877 {
878  actions.push_back(action);
879 
880  // get the current list of actions, if any
881  boost::optional<std::string> current_actions =
882  entries->get_optional<std::string>(get_current_full_path(entry) +
883  path_separator + "actions");
884 
885  // if there were actions already associated with this parameter, add
886  // the current one to it; otherwise, create a one-item list and use
887  // that
888  if (current_actions)
889  {
890  const std::string all_actions =
891  current_actions.get() + "," +
892  Utilities::int_to_string(actions.size() - 1);
893  entries->put(get_current_full_path(entry) + path_separator + "actions",
894  all_actions);
895  }
896  else
897  entries->put(get_current_full_path(entry) + path_separator + "actions",
898  Utilities::int_to_string(actions.size() - 1));
899 
900  if (execute_action)
901  {
902  const std::string default_value = entries->get<std::string>(
903  get_current_full_path(entry) + path_separator + "default_value");
904  action(default_value);
905  }
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
1039 {
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 }
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, const bool execute_action=true)
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:474
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:475
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:1586
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:1675
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:53
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:702
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition: utilities.cc:510
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:756
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:471
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition: utilities.cc:833
double string_to_double(const std::string &s)
Definition: utilities.cc:654
std::string trim(const std::string &input)
Definition: utilities.cc:529
int string_to_int(const std::string &s)
Definition: utilities.cc:606