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:
Bård Skaflestad
2024-04-22 16:48:11 +02:00
parent f01635dcf2
commit 027eed16e9
7 changed files with 190 additions and 61 deletions

View File

@@ -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});

View File

@@ -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]);
} }
} }

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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" );
} }