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