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