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