//-----------------------------------------------------------
//
-// Copyright (C) 2014 - 2016 by the deal.II authors
+// Copyright (C) 2017 by the deal.II authors
//
// This file is part of the deal.II library.
//
* 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
+ * The global subscription mechanism is such that whenever an object of a class
+ * derived from ParameterAcceptor is created, then a pointer to that
+ * object-of-derived-type is registered, together with 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
* 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.
+ * attach a signal to ParameterAcceptor::declare_parameters_call_back and
+ * ParameterAcceptor::parse_parameters_call_back, that are called just after
+ * the declare_parameters() and parse_parameters() functions of each derived
+ * class.
*
* A typical usage of this class is the following:
*
* // which defines the section name where the parameters of MyClass
* // will be stored.
*
- * MyClass(std::string name) :
- * ParameterAcceptor(name)
+ * MyClass() :
+ * ParameterAcceptor("Some class name")
* {
* add_parameter("A param", member_var);
* }
* };
*
* int main() {
- * // Make sure you build your class BEFORE calling
+ * // Make sure you create your object BEFORE calling
* // ParameterAcceptor::initialize()
* MyClass class;
*
*
* @code
* // Again your own class, derived from ParameterAcceptor
+ * //
+ * // If you don't pass anything to the constructor of
+ * // ParameterAcceptor, then the class name is used, "MyClass"
+ * // in this case
* class MyClass : public ParameterAcceptor {
*
- * MyClass(std::string name) :
- * ParameterAcceptor(name)
- * {}
- *
* virtual void declare_parameters(ParameterHandler &prm) {
* ...
* }
* };
*
* int main() {
- * // Make sure you build your class BEFORE calling
+ * // Make sure you create your object BEFORE calling
* // ParameterAcceptor::initialize()
* MyClass class;
* ParameterAcceptor::initialize("file.prm");
* end
* @endcode
*
- * In the following examles, we propose some use cases with increasing
+ * In the following examples, we propose some use cases with increasing
* complexities.
*
* MyClass is derived from ParameterAcceptor and has a
* @code
* class MyClass : public ParameterAcceptor
* {
- * MyClass (std::string name);
- * virtual void declare_parameters(ParameterHandler &prm);
- * private:
- * SomeParsedClass<dim> my_subclass;
- * ...
+ * MyClass (std::string name);
+ * virtual void declare_parameters(ParameterHandler &prm);
+ * private:
+ * SomeParsedClass<dim> my_subclass;
+ * ...
* };
*
* MyClass::MyClass(std::string name)
*
* void MyClass::declare_parmeters(ParameterHandler &prm)
* {
- * // many add_parameter(...);
+ * // many add_parameter(...);
* }
*
* ...
*
* int main()
* {
- * MyClass mc("My Class");
- *
- * ParameterAcceptor::initialize("file.prm");
+ * MyClass mc("My Class");
+ * ParameterAcceptor::initialize("file.prm");
* }
* @endcode
*
* ... #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");
+ * MyClass ca("Class A");
+ * MyClass cb("Class B");
+ * ParameterAcceptor::initialize("file.prm");
* }
* @endcode
*
* @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
+ * SomeParsedClass. There are two strategies to change this behaviour. 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
* int main()
* {
- * MyClass ca("/Class A/Class");
- * MyClass cb("/Class B/Class");
- * ParameterAcceptor::initialize("file.prm");
+ * MyClass ca("/Class A/Class");
+ * MyClass cb("/Class B/Class");
+ * ParameterAcceptor::initialize("file.prm");
* }
* @endcode
* Now, in the parameter file we can find
* 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
+ * ParameterAcceptor like the root folder in Unix systems. 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 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");
+ * MyClass ca("/Class A/Class");
+ * MyClass cb("Class B/Class");
+ * ParameterAcceptor::initialize("file.prm");
* }
* @endcode
* The parameter file will have the following structure
* @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:
+ * a name of the class, subsequent classes will interpret this as
+ * a full path, interpreting the class name as a directory name:
* @code
* int main()
* {
- * MyClass ca("/Class A/Class/");
- * MyClass cb("Class B/Class");
- * ParameterAcceptor::initialize("file.prm");
+ * MyClass ca("/Class A/Class/");
+ * MyClass cb("Class B/Class");
+ * ParameterAcceptor::initialize("file.prm");
* }
* @endcode
* The parameter file will have the following structure
*
* 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**.
+ * ParameterAcceptor::initialize() cannot be done on multiple, concurrently
+ * running threads.
*
* 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
* parameters in the given section, otherwise a pretty printed
* version of the derived class is used.
*/
- ParameterAcceptor(const std::string section_name="");
+ ParameterAcceptor(const std::string §ion_name="");
/**
- * The destructor sets to zero the pointer relative to this index,
- * so that it is safe to destroy the mother class.
+ * Destructor.
*/
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
+ * Call declare_all_parameters(), read the parameters from `filename` (only
+ * if `filename` is a non-empty string), and then call
+ * parse_all_parameters().
+ *
+ * If the parameter `filename` is the empty string, then no attempt to read a
+ * parameter file is done. This may be useful if you are ok with using
+ * default values, and don't want to read external files to use a class
+ * derived from ParameterAcceptor.
+ *
+ * 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.
+ * `prm` or `xml` for input, and `prm`, `xml`, or `tex/latex` for output. If
+ * the output format is `prm`, then `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 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="",
+ static void initialize(const std::string &filename="",
+ const std::string &output_filename="",
const ParameterHandler::OutputStyle output_style_for_prm_format=ParameterHandler::ShortText);
/**
static void clear();
/**
- * Declare parameter entries of the derived class.
+ * Derived classes can use this method to declare their parameters.
+ * ParameterAcceptor::initialize() calls it for each derived class. The
+ * default implementation is empty.
*/
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.
+ * Declare parameter call back. This signal is triggered right after
+ * declare_parameters() has been called, to allow users to prepare their
+ * variables right after parameters have been decalred. The default
+ * implementation is empty.
*/
boost::signals2::signal<void()> declare_parameters_call_back;
/**
- * Parse the (derived class) parameters.
+ * Derived classes can use this method to parse their parameters.
+ * ParameterAcceptor::initialize() calls it for each derived class. The
+ * default implementation is empty.
*/
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.
+ * parse_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.
+ * 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;
*/
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
*/
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.
+ * returns the demangled name of this class.
*/
std::string get_section_name() const;
/**
- * Travers all registered classes, and figure out what
- * subsections we need to enter.
+ * Traverse 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.
+ * the prm.add_parameter() method, after entering the correct section path.
+ * By default it uses the ParameterAcceptor::prm variable as
+ * ParameterHandler.
*
* See the documentation of ParameterHandler::add_parameter() for more
* information.
void add_parameter(const std::string &entry,
ParameterType ¶meter,
const std::string &documentation = std::string(),
+ ParameterHandler &prm = ParameterAcceptor::prm,
const Patterns::PatternBase &pattern =
*Patterns::Tools::Convert<ParameterType>::to_pattern());
private:
/**
- * Make sure we enter the right subsection of the global parameter file.
+ * Make sure we enter the right subsection of the given parameter.
*/
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.
+ * makes sense if enter_my_subsection() was called on `prm` before this one.
*/
void leave_my_subsection(ParameterHandler &prm);
const unsigned int acceptor_id;
/**
- * Separator between section and subsection.
+ * Separator between sections.
*/
static const char sep = '/';
};
+
// Inline and template functions
template<class ParameterType>
void ParameterAcceptor::add_parameter(const std::string &entry,
ParameterType ¶meter,
const std::string &documentation,
+ ParameterHandler &prm,
const Patterns::PatternBase &pattern)
{
enter_my_subsection(prm);
}
+
DEAL_II_NAMESPACE_CLOSE
#endif
//-----------------------------------------------------------
//
-// Copyright (C) 2015 - 2016 by the deal.II authors
+// Copyright (C) 2017 by the deal.II authors
//
// This file is part of the deal.II library.
//
// Static parameter handler
ParameterHandler ParameterAcceptor::prm;
-ParameterAcceptor::ParameterAcceptor(const std::string name) :
+ParameterAcceptor::ParameterAcceptor(const std::string &name) :
acceptor_id(class_list.size()),
section_name(name)
{
void
-ParameterAcceptor::initialize(const std::string filename,
- const std::string output_filename,
+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")
+ if (filename != "")
{
- try
+ // check the extension of input file
+ if (filename.substr(filename.find_last_of(".") + 1) == "prm")
{
- prm.parse_input(filename);
+ 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 it for you."));
+ }
}
- catch (dealii::PathSearch::ExcFileNotFound)
+ else if (filename.substr(filename.find_last_of(".") + 1) == "xml")
{
- 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."));
+ std::ifstream is(filename);
+ if (!is)
+ {
+ std::ofstream out(filename);
+ Assert(out, ExcIO());
+ prm.print_parameters(out, ParameterHandler::XML);
+ out.close();
+ AssertThrow(false, ExcMessage("You specified <"+filename+"> as input "+
+ "parameter file, but it does not exist. " +
+ "We created it for you."));
+ }
+ prm.parse_input_from_xml(is);
}
+ else
+ AssertThrow(false, ExcMessage("Invalid extension of parameter file. Please use .prm or .xml"));
}
- 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());
else
AssertThrow(false,ExcNotImplemented());
}
+
+ // Finally do the parsing.
+ parse_all_parameters();
}
void
-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)
ParameterAcceptor::get_section_path() const
{
Assert(acceptor_id < class_list.size(), ExcInternalError());
- auto my_section_name = get_section_name();
- bool is_absolute = my_section_name.front() == sep;
+ const auto my_section_name = get_section_name();
+ const bool is_absolute = (my_section_name.front() == sep);
std::vector<std::string> sections =
Utilities::split_string_list(my_section_name, sep);
+ // Split string list removes trailing empty strings, but not
+ // preceeding ones. Make sure that if we had an absolute path,
+ // we don't store as first section the empty string.
if (is_absolute)
sections.erase(sections.begin());
else
{
- // If we want a relative path, we prepend the path of the previous class
+ // If we have a relative path, we prepend the path of the previous class
// to ours. This is tricky. If the previous class has a path with a
// trailing /, then the full path is used, else only the path except the
// last one
auto previous_path = class_list[i]->get_section_path();
// See if we need to remove last piece of the path
- if (previous_path.size() >= 1 && has_trailing == false)
+ if ( (previous_path.size() > 0) && has_trailing == false)
previous_path.resize(previous_path.size()-1);
sections.insert(sections.begin(), previous_path.begin(), previous_path.end());
void ParameterAcceptor::enter_my_subsection(ParameterHandler &prm=ParameterAcceptor::prm)
{
- std::vector<std::string> sections = get_section_path();
+ const auto 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();
+ const auto sections = get_section_path();
for (auto sec : sections)
{
prm.leave_subsection();