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  Energy,
168  ControlBHP,
169  ControlTHP,
170  ControlRate,
171  Unsolvable,
172  WrongFlowDirection,
173  };
174 
175  // Default constructor needed for object serialisation. Don't
176  // use this for anything else.
177  WellFailure() = default;
178 
179  WellFailure(Type t, Severity s, int phase, const std::string& well_name)
180  : type_(t), severity_(s), phase_(phase), well_name_(well_name)
181  {}
182 
183  Type type() const { return type_; }
184  Severity severity() const { return severity_; }
185  int phase() const { return phase_; }
186  const std::string& wellName() const { return well_name_; }
187 
188  template <typename Serializer>
189  void serializeOp(Serializer& serializer)
190  {
191  serializer(this->type_);
192  serializer(this->severity_);
193  serializer(this->phase_);
194  serializer(this->well_name_);
195  }
196 
197  private:
198  // Note to maintainers: If you change this list of data members,
199  // then please update serializeOp() accordingly.
200  Type type_ { Type::Invalid };
201  Severity severity_ { Severity::None };
202  int phase_ { -1 };
203  std::string well_name_ {};
204  };
205 
207  {
208  public:
209  // Default constructor needed for object serialisation. Don't
210  // use this for anything else.
211  WellConvergenceMetric() = default;
212 
213  WellConvergenceMetric(WellFailure::Type t, Severity s, int phase, double value, const std::string& well_name)
214  : type_(t), severity_(s), phase_(phase), value_(value), well_name_(well_name)
215  {}
216 
217  WellFailure::Type type() const { return type_; }
218  Severity severity() const { return severity_; }
219  int phase() const { return phase_; }
220  double value() const { return value_; }
221  const std::string& wellName() const { return well_name_; }
222 
223  template <typename Serializer>
224  void serializeOp(Serializer& serializer)
225  {
226  serializer(this->type_);
227  serializer(this->severity_);
228  serializer(this->phase_);
229  serializer(this->value_);
230  serializer(this->well_name_);
231  }
232 
233  private:
234  // Note to maintainers: If you change this list of data members,
235  // then please update serializeOp() accordingly.
236  WellFailure::Type type_ { WellFailure::Type::Invalid };
237  Severity severity_ { Severity::None };
238  int phase_ { -1 };
239  double value_ { 0.0 };
240  std::string well_name_ {};
241  };
242 
243  // ----------- Mutating member functions -----------
244 
246  : ConvergenceReport{0.0}
247  {}
248 
249  explicit ConvergenceReport(const double reportTime)
250  : reportTime_{reportTime}
251  , status_{AllGood}
252  , res_failures_{}
253  , well_failures_{}
254  , wellGroupTargetsViolated_(false)
255  , network_needs_more_balancing_force_another_newton_iteration_(false)
256  {}
257 
258  void clear()
259  {
260  status_ = AllGood;
261  res_failures_.clear();
262  well_failures_.clear();
263  wellGroupTargetsViolated_ = false;
264  network_needs_more_balancing_force_another_newton_iteration_ = false;
265  }
266 
267  void setReservoirFailed(const ReservoirFailure& rf)
268  {
269  status_ = static_cast<Status>(status_ | ReservoirFailed);
270  res_failures_.push_back(rf);
271  }
272 
273  void setWellFailed(const WellFailure& wf)
274  {
275  status_ = static_cast<Status>(status_ | WellFailed);
276  well_failures_.push_back(wf);
277  }
278 
279  template <typename... Args>
280  void setReservoirConvergenceMetric(Args&&... args)
281  {
282  this->res_convergence_.emplace_back(std::forward<Args>(args)...);
283  }
284 
285  template <typename... Args>
286  void setWellConvergenceMetric(Args&&... args)
287  {
288  this->well_convergence_.emplace_back(std::forward<Args>(args)...);
289  }
290 
291  void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated)
292  {
293  wellGroupTargetsViolated_ = wellGroupTargetsViolated;
294  }
295 
296  void setNetworkNotYetBalancedForceAnotherNewtonIteration(const bool network_needs_more_balancing_force_another_newton_iteration)
297  {
298  network_needs_more_balancing_force_another_newton_iteration_ = network_needs_more_balancing_force_another_newton_iteration;
299  }
300 
301  void setCnvPoreVolSplit(const CnvPvSplit& cnvPvSplit,
302  const double eligiblePoreVolume)
303  {
304  this->cnvPvSplit_ = cnvPvSplit;
305  this->eligiblePoreVolume_ = eligiblePoreVolume;
306  }
307 
308  ConvergenceReport& operator+=(const ConvergenceReport& other)
309  {
310  reportTime_ = std::max(reportTime_, other.reportTime_);
311  status_ = static_cast<Status>(status_ | other.status_);
312  res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
313  well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
314  res_convergence_.insert(res_convergence_.end(), other.res_convergence_.begin(), other.res_convergence_.end());
315  well_convergence_.insert(well_convergence_.end(), other.well_convergence_.begin(), other.well_convergence_.end());
316  assert(reservoirFailed() != res_failures_.empty());
317  assert(wellFailed() != well_failures_.empty());
318  wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_);
319  network_needs_more_balancing_force_another_newton_iteration_ = (network_needs_more_balancing_force_another_newton_iteration_
320  || other.network_needs_more_balancing_force_another_newton_iteration_);
321 
322  // Note regarding the CNV pore-volume split: We depend on the
323  // fact that the quantities have already been aggregated across
324  // all MPI ranks--see the implementation of member function
325  // NonlinearSystemBlackOilReservoir::getReservoirConvergence() for details--and are
326  // therefore equal on all ranks. Consequently, we simply assign
327  // 'other's values here, if it is non-empty. Empty splits
328  // typically come from well contributions.
329  if (! other.cnvPvSplit_.first.empty()) {
330  this->cnvPvSplit_ = other.cnvPvSplit_;
331  this->eligiblePoreVolume_ = other.eligiblePoreVolume_;
332  }
333 
334  return *this;
335  }
336 
337  // ----------- Const member functions (queries) -----------
338 
339  double reportTime() const
340  {
341  return reportTime_;
342  }
343 
344  double eligiblePoreVolume() const
345  {
346  return this->eligiblePoreVolume_;
347  }
348 
349  const CnvPvSplit& cnvPvSplit() const
350  {
351  return this->cnvPvSplit_;
352  }
353 
354  bool converged() const
355  {
356  return (status_ == AllGood)
357  && !wellGroupTargetsViolated_
358  && !network_needs_more_balancing_force_another_newton_iteration_;
359  }
360 
361  bool reservoirFailed() const
362  {
363  return status_ & ReservoirFailed;
364  }
365 
366  bool wellFailed() const
367  {
368  return status_ & WellFailed;
369  }
370 
371  const std::vector<ReservoirFailure>& reservoirFailures() const
372  {
373  return res_failures_;
374  }
375 
376  const std::vector<ReservoirConvergenceMetric>& reservoirConvergence() const
377  {
378  return res_convergence_;
379  }
380 
381  const std::vector<WellFailure>& wellFailures() const
382  {
383  return well_failures_;
384  }
385 
386  const std::vector<WellConvergenceMetric>& wellConvergence() const
387  {
388  return well_convergence_;
389  }
390 
391  const PenaltyCard& getPenaltyCard() const
392  {
393  return penaltyCard_;
394  }
395 
396  void addNonConvergedPenalty()
397  {
398  penaltyCard_.nonConverged++;
399  }
400 
401  void addDistanceDecayPenalty()
402  {
403  penaltyCard_.distanceDecay++;
404  }
405 
406  void addLargeWellResidualsPenalty()
407  {
408  penaltyCard_.largeWellResiduals++;
409  }
410 
411  Severity severityOfWorstFailure() const
412  {
413  // A function to get the worst of two severities.
414  auto smax = [](Severity s1, Severity s2) {
415  return s1 < s2 ? s2 : s1;
416  };
417  auto s = Severity::None;
418  for (const auto& f : res_failures_) {
419  s = smax(s, f.severity());
420  }
421  for (const auto& f : well_failures_) {
422  s = smax(s, f.severity());
423  }
424  return s;
425  }
426 
427  template <typename Serializer>
428  void serializeOp(Serializer& serializer)
429  {
430  serializer(this->reportTime_);
431  serializer(this->status_);
432  serializer(this->res_failures_);
433  serializer(this->well_failures_);
434  serializer(this->res_convergence_);
435  serializer(this->well_convergence_);
436  serializer(this->wellGroupTargetsViolated_);
437  serializer(this->network_needs_more_balancing_force_another_newton_iteration_);
438  serializer(this->cnvPvSplit_);
439  serializer(this->eligiblePoreVolume_);
440  serializer(this->penaltyCard_);
441  }
442 
443  private:
444  // ----------- Member variables -----------
445  // Note to maintainers: If you change this list of data members,
446  // then please update serializeOp() accordingly.
447  double reportTime_;
448  Status status_;
449  std::vector<ReservoirFailure> res_failures_;
450  std::vector<WellFailure> well_failures_;
451  std::vector<ReservoirConvergenceMetric> res_convergence_;
452  std::vector<WellConvergenceMetric> well_convergence_;
453  bool wellGroupTargetsViolated_;
454  bool network_needs_more_balancing_force_another_newton_iteration_;
455  CnvPvSplit cnvPvSplit_{};
456  double eligiblePoreVolume_{};
457  PenaltyCard penaltyCard_;
458  };
459 
460  struct StepReport
461  {
462  int report_step;
463  int current_step;
464  std::vector<ConvergenceReport> report;
465  };
466 
467  std::string to_string(const ConvergenceReport::ReservoirFailure::Type t);
468 
469  std::string to_string(const ConvergenceReport::Severity s);
470 
471  std::string to_string(const ConvergenceReport::WellFailure::Type t);
472 
473  std::string to_string(const ConvergenceReport::WellFailure& wf);
474 
475  std::string to_string(const ConvergenceReport::PenaltyCard& pc);
476 
477 
478 
479 } // namespace Opm
480 
481 #endif // OPM_CONVERGENCEREPORT_HEADER_INCLUDED
Definition: ConvergenceReport.hpp:460
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Definition: ConvergenceReport.hpp:160
Definition: ConvergenceReport.hpp:93
Definition: ConvergenceReport.hpp:206
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