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