From 7661f33615e421b1e9f2747e3b68a9c5b22d0b7f Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Sun, 22 Mar 2015 17:46:32 -0500 Subject: [PATCH] Introduce ways to define aliases for parameters. --- doc/news/changes.h | 8 ++ include/deal.II/base/parameter_handler.h | 48 +++++++- source/base/parameter_handler.cc | 114 +++++++++++++++--- .../bits/parameter_handler_3_with_alias_01.cc | 86 +++++++++++++ .../parameter_handler_3_with_alias_01.output | 13 ++ .../bits/parameter_handler_3_with_alias_02.cc | 86 +++++++++++++ .../parameter_handler_3_with_alias_02.output | 13 ++ 7 files changed, 344 insertions(+), 24 deletions(-) create mode 100644 tests/bits/parameter_handler_3_with_alias_01.cc create mode 100644 tests/bits/parameter_handler_3_with_alias_01.output create mode 100644 tests/bits/parameter_handler_3_with_alias_02.cc create mode 100644 tests/bits/parameter_handler_3_with_alias_02.output diff --git a/doc/news/changes.h b/doc/news/changes.h index c544c40428..14c559f78c 100644 --- a/doc/news/changes.h +++ b/doc/news/changes.h @@ -411,6 +411,14 @@ inconvenience this causes. (Wolfgang Bangerth, 2015/03/23) +
  • New: ParameterHandler::declare_alias() allows to define + alternate names for parameters. This is primarily intended to allow + for backward compatible ways of changing the names of parameters + to applications. +
    + (Wolfgang Bangerth, 2015/03/22) +
  • +
  • New: GridGenerator::create_triangulation_with_removed_cells() creates a new mesh out of an existing one by dropping individual cells.
    diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index 55b9e56ca2..5b5e1b3e33 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -1,6 +1,6 @@ // --------------------------------------------------------------------- // -// Copyright (C) 1998 - 2014 by the deal.II authors +// Copyright (C) 1998 - 2015 by the deal.II authors // // This file is part of the deal.II library. // @@ -1647,6 +1647,47 @@ public: const Patterns::PatternBase &pattern = Patterns::Anything(), const std::string &documentation = std::string()); + /** + * Create an alias for an existing entry. This provides a way to refer + * to a parameter in the input file using an alternate name. The + * alias will be in the current section, and the referenced entry needs + * to be an existing entry in the current section. + * + * The primary purpose of this function is to allow for a backward + * compatible way of changing names in input files of applications + * for which backward compatibility is important. This can be + * achieved by changing the name of the parameter in the call to + * declare_entry(), and then creating an alias that maps the old + * name to the new name. This way, old input files can continue + * to refer to parameters under the old name, and they will + * automatically be mapped to the new parameter name. + * + * It is valid to reference in a parameter file to the same parameter + * multiple times. The value that will ultimately be chosen in such + * cases is simply the last value set. This rule also applies to + * aliases, where the final value of a parameter is the last value + * set either through the current name of the parameter or through + * any of its possible multiple aliases. For example, if you have + * an input file that looks like + * @code + * set parm1 = 1 + * set parm1_alias = 2 + * @endcode + * where parm1_alias is an alias declared via + * @code + * prm.declare_alias ("parm1", "parm1_alias"); + * @endcode + * then the final value for the parameter called parm1 + * will be 2, not 1. + * + * @param existing_entry_name The name of an existing parameter + * in the current section that the alias should refer to. + * @param alias_name An alternate name for the parameter referenced + * by the first argument. + */ + void declare_alias (const std::string &existing_entry_name, + const std::string &alias_name); + /** * Enter a subsection. If it does not yet exist, create it. */ @@ -1922,11 +1963,6 @@ private: */ static std::string demangle (const std::string &s); - /** - * Return whether a given node is a parameter node or a subsection node. - */ - static bool is_parameter_node (const boost::property_tree::ptree &); - /** * Path of presently selected subsections; empty list means top level */ diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 7144a41065..a246f59ff6 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -1,6 +1,6 @@ // --------------------------------------------------------------------- // -// Copyright (C) 1998 - 2014 by the deal.II authors +// Copyright (C) 1998 - 2015 by the deal.II authors // // This file is part of the deal.II library. // @@ -1271,13 +1271,30 @@ ParameterHandler::demangle (const std::string &s) -bool -ParameterHandler::is_parameter_node (const boost::property_tree::ptree &p) +namespace { - return static_cast(p.get_optional("value")); -} + /** + * Return whether a given node is a parameter node (as opposed + * to being a subsection or alias node) + */ + bool + is_parameter_node (const boost::property_tree::ptree &p) + { + return static_cast(p.get_optional("value")); + } + /** + * Return whether a given node is a alias node (as opposed + * to being a subsection or parameter node) + */ + bool + is_alias_node (const boost::property_tree::ptree &p) + { + return static_cast(p.get_optional("alias")); + } +} + std::string ParameterHandler::get_current_path () const @@ -1486,6 +1503,13 @@ namespace return false; } } + else if (p->second.get_optional("alias")) + { + // it is an alias node. alias nodes are static and + // there is nothing to do here (but the same applies as + // mentioned in the comment above about the static + // nodes inside parameter nodes + } else { // it must be a subsection @@ -1610,6 +1634,52 @@ ParameterHandler::declare_entry (const std::string &entry, +void +ParameterHandler::declare_alias(const std::string &existing_entry_name, + const std::string &alias_name) +{ + // see if there is anything to refer to already + Assert (entries->get_optional(get_current_full_path(existing_entry_name)), + ExcMessage ("You are trying to declare an alias entry <" + + alias_name + + "> that references an entry <" + + existing_entry_name + + ">, but the latter does not exist.")); + + // now also make sure that if the alias has already been + // declared, that it is also an alias and refers to the same + // entry + if (entries->get_optional(get_current_full_path(alias_name))) + { + Assert (entries->get_optional (get_current_full_path(alias_name) + path_separator + "alias"), + ExcMessage ("You are trying to declare an alias entry <" + + alias_name + + "> but a non-alias entry already exists in this " + "subsection (i.e., there is either a preexisting " + "further subsection, or a parameter entry, with " + "the same name as the alias).")); + Assert (entries->get (get_current_full_path(alias_name) + path_separator + "alias") + == + existing_entry_name, + ExcMessage ("You are trying to declare an alias entry <" + + alias_name + + "> but an alias entry already exists in this " + "subsection and this existing alias references a " + "different parameter entry. Specifically, " + "you are trying to reference the entry <" + + existing_entry_name + + "> whereas the existing alias references " + "the entry <" + + entries->get (get_current_full_path(alias_name) + path_separator + "alias") + + ">.")); + } + + entries->put (get_current_full_path(alias_name) + path_separator + "alias", + existing_entry_name); +} + + + void ParameterHandler::enter_subsection (const std::string &subsection) { const std::string current_path = get_current_path (); @@ -1717,21 +1787,24 @@ void ParameterHandler::set (const std::string &entry_string, const std::string &new_value) { - // assert that the entry is indeed - // declared - if (entries->get_optional - (get_current_full_path(entry_string) + path_separator + "value")) + // resolve aliases before looking up the correct entry + std::string path = get_current_full_path(entry_string); + if (entries->get_optional(path + path_separator + "alias")) + path = get_current_full_path(entries->get(path + path_separator + "alias")); + + // assert that the entry is indeed declared + if (entries->get_optional(path + path_separator + "value")) { const unsigned int pattern_index - = entries->get (get_current_full_path(entry_string) + path_separator + "pattern"); + = entries->get (path + path_separator + "pattern"); AssertThrow (patterns[pattern_index]->match(new_value), ExcValueDoesNotMatchPattern (new_value, entries->get - (get_current_full_path(entry_string) + + (path + path_separator + "pattern_description"))); - entries->put (get_current_full_path(entry_string) + path_separator + "value", + entries->put (path + path_separator + "value", new_value); } else @@ -2219,7 +2292,7 @@ ParameterHandler::print_parameters_section (std::ostream &out, p != current_section.end(); ++p) if (is_parameter_node (p->second) == true) ++n_parameters; - else + else if (is_alias_node (p->second) == false) ++n_sections; if ((style != Description) @@ -2236,7 +2309,9 @@ ParameterHandler::print_parameters_section (std::ostream &out, for (boost::property_tree::ptree::const_assoc_iterator p = current_section.ordered_begin(); p != current_section.not_found(); ++p) - if (is_parameter_node (p->second) == false) + if ((is_parameter_node (p->second) == false) + && + (is_alias_node (p->second) == false)) { // first print the subsection header switch (style) @@ -2482,11 +2557,14 @@ ParameterHandler::scan_line (std::string line, std::string entry_name (line, 0, line.find('=')); std::string entry_value (line, line.find('=')+1, std::string::npos); - const std::string current_path = get_current_path (); + // resolve aliases before we look up the entry + std::string path = get_current_full_path(entry_name); + if (entries->get_optional(path + path_separator + "alias")) + path = get_current_full_path(entries->get(path + path_separator + "alias")); // assert that the entry is indeed // declared - if (entries->get_optional (get_current_full_path(entry_name) + path_separator + "value")) + if (entries->get_optional (path + path_separator + "value")) { // if entry was declared: // does it match the regex? if not, @@ -2497,7 +2575,7 @@ ParameterHandler::scan_line (std::string line, if (entry_value.find ('{') == std::string::npos) { const unsigned int pattern_index - = entries->get (get_current_full_path(entry_name) + path_separator + "pattern"); + = entries->get (path + path_separator + "pattern"); if (!patterns[pattern_index]->match(entry_value)) { std::cerr << "Line <" << lineno @@ -2514,7 +2592,7 @@ ParameterHandler::scan_line (std::string line, } } - entries->put (get_current_full_path(entry_name) + path_separator + "value", + entries->put (path + path_separator + "value", entry_value); return true; } diff --git a/tests/bits/parameter_handler_3_with_alias_01.cc b/tests/bits/parameter_handler_3_with_alias_01.cc new file mode 100644 index 0000000000..7083f24014 --- /dev/null +++ b/tests/bits/parameter_handler_3_with_alias_01.cc @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2003 - 2015 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +// like _03, but use an alias to reference two parameters using the same name. +// in the _with_alias_01 testcase, the alias doesn't do anything (we just +// declare it, but the input file still references the original name) whereas +// the _with_alias_02 does it the other way around + +#include "../tests.h" +#include +#include +#include +#include + + +int main () +{ + try + { + std::ofstream logfile("output"); + deallog.attach(logfile); + deallog.depth_console(0); + deallog.threshold_double(1.e-10); + + ParameterHandler prm; + prm.enter_subsection ("Testing"); + prm.declare_entry ("string list", + "a", + Patterns::List(Patterns::Selection("a|b|c|d|e|f|g|h")), + "docs 1"); + prm.declare_entry ("int", + "1", + Patterns::Integer()); + prm.declare_entry ("double", + "3.1415926", + Patterns::Double(), + "docs 3"); + prm.declare_alias ("int", + "int_alias"); + prm.leave_subsection (); + + // read and then write parameters + prm.read_input(SOURCE_DIR "/prm/parameter_handler_3.prm"); + prm.print_parameters (logfile, ParameterHandler::Text); + } + 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/bits/parameter_handler_3_with_alias_01.output b/tests/bits/parameter_handler_3_with_alias_01.output new file mode 100644 index 0000000000..cf97eae312 --- /dev/null +++ b/tests/bits/parameter_handler_3_with_alias_01.output @@ -0,0 +1,13 @@ + +# Listing of Parameters +# --------------------- +subsection Testing + # docs 3 + set double = 3.1415926 + set int = 3 # default: 1 + + # docs 1 + set string list = a, b, c # default: a +end + + diff --git a/tests/bits/parameter_handler_3_with_alias_02.cc b/tests/bits/parameter_handler_3_with_alias_02.cc new file mode 100644 index 0000000000..08d7b5ea9c --- /dev/null +++ b/tests/bits/parameter_handler_3_with_alias_02.cc @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2003 - 2015 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 at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + + +// like _03, but use an alias to reference two parameters using the same name +// in the _with_alias_01 testcase, the alias doesn't do anything (we just +// declare it, but the input file still references the original name) whereas +// the _with_alias_02 does it the other way around + +#include "../tests.h" +#include +#include +#include +#include + + +int main () +{ + try + { + std::ofstream logfile("output"); + deallog.attach(logfile); + deallog.depth_console(0); + deallog.threshold_double(1.e-10); + + ParameterHandler prm; + prm.enter_subsection ("Testing"); + prm.declare_entry ("string list", + "a", + Patterns::List(Patterns::Selection("a|b|c|d|e|f|g|h")), + "docs 1"); + prm.declare_entry ("int_alias", + "1", + Patterns::Integer()); + prm.declare_entry ("double", + "3.1415926", + Patterns::Double(), + "docs 3"); + prm.declare_alias ("int_alias", + "int"); + prm.leave_subsection (); + + // read and then write parameters + prm.read_input(SOURCE_DIR "/prm/parameter_handler_3.prm"); + prm.print_parameters (logfile, ParameterHandler::Text); + } + 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/bits/parameter_handler_3_with_alias_02.output b/tests/bits/parameter_handler_3_with_alias_02.output new file mode 100644 index 0000000000..4d123c17b5 --- /dev/null +++ b/tests/bits/parameter_handler_3_with_alias_02.output @@ -0,0 +1,13 @@ + +# Listing of Parameters +# --------------------- +subsection Testing + # docs 3 + set double = 3.1415926 + set int_alias = 3 # default: 1 + + # docs 1 + set string list = a, b, c # default: a +end + + -- 2.39.5