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