From e1e68a073917559113d25f1862a1b6b08f72ff39 Mon Sep 17 00:00:00 2001 From: AlexanderBlank Date: Mon, 20 Aug 2018 22:54:59 -0700 Subject: [PATCH] Added overloads for ParameterHandler getters to accept a subsection path so that data from a subsection below the current one can be retrieved while keeping the ParameterHandler const. Also added tests and documentation of this feature., minor text changes. --- include/deal.II/base/parameter_handler.h | 97 ++++- source/base/parameter_handler.cc | 117 +++++- .../parameter_handler/parameter_handler_23.cc | 339 ++++++++++++++++++ .../parameter_handler_23.output | 41 +++ 4 files changed, 583 insertions(+), 11 deletions(-) create mode 100644 tests/parameter_handler/parameter_handler_23.cc create mode 100644 tests/parameter_handler/parameter_handler_23.output diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index b7ea141f88..6e71821ace 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -270,8 +270,34 @@ class MultipleParameterLoop; * @endcode * get() returns the value of the given entry. If the entry was not specified * in the input source(s), the default value is returned. You have to enter - * and leave subsections exactly as you did when declaring subsection. You may - * chose the order in which to transverse the subsection tree. + * and leave subsections exactly as you did when declaring subsections. You may + * choose the order in which to traverse the subsection tree. + * + * It is possible to avoid calls to enter_subsection() and leave_subsection() + * by supplying get() with a vector of strings representing the path from + * which to get a value. For example, the following two versions of + * get_parameters() will produce the same result: + * @code + * void NonLinEq::get_parameters (ParameterHandler &prm) + * { + * prm.enter_subsection ("Equation 1 Settings"); + * prm.enter_subsection ("Linear solver"); + * solver_ = prm.get ("Solver"); + * prm.leave_subsection (); + * prm.leave_subsection (); + * } + * @endcode + * + * @code + * void NonLinEq::get_parameters (const ParameterHandler &prm) + * { + * std::vector path = + * {"Equation 1 Settings", "Linear solver"}; + * solver_ = prm.get (path, "Solver"); + * } + * @endcode + * + * The latter method allows the ParameterHandler reference to be @p const. * * It is guaranteed that only entries matching the given regular expression * are returned, i.e. an input entry value which does not match the regular @@ -1152,15 +1178,29 @@ public: leave_subsection(); /** - * Return value of entry entry_string. If the entry was changed, + * Return value of entry @p entry_string. If the entry was changed, * then the changed value is returned, otherwise the default value. If the - * value of an undeclared entry is required, an exception will be thrown. + * value of an undeclared entry is required, an @p Assert will fail. */ std::string get(const std::string &entry_string) const; /** - * Return value of entry entry_string as long int. (A long + * Return value of entry @p entry_string. If the entry was changed, + * then the changed value is returned, otherwise the default value. If the + * value of an undeclared entry is required, an @p Assert will fail. + * If @p entry_subsection_path is non-empty, the value will be gotten + * from the subsection represented by that path instead of the current + * subsection. The first string in @p entry_subsection_path must be the name + * of a subsection of the current section, and each next string must be the + * name of a subsection of the one before it. + */ + std::string + get(const std::vector &entry_subsection_path, + const std::string & entry_string) const; + + /** + * Return value of entry @p entry_string as long int. (A long * int is chosen so that even very large unsigned values can be returned by * this function). */ @@ -1168,19 +1208,52 @@ public: get_integer(const std::string &entry_string) const; /** - * Return value of entry entry_name as double. + * Return value of entry @p entry_string as long int. (A long + * int is chosen so that even very large unsigned values can be returned by + * this function). + * If @p entry_subsection_path is non-empty, the value will be gotten + * from the subsection represented by that path instead of the current + * subsection. + */ + long int + get_integer(const std::vector &entry_subsection_path, + const std::string & entry_string) const; + + /** + * Return value of entry @p entry_name as @p double. */ double get_double(const std::string &entry_name) const; /** - * Return value of entry entry_name as bool. The entry may - * be "true" or "yes" for true, "false" or "no" for false + * Return value of entry @p entry_name as @p double. + * If @p entry_subsection_path is non-empty, the value will be gotten + * from the subsection represented by that path instead of the current + * subsection. + */ + double + get_double(const std::vector &entry_subsection_path, + const std::string & entry_string) const; + /** + * Return value of entry @p entry_name as @p bool. The entry may + * be "true" or "yes" for @p true, "false" or "no" for @p false * respectively. */ bool get_bool(const std::string &entry_name) const; + /** + * Return value of entry @p entry_name as @p bool. The entry may + * be "true" or "yes" for @p true, "false" or "no" for @p false + * respectively. + * If @p entry_subsection_path is non-empty, the value will be gotten + * from the subsection represented by that path instead of the current + * subsection. + */ + bool + get_bool(const std::vector &entry_subsection_path, + const std::string & entry_string) const; + /** * Change the value presently stored for entry_name to the one * given in the second argument. @@ -1582,6 +1655,14 @@ private: std::string get_current_full_path(const std::string &name) const; + /** + * This function computes a full path into the parameter tree given a path + * from the current subsection and the name of an entry. + */ + std::string + get_current_full_path(const std::vector &sub_path, + const std::string & name) const; + /** * Scan one line of input. input_filename and * current_line_n are the name of the input file and the number of diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 03a3cc0ce8..742203ec2b 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -294,6 +294,25 @@ ParameterHandler::get_current_full_path(const std::string &name) const +std::string +ParameterHandler::get_current_full_path( + const std::vector &sub_path, + const std::string & name) const +{ + std::string path = get_current_path(); + if (path.empty() == false) + path += path_separator; + + if (sub_path.empty() == false) + path += collate_path_string(sub_path) + path_separator; + + path += mangle(name); + + return path; +} + + + void ParameterHandler::parse_input(std::istream & input, const std::string &filename, @@ -783,6 +802,27 @@ ParameterHandler::get(const std::string &entry_string) const +std::string +ParameterHandler::get(const std::vector &entry_subsection_path, + const std::string & entry_string) const +{ + // assert that the entry is indeed + // declared + if (boost::optional value = entries->get_optional( + get_current_full_path(entry_subsection_path, entry_string) + + path_separator + "value")) + return value.get(); + else + { + Assert(false, + ExcEntryUndeclared(demangle( + get_current_full_path(entry_subsection_path, entry_string)))); + return ""; + } +} + + + long int ParameterHandler::get_integer(const std::string &entry_string) const { @@ -795,7 +835,31 @@ ParameterHandler::get_integer(const std::string &entry_string) const AssertThrow(false, ExcMessage("Can't convert the parameter value <" + get(entry_string) + "> for entry <" + - entry_string + " to an integer.")); + entry_string + "> to an integer.")); + return 0; + } +} + + + +long int +ParameterHandler::get_integer( + const std::vector &entry_subsection_path, + const std::string & entry_string) const +{ + try + { + return Utilities::string_to_int(get(entry_subsection_path, entry_string)); + } + catch (...) + { + AssertThrow(false, + ExcMessage( + "Can't convert the parameter value <" + + get(entry_subsection_path, entry_string) + "> for entry <" + + demangle(get_current_full_path(entry_subsection_path, + entry_string)) + + "> to an integer.")); return 0; } } @@ -815,7 +879,32 @@ ParameterHandler::get_double(const std::string &entry_string) const ExcMessage("Can't convert the parameter value <" + get(entry_string) + "> for entry <" + entry_string + - " to a double precision variable.")); + "> to a double precision variable.")); + return 0; + } +} + + + +double +ParameterHandler::get_double( + const std::vector &entry_subsection_path, + const std::string & entry_string) const +{ + try + { + return Utilities::string_to_double( + get(entry_subsection_path, entry_string)); + } + catch (...) + { + AssertThrow(false, + ExcMessage( + "Can't convert the parameter value <" + + get(entry_subsection_path, entry_string) + "> for entry <" + + demangle(get_current_full_path(entry_subsection_path, + entry_string)) + + "> to a double precision variable.")); return 0; } } @@ -830,7 +919,29 @@ ParameterHandler::get_bool(const std::string &entry_string) const AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"), ExcMessage("Can't convert the parameter value <" + get(entry_string) + "> for entry <" + entry_string + - " to a boolean.")); + "> to a boolean.")); + if (s == "true" || s == "yes") + return true; + else + return false; +} + + + +bool +ParameterHandler::get_bool( + const std::vector &entry_subsection_path, + const std::string & entry_string) const +{ + const std::string s = get(entry_subsection_path, entry_string); + + AssertThrow((s == "true") || (s == "false") || (s == "yes") || (s == "no"), + ExcMessage("Can't convert the parameter value <" + + get(entry_subsection_path, entry_string) + + "> for entry <" + + demangle(get_current_full_path(entry_subsection_path, + entry_string)) + + "> to a boolean.")); if (s == "true" || s == "yes") return true; else diff --git a/tests/parameter_handler/parameter_handler_23.cc b/tests/parameter_handler/parameter_handler_23.cc new file mode 100644 index 0000000000..3ae11794c4 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_23.cc @@ -0,0 +1,339 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2018 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + + + +// check use of path in ParameterHandler::Get + +#include + +#include + +#include "../tests.h" + +void +log_entry(const ParameterHandler & prm, + const std::vector path, + const std::string & entry) +{ + for (unsigned int i = 0; i < path.size(); ++i) + { + deallog << path[i] << "."; + } + + deallog << entry << " = "; + deallog << prm.get(path, entry) << std::endl; +} + +void +log_exception(const StandardExceptions::ExcMessage &exc) +{ + std::ostringstream string_stream; + exc.print_info(string_stream); + std::string exc_info = string_stream.str(); + + const std::string whitespace_chars = " \t\r\n\v\f"; + exc_info.erase(0, exc_info.find_first_not_of(whitespace_chars)); + exc_info.erase(exc_info.find_last_not_of(whitespace_chars) + 1); + + deallog << exc_info << std::endl; +} + +void +test_basic() +{ + ParameterHandler prm; + prm.declare_entry("a", "1"); + prm.enter_subsection("x"); + prm.declare_entry("a", "2"); + prm.enter_subsection("y"); + prm.declare_entry("a", "3"); + prm.declare_entry("b", "4"); + prm.leave_subsection(); + prm.enter_subsection("v"); + prm.enter_subsection("v"); + prm.enter_subsection("v"); + prm.declare_entry("a", "5"); + prm.declare_entry("b", "6"); + prm.leave_subsection(); + prm.declare_entry("a", "7"); + prm.leave_subsection(); + prm.leave_subsection(); + prm.enter_subsection("z"); + prm.declare_entry("a", "8"); + prm.leave_subsection(); + prm.leave_subsection(); + prm.declare_entry("b", "9"); + + /* + prm should now look like this + + # Listing of Parameters + # --------------------- + set a = 1 + set b = 9 + + subsection x + set a = 2 + + + subsection v + subsection v + set a = 7 + + + subsection v + set a = 5 + set b = 6 + end + + end + + end + + subsection y + set a = 3 + set b = 4 + end + + subsection z + set a = 8 + end + + end + + */ + + // reading from top level + std::vector path = {}; + log_entry(prm, path, "a"); + path.push_back("x"); + log_entry(prm, path, "a"); + path.push_back("y"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + path.push_back("v"); + path.push_back("v"); + path.push_back("v"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + log_entry(prm, path, "a"); + path.pop_back(); + path.pop_back(); + path.push_back("z"); + log_entry(prm, path, "a"); + path.pop_back(); + path.pop_back(); + log_entry(prm, path, "b"); + + // reading from other subsections + prm.enter_subsection("x"); + deallog << "in x" << std::endl; + log_entry(prm, path, "a"); + path.push_back("y"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + path.push_back("v"); + path.push_back("v"); + path.push_back("v"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + log_entry(prm, path, "a"); + path.pop_back(); + path.pop_back(); + path.push_back("z"); + log_entry(prm, path, "a"); + path.pop_back(); + + prm.enter_subsection("y"); + deallog << "in y" << std::endl; + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + + prm.leave_subsection(); + prm.enter_subsection("v"); + deallog << "in v (first)" << std::endl; + path.push_back("v"); + path.push_back("v"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + log_entry(prm, path, "a"); + path.pop_back(); + + prm.enter_subsection("v"); + deallog << "in v (second)" << std::endl; + path.push_back("v"); + log_entry(prm, path, "a"); + log_entry(prm, path, "b"); + path.pop_back(); + log_entry(prm, path, "a"); +} + +void +test_getting_types() +{ + ParameterHandler prm; + prm.enter_subsection("foo"); + prm.enter_subsection("bar"); + prm.declare_entry("jik", "1"); + prm.declare_entry("baz", "77.3"); + prm.declare_entry("yox", "true"); + prm.declare_entry("spam", "eggs"); + prm.leave_subsection(); + prm.leave_subsection(); + + deallog << "in test_getting_types top level" << std::endl; + + if (prm.get_integer({"foo", "bar"}, "jik") != 1) + deallog << "unexpected failure to read \"1\" as an integer" << std::endl; + + if (prm.get_double({"foo", "bar"}, "jik") != 1) + deallog << "unexpected failure to read \"1\" as a double" << std::endl; + + if (prm.get_double({"foo", "bar"}, "baz") != 77.3) + deallog << "unexpected failure to read \"77.3\" as a double" << std::endl; + + if (prm.get_bool({"foo", "bar"}, "yox") != true) + deallog << "unexpected failure to read \"true\" as a boolean" << std::endl; + + try + { + prm.get_integer({"foo", "bar"}, "baz"); + } + catch (StandardExceptions::ExcMessage &e) + { + log_exception(e); + } + + try + { + prm.get_integer({"foo", "bar"}, "yox"); + } + catch (StandardExceptions::ExcMessage &e) + { + log_exception(e); + } + + try + { + prm.get_double({"foo", "bar"}, "yox"); + } + catch (StandardExceptions::ExcMessage &e) + { + log_exception(e); + } + + try + { + prm.get_bool({"foo", "bar"}, "jik"); + } + catch (StandardExceptions::ExcMessage &e) + { + log_exception(e); + } + + try + { + prm.get_bool({"foo", "bar"}, "spam"); + } + catch (StandardExceptions::ExcMessage &e) + { + log_exception(e); + } +} + +void +test_weird_strings() +{ + const std::vector weird_strings = { + ".,/<[\"';:=-_)*&~\t`/.\\", + "$.7.%... = . -", + "`/=/a/!", + "<<>>>]]]\t\n\n ", + "****&//&%.^$!.$@$%@^*&(*)_/*-`~", + ".,/<[\"';:=-_)*&~\t`/.\\", + "value", + " set value = 5 \n\n."}; + + ParameterHandler prm; + + for (int i = 0; i < 6; ++i) + { + prm.enter_subsection(weird_strings[i]); + } + + prm.declare_entry(weird_strings[6], weird_strings[7]); + + for (int i = 0; i < 6; ++i) + { + prm.leave_subsection(); + } + + std::vector path = {}; + for (int i = 0; i < 3; ++i) + { + prm.enter_subsection(weird_strings[i]); + path.push_back(weird_strings[3 + i]); + } + + deallog << "in " << std::endl; + log_entry(prm, path, weird_strings[6]); +} + +int +main() +{ + initlog(); + + try + { + test_basic(); + test_getting_types(); + test_weird_strings(); + } + catch (std::exception &exc) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Exception on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + return 1; + } + catch (...) + { + deallog << std::endl + << std::endl + << "----------------------------------------------------" + << std::endl; + deallog << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + return 1; + }; + + return 0; +} diff --git a/tests/parameter_handler/parameter_handler_23.output b/tests/parameter_handler/parameter_handler_23.output new file mode 100644 index 0000000000..47efbf1572 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_23.output @@ -0,0 +1,41 @@ + +DEAL::a = 1 +DEAL::x.a = 2 +DEAL::x.y.a = 3 +DEAL::x.y.b = 4 +DEAL::x.v.v.v.a = 5 +DEAL::x.v.v.v.b = 6 +DEAL::x.v.v.a = 7 +DEAL::x.z.a = 8 +DEAL::b = 9 +DEAL::in x +DEAL::a = 2 +DEAL::y.a = 3 +DEAL::y.b = 4 +DEAL::v.v.v.a = 5 +DEAL::v.v.v.b = 6 +DEAL::v.v.a = 7 +DEAL::z.a = 8 +DEAL::in y +DEAL::a = 3 +DEAL::b = 4 +DEAL::in v (first) +DEAL::v.v.a = 5 +DEAL::v.v.b = 6 +DEAL::v.a = 7 +DEAL::in v (second) +DEAL::v.a = 5 +DEAL::v.b = 6 +DEAL::a = 7 +DEAL::in test_getting_types top level +DEAL::Can't convert the parameter value <77.3> for entry to an integer. +DEAL::Can't convert the parameter value for entry to an integer. +DEAL::Can't convert the parameter value for entry to a double precision variable. +DEAL::Can't convert the parameter value <1> for entry to a boolean. +DEAL::Can't convert the parameter value for entry to a boolean. +DEAL::in +DEAL::<<>>>]]] + + .****&//&%.^$!.$@$%@^*&(*)_/*-`~..,/<["';:=-_)*&~ `/.\.value = set value = 5 + +. -- 2.39.5