opm-simulators
PyBaseSimulator_impl.hpp
1 /*
2  Copyright 2025 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_BASE_SIMULATOR_IMPL_HEADER_INCLUDED
20 #define OPM_PY_BASE_SIMULATOR_IMPL_HEADER_INCLUDED
21 
22 // Improve IDE experience
23 #ifndef OPM_PY_BASE_SIMULATOR_HEADER_INCLUDED
24 #include <config.h>
25 #include <opm/simulators/flow/python/PyBaseSimulator.hpp>
26 #endif
27 
28 #include <stdexcept>
29 
30 namespace py = pybind11;
31 
32 namespace Opm::Pybind {
33 
34 template<class TypeTag>
35 PyBaseSimulator<TypeTag>::PyBaseSimulator(const std::string& deck_filename,
36  const std::vector<std::string>& args)
37  : deck_filename_{deck_filename}
38  , args_{args}
39 {
40 }
41 
42 template<class TypeTag>
43 PyBaseSimulator<TypeTag>::
44 PyBaseSimulator(std::shared_ptr<Deck> deck,
45  std::shared_ptr<EclipseState> state,
46  std::shared_ptr<Schedule> schedule,
47  std::shared_ptr<SummaryConfig> summary_config,
48  const std::vector<std::string>& args)
49  : deck_{std::move(deck)}
50  , eclipse_state_{std::move(state)}
51  , schedule_{std::move(schedule)}
52  , summary_config_{std::move(summary_config)}
53  , args_{args}
54 {
55 }
56 
57 // Public methods alphabetically sorted
58 // ------------------------------------
59 template<class TypeTag>
60 void PyBaseSimulator<TypeTag>::advance(int report_step)
61 {
62  while (currentStep() < report_step) {
63  step();
64  }
65 }
66 
67 template<class TypeTag>
68 bool PyBaseSimulator<TypeTag>::checkSimulationFinished()
69 {
70  return getFlowMain().getSimTimer()->done();
71 }
72 
73 // This returns the report step number that will be executed next time step()
74 // is called.
75 template<class TypeTag>
76 int PyBaseSimulator<TypeTag>::currentStep()
77 {
78  return getFlowMain().getSimTimer()->currentStepNum();
79  // NOTE: this->simulator_->episodeIndex() would also return the current
80  // report step number, but this number is always delayed by 1 step relative
81  // to this->flow_main_->getSimTimer()->currentStepNum()
82  // See details in runStep() in file SimulatorFullyImplicitBlackoilEbos.hpp
83 }
84 
85 template<class TypeTag>
86 py::array_t<double>
87 PyBaseSimulator<TypeTag>::getCellVolumes()
88 {
89  auto vector = getMaterialState().getCellVolumes();
90  return py::array(vector.size(), vector.data());
91 }
92 
93 template<class TypeTag>
94 double PyBaseSimulator<TypeTag>::getDT()
95 {
96  return getFlowMain().getPreviousReportStepSize();
97 }
98 
99 template<class TypeTag>
100 py::array_t<double>
101 PyBaseSimulator<TypeTag>::getPorosity()
102 {
103  auto vector = getMaterialState().getPorosity();
104  return py::array(vector.size(), vector.data());
105 }
106 
107 template<class TypeTag>
108 py::array_t<double>
109 PyBaseSimulator<TypeTag>::
110 getFluidStateVariable(const std::string& name) const
111 {
112  auto vector = getFluidState().getFluidStateVariable(name);
113  return py::array(vector.size(), vector.data());
114 }
115 
116 template<class TypeTag>
117 py::array_t<double>
118 PyBaseSimulator<TypeTag>::
119 getPrimaryVariable(const std::string& variable) const
120 {
121  auto vector = getFluidState().getPrimaryVariable(variable);
122  return py::array(vector.size(), vector.data());
123 }
124 
125 template<class TypeTag>
126 py::array_t<int>
127 PyBaseSimulator<TypeTag>::
128 getPrimaryVarMeaning(const std::string& variable) const
129 {
130  auto vector = getFluidState().getPrimaryVarMeaning(variable);
131  return py::array(vector.size(), vector.data());
132 }
133 
134 template<class TypeTag>
135 std::map<std::string, int>
136 PyBaseSimulator<TypeTag>::
137 getPrimaryVarMeaningMap(const std::string& variable) const
138 {
139 
140  return getFluidState().getPrimaryVarMeaningMap(variable);
141 }
142 
143 template<class TypeTag>
144 void PyBaseSimulator<TypeTag>::setPorosity(PyCArray array)
145 {
146  std::size_t size_ = array.size();
147  const double *poro = array.data();
148  getMaterialState().setPorosity(poro, size_);
149 }
150 
151 template<class TypeTag>
152 void
153 PyBaseSimulator<TypeTag>::
154 setPrimaryVariable(const std::string& variable,
155  PyCArray array)
156 {
157  std::size_t size_ = array.size();
158  const double *data = array.data();
159  getFluidState().setPrimaryVariable(variable, data, size_);
160 }
161 
162 template<class TypeTag>
163 void PyBaseSimulator<TypeTag>::
164 setupMpi(bool mpi_init, bool mpi_finalize)
165 {
166  if (this->has_run_init_) {
167  throw std::logic_error("mpi_init() called after step_init()");
168  }
169  this->mpi_init_ = mpi_init;
170  this->mpi_finalize_ = mpi_finalize;
171 }
172 
173 template<class TypeTag>
174 int PyBaseSimulator<TypeTag>::step()
175 {
176  if (!this->has_run_init_) {
177  throw std::logic_error("step() called before step_init()");
178  }
179  if (this->has_run_cleanup_) {
180  throw std::logic_error("step() called after step_cleanup().");
181  }
182  if(checkSimulationFinished()) {
183  throw std::logic_error("step() called, but simulation is done");
184  }
185  auto result = getFlowMain().executeStep();
186  return result;
187 }
188 
189 template<class TypeTag>
190 int PyBaseSimulator<TypeTag>::stepCleanup()
191 {
192  this->has_run_cleanup_ = true;
193  return getFlowMain().executeStepsCleanup();
194 }
195 
196 template<class TypeTag>
197 int PyBaseSimulator<TypeTag>::stepInit()
198 {
199  if (this->has_run_init_) {
200  // Running step_init() multiple times is not implemented yet,
201  if (this->has_run_cleanup_) {
202  throw std::logic_error("step_init() called again");
203  }
204  else {
205  return EXIT_SUCCESS;
206  }
207  }
208  if (this->deck_) {
209  this->main_ = std::make_unique<PyMain<TypeTag>>(
210  this->deck_->getDataFile(),
211  this->eclipse_state_,
212  this->schedule_,
213  this->summary_config_,
214  this->mpi_init_,
215  this->mpi_finalize_
216  );
217  }
218  else {
219  this->main_ = std::make_unique<PyMain<TypeTag>>(
220  this->deck_filename_,
221  this->mpi_init_,
222  this->mpi_finalize_
223  );
224  }
225  this->main_->setArguments(args_);
226  int exit_code = EXIT_SUCCESS;
227  this->flow_main_ = this->main_->initFlowBlackoil(exit_code);
228  if (this->flow_main_) {
229  const int result = this->flow_main_->executeInitStep();
230  this->has_run_init_ = true;
231  this->simulator_ = this->flow_main_->getSimulatorPtr();
232  this->fluid_state_ = std::make_unique<PyFluidState<TypeTag>>(this->simulator_);
233  this->material_state_ = std::make_unique<PyMaterialState<TypeTag>>(this->simulator_);
234  return result;
235  }
236  else {
237  return exit_code;
238  }
239 }
240 
241 template<class TypeTag>
242 int PyBaseSimulator<TypeTag>::run()
243 {
244  auto main_object = Main( this->deck_filename_ );
245  return main_object.runStatic<TypeTag>();
246 }
247 
248 // Private methods
249 // ---------------
250 template<class TypeTag>
251 FlowMain<TypeTag>&
252 PyBaseSimulator<TypeTag>::getFlowMain() const
253 {
254  if (this->flow_main_) {
255  return *this->flow_main_;
256  }
257  else {
258  throw std::runtime_error(
259  "BlackOilSimulator not initialized: "
260  "Cannot get reference to FlowMain object"
261  );
262  }
263 }
264 
265 template<class TypeTag>
266 PyFluidState<TypeTag>&
267 PyBaseSimulator<TypeTag>::getFluidState() const
268 {
269  if (this->fluid_state_) {
270  return *this->fluid_state_;
271  }
272  else {
273  throw std::runtime_error(
274  "BlackOilSimulator not initialized: "
275  "Cannot get reference to fluid state object"
276  );
277  }
278 }
279 
280 template<class TypeTag>
281 PyMaterialState<TypeTag>&
282 PyBaseSimulator<TypeTag>::getMaterialState() const
283 {
284  if (this->material_state_) {
285  return *this->material_state_;
286  }
287  else {
288  throw std::runtime_error(
289  "BlackOilSimulator not initialized: "
290  "Cannot get reference to material state object"
291  );
292  }
293 }
294 
295 } // namespace Opm::Pybind
296 
297 #endif // OPM_PY_BASE_SIMULATOR_IMPL_HEADER_INCLUDED
Definition: PyBaseSimulator.hpp:41