Merge pull request #4621 from vkip/use_mb_from_tuning

Use mass balance limit (XXXMBE) from TUNING with --enable-tuning=true
This commit is contained in:
Bård Skaflestad 2023-06-30 13:04:49 +02:00 committed by GitHub
commit 8c6a92356f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 227 additions and 6 deletions

View File

@ -253,6 +253,7 @@ list (APPEND TEST_SOURCE_FILES
tests/test_RestartSerialization.cpp
tests/test_stoppedwells.cpp
tests/test_timer.cpp
tests/test_tuning_XXXMBE.cpp
tests/test_vfpproperties.cpp
tests/test_wellmodel.cpp
tests/test_wellprodindexcalculator.cpp

View File

@ -21,7 +21,7 @@ set(BASE_RESULT_PATH ${PROJECT_BINARY_DIR}/tests/results)
# Details:
# - This test class simply runs a simulation.
function(add_test_runSimulator)
set(oneValueArgs CASENAME FILENAME SIMULATOR DIR DIR_PREFIX PROCS)
set(oneValueArgs CASENAME FILENAME SIMULATOR DIR DIR_PREFIX PROCS CONFIGURATION)
set(multiValueArgs TEST_ARGS)
cmake_parse_arguments(PARAM "$" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
if(NOT PARAM_DIR)
@ -37,7 +37,8 @@ function(add_test_runSimulator)
-f ${PARAM_FILENAME}
-n ${PARAM_PROCS}
TEST_ARGS ${TEST_ARGS}
CONFIGURATION extra)
CONFIGURATION ${PARAM_CONFIGURATION})
set_tests_properties(runSimulator/${PARAM_CASENAME} PROPERTIES PROCESSORS ${PARAM_PROCS})
endfunction()
###########################################################################
@ -277,13 +278,52 @@ opm_set_test_driver(${PROJECT_SOURCE_DIR}/tests/run-test.sh "")
add_test_runSimulator(CASENAME norne
FILENAME NORNE_ATW2013
SIMULATOR flow
PROCS 1)
PROCS 1
CONFIGURATION extra)
add_test_runSimulator(CASENAME norne_parallel
FILENAME NORNE_ATW2013
SIMULATOR flow
DIR norne
PROCS 4)
PROCS 4
CONFIGURATION extra)
# Tests that are run based on simulator results, but not necessarily direct comparison to reference results
add_test_runSimulator(CASENAME run_tuning_xxxmbe
FILENAME 01_TUNING_XXXMBE
SIMULATOR flow
DIR tuning
PROCS 1
TEST_ARGS --output-extra-convergence-info=iterations --enable-tuning=true)
add_test_runSimulator(CASENAME run_notuning_xxxmbe
FILENAME 01_TUNING_XXXMBE
SIMULATOR flow
DIR tuning
PROCS 1
TEST_ARGS --output-extra-convergence-info=iterations --enable-tuning=false)
set_tests_properties(tuning_XXXMBE PROPERTIES DEPENDS "runSimulator/run_tuning_xxxmbe")
set_tests_properties(tuning_XXXMBE PROPERTIES WORKING_DIRECTORY "${BASE_RESULT_PATH}/flow+run_tuning_xxxmbe")
# Workaround to run same test on different simulation results
get_target_property(notuning_XXXMBE_cmd test_tuning_XXXMBE LOCATION)
if(MPI_FOUND)
set(notuning_XXXMBE_cmd ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} 1 ${notuning_XXXMBE_cmd})
endif()
add_test(
NAME notuning_XXXMBE
COMMAND ${notuning_XXXMBE_cmd}
)
set_tests_properties(notuning_XXXMBE PROPERTIES DEPENDS "runSimulator/run_notuning_xxxmbe")
set_tests_properties(notuning_XXXMBE PROPERTIES WORKING_DIRECTORY "${BASE_RESULT_PATH}/flow+run_notuning_xxxmbe")
set_tests_properties(notuning_XXXMBE PROPERTIES WILL_FAIL TRUE)
include (${CMAKE_CURRENT_SOURCE_DIR}/regressionTests.cmake)
include (${CMAKE_CURRENT_SOURCE_DIR}/restartTests.cmake)

