]> https://gitweb.dealii.org/ - dealii.git/commitdiff
ParameterAcceptor class.
authorLuca Heltai <luca.heltai@sissa.it>
Wed, 20 Sep 2017 09:27:19 +0000 (11:27 +0200)
committerLuca Heltai <luca.heltai@sissa.it>
Tue, 26 Sep 2017 17:19:23 +0000 (19:19 +0200)
include/deal.II/base/parameter_acceptor.h [new file with mode: 0644]
source/base/CMakeLists.txt
source/base/parameter_acceptor.cc [new file with mode: 0644]
tests/parameter_handler/parameter_acceptor_01.cc [new file with mode: 0644]
tests/parameter_handler/parameter_acceptor_01.output [new file with mode: 0644]

diff --git a/include/deal.II/base/parameter_acceptor.h b/include/deal.II/base/parameter_acceptor.h
new file mode 100644 (file)
index 0000000..27fc2a8
--- /dev/null
@@ -0,0 +1,517 @@
+//-----------------------------------------------------------
+//
+//    Copyright (C) 2014 - 2016 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.
+//
+//-----------------------------------------------------------
+
+#ifndef dealii_base_parameter_acceptor_h
+#define dealii_base_parameter_acceptor_h
+
+#include <deal.II/base/config.h>
+#include <deal.II/base/parameter_handler.h>
+#include <deal.II/base/smartpointer.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/exceptions.h>
+#include <boost/signals2/signal.hpp>
+#include <typeinfo>
+
+DEAL_II_NAMESPACE_OPEN
+
+/**
+ * A parameter acceptor base class. This class is used to define a public
+ * interface for classes wich want to use a single global ParameterHandler to
+ * handle parameters. This class declares one static ParameterHandler, and two
+ * static functions (declare_all_parameters() and parse_all_parameters()) that
+ * manage all of the derived classes.
+ *
+ * The basic interface provides two subscription mechanisms: a **global
+ * subscription mechanism** and a **local subscription mechanism**.
+ *
+ * The global subscription mechanism is such that whenever a class that was
+ * derived by ParameterAcceptor is constructed, a static registry
+ * (ParameterAcceptor::class_list) in the base class is updated with a pointer
+ * to the derived class, and a path in the parameter file. Such registry is
+ * traversed upon invocation of the single function
+ * ParameterAcceptor::initialize(file.prm) which in turn calls the method
+ * ParameterAcceptor::declare_parameters() for each of the registered classes,
+ * reads the file `file.prm` and subsequently calls the method
+ * ParameterAcceptor::parse_parameters(), again for each of the registered
+ * classes. The method log_info() can be used to extract informations about the
+ * classes that have been derived from ParameterAcceptor, and that will be
+ * parsed when calling ParameterAcceptor::initialize().
+ *
+ * ParameterAcceptor can be used in two different ways: by overloading the
+ * ParameterAcceptor::declare_parameters() and
+ * ParameterAcceptor::parse_parameters() methods, or by calling its
+ * ParameterAcceptor::add_parameter() method for each parameter we want to
+ * have. This in turns makes sure that the given parameter is registered in the
+ * global parameter handler (by calling ParameterHandler::add_parameter()), at
+ * the correct path. If you define all your parameters using the
+ * ParameterAcceptor::add_parameter() method, then you don't need to overload
+ * any of the virtual methods of this class.
+ *
+ * If some post processing is required on the parsed values, the user can
+ * attach a signal to ParameterAcceptor::parse_parameters_call_back can be
+ * overridden, which is called just after the parse_parameters() function of
+ * each class.
+ *
+ * A typical usage of this class is the following:
+ *
+ * @code
+ * // This is your own class, derived from ParameterAcceptor
+ * class MyClass : public ParameterAcceptor {
+ *
+ * // The constructor of ParameterAcceptor requires a std::string,
+ * // which defines the section name where the parameters of MyClass
+ * // will be stored.
+ *
+ * MyClass(std::string name) :
+ *   ParameterAcceptor(name)
+ * {
+ *    add_parameter("A param", member_var);
+ * }
+ *
+ * private:
+ *   std::vector<unsigned int> member_var;
+ * ...
+ * };
+ *
+ * int main() {
+ *  // Make sure you build your class BEFORE calling
+ *  // ParameterAcceptor::initialize()
+ *  MyClass class;
+ *
+ *  // With this call, all derived classes will have their
+ *  // parameters initialized
+ *  ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ *
+ * An implementation that uses user defined declare and parse functions is given
+ * by the following example:
+ *
+ * @code
+ * // Again your own class, derived from ParameterAcceptor
+ * class MyClass : public ParameterAcceptor {
+ *
+ * MyClass(std::string name) :
+ *   ParameterAcceptor(name)
+ *   {}
+ *
+ *   virtual void declare_parameters(ParameterHandler &prm) {
+ *    ...
+ *   }
+ *
+ *   virtual void parse_parameters(ParameterHandler &prm) {
+ *     ...
+ *   }
+ * };
+ *
+ * int main() {
+ *  // Make sure you build your class BEFORE calling
+ *  // ParameterAcceptor::initialize()
+ *  MyClass class;
+ *  ParameterAcceptor::initialize("file.prm");
+ *  class.run();
+ * }
+ * @endcode
+ *
+ *
+ * Parameter files can be organised into section/subsection/subsubsection.
+ * To do so, the std::string passed to ParameterAcceptor within the
+ * constructor of the derived class needs to contain the separator "/".
+ * In fact, "first/second/third/My Class" will organize the parameters
+ * as follows
+ *
+ * @code
+ * subsection first
+ *   subsection second
+ *     subsection third
+ *       subsection My Class
+ *        ... # all the parameters
+ *       end
+ *     end
+ *   end
+ * end
+ * @endcode
+ *
+ * In the following examles, we propose some use cases with increasing
+ * complexities.
+ *
+ * MyClass is derived from ParameterAcceptor and has a
+ * member object that is derived itself from ParameterAcceptor.
+ * @code
+ * class MyClass : public ParameterAcceptor
+ * {
+ *   MyClass (std::string name);
+ *   virtual void declare_parameters(ParameterHandler &prm);
+ * private:
+ *   SomeParsedClass<dim> my_subclass;
+ *  ...
+ * };
+ *
+ * MyClass::MyClass(std::string name)
+ *  :
+ * ParameterAcceptor(name),
+ * my_subclass("Forcing term")
+ * {}
+ *
+ * void MyClass::declare_parmeters(ParameterHandler &prm)
+ * {
+ *  // many add_parameter(...);
+ * }
+ *
+ * ...
+ *
+ * int main()
+ * {
+ * MyClass mc("My Class");
+ *
+ * ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ *
+ * In this case, the structure of the parameters will be
+ * @code
+ * subsection Forcing term
+ * ... #parameters of SomeParsedClass
+ * end
+ * subsection My class
+ * ... #all the parameters of MyClass defined in declare_parameters
+ * end
+ * @endcode
+ * Note that the sections are alphabetically sorted.
+ *
+ * Now suppose that in the main file we need two or more objects of MyClass
+ * @code
+ * int main()
+ * {
+ *  MyClass ca("Class A");
+ *  MyClass cb("Class B");
+ *  ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ *
+ * What we will read in the parameter file looks like
+ * @code
+ * subsection Class A
+ * ...
+ * end
+ * subsection Class B
+ * ...
+ * end
+ * subsection Forcing term
+ * ...
+ * end
+ * @endcode
+ * Note that there is only one section "Forcing term", this is because
+ * both objects have defined the same name for the section of their
+ * SomeParsedClass. There are two strategies to manage this issue. The
+ * first one (not recommended) would be to change the name of the section
+ * of SomeParsedClass such that it contains also the string passed to
+ * the constructor of MyClass:
+ * @code
+ * MyClass::MyClass(std::string name)
+ *  :
+ * ParameterAcceptor(name),
+ * my_subclass(name+" --- forcing term")
+ * {}
+ * @endcode
+ *
+ * The other way to proceed (recommended) is to use exploit the /section/subsection
+ * approach **in the main class**.
+ * @code
+ * int main()
+ * {
+ *  MyClass ca("/Class A/Class");
+ *  MyClass cb("/Class B/Class");
+ *  ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ * Now, in the parameter file we can find
+ * @code
+ * subsection Class A
+ *   subsection Class
+ *   ...
+ *   end
+ *   subsection Forcing term
+ *   ...
+ *   end
+ * end
+ * subsection Class B
+ *   subsection Class
+ *   ...
+ *   end
+ *   subsection Forcing term
+ *   ...
+ *   end
+ * end
+ * @endcode
+ * Note the "/" at the begin of the string name. This is interpreted by
+ * ParameterAcceptor like the root folder in Unix systems. This means
+ * that the sections "Class A" and "Class B" will not be nested under any
+ * section. On the other hand, if the string does not begin with a "/"
+ * as in the previous cases (and for the ParsedFunction also in this last
+ * example) the section will be created **under the current path**, which
+ * depends on the previously defined sections/subsections/subsubsections.
+ * Indeed, the section "Forcing term" is nested under "Class A" or "Class B".
+ * To make things more clear. let's consider the following two examples
+ * @code
+ * int main()
+ * {
+ *  MyClass ca("/Class A/Class");
+ *  MyClass cb("Class B/Class");
+ *  ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ * The parameter file will have the following structure
+ * @code
+ * subsection Class A
+ *   subsection Class
+ *   ...
+ *   end
+ *   subsection Forcing term
+ *   ...
+ *   end
+ *   subsection Class B
+ *     subsection Class
+ *     ...
+ *     end
+ *     subsection Forcing term
+ *     ...
+ *     end
+ *   end
+ * end
+ * @endcode
+ *
+ * If instead one of the paths ends with "/" instead of just
+ * a name of the class, subsequent classes will be declared
+ * under the full path, as if the class name should be interpreted
+ * as a directory:
+ * @code
+ * int main()
+ * {
+ *  MyClass ca("/Class A/Class/");
+ *  MyClass cb("Class B/Class");
+ *  ParameterAcceptor::initialize("file.prm");
+ * }
+ * @endcode
+ * The parameter file will have the following structure
+ * @code
+ * subsection Class A
+ *   subsection Class
+ *      ...
+ *      subsection Forcing term
+ *      ...
+ *      end
+ *      subsection Class B
+ *          subsection Class
+ *          ...
+ *          end
+ *          subsection Forcing term
+ *          ...
+ *          end
+ *      end
+ *   end
+ * end
+ * @endcode
+ *
+ * As a final remark, in order to allow a proper management of all the
+ * sections/subsections, the instantiation of objects and the call to
+ * ParameterAcceptor::initialize() **cannot be done in multithread**.
+ *
+ * If you pass an empty name, the boost::core::demangle() function is used to
+ * fill the section name with a human readable version of the class name
+ * itself.
+ *
+ * @author Luca Heltai, 2017.
+ */
+class ParameterAcceptor : public Subscriptor
+{
+public:
+  /**
+   * The constructor adds derived classes to the list of acceptors. If
+   * a section name is specified, then this is used to scope the
+   * parameters in the given section, otherwise a pretty printed
+   * version of the derived class is used.
+   */
+  ParameterAcceptor(const std::string section_name="");
+
+  /**
+   * The destructor sets to zero the pointer relative to this index,
+   * so that it is safe to destroy the mother class.
+   */
+  virtual ~ParameterAcceptor();
+
+  /**
+   * Call declare_all_parameters(), read filename (if it is present as input
+   * parameter) and parse_all_parameters() on the static member prm. If
+   * outfilename is not the emtpy string, then write the content that was read
+   * in to the outfilename. The format of both input and output files are
+   * selected using the extensions of the files themselves. This can be either
+   * `prm` or `xml`. If the output format is `prm`, then the
+   * `output_style_for_prm_format` is used to decide wether we write the full
+   * documentation as well, or only the parameters.
+   *
+   * If the input file does not exist, a default one with the same name is created
+   * for you, and an exception is thrown.
+   *
+   * @param filename Input file name
+   * @param output_filename Output file name
+   * @param output_style_for_prm_format How to write the output file if format is `prm`
+   */
+  static void initialize(const std::string filename,
+                         const std::string output_filename="",
+                         const ParameterHandler::OutputStyle output_style_for_prm_format=ParameterHandler::ShortText);
+
+  /**
+   * Clear class list and global parameter file.
+   */
+  static void clear();
+
+  /**
+   * Declare parameter entries of the derived class.
+   */
+  virtual void declare_parameters(ParameterHandler &prm);
+
+  /**
+   * Declare parameter call back. This function is called at the end of
+   * declare_all_parameters, to allow users to process their parameters right
+   * after they have been parsed. The default implementation is empty.
+   *
+   * You can use this function, for example, to create a quadrature
+   * rule after you have read how many quadrature points you wanted
+   * to use from the parameter file.
+   */
+  boost::signals2::signal<void()> declare_parameters_call_back;
+
+  /**
+   * Parse the (derived class) parameters.
+   */
+  virtual void parse_parameters(ParameterHandler &prm);
+
+  /**
+   * Parse parameter call back. This function is called at the end of
+   * parse_all_parameters, to allow users to process their parameters right
+   * after they have been parsed. The default implementation is empty.
+   *
+   * You can use this function, for example, to create a quadrature
+   * rule after you have read how many quadrature points you wanted
+   * to use from the parameter file.
+   */
+  boost::signals2::signal<void()> parse_parameters_call_back;
+
+  /**
+   * Parse the given ParameterHandler. This function enters the
+   * subsection returned by get_section_name() for each derived class,
+   * and parses all parameters that were added using add_parameter().
+   */
+  static void parse_all_parameters(ParameterHandler &prm=ParameterAcceptor::prm);
+
+
+  /**
+   * Print information to deallog about all stored classes.
+   */
+  static void log_info();
+
+
+  /**
+   * Initialize the global ParameterHandler with all derived classes
+   * parameters.This function enters the subsection returned by
+   * get_section_name() for each derived class, and declares all parameters
+   * that were added using add_parameter().
+   */
+  static void declare_all_parameters(ParameterHandler &prm=ParameterAcceptor::prm);
+
+
+  /**
+   * Return the section name of this class. If a name was provided
+   * at construction time, then that name is returned, otherwise it
+   * returns the name of this class, pretty printed.
+   */
+  std::string get_section_name() const;
+
+  /**
+   * Travers all registered classes, and figure out what
+   * subsections we need to enter.
+   */
+  std::vector<std::string> get_section_path() const;
+
+  /**
+   * Add a parameter in the correct path. This method forwards all arguments to
+   * the ParameterHandler::add_parameter() method, after entering the correct
+   * section path.
+   *
+   * See the documentation of ParameterHandler::add_parameter() for more
+   * information.
+   */
+  template <class ParameterType>
+  void add_parameter(const std::string &entry,
+                     ParameterType &parameter,
+                     const std::string &documentation = std::string(),
+                     const Patterns::PatternBase &pattern =
+                       *Patterns::Tools::Convert<ParameterType>::to_pattern());
+
+  /**
+   * The global parameter handler.
+   */
+  static ParameterHandler prm;
+
+private:
+  /**
+   * Make sure we enter the right subsection of the global parameter file.
+   */
+  void enter_my_subsection(ParameterHandler &prm);
+
+  /**
+   * This function undoes what the enter_my_subsection() function did. It only
+   * makes sense if enter_my_subsection() is called before this one.
+   */
+  void leave_my_subsection(ParameterHandler &prm);
+
+  /**
+   * A list containing all constructed classes of type
+   * ParameterAcceptor.
+   */
+  static std::vector<SmartPointer<ParameterAcceptor> > class_list;
+
+  /** The index of this specific class within the class list. */
+  const unsigned int acceptor_id;
+
+  /**
+   * Separator between section and subsection.
+   */
+  static const char sep = '/';
+
+protected:
+  /** The subsection name for this class. */
+  const std::string section_name;
+};
+
+
+// Inline and template functions
+template<class ParameterType>
+void ParameterAcceptor::add_parameter(const std::string& entry,
+                                      ParameterType& parameter,
+                                      const std::string& documentation,
+                                      const Patterns::PatternBase& pattern)
+{
+  enter_my_subsection(prm);
+  prm.add_parameter(entry, parameter, documentation, pattern);
+  leave_my_subsection(prm);
+}
+
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
+
index 172607dcafa2df5d0ba47b4916493fd28c88fb4f..a525a152e613a34ea3659bf84ebd9922eb12046e 100644 (file)
@@ -47,6 +47,7 @@ SET(_unity_include_src
   named_selection.cc
   parallel.cc
   parameter_handler.cc
+  parameter_acceptor.cc
   parsed_function.cc
   partitioner.cc
   patterns.cc
diff --git a/source/base/parameter_acceptor.cc b/source/base/parameter_acceptor.cc
new file mode 100644 (file)
index 0000000..e0213ad
--- /dev/null
@@ -0,0 +1,237 @@
+//-----------------------------------------------------------
+//
+//    Copyright (C) 2015 - 2016 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.
+//
+//-----------------------------------------------------------
+
+#include <deal.II/base/parameter_acceptor.h>
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/revision.h>
+#include <deal.II/base/path_search.h>
+#include <boost/core/demangle.hpp>
+#include <fstream>
+
+DEAL_II_NAMESPACE_OPEN
+
+
+// Static empty class list
+std::vector<SmartPointer<ParameterAcceptor> > ParameterAcceptor::class_list;
+// Static parameter handler
+ParameterHandler ParameterAcceptor::prm;
+
+ParameterAcceptor::ParameterAcceptor(const std::string name) :
+  acceptor_id(class_list.size()),
+  section_name(name)
+{
+  SmartPointer<ParameterAcceptor> pt(this, boost::core::demangle(typeid(*this).name()).c_str());
+  class_list.push_back(pt);
+}
+
+
+ParameterAcceptor::~ParameterAcceptor()
+{
+  class_list[acceptor_id] = 0;
+}
+
+std::string ParameterAcceptor::get_section_name() const
+{
+  return (section_name != "" ? section_name : boost::core::demangle(typeid(*this).name()));
+}
+
+
+void
+ParameterAcceptor::initialize(const std::string filename,
+                              const std::string output_filename,
+                              const ParameterHandler::OutputStyle output_style_for_prm_format)
+{
+  declare_all_parameters();
+  // check the extension of input file
+  if (filename.substr(filename.find_last_of(".") + 1) == "prm")
+    {
+      try
+        {
+          prm.parse_input(filename);
+        }
+      catch (dealii::PathSearch::ExcFileNotFound)
+        {
+          std::ofstream out(filename);
+          Assert(out, ExcIO());
+          prm.print_parameters(out, ParameterHandler::Text);
+          out.close();
+          AssertThrow(false, ExcMessage("You specified "+filename+" as input "+
+                                        "parameter file, but it does not exist. " +
+                                        "We created one for you."));
+        }
+    }
+  else if (filename.substr(filename.find_last_of(".") + 1) == "xml")
+    {
+      std::ifstream is(filename);
+      if (!is)
+        {
+          std::ofstream out(filename);
+          Assert(out, ExcIO());
+          prm.print_parameters(out, ParameterHandler::XML);
+          out.close();
+          is.clear();
+          AssertThrow(false, ExcMessage("You specified "+filename+" as input "+
+                                        "parameter file, but it does not exist. " +
+                                        "We created one for you."));
+        }
+      prm.parse_input_from_xml(is);
+    }
+  else
+    AssertThrow(false, ExcMessage("Invalid extension of parameter file. Please use .prm or .xml"));
+
+  parse_all_parameters();
+  if (output_filename != "")
+    {
+      std::ofstream outfile(output_filename.c_str());
+      Assert(outfile, ExcIO());
+      std::string extension = output_filename.substr(output_filename.find_last_of(".") + 1);
+
+      if ( extension == "prm")
+        {
+          outfile << "# Parameter file generated with " << std::endl
+                  << "# DEAL_II_GIT_BRANCH=   " << DEAL_II_GIT_BRANCH  << std::endl
+                  << "# DEAL_II_GIT_SHORTREV= " << DEAL_II_GIT_SHORTREV << std::endl;
+          Assert(output_style_for_prm_format == ParameterHandler::Text ||
+                 output_style_for_prm_format == ParameterHandler::ShortText,
+                 ExcMessage("Only Text or ShortText can be specified in output_style_for_prm_format."))
+          prm.print_parameters(outfile, output_style_for_prm_format);
+        }
+      else if (extension == "xml")
+        prm.print_parameters(outfile, ParameterHandler::XML);
+      else if (extension == "latex" || extension == "tex")
+        prm.print_parameters(outfile, ParameterHandler::LaTeX);
+      else
+        AssertThrow(false,ExcNotImplemented());
+    }
+}
+
+void
+ParameterAcceptor::clear()
+{
+  class_list.clear();
+  prm.clear();
+}
+
+
+
+void ParameterAcceptor::declare_parameters(ParameterHandler &prm)
+{}
+
+
+
+void ParameterAcceptor::parse_parameters(ParameterHandler &prm)
+{}
+
+
+
+void
+ParameterAcceptor::log_info()
+{
+  deallog.push("ParameterAcceptor");
+  for (unsigned int i=0; i<class_list.size(); ++i)
+    {
+      deallog << "Class " << i << ":";
+      if (class_list[i])
+        deallog << class_list[i]->get_section_name() << std::endl;
+      else
+        deallog << " NULL" << std::endl;
+    }
+  deallog.pop();
+}
+
+void ParameterAcceptor::parse_all_parameters(ParameterHandler &prm)
+{
+  for (unsigned int i=0; i< class_list.size(); ++i)
+    if (class_list[i] != NULL)
+      {
+        class_list[i]->enter_my_subsection(prm);
+        class_list[i]->parse_parameters(prm);
+        class_list[i]->parse_parameters_call_back();
+        class_list[i]->leave_my_subsection(prm);
+      }
+}
+
+void ParameterAcceptor::declare_all_parameters(ParameterHandler &prm)
+{
+  for (unsigned int i=0; i< class_list.size(); ++i)
+    if (class_list[i] != NULL)
+      {
+        class_list[i]->enter_my_subsection(prm);
+        class_list[i]->declare_parameters(prm);
+        class_list[i]->declare_parameters_call_back();
+        class_list[i]->leave_my_subsection(prm);
+      }
+}
+
+
+std::vector<std::string>
+ParameterAcceptor::get_section_path() const
+{
+  Assert(acceptor_id < class_list.size(), ExcInternalError());
+  std::vector<std::string> sections =
+    Utilities::split_string_list(class_list[acceptor_id]->get_section_name(), sep);
+  bool is_absolute = false;
+  if (sections.size() > 1)
+    {
+      // Handle the cases of a leading "/"
+      if (sections[0] == "")
+        {
+          is_absolute = true;
+          sections.erase(sections.begin());
+        }
+    }
+  if (is_absolute == false)
+    {
+      // In all other cases, we scan for earlier classes, and prepend the
+      // first absolute path (in reverse order) we find to ours
+      for (int i=acceptor_id-1; i>=0; --i)
+        if (class_list[i] != NULL)
+          if (class_list[i]->get_section_name().front() == sep)
+            {
+              bool has_trailing = class_list[i]->get_section_name().back() == sep;
+              // Absolute path found
+              auto secs = Utilities::split_string_list(class_list[i]->get_section_name(), sep);
+              Assert(secs[0] == "", ExcInternalError());
+              // Insert all sections except first and last
+              sections.insert(sections.begin(), secs.begin()+1, secs.end()-(has_trailing ? 0 : 1));
+              // exit from for cycle
+              break;
+            }
+    }
+  return sections;
+}
+
+void ParameterAcceptor::enter_my_subsection(ParameterHandler &prm=ParameterAcceptor::prm)
+{
+  std::vector<std::string> sections = get_section_path();
+  for (auto sec : sections)
+    {
+      prm.enter_subsection(sec);
+    }
+}
+
+void ParameterAcceptor::leave_my_subsection(ParameterHandler &prm=ParameterAcceptor::prm)
+{
+  std::vector<std::string> sections = get_section_path();
+  for (auto sec : sections)
+    {
+      prm.leave_subsection();
+    }
+}
+
+
+
+DEAL_II_NAMESPACE_CLOSE
+
diff --git a/tests/parameter_handler/parameter_acceptor_01.cc b/tests/parameter_handler/parameter_acceptor_01.cc
new file mode 100644 (file)
index 0000000..2abeb97
--- /dev/null
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------
+//
+//    Copyright (C) 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.
+//
+//-----------------------------------------------------------
+
+// Classical way of working with parameters.
+
+#include "../tests.h"
+#include <deal.II/base/parameter_acceptor.h>
+
+template<int dim>
+class Test : public ParameterAcceptor
+{
+public:
+  virtual void declare_parameters(ParameterHandler &prm)
+  {
+    prm.declare_entry("A double", "0.0", Patterns::Double(),
+                      "Documentation");
+  };
+
+  virtual void parse_parameters(ParameterHandler &prm)
+  {
+    deallog << "Double: "
+            << prm.get_double("A double") << std::endl;
+  };
+};
+
+
+int main ()
+{
+  initlog();
+  Test<2> a;
+  Test<1> b;
+
+  ParameterHandler prm;
+  a.declare_all_parameters(prm);
+  prm.log_parameters(deallog);
+}
diff --git a/tests/parameter_handler/parameter_acceptor_01.output b/tests/parameter_handler/parameter_acceptor_01.output
new file mode 100644 (file)
index 0000000..e0f0e7f
--- /dev/null
@@ -0,0 +1,3 @@
+
+DEAL:parameters:Test<1>::A double: 0.0
+DEAL:parameters:Test<2>::A double: 0.0

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.