blackoilintensivequantities.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_INTENSIVE_QUANTITIES_HH
29#define EWOMS_BLACK_OIL_INTENSIVE_QUANTITIES_HH
30
31#include <dune/common/fmatrix.hh>
32
33#include <opm/common/ErrorMacros.hpp>
34#include <opm/common/TimingMacros.hpp>
35#include <opm/common/utility/gpuDecorators.hpp>
36
37#include <opm/input/eclipse/EclipseState/Grid/FaceDir.hpp>
38
39#include <opm/material/fluidstates/BlackOilFluidState.hpp>
40#include <opm/material/common/Valgrind.hpp>
41
45
47
48#include <opm/utility/CopyablePtr.hpp>
49
50#include <array>
51#include <cassert>
52#include <cstring>
53#include <stdexcept>
54#include <utility>
55
56namespace Opm {
57
65template <class TypeTag>
67 : public GetPropType<TypeTag, Properties::DiscIntensiveQuantities>
68 , public GetPropType<TypeTag, Properties::FluxModule>::FluxIntensiveQuantities
69 , public BlackOilDiffusionIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableDiffusion>() >
70 , public BlackOilDispersionIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableDispersion>() >
71 , public BlackOilSolventIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableSolvent>()>
72 , public BlackOilExtboIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableExtbo>()>
73 , public BlackOilPolymerIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnablePolymer>()>
74 , public BlackOilFoamIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableFoam>()>
75 , public BlackOilBrineIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableBrine>()>
76 , public BlackOilEnergyIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnergyModuleType>()>
77 , public BlackOilBioeffectsIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableBioeffects>()>
78 , public BlackOilConvectiveMixingIntensiveQuantities<TypeTag, getPropValue<TypeTag, Properties::EnableConvectiveMixing>()>
79{
82
91
92 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
93 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
94 enum { enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>() };
95 static constexpr EnergyModules energyModuleType = getPropValue<TypeTag, Properties::EnergyModuleType>();
96
97 static constexpr bool enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>();
98 static constexpr bool enableBrine = getPropValue<TypeTag, Properties::EnableBrine>();
99 static constexpr bool enableConvectiveMixing = getPropValue<TypeTag, Properties::EnableConvectiveMixing>();
100 static constexpr bool enableDiffusion = getPropValue<TypeTag, Properties::EnableDiffusion>();
101 static constexpr bool enableDispersion = getPropValue<TypeTag, Properties::EnableDispersion>();
102 static constexpr bool enableExtbo = getPropValue<TypeTag, Properties::EnableExtbo>();
103 static constexpr bool enableFoam = getPropValue<TypeTag, Properties::EnableFoam>();
104 static constexpr bool enablePolymer = getPropValue<TypeTag, Properties::EnablePolymer>();
105 static constexpr bool enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>();
106 static constexpr bool enableTemperature = energyModuleType != EnergyModules::NoTemperature;
107
108 enum { enableMech = getPropValue<TypeTag, Properties::EnableMech>() };
109 enum { enableMICP = Indices::enableMICP };
110 enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
111 enum { waterCompIdx = FluidSystem::waterCompIdx };
112 enum { oilCompIdx = FluidSystem::oilCompIdx };
113 enum { gasCompIdx = FluidSystem::gasCompIdx };
114 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
115 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
116 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
117 enum { compositionSwitchIdx = Indices::compositionSwitchIdx };
118
119 static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
120 static constexpr bool waterEnabled = Indices::waterEnabled;
121 static constexpr bool gasEnabled = Indices::gasEnabled;
122 static constexpr bool oilEnabled = Indices::oilEnabled;
123
124 using Toolbox = MathToolbox<Evaluation>;
125 using FluxIntensiveQuantities = typename FluxModule::FluxIntensiveQuantities;
128
129 using DirectionalMobilityPtr = Utility::CopyablePtr<DirectionalMobility<TypeTag>>;
130 using BrineModule = BlackOilBrineModule<TypeTag, enableBrine>;
132 using BioeffectsModule = BlackOilBioeffectsModule<TypeTag, enableBioeffects>;
134
135public:
136 using FluidState = BlackOilFluidState<Evaluation,
137 FluidSystem,
138 energyModuleType != EnergyModules::NoTemperature,
139 energyModuleType == EnergyModules::FullyImplicitThermal,
140 compositionSwitchEnabled,
141 enableVapwat,
142 enableBrine,
143 enableSaltPrecipitation,
144 enableDisgasInWater,
145 enableSolvent,
146 Indices::numPhases>;
147 using ScalarFluidState = BlackOilFluidState<Scalar,
148 FluidSystem,
149 energyModuleType != EnergyModules::NoTemperature,
150 energyModuleType == EnergyModules::FullyImplicitThermal,
151 compositionSwitchEnabled,
152 enableVapwat,
153 enableBrine,
154 enableSaltPrecipitation,
155 enableDisgasInWater,
156 enableSolvent,
157 Indices::numPhases>;
159
161 {
162 if constexpr (compositionSwitchEnabled) {
163 fluidState_.setRs(0.0);
164 fluidState_.setRv(0.0);
165 }
166 if constexpr (enableVapwat) {
167 fluidState_.setRvw(0.0);
168 }
169 if constexpr (enableDisgasInWater) {
170 fluidState_.setRsw(0.0);
171 }
172 }
173
174 OPM_HOST_DEVICE BlackOilIntensiveQuantities& operator=(const BlackOilIntensiveQuantities& other) = default;
175
176 template<class OtherTypeTag>
178
179 // This ctor is used when switching to the GPU typetag which currently supports thermal effects and diffusion.
180 template<class OtherTypeTag>
182 const BlackOilIntensiveQuantities<OtherTypeTag>& other, const FluidSystem& fsystem)
183 : fluidState_(other.fluidState_.template withOtherFluidSystem<FluidSystem>(fsystem))
184 , BlackOilEnergyIntensiveQuantities<TypeTag, energyModuleType>(other)
186 , referencePorosity_(other.referencePorosity_)
187 , porosity_(other.porosity_)
188 , rockCompTransMultiplier_(other.rockCompTransMultiplier_)
189 , mobility_(other.mobility_)
190 , dirMob_(/*NOT YET SUPPORTED ON GPU*/)
191 {
192 }
193
195
204 template <class OtherTypeTag>
206 {
207 BlackOilIntensiveQuantities<OtherTypeTag> newIntQuants(*this, other);
208 return newIntQuants;
209 }
210
211 OPM_HOST_DEVICE void updateTempSalt(const Problem& problem,
212 const PrimaryVariables& priVars,
213 const unsigned globalSpaceIdx,
214 const unsigned timeIdx,
215 const LinearizationType& lintype)
216 {
217 if constexpr (enableTemperature) {
218 asImp_().updateTemperature_(problem, priVars, globalSpaceIdx, timeIdx, lintype);
219 }
220 if constexpr (enableBrine) {
221 asImp_().updateSaltConcentration_(priVars, timeIdx, lintype);
222 }
223 }
224
225 OPM_HOST_DEVICE void updateSaturations(const PrimaryVariables& priVars,
226 const unsigned timeIdx,
227 [[maybe_unused]] const LinearizationType lintype)
228 {
229 // extract the water and the gas saturations for convenience
230 Evaluation Sw = 0.0;
231 if constexpr (waterEnabled) {
232 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw) {
233 assert(Indices::waterSwitchIdx >= 0);
234 if constexpr (Indices::waterSwitchIdx >= 0) {
235 Sw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
236 }
237 }
238 else if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rsw ||
239 priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Disabled)
240 {
241 // water is enabled but is not a primary variable i.e. one component/phase case
242 // or two-phase water + gas with only water present
243 Sw = 1.0;
244 } // else i.e. for MeaningWater() = Rvw, Sw is still 0.0;
245 }
246 Evaluation Sg = 0.0;
247 if constexpr (gasEnabled) {
248 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg) {
249 assert(Indices::compositionSwitchIdx >= 0);
250 if constexpr (compositionSwitchEnabled) {
251 Sg = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
252 }
253 }
254 else if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv) {
255 Sg = 1.0 - Sw;
256 }
257 else if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Disabled) {
258 if constexpr (waterEnabled) {
259 Sg = 1.0 - Sw; // two phase water + gas
260 } else {
261 // one phase case
262 Sg = 1.0;
263 }
264 }
265 }
266 Valgrind::CheckDefined(Sg);
267 Valgrind::CheckDefined(Sw);
268
269 Evaluation So = 1.0 - Sw - Sg;
270
271 // deal with solvent
272 if constexpr (enableSolvent) {
273 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
274 if (getFluidSystem().phaseIsActive(oilPhaseIdx)) {
275 So -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx);
276 }
277 else if (getFluidSystem().phaseIsActive(gasPhaseIdx)) {
278 Sg -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx);
279 }
280 }
281 }
282
283 if (getFluidSystem().phaseIsActive(waterPhaseIdx)) {
284 fluidState_.setSaturation(waterPhaseIdx, Sw);
285 }
286
287 if (getFluidSystem().phaseIsActive(gasPhaseIdx)) {
288 fluidState_.setSaturation(gasPhaseIdx, Sg);
289 }
290
291 if (getFluidSystem().phaseIsActive(oilPhaseIdx)) {
292 fluidState_.setSaturation(oilPhaseIdx, So);
293 }
294 }
295
296 template <class ...Args>
297 OPM_HOST_DEVICE void updateRelpermAndPressures(const Problem& problem,
298 const PrimaryVariables& priVars,
299 const unsigned globalSpaceIdx,
300 const unsigned timeIdx,
301 const LinearizationType& lintype)
302 {
303
304 // Solvent saturation manipulation:
305 // After this, gas saturation will actually be (gas sat + solvent sat)
306 // until set back to just gas saturation in the corresponding call to
307 // solventPostSatFuncUpdate_() further down.
308 if constexpr (enableSolvent) {
309 asImp_().solventPreSatFuncUpdate_(priVars, timeIdx, lintype);
310 }
311
312 // Phase relperms.
313 problem.template updateRelperms<FluidState, Args...>(mobility_, dirMob_, fluidState_, globalSpaceIdx);
314
315 // now we compute all phase pressures
316 using EvalArr = std::array<Evaluation, numPhases>;
317 EvalArr pC;
318 const auto& materialParams = problem.materialLawParams(globalSpaceIdx);
319 MaterialLaw::template capillaryPressures<EvalArr, FluidState, Args...>(pC, materialParams, fluidState_);
320
321 // scaling the capillary pressure due to porosity changes
322 if constexpr (enableBrine) {
323 if (BrineModule::hasPcfactTables() &&
324 priVars.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp)
325 {
326 const unsigned satnumRegionIdx = problem.satnumRegionIndex(globalSpaceIdx);
327 const Evaluation Sp = priVars.makeEvaluation(Indices::saltConcentrationIdx, timeIdx);
328 const Evaluation porosityFactor = min(1.0 - Sp, 1.0); //phi/phi_0
329 const auto& pcfactTable = BrineModule::pcfactTable(satnumRegionIdx);
330 const Evaluation pcFactor = pcfactTable.eval(porosityFactor, /*extrapolation=*/true);
331 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
332 if (getFluidSystem().phaseIsActive(phaseIdx)) {
333 pC[phaseIdx] *= pcFactor;
334 }
335 }
336 }
337 }
338 else if constexpr (enableBioeffects) {
339 if (BioeffectsModule::hasPcfactTables() && referencePorosity_ > 0) {
340 unsigned satnumRegionIdx = problem.satnumRegionIndex(globalSpaceIdx);
341 const Evaluation Sb = priVars.makeEvaluation(Indices::biofilmVolumeFractionIdx, timeIdx);
342 const Evaluation porosityFactor = min(1.0 - Sb/referencePorosity_, 1.0); //phi/phi_0
343 const auto& pcfactTable = BioeffectsModule::pcfactTable(satnumRegionIdx);
344 const Evaluation pcFactor = pcfactTable.eval(porosityFactor, /*extrapolation=*/true);
345 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
346 if (getFluidSystem().phaseIsActive(phaseIdx)) {
347 pC[phaseIdx] *= pcFactor;
348 }
349 }
350 }
351 }
352
353 // oil is the reference phase for pressure
354 if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg) {
355 const Evaluation& pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
356 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
357 if (getFluidSystem().phaseIsActive(phaseIdx)) {
358 fluidState_.setPressure(phaseIdx, pg + (pC[phaseIdx] - pC[gasPhaseIdx]));
359 }
360 }
361 }
362 else if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pw) {
363 const Evaluation& pw = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
364 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
365 if (getFluidSystem().phaseIsActive(phaseIdx)) {
366 fluidState_.setPressure(phaseIdx, pw + (pC[phaseIdx] - pC[waterPhaseIdx]));
367 }
368 }
369 }
370 else {
371 assert(getFluidSystem().phaseIsActive(oilPhaseIdx));
372 const Evaluation& po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
373 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
374 if (getFluidSystem().phaseIsActive(phaseIdx)) {
375 fluidState_.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx]));
376 }
377 }
378 }
379
380 // Update the Saturation functions for the blackoil solvent module.
381 // Including setting gas saturation back to hydrocarbon gas saturation.
382 // Note that this depend on the pressures, so it must be called AFTER the pressures
383 // have been updated.
384 if constexpr (enableSolvent) {
385 asImp_().solventPostSatFuncUpdate_(problem, priVars, globalSpaceIdx, timeIdx, lintype);
386 }
387 }
388
389 OPM_HOST_DEVICE void updateRsRvRsw(const Problem& problem,
390 const PrimaryVariables& priVars,
391 const unsigned globalSpaceIdx,
392 const unsigned timeIdx)
393 {
394 const unsigned pvtRegionIdx = priVars.pvtRegionIndex();
395
396 const Scalar RvMax = getFluidSystem().enableVaporizedOil()
397 ? problem.maxOilVaporizationFactor(timeIdx, globalSpaceIdx)
398 : 0.0;
399 const Scalar RsMax = getFluidSystem().enableDissolvedGas()
400 ? problem.maxGasDissolutionFactor(timeIdx, globalSpaceIdx)
401 : 0.0;
402 const Scalar RswMax = getFluidSystem().enableDissolvedGasInWater()
403 ? problem.maxGasDissolutionFactor(timeIdx, globalSpaceIdx)
404 : 0.0;
405
406 Evaluation SoMax = 0.0;
407 if (getFluidSystem().phaseIsActive(getFluidSystem().oilPhaseIdx)) {
408 SoMax = max(fluidState_.saturation(oilPhaseIdx),
409 problem.maxOilSaturation(globalSpaceIdx));
410 }
411
412 // take the meaning of the switching primary variable into account for the gas
413 // and oil phase compositions
414
415 if constexpr (compositionSwitchEnabled) {
416 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rs) {
417 const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
418 fluidState_.setRs(Rs);
419 }
420 else {
421 if (getFluidSystem().enableDissolvedGas()) { // Add So > 0? i.e. if only water set rs = 0)
422 Evaluation RsSat;
423 if constexpr (enableExtbo) {
424 RsSat = asImp_().rs();
425 } else {
426 RsSat = getFluidSystem().saturatedDissolutionFactor(fluidState_,
427 oilPhaseIdx,
428 pvtRegionIdx,
429 SoMax);
430 }
431 fluidState_.setRs(min(RsMax, RsSat));
432 }
433 else {
434 fluidState_.setRs(0.0);
435 }
436 }
437
438 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv) {
439 const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
440 fluidState_.setRv(Rv);
441 }
442 else {
443 if (getFluidSystem().enableVaporizedOil() ) { // Add Sg > 0? i.e. if only water set rv = 0)
444 Evaluation RvSat;
445 if constexpr (enableExtbo) {
446 RvSat = asImp_().rv();
447 } else {
448 RvSat = getFluidSystem().saturatedDissolutionFactor(fluidState_,
449 gasPhaseIdx,
450 pvtRegionIdx,
451 SoMax);
452 }
453 fluidState_.setRv(min(RvMax, RvSat));
454 }
455 else {
456 fluidState_.setRv(0.0);
457 }
458 }
459 }
460
461 if constexpr (enableVapwat) {
462 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rvw) {
463 const auto& Rvw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
464 fluidState_.setRvw(Rvw);
465 }
466 else {
467 if (getFluidSystem().enableVaporizedWater()) { // Add Sg > 0? i.e. if only water set rv = 0)
468 const Evaluation& RvwSat = getFluidSystem().saturatedVaporizationFactor(fluidState_,
469 gasPhaseIdx,
470 pvtRegionIdx);
471 fluidState_.setRvw(RvwSat);
472 }
473 }
474 }
475
476 if constexpr (enableDisgasInWater) {
477 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rsw) {
478 const auto& Rsw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
479 fluidState_.setRsw(Rsw);
480 }
481 else {
482 if (getFluidSystem().enableDissolvedGasInWater()) {
483 const Evaluation& RswSat = getFluidSystem().saturatedDissolutionFactor(fluidState_,
484 waterPhaseIdx,
485 pvtRegionIdx);
486 fluidState_.setRsw(min(RswMax, RswSat));
487 }
488 }
489 }
490 }
491
492 OPM_HOST_DEVICE void updateMobilityAndInvB()
493 {
494 OPM_TIMEBLOCK_LOCAL(updateMobilityAndInvB, Subsystem::PvtProps);
495 const unsigned pvtRegionIdx = fluidState_.pvtRegionIndex();
496
497 // compute the phase densities and transform the phase permeabilities into mobilities
498 int nmobilities = 1;
499 constexpr int max_nmobilities = 4;
500 std::array<std::array<Evaluation, numPhases>*, max_nmobilities> mobilities = { &mobility_};
501 if (dirMob_) {
502 for (int i = 0; i < 3; ++i) {
503 mobilities[nmobilities] = &(dirMob_->getArray(i));
504 ++nmobilities;
505 }
506 }
507 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
508 if (!getFluidSystem().phaseIsActive(phaseIdx)) {
509 continue;
510 }
511 const auto [b, mu] = getFluidSystem().inverseFormationVolumeFactorAndViscosity(fluidState_, phaseIdx, pvtRegionIdx);
512 fluidState_.setInvB(phaseIdx, b);
513 for (int i = 0; i < nmobilities; ++i) {
514 if constexpr (enableExtbo) {
515 if (phaseIdx == oilPhaseIdx) {
516 (*mobilities[i])[phaseIdx] /= asImp_().oilViscosity();
517 }
518 else if (phaseIdx == gasPhaseIdx) {
519 (*mobilities[i])[phaseIdx] /= asImp_().gasViscosity();
520 }
521 else {
522 (*mobilities[i])[phaseIdx] /= mu;
523 }
524 }
525 else {
526 (*mobilities[i])[phaseIdx] /= mu;
527 }
528 }
529 }
530 Valgrind::CheckDefined(mobility_);
531 }
532
533 OPM_HOST_DEVICE void updatePhaseDensities()
534 {
535 const unsigned pvtRegionIdx = fluidState_.pvtRegionIndex();
536
537 // calculate the phase densities
538 Evaluation rho;
539 if (getFluidSystem().phaseIsActive(waterPhaseIdx)) {
540 rho = fluidState_.invB(waterPhaseIdx);
541 rho *= getFluidSystem().referenceDensity(waterPhaseIdx, pvtRegionIdx);
542 if (getFluidSystem().enableDissolvedGasInWater()) {
543 rho += fluidState_.invB(waterPhaseIdx) *
544 fluidState_.Rsw() *
545 getFluidSystem().referenceDensity(gasPhaseIdx, pvtRegionIdx);
546 }
547 fluidState_.setDensity(waterPhaseIdx, rho);
548 }
549
550 if (getFluidSystem().phaseIsActive(gasPhaseIdx)) {
551 rho = fluidState_.invB(gasPhaseIdx);
552 rho *= getFluidSystem().referenceDensity(gasPhaseIdx, pvtRegionIdx);
553 if (getFluidSystem().enableVaporizedOil()) {
554 rho += fluidState_.invB(gasPhaseIdx) *
555 fluidState_.Rv() *
556 getFluidSystem().referenceDensity(oilPhaseIdx, pvtRegionIdx);
557 }
558 if (getFluidSystem().enableVaporizedWater()) {
559 rho += fluidState_.invB(gasPhaseIdx) *
560 fluidState_.Rvw() *
561 getFluidSystem().referenceDensity(waterPhaseIdx, pvtRegionIdx);
562 }
563 fluidState_.setDensity(gasPhaseIdx, rho);
564 }
565
566 if (getFluidSystem().phaseIsActive(oilPhaseIdx)) {
567 rho = fluidState_.invB(oilPhaseIdx);
568 rho *= getFluidSystem().referenceDensity(oilPhaseIdx, pvtRegionIdx);
569 if (getFluidSystem().enableDissolvedGas()) {
570 rho += fluidState_.invB(oilPhaseIdx) *
571 fluidState_.Rs() *
572 getFluidSystem().referenceDensity(gasPhaseIdx, pvtRegionIdx);
573 }
574 fluidState_.setDensity(oilPhaseIdx, rho);
575 }
576 }
577
578 OPM_HOST_DEVICE void updatePorosity(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx)
579 {
580 const auto& problem = elemCtx.problem();
581 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
582 const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
583 // Retrieve the reference porosity from the problem.
584 referencePorosity_ = problem.porosity(elemCtx, dofIdx, timeIdx);
585 // Account for other effects.
586 this->updatePorosityImpl(problem, priVars, globalSpaceIdx, timeIdx);
587 }
588
589 OPM_HOST_DEVICE void updatePorosity(const Problem& problem,
590 const PrimaryVariables& priVars,
591 const unsigned globalSpaceIdx,
592 const unsigned timeIdx)
593 {
594 // Retrieve the reference porosity from the problem.
595 referencePorosity_ = problem.porosity(globalSpaceIdx, timeIdx);
596 // Account for other effects.
597 this->updatePorosityImpl(problem, priVars, globalSpaceIdx, timeIdx);
598 }
599
600 OPM_HOST_DEVICE void updatePorosityImpl(const Problem& problem,
601 const PrimaryVariables& priVars,
602 const unsigned globalSpaceIdx,
603 const unsigned timeIdx)
604 {
605 const auto& linearizationType = problem.model().linearizer().getLinearizationType();
606
607 // Start from the reference porosity.
608 porosity_ = referencePorosity_;
609
610 // the porosity must be modified by the compressibility of the
611 // rock...
612 const Scalar rockCompressibility = problem.rockCompressibility(globalSpaceIdx);
613 if (rockCompressibility > 0.0) {
614 const Scalar rockRefPressure = problem.rockReferencePressure(globalSpaceIdx);
615 Evaluation x;
616 if (getFluidSystem().phaseIsActive(oilPhaseIdx)) {
617 x = rockCompressibility * (fluidState_.pressure(oilPhaseIdx) - rockRefPressure);
618 }
619 else if (getFluidSystem().phaseIsActive(waterPhaseIdx)) {
620 x = rockCompressibility * (fluidState_.pressure(waterPhaseIdx) - rockRefPressure);
621 }
622 else {
623 x = rockCompressibility * (fluidState_.pressure(gasPhaseIdx) - rockRefPressure);
624 }
625 porosity_ *= 1.0 + x + 0.5 * x * x;
626 }
627
628 // deal with water induced rock compaction
629 porosity_ *= problem.template rockCompPoroMultiplier<Evaluation>(*this, globalSpaceIdx);
630
631 // deal with bioeffects (minimum porosity of 1e-8 to prevent numerical issues)
632 if constexpr (enableBioeffects) {
633 const Evaluation biofilm_ = priVars.makeEvaluation(Indices::biofilmVolumeFractionIdx,
634 timeIdx, linearizationType);
635 Evaluation calcite_ = 0.0;
636 if constexpr (enableMICP) {
637 calcite_ = priVars.makeEvaluation(Indices::calciteVolumeFractionIdx, timeIdx, linearizationType);
638 }
639 porosity_ -= min(biofilm_ + calcite_, referencePorosity_ - 1e-8);
640 }
641
642 // deal with salt-precipitation
643 if (enableSaltPrecipitation && priVars.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
644 const Evaluation Sp = priVars.makeEvaluation(Indices::saltConcentrationIdx, timeIdx);
645 porosity_ *= (1.0 - Sp);
646 }
647
648
649 // Geomechanical updates to porosity/pore volume
650 if constexpr (enableMech) {
651 // TPSA calculations
652 if (problem.simulator().vanguard().eclState().runspec().mechSolver().tpsa()) {
653 // TPSA compressibility term
654 const Scalar rockBiot = problem.rockBiotComp(globalSpaceIdx);
655 if (rockBiot > 0.0) {
656 const Scalar rockRefPressure = problem.rockReferencePressure(globalSpaceIdx);
657 Evaluation active_pressure;
658 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
659 active_pressure = fluidState_.pressure(oilPhaseIdx) - rockRefPressure;
660 } else if (FluidSystem::phaseIsActive(waterPhaseIdx)){
661 active_pressure = fluidState_.pressure(waterPhaseIdx) - rockRefPressure;
662 } else {
663 active_pressure = fluidState_.pressure(gasPhaseIdx) - rockRefPressure;
664 }
665 porosity_ += rockBiot * active_pressure;
666 }
667
668 // TPSA coupling term, pore volume changes due to mechanics
669 porosity_ += problem.rockMechPoroChange(globalSpaceIdx, /*timeIdx=*/timeIdx);
670 }
671 }
672 }
673
674 OPM_HOST_DEVICE void assertFiniteMembers()
675 {
676 // some safety checks in debug mode
677 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
678 if (!getFluidSystem().phaseIsActive(phaseIdx)) {
679 continue;
680 }
681
682 assert(isfinite(fluidState_.density(phaseIdx)));
683 assert(isfinite(fluidState_.saturation(phaseIdx)));
684 assert(isfinite(fluidState_.temperature(phaseIdx)));
685 assert(isfinite(fluidState_.pressure(phaseIdx)));
686 assert(isfinite(fluidState_.invB(phaseIdx)));
687 }
688 assert(isfinite(fluidState_.Rs()));
689 assert(isfinite(fluidState_.Rv()));
690 }
691
695 template <class ...Args>
696 OPM_HOST_DEVICE void update(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx)
697 {
698 ParentType::update(elemCtx, dofIdx, timeIdx);
699 const auto& problem = elemCtx.problem();
700 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
701 const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
702
703 updateCommonPart<Args...>(problem, priVars, globalSpaceIdx, timeIdx);
704
705 updatePorosity(elemCtx, dofIdx, timeIdx);
706
707 // Below: things I want to move to elemCtx-less versions but have not done yet.
708
709 if constexpr (enableSolvent) {
710 asImp_().solventPvtUpdate_(elemCtx, dofIdx, timeIdx);
711 }
712 if constexpr (enableExtbo) {
713 asImp_().zPvtUpdate_();
714 }
715 if constexpr (enablePolymer) {
716 asImp_().polymerPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
717 }
718 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
719 asImp_().updateEnergyQuantities_(elemCtx, dofIdx, timeIdx);
720 }
721 if constexpr (enableFoam) {
722 asImp_().foamPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
723 }
724 if constexpr (enableBioeffects) {
725 asImp_().bioeffectsPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
726 }
727 if constexpr (enableBrine) {
728 asImp_().saltPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
729 }
730 if constexpr (enableConvectiveMixing) {
731 // The ifs are here is to avoid extra calculations for
732 // cases with dry runs and without CO2STORE and DRSDTCON.
733 if (!problem.simulator().vanguard().eclState().getIOConfig().initOnly()) {
734 if (problem.simulator().vanguard().eclState().runspec().co2Storage()) {
735 if (problem.drsdtconIsActive(globalSpaceIdx, problem.simulator().episodeIndex())) {
736 asImp_().updateSaturatedDissolutionFactor_();
737 }
738 }
739 }
740 }
741
742 // update the quantities which are required by the chosen
743 // velocity model
744 FluxIntensiveQuantities::update_(elemCtx, dofIdx, timeIdx);
745
746 // update the diffusion specific quantities of the intensive quantities
747 if constexpr (enableDiffusion) {
748 DiffusionIntensiveQuantities::update_(fluidState_, priVars.pvtRegionIndex(), elemCtx, dofIdx, timeIdx);
749 }
750
751 // update the dispersion specific quantities of the intensive quantities
752 if constexpr (enableDispersion) {
753 DispersionIntensiveQuantities::update_(elemCtx, dofIdx, timeIdx);
754 }
755 }
756
757 template <class ...Args>
758 OPM_HOST_DEVICE void update(const Problem& problem,
759 const PrimaryVariables& priVars,
760 const unsigned globalSpaceIdx,
761 const unsigned timeIdx)
762 {
763 // This is the version of update() that does not use any ElementContext.
764 // It is limited by some modules that are not yet adapted to that.
765 static_assert(!enableSolvent);
766 static_assert(!enableExtbo);
767 static_assert(!enablePolymer);
768 static_assert(!enableFoam);
769 static_assert(!enableMICP);
770 static_assert(!enableBrine);
771 static_assert(!enableDiffusion);
772 static_assert(!enableDispersion);
773
774 this->extrusionFactor_ = 1.0;// to avoid fixing parent update
775 updateCommonPart<Args...>(problem, priVars, globalSpaceIdx, timeIdx);
776 // Porosity requires separate calls so this can be instantiated with ReservoirProblem from the examples/ directory.
777 updatePorosity(problem, priVars, globalSpaceIdx, timeIdx);
778
779 // TODO: Here we should do the parts for solvent etc. at the bottom of the other update() function.
780 }
781
782 // This function updated the parts that are common to the IntensiveQuantities regardless of extensions used.
783 template <class ...Args>
784 OPM_HOST_DEVICE void updateCommonPart(const Problem& problem,
785 const PrimaryVariables& priVars,
786 const unsigned globalSpaceIdx,
787 const unsigned timeIdx)
788 {
789 OPM_TIMEBLOCK_LOCAL(blackoilIntensiveQuanititiesUpdate, Subsystem::SatProps | Subsystem::PvtProps);
790
791 const auto& linearizationType = problem.model().linearizer().getLinearizationType();
792 const unsigned pvtRegionIdx = priVars.pvtRegionIndex();
793
794 fluidState_.setPvtRegionIndex(pvtRegionIdx);
795
796 updateTempSalt(problem, priVars, globalSpaceIdx, timeIdx, linearizationType);
797 updateSaturations(priVars, timeIdx, linearizationType);
798 updateRelpermAndPressures<Args...>(problem, priVars, globalSpaceIdx, timeIdx, linearizationType);
799
800 // update extBO parameters
801 if constexpr (enableExtbo) {
802 asImp_().zFractionUpdate_(priVars, timeIdx);
803 }
804
805 updateRsRvRsw(problem, priVars, globalSpaceIdx, timeIdx);
808
809 rockCompTransMultiplier_ = problem.template rockCompTransMultiplier<Evaluation>(*this, globalSpaceIdx);
810
811#ifndef NDEBUG
813#endif
814 }
815
819 OPM_HOST_DEVICE const FluidState& fluidState() const
820 { return fluidState_; }
821
822 // non-const version
823 OPM_HOST_DEVICE FluidState& fluidState()
824 { return fluidState_; }
825
829 OPM_HOST_DEVICE const Evaluation& mobility(unsigned phaseIdx) const
830 { return mobility_[phaseIdx]; }
831
832 OPM_HOST_DEVICE const Evaluation& mobility(unsigned phaseIdx, FaceDir::DirEnum facedir) const
833 {
834 using Dir = FaceDir::DirEnum;
835 if (dirMob_) {
836 bool constexpr usesStaticFluidSystem = std::is_empty_v<FluidSystem>;
837 if constexpr (usesStaticFluidSystem)
838 {
839 switch (facedir) {
840 case Dir::XMinus:
841 case Dir::XPlus:
842 return dirMob_->getArray(0)[phaseIdx];
843 case Dir::YMinus:
844 case Dir::YPlus:
845 return dirMob_->getArray(1)[phaseIdx];
846 case Dir::ZMinus:
847 case Dir::ZPlus:
848 return dirMob_->getArray(2)[phaseIdx];
849 default:
850 OPM_THROW(std::runtime_error, "Unexpected face direction");
851 }
852 }
853 else{
854 OPM_THROW(std::logic_error, "Directional mobility with non-static fluid system is not supported yet");
855 }
856 }
857 else {
858 return mobility_[phaseIdx];
859 }
860 }
861
865 OPM_HOST_DEVICE const Evaluation& porosity() const
866 { return porosity_; }
867
871 OPM_HOST_DEVICE const Evaluation& rockCompTransMultiplier() const
872 { return rockCompTransMultiplier_; }
873
881 OPM_HOST_DEVICE auto pvtRegionIndex() const -> decltype(std::declval<FluidState>().pvtRegionIndex())
882 { return fluidState_.pvtRegionIndex(); }
883
887 OPM_HOST_DEVICE Evaluation relativePermeability(unsigned phaseIdx) const
888 {
889 // warning: slow
890 return fluidState_.viscosity(phaseIdx) * mobility(phaseIdx);
891 }
892
899 OPM_HOST_DEVICE Scalar referencePorosity() const
900 { return referencePorosity_; }
901
902 OPM_HOST_DEVICE const Evaluation& permFactor() const
903 {
904 if constexpr (enableBioeffects) {
905 return BioeffectsIntQua::permFactor();
906 }
907 else if constexpr (enableSaltPrecipitation) {
908 return BrineIntQua::permFactor();
909 }
910 else {
911 OPM_THROW(std::logic_error, "permFactor() called but salt precipitation and bioeffects are disabled");
912 }
913 }
914
918 OPM_HOST_DEVICE const auto& getFluidSystem() const
919 {
920 return fluidState_.fluidSystem();
921 }
922
923private:
931
932 OPM_HOST_DEVICE Implementation& asImp_()
933 { return *static_cast<Implementation*>(this); }
934
935 FluidState fluidState_;
936 Scalar referencePorosity_;
937 Evaluation porosity_;
938 Evaluation rockCompTransMultiplier_;
939 std::array<Evaluation, numPhases> mobility_;
940
941 // Instead of writing a custom copy constructor and a custom assignment operator just to handle
942 // the dirMob_ unique ptr member variable when copying BlackOilIntensiveQuantites (see for example
943 // updateIntensitiveQuantities_() in fvbaseelementcontext.hh for a copy example) we write the below
944 // custom wrapper class CopyablePtr which wraps the unique ptr and makes it copyable.
945 //
946 // The advantage of this approach is that we avoid having to call all the base class copy constructors and
947 // assignment operators explicitly (which is needed when writing the custom copy constructor and assignment
948 // operators) which could become a maintenance burden. For example, when adding a new base class (if that should
949 // be needed sometime in the future) to BlackOilIntensiveQuantites we could forget to update the copy
950 // constructor and assignment operators.
951 //
952 // We want each copy of the BlackOilIntensiveQuantites to be unique, (TODO: why?) so we have to make a copy
953 // of the unique_ptr each time we copy construct or assign to it from another BlackOilIntensiveQuantites.
954 // (On the other hand, if a copy could share the ptr with the original, a shared_ptr could be used instead and the
955 // wrapper would not be needed)
956 DirectionalMobilityPtr dirMob_;
957};
958
959} // namespace Opm
960
961#endif
Contains classes extending the black-oil model. \detail This file holds dummy definitions,...
Declares the properties required by the black oil model.
Provides the volumetric quantities required for the equations needed by the brine extension of the bl...
Provides the volumetric quantities required for the equations needed by the bioeffects extension of t...
Provides the volumetric quantities required for the equations needed by the convective mixing (DRSDTC...
Provides the volumetric quantities required for the calculation of molecular diffusive fluxes.
Provides the volumetric quantities required for the calculation of dispersive fluxes.
Provides the volumetric quantities required for the equations needed by the energys extension of the ...
Definition: blackoilmodules.hpp:68
Provides the volumetric quantities required for the equations needed by the solvents extension of the...
Provides the volumetric quantities required for the equations needed by the polymers extension of the...
Contains the quantities which are are constant within a finite volume in the black-oil model.
Definition: blackoilintensivequantities.hh:79
OPM_HOST_DEVICE void updatePorosityImpl(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx)
Definition: blackoilintensivequantities.hh:600
OPM_HOST_DEVICE void update(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Definition: blackoilintensivequantities.hh:696
OPM_HOST_DEVICE void updateSaturations(const PrimaryVariables &priVars, const unsigned timeIdx, const LinearizationType lintype)
Definition: blackoilintensivequantities.hh:225
OPM_HOST_DEVICE void updateCommonPart(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx)
Definition: blackoilintensivequantities.hh:784
BlackOilIntensiveQuantities(const BlackOilIntensiveQuantities< OtherTypeTag > &other, const FluidSystem &fsystem)
Definition: blackoilintensivequantities.hh:181
OPM_HOST_DEVICE Scalar referencePorosity() const
Returns the porosity of the rock at reference conditions.
Definition: blackoilintensivequantities.hh:899
OPM_HOST_DEVICE void updateMobilityAndInvB()
Definition: blackoilintensivequantities.hh:492
OPM_HOST_DEVICE BlackOilIntensiveQuantities & operator=(const BlackOilIntensiveQuantities &other)=default
auto withOtherFluidSystem(const GetPropType< OtherTypeTag, Properties::FluidSystem > &other) const
Definition: blackoilintensivequantities.hh:205
OPM_HOST_DEVICE auto pvtRegionIndex() const -> decltype(std::declval< FluidState >().pvtRegionIndex())
Returns the index of the PVT region used to calculate the thermodynamic quantities.
Definition: blackoilintensivequantities.hh:881
OPM_HOST_DEVICE const Evaluation & mobility(unsigned phaseIdx) const
Returns the effective mobility of a given phase within the control volume.
Definition: blackoilintensivequantities.hh:829
OPM_HOST_DEVICE void updatePorosity(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Definition: blackoilintensivequantities.hh:578
OPM_HOST_DEVICE void updatePhaseDensities()
Definition: blackoilintensivequantities.hh:533
OPM_HOST_DEVICE void updateRelpermAndPressures(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx, const LinearizationType &lintype)
Definition: blackoilintensivequantities.hh:297
OPM_HOST_DEVICE FluidState & fluidState()
Definition: blackoilintensivequantities.hh:823
OPM_HOST_DEVICE void update(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx)
Definition: blackoilintensivequantities.hh:758
OPM_HOST_DEVICE void updateTempSalt(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx, const LinearizationType &lintype)
Definition: blackoilintensivequantities.hh:211
OPM_HOST_DEVICE const auto & getFluidSystem() const
Returns the fluid system used by this intensive quantities.
Definition: blackoilintensivequantities.hh:918
GetPropType< TypeTag, Properties::Problem > Problem
Definition: blackoilintensivequantities.hh:158
BlackOilFluidState< Scalar, FluidSystem, energyModuleType !=EnergyModules::NoTemperature, energyModuleType==EnergyModules::FullyImplicitThermal, compositionSwitchEnabled, enableVapwat, enableBrine, enableSaltPrecipitation, enableDisgasInWater, enableSolvent, Indices::numPhases > ScalarFluidState
Definition: blackoilintensivequantities.hh:157
OPM_HOST_DEVICE const FluidState & fluidState() const
Returns the phase state for the control-volume.
Definition: blackoilintensivequantities.hh:819
OPM_HOST_DEVICE Evaluation relativePermeability(unsigned phaseIdx) const
Returns the relative permeability of a given phase within the control volume.
Definition: blackoilintensivequantities.hh:887
BlackOilIntensiveQuantities(const BlackOilIntensiveQuantities &other)=default
OPM_HOST_DEVICE const Evaluation & permFactor() const
Definition: blackoilintensivequantities.hh:902
OPM_HOST_DEVICE BlackOilIntensiveQuantities()
Definition: blackoilintensivequantities.hh:160
OPM_HOST_DEVICE const Evaluation & rockCompTransMultiplier() const
Definition: blackoilintensivequantities.hh:871
OPM_HOST_DEVICE void assertFiniteMembers()
Definition: blackoilintensivequantities.hh:674
OPM_HOST_DEVICE const Evaluation & mobility(unsigned phaseIdx, FaceDir::DirEnum facedir) const
Definition: blackoilintensivequantities.hh:832
OPM_HOST_DEVICE void updatePorosity(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx)
Definition: blackoilintensivequantities.hh:589
OPM_HOST_DEVICE const Evaluation & porosity() const
Returns the average porosity within the control volume.
Definition: blackoilintensivequantities.hh:865
BlackOilFluidState< Evaluation, FluidSystem, energyModuleType !=EnergyModules::NoTemperature, energyModuleType==EnergyModules::FullyImplicitThermal, compositionSwitchEnabled, enableVapwat, enableBrine, enableSaltPrecipitation, enableDisgasInWater, enableSolvent, Indices::numPhases > FluidState
Definition: blackoilintensivequantities.hh:146
OPM_HOST_DEVICE void updateRsRvRsw(const Problem &problem, const PrimaryVariables &priVars, const unsigned globalSpaceIdx, const unsigned timeIdx)
Definition: blackoilintensivequantities.hh:389
Provides the volumetric quantities required for the equations needed by the polymers extension of the...
Provides the volumetric quantities required for the equations needed by the solvents extension of the...
This file contains definitions related to directional mobilities.
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: linearizationtype.hh:34