opm-simulators/tests/test_tuning_XXXMBE.cpp
Bård Skaflestad 027eed16e9 Report CNV Violation Pore-Volume Fraction to INFOITER
This commit includes the fraction of pore-volume whose CNV targets
are violated as a new per-iteration quantity in the INFOITER file
(--output-extra-convergence-info=iteration), with the column header
"CnvErrPvFrac".  We collect the values which are already calculated
in

    BlackoilModel<>::getReservoirConvergence()

and store these as a pair of numerator and denominator in the
ConvergenceReport class.  Note that we need both the numerator and
the denominator in order to aggregate contributions from multiple
ranks.

While here, also make a few more objects 'const' and calculate
column widths directly instead of the maximum number of characters
in writeConvergenceHeader().
2024-05-06 11:31:47 +02:00

157 lines
5.0 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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_MESSAGE( max_mb[0] < 1.0e-6, "max_mb[0] (= " << max_mb[0] << ") is not strictly less than 1.0e-6" );
BOOST_CHECK_MESSAGE( max_mb[1] < 1.0e-8, "max_mb[1] (= " << max_mb[1] << ") is not strictly less than 1.0e-8" );
BOOST_CHECK_MESSAGE( max_mb[2] < 1.0e-10, "max_mb[2] (= " << max_mb[1] << ") is not strictly less than 1.0e-10" );
}