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
31#include <cmath>
32#include <stdexcept>
33#include <string>
34#include <utility>
35
36namespace Opm {
37
38template <class TypeTag>
39SimulatorReportSingle
42{
43 return assembleReservoir(well_model_);
44}
45
46template <class TypeTag>
47void
49updateTUNING(const Tuning& tuning)
50{
51 applyTUNING(param_, tuning);
52}
53
54template <class TypeTag>
55void
57updateTUNINGDP(const TuningDp& tuning_dp)
58{
59 applyTUNINGDP(param_, tuning_dp);
60}
61
62template <class TypeTag>
63void
66{
67 OPM_TIMEBLOCK(updateSolution);
68
69 const bool shouldStore = shouldStoreSolutionUpdate();
70 if (shouldStore) {
71 prepareSolutionUpdate();
72 }
73
74 auto& newtonMethod = simulator_.model().newtonMethod();
75 auto& solution = simulator_.model().solution(/*timeIdx=*/0);
76
77 newtonMethod.applyUpdate(/*nextSolution=*/solution,
78 /*curSolution=*/solution,
79 /*update=*/dx,
80 /*resid=*/dx);
81
82 {
83 OPM_TIMEBLOCK(invalidateAndUpdateIntensiveQuantities);
84 simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
85 }
86
87 if (shouldStore) {
88 storeSolutionUpdate(dx);
89 }
90}
91
92template <class TypeTag>
93template <class LogFailure>
94void
97 const int componentIdx,
98 const std::string_view componentName,
99 const std::span<const Scalar> residuals,
100 const std::span<const ConvergenceReport::ReservoirFailure::Type> types,
101 const std::span<const Scalar> tolerances,
102 const Scalar maxResidualAllowed,
103 LogFailure&& logFailure) const
104{
105 if (residuals.size() != types.size() || residuals.size() != tolerances.size()) {
106 OPM_THROW(std::logic_error, "Mismatched reservoir convergence metric sizes.");
107 }
108
109 using CR = ConvergenceReport;
110 for (std::size_t metricIdx = 0; metricIdx < residuals.size(); ++metricIdx) {
111 const auto residual = residuals[metricIdx];
112 const auto type = types[metricIdx];
113 const auto tolerance = tolerances[metricIdx];
114
115 if (std::isnan(residual)) {
116 report.setReservoirFailed({type, CR::Severity::NotANumber, componentIdx});
117 logFailure("NaN residual for " + std::string(componentName) + " equation.");
118 }
119 else if (residual > maxResidualAllowed) {
120 report.setReservoirFailed({type, CR::Severity::TooLarge, componentIdx});
121 logFailure("Too large residual for " + std::string(componentName) + " equation.");
122 }
123 else if (residual < 0.0) {
124 report.setReservoirFailed({type, CR::Severity::Normal, componentIdx});
125 logFailure("Negative residual for " + std::string(componentName) + " equation.");
126 }
127 else if (residual > tolerance) {
128 report.setReservoirFailed({type, CR::Severity::Normal, componentIdx});
129 }
130
131 report.setReservoirConvergenceMetric(type, componentIdx, residual, tolerance);
132 }
133}
134
135template <class TypeTag>
137NonlinearSystem(Simulator& simulator,
138 const ModelParameters& param,
139 WellModel& wellModel,
140 const bool terminal_output)
141 : simulator_(simulator)
142 , grid_(simulator_.vanguard().grid())
143 , terminal_output_(terminal_output)
144 , param_(param)
145 , well_model_(wellModel)
146 , current_relaxation_(1.0)
147 , dx_old_(simulator_.model().numGridDof())
148{}
149
150template <class TypeTag>
151void
154 const int,
155 const int,
157{
158 failureReport_ = SimulatorReportSingle();
159
160 Dune::Timer perfTimer;
161 perfTimer.start();
162 report.total_linearizations = 1;
163
164 try {
165 report += this->assembleReservoir(well_model_);
166 report.assemble_time += perfTimer.stop();
167
168 // Mark timestep initialized after assembling, because well models can use
169 // needsTimestepInit() to trigger per-step setup during assembly.
170 simulator_.problem().markTimestepInitialized();
171 }
172 catch (...) {
173 report.assemble_time += perfTimer.stop();
174 failureReport_ += report;
175 throw;
176 }
177}
178
179template <class TypeTag>
183{
185 Dune::Timer perfTimer;
186 perfTimer.start();
187
188 const int lastStepFailed = timer.lastStepFailed();
189 if (grid_.comm().size() > 1 && grid_.comm().max(lastStepFailed) != grid_.comm().min(lastStepFailed)) {
190 OPM_THROW(std::runtime_error,
191 "Misalignment of the parallel simulation run in prepareStep "
192 "- the previous step succeeded on some ranks but failed on others.");
193 }
194
195 if (lastStepFailed) {
196 simulator_.model().updateFailed();
197 }
198 else {
199 simulator_.model().advanceTimeLevel();
200 }
201
202 // The model still needs the report-step time context even though flow owns time stepping.
203 simulator_.setTime(timer.simulationTimeElapsed());
204 simulator_.setTimeStepSize(timer.currentStepLength());
205
206 simulator_.problem().resetIterationForNewTimestep();
207 simulator_.problem().beginTimeStep();
208
209 report.pre_post_time += perfTimer.stop();
210 return report;
211}
212
213template <class TypeTag>
214template <class WellModelType>
217assembleReservoir(WellModelType& wellModel)
218{
219 simulator_.problem().beginIteration();
220 simulator_.model().linearizer().linearizeDomain();
221 simulator_.problem().endIteration();
222 return wellModel.lastReport();
223}
224
225template <class TypeTag>
226template <class ModelParametersType>
227void
229applyTUNING(ModelParametersType& param,
230 const Tuning& tuning)
231{
232 param.tolerance_cnv_ = tuning.TRGCNV;
233 param.tolerance_cnv_relaxed_ = tuning.XXXCNV;
234 param.tolerance_mb_ = tuning.TRGMBE;
235 param.tolerance_mb_relaxed_ = tuning.XXXMBE;
236 param.newton_max_iter_ = tuning.NEWTMX;
237 param.newton_min_iter_ = tuning.NEWTMN;
238}
239
240template <class TypeTag>
241template <class ModelParametersType>
242void
244applyTUNINGDP(ModelParametersType& param,
245 const TuningDp& tuning_dp)
246{
247 param.tolerance_max_dp_ = tuning_dp.TRGDDP;
248 param.tolerance_max_ds_ = tuning_dp.TRGDDS;
249 param.tolerance_max_drs_ = tuning_dp.TRGDDRS;
250 param.tolerance_max_drv_ = tuning_dp.TRGDDRV;
251}
252
253template <class TypeTag>
254template <class ValueType>
255std::tuple<ValueType, ValueType>
258 const ValueType primaryVolumeLocal,
259 const ValueType secondaryVolumeLocal,
260 std::vector<ValueType>& sumValues,
261 std::vector<ValueType>& maxValues,
262 std::vector<ValueType>& averagedValues)
263{
264 OPM_TIMEBLOCK(convergenceReduction);
265
266 ValueType primaryVolume = primaryVolumeLocal;
267 ValueType secondaryVolume = secondaryVolumeLocal;
268
269 if (comm.size() > 1) {
270 std::vector<ValueType> sumBuffer;
271 std::vector<ValueType> maxBuffer;
272 const int numComp = averagedValues.size();
273 sumBuffer.reserve(2 * numComp + 2);
274 maxBuffer.reserve(numComp);
275
276 for (int compIdx = 0; compIdx < numComp; ++compIdx) {
277 sumBuffer.push_back(averagedValues[compIdx]);
278 sumBuffer.push_back(sumValues[compIdx]);
279 maxBuffer.push_back(maxValues[compIdx]);
280 }
281
282 sumBuffer.push_back(primaryVolume);
283 sumBuffer.push_back(secondaryVolume);
284
285 comm.sum(sumBuffer.data(), sumBuffer.size());
286 comm.max(maxBuffer.data(), maxBuffer.size());
287
288 for (int compIdx = 0, buffIdx = 0; compIdx < numComp; ++compIdx, ++buffIdx) {
289 averagedValues[compIdx] = sumBuffer[buffIdx];
290 ++buffIdx;
291 sumValues[compIdx] = sumBuffer[buffIdx];
292 }
293
294 for (int compIdx = 0; compIdx < numComp; ++compIdx) {
295 maxValues[compIdx] = maxBuffer[compIdx];
296 }
297
298 primaryVolume = sumBuffer[sumBuffer.size() - 2];
299 secondaryVolume = sumBuffer.back();
300 }
301
302 return {primaryVolume, secondaryVolume};
303}
304
305} // namespace Opm
306
307#endif // OPM_FLOW_NONLINEAR_SYSTEM_IMPL_HEADER_INCLUDED
Definition: ConvergenceReport.hpp:38
void setReservoirConvergenceMetric(Args &&... args)
Definition: ConvergenceReport.hpp:279
void setReservoirFailed(const ReservoirFailure &rf)
Definition: ConvergenceReport.hpp:266
void updateTUNINGDP(const TuningDp &tuning_dp)
Definition: NonlinearSystem_impl.hpp:57
void applyTUNINGDP(ModelParametersType &param, const TuningDp &tuning_dp)
Definition: NonlinearSystem_impl.hpp:244
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:257
void updateSolution(const GlobalEqVector &dx)
Definition: NonlinearSystem_impl.hpp:65
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:96
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:153
void updateTUNING(const Tuning &tuning)
Definition: NonlinearSystem_impl.hpp:49
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: NonlinearSystem.hpp:47
void applyTUNING(ModelParametersType &param, const Tuning &tuning)
Definition: NonlinearSystem_impl.hpp:229
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: NonlinearSystem.hpp:52
SimulatorReportSingle prepareStep(const SimulatorTimerInterface &timer)
Definition: NonlinearSystem_impl.hpp:182
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:137
SimulatorReportSingle assembleReservoir(const SimulatorTimerInterface &timer)
Definition: NonlinearSystem_impl.hpp:41
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
Definition: blackoilbioeffectsmodules.hh:45
Solver parameters for the NonlinearSystemBlackOilReservoir.
Definition: BlackoilModelParameters.hpp:201
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