blackoilprimaryvariables.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 OPM is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9 OPM is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with OPM. If not, see <http://www.gnu.org/licenses/>.
15 Consult the COPYING file in the top-level source directory of this
16 module for the precise wording of the license and the list of
17 copyright holders.
18*/
24#ifndef EWOMS_BLACK_OIL_PRIMARY_VARIABLES_HH
25#define EWOMS_BLACK_OIL_PRIMARY_VARIABLES_HH
26
27#include <dune/common/fvector.hh>
28
29#include <opm/material/common/MathToolbox.hpp>
30#include <opm/material/common/Valgrind.hpp>
31#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
32#include <opm/material/fluidstates/SimpleModularFluidState.hpp>
33
40
42
43#include <algorithm>
44#include <array>
45#include <cassert>
46#include <cstddef>
47#include <cstdint>
48#include <stdexcept>
49#include <type_traits>
50
51namespace Opm::Parameters {
52
53template<class Scalar>
55{ static constexpr Scalar value = 1.0; };
56
57} // namespace Opm::Parameters
58
59namespace Opm {
60
66template <class TypeTag>
68{
71
79
80 // number of equations
81 enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
82
83 // primary variable indices
84 enum { waterSwitchIdx = Indices::waterSwitchIdx };
85 enum { pressureSwitchIdx = Indices::pressureSwitchIdx };
86 enum { compositionSwitchIdx = Indices::compositionSwitchIdx };
87 enum { saltConcentrationIdx = Indices::saltConcentrationIdx };
88 enum { solventSaturationIdx = Indices::solventSaturationIdx };
89
90 static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
91 static constexpr bool waterEnabled = Indices::waterEnabled;
92 static constexpr bool gasEnabled = Indices::gasEnabled;
93 static constexpr bool oilEnabled = Indices::oilEnabled;
94
95 // phase indices from the fluid system
96 enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
97 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
98 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
99 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
100
101 // component indices from the fluid system
102 enum { numComponents = getPropValue<TypeTag, Properties::NumComponents>() };
103 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
104 enum { enableExtbo = getPropValue<TypeTag, Properties::EnableExtbo>() };
105 enum { enablePolymer = getPropValue<TypeTag, Properties::EnablePolymer>() };
106 enum { enableFoam = getPropValue<TypeTag, Properties::EnableFoam>() };
107 enum { enableBrine = getPropValue<TypeTag, Properties::EnableBrine>() };
108 enum { enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>() };
109 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
110 enum { enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>() };
111 enum { enableTemperature = getPropValue<TypeTag, Properties::EnableTemperature>() };
112 enum { enableBioeffects = getPropValue<TypeTag, Properties::EnableBioeffects>() };
113 enum { enableMICP = Indices::enableMICP };
114 enum { gasCompIdx = FluidSystem::gasCompIdx };
115 enum { waterCompIdx = FluidSystem::waterCompIdx };
116 enum { oilCompIdx = FluidSystem::oilCompIdx };
117
118 using Toolbox = MathToolbox<Evaluation>;
119 using ComponentVector = Dune::FieldVector<Scalar, numComponents>;
125
126 static_assert(numPhases == 3, "The black-oil model assumes three phases!");
127 static_assert(numComponents == 3, "The black-oil model assumes three components!");
128
129public:
130 enum class WaterMeaning : std::uint8_t {
131 Sw, // water saturation
132 Rvw, // vaporized water
133 Rsw, // dissolved gas in water
134 Disabled, // The primary variable is not used
135 };
136
137 enum class PressureMeaning : std::uint8_t {
138 Po, // oil pressure
139 Pg, // gas pressure
140 Pw, // water pressure
141 };
142
143 enum class GasMeaning : std::uint8_t {
144 Sg, // gas saturation
145 Rs, // dissolved gas in oil
146 Rv, // vapporized oil
147 Disabled, // The primary variable is not used
148 };
149
150 enum class BrineMeaning : std::uint8_t {
151 Cs, // salt concentration
152 Sp, // (precipitated) salt saturation
153 Disabled, // The primary variable is not used
154 };
155
156 enum class SolventMeaning : std::uint8_t {
157 Ss, // solvent saturation
158 Rsolw, // dissolved solvent in water
159 Disabled, // The primary variable is not used
160 };
161
163 {
164 Valgrind::SetUndefined(*this);
165 pvtRegionIdx_ = 0;
166 }
167
172
174 {
176 result.pvtRegionIdx_ = 1;
177 result.primaryVarsMeaningBrine_ = BrineMeaning::Sp;
178 result.primaryVarsMeaningGas_ = GasMeaning::Rv;
179 result.primaryVarsMeaningPressure_ = PressureMeaning::Pg;
180 result.primaryVarsMeaningWater_ = WaterMeaning::Rsw;
181 result.primaryVarsMeaningSolvent_ = SolventMeaning::Ss;
182 for (std::size_t i = 0; i < result.size(); ++i) {
183 result[i] = i + 1;
184 }
185
186 return result;
187 }
188
189 static void init()
190 {
191 // TODO: these parameters have undocumented non-trivial dependencies
192 pressureScale_ = Parameters::Get<Parameters::PressureScale<Scalar>>();
193 }
194
195 static void registerParameters()
196 {
197 Parameters::Register<Parameters::PressureScale<Scalar>>
198 ("Scaling of pressure primary variable");
199 }
200
201 void setPressureScale(Scalar val)
202 { pressureScale_ = val; }
203
204 Evaluation
205 makeEvaluation(unsigned varIdx, unsigned timeIdx,
206 LinearizationType linearizationType = LinearizationType()) const
207 {
208 const Scalar scale = varIdx == pressureSwitchIdx ? this->pressureScale_ : Scalar{1.0};
209 if (std::is_same_v<Evaluation, Scalar>) {
210 return (*this)[varIdx] * scale; // finite differences
211 }
212 else {
213 // automatic differentiation
214 if (timeIdx == linearizationType.time) {
215 return Toolbox::createVariable((*this)[varIdx], varIdx) * scale;
216 }
217 else {
218 return Toolbox::createConstant((*this)[varIdx]) * scale;
219 }
220 }
221 }
222
230 void setPvtRegionIndex(unsigned value)
231 { pvtRegionIdx_ = static_cast<unsigned short>(value); }
232
236 unsigned pvtRegionIndex() const
237 { return pvtRegionIdx_; }
238
244 { return primaryVarsMeaningWater_; }
245
251 { primaryVarsMeaningWater_ = newMeaning; }
252
258 { return primaryVarsMeaningPressure_; }
259
265 { primaryVarsMeaningPressure_ = newMeaning; }
266
272 { return primaryVarsMeaningGas_; }
273
279 { primaryVarsMeaningGas_ = newMeaning; }
280
282 { return primaryVarsMeaningBrine_; }
283
289 { primaryVarsMeaningBrine_ = newMeaning; }
290
292 { return primaryVarsMeaningSolvent_; }
293
299 { primaryVarsMeaningSolvent_ = newMeaning; }
300
304 template <class FluidState>
305 void assignNaive(const FluidState& fluidState)
306 {
307 using ConstEvaluation = std::remove_reference_t<typename FluidState::Scalar>;
308 using FsEvaluation = std::remove_const_t<ConstEvaluation>;
309 using FsToolbox = MathToolbox<FsEvaluation>;
310
311 const bool gasPresent =
312 FluidSystem::phaseIsActive(gasPhaseIdx)
313 ? fluidState.saturation(gasPhaseIdx) > 0.0
314 : false;
315 const bool oilPresent =
316 FluidSystem::phaseIsActive(oilPhaseIdx)
317 ? fluidState.saturation(oilPhaseIdx) > 0.0
318 : false;
319 const bool waterPresent =
320 FluidSystem::phaseIsActive(waterPhaseIdx)
321 ? fluidState.saturation(waterPhaseIdx) > 0.0
322 : false;
323 const auto& saltSaturation =
324 BlackOil::getSaltSaturation_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
325 const bool precipitatedSaltPresent = enableSaltPrecipitation ? saltSaturation > 0.0 : false;
326 const bool oneActivePhases = FluidSystem::numActivePhases() == 1;
327 // deal with the primary variables for the energy extension
328 EnergyModule::assignPrimaryVars(*this, fluidState);
329
330 // Determine the meaning of the pressure primary variables
331 // Depending on the phases present, this variable is either interpreted as the
332 // pressure of the oil phase, gas phase (if no oil) or water phase (if only water)
333 if (gasPresent && FluidSystem::enableVaporizedOil() && !oilPresent) {
334 primaryVarsMeaningPressure_ = PressureMeaning::Pg;
335 }
336 else if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
337 primaryVarsMeaningPressure_ = PressureMeaning::Po;
338 }
339 else if (waterPresent && FluidSystem::enableDissolvedGasInWater() && !gasPresent) {
340 primaryVarsMeaningPressure_ = PressureMeaning::Pw;
341 }
342 else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
343 primaryVarsMeaningPressure_ = PressureMeaning::Pg;
344 }
345 else {
346 assert(FluidSystem::phaseIsActive(waterPhaseIdx));
347 primaryVarsMeaningPressure_ = PressureMeaning::Pw;
348 }
349
350 // Determine the meaning of the water primary variables
351 // Depending on the phases present, this variable is either interpreted as
352 // water saturation or vapporized water in the gas phase
353 // For two-phase gas-oil models and one-phase case the variable is disabled.
354 if (waterPresent && gasPresent) {
355 primaryVarsMeaningWater_ = WaterMeaning::Sw;
356 }
357 else if (gasPresent && FluidSystem::enableVaporizedWater()) {
358 primaryVarsMeaningWater_ = WaterMeaning::Rvw;
359 }
360 else if (waterPresent && FluidSystem::enableDissolvedGasInWater()) {
361 primaryVarsMeaningWater_ = WaterMeaning::Rsw;
362 }
363 else if (FluidSystem::phaseIsActive(waterPhaseIdx) && !oneActivePhases) {
364 primaryVarsMeaningWater_ = WaterMeaning::Sw;
365 }
366 else {
367 primaryVarsMeaningWater_ = WaterMeaning::Disabled;
368 }
369
370 // Determine the meaning of the gas primary variables
371 // Depending on the phases present, this variable is either interpreted as the
372 // saturation of the gas phase, as the fraction of the gas component in the oil
373 // phase (Rs) or as the fraction of the oil component (Rv) in the gas phase.
374 // For two-phase water-oil and water-gas models and one-phase case the variable is disabled.
375 if (gasPresent && oilPresent) {
376 primaryVarsMeaningGas_ = GasMeaning::Sg;
377 }
378 else if (oilPresent && FluidSystem::enableDissolvedGas()) {
379 primaryVarsMeaningGas_ = GasMeaning::Rs;
380 }
381 else if (gasPresent && FluidSystem::enableVaporizedOil()) {
382 primaryVarsMeaningGas_ = GasMeaning::Rv;
383 }
384 else if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx)) {
385 primaryVarsMeaningGas_ = GasMeaning::Sg;
386 }
387 else {
388 primaryVarsMeaningGas_ = GasMeaning::Disabled;
389 }
390
391 // Determine the meaning of the brine primary variables
392 if constexpr (enableSaltPrecipitation) {
393 if (precipitatedSaltPresent) {
394 primaryVarsMeaningBrine_ = BrineMeaning::Sp;
395 }
396 else {
397 primaryVarsMeaningBrine_ = BrineMeaning::Cs;
398 }
399 }
400 else {
401 primaryVarsMeaningBrine_ = BrineMeaning::Disabled;
402 }
403
404 // assign the actual primary variables
405 switch (primaryVarsMeaningPressure()) {
407 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(oilPhaseIdx)));
408 break;
410 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(gasPhaseIdx)));
411 break;
413 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(waterPhaseIdx)));
414 break;
415 default:
416 throw std::logic_error("No valid primary variable selected for pressure");
417 }
418
419 switch (primaryVarsMeaningWater()) {
420 case WaterMeaning::Sw:
421 {
422 (*this)[waterSwitchIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx));
423 break;
424 }
426 {
427 const auto& rvw = BlackOil::getRvw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
428 (*this)[waterSwitchIdx] = rvw;
429 break;
430 }
432 {
433 const auto& Rsw = BlackOil::getRsw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
434 (*this)[waterSwitchIdx] = Rsw;
435 break;
436 }
438 break;
439 default:
440 throw std::logic_error("No valid primary variable selected for water");
441 }
442 switch (primaryVarsMeaningGas()) {
443 case GasMeaning::Sg:
444 (*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx));
445 break;
446 case GasMeaning::Rs:
447 {
448 const auto& rs = BlackOil::getRs_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
449 (*this)[compositionSwitchIdx] = rs;
450 break;
451 }
452 case GasMeaning::Rv:
453 {
454 const auto& rv = BlackOil::getRv_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
455 (*this)[compositionSwitchIdx] = rv;
456 break;
457 }
459 break;
460 default:
461 throw std::logic_error("No valid primary variable selected for composision");
462 }
463 }
464
476 bool adaptPrimaryVariables(const Problem& problem,
477 unsigned globalDofIdx,
478 [[maybe_unused]] Scalar swMaximum,
479 Scalar thresholdWaterFilledCell, Scalar eps = 0.0)
480 {
481 // this function accesses quite a few black-oil specific low-level functions
482 // directly for better performance (instead of going the canonical way through
483 // the IntensiveQuantities). The reason is that most intensive quantities are not
484 // required to be able to decide if the primary variables needs to be switched or
485 // not, so it would be a waste to compute them.
486
487 // Both the primary variable meaning of water and gas are disabled i.e.
488 // It is a one-phase case and we no variable meaning switch is needed.
491 {
492 return false;
493 }
494
495 // Read the current saturation from the primary variables
496 Scalar sw = 0.0;
497 Scalar sg = 0.0;
498 Scalar saltConcentration = 0.0;
499 const Scalar& T = asImp_().temperature_(problem, globalDofIdx);
501 sw = (*this)[waterSwitchIdx];
502 }
504 sg = (*this)[compositionSwitchIdx];
505 }
507 sw = 1.0;
508 }
509
510 if (primaryVarsMeaningGas() == GasMeaning::Disabled && gasEnabled) {
511 sg = 1.0 - sw; // water + gas case
512 }
513
514 // if solid phase disappeares: Sp (Solid salt saturation) -> Cs (salt concentration)
515 // if solid phase appears: Cs (salt concentration) -> Sp (Solid salt saturation)
516 if constexpr (enableSaltPrecipitation) {
517 const Scalar saltSolubility = BrineModule::saltSol(pvtRegionIndex());
519 saltConcentration = saltSolubility;
520 const Scalar saltSat = (*this)[saltConcentrationIdx];
521 if (saltSat < -eps) { // precipitated salt dissappears
523 (*this)[saltConcentrationIdx] = saltSolubility; // set salt concentration to solubility limit
524 }
525 }
527 saltConcentration = (*this)[saltConcentrationIdx];
528 if (saltConcentration > saltSolubility + eps) { // salt concentration exceeds solubility limit
530 (*this)[saltConcentrationIdx] = 0.0;
531 }
532 }
533 }
534
535 // if solvent saturation disappeares: Ss (Solvent saturation) -> Rsolw (solvent dissolved in water)
536 // if solvent saturation appears: Rsolw (solvent dissolved in water) -> Ss (Solvent saturation)
537 // Scalar rsolw = 0.0; // not needed at the moment since we dont allow for vapwat in combination with rsolw
538 if constexpr (enableSolvent) {
540 const Scalar p = (*this)[pressureSwitchIdx]; // cap-pressure?
541 const Scalar solLimit =
542 SolventModule::solubilityLimit(pvtRegionIndex(), T , p, saltConcentration);
544 const Scalar solSat = (*this)[solventSaturationIdx];
545 if (solSat < -eps) { // solvent dissappears
547 (*this)[solventSaturationIdx] = solLimit; // set rsolw to solubility limit
548 }
549 }
551 const Scalar rsolw = (*this)[solventSaturationIdx];
552 if (rsolw > solLimit + eps) { // solvent appears as phase
554 (*this)[solventSaturationIdx] = 0.0;
555 }
556 }
557 }
558 }
559
560 // keep track if any meaning has changed
561 bool changed = false;
562
563 // Special case for cells with almost only water
564 // for these cells both saturations (if the phase is enabled) is used
565 // to avoid singular systems.
566 // If dissolved gas in water is enabled we shouldn't enter
567 // here but instead switch to Rsw as primary variable
568 // as sw >= 1.0 -> gas <= 0 (i.e. gas phase disappears)
569 if (sw >= thresholdWaterFilledCell && !FluidSystem::enableDissolvedGasInWater()) {
570 // make sure water saturations does not exceed sw_maximum. Default to 1.0
571 if constexpr (waterEnabled) {
572 (*this)[Indices::waterSwitchIdx] = std::min(swMaximum, sw);
574 }
575 // the hydrocarbon gas saturation is set to 0.0
576 if constexpr (compositionSwitchEnabled) {
577 (*this)[Indices::compositionSwitchIdx] = 0.0;
578 }
579
581 if (changed) {
582 if constexpr (compositionSwitchEnabled) {
584 }
585
586 // use water pressure?
587 }
588 return changed;
589 }
590
591 pcFactor_ = 1.0;
592 if constexpr (enableBrine) {
594 unsigned satnumRegionIdx = problem.satnumRegionIndex(globalDofIdx);
595 Scalar Sp = saltConcentration_();
596 Scalar porosityFactor = std::min(1.0 - Sp, 1.0); //phi/phi_0
597 const auto& pcfactTable = BrineModule::pcfactTable(satnumRegionIdx);
598 pcFactor_ = pcfactTable.eval(porosityFactor, /*extrapolation=*/true);
599 }
600 }
601 else if constexpr (enableBioeffects) {
602 if (BioeffectsModule::hasPcfactTables() && problem.referencePorosity(globalDofIdx, 0) > 0) {
603 unsigned satnumRegionIdx = problem.satnumRegionIndex(globalDofIdx);
604 Scalar Sb = biofilmVolumeFraction_() /
605 problem.referencePorosity(globalDofIdx, 0);
606 Scalar porosityFactor = std::min(1.0 - Sb, 1.0); //phi/phi_0
607 const auto& pcfactTable = BioeffectsModule::pcfactTable(satnumRegionIdx);
608 pcFactor_ = pcfactTable.eval(porosityFactor, /*extrapolation=*/true);
609 }
610 }
611
612 switch (primaryVarsMeaningWater()) {
613 case WaterMeaning::Sw:
614 {
615 // if water phase disappeares: Sw (water saturation) -> Rvw (fraction of water in gas phase)
616 if (sw < -eps && sg > eps && FluidSystem::enableVaporizedWater()) {
617 Scalar p = this->pressure_();
619 std::array<Scalar, numPhases> pC{};
620 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
621 const Scalar so = 1.0 - sg - solventSaturation_();
622 computeCapillaryPressures_(pC, so, sg + solventSaturation_(), /*sw=*/ 0.0, matParams);
623 p += pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
624 }
625 const Scalar rvwSat =
626 FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
627 T,
628 p,
629 saltConcentration);
631 (*this)[Indices::waterSwitchIdx] = rvwSat; // primary variable becomes Rvw
632 changed = true;
633 break;
634 }
635 // if gas phase disappeares: Sw (water saturation) -> Rsw (fraction of gas in water phase)
636 // and Pg (gas pressure) -> Pw ( water pressure)
637 if (sg < -eps && sw > eps && FluidSystem::enableDissolvedGasInWater()) {
638 const Scalar pg = this->pressure_();
640 std::array<Scalar, numPhases> pC = { 0.0 };
641 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
642 const Scalar so = 1.0 - sw - solventSaturation_();
643 computeCapillaryPressures_(pC, so, /*sg=*/ 0.0, sw, matParams);
644 const Scalar pw = pg + pcFactor_ * (pC[waterPhaseIdx] - pC[gasPhaseIdx]);
645 const Scalar rswSat =
646 FluidSystem::waterPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
647 T,
648 pw,
649 saltConcentration);
651 const Scalar rswMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
652 (*this)[Indices::waterSwitchIdx] = std::min(rswSat, rswMax); //primary variable becomes Rsw
654 this->setScaledPressure_(pw);
655 changed = true;
656 break;
657 }
658 break;
659 }
661 {
662 const Scalar& rvw = (*this)[waterSwitchIdx];
663 Scalar p = this->pressure_();
665 std::array<Scalar, numPhases> pC{};
666 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
667 const Scalar so = 1.0 - sg - solventSaturation_();
668 computeCapillaryPressures_(pC, so, sg + solventSaturation_(), /*sw=*/ 0.0, matParams);
669 p += pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
670 }
671 const Scalar rvwSat =
672 FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
673 T,
674 p,
675 saltConcentration);
676 // if water phase appears: Rvw (fraction of water in gas phase) -> Sw (water saturation)
677 if (rvw > rvwSat * (1.0 + eps)) {
679 (*this)[Indices::waterSwitchIdx] = 0.0; // water saturation
680 changed = true;
681 }
682 break;
683 }
685 {
686 // Gas phase not present. The hydrocarbon gas phase
687 // appears as soon as more of the gas component is present in the water phase
688 // than what saturated water can hold.
689 const Scalar& pw = this->pressure_();
691 const Scalar rswSat =
692 FluidSystem::waterPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
693 T,
694 pw,
695 saltConcentration);
696
697 const Scalar rsw = (*this)[Indices::waterSwitchIdx];
698 const Scalar rswMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
699 if (rsw > std::min(rswSat, rswMax)) {
700 // the gas phase appears, i.e., switch the primary variables to WaterMeaning::Sw
702 (*this)[Indices::waterSwitchIdx] = 1.0; // hydrocarbon water saturation
704 std::array<Scalar, numPhases> pC{};
705 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
706 computeCapillaryPressures_(pC, /*so=*/ 0.0, /*sg=*/ 0.0, /*sw=*/ 1.0, matParams);
707 const Scalar pg = pw + pcFactor_ * (pC[gasPhaseIdx] - pC[waterPhaseIdx]);
708 this->setScaledPressure_(pg);
709 changed = true;
710 }
711 break;
712 }
714 break;
715 default:
716 throw std::logic_error("No valid primary variable selected for water");
717 }
718
719 // if gas phase disappeares: Sg (gas saturation) -> Rs (fraction of gas in oil phase)
720 // if oil phase disappeares: Sg (gas saturation) -> Rv (fraction of oil in gas phase)
721 // Po (oil pressure ) -> Pg (gas pressure)
722
723 // if gas phase appears: Rs (fraction of gas in oil phase) -> Sg (gas saturation)
724 // if oil phase appears: Rv (fraction of oil in gas phase) -> Sg (gas saturation)
725 // Pg (gas pressure ) -> Po (oil pressure)
726 switch (primaryVarsMeaningGas()) {
727 case GasMeaning::Sg:
728 {
729 const Scalar s = 1.0 - sw - solventSaturation_();
730 if (sg < -eps && s > 0.0 && FluidSystem::enableDissolvedGas()) {
731 const Scalar po = this->pressure_();
733 const Scalar soMax = std::max(s, problem.maxOilSaturation(globalDofIdx));
734 const Scalar rsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
735 const Scalar rsSat =
736 enableExtbo
737 ? ExtboModule::rs(pvtRegionIndex(), po, zFraction_())
738 : FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
739 T,
740 po,
741 s,
742 soMax);
743 (*this)[Indices::compositionSwitchIdx] = std::min(rsMax, rsSat);
744 changed = true;
745 }
746 const Scalar so = 1.0 - sw - solventSaturation_() - sg;
747 if (so < -eps && sg > 0.0 && FluidSystem::enableVaporizedOil()) {
748 // the oil phase disappeared and some hydrocarbon gas phase is still
749 // present, i.e., switch the primary variables to GasMeaning::Rv.
750 // we only have the oil pressure readily available, but we need the gas
751 // pressure, i.e. we must determine capillary pressure
752 const Scalar po = this->pressure_();
753 std::array<Scalar, numPhases> pC{};
754 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
755 computeCapillaryPressures_(pC, /*so=*/0.0, sg + solventSaturation_(), sw, matParams);
756 const Scalar pg = po + pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
757
758 // we start at the GasMeaning::Rv value that corresponds to that of oil-saturated
759 // hydrocarbon gas
761 this->setScaledPressure_(pg);
762 const Scalar soMax = problem.maxOilSaturation(globalDofIdx);
763 const Scalar rvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
764 const Scalar rvSat =
765 enableExtbo
766 ? ExtboModule::rv(pvtRegionIndex(), pg, zFraction_())
767 : FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
768 T,
769 pg,
770 Scalar(0),
771 soMax);
773 (*this)[Indices::compositionSwitchIdx] = std::min(rvMax, rvSat);
774 changed = true;
775 }
776 break;
777 }
778 case GasMeaning::Rs:
779 {
780 // Gas phase not present. The hydrocarbon gas phase
781 // appears as soon as more of the gas component is present in the oil phase
782 // than what saturated oil can hold.
783 const Scalar po = this->pressure_();
784 const Scalar so = 1.0 - sw - solventSaturation_();
785 const Scalar soMax = std::max(so, problem.maxOilSaturation(globalDofIdx));
786 const Scalar rsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
787 const Scalar rsSat =
788 enableExtbo
789 ? ExtboModule::rs(pvtRegionIndex(), po, zFraction_())
790 : FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
791 T,
792 po,
793 so,
794 soMax);
795
796 const Scalar rs = (*this)[Indices::compositionSwitchIdx];
797 if (rs > std::min(rsMax, rsSat * (Scalar{1.0} + eps))) {
798 // the gas phase appears, i.e., switch the primary variables to GasMeaning::Sg
800 (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation
801 changed = true;
802 }
803 break;
804 }
805 case GasMeaning::Rv:
806 {
807 // The oil phase appears as
808 // soon as more of the oil component is present in the hydrocarbon gas phase
809 // than what saturated gas contains. Note that we use the blackoil specific
810 // low-level PVT objects here for performance reasons.
811 const Scalar pg = this->pressure_();
812 const Scalar soMax = problem.maxOilSaturation(globalDofIdx);
813 const Scalar rvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
814 const Scalar rvSat =
815 enableExtbo
816 ? ExtboModule::rv(pvtRegionIndex(), pg, zFraction_())
817 : FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
818 T,
819 pg,
820 /*so=*/Scalar(0.0),
821 soMax);
822
823 const Scalar rv = (*this)[Indices::compositionSwitchIdx];
824 if (rv > std::min(rvMax, rvSat * (Scalar{1.0} + eps))) {
825 // switch to phase equilibrium mode because the oil phase appears. here
826 // we also need the capillary pressures to calculate the oil phase
827 // pressure using the gas phase pressure
828 const Scalar sg2 = 1.0 - sw - solventSaturation_();
829 std::array<Scalar, numPhases> pC{};
830 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
831 computeCapillaryPressures_(pC,
832 /*so=*/0.0,
833 /*sg=*/sg2 + solventSaturation_(),
834 sw,
835 matParams);
836 const Scalar po = pg + pcFactor_ * (pC[oilPhaseIdx] - pC[gasPhaseIdx]);
837
840 this->setScaledPressure_(po);
841 (*this)[Indices::compositionSwitchIdx] = sg2; // hydrocarbon gas saturation
842 changed = true;
843 }
844 break;
845 }
847 break;
848 default:
849 throw std::logic_error("No valid primary variable selected for water");
850 }
851 return changed;
852 }
853
855 {
858 {
859 return false;
860 }
861 Scalar sw = 0.0;
863 sw = (*this)[Indices::waterSwitchIdx];
864 }
865 Scalar sg = 0.0;
867 sg = (*this)[Indices::compositionSwitchIdx];
868 }
869
870 Scalar ssol = 0.0;
872 ssol =(*this) [Indices::solventSaturationIdx];
873 }
874
875 Scalar so = 1.0 - sw - sg - ssol;
876 sw = std::min(std::max(sw, Scalar{0.0}), Scalar{1.0});
877 so = std::min(std::max(so, Scalar{0.0}), Scalar{1.0});
878 sg = std::min(std::max(sg, Scalar{0.0}), Scalar{1.0});
879 ssol = std::min(std::max(ssol, Scalar{0.0}), Scalar{1.0});
880 const Scalar st = sw + so + sg + ssol;
881 sw = sw / st;
882 sg = sg / st;
883 ssol = ssol / st;
884 assert(st > 0.5);
886 (*this)[Indices::waterSwitchIdx] = sw;
887 }
889 (*this)[Indices::compositionSwitchIdx] = sg;
890 }
892 (*this) [Indices::solventSaturationIdx] = ssol;
893 }
894
895 return (st != 1);
896 }
897
899
900 using ParentType::operator=;
901
909 void checkDefined() const
910 {
911#ifndef NDEBUG
912 // check the "real" primary variables
913 for (unsigned i = 0; i < this->size(); ++i) {
914 Valgrind::CheckDefined((*this)[i]);
915 }
916
917 // check the "pseudo" primary variables
918 Valgrind::CheckDefined(primaryVarsMeaningWater_);
919 Valgrind::CheckDefined(primaryVarsMeaningGas_);
920 Valgrind::CheckDefined(primaryVarsMeaningPressure_);
921 Valgrind::CheckDefined(primaryVarsMeaningBrine_);
922 Valgrind::CheckDefined(primaryVarsMeaningSolvent_);
923
924 Valgrind::CheckDefined(pvtRegionIdx_);
925#endif // NDEBUG
926 }
927
928 template<class Serializer>
929 void serializeOp(Serializer& serializer)
930 {
931 using FV = Dune::FieldVector<Scalar, getPropValue<TypeTag, Properties::NumEq>()>;
932 serializer(static_cast<FV&>(*this));
933 serializer(primaryVarsMeaningWater_);
934 serializer(primaryVarsMeaningPressure_);
935 serializer(primaryVarsMeaningGas_);
936 serializer(primaryVarsMeaningBrine_);
937 serializer(primaryVarsMeaningSolvent_);
938 serializer(pvtRegionIdx_);
939 }
940
942 {
943 return
944 static_cast<const FvBasePrimaryVariables<TypeTag>&>(*this) == rhs
945 && this->primaryVarsMeaningWater_ == rhs.primaryVarsMeaningWater_
946 && this->primaryVarsMeaningPressure_ == rhs.primaryVarsMeaningPressure_
947 && this->primaryVarsMeaningGas_ == rhs.primaryVarsMeaningGas_
948 && this->primaryVarsMeaningBrine_ == rhs.primaryVarsMeaningBrine_
949 && this->primaryVarsMeaningSolvent_ == rhs.primaryVarsMeaningSolvent_
950 && this->pvtRegionIdx_ == rhs.pvtRegionIdx_;
951 }
952
953private:
954 Implementation& asImp_()
955 { return *static_cast<Implementation*>(this); }
956
957 const Implementation& asImp_() const
958 { return *static_cast<const Implementation*>(this); }
959
960 Scalar solventSaturation_() const
961 {
962 if constexpr (enableSolvent) {
964 return (*this)[Indices::solventSaturationIdx];
965 }
966 }
967 return 0.0;
968 }
969
970 Scalar zFraction_() const
971 {
972 if constexpr (enableExtbo) {
973 return (*this)[Indices::zFractionIdx];
974 }
975 else {
976 return 0.0;
977 }
978 }
979
980 Scalar saltConcentration_() const
981 {
982 if constexpr (enableBrine) {
983 return (*this)[Indices::saltConcentrationIdx];
984 }
985 else {
986 return 0.0;
987 }
988 }
989
990 Scalar biofilmVolumeFraction_() const
991 {
992 if constexpr (enableBioeffects)
993 return (*this)[Indices::biofilmVolumeFractionIdx];
994 else
995 return 0.0;
996 }
997
998 Scalar temperature_(const Problem& problem, [[maybe_unused]] unsigned globalDofIdx) const
999 {
1000 if constexpr (enableEnergy) {
1001 return (*this)[Indices::temperatureIdx];
1002 }
1003 else if constexpr (enableTemperature) {
1004 return problem.temperature(globalDofIdx, /*timeIdx*/ 0);
1005 }
1006 else {
1007 return FluidSystem::reservoirTemperature();
1008 }
1009 }
1010
1011 template <class Container>
1012 void computeCapillaryPressures_(Container& result,
1013 Scalar so,
1014 Scalar sg,
1015 Scalar sw,
1016 const MaterialLawParams& matParams) const
1017 {
1018 using SatOnlyFluidState = SimpleModularFluidState<Scalar,
1019 numPhases,
1020 numComponents,
1021 FluidSystem,
1022 /*storePressure=*/false,
1023 /*storeTemperature=*/false,
1024 /*storeComposition=*/false,
1025 /*storeFugacity=*/false,
1026 /*storeSaturation=*/true,
1027 /*storeDensity=*/false,
1028 /*storeViscosity=*/false,
1029 /*storeEnthalpy=*/false>;
1030 SatOnlyFluidState fluidState;
1031 fluidState.setSaturation(waterPhaseIdx, sw);
1032 fluidState.setSaturation(oilPhaseIdx, so);
1033 fluidState.setSaturation(gasPhaseIdx, sg);
1034
1035 MaterialLaw::capillaryPressures(result, matParams, fluidState);
1036 }
1037
1038 Scalar pressure_() const
1039 { return (*this)[Indices::pressureSwitchIdx] * this->pressureScale_; }
1040
1041 void setScaledPressure_(Scalar pressure)
1042 { (*this)[Indices::pressureSwitchIdx] = pressure / (this->pressureScale_); }
1043
1044 WaterMeaning primaryVarsMeaningWater_{WaterMeaning::Disabled};
1045 PressureMeaning primaryVarsMeaningPressure_{PressureMeaning::Po};
1046 GasMeaning primaryVarsMeaningGas_{GasMeaning::Disabled};
1047 BrineMeaning primaryVarsMeaningBrine_{BrineMeaning::Disabled};
1048 SolventMeaning primaryVarsMeaningSolvent_{SolventMeaning::Disabled};
1049 unsigned short pvtRegionIdx_;
1050 Scalar pcFactor_;
1051 static inline Scalar pressureScale_ = 1.0;
1052};
1053
1054} // namespace Opm
1055
1056#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.
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,...
Declares the properties required by the black oil model.
Contains the classes required to extend the black-oil model by solvents.
Contains the high level supplements required to extend the black oil model by bioeffects.
Definition: blackoilbioeffectsmodules.hh:93
static bool hasPcfactTables()
Definition: blackoilbioeffectsmodules.hh:481
static const TabulatedFunction & pcfactTable(unsigned satnumRegionIdx)
Definition: blackoilbioeffectsmodules.hh:476
Contains the high level supplements required to extend the black oil model by brine.
Definition: blackoilbrinemodules.hh:56
static Scalar saltSol(unsigned regionIdx)
Definition: blackoilbrinemodules.hh:352
static const TabulatedFunction & pcfactTable(unsigned satnumRegionIdx)
Definition: blackoilbrinemodules.hh:296
static bool hasPcfactTables()
Definition: blackoilbrinemodules.hh:342
Contains the high level supplements required to extend the black oil model by energy.
Definition: blackoilenergymodules.hh:58
static void assignPrimaryVars(PrimaryVariables &priVars, const FluidState &fluidState)
Assign the energy specific primary variables to a PrimaryVariables object.
Definition: blackoilenergymodules.hh:263
Contains the high level supplements required to extend the black oil model.
Definition: blackoilextbomodules.hh:62
static Value rs(unsigned pvtRegionIdx, const Value &pressure, const Value &z)
Definition: blackoilextbomodules.hh:348
static Value rv(unsigned pvtRegionIdx, const Value &pressure, const Value &z)
Definition: blackoilextbomodules.hh:352
Represents the primary variables used by the black-oil model.
Definition: blackoilprimaryvariables.hh:68
bool operator==(const BlackOilPrimaryVariables &rhs) const
Definition: blackoilprimaryvariables.hh:941
WaterMeaning
Definition: blackoilprimaryvariables.hh:130
unsigned pvtRegionIndex() const
Return the index of the region which should be used for PVT properties.
Definition: blackoilprimaryvariables.hh:236
BlackOilPrimaryVariables & operator=(const BlackOilPrimaryVariables &other)=default
SolventMeaning
Definition: blackoilprimaryvariables.hh:156
static void registerParameters()
Definition: blackoilprimaryvariables.hh:195
GasMeaning primaryVarsMeaningGas() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:271
PressureMeaning primaryVarsMeaningPressure() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:257
void serializeOp(Serializer &serializer)
Definition: blackoilprimaryvariables.hh:929
static void init()
Definition: blackoilprimaryvariables.hh:189
void setPrimaryVarsMeaningSolvent(SolventMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:298
BlackOilPrimaryVariables()
Definition: blackoilprimaryvariables.hh:162
static BlackOilPrimaryVariables serializationTestObject()
Definition: blackoilprimaryvariables.hh:173
SolventMeaning primaryVarsMeaningSolvent() const
Definition: blackoilprimaryvariables.hh:291
bool chopAndNormalizeSaturations()
Definition: blackoilprimaryvariables.hh:854
bool adaptPrimaryVariables(const Problem &problem, unsigned globalDofIdx, Scalar swMaximum, Scalar thresholdWaterFilledCell, Scalar eps=0.0)
Adapt the interpretation of the switching variables to be physically meaningful.
Definition: blackoilprimaryvariables.hh:476
void setPrimaryVarsMeaningPressure(PressureMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:264
WaterMeaning primaryVarsMeaningWater() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:243
void setPrimaryVarsMeaningWater(WaterMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:250
void assignNaive(const FluidState &fluidState)
Directly retrieve the primary variables from an arbitrary fluid state.
Definition: blackoilprimaryvariables.hh:305
Evaluation makeEvaluation(unsigned varIdx, unsigned timeIdx, LinearizationType linearizationType=LinearizationType()) const
Definition: blackoilprimaryvariables.hh:205
BrineMeaning
Definition: blackoilprimaryvariables.hh:150
void setPrimaryVarsMeaningBrine(BrineMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:288
BlackOilPrimaryVariables(const BlackOilPrimaryVariables &value)=default
Copy constructor.
BrineMeaning primaryVarsMeaningBrine() const
Definition: blackoilprimaryvariables.hh:281
void setPressureScale(Scalar val)
Definition: blackoilprimaryvariables.hh:201
void setPrimaryVarsMeaningGas(GasMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:278
PressureMeaning
Definition: blackoilprimaryvariables.hh:137
void setPvtRegionIndex(unsigned value)
Set the index of the region which should be used for PVT properties.
Definition: blackoilprimaryvariables.hh:230
void checkDefined() const
< Import base class assignment operators.
Definition: blackoilprimaryvariables.hh:909
GasMeaning
Definition: blackoilprimaryvariables.hh:143
Contains the high level supplements required to extend the black oil model by solvents.
Definition: blackoilsolventmodules.hh:68
static bool isSolubleInWater()
Definition: blackoilsolventmodules.hh:521
static Value solubilityLimit(unsigned pvtIdx, const Value &temperature, const Value &pressure, const Value &saltConcentration)
Definition: blackoilsolventmodules.hh:503
Represents the primary variables used by the a model.
Definition: fvbaseprimaryvariables.hh:53
SimpleModularFluidState< double, 3, 3, FluidSystemSimple, false, false, false, false, true, false, false, false > SatOnlyFluidState
Definition: EquilibrationHelpers_impl.hpp:53
Definition: blackoilnewtonmethodparams.hpp:31
Definition: blackoilbioeffectsmodules.hh:43
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
Definition: blackoilprimaryvariables.hh:55
static constexpr Scalar value
Definition: blackoilprimaryvariables.hh:55