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