opm-simulators
FlowExpNewtonMethod.hpp
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
28 #ifndef OPM_FLOW_EXP_NEWTON_METHOD_HPP
29 #define OPM_FLOW_EXP_NEWTON_METHOD_HPP
30 
31 #include <opm/common/Exceptions.hpp>
32 #include <opm/common/OpmLog/OpmLog.hpp>
33 
36 
37 namespace Opm::Parameters {
38 
39 // the tolerated amount of "incorrect" amount of oil per time step for the complete
40 // reservoir. this is scaled by the pore volume of the reservoir, i.e., larger reservoirs
41 // will tolerate larger residuals.
42 template<class Scalar>
43 struct EclNewtonSumTolerance { static constexpr Scalar value = 1e-5; };
44 
45 // make all Newton iterations strict, i.e., the volumetric Newton tolerance must be
46 // always be upheld in the majority of the spatial domain. In this context, "majority"
47 // means 1 - EclNewtonRelaxedVolumeFraction.
48 struct EclNewtonStrictIterations { static constexpr int value = 100; };
49 
50 // set fraction of the pore volume where the volumetric residual may be violated during
51 // strict Newton iterations
52 template<class Scalar>
53 struct EclNewtonRelaxedVolumeFraction { static constexpr Scalar value = 0.05; };
54 
55 template<class Scalar>
56 struct EclNewtonSumToleranceExponent { static constexpr Scalar value = 1.0 / 3.0; };
57 
58 // the maximum volumetric error of a cell in the relaxed region
59 template<class Scalar>
60 struct EclNewtonRelaxedTolerance { static constexpr Scalar value = NewtonTolerance<Scalar>::value * 1e6; };
61 
62 } // namespace Opm::Parameters
63 
64 namespace Opm {
65 
69 template <class TypeTag>
71 {
72  using ParentType = BlackOilNewtonMethod<TypeTag>;
74 
85 
86  static constexpr unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
87 
88  static constexpr int contiSolventEqIdx = Indices::contiSolventEqIdx;
89  static constexpr int contiPolymerEqIdx = Indices::contiPolymerEqIdx;
90  static constexpr int contiEnergyEqIdx = Indices::contiEnergyEqIdx;
91 
92  friend NewtonMethod<TypeTag>;
93  friend DiscNewtonMethod;
94  friend ParentType;
95 
96 public:
97  explicit FlowExpNewtonMethod(Simulator& simulator) : ParentType(simulator)
98  {
99  errorPvFraction_ = 1.0;
100  relaxedMaxPvFraction_ = Parameters::Get<Parameters::EclNewtonRelaxedVolumeFraction<Scalar>>();
101 
102  sumTolerance_ = 0.0; // this gets determined in the error calculation proceedure
103  relaxedTolerance_ = Parameters::Get<Parameters::EclNewtonRelaxedTolerance<Scalar>>();
104 
105  numStrictIterations_ = Parameters::Get<Parameters::EclNewtonStrictIterations>();
106  }
107 
111  static void registerParameters()
112  {
114 
115  Parameters::Register<Parameters::EclNewtonSumTolerance<Scalar>>
116  ("The maximum error tolerated by the Newton "
117  "method for considering a solution to be converged");
118  Parameters::Register<Parameters::EclNewtonStrictIterations>
119  ("The number of Newton iterations where the "
120  "volumetric error is considered.");
121  Parameters::Register<Parameters::EclNewtonRelaxedVolumeFraction<Scalar>>
122  ("The fraction of the pore volume of the reservoir "
123  "where the volumetric error may be violated during strict Newton iterations.");
124  Parameters::Register<Parameters::EclNewtonSumToleranceExponent<Scalar>>
125  ("The the exponent used to scale the sum tolerance by "
126  "the total pore volume of the reservoir.");
127  Parameters::Register<Parameters::EclNewtonRelaxedTolerance<Scalar>>
128  ("The maximum error which the volumetric residual "
129  "may exhibit if it is in a 'relaxed' region during a strict iteration.");
130  }
131 
136  bool converged() const
137  {
138  if (errorPvFraction_ < relaxedMaxPvFraction_
139  || this->problem().iterationContext().shouldRelax(numStrictIterations_ + 1)) {
140  return (this->error_ < relaxedTolerance_ && errorSum_ < sumTolerance_);
141  }
142 
143  return this->error_ <= this->tolerance() && errorSum_ <= sumTolerance_;
144  }
145 
146  void preSolve_(const SolutionVector&,
147  const GlobalEqVector& currentResidual)
148  {
149  const auto& constraintsMap = this->model().linearizer().constraintsMap();
150  this->lastError_ = this->error_;
151  Scalar newtonMaxError = this->params_.maxError_;
152 
153  // calculate the error as the maximum weighted tolerance of
154  // the solution's residual
155  this->error_ = 0.0;
156  Dune::FieldVector<Scalar, numEq> componentSumError;
157  std::ranges::fill(componentSumError, 0.0);
158  Scalar sumPv = 0.0;
159  errorPvFraction_ = 0.0;
160  const Scalar dt = this->simulator_.timeStepSize();
161  for (unsigned dofIdx = 0; dofIdx < currentResidual.size(); ++dofIdx) {
162  // do not consider auxiliary DOFs for the error
163  if (dofIdx >= this->model().numGridDof()
164  || this->model().dofTotalVolume(dofIdx) <= 0.0) {
165  continue;
166  }
167 
168  if (!this->model().isLocalDof(dofIdx)) {
169  continue;
170  }
171 
172  // also do not consider DOFs which are constraint
173  if (this->enableConstraints_()) {
174  if (constraintsMap.count(dofIdx) > 0) {
175  continue;
176  }
177  }
178 
179  const auto& r = currentResidual[dofIdx];
180  Scalar pvValue = this->simulator_.problem().referencePorosity(dofIdx, /*timeIdx=*/0) *
181  this->model().dofTotalVolume(dofIdx);
182  sumPv += pvValue;
183  bool cnvViolated = false;
184 
185  Scalar dofVolume = this->model().dofTotalVolume(dofIdx);
186 
187  for (unsigned eqIdx = 0; eqIdx < r.size(); ++eqIdx) {
188  Scalar tmpError = r[eqIdx] * dt * this->model().eqWeight(dofIdx, eqIdx) / pvValue;
189  Scalar tmpError2 = r[eqIdx] * this->model().eqWeight(dofIdx, eqIdx);
190 
191  // in the case of a volumetric formulation, the residual in the above is
192  // per cubic meter
193  if (getPropValue<TypeTag, Properties::UseVolumetricResidual>()) {
194  tmpError *= dofVolume;
195  tmpError2 *= dofVolume;
196  }
197 
198  this->error_ = max(std::abs(tmpError), this->error_);
199 
200  if (std::abs(tmpError) > this->params_.tolerance_) {
201  cnvViolated = true;
202  }
203 
204  componentSumError[eqIdx] += std::abs(tmpError2);
205  }
206  if (cnvViolated) {
207  errorPvFraction_ += pvValue;
208  }
209  }
210 
211  // take the other processes into account
212  this->error_ = this->comm_.max(this->error_);
213  componentSumError = this->comm_.sum(componentSumError);
214  sumPv = this->comm_.sum(sumPv);
215  errorPvFraction_ = this->comm_.sum(errorPvFraction_);
216 
217  componentSumError /= sumPv;
218  componentSumError *= dt;
219 
220  errorPvFraction_ /= sumPv;
221 
222  errorSum_ = 0;
223  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
224  errorSum_ = std::max(std::abs(componentSumError[eqIdx]), errorSum_);
225  }
226 
227  // scale the tolerance for the total error with the pore volume. by default, the
228  // exponent is 1/3, i.e., cubic root.
229  Scalar x = Parameters::Get<Parameters::EclNewtonSumTolerance<Scalar>>();
230  Scalar y = Parameters::Get<Parameters::EclNewtonSumToleranceExponent<Scalar>>();
231  sumTolerance_ = x*std::pow(sumPv, y);
232 
233  this->endIterMsg() << " (max: " << this->params_.tolerance_
234  << ", violated for " << errorPvFraction_ * 100
235  << "% of the pore volume), aggegate error: "
236  << errorSum_ << " (max: " << sumTolerance_ << ")";
237 
238  // make sure that the error never grows beyond the maximum
239  // allowed one
240  if (this->error_ > newtonMaxError) {
241  throw NumericalProblem("Newton: Error "+std::to_string(double(this->error_))
242  + " is larger than maximum allowed error of "
243  + std::to_string(double(newtonMaxError)));
244  }
245 
246  // make sure that the error never grows beyond the maximum
247  // allowed one
248  if (errorSum_ > newtonMaxError) {
249  throw NumericalProblem("Newton: Sum of the error "+std::to_string(double(errorSum_))
250  + " is larger than maximum allowed error of "
251  + std::to_string(double(newtonMaxError)));
252  }
253  }
254 
255  void endIteration_(SolutionVector& nextSolution,
256  const SolutionVector& currentSolution)
257  {
258  ParentType::endIteration_(nextSolution, currentSolution);
259  OpmLog::debug( "Newton iteration " + std::to_string(this->problem().iterationContext().iteration()) + ""
260  + " error: " + std::to_string(double(this->error_))
261  + this->endIterMsg().str());
262  this->endIterMsg().str("");
263  }
264 
265 private:
266  Scalar errorPvFraction_;
267  Scalar errorSum_;
268 
269  Scalar relaxedTolerance_;
270  Scalar relaxedMaxPvFraction_;
271 
272  Scalar sumTolerance_;
273 
274  int numStrictIterations_;
275 };
276 
277 } // namespace Opm
278 
279 #endif
The value for the error below which convergence is declared.
Definition: newtonmethodparams.hpp:53
A newton solver.
Definition: FlowExpNewtonMethod.hpp:70
The multi-dimensional Newton method.
Definition: newtonmethod.hh:64
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
Definition: FlowExpNewtonMethod.hpp:48
Definition: FlowExpNewtonMethod.hpp:53
static void registerParameters()
Register all run-time parameters for the Newton method.
Definition: FlowExpNewtonMethod.hpp:111
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Definition: blackoilnewtonmethodparams.hpp:31
Definition: FlowExpNewtonMethod.hpp:43
A newton solver which is specific to the black oil model.
Definition: blackoilnewtonmethod.hpp:63
Definition: FlowExpNewtonMethod.hpp:60
static void registerParameters()
Register all run-time parameters for the blackoil newton method.
Definition: blackoilnewtonmethod.hpp:100
void endIteration_(SolutionVector &uCurrentIter, const SolutionVector &uLastIter)
Indicates that one Newton iteration was finished.
Definition: blackoilnewtonmethod.hpp:132
bool converged() const
Returns true if the error of the solution is below the tolerance.
Definition: FlowExpNewtonMethod.hpp:136
Definition: FlowExpNewtonMethod.hpp:56
A newton solver which is specific to the black oil model.