View File

@ -24,6 +24,8 @@
#ifndef OPM_BLACKOILMODELEBOS_HEADER_INCLUDED
#define OPM_BLACKOILMODELEBOS_HEADER_INCLUDED
#include <fmt/format.h>
#include <ebos/eclproblem.hh>
#include <opm/common/ErrorMacros.hpp>
@ -1523,6 +1525,7 @@ namespace Opm {
return grid_.comm().sum(errorPV);
}
ConvergenceReport getDomainReservoirConvergence(const double reportTime,
const double dt,
const int iteration,
@ -1632,6 +1635,14 @@ namespace Opm {
void updateTUNING(const Tuning& tuning) {
param_.tolerance_mb_ = tuning.XXXMBE;
if ( terminal_output_ ) {
OpmLog::debug(fmt::format("Setting BlackoilModelEbos mass balance limit (XXXMBE) to {:.2e}", tuning.XXXMBE));
}
}
ConvergenceReport getReservoirConvergence(const double reportTime,
const double dt,
const int iteration,

View File

@ -23,6 +23,7 @@
#define OPM_SIMULATORFULLYIMPLICITBLACKOILEBOS_HEADER_INCLUDED
#include <dune/common/hash.hh>
#include <fmt/format.h>
#include <opm/simulators/flow/BlackoilModelEbos.hpp>
#include <opm/simulators/flow/BlackoilModelParametersEbos.hpp>
@ -320,6 +321,13 @@ public:
}
}
void updateTUNING(const Tuning& tuning) {
modelParam_.tolerance_mb_ = tuning.XXXMBE;
if (terminalOutput_) {
OpmLog::debug(fmt::format("Setting SimulatorFullyImplicitBlackoilEbos mass balance limit (XXXMBE) to {:.2e}", tuning.XXXMBE));
}
}
bool runStep(SimulatorTimer& timer)
{
if (schedule().exitStatus().has_value()) {
@ -393,6 +401,10 @@ public:
const auto& tuning = sched_state.tuning();
const auto& max_next_tstep = sched_state.max_next_tstep();
adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
// \Note: Assumes TUNING is only used with adaptive time-stepping
// \Note: Need to update both solver (model) and simulator since solver is re-created each report step.
solver_->model().updateTUNING(tuning);
this->updateTUNING(tuning);
}
}
bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||

View File

@ -33,8 +33,8 @@ TEST_ARGS="$@"
mkdir -p ${RESULT_PATH}
if (( ${MPI_PROCS} > 1))
then
mpirun -np ${MPI_PROCS} ${BINPATH}/${EXE_NAME} ${TEST_ARGS} --output-dir=${RESULT_PATH}
mpirun -np ${MPI_PROCS} ${BINPATH}/${EXE_NAME} ${TEST_ARGS} --output-dir=${RESULT_PATH} "${INPUT_DATA_PATH}/${FILENAME}.DATA"
else
${BINPATH}/${EXE_NAME} ${TEST_ARGS} --output-dir=${RESULT_PATH}
${BINPATH}/${EXE_NAME} ${TEST_ARGS} --output-dir=${RESULT_PATH} "${INPUT_DATA_PATH}/${FILENAME}.DATA"
fi
test $? -eq 0 || exit 1

View File

@ -0,0 +1,157 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <limits>
#include <algorithm>
#define BOOST_TEST_MODULE TestTuningXXXMBE
#include <boost/test/unit_test.hpp>
struct Column : public std::vector<std::string> {
Column(const std::string& name_, const int size = 0, const int num_rows_estimate = 1000) :
std::vector<std::string>(size), name(name_)
{
this->reserve(num_rows_estimate);
}
// Return vector of double values, invalid elements set to NaN
std::vector<double> dvalues() const {
std::vector<double> vec;
vec.reserve(this->size());
const auto& conv_func = [](const std::string& strval) {
double dval;
try {
dval = std::stod(strval);
} catch (std::invalid_argument& exc) {
dval = std::numeric_limits<double>::quiet_NaN();
}
return dval;
};
std::transform(this->cbegin(), this->cend(), std::back_inserter(vec), conv_func);
return vec;
}
// Return vector of double values values, invalid elements set to std::numeric_limits<int>::min()
std::vector<int> ivalues() const {
std::vector<int> vec;
vec.reserve(this->size());
const auto& conv_func = [](const std::string& strval) {
int ival;
try {
ival = std::stoi(strval);
} catch (std::invalid_argument& exc) {
ival = std::numeric_limits<int>::min();
}
return ival;
};
std::transform(this->cbegin(), this->cend(), std::back_inserter(vec), conv_func);
return vec;
}
std::string name;
};
struct ColumnData {
ColumnData(const std::string& file_name, const int num_columns_estimate=20) {
raw_columns.reserve(num_columns_estimate);
load_file(file_name);
}
void load_file(const std::string& file_name) {
// Open file and read first line with column names
std::ifstream ifs(file_name);
std::string line, colname;
std::getline(ifs, line);
std::istringstream iss(line);
while (iss >> colname) {
column_names.push_back(colname);
raw_columns.emplace_back(colname);
columns[colname] = &(raw_columns.back());
}
const int num_columns = column_names.size();
// Read remaining lines into std::string vectors
int lineno = 1;
while (std::getline(ifs, line)) {
iss.str(line); iss.clear();
int i=0;
while (iss >> colname && i < num_columns) {
raw_columns[i].push_back(colname);
++i;
}
if (i >= num_columns && iss >> colname) {
std::cout << "Warning:Ignoring extra column(s) on line " << lineno << std::endl;
}
++lineno;
}
}
// Get data vectors of different types
std::vector<double> get_dvector(const std::string& colname) const { return columns.at(colname)->dvalues(); }
std::vector<int> get_ivector(const std::string& colname) const { return columns.at(colname)->ivalues(); }
// Default is to return double values
std::vector<double> operator[](const std::string& colname) const { return columns.at(colname)->dvalues(); }
std::vector<std::string> column_names;
std::vector<Column> raw_columns;
std::map<std::string, Column*> columns;
};
BOOST_AUTO_TEST_CASE(CheckMassBalanceWithinXXXMBE)
{
//std::string case_name(boost::unit_test::framework::master_test_suite().argv[1]);
std::string case_name("01_TUNING_XXXMBE");
std::string file_name = case_name + ".INFOITER";
ColumnData data(file_name);
auto rstep = data.get_ivector("ReportStep");
auto tstep = data.get_ivector("TimeStep");
auto mbo = data["MB_Oil"];
auto mbw = data["MB_Water"];
auto mbg = data["MB_Gas"];
const int num_reports = 1 + *std::max_element(rstep.begin(), rstep.end());
std::vector<double> max_mb;
max_mb.reserve(num_reports);
// Find the maximum mass balance error at each converged time step for each report step..
const int nrows = rstep.size();
int rcur = 0;
int tcur = 0;
double max_mb_step = std::numeric_limits<double>::min();
for (int i=0; i<(nrows-1); ++i) {
if (tcur != tstep[i+1] || rcur != rstep[i+1]) {
max_mb_step = std::max({mbo[i], mbw[i], mbg[i], max_mb_step});
tcur = tstep[i+1];
}
if (rcur != rstep[i+1]) {
max_mb.push_back(max_mb_step);
max_mb_step = std::numeric_limits<double>::min();
rcur = rstep[i+1];
}
}
max_mb.push_back( std::max({mbo.back(), mbw.back(), mbg.back(), max_mb_step}) );
BOOST_TEST_MESSAGE("---------------------------------------------------------------------------");
BOOST_TEST_MESSAGE("Found the following converged max mass balance error (per report step):");
for (auto& val : max_mb)
BOOST_TEST_MESSAGE(val);
BOOST_TEST_MESSAGE("---------------------------------------------------------------------------");
BOOST_CHECK( max_mb[0] < 1.0e-6 );
BOOST_CHECK( max_mb[1] < 1.0e-8 );
BOOST_CHECK( max_mb[2] < 1.0e-10 );
}