mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-11-22 09:16:27 -06:00
Don't Output INFOSTEP File by Default
This commit introduces a new helper class, ConvergenceOutputConfiguration which parses comma separated option strings into a runtime configuration object for whether to output additional convergence information and, if so, what information to output. Supported option string values are * "none" -- Dont want any additional convergence output. * "steps" -- Want additional convergence output pertaining to the converged solution at the end of each timestep. * "iterations" -- Want additional convergence output pertaining to each non-linar ieration in each timestep. Option value "none" overrides all other options. In other words, if the user requests "none", then there will be no additional convergence output, even if there are other options in the option string. We add a new option, ExtraConvergenceOutput (command line option --extra-convergence-output), which takes a string argument expected to be a comma separated combination of these options. The default value is "none". Finally, make the INFOSTEP file output conditional on the user supplying "steps" as an argument to the new option.
This commit is contained in:
parent
81650a620d
commit
63654a73fc
@ -41,6 +41,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/core/props/satfunc/RelpermDiagnostics.cpp
|
||||
opm/simulators/timestepping/SimulatorReport.cpp
|
||||
opm/simulators/flow/countGlobalCells.cpp
|
||||
opm/simulators/flow/ConvergenceOutputConfiguration.cpp
|
||||
opm/simulators/flow/KeywordValidation.cpp
|
||||
opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp
|
||||
opm/simulators/flow/ValidationFunctions.cpp
|
||||
@ -171,6 +172,7 @@ endif()
|
||||
list (APPEND TEST_SOURCE_FILES
|
||||
tests/test_ALQState.cpp
|
||||
tests/test_blackoil_amg.cpp
|
||||
tests/test_convergenceoutputconfiguration.cpp
|
||||
tests/test_convergencereport.cpp
|
||||
tests/test_deferredlogger.cpp
|
||||
tests/test_eclinterregflows.cpp
|
||||
@ -271,6 +273,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/simulators/flow/countGlobalCells.hpp
|
||||
opm/simulators/flow/BlackoilModelEbos.hpp
|
||||
opm/simulators/flow/BlackoilModelParametersEbos.hpp
|
||||
opm/simulators/flow/ConvergenceOutputConfiguration.hpp
|
||||
opm/simulators/flow/FlowMainEbos.hpp
|
||||
opm/simulators/flow/Main.hpp
|
||||
opm/simulators/flow/NonlinearSolverEbos.hpp
|
||||
|
128
opm/simulators/flow/ConvergenceOutputConfiguration.cpp
Normal file
128
opm/simulators/flow/ConvergenceOutputConfiguration.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/simulators/flow/ConvergenceOutputConfiguration.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace {
|
||||
std::vector<std::string> tokenizeOptionValues(std::string_view options)
|
||||
{
|
||||
const auto split = std::regex { R"(\s*,\s*)" };
|
||||
return {
|
||||
std::cregex_token_iterator {
|
||||
options.begin(), options.end(), split, -1
|
||||
},
|
||||
std::cregex_token_iterator {}
|
||||
};
|
||||
}
|
||||
|
||||
void reportUnsupportedOptionValuesAndThrow(std::vector<std::string> unsupp,
|
||||
std::string_view optionName)
|
||||
{
|
||||
std::sort(unsupp.begin(), unsupp.end());
|
||||
auto u = std::unique(unsupp.begin(), unsupp.end());
|
||||
|
||||
const auto pl = (std::distance(unsupp.begin(), u) != 1) ? "s" : "";
|
||||
|
||||
if (optionName.empty()) {
|
||||
throw std::invalid_argument {
|
||||
fmt::format("Unsupported convergence output "
|
||||
"option value{}: {}\n"
|
||||
"Supported values are \"none\", "
|
||||
"\"steps\", and \"iterations\"",
|
||||
pl, fmt::join(unsupp.begin(), u, ", "))
|
||||
};
|
||||
}
|
||||
|
||||
throw std::invalid_argument {
|
||||
fmt::format("Option {}:\n - Unsupported value{}: {}\n"
|
||||
" - Supported values are \"none\", "
|
||||
"\"steps\", and \"iterations\"",
|
||||
optionName, pl,
|
||||
fmt::join(unsupp.begin(), u, ", "))
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<Opm::ConvergenceOutputConfiguration::Option>
|
||||
getOptions(std::string_view options, std::string_view optionName)
|
||||
{
|
||||
using Option = Opm::ConvergenceOutputConfiguration::Option;
|
||||
|
||||
auto opt = std::vector<Option>{};
|
||||
|
||||
const auto values = std::unordered_map<std::string, Option> {
|
||||
{ "none" , Option::None },
|
||||
{ "step" , Option::Steps }, // Alias for 'steps' (plural)
|
||||
{ "steps" , Option::Steps },
|
||||
{ "iteration" , Option::Iterations }, // Alias for 'iterations' (plural)
|
||||
{ "iterations", Option::Iterations },
|
||||
};
|
||||
|
||||
auto unsupp = std::vector<std::string>{};
|
||||
for (const auto& value : tokenizeOptionValues(options)) {
|
||||
if (auto option = values.find(value); option != values.end()) {
|
||||
opt.push_back(option->second);
|
||||
}
|
||||
else {
|
||||
unsupp.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (! unsupp.empty()) {
|
||||
reportUnsupportedOptionValuesAndThrow(std::move(unsupp), optionName);
|
||||
}
|
||||
|
||||
return opt;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
// ===========================================================================
|
||||
// Public Interface Below Separator
|
||||
// ===========================================================================
|
||||
|
||||
Opm::ConvergenceOutputConfiguration::
|
||||
ConvergenceOutputConfiguration(std::string_view options,
|
||||
std::string_view optionName)
|
||||
{
|
||||
auto is_none = false;
|
||||
for (const auto& option : getOptions(options, optionName)) {
|
||||
if (option == Option::None) {
|
||||
is_none = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this->flag_ |= static_cast<std::byte>(option);
|
||||
}
|
||||
|
||||
if (is_none) {
|
||||
// Recall: "none" overrides all other options.
|
||||
this->flag_ = std::byte{0};
|
||||
}
|
||||
}
|
93
opm/simulators/flow/ConvergenceOutputConfiguration.hpp
Normal file
93
opm/simulators/flow/ConvergenceOutputConfiguration.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONVERGENCE_OUTPUT_CONFIGURATION_HPP
|
||||
#define CONVERGENCE_OUTPUT_CONFIGURATION_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/// Parse comma separated option strings into a runtime configuration object
|
||||
/// for whether to output additional convergence information and, if so,
|
||||
/// what information to output.
|
||||
///
|
||||
/// Supported option string values are
|
||||
///
|
||||
/// * "none" -- Dont want any additional convergence output.
|
||||
///
|
||||
/// * "steps" -- Want additional convergence output pertaining to the
|
||||
/// converged solution at the end of each timestep.
|
||||
///
|
||||
/// * "iterations" -- Want additional convergence output pertaining to each
|
||||
/// non-linar ieration in each timestep.
|
||||
///
|
||||
/// Option value "none" overrides all other options. In other words, if the
|
||||
/// user requests "none", then there will be no additional convergence
|
||||
/// output, even if there are other options in the option string.
|
||||
class ConvergenceOutputConfiguration
|
||||
{
|
||||
public:
|
||||
/// Option values.
|
||||
///
|
||||
/// None overrides all other options. In other words, if the user
|
||||
/// requests None, then there will be no additional convergence output,
|
||||
/// even if there are other options in the option string.
|
||||
enum class Option : unsigned char {
|
||||
None = 0,
|
||||
Steps = 1 << 1,
|
||||
Iterations = 1 << 2,
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
///
|
||||
/// Parses comma separated option string into runtime configuration
|
||||
/// option.
|
||||
///
|
||||
/// \param[in] options Comma separated option string.
|
||||
///
|
||||
/// \param[in] optionName Name of command line option whose value is \p
|
||||
/// options. Used as diagnostic information only, and only if
|
||||
/// specified.
|
||||
explicit ConvergenceOutputConfiguration(std::string_view options,
|
||||
std::string_view optionName = "");
|
||||
|
||||
/// Whether or not user wants any additional convergence output at all.
|
||||
bool any() const
|
||||
{
|
||||
return this->flag_ != std::byte{0};
|
||||
}
|
||||
|
||||
/// Whether or not user wants specific convergence output.
|
||||
///
|
||||
/// \param[in] opt Specific convergence output type.
|
||||
bool want(const Option opt) const
|
||||
{
|
||||
return std::to_integer<int>(this->flag_ & static_cast<std::byte>(opt)) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Option flags. Treated as a small bitset.
|
||||
std::byte flag_{0};
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // CONVERGENCE_OUTPUT_CONFIGURATION_HPP
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <opm/simulators/flow/ConvergenceOutputConfiguration.hpp>
|
||||
#include <opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp>
|
||||
#include <opm/simulators/utils/ParallelFileMerger.hpp>
|
||||
#include <opm/simulators/utils/moduleVersion.hpp>
|
||||
@ -574,27 +575,37 @@ namespace Opm
|
||||
// Output summary after simulation has completed
|
||||
void runSimulatorAfterSim_(SimulatorReport &report)
|
||||
{
|
||||
if (this->output_cout_) {
|
||||
std::ostringstream ss;
|
||||
ss << "\n\n================ End of simulation ===============\n\n";
|
||||
ss << fmt::format("Number of MPI processes: {:9}\n", mpi_size_ );
|
||||
#if _OPENMP
|
||||
int threads = omp_get_max_threads();
|
||||
if (! this->output_cout_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int threads
|
||||
#if !defined(_OPENMP) || !_OPENMP
|
||||
= 1;
|
||||
#else
|
||||
int threads = 1;
|
||||
= omp_get_max_threads();
|
||||
#endif
|
||||
ss << fmt::format("Threads per MPI process: {:9}\n", threads);
|
||||
report.reportFullyImplicit(ss);
|
||||
OpmLog::info(ss.str());
|
||||
const std::string dir = eclState().getIOConfig().getOutputDir();
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << "\n\n================ End of simulation ===============\n\n";
|
||||
ss << fmt::format("Number of MPI processes: {:9}\n", mpi_size_ );
|
||||
ss << fmt::format("Threads per MPI process: {:9}\n", threads);
|
||||
report.reportFullyImplicit(ss);
|
||||
OpmLog::info(ss.str());
|
||||
|
||||
const auto extraConvOutput = ConvergenceOutputConfiguration {
|
||||
EWOMS_GET_PARAM(TypeTag, std::string, ExtraConvergenceOutput),
|
||||
R"(ExtraConvergenceOutput (--extra-convergence-output))"
|
||||
};
|
||||
|
||||
if (extraConvOutput.want(ConvergenceOutputConfiguration::Option::Steps)) {
|
||||
namespace fs = ::std::filesystem;
|
||||
fs::path output_dir(dir);
|
||||
{
|
||||
std::string filename = eclState().getIOConfig().getBaseName() + ".INFOSTEP";
|
||||
fs::path fullpath = output_dir / filename;
|
||||
std::ofstream os(fullpath.string());
|
||||
report.fullReports(os);
|
||||
}
|
||||
|
||||
const auto infostep = fs::path { eclState().getIOConfig().getOutputDir() } /
|
||||
fs::path { eclState().getIOConfig().getBaseName() }.concat(".INFOSTEP");
|
||||
|
||||
std::ofstream os(infostep);
|
||||
report.fullReports(os);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,12 @@ struct EnableTuning {
|
||||
using type = UndefinedProperty;
|
||||
};
|
||||
|
||||
template <class TypeTag, class MyTypeTag>
|
||||
struct ExtraConvergenceOutput
|
||||
{
|
||||
using type = UndefinedProperty;
|
||||
};
|
||||
|
||||
template<class TypeTag>
|
||||
struct EnableTerminalOutput<TypeTag, TTag::EclFlowProblem> {
|
||||
static constexpr bool value = true;
|
||||
@ -57,6 +63,12 @@ struct EnableTuning<TypeTag, TTag::EclFlowProblem> {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template <class TypeTag>
|
||||
struct ExtraConvergenceOutput<TypeTag, TTag::EclFlowProblem>
|
||||
{
|
||||
static constexpr auto* value = "none";
|
||||
};
|
||||
|
||||
} // namespace Opm::Properties
|
||||
|
||||
namespace Opm {
|
||||
@ -137,6 +149,15 @@ public:
|
||||
"Use adaptive time stepping between report steps");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, bool, EnableTuning,
|
||||
"Honor some aspects of the TUNING keyword.");
|
||||
EWOMS_REGISTER_PARAM(TypeTag, std::string, ExtraConvergenceOutput,
|
||||
"Provide additional convergence output "
|
||||
"files for diagnostic purposes. "
|
||||
"\"none\" gives no extra output and "
|
||||
"overrides all other options, "
|
||||
"\"steps\" generates an INFOSTEP file, "
|
||||
"\"iterations\" generates an INFOITER file. "
|
||||
"Combine options with commas, e.g., "
|
||||
"\"steps,iterations\" for multiple outputs.");
|
||||
}
|
||||
|
||||
/// Run the simulation.
|
||||
|
160
tests/test_convergenceoutputconfiguration.cpp
Normal file
160
tests/test_convergenceoutputconfiguration.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright 2022 Equinor.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define BOOST_TEST_MODULE TestConvergenceOutputConfiguration
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <opm/simulators/flow/ConvergenceOutputConfiguration.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Common_Operations)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(None)
|
||||
{
|
||||
const auto config = Opm::ConvergenceOutputConfiguration{"none"};
|
||||
BOOST_CHECK_MESSAGE(! config.any(),
|
||||
"Configuration object with option value "
|
||||
"\"none\" must NOT activate output");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Steps)
|
||||
{
|
||||
const auto config = Opm::ConvergenceOutputConfiguration{"steps"};
|
||||
BOOST_CHECK_MESSAGE(config.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(config.want(Opm::ConvergenceOutputConfiguration::Option::Steps),
|
||||
"Configuration object with \"steps\" "
|
||||
"option value must activate Steps option");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Steps_Alias)
|
||||
{
|
||||
const auto config = Opm::ConvergenceOutputConfiguration{"step"};
|
||||
BOOST_CHECK_MESSAGE(config.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(config.want(Opm::ConvergenceOutputConfiguration::Option::Steps),
|
||||
"Configuration object with \"step\" "
|
||||
"option value must activate Steps option");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Iterations)
|
||||
{
|
||||
const auto config = Opm::ConvergenceOutputConfiguration{"iterations"};
|
||||
BOOST_CHECK_MESSAGE(config.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(config.want(Opm::ConvergenceOutputConfiguration::Option::Iterations),
|
||||
"Configuration object with \"iterations\" "
|
||||
"option value must activate Steps option");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Iterations_Alias)
|
||||
{
|
||||
const auto config = Opm::ConvergenceOutputConfiguration{"iteration"};
|
||||
BOOST_CHECK_MESSAGE(config.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(config.want(Opm::ConvergenceOutputConfiguration::Option::Iterations),
|
||||
"Configuration object with \"iterations\" "
|
||||
"option value must activate Steps option");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Combinations)
|
||||
{
|
||||
const auto steps_iter = Opm::ConvergenceOutputConfiguration{"steps,iterations"};
|
||||
BOOST_CHECK_MESSAGE(steps_iter.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(steps_iter.want(Opm::ConvergenceOutputConfiguration::Option::Steps),
|
||||
"Configuration object with \"steps\" "
|
||||
"option value must activate Steps option");
|
||||
BOOST_CHECK_MESSAGE(steps_iter.want(Opm::ConvergenceOutputConfiguration::Option::Iterations),
|
||||
"Configuration object with \"iterations\" "
|
||||
"option value must activate Steps option");
|
||||
|
||||
const auto iter_steps = Opm::ConvergenceOutputConfiguration{"iterations,steps"};
|
||||
BOOST_CHECK_MESSAGE(iter_steps.any(),
|
||||
"Configuration object with supported "
|
||||
"option value must activate option");
|
||||
BOOST_CHECK_MESSAGE(iter_steps.want(Opm::ConvergenceOutputConfiguration::Option::Steps),
|
||||
"Configuration object with \"steps\" "
|
||||
"option value must activate Steps option");
|
||||
BOOST_CHECK_MESSAGE(iter_steps.want(Opm::ConvergenceOutputConfiguration::Option::Iterations),
|
||||
"Configuration object with \"iterations\" "
|
||||
"option value must activate Steps option");
|
||||
|
||||
const auto none_iter_steps = Opm::ConvergenceOutputConfiguration{"none,iterations,steps"};
|
||||
BOOST_CHECK_MESSAGE(! none_iter_steps.any(),
|
||||
"Configuration object with any option "
|
||||
"value \"none\" must NOT activate output");
|
||||
|
||||
const auto iter_none_steps = Opm::ConvergenceOutputConfiguration{"iterations,none,steps"};
|
||||
BOOST_CHECK_MESSAGE(! iter_none_steps.any(),
|
||||
"Configuration object with any option "
|
||||
"value \"none\" must NOT activate output");
|
||||
|
||||
const auto steps_iter_none = Opm::ConvergenceOutputConfiguration{"steps,iterations, none"};
|
||||
BOOST_CHECK_MESSAGE(! steps_iter_none.any(),
|
||||
"Configuration object with any option "
|
||||
"value \"none\" must NOT activate output");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END() // Common_Operations
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Failed_Construction)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Misprint)
|
||||
{
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"nonce"},
|
||||
std::invalid_argument);
|
||||
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"stepS"},
|
||||
std::invalid_argument);
|
||||
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"steps, iter"},
|
||||
std::invalid_argument);
|
||||
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"steps, iterations, non"},
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Unknown)
|
||||
{
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"Hello"},
|
||||
std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"meow"},
|
||||
std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{""},
|
||||
std::invalid_argument);
|
||||
BOOST_CHECK_THROW(Opm::ConvergenceOutputConfiguration{"xyz,zy;;;"},
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user