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