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