11 double T_min,
double T_max,
char prop_key,
12 short Q,
double output_scale) {
14 throw std::invalid_argument(
"SuperancillaryTemperatureBoundaryCurve::build: null SuperAncillary handle");
16 if (!(T_min > 0.0) || !(T_max > T_min)) {
17 throw std::invalid_argument(
"SuperancillaryTemperatureBoundaryCurve::build: need 0 < T_min < T_max");
19 if (Q != 0 && Q != 1) {
20 throw std::invalid_argument(
"SuperancillaryTemperatureBoundaryCurve::build: Q must be 0 (liquid) or 1 (vapor)");
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);
35 const double y = sa->eval_sat(
T, prop_key, Q) * output_scale;
36 if (std::isfinite(y)) {
38 b_min = std::min(b_min, y);
39 b_max = std::max(b_max, y);
46 if (finite_probe_count == 0) {
47 throw std::runtime_error(
"SuperancillaryTemperatureBoundaryCurve::build: SuperAncillary rejected all probes in the requested T range");
49 if (!(b_max > b_min)) {
52 const double eps = std::max(std::abs(b_min) * std::numeric_limits<double>::epsilon(), std::numeric_limits<double>::min());
56 return std::make_unique<SuperancillaryTemperatureBoundaryCurve>(std::move(sa), T_min, T_max, prop_key, Q, output_scale, b_min, b_max);