opm-common
GenericOilGasWaterFluidSystem.hpp
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  Copyright 2023 SINTEF Digital, Mathematics and Cybernetics.
5 
6  This file is part of the Open Porous Media project (OPM).
7 
8  OPM is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 2 of the License, or
11  (at your option) any later version.
12 
13  OPM is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with OPM. If not, see <http://www.gnu.org/licenses/>.
20 
21  Consult the COPYING file in the top-level source directory of this
22  module for the precise wording of the license and the list of
23  copyright holders.
24 */
25 
26 #ifndef OPM_GENERIC_OIL_GAS_WATER_FLUIDSYSTEM_HPP
27 #define OPM_GENERIC_OIL_GAS_WATER_FLUIDSYSTEM_HPP
28 
29 #include <opm/common/OpmLog/OpmLog.hpp>
30 
31 #include <opm/input/eclipse/EclipseState/EclipseState.hpp>
32 #include <opm/input/eclipse/Schedule/Schedule.hpp>
33 
34 #include <opm/material/eos/CubicEOS.hpp>
37 #include <opm/material/fluidsystems/PTFlashParameterCache.hpp> // TODO: this is something else need to check
39 
40 #include <algorithm>
41 #include <array>
42 #include <cassert>
43 #include <cstddef>
44 #include <string>
45 #include <string_view>
46 #include <type_traits>
47 
48 #include <fmt/format.h>
49 
50 namespace Opm {
51 
60  template<class Scalar, int NumComp, bool enableWater>
62  : public BaseFluidSystem<Scalar, GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater> > {
63  public:
64  // TODO: I do not think these should be constant in fluidsystem, will try to make it non-constant later
65  static constexpr bool waterEnabled = enableWater;
66  static constexpr int numPhases = enableWater ? 3 : 2;
67  static constexpr int numComponents = NumComp;
68  static constexpr int numMisciblePhases = 2;
69  // \Note: not totally sure when we should distinguish numMiscibleComponents and numComponents.
70  // Possibly when with a dummy phase like water?
71  static constexpr int numMiscibleComponents = NumComp;
72  // TODO: phase location should be more general
73  static constexpr int oilPhaseIdx = 0;
74  static constexpr int gasPhaseIdx = 1;
75  static constexpr int waterPhaseIdx = 2;
76 
77  static constexpr int waterCompIdx = -1;
78  static constexpr int oilCompIdx = 0;
79  static constexpr int gasCompIdx = 1;
80  static constexpr int compositionSwitchIdx = -1; // equil initializer
81 
82  template <class ValueType>
87 
88  struct ComponentParam {
89  std::string name;
90  Scalar molar_mass; // unit: g/mol
91  Scalar critic_temp; // unit: K
92  Scalar critic_pres; // unit: parscal
93  Scalar critic_vol; // unit: m^3/kmol
94  Scalar acentric_factor; // unit: dimension less
95 
96  ComponentParam(const std::string_view name_, const Scalar molar_mass_, const Scalar critic_temp_,
97  const Scalar critic_pres_, const Scalar critic_vol_, const Scalar acentric_factor_)
98  : name(name_),
99  molar_mass(molar_mass_),
100  critic_temp(critic_temp_),
101  critic_pres(critic_pres_),
102  critic_vol(critic_vol_),
103  acentric_factor(acentric_factor_)
104  {}
105  };
106 
107  static bool phaseIsActive(unsigned phaseIdx)
108  {
109  if constexpr (enableWater) {
110  assert(phaseIdx < numPhases);
111  return true;
112  }
113  else {
114  if (phaseIdx == waterPhaseIdx)
115  return false;
116  assert(phaseIdx < numPhases);
117  return true;
118  }
119  }
120 
121  template<typename Param>
122  static void addComponent(const Param& param)
123  {
124  // Check if the current size is less than the maximum allowed components.
125  if (component_param_.size() < numComponents) {
126  component_param_.push_back(param);
127  } else {
128  // Adding another component would exceed the limit.
129  const std::string msg = fmt::format("The fluid system has reached its maximum capacity of {} components,"
130  "the component '{}' will not be added.", NumComp, param.name);
131  OpmLog::note(msg);
132  // Optionally, throw an exception?
133  }
134  }
135 
139  static void initFromState(const EclipseState& eclState, const Schedule& schedule)
140  {
141  // TODO: we are not considering the EOS region for now
142  const auto& comp_config = eclState.compositionalConfig();
143  // how should we utilize the numComps from the CompositionalConfig?
145  const std::size_t num_comps = comp_config.numComps();
146  // const std::size_t num_eos_region = comp_config.
147  assert(num_comps == NumComp);
148  const auto& names = comp_config.compName();
149  const auto& eos_props = comp_config.eosProps(0);
150  FluidSystem::init();
151  using CompParm = typename FluidSystem::ComponentParam;
152  for (std::size_t c = 0; c < num_comps; ++c) {
153  // we use m^3/kmol for the critic volume in the flash calculation, so we multiply 1.e3 for the critic volume
154  FluidSystem::addComponent(CompParm{names[c],
155  static_cast<Scalar>(eos_props.molecular_weights[c]),
156  static_cast<Scalar>(eos_props.critical_temperature[c]),
157  static_cast<Scalar>(eos_props.critical_pressure[c]),
158  static_cast<Scalar>(eos_props.critical_volume[c] * 1.e3),
159  static_cast<Scalar>(eos_props.acentric_factors[c])});
160  }
161 
162  const auto& bic = eos_props.binary_interaction_coefficient;
163  if constexpr (std::is_same_v<Scalar, double>) {
164  interaction_coefficients_ = bic;
165  } else {
166  interaction_coefficients_.resize(bic.size());
167  std::ranges::copy(bic, interaction_coefficients_.begin());
168  }
169 
170  const auto& lbc = comp_config.lbcCoefficients();
171  std::ranges::copy(lbc, lbc_coefficients_.begin());
172 
173  // Init. water pvt from deck
174  waterPvt_->initFromState(eclState, schedule);
175 
176  }
177 
178  static void init()
179  {
180  waterPvt_ = std::make_shared<WaterPvt>();
181  component_param_.reserve(numComponents);
182  }
183 
187  static void setWaterPvt(std::shared_ptr<WaterPvt> pvtObj)
188  { waterPvt_ = std::move(pvtObj); }
189 
195  static Scalar acentricFactor(unsigned compIdx)
196  {
197  assert(isConsistent());
198  assert(compIdx < numComponents);
199 
200  return component_param_[compIdx].acentric_factor;
201  }
207  static Scalar criticalTemperature(unsigned compIdx)
208  {
209  assert(isConsistent());
210  assert(compIdx < numComponents);
211 
212  return component_param_[compIdx].critic_temp;
213  }
219  static Scalar criticalPressure(unsigned compIdx)
220  {
221  assert(isConsistent());
222  assert(compIdx < numComponents);
223 
224  return component_param_[compIdx].critic_pres;
225  }
231  static Scalar criticalVolume(unsigned compIdx)
232  {
233  assert(isConsistent());
234  assert(compIdx < numComponents);
235 
236  return component_param_[compIdx].critic_vol;
237  }
238 
240  static Scalar molarMass(unsigned compIdx)
241  {
242  assert(isConsistent());
243  assert(compIdx < numComponents);
244 
245  return component_param_[compIdx].molar_mass;
246  }
247 
254  static const std::array<Scalar, 5>& lbcCoefficients()
255  { return lbc_coefficients_; }
256 
261  static Scalar interactionCoefficient(unsigned comp1Idx, unsigned comp2Idx)
262  {
263  assert(isConsistent());
264  assert(comp1Idx < numComponents);
265  assert(comp2Idx < numComponents);
266  if (interaction_coefficients_.empty() || comp2Idx == comp1Idx) {
267  return 0.0;
268  }
269  // make sure row is the bigger value compared to column number
270  const auto [column, row] = std::minmax(comp1Idx, comp2Idx);
271  const unsigned index = (row * (row - 1) / 2 + column); // it is the current understanding
272  return interaction_coefficients_[index];
273  }
274 
276  static std::string_view phaseName(unsigned phaseIdx)
277  {
278  static const std::string_view name[] = {"o", // oleic phase
279  "g", // gas phase
280  "w"}; // aqueous phase
281 
282  assert(phaseIdx < numPhases);
283  return name[phaseIdx];
284  }
285 
287  static std::string_view componentName(unsigned compIdx)
288  {
289  assert(isConsistent());
290  assert(compIdx < numComponents);
291 
292  return component_param_[compIdx].name;
293  }
294 
298  template <class FluidState, class LhsEval = typename FluidState::ValueType, class ParamCacheEval = LhsEval>
299  static LhsEval density(const FluidState& fluidState,
300  const ParameterCache<ParamCacheEval>& paramCache,
301  unsigned phaseIdx)
302  {
303  assert(isConsistent());
304  assert(phaseIdx < numPhases);
305 
306  if (phaseIdx == oilPhaseIdx || phaseIdx == gasPhaseIdx) {
307  return decay<LhsEval>(fluidState.averageMolarMass(phaseIdx) / paramCache.molarVolume(phaseIdx));
308  }
309  else {
310  const LhsEval& p = decay<LhsEval>(fluidState.pressure(phaseIdx));
311  const LhsEval& T = decay<LhsEval>(fluidState.temperature(phaseIdx));
312  const Scalar& rho_w_ref = waterPvt_->waterReferenceDensity(0);
313  const LhsEval& bw = waterPvt_->inverseFormationVolumeFactor(0, T, p, LhsEval(0.0), LhsEval(0.0));
314  return rho_w_ref * bw;
315  }
316 
317  return {};
318  }
319 
321  template <class FluidState, class LhsEval = typename FluidState::ValueType, class ParamCacheEval = LhsEval>
322  static LhsEval viscosity(const FluidState& fluidState,
323  const ParameterCache<ParamCacheEval>& paramCache,
324  unsigned phaseIdx)
325  {
326  assert(isConsistent());
327  assert(phaseIdx < numPhases);
328 
329  if (phaseIdx == oilPhaseIdx || phaseIdx == gasPhaseIdx) {
330  // Use LBC method to calculate viscosity
331  return decay<LhsEval>(ViscosityModel::LBC(fluidState, paramCache, phaseIdx));
332  }
333  else {
334  const LhsEval& p = decay<LhsEval>(fluidState.pressure(phaseIdx));
335  const LhsEval& T = decay<LhsEval>(fluidState.temperature(phaseIdx));
336  return waterPvt_->viscosity(0, T, p, LhsEval(0.0), LhsEval(0.0));
337  }
338  }
339 
341  template <class FluidState, class LhsEval = typename FluidState::ValueType, class ParamCacheEval = LhsEval>
342  static LhsEval fugacityCoefficient(const FluidState& fluidState,
343  const ParameterCache<ParamCacheEval>& paramCache,
344  unsigned phaseIdx,
345  unsigned compIdx)
346  {
347  if (waterEnabled && phaseIdx == static_cast<unsigned int>(waterPhaseIdx))
348  return LhsEval(0.0);
349 
350  assert(isConsistent());
351  assert(phaseIdx < numPhases);
352  assert(compIdx < numComponents);
353 
354  return decay<LhsEval>(CubicEOS::computeFugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx));
355  }
356 
357  // TODO: the following interfaces are needed by function checkFluidSystem()
359  static bool isCompressible([[maybe_unused]] unsigned phaseIdx)
360  {
361  assert(phaseIdx < numPhases);
362 
363  return true;
364  }
365 
367  static bool isIdealMixture([[maybe_unused]] unsigned phaseIdx)
368  {
369  assert(phaseIdx < numPhases);
370 
371  return false;
372  }
373 
375  static bool isLiquid(unsigned phaseIdx)
376  {
377  assert(phaseIdx < numPhases);
378 
379  return (phaseIdx == oilPhaseIdx);
380  }
381 
383  static bool isIdealGas(unsigned phaseIdx)
384  {
385  assert(phaseIdx < numPhases);
386 
387  return (phaseIdx == gasPhaseIdx);
388  }
389  // the following funcitons are needed to compile the GenericOutputBlackoilModule
390  // not implemented for this FluidSystem yet
391  template <class LhsEval>
392  static LhsEval convertXwGToxwG(const LhsEval&, unsigned)
393  {
394  assert(false && "convertXwGToxwG not implemented for GenericOilGasWaterFluidSystem!");
395  return 0.;
396  }
397  template <class LhsEval>
398  static LhsEval convertXoGToxoG(const LhsEval&, unsigned)
399  {
400  assert(false && "convertXoGToxoG not implemented for GenericOilGasWaterFluidSystem!");
401  return 0.;
402  }
403 
404  template <class LhsEval>
405  static LhsEval convertxoGToXoG(const LhsEval&, unsigned)
406  {
407  assert(false && "convertxoGToXoG not implemented for GenericOilGasWaterFluidSystem!");
408  return 0.;
409  }
410 
411  template <class LhsEval>
412  static LhsEval convertXgOToxgO(const LhsEval&, unsigned)
413  {
414  assert(false && "convertXgOToxgO not implemented for GenericOilGasWaterFluidSystem!");
415  return 0.;
416  }
417 
418  template <class LhsEval>
419  static LhsEval convertRswToXwG(const LhsEval&, unsigned)
420  {
421  assert(false && "convertRswToXwG not implemented for GenericOilGasWaterFluidSystem!");
422  return 0.;
423  }
424 
425  template <class LhsEval>
426  static LhsEval convertRvwToXgW(const LhsEval&, unsigned)
427  {
428  assert(false && "convertRvwToXgW not implemented for GenericOilGasWaterFluidSystem!");
429  return 0.;
430  }
431 
432  template <class LhsEval>
433  static LhsEval convertXgWToxgW(const LhsEval&, unsigned)
434  {
435  assert(false && "convertXgWToxgW not implemented for GenericOilGasWaterFluidSystem!");
436  return 0.;
437  }
438 
439  static bool enableDissolvedGas()
440  {
441  return false;
442  }
443 
444  static bool enableDissolvedGasInWater()
445  {
446  return false;
447  }
448 
449  static bool enableVaporizedWater()
450  {
451  return false;
452  }
453 
454  static bool enableVaporizedOil()
455  {
456  return false;
457  }
458 
459  private:
460  static bool isConsistent() {
461  return component_param_.size() == NumComp;
462  }
463 
464  static std::vector<ComponentParam> component_param_;
465  static std::vector<Scalar> interaction_coefficients_;
466  static std::array<Scalar, 5> lbc_coefficients_;
467  static std::shared_ptr<WaterPvt> waterPvt_;
468 
469  public:
470  static std::string printComponentParams() {
471  std::string result = "Components Information:\n";
472  for (const auto& param : component_param_) {
473  result += fmt::format("Name: {}\n", param.name);
474  result += fmt::format("Molar Mass: {} g/mol\n", param.molar_mass);
475  result += fmt::format("Critical Temperature: {} K\n", param.critic_temp);
476  result += fmt::format("Critical Pressure: {} Pascal\n", param.critic_pres);
477  result += fmt::format("Critical Volume: {} m^3/kmol\n", param.critic_vol);
478  result += fmt::format("Acentric Factor: {}\n", param.acentric_factor);
479  result += "---------------------------------\n";
480  }
481  return result;
482  }
483  };
484 
485  template <class Scalar, int NumComp, bool enableWater>
486  std::vector<typename GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater>::ComponentParam>
487  GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater>::component_param_;
488 
489  template <class Scalar, int NumComp, bool enableWater>
490  std::vector<Scalar>
491  GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater>::interaction_coefficients_;
492 
493  template <class Scalar, int NumComp, bool enableWater>
494  std::array<Scalar, 5>
495  GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater>::lbc_coefficients_ =
496  ViscosityModel::defaultLBCCoefficients();
497 
498  template <class Scalar, int NumComp, bool enableWater>
499  std::shared_ptr<WaterPvtMultiplexer<Scalar> >
500  GenericOilGasWaterFluidSystem<Scalar, NumComp, enableWater>::waterPvt_;
501 
502 }
503 #endif // OPM_GENERIC_OIL_GAS_WATER_FLUIDSYSTEM_HPP
static Scalar criticalTemperature(unsigned compIdx)
Critical temperature of a component [K].
Definition: GenericOilGasWaterFluidSystem.hpp:207
static Scalar criticalVolume(unsigned compIdx)
Critical volume of a component [m3].
Definition: GenericOilGasWaterFluidSystem.hpp:231
Specifies the parameter cache used by the SPE-5 fluid system.
Definition: PTFlashParameterCache.hpp:49
static void initFromState(const EclipseState &eclState, const Schedule &schedule)
Initialize the fluid system using an ECL deck object.
Definition: GenericOilGasWaterFluidSystem.hpp:139
Definition: Schedule.hpp:102
Definition: ViscosityModels.hpp:42
static Scalar molarMass(unsigned compIdx)
Return the molar mass of a component in [kg/mol].
Definition: GenericOilGasWaterFluidSystem.hpp:240
static LhsEval density(const FluidState &fluidState, const ParameterCache< ParamCacheEval > &paramCache, unsigned phaseIdx)
Calculate the density [kg/m^3] of a fluid phase.
Definition: GenericOilGasWaterFluidSystem.hpp:299
This class represents the Pressure-Volume-Temperature relations of the water phase in the black-oil m...
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Scalar molarVolume(unsigned phaseIdx) const
Returns the molar volume of a phase [m^3/mol].
Definition: PTFlashParameterCache.hpp:283
Definition: CubicEOS.hpp:33
static LhsEval fugacityCoefficient(const FluidState &fluidState, const ParameterCache< ParamCacheEval > &paramCache, unsigned phaseIdx, unsigned compIdx)
Calculate the fugacity coefficient [Pa] of an individual component in a fluid phase.
Definition: GenericOilGasWaterFluidSystem.hpp:342
A two phase system that can contain NumComp components.
Definition: GenericOilGasWaterFluidSystem.hpp:61
Definition: EclipseState.hpp:66
static bool isIdealMixture([[maybe_unused]] unsigned phaseIdx)
Returns true if and only if a fluid phase is assumed to be an ideal mixture.
Definition: GenericOilGasWaterFluidSystem.hpp:367
static const std::array< Scalar, 5 > & lbcCoefficients()
Coefficients for the Lorentz-Bray-Clark viscosity correlation.
Definition: GenericOilGasWaterFluidSystem.hpp:254
static LhsEval viscosity(const FluidState &fluidState, const ParameterCache< ParamCacheEval > &paramCache, unsigned phaseIdx)
Calculate the dynamic viscosity of a fluid phase [Pa*s].
Definition: GenericOilGasWaterFluidSystem.hpp:322
static Scalar criticalPressure(unsigned compIdx)
Critical pressure of a component [Pa].
Definition: GenericOilGasWaterFluidSystem.hpp:219
This class represents the Pressure-Volume-Temperature relations of the water phase in the black-oil m...
Definition: ConstantCompressibilityBrinePvt.hpp:39
The base class for all fluid systems.
Definition: BaseFluidSystem.hpp:42
static std::string_view phaseName(unsigned phaseIdx)
Return the human readable name of a fluid phase.
Definition: GenericOilGasWaterFluidSystem.hpp:276
static bool isLiquid(unsigned phaseIdx)
Return whether a phase is liquid.
Definition: GenericOilGasWaterFluidSystem.hpp:375
static bool isCompressible([[maybe_unused]] unsigned phaseIdx)
Returns true if and only if a fluid phase is assumed to be compressible.
Definition: GenericOilGasWaterFluidSystem.hpp:359
static Scalar acentricFactor(unsigned compIdx)
The acentric factor of a component [].
Definition: GenericOilGasWaterFluidSystem.hpp:195
static bool isIdealGas(unsigned phaseIdx)
Returns true if and only if a fluid phase is assumed to be an ideal gas.
Definition: GenericOilGasWaterFluidSystem.hpp:383
Scalar Scalar
The type used for scalar quantities.
Definition: BaseFluidSystem.hpp:48
static Scalar interactionCoefficient(unsigned comp1Idx, unsigned comp2Idx)
Returns the interaction coefficient for two components.
Definition: GenericOilGasWaterFluidSystem.hpp:261
Definition: GenericOilGasWaterFluidSystem.hpp:88
static std::string_view componentName(unsigned compIdx)
Return the human readable name of a component.
Definition: GenericOilGasWaterFluidSystem.hpp:287
Specifies the parameter cache used by the SPE-5 fluid system.
static void setWaterPvt(std::shared_ptr< WaterPvt > pvtObj)
Set the pressure-volume-saturation (PVT) relations for the water phase.
Definition: GenericOilGasWaterFluidSystem.hpp:187
The base class for all fluid systems.