Reference documentation for deal.II version GIT 49863513f1 2023-10-02 19:40: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 - 2023 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  }
720  else
721  {
722  // it must be a subsection
723  recursively_compress_tree(p.second);
724  }
725  }
726  }
727 } // namespace
728 
729 
730 
731 void
733  const bool skip_undefined)
734 {
735  AssertThrow(in.fail() == false, ExcIO());
736  // read the XML tree assuming that (as we
737  // do in print_parameters(XML) it has only
738  // a single top-level node called
739  // "ParameterHandler"
740  boost::property_tree::ptree single_node_tree;
741  // This boost function will raise an exception if this is not a valid XML
742  // file.
743  read_xml(in, single_node_tree);
744 
745  // make sure there is a single top-level element
746  // called "ParameterHandler"
747  AssertThrow(single_node_tree.get_optional<std::string>("ParameterHandler"),
748  ExcInvalidXMLParameterFile("There is no top-level XML element "
749  "called \"ParameterHandler\"."));
750 
751  const std::size_t n_top_level_elements =
752  std::distance(single_node_tree.begin(), single_node_tree.end());
753  if (n_top_level_elements != 1)
754  {
755  std::ostringstream top_level_message;
756  top_level_message << "The ParameterHandler input parser found "
757  << n_top_level_elements
758  << " top level elements while reading\n "
759  << " an XML format input file, but there should be"
760  << " exactly one top level element.\n"
761  << " The top level elements are:\n";
762 
763  unsigned int entry_n = 0;
764  for (boost::property_tree::ptree::iterator it = single_node_tree.begin();
765  it != single_node_tree.end();
766  ++it, ++entry_n)
767  {
768  top_level_message
769  << " " << it->first
770  << (entry_n != n_top_level_elements - 1 ? "\n" : "");
771  }
772 
773  // repeat assertion condition to make the printed version easier to read
774  AssertThrow(n_top_level_elements == 1,
775  ExcInvalidXMLParameterFile(top_level_message.str()));
776  }
777 
778  // read the child elements recursively
779  const boost::property_tree::ptree &my_entries =
780  single_node_tree.get_child("ParameterHandler");
781 
782  read_xml_recursively(
783  my_entries, "", path_separator, patterns, skip_undefined, *this);
784 }
785 
786 
787 void
789  const bool skip_undefined)
790 {
791  AssertThrow(in.fail() == false, ExcIO());
792 
793  boost::property_tree::ptree node_tree;
794  // This boost function will raise an exception if this is not a valid JSON
795  // file.
796  try
797  {
798  read_json(in, node_tree);
799  }
800  catch (const std::exception &e)
801  {
802  AssertThrow(
803  false,
804  ExcMessage(
805  "The provided JSON file is not valid. Boost aborted with the "
806  "following assert message: \n\n" +
807  std::string(e.what())));
808  }
809 
810  // The xml function is reused to read in the xml into the parameter file.
811  // This means that only mangled files can be read.
812  read_xml_recursively(
813  node_tree, "", path_separator, patterns, skip_undefined, *this);
814 }
815 
816 
817 
818 void
820 {
821  entries = std::make_unique<boost::property_tree::ptree>();
822  entries_set_status.clear();
823 }
824 
825 
826 
827 void
828 ParameterHandler::declare_entry(const std::string &entry,
829  const std::string &default_value,
830  const Patterns::PatternBase &pattern,
831  const std::string &documentation,
832  const bool has_to_be_set)
833 {
834  entries->put(get_current_full_path(entry) + path_separator + "value",
835  default_value);
836  entries->put(get_current_full_path(entry) + path_separator + "default_value",
837  default_value);
838  entries->put(get_current_full_path(entry) + path_separator + "documentation",
839  documentation);
840 
841  // initialize with false
842  const std::pair<bool, bool> set_status =
843  std::pair<bool, bool>(has_to_be_set, false);
844  entries_set_status.insert(
845  std::pair<std::string, std::pair<bool, bool>>(get_current_full_path(entry),
846  set_status));
847 
848  patterns.reserve(patterns.size() + 1);
849  patterns.emplace_back(pattern.clone());
850  entries->put(get_current_full_path(entry) + path_separator + "pattern",
851  static_cast<unsigned int>(patterns.size() - 1));
852  // also store the description of
853  // the pattern. we do so because we
854  // may wish to export the whole
855  // thing as XML or any other format
856  // so that external tools can work
857  // on the parameter file; in that
858  // case, they will have to be able
859  // to re-create the patterns as far
860  // as possible
862  "pattern_description",
863  patterns.back()->description());
864 
865  // as documented, do the default value checking at the very end
866  AssertThrow(pattern.match(default_value),
867  ExcValueDoesNotMatchPattern(default_value,
868  pattern.description()));
869 }
870 
871 
872 
873 void
875  const std::string &entry,
876  const std::function<void(const std::string &)> &action,
877  const bool execute_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  if (execute_action)
902  {
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 
911 void
912 ParameterHandler::declare_alias(const std::string &existing_entry_name,
913  const std::string &alias_name,
914  const bool alias_is_deprecated)
915 {
916  // see if there is anything to refer to already
917  Assert(entries->get_optional<std::string>(
918  get_current_full_path(existing_entry_name)),
919  ExcMessage("You are trying to declare an alias entry <" + alias_name +
920  "> that references an entry <" + existing_entry_name +
921  ">, but the latter does not exist."));
922  // then also make sure that what is being referred to is in
923  // fact a parameter (not an alias or subsection)
924  Assert(entries->get_optional<std::string>(
925  get_current_full_path(existing_entry_name) + path_separator +
926  "value"),
927  ExcMessage("You are trying to declare an alias entry <" + alias_name +
928  "> that references an entry <" + existing_entry_name +
929  ">, but the latter does not seem to be a "
930  "parameter declaration."));
931 
932 
933  // now also make sure that if the alias has already been
934  // declared, that it is also an alias and refers to the same
935  // entry
936  if (entries->get_optional<std::string>(get_current_full_path(alias_name)))
937  {
938  Assert(entries->get_optional<std::string>(
939  get_current_full_path(alias_name) + path_separator + "alias"),
940  ExcMessage("You are trying to declare an alias entry <" +
941  alias_name +
942  "> but a non-alias entry already exists in this "
943  "subsection (i.e., there is either a preexisting "
944  "further subsection, or a parameter entry, with "
945  "the same name as the alias)."));
946  Assert(entries->get<std::string>(get_current_full_path(alias_name) +
947  path_separator + "alias") ==
948  existing_entry_name,
949  ExcMessage(
950  "You are trying to declare an alias entry <" + alias_name +
951  "> but an alias entry already exists in this "
952  "subsection and this existing alias references a "
953  "different parameter entry. Specifically, "
954  "you are trying to reference the entry <" +
955  existing_entry_name +
956  "> whereas the existing alias references "
957  "the entry <" +
958  entries->get<std::string>(get_current_full_path(alias_name) +
959  path_separator + "alias") +
960  ">."));
961  }
962 
963  entries->put(get_current_full_path(alias_name) + path_separator + "alias",
964  existing_entry_name);
965  entries->put(get_current_full_path(alias_name) + path_separator +
966  "deprecation_status",
967  (alias_is_deprecated ? "true" : "false"));
968 }
969 
970 
971 
972 void
973 ParameterHandler::enter_subsection(const std::string &subsection)
974 {
975  // if necessary create subsection
976  if (!entries->get_child_optional(get_current_full_path(subsection)))
977  entries->add_child(get_current_full_path(subsection),
978  boost::property_tree::ptree());
979 
980  // then enter it
981  subsection_path.push_back(subsection);
982 }
983 
984 
985 
986 void
988 {
989  // assert there is a subsection that
990  // we may leave
992 
993  if (subsection_path.size() > 0)
994  subsection_path.pop_back();
995 }
996 
997 
998 
999 bool
1001  const std::vector<std::string> &sub_path) const
1002 {
1003  // Get full path to sub_path (i.e. prepend subsection_path to sub_path).
1004  std::vector<std::string> full_path(subsection_path);
1005  full_path.insert(full_path.end(), sub_path.begin(), sub_path.end());
1006 
1007  boost::optional<const boost::property_tree::ptree &> subsection(
1008  entries->get_child_optional(
1009  collate_path_string(path_separator, full_path)));
1010 
1011  // If subsection is boost::null (i.e. it does not exist)
1012  // or it exists as a parameter/alias node, return false.
1013  // Otherwise (i.e. it exists as a subsection node), return true.
1014  return !(!subsection || is_parameter_node(subsection.get()) ||
1015  is_alias_node(subsection.get()));
1016 }
1017 
1018 
1019 
1020 std::string
1021 ParameterHandler::get(const std::string &entry_string) const
1022 {
1023  // assert that the entry is indeed
1024  // declared
1025  if (boost::optional<std::string> value = entries->get_optional<std::string>(
1026  get_current_full_path(entry_string) + path_separator + "value"))
1027  return value.get();
1028  else
1029  {
1030  Assert(false, ExcEntryUndeclared(entry_string));
1031  return "";
1032  }
1033 }
1034 
1035 
1036 
1037 std::string
1038 ParameterHandler::get(const std::vector<std::string> &entry_subsection_path,
1039  const std::string &entry_string) const
1040 {
1041  // assert that the entry is indeed
1042  // declared
1043  if (boost::optional<std::string> value = entries->get_optional<std::string>(
1044  get_current_full_path(entry_subsection_path, entry_string) +
1045  path_separator + "value"))
1046  return value.get();
1047  else
1048  {
1049  Assert(false,
1050  ExcEntryUndeclared(demangle(
1051  get_current_full_path(entry_subsection_path, entry_string))));
1052  return "";
1053  }
1055 
1056 
1057 
1058 long int
1059 ParameterHandler::get_integer(const std::string &entry_string) const
1060 {
1061  try
1062  {
1063  return Utilities::string_to_int(get(entry_string));
1064  }
1065  catch (...)
1066  {
1067  AssertThrow(false,
1068  ExcMessage("Can't convert the parameter value <" +
1069  get(entry_string) + "> for entry <" +
1070  entry_string + "> to an integer."));
1071  return 0;
1072  }
1073 }
1074 
1075 
1076 
1077 long int
1079  const std::vector<std::string> &entry_subsection_path,
1080  const std::string &entry_string) const
1081 {
1082  try
1083  {
1084  return Utilities::string_to_int(get(entry_subsection_path, entry_string));
1085  }
1086  catch (...)
1087  {
1088  AssertThrow(false,
1089  ExcMessage(
1090  "Can't convert the parameter value <" +
1091  get(entry_subsection_path, entry_string) + "> for entry <" +
1092  demangle(get_current_full_path(entry_subsection_path,
1093  entry_string)) +
1094  "> to an integer."));
1095  return 0;
1096  }
1097 }
1098 
1099 
1100 
1101 double
1102 ParameterHandler::get_double(const std::string &entry_string) const
1103 {
1104  try
1105  {
1106  return Utilities::string_to_double(get(entry_string));
1107  }
1108  catch (...)
1109  {
1110  AssertThrow(false,
1111  ExcMessage("Can't convert the parameter value <" +
1112  get(entry_string) + "> for entry <" +
1113  entry_string +
1114  "> to a double precision variable."));
1115  return 0;
1116  }
1117 }
1118 
1119 
1120 
1121 double
1123  const std::vector<std::string> &entry_subsection_path,
1124  const std::string &entry_string) const
1125 {
1126  try
1127  {
1129  get(entry_subsection_path, entry_string));
1130  }
1131  catch (...)
1132  {
1133  AssertThrow(false,
1134  ExcMessage(
1135  "Can't convert the parameter value <" +
1136  get(entry_subsection_path, entry_string) + "> for entry <" +
1137  demangle(get_current_full_path(entry_subsection_path,
1138  entry_string)) +
1139  "> to a double precision variable."));
1140  return 0;
1141  }
1142 }
1143 
1144 
1145 
1146 bool
1147 ParameterHandler::get_bool(const std::string &entry_string) const
1148 {
1149  const std::string s = get(entry_string);
1150 
1151  AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1152  ExcMessage("Can't convert the parameter value <" +
1153  get(entry_string) + "> for entry <" + entry_string +
1154  "> to a boolean."));
1155  if (s == "true" || s == "yes")
1156  return true;
1157  else
1158  return false;
1159 }
1160 
1161 
1162 
1163 bool
1165  const std::vector<std::string> &entry_subsection_path,
1166  const std::string &entry_string) const
1167 {
1168  const std::string s = get(entry_subsection_path, entry_string);
1169 
1170  AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1171  ExcMessage("Can't convert the parameter value <" +
1172  get(entry_subsection_path, entry_string) +
1173  "> for entry <" +
1174  demangle(get_current_full_path(entry_subsection_path,
1175  entry_string)) +
1176  "> to a boolean."));
1177  if (s == "true" || s == "yes")
1178  return true;
1179  else
1180  return false;
1181 }
1182 
1183 
1184 
1185 void
1186 ParameterHandler::set(const std::string &entry_string,
1187  const std::string &new_value)
1188 {
1189  // resolve aliases before looking up the correct entry
1190  std::string path = get_current_full_path(entry_string);
1191  if (entries->get_optional<std::string>(path + path_separator + "alias"))
1192  path = get_current_full_path(
1193  entries->get<std::string>(path + path_separator + "alias"));
1194 
1195  // get the node for the entry. if it doesn't exist, then we end up
1196  // in the else-branch below, which asserts that the entry is indeed
1197  // declared
1198  if (entries->get_optional<std::string>(path + path_separator + "value"))
1199  {
1200  // verify that the new value satisfies the provided pattern
1201  const unsigned int pattern_index =
1202  entries->get<unsigned int>(path + path_separator + "pattern");
1203  AssertThrow(patterns[pattern_index]->match(new_value),
1204  ExcValueDoesNotMatchPattern(new_value,
1205  entries->get<std::string>(
1206  path + path_separator +
1207  "pattern_description")));
1208 
1209  // then also execute the actions associated with this
1210  // parameter (if any have been provided)
1211  const boost::optional<std::string> action_indices_as_string =
1212  entries->get_optional<std::string>(path + path_separator + "actions");
1213  if (action_indices_as_string)
1214  {
1215  std::vector<int> action_indices = Utilities::string_to_int(
1216  Utilities::split_string_list(action_indices_as_string.get()));
1217  for (const unsigned int index : action_indices)
1218  if (actions.size() >= index + 1)
1219  actions[index](new_value);
1220  }
1221 
1222  // finally write the new value into the database
1223  entries->put(path + path_separator + "value", new_value);
1224 
1225  auto map_iter = entries_set_status.find(path);
1226  if (map_iter != entries_set_status.end())
1227  map_iter->second = std::pair<bool, bool>(map_iter->second.first, true);
1228  else
1229  AssertThrow(false,
1230  ExcMessage("Could not find parameter " + path +
1231  " in map entries_set_status."));
1232  }
1233  else
1234  AssertThrow(false, ExcEntryUndeclared(entry_string));
1235 }
1236 
1237 
1238 void
1239 ParameterHandler::set(const std::string &entry_string, const char *new_value)
1240 {
1241  // simply forward
1242  set(entry_string, std::string(new_value));
1243 }
1244 
1245 
1246 void
1247 ParameterHandler::set(const std::string &entry_string, const double new_value)
1248 {
1249  std::ostringstream s;
1250  s << std::setprecision(16);
1251  s << new_value;
1252 
1253  // hand this off to the function that
1254  // actually sets the value as a string
1255  set(entry_string, s.str());
1256 }
1257 
1258 
1259 
1260 void
1261 ParameterHandler::set(const std::string &entry_string, const long int new_value)
1262 {
1263  std::ostringstream s;
1264  s << new_value;
1265 
1266  // hand this off to the function that
1267  // actually sets the value as a string
1268  set(entry_string, s.str());
1269 }
1270 
1271 
1272 
1273 void
1274 ParameterHandler::set(const std::string &entry_string, const bool new_value)
1275 {
1276  // hand this off to the function that
1277  // actually sets the value as a string
1278  set(entry_string, (new_value ? "true" : "false"));
1279 }
1280 
1281 
1282 
1283 std::ostream &
1285  const OutputStyle style) const
1286 {
1287  AssertThrow(out.fail() == false, ExcIO());
1288 
1289  assert_validity_of_output_style(style);
1290 
1291  // Create entries copy and sort it, if needed.
1292  // In this way we ensure that the class state is never
1293  // modified by this function.
1294  boost::property_tree::ptree current_entries = *entries.get();
1295 
1296  // Sort parameters alphabetically, if needed.
1297  if ((style & KeepDeclarationOrder) == 0)
1298  {
1299  // Dive recursively into the subsections,
1300  // starting from the top level.
1301  recursively_sort_parameters(path_separator,
1302  std::vector<std::string>(),
1303  current_entries);
1304  }
1305 
1306  // we'll have to print some text that is padded with spaces;
1307  // set the appropriate fill character, but also make sure that
1308  // we will restore the previous setting (and all other stream
1309  // flags) when we exit this function
1310  boost::io::ios_flags_saver restore_flags(out);
1311  boost::io::basic_ios_fill_saver<char> restore_fill_state(out);
1312  out.fill(' ');
1313 
1314  // we treat XML and JSON is one step via BOOST, whereas all of the others are
1315  // done recursively in our own code. take care of the two special formats
1316  // first
1317 
1318  // explicitly compress the tree if requested
1319  if (((style & Short) != 0) && ((style & (XML | JSON)) != 0))
1320  {
1321  // modify the copy of the tree
1322  recursively_compress_tree(current_entries);
1323  }
1324 
1325  if ((style & XML) != 0)
1326  {
1327  // call the writer function and exit as there is nothing
1328  // further to do down in this function
1329  //
1330  // XML has a requirement that there can only be one
1331  // single top-level entry, but we may have multiple
1332  // entries and sections. we work around this by
1333  // creating a tree just for this purpose with the
1334  // single top-level node "ParameterHandler" and
1335  // assign the existing tree under it
1336  boost::property_tree::ptree single_node_tree;
1337  single_node_tree.add_child("ParameterHandler", current_entries);
1338 
1339  write_xml(out, single_node_tree);
1340  return out;
1341  }
1342 
1343  if ((style & JSON) != 0)
1344  {
1345  boost::property_tree::ptree current_entries_damangled;
1346  recursively_demangle(current_entries, current_entries_damangled);
1347  write_json(out, current_entries_damangled);
1348  return out;
1349  }
1350 
1351  // for all of the other formats, print a preamble:
1352  if (((style & Short) != 0) && ((style & Text) != 0))
1353  {
1354  // nothing to do
1355  }
1356  else if ((style & Text) != 0)
1357  {
1358  out << "# Listing of Parameters" << std::endl
1359  << "# ---------------------" << std::endl;
1360  }
1361  else if ((style & LaTeX) != 0)
1362  {
1363  out << "\\subsection{Global parameters}" << std::endl;
1364  out << "\\label{parameters:global}" << std::endl;
1365  out << std::endl << std::endl;
1366  }
1367  else if ((style & Description) != 0)
1368  {
1369  out << "Listing of Parameters:" << std::endl << std::endl;
1370  }
1371  else
1372  {
1373  Assert(false, ExcNotImplemented());
1374  }
1375 
1376  // dive recursively into the subsections
1378  current_entries,
1379  std::vector<std::string>(), // start at the top level
1380  style,
1381  0,
1382  out);
1383 
1384  return out;
1385 }
1386 
1387 
1388 
1389 void
1391  const std::string &filename,
1392  const ParameterHandler::OutputStyle style) const
1393 {
1394  std::string extension = filename.substr(filename.find_last_of('.') + 1);
1395  boost::algorithm::to_lower(extension);
1396 
1397  ParameterHandler::OutputStyle output_style = style;
1398  if (extension == "prm")
1399  output_style = style | PRM;
1400  else if (extension == "xml")
1401  output_style = style | XML;
1402  else if (extension == "json")
1403  output_style = style | JSON;
1404  else if (extension == "tex")
1405  output_style = style | LaTeX;
1406 
1407  std::ofstream out(filename);
1408  AssertThrow(out.fail() == false, ExcIO());
1409  print_parameters(out, output_style);
1410 }
1411 
1412 
1413 
1414 void
1416  const boost::property_tree::ptree &tree,
1417  const std::vector<std::string> &target_subsection_path,
1418  const OutputStyle style,
1419  const unsigned int indent_level,
1420  std::ostream &out) const
1421 {
1422  AssertThrow(out.fail() == false, ExcIO());
1423 
1424  // this function should not be necessary for XML or JSON output...
1425  Assert(!(style & (XML | JSON)), ExcInternalError());
1426 
1427  const boost::property_tree::ptree &current_section =
1428  tree.get_child(collate_path_string(path_separator, target_subsection_path));
1429 
1430  unsigned int overall_indent_level = indent_level;
1431 
1432  const bool is_short = (style & Short) != 0;
1433 
1434  if ((style & Text) != 0)
1435  {
1436  // first find out the longest entry name to be able to align the
1437  // equal signs to do this loop over all nodes of the current
1438  // tree, select the parameter nodes (and discard sub-tree nodes)
1439  // and take the maximum of their lengths
1440  //
1441  // likewise find the longest actual value string to make sure we
1442  // can align the default and documentation strings
1443  std::size_t longest_name = 0;
1444  std::size_t longest_value = 0;
1445  for (const auto &p : current_section)
1446  if (is_parameter_node(p.second) == true)
1447  {
1448  longest_name = std::max(longest_name, demangle(p.first).size());
1449  longest_value = std::max(longest_value,
1450  p.second.get<std::string>("value").size());
1451  }
1452 
1453  // print entries one by one
1454  bool first_entry = true;
1455  for (const auto &p : current_section)
1456  if (is_parameter_node(p.second) == true)
1457  {
1458  const std::string value = p.second.get<std::string>("value");
1459 
1460  // if there is documentation, then add an empty line
1461  // (unless this is the first entry in a subsection), print
1462  // the documentation, and then the actual entry; break the
1463  // documentation into readable chunks such that the whole
1464  // thing is at most 78 characters wide
1465  if (!is_short &&
1466  !p.second.get<std::string>("documentation").empty())
1467  {
1468  if (first_entry == false)
1469  out << '\n';
1470  else
1471  first_entry = false;
1472 
1473  const std::vector<std::string> doc_lines =
1475  p.second.get<std::string>("documentation"),
1476  78 - overall_indent_level * 2 - 2);
1477 
1478  for (const auto &doc_line : doc_lines)
1479  out << std::setw(overall_indent_level * 2) << ""
1480  << "# " << doc_line << '\n';
1481  }
1482 
1483  // print name and value of this entry
1484  out << std::setw(overall_indent_level * 2) << ""
1485  << "set " << demangle(p.first)
1486  << std::setw(longest_name - demangle(p.first).size() + 1) << " "
1487  << "= " << value;
1488 
1489  // finally print the default value, but only if it differs
1490  // from the actual value
1491  if (!is_short &&
1492  value != p.second.get<std::string>("default_value"))
1493  {
1494  out << std::setw(longest_value - value.size() + 1) << ' '
1495  << "# ";
1496  out << "default: "
1497  << p.second.get<std::string>("default_value");
1498  }
1499 
1500  out << '\n';
1501  }
1502  }
1503  else if ((style & LaTeX) != 0)
1504  {
1505  auto escape = [](const std::string &input) {
1507  };
1508 
1509  // if there are any parameters in this section then print them
1510  // as an itemized list
1511  const bool parameters_exist_here =
1512  std::any_of(current_section.begin(),
1513  current_section.end(),
1514  [](const boost::property_tree::ptree::value_type &p) {
1515  return is_parameter_node(p.second) ||
1516  is_alias_node(p.second);
1517  });
1518  if (parameters_exist_here)
1519  {
1520  out << "\\begin{itemize}" << '\n';
1521 
1522  // print entries one by one
1523  for (const auto &p : current_section)
1524  if (is_parameter_node(p.second) == true)
1525  {
1526  const std::string value = p.second.get<std::string>("value");
1527 
1528  // print name
1529  out << "\\item {\\it Parameter name:} {\\tt "
1530  << escape(demangle(p.first)) << "}\n"
1531  << "\\phantomsection";
1532  {
1533  // create label: labels are not to be escaped but
1534  // mangled
1535  std::string label = "parameters:";
1536  for (const auto &path : target_subsection_path)
1537  {
1538  label.append(mangle(path));
1539  label.append("/");
1540  }
1541  label.append(p.first);
1542  // Backwards-compatibility. Output the label with and
1543  // without escaping whitespace:
1544  if (label.find("_20") != std::string::npos)
1545  out << "\\label{"
1546  << Utilities::replace_in_string(label, "_20", " ")
1547  << "}\n";
1548  out << "\\label{" << label << "}\n";
1549  }
1550  out << "\n\n";
1551 
1552  out << "\\index[prmindex]{" << escape(demangle(p.first))
1553  << "}\n";
1554  out << "\\index[prmindexfull]{";
1555  for (const auto &path : target_subsection_path)
1556  out << escape(path) << "!";
1557  out << escape(demangle(p.first)) << "}\n";
1558 
1559  // finally print value and default
1560  out << "{\\it Value:} " << escape(value) << "\n\n"
1561  << '\n'
1562  << "{\\it Default:} "
1563  << escape(p.second.get<std::string>("default_value"))
1564  << "\n\n"
1565  << '\n';
1566 
1567  // if there is a documenting string, print it as well but
1568  // don't escape to allow formatting/formulas
1569  if (!is_short &&
1570  !p.second.get<std::string>("documentation").empty())
1571  out << "{\\it Description:} "
1572  << p.second.get<std::string>("documentation") << "\n\n"
1573  << '\n';
1574  if (!is_short)
1575  {
1576  // also output possible values, do not escape because the
1577  // description internally will use LaTeX formatting
1578  const unsigned int pattern_index =
1579  p.second.get<unsigned int>("pattern");
1580  const std::string desc_str =
1581  patterns[pattern_index]->description(
1583  out << "{\\it Possible values:} " << desc_str << '\n';
1584  }
1585  }
1586  else if (is_alias_node(p.second) == true)
1587  {
1588  const std::string alias = p.second.get<std::string>("alias");
1589 
1590  // print name
1591  out << "\\item {\\it Parameter name:} {\\tt "
1592  << escape(demangle(p.first)) << "}\n"
1593  << "\\phantomsection";
1594  {
1595  // create label: labels are not to be escaped but
1596  // mangled
1597  std::string label = "parameters:";
1598  for (const auto &path : target_subsection_path)
1599  {
1600  label.append(mangle(path));
1601  label.append("/");
1602  }
1603  label.append(p.first);
1604  // Backwards-compatibility. Output the label with and
1605  // without escaping whitespace:
1606  if (label.find("_20") != std::string::npos)
1607  out << "\\label{"
1608  << Utilities::replace_in_string(label, "_20", " ")
1609  << "}\n";
1610  out << "\\label{" << label << "}\n";
1611  }
1612  out << "\n\n";
1613 
1614  out << "\\index[prmindex]{" << escape(demangle(p.first))
1615  << "}\n";
1616  out << "\\index[prmindexfull]{";
1617  for (const auto &path : target_subsection_path)
1618  out << escape(path) << "!";
1619  out << escape(demangle(p.first)) << "}\n";
1620 
1621  // finally print alias and indicate if it is deprecated
1622  out
1623  << "This parameter is an alias for the parameter ``\\texttt{"
1624  << escape(alias) << "}''."
1625  << (p.second.get<std::string>("deprecation_status") ==
1626  "true" ?
1627  " Its use is deprecated." :
1628  "")
1629  << "\n\n"
1630  << '\n';
1631  }
1632  out << "\\end{itemize}" << '\n';
1633  }
1634  }
1635  else if ((style & Description) != 0)
1636  {
1637  // first find out the longest entry name to be able to align the
1638  // equal signs
1639  std::size_t longest_name = 0;
1640  for (const auto &p : current_section)
1641  if (is_parameter_node(p.second) == true)
1642  longest_name = std::max(longest_name, demangle(p.first).size());
1643 
1644  // print entries one by one
1645  for (const auto &p : current_section)
1646  if (is_parameter_node(p.second) == true)
1647  {
1648  // print name and value
1649  out << std::setw(overall_indent_level * 2) << ""
1650  << "set " << demangle(p.first)
1651  << std::setw(longest_name - demangle(p.first).size() + 1) << " "
1652  << " = ";
1653 
1654  // print possible values:
1655  const unsigned int pattern_index =
1656  p.second.get<unsigned int>("pattern");
1657  const std::string full_desc_str =
1658  patterns[pattern_index]->description(Patterns::PatternBase::Text);
1659  const std::vector<std::string> description_str =
1661  full_desc_str, 78 - overall_indent_level * 2 - 2, '|');
1662  if (description_str.size() > 1)
1663  {
1664  out << '\n';
1665  for (const auto &description : description_str)
1666  out << std::setw(overall_indent_level * 2 + 6) << ""
1667  << description << '\n';
1668  }
1669  else if (description_str.empty() == false)
1670  out << " " << description_str[0] << '\n';
1671  else
1672  out << '\n';
1673 
1674  // if there is a documenting string, print it as well
1675  if (!is_short &&
1676  p.second.get<std::string>("documentation").size() != 0)
1677  out << std::setw(overall_indent_level * 2 + longest_name + 10)
1678  << ""
1679  << "(" << p.second.get<std::string>("documentation") << ")"
1680  << '\n';
1681  }
1682  }
1683  else
1684  {
1685  Assert(false, ExcNotImplemented());
1686  }
1687 
1688 
1689  // if there was text before and there are sections to come, put two
1690  // newlines between the last entry and the first subsection
1691  {
1692  unsigned int n_parameters = 0;
1693  unsigned int n_sections = 0;
1694  for (const auto &p : current_section)
1695  if (is_parameter_node(p.second) == true)
1696  ++n_parameters;
1697  else if (is_alias_node(p.second) == false)
1698  ++n_sections;
1699 
1700  if (((style & Description) == 0) &&
1701  (!(((style & Text) != 0) && is_short)) && (n_parameters != 0) &&
1702  (n_sections != 0))
1703  out << "\n\n";
1704  }
1705 
1706  // now transverse subsections tree
1707  for (const auto &p : current_section)
1708  if ((is_parameter_node(p.second) == false) &&
1709  (is_alias_node(p.second) == false))
1710  {
1711  // first print the subsection header
1712  if (((style & Text) != 0) || ((style & Description) != 0))
1713  {
1714  out << std::setw(overall_indent_level * 2) << ""
1715  << "subsection " << demangle(p.first) << '\n';
1716  }
1717  else if ((style & LaTeX) != 0)
1718  {
1719  auto escape = [](const std::string &input) {
1720  return Patterns::internal::escape(input,
1722  };
1723 
1724  out << '\n' << "\\subsection{Parameters in section \\tt ";
1725 
1726  // find the path to the current section so that we can
1727  // print it in the \subsection{...} heading
1728  for (const auto &path : target_subsection_path)
1729  out << escape(path) << "/";
1730  out << escape(demangle(p.first));
1731 
1732  out << "}" << '\n';
1733  out << "\\label{parameters:";
1734  for (const auto &path : target_subsection_path)
1735  out << mangle(path) << "/";
1736  out << p.first << "}";
1737  out << '\n';
1738 
1739  out << '\n';
1740  }
1741  else
1742  {
1743  Assert(false, ExcNotImplemented());
1744  }
1745 
1746  // then the contents of the subsection
1747  const std::string subsection = demangle(p.first);
1748  std::vector<std::string> directory_path = target_subsection_path;
1749  directory_path.emplace_back(subsection);
1750 
1752  tree, directory_path, style, overall_indent_level + 1, out);
1753 
1754  if (is_short && ((style & Text) != 0))
1755  {
1756  // write end of subsection.
1757  out << std::setw(overall_indent_level * 2) << ""
1758  << "end" << '\n';
1759  }
1760  else if ((style & Text) != 0)
1761  {
1762  // write end of subsection. one blank line after each
1763  // subsection
1764  out << std::setw(overall_indent_level * 2) << ""
1765  << "end" << '\n'
1766  << '\n';
1767 
1768  // if this is a toplevel subsection, then have two
1769  // newlines
1770  if (overall_indent_level == 0)
1771  out << '\n';
1772  }
1773  else if ((style & Description) != 0)
1774  {
1775  // nothing to do
1776  }
1777  else if ((style & LaTeX) != 0)
1778  {
1779  // nothing to do
1780  }
1781  else
1782  {
1783  Assert(false, ExcNotImplemented());
1784  }
1785  }
1786 }
1787 
1788 
1789 
1790 void
1792 {
1793  out.push("parameters");
1794  // dive recursively into the subsections
1795  log_parameters_section(out, style);
1796 
1797  out.pop();
1798 }
1799 
1800 
1801 void
1803  const OutputStyle style)
1804 {
1805  // Create entries copy and sort it, if needed.
1806  // In this way we ensure that the class state is never
1807  // modified by this function.
1808  boost::property_tree::ptree sorted_entries;
1809  boost::property_tree::ptree *current_entries = entries.get();
1810 
1811  // Sort parameters alphabetically, if needed.
1812  if ((style & KeepDeclarationOrder) == 0)
1813  {
1814  sorted_entries = *entries;
1815  current_entries = &sorted_entries;
1816 
1817  // Dive recursively into the subsections,
1818  // starting from the current level.
1819  recursively_sort_parameters(path_separator,
1821  sorted_entries);
1822  }
1823 
1824  const boost::property_tree::ptree &current_section =
1825  current_entries->get_child(get_current_path());
1826 
1827  // print entries one by one
1828  for (const auto &p : current_section)
1829  if (is_parameter_node(p.second) == true)
1830  out << demangle(p.first) << ": " << p.second.get<std::string>("value")
1831  << std::endl;
1832 
1833  // now transverse subsections tree
1834  for (const auto &p : current_section)
1835  if (is_parameter_node(p.second) == false)
1836  {
1837  out.push(demangle(p.first));
1838  enter_subsection(demangle(p.first));
1839  log_parameters_section(out, style);
1840  leave_subsection();
1841  out.pop();
1842  }
1843 }
1844 
1845 
1846 
1847 void
1849  const std::string &input_filename,
1850  const unsigned int current_line_n,
1851  const bool skip_undefined)
1852 {
1853  // save a copy for some error messages
1854  const std::string original_line = line;
1855 
1856  // if there is a comment, delete it
1857  if (line.find('#') != std::string::npos)
1858  line.erase(line.find('#'), std::string::npos);
1859 
1860  // replace \t by space:
1861  while (line.find('\t') != std::string::npos)
1862  line.replace(line.find('\t'), 1, " ");
1863 
1864  // trim start and end:
1865  line = Utilities::trim(line);
1866 
1867  // if line is now empty: leave
1868  if (line.empty())
1869  {
1870  return;
1871  }
1872  // enter subsection
1873  else if (Utilities::match_at_string_start(line, "SUBSECTION ") ||
1874  Utilities::match_at_string_start(line, "subsection "))
1875  {
1876  // delete this prefix
1877  line.erase(0, std::string("subsection").size() + 1);
1878 
1879  const std::string subsection = Utilities::trim(line);
1880 
1881  // check whether subsection exists
1882  AssertThrow(skip_undefined || entries->get_child_optional(
1883  get_current_full_path(subsection)),
1884  ExcNoSubsection(current_line_n,
1885  input_filename,
1886  demangle(get_current_full_path(subsection))));
1887 
1888  // subsection exists
1889  subsection_path.push_back(subsection);
1890  }
1891  // exit subsection
1892  else if (Utilities::match_at_string_start(line, "END") ||
1893  Utilities::match_at_string_start(line, "end"))
1894  {
1895  line.erase(0, 3);
1896  while ((line.size() > 0) && ((std::isspace(line[0])) != 0))
1897  line.erase(0, 1);
1898 
1899  AssertThrow(
1900  line.empty(),
1901  ExcCannotParseLine(current_line_n,
1902  input_filename,
1903  "Invalid content after 'end' or 'END' statement."));
1904  AssertThrow(subsection_path.size() != 0,
1905  ExcCannotParseLine(current_line_n,
1906  input_filename,
1907  "There is no subsection to leave here."));
1908  leave_subsection();
1909  }
1910  // regular entry
1911  else if (Utilities::match_at_string_start(line, "SET ") ||
1912  Utilities::match_at_string_start(line, "set "))
1913  {
1914  // erase "set" statement
1915  line.erase(0, 4);
1916 
1917  std::string::size_type pos = line.find('=');
1918  AssertThrow(
1919  pos != std::string::npos,
1920  ExcCannotParseLine(current_line_n,
1921  input_filename,
1922  "Invalid format of 'set' or 'SET' statement."));
1923 
1924  // extract entry name and value and trim
1925  std::string entry_name = Utilities::trim(std::string(line, 0, pos));
1926  std::string entry_value =
1927  Utilities::trim(std::string(line, pos + 1, std::string::npos));
1928 
1929  // resolve aliases before we look up the entry. if necessary, print
1930  // a warning that the alias is deprecated
1931  std::string path = get_current_full_path(entry_name);
1932  if (entries->get_optional<std::string>(path + path_separator + "alias"))
1933  {
1934  if (entries->get<std::string>(path + path_separator +
1935  "deprecation_status") == "true")
1936  {
1937  std::cerr << "Warning in line <" << current_line_n
1938  << "> of file <" << input_filename
1939  << ">: You are using the deprecated spelling <"
1940  << entry_name << "> of the parameter <"
1941  << entries->get<std::string>(path + path_separator +
1942  "alias")
1943  << ">." << std::endl;
1944  }
1945  path = get_current_full_path(
1946  entries->get<std::string>(path + path_separator + "alias"));
1947  }
1948 
1949  // get the node for the entry. if it doesn't exist, then we end up
1950  // in the else-branch below, which asserts that the entry is indeed
1951  // declared
1952  if (entries->get_optional<std::string>(path + path_separator + "value"))
1953  {
1954  // if entry was declared: does it match the regex? if not, don't enter
1955  // it into the database exception: if it contains characters which
1956  // specify it as a multiple loop entry, then ignore content
1957  if (entry_value.find('{') == std::string::npos)
1958  {
1959  // verify that the new value satisfies the provided pattern
1960  const unsigned int pattern_index =
1961  entries->get<unsigned int>(path + path_separator + "pattern");
1962  AssertThrow(patterns[pattern_index]->match(entry_value),
1964  current_line_n,
1965  input_filename,
1966  entry_value,
1967  entry_name,
1968  patterns[pattern_index]->description()));
1969 
1970  // then also execute the actions associated with this
1971  // parameter (if any have been provided)
1972  const boost::optional<std::string> action_indices_as_string =
1973  entries->get_optional<std::string>(path + path_separator +
1974  "actions");
1975  if (action_indices_as_string)
1976  {
1977  std::vector<int> action_indices =
1979  action_indices_as_string.get()));
1980  for (const unsigned int index : action_indices)
1981  if (actions.size() >= index + 1)
1982  actions[index](entry_value);
1983  }
1984  }
1985 
1986  // finally write the new value into the database
1987  entries->put(path + path_separator + "value", entry_value);
1988 
1989  auto map_iter = entries_set_status.find(path);
1990  if (map_iter != entries_set_status.end())
1991  map_iter->second =
1992  std::pair<bool, bool>(map_iter->second.first, true);
1993  else
1994  AssertThrow(false,
1995  ExcMessage("Could not find parameter " + path +
1996  " in map entries_set_status."));
1997  }
1998  else
1999  {
2000  AssertThrow(
2001  skip_undefined,
2002  ExcCannotParseLine(current_line_n,
2003  input_filename,
2004  ("No entry with name <" + entry_name +
2005  "> was declared in the current subsection.")));
2006  }
2007  }
2008  // an include statement?
2009  else if (Utilities::match_at_string_start(line, "include ") ||
2010  Utilities::match_at_string_start(line, "INCLUDE "))
2011  {
2012  // erase "include " statement and eliminate spaces
2013  line.erase(0, 7);
2014  while ((line.size() > 0) && (line[0] == ' '))
2015  line.erase(0, 1);
2016 
2017  // the remainder must then be a filename
2018  AssertThrow(line.size() != 0,
2019  ExcCannotParseLine(current_line_n,
2020  input_filename,
2021  "The current line is an 'include' or "
2022  "'INCLUDE' statement, but it does not "
2023  "name a file for inclusion."));
2024 
2025  std::ifstream input(line);
2026  AssertThrow(input,
2027  ExcCannotOpenIncludeStatementFile(current_line_n,
2028  input_filename,
2029  line));
2030  parse_input(input, line, "", skip_undefined);
2031  }
2032  else
2033  {
2034  AssertThrow(
2035  false,
2036  ExcCannotParseLine(current_line_n,
2037  input_filename,
2038  "The line\n\n"
2039  " <" +
2040  original_line +
2041  ">\n\n"
2042  "could not be parsed: please check to "
2043  "make sure that the file is not missing a "
2044  "'set', 'include', 'subsection', or 'end' "
2045  "statement."));
2046  }
2047 }
2048 
2049 
2050 
2051 std::size_t
2053 {
2054  // TODO: add to this an estimate of the memory in the property_tree
2056 }
2057 
2058 
2059 
2060 bool
2062 {
2063  if (patterns.size() != prm2.patterns.size())
2064  return false;
2065 
2066  for (unsigned int j = 0; j < patterns.size(); ++j)
2067  if (patterns[j]->description() != prm2.patterns[j]->description())
2068  return false;
2069 
2070  // instead of walking through all
2071  // the nodes of the two trees
2072  // entries and prm2.entries and
2073  // comparing them for equality,
2074  // simply dump the content of the
2075  // entire structure into a string
2076  // and compare those for equality
2077  std::ostringstream o1, o2;
2078  write_json(o1, *entries);
2079  write_json(o2, *prm2.entries);
2080  return (o1.str() == o2.str());
2081 }
2082 
2083 
2084 
2085 std::set<std::string>
2087 {
2088  std::set<std::string> entries_wrongly_not_set;
2089 
2090  for (const auto &it : entries_set_status)
2091  if (it.second.first == true && it.second.second == false)
2092  entries_wrongly_not_set.insert(it.first);
2093 
2094  return entries_wrongly_not_set;
2095 }
2096 
2097 
2098 
2099 void
2101 {
2102  const std::set<std::string> entries_wrongly_not_set =
2104 
2105  if (entries_wrongly_not_set.size() > 0)
2106  {
2107  std::string list_of_missing_parameters = "\n\n";
2108  for (const auto &it : entries_wrongly_not_set)
2109  list_of_missing_parameters += " " + it + "\n";
2110  list_of_missing_parameters += "\n";
2111 
2112  AssertThrow(
2113  entries_wrongly_not_set.empty(),
2114  ExcMessage(
2115  "Not all entries of the parameter handler that were declared with "
2116  "`has_to_be_set = true` have been set. The following parameters " +
2117  list_of_missing_parameters +
2118  " have not been set. "
2119  "A possible reason might be that you did not add these parameter to "
2120  "the input file or that their spelling is not correct."));
2121  }
2122 }
2123 
2124 
2125 
2127  : n_branches(0)
2128 {}
2129 
2130 
2131 
2132 void
2134  const std::string &filename,
2135  const std::string &last_line,
2136  const bool skip_undefined)
2137 {
2138  AssertThrow(input.fail() == false, ExcIO());
2139 
2140  // Note that (to avoid infinite recursion) we have to explicitly call the
2141  // base class version of parse_input and *not* a wrapper (which may be
2142  // virtual and lead us back here)
2143  ParameterHandler::parse_input(input, filename, last_line, skip_undefined);
2144  init_branches();
2145 }
2146 
2147 
2148 
2149 void
2151 {
2152  for (unsigned int run_no = 0; run_no < n_branches; ++run_no)
2153  {
2154  // give create_new one-based numbers
2155  uc.create_new(run_no + 1);
2156  fill_entry_values(run_no);
2157  uc.run(*this);
2158  }
2159 }
2160 
2161 
2162 
2163 void
2165 {
2166  multiple_choices.clear();
2168 
2169  // split up different values
2170  for (auto &multiple_choice : multiple_choices)
2171  multiple_choice.split_different_values();
2172 
2173  // finally calculate number of branches
2174  n_branches = 1;
2175  for (const auto &multiple_choice : multiple_choices)
2176  if (multiple_choice.type == Entry::variant)
2177  n_branches *= multiple_choice.different_values.size();
2178 
2179  // check whether array entries have the correct
2180  // number of entries
2181  for (const auto &multiple_choice : multiple_choices)
2182  if (multiple_choice.type == Entry::array)
2183  if (multiple_choice.different_values.size() != n_branches)
2184  std::cerr << " The entry value" << std::endl
2185  << " " << multiple_choice.entry_value << std::endl
2186  << " for the entry named" << std::endl
2187  << " " << multiple_choice.entry_name << std::endl
2188  << " does not have the right number of entries for the "
2189  << std::endl
2190  << " " << n_branches
2191  << " variant runs that will be performed." << std::endl;
2192 
2193 
2194  // do a first run on filling the values to
2195  // check for the conformance with the regexp
2196  // (later on, this will be lost in the whole
2197  // other output)
2198  for (unsigned int i = 0; i < n_branches; ++i)
2199  fill_entry_values(i);
2200 }
2201 
2202 
2203 
2204 void
2206 {
2207  const boost::property_tree::ptree &current_section =
2208  entries->get_child(get_current_path());
2209 
2210  // check all entries in the present
2211  // subsection whether they are
2212  // multiple entries
2213  for (const auto &p : current_section)
2214  if (is_parameter_node(p.second) == true)
2215  {
2216  const std::string value = p.second.get<std::string>("value");
2217  if (value.find('{') != std::string::npos)
2218  multiple_choices.emplace_back(subsection_path,
2219  demangle(p.first),
2220  value);
2221  }
2222 
2223  // then loop over all subsections
2224  for (const auto &p : current_section)
2225  if (is_parameter_node(p.second) == false)
2226  {
2227  enter_subsection(demangle(p.first));
2229  leave_subsection();
2230  }
2231 }
2232 
2233 
2234 
2235 void
2237 {
2238  unsigned int possibilities = 1;
2239 
2240  std::vector<Entry>::iterator choice;
2241  for (choice = multiple_choices.begin(); choice != multiple_choices.end();
2242  ++choice)
2243  {
2244  const unsigned int selection =
2245  (run_no / possibilities) % choice->different_values.size();
2246  std::string entry_value;
2247  if (choice->type == Entry::variant)
2248  entry_value = choice->different_values[selection];
2249  else
2250  {
2251  if (run_no >= choice->different_values.size())
2252  {
2253  std::cerr
2254  << "The given array for entry <" << choice->entry_name
2255  << "> does not contain enough elements! Taking empty string instead."
2256  << std::endl;
2257  entry_value = "";
2258  }
2259  else
2260  entry_value = choice->different_values[run_no];
2261  }
2262 
2263  // temporarily enter the
2264  // subsection tree of this
2265  // multiple entry, set the
2266  // value, and get out
2267  // again. the set() operation
2268  // also tests for the
2269  // correctness of the value
2270  // with regard to the pattern
2271  subsection_path.swap(choice->subsection_path);
2272  set(choice->entry_name, entry_value);
2273  subsection_path.swap(choice->subsection_path);
2274 
2275  // move ahead if it was a variant entry
2276  if (choice->type == Entry::variant)
2277  possibilities *= choice->different_values.size();
2278  }
2279 }
2280 
2281 
2282 
2283 std::size_t
2285 {
2286  std::size_t mem = ParameterHandler::memory_consumption();
2287  for (const auto &multiple_choice : multiple_choices)
2288  mem += multiple_choice.memory_consumption();
2289 
2290  return mem;
2291 }
2292 
2293 
2294 
2295 MultipleParameterLoop::Entry::Entry(const std::vector<std::string> &ssp,
2296  const std::string &Name,
2297  const std::string &Value)
2298  : subsection_path(ssp)
2299  , entry_name(Name)
2300  , entry_value(Value)
2301  , type(Entry::array)
2302 {}
2303 
2304 
2305 
2306 void
2308 {
2309  // split string into three parts:
2310  // part before the opening "{",
2311  // the selection itself, final
2312  // part after "}"
2313  std::string prefix(entry_value, 0, entry_value.find('{'));
2314  std::string multiple(entry_value,
2315  entry_value.find('{') + 1,
2316  entry_value.rfind('}') - entry_value.find('{') - 1);
2317  std::string postfix(entry_value,
2318  entry_value.rfind('}') + 1,
2319  std::string::npos);
2320  // if array entry {{..}}: delete inner
2321  // pair of braces
2322  if (multiple[0] == '{')
2323  multiple.erase(0, 1);
2324  if (multiple.back() == '}')
2325  multiple.erase(multiple.size() - 1, 1);
2326  // erase leading and trailing spaces
2327  // in multiple
2328  while (std::isspace(multiple[0]) != 0)
2329  multiple.erase(0, 1);
2330  while (std::isspace(multiple.back()) != 0)
2331  multiple.erase(multiple.size() - 1, 1);
2332 
2333  // delete spaces around '|'
2334  while (multiple.find(" |") != std::string::npos)
2335  multiple.replace(multiple.find(" |"), 2, "|");
2336  while (multiple.find("| ") != std::string::npos)
2337  multiple.replace(multiple.find("| "), 2, "|");
2338 
2339  while (multiple.find('|') != std::string::npos)
2340  {
2341  different_values.push_back(
2342  prefix + std::string(multiple, 0, multiple.find('|')) + postfix);
2343  multiple.erase(0, multiple.find('|') + 1);
2344  }
2345  // make up the last selection ("while" broke
2346  // because there was no '|' any more
2347  different_values.push_back(prefix + multiple + postfix);
2348  // finally check whether this was a variant
2349  // entry ({...}) or an array ({{...}})
2350  if ((entry_value.find("{{") != std::string::npos) &&
2351  (entry_value.find("}}") != std::string::npos))
2352  type = Entry::array;
2353  else
2354  type = Entry::variant;
2355 }
2356 
2357 
2358 std::size_t
2360 {
2364  MemoryConsumption::memory_consumption(different_values) +
2365  sizeof(type));
2366 }
2367 
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:477
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:478
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:1616
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:1705
types::global_dof_index size_type
Definition: cuda_kernels.h:45
std::enable_if_t< std::is_fundamental_v< T >, 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