ConvergenceReport.hpp
Go to the documentation of this file.
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
31namespace Opm
32{
33
38 {
39 public:
40
41 // ----------- Types -----------
42
43 enum Status {
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 {
61
62 int total() const {
64 }
65
66 void reset()
67 {
68 nonConverged = 0;
69 distanceDecay = 0;
71 }
72
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
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.
132
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.
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.
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.
237 Severity severity_ { Severity::None };
238 int phase_ { -1 };
239 double value_ { 0.0 };
240 std::string well_name_ {};
241 };
242
246 enum struct CnvRelaxSource {
247 None,
248 PvFraction,
249 SolChange,
250 FinalIter,
251 IterCount,
252 };
253
259 enum struct OscillationSource {
260 NotDetected,
261 Reservoir,
262 WellControl,
263 Mixed,
264 };
265
266 // ----------- Mutating member functions -----------
267
269 : ConvergenceReport{0.0}
270 {}
271
272 explicit ConvergenceReport(const double reportTime)
273 : reportTime_{reportTime}
274 , status_{AllGood}
275 , res_failures_{}
276 , well_failures_{}
277 , wellGroupTargetsViolated_(false)
278 , network_needs_more_balancing_force_another_newton_iteration_(false)
279 {}
280
281 void clear()
282 {
283 status_ = AllGood;
284 res_failures_.clear();
285 well_failures_.clear();
286 wellGroupTargetsViolated_ = false;
287 network_needs_more_balancing_force_another_newton_iteration_ = false;
288 }
289
291 {
292 status_ = static_cast<Status>(status_ | ReservoirFailed);
293 res_failures_.push_back(rf);
294 }
295
297 {
298 status_ = static_cast<Status>(status_ | WellFailed);
299 well_failures_.push_back(wf);
300 }
301
302 template <typename... Args>
303 void setReservoirConvergenceMetric(Args&&... args)
304 {
305 this->res_convergence_.emplace_back(std::forward<Args>(args)...);
306 }
307
308 template <typename... Args>
309 void setWellConvergenceMetric(Args&&... args)
310 {
311 this->well_convergence_.emplace_back(std::forward<Args>(args)...);
312 }
313
315 {
316 wellGroupTargetsViolated_ = wellGroupTargetsViolated;
317 }
318
319 void setNetworkNotYetBalancedForceAnotherNewtonIteration(const bool network_needs_more_balancing_force_another_newton_iteration)
320 {
321 network_needs_more_balancing_force_another_newton_iteration_ = network_needs_more_balancing_force_another_newton_iteration;
322 }
323
325 const double eligiblePoreVolume)
326 {
327 this->cnvPvSplit_ = cnvPvSplit;
328 this->eligiblePoreVolume_ = eligiblePoreVolume;
329 }
330
334 {
335 this->oscillationSource_ = source;
336 }
337
340 void setCnvRelaxation(const CnvRelaxSource source, const double toleranceApplied)
341 {
342 this->cnvRelaxSource_ = source;
343 this->cnvToleranceApplied_ = toleranceApplied;
344 }
345
347 {
348 reportTime_ = std::max(reportTime_, other.reportTime_);
349 status_ = static_cast<Status>(status_ | other.status_);
350 res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
351 well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
352 res_convergence_.insert(res_convergence_.end(), other.res_convergence_.begin(), other.res_convergence_.end());
353 well_convergence_.insert(well_convergence_.end(), other.well_convergence_.begin(), other.well_convergence_.end());
354 assert(reservoirFailed() != res_failures_.empty());
355 assert(wellFailed() != well_failures_.empty());
356 wellGroupTargetsViolated_ = (wellGroupTargetsViolated_ || other.wellGroupTargetsViolated_);
357 network_needs_more_balancing_force_another_newton_iteration_ = (network_needs_more_balancing_force_another_newton_iteration_
358 || other.network_needs_more_balancing_force_another_newton_iteration_);
359
360 // Note regarding the CNV pore-volume split: We depend on the
361 // fact that the quantities have already been aggregated across
362 // all MPI ranks--see the implementation of member function
363 // NonlinearSystemBlackOilReservoir::getReservoirConvergence() for details--and are
364 // therefore equal on all ranks. Consequently, we simply assign
365 // 'other's values here, if it is non-empty. Empty splits
366 // typically come from well contributions.
367 if (! other.cnvPvSplit_.first.empty()) {
368 this->cnvPvSplit_ = other.cnvPvSplit_;
369 this->eligiblePoreVolume_ = other.eligiblePoreVolume_;
370 }
371
372 // Same reasoning as the pore-volume split: only the reservoir report sets
373 // these, so take 'other's values whenever it carries them.
374 if (other.cnvToleranceApplied_ > 0.0) {
375 this->cnvRelaxSource_ = other.cnvRelaxSource_;
376 this->cnvToleranceApplied_ = other.cnvToleranceApplied_;
377 }
378
379 return *this;
380 }
381
382 // ----------- Const member functions (queries) -----------
383
384 double reportTime() const
385 {
386 return reportTime_;
387 }
388
389 double eligiblePoreVolume() const
390 {
391 return this->eligiblePoreVolume_;
392 }
393
394 const CnvPvSplit& cnvPvSplit() const
395 {
396 return this->cnvPvSplit_;
397 }
398
401 {
402 return this->oscillationSource_;
403 }
404
407 {
408 return this->cnvRelaxSource_;
409 }
410
412 double cnvToleranceApplied() const
413 {
414 return this->cnvToleranceApplied_;
415 }
416
417 bool converged() const
418 {
419 return (status_ == AllGood)
420 && !wellGroupTargetsViolated_
421 && !network_needs_more_balancing_force_another_newton_iteration_;
422 }
423
428 {
429 return wellGroupTargetsViolated_;
430 }
431
435 {
436 return network_needs_more_balancing_force_another_newton_iteration_;
437 }
438
439 bool reservoirFailed() const
440 {
441 return status_ & ReservoirFailed;
442 }
443
444 bool wellFailed() const
445 {
446 return status_ & WellFailed;
447 }
448
449 const std::vector<ReservoirFailure>& reservoirFailures() const
450 {
451 return res_failures_;
452 }
453
454 const std::vector<ReservoirConvergenceMetric>& reservoirConvergence() const
455 {
456 return res_convergence_;
457 }
458
459 const std::vector<WellFailure>& wellFailures() const
460 {
461 return well_failures_;
462 }
463
464 const std::vector<WellConvergenceMetric>& wellConvergence() const
465 {
466 return well_convergence_;
467 }
468
470 {
471 return penaltyCard_;
472 }
473
475 {
476 penaltyCard_.nonConverged++;
477 }
478
480 {
481 penaltyCard_.distanceDecay++;
482 }
483
485 {
486 penaltyCard_.largeWellResiduals++;
487 }
488
490 {
491 // A function to get the worst of two severities.
492 auto smax = [](Severity s1, Severity s2) {
493 return s1 < s2 ? s2 : s1;
494 };
495 auto s = Severity::None;
496 for (const auto& f : res_failures_) {
497 s = smax(s, f.severity());
498 }
499 for (const auto& f : well_failures_) {
500 s = smax(s, f.severity());
501 }
502 return s;
503 }
504
505 template <typename Serializer>
506 void serializeOp(Serializer& serializer)
507 {
508 serializer(this->reportTime_);
509 serializer(this->status_);
510 serializer(this->res_failures_);
511 serializer(this->well_failures_);
512 serializer(this->res_convergence_);
513 serializer(this->well_convergence_);
514 serializer(this->wellGroupTargetsViolated_);
515 serializer(this->network_needs_more_balancing_force_another_newton_iteration_);
516 serializer(this->cnvPvSplit_);
517 serializer(this->eligiblePoreVolume_);
518 serializer(this->cnvRelaxSource_);
519 serializer(this->cnvToleranceApplied_);
520 serializer(this->oscillationSource_);
521 serializer(this->penaltyCard_);
522 }
523
524 private:
525 // ----------- Member variables -----------
526 // Note to maintainers: If you change this list of data members,
527 // then please update serializeOp() accordingly.
528 double reportTime_;
529 Status status_;
530 std::vector<ReservoirFailure> res_failures_;
531 std::vector<WellFailure> well_failures_;
532 std::vector<ReservoirConvergenceMetric> res_convergence_;
533 std::vector<WellConvergenceMetric> well_convergence_;
534 bool wellGroupTargetsViolated_;
535 bool network_needs_more_balancing_force_another_newton_iteration_;
536 CnvPvSplit cnvPvSplit_{};
537 double eligiblePoreVolume_{};
538 CnvRelaxSource cnvRelaxSource_{CnvRelaxSource::None};
539 double cnvToleranceApplied_{};
541 PenaltyCard penaltyCard_;
542 };
543
545 {
548 std::vector<ConvergenceReport> report;
549 };
550
552
554
556
558
560
562
564
567
568
569
570} // namespace Opm
571
572#endif // OPM_CONVERGENCEREPORT_HEADER_INCLUDED
Definition: ConvergenceReport.hpp:127
int phase() const
Definition: ConvergenceReport.hpp:138
double value() const
Definition: ConvergenceReport.hpp:139
ReservoirFailure::Type type() const
Definition: ConvergenceReport.hpp:137
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:143
double tolerance() const
Definition: ConvergenceReport.hpp:140
ReservoirConvergenceMetric(ReservoirFailure::Type t, int phase, double value, double tolerance)
Definition: ConvergenceReport.hpp:133
Definition: ConvergenceReport.hpp:94
int phase() const
Definition: ConvergenceReport.hpp:108
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:111
Type
Definition: ConvergenceReport.hpp:96
ReservoirFailure(Type t, Severity s, int phase)
Definition: ConvergenceReport.hpp:102
Type type() const
Definition: ConvergenceReport.hpp:106
Severity severity() const
Definition: ConvergenceReport.hpp:107
Definition: ConvergenceReport.hpp:207
WellConvergenceMetric(WellFailure::Type t, Severity s, int phase, double value, const std::string &well_name)
Definition: ConvergenceReport.hpp:213
int phase() const
Definition: ConvergenceReport.hpp:219
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:224
double value() const
Definition: ConvergenceReport.hpp:220
WellFailure::Type type() const
Definition: ConvergenceReport.hpp:217
const std::string & wellName() const
Definition: ConvergenceReport.hpp:221
Severity severity() const
Definition: ConvergenceReport.hpp:218
Definition: ConvergenceReport.hpp:161
const std::string & wellName() const
Definition: ConvergenceReport.hpp:186
Type
Definition: ConvergenceReport.hpp:163
int phase() const
Definition: ConvergenceReport.hpp:185
Severity severity() const
Definition: ConvergenceReport.hpp:184
WellFailure(Type t, Severity s, int phase, const std::string &well_name)
Definition: ConvergenceReport.hpp:179
Type type() const
Definition: ConvergenceReport.hpp:183
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:189
Definition: ConvergenceReport.hpp:38
ConvergenceReport()
Definition: ConvergenceReport.hpp:268
Severity severityOfWorstFailure() const
Definition: ConvergenceReport.hpp:489
const std::vector< ReservoirConvergenceMetric > & reservoirConvergence() const
Definition: ConvergenceReport.hpp:454
void addDistanceDecayPenalty()
Definition: ConvergenceReport.hpp:479
void setWellFailed(const WellFailure &wf)
Definition: ConvergenceReport.hpp:296
void setWellGroupTargetsViolated(const bool wellGroupTargetsViolated)
Definition: ConvergenceReport.hpp:314
bool reservoirFailed() const
Definition: ConvergenceReport.hpp:439
const PenaltyCard & getPenaltyCard() const
Definition: ConvergenceReport.hpp:469
double cnvToleranceApplied() const
The CNV tolerance actually applied (0 if not recorded).
Definition: ConvergenceReport.hpp:412
const CnvPvSplit & cnvPvSplit() const
Definition: ConvergenceReport.hpp:394
OscillationSource
Definition: ConvergenceReport.hpp:259
const std::vector< WellConvergenceMetric > & wellConvergence() const
Definition: ConvergenceReport.hpp:464
void setReservoirConvergenceMetric(Args &&... args)
Definition: ConvergenceReport.hpp:303
Severity
Definition: ConvergenceReport.hpp:49
CnvRelaxSource cnvRelaxSource() const
Which condition granted the relaxed CNV tolerance this iteration.
Definition: ConvergenceReport.hpp:406
double reportTime() const
Definition: ConvergenceReport.hpp:384
void setOscillationSource(const OscillationSource source)
Record that the Newton solver damped this iteration for oscillation, together with what was unsatisfi...
Definition: ConvergenceReport.hpp:333
bool networkNeedsMoreBalancing() const
Whether the network balance forced another Newton iteration even when all residual metrics are conver...
Definition: ConvergenceReport.hpp:434
void clear()
Definition: ConvergenceReport.hpp:281
ConvergenceReport(const double reportTime)
Definition: ConvergenceReport.hpp:272
void addNonConvergedPenalty()
Definition: ConvergenceReport.hpp:474
OscillationSource oscillationSource() const
What was unsatisfied when oscillation damping was triggered, if it was.
Definition: ConvergenceReport.hpp:400
bool converged() const
Definition: ConvergenceReport.hpp:417
Status
Definition: ConvergenceReport.hpp:43
@ ReservoirFailed
Definition: ConvergenceReport.hpp:45
@ AllGood
Definition: ConvergenceReport.hpp:44
@ WellFailed
Definition: ConvergenceReport.hpp:46
const std::vector< ReservoirFailure > & reservoirFailures() const
Definition: ConvergenceReport.hpp:449
void setCnvRelaxation(const CnvRelaxSource source, const double toleranceApplied)
Record which condition granted the relaxed CNV tolerance and the tolerance actually applied,...
Definition: ConvergenceReport.hpp:340
const std::vector< WellFailure > & wellFailures() const
Definition: ConvergenceReport.hpp:459
void addLargeWellResidualsPenalty()
Definition: ConvergenceReport.hpp:484
void setReservoirFailed(const ReservoirFailure &rf)
Definition: ConvergenceReport.hpp:290
bool wellGroupTargetsViolated() const
Whether well/group control targets were violated (a control or target changed this iteration),...
Definition: ConvergenceReport.hpp:427
ConvergenceReport & operator+=(const ConvergenceReport &other)
Definition: ConvergenceReport.hpp:346
void setNetworkNotYetBalancedForceAnotherNewtonIteration(const bool network_needs_more_balancing_force_another_newton_iteration)
Definition: ConvergenceReport.hpp:319
bool wellFailed() const
Definition: ConvergenceReport.hpp:444
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:506
void setCnvPoreVolSplit(const CnvPvSplit &cnvPvSplit, const double eligiblePoreVolume)
Definition: ConvergenceReport.hpp:324
std::pair< std::vector< double >, std::vector< int > > CnvPvSplit
Definition: ConvergenceReport.hpp:91
CnvRelaxSource
Definition: ConvergenceReport.hpp:246
@ None
strict tolerance applied
double eligiblePoreVolume() const
Definition: ConvergenceReport.hpp:389
void setWellConvergenceMetric(Args &&... args)
Definition: ConvergenceReport.hpp:309
Definition: blackoilbioeffectsmodules.hh:45
ConvergenceReport::OscillationSource classifyOscillationSource(const ConvergenceReport &report)
Classify what was unsatisfied in a report, for oscillation-source reporting.
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: ConvergenceReport.hpp:57
void serializeOp(Serializer &serializer)
Definition: ConvergenceReport.hpp:81
int nonConverged
Definition: ConvergenceReport.hpp:58
int total() const
Definition: ConvergenceReport.hpp:62
int largeWellResiduals
Definition: ConvergenceReport.hpp:60
PenaltyCard & operator+=(const PenaltyCard &other)
Definition: ConvergenceReport.hpp:73
void reset()
Definition: ConvergenceReport.hpp:66
int distanceDecay
Definition: ConvergenceReport.hpp:59
Definition: ConvergenceReport.hpp:545
std::vector< ConvergenceReport > report
Definition: ConvergenceReport.hpp:548
int report_step
Definition: ConvergenceReport.hpp:546
int current_step
Definition: ConvergenceReport.hpp:547