28#ifndef OPM_BLACK_OIL_NEWTON_METHOD_HPP
29#define OPM_BLACK_OIL_NEWTON_METHOD_HPP
31#include <opm/common/Exceptions.hpp>
41#include <opm/material/common/Valgrind.hpp>
50template <
class TypeTag,
class MyTypeTag>
51struct DiscNewtonMethod;
62template <
class TypeTag>
75 static constexpr bool enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>();
76 using BioeffectsModule = BlackOilBioeffectsModule<TypeTag, enableBioeffects>;
78 static const unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
79 static constexpr bool enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>();
92 ParentType::finishInit();
94 wasSwitched_.resize(this->model().numTotalDof(),
false);
99 numPriVarsSwitched_ = 0;
100 std::fill(wasSwitched_.begin(), wasSwitched_.end(),
false);
108 ParentType::registerParameters();
117 {
return numPriVarsSwitched_; }
128 numPriVarsSwitched_ = 0;
129 ParentType::beginIteration_();
139 const SolutionVector& uLastIter)
144 const int localSwitched = numPriVarsSwitched_;
145 MPI_Allreduce(&localSwitched,
146 &numPriVarsSwitched_,
153 this->simulator_.model().newtonMethod().endIterMsg()
154 <<
", num switched=" << numPriVarsSwitched_;
156 ParentType::endIteration_(uCurrentIter, uLastIter);
161 const SolutionVector& currentSolution,
162 const GlobalEqVector& solutionUpdate,
163 const GlobalEqVector& currentResidual)
165 const auto& comm = this->simulator_.gridView().comm();
169 ParentType::update_(nextSolution,
178 succeeded = comm.min(succeeded);
181 throw NumericalProblem(
"A process did not succeed in adapting the primary variables");
184 numPriVarsSwitched_ = comm.sum(numPriVarsSwitched_);
187 template <
class DofIndices>
189 const SolutionVector& currentSolution,
190 const GlobalEqVector& solutionUpdate,
191 const GlobalEqVector& currentResidual,
192 const DofIndices& dofIndices)
194 const auto zero = 0.0 * solutionUpdate[0];
195 for (
auto dofIdx : dofIndices) {
196 if (solutionUpdate[dofIdx] == zero) {
200 nextSolution[dofIdx],
201 currentSolution[dofIdx],
202 solutionUpdate[dofIdx],
203 currentResidual[dofIdx]);
212 PrimaryVariables& nextValue,
213 const PrimaryVariables& currentValue,
214 const EqVector& update,
215 const EqVector& currentResidual)
217 static constexpr bool enableSolvent =
218 Indices::solventSaturationIdx != std::numeric_limits<unsigned>::max();
219 static constexpr bool enableExtbo =
220 Indices::zFractionIdx != std::numeric_limits<unsigned>::max();
221 static constexpr bool enablePolymer =
222 Indices::polymerConcentrationIdx != std::numeric_limits<unsigned>::max();
223 static constexpr bool enablePolymerWeight =
224 Indices::polymerMoleWeightIdx != std::numeric_limits<unsigned>::max();
225 static constexpr bool enableFullyImplicitThermal =
226 Indices::temperatureIdx != std::numeric_limits<unsigned>::max();
227 static constexpr bool enableFoam =
228 Indices::foamConcentrationIdx != std::numeric_limits<unsigned>::max();
229 static constexpr bool enableBrine =
230 Indices::saltConcentrationIdx != std::numeric_limits<unsigned>::max();
231 static constexpr bool enableMICP = Indices::enableMICP;
233 currentValue.checkDefined();
234 Valgrind::CheckDefined(update);
235 Valgrind::CheckDefined(currentResidual);
238 Scalar deltaSw = 0.0;
239 Scalar deltaSo = 0.0;
240 Scalar deltaSg = 0.0;
241 Scalar deltaSs = 0.0;
243 if (currentValue.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw)
245 if constexpr (Indices::waterSwitchIdx != std::numeric_limits<unsigned>::max()) {
246 deltaSw = update[Indices::waterSwitchIdx];
250 if (currentValue.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg)
252 if constexpr (Indices::compositionSwitchIdx != std::numeric_limits<unsigned>::max()) {
253 deltaSg = update[Indices::compositionSwitchIdx];
257 if (currentValue.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
258 if constexpr (Indices::solventSaturationIdx != std::numeric_limits<unsigned>::max()) {
259 deltaSs = update[Indices::solventSaturationIdx];
265 Scalar maxSatDelta = std::max(std::abs(deltaSg), std::abs(deltaSo));
266 maxSatDelta = std::max(maxSatDelta, std::abs(deltaSw));
267 maxSatDelta = std::max(maxSatDelta, std::abs(deltaSs));
271 Scalar satAlpha = 1.0;
272 if (maxSatDelta > bparams_.dsMax_) {
273 satAlpha = bparams_.dsMax_ / maxSatDelta;
276 for (
unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
283 Scalar delta = update[pvIdx];
286 if (pvIdx == Indices::pressureSwitchIdx) {
287 if (std::abs(delta) > bparams_.dpMaxRel_ * currentValue[pvIdx]) {
288 delta =
signum(delta) * bparams_.dpMaxRel_ * currentValue[pvIdx];
292 else if (pvIdx == Indices::waterSwitchIdx)
293 if (currentValue.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw) {
298 if (delta > currentValue[ Indices::waterSwitchIdx]) {
299 delta = currentValue[ Indices::waterSwitchIdx];
302 else if (pvIdx == Indices::compositionSwitchIdx) {
308 if (currentValue.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg) {
313 if (delta > currentValue[Indices::compositionSwitchIdx]) {
314 delta = currentValue[Indices::compositionSwitchIdx];
318 else if (enableSolvent && pvIdx == Indices::solventSaturationIdx) {
320 if (currentValue.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
325 if (delta > currentValue[Indices::solventSaturationIdx]) {
326 delta = currentValue[Indices::solventSaturationIdx];
330 else if (enableExtbo && pvIdx == Indices::zFractionIdx) {
332 const auto& curr = currentValue[Indices::zFractionIdx];
333 delta = std::clamp(delta, curr - Scalar{1.0}, curr);
335 else if (enablePolymerWeight && pvIdx == Indices::polymerMoleWeightIdx) {
336 const double sign = delta >= 0. ? 1. : -1.;
339 const Scalar maxMolarWeightChange = 100.0;
340 delta = sign * std::min(std::abs(delta), maxMolarWeightChange);
343 else if (enableFullyImplicitThermal && pvIdx == Indices::temperatureIdx) {
344 const double sign = delta >= 0. ? 1. : -1.;
345 delta = sign * std::min(std::abs(delta), bparams_.maxTempChange_);
347 else if (enableBrine && pvIdx == Indices::saltConcentrationIdx &&
348 enableSaltPrecipitation &&
349 currentValue.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp)
351 const Scalar maxSaltSaturationChange = 0.1;
352 const Scalar sign = delta >= 0. ? 1. : -1.;
353 delta = sign * std::min(std::abs(delta), maxSaltSaturationChange);
357 nextValue[pvIdx] = currentValue[pvIdx] - delta;
360 if (enableSolvent && pvIdx == Indices::solventSaturationIdx) {
361 if (currentValue.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
362 nextValue[pvIdx] = std::min(std::max(nextValue[pvIdx], Scalar{0.0}), Scalar{1.0});
367 if (enableExtbo && pvIdx == Indices::zFractionIdx) {
368 nextValue[pvIdx] = std::min(std::max(nextValue[pvIdx], Scalar{0.0}), Scalar{1.0});
372 if (enablePolymer && pvIdx == Indices::polymerConcentrationIdx) {
373 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
376 if (enablePolymerWeight && pvIdx == Indices::polymerMoleWeightIdx) {
377 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
378 const double polymerConcentration = nextValue[Indices::polymerConcentrationIdx];
379 if (polymerConcentration < 1.e-10) {
380 nextValue[pvIdx] = 0.0;
385 if (enableFoam && pvIdx == Indices::foamConcentrationIdx) {
386 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
389 if (enableBrine && pvIdx == Indices::saltConcentrationIdx) {
391 if (!enableSaltPrecipitation ||
392 currentValue.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Cs)
394 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
397 if (enableSaltPrecipitation &&
398 currentValue.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp)
400 nextValue[pvIdx] = std::min(nextValue[pvIdx], Scalar{1.0-1.e-8});
405 if (enableFullyImplicitThermal && pvIdx == Indices::temperatureIdx) {
406 nextValue[pvIdx] = std::clamp(nextValue[pvIdx], bparams_.tempMin_, bparams_.tempMax_);
409 if (pvIdx == Indices::pressureSwitchIdx) {
410 nextValue[pvIdx] = std::clamp(nextValue[pvIdx], bparams_.pressMin_, bparams_.pressMax_);
418 if constexpr (enableBioeffects) {
419 if (pvIdx == Indices::microbialConcentrationIdx) {
420 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
422 if (pvIdx == Indices::biofilmVolumeFractionIdx) {
423 nextValue[pvIdx] = std::clamp(nextValue[pvIdx],
425 this->problem().referencePorosity(globalDofIdx, 0) - 1e-8);
427 if constexpr (enableMICP) {
428 if (pvIdx == Indices::oxygenConcentrationIdx) {
429 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
431 if (pvIdx == Indices::ureaConcentrationIdx) {
432 nextValue[pvIdx] = std::max(nextValue[pvIdx], Scalar{0.0});
434 if (pvIdx == Indices::calciteVolumeFractionIdx) {
435 nextValue[pvIdx] = std::clamp(nextValue[pvIdx], Scalar{0.0},
436 this->problem().referencePorosity(globalDofIdx, 0) - 1e-8);
445 if (wasSwitched_[globalDofIdx]) {
446 wasSwitched_[globalDofIdx] = nextValue.adaptPrimaryVariables(this->problem(),
448 bparams_.waterSaturationMax_,
449 bparams_.waterOnlyThreshold_,
450 bparams_.priVarOscilationThreshold_);
453 wasSwitched_[globalDofIdx] = nextValue.adaptPrimaryVariables(this->problem(),
455 bparams_.waterSaturationMax_,
456 bparams_.waterOnlyThreshold_);
459 if (wasSwitched_[globalDofIdx]) {
460 ++numPriVarsSwitched_;
462 if (bparams_.projectSaturations_) {
463 nextValue.chopAndNormalizeSaturations();
466 nextValue.checkDefined();
470 int numPriVarsSwitched_{};
472 BlackoilNewtonParams<Scalar> bparams_{};
476 std::vector<bool> wasSwitched_{};
Contains classes extending the black-oil model. \detail This file holds dummy definitions,...
Declares the properties required by the black oil model.
A newton solver which is specific to the black oil model.
Definition: blackoilnewtonmethod.hpp:64
void beginIteration_()
Indicates the beginning of a Newton iteration.
Definition: blackoilnewtonmethod.hpp:126
void resetPrimaryVariableSwitches()
Definition: blackoilnewtonmethod.hpp:97
static void registerParameters()
Register all run-time parameters for the blackoil newton method.
Definition: blackoilnewtonmethod.hpp:106
void update_(SolutionVector &nextSolution, const SolutionVector ¤tSolution, const GlobalEqVector &solutionUpdate, const GlobalEqVector ¤tResidual)
Definition: blackoilnewtonmethod.hpp:160
void finishInit()
Finialize the construction of the object.
Definition: blackoilnewtonmethod.hpp:90
void endIteration_(SolutionVector &uCurrentIter, const SolutionVector &uLastIter)
Indicates that one Newton iteration was finished.
Definition: blackoilnewtonmethod.hpp:138
unsigned numPriVarsSwitched() const
Returns the number of degrees of freedom for which the interpretation has changed for the most recent...
Definition: blackoilnewtonmethod.hpp:116
BlackOilNewtonMethod(Simulator &simulator)
Definition: blackoilnewtonmethod.hpp:82
void updatePrimaryVariables_(unsigned globalDofIdx, PrimaryVariables &nextValue, const PrimaryVariables ¤tValue, const EqVector &update, const EqVector ¤tResidual)
Update a single primary variables object.
Definition: blackoilnewtonmethod.hpp:211
friend ParentType
Definition: blackoilnewtonmethod.hpp:121
void update_(SolutionVector &nextSolution, const SolutionVector ¤tSolution, const GlobalEqVector &solutionUpdate, const GlobalEqVector ¤tResidual, const DofIndices &dofIndices)
Definition: blackoilnewtonmethod.hpp:188
The multi-dimensional Newton method.
Definition: newtonmethod.hh:100
Definition: blackoilmodel.hh:74
Definition: blackoilbioeffectsmodules.hh:45
constexpr int signum(Scalar val)
Template function which returns the sign of a floating point value.
Definition: signum.hh:41
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
static void registerParameters()
Registers the parameters in parameter system.