10#if defined(ENABLE_CATCH)
14# include <catch2/catch_all.hpp>
50 double THETA = 1 -
T /
T_r;
62 return std::numeric_limits<double>::quiet_NaN();
65 for (std::size_t i = 0; i <
N; ++i) {
66 s[i] = n[i] * pow(THETA, t[i]);
68 double summer = std::accumulate(s.begin(), s.end(), 0.0);
73 double tau_r_value = NAN;
75 tau_r_value =
T_r /
T;
93 double call(
double T)
override {
95 return current_value - value;
98 solver_resid resid(
this, value);
100 min_bound = Tmin - 0.01;
120 part.p_min = part.p_0 + part.a * (pow(part.T_min / part.T_0, part.c) - 1);
121 part.p_max = part.p_0 + part.a * (pow(part.T_max / part.T_0, part.c) - 1);
130 part.p_min = part.evaluate(part.T_min);
131 part.p_max = part.evaluate(part.T_max);
140 part.p_min = part.evaluate(part.T_min);
141 part.p_max = part.evaluate(part.T_max);
154 throw ValueError(
"Melting line curve not set");
158 }
else if (OF ==
iP_min) {
160 }
else if (OF ==
iT_max) {
162 }
else if (OF ==
iT_min) {
164 }
else if (OF ==
iP && GIVEN ==
iT) {
170 return part.p_0 + part.a * (pow(
T / part.T_0, part.c) - 1);
173 throw ValueError(
"unable to calculate melting line (p,T) for Simon curve");
178 return part.evaluate(
T);
181 throw ValueError(
"unable to calculate melting line (p,T) for polynomial_in_Tr curve");
186 return part.evaluate(
T);
189 throw ValueError(
"unable to calculate melting line (p,T) for polynomial_in_Theta curve");
198 CoolPropDbl T = pow((value - part.p_0) / part.a + 1, 1 / part.c) * part.T_0;
199 if (
get_config_bool(DONT_CHECK_PROPERTY_LIMITS) || (
T >= part.T_0 &&
T <= part.T_max)) {
203 throw ValueError(
format(
"unable to calculate melting line T(p) for Simon curve for p=%Lg; bounds are %Lg,%Lg Pa", value,
pmin,
pmax));
211 double call(
double T)
override {
216 return given_p - calc_p;
223 solver_resid resid(&part, value);
229 format(
"unable to calculate melting line T(p) for polynomial_in_Theta curve for p=%Lg; bounds are %Lg,%Lg Pa", value,
pmin,
pmax));
238 double call(
double T)
override {
243 return given_p - calc_p;
250 solver_resid resid(&part, value);
257 format(
"unable to calculate melting line T(p) for polynomial_in_Theta curve for p=%Lg; bounds are %Lg,%Lg Pa", value,
pmin,
pmax));
265 std::vector<std::pair<CoolPropDbl, CoolPropDbl>> out;
268 out.emplace_back(p.p_min, p.p_max);
271 out.emplace_back(p.p_min, p.p_max);
274 out.emplace_back(p.p_min, p.p_max);
281#if defined(ENABLE_CATCH)
282TEST_CASE(
"Water melting line",
"[melting]") {
285 SECTION(
"Ice Ih-liquid") {
286 double actual = AS->melting_line(
iT,
iP, 138.268e6);
287 double expected = 260.0;
290 CHECK(std::abs(actual - expected) < 0.01);
292 SECTION(
"Ice III-liquid") {
293 double actual = AS->melting_line(
iT,
iP, 268.685e6);
294 double expected = 254;
297 CHECK(std::abs(actual - expected) < 0.01);
299 SECTION(
"Ice V-liquid") {
300 double actual = AS->melting_line(
iT,
iP, 479.640e6);
301 double expected = 265;
304 CHECK(std::abs(actual - expected) < 0.01);
306 SECTION(
"Ice VI-liquid") {
307 double actual = AS->melting_line(
iT,
iP, 1356.76e6);
308 double expected = 320;
311 CHECK(std::abs(actual - expected) < 1);
315TEST_CASE(
"Tests for values from melting lines",
"[melting]") {
318 for (
const auto& fluid : fluids) {
326 if (!AS->has_melting_line() || !fluid.compare(
"Water") || !fluid.compare(
"HeavyWater")) {
336 std::ostringstream ss0;
337 ss0 <<
"Check melting line limits for fluid " << fluid;
338 SECTION(ss0.str(),
"") {
351 const double p_range = pmax - pmin;
352 for (
int p_i = 0; p_i < 5; ++p_i) {
353 const double p = pmin + (0.1 + 0.2 * p_i) * p_range;
355 std::ostringstream ss1;
356 ss1 <<
"Melting line for " << fluid <<
" at p=" << p;
357 SECTION(ss1.str(),
"") {
358 double actual_T = AS->melting_line(
iT,
iP, p);
362 CHECK(actual_T > Tmin);
363 CHECK(actual_T < Tmax);
367 std::ostringstream ss2;
368 ss2 <<
"Ensure melting line valid for " << fluid <<
" @ EOS pmax";
369 SECTION(ss2.str(),
"") {
370 double actual_T = -_HUGE;
371 double EOS_pmax = AS->pmax();
372 double T_pmax_required = -1;
375 T_pmax_required = AS->melting_line(
iT,
iP, EOS_pmax);
383 CAPTURE(T_pmax_required);
385 CHECK_NOTHROW(actual_T = AS->melting_line(
iT,
iP, EOS_pmax));
391TEST_CASE(
"Test that hs_anchor enthalpy/entropy agrees with EOS",
"[ancillaries]") {
393 for (
const auto& fluid : fluids) {
399 std::ostringstream ss1;
400 ss1 <<
"Check hs_anchor for " << fluid;
401 SECTION(ss1.str(),
"") {
402 INFO(
"The enthalpy and entropy are hardcoded in the fluid JSON files. They MUST agree with the values calculated by the EOS");
404 double EOS_hmolar = AS->hmolar();
405 double EOS_smolar = AS->smolar();
406 CAPTURE(hs_anchor.
hmolar);
407 CAPTURE(hs_anchor.
smolar);
410 CHECK(std::abs(EOS_hmolar - hs_anchor.
hmolar) < 1e-3);
411 CHECK(std::abs(EOS_smolar - hs_anchor.
smolar) < 1e-3);
416TEST_CASE(
"Surface tension",
"[surface_tension]") {
417 SECTION(
"from PropsSI") {
420 SECTION(
"from saturation_ancillary") {
423 SECTION(
"from AbstractState") {
426 CHECK_NOTHROW(AS->surface_tension());