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 "blackoilproperties.hh"
35
37
38#include <dune/common/fvector.hh>
39
40#include <opm/material/constraintsolvers/NcpFlash.hpp>
41#include <opm/material/fluidstates/CompositionalFluidState.hpp>
42#include <opm/material/fluidstates/SimpleModularFluidState.hpp>
43#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
44#include <opm/material/common/Valgrind.hpp>
45
46namespace Opm::Properties {
47 template<class TypeTag, class MyTypeTag>
50 static constexpr type value = 1.0;
51 };
52}
53
54
55namespace Opm {
56template <class TypeTag, bool enableSolvent>
58
59template <class TypeTag, bool enableExtbo>
61
62template <class TypeTag, bool enablePolymer>
64
65template <class TypeTag, bool enableBrine>
67
73template <class TypeTag>
75{
78
86
87 // number of equations
88 enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
89
90 // primary variable indices
91 enum { waterSwitchIdx = Indices::waterSwitchIdx };
92 enum { pressureSwitchIdx = Indices::pressureSwitchIdx };
93 enum { compositionSwitchIdx = Indices::compositionSwitchIdx };
94 enum { saltConcentrationIdx = Indices::saltConcentrationIdx };
95 enum { solventSaturationIdx = Indices::solventSaturationIdx };
96
97 static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
98 static constexpr bool waterEnabled = Indices::waterEnabled;
99 static constexpr bool gasEnabled = Indices::gasEnabled;
100 static constexpr bool oilEnabled = Indices::oilEnabled;
101
102 // phase indices from the fluid system
103 enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
104 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
105 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
106 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
107
108 // component indices from the fluid system
109 enum { numComponents = getPropValue<TypeTag, Properties::NumComponents>() };
110 enum { enableSolvent = getPropValue<TypeTag, Properties::EnableSolvent>() };
111 enum { enableExtbo = getPropValue<TypeTag, Properties::EnableExtbo>() };
112 enum { enablePolymer = getPropValue<TypeTag, Properties::EnablePolymer>() };
113 enum { enableFoam = getPropValue<TypeTag, Properties::EnableFoam>() };
114 enum { enableBrine = getPropValue<TypeTag, Properties::EnableBrine>() };
115 enum { enableSaltPrecipitation = getPropValue<TypeTag, Properties::EnableSaltPrecipitation>() };
116 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
117 enum { enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>() };
118 enum { enableTemperature = getPropValue<TypeTag, Properties::EnableTemperature>() };
119 enum { enableMICP = getPropValue<TypeTag, Properties::EnableMICP>() };
120 enum { gasCompIdx = FluidSystem::gasCompIdx };
121 enum { waterCompIdx = FluidSystem::waterCompIdx };
122 enum { oilCompIdx = FluidSystem::oilCompIdx };
123
124 using Toolbox = MathToolbox<Evaluation>;
125 using ComponentVector = Dune::FieldVector<Scalar, numComponents>;
133
134 static_assert(numPhases == 3, "The black-oil model assumes three phases!");
135 static_assert(numComponents == 3, "The black-oil model assumes three components!");
136
137public:
138 enum class WaterMeaning {
139 Sw, // water saturation
140 Rvw, // vaporized water
141 Rsw, // dissolved gas in water
142 Disabled, // The primary variable is not used
143 };
144
145 enum class PressureMeaning {
146 Po, // oil pressure
147 Pg, // gas pressure
148 Pw, // water pressure
149 };
150 enum class GasMeaning {
151 Sg, // gas saturation
152 Rs, // dissolved gas in oil
153 Rv, // vapporized oil
154 Disabled, // The primary variable is not used
155 };
156
157 enum class BrineMeaning {
158 Cs, // salt concentration
159 Sp, // (precipitated) salt saturation
160 Disabled, // The primary variable is not used
161 };
162
163 enum class SolventMeaning {
164 Ss, // solvent saturation
165 Rsolw, // dissolved solvent in water
166 Disabled, // The primary variable is not used
167 };
168
170 : ParentType()
171 {
172 Valgrind::SetUndefined(*this);
173 pvtRegionIdx_ = 0;
174 }
175
180 : ParentType(value)
181 {
182 Valgrind::SetUndefined(primaryVarsMeaningWater_);
183 Valgrind::SetUndefined(primaryVarsMeaningGas_);
184 Valgrind::SetUndefined(primaryVarsMeaningPressure_);
185 Valgrind::SetUndefined(primaryVarsMeaningBrine_);
186 Valgrind::SetUndefined(primaryVarsMeaningSolvent_);
187
188 pvtRegionIdx_ = 0;
189 }
190
195
197 {
199 result.pvtRegionIdx_ = 1;
200 result.primaryVarsMeaningBrine_ = BrineMeaning::Sp;
201 result.primaryVarsMeaningGas_ = GasMeaning::Rv;
202 result.primaryVarsMeaningPressure_ = PressureMeaning::Pg;
203 result.primaryVarsMeaningWater_ = WaterMeaning::Rsw;
204 result.primaryVarsMeaningSolvent_ = SolventMeaning::Ss;
205 for (size_t i = 0; i < result.size(); ++i) {
206 result[i] = i+1;
207 }
208
209 return result;
210 }
211
212 static void init()
213 {
214 // TODO: these parameters have undocumented non-trivial dependencies
215 pressureScale_ = Parameters::get<TypeTag, Properties::PressureScale>();
216 }
217
218 static void registerParameters()
219 {
220 Parameters::registerParam<TypeTag, Properties::PressureScale>
221 ("Scaling of pressure primary variable");
222 }
223
224 void setPressureScale(Scalar val)
225 {
226 pressureScale_ = val;
227 }
228
229 Evaluation
230 makeEvaluation(unsigned varIdx, unsigned timeIdx, LinearizationType linearizationType = LinearizationType()) const
231 {
232 Scalar scale = 1.0;
233 if (varIdx == pressureSwitchIdx) {
234 scale = this->pressureScale_;
235 }
236 if (std::is_same<Evaluation, Scalar>::value)
237 return (*this)[varIdx] * scale; // finite differences
238 else {
239 // automatic differentiation
240 if (timeIdx == linearizationType.time)
241 return Toolbox::createVariable((*this)[varIdx], varIdx) * scale;
242 else
243 return Toolbox::createConstant((*this)[varIdx]) * scale;
244 }
245 }
246
254 void setPvtRegionIndex(unsigned value)
255 { pvtRegionIdx_ = static_cast<unsigned short>(value); }
256
260 unsigned pvtRegionIndex() const
261 { return pvtRegionIdx_; }
262
268 { return primaryVarsMeaningWater_; }
269
275 { primaryVarsMeaningWater_ = newMeaning; }
276
282 { return primaryVarsMeaningPressure_; }
283
289 { primaryVarsMeaningPressure_ = newMeaning; }
290
296 { return primaryVarsMeaningGas_; }
297
303 { primaryVarsMeaningGas_ = newMeaning; }
304
306 { return primaryVarsMeaningBrine_; }
307
314 { primaryVarsMeaningBrine_ = newMeaning; }
315
316
318 { return primaryVarsMeaningSolvent_; }
319
326 { primaryVarsMeaningSolvent_ = newMeaning; }
327
331 template <class FluidState>
332 void assignMassConservative(const FluidState& fluidState,
333 const MaterialLawParams& matParams,
334 bool isInEquilibrium = false)
335 {
336 using ConstEvaluation = typename std::remove_reference<typename FluidState::Scalar>::type;
337 using FsEvaluation = typename std::remove_const<ConstEvaluation>::type;
338 using FsToolbox = MathToolbox<FsEvaluation>;
339
340#ifndef NDEBUG
341 // make sure the temperature is the same in all fluid phases
342 for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) {
343 Valgrind::CheckDefined(fluidState.temperature(0));
344 Valgrind::CheckDefined(fluidState.temperature(phaseIdx));
345
346 assert(fluidState.temperature(0) == fluidState.temperature(phaseIdx));
347 }
348#endif // NDEBUG
349
350 // for the equilibrium case, we don't need complicated
351 // computations.
352 if (isInEquilibrium) {
353 assignNaive(fluidState);
354 return;
355 }
356
357 // If your compiler bails out here, you're probably not using a suitable black
358 // oil fluid system.
359 typename FluidSystem::template ParameterCache<Scalar> paramCache;
360 paramCache.setRegionIndex(pvtRegionIdx_);
361 paramCache.setMaxOilSat(FsToolbox::value(fluidState.saturation(oilPhaseIdx)));
362
363 // create a mutable fluid state with well defined densities based on the input
364 using NcpFlash = NcpFlash<Scalar, FluidSystem>;
365 using FlashFluidState = CompositionalFluidState<Scalar, FluidSystem>;
366 FlashFluidState fsFlash;
367 fsFlash.setTemperature(FsToolbox::value(fluidState.temperature(/*phaseIdx=*/0)));
368 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
369 fsFlash.setPressure(phaseIdx, FsToolbox::value(fluidState.pressure(phaseIdx)));
370 fsFlash.setSaturation(phaseIdx, FsToolbox::value(fluidState.saturation(phaseIdx)));
371 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
372 fsFlash.setMoleFraction(phaseIdx, compIdx, FsToolbox::value(fluidState.moleFraction(phaseIdx, compIdx)));
373 }
374
375 paramCache.updateAll(fsFlash);
376 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
377 if (!FluidSystem::phaseIsActive(phaseIdx))
378 continue;
379
380 Scalar rho = FluidSystem::template density<FlashFluidState, Scalar>(fsFlash, paramCache, phaseIdx);
381 fsFlash.setDensity(phaseIdx, rho);
382 }
383
384 // calculate the "global molarities"
385 ComponentVector globalMolarities(0.0);
386 for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
387 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
388 if (!FluidSystem::phaseIsActive(phaseIdx))
389 continue;
390
391 globalMolarities[compIdx] +=
392 fsFlash.saturation(phaseIdx) * fsFlash.molarity(phaseIdx, compIdx);
393 }
394 }
395
396 // use a flash calculation to calculate a fluid state in
397 // thermodynamic equilibrium
398
399 // run the flash calculation
400 NcpFlash::template solve<MaterialLaw>(fsFlash, matParams, paramCache, globalMolarities);
401
402 // use the result to assign the primary variables
403 assignNaive(fsFlash);
404 }
405
409 template <class FluidState>
410 void assignNaive(const FluidState& fluidState)
411 {
412 using ConstEvaluation = typename std::remove_reference<typename FluidState::Scalar>::type;
413 using FsEvaluation = typename std::remove_const<ConstEvaluation>::type;
414 using FsToolbox = MathToolbox<FsEvaluation>;
415
416 bool gasPresent = FluidSystem::phaseIsActive(gasPhaseIdx)?(fluidState.saturation(gasPhaseIdx) > 0.0):false;
417 bool oilPresent = FluidSystem::phaseIsActive(oilPhaseIdx)?(fluidState.saturation(oilPhaseIdx) > 0.0):false;
418 bool waterPresent = FluidSystem::phaseIsActive(waterPhaseIdx)?(fluidState.saturation(waterPhaseIdx) > 0.0):false;
419 const auto& saltSaturation = BlackOil::getSaltSaturation_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
420 bool precipitatedSaltPresent = enableSaltPrecipitation?(saltSaturation > 0.0):false;
421 bool oneActivePhases = FluidSystem::numActivePhases() == 1;
422 // deal with the primary variables for the energy extension
423 EnergyModule::assignPrimaryVars(*this, fluidState);
424
425 // Determine the meaning of the pressure primary variables
426 // Depending on the phases present, this variable is either interpreted as the
427 // pressure of the oil phase, gas phase (if no oil) or water phase (if only water)
428 if (gasPresent && FluidSystem::enableVaporizedOil() && !oilPresent){
429 primaryVarsMeaningPressure_ = PressureMeaning::Pg;
430 } else if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
431 primaryVarsMeaningPressure_ = PressureMeaning::Po;
432 } else if ( waterPresent && FluidSystem::enableDissolvedGasInWater() && !gasPresent){
433 primaryVarsMeaningPressure_ = PressureMeaning::Pw;
434 } else if (FluidSystem::phaseIsActive(gasPhaseIdx)) {
435 primaryVarsMeaningPressure_ = PressureMeaning::Pg;
436 } else {
437 assert(FluidSystem::phaseIsActive(waterPhaseIdx));
438 primaryVarsMeaningPressure_ = PressureMeaning::Pw;
439 }
440
441 // Determine the meaning of the water primary variables
442 // Depending on the phases present, this variable is either interpreted as
443 // water saturation or vapporized water in the gas phase
444 // For two-phase gas-oil models and one-phase case the variable is disabled.
445 if ( waterPresent && gasPresent ){
446 primaryVarsMeaningWater_ = WaterMeaning::Sw;
447 } else if (gasPresent && FluidSystem::enableVaporizedWater()) {
448 primaryVarsMeaningWater_ = WaterMeaning::Rvw;
449 } else if (waterPresent && FluidSystem::enableDissolvedGasInWater()) {
450 primaryVarsMeaningWater_ = WaterMeaning::Rsw;
451 } else if (FluidSystem::phaseIsActive(waterPhaseIdx) && !oneActivePhases) {
452 primaryVarsMeaningWater_ = WaterMeaning::Sw;
453 } else {
454 primaryVarsMeaningWater_ = WaterMeaning::Disabled;
455 }
456
457 // Determine the meaning of the gas primary variables
458 // Depending on the phases present, this variable is either interpreted as the
459 // saturation of the gas phase, as the fraction of the gas component in the oil
460 // phase (Rs) or as the fraction of the oil component (Rv) in the gas phase.
461 // For two-phase water-oil and water-gas models and one-phase case the variable is disabled.
462 if ( gasPresent && oilPresent ) {
463 primaryVarsMeaningGas_ = GasMeaning::Sg;
464 } else if (oilPresent && FluidSystem::enableDissolvedGas()) {
465 primaryVarsMeaningGas_ = GasMeaning::Rs;
466 } else if (gasPresent && FluidSystem::enableVaporizedOil()){
467 primaryVarsMeaningGas_ = GasMeaning::Rv;
468 } else if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx)) {
469 primaryVarsMeaningGas_ = GasMeaning::Sg;
470 } else {
471 primaryVarsMeaningGas_ = GasMeaning::Disabled;
472 }
473
474 // Determine the meaning of the brine primary variables
475 if constexpr (enableSaltPrecipitation){
476 if (precipitatedSaltPresent)
477 primaryVarsMeaningBrine_ = BrineMeaning::Sp;
478 else
479 primaryVarsMeaningBrine_ = BrineMeaning::Cs;
480 } else {
481 primaryVarsMeaningBrine_ = BrineMeaning::Disabled;
482 }
483
484 // assign the actual primary variables
487 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(oilPhaseIdx)));
488 break;
490 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(gasPhaseIdx)));
491 break;
493 this->setScaledPressure_(FsToolbox::value(fluidState.pressure(waterPhaseIdx)));
494 break;
495 default:
496 throw std::logic_error("No valid primary variable selected for pressure");
497 }
498 switch(primaryVarsMeaningWater()) {
499 case WaterMeaning::Sw:
500 {
501 (*this)[waterSwitchIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx));
502 break;
503 }
505 {
506 const auto& rvw = BlackOil::getRvw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
507 (*this)[waterSwitchIdx] = rvw;
508 break;
509 }
511 {
512 const auto& Rsw = BlackOil::getRsw_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
513 (*this)[waterSwitchIdx] = Rsw;
514 break;
515 }
517 {
518 break;
519 }
520 default:
521 throw std::logic_error("No valid primary variable selected for water");
522 }
523 switch(primaryVarsMeaningGas()) {
524 case GasMeaning::Sg:
525 {
526 (*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx));
527 break;
528 }
529 case GasMeaning::Rs:
530 {
531 const auto& rs = BlackOil::getRs_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
532 (*this)[compositionSwitchIdx] = rs;
533 break;
534 }
535 case GasMeaning::Rv:
536 {
537 const auto& rv = BlackOil::getRv_<FluidSystem, FluidState, Scalar>(fluidState, pvtRegionIdx_);
538 (*this)[compositionSwitchIdx] = rv;
539 break;
540 }
542 {
543 break;
544 }
545 default:
546 throw std::logic_error("No valid primary variable selected for composision");
547 }
548 }
549
561 bool adaptPrimaryVariables(const Problem& problem,
562 unsigned globalDofIdx,
563 [[maybe_unused]] Scalar swMaximum,
564 Scalar thresholdWaterFilledCell, Scalar eps = 0.0)
565 {
566 // this function accesses quite a few black-oil specific low-level functions
567 // directly for better performance (instead of going the canonical way through
568 // the IntensiveQuantities). The reason is that most intensive quantities are not
569 // required to be able to decide if the primary variables needs to be switched or
570 // not, so it would be a waste to compute them.
571
572 // Both the primary variable meaning of water and gas are disabled i.e.
573 // It is a one-phase case and we no variable meaning switch is needed.
575 return false;
576 }
577
578 // Read the current saturation from the primary variables
579 Scalar sw = 0.0;
580 Scalar sg = 0.0;
581 Scalar saltConcentration = 0.0;
582 const Scalar& T = asImp_().temperature_(problem, globalDofIdx);
584 sw = (*this)[waterSwitchIdx];
586 sg = (*this)[compositionSwitchIdx];
587
588 if (primaryVarsMeaningGas() == GasMeaning::Disabled && gasEnabled)
589 sg = 1.0 - sw; // water + gas case
590
591 // if solid phase disappeares: Sp (Solid salt saturation) -> Cs (salt concentration)
592 // if solid phase appears: Cs (salt concentration) -> Sp (Solid salt saturation)
593 if constexpr (enableSaltPrecipitation) {
594 Scalar saltSolubility = BrineModule::saltSol(pvtRegionIndex());
596 saltConcentration = saltSolubility;
597 Scalar saltSat = (*this)[saltConcentrationIdx];
598 if (saltSat < -eps){ //precipitated salt dissappears
600 (*this)[saltConcentrationIdx] = saltSolubility; //set salt concentration to solubility limit
601 }
602 }
604 saltConcentration = (*this)[saltConcentrationIdx];
605 if (saltConcentration > saltSolubility + eps){ //salt concentration exceeds solubility limit
607 (*this)[saltConcentrationIdx] = 0.0;
608 }
609 }
610 }
611
612 // if solvent saturation disappeares: Ss (Solvent saturation) -> Rsolw (solvent dissolved in water)
613 // if solvent saturation appears: Rsolw (solvent dissolved in water) -> Ss (Solvent saturation)
614 // Scalar rsolw = 0.0; // not needed at the moment since we dont allow for vapwat in combination with rsolw
615 if constexpr (enableSolvent) {
617 Scalar p = (*this)[pressureSwitchIdx]; // cap-pressure?
618 Scalar solLimit = SolventModule::solubilityLimit(pvtRegionIndex(), T , p, saltConcentration);
620 Scalar solSat = (*this)[solventSaturationIdx];
621 if (solSat < -eps){ //solvent dissappears
623 (*this)[solventSaturationIdx] = solLimit; //set rsolw to solubility limit
624
625 }
626 }
628 Scalar rsolw = (*this)[solventSaturationIdx];
629 if (rsolw > solLimit + eps){ //solvent appears as phase
631 (*this)[solventSaturationIdx] = 0.0;
632 }
633 }
634 }
635 }
636
637 // keep track if any meaning has changed
638 bool changed = false;
639
640 // Special case for cells with almost only water
641 // for these cells both saturations (if the phase is enabled) is used
642 // to avoid singular systems.
643 // If dissolved gas in water is enabled we shouldn't enter
644 // here but instead switch to Rsw as primary variable
645 // as sw >= 1.0 -> gas <= 0 (i.e. gas phase disappears)
646 if (sw >= thresholdWaterFilledCell && !FluidSystem::enableDissolvedGasInWater()) {
647
648 // make sure water saturations does not exceed sw_maximum. Default to 1.0
649 if constexpr (waterEnabled) {
650 (*this)[Indices::waterSwitchIdx] = std::min(swMaximum, sw);
652 }
653 // the hydrocarbon gas saturation is set to 0.0
654 if constexpr (compositionSwitchEnabled)
655 (*this)[Indices::compositionSwitchIdx] = 0.0;
656
658 if(changed) {
659 if constexpr (compositionSwitchEnabled)
661
662 // use water pressure?
663 }
664 return changed;
665 }
666
668 unsigned satnumRegionIdx = problem.satnumRegionIndex(globalDofIdx);
669 Scalar Sp = saltConcentration_();
670 Scalar porosityFactor = min(1.0 - Sp, 1.0); //phi/phi_0
671 const auto& pcfactTable = BrineModule::pcfactTable(satnumRegionIdx);
672 pcFactor_ = pcfactTable.eval(porosityFactor, /*extrapolation=*/true);
673 }
674 else {
675 pcFactor_ = 1.0;
676 }
677
678 switch(primaryVarsMeaningWater()) {
679 case WaterMeaning::Sw:
680 {
681 // if water phase disappeares: Sw (water saturation) -> Rvw (fraction of water in gas phase)
682 if(sw < -eps && sg > eps && FluidSystem::enableVaporizedWater()) {
683 Scalar p = this->pressure_();
685 std::array<Scalar, numPhases> pC = { 0.0 };
686 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
687 Scalar so = 1.0 - sg - solventSaturation_();
688 computeCapillaryPressures_(pC, so, sg + solventSaturation_(), /*sw=*/ 0.0, matParams);
689 p += pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
690 }
691 Scalar rvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
692 T,
693 p,
694 saltConcentration);
696 (*this)[Indices::waterSwitchIdx] = rvwSat; //primary variable becomes Rvw
697 changed = true;
698 break;
699 }
700 // if gas phase disappeares: Sw (water saturation) -> Rsw (fraction of gas in water phase)
701 // and Pg (gas pressure) -> Pw ( water pressure)
702 if(sg < -eps && sw > eps && FluidSystem::enableDissolvedGasInWater()) {
703 const Scalar pg = this->pressure_();
705 std::array<Scalar, numPhases> pC = { 0.0 };
706 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
707 Scalar so = 1.0 - sw - solventSaturation_();
708 computeCapillaryPressures_(pC, so, /*sg=*/ 0.0, sw, matParams);
709 Scalar pw = pg + pcFactor_ * (pC[waterPhaseIdx] - pC[gasPhaseIdx]);
710 Scalar rswSat = FluidSystem::waterPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
711 T,
712 pw,
713 saltConcentration);
715 (*this)[Indices::waterSwitchIdx] = rswSat; //primary variable becomes Rsw
717 this->setScaledPressure_(pw);
718 changed = true;
719 break;
720 }
721 break;
722 }
724 {
725 const Scalar& rvw = (*this)[waterSwitchIdx];
726 Scalar p = this->pressure_();
728 std::array<Scalar, numPhases> pC = { 0.0 };
729 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
730 Scalar so = 1.0 - sg - solventSaturation_();
731 computeCapillaryPressures_(pC, so, sg + solventSaturation_(), /*sw=*/ 0.0, matParams);
732 p += pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
733 }
734 Scalar rvwSat = FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_,
735 T,
736 p,
737 saltConcentration);
738 // if water phase appears: Rvw (fraction of water in gas phase) -> Sw (water saturation)
739 if (rvw > rvwSat*(1.0 + eps)) {
741 (*this)[Indices::waterSwitchIdx] = 0.0; // water saturation
742 changed = true;
743 }
744 break;
745 }
747 {
748 // Gas phase not present. The hydrocarbon gas phase
749 // appears as soon as more of the gas component is present in the water phase
750 // than what saturated water can hold.
751 const Scalar& pw = this->pressure_();
753 Scalar rswSat = FluidSystem::waterPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
754 T,
755 pw,
756 saltConcentration);
757
758 Scalar rsw = (*this)[Indices::waterSwitchIdx];
759 if (rsw > rswSat) {
760 // the gas phase appears, i.e., switch the primary variables to WaterMeaning::Sw
762 (*this)[Indices::waterSwitchIdx] = 1.0; // hydrocarbon water saturation
764 std::array<Scalar, numPhases> pC = { 0.0 };
765 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
766 computeCapillaryPressures_(pC, /*so=*/ 0.0, /*sg=*/ 0.0, /*sw=*/ 1.0, matParams);
767 Scalar pg = pw + pcFactor_ * (pC[gasPhaseIdx] - pC[waterPhaseIdx]);
768 this->setScaledPressure_(pg);
769 changed = true;
770 }
771 break;
772 }
774 {
775 break;
776 }
777 default:
778 throw std::logic_error("No valid primary variable selected for water");
779 }
780
781
782 // if gas phase disappeares: Sg (gas saturation) -> Rs (fraction of gas in oil phase)
783 // if oil phase disappeares: Sg (gas saturation) -> Rv (fraction of oil in gas phase)
784 // Po (oil pressure ) -> Pg (gas pressure)
785
786 // if gas phase appears: Rs (fraction of gas in oil phase) -> Sg (gas saturation)
787 // if oil phase appears: Rv (fraction of oil in gas phase) -> Sg (gas saturation)
788 // Pg (gas pressure ) -> Po (oil pressure)
789 switch(primaryVarsMeaningGas()) {
790 case GasMeaning::Sg:
791 {
792 Scalar s = 1.0 - sw - solventSaturation_();
793 if (sg < -eps && s > 0.0 && FluidSystem::enableDissolvedGas()) {
794 const Scalar po = this->pressure_();
796 Scalar soMax = std::max(s, problem.maxOilSaturation(globalDofIdx));
797 Scalar rsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
798 Scalar rsSat = enableExtbo ? ExtboModule::rs(pvtRegionIndex(),
799 po,
800 zFraction_())
801 : FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
802 T,
803 po,
804 s,
805 soMax);
806 (*this)[Indices::compositionSwitchIdx] = std::min(rsMax, rsSat);
807 changed = true;
808 }
809 Scalar so = 1.0 - sw - solventSaturation_() - sg;
810 if (so < -eps && sg > 0.0 && FluidSystem::enableVaporizedOil()) {
811 // the oil phase disappeared and some hydrocarbon gas phase is still
812 // present, i.e., switch the primary variables to GasMeaning::Rv.
813 // we only have the oil pressure readily available, but we need the gas
814 // pressure, i.e. we must determine capillary pressure
815 const Scalar po = this->pressure_();
816 std::array<Scalar, numPhases> pC = { 0.0 };
817 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
818 computeCapillaryPressures_(pC, /*so=*/0.0, sg + solventSaturation_(), sw, matParams);
819 Scalar pg = po + pcFactor_ * (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
820
821 // we start at the GasMeaning::Rv value that corresponds to that of oil-saturated
822 // hydrocarbon gas
824 this->setScaledPressure_(pg);
825 Scalar soMax = problem.maxOilSaturation(globalDofIdx);
826 Scalar rvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
827 Scalar rvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
828 pg,
829 zFraction_())
830 : FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
831 T,
832 pg,
833 Scalar(0),
834 soMax);
836 (*this)[Indices::compositionSwitchIdx] = std::min(rvMax, rvSat);
837 changed = true;
838 }
839 break;
840 }
841 case GasMeaning::Rs:
842 {
843 // Gas phase not present. The hydrocarbon gas phase
844 // appears as soon as more of the gas component is present in the oil phase
845 // than what saturated oil can hold.
846 const Scalar po = this->pressure_();
847 Scalar so = 1.0 - sw - solventSaturation_();
848 Scalar soMax = std::max(so, problem.maxOilSaturation(globalDofIdx));
849 Scalar rsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx);
850 Scalar rsSat = enableExtbo ? ExtboModule::rs(pvtRegionIndex(),
851 po,
852 zFraction_())
853 : FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_,
854 T,
855 po,
856 so,
857 soMax);
858
859 Scalar rs = (*this)[Indices::compositionSwitchIdx];
860 if (rs > std::min(rsMax, rsSat*(1.0 + eps))) {
861 // the gas phase appears, i.e., switch the primary variables to GasMeaning::Sg
863 (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation
864 changed = true;
865 }
866 break;
867 }
868 case GasMeaning::Rv:
869 {
870 // The oil phase appears as
871 // soon as more of the oil component is present in the hydrocarbon gas phase
872 // than what saturated gas contains. Note that we use the blackoil specific
873 // low-level PVT objects here for performance reasons.
874 const Scalar pg = this->pressure_();
875 Scalar soMax = problem.maxOilSaturation(globalDofIdx);
876 Scalar rvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx);
877 Scalar rvSat = enableExtbo ? ExtboModule::rv(pvtRegionIndex(),
878 pg,
879 zFraction_())
880 : FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_,
881 T,
882 pg,
883 /*so=*/Scalar(0.0),
884 soMax);
885
886 Scalar rv = (*this)[Indices::compositionSwitchIdx];
887 if (rv > std::min(rvMax, rvSat*(1.0 + eps))) {
888 // switch to phase equilibrium mode because the oil phase appears. here
889 // we also need the capillary pressures to calculate the oil phase
890 // pressure using the gas phase pressure
891 Scalar sg2 = 1.0 - sw - solventSaturation_();
892 std::array<Scalar, numPhases> pC = { 0.0 };
893 const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx);
894 computeCapillaryPressures_(pC,
895 /*so=*/0.0,
896 /*sg=*/sg2 + solventSaturation_(),
897 sw,
898 matParams);
899 Scalar po = pg + pcFactor_ * (pC[oilPhaseIdx] - pC[gasPhaseIdx]);
900
903 this->setScaledPressure_(po);
904 (*this)[Indices::compositionSwitchIdx] = sg2; // hydrocarbon gas saturation
905 changed = true;
906 }
907 break;
908 }
910 {
911 break;
912 }
913 default:
914 throw std::logic_error("No valid primary variable selected for water");
915 }
916 return changed;
917 }
918
922 return false;
923 }
924 Scalar sw = 0.0;
926 sw = (*this)[Indices::waterSwitchIdx];
927 Scalar sg = 0.0;
929 sg = (*this)[Indices::compositionSwitchIdx];
930
931 Scalar ssol = 0.0;
933 ssol =(*this) [Indices::solventSaturationIdx];
934
935 Scalar so = 1.0 - sw - sg - ssol;
936 sw = std::min(std::max(sw,0.0),1.0);
937 so = std::min(std::max(so,0.0),1.0);
938 sg = std::min(std::max(sg,0.0),1.0);
939 ssol = std::min(std::max(ssol,0.0),1.0);
940 Scalar st = sw + so + sg + ssol;
941 sw = sw/st;
942 sg = sg/st;
943 ssol = ssol/st;
944 assert(st>0.5);
946 (*this)[Indices::waterSwitchIdx] = sw;
948 (*this)[Indices::compositionSwitchIdx] = sg;
950 (*this) [Indices::solventSaturationIdx] = ssol;
951
952 return !(st==1);
953 }
954
957 {
958 for (unsigned i = 0; i < numEq; ++i)
959 (*this)[i] = value;
960
961 return *this;
962 }
963
971 void checkDefined() const
972 {
973#ifndef NDEBUG
974 // check the "real" primary variables
975 for (unsigned i = 0; i < this->size(); ++i)
976 Valgrind::CheckDefined((*this)[i]);
977
978 // check the "pseudo" primary variables
979 Valgrind::CheckDefined(primaryVarsMeaningWater_);
980 Valgrind::CheckDefined(primaryVarsMeaningGas_);
981 Valgrind::CheckDefined(primaryVarsMeaningPressure_);
982 Valgrind::CheckDefined(primaryVarsMeaningBrine_);
983 Valgrind::CheckDefined(primaryVarsMeaningSolvent_);
984
985 Valgrind::CheckDefined(pvtRegionIdx_);
986#endif // NDEBUG
987 }
988
989 template<class Serializer>
990 void serializeOp(Serializer& serializer)
991 {
992 using FV = Dune::FieldVector<double,getPropValue<TypeTag, Properties::NumEq>()>;
993 serializer(static_cast<FV&>(*this));
994 serializer(primaryVarsMeaningWater_);
995 serializer(primaryVarsMeaningPressure_);
996 serializer(primaryVarsMeaningGas_);
997 serializer(primaryVarsMeaningBrine_);
998 serializer(primaryVarsMeaningSolvent_);
999 serializer(pvtRegionIdx_);
1000 }
1001
1003 {
1004 return static_cast<const FvBasePrimaryVariables<TypeTag>&>(*this) == rhs &&
1005 this->primaryVarsMeaningWater_ == rhs.primaryVarsMeaningWater_ &&
1006 this->primaryVarsMeaningPressure_ == rhs.primaryVarsMeaningPressure_ &&
1007 this->primaryVarsMeaningGas_ == rhs.primaryVarsMeaningGas_ &&
1008 this->primaryVarsMeaningBrine_ == rhs.primaryVarsMeaningBrine_ &&
1009 this->primaryVarsMeaningSolvent_ == rhs.primaryVarsMeaningSolvent_ &&
1010 this->pvtRegionIdx_ == rhs.pvtRegionIdx_;
1011 }
1012
1013private:
1014 Implementation& asImp_()
1015 { return *static_cast<Implementation*>(this); }
1016
1017 const Implementation& asImp_() const
1018 { return *static_cast<const Implementation*>(this); }
1019
1020 Scalar solventSaturation_() const
1021 {
1022 if constexpr (enableSolvent) {
1024 return (*this)[Indices::solventSaturationIdx];
1025 }
1026 return 0.0;
1027 }
1028
1029 Scalar zFraction_() const
1030 {
1031 if constexpr (enableExtbo)
1032 return (*this)[Indices::zFractionIdx];
1033 else
1034 return 0.0;
1035 }
1036
1037 Scalar polymerConcentration_() const
1038 {
1039 if constexpr (enablePolymer)
1040 return (*this)[Indices::polymerConcentrationIdx];
1041 else
1042 return 0.0;
1043 }
1044
1045 Scalar foamConcentration_() const
1046 {
1047 if constexpr (enableFoam)
1048 return (*this)[Indices::foamConcentrationIdx];
1049 else
1050 return 0.0;
1051 }
1052
1053 Scalar saltConcentration_() const
1054 {
1055 if constexpr (enableBrine)
1056 return (*this)[Indices::saltConcentrationIdx];
1057 else
1058 return 0.0;
1059 }
1060
1061 Scalar temperature_(const Problem& problem, [[maybe_unused]] unsigned globalDofIdx) const
1062 {
1063 if constexpr (enableEnergy)
1064 return (*this)[Indices::temperatureIdx];
1065 else if constexpr( enableTemperature)
1066 return problem.temperature(globalDofIdx, /*timeIdx*/ 0);
1067
1068 else
1069 return FluidSystem::reservoirTemperature();
1070 }
1071
1072 Scalar microbialConcentration_() const
1073 {
1074 if constexpr (enableMICP)
1075 return (*this)[Indices::microbialConcentrationIdx];
1076 else
1077 return 0.0;
1078 }
1079
1080 Scalar oxygenConcentration_() const
1081 {
1082 if constexpr (enableMICP)
1083 return (*this)[Indices::oxygenConcentrationIdx];
1084 else
1085 return 0.0;
1086 }
1087
1088 Scalar ureaConcentration_() const
1089 {
1090 if constexpr (enableMICP)
1091 return (*this)[Indices::ureaConcentrationIdx];
1092 else
1093 return 0.0;
1094 }
1095
1096 Scalar biofilmConcentration_() const
1097 {
1098 if constexpr (enableMICP)
1099 return (*this)[Indices::biofilmConcentrationIdx];
1100 else
1101 return 0.0;
1102 }
1103
1104 Scalar calciteConcentration_() const
1105 {
1106 if constexpr (enableMICP)
1107 return (*this)[Indices::calciteConcentrationIdx];
1108 else
1109 return 0.0;
1110 }
1111
1112 template <class Container>
1113 void computeCapillaryPressures_(Container& result,
1114 Scalar so,
1115 Scalar sg,
1116 Scalar sw,
1117 const MaterialLawParams& matParams) const
1118 {
1119 using SatOnlyFluidState = SimpleModularFluidState<Scalar,
1120 numPhases,
1121 numComponents,
1122 FluidSystem,
1123 /*storePressure=*/false,
1124 /*storeTemperature=*/false,
1125 /*storeComposition=*/false,
1126 /*storeFugacity=*/false,
1127 /*storeSaturation=*/true,
1128 /*storeDensity=*/false,
1129 /*storeViscosity=*/false,
1130 /*storeEnthalpy=*/false>;
1131 SatOnlyFluidState fluidState;
1132 fluidState.setSaturation(waterPhaseIdx, sw);
1133 fluidState.setSaturation(oilPhaseIdx, so);
1134 fluidState.setSaturation(gasPhaseIdx, sg);
1135
1136 MaterialLaw::capillaryPressures(result, matParams, fluidState);
1137 }
1138
1139 Scalar pressure_() const
1140 {
1141 return (*this)[Indices::pressureSwitchIdx] * this->pressureScale_;
1142 }
1143
1144 void setScaledPressure_(Scalar pressure)
1145 {
1146 (*this)[Indices::pressureSwitchIdx] = pressure / (this->pressureScale_);
1147 }
1148
1149 WaterMeaning primaryVarsMeaningWater_{WaterMeaning::Disabled};
1150 PressureMeaning primaryVarsMeaningPressure_{PressureMeaning::Po};
1151 GasMeaning primaryVarsMeaningGas_{GasMeaning::Disabled};
1152 BrineMeaning primaryVarsMeaningBrine_{BrineMeaning::Disabled};
1153 SolventMeaning primaryVarsMeaningSolvent_{SolventMeaning::Disabled};
1154 unsigned short pvtRegionIdx_;
1155 Scalar pcFactor_;
1156 static inline Scalar pressureScale_ = 1.0;
1157};
1158
1159
1160} // namespace Opm
1161
1162#endif
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,...
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.
Contains the high level supplements required to extend the black oil model by brine.
Definition: blackoilbrinemodules.hh:58
static Scalar saltSol(unsigned regionIdx)
Definition: blackoilbrinemodules.hh:394
static const TabulatedFunction & pcfactTable(unsigned satnumRegionIdx)
Definition: blackoilbrinemodules.hh:342
static bool hasPcfactTables()
Definition: blackoilbrinemodules.hh:386
Contains the high level supplements required to extend the black oil model by energy.
Definition: blackoilenergymodules.hh:52
static void assignPrimaryVars(PrimaryVariables &priVars, Scalar)
Assign the energy specific primary variables to a PrimaryVariables object.
Definition: blackoilenergymodules.hh:247
Contains the high level supplements required to extend the black oil model.
Definition: blackoilextbomodules.hh:69
static Value rs(unsigned pvtRegionIdx, const Value &pressure, const Value &z)
Definition: blackoilextbomodules.hh:518
static Value rv(unsigned pvtRegionIdx, const Value &pressure, const Value &z)
Definition: blackoilextbomodules.hh:523
Contains the high level supplements required to extend the black oil model to include the effects of ...
Definition: blackoilfoammodules.hh:57
Contains the high level supplements required to extend the black oil model by MICP.
Definition: blackoilmicpmodules.hh:56
Contains the high level supplements required to extend the black oil model by polymer.
Definition: blackoilpolymermodules.hh:61
Represents the primary variables used by the black-oil model.
Definition: blackoilprimaryvariables.hh:75
bool operator==(const BlackOilPrimaryVariables &rhs) const
Definition: blackoilprimaryvariables.hh:1002
unsigned pvtRegionIndex() const
Return the index of the region which should be used for PVT properties.
Definition: blackoilprimaryvariables.hh:260
WaterMeaning
Definition: blackoilprimaryvariables.hh:138
BlackOilPrimaryVariables & operator=(const BlackOilPrimaryVariables &other)=default
static void registerParameters()
Definition: blackoilprimaryvariables.hh:218
GasMeaning primaryVarsMeaningGas() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:295
PressureMeaning primaryVarsMeaningPressure() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:281
void serializeOp(Serializer &serializer)
Definition: blackoilprimaryvariables.hh:990
static void init()
Definition: blackoilprimaryvariables.hh:212
void setPrimaryVarsMeaningSolvent(SolventMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:325
BlackOilPrimaryVariables()
Definition: blackoilprimaryvariables.hh:169
static BlackOilPrimaryVariables serializationTestObject()
Definition: blackoilprimaryvariables.hh:196
SolventMeaning primaryVarsMeaningSolvent() const
Definition: blackoilprimaryvariables.hh:317
bool chopAndNormalizeSaturations()
Definition: blackoilprimaryvariables.hh:919
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:561
void setPrimaryVarsMeaningPressure(PressureMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:288
WaterMeaning primaryVarsMeaningWater() const
Return the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:267
PressureMeaning
Definition: blackoilprimaryvariables.hh:145
void setPrimaryVarsMeaningWater(WaterMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:274
void assignNaive(const FluidState &fluidState)
Directly retrieve the primary variables from an arbitrary fluid state.
Definition: blackoilprimaryvariables.hh:410
Evaluation makeEvaluation(unsigned varIdx, unsigned timeIdx, LinearizationType linearizationType=LinearizationType()) const
Definition: blackoilprimaryvariables.hh:230
void assignMassConservative(const FluidState &fluidState, const MaterialLawParams &matParams, bool isInEquilibrium=false)
Set the primary variables from an arbitrary fluid state in a mass conservative way.
Definition: blackoilprimaryvariables.hh:332
BlackOilPrimaryVariables(Scalar value)
Constructor with assignment from scalar.
Definition: blackoilprimaryvariables.hh:179
void setPrimaryVarsMeaningBrine(BrineMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:313
BlackOilPrimaryVariables(const BlackOilPrimaryVariables &value)=default
Copy constructor.
SolventMeaning
Definition: blackoilprimaryvariables.hh:163
BrineMeaning primaryVarsMeaningBrine() const
Definition: blackoilprimaryvariables.hh:305
BlackOilPrimaryVariables & operator=(Scalar value)
Definition: blackoilprimaryvariables.hh:956
GasMeaning
Definition: blackoilprimaryvariables.hh:150
BrineMeaning
Definition: blackoilprimaryvariables.hh:157
void setPressureScale(Scalar val)
Definition: blackoilprimaryvariables.hh:224
void setPrimaryVarsMeaningGas(GasMeaning newMeaning)
Set the interpretation which should be applied to the switching primary variables.
Definition: blackoilprimaryvariables.hh:302
void setPvtRegionIndex(unsigned value)
Set the index of the region which should be used for PVT properties.
Definition: blackoilprimaryvariables.hh:254
void checkDefined() const
Instruct valgrind to check the definedness of all attributes of this class.
Definition: blackoilprimaryvariables.hh:971
Contains the high level supplements required to extend the black oil model by solvents.
Definition: blackoilsolventmodules.hh:68
static bool isSolubleInWater()
Definition: blackoilsolventmodules.hh:747
static const Value solubilityLimit(unsigned pvtIdx, const Value &temperature, const Value &pressure, const Value &saltConcentration)
Definition: blackoilsolventmodules.hh:735
Represents the primary variables used by the a model.
Definition: fvbaseprimaryvariables.hh:52
Definition: blackoilmodel.hh:72
Definition: blackoilboundaryratevector.hh:37
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:242
Definition: linearizationtype.hh:35
Definition: blackoilprimaryvariables.hh:48
static constexpr type value
Definition: blackoilprimaryvariables.hh:50
GetPropType< TypeTag, Scalar > type
Definition: blackoilprimaryvariables.hh:49