20 #ifndef OPM_NONLINEAR_SYSTEM_COMPOSITIONAL_IMPL_HEADER_INCLUDED 21 #define OPM_NONLINEAR_SYSTEM_COMPOSITIONAL_IMPL_HEADER_INCLUDED 23 #ifndef OPM_NONLINEAR_SYSTEM_COMPOSITIONAL_HEADER_INCLUDED 25 #include <opm/simulators/flow/NonlinearSystemCompositional.hpp> 28 #include <dune/common/timer.hh> 30 #include <opm/common/ErrorMacros.hpp> 31 #include <opm/common/OpmLog/OpmLog.hpp> 39 template <
class TypeTag>
40 NonlinearSystemCompositional<TypeTag>::
41 NonlinearSystemCompositional(Simulator& simulator,
42 const ModelParameters& param,
43 CompWellModel<TypeTag>& wellModel,
44 const bool terminalOutput)
45 : ParentType(simulator, param, wellModel, terminalOutput)
47 this->convergence_reports_.reserve(64);
50 template <
class TypeTag>
52 NonlinearSystemCompositional<TypeTag>::
53 prepareStep(
const SimulatorTimerInterface& timer)
55 SimulatorReportSingle report;
56 Dune::Timer perfTimer;
59 const int lastStepFailed = timer.lastStepFailed();
60 if (this->grid_.comm().size() > 1
61 && this->grid_.comm().max(lastStepFailed) != this->grid_.comm().min(lastStepFailed)) {
62 OPM_THROW(std::runtime_error,
63 "Misalignment of the parallel simulation run in prepareStep " 64 "- the previous step succeeded on some ranks but failed on others.");
68 this->wellModel().restoreLastValidState();
69 this->simulator_.model().updateFailed();
72 this->simulator_.model().advanceTimeLevel();
75 this->simulator_.setTime(timer.simulationTimeElapsed());
76 this->simulator_.setTimeStepSize(timer.currentStepLength());
78 this->simulator_.problem().resetIterationForNewTimestep();
79 this->simulator_.problem().beginTimeStep();
81 report.pre_post_time += perfTimer.stop();
85 template <
class TypeTag>
87 NonlinearSystemCompositional<TypeTag>::
88 initialLinearization(SimulatorReportSingle& report,
91 const SimulatorTimerInterface& timer)
93 ParentType::initialLinearization(report,
97 Dune::Timer perfTimer;
100 auto convrep = ConvergenceReport{timer.simulationTimeElapsed()};
101 const auto residualMetrics = this->reservoirResidualMetrics();
102 const auto tolerance = this->simulator_.model().newtonMethod().tolerance();
104 for (
int compIdx = 0; compIdx < numEq; ++compIdx) {
105 const std::array<Scalar, 1> residual{residualMetrics[compIdx]};
106 const std::array<ConvergenceReport::ReservoirFailure::Type, 1> types{
107 ConvergenceReport::ReservoirFailure::Type::MassBalance
109 const std::array<Scalar, 1> tolerances{tolerance};
111 this->addReservoirConvergenceMetrics(
114 this->compNames_.name(compIdx),
118 this->param_.max_residual_allowed_,
119 [
this](
const std::string& message)
121 if (this->terminal_output_) {
122 OpmLog::debug(message);
127 const auto severity = convrep.severityOfWorstFailure();
128 const bool wellConverged = this->wellModel().getWellConvergence();
129 report.converged = convrep.converged() && wellConverged &&
130 this->simulator_.problem().iterationContext().iteration() >= minIter;
132 this->convergence_reports_.back().report.push_back(std::move(convrep));
133 report.update_time += perfTimer.stop();
134 this->residual_norms_history_.push_back(residualMetrics);
136 if (severity == ConvergenceReport::Severity::NotANumber) {
137 this->failureReport_ += report;
138 OPM_THROW_PROBLEM(NumericalProblem,
"NaN residual found!");
141 if (severity == ConvergenceReport::Severity::TooLarge) {
142 this->failureReport_ += report;
143 OPM_THROW_NOLOG(NumericalProblem,
"Too large residual found!");
147 template <
class TypeTag>
148 template <
class NonlinearSolverType>
149 SimulatorReportSingle
150 NonlinearSystemCompositional<TypeTag>::
151 nonlinearIteration(
const SimulatorTimerInterface& timer,
152 NonlinearSolverType& nonlinearSolver)
154 if (this->simulator_.problem().iterationContext().needsTimestepInit()) {
155 this->residual_norms_history_.clear();
156 this->current_relaxation_ = 1.0;
158 this->convergence_reports_.push_back({timer.reportStepNum(), timer.currentStepNum(), {}});
159 this->convergence_reports_.back().report.reserve(numEq);
162 auto result = this->nonlinearIterationNewton(timer, nonlinearSolver);
163 this->simulator_.problem().advanceIteration();
167 template <
class TypeTag>
168 template <
class NonlinearSolverType>
169 SimulatorReportSingle
170 NonlinearSystemCompositional<TypeTag>::
171 nonlinearIterationNewton(
const SimulatorTimerInterface& timer,
172 NonlinearSolverType& nonlinearSolver)
176 SimulatorReportSingle report;
177 Dune::Timer perfTimer;
179 this->initialLinearization(report,
180 this->param_.newton_min_iter_,
181 this->param_.newton_max_iter_,
184 if (!report.converged) {
187 report.total_newton_iterations = 1;
189 BVector x(this->simulator_.model().numGridDof());
190 this->linear_solve_setup_time_ = 0.0;
193 auto& linearizer = this->simulator_.model().linearizer();
194 linearizer.linearizeAuxiliaryEquations();
195 linearizer.finalize();
197 this->solveJacobianSystem(x);
199 report.linear_solve_setup_time += this->linear_solve_setup_time_;
200 report.linear_solve_time += perfTimer.stop();
201 report.total_linear_iterations += this->linearIterationsLastSolve();
204 report.linear_solve_setup_time += this->linear_solve_setup_time_;
205 report.linear_solve_time += perfTimer.stop();
206 report.total_linear_iterations += this->linearIterationsLastSolve();
208 this->failureReport_ += report;
215 auto& model = this->simulator_.model();
216 for (
unsigned auxModIdx = 0; auxModIdx < model.numAuxiliaryModules(); ++auxModIdx) {
217 model.auxiliaryModule(auxModIdx)->postSolve(x);
220 if (this->param_.use_update_stabilization_) {
221 bool isOscillate =
false;
222 bool isStagnate =
false;
223 nonlinearSolver.detectOscillations(this->residual_norms_history_,
224 this->residual_norms_history_.size() - 1,
229 this->current_relaxation_ -= nonlinearSolver.relaxIncrement();
230 this->current_relaxation_ = std::max(this->current_relaxation_, nonlinearSolver.relaxMax());
232 if (this->terminalOutputEnabled()) {
233 OpmLog::info(
" Oscillating behavior detected: Relaxation set to " 234 + std::to_string(this->current_relaxation_));
238 nonlinearSolver.stabilizeNonlinearUpdate(x, this->dx_old_, this->current_relaxation_);
241 this->updateSolution(x);
242 report.update_time += perfTimer.stop();
248 template <
class TypeTag>
249 typename NonlinearSystemCompositional<TypeTag>::Scalar
250 NonlinearSystemCompositional<TypeTag>::
251 relativeChange()
const 253 Scalar resultDelta = 0.0;
254 Scalar resultDenom = 0.0;
256 const auto& elemMapper = this->simulator_.model().elementMapper();
257 const auto& gridView = this->simulator_.gridView();
259 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
260 const unsigned globalElemIdx = elemMapper.index(elem);
261 const auto& priVarsNew = this->simulator_.model().solution(0)[globalElemIdx];
262 const auto& priVarsOld = this->simulator_.model().solution(1)[globalElemIdx];
264 for (
int pvIdx = 0; pvIdx < static_cast<int>(priVarsNew.size()); ++pvIdx) {
265 const auto delta = priVarsNew[pvIdx] - priVarsOld[pvIdx];
266 resultDelta += delta * delta;
267 resultDenom += priVarsNew[pvIdx] * priVarsNew[pvIdx];
271 resultDelta = gridView.comm().sum(resultDelta);
272 resultDenom = gridView.comm().sum(resultDenom);
274 return resultDenom > 0.0 ? resultDelta / resultDenom : 0.0;
277 template <
class TypeTag>
279 NonlinearSystemCompositional<TypeTag>::
280 solveJacobianSystem(BVector& x)
282 auto& jacobian = this->simulator_.model().linearizer().jacobian();
283 auto& residual = this->simulator_.model().linearizer().residual();
284 auto& linSolver = this->simulator_.model().newtonMethod().linearSolver();
288 Dune::Timer perfTimer;
290 linSolver.prepare(jacobian, residual);
291 this->linear_solve_setup_time_ = perfTimer.stop();
292 linSolver.setResidual(residual);
293 linSolver.getResidual(residual);
294 linSolver.setMatrix(jacobian);
298 template <
class TypeTag>
299 std::vector<typename NonlinearSystemCompositional<TypeTag>::Scalar>
300 NonlinearSystemCompositional<TypeTag>::
301 reservoirResidualMetrics()
const 303 const auto& model = this->simulator_.model();
304 const auto& residual = model.linearizer().residual();
305 const auto& constraintsMap = model.linearizer().constraintsMap();
307 std::vector<Scalar> residualMetrics(numEq, 0.0);
309 for (
unsigned dofIdx = 0; dofIdx < residual.size(); ++dofIdx) {
310 if (dofIdx >= model.numGridDof() || model.dofTotalVolume(dofIdx) <= 0.0) {
314 if (constraintsMap.count(dofIdx) > 0) {
318 const auto& localResidual = residual[dofIdx];
319 for (
int eqIdx = 0; eqIdx < numEq; ++eqIdx) {
320 residualMetrics[eqIdx] = std::max(
321 residualMetrics[eqIdx],
322 std::abs(localResidual[eqIdx] * model.eqWeight(dofIdx, eqIdx)));
326 if (this->grid_.comm().size() > 1 && !residualMetrics.empty()) {
327 this->grid_.comm().max(residualMetrics.data(), residualMetrics.size());
330 return residualMetrics;
335 #endif // OPM_NONLINEAR_SYSTEM_COMPOSITIONAL_IMPL_HEADER_INCLUDED Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45