Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend ParameterHandler::parse_input() for file-type-independent parsing with inbuilt correctness check #9741

Merged
merged 1 commit into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/news/changes/minor/20200326NiklasFehn
Original file line number Diff line number Diff line change
@@ -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.
<br>
(Niklas Fehn, 2020/03/26)
59 changes: 19 additions & 40 deletions include/deal.II/base/parameter_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
* <code>read_input</code> 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
Expand Down
36 changes: 31 additions & 5 deletions source/base/parameter_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <deal.II/base/path_search.h>
#include <deal.II/base/utilities.h>

#include <boost/algorithm/string.hpp>
#include <boost/io/ios_state.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
Expand Down Expand Up @@ -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();
}


Expand Down
103 changes: 103 additions & 0 deletions tests/parameter_handler/parameter_handler_26.cc
Original file line number Diff line number Diff line change
@@ -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 <deal.II/base/parameter_handler.h>

#include <map>

#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;
}
}
18 changes: 18 additions & 0 deletions tests/parameter_handler/parameter_handler_26.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

DEAL::
DEAL::successful
DEAL::
--------------------------------------------------------
An error occurred in file <parameter_handler.cc> 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.
--------------------------------------------------------

2 changes: 1 addition & 1 deletion tests/parameter_handler/parameter_handler_read_json_02.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@



// check ParameterHandler::parse_input_from_xml
// check ParameterHandler::parse_input_from_json

#include <deal.II/base/parameter_handler.h>

Expand Down
55 changes: 55 additions & 0 deletions tests/parameter_handler/parameter_handler_read_json_03.cc
Original file line number Diff line number Diff line change
@@ -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 <deal.II/base/parameter_handler.h>

#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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

56 changes: 56 additions & 0 deletions tests/parameter_handler/parameter_handler_read_prm_01.cc
Original file line number Diff line number Diff line change
@@ -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 <deal.II/base/parameter_handler.h>

#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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@