28 #ifndef EWOMS_BLACK_OIL_FOAM_MODULE_HH 29 #define EWOMS_BLACK_OIL_FOAM_MODULE_HH 31 #include <dune/common/fvector.hh> 33 #include <opm/common/OpmLog/OpmLog.hpp> 34 #include <opm/common/utility/gpuDecorators.hpp> 36 #include <opm/input/eclipse/EclipseState/Phase.hpp> 58 template <
class TypeTag,
bool enableFoamV = getPropValue<TypeTag, Properties::EnableFoam>()>
73 using Toolbox = MathToolbox<Evaluation>;
75 using TabulatedFunction =
typename BlackOilFoamParams<Scalar>::TabulatedFunction;
77 static constexpr
unsigned foamConcentrationIdx = Indices::foamConcentrationIdx;
78 static constexpr
unsigned contiFoamEqIdx = Indices::contiFoamEqIdx;
79 static constexpr
unsigned gasPhaseIdx = FluidSystem::gasPhaseIdx;
80 static constexpr
unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
82 static constexpr
unsigned enableFoam = enableFoamV;
84 static constexpr
unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
86 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
107 if constexpr (enableFoam) {
108 if (Parameters::Get<Parameters::EnableVtkOutput>()) {
109 OpmLog::warning(
"VTK output requested, currently unsupported by the foam module.");
115 static bool primaryVarApplies(
unsigned pvIdx)
117 if constexpr (enableFoam) {
118 return pvIdx == foamConcentrationIdx;
125 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
127 assert(primaryVarApplies(pvIdx));
128 return "foam_concentration";
131 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
133 assert(primaryVarApplies(pvIdx));
136 return static_cast<Scalar
>(1.0);
139 static bool eqApplies(
unsigned eqIdx)
141 if constexpr (enableFoam) {
142 return eqIdx == contiFoamEqIdx;
149 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
151 assert(eqApplies(eqIdx));
156 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
158 assert(eqApplies(eqIdx));
161 return static_cast<Scalar
>(1.0);
165 template <
class StorageType>
166 OPM_HOST_DEVICE
static void addStorage(StorageType& storage,
167 const IntensiveQuantities& intQuants)
169 using LhsEval =
typename StorageType::value_type;
171 if constexpr (enableFoam) {
172 const auto& fs = intQuants.fluidState();
174 LhsEval surfaceVolume = Toolbox::template decay<LhsEval>(intQuants.porosity());
175 if (params_.transport_phase_ == Phase::WATER) {
176 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
177 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx));
178 }
else if (params_.transport_phase_ == Phase::GAS) {
179 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(gasPhaseIdx)) *
180 Toolbox::template decay<LhsEval>(fs.invB(gasPhaseIdx));
181 }
else if (params_.transport_phase_ == Phase::SOLVENT) {
182 if constexpr (enableSolvent) {
183 surfaceVolume *= Toolbox::template decay<LhsEval>( intQuants.solventSaturation()) *
184 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
187 throw std::runtime_error(
"Transport phase is GAS/WATER/SOLVENT");
191 surfaceVolume = max(surfaceVolume, 1e-10);
194 const LhsEval freeFoam = surfaceVolume *
195 Toolbox::template decay<LhsEval>(intQuants.foamConcentration());
198 const LhsEval adsorbedFoam =
199 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
200 Toolbox::template decay<LhsEval>(intQuants.foamRockDensity()) *
201 Toolbox::template decay<LhsEval>(intQuants.foamAdsorbed());
203 const LhsEval accumulationFoam = freeFoam + adsorbedFoam;
204 storage[contiFoamEqIdx] += accumulationFoam;
208 static void computeFlux([[maybe_unused]] RateVector& flux,
209 [[maybe_unused]]
const ElementContext& elemCtx,
210 [[maybe_unused]]
unsigned scvfIdx,
211 [[maybe_unused]]
unsigned timeIdx)
213 if constexpr (enableFoam) {
214 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
215 const unsigned inIdx = extQuants.interiorIndex();
220 switch (transportPhase()) {
222 const unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
223 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
224 if (upIdx == inIdx) {
225 flux[contiFoamEqIdx] =
226 extQuants.volumeFlux(waterPhaseIdx) *
227 up.fluidState().invB(waterPhaseIdx) *
228 up.foamConcentration();
230 flux[contiFoamEqIdx] =
231 extQuants.volumeFlux(waterPhaseIdx) *
232 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
233 decay<Scalar>(up.foamConcentration());
238 const unsigned upIdx = extQuants.upstreamIndex(gasPhaseIdx);
239 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
240 if (upIdx == inIdx) {
241 flux[contiFoamEqIdx] =
242 extQuants.volumeFlux(gasPhaseIdx) *
243 up.fluidState().invB(gasPhaseIdx) *
244 up.foamConcentration();
246 flux[contiFoamEqIdx] =
247 extQuants.volumeFlux(gasPhaseIdx) *
248 decay<Scalar>(up.fluidState().invB(gasPhaseIdx)) *
249 decay<Scalar>(up.foamConcentration());
254 if constexpr (enableSolvent) {
255 const unsigned upIdx = extQuants.solventUpstreamIndex();
256 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
257 if (upIdx == inIdx) {
258 flux[contiFoamEqIdx] =
259 extQuants.solventVolumeFlux() *
260 up.solventInverseFormationVolumeFactor() *
261 up.foamConcentration();
263 flux[contiFoamEqIdx] =
264 extQuants.solventVolumeFlux() *
265 decay<Scalar>(up.solventInverseFormationVolumeFactor()) *
266 decay<Scalar>(up.foamConcentration());
269 throw std::runtime_error(
"Foam transport phase is SOLVENT but SOLVENT is not activated.");
273 throw std::runtime_error(
"Foam transport phase must be GAS/WATER/SOLVENT.");
286 return static_cast<Scalar
>(0.0);
289 template <
class DofEntity>
290 static void serializeEntity([[maybe_unused]]
const Model& model,
291 [[maybe_unused]] std::ostream& outstream,
292 [[maybe_unused]]
const DofEntity& dof)
294 if constexpr (enableFoam) {
295 const unsigned dofIdx = model.dofMapper().index(dof);
296 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
297 outstream << priVars[foamConcentrationIdx];
301 template <
class DofEntity>
302 static void deserializeEntity([[maybe_unused]] Model& model,
303 [[maybe_unused]] std::istream& instream,
304 [[maybe_unused]]
const DofEntity& dof)
306 if constexpr (enableFoam) {
307 const unsigned dofIdx = model.dofMapper().index(dof);
308 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
309 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
311 instream >> priVars0[foamConcentrationIdx];
314 priVars1[foamConcentrationIdx] = priVars0[foamConcentrationIdx];
318 static const Scalar foamRockDensity(
const ElementContext& elemCtx,
322 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
323 return params_.foamRockDensity_[satnumRegionIdx];
326 static bool foamAllowDesorption(
const ElementContext& elemCtx,
330 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
331 return params_.foamAllowDesorption_[satnumRegionIdx];
334 static const TabulatedFunction& adsorbedFoamTable(
const ElementContext& elemCtx,
338 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
339 return params_.adsorbedFoamTable_[satnumRegionIdx];
342 static const TabulatedFunction& gasMobilityMultiplierTable(
const ElementContext& elemCtx,
346 const unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
347 return params_.gasMobilityMultiplierTable_[pvtnumRegionIdx];
350 static const typename BlackOilFoamParams<Scalar>::FoamCoefficients&
351 foamCoefficients(
const ElementContext& elemCtx,
352 const unsigned scvIdx,
353 const unsigned timeIdx)
355 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
356 return params_.foamCoefficients_[satnumRegionIdx];
359 static Phase transportPhase()
360 {
return params_.transport_phase_; }
363 static BlackOilFoamParams<Scalar> params_;
366 template <
class TypeTag,
bool enableFoam>
367 BlackOilFoamParams<typename BlackOilFoamModule<TypeTag, enableFoam>::Scalar>
368 BlackOilFoamModule<TypeTag, enableFoam>::params_;
370 template <
class TypeTag,
bool enableFoam>
380 template <
class TypeTag>
395 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
397 static constexpr
int foamConcentrationIdx = Indices::foamConcentrationIdx;
398 static constexpr
unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
399 static constexpr
unsigned oilPhaseIdx = FluidSystem::oilPhaseIdx;
400 static constexpr
int gasPhaseIdx = FluidSystem::gasPhaseIdx;
412 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
413 foamConcentration_ = priVars.makeEvaluation(foamConcentrationIdx, timeIdx);
414 const auto& fs = asImp_().fluidState_;
417 Evaluation mobilityReductionFactor = 1.0;
418 if constexpr (
false) {
422 const auto& foamCoefficients = FoamModule::foamCoefficients(elemCtx, dofIdx, timeIdx);
424 const Scalar fm_mob = foamCoefficients.fm_mob;
426 const Scalar fm_surf = foamCoefficients.fm_surf;
427 const Scalar ep_surf = foamCoefficients.ep_surf;
429 const Scalar fm_oil = foamCoefficients.fm_oil;
430 const Scalar fl_oil = foamCoefficients.fl_oil;
431 const Scalar ep_oil = foamCoefficients.ep_oil;
433 const Scalar fm_dry = foamCoefficients.fm_dry;
434 const Scalar ep_dry = foamCoefficients.ep_dry;
436 const Scalar fm_cap = foamCoefficients.fm_cap;
437 const Scalar ep_cap = foamCoefficients.ep_cap;
439 const Evaluation C_surf = foamConcentration_;
440 const Evaluation Ca = 1e10;
441 const Evaluation S_o = fs.saturation(oilPhaseIdx);
442 const Evaluation S_w = fs.saturation(waterPhaseIdx);
444 const Evaluation F1 = pow(C_surf / fm_surf, ep_surf);
445 const Evaluation F2 = pow((fm_oil - S_o) / (fm_oil - fl_oil), ep_oil);
446 const Evaluation F3 = pow(fm_cap / Ca, ep_cap);
447 const Evaluation F7 = 0.5 + atan(ep_dry * (S_w - fm_dry)) / std::numbers::pi_v<Scalar>;
449 mobilityReductionFactor = 1. / (1. + fm_mob * F1 * F2 * F3 * F7);
454 const auto& gasMobilityMultiplier = FoamModule::gasMobilityMultiplierTable(elemCtx, dofIdx, timeIdx);
455 mobilityReductionFactor = gasMobilityMultiplier.eval(foamConcentration_,
true);
459 switch (FoamModule::transportPhase()) {
461 asImp_().mobility_[waterPhaseIdx] *= mobilityReductionFactor;
464 asImp_().mobility_[gasPhaseIdx] *= mobilityReductionFactor;
467 if constexpr (enableSolvent) {
468 asImp_().solventMobility_ *= mobilityReductionFactor;
470 throw std::runtime_error(
"Foam transport phase is SOLVENT but SOLVENT is not activated.");
474 throw std::runtime_error(
"Foam transport phase must be GAS/WATER/SOLVENT.");
477 foamRockDensity_ = FoamModule::foamRockDensity(elemCtx, dofIdx, timeIdx);
479 const auto& adsorbedFoamTable = FoamModule::adsorbedFoamTable(elemCtx, dofIdx, timeIdx);
480 foamAdsorbed_ = adsorbedFoamTable.eval(foamConcentration_,
true);
481 if (!FoamModule::foamAllowDesorption(elemCtx, dofIdx, timeIdx)) {
482 throw std::runtime_error(
"Foam module does not support the 'no desorption' option.");
486 const Evaluation& foamConcentration()
const 487 {
return foamConcentration_; }
489 Scalar foamRockDensity()
const 490 {
return foamRockDensity_; }
492 const Evaluation& foamAdsorbed()
const 493 {
return foamAdsorbed_; }
496 Implementation& asImp_()
497 {
return *
static_cast<Implementation*
>(
this); }
499 Evaluation foamConcentration_;
500 Scalar foamRockDensity_;
501 Evaluation foamAdsorbed_;
504 template <
class TypeTag>
512 void foamPropertiesUpdate_(
const ElementContext&,
517 const Evaluation& foamConcentration()
const 518 {
throw std::runtime_error(
"foamConcentration() called but foam is disabled"); }
520 Scalar foamRockDensity()
const 521 {
throw std::runtime_error(
"foamRockDensity() called but foam is disabled"); }
523 Scalar foamAdsorbed()
const 524 {
throw std::runtime_error(
"foamAdsorbed() called but foam is disabled"); }
static void registerParameters()
Register all run-time parameters for the black-oil foam module.
Definition: blackoilfoammodules.hh:98
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 registerOutputModules(Model &, Simulator &)
Register all foam specific VTK and ECL output modules.
Definition: blackoilfoammodules.hh:104
Contains the high level supplements required to extend the black oil model to include the effects of ...
Definition: blackoilfoammodules.hh:59
Contains the parameters to extend the black-oil model to include the effects of foam.
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Struct holding the parameters for the BlackoilFoamModule class.
Definition: blackoilfoamparams.hpp:43
Declares the properties required by the black oil model.
Declare the properties used by the infrastructure code of the finite volume discretizations.
void foamPropertiesUpdate_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Update the intensive properties needed to handle polymers from the primary variables.
Definition: blackoilfoammodules.hh:408
static Scalar computeUpdateError(const PrimaryVariables &, const EqVector &)
Return how much a Newton-Raphson update is considered an error.
Definition: blackoilfoammodules.hh:281
Declare the properties used by the infrastructure code of the finite volume discretizations.
Provides the volumetric quantities required for the equations needed by the polymers extension of the...
Definition: blackoilfoammodules.hh:371
static void setParams(BlackOilFoamParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilfoammodules.hh:90