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