Loading [MathJax]/extensions/TeX/AMSsymbols.js
 deal.II version GIT relicensing-2791-g2e2a880805 2025-03-11 02:00: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\}}\)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <set>
39#include <sstream>
40
41
43
44
46 : entries(new boost::property_tree::ptree())
47{}
48
49
50namespace
51{
52 std::string
53 mangle(const std::string &s)
54 {
55 std::string u;
56
57 // reserve the minimum number of characters we will need. it may
58 // be more but this is the least we can do
59 u.reserve(s.size());
60
61 // see if the name is special and if so mangle the whole thing
62 const bool mangle_whole_string = (s == "value");
63
64 // for all parts of the string, see if it is an allowed character or not
65 for (const char c : s)
66 {
67 static const std::string allowed_characters(
68 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
69
70 if ((!mangle_whole_string) &&
71 (allowed_characters.find(c) != std::string::npos))
72 u.push_back(c);
73 else
74 {
75 u.push_back('_');
76 static const char hex[16] = {'0',
77 '1',
78 '2',
79 '3',
80 '4',
81 '5',
82 '6',
83 '7',
84 '8',
85 '9',
86 'a',
87 'b',
88 'c',
89 'd',
90 'e',
91 'f'};
92 u.push_back(hex[static_cast<unsigned char>(c) / 16]);
93 u.push_back(hex[static_cast<unsigned char>(c) % 16]);
94 }
95 }
96
97 return u;
98 }
99
100
101
102 std::string
103 demangle(const std::string &s)
104 {
105 std::string u;
106 u.reserve(s.size());
107
108 for (unsigned int i = 0; i < s.size(); ++i)
109 if (s[i] != '_')
110 u.push_back(s[i]);
111 else
112 {
113 Assert(i + 2 < s.size(),
114 ExcMessage("Trying to demangle an invalid string."));
115
116 unsigned char c = 0;
117 switch (s[i + 1])
118 {
119 case '0':
120 c = 0 * 16;
121 break;
122 case '1':
123 c = 1 * 16;
124 break;
125 case '2':
126 c = 2 * 16;
127 break;
128 case '3':
129 c = 3 * 16;
130 break;
131 case '4':
132 c = 4 * 16;
133 break;
134 case '5':
135 c = 5 * 16;
136 break;
137 case '6':
138 c = 6 * 16;
139 break;
140 case '7':
141 c = 7 * 16;
142 break;
143 case '8':
144 c = 8 * 16;
145 break;
146 case '9':
147 c = 9 * 16;
148 break;
149 case 'a':
150 c = 10 * 16;
151 break;
152 case 'b':
153 c = 11 * 16;
154 break;
155 case 'c':
156 c = 12 * 16;
157 break;
158 case 'd':
159 c = 13 * 16;
160 break;
161 case 'e':
162 c = 14 * 16;
163 break;
164 case 'f':
165 c = 15 * 16;
166 break;
167 default:
169 }
170 switch (s[i + 2])
171 {
172 case '0':
173 c += 0;
174 break;
175 case '1':
176 c += 1;
177 break;
178 case '2':
179 c += 2;
180 break;
181 case '3':
182 c += 3;
183 break;
184 case '4':
185 c += 4;
186 break;
187 case '5':
188 c += 5;
189 break;
190 case '6':
191 c += 6;
192 break;
193 case '7':
194 c += 7;
195 break;
196 case '8':
197 c += 8;
198 break;
199 case '9':
200 c += 9;
201 break;
202 case 'a':
203 c += 10;
204 break;
205 case 'b':
206 c += 11;
207 break;
208 case 'c':
209 c += 12;
210 break;
211 case 'd':
212 c += 13;
213 break;
214 case 'e':
215 c += 14;
216 break;
217 case 'f':
218 c += 15;
219 break;
220 default:
222 }
223
224 u.push_back(static_cast<char>(c));
225
226 // skip the two characters
227 i += 2;
228 }
229
230 return u;
231 }
232
237 bool
238 is_parameter_node(const boost::property_tree::ptree &p)
239 {
240 return static_cast<bool>(p.get_optional<std::string>("value"));
241 }
242
243
248 bool
249 is_alias_node(const boost::property_tree::ptree &p)
250 {
251 return static_cast<bool>(p.get_optional<std::string>("alias"));
252 }
253
260 std::string
261 collate_path_string(const char separator,
262 const std::vector<std::string> &subsection_path)
263 {
264 if (subsection_path.size() > 0)
265 {
266 std::string p = mangle(subsection_path[0]);
267 for (unsigned int i = 1; i < subsection_path.size(); ++i)
268 {
269 p += separator;
270 p += mangle(subsection_path[i]);
271 }
272 return p;
273 }
274 else
275 return "";
276 }
277
283 void
284 recursively_sort_parameters(
285 const char separator,
286 const std::vector<std::string> &target_subsection_path,
287 boost::property_tree::ptree &tree)
288 {
289 boost::property_tree::ptree &current_section =
290 tree.get_child(collate_path_string(separator, target_subsection_path));
291
292 // Custom comparator to ensure that the order of sorting is:
293 // - sorted parameters and aliases;
294 // - sorted subsections.
295 static auto compare =
296 [](const std::pair<std::string, boost::property_tree::ptree> &a,
297 const std::pair<std::string, boost::property_tree::ptree> &b) {
298 bool a_is_param =
299 (is_parameter_node(a.second) || is_alias_node(a.second));
300
301 bool b_is_param =
302 (is_parameter_node(b.second) || is_alias_node(b.second));
303
304 // If a is a parameter/alias and b is a subsection,
305 // a should go first, and vice-versa.
306 if (a_is_param && !b_is_param)
307 return true;
308
309 if (!a_is_param && b_is_param)
310 return false;
311
312 // Otherwise, compare a and b.
313 return a.first < b.first;
314 };
315
316 current_section.sort(compare);
317
318 // Now transverse subsections tree recursively.
319 for (const auto &p : current_section)
320 {
321 if ((is_parameter_node(p.second) == false) &&
322 (is_alias_node(p.second) == false))
323 {
324 const std::string subsection = demangle(p.first);
325
326 std::vector<std::string> subsection_path = target_subsection_path;
327 subsection_path.emplace_back(subsection);
328
329 recursively_sort_parameters(separator, subsection_path, tree);
330 }
331 }
332 }
333
341 void
342 recursively_mangle_or_demangle(const boost::property_tree::ptree &tree_in,
343 boost::property_tree::ptree &tree_out,
344 const bool do_mangle,
345 const bool is_parameter_or_alias_node = false)
346 {
347 for (const auto &p : tree_in)
348 {
349 if (is_parameter_or_alias_node)
350 {
351 tree_out.put_child(p.first, p.second);
352 }
353 else
354 {
355 boost::property_tree::ptree temp;
356
357 if (const auto val = p.second.get_value_optional<std::string>())
358 temp.put_value<std::string>(*val);
359
360 recursively_mangle_or_demangle(p.second,
361 temp,
362 do_mangle,
363 is_parameter_node(p.second) ||
364 is_alias_node(p.second));
365 tree_out.put_child(do_mangle ? mangle(p.first) : demangle(p.first),
366 temp);
367 }
368 }
369 }
370
374 void
375 assert_validity_of_output_style(const ParameterHandler::OutputStyle style)
376 {
378 (((style & ParameterHandler::XML) != 0) +
379 ((style & ParameterHandler::JSON) != 0) +
380 ((style & ParameterHandler::PRM) != 0) +
381 ((style & ParameterHandler::Description) != 0) +
382 ((style & ParameterHandler::LaTeX) != 0)) == 1,
384 "You have chosen either no or multiple style formats. You can choose "
385 "between: PRM, Description, LaTeX, XML, JSON."));
386 }
387
388} // namespace
389
390
391
392std::string
394{
395 return collate_path_string(path_separator, subsection_path);
396}
397
398
399
400std::string
401ParameterHandler::get_current_full_path(const std::string &name) const
402{
403 std::string path = get_current_path();
404 if (path.empty() == false)
405 path += path_separator;
406
407 path += mangle(name);
408
409 return path;
410}
411
412
413
414std::string
416 const std::vector<std::string> &sub_path,
417 const std::string &name) const
418{
419 std::string path = get_current_path();
420 if (path.empty() == false)
421 path += path_separator;
422
423 if (sub_path.empty() == false)
424 path += collate_path_string(path_separator, sub_path) + path_separator;
425
426 path += mangle(name);
427
428 return path;
429}
430
431
432
433void
435 const std::string &filename,
436 const std::string &last_line,
437 const bool skip_undefined)
438{
439 AssertThrow(input.fail() == false, ExcIO());
440
441 // store subsections we are currently in
442 const std::vector<std::string> saved_path = subsection_path;
443
444 std::string input_line;
445 std::string fully_concatenated_line;
446 bool is_concatenated = false;
447 // Maintain both the current line number and the current logical line
448 // number, where the latter refers to the line number where (possibly) the
449 // current line continuation started.
450 unsigned int current_line_n = 0;
451 unsigned int current_logical_line_n = 0;
452
453 // Keep a list of deprecation messages if we encounter deprecated entries.
454 std::string deprecation_messages;
455
456 // define an action that tries to scan a line.
457 //
458 // if that fails, i.e., if scan_line throws
459 // an exception either because a parameter doesn't match its
460 // pattern or because an associated action throws an exception,
461 // then try to rewind the set of subsections to the same
462 // point where we were when the current function was called.
463 // this at least allows to read parameters from a predictable
464 // state, rather than leave the subsection stack in some
465 // unknown state.
466 //
467 // after unwinding the subsection stack, just re-throw the exception
468 auto scan_line_or_cleanup =
469 [this,
470 &skip_undefined,
471 &saved_path,
472 &deprecation_messages](const std::string &line,
473 const std::string &filename,
474 const unsigned int line_number) {
475 try
476 {
477 scan_line(line, filename, line_number, skip_undefined);
478 }
479 catch (ExcEntryIsDeprecated &e)
480 {
481 deprecation_messages += e.what();
482 }
483 catch (...)
484 {
485 while ((saved_path != subsection_path) &&
486 (subsection_path.size() > 0))
488
489 throw;
490 }
491 };
492
493
494 while (std::getline(input, input_line))
495 {
496 ++current_line_n;
497 if (!is_concatenated)
498 current_logical_line_n = current_line_n;
499 // Trim the whitespace at the ends of the line here instead of in
500 // scan_line. This makes the continuation line logic a lot simpler.
501 input_line = Utilities::trim(input_line);
502
503 // If we see the line which is the same as @p last_line ,
504 // terminate the parsing.
505 if (last_line.size() != 0 && input_line == last_line)
506 break;
507
508 // Check whether or not the current line should be joined with the next
509 // line before calling scan_line.
510 if (input_line.size() != 0 &&
511 input_line.find_last_of('\\') == input_line.size() - 1)
512 {
513 input_line.erase(input_line.size() - 1); // remove the last '\'
514 is_concatenated = true;
515
516 fully_concatenated_line += input_line;
517 }
518 // If the previous line ended in a '\' but the current did not, then we
519 // should proceed to scan_line.
520 else if (is_concatenated)
521 {
522 fully_concatenated_line += input_line;
523 is_concatenated = false;
524 }
525 // Finally, if neither the previous nor current lines are continuations,
526 // then the current input line is entirely concatenated.
527 else
528 {
529 fully_concatenated_line = input_line;
530 }
531
532 if (!is_concatenated)
533 {
534 scan_line_or_cleanup(fully_concatenated_line,
535 filename,
536 current_logical_line_n);
537
538 fully_concatenated_line.clear();
539 }
540 }
541
542 // While it does not make much sense for anyone to actually do this, allow
543 // the last line to end in a backslash. To do so, we need to parse
544 // whatever was left in the stash of concatenated lines
545 if (is_concatenated)
546 scan_line_or_cleanup(fully_concatenated_line, filename, current_line_n);
547
548 if (saved_path != subsection_path)
549 {
550 std::stringstream paths_message;
551 if (saved_path.size() > 0)
552 {
553 paths_message << "Path before loading input:\n";
554 for (unsigned int i = 0; i < subsection_path.size(); ++i)
555 {
556 paths_message << std::setw(i * 2 + 4) << " "
557 << "subsection " << saved_path[i] << '\n';
558 }
559 paths_message << "Current path:\n";
560 for (unsigned int i = 0; i < subsection_path.size(); ++i)
561 {
562 paths_message << std::setw(i * 2 + 4) << " "
563 << "subsection " << subsection_path[i]
564 << (i == subsection_path.size() - 1 ? "" : "\n");
565 }
566 }
567 // restore subsection we started with before throwing the exception:
568 subsection_path = saved_path;
569 AssertThrow(false,
570 ExcUnbalancedSubsections(filename, paths_message.str()));
571 }
572
573 // if we encountered deprecated entries, throw an exception
574 // that contains all the deprecation messages
575 AssertThrow(deprecation_messages.empty(),
576 ExcEncounteredDeprecatedEntries(deprecation_messages));
577}
578
579
580
581void
582ParameterHandler::parse_input(const std::string &filename,
583 const std::string &last_line,
584 const bool skip_undefined,
585 const bool assert_mandatory_entries_are_found)
586{
587 std::ifstream is(filename);
588 AssertThrow(is, ExcFileNotOpen(filename));
589
590 std::string file_ending = filename.substr(filename.find_last_of('.') + 1);
591 boost::algorithm::to_lower(file_ending);
592 if (file_ending == "prm")
593 parse_input(is, filename, last_line, skip_undefined);
594 else if (file_ending == "xml")
595 parse_input_from_xml(is, skip_undefined);
596 else if (file_ending == "json")
597 parse_input_from_json(is, skip_undefined);
598 else
599 AssertThrow(false,
600 ExcMessage("The given input file <" + filename +
601 "> has a file name extension <" + file_ending +
602 "> that is not recognized. Supported types "
603 "are .prm, .xml, and .json."));
604
605 if (assert_mandatory_entries_are_found)
607}
608
609
610
611void
613 const std::string &last_line,
614 const bool skip_undefined)
615{
616 std::istringstream input_stream(s);
617 parse_input(input_stream, "input string", last_line, 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 if (skip_undefined)
645 {
646 try
647 {
648 prm.set(demangle(p.first), p.second.data());
649 }
651 {
652 // ignore undeclared entry assert
653 }
654 }
655 else
656 prm.set(demangle(p.first), p.second.data());
657 }
658 else if (p.second.get_optional<std::string>("value"))
659 {
660 // set the found parameter in the destination argument
661 if (skip_undefined)
662 {
663 try
664 {
665 prm.set(demangle(p.first),
666 p.second.get<std::string>("value"));
667 }
669 {
670 // ignore undeclared entry assert
671 }
672 }
673 else
674 prm.set(demangle(p.first), p.second.get<std::string>("value"));
675
676 // this node might have sub-nodes in addition to "value", such as
677 // "default_value", "documentation", etc. we might at some point
678 // in the future want to make sure that if they exist that they
679 // match the ones in the 'destination' tree
680 }
681 else if (p.second.get_optional<std::string>("alias"))
682 {
683 // it is an alias node. alias nodes are static and there is
684 // nothing to do here (but the same applies as mentioned in the
685 // comment above about the static nodes inside parameter nodes
686 }
687 else
688 {
689 try
690 {
691 // it must be a subsection
692 prm.enter_subsection(demangle(p.first), !skip_undefined);
693 read_xml_recursively(p.second,
694 (current_path.empty() ?
695 p.first :
696 current_path + path_separator +
697 p.first),
698 path_separator,
699 patterns,
700 skip_undefined,
701 prm);
702 prm.leave_subsection();
703 }
705 {
706 // ignore undeclared entry assert
707 }
708 }
709 }
710 }
711
712 // Recursively go through the @p source tree and collapse the nodes of the
713 // format:
714 //
715 //"key":
716 // {
717 // "value" : "val",
718 // "default_value" : "...",
719 // "documentation" : "...",
720 // "pattern" : "...",
721 // "pattern_description": "..."
722 // },
723 //
724 // to
725 //
726 // "key" : "val";
727 //
728 // As an example a JSON file is shown. However, this function also works for
729 // XML since both formats are build around the same BOOST data structures.
730 //
731 // This function is strongly based on read_xml_recursively().
732 void
733 recursively_compress_tree(boost::property_tree::ptree &source)
734 {
735 for (auto &p : source)
736 {
737 if (p.second.get_optional<std::string>("value"))
738 {
739 // save the value in a temporal variable
740 const auto temp = p.second.get<std::string>("value");
741 // clear node (children and value)
742 p.second.clear();
743 // set the correct value
744 p.second.put_value<std::string>(temp);
745 }
746 else if (p.second.get_optional<std::string>("alias"))
747 {
748 }
749 else
750 {
751 // it must be a subsection
752 recursively_compress_tree(p.second);
753 }
754 }
755 }
756
757 void
758 recursively_keep_non_default(const boost::property_tree::ptree &tree_in,
759 boost::property_tree::ptree &tree_out)
760 {
761 for (const auto &p : tree_in)
762 {
763 if (is_parameter_node(p.second))
764 {
765 const std::string value = p.second.get<std::string>("value");
766
767 if (value != p.second.get<std::string>("default_value"))
768 tree_out.put_child(p.first, p.second);
769 }
770 else if (is_alias_node(p.second))
771 {
772 // nothing to do
773 }
774 else
775 {
776 boost::property_tree::ptree temp;
777
778 if (const auto val = p.second.get_value_optional<std::string>())
779 temp.put_value<std::string>(*val);
780
781 recursively_keep_non_default(p.second, temp);
782
783 if (temp.size() > 0)
784 tree_out.put_child(p.first, temp);
785 }
786 }
787 }
788} // namespace
789
790
791
792void
794 const bool skip_undefined)
795{
796 AssertThrow(in.fail() == false, ExcIO());
797 // read the XML tree assuming that (as we
798 // do in print_parameters(XML) it has only
799 // a single top-level node called
800 // "ParameterHandler"
801 boost::property_tree::ptree single_node_tree;
802 // This boost function will raise an exception if this is not a valid XML
803 // file.
804 read_xml(in, single_node_tree);
805
806 // make sure there is a single top-level element
807 // called "ParameterHandler"
808 AssertThrow(single_node_tree.get_optional<std::string>("ParameterHandler"),
809 ExcInvalidXMLParameterFile("There is no top-level XML element "
810 "called \"ParameterHandler\"."));
811
812 const std::size_t n_top_level_elements =
813 std::distance(single_node_tree.begin(), single_node_tree.end());
814 if (n_top_level_elements != 1)
815 {
816 std::ostringstream top_level_message;
817 top_level_message << "The ParameterHandler input parser found "
818 << n_top_level_elements
819 << " top level elements while reading\n "
820 << " an XML format input file, but there should be"
821 << " exactly one top level element.\n"
822 << " The top level elements are:\n";
823
824 unsigned int entry_n = 0;
825 for (boost::property_tree::ptree::iterator it = single_node_tree.begin();
826 it != single_node_tree.end();
827 ++it, ++entry_n)
828 {
829 top_level_message
830 << " " << it->first
831 << (entry_n != n_top_level_elements - 1 ? "\n" : "");
832 }
833
834 // repeat assertion condition to make the printed version easier to read
835 AssertThrow(n_top_level_elements == 1,
836 ExcInvalidXMLParameterFile(top_level_message.str()));
837 }
838
839 // read the child elements recursively
840 const boost::property_tree::ptree &my_entries =
841 single_node_tree.get_child("ParameterHandler");
842
843 read_xml_recursively(
844 my_entries, "", path_separator, patterns, skip_undefined, *this);
845}
846
847
848void
850 const bool skip_undefined)
851{
852 AssertThrow(in.fail() == false, ExcIO());
853
854 boost::property_tree::ptree node_tree;
855 // This boost function will raise an exception if this is not a valid JSON
856 // file.
857 try
858 {
859 read_json(in, node_tree);
860 }
861 catch (const std::exception &e)
862 {
864 false,
866 "The provided JSON file is not valid. Boost aborted with the "
867 "following assert message: \n\n" +
868 std::string(e.what())));
869 }
870
871 // The xml function is reused to read in the xml into the parameter file.
872 // This function can only read mangled files. Therefore, we create a mangled
873 // tree first.
874 boost::property_tree::ptree node_tree_mangled;
875 recursively_mangle_or_demangle(node_tree,
876 node_tree_mangled,
877 true /*do_mangle*/);
878 read_xml_recursively(
879 node_tree_mangled, "", path_separator, patterns, skip_undefined, *this);
880}
881
882
883
884void
886{
887 entries = std::make_unique<boost::property_tree::ptree>();
888 entries_set_status.clear();
889}
890
891
892
893void
894ParameterHandler::declare_entry(const std::string &entry,
895 const std::string &default_value,
896 const Patterns::PatternBase &pattern,
897 const std::string &documentation,
898 const bool has_to_be_set)
899{
900 entries->put(get_current_full_path(entry) + path_separator + "value",
901 default_value);
902 entries->put(get_current_full_path(entry) + path_separator + "default_value",
903 default_value);
904 entries->put(get_current_full_path(entry) + path_separator + "documentation",
905 documentation);
906
907 // initialize with false
908 const std::pair<bool, bool> set_status =
909 std::pair<bool, bool>(has_to_be_set, false);
910 entries_set_status.insert(
911 std::pair<std::string, std::pair<bool, bool>>(get_current_full_path(entry),
912 set_status));
913
914 patterns.reserve(patterns.size() + 1);
915 patterns.emplace_back(pattern.clone());
916 entries->put(get_current_full_path(entry) + path_separator + "pattern",
917 static_cast<unsigned int>(patterns.size() - 1));
918 // also store the description of
919 // the pattern. we do so because we
920 // may wish to export the whole
921 // thing as XML or any other format
922 // so that external tools can work
923 // on the parameter file; in that
924 // case, they will have to be able
925 // to re-create the patterns as far
926 // as possible
928 "pattern_description",
929 patterns.back()->description());
930
931 // as documented, do the default value checking at the very end
932 AssertThrow(pattern.match(default_value),
933 ExcValueDoesNotMatchPattern(default_value,
934 pattern.description()));
935}
936
937
938
939void
941 const std::string &entry,
942 const std::function<void(const std::string &)> &action,
943 const bool execute_action)
944{
945 actions.push_back(action);
946
947 // get the current list of actions, if any
948 boost::optional<std::string> current_actions =
949 entries->get_optional<std::string>(get_current_full_path(entry) +
950 path_separator + "actions");
951
952 // if there were actions already associated with this parameter, add
953 // the current one to it; otherwise, create a one-item list and use
954 // that
955 if (current_actions)
956 {
957 const std::string all_actions =
958 current_actions.get() + "," +
960 entries->put(get_current_full_path(entry) + path_separator + "actions",
961 all_actions);
962 }
963 else
964 entries->put(get_current_full_path(entry) + path_separator + "actions",
966
967 if (execute_action)
968 {
969 const std::string default_value = entries->get<std::string>(
970 get_current_full_path(entry) + path_separator + "default_value");
971 action(default_value);
972 }
973}
974
975
976
977void
978ParameterHandler::declare_alias(const std::string &existing_entry_name,
979 const std::string &alias_name,
980 const bool alias_is_deprecated)
981{
982 // see if there is anything to refer to already
983 Assert(entries->get_optional<std::string>(
984 get_current_full_path(existing_entry_name)),
985 ExcMessage("You are trying to declare an alias entry <" + alias_name +
986 "> that references an entry <" + existing_entry_name +
987 ">, but the latter does not exist."));
988 // then also make sure that what is being referred to is in
989 // fact a parameter (not an alias or subsection)
990 Assert(entries->get_optional<std::string>(
991 get_current_full_path(existing_entry_name) + path_separator +
992 "value"),
993 ExcMessage("You are trying to declare an alias entry <" + alias_name +
994 "> that references an entry <" + existing_entry_name +
995 ">, but the latter does not seem to be a "
996 "parameter declaration."));
997
998
999 // now also make sure that if the alias has already been
1000 // declared, that it is also an alias and refers to the same
1001 // entry
1002 if (entries->get_optional<std::string>(get_current_full_path(alias_name)))
1003 {
1004 Assert(entries->get_optional<std::string>(
1005 get_current_full_path(alias_name) + path_separator + "alias"),
1006 ExcMessage("You are trying to declare an alias entry <" +
1007 alias_name +
1008 "> but a non-alias entry already exists in this "
1009 "subsection (i.e., there is either a preexisting "
1010 "further subsection, or a parameter entry, with "
1011 "the same name as the alias)."));
1012 Assert(entries->get<std::string>(get_current_full_path(alias_name) +
1013 path_separator + "alias") ==
1014 existing_entry_name,
1015 ExcMessage(
1016 "You are trying to declare an alias entry <" + alias_name +
1017 "> but an alias entry already exists in this "
1018 "subsection and this existing alias references a "
1019 "different parameter entry. Specifically, "
1020 "you are trying to reference the entry <" +
1021 existing_entry_name +
1022 "> whereas the existing alias references "
1023 "the entry <" +
1024 entries->get<std::string>(get_current_full_path(alias_name) +
1025 path_separator + "alias") +
1026 ">."));
1027 }
1028
1029 entries->put(get_current_full_path(alias_name) + path_separator + "alias",
1030 existing_entry_name);
1031
1032 if (alias_is_deprecated)
1033 mark_as_deprecated(alias_name);
1034 else
1035 mark_as_deprecated(alias_name, false);
1036}
1037
1038
1039
1040void
1041ParameterHandler::mark_as_deprecated(const std::string &existing_entry_name,
1042 const bool is_deprecated)
1044 // assert that the entry exists
1045 Assert(entries->get_optional<std::string>(
1046 get_current_full_path(existing_entry_name)),
1047 ExcMessage("You are trying to mark the entry <" + existing_entry_name +
1048 "> as deprecated, but the entry does not exist."));
1049
1050 // then also make sure that what is being referred to is in
1051 // fact a parameter or alias (not a subsection)
1052 Assert(
1053 entries->get_optional<std::string>(
1054 get_current_full_path(existing_entry_name) + path_separator + "value") ||
1055 entries->get_optional<std::string>(
1056 get_current_full_path(existing_entry_name) + path_separator + "alias"),
1057 ExcMessage("You are trying to mark the entry <" + existing_entry_name +
1058 "> as deprecated, but the entry does not seem to be a "
1059 "parameter declaration or a parameter alias."));
1060
1061 entries->put(get_current_full_path(existing_entry_name) + path_separator +
1062 "deprecation_status",
1063 is_deprecated ? "true" : "false");
1064}
1065
1066
1067
1068void
1069ParameterHandler::enter_subsection(const std::string &subsection,
1070 const bool create_path_if_needed)
1071{
1072 // if necessary create subsection
1073 const auto path_exists =
1074 entries->get_child_optional(get_current_full_path(subsection));
1075
1076 if (!create_path_if_needed)
1077 {
1078 AssertThrow(path_exists,
1080 }
1081
1082 if (!path_exists)
1083 entries->add_child(get_current_full_path(subsection),
1084 boost::property_tree::ptree());
1085
1086 // then enter it
1087 subsection_path.push_back(subsection);
1088}
1089
1090
1091
1092void
1094{
1095 // assert there is a subsection that
1096 // we may leave
1098
1099 if (subsection_path.size() > 0)
1100 subsection_path.pop_back();
1101}
1102
1103
1104
1105bool
1107 const std::vector<std::string> &sub_path) const
1108{
1109 // Get full path to sub_path (i.e. prepend subsection_path to sub_path).
1110 std::vector<std::string> full_path(subsection_path);
1111 full_path.insert(full_path.end(), sub_path.begin(), sub_path.end());
1112
1113 boost::optional<const boost::property_tree::ptree &> subsection(
1114 entries->get_child_optional(
1115 collate_path_string(path_separator, full_path)));
1116
1117 // If subsection is boost::null (i.e. it does not exist)
1118 // or it exists as a parameter/alias node, return false.
1119 // Otherwise (i.e. it exists as a subsection node), return true.
1120 return !(!subsection || is_parameter_node(subsection.get()) ||
1121 is_alias_node(subsection.get()));
1122}
1123
1124
1125
1126std::string
1127ParameterHandler::get(const std::string &entry_string) const
1128{
1129 // assert that the entry is indeed
1130 // declared
1131 if (boost::optional<std::string> value = entries->get_optional<std::string>(
1132 get_current_full_path(entry_string) + path_separator + "value"))
1133 return value.get();
1134 else
1135 {
1136 Assert(false, ExcEntryUndeclared(entry_string));
1137 return "";
1138 }
1139}
1140
1141
1142
1143std::string
1144ParameterHandler::get(const std::vector<std::string> &entry_subsection_path,
1145 const std::string &entry_string) const
1146{
1147 // assert that the entry is indeed
1148 // declared
1149 if (boost::optional<std::string> value = entries->get_optional<std::string>(
1150 get_current_full_path(entry_subsection_path, entry_string) +
1151 path_separator + "value"))
1152 return value.get();
1153 else
1154 {
1155 Assert(false,
1156 ExcEntryUndeclared(demangle(
1157 get_current_full_path(entry_subsection_path, entry_string))));
1158 return "";
1159 }
1160}
1161
1162
1163
1164long int
1165ParameterHandler::get_integer(const std::string &entry_string) const
1166{
1167 try
1168 {
1169 return Utilities::string_to_int(get(entry_string));
1170 }
1171 catch (...)
1172 {
1173 AssertThrow(false,
1174 ExcMessage("Can't convert the parameter value <" +
1175 get(entry_string) + "> for entry <" +
1176 entry_string + "> to an integer."));
1177 return 0;
1178 }
1179}
1180
1181
1182
1183long int
1185 const std::vector<std::string> &entry_subsection_path,
1186 const std::string &entry_string) const
1187{
1188 try
1189 {
1190 return Utilities::string_to_int(get(entry_subsection_path, entry_string));
1191 }
1192 catch (...)
1193 {
1194 AssertThrow(false,
1195 ExcMessage(
1196 "Can't convert the parameter value <" +
1197 get(entry_subsection_path, entry_string) + "> for entry <" +
1198 demangle(get_current_full_path(entry_subsection_path,
1199 entry_string)) +
1200 "> to an integer."));
1201 return 0;
1202 }
1203}
1204
1205
1206
1207double
1208ParameterHandler::get_double(const std::string &entry_string) const
1209{
1210 try
1211 {
1212 return Utilities::string_to_double(get(entry_string));
1213 }
1214 catch (...)
1215 {
1216 AssertThrow(false,
1217 ExcMessage("Can't convert the parameter value <" +
1218 get(entry_string) + "> for entry <" +
1219 entry_string +
1220 "> to a double precision variable."));
1221 return 0;
1222 }
1223}
1224
1225
1226
1227double
1229 const std::vector<std::string> &entry_subsection_path,
1230 const std::string &entry_string) const
1231{
1232 try
1233 {
1235 get(entry_subsection_path, entry_string));
1236 }
1237 catch (...)
1238 {
1239 AssertThrow(false,
1240 ExcMessage(
1241 "Can't convert the parameter value <" +
1242 get(entry_subsection_path, entry_string) + "> for entry <" +
1243 demangle(get_current_full_path(entry_subsection_path,
1244 entry_string)) +
1245 "> to a double precision variable."));
1246 return 0;
1247 }
1248}
1249
1250
1251
1252bool
1253ParameterHandler::get_bool(const std::string &entry_string) const
1254{
1255 const std::string s = get(entry_string);
1256
1257 AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1258 ExcMessage("Can't convert the parameter value <" +
1259 get(entry_string) + "> for entry <" + entry_string +
1260 "> to a boolean."));
1261 if (s == "true" || s == "yes")
1262 return true;
1263 else
1264 return false;
1265}
1266
1267
1268
1269bool
1271 const std::vector<std::string> &entry_subsection_path,
1272 const std::string &entry_string) const
1273{
1274 const std::string s = get(entry_subsection_path, entry_string);
1275
1276 AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"),
1277 ExcMessage("Can't convert the parameter value <" +
1278 get(entry_subsection_path, entry_string) +
1279 "> for entry <" +
1280 demangle(get_current_full_path(entry_subsection_path,
1281 entry_string)) +
1282 "> to a boolean."));
1283 if (s == "true" || s == "yes")
1284 return true;
1285 else
1286 return false;
1287}
1288
1289
1290
1291void
1292ParameterHandler::set(const std::string &entry_string,
1293 const std::string &new_value)
1294{
1295 // resolve aliases before looking up the correct entry
1296 std::string path = get_current_full_path(entry_string);
1297 if (entries->get_optional<std::string>(path + path_separator + "alias"))
1298 path = get_current_full_path(
1299 entries->get<std::string>(path + path_separator + "alias"));
1300
1301 // get the node for the entry. if it doesn't exist, then we end up
1302 // in the else-branch below, which asserts that the entry is indeed
1303 // declared
1304 if (entries->get_optional<std::string>(path + path_separator + "value"))
1305 {
1306 // verify that the new value satisfies the provided pattern
1307 const unsigned int pattern_index =
1308 entries->get<unsigned int>(path + path_separator + "pattern");
1309 AssertThrow(patterns[pattern_index]->match(new_value),
1311 entries->get<std::string>(
1312 path + path_separator +
1313 "pattern_description")));
1314
1315 // then also execute the actions associated with this
1316 // parameter (if any have been provided)
1317 const boost::optional<std::string> action_indices_as_string =
1318 entries->get_optional<std::string>(path + path_separator + "actions");
1319 if (action_indices_as_string)
1320 {
1321 std::vector<int> action_indices = Utilities::string_to_int(
1322 Utilities::split_string_list(action_indices_as_string.get()));
1323 for (const unsigned int index : action_indices)
1324 if (actions.size() >= index + 1)
1325 actions[index](new_value);
1326 }
1327
1328 // finally write the new value into the database
1329 entries->put(path + path_separator + "value", new_value);
1330
1331 auto map_iter = entries_set_status.find(path);
1332 if (map_iter != entries_set_status.end())
1333 map_iter->second = std::pair<bool, bool>(map_iter->second.first, true);
1334 else
1335 AssertThrow(false,
1336 ExcMessage("Could not find parameter " + path +
1337 " in map entries_set_status."));
1338 }
1339 else
1340 AssertThrow(false, ExcEntryUndeclared(entry_string));
1341}
1342
1343
1344void
1345ParameterHandler::set(const std::string &entry_string, const char *new_value)
1346{
1347 // simply forward
1348 set(entry_string, std::string(new_value));
1349}
1350
1351
1352void
1353ParameterHandler::set(const std::string &entry_string, const double new_value)
1354{
1355 std::ostringstream s;
1356 s << std::setprecision(16);
1357 s << new_value;
1358
1359 // hand this off to the function that
1360 // actually sets the value as a string
1361 set(entry_string, s.str());
1362}
1363
1364
1365
1366void
1367ParameterHandler::set(const std::string &entry_string, const long int new_value)
1368{
1369 std::ostringstream s;
1370 s << new_value;
1371
1372 // hand this off to the function that
1373 // actually sets the value as a string
1374 set(entry_string, s.str());
1375}
1376
1377
1378
1379void
1380ParameterHandler::set(const std::string &entry_string, const bool new_value)
1381{
1382 // hand this off to the function that
1383 // actually sets the value as a string
1384 set(entry_string, (new_value ? "true" : "false"));
1385}
1386
1387
1388
1389std::ostream &
1391 const OutputStyle style) const
1392{
1393 AssertThrow(out.fail() == false, ExcIO());
1394
1395 assert_validity_of_output_style(style);
1396
1397 // Create entries copy and sort it, if needed.
1398 // In this way we ensure that the class state is never
1399 // modified by this function.
1400 boost::property_tree::ptree current_entries = *entries.get();
1401
1402 // Sort parameters alphabetically, if needed.
1403 if ((style & KeepDeclarationOrder) == 0)
1404 {
1405 // Dive recursively into the subsections,
1406 // starting from the top level.
1407 recursively_sort_parameters(path_separator,
1408 std::vector<std::string>(),
1409 current_entries);
1410 }
1411
1412 if ((style & KeepOnlyChanged) != 0)
1413 {
1414 boost::property_tree::ptree current_entries_without_default;
1415 recursively_keep_non_default(current_entries,
1416 current_entries_without_default);
1417 current_entries = current_entries_without_default;
1418 }
1419
1420 // we'll have to print some text that is padded with spaces;
1421 // set the appropriate fill character, but also make sure that
1422 // we will restore the previous setting (and all other stream
1423 // flags) when we exit this function
1424 boost::io::ios_flags_saver restore_flags(out);
1425 boost::io::basic_ios_fill_saver<char> restore_fill_state(out);
1426 out.fill(' ');
1427
1428 // we treat XML and JSON is one step via BOOST, whereas all of the others are
1429 // done recursively in our own code. take care of the two special formats
1430 // first
1431
1432 // explicitly compress the tree if requested
1433 if (((style & Short) != 0) && ((style & (XML | JSON)) != 0))
1434 {
1435 // modify the copy of the tree
1436 recursively_compress_tree(current_entries);
1437 }
1438
1439 if ((style & XML) != 0)
1440 {
1441 // call the writer function and exit as there is nothing
1442 // further to do down in this function
1443 //
1444 // XML has a requirement that there can only be one
1445 // single top-level entry, but we may have multiple
1446 // entries and sections. we work around this by
1447 // creating a tree just for this purpose with the
1448 // single top-level node "ParameterHandler" and
1449 // assign the existing tree under it
1450 boost::property_tree::ptree single_node_tree;
1451 single_node_tree.add_child("ParameterHandler", current_entries);
1452
1453 write_xml(out, single_node_tree);
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 << "> of file <" << input_filename
2071 << ">: You are using the deprecated spelling <"
2072 << entry_name << "> of the parameter <"
2073 << entries->get<std::string>(path + path_separator +
2074 "alias")
2075 << ">." << std::endl;
2076 }
2077 path = get_current_full_path(
2078 entries->get<std::string>(path + path_separator + "alias"));
2079 }
2080
2081 // get the node for the entry. if it doesn't exist, then we end up
2082 // in the else-branch below, which asserts that the entry is indeed
2083 // declared
2084 if (entries->get_optional<std::string>(path + path_separator + "value"))
2085 {
2086 // if entry was declared: does it match the regex? if not, don't enter
2087 // it into the database exception: if it contains characters which
2088 // specify it as a multiple loop entry, then ignore content
2089 if (entry_value.find('{') == std::string::npos)
2090 {
2091 // verify that the new value satisfies the provided pattern
2092 const unsigned int pattern_index =
2093 entries->get<unsigned int>(path + path_separator + "pattern");
2094 AssertThrow(patterns[pattern_index]->match(entry_value),
2096 current_line_n,
2097 input_filename,
2098 entry_value,
2099 entry_name,
2100 patterns[pattern_index]->description()));
2101
2102 // then also execute the actions associated with this
2103 // parameter (if any have been provided)
2104 const boost::optional<std::string> action_indices_as_string =
2105 entries->get_optional<std::string>(path + path_separator +
2106 "actions");
2107 if (action_indices_as_string)
2108 {
2109 std::vector<int> action_indices =
2111 action_indices_as_string.get()));
2112 for (const unsigned int index : action_indices)
2113 if (actions.size() >= index + 1)
2114 actions[index](entry_value);
2115 }
2116 }
2117
2118 // finally write the new value into the database
2119 entries->put(path + path_separator + "value", entry_value);
2120
2121 // record that the entry has been set manually
2122 auto map_iter = entries_set_status.find(path);
2123 if (map_iter != entries_set_status.end())
2124 map_iter->second =
2125 std::pair<bool, bool>(map_iter->second.first, true);
2126 else
2127 AssertThrow(false,
2128 ExcMessage("Could not find parameter " + path +
2129 " in map entries_set_status."));
2130
2131 // Check if the entry (or the resolved alias) is deprecated,
2132 // throw an exception if it is
2133 if (entries->get_optional<std::string>(path + path_separator +
2134 "deprecation_status") &&
2135 entries->get<std::string>(path + path_separator +
2136 "deprecation_status") == "true")
2137 {
2138 AssertThrow(false,
2139 ExcEntryIsDeprecated(current_line_n,
2140 input_filename,
2141 entry_name));
2142 }
2143 }
2144 else
2145 {
2147 skip_undefined,
2148 ExcCannotParseLine(current_line_n,
2149 input_filename,
2150 ("No entry with name <" + entry_name +
2151 "> was declared in the current subsection.")));
2152 }
2153 }
2154 // an include statement?
2155 else if (Utilities::match_at_string_start(line, "include ") ||
2156 Utilities::match_at_string_start(line, "INCLUDE "))
2157 {
2158 // erase "include " statement and eliminate spaces
2159 line.erase(0, 7);
2160 while ((line.size() > 0) && (line[0] == ' '))
2161 line.erase(0, 1);
2162
2163 // the remainder must then be a filename
2164 AssertThrow(line.size() != 0,
2165 ExcCannotParseLine(current_line_n,
2166 input_filename,
2167 "The current line is an 'include' or "
2168 "'INCLUDE' statement, but it does not "
2169 "name a file for inclusion."));
2170
2171 std::ifstream input(line);
2172 AssertThrow(input,
2173 ExcCannotOpenIncludeStatementFile(current_line_n,
2174 input_filename,
2175 line));
2176 parse_input(input, line, "", skip_undefined);
2177 }
2178 else
2179 {
2181 false,
2182 ExcCannotParseLine(current_line_n,
2183 input_filename,
2184 "The line\n\n"
2185 " <" +
2186 original_line +
2187 ">\n\n"
2188 "could not be parsed: please check to "
2189 "make sure that the file is not missing a "
2190 "'set', 'include', 'subsection', or 'end' "
2191 "statement."));
2192 }
2193}
2194
2195
2196
2197std::size_t
2199{
2200 // TODO: add to this an estimate of the memory in the property_tree
2202}
2203
2204
2205
2206bool
2208{
2209 if (patterns.size() != prm2.patterns.size())
2210 return false;
2211
2212 for (unsigned int j = 0; j < patterns.size(); ++j)
2213 if (patterns[j]->description() != prm2.patterns[j]->description())
2214 return false;
2215
2216 // instead of walking through all
2217 // the nodes of the two trees
2218 // entries and prm2.entries and
2219 // comparing them for equality,
2220 // simply dump the content of the
2221 // entire structure into a string
2222 // and compare those for equality
2223 std::ostringstream o1, o2;
2224 write_json(o1, *entries);
2225 write_json(o2, *prm2.entries);
2226 return (o1.str() == o2.str());
2227}
2228
2229
2230
2231std::set<std::string>
2233{
2234 std::set<std::string> entries_wrongly_not_set;
2235
2236 for (const auto &it : entries_set_status)
2237 if (it.second.first == true && it.second.second == false)
2238 entries_wrongly_not_set.insert(it.first);
2239
2240 return entries_wrongly_not_set;
2241}
2242
2243
2244
2245void
2247{
2248 const std::set<std::string> entries_wrongly_not_set =
2250
2251 if (entries_wrongly_not_set.size() > 0)
2252 {
2253 std::string list_of_missing_parameters = "\n\n";
2254 for (const auto &it : entries_wrongly_not_set)
2255 list_of_missing_parameters += " " + it + "\n";
2256 list_of_missing_parameters += "\n";
2257
2259 entries_wrongly_not_set.empty(),
2260 ExcMessage(
2261 "Not all entries of the parameter handler that were declared with "
2262 "`has_to_be_set = true` have been set. The following parameters " +
2263 list_of_missing_parameters +
2264 " have not been set. "
2265 "A possible reason might be that you did not add these parameter to "
2266 "the input file or that their spelling is not correct."));
2267 }
2268}
2269
2270
2271
2275
2276
2277
2278void
2280 const std::string &filename,
2281 const std::string &last_line,
2282 const bool skip_undefined)
2283{
2284 AssertThrow(input.fail() == false, ExcIO());
2285
2286 // Note that (to avoid infinite recursion) we have to explicitly call the
2287 // base class version of parse_input and *not* a wrapper (which may be
2288 // virtual and lead us back here)
2289 ParameterHandler::parse_input(input, filename, last_line, skip_undefined);
2290 init_branches();
2291}
2292
2293
2294
2295void
2297{
2298 for (unsigned int run_no = 0; run_no < n_branches; ++run_no)
2299 {
2300 // give create_new one-based numbers
2301 uc.create_new(run_no + 1);
2302 fill_entry_values(run_no);
2303 uc.run(*this);
2304 }
2305}
2306
2307
2308
2309void
2311{
2312 multiple_choices.clear();
2314
2315 // split up different values
2316 for (auto &multiple_choice : multiple_choices)
2317 multiple_choice.split_different_values();
2318
2319 // finally calculate number of branches
2320 n_branches = 1;
2321 for (const auto &multiple_choice : multiple_choices)
2322 if (multiple_choice.type == Entry::variant)
2323 n_branches *= multiple_choice.different_values.size();
2324
2325 // check whether array entries have the correct
2326 // number of entries
2327 for (const auto &multiple_choice : multiple_choices)
2328 if (multiple_choice.type == Entry::array)
2329 if (multiple_choice.different_values.size() != n_branches)
2330 std::cerr << " The entry value" << std::endl
2331 << " " << multiple_choice.entry_value << std::endl
2332 << " for the entry named" << std::endl
2333 << " " << multiple_choice.entry_name << std::endl
2334 << " does not have the right number of entries for the "
2335 << std::endl
2336 << " " << n_branches
2337 << " variant runs that will be performed." << std::endl;
2338
2339
2340 // do a first run on filling the values to
2341 // check for the conformance with the regexp
2342 // (later on, this will be lost in the whole
2343 // other output)
2344 for (unsigned int i = 0; i < n_branches; ++i)
2346}
2347
2348
2349
2350void
2352{
2353 const boost::property_tree::ptree &current_section =
2354 entries->get_child(get_current_path());
2355
2356 // check all entries in the present
2357 // subsection whether they are
2358 // multiple entries
2359 for (const auto &p : current_section)
2360 if (is_parameter_node(p.second) == true)
2361 {
2362 const std::string value = p.second.get<std::string>("value");
2363 if (value.find('{') != std::string::npos)
2364 multiple_choices.emplace_back(subsection_path,
2365 demangle(p.first),
2366 value);
2367 }
2368
2369 // then loop over all subsections
2370 for (const auto &p : current_section)
2371 if (is_parameter_node(p.second) == false)
2372 {
2373 enter_subsection(demangle(p.first));
2376 }
2377}
2378
2379
2380
2381void
2383{
2384 unsigned int possibilities = 1;
2385
2386 std::vector<Entry>::iterator choice;
2387 for (choice = multiple_choices.begin(); choice != multiple_choices.end();
2388 ++choice)
2389 {
2390 const unsigned int selection =
2391 (run_no / possibilities) % choice->different_values.size();
2392 std::string entry_value;
2393 if (choice->type == Entry::variant)
2394 entry_value = choice->different_values[selection];
2395 else
2396 {
2397 if (run_no >= choice->different_values.size())
2398 {
2399 std::cerr
2400 << "The given array for entry <" << choice->entry_name
2401 << "> does not contain enough elements! Taking empty string instead."
2402 << std::endl;
2403 entry_value = "";
2404 }
2405 else
2406 entry_value = choice->different_values[run_no];
2407 }
2408
2409 // temporarily enter the
2410 // subsection tree of this
2411 // multiple entry, set the
2412 // value, and get out
2413 // again. the set() operation
2414 // also tests for the
2415 // correctness of the value
2416 // with regard to the pattern
2417 subsection_path.swap(choice->subsection_path);
2418 set(choice->entry_name, entry_value);
2419 subsection_path.swap(choice->subsection_path);
2420
2421 // move ahead if it was a variant entry
2422 if (choice->type == Entry::variant)
2423 possibilities *= choice->different_values.size();
2424 }
2425}
2426
2427
2428
2429std::size_t
2431{
2432 std::size_t mem = ParameterHandler::memory_consumption();
2433 for (const auto &multiple_choice : multiple_choices)
2434 mem += multiple_choice.memory_consumption();
2435
2436 return mem;
2437}
2438
2439
2440
2441MultipleParameterLoop::Entry::Entry(const std::vector<std::string> &ssp,
2442 const std::string &Name,
2443 const std::string &Value)
2444 : subsection_path(ssp)
2445 , entry_name(Name)
2446 , entry_value(Value)
2447 , type(Entry::array)
2448{}
2449
2450
2451
2452void
2454{
2455 // split string into three parts:
2456 // part before the opening "{",
2457 // the selection itself, final
2458 // part after "}"
2459 std::string prefix(entry_value, 0, entry_value.find('{'));
2460 std::string multiple(entry_value,
2461 entry_value.find('{') + 1,
2462 entry_value.rfind('}') - entry_value.find('{') - 1);
2463 std::string postfix(entry_value,
2464 entry_value.rfind('}') + 1,
2465 std::string::npos);
2466 // if array entry {{..}}: delete inner
2467 // pair of braces
2468 if (multiple[0] == '{')
2469 multiple.erase(0, 1);
2470 if (multiple.back() == '}')
2471 multiple.erase(multiple.size() - 1, 1);
2472 // erase leading and trailing spaces
2473 // in multiple
2474 while (std::isspace(multiple[0]) != 0)
2475 multiple.erase(0, 1);
2476 while (std::isspace(multiple.back()) != 0)
2477 multiple.erase(multiple.size() - 1, 1);
2478
2479 // delete spaces around '|'
2480 while (multiple.find(" |") != std::string::npos)
2481 multiple.replace(multiple.find(" |"), 2, "|");
2482 while (multiple.find("| ") != std::string::npos)
2483 multiple.replace(multiple.find("| "), 2, "|");
2484
2485 while (multiple.find('|') != std::string::npos)
2486 {
2487 different_values.push_back(
2488 prefix + std::string(multiple, 0, multiple.find('|')) + postfix);
2489 multiple.erase(0, multiple.find('|') + 1);
2490 }
2491 // make up the last selection ("while" broke
2492 // because there was no '|' any more
2493 different_values.push_back(prefix + multiple + postfix);
2494 // finally check whether this was a variant
2495 // entry ({...}) or an array ({{...}})
2496 if ((entry_value.find("{{") != std::string::npos) &&
2497 (entry_value.find("}}") != std::string::npos))
2498 type = Entry::array;
2499 else
2500 type = Entry::variant;
2501}
2502
2503
2504std::size_t
2513
void push(const std::string &text)
Definition logstream.cc:304
void pop()
Definition logstream.cc:318
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:40
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > first
Definition grid_out.cc:4629
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:743
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:694
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition utilities.cc:502
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition utilities.cc:748
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:463
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition utilities.cc:825
double string_to_double(const std::string &s)
Definition utilities.cc:646
std::string trim(const std::string &input)
Definition utilities.cc:521
int string_to_int(const std::string &s)
Definition utilities.cc:598
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)