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