diff --git a/doc/news/changes/minor/20200326NiklasFehn b/doc/news/changes/minor/20200326NiklasFehn new file mode 100644 index 000000000000..6a97e7e3ef18 --- /dev/null +++ b/doc/news/changes/minor/20200326NiklasFehn @@ -0,0 +1,6 @@ +Extension: The function ParameterHandler::parse_input() has been extended so that +the same parse_input function can be called independently of the type of input +file (prm, xml, json). An additional parameter assert_mandatory_entries_are_found +is introduced to avoid errors, e.g., due to typos in the input file. +
+(Niklas Fehn, 2020/03/26) diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index ebc1bdf2618b..a9eb31d0af46 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -965,52 +965,31 @@ class ParameterHandler : public Subscriptor const bool skip_undefined = false); /** - * Parse the given file to provide values for known parameter fields. The - * PathSearch class "PARAMETERS" is used to find the file. + * Parse input from a specified parameter file @param filename independently + * of the type of input file (prm, xml, json) being used. The code path + * selected by this function is extracted from the ending of the filename, + * so the user has to make sure that the content of the input file is + * consistent with its name. * - * The function in essence reads the entire file into a stream and - * then calls the other parse_input() function with that stream. See - * there for more information. + * The parameter @p last_line will only be used for parameter files of .prm type. + * See the other parse_input function for documentation. * - * Previous versions of deal.II included a similar function named - * read_input which, if the parameter file could not be found - * by PathSearch::find, would not modify the calling ParameterHandler (i.e., - * the parameters would all be set to their default values) and would - * (optionally) create a parameter file with default values. In order to - * obtain that behavior one should catch the PathSearch::ExcFileNotFound - * exception and then optionally call ParameterHandler::print_parameters, - * e.g., + * The user can specify whether parameters in the input file not added to the + * parameter handler will be skipped by @p skip_undefined (enables partial + * parsing), and whether the code will assert that all parameters of the + * parameter handler declared with flag `has_to_be_set=true` are indeed found + * in the input file. * - * @code - * const std::string filename = "parameters.prm"; - * const bool print_default_prm_file = true; - * try - * { - * parameter_handler.parse_input (filename); - * } - * catch (const PathSearch::ExcFileNotFound &) - * { - * std::cerr << "ParameterHandler::parse_input: could not open file <" - * << filename - * << "> for reading." - * << std::endl; - * if (print_default_prm_file) - * { - * std::cerr << "Trying to make file <" - * << filename - * << "> with default values for you." - * << std::endl; - * std::ofstream output (filename); - * parameter_handler.print_parameters( - * output, ParameterHandler::OutputStyle::Text); - * } - * } - * @endcode + * If the function is called with `skip_undefined=true`, it is recommended to + * also set `assert_mandatory_entries_are_found=true`. For example, this + * ensures that parameters with typos in the input file will not be skipped, + * while such mistakes would otherwise remain unrecognized. */ virtual void parse_input(const std::string &filename, - const std::string &last_line = "", - const bool skip_undefined = false); + const std::string &last_line = "", + const bool skip_undefined = false, + const bool assert_mandatory_entries_are_found = false); /** * Parse input from a string to populate known parameter fields. The lines diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 82167e8a61bb..d25e89022079 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -509,13 +510,38 @@ ParameterHandler::parse_input(std::istream & input, void ParameterHandler::parse_input(const std::string &filename, const std::string &last_line, - const bool skip_undefined) + const bool skip_undefined, + const bool assert_mandatory_entries_are_found) { - PathSearch search("PARAMETERS"); + std::filebuf fb; + if (fb.open(filename, std::ios::in)) + { + std::istream is(&fb); + std::string file_ending = filename.substr(filename.find_last_of('.') + 1); + boost::algorithm::to_lower(file_ending); + if (file_ending == "prm") + parse_input(is, filename, last_line, skip_undefined); + else if (file_ending == "xml") + parse_input_from_xml(is, skip_undefined); + else if (file_ending == "json") + parse_input_from_json(is, skip_undefined); + else + AssertThrow( + false, + ExcMessage( + "Unknown input file. Supported types are .prm, .xml, and .json.")); + + fb.close(); + } + else + { + AssertThrow(false, + ExcMessage("Invalid filename " + filename + + " provided. File does not exist.")); + } - std::string openname = search.find(filename); - std::ifstream file_stream(openname.c_str()); - parse_input(file_stream, filename, last_line, skip_undefined); + if (assert_mandatory_entries_are_found) + assert_that_entries_have_been_set(); } diff --git a/tests/parameter_handler/parameter_handler_26.cc b/tests/parameter_handler/parameter_handler_26.cc new file mode 100644 index 000000000000..7d62d2410296 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_26.cc @@ -0,0 +1,103 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2019 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. +// +// --------------------------------------------------------------------- + +#include + +#include + +#include "../tests.h" + +void +success() +{ + unsigned int dim = 2; + std::string precision = "double"; + + ParameterHandler prm; + prm.enter_subsection("General"); + // this one does not have to be set + prm.add_parameter("dim", + dim, + "Number of space dimensions", + Patterns::Integer(2, 3)); + // this one has to be set + prm.declare_entry("Precision", + precision, + Patterns::Selection("float|double"), + "Floating point precision", + true); + prm.leave_subsection(); + + try + { + std::string source = SOURCE_DIR; + std::string filename = source + "/prm/parameter_handler_26_success.json"; + prm.parse_input(filename, "", true, true); + } + catch (std::exception &exc) + { + deallog << exc.what() << std::endl; + } + + deallog << std::endl << "successful" << std::endl; +} + +void +fail() +{ + unsigned int dim = 2; + std::string precision = "double"; + + ParameterHandler prm; + prm.enter_subsection("General"); + // both parameters have to be set + prm.add_parameter( + "dim", dim, "Number of space dimensions", Patterns::Integer(2, 3), true); + prm.add_parameter("Precision", + precision, + "Floating point precision", + Patterns::Selection("float|double"), + true); + prm.leave_subsection(); + + try + { + std::string source = SOURCE_DIR; + std::string filename = source + "/prm/parameter_handler_26_fail.json"; + prm.parse_input(filename, "", true, true); + } + catch (std::exception &exc) + { + deallog << exc.what() << std::endl; + } +} + + +int +main() +{ + initlog(); + deallog.get_file_stream().precision(3); + + try + { + success(); + fail(); + } + catch (std::exception &exc) + { + deallog << exc.what() << std::endl; + } +} diff --git a/tests/parameter_handler/parameter_handler_26.output b/tests/parameter_handler/parameter_handler_26.output new file mode 100644 index 000000000000..e9c22845832e --- /dev/null +++ b/tests/parameter_handler/parameter_handler_26.output @@ -0,0 +1,18 @@ + +DEAL:: +DEAL::successful +DEAL:: +-------------------------------------------------------- +An error occurred in file in function + void dealii::ParameterHandler::assert_that_entries_have_been_set() const +The violated condition was: + entries_wrongly_not_set.size() == 0 +Additional information: + Not all entries of the parameter handler that were declared with `has_to_be_set = true` have been set. The following parameters + + General.Precision + General.dim + + have not been set. A possible reason might be that you did not add these parameter to the input file or that their spelling is not correct. +-------------------------------------------------------- + diff --git a/tests/parameter_handler/parameter_handler_read_json_02.cc b/tests/parameter_handler/parameter_handler_read_json_02.cc index b1f7e0f6e6a5..fafe3c7f35a7 100644 --- a/tests/parameter_handler/parameter_handler_read_json_02.cc +++ b/tests/parameter_handler/parameter_handler_read_json_02.cc @@ -15,7 +15,7 @@ -// check ParameterHandler::parse_input_from_xml +// check ParameterHandler::parse_input_from_json #include diff --git a/tests/parameter_handler/parameter_handler_read_json_03.cc b/tests/parameter_handler/parameter_handler_read_json_03.cc new file mode 100644 index 000000000000..b411a87a3e99 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_json_03.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2020 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 ParameterHandler::parse_input() for json file + +#include + +#include "../tests.h" + + +int +main() +{ + initlog(); + + // default values + int int1 = 0; + int int2 = 0; + int int3 = 0; + int int4 = 0; + + ParameterHandler prm; + prm.add_parameter("int1", int1); + prm.add_parameter("int2", int2); + + prm.enter_subsection("dummy"); + prm.add_parameter("int3", int3); + prm.add_parameter("int4", int4); + prm.leave_subsection(); + + std::string source = SOURCE_DIR; + std::string filename = source + "/prm/parameter_handler_read_json_03.json"; + prm.parse_input(filename, "", true, true); + + AssertDimension(int1, 1); + AssertDimension(int2, 2); + AssertDimension(int3, 3); + AssertDimension(int4, 4); + + return 0; +} diff --git a/tests/parameter_handler/parameter_handler_read_json_03.output b/tests/parameter_handler/parameter_handler_read_json_03.output new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_json_03.output @@ -0,0 +1 @@ + diff --git a/tests/parameter_handler/parameter_handler_read_prm_01.cc b/tests/parameter_handler/parameter_handler_read_prm_01.cc new file mode 100644 index 000000000000..f1b49420ca82 --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_prm_01.cc @@ -0,0 +1,56 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2020 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 ParameterHandler::parse_input for prm file + +#include + +#include "../tests.h" + + +int +main() +{ + initlog(); + + // default values + int int1 = 0; + int int2 = 0; + int int3 = 0; + int int4 = 0; + + ParameterHandler prm; + prm.add_parameter("int1", int1); + prm.add_parameter("int2", int2); + + prm.enter_subsection("dummy"); + prm.add_parameter("int3", int3); + prm.add_parameter("int4", int4); + prm.leave_subsection(); + + // read from json + std::string source = SOURCE_DIR; + std::string filename = source + "/prm/parameter_handler_read_prm_01.prm"; + prm.parse_input(filename, "", true, true); + + AssertDimension(int1, 1); + AssertDimension(int2, 2); + AssertDimension(int3, 3); + AssertDimension(int4, 4); + + return 0; +} diff --git a/tests/parameter_handler/parameter_handler_read_prm_01.output b/tests/parameter_handler/parameter_handler_read_prm_01.output new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_prm_01.output @@ -0,0 +1 @@ + diff --git a/tests/parameter_handler/parameter_handler_read_xml_01.cc b/tests/parameter_handler/parameter_handler_read_xml_01.cc new file mode 100644 index 000000000000..6e8db1a1bf6e --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_xml_01.cc @@ -0,0 +1,55 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2020 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 ParameterHandler::parse_input for xml file + +#include + +#include "../tests.h" + + +int +main() +{ + initlog(); + + // default values + int int1 = 0; + int int2 = 0; + int int3 = 0; + int int4 = 0; + + ParameterHandler prm; + prm.add_parameter("int1", int1); + prm.add_parameter("int2", int2); + + prm.enter_subsection("dummy"); + prm.add_parameter("int3", int3); + prm.add_parameter("int4", int4); + prm.leave_subsection(); + + std::string source = SOURCE_DIR; + std::string filename = source + "/prm/parameter_handler_read_xml_01.xml"; + prm.parse_input(filename, "", true, true); + + AssertDimension(int1, 1); + AssertDimension(int2, 2); + AssertDimension(int3, 3); + AssertDimension(int4, 4); + + return 0; +} diff --git a/tests/parameter_handler/parameter_handler_read_xml_01.output b/tests/parameter_handler/parameter_handler_read_xml_01.output new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/parameter_handler/parameter_handler_read_xml_01.output @@ -0,0 +1 @@ + diff --git a/tests/parameter_handler/prm/parameter_handler_26_fail.json b/tests/parameter_handler/prm/parameter_handler_26_fail.json new file mode 100644 index 000000000000..bb2607322507 --- /dev/null +++ b/tests/parameter_handler/prm/parameter_handler_26_fail.json @@ -0,0 +1,5 @@ +{ + "General": { + "Precison": "float" + } +} diff --git a/tests/parameter_handler/prm/parameter_handler_26_success.json b/tests/parameter_handler/prm/parameter_handler_26_success.json new file mode 100644 index 000000000000..2df3ba6266b2 --- /dev/null +++ b/tests/parameter_handler/prm/parameter_handler_26_success.json @@ -0,0 +1,5 @@ +{ + "General": { + "Precision": "float" + } +} diff --git a/tests/parameter_handler/prm/parameter_handler_read_json_03.json b/tests/parameter_handler/prm/parameter_handler_read_json_03.json new file mode 100644 index 000000000000..0ed12e1a28d4 --- /dev/null +++ b/tests/parameter_handler/prm/parameter_handler_read_json_03.json @@ -0,0 +1,8 @@ +{ + "int1": {"value": 1}, + "int2": 2, + "dummy" : {"int3" : 3, "int4" : 4}, + "int5": {"value": 5}, + "int6": 6, + "dummy2" : {"int7" : 7, "int8" : 8} +} \ No newline at end of file diff --git a/tests/parameter_handler/prm/parameter_handler_read_prm_01.prm b/tests/parameter_handler/prm/parameter_handler_read_prm_01.prm new file mode 100644 index 000000000000..d8f2b892a031 --- /dev/null +++ b/tests/parameter_handler/prm/parameter_handler_read_prm_01.prm @@ -0,0 +1,12 @@ +set int1 = 1 +set int2 = 2 +subsection dummy + set int3 = 3 + set int4 = 4 +end +set int5 = 5 +set int6 = 6 +subsection dummy2 + set int7 = 7 + set int8 = 8 +end diff --git a/tests/parameter_handler/prm/parameter_handler_read_xml_01.xml b/tests/parameter_handler/prm/parameter_handler_read_xml_01.xml new file mode 100644 index 000000000000..79d929f7e733 --- /dev/null +++ b/tests/parameter_handler/prm/parameter_handler_read_xml_01.xml @@ -0,0 +1,15 @@ + + +1 +2 + + 3 + 4 + +5 +6 + + 7 + 8 + +