CoolProp 8.0.0
An open-source fluid property and humid air property database
Region.h
Go to the documentation of this file.
1#ifndef COOLPROP_REGION_REGION_H
2#define COOLPROP_REGION_REGION_H
3
4#include <memory>
5#include <utility>
6
9
10namespace CoolProp {
11namespace region {
12
13// A single region in (a, b) space.
14//
15// Geometry:
16// - Primary axis a is mapped to xi in [0, 1] via an AxisTransform
17// (linear or log scale). The transform fixes the [a_lo, a_hi]
18// interval.
19// - Secondary axis b is bounded below by `b_lo(a)` and above by
20// `b_hi(a)`, two BoundaryCurves that are explicit functions of a.
21// The normalised coordinate eta lives in [0, 1] when (a, b) is inside
22// the region. Its scale is selectable (default LINEAR):
23// LINEAR : eta = (b - b_lo(a)) / (b_hi(a) - b_lo(a))
24// LOG : eta = (log b - log b_lo(a)) / (log b_hi(a) - log b_lo(a))
25// LOG is the right choice when b spans orders of magnitude *and* the
26// tabulated property tracks b geometrically — e.g. the DmassT preset's
27// VAPOR/SUPER regions, where rho_hi/rho_lo ~ 1e5 and p ∝ rho in the
28// ideal-gas tail. Under LINEAR that tail collapses below the first
29// grid node and the EXP-SVD can't resolve the multi-decade pressure
30// swing (CoolProp-wvtz); LOG gives it uniform-in-decade resolution.
31// Only LINEAR and LOG are supported on the secondary axis (the POWER
32// scales are primary-axis-only).
33//
34// Dispatch:
35// `aabb_contains` is the cheap first-pass filter — four comparisons
36// against the precomputed bounding box; no virtual calls. It will
37// admit false positives for curved regions (points inside the AABB
38// but outside the curve envelope), so a second-pass `curve_contains`
39// evaluates the boundary curves to make the precise decision. This
40// matches the typical region-atlas dispatch: scan AABBs first, then
41// call into the curve check only on hits.
42//
43// Lifetime:
44// The Region owns its two BoundaryCurves via std::unique_ptr; copy
45// construction is deleted because BoundaryCurves are abstract. Move
46// construction is allowed.
47class Region
48{
49 public:
50 struct BBox
51 {
52 double a_lo;
53 double a_hi;
54 double b_min;
55 double b_max;
56 };
57
58 // secondary_scale selects how eta normalises the secondary axis
59 // (LINEAR default; LOG for wide-dynamic-range axes — see class
60 // docstring). Throws std::invalid_argument for any other scale.
61 Region(AxisTransform primary, std::unique_ptr<BoundaryCurve> b_lo, std::unique_ptr<BoundaryCurve> b_hi,
63
64 Region(const Region&) = delete;
65 Region& operator=(const Region&) = delete;
66 // Custom move ops invalidate `bbox_` on the moved-from instance so
67 // `aabb_contains` returns false unconditionally. The default
68 // move-op leaves bbox_ populated even though b_lo_ / b_hi_ are
69 // nulled — any subsequent aabb_contains hit would then fall through
70 // into curve_contains and dereference a null unique_ptr.
71 Region(Region&& other) noexcept;
72 Region& operator=(Region&& other) noexcept;
73 ~Region() = default;
74
75 // O(1), no curve evaluation.
76 [[nodiscard]] inline bool aabb_contains(double a, double b) const noexcept {
77 return a >= bbox_.a_lo && a <= bbox_.a_hi && b >= bbox_.b_min && b <= bbox_.b_max;
78 }
79
80 // Evaluates both BoundaryCurves at a; only call when aabb_contains
81 // already returned true. Returns false outside the curve envelope.
82 [[nodiscard]] bool curve_contains(double a, double b) const noexcept;
83
84 // (a, b) -> (xi, eta). Assumes (a, b) is inside the region; caller
85 // is responsible for an aabb_contains / curve_contains gate.
86 [[nodiscard]] std::pair<double, double> to_normalized(double a, double b) const noexcept;
87
88 // (xi, eta) -> (a, b).
89 [[nodiscard]] std::pair<double, double> from_normalized(double xi, double eta) const noexcept;
90
91 [[nodiscard]] const AxisTransform& primary() const noexcept {
92 return primary_;
93 }
94 [[nodiscard]] AxisScale secondary_scale() const noexcept {
95 return secondary_scale_;
96 }
97 [[nodiscard]] const BoundaryCurve& b_lo() const noexcept {
98 return *b_lo_;
99 }
100 [[nodiscard]] const BoundaryCurve& b_hi() const noexcept {
101 return *b_hi_;
102 }
103 [[nodiscard]] const BBox& bbox() const noexcept {
104 return bbox_;
105 }
106
107 private:
108 AxisTransform primary_;
109 AxisScale secondary_scale_;
110 std::unique_ptr<BoundaryCurve> b_lo_;
111 std::unique_ptr<BoundaryCurve> b_hi_;
112 BBox bbox_;
113};
114
115} // namespace region
116} // namespace CoolProp
117
118#endif // COOLPROP_REGION_REGION_H