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