Skip to content

Commit

Permalink
Merge pull request #5302 from bska/more-infostep-cnv
Browse files Browse the repository at this point in the history
Report CNV Violation Pore-Volume Fraction to INFOITER
  • Loading branch information
atgeirr committed May 6, 2024
2 parents f01635d + 027eed1 commit ae7307d
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 61 deletions.
22 changes: 13 additions & 9 deletions opm/simulators/flow/BlackoilModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,17 +897,18 @@ namespace Opm {
Vector R_sum(numComp, 0.0 );
Vector maxCoeff(numComp, std::numeric_limits< Scalar >::lowest() );
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
const auto [ pvSum, numAquiferPvSum ] =
convergenceReduction(grid_.comm(), pvSumLocal,
numAquiferPvSumLocal,
R_sum, maxCoeff, B_avg);

auto cnvErrorPvFraction = computeCnvErrorPv(B_avg, dt);
cnvErrorPvFraction /= (pvSum - numAquiferPvSum);

const auto cnvErrorPvFraction =
computeCnvErrorPv(B_avg, dt)
/ (pvSum - numAquiferPvSum);

// 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.
Expand All @@ -927,7 +928,7 @@ namespace Opm {
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;

if (relax_final_iteration_mb || relax_final_iteration_cnv) {
if (relax_final_iteration_mb || relax_final_iteration_cnv) {
if ( terminal_output_ ) {
std::string message = "Number of newton iterations reached its maximum try to continue with relaxed tolerances:";
if (relax_final_iteration_mb)
Expand All @@ -944,7 +945,7 @@ namespace Opm {
// Finish computation
std::vector<Scalar> CNV(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];
mass_balance_residual[compIdx] = std::abs(B_avg[compIdx]*R_sum[compIdx]) * dt / pvSum;
Expand All @@ -953,12 +954,15 @@ namespace Opm {

// Create convergence report.
ConvergenceReport report{reportTime};
report.setPoreVolCnvViolationFraction(cnvErrorPvFraction, pvSum - numAquiferPvSum);

using CR = ConvergenceReport;
for (int compIdx = 0; compIdx < numComp; ++compIdx) {
double res[2] = { mass_balance_residual[compIdx], CNV[compIdx] };
CR::ReservoirFailure::Type types[2] = { CR::ReservoirFailure::Type::MassBalance,
const double res[2] = { mass_balance_residual[compIdx], CNV[compIdx] };
const CR::ReservoirFailure::Type types[2] = { CR::ReservoirFailure::Type::MassBalance,
CR::ReservoirFailure::Type::Cnv };
double tol[2] = { tol_mb, tol_cnv };
const double tol[2] = { tol_mb, tol_cnv };

for (int ii : {0, 1}) {
if (std::isnan(res[ii])) {
report.setReservoirFailed({types[ii], CR::Severity::NotANumber, compIdx});
Expand Down
1 change: 1 addition & 0 deletions opm/simulators/flow/BlackoilModelNldd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ class BlackoilModelNldd {
} else if (res[ii] > tol[ii]) {
report.setReservoirFailed({types[ii], CR::Severity::Normal, compIdx});
}

report.setReservoirConvergenceMetric(types[ii], compIdx, res[ii]);
}
}
Expand Down
83 changes: 63 additions & 20 deletions opm/simulators/flow/ExtraConvergenceOutputThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <opm/simulators/timestepping/ConvergenceReport.hpp>

#include <algorithm>
#include <array>
#include <cassert>
#include <condition_variable>
#include <cstddef>
Expand All @@ -40,12 +41,44 @@
#include <stdexcept>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

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
formatMetricColumn(const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
const Opm::ConvergenceReport::ReservoirConvergenceMetric& metric)
Expand All @@ -65,45 +98,49 @@ namespace {
[&getPhaseName](const std::string::size_type maxChar,
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,
const Opm::ConvergenceOutputThread::ComponentToPhaseName& getPhaseName,
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" << ' '
<< std::right << std::setw(minColSize) << "Time" << ' '
<< std::right << std::setw(minColSize) << "Iteration";
{
auto leadingSpace = false;

const auto& metrics = firstRequest.reports.front().reservoirConvergence();
const auto maxChar = maxColHeaderSize(minColSize, getPhaseName, metrics);
for (const auto& columnHeader : initial_headers) {
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) {
os << std::right << std::setw(maxChar + 1)
os << std::right << std::setw(headerSize)
<< formatMetricColumn(getPhaseName, metric);
}

// Note: Newline character intentionally placed in separate output
// 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,
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 auto firstColSize = std::string::size_type{11};

os.setf(std::ios_base::scientific);

auto iter = 0;
Expand All @@ -112,19 +149,23 @@ namespace {
<< std::setw(firstColSize) << request.currentStep << ' '
<< std::setprecision(4) << std::setw(firstColSize)
<< convertTime(report.reportTime()) << ' '
<< std::setprecision(4) << std::setw(firstColSize)
<< report.cnvViolatedPvFraction() << ' '
<< std::setw(firstColSize) << iter;

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

if (report.wellFailed()) {
for (const auto& wf : report.wellFailures()) {
os << " " << to_string(wf);
os << ' ' << to_string(wf);
}
}

os << '\n';

++iter;
Expand Down Expand Up @@ -160,6 +201,7 @@ class Opm::ConvergenceOutputThread::Impl
ComponentToPhaseName getPhaseName_{};
ConvertToTimeUnits convertTime_{};
std::optional<std::ofstream> infoIter_{};
std::string::size_type firstColSize_{0};
std::string::size_type colSize_{0};
bool haveOutputIterHeader_{false};
bool finalRequestWritten_{false};
Expand Down Expand Up @@ -203,7 +245,7 @@ writeIterInfo(const std::vector<ConvergenceReportQueue::OutputRequest>& requests
}

if (! this->haveOutputIterHeader_) {
this->colSize_ =
std::tie(this->firstColSize_, this->colSize_) =
writeConvergenceHeader(this->infoIter_.value(),
this->getPhaseName_,
requests.front());
Expand All @@ -213,6 +255,7 @@ writeIterInfo(const std::vector<ConvergenceReportQueue::OutputRequest>& requests
for (const auto& request : requests) {
writeConvergenceRequest(this->infoIter_.value(),
this->convertTime_,
this->firstColSize_,
this->colSize_,
request);

Expand Down
22 changes: 16 additions & 6 deletions opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,16 @@ class SimulatorFullyImplicitBlackoil : private SerializableSim
+ schedule().seconds(timer.currentStepNum()),
timer.currentStepLength());
simulator_.setEpisodeIndex(timer.currentStepNum());

if (serializer_.shouldLoad()) {
wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
serializer_.loadState();
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
// in case the report steps are too large for the solver to converge
Expand Down Expand Up @@ -442,10 +445,17 @@ class SimulatorFullyImplicitBlackoil : private SerializableSim
report_.success.solver_time += solverTimer_->secsSinceStart();

if (this->grid().comm().rank() == 0) {
// Grab the step convergence reports that are new since last we were here.
const auto& reps = solver_->model().stepReports();
this->writeConvergenceOutput(std::vector<StepReport>{reps.begin() + already_reported_steps_, reps.end()});
already_reported_steps_ = reps.size();
// Grab the step convergence reports that are new since last we
// were here.
const auto& reps = this->solver_->model().stepReports();

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.
Expand Down

0 comments on commit ae7307d

Please sign in to comment.