opm-simulators
CompWellFlash.hpp
1 /*
2  Copyright 2026, SINTEF Digital
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 3 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 
20 #ifndef OPM_COMP_WELL_FLASH_HPP
21 #define OPM_COMP_WELL_FLASH_HPP
22 
23 #include <opm/material/Constants.hpp>
24 #include <opm/material/constraintsolvers/PTFlash.hpp>
25 #include <opm/material/densead/Math.hpp>
26 #include <opm/material/fluidstates/CompositionalFluidState.hpp>
27 
28 #include <opm/input/eclipse/EclipseState/Compositional/CompositionalConfig.hpp>
29 
30 #include <array>
31 #include <type_traits>
32 
33 namespace Opm {
34 
53 template <typename FluidSystem, typename T>
54 void flashWellboreFluidState(CompositionalFluidState<T, FluidSystem>& fluid_state,
55  const typename FluidSystem::Scalar flash_tolerance = 1.e-6)
56 {
57  using Scalar = typename FluidSystem::Scalar;
58  using EOSType = CompositionalConfig::EOSType;
59 
60  bool single_phase = false;
61  if constexpr (std::is_same_v<T, Scalar>) {
62  single_phase = PTFlash<Scalar, FluidSystem>::flash_solve_scalar_(fluid_state, "ssi", flash_tolerance, EOSType::PR);
63  } else { // Evaluation
64  single_phase = PTFlash<Scalar, FluidSystem>::solve(fluid_state, "ssi", flash_tolerance, EOSType::PR);
65  }
66 
67  constexpr Scalar R = Constants<Scalar>::R;
68  typename FluidSystem::template ParameterCache<T> param_cache {EOSType::PR};
69  param_cache.updatePhase(fluid_state, FluidSystem::oilPhaseIdx);
70  const auto Z_L = (param_cache.molarVolume(FluidSystem::oilPhaseIdx) * fluid_state.pressure(FluidSystem::oilPhaseIdx)) /
71  (R * fluid_state.temperature(FluidSystem::oilPhaseIdx));
72  param_cache.updatePhase(fluid_state, FluidSystem::gasPhaseIdx);
73  const auto Z_V = (param_cache.molarVolume(FluidSystem::gasPhaseIdx) * fluid_state.pressure(FluidSystem::gasPhaseIdx)) /
74  (R * fluid_state.temperature(FluidSystem::gasPhaseIdx));
75 
76  auto L = fluid_state.L();
77  if (single_phase) {
78  // we check whether the phase label is correct
79  if (L > 0.9 && Z_L > 0.8) { // marked as liquid phase while compress factor shows it is gas
80  L = 0.;
81  fluid_state.setLvalue(L);
82  } else if (L < 0.1 && Z_V < 0.5) { // marked as gas phase while compress factor shows it is liquid
83  L = 1.;
84  fluid_state.setLvalue(L);
85  }
86  }
87  T So = max((L * Z_L / (L * Z_L + (1 - L) * Z_V)), 0.0);
88  T Sg = max(1 - So, 0.0);
89  T sumS = So + Sg;
90  So /= sumS;
91  Sg /= sumS;
92 
93  fluid_state.setSaturation(FluidSystem::oilPhaseIdx, So);
94  fluid_state.setSaturation(FluidSystem::gasPhaseIdx, Sg);
95 
96  fluid_state.setCompressFactor(FluidSystem::oilPhaseIdx, Z_L);
97  fluid_state.setCompressFactor(FluidSystem::gasPhaseIdx, Z_V);
98 
99  fluid_state.setDensity(FluidSystem::oilPhaseIdx, FluidSystem::density(fluid_state, param_cache, FluidSystem::oilPhaseIdx));
100  fluid_state.setDensity(FluidSystem::gasPhaseIdx, FluidSystem::density(fluid_state, param_cache, FluidSystem::gasPhaseIdx));
101 }
102 
111 template <typename FluidSystem, typename T, typename Scalar>
112 std::array<T, FluidSystem::numComponents>
113 wellboreComponentMasses(const CompositionalFluidState<T, FluidSystem>& fluid_state,
114  const Scalar wellbore_volume)
115 {
116  std::array<T, FluidSystem::numComponents> component_masses;
117 
118  const auto& so = fluid_state.saturation(FluidSystem::oilPhaseIdx);
119  const auto& sg = fluid_state.saturation(FluidSystem::gasPhaseIdx);
120  const auto& density_oil = fluid_state.density(FluidSystem::oilPhaseIdx);
121  const auto& density_gas = fluid_state.density(FluidSystem::gasPhaseIdx);
122 
123  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
124  const auto oil_mass_fraction = fluid_state.massFraction(FluidSystem::oilPhaseIdx, comp_idx);
125  const auto gas_mass_fraction = fluid_state.massFraction(FluidSystem::gasPhaseIdx, comp_idx);
126  component_masses[comp_idx] = (oil_mass_fraction * density_oil * so +
127  gas_mass_fraction * density_gas * sg) * wellbore_volume;
128  }
129 
130  return component_masses;
131 }
132 
133 } // end of namespace Opm
134 
135 #endif // OPM_COMP_WELL_FLASH_HPP
std::array< T, FluidSystem::numComponents > wellboreComponentMasses(const CompositionalFluidState< T, FluidSystem > &fluid_state, const Scalar wellbore_volume)
Mass [kg] of each component held in the wellbore control volume, given an already-flashed two-phase f...
Definition: CompWellFlash.hpp:113
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
void flashWellboreFluidState(CompositionalFluidState< T, FluidSystem > &fluid_state, const typename FluidSystem::Scalar flash_tolerance=1.e-6)
Flash the wellbore fluid at its current (pressure, temperature, overall composition) and fill in the ...
Definition: CompWellFlash.hpp:54