opm-common
BrineCo2Pvt.hpp
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 */
27 #ifndef OPM_BRINE_CO2_PVT_HPP
28 #define OPM_BRINE_CO2_PVT_HPP
29 
31 #include <opm/common/TimingMacros.hpp>
32 #include <opm/common/ErrorMacros.hpp>
33 #include <opm/common/utility/gpuDecorators.hpp>
35 #include <opm/common/utility/VectorWithDefaultAllocator.hpp>
36 
38 
44 #include <opm/material/components/CO2Tables.hpp>
48 
49 #include <opm/input/eclipse/EclipseState/Co2StoreConfig.hpp>
50 
51 #include <cstddef>
52 #include <vector>
53 
54 namespace Opm {
55 
56 class EclipseState;
57 class Schedule;
58 class Co2StoreConfig;
59 class EzrokhiTable;
60 
61 // forward declaration of the class so the function in the next namespace can be declared
62 template <class Scalar, template <class> class Storage>
64 
65 #if HAVE_CUDA
66 // declaration of make_view in correct namespace so friend function can be declared in the class
67 namespace gpuistl {
68  template <class ScalarT>
71 }
72 #endif
73 
78 template <class Scalar, template <class> class Storage = Opm::VectorWithDefaultAllocator>
79 class BrineCo2Pvt
80 {
81  using Params = Opm::CO2Tables<double, Storage>;
82  using ContainerT = Storage<Scalar>;
83  static constexpr bool extrapolate = true;
84  //typedef H2O<Scalar> H2O_IAPWS;
85  //typedef Brine<Scalar, H2O_IAPWS> Brine_IAPWS;
86  //typedef TabulatedComponent<Scalar, H2O_IAPWS> H2O_Tabulated;
87  //typedef TabulatedComponent<Scalar, Brine_IAPWS> Brine_Tabulated;
88 
89  //typedef H2O_Tabulated H2O;
90  //typedef Brine_Tabulated Brine;
91 
92 
93 public:
97 
100 
101  BrineCo2Pvt() = default;
102 
103  explicit BrineCo2Pvt(const ContainerT& salinity,
104  int activityModel = 3,
105  int thermalMixingModelSalt = 1,
106  int thermalMixingModelLiquid = 2,
107  Scalar T_ref = 288.71, //(273.15 + 15.56)
108  Scalar P_ref = 101325);
109 
110  BrineCo2Pvt(const ContainerT& brineReferenceDensity,
111  const ContainerT& co2ReferenceDensity,
112  const ContainerT& salinity,
113  int activityModel,
114  Co2StoreConfig::SaltMixingType thermalMixingModelSalt,
115  Co2StoreConfig::LiquidMixingType thermalMixingModelLiquid,
116  Params params)
117  : brineReferenceDensity_(brineReferenceDensity)
118  , co2ReferenceDensity_(co2ReferenceDensity)
119  , salinity_(salinity)
120  , activityModel_(activityModel)
121  , liquidMixType_(thermalMixingModelLiquid)
122  , saltMixType_(thermalMixingModelSalt)
123  , co2Tables_(params)
124 {
125 }
126 
131  void initFromState(const EclipseState& eclState, const Schedule&);
132 
133  void setNumRegions(std::size_t numRegions);
134 
135  void setVapPars(const Scalar, const Scalar)
136  {
137  }
138 
139 
140  OPM_HOST_DEVICE static constexpr bool isActive()
141  {
142  return true;
143  }
144 
148  void setReferenceDensities(unsigned regionIdx,
149  Scalar rhoRefBrine,
150  Scalar rhoRefCO2,
151  Scalar /*rhoRefWater*/);
152 
156  void initEnd()
157  {
158  }
159 
166  void setEnableDissolvedGas(bool yesno)
167  { enableDissolution_ = yesno; }
168 
175  void setEnableSaltConcentration(bool yesno)
176  { enableSaltConcentration_ = yesno; }
177 
181  void setActivityModelSalt(int activityModel);
182 
186  void setThermalMixingModel(int thermalMixingModelSalt, int thermalMixingModelLiquid);
187 
188  void setEzrokhiDenCoeff(const std::vector<EzrokhiTable>& denaqa);
189 
190  void setEzrokhiViscCoeff(const std::vector<EzrokhiTable>& viscaqa);
191 
195  unsigned numRegions() const
196  { return brineReferenceDensity_.size(); }
197 
198  OPM_HOST_DEVICE Scalar hVap(unsigned ) const{
199  return 0;
200  }
201 
205  OPM_HOST_DEVICE static constexpr bool mixingEnergy()
206  { return false; }
207 
211  template <class Evaluation>
212  OPM_HOST_DEVICE Evaluation internalEnergy(unsigned regionIdx,
213  const Evaluation& temperature,
214  const Evaluation& pressure,
215  const Evaluation& Rs,
216  const Evaluation& saltConcentration) const
217  {
218  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
219  const Evaluation salinity = salinityFromConcentration(regionIdx, temperature, pressure, saltConcentration);
220  const Evaluation xlCO2 = convertRsToXoG_(Rs,regionIdx);
221  return (liquidEnthalpyBrineCO2_(temperature,
222  pressure,
223  salinity,
224  xlCO2)
225  - pressure / density(regionIdx, temperature, pressure, Rs, salinity ));
226  }
230  template <class Evaluation>
231  OPM_HOST_DEVICE Evaluation internalEnergy(unsigned regionIdx,
232  const Evaluation& temperature,
233  const Evaluation& pressure,
234  const Evaluation& Rs) const
235  {
236  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
237  const Evaluation xlCO2 = convertRsToXoG_(Rs,regionIdx);
238  return (liquidEnthalpyBrineCO2_(temperature,
239  pressure,
240  Evaluation(salinity_[regionIdx]),
241  xlCO2)
242  - pressure / density(regionIdx, temperature, pressure, Rs, Evaluation(salinity_[regionIdx])));
243  }
244 
248  template <class Evaluation>
249  OPM_HOST_DEVICE Evaluation viscosity(unsigned regionIdx,
250  const Evaluation& temperature,
251  const Evaluation& pressure,
252  const Evaluation& /*Rs*/) const
253  {
254  //TODO: The viscosity does not yet depend on the composition
255  return saturatedViscosity(regionIdx, temperature, pressure);
256  }
257 
261  template <class Evaluation>
262  OPM_HOST_DEVICE Evaluation saturatedViscosity(unsigned regionIdx,
263  const Evaluation& temperature,
264  const Evaluation& pressure,
265  const Evaluation& saltConcentration) const
266  {
267  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
268  const Evaluation salinity = salinityFromConcentration(regionIdx, temperature, pressure, saltConcentration);
269  if (enableEzrokhiViscosity_) {
270  const Evaluation& mu_pure = H2O::liquidViscosity(temperature, pressure, extrapolate);
271  const Evaluation& nacl_exponent = ezrokhiExponent_(temperature, ezrokhiViscNaClCoeff_);
272  return mu_pure * pow(10.0, nacl_exponent * salinity);
273  }
274  else {
275  return Brine::liquidViscosity(temperature, pressure, salinity);
276  }
277  }
278 
282  template <class Evaluation>
283  OPM_HOST_DEVICE Evaluation viscosity(unsigned regionIdx,
284  const Evaluation& temperature,
285  const Evaluation& pressure,
286  const Evaluation& /*Rsw*/,
287  const Evaluation& saltConcentration) const
288  {
289  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
290  //TODO: The viscosity does not yet depend on the composition
291  return saturatedViscosity(regionIdx, temperature, pressure, saltConcentration);
292  }
293 
297  template <class Evaluation>
298  OPM_HOST_DEVICE Evaluation saturatedViscosity(unsigned regionIdx,
299  const Evaluation& temperature,
300  const Evaluation& pressure) const
301  {
302  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
303  if (enableEzrokhiViscosity_) {
304  const Evaluation& mu_pure = H2O::liquidViscosity(temperature, pressure, extrapolate);
305  const Evaluation& nacl_exponent = ezrokhiExponent_(temperature, ezrokhiViscNaClCoeff_);
306  return mu_pure * pow(10.0, nacl_exponent * Evaluation(salinity_[regionIdx]));
307  }
308  else {
309  return Brine::liquidViscosity(temperature, pressure, Evaluation(salinity_[regionIdx]));
310  }
311 
312  }
313 
314 
318  template <class Evaluation>
319  OPM_HOST_DEVICE Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx,
320  const Evaluation& temperature,
321  const Evaluation& pressure,
322  const Evaluation& saltconcentration) const
323  {
324  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
325  const Evaluation salinity = salinityFromConcentration(regionIdx, temperature,
326  pressure, saltconcentration);
327  Evaluation rs_sat = rsSat(regionIdx, temperature, pressure, salinity);
328  return (1.0 - convertRsToXoG_(rs_sat,regionIdx)) * density(regionIdx, temperature,
329  pressure, rs_sat, salinity)
330  / brineReferenceDensity_[regionIdx];
331  }
335  template <class Evaluation>
336  OPM_HOST_DEVICE Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
337  const Evaluation& temperature,
338  const Evaluation& pressure,
339  const Evaluation& Rs,
340  const Evaluation& saltConcentration) const
341  {
342  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
343  const Evaluation salinity = salinityFromConcentration(regionIdx, temperature,
344  pressure, saltConcentration);
345  return (1.0 - convertRsToXoG_(Rs,regionIdx)) * density(regionIdx, temperature,
346  pressure, Rs, salinity)
347  / brineReferenceDensity_[regionIdx];
348  }
352  template <class Evaluation>
353  OPM_HOST_DEVICE Evaluation inverseFormationVolumeFactor(unsigned regionIdx,
354  const Evaluation& temperature,
355  const Evaluation& pressure,
356  const Evaluation& Rs) const
357  {
358  return (1.0 - convertRsToXoG_(Rs,regionIdx)) * density(regionIdx, temperature, pressure,
359  Rs, Evaluation(salinity_[regionIdx]))
360  / brineReferenceDensity_[regionIdx];
361  }
362 
366  template <class FluidState, class LhsEval = typename FluidState::ValueType>
367  std::pair<LhsEval, LhsEval>
368  OPM_HOST_DEVICE inverseFormationVolumeFactorAndViscosity(const FluidState& fluidState, unsigned regionIdx) const
369  {
370  // Deal with the possibility that we are in a two-phase CO2STORE with OIL and GAS as phases.
371  const bool waterIsActive = fluidState.phaseIsActive(FluidState::waterPhaseIdx);
372  const int myPhaseIdx = waterIsActive ? FluidState::waterPhaseIdx : FluidState::oilPhaseIdx;
373  const LhsEval& Rsw = waterIsActive ? decay<LhsEval>(fluidState.Rsw()) : decay<LhsEval>(fluidState.Rs());
374 
375  const LhsEval& T = decay<LhsEval>(fluidState.temperature(myPhaseIdx));
376  const LhsEval& p = decay<LhsEval>(fluidState.pressure(myPhaseIdx));
377  const LhsEval& saltConcentration
378  = BlackOil::template getSaltConcentration_<FluidState, LhsEval>(fluidState, regionIdx);
379  // TODO: The viscosity does not yet depend on the composition
380  return { this->inverseFormationVolumeFactor(regionIdx, T, p, Rsw, saltConcentration) ,
381  this->saturatedViscosity(regionIdx, T, p, saltConcentration) };
382  }
383 
387  template <class Evaluation>
388  OPM_HOST_DEVICE Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx,
389  const Evaluation& temperature,
390  const Evaluation& pressure) const
391  {
392  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
393  Evaluation rs_sat = rsSat(regionIdx, temperature, pressure, Evaluation(salinity_[regionIdx]));
394  return (1.0 - convertRsToXoG_(rs_sat,regionIdx)) * density(regionIdx, temperature, pressure,
395  rs_sat, Evaluation(salinity_[regionIdx]))
396  / brineReferenceDensity_[regionIdx];
397  }
398 
405  template <class Evaluation>
406  OPM_HOST_DEVICE Evaluation saturationPressure(unsigned /*regionIdx*/,
407  const Evaluation& /*temperature*/,
408  const Evaluation& /*Rs*/) const
409  {
410 #if OPM_IS_INSIDE_DEVICE_FUNCTION
411  assert(false && "Requested the saturation pressure for the brine-co2 pvt module. Not yet implemented.");
412  return {}; // unreachable
413 #else
414  throw std::runtime_error("Requested the saturation pressure for the brine-co2 pvt module. "
415  "Not yet implemented.");
416 #endif
417  }
418 
425  template <class Evaluation>
426  OPM_HOST_DEVICE Evaluation saturationPressure(unsigned /*regionIdx*/,
427  const Evaluation& /*temperature*/,
428  const Evaluation& /*Rs*/,
429  const Evaluation& /*saltConcentration*/) const
430  {
431 #if OPM_IS_INSIDE_DEVICE_FUNCTION
432  assert(false && "Requested the saturation pressure for the brine-co2 pvt module. Not yet implemented.");
433  return {}; // unreachable
434 #else
435  throw std::runtime_error("Requested the saturation pressure for the brine-co2 pvt module. "
436  "Not yet implemented.");
437 #endif
438  }
439 
443  template <class Evaluation>
444  OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx,
445  const Evaluation& temperature,
446  const Evaluation& pressure,
447  const Evaluation& /*oilSaturation*/,
448  const Evaluation& /*maxOilSaturation*/) const
449  {
450  //TODO support VAPPARS
451  return rsSat(regionIdx, temperature, pressure, Evaluation(salinity_[regionIdx]));
452  }
453 
457  template <class Evaluation>
458  OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx,
459  const Evaluation& temperature,
460  const Evaluation& pressure,
461  const Evaluation& saltConcentration) const
462  {
463  const Evaluation salinity = salinityFromConcentration(regionIdx, temperature,
464  pressure, saltConcentration);
465  return rsSat(regionIdx, temperature, pressure, salinity);
466  }
467 
471  template <class Evaluation>
472  OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx,
473  const Evaluation& temperature,
474  const Evaluation& pressure) const
475  {
476  return rsSat(regionIdx, temperature, pressure, Evaluation(salinity_[regionIdx]));
477  }
478 
479  OPM_HOST_DEVICE Scalar oilReferenceDensity(unsigned regionIdx) const
480  { return brineReferenceDensity_[regionIdx]; }
481 
482  OPM_HOST_DEVICE Scalar waterReferenceDensity(unsigned regionIdx) const
483  { return brineReferenceDensity_[regionIdx]; }
484 
485  OPM_HOST_DEVICE Scalar gasReferenceDensity(unsigned regionIdx) const
486  { return co2ReferenceDensity_[regionIdx]; }
487 
488  OPM_HOST_DEVICE Scalar salinity(unsigned regionIdx) const
489  { return salinity_[regionIdx]; }
490 
491  OPM_HOST_DEVICE const ContainerT& getBrineReferenceDensity() const
492  { return brineReferenceDensity_; }
493 
494  OPM_HOST_DEVICE const ContainerT& getCo2ReferenceDensity() const
495  { return co2ReferenceDensity_; }
496 
497  OPM_HOST_DEVICE const ContainerT& getSalinity() const
498  { return salinity_; }
499 
500  OPM_HOST_DEVICE const Params& getParams() const
501  { return co2Tables_; }
502 
503  OPM_HOST_DEVICE Co2StoreConfig::SaltMixingType getThermalMixingModelSalt() const
504  { return saltMixType_; }
505 
506  OPM_HOST_DEVICE Co2StoreConfig::LiquidMixingType getThermalMixingModelLiquid() const
507  { return liquidMixType_; }
508 
509  OPM_HOST_DEVICE int getActivityModel() const
510  { return activityModel_; }
511 
512  template <class Evaluation>
513  OPM_HOST_DEVICE Evaluation diffusionCoefficient(const Evaluation& temperature,
514  const Evaluation& pressure,
515  unsigned /*compIdx*/,
516  unsigned regionIdx = 0) const
517  {
518  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
519  // Diffusion coefficient of CO2 in pure water according to
520  // (McLachlan and Danckwerts, 1972)
521  const Evaluation log_D_H20 = -4.1764 + 712.52 / temperature
522  -2.5907e5 / (temperature * temperature);
523 
524  // Diffusion coefficient of CO2 in the brine phase modified following
525  // (Ratcliff and Holdcroft,1963 and Al-Rawajfeh, 2004)
526 
527  // Water viscosity
528  const Evaluation& mu_H20 = H2O::liquidViscosity(temperature, pressure, extrapolate);
529  Evaluation mu_Brine;
530  if (enableEzrokhiViscosity_) {
531  const Evaluation& nacl_exponent = ezrokhiExponent_(temperature,
532  ezrokhiViscNaClCoeff_);
533  mu_Brine = mu_H20 * pow(10.0, nacl_exponent * Evaluation(salinity_[regionIdx]));
534  }
535  else {
536  // Brine viscosity
537  mu_Brine = Brine::liquidViscosity(temperature, pressure, Evaluation(salinity_[regionIdx]));
538  }
539  const Evaluation log_D_Brine = log_D_H20 - 0.87*log10(mu_Brine / mu_H20);
540 
541  return pow(Evaluation(10), log_D_Brine) * 1e-4; // convert from cm2/s to m2/s
542  }
543 
544  template <class Evaluation>
545  OPM_HOST_DEVICE Evaluation density(unsigned regionIdx,
546  const Evaluation& temperature,
547  const Evaluation& pressure,
548  const Evaluation& Rs,
549  const Evaluation& salinity) const
550  {
551  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
552  Evaluation xlCO2 = convertXoGToxoG_(convertRsToXoG_(Rs,regionIdx), salinity);
553  Evaluation result = liquidDensity_(temperature,
554  pressure,
555  xlCO2,
556  salinity);
557 
558  Valgrind::CheckDefined(result);
559  return result;
560  }
561 
562  template <class Evaluation>
563  OPM_HOST_DEVICE Evaluation rsSat(unsigned regionIdx,
564  const Evaluation& temperature,
565  const Evaluation& pressure,
566  const Evaluation& salinity) const
567  {
568  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
569  if (!enableDissolution_) {
570  return 0.0;
571  }
572 
573  // calulate the equilibrium composition for the given
574  // temperature and pressure.
575  Evaluation xgH2O;
576  Evaluation xlCO2;
578  temperature,
579  pressure,
580  salinity,
581  /*knownPhaseIdx=*/-1,
582  xlCO2,
583  xgH2O,
584  activityModel_,
585  extrapolate);
586 
587  // normalize the phase compositions
588  xlCO2 = max(0.0, min(1.0, xlCO2));
589 
590  return convertXoGToRs(convertxoGToXoG(xlCO2, salinity), regionIdx);
591  }
592 
593 private:
594  template <class LhsEval>
595  OPM_HOST_DEVICE LhsEval ezrokhiExponent_(const LhsEval& temperature,
596  const ContainerT& ezrokhiCoeff) const
597  {
598  const LhsEval& tempC = temperature - 273.15;
599  return ezrokhiCoeff[0] + tempC * (ezrokhiCoeff[1] + ezrokhiCoeff[2] * tempC);
600  }
601 
602  template <class LhsEval>
603  OPM_HOST_DEVICE LhsEval liquidDensity_(const LhsEval& T,
604  const LhsEval& pl,
605  const LhsEval& xlCO2,
606  const LhsEval& salinity) const
607  {
608  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
609  Valgrind::CheckDefined(T);
610  Valgrind::CheckDefined(pl);
611  Valgrind::CheckDefined(xlCO2);
612 
613  if (!extrapolate && T < 273.15) {
614 #if OPM_IS_INSIDE_DEVICE_FUNCTION
615  assert(false && "Liquid density for Brine and CO2 is only defined above 273.15K");
616 #else
617  const std::string msg =
618  "Liquid density for Brine and CO2 is only "
619  "defined above 273.15K (is " +
620  std::to_string(getValue(T)) + "K)";
621  throw NumericalProblem(msg);
622 #endif
623  }
624  if (!extrapolate && pl >= 2.5e8) {
625 #if OPM_IS_INSIDE_DEVICE_FUNCTION
626  assert(false && "Liquid density for Brine and CO2 is only defined below 250MPa");
627 #else
628  const std::string msg =
629  "Liquid density for Brine and CO2 is only "
630  "defined below 250MPa (is " +
631  std::to_string(getValue(pl)) + "Pa)";
632  throw NumericalProblem(msg);
633 #endif
634  }
635 
636  const LhsEval& rho_pure = H2O::liquidDensity(T, pl, extrapolate);
637  if (enableEzrokhiDensity_) {
638  const LhsEval& nacl_exponent = ezrokhiExponent_(T, ezrokhiDenNaClCoeff_);
639  const LhsEval& co2_exponent = ezrokhiExponent_(T, ezrokhiDenCo2Coeff_);
640  const LhsEval& XCO2 = convertxoGToXoG(xlCO2, salinity);
641  return rho_pure * pow(10.0, nacl_exponent * salinity + co2_exponent * XCO2);
642  }
643  else {
644  const LhsEval& rho_brine = Brine::liquidDensity(T, pl, salinity, rho_pure);
645  const LhsEval& rho_lCO2 = liquidDensityWaterCO2_(T, xlCO2, rho_pure);
646  const LhsEval& contribCO2 = rho_lCO2 - rho_pure;
647  return rho_brine + contribCO2;
648  }
649  }
650 
651  template <class LhsEval>
652  OPM_HOST_DEVICE LhsEval liquidDensityWaterCO2_(const LhsEval& temperature,
653  const LhsEval& xlCO2,
654  const LhsEval& rho_pure) const
655  {
656  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
657  Scalar M_CO2 = CO2::molarMass();
658  Scalar M_H2O = H2O::molarMass();
659 
660  const LhsEval& tempC = temperature - 273.15; /* tempC : temperature in °C */
661  // calculate the mole fraction of CO2 in the liquid. note that xlH2O is available
662  // as a function parameter, but in the case of a pure gas phase the value of M_T
663  // for the virtual liquid phase can become very large
664  const LhsEval xlH2O = 1.0 - xlCO2;
665  const LhsEval& M_T = M_H2O * xlH2O + M_CO2 * xlCO2;
666  const LhsEval& V_phi =
667  (37.51 +
668  tempC*(-9.585e-2 +
669  tempC*(8.74e-4 -
670  tempC*5.044e-7))) / 1.0e6;
671  return 1 / (xlCO2 * V_phi/M_T + M_H2O * xlH2O / (rho_pure * M_T));
672  }
673 
678  template <class LhsEval>
679  OPM_HOST_DEVICE LhsEval convertRsToXoG_(const LhsEval& Rs, unsigned regionIdx) const
680  {
681  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
682  Scalar rho_oRef = brineReferenceDensity_[regionIdx];
683  Scalar rho_gRef = co2ReferenceDensity_[regionIdx];
684 
685  const LhsEval& rho_oG = Rs*rho_gRef;
686  return rho_oG/(rho_oRef + rho_oG);
687  }
688 
692  template <class LhsEval>
693  OPM_HOST_DEVICE LhsEval convertXoGToxoG_(const LhsEval& XoG, const LhsEval& salinity) const
694  {
695  OPM_TIMEFUNCTION_LOCAL(Subsystem::PvtProps);
696  Scalar M_CO2 = CO2::molarMass();
697  LhsEval M_Brine = Brine::molarMass(salinity);
698  return XoG*M_Brine / (M_CO2*(1 - XoG) + XoG*M_Brine);
699  }
700 
704  template <class LhsEval>
705  OPM_HOST_DEVICE LhsEval convertxoGToXoG(const LhsEval& xoG, const LhsEval& salinity) const
706  {
707  OPM_TIMEBLOCK_LOCAL(convertxoGToXoG, Subsystem::PvtProps);
708  Scalar M_CO2 = CO2::molarMass();
709  LhsEval M_Brine = Brine::molarMass(salinity);
710 
711  return xoG*M_CO2 / (xoG*(M_CO2 - M_Brine) + M_Brine);
712  }
713 
718  template <class LhsEval>
719  OPM_HOST_DEVICE LhsEval convertXoGToRs(const LhsEval& XoG, unsigned regionIdx) const
720  {
721  Scalar rho_oRef = brineReferenceDensity_[regionIdx];
722  Scalar rho_gRef = co2ReferenceDensity_[regionIdx];
723 
724  return XoG/(1.0 - XoG)*(rho_oRef/rho_gRef);
725  }
726 
727  template <class LhsEval>
728  OPM_HOST_DEVICE LhsEval liquidEnthalpyBrineCO2_(const LhsEval& T,
729  const LhsEval& p,
730  const LhsEval& salinity,
731  const LhsEval& X_CO2_w) const
732  {
733  if (liquidMixType_ == Co2StoreConfig::LiquidMixingType::NONE
734  && saltMixType_ == Co2StoreConfig::SaltMixingType::NONE)
735  {
736  return H2O::liquidEnthalpy(T, p);
737  }
738 
739  LhsEval hw = H2O::liquidEnthalpy(T, p) /1E3; /* kJ/kg */
740  LhsEval h_ls1 = hw;
741  // Use mixing model for salt by MICHAELIDES
742  if (saltMixType_ == Co2StoreConfig::SaltMixingType::MICHAELIDES) {
743 
744  /* X_CO2_w : mass fraction of CO2 in brine */
745 
746  /* same function as enthalpy_brine, only extended by CO2 content */
747 
748  /*Numerical coefficents from PALLISER*/
749  static constexpr Scalar f[] = {
750  2.63500E-1, 7.48368E-6, 1.44611E-6, -3.80860E-10
751  };
752 
753  /*Numerical coefficents from MICHAELIDES for the enthalpy of brine*/
754  static constexpr Scalar a[4][3] = {
755  { 9633.6, -4080.0, +286.49 },
756  { +166.58, +68.577, -4.6856 },
757  { -0.90963, -0.36524, +0.249667E-1 },
758  { +0.17965E-2, +0.71924E-3, -0.4900E-4 }
759  };
760 
761  LhsEval theta, h_NaCl;
762  LhsEval d_h, delta_h;
763 
764  theta = T - 273.15;
765 
766  // Regularization
767  Scalar scalarTheta = scalarValue(theta);
768  Scalar S_lSAT = f[0] + scalarTheta*(f[1] + scalarTheta*(f[2] + scalarTheta*f[3]));
769 
770  LhsEval S = salinity;
771  if (S > S_lSAT)
772  S = S_lSAT;
773 
774  /*DAUBERT and DANNER*/
775  /*U=*/h_NaCl = (3.6710E4*T + 0.5*(6.2770E1)*T*T - ((6.6670E-2)/3)*T*T*T
776  +((2.8000E-5)/4)*(T*T*T*T))/(58.44E3)- 2.045698e+02; /* kJ/kg */
777 
778  LhsEval m = 1E3 / 58.44 * S / (1 - S);
779  d_h = 0;
780 
781  for (int i = 0; i <=3; ++i) {
782  for (int j = 0; j <= 2; ++j) {
783  d_h += a[i][j] * pow(theta, static_cast<Scalar>(i)) * pow(m, j);
784  }
785  }
786  /* heat of dissolution for halite according to Michaelides 1971 */
787  delta_h = (4.184/(1E3 + (58.44 * m)))*d_h;
788 
789  /* Enthalpy of brine without CO2 */
790  h_ls1 =(1-S)*hw + S*h_NaCl + S*delta_h; /* kJ/kg */
791 
792  // Use Enthalpy of brine without CO2
793  if (liquidMixType_ == Co2StoreConfig::LiquidMixingType::NONE) {
794  return h_ls1*1E3;
795  }
796  }
797 
798  LhsEval delta_hCO2, hg;
799  /* heat of dissolution for CO2 according to Fig. 6 in Duan and Sun 2003. (kJ/kg)
800  In the relevant temperature ranges CO2 dissolution is
801  exothermal */
802  if (liquidMixType_ == Co2StoreConfig::LiquidMixingType::DUANSUN) {
803  delta_hCO2 = (-57.4375 + T * 0.1325) * 1000/44;
804  }
805  else {
806  delta_hCO2 = 0.0;
807  }
808 
809  /* enthalpy contribution of CO2 (kJ/kg) */
810  hg = CO2::gasEnthalpy(co2Tables_, T, p, extrapolate)/1E3 + delta_hCO2;
811 
812  /* Enthalpy of brine with dissolved CO2 */
813  return (h_ls1 - X_CO2_w*hw + hg*X_CO2_w)*1E3; /*J/kg*/
814  }
815 
816  template <class LhsEval>
817  OPM_HOST_DEVICE const LhsEval salinityFromConcentration(unsigned regionIdx,
818  const LhsEval&T,
819  const LhsEval& P,
820  const LhsEval& saltConcentration) const
821  {
822  if (enableSaltConcentration_) {
823  // Convert concentration [kg/m³] to mass fraction [kg_salt/kg_solution].
824  // First approximation using pure water density
825  const LhsEval rho_w = H2O::liquidDensity(T, P, true);
826  const LhsEval S_approx = saltConcentration / rho_w;
827  // Improved estimate using Batzle-Wang brine density
828  const LhsEval rho_brine = Brine::liquidDensity(T, P, S_approx, rho_w);
829  return saltConcentration / rho_brine;
830  }
831 
832  return salinity(regionIdx);
833  }
834 
835  #if HAVE_CUDA
836  template <class ScalarT>
837  friend BrineCo2Pvt<ScalarT, gpuistl::GpuView>
838  gpuistl::make_view(BrineCo2Pvt<ScalarT, gpuistl::GpuBuffer>&);
839  #endif
840 
841  ContainerT brineReferenceDensity_{};
842  ContainerT co2ReferenceDensity_{};
843  ContainerT salinity_{};
844  ContainerT ezrokhiDenNaClCoeff_{};
845  ContainerT ezrokhiDenCo2Coeff_{};
846  ContainerT ezrokhiViscNaClCoeff_{};
847  bool enableEzrokhiDensity_ = false;
848  bool enableEzrokhiViscosity_ = false;
849  bool enableDissolution_ = true;
850  bool enableSaltConcentration_ = false;
851  int activityModel_{};
852  Co2StoreConfig::LiquidMixingType liquidMixType_{};
853  Co2StoreConfig::SaltMixingType saltMixType_{};
854  Params co2Tables_;
855 };
856 
857 } // namespace Opm
858 
859 #if HAVE_CUDA
860 namespace Opm::gpuistl
861 {
862 
863  template<class ScalarT>
864  BrineCo2Pvt<ScalarT, GpuBuffer>
865  copy_to_gpu(const BrineCo2Pvt<ScalarT>& cpuBrineCo2)
866  {
867  return BrineCo2Pvt<ScalarT, GpuBuffer>(
868  GpuBuffer<ScalarT>(cpuBrineCo2.getBrineReferenceDensity()),
869  GpuBuffer<ScalarT>(cpuBrineCo2.getCo2ReferenceDensity()),
870  GpuBuffer<ScalarT>(cpuBrineCo2.getSalinity()),
871  cpuBrineCo2.getActivityModel(),
872  cpuBrineCo2.getThermalMixingModelSalt(),
873  cpuBrineCo2.getThermalMixingModelLiquid(),
874  copy_to_gpu(cpuBrineCo2.getParams())
875  );
876  }
877 
878  template <class ScalarT>
879  BrineCo2Pvt<ScalarT, GpuView>
880  make_view(BrineCo2Pvt<ScalarT, GpuBuffer>& brineCo2Pvt)
881  {
882 
883  using ContainedType = ScalarT;
884 
885  auto newBrineReferenceDensity = make_view<ContainedType>(brineCo2Pvt.brineReferenceDensity_);
886  auto newGasReferenceDensity = make_view<ContainedType>(brineCo2Pvt.co2ReferenceDensity_);
887  auto newSalinity = make_view<ContainedType>(brineCo2Pvt.salinity_);
888 
889  return BrineCo2Pvt<ScalarT, GpuView>(
890  newBrineReferenceDensity,
891  newGasReferenceDensity,
892  newSalinity,
893  brineCo2Pvt.getActivityModel(),
894  brineCo2Pvt.getThermalMixingModelSalt(),
895  brineCo2Pvt.getThermalMixingModelLiquid(),
896  make_view(brineCo2Pvt.co2Tables_)
897  );
898  }
899 } // namespace Opm::gpuistl
900 #endif // HAVE_CUDA
901 
902 #endif
Material properties of pure water .
Definition: H2O.hpp:64
This class represents the Pressure-Volume-Temperature relations of the liquid phase for a CO2-Brine s...
Definition: BrineCo2Pvt.hpp:63
static OPM_HOST_DEVICE Scalar molarMass()
The mass in [kg] of one mole of CO2.
Definition: CO2.hpp:73
OPM_HOST_DEVICE Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: BrineCo2Pvt.hpp:249
A class for the brine fluid properties.
Definition: BrineDynamic.hpp:48
void initFromState(const EclipseState &eclState, const Schedule &)
Initialize the parameters for Brine-CO2 system using an ECL deck.
Definition: BrineCo2Pvt.cpp:67
A class for the CO2 fluid properties.
unsigned numRegions() const
Return the number of PVT regions which are considered by this PVT-object.
Definition: BrineCo2Pvt.hpp:195
OPM_HOST_DEVICE Evaluation saturationPressure(unsigned, const Evaluation &, const Evaluation &) const
Returns the saturation pressure of the brine phase [Pa] depending on its mass fraction of the gas com...
Definition: BrineCo2Pvt.hpp:406
std::pair< LhsEval, LhsEval > OPM_HOST_DEVICE inverseFormationVolumeFactorAndViscosity(const FluidState &fluidState, unsigned regionIdx) const
Returns the formation volume factor [-] and viscosity [Pa s] of the fluid phase.
Definition: BrineCo2Pvt.hpp:368
static OPM_HOST_DEVICE constexpr bool mixingEnergy()
Indicates whether this PVT object computes the water internal energy via a thermal mixing model...
Definition: BrineCo2Pvt.hpp:205
static OPM_HOST_DEVICE Evaluation liquidViscosity(const Evaluation &temperature, const Evaluation &pressure, bool extrapolate)
The dynamic viscosity of pure water.
Definition: SimpleHuDuanH2O.hpp:361
static OPM_HOST_DEVICE Evaluation gasEnthalpy(const Params &params, const Evaluation &temperature, const Evaluation &pressure, bool extrapolate=false)
Specific enthalpy of gaseous CO2 [J/kg].
Definition: CO2.hpp:171
Definition: Schedule.hpp:102
static OPM_HOST_DEVICE Evaluation liquidEnthalpy(const Evaluation &temperature, const Evaluation &)
Specific enthalpy of liquid water .
Definition: SimpleHuDuanH2O.hpp:202
static OPM_HOST_DEVICE Scalar molarMass()
The molar mass in of water.
Definition: SimpleHuDuanH2O.hpp:103
OPM_HOST_DEVICE Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rs, const Evaluation &saltConcentration) const
Returns the formation volume factor [-] of the fluid phase.
Definition: BrineCo2Pvt.hpp:336
Provides the OPM specific exception classes.
static OPM_HOST_DEVICE Evaluation liquidViscosity(const Evaluation &temperature, const Evaluation &, const Evaluation &salinity)
The dynamic liquid viscosity of the pure component.
Definition: BrineDynamic.hpp:385
void setThermalMixingModel(int thermalMixingModelSalt, int thermalMixingModelLiquid)
Set thermal mixing model for co2 in brine.
Definition: BrineCo2Pvt.cpp:183
static OPM_HOST_DEVICE Evaluation liquidDensity(const Evaluation &temperature, const Evaluation &pressure, bool extrapolate)
The density of pure water at a given pressure and temperature .
Definition: SimpleHuDuanH2O.hpp:316
PiecewiseLinearTwoPhaseMaterialParams< TraitsT, ViewType > make_view(PiecewiseLinearTwoPhaseMaterialParams< TraitsT, ContainerType > &params)
this function is intented to make a GPU friendly view of the PiecewiseLinearTwoPhaseMaterialParams ...
Definition: PiecewiseLinearTwoPhaseMaterialParams.hpp:312
A class for the brine fluid properties.
Definition: Brine.hpp:47
OPM_HOST_DEVICE Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the dynamic viscosity [Pa s] of oil saturated gas at given pressure.
Definition: BrineCo2Pvt.hpp:298
OPM_HOST_DEVICE Evaluation saturatedViscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltConcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: BrineCo2Pvt.hpp:262
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Convience header to include the gpuistl headers if HAVE_CUDA is defined.
void setEnableSaltConcentration(bool yesno)
Specify whether the PVT model should consider salt concentration from the fluidstate or a fixed salin...
Definition: BrineCo2Pvt.hpp:175
OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltConcentration) const
Returns the gas dissoluiton factor [m^3/m^3] of the liquid phase.
Definition: BrineCo2Pvt.hpp:458
Binary coefficients for water and CO2.
Binary coefficients for brine and CO2.
Definition: Brine_CO2.hpp:48
OPM_HOST_DEVICE Evaluation inverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rs) const
Returns the formation volume factor [-] of the fluid phase.
Definition: BrineCo2Pvt.hpp:353
OPM_HOST_DEVICE Evaluation internalEnergy(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rs) const
Returns the specific enthalpy [J/kg] of gas given a set of parameters.
Definition: BrineCo2Pvt.hpp:231
Definition: EclipseState.hpp:66
OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns thegas dissoluiton factor [m^3/m^3] of the liquid phase.
Definition: BrineCo2Pvt.hpp:472
void setReferenceDensities(unsigned regionIdx, Scalar rhoRefBrine, Scalar rhoRefCO2, Scalar)
Initialize the reference densities of all fluids for a given PVT region.
Definition: BrineCo2Pvt.cpp:160
A class for the CO2 fluid properties.
Definition: CO2.hpp:57
OPM_HOST_DEVICE Evaluation saturatedGasDissolutionFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &, const Evaluation &) const
Returns the gas dissoluiton factor [m^3/m^3] of the liquid phase.
Definition: BrineCo2Pvt.hpp:444
A simple version of pure water with density from Hu et al.
Implements a scalar function that depends on two variables and which is sampled on an uniform X-Y gri...
A simple version of pure water with density from Hu et al.
Definition: SimpleHuDuanH2O.hpp:65
A class for the brine fluid properties.
static OPM_HOST_DEVICE void calculateMoleFractions(const CO2Params &params, const Evaluation &temperature, const Evaluation &pg, const Evaluation &salinity, const int knownPhaseIdx, Evaluation &xlCO2, Evaluation &ygH2O, const int &activityModel, bool extrapolate=false)
Returns the mol (!) fraction of CO2 in the liquid phase and the mol_ (!) fraction of H2O in the gas p...
Definition: Brine_CO2.hpp:113
A generic class which tabulates all thermodynamic properties of a given component.
static OPM_HOST_DEVICE Evaluation liquidDensity(const Evaluation &temperature, const Evaluation &pressure, const Evaluation &salinity, bool extrapolate=false)
The density of the liquid component at a given pressure in and temperature in . ...
Definition: BrineDynamic.hpp:283
void initEnd()
Finish initializing the oil phase PVT properties.
Definition: BrineCo2Pvt.hpp:156
PiecewiseLinearTwoPhaseMaterialParams< TraitsT, GPUContainerType > copy_to_gpu(const PiecewiseLinearTwoPhaseMaterialParams< TraitsT > &params)
Move a PiecewiseLinearTwoPhaseMaterialParams-object to the GPU.
Definition: PiecewiseLinearTwoPhaseMaterialParams.hpp:285
Definition: PiecewiseLinearTwoPhaseMaterialParams.hpp:47
OPM_HOST_DEVICE Evaluation internalEnergy(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &Rs, const Evaluation &saltConcentration) const
Returns the specific enthalpy [J/kg] of gas given a set of parameters.
Definition: BrineCo2Pvt.hpp:212
Binary coefficients for brine and CO2.
static Scalar molarMass()
The molar mass in of the component.
Definition: Component.hpp:93
OPM_HOST_DEVICE Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &saltconcentration) const
Returns the formation volume factor [-] of the fluid phase.
Definition: BrineCo2Pvt.hpp:319
OPM_HOST_DEVICE Evaluation saturationPressure(unsigned, const Evaluation &, const Evaluation &, const Evaluation &) const
Returns the saturation pressure of the brine phase [Pa] depending on its mass fraction of the gas com...
Definition: BrineCo2Pvt.hpp:426
OPM_HOST_DEVICE Evaluation saturatedInverseFormationVolumeFactor(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure) const
Returns the formation volume factor [-] of brine saturated with CO2 at a given pressure.
Definition: BrineCo2Pvt.hpp:388
OPM_HOST_DEVICE Evaluation viscosity(unsigned regionIdx, const Evaluation &temperature, const Evaluation &pressure, const Evaluation &, const Evaluation &saltConcentration) const
Returns the dynamic viscosity [Pa s] of the fluid phase given a set of parameters.
Definition: BrineCo2Pvt.hpp:283
void setEnableDissolvedGas(bool yesno)
Specify whether the PVT model should consider that the CO2 component can dissolve in the brine phase...
Definition: BrineCo2Pvt.hpp:166
void setActivityModelSalt(int activityModel)
Set activity coefficient model for salt in solubility model.
Definition: BrineCo2Pvt.cpp:171