NonlinearSystem_impl.hpp
Go to the documentation of this file.
1#ifndef OPM_FLOW_NONLINEAR_SYSTEM_IMPL_HEADER_INCLUDED
2#define OPM_FLOW_NONLINEAR_SYSTEM_IMPL_HEADER_INCLUDED
3/*
4 Copyright 2026, SINTEF Digital
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20*/
21#ifndef OPM_FLOW_NONLINEAR_SYSTEM_HEADER_INCLUDED
22#include <config.h>
24#endif
25
26#include <dune/common/timer.hh>
27
28#include <opm/common/ErrorMacros.hpp>
29#include <opm/common/TimingMacros.hpp>
30
33
34#include <cmath>
35#include <stdexcept>
36#include <string>
37#include <utility>
38
39namespace Opm {
40
41template <class TypeTag>
42SimulatorReportSingle
45{
46 return assembleReservoir(well_model_);
47}
48
49template <class TypeTag>
50void
52updateTUNING(const Tuning& tuning)
53{
54 applyTUNING(param_, tuning);
55}
56
57template <class TypeTag>
58void
60updateTUNINGDP(const TuningDp& tuning_dp)
61{
62 applyTUNINGDP(param_, tuning_dp);
63}
64
65template <class TypeTag>
66void
69{
70 OPM_TIMEBLOCK(updateSolution);
71
72 const bool shouldStore = shouldStoreSolutionUpdate();
73 if (shouldStore) {
74 prepareSolutionUpdate();
75 }
76
77 auto& newtonMethod = simulator_.model().newtonMethod();
78 auto& solution = simulator_.model().solution(/*timeIdx=*/0);
79
80 newtonMethod.applyUpdate(/*nextSolution=*/solution,
81 /*curSolution=*/solution,
82 /*update=*/dx,
83 /*resid=*/dx);
84
85 postSolutionUpdate();
86
87 {
88 OPM_TIMEBLOCK(invalidateAndUpdateIntensiveQuantities);
89 simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
90 }
91
92 if (shouldStore) {
93 storeSolutionUpdate(dx);
94 }
95}
96
97template <class TypeTag>
98template <class LogFailure>
99void
102 const int componentIdx,
103 const std::string_view componentName,
104 const std::span<const Scalar> residuals,
105 const std::span<const ConvergenceReport::ReservoirFailure::Type> types,
106 const std::span<const Scalar> tolerances,
107 const Scalar maxResidualAllowed,
108 LogFailure&& logFailure) const
109{
110 if (residuals.size() != types.size() || residuals.size() != tolerances.size()) {
111 OPM_THROW(std::logic_error, "Mismatched reservoir convergence metric sizes.");
112 }
113
114 using CR = ConvergenceReport;
115 for (std::size_t metricIdx = 0; metricIdx < residuals.size(); ++metricIdx) {
116 const auto residual = residuals[metricIdx];
117 const auto type = types[metricIdx];
118 const auto tolerance = tolerances[metricIdx];
119
120 if (std::isnan(residual)) {
121 report.setReservoirFailed({type, CR::Severity::NotANumber, componentIdx});
122 logFailure("NaN residual for " + std::string(componentName) + " equation.");
123 }
124 else if (residual > maxResidualAllowed) {
125 report.setReservoirFailed({type, CR::Severity::TooLarge, componentIdx});
126 logFailure("Too large residual for " + std::string(componentName) + " equation.");
127 }
128 else if (residual < 0.0) {
129 report.setReservoirFailed({type, CR::Severity::Normal, componentIdx});
130 logFailure("Negative residual for " + std::string(componentName) + " equation.");
131 }
132 else if (residual > tolerance) {
133 report.setReservoirFailed({type, CR::Severity::Normal, componentIdx});
134 }
135
136 report.setReservoirConvergenceMetric(type, componentIdx, residual, tolerance);
137 }
138}
139
140template <class TypeTag>
142NonlinearSystem(Simulator& simulator,
143 const ModelParameters& param,
144 WellModel& wellModel,
145 const bool terminal_output)
146 : simulator_(simulator)
147 , grid_(simulator_.vanguard().grid())
148 , terminal_output_(terminal_output)
149 , enable_state_rollback_(Parameters::Get<Parameters::EnableStateRollback>())
150 , param_(param)
151 , well_model_(wellModel)
152 , current_relaxation_(1.0)
153 , dx_old_(simulator_.model().numGridDof())
154{}
155
156template <class TypeTag>
157void
160 const int,
161 const int,
163{
164 failureReport_ = SimulatorReportSingle();
165
166 Dune::Timer perfTimer;
167 perfTimer.start();
168 report.total_linearizations = 1;
169
170 try {
171 report += this->assembleReservoir(well_model_);
172 report.assemble_time += perfTimer.stop();
173
174 // Mark timestep initialized after assembling, because well models can use
175 // needsTimestepInit() to trigger per-step setup during assembly.
176 simulator_.problem().markTimestepInitialized();
177 }
178 catch (...) {
179 report.assemble_time += perfTimer.stop();
180 failureReport_ += report;
181 throw;
182 }
183}
184
185template <class TypeTag>
189{
191 Dune::Timer perfTimer;
192 perfTimer.start();
193
194 const int lastStepFailed = timer.lastStepFailed();
195 if (grid_.comm().size() > 1 && grid_.comm().max(lastStepFailed) != grid_.comm().min(lastStepFailed)) {
196 OPM_THROW(std::runtime_error,
197 "Misalignment of the parallel simulation run in prepareStep "
198 "- the previous step succeeded on some ranks but failed on others.");
199 }
200
201 if (lastStepFailed) {
202 simulator_.problem().updateFailed();
203 if (enable_state_rollback_) {
204 simulator_.model().newtonMethod().eraseMatrix();
205 }
206 }
207 else {
208 simulator_.problem().advanceTimeLevel();
209 }
210
211 // The model still needs the report-step time context even though flow owns time stepping.
212 simulator_.setTime(timer.simulationTimeElapsed());
213 simulator_.setTimeStepSize(timer.currentStepLength());
214
215 simulator_.problem().resetIterationForNewTimestep();
216 simulator_.problem().beginTimeStep();
217
218 report.pre_post_time += perfTimer.stop();
219 return report;
220}
221
222template <class TypeTag>
223template <class WellModelType>
226assembleReservoir(WellModelType& wellModel)
227{
228 simulator_.problem().beginIteration();
229 simulator_.model().linearizer().linearizeDomain();
230 simulator_.problem().endIteration();
231 return wellModel.lastReport();
232}
233
234template <class TypeTag>
235template <class ModelParametersType>
236void
238applyTUNING(ModelParametersType& param,
239 const Tuning& tuning)
240{
241 param.tolerance_cnv_ = tuning.TRGCNV;
242 param.tolerance_cnv_relaxed_ = tuning.XXXCNV;
243 param.tolerance_mb_ = tuning.TRGMBE;
244 param.tolerance_mb_relaxed_ = tuning.XXXMBE;
245 param.newton_max_iter_ = tuning.NEWTMX;
246 param.newton_min_iter_ = tuning.NEWTMN;
247}
248
249template <class TypeTag>
250template <class ModelParametersType>
251void
253applyTUNINGDP(ModelParametersType& param,
254 const TuningDp& tuning_dp)
255{
256 param.tolerance_max_dp_ = tuning_dp.TRGDDP;
257 param.tolerance_max_ds_ = tuning_dp.TRGDDS;
258 param.tolerance_max_drs_ = tuning_dp.TRGDDRS;
259 param.tolerance_max_drv_ = tuning_dp.TRGDDRV;
260}
261
262template <class TypeTag>
263template <class ValueType>
264std::tuple<ValueType, ValueType>
267 const ValueType primaryVolumeLocal,
268 const ValueType secondaryVolumeLocal,
269 std::vector<ValueType>& sumValues,
270 std::vector<ValueType>& maxValues,
271 std::vector<ValueType>& averagedValues)
272{
273 OPM_TIMEBLOCK(convergenceReduction);
274
275 ValueType primaryVolume = primaryVolumeLocal;
276 ValueType secondaryVolume = secondaryVolumeLocal;
277
278 if (comm.size() > 1) {
279 std::vector<ValueType> sumBuffer;
280 std::vector<ValueType> maxBuffer;
281 const int numComp = averagedValues.size();
282 sumBuffer.reserve(2 * numComp + 2);
283 maxBuffer.reserve(numComp);
284
285 for (int compIdx = 0; compIdx < numComp; ++compIdx) {
286 sumBuffer.push_back(averagedValues[compIdx]);
287 sumBuffer.push_back(sumValues[compIdx]);
288 maxBuffer.push_back(maxValues[compIdx]);
289 }
290
291 sumBuffer.push_back(primaryVolume);
292 sumBuffer.push_back(secondaryVolume);
293
294 comm.sum(sumBuffer.data(), sumBuffer.size());
295 comm.max(maxBuffer.data(), maxBuffer.size());
296
297 for (int compIdx = 0, buffIdx = 0; compIdx < numComp; ++compIdx, ++buffIdx) {
298 averagedValues[compIdx] = sumBuffer[buffIdx];
299 ++buffIdx;
300 sumValues[compIdx] = sumBuffer[buffIdx];
301 }
302
303 for (int compIdx = 0; compIdx < numComp; ++compIdx) {
304 maxValues[compIdx] = maxBuffer[compIdx];
305 }
306
307 primaryVolume = sumBuffer[sumBuffer.size() - 2];
308 secondaryVolume = sumBuffer.back();
309 }
310
311 return {primaryVolume, secondaryVolume};
312}
313
314} // namespace Opm
315
316#endif // OPM_FLOW_NONLINEAR_SYSTEM_IMPL_HEADER_INCLUDED
Defines some fundamental parameters for all models.
Definition: ConvergenceReport.hpp:38
void setReservoirConvergenceMetric(Args &&... args)
Definition: ConvergenceReport.hpp:303
void setReservoirFailed(const ReservoirFailure &rf)
Definition: ConvergenceReport.hpp:290
void updateTUNINGDP(const TuningDp &tuning_dp)
Definition: NonlinearSystem_impl.hpp:60
void applyTUNINGDP(ModelParametersType &param, const TuningDp &tuning_dp)
Definition: NonlinearSystem_impl.hpp:253
std::tuple< ValueType, ValueType > convergenceReduction(Parallel::Communication comm, const ValueType primaryVolumeLocal, const ValueType secondaryVolumeLocal, std::vector< ValueType > &sumValues, std::vector< ValueType > &maxValues, std::vector< ValueType > &averagedValues)
Definition: NonlinearSystem_impl.hpp:266
void updateSolution(const GlobalEqVector &dx)
Definition: NonlinearSystem_impl.hpp:68
void addReservoirConvergenceMetrics(ConvergenceReport &report, const int componentIdx, const std::string_view componentName, const std::span< const Scalar > residuals, const std::span< const ConvergenceReport::ReservoirFailure::Type > types, const std::span< const Scalar > tolerances, const Scalar maxResidualAllowed, LogFailure &&logFailure) const
Definition: NonlinearSystem_impl.hpp:101
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: NonlinearSystem.hpp:51
virtual void initialLinearization(SimulatorReportSingle &report, int minIter, int maxIter, const SimulatorTimerInterface &timer)
Definition: NonlinearSystem_impl.hpp:159
void updateTUNING(const Tuning &tuning)
Definition: NonlinearSystem_impl.hpp:52
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: NonlinearSystem.hpp:47
void applyTUNING(ModelParametersType &param, const Tuning &tuning)
Definition: NonlinearSystem_impl.hpp:238
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: NonlinearSystem.hpp:52
SimulatorReportSingle prepareStep(const SimulatorTimerInterface &timer)
Definition: NonlinearSystem_impl.hpp:188
GetPropType< TypeTag, Properties::WellModel > WellModel
Definition: NonlinearSystem.hpp:54
NonlinearSystem(Simulator &simulator, const ModelParameters &param, WellModel &wellModel, const bool terminal_output)
Definition: NonlinearSystem_impl.hpp:142
SimulatorReportSingle assembleReservoir(const SimulatorTimerInterface &timer)
Definition: NonlinearSystem_impl.hpp:44
Interface class for SimulatorTimer objects, to be improved.
Definition: SimulatorTimerInterface.hpp:34
virtual bool lastStepFailed() const =0
Return true if last time step failed.
virtual double currentStepLength() const =0
virtual double simulationTimeElapsed() const =0
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hpp:192
Definition: blackoilbioeffectsmodules.hh:45
This file provides the infrastructure to retrieve run-time parameters.
Solver parameters for the NonlinearSystemBlackOilReservoir.
Definition: BlackoilModelParameters.hpp:207
A struct for returning timing data from a simulator to its caller.
Definition: SimulatorReport.hpp:34
double assemble_time
Definition: SimulatorReport.hpp:39
double pre_post_time
Definition: SimulatorReport.hpp:40
unsigned int total_linearizations
Definition: SimulatorReport.hpp:49