opm-simulators
Loading...
Searching...
No Matches
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) {
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
350 static const typename BlackOilFoamParams<Scalar>::FoamCoefficients&
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
359 static Phase transportPhase()
360 { return params_.transport_phase_; }
361
362private:
363 static BlackOilFoamParams<Scalar> params_;
364};
365
366template <class TypeTag, bool enableFoam>
368BlackOilFoamModule<TypeTag, enableFoam>::params_;
369
370template <class TypeTag, bool enableFoam>
372
380template <class TypeTag>
381class BlackOilFoamIntensiveQuantities<TypeTag, /*enableFoam=*/true>
382{
384
392
393 using FoamModule = BlackOilFoamModule<TypeTag>;
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
499 Evaluation foamConcentration_;
500 Scalar foamRockDensity_;
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.
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
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 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 void setParams(BlackOilFoamParams< Scalar > &&params)
Set parameters.
Definition blackoilfoammodules.hh:90
static Scalar computeUpdateError(const PrimaryVariables &, const EqVector &)
Return how much a Newton-Raphson update is considered an error.
Definition blackoilfoammodules.hh:281
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.
This file contains a set of helper functions used by VFPProd / VFPInj.
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
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:240
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition parametersystem.hpp:187
Struct holding the parameters for the BlackoilFoamModule class.
Definition blackoilfoamparams.hpp:44