mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
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().
This commit is contained in:
@@ -897,7 +897,8 @@ namespace Opm {
|
|||||||
Vector R_sum(numComp, 0.0 );
|
Vector R_sum(numComp, 0.0 );
|
||||||
Vector maxCoeff(numComp, std::numeric_limits< Scalar >::lowest() );
|
Vector maxCoeff(numComp, std::numeric_limits< Scalar >::lowest() );
|
||||||
std::vector<int> maxCoeffCell(numComp, -1);
|
std::vector<int> maxCoeffCell(numComp, -1);
|
||||||
const auto [ pvSumLocal, numAquiferPvSumLocal] = localConvergenceData(R_sum, maxCoeff, B_avg, maxCoeffCell);
|
const auto [ pvSumLocal, numAquiferPvSumLocal] =
|
||||||
|
this->localConvergenceData(R_sum, maxCoeff, B_avg, maxCoeffCell);
|
||||||
|
|
||||||
// compute global sum and max of quantities
|
// compute global sum and max of quantities
|
||||||
const auto [ pvSum, numAquiferPvSum ] =
|
const auto [ pvSum, numAquiferPvSum ] =
|
||||||
@@ -905,9 +906,9 @@ namespace Opm {
|
|||||||
numAquiferPvSumLocal,
|
numAquiferPvSumLocal,
|
||||||
R_sum, maxCoeff, B_avg);
|
R_sum, maxCoeff, B_avg);
|
||||||
|
|
||||||
auto cnvErrorPvFraction = computeCnvErrorPv(B_avg, dt);
|
const auto cnvErrorPvFraction =
|
||||||
cnvErrorPvFraction /= (pvSum - numAquiferPvSum);
|
computeCnvErrorPv(B_avg, dt)
|
||||||
|
/ (pvSum - numAquiferPvSum);
|
||||||
|
|
||||||
// For each iteration, we need to determine whether to use the relaxed tolerances.
|
// For each iteration, we need to determine whether to use the relaxed tolerances.
|
||||||
// To disable the usage of relaxed tolerances, you can set the relaxed tolerances as the strict tolerances.
|
// To disable the usage of relaxed tolerances, you can set the relaxed tolerances as the strict tolerances.
|
||||||
@@ -927,7 +928,7 @@ namespace Opm {
|
|||||||
const bool relax_pv_fraction_cnv = cnvErrorPvFraction < param_.relaxed_max_pv_fraction_;
|
const bool relax_pv_fraction_cnv = cnvErrorPvFraction < param_.relaxed_max_pv_fraction_;
|
||||||
const bool use_relaxed_cnv = relax_final_iteration_cnv || relax_pv_fraction_cnv || relax_iter_cnv;
|
const bool use_relaxed_cnv = relax_final_iteration_cnv || relax_pv_fraction_cnv || relax_iter_cnv;
|
||||||
|
|
||||||
if (relax_final_iteration_mb || relax_final_iteration_cnv) {
|
if (relax_final_iteration_mb || relax_final_iteration_cnv) {
|
||||||
if ( terminal_output_ ) {
|
if ( terminal_output_ ) {
|
||||||
std::string message = "Number of newton iterations reached its maximum try to continue with relaxed tolerances:";
|
std::string message = "Number of newton iterations reached its maximum try to continue with relaxed tolerances:";
|
||||||
if (relax_final_iteration_mb)
|
if (relax_final_iteration_mb)
|
||||||
@@ -944,7 +945,7 @@ namespace Opm {
|
|||||||
// Finish computation
|
// Finish computation
|
||||||
std::vector<Scalar> CNV(numComp);
|
std::vector<Scalar> CNV(numComp);
|
||||||
std::vector<Scalar> mass_balance_residual(numComp);
|
std::vector<Scalar> mass_balance_residual(numComp);
|
||||||
for ( int compIdx = 0; compIdx < numComp; ++compIdx )
|
for (int compIdx = 0; compIdx < numComp; ++compIdx)
|
||||||
{
|
{
|
||||||
CNV[compIdx] = B_avg[compIdx] * dt * maxCoeff[compIdx];
|
CNV[compIdx] = B_avg[compIdx] * dt * maxCoeff[compIdx];
|
||||||
mass_balance_residual[compIdx] = std::abs(B_avg[compIdx]*R_sum[compIdx]) * dt / pvSum;
|
mass_balance_residual[compIdx] = std::abs(B_avg[compIdx]*R_sum[compIdx]) * dt / pvSum;
|
||||||
@@ -953,12 +954,15 @@ namespace Opm {
|
|||||||
|
|
||||||
// Create convergence report.
|
// Create convergence report.
|
||||||
ConvergenceReport report{reportTime};
|
ConvergenceReport report{reportTime};
|
||||||
|
report.setPoreVolCnvViolationFraction(cnvErrorPvFraction, pvSum - numAquiferPvSum);
|
||||||
|
|
||||||
using CR = ConvergenceReport;
|
using CR = ConvergenceReport;
|
||||||
for (int compIdx = 0; compIdx < numComp; ++compIdx) {
|
for (int compIdx = 0; compIdx < numComp; ++compIdx) {
|
||||||
double res[2] = { mass_balance_residual[compIdx], CNV[compIdx] };
|
const double res[2] = { mass_balance_residual[compIdx], CNV[compIdx] };
|
||||||
CR::ReservoirFailure::Type types[2] = { CR::ReservoirFailure::Type::MassBalance,
|
const CR::ReservoirFailure::Type types[2] = { CR::ReservoirFailure::Type::MassBalance,
|
||||||
CR::ReservoirFailure::Type::Cnv };
|
CR::ReservoirFailure::Type::Cnv };
|
||||||
double tol[2] = { tol_mb, tol_cnv };
|
const double tol[2] = { tol_mb, tol_cnv };
|
||||||
|
|
||||||
for (int ii : {0, 1}) {
|
for (int ii : {0, 1}) {
|
||||||
if (std::isnan(res[ii])) {
|
if (std::isnan(res[ii])) {
|
||||||
report.setReservoirFailed({types[ii], CR::Severity::NotANumber, compIdx});
|
report.setReservoirFailed({types[ii], CR::Severity::NotANumber, compIdx});
|
||||||
|
|||||||
@@ -656,6 +656,7 @@ private:
|
|||||||
} else if (res[ii] > tol[ii]) {
|
} else if (res[ii] > tol[ii]) {
|
||||||
report.setReservoirFailed({types[ii], CR::Severity::Normal, compIdx});
|
report.setReservoirFailed({types[ii], CR::Severity::Normal, compIdx});
|
||||||
}
|
}
|
||||||
|
|
||||||
report.setReservoirConvergenceMetric(types[ii], compIdx, res[ii]);
|
report.setReservoirConvergenceMetric(types[ii], compIdx, res[ii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <opm/simulators/timestepping/ConvergenceReport.hpp>
|
#include <opm/simulators/timestepping/ConvergenceReport.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
@@ -40,12 +41,44 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
auto fixedHeaders() noexcept
|
||||||
|
{
|
||||||
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
|
return std::array {
|
||||||
|
"ReportStep"s,
|
||||||
|
"TimeStep"s,
|
||||||
|
"Time"s,
|
||||||
|
"CnvErrPvFrac"s,
|
||||||
|
"Iteration"s,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HeaderSequence>
|
||||||
|
auto maxHeaderSize(const HeaderSequence& headers)
|
||||||
|
{
|
||||||
|
using sz_t = std::remove_cv_t<std::remove_reference_t<
|
||||||
|
decltype(std::declval<HeaderSequence>().front().size())>>;
|
||||||
|
|
||||||
|
if (headers.empty()) {
|
||||||
|
return sz_t{0};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::accumulate(headers.begin(), headers.end(), sz_t{1},
|
||||||
|
[](const auto m, const auto& header)
|
||||||
|
{
|
||||||
|
return std::max(m, header.size() + 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
formatMetricColumn(const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
|
formatMetricColumn(const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
|
||||||
const Opm::ConvergenceReport::ReservoirConvergenceMetric& metric)
|
const Opm::ConvergenceReport::ReservoirConvergenceMetric& metric)
|
||||||
@@ -65,45 +98,49 @@ namespace {
|
|||||||
[&getPhaseName](const std::string::size_type maxChar,
|
[&getPhaseName](const std::string::size_type maxChar,
|
||||||
const Opm::ConvergenceReport::ReservoirConvergenceMetric& metric)
|
const Opm::ConvergenceReport::ReservoirConvergenceMetric& metric)
|
||||||
{
|
{
|
||||||
return std::max(maxChar, formatMetricColumn(getPhaseName, metric).size());
|
return std::max(maxChar, formatMetricColumn(getPhaseName, metric).size() + 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string::size_type
|
std::pair<std::string::size_type, std::string::size_type>
|
||||||
writeConvergenceHeader(std::ostream& os,
|
writeConvergenceHeader(std::ostream& os,
|
||||||
const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
|
const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
|
||||||
const Opm::ConvergenceReportQueue::OutputRequest& firstRequest)
|
const Opm::ConvergenceReportQueue::OutputRequest& firstRequest)
|
||||||
{
|
{
|
||||||
const auto minColSize = std::string::size_type{11};
|
const auto initial_headers = fixedHeaders();
|
||||||
|
const auto minColSize = maxHeaderSize(initial_headers);
|
||||||
|
|
||||||
os << std::right << std::setw(minColSize) << "ReportStep" << ' '
|
{
|
||||||
<< std::right << std::setw(minColSize) << "TimeStep" << ' '
|
auto leadingSpace = false;
|
||||||
<< std::right << std::setw(minColSize) << "Time" << ' '
|
|
||||||
<< std::right << std::setw(minColSize) << "Iteration";
|
|
||||||
|
|
||||||
const auto& metrics = firstRequest.reports.front().reservoirConvergence();
|
for (const auto& columnHeader : initial_headers) {
|
||||||
const auto maxChar = maxColHeaderSize(minColSize, getPhaseName, metrics);
|
if (leadingSpace) { os << ' '; }
|
||||||
|
os << std::right << std::setw(minColSize) << columnHeader;
|
||||||
|
leadingSpace = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& metrics = firstRequest.reports.front().reservoirConvergence();
|
||||||
|
const auto headerSize = maxColHeaderSize(minColSize, getPhaseName, metrics);
|
||||||
|
|
||||||
for (const auto& metric : metrics) {
|
for (const auto& metric : metrics) {
|
||||||
os << std::right << std::setw(maxChar + 1)
|
os << std::right << std::setw(headerSize)
|
||||||
<< formatMetricColumn(getPhaseName, metric);
|
<< formatMetricColumn(getPhaseName, metric);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Newline character intentionally placed in separate output
|
// Note: Newline character intentionally placed in separate output
|
||||||
// request to not influence right-justification of column header.
|
// request to not influence right-justification of column header.
|
||||||
os << std::right << std::setw(maxChar + 1) << "WellStatus" << '\n';
|
os << std::right << std::setw(headerSize) << "WellStatus" << '\n';
|
||||||
|
|
||||||
return maxChar;
|
return { minColSize, headerSize };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void writeConvergenceRequest(std::ostream& os,
|
void writeConvergenceRequest(std::ostream& os,
|
||||||
const Opm::ConvergenceOutputThread::ConvertToTimeUnits& convertTime,
|
const Opm::ConvergenceOutputThread::ConvertToTimeUnits& convertTime,
|
||||||
std::string::size_type colSize,
|
const std::string::size_type firstColSize,
|
||||||
|
const std::string::size_type colSize,
|
||||||
const Opm::ConvergenceReportQueue::OutputRequest& request)
|
const Opm::ConvergenceReportQueue::OutputRequest& request)
|
||||||
{
|
{
|
||||||
const auto firstColSize = std::string::size_type{11};
|
|
||||||
|
|
||||||
os.setf(std::ios_base::scientific);
|
os.setf(std::ios_base::scientific);
|
||||||
|
|
||||||
auto iter = 0;
|
auto iter = 0;
|
||||||
@@ -112,19 +149,23 @@ namespace {
|
|||||||
<< std::setw(firstColSize) << request.currentStep << ' '
|
<< std::setw(firstColSize) << request.currentStep << ' '
|
||||||
<< std::setprecision(4) << std::setw(firstColSize)
|
<< std::setprecision(4) << std::setw(firstColSize)
|
||||||
<< convertTime(report.reportTime()) << ' '
|
<< convertTime(report.reportTime()) << ' '
|
||||||
|
<< std::setprecision(4) << std::setw(firstColSize)
|
||||||
|
<< report.cnvViolatedPvFraction() << ' '
|
||||||
<< std::setw(firstColSize) << iter;
|
<< std::setw(firstColSize) << iter;
|
||||||
|
|
||||||
for (const auto& metric : report.reservoirConvergence()) {
|
for (const auto& metric : report.reservoirConvergence()) {
|
||||||
os << std::setprecision(4) << std::setw(colSize + 1) << metric.value();
|
os << std::setprecision(4) << std::setw(colSize) << metric.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
os << std::right << std::setw(colSize + 1)
|
os << std::right << std::setw(colSize)
|
||||||
<< (report.wellFailed() ? "FAIL" : "CONV");
|
<< (report.wellFailed() ? "FAIL" : "CONV");
|
||||||
|
|
||||||
if (report.wellFailed()) {
|
if (report.wellFailed()) {
|
||||||
for (const auto& wf : report.wellFailures()) {
|
for (const auto& wf : report.wellFailures()) {
|
||||||
os << " " << to_string(wf);
|
os << ' ' << to_string(wf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os << '\n';
|
os << '\n';
|
||||||
|
|
||||||
++iter;
|
++iter;
|
||||||
@@ -160,6 +201,7 @@ private:
|
|||||||
ComponentToPhaseName getPhaseName_{};
|
ComponentToPhaseName getPhaseName_{};
|
||||||
ConvertToTimeUnits convertTime_{};
|
ConvertToTimeUnits convertTime_{};
|
||||||
std::optional<std::ofstream> infoIter_{};
|
std::optional<std::ofstream> infoIter_{};
|
||||||
|
std::string::size_type firstColSize_{0};
|
||||||
std::string::size_type colSize_{0};
|
std::string::size_type colSize_{0};
|
||||||
bool haveOutputIterHeader_{false};
|
bool haveOutputIterHeader_{false};
|
||||||
bool finalRequestWritten_{false};
|
bool finalRequestWritten_{false};
|
||||||
@@ -203,7 +245,7 @@ writeIterInfo(const std::vector<ConvergenceReportQueue::OutputRequest>& requests
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! this->haveOutputIterHeader_) {
|
if (! this->haveOutputIterHeader_) {
|
||||||
this->colSize_ =
|
std::tie(this->firstColSize_, this->colSize_) =
|
||||||
writeConvergenceHeader(this->infoIter_.value(),
|
writeConvergenceHeader(this->infoIter_.value(),
|
||||||
this->getPhaseName_,
|
this->getPhaseName_,
|
||||||
requests.front());
|
requests.front());
|
||||||
@@ -213,6 +255,7 @@ writeIterInfo(const std::vector<ConvergenceReportQueue::OutputRequest>& requests
|
|||||||
for (const auto& request : requests) {
|
for (const auto& request : requests) {
|
||||||
writeConvergenceRequest(this->infoIter_.value(),
|
writeConvergenceRequest(this->infoIter_.value(),
|
||||||
this->convertTime_,
|
this->convertTime_,
|
||||||
|
this->firstColSize_,
|
||||||
this->colSize_,
|
this->colSize_,
|
||||||
request);
|
request);
|
||||||
|
|
||||||
|
|||||||
@@ -363,13 +363,16 @@ public:
|
|||||||
+ schedule().seconds(timer.currentStepNum()),
|
+ schedule().seconds(timer.currentStepNum()),
|
||||||
timer.currentStepLength());
|
timer.currentStepLength());
|
||||||
simulator_.setEpisodeIndex(timer.currentStepNum());
|
simulator_.setEpisodeIndex(timer.currentStepNum());
|
||||||
|
|
||||||
if (serializer_.shouldLoad()) {
|
if (serializer_.shouldLoad()) {
|
||||||
wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
|
wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
|
||||||
serializer_.loadState();
|
serializer_.loadState();
|
||||||
simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
|
simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
|
||||||
}
|
}
|
||||||
solver_->model().beginReportStep();
|
|
||||||
bool enableTUNING = Parameters::get<TypeTag, Properties::EnableTuning>();
|
this->solver_->model().beginReportStep();
|
||||||
|
|
||||||
|
const bool enableTUNING = Parameters::get<TypeTag, Properties::EnableTuning>();
|
||||||
|
|
||||||
// If sub stepping is enabled allow the solver to sub cycle
|
// If sub stepping is enabled allow the solver to sub cycle
|
||||||
// in case the report steps are too large for the solver to converge
|
// in case the report steps are too large for the solver to converge
|
||||||
@@ -442,10 +445,17 @@ public:
|
|||||||
report_.success.solver_time += solverTimer_->secsSinceStart();
|
report_.success.solver_time += solverTimer_->secsSinceStart();
|
||||||
|
|
||||||
if (this->grid().comm().rank() == 0) {
|
if (this->grid().comm().rank() == 0) {
|
||||||
// Grab the step convergence reports that are new since last we were here.
|
// Grab the step convergence reports that are new since last we
|
||||||
const auto& reps = solver_->model().stepReports();
|
// were here.
|
||||||
this->writeConvergenceOutput(std::vector<StepReport>{reps.begin() + already_reported_steps_, reps.end()});
|
const auto& reps = this->solver_->model().stepReports();
|
||||||
already_reported_steps_ = reps.size();
|
|
||||||
|
auto reports = std::vector<StepReport> {
|
||||||
|
reps.begin() + this->already_reported_steps_, reps.end()
|
||||||
|
};
|
||||||
|
|
||||||
|
this->writeConvergenceOutput(std::move(reports));
|
||||||
|
|
||||||
|
this->already_reported_steps_ = reps.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment timer, remember well state.
|
// Increment timer, remember well state.
|
||||||
|
|||||||
@@ -40,56 +40,78 @@ namespace Opm
|
|||||||
|
|
||||||
// ----------- Types -----------
|
// ----------- Types -----------
|
||||||
|
|
||||||
enum Status { AllGood = 0,
|
enum Status {
|
||||||
ReservoirFailed = 1 << 0,
|
AllGood = 0,
|
||||||
WellFailed = 1 << 1 };
|
ReservoirFailed = 1 << 0,
|
||||||
enum struct Severity { None = 0,
|
WellFailed = 1 << 1,
|
||||||
Normal = 1,
|
};
|
||||||
TooLarge = 2,
|
|
||||||
NotANumber = 3 };
|
enum struct Severity {
|
||||||
|
None = 0,
|
||||||
|
Normal = 1,
|
||||||
|
TooLarge = 2,
|
||||||
|
NotANumber = 3,
|
||||||
|
};
|
||||||
|
|
||||||
class ReservoirFailure
|
class ReservoirFailure
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum struct Type { Invalid, MassBalance, Cnv };
|
enum struct Type { Invalid, MassBalance, Cnv };
|
||||||
|
|
||||||
ReservoirFailure(Type t, Severity s, int phase)
|
ReservoirFailure(Type t, Severity s, int phase)
|
||||||
: type_(t), severity_(s), phase_(phase)
|
: type_(t), severity_(s), phase_(phase)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
Type type() const { return type_; }
|
Type type() const { return type_; }
|
||||||
Severity severity() const { return severity_; }
|
Severity severity() const { return severity_; }
|
||||||
int phase() const { return phase_; }
|
int phase() const { return phase_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type_;
|
Type type_;
|
||||||
Severity severity_;
|
Severity severity_;
|
||||||
int phase_;
|
int phase_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReservoirConvergenceMetric
|
class ReservoirConvergenceMetric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReservoirConvergenceMetric(ReservoirFailure::Type t, int phase, double value)
|
ReservoirConvergenceMetric(ReservoirFailure::Type t, int phase, double value)
|
||||||
: type_(t), phase_(phase), value_(value)
|
: type_(t), phase_(phase), value_(value)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
ReservoirFailure::Type type() const { return type_; }
|
ReservoirFailure::Type type() const { return type_; }
|
||||||
int phase() const { return phase_; }
|
int phase() const { return phase_; }
|
||||||
double value() const { return value_; }
|
double value() const { return value_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReservoirFailure::Type type_;
|
ReservoirFailure::Type type_;
|
||||||
int phase_;
|
int phase_;
|
||||||
double value_;
|
double value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WellFailure
|
class WellFailure
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum struct Type { Invalid, MassBalance, Pressure, ControlBHP, ControlTHP, ControlRate, Unsolvable, WrongFlowDirection };
|
enum struct Type {
|
||||||
|
Invalid,
|
||||||
|
MassBalance,
|
||||||
|
Pressure,
|
||||||
|
ControlBHP,
|
||||||
|
ControlTHP,
|
||||||
|
ControlRate,
|
||||||
|
Unsolvable,
|
||||||
|
WrongFlowDirection,
|
||||||
|
};
|
||||||
|
|
||||||
WellFailure(Type t, Severity s, int phase, const std::string& well_name)
|
WellFailure(Type t, Severity s, int phase, const std::string& well_name)
|
||||||
: type_(t), severity_(s), phase_(phase), well_name_(well_name)
|
: type_(t), severity_(s), phase_(phase), well_name_(well_name)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
Type type() const { return type_; }
|
Type type() const { return type_; }
|
||||||
Severity severity() const { return severity_; }
|
Severity severity() const { return severity_; }
|
||||||
int phase() const { return phase_; }
|
int phase() const { return phase_; }
|
||||||
const std::string& wellName() const { return well_name_; }
|
const std::string& wellName() const { return well_name_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type type_;
|
Type type_;
|
||||||
Severity severity_;
|
Severity severity_;
|
||||||
@@ -101,8 +123,7 @@ namespace Opm
|
|||||||
|
|
||||||
ConvergenceReport()
|
ConvergenceReport()
|
||||||
: ConvergenceReport{0.0}
|
: ConvergenceReport{0.0}
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
explicit ConvergenceReport(const double reportTime)
|
explicit ConvergenceReport(const double reportTime)
|
||||||
: reportTime_{reportTime}
|
: reportTime_{reportTime}
|
||||||
@@ -110,8 +131,7 @@ namespace Opm
|
|||||||
, res_failures_{}
|
, res_failures_{}
|
||||||
, well_failures_{}
|
, well_failures_{}
|
||||||
, wellGroupTargetsViolated_(false)
|
, wellGroupTargetsViolated_(false)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
@@ -144,6 +164,13 @@ namespace Opm
|
|||||||
wellGroupTargetsViolated_ = wellGroupTargetsViolated;
|
wellGroupTargetsViolated_ = wellGroupTargetsViolated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPoreVolCnvViolationFraction(const double cnvErrorPvFraction,
|
||||||
|
const double cnvErrorPvFractionDenom)
|
||||||
|
{
|
||||||
|
this->pvFracCnvViol_ = cnvErrorPvFraction;
|
||||||
|
this->pvFracCnvViolDenom_ = cnvErrorPvFractionDenom;
|
||||||
|
}
|
||||||
|
|
||||||
ConvergenceReport& operator+=(const ConvergenceReport& other)
|
ConvergenceReport& operator+=(const ConvergenceReport& other)
|
||||||
{
|
{
|
||||||
reportTime_ = std::max(reportTime_, other.reportTime_);
|
reportTime_ = std::max(reportTime_, other.reportTime_);
|
||||||
@@ -154,6 +181,21 @@ namespace Opm
|
|||||||
assert(reservoirFailed() != res_failures_.empty());
|
assert(reservoirFailed() != res_failures_.empty());
|
||||||
assert(wellFailed() != well_failures_.empty());
|
assert(wellFailed() != well_failures_.empty());
|
||||||
wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_);
|
wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_);
|
||||||
|
|
||||||
|
if ((this->pvFracCnvViolDenom_ > 0.0) ||
|
||||||
|
(other.pvFracCnvViolDenom_ > 0.0))
|
||||||
|
{
|
||||||
|
this->pvFracCnvViol_ = (this->pvFracCnvViol_ * this->pvFracCnvViolDenom_ +
|
||||||
|
other.pvFracCnvViol_ * other.pvFracCnvViolDenom_)
|
||||||
|
/ (this->pvFracCnvViolDenom_ + other.pvFracCnvViolDenom_);
|
||||||
|
|
||||||
|
this->pvFracCnvViolDenom_ += other.pvFracCnvViolDenom_;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->pvFracCnvViol_ = 0.0;
|
||||||
|
this->pvFracCnvViolDenom_ = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +206,16 @@ namespace Opm
|
|||||||
return reportTime_;
|
return reportTime_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cnvViolatedPvFraction() const
|
||||||
|
{
|
||||||
|
return this->pvFracCnvViol_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<double, double> cnvViolatedPvFractionPack() const
|
||||||
|
{
|
||||||
|
return { this->pvFracCnvViol_, this->pvFracCnvViolDenom_ };
|
||||||
|
}
|
||||||
|
|
||||||
bool converged() const
|
bool converged() const
|
||||||
{
|
{
|
||||||
return (status_ == AllGood) && !wellGroupTargetsViolated_;
|
return (status_ == AllGood) && !wellGroupTargetsViolated_;
|
||||||
@@ -211,7 +263,6 @@ namespace Opm
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// ----------- Member variables -----------
|
// ----------- Member variables -----------
|
||||||
double reportTime_;
|
double reportTime_;
|
||||||
Status status_;
|
Status status_;
|
||||||
@@ -219,6 +270,8 @@ namespace Opm
|
|||||||
std::vector<WellFailure> well_failures_;
|
std::vector<WellFailure> well_failures_;
|
||||||
std::vector<ReservoirConvergenceMetric> res_convergence_;
|
std::vector<ReservoirConvergenceMetric> res_convergence_;
|
||||||
bool wellGroupTargetsViolated_;
|
bool wellGroupTargetsViolated_;
|
||||||
|
double pvFracCnvViol_{};
|
||||||
|
double pvFracCnvViolDenom_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StepReport
|
struct StepReport
|
||||||
@@ -228,7 +281,6 @@ namespace Opm
|
|||||||
std::vector<ConvergenceReport> report;
|
std::vector<ConvergenceReport> report;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t);
|
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t);
|
||||||
|
|
||||||
std::string to_string(const ConvergenceReport::Severity s);
|
std::string to_string(const ConvergenceReport::Severity s);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include <opm/simulators/timestepping/gatherConvergenceReport.hpp>
|
#include <opm/simulators/timestepping/gatherConvergenceReport.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#if HAVE_MPI
|
#if HAVE_MPI
|
||||||
|
|
||||||
#include <mpi.h>
|
#include <mpi.h>
|
||||||
@@ -76,15 +78,24 @@ namespace
|
|||||||
{
|
{
|
||||||
// Pack the data.
|
// Pack the data.
|
||||||
// Status will not be packed, it is possible to deduce from the other data.
|
// Status will not be packed, it is possible to deduce from the other data.
|
||||||
// Reservoir failures.
|
|
||||||
double reportTime = local_report.reportTime();
|
double reportTime = local_report.reportTime();
|
||||||
MPI_Pack(&reportTime, 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
MPI_Pack(&reportTime, 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto cnvPvFrac = local_report.cnvViolatedPvFractionPack();
|
||||||
|
|
||||||
|
MPI_Pack(&cnvPvFrac.first , 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
MPI_Pack(&cnvPvFrac.second, 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reservoir failures.
|
||||||
const auto rf = local_report.reservoirFailures();
|
const auto rf = local_report.reservoirFailures();
|
||||||
int num_rf = rf.size();
|
int num_rf = rf.size();
|
||||||
MPI_Pack(&num_rf, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
MPI_Pack(&num_rf, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
for (const auto& f : rf) {
|
for (const auto& f : rf) {
|
||||||
packReservoirFailure(f, buf, offset, mpi_communicator);
|
packReservoirFailure(f, buf, offset, mpi_communicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reservoir convergence metrics.
|
// Reservoir convergence metrics.
|
||||||
const auto rm = local_report.reservoirConvergence();
|
const auto rm = local_report.reservoirConvergence();
|
||||||
int num_rm = rm.size();
|
int num_rm = rm.size();
|
||||||
@@ -92,6 +103,7 @@ namespace
|
|||||||
for (const auto& m : rm) {
|
for (const auto& m : rm) {
|
||||||
packReservoirConvergenceMetric(m, buf, offset, mpi_communicator);
|
packReservoirConvergenceMetric(m, buf, offset, mpi_communicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Well failures.
|
// Well failures.
|
||||||
const auto wf = local_report.wellFailures();
|
const auto wf = local_report.wellFailures();
|
||||||
int num_wf = wf.size();
|
int num_wf = wf.size();
|
||||||
@@ -114,7 +126,7 @@ namespace
|
|||||||
for (const auto& f : local_report.wellFailures()) {
|
for (const auto& f : local_report.wellFailures()) {
|
||||||
wellnames_length += (f.wellName().size() + 1);
|
wellnames_length += (f.wellName().size() + 1);
|
||||||
}
|
}
|
||||||
return (3 + 3*num_rf + 2*num_rm + 4*num_wf)*int_pack_size + (1 + 1*num_rm)*double_pack_size + wellnames_length;
|
return (3 + 3*num_rf + 2*num_rm + 4*num_wf)*int_pack_size + (3 + 1*num_rm)*double_pack_size + wellnames_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvergenceReport::ReservoirFailure unpackReservoirFailure(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
ConvergenceReport::ReservoirFailure unpackReservoirFailure(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
||||||
@@ -169,7 +181,15 @@ namespace
|
|||||||
auto* data = const_cast<char*>(recv_buffer.data());
|
auto* data = const_cast<char*>(recv_buffer.data());
|
||||||
double reportTime{0.0};
|
double reportTime{0.0};
|
||||||
MPI_Unpack(data, recv_buffer.size(), &offset, &reportTime, 1, MPI_DOUBLE, mpi_communicator);
|
MPI_Unpack(data, recv_buffer.size(), &offset, &reportTime, 1, MPI_DOUBLE, mpi_communicator);
|
||||||
|
|
||||||
ConvergenceReport cr{reportTime};
|
ConvergenceReport cr{reportTime};
|
||||||
|
|
||||||
|
auto cnvPvFrac = std::pair { 0.0, 0.0 };
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &cnvPvFrac.first , 1, MPI_DOUBLE, mpi_communicator);
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &cnvPvFrac.second, 1, MPI_DOUBLE, mpi_communicator);
|
||||||
|
|
||||||
|
cr.setPoreVolCnvViolationFraction(cnvPvFrac.first, cnvPvFrac.second);
|
||||||
|
|
||||||
int num_rf = -1;
|
int num_rf = -1;
|
||||||
MPI_Unpack(data, recv_buffer.size(), &offset, &num_rf, 1, MPI_INT, mpi_communicator);
|
MPI_Unpack(data, recv_buffer.size(), &offset, &num_rf, 1, MPI_INT, mpi_communicator);
|
||||||
for (int rf = 0; rf < num_rf; ++rf) {
|
for (int rf = 0; rf < num_rf; ++rf) {
|
||||||
|
|||||||
@@ -149,9 +149,8 @@ BOOST_AUTO_TEST_CASE(CheckMassBalanceWithinXXXMBE)
|
|||||||
BOOST_TEST_MESSAGE("---------------------------------------------------------------------------");
|
BOOST_TEST_MESSAGE("---------------------------------------------------------------------------");
|
||||||
|
|
||||||
|
|
||||||
BOOST_CHECK( max_mb[0] < 1.0e-6 );
|
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( max_mb[1] < 1.0e-8 );
|
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( max_mb[2] < 1.0e-10 );
|
BOOST_CHECK_MESSAGE( max_mb[2] < 1.0e-10, "max_mb[2] (= " << max_mb[1] << ") is not strictly less than 1.0e-10" );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user