mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #4322 from bska/conditional-infostep-output
Don't Output INFOSTEP File by Default
This commit is contained in:
commit
4827de23ce
@ -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