opm-simulators
WellState.hpp
1 /*
2  Copyright 2014 SINTEF ICT, Applied Mathematics.
3  Copyright 2017 IRIS AS
4 
5  This file is part of the Open Porous Media project (OPM).
6 
7  OPM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  OPM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with OPM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
22 #define OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
23 
24 #include <dune/common/version.hh>
25 #include <dune/common/parallel/mpihelper.hh>
26 
27 #include <opm/common/ErrorMacros.hpp>
28 
29 #include <opm/material/fluidsystems/PhaseUsageInfo.hpp>
30 
31 #include <opm/input/eclipse/Schedule/Events.hpp>
32 
33 #include <opm/output/data/Wells.hpp>
34 
35 #include <opm/simulators/wells/GlobalWellInfo.hpp>
36 #include <opm/simulators/wells/PerfData.hpp>
37 #include <opm/simulators/wells/SegmentState.hpp>
38 #include <opm/simulators/wells/SingleWellState.hpp>
39 #include <opm/simulators/wells/WellContainer.hpp>
40 
41 #include <opm/simulators/utils/ParallelCommunication.hpp>
42 
43 #include <algorithm>
44 #include <cstddef>
45 #include <cstdint>
46 #include <functional>
47 #include <map>
48 #include <optional>
49 #include <string>
50 #include <utility>
51 #include <vector>
52 
53 namespace Opm
54 {
55 
56 template<class Scalar> class ParallelWellInfo;
57 template<class Scalar> struct PerforationData;
58 template<class Scalar> class ConnFracStatistics;
59 class Schedule;
60 enum class WellStatus : std::uint8_t;
61 
64 template<typename Scalar, typename IndexTraits>
65 class WellState
66 {
67 public:
68  struct RsConstInfo
69  {
70  RsConstInfo() = default;
71  RsConstInfo(const bool en, const Scalar val)
72  : enabled { en }
73  , value { val }
74  {}
75 
76  // True when RSCONST-based reporting should be applied.
77  bool enabled {false};
78 
79  // Constant Rs value (surface gas volume per surface oil volume).
80  Scalar value {};
81  };
82 
83  static const std::uint64_t event_mask = ScheduleEvents::WELL_STATUS_CHANGE
84  | ScheduleEvents::PRODUCTION_UPDATE
85  | ScheduleEvents::INJECTION_UPDATE;
86 
87  // TODO: same definition with WellInterface, eventually they should go to a common header file.
88 
89  // TODO: trying to PhasedIdx to make it more explicit as phase index, will evaluate how it goes.
90  // TODO: eventually, we should distinguish phase index and component index
91  static const int waterPhaseIdx = IndexTraits::waterPhaseIdx;
92  static const int oilPhaseIdx = IndexTraits::oilPhaseIdx;
93  static const int gasPhaseIdx = IndexTraits::gasPhaseIdx;
94 
95  // Only usable for testing purposes
96  explicit WellState(const ParallelWellInfo<Scalar>& pinfo);
97 
98  explicit WellState(const PhaseUsageInfo<IndexTraits>& pu)
99  : phaseUsageInfo_(pu)
100  {}
101 
102  static WellState serializationTestObject(const ParallelWellInfo<Scalar>& pinfo);
103 
104  std::size_t size() const
105  {
106  return this->wells_.size();
107  }
108 
109  std::vector<std::string> wells() const
110  {
111  return this->wells_.wells();
112  }
113 
114  int numWells() const
115  {
116  return this->size();
117  }
118 
119  // TODO: temporary naming during development, will change to phaseUsage() later
120  const PhaseUsageInfo<IndexTraits>& phaseUsageInfo() const
121  {
122  return this->phaseUsageInfo_;
123  }
124 
125  const ParallelWellInfo<Scalar>& parallelWellInfo(std::size_t well_index) const;
126 
130  void init(const std::vector<Scalar>& cellPressures,
131  const std::vector<Scalar>& cellTemperatures,
132  const Schedule& schedule,
133  const std::vector<Well>& wells_ecl,
134  const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
135  const int report_step,
136  const WellState* prevState,
137  const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
138  const SummaryState& summary_state,
139  const bool enableDistributedWells);
140 
141  void resize(const std::vector<Well>& wells_ecl,
142  const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
143  const Schedule& schedule,
144  const bool handle_ms_well,
145  const std::size_t numCells,
146  const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
147  const SummaryState& summary_state,
148  const bool enable_distributed_wells,
149  const bool thermal);
150 
151  void setCurrentWellRates(const std::string& wellName,
152  const std::vector<Scalar>& new_rates)
153  {
154  auto& [owner, rates] = this->well_rates.at(wellName);
155  if (owner)
156  rates = new_rates;
157  }
158 
159  const std::vector<Scalar>& currentWellRates(const std::string& wellName) const;
160 
161  bool hasWellRates(const std::string& wellName) const
162  {
163  return this->well_rates.find(wellName) != this->well_rates.end();
164  }
165 
166  void clearWellRates()
167  {
168  this->well_rates.clear();
169  }
170 
171  void gatherVectorsOnRoot(const std::vector<data::Connection>& from_connections,
172  std::vector<data::Connection>& to_connections,
173  const Parallel::Communication& comm) const;
174 
175  data::Wells
176  report(const int* globalCellIdxMap,
177  const std::function<bool(const std::size_t)>& wasDynamicallyClosed,
178  const RsConstInfo& rsConst = RsConstInfo{}) const;
179 
180  void reportConnections(std::vector<data::Connection>& connections,
181  std::size_t well_index,
182  const int* globalCellIdxMap) const;
183 
187  void initWellStateMSWell(const std::vector<Well>& wells_ecl,
188  const WellState* prev_well_state,
189  const bool thermal);
190 
191  static void calculateSegmentRates(const ParallelWellInfo<Scalar>& pw_info,
192  const std::vector<std::vector<int>>& segment_inlets,
193  const std::vector<std::vector<int>>& segment_perforations,
194  const std::vector<Scalar>& perforation_rates,
195  const int np,
196  const int segment,
197  std::vector<Scalar>& segment_rates);
198 
199 
200  void communicateGroupRates(const Parallel::Communication& comm);
201 
202  void updateGlobalIsGrup(const Parallel::Communication& comm,
203  const std::vector<WellStatus>& well_status);
204  void updateEfficiencyScalingFactor(const std::string& wellName,
205  const Scalar value);
206 
207  bool isInjectionGrup(const std::string& name) const
208  {
209  return this->global_well_info.value().in_injecting_group(name);
210  }
211 
212  bool isProductionGrup(const std::string& name) const
213  {
214  return this->global_well_info.value().in_producing_group(name);
215  }
216 
217  bool isOpen(const std::string& name) const
218  {
219  return this->global_well_info.value().is_open(name);
220  }
221 
222  Scalar getGlobalEfficiencyScalingFactor(const std::string& name) const
223  {
224  return this->global_well_info.value().efficiency_scaling_factor(name);
225  }
226 
227  // If the ALQ has changed since the previous time step,
228  // reset current_alq and update default_alq. ALQ is used for
229  // constant lift gas injection and for gas lift optimization
230  // (THP controlled wells).
231  void updateWellsDefaultALQ(const Schedule& schedule,
232  const int report_step,
233  const SummaryState& summary_state);
234 
235  void gliftTimeStepInit()
236  {
237  for (size_t i = 0; i < this->size(); ++i) {
238  this->wells_[i].alq_state.reset_count();
239  }
240  }
241 
242 
243  int wellNameToGlobalIdx(const std::string& name)
244  {
245  return this->global_well_info.value().well_index(name);
246  }
247 
248  std::string globalIdxToWellName(const int index)
249  {
250  return this->global_well_info.value().well_name(index);
251  }
252 
253  bool wellIsOwned(std::size_t well_index,
254  const std::string& wellName) const;
255 
256  bool wellIsOwned(const std::string& wellName) const;
257 
258  bool isRank0() const {
259  return this->global_well_info.value().isRank0();
260  }
261 
262  void updateStatus(std::size_t well_index, WellStatus status);
263 
264  void openWell(std::size_t well_index);
265  void shutWell(std::size_t well_index);
266  void stopWell(std::size_t well_index);
267 
269  constexpr int numPhases() const
270  {
271  return phaseUsageInfo_.numActivePhases();
272  }
273 
275  std::vector<Scalar>& wellRates(std::size_t well_index)
276  { return this->wells_[well_index].surface_rates; }
277  const std::vector<Scalar>& wellRates(std::size_t well_index) const
278  { return this->wells_[well_index].surface_rates; }
279 
280  const std::string& name(std::size_t well_index) const
281  {
282  return this->wells_.well_name(well_index);
283  }
284 
285  std::optional<std::size_t> index(const std::string& well_name) const
286  {
287  return this->wells_.well_index(well_name);
288  }
289 
290  const SingleWellState<Scalar, IndexTraits>& operator[](std::size_t well_index) const
291  {
292  return this->wells_[well_index];
293  }
294 
295  const SingleWellState<Scalar, IndexTraits>& operator[](const std::string& well_name) const
296  {
297  return this->wells_[well_name];
298  }
299 
300  SingleWellState<Scalar, IndexTraits>& operator[](std::size_t well_index)
301  {
302  return this->wells_[well_index];
303  }
304 
305  SingleWellState<Scalar, IndexTraits>& operator[](const std::string& well_name)
306  {
307  return this->wells_[well_name];
308  }
309 
310  const SingleWellState<Scalar, IndexTraits>& well(std::size_t well_index) const
311  {
312  return this->operator[](well_index);
313  }
314 
315  const SingleWellState<Scalar, IndexTraits>& well(const std::string& well_name) const
316  {
317  return this->operator[](well_name);
318  }
319 
320  SingleWellState<Scalar, IndexTraits>& well(std::size_t well_index)
321  {
322  return this->operator[](well_index);
323  }
324 
325  SingleWellState<Scalar, IndexTraits>& well(const std::string& well_name)
326  {
327  return this->operator[](well_name);
328  }
329 
330  bool has(const std::string& well_name) const
331  {
332  return this->wells_.has(well_name);
333  }
334 
335  bool operator==(const WellState&) const;
336 
337  template<class Serializer>
338  void serializeOp(Serializer& serializer)
339  {
340  serializer(well_rates);
341  if (serializer.isSerializing()) {
342  serializer(wells_.size());
343  } else {
344  std::size_t serialized_size = 0;
345  serializer(serialized_size);
346  if (serialized_size != wells_.size()) {
347  OPM_THROW(std::runtime_error, "Error deserializing WellState: size mismatch");
348  }
349  }
350  for (auto& w : wells_) {
351  serializer(w);
352  }
353  serializer(permanently_inactive_well_names_);
354  }
355 
356  bool is_permanently_inactive_well(const std::string& wname) const {
357  return std::ranges::find(this->permanently_inactive_well_names_, wname) !=
358  this->permanently_inactive_well_names_.end();
359  }
360 
361 private:
362  bool enableDistributedWells_ = false;
363 
364  PhaseUsageInfo<IndexTraits> phaseUsageInfo_;
365 
366  // The wells_ variable is essentially a map of all the wells on the current
367  // process. Observe that since a well can be split over several processes a
368  // well might appear in the WellContainer on different processes.
369  WellContainer<SingleWellState<Scalar, IndexTraits>> wells_;
370 
371  // The members global_well_info and well_rates are map like
372  // structures which will have entries for *all* the wells in the system.
373 
374  // Use of std::optional<> here is a technical crutch, the
375  // WellStateFullyImplicitBlackoil class should be default constructible,
376  // whereas the GlobalWellInfo is not.
377  std::optional<GlobalWellInfo<Scalar>> global_well_info;
378 
379  // The well_rates variable is defined for all wells on all processors. The
380  // bool in the value pair is whether the current process owns the well or
381  // not.
382  std::map<std::string, std::pair<bool, std::vector<Scalar>>> well_rates;
383 
384  // Keep track of permanently inactive well names
385  std::vector<std::string> permanently_inactive_well_names_;
386 
387  data::Segment
388  reportSegmentResults(const int well_id,
389  const int seg_ix,
390  const int seg_no) const;
391 
392 
398  void base_init(const std::vector<Scalar>& cellPressures,
399  const std::vector<Scalar>& cellTemperatures,
400  const std::vector<Well>& wells_ecl,
401  const std::vector<std::reference_wrapper<ParallelWellInfo<Scalar>>>& parallel_well_info,
402  const std::vector<std::vector<PerforationData<Scalar>>>& well_perf_data,
403  const SummaryState& summary_state);
404 
405  void initSingleWell(const std::vector<Scalar>& cellPressures,
406  const std::vector<Scalar>& cellTemperatures,
407  const Well& well,
408  const std::vector<PerforationData<Scalar>>& well_perf_data,
409  const ParallelWellInfo<Scalar>& well_info,
410  const SummaryState& summary_state);
411 
412  void initSingleProducer(const Well& well,
413  const ParallelWellInfo<Scalar>& well_info,
414  Scalar pressure_first_connection,
415  Scalar temperature_first_connection,
416  const std::vector<PerforationData<Scalar>>& well_perf_data,
417  const SummaryState& summary_state);
418 
419  void initSingleInjector(const Well& well,
420  const ParallelWellInfo<Scalar>& well_info,
421  Scalar pressure_first_connection,
422  Scalar temperature_first_connection,
423  const std::vector<PerforationData<Scalar>>& well_perf_data,
424  const SummaryState& summary_state);
425 
426  static void calculateSegmentRatesBeforeSum(const ParallelWellInfo<Scalar>& pw_info,
427  const std::vector<std::vector<int>>& segment_inlets,
428  const std::vector<std::vector<int>>& segment_perforations,
429  const std::vector<Scalar>& perforation_rates,
430  const int np,
431  const int segment,
432  std::vector<Scalar>& segment_rates);
433 
434  void reportConnectionFactors(const std::size_t well_index,
435  std::vector<data::Connection>& connections) const;
436 
437  void reportConnectionPressuresAndRates(const std::size_t well_index,
438  std::vector<data::Connection>& connections) const;
439 
440  void reportConnectionFilterCake(const std::size_t well_index,
441  std::vector<data::Connection>& connections) const;
442 
443  void reportFractureStatistics(const std::vector<ConnFracStatistics<Scalar>>& stats,
444  std::vector<data::Connection>& connections) const;
445 };
446 
447 } // namespace Opm
448 
449 // TODO: we are missing pu, while it was not there in the first place
450 #endif // OPM_WELLSTATEFULLYIMPLICITBLACKOIL_HEADER_INCLUDED
std::vector< Scalar > & wellRates(std::size_t well_index)
One rate per well and phase.
Definition: WellState.hpp:275
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Definition: WellState.hpp:68
Class encapsulating some information about parallel wells.
Definition: MSWellHelpers.hpp:34
Definition: GasLiftGroupInfo.hpp:38
constexpr int numPhases() const
The number of phases present.
Definition: WellState.hpp:269
The state of a set of wells, tailored for use by the fully implicit blackoil simulator.
Definition: TemperatureModel.hpp:65