CoolProp
8.0.0
An open-source fluid property and humid air property database
include
CoolProp
sbtl
SaturationSurrogate.h
Go to the documentation of this file.
1
#ifndef COOLPROP_SBTL_SATURATION_SURROGATE_H
2
#define COOLPROP_SBTL_SATURATION_SURROGATE_H
3
4
#include <cstddef>
5
#include <memory>
6
7
#include "
CoolProp/AbstractState.h
"
8
9
namespace
CoolProp
{
10
namespace
region {
11
class
CubicSplineCurve;
12
}
// namespace region
13
14
namespace
sbtl {
15
16
// SaturationSurrogate — a small cubic-spline surrogate for the
17
// saturation dome, built by sampling QT_INPUTS on a source backend at
18
// construction. Mirrors the eval_sat / get_T_from_p shape of
19
// `superancillary::SuperAncillary` so the SVDSBTL backend can use it
20
// as a drop-in replacement when the source backend doesn't expose a
21
// SuperAncillary (REFPROP today; SRK / PR / etc. in the future).
22
//
23
// **Why this exists.** Every dome-touching query through
24
// SVDSBTL&<source-without-SA> falls through to source.update(PQ_INPUTS
25
// / QT_INPUTS) for sat endpoints — REFPROP's PQ flash is ~1-5 ms per
26
// call, whereas an SA-style spline eval is ~50 ns. Closing this 4-5
27
// orders-of-magnitude gap is the point of the surrogate.
28
//
29
// **What is sampled.** At each of `n_knots` temperatures spanning
30
// [T_triple * (1 + 1e-6), 0.9999 * T_crit], the source is queried via
31
// QT_INPUTS at Q=0 and Q=1, capturing P, D, H, S, U on both sides.
32
// The additive 1e-6 offset on T_triple keeps the first probe one ULP-
33
// class step inside the source's flash range — some backends report
34
// T_triple at the boundary of where QT_INPUTS converges, and a bare
35
// T_triple probe fails on those.
36
// The 0.9999 multiplier on T_crit keeps the highest knot well clear of
37
// the sqrt-singularity at the critical point — cubic splines can't
38
// represent the singularity, so the surrogate trades accuracy near
39
// T_crit for clean interpolation everywhere else.
40
//
41
// **Spacing.** Chebyshev-Lobatto knot distribution in T over
42
// [T_triple, 0.9999 * T_crit] — clusters knots toward both endpoints
43
// to absorb the sharp density bend approaching T_crit (saturated-rho
44
// is the budget-binding property; log-T spacing missed 1e-6 there).
45
// Cubic spline interpolation between the knots.
46
//
47
// **Accuracy target.** Relative error <= 1e-6 vs source QT_INPUTS on
48
// smooth-fluid probes well away from the critical point. Accuracy
49
// degrades as T -> T_crit (sqrt-singularity not captured by
50
// polynomials); callers querying that slice should use the
51
// critical-patch source fallback in SVDSBTLBackend instead.
52
//
53
// **Units.** Matches SuperAncillary's molar convention: P in Pa, D in
54
// mol/m^3, H/U in J/mol, S in J/(mol K). Caller (SVDSBTLBackend)
55
// converts to mass basis as needed downstream.
56
class
SaturationSurrogate
57
{
58
public
:
59
// Build a surrogate by sampling `src` at `n_knots` temperatures.
60
// Returns nullptr on build failure (degenerate triple/critical pair,
61
// n_knots < 4, or source rejects too many QT_INPUTS probes to form a
62
// valid spline). Mutates `src` state during sampling.
63
//
64
// Source-backend requirements: must support QT_INPUTS, must report
65
// T_triple() and T_critical() correctly. HEOS, REFPROP, IF97 all
66
// satisfy these; mixtures do not (no single sat dome).
67
[[nodiscard]]
static
std::unique_ptr<SaturationSurrogate>
build_from_source
(
::CoolProp::AbstractState
& src, std::size_t
n_knots
= 96);
68
69
SaturationSurrogate
(
const
SaturationSurrogate
&) =
delete
;
70
SaturationSurrogate
&
operator=
(
const
SaturationSurrogate
&) =
delete
;
71
SaturationSurrogate
(
SaturationSurrogate
&&) =
delete
;
72
SaturationSurrogate
&
operator=
(
SaturationSurrogate
&&) =
delete
;
73
~SaturationSurrogate
();
74
75
// Inverse pressure -> temperature. Same contract as
76
// SuperAncillary::get_T_from_p — argument is pressure in Pa (NOT its
77
// log), returns saturation temperature in K. Throws std::out_of_range
78
// if `p` is outside the surrogate's [p_min, p_max] build range.
79
[[nodiscard]]
double
get_T_from_p
(
double
p)
const
;
80
81
// Evaluate a saturated property at (T, side). Matches
82
// SuperAncillary::eval_sat — `what` is in {'P','D','H','S','U'},
83
// `side` is 0 (liquid) or 1 (vapor). Throws std::invalid_argument
84
// on bad keys / sides, std::out_of_range on T outside the build range.
85
[[nodiscard]]
double
eval_sat
(
double
T
,
char
what,
int
side)
const
;
86
87
// Build interval, exposed for diagnostics + tests.
88
[[nodiscard]]
double
T_min
() const noexcept;
89
[[nodiscard]]
double
T_max
() const noexcept;
90
[[nodiscard]] std::
size_t
n_knots
() const noexcept;
91
92
private:
93
SaturationSurrogate
();
94
struct
Impl
;
95
std::unique_ptr<
Impl
> impl_;
96
};
97
98
}
// namespace sbtl
99
}
// namespace CoolProp
100
101
#endif
// COOLPROP_SBTL_SATURATION_SURROGATE_H
Generated by
1.9.4