mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Capture Timestep's Non-Linear Convergence History
This enables outputting a formatted record of the limiting MB and CNV quantities as time and non-linear iterations progress. This, in turn, is intended for diagnostic and analysis purposes and will not be output unless specifically requested. In particular, add a new type, ConvergenceReport::ReservoirConvergenceMetric which captures the convergence metric type (MB or CNV) along with the associate phase and numerical value of the convergence metric. We add a vector of these convergence metric objects as a new data member of the ConvergenceReport. Finally, foreshadowing the intended use case, also store the report time in the ConvergenceReport object.
This commit is contained in:
parent
8997437ede
commit
3c63a7aa6d
@ -888,7 +888,8 @@ namespace Opm {
|
|||||||
return grid_.comm().sum(errorPV);
|
return grid_.comm().sum(errorPV);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvergenceReport getReservoirConvergence(const double dt,
|
ConvergenceReport getReservoirConvergence(const double reportTime,
|
||||||
|
const double dt,
|
||||||
const int iteration,
|
const int iteration,
|
||||||
std::vector<Scalar>& B_avg,
|
std::vector<Scalar>& B_avg,
|
||||||
std::vector<Scalar>& residual_norms)
|
std::vector<Scalar>& residual_norms)
|
||||||
@ -927,7 +928,7 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create convergence report.
|
// Create convergence report.
|
||||||
ConvergenceReport report;
|
ConvergenceReport report{reportTime};
|
||||||
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] };
|
double res[2] = { mass_balance_residual[compIdx], CNV[compIdx] };
|
||||||
@ -953,6 +954,7 @@ namespace Opm {
|
|||||||
} 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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1003,7 +1005,9 @@ namespace Opm {
|
|||||||
{
|
{
|
||||||
// Get convergence reports for reservoir and wells.
|
// Get convergence reports for reservoir and wells.
|
||||||
std::vector<Scalar> B_avg(numEq, 0.0);
|
std::vector<Scalar> B_avg(numEq, 0.0);
|
||||||
auto report = getReservoirConvergence(timer.currentStepLength(), iteration, B_avg, residual_norms);
|
auto report = getReservoirConvergence(timer.simulationTimeElapsed(),
|
||||||
|
timer.currentStepLength(),
|
||||||
|
iteration, B_avg, residual_norms);
|
||||||
report += wellModel().getWellConvergence(B_avg, /*checkWellGroupControls*/report.converged());
|
report += wellModel().getWellConvergence(B_avg, /*checkWellGroupControls*/report.converged());
|
||||||
|
|
||||||
return report;
|
return report;
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
#ifndef OPM_CONVERGENCEREPORT_HEADER_INCLUDED
|
#ifndef OPM_CONVERGENCEREPORT_HEADER_INCLUDED
|
||||||
#define OPM_CONVERGENCEREPORT_HEADER_INCLUDED
|
#define OPM_CONVERGENCEREPORT_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Opm
|
namespace Opm
|
||||||
@ -61,6 +63,21 @@ namespace Opm
|
|||||||
Severity severity_;
|
Severity severity_;
|
||||||
int phase_;
|
int phase_;
|
||||||
};
|
};
|
||||||
|
class ReservoirConvergenceMetric
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReservoirConvergenceMetric(ReservoirFailure::Type t, int phase, double value)
|
||||||
|
: type_(t), phase_(phase), value_(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ReservoirFailure::Type type() const { return type_; }
|
||||||
|
int phase() const { return phase_; }
|
||||||
|
double value() const { return value_; }
|
||||||
|
private:
|
||||||
|
ReservoirFailure::Type type_;
|
||||||
|
int phase_;
|
||||||
|
double value_;
|
||||||
|
};
|
||||||
class WellFailure
|
class WellFailure
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -83,7 +100,13 @@ namespace Opm
|
|||||||
// ----------- Mutating member functions -----------
|
// ----------- Mutating member functions -----------
|
||||||
|
|
||||||
ConvergenceReport()
|
ConvergenceReport()
|
||||||
: status_{AllGood}
|
: ConvergenceReport{0.0}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ConvergenceReport(const double reportTime)
|
||||||
|
: reportTime_{reportTime}
|
||||||
|
, status_{AllGood}
|
||||||
, res_failures_{}
|
, res_failures_{}
|
||||||
, well_failures_{}
|
, well_failures_{}
|
||||||
, wellGroupTargetsViolated_(false)
|
, wellGroupTargetsViolated_(false)
|
||||||
@ -110,6 +133,12 @@ namespace Opm
|
|||||||
well_failures_.push_back(wf);
|
well_failures_.push_back(wf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void setReservoirConvergenceMetric(Args&&... args)
|
||||||
|
{
|
||||||
|
this->res_convergence_.emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated)
|
void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated)
|
||||||
{
|
{
|
||||||
wellGroupTargetsViolated_ = wellGroupTargetsViolated;
|
wellGroupTargetsViolated_ = wellGroupTargetsViolated;
|
||||||
@ -117,9 +146,11 @@ namespace Opm
|
|||||||
|
|
||||||
ConvergenceReport& operator+=(const ConvergenceReport& other)
|
ConvergenceReport& operator+=(const ConvergenceReport& other)
|
||||||
{
|
{
|
||||||
|
reportTime_ = std::max(reportTime_, other.reportTime_);
|
||||||
status_ = static_cast<Status>(status_ | other.status_);
|
status_ = static_cast<Status>(status_ | other.status_);
|
||||||
res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
|
res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
|
||||||
well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
|
well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
|
||||||
|
res_convergence_.insert(res_convergence_.end(), other.res_convergence_.begin(), other.res_convergence_.end());
|
||||||
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_);
|
||||||
@ -128,6 +159,11 @@ namespace Opm
|
|||||||
|
|
||||||
// ----------- Const member functions (queries) -----------
|
// ----------- Const member functions (queries) -----------
|
||||||
|
|
||||||
|
double reportTime() const
|
||||||
|
{
|
||||||
|
return reportTime_;
|
||||||
|
}
|
||||||
|
|
||||||
bool converged() const
|
bool converged() const
|
||||||
{
|
{
|
||||||
return (status_ == AllGood) && !wellGroupTargetsViolated_;
|
return (status_ == AllGood) && !wellGroupTargetsViolated_;
|
||||||
@ -148,6 +184,11 @@ namespace Opm
|
|||||||
return res_failures_;
|
return res_failures_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<ReservoirConvergenceMetric>& reservoirConvergence() const
|
||||||
|
{
|
||||||
|
return res_convergence_;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<WellFailure>& wellFailures() const
|
const std::vector<WellFailure>& wellFailures() const
|
||||||
{
|
{
|
||||||
return well_failures_;
|
return well_failures_;
|
||||||
@ -172,9 +213,11 @@ namespace Opm
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// ----------- Member variables -----------
|
// ----------- Member variables -----------
|
||||||
|
double reportTime_;
|
||||||
Status status_;
|
Status status_;
|
||||||
std::vector<ReservoirFailure> res_failures_;
|
std::vector<ReservoirFailure> res_failures_;
|
||||||
std::vector<WellFailure> well_failures_;
|
std::vector<WellFailure> well_failures_;
|
||||||
|
std::vector<ReservoirConvergenceMetric> res_convergence_;
|
||||||
bool wellGroupTargetsViolated_;
|
bool wellGroupTargetsViolated_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
Copyright 2018, 2022 Equinor ASA.
|
||||||
Copyright 2018 SINTEF Digital, Mathematics and Cybernetics.
|
Copyright 2018 SINTEF Digital, Mathematics and Cybernetics.
|
||||||
Copyright 2018 Equinor.
|
|
||||||
|
|
||||||
This file is part of the Open Porous Media project (OPM).
|
This file is part of the Open Porous Media project (OPM).
|
||||||
|
|
||||||
@ -43,6 +43,18 @@ namespace
|
|||||||
MPI_Pack(&phase, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
MPI_Pack(&phase, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void packReservoirConvergenceMetric(const ConvergenceReport::ReservoirConvergenceMetric& m,
|
||||||
|
std::vector<char>& buf,
|
||||||
|
int& offset, MPI_Comm mpi_communicator)
|
||||||
|
{
|
||||||
|
int type = static_cast<int>(m.type());
|
||||||
|
int phase = m.phase();
|
||||||
|
double value = m.value();
|
||||||
|
MPI_Pack(&type, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
MPI_Pack(&phase, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
MPI_Pack(&value, 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
}
|
||||||
|
|
||||||
void packWellFailure(const ConvergenceReport::WellFailure& f,
|
void packWellFailure(const ConvergenceReport::WellFailure& f,
|
||||||
std::vector<char>& buf,
|
std::vector<char>& buf,
|
||||||
int& offset, MPI_Comm mpi_communicator)
|
int& offset, MPI_Comm mpi_communicator)
|
||||||
@ -65,12 +77,21 @@ 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.
|
// Reservoir failures.
|
||||||
|
double reportTime = local_report.reportTime();
|
||||||
|
MPI_Pack(&reportTime, 1, MPI_DOUBLE, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
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.
|
||||||
|
const auto rm = local_report.reservoirConvergence();
|
||||||
|
int num_rm = rm.size();
|
||||||
|
MPI_Pack(&num_rm, 1, MPI_INT, buf.data(), buf.size(), &offset, mpi_communicator);
|
||||||
|
for (const auto& m : rm) {
|
||||||
|
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();
|
||||||
@ -84,13 +105,16 @@ namespace
|
|||||||
{
|
{
|
||||||
int int_pack_size = 0;
|
int int_pack_size = 0;
|
||||||
MPI_Pack_size(1, MPI_INT, mpi_communicator, &int_pack_size);
|
MPI_Pack_size(1, MPI_INT, mpi_communicator, &int_pack_size);
|
||||||
|
int double_pack_size = 0;
|
||||||
|
MPI_Pack_size(1, MPI_DOUBLE, mpi_communicator, &double_pack_size);
|
||||||
const int num_rf = local_report.reservoirFailures().size();
|
const int num_rf = local_report.reservoirFailures().size();
|
||||||
|
const int num_rm = local_report.reservoirConvergence().size();
|
||||||
const int num_wf = local_report.wellFailures().size();
|
const int num_wf = local_report.wellFailures().size();
|
||||||
int wellnames_length = 0;
|
int wellnames_length = 0;
|
||||||
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 (2 + 3*num_rf + 4*num_wf) * int_pack_size + wellnames_length;
|
return (3 + 3*num_rf + 2*num_rm + 4*num_wf)*int_pack_size + (1 + 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)
|
||||||
@ -107,6 +131,19 @@ namespace
|
|||||||
phase);
|
phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConvergenceReport::ReservoirConvergenceMetric
|
||||||
|
unpackReservoirConvergenceMetric(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
||||||
|
{
|
||||||
|
int type = -1;
|
||||||
|
int phase = -1;
|
||||||
|
double value = -1.0;
|
||||||
|
auto* data = const_cast<char*>(recv_buffer.data());
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &type, 1, MPI_INT, mpi_communicator);
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &phase, 1, MPI_INT, mpi_communicator);
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &value, 1, MPI_DOUBLE, mpi_communicator);
|
||||||
|
return { static_cast<ConvergenceReport::ReservoirFailure::Type>(type), phase, value };
|
||||||
|
}
|
||||||
|
|
||||||
ConvergenceReport::WellFailure unpackWellFailure(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
ConvergenceReport::WellFailure unpackWellFailure(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
||||||
{
|
{
|
||||||
int type = -1;
|
int type = -1;
|
||||||
@ -129,14 +166,21 @@ namespace
|
|||||||
|
|
||||||
ConvergenceReport unpackSingleConvergenceReport(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
ConvergenceReport unpackSingleConvergenceReport(const std::vector<char>& recv_buffer, int& offset, MPI_Comm mpi_communicator)
|
||||||
{
|
{
|
||||||
ConvergenceReport cr;
|
|
||||||
int num_rf = -1;
|
|
||||||
auto* data = const_cast<char*>(recv_buffer.data());
|
auto* data = const_cast<char*>(recv_buffer.data());
|
||||||
|
double reportTime{0.0};
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &reportTime, 1, MPI_DOUBLE, mpi_communicator);
|
||||||
|
ConvergenceReport cr{reportTime};
|
||||||
|
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) {
|
||||||
ConvergenceReport::ReservoirFailure f = unpackReservoirFailure(recv_buffer, offset, mpi_communicator);
|
ConvergenceReport::ReservoirFailure f = unpackReservoirFailure(recv_buffer, offset, mpi_communicator);
|
||||||
cr.setReservoirFailed(f);
|
cr.setReservoirFailed(f);
|
||||||
}
|
}
|
||||||
|
int num_rm = -1;
|
||||||
|
MPI_Unpack(data, recv_buffer.size(), &offset, &num_rm, 1, MPI_INT, mpi_communicator);
|
||||||
|
for (int rm = 0; rm < num_rm; ++rm) {
|
||||||
|
cr.setReservoirConvergenceMetric(unpackReservoirConvergenceMetric(recv_buffer, offset, mpi_communicator));
|
||||||
|
}
|
||||||
int num_wf = -1;
|
int num_wf = -1;
|
||||||
MPI_Unpack(data, recv_buffer.size(), &offset, &num_wf, 1, MPI_INT, mpi_communicator);
|
MPI_Unpack(data, recv_buffer.size(), &offset, &num_wf, 1, MPI_INT, mpi_communicator);
|
||||||
for (int wf = 0; wf < num_wf; ++wf) {
|
for (int wf = 0; wf < num_wf; ++wf) {
|
||||||
|
Loading…
Reference in New Issue
Block a user