blackoilfoammodules.hh
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 EWOMS_BLACK_OIL_FOAM_MODULE_HH
29#define EWOMS_BLACK_OIL_FOAM_MODULE_HH
30
31#include <dune/common/fvector.hh>
32
33#include <opm/common/ErrorMacros.hpp>
34#include <opm/common/OpmLog/OpmLog.hpp>
35#include <opm/common/utility/gpuDecorators.hpp>
36
37#include <opm/input/eclipse/EclipseState/Phase.hpp>
38
41
44
45#include <cassert>
46#include <istream>
47#include <numbers>
48#include <ostream>
49#include <stdexcept>
50#include <string>
51
52namespace Opm {
53
59template <class TypeTag, bool enableFoamV = getPropValue<TypeTag, Properties::EnableFoam>()>
61{
73
74 using Toolbox = MathToolbox<Evaluation>;
75
76 using TabulatedFunction = typename BlackOilFoamParams<Scalar>::TabulatedFunction;
77
78 static constexpr unsigned foamConcentrationIdx = Indices::foamConcentrationIdx;
79 static constexpr unsigned contiFoamEqIdx = Indices::contiFoamEqIdx;
80 static constexpr unsigned gasPhaseIdx = FluidSystem::gasPhaseIdx;
81 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
82
83 static constexpr unsigned enableFoam = enableFoamV;
84
85 static constexpr unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
86
87 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
88
89public:
92 {
93 params_ = params;
94 }
95
99 static void registerParameters()
100 {}
101
105 static void registerOutputModules(Model&,
106 Simulator&)
107 {
108 if constexpr (enableFoam) {
109 if (Parameters::Get<Parameters::EnableVtkOutput>()) {
110 OpmLog::warning("VTK output requested, currently unsupported by the foam module.");
111 }
112 }
113 //model.addOutputModule(new VtkBlackOilFoamModule<TypeTag>(simulator));
114 }
115
116 static bool primaryVarApplies(unsigned pvIdx)
117 {
118 if constexpr (enableFoam) {
119 return pvIdx == foamConcentrationIdx;
120 }
121 else {
122 return false;
123 }
124 }
125
126 static std::string primaryVarName([[maybe_unused]] unsigned pvIdx)
127 {
128 assert(primaryVarApplies(pvIdx));
129 return "foam_concentration";
130 }
131
132 static Scalar primaryVarWeight([[maybe_unused]] unsigned pvIdx)
133 {
134 assert(primaryVarApplies(pvIdx));
135
136 // TODO: it may be beneficial to chose this differently.
137 return static_cast<Scalar>(1.0);
138 }
139
140 static bool eqApplies(unsigned eqIdx)
141 {
142 if constexpr (enableFoam) {
143 return eqIdx == contiFoamEqIdx;
144 }
145 else {
146 return false;
147 }
148 }
149
150 static std::string eqName([[maybe_unused]] unsigned eqIdx)
151 {
152 assert(eqApplies(eqIdx));
153
154 return "conti^foam";
155 }
156
157 static Scalar eqWeight([[maybe_unused]] unsigned eqIdx)
158 {
159 assert(eqApplies(eqIdx));
160
161 // TODO: it may be beneficial to chose this differently.
162 return static_cast<Scalar>(1.0);
163 }
164
165 // must be called after water storage is computed
166 template <class StorageType>
167 OPM_HOST_DEVICE static void addStorage(StorageType& storage,
168 const IntensiveQuantities& intQuants)
169 {
170 using LhsEval = typename StorageType::value_type;
171
172 if constexpr (enableFoam) {
173 const auto& fs = intQuants.fluidState();
174
175 LhsEval surfaceVolume = Toolbox::template decay<LhsEval>(intQuants.porosity());
176 if (params_.transport_phase_ == Phase::WATER) {
177 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
178 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx));
179 } else if (params_.transport_phase_ == Phase::GAS) {
180 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(gasPhaseIdx)) *
181 Toolbox::template decay<LhsEval>(fs.invB(gasPhaseIdx));
182 } else if (params_.transport_phase_ == Phase::SOLVENT) {
183 if constexpr (enableSolvent) {
184 surfaceVolume *= Toolbox::template decay<LhsEval>( intQuants.solventSaturation()) *
185 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
186 }
187 } else {
188 OPM_THROW(std::runtime_error, "Transport phase is GAS/WATER/SOLVENT");
189 }
190
191 // Avoid singular matrix if no gas is present.
192 surfaceVolume = max(surfaceVolume, 1e-10);
193
194 // Foam/surfactant in free phase.
195 const LhsEval freeFoam = surfaceVolume *
196 Toolbox::template decay<LhsEval>(intQuants.foamConcentration());
197
198 // Adsorbed foam/surfactant.
199 const LhsEval adsorbedFoam =
200 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
201 Toolbox::template decay<LhsEval>(intQuants.foamRockDensity()) *
202 Toolbox::template decay<LhsEval>(intQuants.foamAdsorbed());
203
204 const LhsEval accumulationFoam = freeFoam + adsorbedFoam;
205 storage[contiFoamEqIdx] += accumulationFoam;
206 }
207 }
208
209 static void computeFlux([[maybe_unused]] RateVector& flux,
210 [[maybe_unused]] const ElementContext& elemCtx,
211 [[maybe_unused]] unsigned scvfIdx,
212 [[maybe_unused]] unsigned timeIdx)
213 {
214 if constexpr (enableFoam) {
215 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
216 const unsigned inIdx = extQuants.interiorIndex();
217
218 // The effect of the mobility reduction factor is
219 // incorporated in the mobility for the relevant phase,
220 // so fluxes do not need modification here.
221 switch (transportPhase()) {
222 case Phase::WATER: {
223 const unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
224 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
225 if (upIdx == inIdx) {
226 flux[contiFoamEqIdx] =
227 extQuants.volumeFlux(waterPhaseIdx) *
228 up.fluidState().invB(waterPhaseIdx) *
229 up.foamConcentration();
230 } else {
231 flux[contiFoamEqIdx] =
232 extQuants.volumeFlux(waterPhaseIdx) *
233 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
234 decay<Scalar>(up.foamConcentration());
235 }
236 break;
237 }
238 case Phase::GAS: {
239 const unsigned upIdx = extQuants.upstreamIndex(gasPhaseIdx);
240 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
241 if (upIdx == inIdx) {
242 flux[contiFoamEqIdx] =
243 extQuants.volumeFlux(gasPhaseIdx) *
244 up.fluidState().invB(gasPhaseIdx) *
245 up.foamConcentration();
246 } else {
247 flux[contiFoamEqIdx] =
248 extQuants.volumeFlux(gasPhaseIdx) *
249 decay<Scalar>(up.fluidState().invB(gasPhaseIdx)) *
250 decay<Scalar>(up.foamConcentration());
251 }
252 break;
253 }
254 case Phase::SOLVENT:
255 if constexpr (enableSolvent) {
256 const unsigned upIdx = extQuants.solventUpstreamIndex();
257 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
258 if (upIdx == inIdx) {
259 flux[contiFoamEqIdx] =
260 extQuants.solventVolumeFlux() *
261 up.solventInverseFormationVolumeFactor() *
262 up.foamConcentration();
263 } else {
264 flux[contiFoamEqIdx] =
265 extQuants.solventVolumeFlux() *
266 decay<Scalar>(up.solventInverseFormationVolumeFactor()) *
267 decay<Scalar>(up.foamConcentration());
268 }
269 } else {
270 throw std::runtime_error("Foam transport phase is SOLVENT but SOLVENT is not activated.");
271 }
272 break;
273 default:
274 throw std::runtime_error("Foam transport phase must be GAS/WATER/SOLVENT.");
275 }
276 }
277 }
278
282 static Scalar computeUpdateError(const PrimaryVariables&,
283 const EqVector&)
284 {
285 // do not consider the change of foam primary variables for convergence
286 // TODO: maybe this should be changed
287 return static_cast<Scalar>(0.0);
288 }
289
290 template <class DofEntity>
291 static void serializeEntity([[maybe_unused]] const Model& model,
292 [[maybe_unused]] std::ostream& outstream,
293 [[maybe_unused]] const DofEntity& dof)
294 {
295 if constexpr (enableFoam) {
296 const unsigned dofIdx = model.dofMapper().index(dof);
297 const PrimaryVariables& priVars = model.solution(/*timeIdx=*/0)[dofIdx];
298 outstream << priVars[foamConcentrationIdx];
299 }
300 }
301
302 template <class DofEntity>
303 static void deserializeEntity([[maybe_unused]] Model& model,
304 [[maybe_unused]] std::istream& instream,
305 [[maybe_unused]] const DofEntity& dof)
306 {
307 if constexpr (enableFoam) {
308 const unsigned dofIdx = model.dofMapper().index(dof);
309 PrimaryVariables& priVars0 = model.solution(/*timeIdx=*/0)[dofIdx];
310 PrimaryVariables& priVars1 = model.solution(/*timeIdx=*/1)[dofIdx];
311
312 instream >> priVars0[foamConcentrationIdx];
313
314 // set the primary variables for the beginning of the current time step.
315 priVars1[foamConcentrationIdx] = priVars0[foamConcentrationIdx];
316 }
317 }
318
319 static const Scalar foamRockDensity(const ElementContext& elemCtx,
320 unsigned scvIdx,
321 unsigned timeIdx)
322 {
323 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
324 return params_.foamRockDensity_[satnumRegionIdx];
325 }
326
327 static bool foamAllowDesorption(const ElementContext& elemCtx,
328 unsigned scvIdx,
329 unsigned timeIdx)
330 {
331 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
332 return params_.foamAllowDesorption_[satnumRegionIdx];
333 }
334
335 static const TabulatedFunction& adsorbedFoamTable(const ElementContext& elemCtx,
336 unsigned scvIdx,
337 unsigned timeIdx)
338 {
339 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
340 return params_.adsorbedFoamTable_[satnumRegionIdx];
341 }
342
343 static const TabulatedFunction& gasMobilityMultiplierTable(const ElementContext& elemCtx,
344 unsigned scvIdx,
345 unsigned timeIdx)
346 {
347 const unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
348 return params_.gasMobilityMultiplierTable_[pvtnumRegionIdx];
349 }
350
352 foamCoefficients(const ElementContext& elemCtx,
353 const unsigned scvIdx,
354 const unsigned timeIdx)
355 {
356 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
357 return params_.foamCoefficients_[satnumRegionIdx];
358 }
359
361 { return params_.transport_phase_; }
362
363private:
364 static BlackOilFoamParams<Scalar> params_;
365};
366
367template <class TypeTag, bool enableFoam>
368BlackOilFoamParams<typename BlackOilFoamModule<TypeTag, enableFoam>::Scalar>
369BlackOilFoamModule<TypeTag, enableFoam>::params_;
370
371template <class TypeTag, bool enableFoam>
373
381template <class TypeTag>
382class BlackOilFoamIntensiveQuantities<TypeTag, /*enableFoam=*/true>
383{
385
393
395
396 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
397
398 static constexpr int foamConcentrationIdx = Indices::foamConcentrationIdx;
399 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
400 static constexpr unsigned oilPhaseIdx = FluidSystem::oilPhaseIdx;
401 static constexpr int gasPhaseIdx = FluidSystem::gasPhaseIdx;
402
403public:
409 void foamPropertiesUpdate_(const ElementContext& elemCtx,
410 unsigned dofIdx,
411 unsigned timeIdx)
412 {
413 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
414 foamConcentration_ = priVars.makeEvaluation(foamConcentrationIdx, timeIdx);
415 const auto& fs = asImp_().fluidState_;
416
417 // Compute gas mobility reduction factor
418 Evaluation mobilityReductionFactor = 1.0;
419 if constexpr (false) {
420 // The functional model is used.
421 // TODO: allow this model.
422 // In order to do this we must allow transport to be in the water phase, not just the gas phase.
423 const auto& foamCoefficients = FoamModule::foamCoefficients(elemCtx, dofIdx, timeIdx);
424
425 const Scalar fm_mob = foamCoefficients.fm_mob;
426
427 const Scalar fm_surf = foamCoefficients.fm_surf;
428 const Scalar ep_surf = foamCoefficients.ep_surf;
429
430 const Scalar fm_oil = foamCoefficients.fm_oil;
431 const Scalar fl_oil = foamCoefficients.fl_oil;
432 const Scalar ep_oil = foamCoefficients.ep_oil;
433
434 const Scalar fm_dry = foamCoefficients.fm_dry;
435 const Scalar ep_dry = foamCoefficients.ep_dry;
436
437 const Scalar fm_cap = foamCoefficients.fm_cap;
438 const Scalar ep_cap = foamCoefficients.ep_cap;
439
440 const Evaluation C_surf = foamConcentration_;
441 const Evaluation Ca = 1e10; // TODO: replace with proper capillary number.
442 const Evaluation S_o = fs.saturation(oilPhaseIdx);
443 const Evaluation S_w = fs.saturation(waterPhaseIdx);
444
445 const Evaluation F1 = pow(C_surf / fm_surf, ep_surf);
446 const Evaluation F2 = pow((fm_oil - S_o) / (fm_oil - fl_oil), ep_oil);
447 const Evaluation F3 = pow(fm_cap / Ca, ep_cap);
448 const Evaluation F7 = 0.5 + atan(ep_dry * (S_w - fm_dry)) / std::numbers::pi_v<Scalar>;
449
450 mobilityReductionFactor = 1. / (1. + fm_mob * F1 * F2 * F3 * F7);
451 } else {
452 // The tabular model is used.
453 // Note that the current implementation only includes the effect of foam concentration (FOAMMOB),
454 // and not the optional pressure dependence (FOAMMOBP) or shear dependence (FOAMMOBS).
455 const auto& gasMobilityMultiplier = FoamModule::gasMobilityMultiplierTable(elemCtx, dofIdx, timeIdx);
456 mobilityReductionFactor = gasMobilityMultiplier.eval(foamConcentration_, /* extrapolate = */ true);
457 }
458
459 // adjust mobility
460 switch (FoamModule::transportPhase()) {
461 case Phase::WATER:
462 asImp_().mobility_[waterPhaseIdx] *= mobilityReductionFactor;
463 break;
464 case Phase::GAS:
465 asImp_().mobility_[gasPhaseIdx] *= mobilityReductionFactor;
466 break;
467 case Phase::SOLVENT:
468 if constexpr (enableSolvent) {
469 asImp_().solventMobility_ *= mobilityReductionFactor;
470 } else {
471 throw std::runtime_error("Foam transport phase is SOLVENT but SOLVENT is not activated.");
472 }
473 break;
474 default:
475 throw std::runtime_error("Foam transport phase must be GAS/WATER/SOLVENT.");
476 }
477
478 foamRockDensity_ = FoamModule::foamRockDensity(elemCtx, dofIdx, timeIdx);
479
480 const auto& adsorbedFoamTable = FoamModule::adsorbedFoamTable(elemCtx, dofIdx, timeIdx);
481 foamAdsorbed_ = adsorbedFoamTable.eval(foamConcentration_, /*extrapolate=*/true);
482 if (!FoamModule::foamAllowDesorption(elemCtx, dofIdx, timeIdx)) {
483 throw std::runtime_error("Foam module does not support the 'no desorption' option.");
484 }
485 }
486
487 const Evaluation& foamConcentration() const
488 { return foamConcentration_; }
489
490 Scalar foamRockDensity() const
491 { return foamRockDensity_; }
492
493 const Evaluation& foamAdsorbed() const
494 { return foamAdsorbed_; }
495
496protected:
497 Implementation& asImp_()
498 { return *static_cast<Implementation*>(this); }
499
502 Evaluation foamAdsorbed_;
503};
504
505template <class TypeTag>
507{
511
512public:
513 void foamPropertiesUpdate_(const ElementContext&,
514 unsigned,
515 unsigned)
516 {}
517
518 const Evaluation& foamConcentration() const
519 { throw std::runtime_error("foamConcentration() called but foam is disabled"); }
520
521 Scalar foamRockDensity() const
522 { throw std::runtime_error("foamRockDensity() called but foam is disabled"); }
523
524 Scalar foamAdsorbed() const
525 { throw std::runtime_error("foamAdsorbed() called but foam is disabled"); }
526};
527
528} // namespace Opm
529
530#endif
Contains the parameters to extend the black-oil model to include the effects of foam.
Declares the properties required by the black oil model.
Scalar foamRockDensity() const
Definition: blackoilfoammodules.hh:521
const Evaluation & foamConcentration() const
Definition: blackoilfoammodules.hh:518
void foamPropertiesUpdate_(const ElementContext &, unsigned, unsigned)
Definition: blackoilfoammodules.hh:513
Scalar foamAdsorbed() const
Definition: blackoilfoammodules.hh:524
Evaluation foamConcentration_
Definition: blackoilfoammodules.hh:500
void foamPropertiesUpdate_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Update the intensive properties needed to handle polymers from the primary variables.
Definition: blackoilfoammodules.hh:409
const Evaluation & foamAdsorbed() const
Definition: blackoilfoammodules.hh:493
Scalar foamRockDensity() const
Definition: blackoilfoammodules.hh:490
Evaluation foamAdsorbed_
Definition: blackoilfoammodules.hh:502
Implementation & asImp_()
Definition: blackoilfoammodules.hh:497
const Evaluation & foamConcentration() const
Definition: blackoilfoammodules.hh:487
Scalar foamRockDensity_
Definition: blackoilfoammodules.hh:501
Provides the volumetric quantities required for the equations needed by the polymers extension of the...
Definition: blackoilfoammodules.hh:372
Contains the high level supplements required to extend the black oil model to include the effects of ...
Definition: blackoilfoammodules.hh:61
static bool eqApplies(unsigned eqIdx)
Definition: blackoilfoammodules.hh:140
static void registerOutputModules(Model &, Simulator &)
Register all foam specific VTK and ECL output modules.
Definition: blackoilfoammodules.hh:105
static void registerParameters()
Register all run-time parameters for the black-oil foam module.
Definition: blackoilfoammodules.hh:99
static std::string primaryVarName(unsigned pvIdx)
Definition: blackoilfoammodules.hh:126
static Scalar eqWeight(unsigned eqIdx)
Definition: blackoilfoammodules.hh:157
static void deserializeEntity(Model &model, std::istream &instream, const DofEntity &dof)
Definition: blackoilfoammodules.hh:303
static void setParams(BlackOilFoamParams< Scalar > &&params)
Set parameters.
Definition: blackoilfoammodules.hh:91
static std::string eqName(unsigned eqIdx)
Definition: blackoilfoammodules.hh:150
static bool primaryVarApplies(unsigned pvIdx)
Definition: blackoilfoammodules.hh:116
static bool foamAllowDesorption(const ElementContext &elemCtx, unsigned scvIdx, unsigned timeIdx)
Definition: blackoilfoammodules.hh:327
static Scalar primaryVarWeight(unsigned pvIdx)
Definition: blackoilfoammodules.hh:132
static OPM_HOST_DEVICE void addStorage(StorageType &storage, const IntensiveQuantities &intQuants)
Definition: blackoilfoammodules.hh:167
static const BlackOilFoamParams< Scalar >::FoamCoefficients & foamCoefficients(const ElementContext &elemCtx, const unsigned scvIdx, const unsigned timeIdx)
Definition: blackoilfoammodules.hh:352
static void computeFlux(RateVector &flux, const ElementContext &elemCtx, unsigned scvfIdx, unsigned timeIdx)
Definition: blackoilfoammodules.hh:209
static Scalar computeUpdateError(const PrimaryVariables &, const EqVector &)
Return how much a Newton-Raphson update is considered an error.
Definition: blackoilfoammodules.hh:282
static const Scalar foamRockDensity(const ElementContext &elemCtx, unsigned scvIdx, unsigned timeIdx)
Definition: blackoilfoammodules.hh:319
static void serializeEntity(const Model &model, std::ostream &outstream, const DofEntity &dof)
Definition: blackoilfoammodules.hh:291
static const TabulatedFunction & adsorbedFoamTable(const ElementContext &elemCtx, unsigned scvIdx, unsigned timeIdx)
Definition: blackoilfoammodules.hh:335
static Phase transportPhase()
Definition: blackoilfoammodules.hh:360
static const TabulatedFunction & gasMobilityMultiplierTable(const ElementContext &elemCtx, unsigned scvIdx, unsigned timeIdx)
Definition: blackoilfoammodules.hh:343
Declare the properties used by the infrastructure code of the finite volume discretizations.
Declare the properties used by the infrastructure code of the finite volume discretizations.
Phase
Phase indices for reservoir coupling, we currently only support black-oil phases (oil,...
Definition: ReservoirCoupling.hpp:156
Definition: blackoilbioeffectsmodules.hh:45
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: blackoilfoamparams.hpp:60
Struct holding the parameters for the BlackoilFoamModule class.
Definition: blackoilfoamparams.hpp:44
Tabulated1DFunction< Scalar > TabulatedFunction
Definition: blackoilfoamparams.hpp:45