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