diff --git a/examples/compute_eikonal_from_files.cpp b/examples/compute_eikonal_from_files.cpp index 8f25c25e..b583becb 100644 --- a/examples/compute_eikonal_from_files.cpp +++ b/examples/compute_eikonal_from_files.cpp @@ -60,7 +60,7 @@ try { using namespace Opm; - parameter::ParameterGroup param(argc, argv, false); + parameter::ParameterGroup param(argc, argv); // Read grid. GridManager grid_manager(param.get("grid_filename")); diff --git a/examples/compute_initial_state.cpp b/examples/compute_initial_state.cpp index 3b118c15..4eeec0b2 100644 --- a/examples/compute_initial_state.cpp +++ b/examples/compute_initial_state.cpp @@ -81,7 +81,7 @@ try using namespace Opm; // Setup. - parameter::ParameterGroup param(argc, argv, false); + parameter::ParameterGroup param(argc, argv); std::cout << "--------------- Reading parameters ---------------" << std::endl; const std::string deck_filename = param.get("deck_filename"); Opm::ParserPtr parser(new Opm::Parser() ); diff --git a/examples/compute_tof.cpp b/examples/compute_tof.cpp index 6945fa76..4d3148b5 100644 --- a/examples/compute_tof.cpp +++ b/examples/compute_tof.cpp @@ -160,7 +160,7 @@ try using namespace Opm; std::cout << "\n================ Test program for incompressible tof computations ===============\n\n"; - parameter::ParameterGroup param(argc, argv, false); + parameter::ParameterGroup param(argc, argv); std::cout << "--------------- Reading parameters ---------------" << std::endl; // Read the deck. diff --git a/examples/compute_tof_from_files.cpp b/examples/compute_tof_from_files.cpp index a029eb62..f0964aaa 100644 --- a/examples/compute_tof_from_files.cpp +++ b/examples/compute_tof_from_files.cpp @@ -77,7 +77,7 @@ try { using namespace Opm; - parameter::ParameterGroup param(argc, argv, false); + parameter::ParameterGroup param(argc, argv); // Read grid. GridManager grid_manager(param.get("grid_filename")); diff --git a/opm/core/linalg/LinearSolverPetsc.cpp b/opm/core/linalg/LinearSolverPetsc.cpp index 3394ff70..044962d8 100644 --- a/opm/core/linalg/LinearSolverPetsc.cpp +++ b/opm/core/linalg/LinearSolverPetsc.cpp @@ -38,8 +38,10 @@ namespace{ : default_type_(default_type) { // g++-4.4 has problems converting const char* to char* - // which it thinks is needed for constructing std::string. - // Using operator[] circumvents this problem. + // The problem is caused by the mapped type being PCType + // which (at least in PETSc 3.2) is char* because of C + // (in the header there is "#define PCType character*(80)"). + // and the KSP... defines being const char* (because of C++). type_map_["richardson"] = KSPRICHARDSON; // Not available in PETSC 3.2 on Debian //type_map_["chebyshev"] = KSPCHEBYSHEV; diff --git a/opm/core/utility/parameters/ParameterGroup.cpp b/opm/core/utility/parameters/ParameterGroup.cpp index a6d7837d..ab4d7ad5 100644 --- a/opm/core/utility/parameters/ParameterGroup.cpp +++ b/opm/core/utility/parameters/ParameterGroup.cpp @@ -329,5 +329,10 @@ namespace Opm { } } + const std::vector& ParameterGroup::unhandledArguments() const + { + return unhandled_arguments_; + } + } // namespace parameter } // namespace Opm diff --git a/opm/core/utility/parameters/ParameterGroup.hpp b/opm/core/utility/parameters/ParameterGroup.hpp index 466d242c..1efd19a6 100644 --- a/opm/core/utility/parameters/ParameterGroup.hpp +++ b/opm/core/utility/parameters/ParameterGroup.hpp @@ -127,12 +127,16 @@ namespace Opm { /// /// It is required that argv[0] is the program name, while if /// 0 < i < argc, then argv[i] is either - /// the name of an xml file or parametername=value. + /// the name of an xml file, parameter file or parametername=value. /// /// \param argc is the number of command-line arguments, /// including the name of the executable. /// \param argv is an array of char*, each of which is a - /// command line argument. + /// command line argument. + /// \param verify_syntax If true (default), then it is an error to + /// pass arguments that cannot be handled by the ParameterGroup, + /// or an empty argument list. If false, such arguments are stored + /// and can be retrieved later with unhandledArguments(). template ParameterGroup(int argc, StringArray argv, const bool verify_syntax = true); @@ -267,6 +271,9 @@ namespace Opm { /// Insert a new parameter item into the group. void insertParameter(const std::string& name, const std::string& value); + /// Unhandled arguments from command line parsing. + const std::vector& unhandledArguments() const; + private: typedef std::shared_ptr data_type; typedef std::pair pair_type; @@ -276,11 +283,12 @@ namespace Opm { map_type map_; const ParameterGroup* parent_; bool output_is_enabled_; + std::vector unhandled_arguments_; template T translate(const pair_type& data, const Requirement& chk) const; template - void parseCommandLineArguments(int argc, StringArray argv); + void parseCommandLineArguments(int argc, StringArray argv, bool verify_syntax); void recursiveSetIsOutputEnabled(bool output_is_enabled); // helper routines to do textual I/O diff --git a/opm/core/utility/parameters/ParameterGroup_impl.hpp b/opm/core/utility/parameters/ParameterGroup_impl.hpp index eb8ebb1b..232ba402 100644 --- a/opm/core/utility/parameters/ParameterGroup_impl.hpp +++ b/opm/core/utility/parameters/ParameterGroup_impl.hpp @@ -38,11 +38,13 @@ #include #include +#include #include #include #include #include +#include namespace Opm { namespace parameter { @@ -115,11 +117,11 @@ namespace Opm { << "[...]" << std::endl; exit(EXIT_FAILURE); } - this->parseCommandLineArguments(argc, argv); + this->parseCommandLineArguments(argc, argv, verify_syntax); } template - void ParameterGroup::parseCommandLineArguments(int argc, StringArray argv) + void ParameterGroup::parseCommandLineArguments(int argc, StringArray argv, bool verify_syntax) { std::vector files; std::vector > assignments; @@ -150,9 +152,13 @@ namespace Opm { } else if (file_type.second == "param") { this->readParam(files[i]); } else { - std::cout << "WARNING: Ignoring file '" - << files[i] << "' with unknown extension.\n" - << "Valid filename extensions are 'xml' and 'param'.\n"; + if (verify_syntax) { + std::cerr << "ERROR: Input '" << files[i] << "' is not a valid name for a parameter file.\n"; + std::cerr << " Valid filename extensions are 'xml' and 'param'.\n"; + OPM_THROW(std::runtime_error, "ParameterGroup cannot handle argument: " << files[i]); + } else { + unhandled_arguments_.push_back(files[i]); + } } } for (int i = 0; i < int(assignments.size()); ++i) { diff --git a/tests/test_param.cpp b/tests/test_param.cpp index afb0cc51..972b20db 100644 --- a/tests/test_param.cpp +++ b/tests/test_param.cpp @@ -47,22 +47,24 @@ #include #include #include +#include using namespace Opm; BOOST_AUTO_TEST_CASE(commandline_syntax_init) { typedef const char* cp; - cp argv[] = { "program_command", - "topitem=somestring", - "/slashtopitem=anotherstring", - "/group/item=1", - "/group/anotheritem=2", - "/group/subgroup/item=3", - "/group/subgroup/anotheritem=4", - "/group/item=overridingstring" }; - const std::size_t argc = sizeof(argv)/sizeof(argv[0]); - parameter::ParameterGroup p(argc, argv); + std::vector argv = { "program_command", + "topitem=somestring", + "/slashtopitem=anotherstring", + "/group/item=1", + "/group/anotheritem=2", + "/group/subgroup/item=3", + "/group/subgroup/anotheritem=4", + "/group/item=overridingstring", + 0 }; + const std::size_t argc = argv.size() - 1; + parameter::ParameterGroup p(argc, argv.data()); BOOST_CHECK(p.get("topitem") == "somestring"); std::ostringstream os; p.writeParamToStream(os); @@ -73,6 +75,7 @@ BOOST_AUTO_TEST_CASE(commandline_syntax_init) "/slashtopitem=anotherstring\n" "/topitem=somestring\n"; BOOST_CHECK(os.str() == correct_answer); + BOOST_CHECK(p.unhandledArguments().empty()); // Tests that only run in debug mode. #ifndef NDEBUG @@ -83,11 +86,13 @@ BOOST_AUTO_TEST_CASE(commandline_syntax_init) BOOST_AUTO_TEST_CASE(xml_syntax_init) { typedef const char* cp; - cp argv[] = { "program_command", - "testdata.xml", - "/group/item=overridingstring" }; - const std::size_t argc = sizeof(argv)/sizeof(argv[0]); - parameter::ParameterGroup p(argc, argv); + std::vector argv = { "program_command", + "testdata.xml", + "/group/item=overridingstring", + "unhandledargument", + 0}; + const std::size_t argc = argv.size() - 1; + parameter::ParameterGroup p(argc, argv.data(), false); BOOST_CHECK(p.get("topitem") == "somestring"); std::ostringstream os; p.writeParamToStream(os); @@ -98,8 +103,22 @@ BOOST_AUTO_TEST_CASE(xml_syntax_init) "/slashtopitem=anotherstring\n" "/topitem=somestring\n"; BOOST_CHECK(os.str() == correct_answer); - + BOOST_REQUIRE(p.unhandledArguments().size() == 1); + BOOST_CHECK_EQUAL(p.unhandledArguments()[0], "unhandledargument"); // Tests that only run in debug mode. #ifndef NDEBUG #endif } + + +BOOST_AUTO_TEST_CASE(failing_strict_xml_syntax_init) +{ + typedef const char* cp; + std::vector argv = { "program_command", + "testdata.xml", + "/group/item=overridingstring", + "unhandledargument", + 0 }; + const std::size_t argc = argv.size() - 1; + BOOST_CHECK_THROW(parameter::ParameterGroup p(argc, argv.data()), std::runtime_error); +}