Reference documentation for deal.II version 8.5.1
parameter_handler.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/parameter_handler.h>
18 #include <deal.II/base/logstream.h>
19 #include <deal.II/base/path_search.h>
20 #include <deal.II/base/memory_consumption.h>
21 #include <deal.II/base/utilities.h>
22 
23 DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
24 #include <boost/property_tree/ptree.hpp>
25 #include <boost/property_tree/xml_parser.hpp>
26 #include <boost/property_tree/json_parser.hpp>
27 DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
28 
29 #include <fstream>
30 #include <iostream>
31 #include <iomanip>
32 #include <cstdlib>
33 #include <algorithm>
34 #include <sstream>
35 #include <cctype>
36 #include <limits>
37 #include <cstring>
38 
39 
40 DEAL_II_NAMESPACE_OPEN
41 
42 
43 
44 //TODO[WB]: various functions here could be simplified by using namespace Utilities
45 
46 namespace Patterns
47 {
48 
49  namespace
50  {
57  bool has_only_whitespace (std::istream &in)
58  {
59  while (in)
60  {
61  char c;
62 
63  // skip if we've reached the end of
64  // the line
65  if (!(in >> c))
66  break;
67 
68  if ((c != ' ') && (c != '\t'))
69  return false;
70  }
71  return true;
72  }
73  }
74 
75 
76 
77  PatternBase *pattern_factory (const std::string &description)
78  {
79  PatternBase *p;
80 
81  p = Integer::create(description);
82  if (p != 0)
83  return p;
84 
85  p = Double::create(description);
86  if (p !=0 )
87  return p;
88 
89  p = Selection::create(description);
90  if (p !=0 )
91  return p;
92 
93  p = List::create(description);
94  if (p !=0 )
95  return p;
96 
97  p = MultipleSelection::create(description);
98  if (p !=0 )
99  return p;
100 
101  p = Bool::create(description);
102  if (p!=0 )
103  return p;
104 
105  p = Anything::create(description);
106  if (p !=0 )
107  return p;
108 
109  p = FileName::create(description);
110  if (p !=0 )
111  return p;
112 
113  p = DirectoryName::create(description);
114  if (p!=0 )
115  return p;
116 
117  Assert(false, ExcNotImplemented());
118 
119  return 0;
120  }
121 
122 
123 
125  {}
126 
127 
128  std::size_t
130  {
131  if (dynamic_cast<const Integer *>(this) != 0)
132  return sizeof(Integer);
133  else if (dynamic_cast<const Double *>(this) != 0)
134  return sizeof(Double);
135  else if (dynamic_cast<const Bool *>(this) != 0)
136  return sizeof(Bool);
137  else if (dynamic_cast<const Anything *>(this) != 0)
138  return sizeof(Anything);
139  else
140  return sizeof(*this) + 32;
141  }
142 
143 
144 
145  const int Integer::min_int_value = std::numeric_limits<int>::min();
146  const int Integer::max_int_value = std::numeric_limits<int>::max();
147 
148  const char *Integer::description_init = "[Integer";
149 
150  Integer::Integer (const int lower_bound,
151  const int upper_bound)
152  :
153  lower_bound (lower_bound),
154  upper_bound (upper_bound)
155  {}
156 
157 
158 
159  bool Integer::match (const std::string &test_string) const
160  {
161  std::istringstream str(test_string);
162 
163  int i;
164  if (!(str >> i))
165  return false;
166 
167  if (!has_only_whitespace (str))
168  return false;
169  // check whether valid bounds
170  // were specified, and if so
171  // enforce their values
172  if (lower_bound <= upper_bound)
173  return ((lower_bound <= i) &&
174  (upper_bound >= i));
175  else
176  return true;
177  }
178 
179 
180 
181  std::string Integer::description (const OutputStyle style) const
182  {
183  switch (style)
184  {
185  case Machine:
186  {
187  // check whether valid bounds
188  // were specified, and if so
189  // output their values
190  if (lower_bound <= upper_bound)
191  {
192  std::ostringstream description;
193 
195  <<" range "
196  << lower_bound << "..." << upper_bound
197  << " (inclusive)]";
198  return description.str();
199  }
200  else
201  // if no bounds were given, then
202  // return generic string
203  return "[Integer]";
204  }
205  case Text:
206  {
207  if (lower_bound <= upper_bound)
208  {
209  std::ostringstream description;
210 
211  description << "An integer n such that "
212  << lower_bound << " <= n <= " << upper_bound;
213 
214  return description.str();
215  }
216  else
217  return "An integer";
218  }
219  case LaTeX:
220  {
221  if (lower_bound <= upper_bound)
222  {
223  std::ostringstream description;
224 
225  description << "An integer @f$n@f$ such that @f$"
226  << lower_bound << "\\leq n \\leq " << upper_bound
227  << "@f$";
228 
229  return description.str();
230  }
231  else
232  return "An integer";
233  }
234  default:
235  AssertThrow(false, ExcNotImplemented());
236  }
237  // Should never occur without an exception, but prevent compiler from
238  // complaining
239  return "";
240  }
241 
242 
243 
244  PatternBase *
245  Integer::clone () const
246  {
247  return new Integer(lower_bound, upper_bound);
248  }
249 
250 
251 
252  Integer *Integer::create (const std::string &description)
253  {
254  if (description.compare(0, std::strlen(description_init), description_init) == 0)
255  {
256  std::istringstream is(description);
257 
258  if (is.str().size() > strlen(description_init) + 1)
259  {
260 //TODO: verify that description matches the pattern "^\[Integer range \d+\.\.\.\d+\]@f$"
262 
263  is.ignore(strlen(description_init) + strlen(" range "));
264 
265  if (!(is >> lower_bound))
266  return new Integer();
267 
268  is.ignore(strlen("..."));
269 
270  if (!(is >> upper_bound))
271  return new Integer();
272 
273  return new Integer(lower_bound, upper_bound);
274  }
275  else
276  return new Integer();
277  }
278  else
279  return 0;
280  }
281 
282 
283 
284  const double Double::min_double_value = -std::numeric_limits<double>::max();
285  const double Double::max_double_value = std::numeric_limits<double>::max();
286 
287  const char *Double::description_init = "[Double";
288 
289  Double::Double (const double lower_bound,
290  const double upper_bound)
291  :
292  lower_bound (lower_bound),
293  upper_bound (upper_bound)
294  {}
295 
296 
297 
298  bool Double::match (const std::string &test_string) const
299  {
300  std::istringstream str(test_string);
301 
302  double d;
303  if (!(str >> d))
304  return false;
305 
306  if (!has_only_whitespace (str))
307  return false;
308  // check whether valid bounds
309  // were specified, and if so
310  // enforce their values
311  if (lower_bound <= upper_bound)
312  return ((lower_bound <= d) &&
313  (upper_bound >= d));
314  else
315  return true;
316  }
317 
318 
319 
320  std::string Double::description (const OutputStyle style) const
321  {
322  switch (style)
323  {
324  case Machine:
325  {
326  std::ostringstream description;
327 
328  if (lower_bound <= upper_bound)
329  {
330  // bounds are valid
331  description << description_init << " ";
332  // We really want to compare with ==, but -Wfloat-equal would create
333  // a warning here, so work around it.
334  if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound)))
335  description << "-MAX_DOUBLE";
336  else
338  description << "...";
339  if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound)))
340  description << "MAX_DOUBLE";
341  else
343  description << " (inclusive)]";
344  return description.str();
345  }
346  else
347  {
348  // invalid bounds, assume unbounded double:
349  description << description_init << "]";
350  return description.str();
351  }
352  }
353  case Text:
354  {
355  if (lower_bound <= upper_bound)
356  {
357  std::ostringstream description;
358 
359  description << "A floating point number v such that ";
360  if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound)))
361  description << "-MAX_DOUBLE";
362  else
364  description << " <= v <= ";
365  if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound)))
366  description << "MAX_DOUBLE";
367  else
369 
370  return description.str();
371  }
372  else
373  return "A floating point number";
374  }
375  case LaTeX:
376  {
377  if (lower_bound <= upper_bound)
378  {
379  std::ostringstream description;
380 
381  description << "A floating point number @f$v@f$ such that @f$";
382  if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound)))
383  description << "-\\text{MAX\\_DOUBLE}";
384  else
386  description << " \\leq v \\leq ";
387  if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound)))
388  description << "\\text{MAX\\_DOUBLE}";
389  else
391  description << "@f$";
392 
393  return description.str();
394  }
395  else
396  return "A floating point number";
397  }
398  default:
399  AssertThrow(false, ExcNotImplemented());
400  }
401  // Should never occur without an exception, but prevent compiler from
402  // complaining
403  return "";
404  }
405 
406 
407  PatternBase *
408  Double::clone () const
409  {
410  return new Double(lower_bound, upper_bound);
411  }
412 
413 
414 
415  Double *Double::create (const std::string &description)
416  {
417  const std::string description_init_str = description_init;
418  if (description.compare(0, description_init_str.size(), description_init_str) != 0)
419  return NULL;
420  if (*description.rbegin() != ']')
421  return NULL;
422 
423  std::string temp = description.substr(description_init_str.size());
424  if (temp == "]")
425  return new Double(1.0, -1.0); // return an invalid range
426 
427  if (temp.find("...") != std::string::npos)
428  temp.replace(temp.find("..."), 3, " ");
429 
430  double lower_bound = min_double_value,
432 
433  std::istringstream is(temp);
434  if (0 == temp.compare(0, std::strlen(" -MAX_DOUBLE"), " -MAX_DOUBLE"))
435  is.ignore(std::strlen(" -MAX_DOUBLE"));
436  else
437  {
438  // parse lower bound and give up if not a double
439  if (!(is >> lower_bound))
440  return NULL;
441  }
442 
443  // ignore failure here and assume we got MAX_DOUBLE as upper bound:
444  is >> upper_bound;
445  if (is.fail())
447 
448  return new Double(lower_bound, upper_bound);
449  }
450 
451 
452 
453  const char *Selection::description_init = "[Selection";
454 
455 
456  Selection::Selection (const std::string &seq)
457  : sequence(seq)
458  {
459  while (sequence.find(" |") != std::string::npos)
460  sequence.replace (sequence.find(" |"), 2, "|");
461  while (sequence.find("| ") != std::string::npos)
462  sequence.replace (sequence.find("| "), 2, "|");
463  }
464 
465 
466 
467  bool Selection::match (const std::string &test_string) const
468  {
469  std::string tmp(sequence);
470 
471  // remove whitespace at beginning
472  while ((tmp.length() != 0) && (std::isspace (tmp[0])))
473  tmp.erase (0,1);
474 
475  // check the different possibilities
476  while (tmp.find('|') != std::string::npos)
477  {
478  if (test_string == std::string(tmp, 0, tmp.find('|')))
479  return true;
480 
481  tmp.erase (0, tmp.find('|')+1);
482  };
483 
484  //remove whitespace at the end
485  while ((tmp.length() != 0) && (std::isspace (*(tmp.end()-1))))
486  tmp.erase (tmp.end()-1);
487 
488  // check last choice, not finished by |
489  if (test_string == tmp)
490  return true;
491 
492  // not found
493  return false;
494  }
495 
496 
497 
498  std::string Selection::description (const OutputStyle style) const
499  {
500  switch (style)
501  {
502  case Machine:
503  {
504  std::ostringstream description;
505 
507  << " "
508  << sequence
509  << " ]";
510 
511  return description.str();
512  }
513  case Text:
514  case LaTeX:
515  {
516  std::ostringstream description;
517 
518  description << "Any one of "
520 
521  return description.str();
522  }
523  default:
524  AssertThrow(false, ExcNotImplemented());
525  }
526  // Should never occur without an exception, but prevent compiler from
527  // complaining
528  return "";
529  }
530 
531 
532 
533  PatternBase *
535  {
536  return new Selection(sequence);
537  }
538 
539 
540  std::size_t
542  {
543  return (sizeof(PatternBase) +
545  }
546 
547 
548 
549  Selection *Selection::create (const std::string &description)
550  {
551  if (description.compare(0, std::strlen(description_init), description_init) == 0)
552  {
553  std::string sequence(description);
554 
555  sequence.erase(0, std::strlen(description_init) + 1);
556  sequence.erase(sequence.length()-2, 2);
557 
558  return new Selection(sequence);
559  }
560  else
561  return 0;
562  }
563 
564 
565 
566  const unsigned int List::max_int_value
567  = std::numeric_limits<unsigned int>::max();
568 
569  const char *List::description_init = "[List";
570 
571 
573  const unsigned int min_elements,
574  const unsigned int max_elements,
575  const std::string &separator)
576  :
577  pattern (p.clone()),
578  min_elements (min_elements),
579  max_elements (max_elements),
580  separator (separator)
581  {
584  Assert (separator.size() > 0,
585  ExcMessage ("The separator must have a non-zero length."));
586  }
587 
588 
589 
591  {
592  delete pattern;
593  pattern = 0;
594  }
595 
596 
597 
598  bool List::match (const std::string &test_string_list) const
599  {
600  std::string tmp = test_string_list;
601  std::vector<std::string> split_list;
602 
603  // first split the input list
604  while (tmp.length() != 0)
605  {
606  std::string name;
607  name = tmp;
608 
609  if (name.find(separator) != std::string::npos)
610  {
611  name.erase (name.find(separator), std::string::npos);
612  tmp.erase (0, tmp.find(separator)+separator.size());
613  }
614  else
615  tmp = "";
616 
617  while ((name.length() != 0) &&
618  (std::isspace (name[0])))
619  name.erase (0,1);
620 
621  while (std::isspace (name[name.length()-1]))
622  name.erase (name.length()-1, 1);
623 
624  split_list.push_back (name);
625  }
626 
627  if ((split_list.size() < min_elements) ||
628  (split_list.size() > max_elements))
629  return false;
630 
631  // check the different possibilities
632  for (std::vector<std::string>::const_iterator
633  test_string = split_list.begin();
634  test_string != split_list.end(); ++test_string)
635  if (pattern->match (*test_string) == false)
636  return false;
637 
638  return true;
639  }
640 
641 
642 
643  std::string List::description (const OutputStyle style) const
644  {
645  switch (style)
646  {
647  case Machine:
648  {
649  std::ostringstream description;
650 
652  << " list of <" << pattern->description(style) << ">"
653  << " of length " << min_elements << "..." << max_elements
654  << " (inclusive)";
655  if (separator != ",")
656  description << " separated by <" << separator << ">";
657  description << "]";
658 
659  return description.str();
660  }
661  case Text:
662  case LaTeX:
663  {
664  std::ostringstream description;
665 
666  description << "A list of "
667  << min_elements << " to " << max_elements
668  << " elements ";
669  if (separator != ",")
670  description << "separated by <" << separator << "> ";
671  description << "where each element is ["
672  << pattern->description(style)
673  << "]";
674 
675  return description.str();
676  }
677  default:
678  AssertThrow(false, ExcNotImplemented());
679  }
680  // Should never occur without an exception, but prevent compiler from
681  // complaining
682  return "";
683  }
684 
685 
686 
687  PatternBase *
688  List::clone () const
689  {
691  }
692 
693 
694  std::size_t
696  {
697  return (sizeof(*this) +
700  }
701 
702 
703 
704  List *List::create (const std::string &description)
705  {
706  if (description.compare(0, std::strlen(description_init), description_init) == 0)
707  {
709 
710  std::istringstream is(description);
711  is.ignore(strlen(description_init) + strlen(" list of <"));
712 
713  std::string str;
714  std::getline(is, str, '>');
715 
716  std_cxx11::shared_ptr<PatternBase> base_pattern (pattern_factory(str));
717 
718  is.ignore(strlen(" of length "));
719  if (!(is >> min_elements))
720  return new List(*base_pattern);
721 
722  is.ignore(strlen("..."));
723  if (!(is >> max_elements))
724  return new List(*base_pattern, min_elements);
725 
726  is.ignore(strlen(" separated by <"));
727  std::string separator;
728  if (!is)
729  std::getline(is, separator, '>');
730  else
731  separator = ",";
732 
733  return new List(*base_pattern, min_elements, max_elements, separator);
734  }
735  else
736  return 0;
737  }
738 
739 
740 
741  const unsigned int Map::max_int_value
742  = std::numeric_limits<unsigned int>::max();
743 
744  const char *Map::description_init = "[Map";
745 
746 
747  Map::Map (const PatternBase &p_key,
748  const PatternBase &p_value,
749  const unsigned int min_elements,
750  const unsigned int max_elements,
751  const std::string &separator)
752  :
753  key_pattern (p_key.clone()),
754  value_pattern (p_value.clone()),
755  min_elements (min_elements),
756  max_elements (max_elements),
757  separator (separator)
758  {
761  Assert (separator.size() > 0,
762  ExcMessage ("The separator must have a non-zero length."));
763  Assert (separator != ":",
764  ExcMessage ("The separator can not be a colon ':' since that "
765  "is the separator between the two elements of <key:value> pairs"));
766  }
767 
768 
769 
771  {
772  delete key_pattern;
773  key_pattern = 0;
774 
775  delete value_pattern;
776  value_pattern = 0;
777  }
778 
779 
780 
781  bool Map::match (const std::string &test_string_list) const
782  {
783  std::string tmp = test_string_list;
784  std::vector<std::string> split_list;
785 
786  // first split the input list at comma sites
787  while (tmp.length() != 0)
788  {
789  std::string map_entry;
790  map_entry = tmp;
791 
792  if (map_entry.find(separator) != std::string::npos)
793  {
794  map_entry.erase (map_entry.find(separator), std::string::npos);
795  tmp.erase (0, tmp.find(separator)+separator.size());
796  }
797  else
798  tmp = "";
799 
800  while ((map_entry.length() != 0) &&
801  (std::isspace (map_entry[0])))
802  map_entry.erase (0,1);
803 
804  while (std::isspace (map_entry[map_entry.length()-1]))
805  map_entry.erase (map_entry.length()-1, 1);
806 
807  split_list.push_back (map_entry);
808  }
809 
810  if ((split_list.size() < min_elements) ||
811  (split_list.size() > max_elements))
812  return false;
813 
814  // check the different possibilities
815  for (std::vector<std::string>::const_iterator
816  test_string = split_list.begin();
817  test_string != split_list.end(); ++test_string)
818  {
819  // separate key and value from the test_string
820  if (test_string->find(":") == std::string::npos)
821  return false;
822 
823  // we know now that there is a ':', so split the string there
824  // and trim spaces
825  std::string key = *test_string;
826  key.erase (key.find(":"), std::string::npos);
827  while ((key.length() > 0) && (std::isspace (key[key.length()-1])))
828  key.erase (key.length()-1, 1);
829 
830  std::string value = *test_string;
831  value.erase (0, value.find(":")+1);
832  while ((value.length() > 0) && (std::isspace (value[0])))
833  value.erase (0, 1);
834 
835  // then verify that the patterns are satisfied
836  if (key_pattern->match (key) == false)
837  return false;
838  if (value_pattern->match (value) == false)
839  return false;
840  }
841 
842  return true;
843  }
844 
845 
846 
847  std::string Map::description (const OutputStyle style) const
848  {
849  switch (style)
850  {
851  case Machine:
852  {
853  std::ostringstream description;
854 
856  << " map of <"
857  << key_pattern->description(style) << ":"
858  << value_pattern->description(style) << ">"
859  << " of length " << min_elements << "..." << max_elements
860  << " (inclusive)";
861  if (separator != ",")
862  description << " separated by <" << separator << ">";
863  description << "]";
864 
865  return description.str();
866  }
867  case Text:
868  case LaTeX:
869  {
870  std::ostringstream description;
871 
872  description << "A key-value map of "
873  << min_elements << " to " << max_elements
874  << " elements ";
875  if (separator != ",")
876  description << " separated by <" << separator << "> ";
877  description << " where each key is ["
878  << key_pattern->description(style)
879  << "]"
880  << " and each value is ["
881  << value_pattern->description(style)
882  << "]";
883 
884  return description.str();
885  }
886  default:
887  AssertThrow(false, ExcNotImplemented());
888  }
889  // Should never occur without an exception, but prevent compiler from
890  // complaining
891  return "";
892  }
893 
894 
895 
896  PatternBase *
897  Map::clone () const
898  {
899  return new Map(*key_pattern, *value_pattern,
901  separator);
902  }
903 
904 
905  std::size_t
907  {
908  return (sizeof(*this) +
910  MemoryConsumption::memory_consumption (*value_pattern) +
912  }
913 
914 
915 
916  Map *Map::create (const std::string &description)
917  {
918  if (description.compare(0, std::strlen(description_init), description_init) == 0)
919  {
921 
922  std::istringstream is(description);
923  is.ignore(strlen(description_init) + strlen(" map of <"));
924 
925  std::string str;
926  std::getline(is, str, '>');
927 
928  // split 'str' into key and value
929  std::string key = str;
930  key.erase (key.find(":"), std::string::npos);
931 
932  std::string value = str;
933  value.erase (0, value.find(":")+1);
934 
935  std_cxx11::shared_ptr<PatternBase> key_pattern (pattern_factory(key));
936  std_cxx11::shared_ptr<PatternBase> value_pattern (pattern_factory(value));
937 
938  is.ignore(strlen(" of length "));
939  if (!(is >> min_elements))
940  return new Map(*key_pattern, *value_pattern);
941 
942  is.ignore(strlen("..."));
943  if (!(is >> max_elements))
944  return new Map(*key_pattern, *value_pattern, min_elements);
945 
946  is.ignore(strlen(" separated by <"));
947  std::string separator;
948  if (!is)
949  std::getline(is, separator, '>');
950  else
951  separator = ",";
952 
953  return new Map(*key_pattern, *value_pattern,
955  separator);
956  }
957  else
958  return 0;
959  }
960 
961 
962 
963  const char *MultipleSelection::description_init = "[MultipleSelection";
964 
965 
966  MultipleSelection::MultipleSelection (const std::string &seq)
967  {
968  Assert (seq.find (",") == std::string::npos, ExcCommasNotAllowed(seq.find(",")));
969 
970  sequence = seq;
971  while (sequence.find(" |") != std::string::npos)
972  sequence.replace (sequence.find(" |"), 2, "|");
973  while (sequence.find("| ") != std::string::npos)
974  sequence.replace (sequence.find("| "), 2, "|");
975  }
976 
977 
978 
979  bool MultipleSelection::match (const std::string &test_string_list) const
980  {
981  std::string tmp = test_string_list;
982  std::vector<std::string> split_names;
983 
984  // first split the input list
985  while (tmp.length() != 0)
986  {
987  std::string name;
988  name = tmp;
989 
990  if (name.find(",") != std::string::npos)
991  {
992  name.erase (name.find(","), std::string::npos);
993  tmp.erase (0, tmp.find(",")+1);
994  }
995  else
996  tmp = "";
997 
998  while ((name.length() != 0) &&
999  (std::isspace (name[0])))
1000  name.erase (0,1);
1001  while (std::isspace (name[name.length()-1]))
1002  name.erase (name.length()-1, 1);
1003 
1004  split_names.push_back (name);
1005  };
1006 
1007 
1008  // check the different possibilities
1009  for (std::vector<std::string>::const_iterator test_string = split_names.begin();
1010  test_string != split_names.end(); ++test_string)
1011  {
1012  bool string_found = false;
1013 
1014  tmp = sequence;
1015  while (tmp.find('|') != std::string::npos)
1016  {
1017  if (*test_string == std::string(tmp, 0, tmp.find('|')))
1018  {
1019  // string found, quit
1020  // loop. don't change
1021  // tmp, since we don't
1022  // need it anymore.
1023  string_found = true;
1024  break;
1025  };
1026 
1027  tmp.erase (0, tmp.find('|')+1);
1028  };
1029  // check last choice, not finished by |
1030  if (!string_found)
1031  if (*test_string == tmp)
1032  string_found = true;
1033 
1034  if (!string_found)
1035  return false;
1036  };
1037 
1038  return true;
1039  }
1040 
1041 
1042 
1043  std::string MultipleSelection::description (const OutputStyle style) const
1044  {
1045  switch (style)
1046  {
1047  case Machine:
1048  {
1049  std::ostringstream description;
1050 
1052  << " "
1053  << sequence
1054  << " ]";
1055 
1056  return description.str();
1057  }
1058  case Text:
1059  case LaTeX:
1060  {
1061  std::ostringstream description;
1062 
1063  description << "A comma-separated list of any of "
1065 
1066  return description.str();
1067  }
1068  default:
1069  AssertThrow(false, ExcNotImplemented());
1070  }
1071  // Should never occur without an exception, but prevent compiler from
1072  // complaining
1073  return "";
1074  }
1075 
1076 
1077 
1078  PatternBase *
1080  {
1081  return new MultipleSelection(sequence);
1082  }
1083 
1084 
1085  std::size_t
1087  {
1088  return (sizeof(PatternBase) +
1090  }
1091 
1092 
1093 
1094  MultipleSelection *MultipleSelection::create (const std::string &description)
1095  {
1096  if (description.compare(0, std::strlen(description_init), description_init) == 0)
1097  {
1098  std::string sequence(description);
1099 
1100  sequence.erase(0, std::strlen(description_init) + 1);
1101  sequence.erase(sequence.length()-2, 2);
1102 
1103  return new MultipleSelection(sequence);
1104  }
1105  else
1106  return 0;
1107  }
1108 
1109 
1110 
1111  const char *Bool::description_init = "[Bool";
1112 
1113 
1115  :
1116  Selection ("true|false")
1117  {}
1118 
1119 
1120 
1121  std::string Bool::description (const OutputStyle style) const
1122  {
1123  switch (style)
1124  {
1125  case Machine:
1126  {
1127  std::ostringstream description;
1128 
1130  << "]";
1131 
1132  return description.str();
1133  }
1134  case Text:
1135  case LaTeX:
1136  {
1137  return "A boolean value (true or false)";
1138  }
1139  default:
1140  AssertThrow(false, ExcNotImplemented());
1141  }
1142  // Should never occur without an exception, but prevent compiler from
1143  // complaining
1144  return "";
1145  }
1146 
1147 
1148 
1149  PatternBase *
1150  Bool::clone () const
1151  {
1152  return new Bool();
1153  }
1154 
1155 
1156 
1157  Bool *Bool::create (const std::string &description)
1158  {
1159  if (description.compare(0, std::strlen(description_init), description_init) == 0)
1160  return new Bool();
1161  else
1162  return 0;
1163  }
1164 
1165 
1166 
1167  const char *Anything::description_init = "[Anything";
1168 
1169 
1171  {}
1172 
1173 
1174 
1175  bool Anything::match (const std::string &) const
1176  {
1177  return true;
1178  }
1179 
1180 
1181 
1182  std::string Anything::description (const OutputStyle style) const
1183  {
1184  switch (style)
1185  {
1186  case Machine:
1187  {
1188  std::ostringstream description;
1189 
1191  << "]";
1192 
1193  return description.str();
1194  }
1195  case Text:
1196  case LaTeX:
1197  {
1198  return "Any string";
1199  }
1200  default:
1201  AssertThrow(false, ExcNotImplemented());
1202  }
1203  // Should never occur without an exception, but prevent compiler from
1204  // complaining
1205  return "";
1206  }
1207 
1208 
1209 
1210  PatternBase *
1212  {
1213  return new Anything();
1214  }
1215 
1216 
1217 
1218  Anything *Anything::create (const std::string &description)
1219  {
1220  if (description.compare(0, std::strlen(description_init), description_init) == 0)
1221  return new Anything();
1222  else
1223  return 0;
1224  }
1225 
1226 
1227 
1228  const char *FileName::description_init = "[FileName";
1229 
1230 
1232  : file_type (type)
1233  {}
1234 
1235 
1236 
1237  bool FileName::match (const std::string &) const
1238  {
1239  return true;
1240  }
1241 
1242 
1243 
1244  std::string FileName::description (const OutputStyle style) const
1245  {
1246  switch (style)
1247  {
1248  case Machine:
1249  {
1250  std::ostringstream description;
1251 
1253 
1254  if (file_type == input)
1255  description << " (Type: input)]";
1256  else
1257  description << " (Type: output)]";
1258 
1259  return description.str();
1260  }
1261  case Text:
1262  case LaTeX:
1263  {
1264  if (file_type == input)
1265  return "an input filename";
1266  else
1267  return "an output filename";
1268  }
1269  default:
1270  AssertThrow(false, ExcNotImplemented());
1271  }
1272  // Should never occur without an exception, but prevent compiler from
1273  // complaining
1274  return "";
1275  }
1276 
1277 
1278 
1279  PatternBase *
1281  {
1282  return new FileName(file_type);
1283  }
1284 
1285 
1286 
1287  FileName *FileName::create (const std::string &description)
1288  {
1289  if (description.compare(0, std::strlen(description_init), description_init) == 0)
1290  {
1291  std::istringstream is(description);
1292  std::string file_type;
1293  FileType type;
1294 
1295  is.ignore(strlen(description_init) + strlen(" (Type:"));
1296 
1297  is >> file_type;
1298 
1299  if (file_type == "input)]")
1300  type = input;
1301  else
1302  type = output;
1303 
1304  return new FileName(type);
1305  }
1306  else
1307  return 0;
1308  }
1309 
1310 
1311 
1312  const char *DirectoryName::description_init = "[DirectoryName";
1313 
1314 
1316  {}
1317 
1318 
1319 
1320  bool DirectoryName::match (const std::string &) const
1321  {
1322  return true;
1323  }
1324 
1325 
1326 
1327  std::string DirectoryName::description (const OutputStyle style) const
1328  {
1329  switch (style)
1330  {
1331  case Machine:
1332  {
1333  std::ostringstream description;
1334 
1335  description << description_init << "]";
1336 
1337  return description.str();
1338  }
1339  case Text:
1340  case LaTeX:
1341  {
1342  return "A directory name";
1343  }
1344  default:
1345  AssertThrow(false, ExcNotImplemented());
1346  }
1347  // Should never occur without an exception, but prevent compiler from
1348  // complaining
1349  return "";
1350  }
1351 
1352 
1353 
1354  PatternBase *
1356  {
1357  return new DirectoryName();
1358  }
1359 
1360 
1361 
1362  DirectoryName *DirectoryName::create (const std::string &description)
1363  {
1364  if (description.compare(0, std::strlen(description_init), description_init) == 0)
1365  return new DirectoryName();
1366  else
1367  return 0;
1368  }
1369 
1370 } // end namespace Patterns
1371 
1372 
1373 
1375  :
1376  entries (new boost::property_tree::ptree())
1377 {}
1378 
1379 
1380 
1382 {}
1383 
1384 
1385 
1386 std::string
1387 ParameterHandler::mangle (const std::string &s)
1388 {
1389  std::string u;
1390 
1391  // reserve the minimum number of characters we will need. it may
1392  // be more but this is the least we can do
1393  u.reserve (s.size());
1394 
1395  // see if the name is special and if so mangle the whole thing
1396  const bool mangle_whole_string = (s == "value");
1397 
1398  // for all parts of the string, see
1399  // if it is an allowed character or
1400  // not
1401  for (unsigned int i=0; i<s.size(); ++i)
1402  {
1403  static const std::string allowed_characters
1404  ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
1405 
1406  if ((! mangle_whole_string)
1407  &&
1408  (allowed_characters.find (s[i]) != std::string::npos))
1409  u.push_back (s[i]);
1410  else
1411  {
1412  u.push_back ('_');
1413  static const char hex[16]
1414  = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
1415  u.push_back (hex[static_cast<unsigned char>(s[i])/16]);
1416  u.push_back (hex[static_cast<unsigned char>(s[i])%16]);
1417  }
1418  }
1419 
1420  return u;
1421 }
1422 
1423 
1424 
1425 std::string
1426 ParameterHandler::demangle (const std::string &s)
1427 {
1428  std::string u;
1429  u.reserve (s.size());
1430 
1431  for (unsigned int i=0; i<s.size(); ++i)
1432  if (s[i] != '_')
1433  u.push_back (s[i]);
1434  else
1435  {
1436  Assert (i+2 < s.size(),
1437  ExcMessage ("Trying to demangle an invalid string."));
1438 
1439  unsigned char c = 0;
1440  switch (s[i+1])
1441  {
1442  case '0':
1443  c = 0 * 16;
1444  break;
1445  case '1':
1446  c = 1 * 16;
1447  break;
1448  case '2':
1449  c = 2 * 16;
1450  break;
1451  case '3':
1452  c = 3 * 16;
1453  break;
1454  case '4':
1455  c = 4 * 16;
1456  break;
1457  case '5':
1458  c = 5 * 16;
1459  break;
1460  case '6':
1461  c = 6 * 16;
1462  break;
1463  case '7':
1464  c = 7 * 16;
1465  break;
1466  case '8':
1467  c = 8 * 16;
1468  break;
1469  case '9':
1470  c = 9 * 16;
1471  break;
1472  case 'a':
1473  c = 10 * 16;
1474  break;
1475  case 'b':
1476  c = 11 * 16;
1477  break;
1478  case 'c':
1479  c = 12 * 16;
1480  break;
1481  case 'd':
1482  c = 13 * 16;
1483  break;
1484  case 'e':
1485  c = 14 * 16;
1486  break;
1487  case 'f':
1488  c = 15 * 16;
1489  break;
1490  default:
1491  Assert (false, ExcInternalError());
1492  }
1493  switch (s[i+2])
1494  {
1495  case '0':
1496  c += 0;
1497  break;
1498  case '1':
1499  c += 1;
1500  break;
1501  case '2':
1502  c += 2;
1503  break;
1504  case '3':
1505  c += 3;
1506  break;
1507  case '4':
1508  c += 4;
1509  break;
1510  case '5':
1511  c += 5;
1512  break;
1513  case '6':
1514  c += 6;
1515  break;
1516  case '7':
1517  c += 7;
1518  break;
1519  case '8':
1520  c += 8;
1521  break;
1522  case '9':
1523  c += 9;
1524  break;
1525  case 'a':
1526  c += 10;
1527  break;
1528  case 'b':
1529  c += 11;
1530  break;
1531  case 'c':
1532  c += 12;
1533  break;
1534  case 'd':
1535  c += 13;
1536  break;
1537  case 'e':
1538  c += 14;
1539  break;
1540  case 'f':
1541  c += 15;
1542  break;
1543  default:
1544  Assert (false, ExcInternalError());
1545  }
1546 
1547  u.push_back (static_cast<char>(c));
1548 
1549  // skip the two characters
1550  i += 2;
1551  }
1552 
1553  return u;
1554 }
1555 
1556 
1557 
1558 namespace
1559 {
1564  bool
1565  is_parameter_node (const boost::property_tree::ptree &p)
1566  {
1567  return static_cast<bool>(p.get_optional<std::string>("value"));
1568  }
1569 
1570 
1575  bool
1576  is_alias_node (const boost::property_tree::ptree &p)
1577  {
1578  return static_cast<bool>(p.get_optional<std::string>("alias"));
1579  }
1580 }
1581 
1582 
1583 std::string
1585 {
1586  if (subsection_path.size() > 0)
1587  {
1588  std::string p = mangle(subsection_path[0]);
1589  for (unsigned int i=1; i<subsection_path.size(); ++i)
1590  {
1591  p += path_separator;
1592  p += mangle(subsection_path[i]);
1593  }
1594  return p;
1595  }
1596  else
1597  return "";
1598 }
1599 
1600 
1601 
1602 std::string
1603 ParameterHandler::get_current_full_path (const std::string &name) const
1604 {
1605  std::string path = get_current_path ();
1606  if (path.empty() == false)
1607  path += path_separator;
1608 
1609  path += mangle(name);
1610 
1611  return path;
1612 }
1613 
1614 
1615 
1616 bool ParameterHandler::read_input (std::istream &input,
1617  const std::string &filename,
1618  const std::string &last_line)
1619 {
1620  try
1621  {
1622  parse_input(input, filename, last_line);
1623  return true;
1624  }
1625  catch (const ExcIO &)
1626  {
1627  throw;
1628  }
1629  // This catch block more or less duplicates the old behavior of this function,
1630  // which was to print something to stderr for every parsing error (which are
1631  // now exceptions) and then return false.
1632  catch (const ExceptionBase &exc)
1633  {
1634  std::cerr << exc.what() << std::endl;
1635  }
1636  return false;
1637 }
1638 
1639 
1640 
1641 void ParameterHandler::parse_input (std::istream &input,
1642  const std::string &filename,
1643  const std::string &last_line)
1644 {
1645  AssertThrow (input, ExcIO());
1646 
1647  // store subsections we are currently in
1648  std::vector<std::string> saved_path = subsection_path;
1649 
1650  std::string input_line;
1651  std::string fully_concatenated_line;
1652  bool is_concatenated = false;
1653  // Maintain both the current line number and the current logical line
1654  // number, where the latter refers to the line number where (possibly) the
1655  // current line continuation started.
1656  unsigned int current_line_n = 0;
1657  unsigned int current_logical_line_n = 0;
1658 
1659  while (std::getline (input, input_line))
1660  {
1661  ++current_line_n;
1662  if (!is_concatenated)
1663  current_logical_line_n = current_line_n;
1664  // Trim the whitespace at the ends of the line here instead of in
1665  // scan_line. This makes the continuation line logic a lot simpler.
1666  input_line = Utilities::trim (input_line);
1667 
1668  // If we see the line which is the same as @p last_line ,
1669  // terminate the parsing.
1670  if (last_line.length() != 0 &&
1671  input_line == last_line)
1672  break;
1673 
1674  // Check whether or not the current line should be joined with the next
1675  // line before calling scan_line.
1676  if (input_line.length() != 0 &&
1677  input_line.find_last_of('\\') == input_line.length() - 1)
1678  {
1679  input_line.erase (input_line.length() - 1); // remove the last '\'
1680  is_concatenated = true;
1681 
1682  fully_concatenated_line += input_line;
1683  }
1684  // If the previous line ended in a '\' but the current did not, then we
1685  // should proceed to scan_line.
1686  else if (is_concatenated)
1687  {
1688  fully_concatenated_line += input_line;
1689  is_concatenated = false;
1690  }
1691  // Finally, if neither the previous nor current lines are continuations,
1692  // then the current input line is entirely concatenated.
1693  else
1694  {
1695  fully_concatenated_line = input_line;
1696  }
1697 
1698  if (!is_concatenated)
1699  {
1700  scan_line (fully_concatenated_line, filename, current_logical_line_n);
1701  fully_concatenated_line.clear();
1702  }
1703  }
1704 
1705  // While it does not make much sense for anyone to actually do this, allow
1706  // the last line to end in a backslash.
1707  if (is_concatenated)
1708  {
1709  scan_line (fully_concatenated_line, filename, current_line_n);
1710  }
1711 
1712  if (saved_path != subsection_path)
1713  {
1714  std::stringstream paths_message;
1715  if (saved_path.size() > 0)
1716  {
1717  paths_message << "Path before loading input:\n";
1718  for (unsigned int i=0; i < subsection_path.size(); ++i)
1719  {
1720  paths_message << std::setw(i*2 + 4)
1721  << " "
1722  << "subsection "
1723  << saved_path[i]
1724  << '\n';
1725  }
1726  paths_message << "Current path:\n";
1727  for (unsigned int i=0; i < subsection_path.size(); ++i)
1728  {
1729  paths_message << std::setw(i*2 + 4)
1730  << " "
1731  << "subsection "
1732  << subsection_path[i]
1733  << (i == subsection_path.size() - 1 ? "" : "\n");
1734  }
1735  }
1736  // restore subsection we started with before throwing the exception:
1737  subsection_path = saved_path;
1738  AssertThrow (false, ExcUnbalancedSubsections (filename, paths_message.str()));
1739  }
1740 }
1741 
1742 
1743 
1744 bool ParameterHandler::read_input (const std::string &filename,
1745  const bool optional,
1746  const bool write_compact,
1747  const std::string &last_line)
1748 {
1749  PathSearch search("PARAMETERS");
1750 
1751  try
1752  {
1753  std::string openname = search.find(filename);
1754  std::ifstream file_stream (openname.c_str());
1755  AssertThrow(file_stream, ExcIO());
1756 
1757  return read_input (file_stream, filename, last_line);
1758  }
1759  catch (const PathSearch::ExcFileNotFound &)
1760  {
1761  std::cerr << "ParameterHandler::read_input: could not open file <"
1762  << filename << "> for reading." << std::endl;
1763  if (!optional)
1764  {
1765  std::cerr << "Trying to make file <"
1766  << filename << "> with default values for you." << std::endl;
1767  std::ofstream output (filename.c_str());
1768  if (output)
1769  print_parameters (output, (write_compact ? ShortText : Text));
1770  }
1771  }
1772  return false;
1773 }
1774 
1775 
1776 
1777 void ParameterHandler::parse_input (const std::string &filename,
1778  const std::string &last_line)
1779 {
1780  PathSearch search("PARAMETERS");
1781 
1782  std::string openname = search.find(filename);
1783  std::ifstream file_stream (openname.c_str());
1784  parse_input (file_stream, filename, last_line);
1785 }
1786 
1787 
1788 
1789 bool
1791  const std::string &last_line)
1792 {
1793  try
1794  {
1795  parse_input_from_string (s, last_line);
1796  return true;
1797  }
1798  catch (const ExcIO &)
1799  {
1800  throw;
1801  }
1802  // This catch block more or less duplicates the old behavior of this function,
1803  // which was to print something to stderr for every parsing error (which are
1804  // now exceptions) and then return false.
1805  catch (const ExceptionBase &exc)
1806  {
1807  std::cerr << exc.what() << std::endl;
1808  }
1809  return false;
1810 }
1811 
1812 
1813 
1814 void
1816  const std::string &last_line)
1817 {
1818  std::istringstream input_stream (s);
1819  parse_input (input_stream, "input string", last_line);
1820 }
1821 
1822 
1823 
1824 namespace
1825 {
1826  // Recursively go through the 'source' tree and see if we can find
1827  // corresponding entries in the 'destination' tree. If not, error out
1828  // (i.e. we have just read an XML file that has entries that weren't
1829  // declared in the ParameterHandler object); if so, copy the value of these
1830  // nodes into the destination object
1831  void
1832  read_xml_recursively (const boost::property_tree::ptree &source,
1833  const std::string &current_path,
1834  const char path_separator,
1835  const std::vector<std_cxx11::shared_ptr<const Patterns::PatternBase> > &
1836  patterns,
1837  boost::property_tree::ptree &destination)
1838  {
1839  for (boost::property_tree::ptree::const_iterator p = source.begin();
1840  p != source.end(); ++p)
1841  {
1842  // a sub-tree must either be a parameter node or a subsection
1843  if (p->second.get_optional<std::string>("value"))
1844  {
1845  // make sure we have a corresponding entry in the destination
1846  // object as well
1847  const std::string full_path
1848  = (current_path == ""
1849  ?
1850  p->first
1851  :
1852  current_path + path_separator + p->first);
1853 
1854  const std::string new_value
1855  = p->second.get<std::string>("value");
1856  AssertThrow (destination.get_optional<std::string> (full_path)
1857  &&
1858  destination.get_optional<std::string>
1859  (full_path + path_separator + "value"),
1861 
1862  // first make sure that the new entry actually satisfies its
1863  // constraints
1864  const unsigned int pattern_index
1865  = destination.get<unsigned int> (full_path +
1866  path_separator +
1867  "pattern");
1868  AssertThrow (patterns[pattern_index]->match(new_value),
1870  // XML entries sometimes have extra surrounding
1871  // newlines
1872  (Utilities::trim(new_value),
1873  p->first,
1874  patterns[pattern_index]->description()));
1875 
1876  // set the found parameter in the destination argument
1877  destination.put (full_path + path_separator + "value",
1878  new_value);
1879 
1880  // this node might have sub-nodes in addition to "value", such as
1881  // "default_value", "documentation", etc. we might at some point
1882  // in the future want to make sure that if they exist that they
1883  // match the ones in the 'destination' tree
1884  }
1885  else if (p->second.get_optional<std::string>("alias"))
1886  {
1887  // it is an alias node. alias nodes are static and there is
1888  // nothing to do here (but the same applies as mentioned in the
1889  // comment above about the static nodes inside parameter nodes
1890  }
1891  else
1892  {
1893  // it must be a subsection
1894  read_xml_recursively (p->second,
1895  (current_path == "" ?
1896  p->first :
1897  current_path + path_separator + p->first),
1898  path_separator,
1899  patterns,
1900  destination);
1901  }
1902  }
1903  }
1904 }
1905 
1906 
1907 
1909 {
1910  try
1911  {
1912  parse_input_from_xml (in);
1913  return true;
1914  }
1915  catch (const ExcIO &)
1916  {
1917  throw;
1918  }
1919  catch (const ExceptionBase &exc)
1920  {
1921  std::cerr << exc.what() << std::endl;
1922  }
1923  return false;
1924 }
1925 
1926 
1927 
1929 {
1930  AssertThrow(in, ExcIO());
1931  // read the XML tree assuming that (as we
1932  // do in print_parameters(XML) it has only
1933  // a single top-level node called
1934  // "ParameterHandler"
1935  boost::property_tree::ptree single_node_tree;
1936  // This boost function will raise an exception if this is not a valid XML
1937  // file.
1938  read_xml (in, single_node_tree);
1939 
1940  // make sure there is a single top-level element
1941  // called "ParameterHandler"
1942  AssertThrow (single_node_tree.get_optional<std::string>("ParameterHandler"),
1943  ExcInvalidXMLParameterFile ("There is no top-level XML element "
1944  "called \"ParameterHandler\"."));
1945 
1946  const std::size_t n_top_level_elements = std::distance (single_node_tree.begin(),
1947  single_node_tree.end());
1948  if (n_top_level_elements != 1)
1949  {
1950  std::ostringstream top_level_message;
1951  top_level_message << "The ParameterHandler input parser found "
1952  << n_top_level_elements
1953  << " top level elements while reading\n "
1954  << " an XML format input file, but there should be"
1955  << " exactly one top level element.\n"
1956  << " The top level elements are:\n";
1957 
1958  unsigned int entry_n = 0;
1959  for (boost::property_tree::ptree::iterator it = single_node_tree.begin();
1960  it != single_node_tree.end(); ++it, ++entry_n)
1961  {
1962  top_level_message << " "
1963  << it->first
1964  << (entry_n != n_top_level_elements - 1 ? "\n" : "");
1965  }
1966 
1967  // repeat assertion condition to make the printed version easier to read
1968  AssertThrow (n_top_level_elements == 1,
1969  ExcInvalidXMLParameterFile (top_level_message.str()));
1970  }
1971 
1972  // read the child elements recursively
1973  const boost::property_tree::ptree
1974  &my_entries = single_node_tree.get_child("ParameterHandler");
1975 
1976  read_xml_recursively (my_entries, "", path_separator, patterns, *entries);
1977 }
1978 
1979 
1980 
1982 {
1983  entries.reset (new boost::property_tree::ptree());
1984 }
1985 
1986 
1987 
1988 void
1989 ParameterHandler::declare_entry (const std::string &entry,
1990  const std::string &default_value,
1991  const Patterns::PatternBase &pattern,
1992  const std::string &documentation)
1993 {
1994  entries->put (get_current_full_path(entry) + path_separator + "value",
1995  default_value);
1996  entries->put (get_current_full_path(entry) + path_separator + "default_value",
1997  default_value);
1998  entries->put (get_current_full_path(entry) + path_separator + "documentation",
1999  documentation);
2000 
2001  // clone the pattern and store its
2002  // index in the node
2003  patterns.push_back (std_cxx11::shared_ptr<const Patterns::PatternBase>
2004  (pattern.clone()));
2005  entries->put (get_current_full_path(entry) + path_separator + "pattern",
2006  static_cast<unsigned int>(patterns.size()-1));
2007  // also store the description of
2008  // the pattern. we do so because we
2009  // may wish to export the whole
2010  // thing as XML or any other format
2011  // so that external tools can work
2012  // on the parameter file; in that
2013  // case, they will have to be able
2014  // to re-create the patterns as far
2015  // as possible
2017  "pattern_description",
2018  patterns.back()->description());
2019 
2020  // as documented, do the default value checking at the very end
2021  AssertThrow (pattern.match (default_value),
2022  ExcValueDoesNotMatchPattern (default_value, pattern.description()));
2023 }
2024 
2025 
2026 
2027 void
2028 ParameterHandler::declare_alias(const std::string &existing_entry_name,
2029  const std::string &alias_name,
2030  const bool alias_is_deprecated)
2031 {
2032  // see if there is anything to refer to already
2033  Assert (entries->get_optional<std::string>(get_current_full_path(existing_entry_name)),
2034  ExcMessage ("You are trying to declare an alias entry <"
2035  + alias_name +
2036  "> that references an entry <"
2037  + existing_entry_name +
2038  ">, but the latter does not exist."));
2039  // then also make sure that what is being referred to is in
2040  // fact a parameter (not an alias or subsection)
2041  Assert (entries->get_optional<std::string>(get_current_full_path(existing_entry_name) + path_separator + "value"),
2042  ExcMessage ("You are trying to declare an alias entry <"
2043  + alias_name +
2044  "> that references an entry <"
2045  + existing_entry_name +
2046  ">, but the latter does not seem to be a "
2047  "parameter declaration."));
2048 
2049 
2050  // now also make sure that if the alias has already been
2051  // declared, that it is also an alias and refers to the same
2052  // entry
2053  if (entries->get_optional<std::string>(get_current_full_path(alias_name)))
2054  {
2055  Assert (entries->get_optional<std::string> (get_current_full_path(alias_name) + path_separator + "alias"),
2056  ExcMessage ("You are trying to declare an alias entry <"
2057  + alias_name +
2058  "> but a non-alias entry already exists in this "
2059  "subsection (i.e., there is either a preexisting "
2060  "further subsection, or a parameter entry, with "
2061  "the same name as the alias)."));
2062  Assert (entries->get<std::string> (get_current_full_path(alias_name) + path_separator + "alias")
2063  ==
2064  existing_entry_name,
2065  ExcMessage ("You are trying to declare an alias entry <"
2066  + alias_name +
2067  "> but an alias entry already exists in this "
2068  "subsection and this existing alias references a "
2069  "different parameter entry. Specifically, "
2070  "you are trying to reference the entry <"
2071  + existing_entry_name +
2072  "> whereas the existing alias references "
2073  "the entry <"
2074  + entries->get<std::string> (get_current_full_path(alias_name) + path_separator + "alias") +
2075  ">."));
2076  }
2077 
2078  entries->put (get_current_full_path(alias_name) + path_separator + "alias",
2079  existing_entry_name);
2080  entries->put (get_current_full_path(alias_name) + path_separator + "deprecation_status",
2081  (alias_is_deprecated ? "true" : "false"));
2082 }
2083 
2084 
2085 
2086 void ParameterHandler::enter_subsection (const std::string &subsection)
2087 {
2088  // if necessary create subsection
2089  if (!entries->get_child_optional (get_current_full_path(subsection)))
2090  entries->add_child (get_current_full_path(subsection),
2091  boost::property_tree::ptree());
2092 
2093  // then enter it
2094  subsection_path.push_back (subsection);
2095 }
2096 
2097 
2098 
2100 {
2101  // assert there is a subsection that
2102  // we may leave
2103  Assert (subsection_path.size() != 0, ExcAlreadyAtTopLevel());
2104 
2105  if (subsection_path.size() > 0)
2106  subsection_path.pop_back ();
2107 }
2108 
2109 
2110 
2111 std::string
2112 ParameterHandler::get (const std::string &entry_string) const
2113 {
2114  // assert that the entry is indeed
2115  // declared
2116  if (boost::optional<std::string> value
2117  = entries->get_optional<std::string> (get_current_full_path(entry_string) + path_separator + "value"))
2118  return value.get();
2119  else
2120  {
2121  Assert (false, ExcEntryUndeclared(entry_string));
2122  return "";
2123  }
2124 }
2125 
2126 
2127 
2128 long int ParameterHandler::get_integer (const std::string &entry_string) const
2129 {
2130  try
2131  {
2132  return Utilities::string_to_int (get (entry_string));
2133  }
2134  catch (...)
2135  {
2136  AssertThrow (false,
2137  ExcMessage("Can't convert the parameter value <"
2138  + get(entry_string) +
2139  "> for entry <"
2140  + entry_string +
2141  " to an integer."));
2142  return 0;
2143  }
2144 }
2145 
2146 
2147 
2148 double ParameterHandler::get_double (const std::string &entry_string) const
2149 {
2150  try
2151  {
2152  return Utilities::string_to_double (get (entry_string));
2153  }
2154  catch (...)
2155  {
2156  AssertThrow (false,
2157  ExcMessage("Can't convert the parameter value <"
2158  + get(entry_string) +
2159  "> for entry <"
2160  + entry_string +
2161  " to a double precision variable."));
2162  return 0;
2163  }
2164 }
2165 
2166 
2167 
2168 bool ParameterHandler::get_bool (const std::string &entry_string) const
2169 {
2170  const std::string s = get(entry_string);
2171 
2172  AssertThrow ((s=="true") || (s=="false") ||
2173  (s=="yes") || (s=="no"),
2174  ExcMessage("Can't convert the parameter value <"
2175  + get(entry_string) +
2176  "> for entry <"
2177  + entry_string +
2178  " to a boolean."));
2179  if (s=="true" || s=="yes")
2180  return true;
2181  else
2182  return false;
2183 }
2184 
2185 
2186 
2187 void
2188 ParameterHandler::set (const std::string &entry_string,
2189  const std::string &new_value)
2190 {
2191  // resolve aliases before looking up the correct entry
2192  std::string path = get_current_full_path(entry_string);
2193  if (entries->get_optional<std::string>(path + path_separator + "alias"))
2194  path = get_current_full_path(entries->get<std::string>(path + path_separator + "alias"));
2195 
2196  // assert that the entry is indeed declared
2197  if (entries->get_optional<std::string>(path + path_separator + "value"))
2198  {
2199  const unsigned int pattern_index
2200  = entries->get<unsigned int> (path + path_separator + "pattern");
2201  AssertThrow (patterns[pattern_index]->match(new_value),
2202  ExcValueDoesNotMatchPattern (new_value,
2203  entries->get<std::string>
2204  (path +
2205  path_separator +
2206  "pattern_description")));
2207 
2208  entries->put (path + path_separator + "value",
2209  new_value);
2210  }
2211  else
2212  AssertThrow (false, ExcEntryUndeclared(entry_string));
2213 }
2214 
2215 
2216 void
2217 ParameterHandler::set (const std::string &entry_string,
2218  const char *new_value)
2219 {
2220  // simply forward
2221  set (entry_string, std::string(new_value));
2222 }
2223 
2224 
2225 void
2226 ParameterHandler::set (const std::string &entry_string,
2227  const double &new_value)
2228 {
2229  std::ostringstream s;
2230  s << std::setprecision(16);
2231  s << new_value;
2232 
2233  // hand this off to the function that
2234  // actually sets the value as a string
2235  set (entry_string, s.str());
2236 }
2237 
2238 
2239 
2240 void
2241 ParameterHandler::set (const std::string &entry_string,
2242  const long int &new_value)
2243 {
2244  std::ostringstream s;
2245  s << new_value;
2246 
2247  // hand this off to the function that
2248  // actually sets the value as a string
2249  set (entry_string, s.str());
2250 }
2251 
2252 
2253 
2254 void
2255 ParameterHandler::set (const std::string &entry_string,
2256  const bool &new_value)
2257 {
2258  // hand this off to the function that
2259  // actually sets the value as a string
2260  set (entry_string,
2261  (new_value ? "true" : "false"));
2262 }
2263 
2264 
2265 
2266 std::ostream &
2268  const OutputStyle style)
2269 {
2270  AssertThrow (out, ExcIO());
2271 
2272  switch (style)
2273  {
2274  case XML:
2275  {
2276  // call the writer
2277  // function and exit as
2278  // there is nothing
2279  // further to do down in
2280  // this function
2281  //
2282  // XML has a requirement that
2283  // there can only be one
2284  // single top-level entry,
2285  // but we may have multiple
2286  // entries and sections. we
2287  // work around this by
2288  // creating a tree just for
2289  // this purpose with the
2290  // single top-level node
2291  // "ParameterHandler" and
2292  // assign the existing tree
2293  // under it
2294  boost::property_tree::ptree single_node_tree;
2295  single_node_tree.add_child("ParameterHandler",
2296  *entries);
2297 
2298  write_xml (out, single_node_tree);
2299  return out;
2300  }
2301 
2302 
2303  case JSON:
2304  // call the writer
2305  // function and exit as
2306  // there is nothing
2307  // further to do down in
2308  // this function
2309  write_json (out, *entries);
2310  return out;
2311 
2312  case Text:
2313  out << "# Listing of Parameters" << std::endl
2314  << "# ---------------------" << std::endl;
2315  break;
2316  case LaTeX:
2317  out << "\\subsection{Global parameters}" << std::endl;
2318  out << "\\label{parameters:global}" << std::endl;
2319  out << std::endl << std::endl;
2320  break;
2321  case Description:
2322  out << "Listing of Parameters:" << std::endl << std::endl;
2323  break;
2324  case ShortText:
2325  break;
2326  default:
2327  Assert (false, ExcNotImplemented());
2328  };
2329 
2330  // dive recursively into the subsections
2331  print_parameters_section (out, style, 0);
2332 
2333  switch (style)
2334  {
2335  case Text:
2336  case Description:
2337  case ShortText:
2338  break;
2339  case LaTeX:
2340  break;
2341  default:
2342  Assert (false, ExcNotImplemented());
2343  };
2344 
2345  return out;
2346 }
2347 
2348 
2349 
2350 // Print a section in the desired style. The styles are separated into
2351 // several verbosity classes depending on the higher bits.
2352 //
2353 // If bit 7 (128) is set, comments are not printed.
2354 // If bit 6 (64) is set, default values after change are not printed.
2355 void
2357  const OutputStyle style,
2358  const unsigned int indent_level,
2359  const bool include_top_level_elements)
2360 {
2361  AssertThrow (out, ExcIO());
2362 
2363  const boost::property_tree::ptree &current_section
2364  = entries->get_child (get_current_path());
2365 
2366  unsigned int overall_indent_level = indent_level;
2367 
2368  switch (style)
2369  {
2370  case XML:
2371  {
2372  if (include_top_level_elements)
2373  {
2374  // call the writer
2375  // function and exit as
2376  // there is nothing
2377  // further to do down in
2378  // this function
2379  //
2380  // XML has a requirement that
2381  // there can only be one
2382  // single top-level entry,
2383  // but a section has multiple
2384  // entries and sections. we
2385  // work around this by
2386  // creating a tree just for
2387  // this purpose with the
2388  // single top-level node
2389  // "ParameterHandler" and
2390  // assign the full path of
2391  // down to the current section
2392  // under it
2393  boost::property_tree::ptree single_node_tree;
2394 
2395  // if there is no subsection selected,
2396  // add the whole tree of entries,
2397  // otherwise add a root element
2398  // and the selected subsection under it
2399  if (subsection_path.size() == 0)
2400  {
2401  single_node_tree.add_child("ParameterHandler",
2402  *entries);
2403  }
2404  else
2405  {
2406  std::string path ("ParameterHandler");
2407 
2408  single_node_tree.add_child(path,
2409  boost::property_tree::ptree());
2410 
2411  path += path_separator + get_current_path ();
2412  single_node_tree.add_child (path, current_section);
2413  };
2414 
2415  write_xml (out, single_node_tree);
2416  }
2417  else
2418  Assert (false, ExcNotImplemented());
2419 
2420  break;
2421  }
2422  case Text:
2423  case ShortText:
2424  {
2425  // if there are top level elements to print, do it
2426  if (include_top_level_elements && (subsection_path.size() > 0))
2427  for (unsigned int i=0; i<subsection_path.size(); ++i)
2428  {
2429  out << std::setw(overall_indent_level*2) << ""
2430  << "subsection " << demangle (subsection_path[i]) << std::endl;
2431  overall_indent_level += 1;
2432  };
2433 
2434  // first find out the longest
2435  // entry name to be able to
2436  // align the equal signs
2437  //
2438  // to do this loop over all
2439  // nodes of the current tree,
2440  // select the parameter nodes
2441  // (and discard sub-tree
2442  // nodes) and take the
2443  // maximum of their lengths
2444  std::size_t longest_name = 0;
2445  for (boost::property_tree::ptree::const_iterator
2446  p = current_section.begin();
2447  p != current_section.end(); ++p)
2448  if (is_parameter_node (p->second) == true)
2449  longest_name = std::max (longest_name,
2450  demangle(p->first).length());
2451 
2452  // likewise find the longest
2453  // actual value string to
2454  // make sure we can align the
2455  // default and documentation
2456  // strings
2457  std::size_t longest_value = 0;
2458  for (boost::property_tree::ptree::const_iterator
2459  p = current_section.begin();
2460  p != current_section.end(); ++p)
2461  if (is_parameter_node (p->second) == true)
2462  longest_value = std::max (longest_value,
2463  p->second.get<std::string>("value").length());
2464 
2465 
2466  // print entries one by
2467  // one. make sure they are
2468  // sorted by using the
2469  // appropriate iterators
2470  bool first_entry = true;
2471  for (boost::property_tree::ptree::const_assoc_iterator
2472  p = current_section.ordered_begin();
2473  p != current_section.not_found(); ++p)
2474  if (is_parameter_node (p->second) == true)
2475  {
2476  const std::string value = p->second.get<std::string>("value");
2477 
2478  // if there is documentation,
2479  // then add an empty line (unless
2480  // this is the first entry in a
2481  // subsection), print the
2482  // documentation, and then the
2483  // actual entry; break the
2484  // documentation into readable
2485  // chunks such that the whole
2486  // thing is at most 78 characters
2487  // wide
2488  if ((!(style & 128)) &&
2489  !p->second.get<std::string>("documentation").empty())
2490  {
2491  if (first_entry == false)
2492  out << std::endl;
2493  else
2494  first_entry = false;
2495 
2496  const std::vector<std::string> doc_lines
2497  = Utilities::
2498  break_text_into_lines (p->second.get<std::string>("documentation"),
2499  78 - overall_indent_level*2 - 2);
2500 
2501  for (unsigned int i=0; i<doc_lines.size(); ++i)
2502  out << std::setw(overall_indent_level*2) << ""
2503  << "# "
2504  << doc_lines[i]
2505  << std::endl;
2506  }
2507 
2508 
2509 
2510  // print name and value
2511  // of this entry
2512  out << std::setw(overall_indent_level*2) << ""
2513  << "set "
2514  << demangle(p->first)
2515  << std::setw(longest_name-demangle(p->first).length()+1) << " "
2516  << "= " << value;
2517 
2518  // finally print the
2519  // default value, but
2520  // only if it differs
2521  // from the actual value
2522  if ((!(style & 64)) && value != p->second.get<std::string>("default_value"))
2523  {
2524  out << std::setw(longest_value-value.length()+1) << ' '
2525  << "# ";
2526  out << "default: " << p->second.get<std::string>("default_value");
2527  }
2528 
2529  out << std::endl;
2530  }
2531 
2532  break;
2533  }
2534 
2535  case LaTeX:
2536  {
2537  // if there are any parameters in
2538  // this section then print them as an
2539  // itemized list
2540  bool parameters_exist_here = false;
2541  for (boost::property_tree::ptree::const_assoc_iterator
2542  p = current_section.ordered_begin();
2543  p != current_section.not_found(); ++p)
2544  if ((is_parameter_node (p->second) == true)
2545  ||
2546  (is_alias_node (p->second) == true))
2547  {
2548  parameters_exist_here = true;
2549  break;
2550  }
2551 
2552  if (parameters_exist_here)
2553  {
2554  out << "\\begin{itemize}"
2555  << std::endl;
2556 
2557  // print entries one by
2558  // one. make sure they are
2559  // sorted by using the
2560  // appropriate iterators
2561  for (boost::property_tree::ptree::const_assoc_iterator
2562  p = current_section.ordered_begin();
2563  p != current_section.not_found(); ++p)
2564  if (is_parameter_node (p->second) == true)
2565  {
2566  const std::string value = p->second.get<std::string>("value");
2567 
2568  // print name
2569  out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
2570  << "\\phantomsection\\label{parameters:";
2571  for (unsigned int i=0; i<subsection_path.size(); ++i)
2572  out << subsection_path[i] << "/";
2573  out << demangle(p->first);
2574  out << "}\n\n"
2575  << std::endl;
2576 
2577  out << "\\index[prmindex]{"
2578  << demangle(p->first)
2579  << "}\n";
2580  out << "\\index[prmindexfull]{";
2581  for (unsigned int i=0; i<subsection_path.size(); ++i)
2582  out << subsection_path[i] << "!";
2583  out << demangle(p->first)
2584  << "}\n";
2585 
2586  // finally print value and default
2587  out << "{\\it Value:} " << value << "\n\n"
2588  << std::endl
2589  << "{\\it Default:} "
2590  << p->second.get<std::string>("default_value") << "\n\n"
2591  << std::endl;
2592 
2593  // if there is a
2594  // documenting string,
2595  // print it as well
2596  if (!p->second.get<std::string>("documentation").empty())
2597  out << "{\\it Description:} "
2598  << p->second.get<std::string>("documentation") << "\n\n"
2599  << std::endl;
2600 
2601  // also output possible values
2602  const unsigned int pattern_index = p->second.get<unsigned int> ("pattern");
2603  const std::string desc_str = patterns[pattern_index]->description (Patterns::PatternBase::LaTeX);
2604  out << "{\\it Possible values:} "
2605  << desc_str
2606  << std::endl;
2607  }
2608  else if (is_alias_node (p->second) == true)
2609  {
2610  const std::string alias = p->second.get<std::string>("alias");
2611 
2612  // print name
2613  out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
2614  << "\\phantomsection\\label{parameters:";
2615  for (unsigned int i=0; i<subsection_path.size(); ++i)
2616  out << subsection_path[i] << "/";
2617  out << demangle(p->first);
2618  out << "}\n\n"
2619  << std::endl;
2620 
2621  out << "\\index[prmindex]{"
2622  << demangle(p->first)
2623  << "}\n";
2624  out << "\\index[prmindexfull]{";
2625  for (unsigned int i=0; i<subsection_path.size(); ++i)
2626  out << subsection_path[i] << "!";
2627  out << demangle(p->first)
2628  << "}\n";
2629 
2630  // finally print alias and indicate if it is deprecated
2631  out << "This parameter is an alias for the parameter ``\\texttt{"
2632  << alias << "}''."
2633  << (p->second.get<std::string>("deprecation_status") == "true"
2634  ?
2635  " Its use is deprecated."
2636  :
2637  "")
2638  << "\n\n"
2639  << std::endl;
2640  }
2641  out << "\\end{itemize}" << std::endl;
2642  }
2643 
2644  break;
2645  }
2646 
2647  case Description:
2648  {
2649  // if there are top level elements to print, do it
2650  if (include_top_level_elements && (subsection_path.size() > 0))
2651  for (unsigned int i=0; i<subsection_path.size(); ++i)
2652  {
2653  out << std::setw(overall_indent_level*2) << ""
2654  << "subsection " << demangle (subsection_path[i]) << std::endl;
2655  overall_indent_level += 1;
2656  };
2657 
2658  // first find out the longest
2659  // entry name to be able to
2660  // align the equal signs
2661  std::size_t longest_name = 0;
2662  for (boost::property_tree::ptree::const_iterator
2663  p = current_section.begin();
2664  p != current_section.end(); ++p)
2665  if (is_parameter_node (p->second) == true)
2666  longest_name = std::max (longest_name,
2667  demangle(p->first).length());
2668 
2669  // print entries one by
2670  // one. make sure they are
2671  // sorted by using the
2672  // appropriate iterators
2673  for (boost::property_tree::ptree::const_assoc_iterator
2674  p = current_section.ordered_begin();
2675  p != current_section.not_found(); ++p)
2676  if (is_parameter_node (p->second) == true)
2677  {
2678  // print name and value
2679  out << std::setw(overall_indent_level*2) << ""
2680  << "set "
2681  << demangle(p->first)
2682  << std::setw(longest_name-demangle(p->first).length()+1) << " "
2683  << " = ";
2684 
2685  // print possible values:
2686  const unsigned int pattern_index = p->second.get<unsigned int> ("pattern");
2687  const std::string full_desc_str = patterns[pattern_index]->description (Patterns::PatternBase::Text);
2688  const std::vector<std::string> description_str
2689  = Utilities::break_text_into_lines (full_desc_str,
2690  78 - overall_indent_level*2 - 2, '|');
2691  if (description_str.size() > 1)
2692  {
2693  out << std::endl;
2694  for (unsigned int i=0; i<description_str.size(); ++i)
2695  out << std::setw(overall_indent_level*2+6) << ""
2696  << description_str[i] << std::endl;
2697  }
2698  else if (description_str.empty() == false)
2699  out << " " << description_str[0] << std::endl;
2700  else
2701  out << std::endl;
2702 
2703  // if there is a
2704  // documenting string,
2705  // print it as well
2706  if (p->second.get<std::string>("documentation").length() != 0)
2707  out << std::setw(overall_indent_level*2 + longest_name + 10) << ""
2708  << "(" << p->second.get<std::string>("documentation") << ")" << std::endl;
2709  }
2710 
2711  break;
2712  }
2713 
2714  default:
2715  Assert (false, ExcNotImplemented());
2716  }
2717 
2718 
2719  // if there was text before and there are
2720  // sections to come, put two newlines
2721  // between the last entry and the first
2722  // subsection
2723  if (style != XML)
2724  {
2725  unsigned int n_parameters = 0;
2726  unsigned int n_sections = 0;
2727  for (boost::property_tree::ptree::const_iterator
2728  p = current_section.begin();
2729  p != current_section.end(); ++p)
2730  if (is_parameter_node (p->second) == true)
2731  ++n_parameters;
2732  else if (is_alias_node (p->second) == false)
2733  ++n_sections;
2734 
2735  if ((style != Description)
2736  &&
2737  (!(style & 128))
2738  &&
2739  (n_parameters != 0)
2740  &&
2741  (n_sections != 0))
2742  out << std::endl << std::endl;
2743 
2744  // now traverse subsections tree,
2745  // in alphabetical order
2746  for (boost::property_tree::ptree::const_assoc_iterator
2747  p = current_section.ordered_begin();
2748  p != current_section.not_found(); ++p)
2749  if ((is_parameter_node (p->second) == false)
2750  &&
2751  (is_alias_node (p->second) == false))
2752  {
2753  // first print the subsection header
2754  switch (style)
2755  {
2756  case Text:
2757  case Description:
2758  case ShortText:
2759  out << std::setw(overall_indent_level*2) << ""
2760  << "subsection " << demangle(p->first) << std::endl;
2761  break;
2762  case LaTeX:
2763  {
2764  out << std::endl
2765  << "\\subsection{Parameters in section \\tt ";
2766 
2767  // find the path to the
2768  // current section so that we
2769  // can print it in the
2770  // \subsection{...} heading
2771  for (unsigned int i=0; i<subsection_path.size(); ++i)
2772  out << subsection_path[i] << "/";
2773  out << demangle(p->first);
2774 
2775  out << "}" << std::endl;
2776  out << "\\label{parameters:";
2777  for (unsigned int i=0; i<subsection_path.size(); ++i)
2778  out << mangle(subsection_path[i]) << "/";
2779  out << p->first << "}";
2780  out << std::endl;
2781 
2782  out << std::endl;
2783  break;
2784  }
2785 
2786  default:
2787  Assert (false, ExcNotImplemented());
2788  };
2789 
2790  // then the contents of the
2791  // subsection
2792  enter_subsection (demangle(p->first));
2793  print_parameters_section (out, style, overall_indent_level+1);
2794  leave_subsection ();
2795  switch (style)
2796  {
2797  case Text:
2798  // write end of
2799  // subsection. one
2800  // blank line after
2801  // each subsection
2802  out << std::setw(overall_indent_level*2) << ""
2803  << "end" << std::endl
2804  << std::endl;
2805 
2806  // if this is a toplevel
2807  // subsection, then have two
2808  // newlines
2809  if (overall_indent_level == 0)
2810  out << std::endl;
2811 
2812  break;
2813  case Description:
2814  break;
2815  case ShortText:
2816  // write end of
2817  // subsection.
2818  out << std::setw(overall_indent_level*2) << ""
2819  << "end" << std::endl;
2820  break;
2821  case LaTeX:
2822  break;
2823  default:
2824  Assert (false, ExcNotImplemented());
2825  }
2826  }
2827  }
2828 
2829  // close top level elements, if there are any
2830  switch (style)
2831  {
2832  case XML:
2833  case LaTeX:
2834  case Description:
2835  break;
2836  case Text:
2837  case ShortText:
2838  {
2839  if (include_top_level_elements && (subsection_path.size() > 0))
2840  for (unsigned int i=0; i<subsection_path.size(); ++i)
2841  {
2842  overall_indent_level -= 1;
2843  out << std::setw(overall_indent_level*2) << ""
2844  << "end" << std::endl;
2845  };
2846 
2847  break;
2848  }
2849 
2850  default:
2851  Assert (false, ExcNotImplemented());
2852  }
2853 
2854 }
2855 
2856 
2857 
2858 void
2860 {
2861  out.push("parameters");
2862  // dive recursively into the
2863  // subsections
2864  log_parameters_section (out);
2865 
2866  out.pop();
2867 }
2868 
2869 
2870 
2871 void
2873 {
2874  const boost::property_tree::ptree &current_section
2875  = entries->get_child (get_current_path());
2876 
2877  // print entries one by
2878  // one. make sure they are
2879  // sorted by using the
2880  // appropriate iterators
2881  for (boost::property_tree::ptree::const_assoc_iterator
2882  p = current_section.ordered_begin();
2883  p != current_section.not_found(); ++p)
2884  if (is_parameter_node (p->second) == true)
2885  out << demangle(p->first) << ": "
2886  << p->second.get<std::string>("value") << std::endl;
2887 
2888  // now transverse subsections tree
2889  // now traverse subsections tree,
2890  // in alphabetical order
2891  for (boost::property_tree::ptree::const_assoc_iterator
2892  p = current_section.ordered_begin();
2893  p != current_section.not_found(); ++p)
2894  if (is_parameter_node (p->second) == false)
2895  {
2896  out.push (demangle(p->first));
2897  enter_subsection (demangle(p->first));
2898  log_parameters_section (out);
2899  leave_subsection ();
2900  out.pop ();
2901  }
2902 }
2903 
2904 
2905 
2906 void
2908  const std::string &input_filename,
2909  const unsigned int current_line_n)
2910 {
2911  // save a copy for some error messages
2912  const std::string original_line = line;
2913 
2914  // if there is a comment, delete it
2915  if (line.find('#') != std::string::npos)
2916  line.erase (line.find("#"), std::string::npos);
2917 
2918  // replace \t by space:
2919  while (line.find('\t') != std::string::npos)
2920  line.replace (line.find('\t'), 1, " ");
2921 
2922  //trim start and end:
2923  line = Utilities::trim(line);
2924 
2925  // if line is now empty: leave
2926  if (line.length() == 0)
2927  {
2928  return;
2929  }
2930  // enter subsection
2931  else if (Utilities::match_at_string_start(line, "SUBSECTION ") ||
2932  Utilities::match_at_string_start(line, "subsection "))
2933  {
2934  // delete this prefix
2935  line.erase (0, std::string("subsection").length()+1);
2936 
2937  const std::string subsection = Utilities::trim(line);
2938 
2939  // check whether subsection exists
2940  AssertThrow (entries->get_child_optional (get_current_full_path(subsection)),
2941  ExcNoSubsection (current_line_n,
2942  input_filename,
2943  demangle(get_current_full_path(subsection))));
2944 
2945  // subsection exists
2946  subsection_path.push_back (subsection);
2947  }
2948  // exit subsection
2949  else if (Utilities::match_at_string_start(line, "END") ||
2950  Utilities::match_at_string_start(line, "end"))
2951  {
2952  line.erase (0, 3);
2953  while ((line.size() > 0) && (std::isspace(line[0])))
2954  line.erase (0, 1);
2955 
2956  AssertThrow (line.size() == 0,
2957  ExcCannotParseLine (current_line_n,
2958  input_filename,
2959  "Invalid content after 'end' or 'END' statement."));
2960  AssertThrow (subsection_path.size() != 0,
2961  ExcCannotParseLine (current_line_n,
2962  input_filename,
2963  "There is no subsection to leave here."));
2964  leave_subsection ();
2965  }
2966  // regular entry
2967  else if (Utilities::match_at_string_start(line, "SET ") ||
2968  Utilities::match_at_string_start(line, "set "))
2969  {
2970  // erase "set" statement
2971  line.erase (0, 4);
2972 
2973  std::string::size_type pos = line.find("=");
2974  AssertThrow (pos != std::string::npos,
2975  ExcCannotParseLine (current_line_n,
2976  input_filename,
2977  "Invalid format of 'set' or 'SET' statement."));
2978 
2979  // extract entry name and value and trim
2980  std::string entry_name = Utilities::trim(std::string(line, 0, pos));
2981  std::string entry_value = Utilities::trim(std::string(line, pos+1, std::string::npos));
2982 
2983  // resolve aliases before we look up the entry. if necessary, print
2984  // a warning that the alias is deprecated
2985  std::string path = get_current_full_path(entry_name);
2986  if (entries->get_optional<std::string>(path + path_separator + "alias"))
2987  {
2988  if (entries->get<std::string>(path + path_separator + "deprecation_status") == "true")
2989  {
2990  std::cerr << "Warning in line <" << current_line_n
2991  << "> of file <" << input_filename
2992  << ">: You are using the deprecated spelling <"
2993  << entry_name
2994  << "> of the parameter <"
2995  << entries->get<std::string>(path + path_separator + "alias")
2996  << ">." << std::endl;
2997  }
2998  path = get_current_full_path(entries->get<std::string>(path + path_separator + "alias"));
2999  }
3000 
3001  // assert that the entry is indeed declared
3002  if (entries->get_optional<std::string> (path + path_separator + "value"))
3003  {
3004  // if entry was declared:
3005  // does it match the regex? if not,
3006  // don't enter it into the database
3007  // exception: if it contains characters
3008  // which specify it as a multiple loop
3009  // entry, then ignore content
3010  if (entry_value.find ('{') == std::string::npos)
3011  {
3012  const unsigned int pattern_index
3013  = entries->get<unsigned int> (path + path_separator + "pattern");
3014  AssertThrow (patterns[pattern_index]->match (entry_value),
3015  ExcInvalidEntryForPattern (current_line_n,
3016  input_filename,
3017  entry_value,
3018  entry_name,
3019  patterns[pattern_index]->description()));
3020  }
3021 
3022  entries->put (path + path_separator + "value",
3023  entry_value);
3024  }
3025  else
3026  {
3027  AssertThrow (false,
3028  ExcCannotParseLine(current_line_n,
3029  input_filename,
3030  ("No entry with name <" + entry_name +
3031  "> was declared in the current subsection.")));
3032  }
3033  }
3034  // an include statement?
3035  else if (Utilities::match_at_string_start(line, "include ") ||
3036  Utilities::match_at_string_start(line, "INCLUDE "))
3037  {
3038  // erase "include " statement and eliminate spaces
3039  line.erase (0, 7);
3040  while ((line.size() > 0) && (line[0] == ' '))
3041  line.erase (0, 1);
3042 
3043  // the remainder must then be a filename
3044  AssertThrow (line.size() !=0,
3045  ExcCannotParseLine (current_line_n,
3046  input_filename,
3047  "The current line is an 'include' or "
3048  "'INCLUDE' statement, but it does not "
3049  "name a file for inclusion."));
3050 
3051  std::ifstream input (line.c_str());
3052  AssertThrow (input, ExcCannotOpenIncludeStatementFile (current_line_n,
3053  input_filename,
3054  line));
3055  parse_input (input);
3056  }
3057  else
3058  {
3059  AssertThrow (false,
3060  ExcCannotParseLine (current_line_n,
3061  input_filename,
3062  "The line\n\n"
3063  " <"
3064  + original_line
3065  + ">\n\n"
3066  "could not be parsed: please check to "
3067  "make sure that the file is not missing a "
3068  "'set', 'include', 'subsection', or 'end' "
3069  "statement."));
3070  }
3071 }
3072 
3073 
3074 
3075 std::size_t
3077 {
3078 //TODO: add to this an estimate of the memory in the property_tree
3080 }
3081 
3082 
3083 
3084 bool
3086 {
3087  if (patterns.size() != prm2.patterns.size())
3088  return false;
3089 
3090  for (unsigned int j=0; j<patterns.size(); ++j)
3091  if (patterns[j]->description() != prm2.patterns[j]->description())
3092  return false;
3093 
3094  // instead of walking through all
3095  // the nodes of the two trees
3096  // entries and prm2.entries and
3097  // comparing them for equality,
3098  // simply dump the content of the
3099  // entire structure into a string
3100  // and compare those for equality
3101  std::ostringstream o1, o2;
3102  write_json (o1, *entries);
3103  write_json (o2, *prm2.entries);
3104  return (o1.str() == o2.str());
3105 }
3106 
3107 
3108 
3109 
3111 {}
3112 
3113 
3114 
3116  :
3117  n_branches(0)
3118 {}
3119 
3120 
3121 
3123 {}
3124 
3125 
3126 
3127 bool
3129  const std::string &filename,
3130  const std::string &last_line)
3131 {
3132 
3133  try
3134  {
3135  MultipleParameterLoop::parse_input(input, filename, last_line);
3136  return true;
3137  }
3138  catch (const ExcIO &)
3139  {
3140  throw;
3141  }
3142  // This catch block more or less duplicates the old behavior of this function,
3143  // which was to print something to stderr for every parsing error (which are
3144  // now exceptions) and then return false.
3145  catch (const ExceptionBase &exc)
3146  {
3147  std::cerr << exc.what() << std::endl;
3148  }
3149  return false;
3150 }
3151 
3152 
3153 
3154 void
3156  const std::string &filename,
3157  const std::string &last_line)
3158 {
3159  AssertThrow (input, ExcIO());
3160 
3161  // Note that (to avoid infinite recursion) we have to explicitly call the
3162  // base class version of parse_input and *not* a wrapper (which may be
3163  // virtual and lead us back here)
3164  ParameterHandler::parse_input (input, filename, last_line);
3165  init_branches ();
3166 }
3167 
3168 
3169 
3171 {
3172  for (unsigned int run_no=0; run_no<n_branches; ++run_no)
3173  {
3174  // give create_new one-based numbers
3175  uc.create_new (run_no+1);
3176  fill_entry_values (run_no);
3177  uc.run (*this);
3178  };
3179 }
3180 
3181 
3182 
3184 {
3185  multiple_choices.clear ();
3187 
3188  // split up different values
3189  for (unsigned int i=0; i<multiple_choices.size(); ++i)
3190  multiple_choices[i].split_different_values ();
3191 
3192  // finally calculate number of branches
3193  n_branches = 1;
3194  for (unsigned int i=0; i<multiple_choices.size(); ++i)
3195  if (multiple_choices[i].type == Entry::variant)
3196  n_branches *= multiple_choices[i].different_values.size();
3197 
3198  // check whether array entries have the correct
3199  // number of entries
3200  for (unsigned int i=0; i<multiple_choices.size(); ++i)
3201  if (multiple_choices[i].type == Entry::array)
3202  if (multiple_choices[i].different_values.size() != n_branches)
3203  std::cerr << " The entry value" << std::endl
3204  << " " << multiple_choices[i].entry_value << std::endl
3205  << " for the entry named" << std::endl
3206  << " " << multiple_choices[i].entry_name << std::endl
3207  << " does not have the right number of entries for the " << std::endl
3208  << " " << n_branches << " variant runs that will be performed."
3209  << std::endl;
3210 
3211 
3212  // do a first run on filling the values to
3213  // check for the conformance with the regexp
3214  // (later on, this will be lost in the whole
3215  // other output)
3216  for (unsigned int i=0; i<n_branches; ++i)
3217  fill_entry_values (i);
3218 }
3219 
3220 
3221 
3223 {
3224  const boost::property_tree::ptree &current_section
3225  = entries->get_child (get_current_path());
3226 
3227  // check all entries in the present
3228  // subsection whether they are
3229  // multiple entries
3230  //
3231  // we loop over entries in sorted
3232  // order to guarantee backward
3233  // compatibility to an earlier
3234  // implementation
3235  for (boost::property_tree::ptree::const_assoc_iterator
3236  p = current_section.ordered_begin();
3237  p != current_section.not_found(); ++p)
3238  if (is_parameter_node (p->second) == true)
3239  {
3240  const std::string value = p->second.get<std::string>("value");
3241  if (value.find('{') != std::string::npos)
3243  demangle(p->first),
3244  value));
3245  }
3246 
3247  // then loop over all subsections
3248  for (boost::property_tree::ptree::const_iterator
3249  p = current_section.begin();
3250  p != current_section.end(); ++p)
3251  if (is_parameter_node (p->second) == false)
3252  {
3253  enter_subsection (demangle(p->first));
3255  leave_subsection ();
3256  }
3257 }
3258 
3259 
3260 
3261 
3262 void MultipleParameterLoop::fill_entry_values (const unsigned int run_no)
3263 {
3264  unsigned int possibilities = 1;
3265 
3266  std::vector<Entry>::iterator choice;
3267  for (choice = multiple_choices.begin();
3268  choice != multiple_choices.end();
3269  ++choice)
3270  {
3271  const unsigned int selection
3272  = (run_no/possibilities) % choice->different_values.size();
3273  std::string entry_value;
3274  if (choice->type == Entry::variant)
3275  entry_value = choice->different_values[selection];
3276  else
3277  {
3278  if (run_no>=choice->different_values.size())
3279  {
3280  std::cerr << "The given array for entry <"
3281  << choice->entry_name
3282  << "> does not contain enough elements! Taking empty string instead."
3283  << std::endl;
3284  entry_value = "";
3285  }
3286  else
3287  entry_value = choice->different_values[run_no];
3288  }
3289 
3290  // temporarily enter the
3291  // subsection tree of this
3292  // multiple entry, set the
3293  // value, and get out
3294  // again. the set() operation
3295  // also tests for the
3296  // correctness of the value
3297  // with regard to the pattern
3298  subsection_path.swap (choice->subsection_path);
3299  set (choice->entry_name, entry_value);
3300  subsection_path.swap (choice->subsection_path);
3301 
3302  // move ahead if it was a variant entry
3303  if (choice->type == Entry::variant)
3304  possibilities *= choice->different_values.size();
3305  }
3306 }
3307 
3308 
3309 
3310 
3311 std::size_t
3313 {
3314  std::size_t mem = ParameterHandler::memory_consumption ();
3315  for (unsigned int i=0; i<multiple_choices.size(); ++i)
3316  mem += multiple_choices[i].memory_consumption ();
3317 
3318  return mem;
3319 }
3320 
3321 
3322 
3323 MultipleParameterLoop::Entry::Entry (const std::vector<std::string> &ssp,
3324  const std::string &Name,
3325  const std::string &Value)
3326  :
3327  subsection_path (ssp), entry_name(Name), entry_value(Value), type (Entry::array)
3328 {}
3329 
3330 
3331 
3333 {
3334  // split string into three parts:
3335  // part before the opening "{",
3336  // the selection itself, final
3337  // part after "}"
3338  std::string prefix (entry_value, 0, entry_value.find('{'));
3339  std::string multiple(entry_value, entry_value.find('{')+1,
3340  entry_value.rfind('}')-entry_value.find('{')-1);
3341  std::string postfix (entry_value, entry_value.rfind('}')+1, std::string::npos);
3342  // if array entry {{..}}: delete inner
3343  // pair of braces
3344  if (multiple[0]=='{')
3345  multiple.erase (0,1);
3346  if (multiple[multiple.size()-1] == '}')
3347  multiple.erase (multiple.size()-1, 1);
3348  // erase leading and trailing spaces
3349  // in multiple
3350  while (std::isspace (multiple[0])) multiple.erase (0,1);
3351  while (std::isspace (multiple[multiple.size()-1])) multiple.erase (multiple.size()-1,1);
3352 
3353  // delete spaces around '|'
3354  while (multiple.find(" |") != std::string::npos)
3355  multiple.replace (multiple.find(" |"), 2, "|");
3356  while (multiple.find("| ") != std::string::npos)
3357  multiple.replace (multiple.find("| "), 2, "|");
3358 
3359  while (multiple.find('|') != std::string::npos)
3360  {
3361  different_values.push_back (prefix +
3362  std::string(multiple, 0, multiple.find('|'))+
3363  postfix);
3364  multiple.erase (0, multiple.find('|')+1);
3365  };
3366  // make up the last selection ("while" broke
3367  // because there was no '|' any more
3368  different_values.push_back (prefix+multiple+postfix);
3369  // finally check whether this was a variant
3370  // entry ({...}) or an array ({{...}})
3371  if ((entry_value.find("{{") != std::string::npos) &&
3372  (entry_value.find("}}") != std::string::npos))
3373  type = Entry::array;
3374  else
3375  type = Entry::variant;
3376 }
3377 
3378 
3379 std::size_t
3381 {
3385  MemoryConsumption::memory_consumption (different_values) +
3386  sizeof (type));
3387 }
3388 
3389 DEAL_II_NAMESPACE_CLOSE
std::vector< Entry > multiple_choices
std::size_t memory_consumption() const
long int get_integer(const std::string &entry_string) const
virtual bool match(const std::string &test_string) const
void pop()
Definition: logstream.cc:306
static const char path_separator
PatternBase * key_pattern
virtual bool match(const std::string &test_string) const
const double upper_bound
static const char * description_init
void loop(UserClass &uc)
static const char * description_init
static ::ExceptionBase & ExcInvalidEntryForPatternXML(std::string arg1, std::string arg2, std::string arg3)
static ::ExceptionBase & ExcCannotOpenIncludeStatementFile(int arg1, std::string arg2, std::string arg3)
static ::ExceptionBase & ExcIO()
virtual void run(ParameterHandler &prm)=0
std::string get_current_path() const
virtual bool match(const std::string &test_string) const
static ::ExceptionBase & ExcEntryUndeclared(std::string arg1)
std::string trim(const std::string &input)
Definition: utilities.cc:134
std::string get(const std::string &entry_string) const
static ::ExceptionBase & ExcUnbalancedSubsections(std::string arg1, std::string arg2)
std::size_t memory_consumption() const
const std::string separator
static Map * create(const std::string &description)
void log_parameters(LogStream &out)
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
Definition: utilities.cc:316
static const unsigned int max_int_value
static const char * description_init
void set(const std::string &entry_name, const std::string &new_value)
virtual PatternBase * clone() const
virtual bool match(const std::string &test_string) const
void log_parameters_section(LogStream &out)
virtual std::string description(const OutputStyle style=Machine) const
static Double * create(const std::string &description)
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="")
static const int max_int_value
#define AssertThrow(cond, exc)
Definition: exceptions.h:369
const unsigned int max_elements
static ::ExceptionBase & ExcCommasNotAllowed(int arg1)
static const char * description_init
static ::ExceptionBase & ExcValueDoesNotMatchPattern(std::string arg1, std::string arg2)
std::vector< std::string > subsection_path
static const int min_int_value
double string_to_double(const std::string &s)
Definition: utilities.cc:230
static ::ExceptionBase & ExcInvalidRange(int arg1, int arg2)
const double lower_bound
virtual PatternBase * clone() const =0
void enter_subsection(const std::string &subsection)
static ::ExceptionBase & ExcFileNotFound(std::string arg1, std::string arg2)
virtual void parse_input_from_xml(std::istream &input)
FileName(const FileType type=input)
static ::ExceptionBase & ExcInvalidXMLParameterFile()
static const char * description_init
virtual PatternBase * clone() const
static ::ExceptionBase & ExcMessage(std::string arg1)
static const char * description_init
static Integer * create(const std::string &description)
virtual void create_new(const unsigned int run_no)=0
PatternBase * pattern
static ::ExceptionBase & ExcCannotParseLine(int arg1, std::string arg2, std::string arg3)
double get_double(const std::string &entry_name) const
virtual bool read_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="") 1
std::size_t memory_consumption() const
static const char * description_init
static Bool * create(const std::string &description)
virtual std::string description(const OutputStyle style=Machine) const
virtual bool read_input_from_xml(std::istream &input) 1
virtual std::string description(const OutputStyle style=Machine) const
Double(const double lower_bound=min_double_value, const double upper_bound=max_double_value)
#define Assert(cond, exc)
Definition: exceptions.h:313
std::string get_current_full_path(const std::string &name) const
List(const PatternBase &base_pattern, const unsigned int min_elements=0, const unsigned int max_elements=max_int_value, const std::string &separator=",")
MultipleSelection(const std::string &seq)
virtual std::size_t memory_consumption() const
static const char * description_init
static Anything * create(const std::string &description)
static ::ExceptionBase & ExcInvalidRange(int arg1, int arg2)
Map(const PatternBase &key_pattern, const PatternBase &value_pattern, const unsigned int min_elements=0, const unsigned int max_elements=max_int_value, const std::string &separator=",")
PatternBase * pattern_factory(const std::string &description)
static std::string mangle(const std::string &s)
bool match_at_string_start(const std::string &name, const std::string &pattern)
Definition: utilities.cc:393
virtual std::string description(const OutputStyle style=Machine) const
virtual PatternBase * clone() const
std::size_t memory_consumption() const
static const double min_double_value
void fill_entry_values(const unsigned int run_no)
virtual bool read_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="") 1
virtual std::string description(const OutputStyle style=Machine) const
bool get_bool(const std::string &entry_name) const
virtual bool match(const std::string &test_string) const
static const char * description_init
virtual void parse_input_from_string(const char *s, const std::string &last_line="")
static ::ExceptionBase & ExcAlreadyAtTopLevel()
virtual PatternBase * clone() const
std::string replace_in_string(const std::string &input, const std::string &from, const std::string &to)
Definition: utilities.cc:115
virtual std::string description(const OutputStyle style=Machine) const
virtual bool match(const std::string &test_string) const =0
virtual PatternBase * clone() const
virtual std::string description(const OutputStyle style=Machine) const
bool operator==(const ParameterHandler &prm2) const
std::string find(const std::string &filename, const char *open_mode="r")
Definition: path_search.cc:172
virtual bool match(const std::string &test_string) const
static const char * description_init
std::size_t memory_consumption() const
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
std::size_t memory_consumption() const
virtual PatternBase * clone() const
static const double max_double_value
void push(const std::string &text)
Definition: logstream.cc:294
virtual std::string description(const OutputStyle style=Machine) const =0
virtual bool match(const std::string &test_string) const
virtual PatternBase * clone() const
static std::string demangle(const std::string &s)
std::ostream & print_parameters(std::ostream &out, const OutputStyle style)
Integer(const int lower_bound=min_int_value, const int upper_bound=max_int_value)
void print_parameters_section(std::ostream &out, const OutputStyle style, const unsigned int indent_level, const bool include_top_level_elements=false)
virtual PatternBase * clone() const
std_cxx11::unique_ptr< boost::property_tree::ptree > entries
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation=std::string())
int string_to_int(const std::string &s)
Definition: utilities.cc:192
Selection(const std::string &seq)
static DirectoryName * create(const std::string &description)
static ::ExceptionBase & ExcNotImplemented()
static FileName * create(const std::string &description)
static MultipleSelection * create(const std::string &description)
virtual bool match(const std::string &test_string) const
void scan_line(std::string line, const std::string &input_filename, const unsigned int current_line_n)
const unsigned int min_elements
std::size_t memory_consumption() const
static ::ExceptionBase & ExcInvalidEntryForPattern(int arg1, std::string arg2, std::string arg3, std::string arg4, std::string arg5)
static List * create(const std::string &description)
virtual bool read_input_from_string(const char *s, const std::string &last_line="")
static const unsigned int max_int_value
static Selection * create(const std::string &description)
virtual PatternBase * clone() const
static ::ExceptionBase & ExcNoSubsection(int arg1, std::string arg2, std::string arg3)
const std::string separator
virtual std::string description(const OutputStyle style=Machine) const
void declare_alias(const std::string &existing_entry_name, const std::string &alias_name, const bool alias_is_deprecated=false)
const unsigned int max_elements
virtual std::string description(const OutputStyle style=Machine) const
virtual const char * what() const DEAL_II_NOEXCEPT
Definition: exceptions.cc:138
virtual bool match(const std::string &test_string) const
const unsigned int min_elements
virtual std::string description(const OutputStyle style=Machine) const
std::vector< std_cxx11::shared_ptr< const Patterns::PatternBase > > patterns
virtual PatternBase * clone() const
static ::ExceptionBase & ExcInternalError()
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="")