From 9937254763e5383708893fa26a009fdb033fbcf4 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Tue, 12 Jan 2021 23:44:50 +0100 Subject: [PATCH] ParameterAcceptor::enter/leave_subsection() --- doc/news/changes/minor/20210112LucaHeltai | 5 ++ include/deal.II/base/parameter_acceptor.h | 64 +++++++++++++++ source/base/parameter_acceptor.cc | 41 +++++++++- .../parameter_acceptor_10.cc | 81 +++++++++++++++++++ .../parameter_acceptor_10.output | 31 +++++++ 5 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 doc/news/changes/minor/20210112LucaHeltai create mode 100644 tests/parameter_handler/parameter_acceptor_10.cc create mode 100644 tests/parameter_handler/parameter_acceptor_10.output diff --git a/doc/news/changes/minor/20210112LucaHeltai b/doc/news/changes/minor/20210112LucaHeltai new file mode 100644 index 0000000000..64ab70b0ec --- /dev/null +++ b/doc/news/changes/minor/20210112LucaHeltai @@ -0,0 +1,5 @@ +New: Created two new methods ParameterAcceptor::enter_subsection() and +ParameterAcceptor::leave_subsection() that allow more intricated parameter +paths within ParameterAcceptor classes. +
+(Luca Heltai, 2021/01/12) diff --git a/include/deal.II/base/parameter_acceptor.h b/include/deal.II/base/parameter_acceptor.h index 79693c1f9b..51653b9f3a 100644 --- a/include/deal.II/base/parameter_acceptor.h +++ b/include/deal.II/base/parameter_acceptor.h @@ -516,6 +516,67 @@ public: */ static ParameterHandler prm; + /** + * Add the given @p subsection to the global path stored in this class. + * + * This function changes the behaviour of enter_my_subsection(), by + * appending a new subsection to the path stored in this class. + * + * This method can be used to split the parameters of this class into + * subsections, while still maintaining the general behaviour of this + * class. + * + * An example usage is given by the following snippet: + * @code + * class MyClass : public ParameterAcceptor + * { + * MyClass() + * : ParameterAcceptor("Main section") + * { + * add_parameter("A param", member_var); + * enter_subsection("New section"); + * add_parameter("Another param", another_member_var); + * leave_subsection(); + * } + * + * private: + * std::vector member_var = {1,2}; + * std::map another_member_var; + * ... + * }; + * + * int main() + * { + * // ParameterAcceptor::initialize() + * MyClass class; + * + * // With this call, all derived classes will have their + * // parameters initialized + * ParameterAcceptor::initialize("file.prm"); + * } + * @endcode + * + * which will produce a parameter file organized as + * + * @code + * subsection Main section + * set A param = 1, 2 + * subsection New section + * set Another param = + * end + * end + * @endcode + */ + void + enter_subsection(const std::string &subsection); + + /** + * Leave the subsection that was entered by calling the enter_subsection() + * function. + */ + void + leave_subsection(); + /** * Make sure we enter the right subsection of the given parameter. */ @@ -547,6 +608,9 @@ private: protected: /** The subsection name for this class. */ const std::string section_name; + + /** The subsubsections that are currently active. */ + std::vector subsections; }; diff --git a/source/base/parameter_acceptor.cc b/source/base/parameter_acceptor.cc index 063849be27..1dfbcfb8a9 100644 --- a/source/base/parameter_acceptor.cc +++ b/source/base/parameter_acceptor.cc @@ -39,11 +39,14 @@ ParameterAcceptor::ParameterAcceptor(const std::string &name) } + ParameterAcceptor::~ParameterAcceptor() { class_list[acceptor_id] = nullptr; } + + std::string ParameterAcceptor::get_section_name() const { @@ -52,6 +55,7 @@ ParameterAcceptor::get_section_name() const } + void ParameterAcceptor::initialize( const std::string & filename, @@ -96,6 +100,8 @@ ParameterAcceptor::initialize(std::istream &input_stream, ParameterHandler &prm) parse_all_parameters(prm); } + + void ParameterAcceptor::clear() { @@ -130,6 +136,8 @@ ParameterAcceptor::parse_all_parameters(ParameterHandler &prm) } } + + void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm) { @@ -144,6 +152,7 @@ ParameterAcceptor::declare_all_parameters(ParameterHandler &prm) } + std::vector ParameterAcceptor::get_section_path() const { @@ -182,9 +191,37 @@ ParameterAcceptor::get_section_path() const break; } } + // Finally, insert the remaining subsections + sections.insert(sections.end(), subsections.begin(), subsections.end()); return sections; } + + +void +ParameterAcceptor::enter_subsection(const std::string &subsection) +{ + AssertThrow(subsection.find(sep) == std::string::npos, + ExcMessage( + "A subsection name cannot contain the special character '/'")); + // First the easy case. + if (subsection == "") + return; + subsections.push_back(subsection); +} + + + +void +ParameterAcceptor::leave_subsection() +{ + AssertThrow(subsections.size() > 0, + ExcMessage("There is no subsection to leave here.")); + subsections.pop_back(); +} + + + void ParameterAcceptor::enter_my_subsection( ParameterHandler &prm = ParameterAcceptor::prm) @@ -196,6 +233,8 @@ ParameterAcceptor::enter_my_subsection( } } + + void ParameterAcceptor::leave_my_subsection( ParameterHandler &prm = ParameterAcceptor::prm) @@ -207,6 +246,4 @@ ParameterAcceptor::leave_my_subsection( } } - - DEAL_II_NAMESPACE_CLOSE diff --git a/tests/parameter_handler/parameter_acceptor_10.cc b/tests/parameter_handler/parameter_acceptor_10.cc new file mode 100644 index 0000000000..e1a9aa1bbb --- /dev/null +++ b/tests/parameter_handler/parameter_acceptor_10.cc @@ -0,0 +1,81 @@ +//----------------------------------------------------------- +// +// Copyright (C) 2017 - 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. +// +//----------------------------------------------------------- + + +// Test subsectioning within parameter acceptor itself + +#include +#include + +#include "../tests.h" + +class Test : public ParameterAcceptor +{ +public: + Test(const std::string &sec_name = "First Class", + const std::string &par_name = "Parameter name", + const std::string &par_value = "Parameter value", + const std::string &subsection_name = "") + : ParameterAcceptor(sec_name) + , par_name(par_name) + , par_value(par_value) + { + if (subsection_name != "") + enter_subsection(subsection_name); + add_parameter(par_name, this->par_value); + if (subsection_name != "") + leave_subsection(); + + deallog << "Section Name : " << sec_name << std::endl; + deallog << "N sections : " << get_section_path().size() << std::endl; + deallog << "Sections : "; + for (auto s : get_section_path()) + deallog << "\"" << s << "\" "; + deallog << std::endl << std::endl; + }; + +private: + std::string par_name; + std::string par_value; + std::string subsection_name; +}; + +int +main() +{ + initlog(); + auto &prm = ParameterAcceptor::prm; + + // Relative, no subsections + Test a("Class A", "Parameter A", "a"); + + // Relative, with subsection + Test c("Class B", "Parameter C", "c", "Subsection B"); + + // Explicit, with absolute path + Test d1("/Class D/Class D1", "Parameter D1", "d"); + + // Relative to previous, with trailing + Test d2("Class D2/", "Parameter D2", "d"); + + // Relative to previous + Test d3("Class D2D3", "Parameter D2D3", "e"); + + // Relative to previous, with subsection + Test d4("Class D2D3", "Parameter D2D3", "e", "Subsection D2D3"); + + ParameterAcceptor::declare_all_parameters(); + prm.log_parameters(deallog); +} diff --git a/tests/parameter_handler/parameter_acceptor_10.output b/tests/parameter_handler/parameter_acceptor_10.output new file mode 100644 index 0000000000..5d9711ead5 --- /dev/null +++ b/tests/parameter_handler/parameter_acceptor_10.output @@ -0,0 +1,31 @@ + +DEAL::Section Name : Class A +DEAL::N sections : 1 +DEAL::Sections : "Class A" +DEAL:: +DEAL::Section Name : Class B +DEAL::N sections : 1 +DEAL::Sections : "Class B" +DEAL:: +DEAL::Section Name : /Class D/Class D1 +DEAL::N sections : 2 +DEAL::Sections : "Class D" "Class D1" +DEAL:: +DEAL::Section Name : Class D2/ +DEAL::N sections : 2 +DEAL::Sections : "Class D" "Class D2" +DEAL:: +DEAL::Section Name : Class D2D3 +DEAL::N sections : 3 +DEAL::Sections : "Class D" "Class D2" "Class D2D3" +DEAL:: +DEAL::Section Name : Class D2D3 +DEAL::N sections : 3 +DEAL::Sections : "Class D" "Class D2" "Class D2D3" +DEAL:: +DEAL:parameters:Class A::Parameter A: a +DEAL:parameters:Class B:Subsection B::Parameter C: c +DEAL:parameters:Class D:Class D1::Parameter D1: d +DEAL:parameters:Class D:Class D2::Parameter D2: d +DEAL:parameters:Class D:Class D2:Class D2D3::Parameter D2D3: e +DEAL:parameters:Class D:Class D2:Class D2D3:Subsection D2D3::Parameter D2D3: e -- 2.39.5