opm-simulators
ConvergenceReport.hpp
1 /*
2  Copyright 2018 SINTEF Digital, Mathematics and Cybernetics.
3  Copyright 2018, 2024 Equinor.
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_CONVERGENCEREPORT_HEADER_INCLUDED
22 #define OPM_CONVERGENCEREPORT_HEADER_INCLUDED
23 
24 #include <algorithm>
25 #include <cassert>
26 #include <numeric>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 namespace Opm
32 {
33 
38  {
39  public:
40 
41  // ----------- Types -----------
42 
43  enum Status {
44  AllGood = 0,
45  ReservoirFailed = 1 << 0,
46  WellFailed = 1 << 1,
47  };
48  // More severe problems should have higher numbers
49  enum struct Severity {
50  None = 0,
51  Normal = 1,
52  ConvergenceMonitorFailure = 2,
53  TooLarge = 3,
54  NotANumber = 4,
55  };
56 
57  struct PenaltyCard {
58  int nonConverged{0};
59  int distanceDecay{0};
60  int largeWellResiduals{0};
61 
62  int total() const {
63  return nonConverged + distanceDecay + largeWellResiduals;
64  }
65 
66  void reset()
67  {
68  nonConverged = 0;
69  distanceDecay = 0;
70  largeWellResiduals = 0;
71  }
72 
73  PenaltyCard& operator+=(const PenaltyCard& other) {
74  nonConverged += other.nonConverged;
75  distanceDecay += other.distanceDecay;
76  largeWellResiduals += other.largeWellResiduals;
77  return *this;
78  }
79 
80  template <typename Serializer>
81  void serializeOp(Serializer& serializer)
82  {
83  serializer(nonConverged);
84  serializer(distanceDecay);
85  serializer(largeWellResiduals);
86  }
87  };
88 
89  using CnvPvSplit = std::pair<
90  std::vector<double>,
91  std::vector<int>>;
92 
94  {
95  public:
96  enum struct Type { Invalid, MassBalance, Cnv, ConvergenceMonitorFailure };
97 
98  // Default constructor needed for object serialisation. Don't
99  // use this for anything else.
100  ReservoirFailure() = default;
101 
102  ReservoirFailure(Type t, Severity s, int phase)
103  : type_(t), severity_(s), phase_(phase)
104  {}
105 
106  Type type() const { return type_; }
107  Severity severity() const { return severity_; }
108  int phase() const { return phase_; }
109 
110  template <typename Serializer>
111  void serializeOp(Serializer& serializer)
112  {
113  serializer(this->type_);
114  serializer(this->severity_);
115  serializer(this->phase_);
116  }
117 
118  private:
119  // Note to maintainers: If you change this list of data members,
120  // then please update serializeOp() accordingly.
121  Type type_ { Type::Invalid };
122  Severity severity_ { Severity::None };
123  int phase_ { -1 };
124  };
125 
127  {
128  public:
129  // Default constructor needed for object serialisation. Don't
130  // use this for anything else.
131  ReservoirConvergenceMetric() = default;
132 
133  ReservoirConvergenceMetric(ReservoirFailure::Type t, int phase, double value, double tolerance)
134  : type_(t), phase_(phase), value_(value), tolerance_(tolerance)
135  {}
136 
137  ReservoirFailure::Type type() const { return type_; }
138  int phase() const { return phase_; }
139  double value() const { return value_; }
140  double tolerance() const { return tolerance_; }
141 
142  template <typename Serializer>
143  void serializeOp(Serializer& serializer)
144  {
145  serializer(this->type_);
146  serializer(this->phase_);
147  serializer(this->value_);
148  serializer(this->tolerance_);
149  }
150 
151  private:
152  // Note to maintainers: If you change this list of data members,
153  // then please update serializeOp() accordingly.
154  ReservoirFailure::Type type_ { ReservoirFailure::Type::Invalid };
155  int phase_ { -1 };
156  double value_ { 0.0 };
157  double tolerance_ { 0.0 };
158  };
159 
161  {
162  public:
163  enum struct Type {
164  Invalid,
165  MassBalance,
166  Pressure,
167  ControlBHP,
168  ControlTHP,
169  ControlRate,
170  Unsolvable,
171  WrongFlowDirection,
172  };
173 
174  // Default constructor needed for object serialisation. Don't
175  // use this for anything else.
176  WellFailure() = default;
177 
178  WellFailure(Type t, Severity s, int phase, const std::string& well_name)
179  : type_(t), severity_(s), phase_(phase), well_name_(well_name)
180  {}
181 
182  Type type() const { return type_; }
183  Severity severity() const { return severity_; }
184  int phase() const { return phase_; }
185  const std::string& wellName() const { return well_name_; }
186 
187  template <typename Serializer>
188  void serializeOp(Serializer& serializer)
189  {
190  serializer(this->type_);
191  serializer(this->severity_);
192  serializer(this->phase_);
193  serializer(this->well_name_);
194  }
195 
196  private:
197  // Note to maintainers: If you change this list of data members,
198  // then please update serializeOp() accordingly.
199  Type type_ { Type::Invalid };
200  Severity severity_ { Severity::None };
201  int phase_ { -1 };
202  std::string well_name_ {};
203  };
204 
206  {
207  public:
208  // Default constructor needed for object serialisation. Don't
209  // use this for anything else.
210  WellConvergenceMetric() = default;
211 
212  WellConvergenceMetric(WellFailure::Type t, Severity s, int phase, double value, const std::string& well_name)
213  : type_(t), severity_(s), phase_(phase), value_(value), well_name_(well_name)
214  {}
215 
216  WellFailure::Type type() const { return type_; }
217  Severity severity() const { return severity_; }
218  int phase() const { return phase_; }
219  double value() const { return value_; }
220  const std::string& wellName() const { return well_name_; }
221 
222  template <typename Serializer>
223  void serializeOp(Serializer& serializer)
224  {
225  serializer(this->type_);
226  serializer(this->severity_);
227  serializer(this->phase_);
228  serializer(this->value_);
229  serializer(this->well_name_);
230  }
231 
232  private:
233  // Note to maintainers: If you change this list of data members,
234  // then please update serializeOp() accordingly.
235  WellFailure::Type type_ { WellFailure::Type::Invalid };
236  Severity severity_ { Severity::None };
237  int phase_ { -1 };
238  double value_ { 0.0 };
239  std::string well_name_ {};
240  };
241 
242  // ----------- Mutating member functions -----------
243 
245  : ConvergenceReport{0.0}
246  {}
247 
248  explicit ConvergenceReport(const double reportTime)
249  : reportTime_{reportTime}
250  , status_{AllGood}
251  , res_failures_{}
252  , well_failures_{}
253  , wellGroupTargetsViolated_(false)
254  , network_needs_more_balancing_force_another_newton_iteration_(false)
255  {}
256 
257  void clear()
258  {
259  status_ = AllGood;
260  res_failures_.clear();
261  well_failures_.clear();
262  wellGroupTargetsViolated_ = false;
263  network_needs_more_balancing_force_another_newton_iteration_ = false;
264  }
265 
266  void setReservoirFailed(const ReservoirFailure& rf)
267  {
268  status_ = static_cast<Status>(status_ | ReservoirFailed);
269  res_failures_.push_back(rf);
270  }
271 
272  void setWellFailed(const WellFailure& wf)
273  {
274  status_ = static_cast<Status>(status_ | WellFailed);
275  well_failures_.push_back(wf);
276  }
277 
278  template <typename... Args>
279  void setReservoirConvergenceMetric(Args&&... args)
280  {
281  this->res_convergence_.emplace_back(std::forward<Args>(args)...);
282  }
283 
284  template <typename... Args>
285  void setWellConvergenceMetric(Args&&... args)
286  {
287  this->well_convergence_.emplace_back(std::forward<Args>(args)...);
288  }
289 
290  void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated)
291  {
292  wellGroupTargetsViolated_ = wellGroupTargetsViolated;
293  }
294 
295  void setNetworkNotYetBalancedForceAnotherNewtonIteration(const bool network_needs_more_balancing_force_another_newton_iteration)
296  {
297  network_needs_more_balancing_force_another_newton_iteration_ = network_needs_more_balancing_force_another_newton_iteration;
298  }
299 
300  void setCnvPoreVolSplit(const CnvPvSplit& cnvPvSplit,
301  const double eligiblePoreVolume)
302  {
303  this->cnvPvSplit_ = cnvPvSplit;
304  this->eligiblePoreVolume_ = eligiblePoreVolume;
305  }
306 
307  ConvergenceReport& operator+=(const ConvergenceReport& other)
308  {
309  reportTime_ = std::max(reportTime_, other.reportTime_);
310  status_ = static_cast<Status>(status_ | other.status_);
311  res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
312  well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
313  res_convergence_.insert(res_convergence_.end(), other.res_convergence_.begin(), other.res_convergence_.end());
314  well_convergence_.insert(well_convergence_.end(), other.well_convergence_.begin(), other.well_convergence_.end());
315  assert(reservoirFailed() != res_failures_.empty());
316  assert(wellFailed() != well_failures_.empty());
317  wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_);
318  network_needs_more_balancing_force_another_newton_iteration_ = (network_needs_more_balancing_force_another_newton_iteration_
319  || other.network_needs_more_balancing_force_another_newton_iteration_);
320 
321  // Note regarding the CNV pore-volume split: We depend on the
322  // fact that the quantities have already been aggregated across
323  // all MPI ranks--see the implementation of member function
324  // BlackoilModel::getReservoirConvergence() for details--and are
325  // therefore equal on all ranks. Consequently, we simply assign
326  // 'other's values here, if it is non-empty. Empty splits
327  // typically come from well contributions.
328  if (! other.cnvPvSplit_.first.empty()) {
329  this->cnvPvSplit_ = other.cnvPvSplit_;
330  this->eligiblePoreVolume_ = other.eligiblePoreVolume_;
331  }
332 
333  return *this;
334  }
335 
336  // ----------- Const member functions (queries) -----------
337 
338  double reportTime() const
339  {
340  return reportTime_;
341  }
342 
343  double eligiblePoreVolume() const
344  {
345  return this->eligiblePoreVolume_;
346  }
347 
348  const CnvPvSplit& cnvPvSplit() const
349  {
350  return this->cnvPvSplit_;
351  }
352 
353  bool converged() const
354  {
355  return (status_ == AllGood)
356  && !wellGroupTargetsViolated_
357  && !network_needs_more_balancing_force_another_newton_iteration_;
358  }
359 
360  bool reservoirFailed() const
361  {
362  return status_ & ReservoirFailed;
363  }
364 
365  bool wellFailed() const
366  {
367  return status_ & WellFailed;
368  }
369 
370  const std::vector<ReservoirFailure>& reservoirFailures() const
371  {
372  return res_failures_;
373  }
374 
375  const std::vector<ReservoirConvergenceMetric>& reservoirConvergence() const
376  {
377  return res_convergence_;
378  }
379 
380  const std::vector<WellFailure>& wellFailures() const
381  {
382  return well_failures_;
383  }
384 
385  const std::vector<WellConvergenceMetric>& wellConvergence() const
386  {
387  return well_convergence_;
388  }
389 
390  const PenaltyCard& getPenaltyCard() const
391  {
392  return penaltyCard_;
393  }
394 
395  void addNonConvergedPenalty()
396  {
397  penaltyCard_.nonConverged++;
398  }
399 
400  void addDistanceDecayPenalty()
401  {
402  penaltyCard_.distanceDecay++;
403  }
404 
405  void addLargeWellResidualsPenalty()
406  {
407  penaltyCard_.largeWellResiduals++;
408  }
409 
410  Severity severityOfWorstFailure() const
411  {
412  // A function to get the worst of two severities.
413  auto smax = [](Severity s1, Severity s2) {
414  return s1 < s2 ? s2 : s1;
415  };
416  auto s = Severity::None;
417  for (const auto& f : res_failures_) {
418  s = smax(s, f.severity());
419  }
420  for (const auto& f : well_failures_) {
421  s = smax(s, f.severity());
422  }
423  return s;
424  }
425 
426  template <typename Serializer>
427  void serializeOp(Serializer& serializer)
428  {
429  serializer(this->reportTime_);
430  serializer(this->status_);
431  serializer(this->res_failures_);
432  serializer(this->well_failures_);
433  serializer(this->res_convergence_);
434  serializer(this->well_convergence_);
435  serializer(this->wellGroupTargetsViolated_);
436  serializer(this->network_needs_more_balancing_force_another_newton_iteration_);
437  serializer(this->cnvPvSplit_);
438  serializer(this->eligiblePoreVolume_);
439  serializer(this->penaltyCard_);
440  }
441 
442  private:
443  // ----------- Member variables -----------
444  // Note to maintainers: If you change this list of data members,
445  // then please update serializeOp() accordingly.
446  double reportTime_;
447  Status status_;
448  std::vector<ReservoirFailure> res_failures_;
449  std::vector<WellFailure> well_failures_;
450  std::vector<ReservoirConvergenceMetric> res_convergence_;
451  std::vector<WellConvergenceMetric> well_convergence_;
452  bool wellGroupTargetsViolated_;
453  bool network_needs_more_balancing_force_another_newton_iteration_;
454  CnvPvSplit cnvPvSplit_{};
455  double eligiblePoreVolume_{};
456  PenaltyCard penaltyCard_;
457  };
458 
459  struct StepReport
460  {
461  int report_step;
462  int current_step;
463  std::vector<ConvergenceReport> report;
464  };
465 
466  std::string to_string(const ConvergenceReport::ReservoirFailure::Type t);
467 
468  std::string to_string(const ConvergenceReport::Severity s);
469 
470  std::string to_string(const ConvergenceReport::WellFailure::Type t);
471 
472  std::string to_string(const ConvergenceReport::WellFailure& wf);
473 
474  std::string to_string(const ConvergenceReport::PenaltyCard& pc);
475 
476 
477 
478 } // namespace Opm
479 
480 #endif // OPM_CONVERGENCEREPORT_HEADER_INCLUDED
Definition: ConvergenceReport.hpp:459
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Definition: ConvergenceReport.hpp:160
Definition: ConvergenceReport.hpp:93
Definition: ConvergenceReport.hpp:205
Definition: ConvergenceReport.hpp:126
Represents the convergence status of the whole simulator, to make it possible to query and store the ...
Definition: ConvergenceReport.hpp:37
Definition: ConvergenceReport.hpp:57