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