CoolProp 8.0.0
An open-source fluid property and humid air property database
SuperancillaryTemperatureBoundaryCurve.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5#include <stdexcept>
6
7namespace CoolProp {
8namespace region {
9
10std::unique_ptr<SuperancillaryTemperatureBoundaryCurve> SuperancillaryTemperatureBoundaryCurve::build(std::shared_ptr<SuperAncillary_t> sa,
11 double T_min, double T_max, char prop_key,
12 short Q, double output_scale) {
13 if (!sa) {
14 throw std::invalid_argument("SuperancillaryTemperatureBoundaryCurve::build: null SuperAncillary handle");
15 }
16 if (!(T_min > 0.0) || !(T_max > T_min)) {
17 throw std::invalid_argument("SuperancillaryTemperatureBoundaryCurve::build: need 0 < T_min < T_max");
18 }
19 if (Q != 0 && Q != 1) {
20 throw std::invalid_argument("SuperancillaryTemperatureBoundaryCurve::build: Q must be 0 (liquid) or 1 (vapor)");
21 }
22
23 // Probe the curve at linear-T sample points to pre-compute the
24 // (b_min, b_max) AABB. 32 probes give a tight bound for smooth
25 // boundary curves. T span is at most factor ~3, so log spacing
26 // wouldn't help — linear is the right default.
27 constexpr std::size_t kProbes = 32;
28 double b_min = std::numeric_limits<double>::infinity();
29 double b_max = -std::numeric_limits<double>::infinity();
30 std::size_t finite_probe_count = 0;
31 for (std::size_t k = 0; k < kProbes; ++k) {
32 const double f = static_cast<double>(k) / static_cast<double>(kProbes - 1);
33 const double T = T_min + f * (T_max - T_min);
34 try {
35 const double y = sa->eval_sat(T, prop_key, Q) * output_scale;
36 if (std::isfinite(y)) {
37 ++finite_probe_count;
38 b_min = std::min(b_min, y);
39 b_max = std::max(b_max, y);
40 }
41 } catch (...) { // NOLINT(bugprone-empty-catch)
42 // SA may reject queries exotically close to the critical
43 // point. Skip and keep surrounding probes.
44 }
45 }
46 if (finite_probe_count == 0) {
47 throw std::runtime_error("SuperancillaryTemperatureBoundaryCurve::build: SuperAncillary rejected all probes in the requested T range");
48 }
49 if (!(b_max > b_min)) { // CodeQL-safe form of b_min == b_max (b_min <= b_max always holds here)
50 // Degenerate near-flat curve; inflate by 1 ULP per side so the
51 // AABB has non-zero b-extent and Region machinery doesn't trip.
52 const double eps = std::max(std::abs(b_min) * std::numeric_limits<double>::epsilon(), std::numeric_limits<double>::min());
53 b_min -= eps;
54 b_max += eps;
55 }
56 return std::make_unique<SuperancillaryTemperatureBoundaryCurve>(std::move(sa), T_min, T_max, prop_key, Q, output_scale, b_min, b_max);
57}
58
59} // namespace region
60} // namespace CoolProp