opm-simulators
PyFluidState_impl.hpp
1 /*
2  Copyright 2023 Equinor ASA.
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 #ifndef OPM_PY_FLUID_STATE_IMPL_HEADER_INCLUDED
20 #define OPM_PY_FLUID_STATE_IMPL_HEADER_INCLUDED
21 
22 // Improve IDE experience
23 #ifndef OPM_PY_FLUID_STATE_HEADER_INCLUDED
24 #include <config.h>
25 #include <opm/simulators/flow/python/PyFluidState.hpp>
26 #endif
27 
28 #include <opm/material/common/MathToolbox.hpp>
29 
30 #include <stdexcept>
31 
32 #include <fmt/format.h>
33 
34 namespace Opm::Pybind {
35 
36 template <class TypeTag>
37 PyFluidState<TypeTag>::
38 PyFluidState(Simulator* simulator)
39  : simulator_(simulator)
40 {}
41 
42 // Public methods alphabetically sorted
43 // ------------------------------------
44 
45 template <class TypeTag>
46 std::vector<int>
47 PyFluidState<TypeTag>::
48 getPrimaryVarMeaning(const std::string& variable) const
49 {
50  Model& model = this->simulator_->model();
51  auto& sol = model.solution(/*timeIdx*/0);
52  const auto size = model.numGridDof();
53  std::vector<int> array(size);
54  for (unsigned dof_idx = 0; dof_idx < size; ++dof_idx) {
55  auto primary_vars = sol[dof_idx];
56  array[dof_idx] = getVariableMeaning_(primary_vars, variable);
57  }
58  return array;
59 }
60 
61 template <class TypeTag>
62 std::map<std::string, int>
63 PyFluidState<TypeTag>::
64 getPrimaryVarMeaningMap(const std::string& variable) const
65 {
66  if (variable.compare("pressure") == 0) {
67  return {{ "Po", static_cast<int>(PrimaryVariables::PressureMeaning::Po) },
68  { "Pw", static_cast<int>(PrimaryVariables::PressureMeaning::Pw) },
69  { "Pg", static_cast<int>(PrimaryVariables::PressureMeaning::Pg) }};
70  }
71  else if (variable.compare("water") == 0) {
72  return {{ "Sw", static_cast<int>(PrimaryVariables::WaterMeaning::Sw) },
73  { "Rvw", static_cast<int>(PrimaryVariables::WaterMeaning::Rvw) },
74  { "Rsw", static_cast<int>(PrimaryVariables::WaterMeaning::Rsw) },
75  { "Disabled", static_cast<int>(PrimaryVariables::WaterMeaning::Disabled) }};
76  }
77  else if (variable.compare("gas") == 0) {
78  return {{ "Sg", static_cast<int>(PrimaryVariables::GasMeaning::Sg) },
79  { "Rs", static_cast<int>(PrimaryVariables::GasMeaning::Rs) },
80  { "Rv", static_cast<int>(PrimaryVariables::GasMeaning::Rv) },
81  { "Disabled", static_cast<int>(PrimaryVariables::GasMeaning::Disabled) }};
82  }
83  else if (variable.compare("brine") == 0) {
84  return {{ "Cs", static_cast<int>(PrimaryVariables::BrineMeaning::Cs) },
85  { "Sp", static_cast<int>(PrimaryVariables::BrineMeaning::Sp) },
86  { "Disabled", static_cast<int>(PrimaryVariables::BrineMeaning::Disabled) }};
87  }
88  else {
89  const std::string msg = fmt::format(
90  "Unknown variable meaning '{}': Expected pressure, water, gas, or brine", variable);
91  throw std::runtime_error(msg);
92  }
93 }
94 
95 /* Meaning of the primary variables: Sw, Sg, po, pg, Rs, Rv
96  * 1. Sw_po_Sg -> threephase case
97  * 2. Sw_po_Rs -> water + oil case
98  * 3. Sw_pg_Rv -> water + gas case
99  */
100 
101 /* Variables:
102  Sw = Water saturation,
103  So = Oil saturation,
104  Sg = Gas saturation,
105  pw = Water pressure,
106  po = Oil pressure,
107  pg = Gas pressure,
108  Rs = The solution gas oil ratio: The amount of gas dissolved in the oil
109  Rv = The oil vaporization factor of the gas phase
110  invB = The inverse formation volume factor of a fluid phase
111  rho_w = Water density,
112  rho_o = Oil density,
113  rho_g = Gas density,
114  mu_w = Water viscosity,
115  mu_o = Oil viscosity,
116  mu_g = Gas viscosity,
117  kr_w = Water relperm,
118  kr_o = Oil relperm,
119  kr_g = Gas relperm,
120  */
121 template <class TypeTag>
122 std::vector<double>
123 PyFluidState<TypeTag>::
124 getFluidStateVariable(const std::string& name) const
125 {
126  Model& model = this->simulator_->model();
127  const auto size = model.numGridDof();
128  std::vector<double> array(size);
129  const auto& grid_view = this->simulator_->vanguard().gridView();
130  /* NOTE: grid_view.size(0) should give the same value as
131  * model.numGridDof()
132  */
133  ElementContext elem_ctx(*this->simulator_);
134  auto var_type = getVariableType_(name);
135  for (const auto& elem : elements(grid_view, Dune::Partitions::interior)) {
136  elem_ctx.updatePrimaryStencil(elem);
137  elem_ctx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
138  for (unsigned dof_idx = 0; dof_idx < elem_ctx.numPrimaryDof(/*timeIdx=*/0); ++dof_idx) {
139  const auto& int_quants = elem_ctx.intensiveQuantities(dof_idx, /*timeIdx=*/0);
140  const auto& fs = int_quants.fluidState();
141  unsigned global_dof_idx = elem_ctx.globalSpaceIndex(dof_idx, /*timeIdx=*/0);
142  array[global_dof_idx] = getVariableValue_(fs, var_type, name);
143  }
144  }
145  return array;
146 }
147 
148 template <class TypeTag>
149 std::vector<double>
150 PyFluidState<TypeTag>::
151 getPrimaryVariable(const std::string& idx_name) const
152 {
153  std::size_t primary_var_idx = getPrimaryVarIndex_(idx_name);
154  Model& model = this->simulator_->model();
155  auto& sol = model.solution(/*timeIdx*/0);
156  const auto size = model.numGridDof();
157  std::vector<double> array(size);
158  for (unsigned dof_idx = 0; dof_idx < size; ++dof_idx) {
159  auto primary_vars = sol[dof_idx];
160  array[dof_idx] = primary_vars[primary_var_idx];
161  }
162  return array;
163 }
164 
165 template <class TypeTag>
166 void
167 PyFluidState<TypeTag>::
168 setPrimaryVariable(const std::string& idx_name,
169  const double* data,
170  std::size_t size)
171 {
172  const std::size_t primary_var_idx = getPrimaryVarIndex_(idx_name);
173  Model& model = this->simulator_->model();
174  auto& sol = model.solution(/*timeIdx*/0);
175  const auto model_size = model.numGridDof();
176  if (model_size != size) {
177  const std::string msg = fmt::format(
178  "Cannot set primary variable. Expected array of size {} but got array of size: {}",
179  model_size, size);
180  throw std::runtime_error(msg);
181  }
182  for (unsigned dof_idx = 0; dof_idx < size; ++dof_idx) {
183  auto& primary_vars = sol[dof_idx];
184  primary_vars[primary_var_idx] = data[dof_idx];
185  }
186 }
187 
188 // Private methods alphabetically sorted
189 // -------------------------------------
190 
191 template <class TypeTag>
192 std::size_t
193 PyFluidState<TypeTag>::
194 getPrimaryVarIndex_(const std::string& idx_name) const
195 {
196  if (idx_name.compare("pressure") == 0) {
197  return Indices::pressureSwitchIdx;
198  }
199  else if (idx_name.compare("water_saturation") == 0) {
200  return Indices::waterSwitchIdx;
201  }
202  else if (idx_name.compare("composition") == 0) {
203  return Indices::compositionSwitchIdx;
204  }
205  else {
206  const std::string msg = fmt::format("Unknown primary variable index name: {}", idx_name);
207  throw std::runtime_error(msg);
208  }
209 }
210 
211 template <class TypeTag>
212 int
213 PyFluidState<TypeTag>::
214 getVariableMeaning_(PrimaryVariables& primary_vars,
215  const std::string& variable) const
216 {
217  if (variable.compare("pressure") == 0) {
218  return static_cast<int>(primary_vars.primaryVarsMeaningPressure());
219  }
220  else if(variable.compare("water") == 0) {
221  return static_cast<int>(primary_vars.primaryVarsMeaningWater());
222  }
223  else if (variable.compare("gas") == 0) {
224  return static_cast<int>(primary_vars.primaryVarsMeaningGas());
225  }
226  else if (variable.compare("brine") == 0) {
227  return static_cast<int>(primary_vars.primaryVarsMeaningBrine());
228  }
229  else {
230  const std::string msg = fmt::format(
231  "Unknown variable meaning '{}': Expected pressure, water, gas, or brine", variable);
232  throw std::runtime_error(msg);
233  }
234 }
235 
236 template <class TypeTag>
237 typename PyFluidState<TypeTag>::VariableType
238 PyFluidState<TypeTag>::
239 getVariableType_(const std::string& name) const
240 {
241  static std::map<std::string, VariableType> variable_type_map{
242  {"Sw", VariableType::Sw},
243  {"Sg", VariableType::Sg},
244  {"So", VariableType::So},
245  {"pw", VariableType::pw},
246  {"pg", VariableType::pg},
247  {"po", VariableType::po},
248  {"Rs", VariableType::Rs},
249  {"Rv", VariableType::Rv},
250  {"rho_w", VariableType::rho_w},
251  {"rho_g", VariableType::rho_g},
252  {"rho_o", VariableType::rho_o},
253  {"T", VariableType::T}
254  };
255 
256  if (variable_type_map.count(name) == 0) {
257  variableNotFoundError_(name);
258  }
259  return variable_type_map.at(name);
260 }
261 
262 template <class TypeTag>
263 template <class FluidState>
264 double
265 PyFluidState<TypeTag>::
266 getVariableValue_(FluidState& fs,
267  VariableType var_type,
268  const std::string& name) const
269 {
270  switch(var_type) {
271  case VariableType::pw :
272  return getValue(fs.pressure(FluidSystem::waterPhaseIdx));
273  case VariableType::pg :
274  return getValue(fs.pressure(FluidSystem::gasPhaseIdx));
275  case VariableType::po :
276  return getValue(fs.pressure(FluidSystem::oilPhaseIdx));
277  case VariableType::rho_w :
278  return getValue(fs.density(FluidSystem::waterPhaseIdx));
279  case VariableType::rho_g :
280  return getValue(fs.density(FluidSystem::gasPhaseIdx));
281  case VariableType::rho_o :
282  return getValue(fs.density(FluidSystem::oilPhaseIdx));
283  case VariableType::Rs :
284  return getValue(fs.Rs());
285  case VariableType::Rv :
286  return getValue(fs.Rv());
287  case VariableType::Sw :
288  return getValue(fs.saturation(FluidSystem::waterPhaseIdx));
289  case VariableType::Sg :
290  return getValue(fs.saturation(FluidSystem::gasPhaseIdx));
291  case VariableType::So :
292  return getValue(fs.saturation(FluidSystem::oilPhaseIdx));
293  case VariableType::T :
294  return getValue(fs.temperature(FluidSystem::waterPhaseIdx));
295  default:
296  variableNotFoundError_(name);
297  return 0.0; // unreachable, shut up compiler
298  }
299 }
300 
301 template <class TypeTag>
302 void
303 PyFluidState<TypeTag>::
304 variableNotFoundError_(const std::string& name) const
305 {
306  const std::string msg = fmt::format("Access to variable '{}' is not implemented yet!", name);
307  throw std::runtime_error(msg);
308 }
309 
310 } // namespace Opm::Pybind
311 
312 #endif // OPM_PY_FLUID_STATE_IMPL_HEADER_INCLUDED
Definition: PyBaseSimulator.hpp:41