diff --git a/opm/simulators/timestepping/ConvergenceReport.hpp b/opm/simulators/timestepping/ConvergenceReport.hpp index d51ccd8d4..38692d9e2 100644 --- a/opm/simulators/timestepping/ConvergenceReport.hpp +++ b/opm/simulators/timestepping/ConvergenceReport.hpp @@ -191,6 +191,43 @@ namespace Opm std::string well_name_ {}; }; + class WellConvergenceMetric + { + public: + // Default constructor needed for object serialisation. Don't + // use this for anything else. + WellConvergenceMetric() = default; + + WellConvergenceMetric(WellFailure::Type t, Severity s, int phase, double value, const std::string& well_name) + : type_(t), severity_(s), phase_(phase), value_(value), well_name_(well_name) + {} + + WellFailure::Type type() const { return type_; } + Severity severity() const { return severity_; } + int phase() const { return phase_; } + double value() const { return value_; } + const std::string& wellName() const { return well_name_; } + + template + void serializeOp(Serializer& serializer) + { + serializer(this->type_); + serializer(this->severity_); + serializer(this->phase_); + serializer(this->value_); + serializer(this->well_name_); + } + + private: + // Note to maintainers: If you change this list of data members, + // then please update serializeOp() accordingly. + WellFailure::Type type_ { WellFailure::Type::Invalid }; + Severity severity_ { Severity::None }; + int phase_ { -1 }; + double value_ { 0.0 }; + std::string well_name_ {}; + }; + // ----------- Mutating member functions ----------- ConvergenceReport() @@ -231,6 +268,12 @@ namespace Opm this->res_convergence_.emplace_back(std::forward(args)...); } + template + void setWellConvergenceMetric(Args&&... args) + { + this->well_convergence_.emplace_back(std::forward(args)...); + } + void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated) { wellGroupTargetsViolated_ = wellGroupTargetsViolated; @@ -250,6 +293,7 @@ namespace Opm 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()); res_convergence_.insert(res_convergence_.end(), other.res_convergence_.begin(), other.res_convergence_.end()); + well_convergence_.insert(well_convergence_.end(), other.well_convergence_.begin(), other.well_convergence_.end()); assert(reservoirFailed() != res_failures_.empty()); assert(wellFailed() != well_failures_.empty()); wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_); @@ -316,6 +360,11 @@ namespace Opm return well_failures_; } + const std::vector& wellConvergence() const + { + return well_convergence_; + } + const PenaltyCard& getPenaltyCard() const { return penaltyCard_; @@ -360,6 +409,7 @@ namespace Opm serializer(this->res_failures_); serializer(this->well_failures_); serializer(this->res_convergence_); + serializer(this->well_convergence_); serializer(this->wellGroupTargetsViolated_); serializer(this->cnvPvSplit_); serializer(this->eligiblePoreVolume_); @@ -375,6 +425,7 @@ namespace Opm std::vector res_failures_; std::vector well_failures_; std::vector res_convergence_; + std::vector well_convergence_; bool wellGroupTargetsViolated_; CnvPvSplit cnvPvSplit_{}; double eligiblePoreVolume_{}; diff --git a/opm/simulators/wells/StandardWellEval.cpp b/opm/simulators/wells/StandardWellEval.cpp index d29c59e47..5dab4b5d1 100644 --- a/opm/simulators/wells/StandardWellEval.cpp +++ b/opm/simulators/wells/StandardWellEval.cpp @@ -134,13 +134,20 @@ getWellConvergence(const WellState& well_state, if (std::isnan(well_flux_residual[compIdx])) { report.setWellFailed({type, CR::Severity::NotANumber, compIdx, baseif_.name()}); + report.setWellConvergenceMetric(type, CR::Severity::NotANumber, compIdx, well_flux_residual[compIdx], baseif_.name()); } else if (well_flux_residual[compIdx] > maxResidualAllowed) { report.setWellFailed({type, CR::Severity::TooLarge, compIdx, baseif_.name()}); + report.setWellConvergenceMetric(type, CR::Severity::TooLarge, compIdx, well_flux_residual[compIdx], baseif_.name()); } else if (!relax_tolerance && well_flux_residual[compIdx] > tol_wells) { report.setWellFailed({type, CR::Severity::Normal, compIdx, baseif_.name()}); + report.setWellConvergenceMetric(type, CR::Severity::Normal, compIdx, well_flux_residual[compIdx], baseif_.name()); } else if (well_flux_residual[compIdx] > relaxed_tolerance_flow) { report.setWellFailed({type, CR::Severity::Normal, compIdx, baseif_.name()}); + report.setWellConvergenceMetric(type, CR::Severity::Normal, compIdx, well_flux_residual[compIdx], baseif_.name()); + } else { + report.setWellConvergenceMetric(CR::WellFailure::Type::Invalid, CR::Severity::None, compIdx, well_flux_residual[compIdx], baseif_.name()); } + } WellConvergence(baseif_).