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