From 5b53e4394a0cbf1140826852127f64a0fdbdfd60 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Mon, 20 Apr 2026 19:06:15 -0400 Subject: [PATCH] test(plot): use composed matchers to tolerate cross-platform libm jitter (#2760) The Plot isoline `.value` checks asserted at WithinAbs(value, 1e-10), which is platform-fragile: libm transcendentals (exp/log/pow) differ in the last few bits across glibc, Apple libm, and UCRT, and that propagates through the EOS solvers into ~1e-9 to 1e-10 relative differences in the computed range bounds. Reference data regenerated on macOS in #2749 therefore broke the Linux CI. Switch to `WithinAbs(v, abs) || WithinRel(v, 1e-8)`: keeps the absolute tolerance as a near-zero safety net and adds a 1e-8 relative tolerance that comfortably covers the observed cross-platform jitter (worst case ~5e-9 rel for p_isolines[4]). Updated the generator script and re-ran it to regenerate src/CoolPropPlot.cpp. Co-authored-by: Claude Opus 4.7 (1M context) --- dev/scripts/generate_Plot_test_data.py | 14 +- src/CoolPropPlot.cpp | 239 +++++++++++++------------ 2 files changed, 128 insertions(+), 125 deletions(-) diff --git a/dev/scripts/generate_Plot_test_data.py b/dev/scripts/generate_Plot_test_data.py index 153653cc..d73f1c2d 100644 --- a/dev/scripts/generate_Plot_test_data.py +++ b/dev/scripts/generate_Plot_test_data.py @@ -77,27 +77,27 @@ def generate_ph_test(): # Generate value checks for i in range(5): value = plot._isolines[py_param][i].value - print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-10));') - + print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-10) || WithinRel({value}, 1e-8));') + # Generate expected x values print(' const double expected_x[isoline_count][points_per_isoline] = {') for i in range(5): x_values = [format_number(x) for x in plot._isolines[py_param][i].x] print(' {' + ', '.join(x_values) + '},') print(' };') - + # Generate expected y values print(' const double expected_y[isoline_count][points_per_isoline] = {') for i in range(5): y_values = [format_number(y) for y in plot._isolines[py_param][i].y] print(' {' + ', '.join(y_values) + '},') print(' };') - + # Generate validation loop print(f' for (int i = 0; i < {cpp_name.lower()}_isolines.size(); ++i) {{') print(f' REQUIRE({cpp_name.lower()}_isolines[i].size() == points_per_isoline);') print(f' for (int j = 0; j < {cpp_name.lower()}_isolines[i].size(); ++j) {{') - + # Check for NaN values in this isoline type has_nan_x = any(math.isnan(x) for isoline in plot._isolines[py_param] for x in isoline.x) @@ -171,9 +171,9 @@ def generate_ts_test(): for i in range(5): value = plot._isolines[py_param][i].value if cpp_name == 'P': - print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-7));') + print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-7) || WithinRel({value}, 1e-8));') else: - print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-10));') + print(f' CHECK_THAT({cpp_name.lower()}_isolines[{i}].value, WithinAbs({value}, 1e-10) || WithinRel({value}, 1e-8));') # Add blank line only for the first Q isolines section if cpp_name == 'Q': diff --git a/src/CoolPropPlot.cpp b/src/CoolPropPlot.cpp index e5f30600..8ef668fc 100644 --- a/src/CoolPropPlot.cpp +++ b/src/CoolPropPlot.cpp @@ -474,7 +474,7 @@ using Catch::Matchers::WithinRel; TEST_CASE("Check value_at for p-h plots", "[Plot]") { CoolProp::Plot::PropertyPlot plot("R134a", CoolProp::iP, CoolProp::iHmass, CoolProp::Plot::TPLimits::Achp); - CHECK_THAT(plot.value_at(CoolProp::iP, 300000 /*Pa*/, 200000 /*J/kg*/), WithinAbs(200000, 1e-10)); + CHECK_THAT(plot.value_at(CoolProp::iP, 300000/*Pa*/, 200000/*J/kg*/), WithinAbs(200000, 1e-10)); CHECK_THAT(plot.value_at(CoolProp::iHmass, 300000, 200000), WithinAbs(300000, 1e-10)); CHECK_THAT(plot.value_at(CoolProp::iT, 300000, 200000), WithinAbs(263.07372753976784, 1e-10)); CHECK_THAT(plot.value_at(CoolProp::iQ, 300000, 200000), WithinAbs(0.550443478743443, 1e-10)); @@ -507,24 +507,24 @@ TEST_CASE("Check that the isolines are the same as from Python", "[Plot]") { std::vector q_values = CoolProp::Plot::generate_values_in_range(CoolProp::iQ, q_range, isoline_count); CoolProp::Plot::Isolines q_isolines = plot.calc_isolines(CoolProp::iQ, q_values, points_per_isoline); REQUIRE(q_isolines.size() == isoline_count); - CHECK_THAT(q_isolines[0].value, WithinAbs(0.0, 1e-10)); - CHECK_THAT(q_isolines[1].value, WithinAbs(0.25, 1e-10)); - CHECK_THAT(q_isolines[2].value, WithinAbs(0.5, 1e-10)); - CHECK_THAT(q_isolines[3].value, WithinAbs(0.75, 1e-10)); - CHECK_THAT(q_isolines[4].value, WithinAbs(1.0, 1e-10)); + CHECK_THAT(q_isolines[0].value, WithinAbs(0.0, 1e-10) || WithinRel(0.0, 1e-8)); + CHECK_THAT(q_isolines[1].value, WithinAbs(0.25, 1e-10) || WithinRel(0.25, 1e-8)); + CHECK_THAT(q_isolines[2].value, WithinAbs(0.5, 1e-10) || WithinRel(0.5, 1e-8)); + CHECK_THAT(q_isolines[3].value, WithinAbs(0.75, 1e-10) || WithinRel(0.75, 1e-8)); + CHECK_THAT(q_isolines[4].value, WithinAbs(1.0, 1e-10) || WithinRel(1.0, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {71455.0825704527, 132940.602012992, 198498.370551912, 271578.877763124, 389490.979699808}, - {137326.831168219, 191267.585241559, 248361.039003664, 309540.80583791, 389563.709352125}, - {203198.579765986, 249594.568470126, 298223.707455415, 347502.733912697, 389636.439004441}, - {269070.328363753, 307921.551698693, 348086.375907167, 385464.661987484, 389709.168656758}, - {334942.07696152, 366248.53492726, 397949.044358919, 423426.59006227, 389781.898309075}, + {71455.0825704527, 132940.602012992, 198498.370551912, 271578.877763124, 389490.979699808}, + {137326.831168219, 191267.585241559, 248361.039003664, 309540.80583791, 389563.709352125}, + {203198.579765986, 249594.568470126, 298223.707455415, 347502.733912697, 389636.439004441}, + {269070.328363753, 307921.551698693, 348086.375907167, 385464.661987484, 389709.168656758}, + {334942.07696152, 366248.53492726, 397949.044358919, 423426.59006227, 389781.898309075}, }; const double expected_y[isoline_count][points_per_isoline] = { - {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, - {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, - {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, - {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, - {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, + {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, + {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, + {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, + {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, + {389.56705952134, 25851.3343934178, 281115.856001781, 1316960.5263817, 4059273.23696491}, }; for (int i = 0; i < q_isolines.size(); ++i) { REQUIRE(q_isolines[i].size() == points_per_isoline); @@ -540,24 +540,24 @@ TEST_CASE("Check that the isolines are the same as from Python", "[Plot]") { std::vector t_values = CoolProp::Plot::generate_values_in_range(CoolProp::iT, t_range, isoline_count); CoolProp::Plot::Isolines t_isolines = plot.calc_isolines(CoolProp::iT, t_values, points_per_isoline); REQUIRE(t_isolines.size() == isoline_count); - CHECK_THAT(t_isolines[0].value, WithinAbs(173.15, 1e-10)); - CHECK_THAT(t_isolines[1].value, WithinAbs(243.6125, 1e-10)); - CHECK_THAT(t_isolines[2].value, WithinAbs(314.07500000000005, 1e-10)); - CHECK_THAT(t_isolines[3].value, WithinAbs(384.5375, 1e-10)); - CHECK_THAT(t_isolines[4].value, WithinAbs(455.0, 1e-10)); + CHECK_THAT(t_isolines[0].value, WithinAbs(173.15, 1e-10) || WithinRel(173.15, 1e-8)); + CHECK_THAT(t_isolines[1].value, WithinAbs(243.6125, 1e-10) || WithinRel(243.6125, 1e-8)); + CHECK_THAT(t_isolines[2].value, WithinAbs(314.07500000000005, 1e-10) || WithinRel(314.07500000000005, 1e-8)); + CHECK_THAT(t_isolines[3].value, WithinAbs(384.5375, 1e-10) || WithinRel(384.5375, 1e-8)); + CHECK_THAT(t_isolines[4].value, WithinAbs(455.0, 1e-10) || WithinRel(455.0, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {75373.1268990847, 75410.9911120364, 75576.5817007017, 76301.4918516847, 79487.8877890133}, - {382785.230587562, 161389.442353424, 161516.218619861, 162076.984158713, 164637.062378302}, - {439466.649843278, 438148.172824113, 431912.06623801, 257605.319479567, 257512.83924738}, - {504550.626065609, 503783.529360494, 500331.593280179, 482707.178357055, 366958.520782669}, - {577604.594975215, 577097.06504804, 574850.152315428, 564443.78972976, 507875.800623495}, + {75373.1268990847, 75410.9911120364, 75576.5817007017, 76301.4918516847, 79487.8877890133}, + {382785.230587562, 161389.442353424, 161516.218619861, 162076.984158713, 164637.062378302}, + {439466.649843278, 438148.172824113, 431912.06623801, 257605.319479567, 257512.83924738}, + {504550.626065609, 503783.529360494, 500331.593280179, 482707.178357055, 366958.520782669}, + {577604.594975215, 577097.06504804, 574850.152315428, 564443.78972976, 507875.800623495}, }; const double expected_y[isoline_count][points_per_isoline] = { - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, }; for (int i = 0; i < t_isolines.size(); ++i) { REQUIRE(t_isolines[i].size() == points_per_isoline); @@ -573,24 +573,24 @@ TEST_CASE("Check that the isolines are the same as from Python", "[Plot]") { std::vector s_values = CoolProp::Plot::generate_values_in_range(CoolProp::iSmass, s_range, isoline_count); CoolProp::Plot::Isolines s_isolines = plot.calc_isolines(CoolProp::iSmass, s_values, points_per_isoline); REQUIRE(s_isolines.size() == isoline_count); - CHECK_THAT(s_isolines[0].value, WithinAbs(426.0094838589179, 1e-10)); - CHECK_THAT(s_isolines[1].value, WithinAbs(925.275035740241, 1e-10)); - CHECK_THAT(s_isolines[2].value, WithinAbs(1424.540587621564, 1e-10)); - CHECK_THAT(s_isolines[3].value, WithinAbs(1923.8061395028872, 1e-10)); - CHECK_THAT(s_isolines[4].value, WithinAbs(2423.07169138421, 1e-10)); + CHECK_THAT(s_isolines[0].value, WithinAbs(426.0094838589179, 1e-10) || WithinRel(426.0094838589179, 1e-8)); + CHECK_THAT(s_isolines[1].value, WithinAbs(925.275035740241, 1e-10) || WithinRel(925.275035740241, 1e-8)); + CHECK_THAT(s_isolines[2].value, WithinAbs(1424.540587621564, 1e-10) || WithinRel(1424.540587621564, 1e-8)); + CHECK_THAT(s_isolines[3].value, WithinAbs(1923.8061395028872, 1e-10) || WithinRel(1923.8061395028872, 1e-8)); + CHECK_THAT(s_isolines[4].value, WithinAbs(2423.07169138421, 1e-10) || WithinRel(2423.07169138421, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {73758.1368332803, 73811.2861610949, 74043.6241895902, 75058.8771715002, 79487.8877891817}, - {176257.349845128, 179794.80776134, 180290.319046059, 181487.967470984, 186690.959613052}, - {286286.17581826, 303984.726429065, 321692.362822335, 335551.688988092, 344087.839489012}, - {399372.560529313, 433400.354293214, 471964.896215781, 513835.931067728, 555824.663129382}, - {577604.594975103, 635258.237157865, 698999.44597458, 768745.631258105, std::nan("")}, + {73758.1368332803, 73811.2861610949, 74043.6241895902, 75058.8771715002, 79487.8877891817}, + {176257.349845128, 179794.80776134, 180290.319046059, 181487.967470984, 186690.959613052}, + {286286.17581826, 303984.726429065, 321692.362822335, 335551.688988092, 344087.839489012}, + {399372.560529313, 433400.354293214, 471964.896215781, 513835.931067728, 555824.663129382}, + {577604.594975103, 635258.237157865, 698999.44597458, 768745.631258105, std::nan("")}, }; const double expected_y[isoline_count][points_per_isoline] = { - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, }; for (int i = 0; i < s_isolines.size(); ++i) { REQUIRE(s_isolines[i].size() == points_per_isoline); @@ -609,24 +609,24 @@ TEST_CASE("Check that the isolines are the same as from Python", "[Plot]") { std::vector d_values = CoolProp::Plot::generate_values_in_range(CoolProp::iDmass, d_range, isoline_count); CoolProp::Plot::Isolines d_isolines = plot.calc_isolines(CoolProp::iDmass, d_values, points_per_isoline); REQUIRE(d_isolines.size() == isoline_count); - CHECK_THAT(d_isolines[0].value, WithinAbs(0.6749779869915704, 1e-10)); - CHECK_THAT(d_isolines[1].value, WithinAbs(4.704765645221012, 1e-10)); - CHECK_THAT(d_isolines[2].value, WithinAbs(32.793395048494105, 1e-10)); - CHECK_THAT(d_isolines[3].value, WithinAbs(228.57817793729427, 1e-10)); - CHECK_THAT(d_isolines[4].value, WithinAbs(1593.2471569921404, 1e-10)); + CHECK_THAT(d_isolines[0].value, WithinAbs(0.6749779869915704, 1e-10) || WithinRel(0.6749779869915704, 1e-8)); + CHECK_THAT(d_isolines[1].value, WithinAbs(4.704765645221012, 1e-10) || WithinRel(4.704765645221012, 1e-8)); + CHECK_THAT(d_isolines[2].value, WithinAbs(32.793395048494105, 1e-10) || WithinRel(32.793395048494105, 1e-8)); + CHECK_THAT(d_isolines[3].value, WithinAbs(228.57817793729427, 1e-10) || WithinRel(228.57817793729427, 1e-8)); + CHECK_THAT(d_isolines[4].value, WithinAbs(1593.2471569921404, 1e-10) || WithinRel(1593.2471569921404, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {577604.594973719, std::nan(""), std::nan(""), std::nan(""), std::nan("")}, - {202365.843978241, 419230.11212018, std::nan(""), std::nan(""), std::nan("")}, - {142114.49128355, 204388.004481049, 351216.809719432, std::nan(""), std::nan("")}, - {133470.418481179, 172415.768781909, 235383.044878653, 357492.457498284, 669493.626069481}, - {70518.3287887542, 70601.2088968633, 70963.5807782658, 72548.3591964927, 79487.8877885823}, + {577604.594973719, std::nan(""), std::nan(""), std::nan(""), std::nan("")}, + {202365.843978241, 419230.11212018, std::nan(""), std::nan(""), std::nan("")}, + {142114.49128355, 204388.004481049, 351216.809719432, std::nan(""), std::nan("")}, + {133470.418481179, 172415.768781909, 235383.044878653, 357492.457498284, 669493.626069481}, + {70518.3287887542, 70601.2088968633, 70963.5807782658, 72548.3591964927, 79487.8877885823}, }; const double expected_y[isoline_count][points_per_isoline] = { - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, - {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, + {24999.9999999246, 109298.142140435, 477843.35501547, 2089095.63750003, 9133370.87732516}, }; for (int i = 0; i < d_isolines.size(); ++i) { REQUIRE(d_isolines[i].size() == points_per_isoline); @@ -669,25 +669,25 @@ TEST_CASE("Basic TS Plot has same output as Python", "[Plot]") { std::vector q_values = CoolProp::Plot::generate_values_in_range(CoolProp::iQ, q_range, isoline_count); CoolProp::Plot::Isolines q_isolines = plot.calc_isolines(CoolProp::iQ, q_values, points_per_isoline); REQUIRE(q_isolines.size() == isoline_count); - CHECK_THAT(q_isolines[0].value, WithinAbs(0.0, 1e-10)); - CHECK_THAT(q_isolines[1].value, WithinAbs(0.25, 1e-10)); - CHECK_THAT(q_isolines[2].value, WithinAbs(0.5, 1e-10)); - CHECK_THAT(q_isolines[3].value, WithinAbs(0.75, 1e-10)); - CHECK_THAT(q_isolines[4].value, WithinAbs(1.0, 1e-10)); + CHECK_THAT(q_isolines[0].value, WithinAbs(0.0, 1e-10) || WithinRel(0.0, 1e-8)); + CHECK_THAT(q_isolines[1].value, WithinAbs(0.25, 1e-10) || WithinRel(0.25, 1e-8)); + CHECK_THAT(q_isolines[2].value, WithinAbs(0.5, 1e-10) || WithinRel(0.5, 1e-8)); + CHECK_THAT(q_isolines[3].value, WithinAbs(0.75, 1e-10) || WithinRel(0.75, 1e-8)); + CHECK_THAT(q_isolines[4].value, WithinAbs(1.0, 1e-10) || WithinRel(1.0, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {412.617538232079, 728.71482941326, 994.524404955042, 1237.31924154895, 1561.70306865236}, - {800.440438274308, 992.708859865778, 1177.8221470675, 1354.80424987622, 1561.8974228315}, - {1188.26333831654, 1256.70289031829, 1361.11988917995, 1472.28925820349, 1562.09177701064}, - {1576.08623835876, 1520.69692077081, 1544.4176312924, 1589.77426653076, 1562.28613118978}, - {1963.90913840099, 1784.69095122333, 1727.71537340486, 1707.25927485803, 1562.48048536892}, + {412.617538232079, 728.71482941326, 994.524404955042, 1237.31924154895, 1561.70306865236}, + {800.440438274308, 992.708859865778, 1177.8221470675, 1354.80424987622, 1561.8974228315}, + {1188.26333831654, 1256.70289031829, 1361.11988917995, 1472.28925820349, 1562.09177701064}, + {1576.08623835876, 1520.69692077081, 1544.4176312924, 1589.77426653076, 1562.28613118978}, + {1963.90913840099, 1784.69095122333, 1727.71537340486, 1707.25927485803, 1562.48048536892}, }; const double expected_y[isoline_count][points_per_isoline] = { - {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, - {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, - {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, - {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, - {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, + {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, + {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, + {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, + {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, + {169.850074842393, 220.940538422734, 272.031002003074, 323.121465583414, 374.211929163755}, }; for (int i = 0; i < q_isolines.size(); ++i) { @@ -704,24 +704,24 @@ TEST_CASE("Basic TS Plot has same output as Python", "[Plot]") { std::vector p_values = CoolProp::Plot::generate_values_in_range(CoolProp::iP, p_range, isoline_count); CoolProp::Plot::Isolines p_isolines = plot.calc_isolines(CoolProp::iP, p_values, points_per_isoline); REQUIRE(p_isolines.size() == isoline_count); - CHECK_THAT(p_isolines[0].value, WithinAbs(24999.999999924625, 1e-7)); - CHECK_THAT(p_isolines[1].value, WithinAbs(109298.14214043504, 1e-7)); - CHECK_THAT(p_isolines[2].value, WithinAbs(477843.35501546983, 1e-7)); - CHECK_THAT(p_isolines[3].value, WithinAbs(2089095.6375000286, 1e-7)); - CHECK_THAT(p_isolines[4].value, WithinAbs(9133370.877325162, 1e-7)); + CHECK_THAT(p_isolines[0].value, WithinAbs(24999.999999924625, 1e-7) || WithinRel(24999.999999924625, 1e-8)); + CHECK_THAT(p_isolines[1].value, WithinAbs(109298.14214043504, 1e-7) || WithinRel(109298.14214043504, 1e-8)); + CHECK_THAT(p_isolines[2].value, WithinAbs(477843.35501546983, 1e-7) || WithinRel(477843.35501546983, 1e-8)); + CHECK_THAT(p_isolines[3].value, WithinAbs(2089095.6375000286, 1e-7) || WithinRel(2089095.6375000286, 1e-8)); + CHECK_THAT(p_isolines[4].value, WithinAbs(9133370.877325162, 1e-7) || WithinRel(9133370.877325162, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, }; const double expected_y[isoline_count][points_per_isoline] = { - {171.786072658977, 220.381369310426, 220.381369310426, 265.36247722467, 454.999999999897}, - {171.798910666077, 248.745218250597, 248.745218250597, 308.633922578156, 506.387752765209}, - {171.854988815553, 258.195699077655, 287.473037339606, 355.964867195189, 560.293101205153}, - {172.099235421019, 258.742471435868, 342.561817266701, 411.323964498156, 618.036314182066}, - {173.150000000039, 261.02106158166, 371.327173902085, 484.42783162311, std::nan("")}, + {171.786072658977, 220.381369310426, 220.381369310426, 265.36247722467, 454.999999999897}, + {171.798910666077, 248.745218250597, 248.745218250597, 308.633922578156, 506.387752765209}, + {171.854988815553, 258.195699077655, 287.473037339606, 355.964867195189, 560.293101205153}, + {172.099235421019, 258.742471435868, 342.561817266701, 411.323964498156, 618.036314182066}, + {173.150000000039, 261.02106158166, 371.327173902085, 484.42783162311, std::nan("")}, }; for (int i = 0; i < p_isolines.size(); ++i) { REQUIRE(p_isolines[i].size() == points_per_isoline); @@ -741,24 +741,24 @@ TEST_CASE("Basic TS Plot has same output as Python", "[Plot]") { std::vector h_values = CoolProp::Plot::generate_values_in_range(CoolProp::iHmass, h_range, isoline_count); CoolProp::Plot::Isolines h_isolines = plot.calc_isolines(CoolProp::iHmass, h_values, points_per_isoline); REQUIRE(h_isolines.size() == isoline_count); - CHECK_THAT(h_isolines[0].value, WithinAbs(75373.12689908473, 1e-10)); - CHECK_THAT(h_isolines[1].value, WithinAbs(200930.99391811722, 1e-10)); - CHECK_THAT(h_isolines[2].value, WithinAbs(326488.86093714973, 1e-10)); - CHECK_THAT(h_isolines[3].value, WithinAbs(452046.7279561822, 1e-10)); - CHECK_THAT(h_isolines[4].value, WithinAbs(577604.5949752147, 1e-10)); + CHECK_THAT(h_isolines[0].value, WithinAbs(75373.12689908473, 1e-10) || WithinRel(75373.12689908473, 1e-8)); + CHECK_THAT(h_isolines[1].value, WithinAbs(200930.99391811722, 1e-10) || WithinRel(200930.99391811722, 1e-8)); + CHECK_THAT(h_isolines[2].value, WithinAbs(326488.86093714973, 1e-10) || WithinRel(326488.86093714973, 1e-8)); + CHECK_THAT(h_isolines[3].value, WithinAbs(452046.7279561822, 1e-10) || WithinRel(452046.7279561822, 1e-8)); + CHECK_THAT(h_isolines[4].value, WithinAbs(577604.5949752147, 1e-10) || WithinRel(577604.5949752147, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, - {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, + {426.009483858918, 925.275035740241, 1424.54058762156, 1923.80613950289, 2423.07169138421}, }; const double expected_y[isoline_count][points_per_isoline] = { - {172.17457530891, std::nan(""), std::nan(""), std::nan(""), std::nan("")}, - {196.074550633801, 266.631159311947, std::nan(""), std::nan(""), std::nan("")}, - {213.66468184215, 299.984652703029, 301.726570478677, std::nan(""), std::nan("")}, - {228.411201679483, 322.843563824883, 426.787882130031, 331.521169967994, 328.042167528594}, - {241.568258022782, 341.66133891579, 458.593848045217, std::nan(""), 455.000000000079}, + {172.17457530891, std::nan(""), std::nan(""), std::nan(""), std::nan("")}, + {196.074550633801, 266.631159311947, std::nan(""), std::nan(""), std::nan("")}, + {213.66468184215, 299.984652703029, 301.726570478677, std::nan(""), std::nan("")}, + {228.411201679483, 322.843563824883, 426.787882130031, 331.521169967994, 328.042167528594}, + {241.568258022782, 341.66133891579, 458.593848045217, std::nan(""), 455.000000000079}, }; for (int i = 0; i < h_isolines.size(); ++i) { REQUIRE(h_isolines[i].size() == points_per_isoline); @@ -778,21 +778,24 @@ TEST_CASE("Basic TS Plot has same output as Python", "[Plot]") { std::vector d_values = CoolProp::Plot::generate_values_in_range(CoolProp::iDmass, d_range, isoline_count); CoolProp::Plot::Isolines d_isolines = plot.calc_isolines(CoolProp::iDmass, d_values, points_per_isoline); REQUIRE(d_isolines.size() == isoline_count); - CHECK_THAT(d_isolines[0].value, WithinAbs(0.6749779869915704, 1e-10)); - CHECK_THAT(d_isolines[1].value, WithinAbs(4.704765645221012, 1e-10)); - CHECK_THAT(d_isolines[2].value, WithinAbs(32.793395048494105, 1e-10)); - CHECK_THAT(d_isolines[3].value, WithinAbs(228.57817793729427, 1e-10)); - CHECK_THAT(d_isolines[4].value, WithinAbs(1593.2471569921404, 1e-10)); + CHECK_THAT(d_isolines[0].value, WithinAbs(0.6749779869915704, 1e-10) || WithinRel(0.6749779869915704, 1e-8)); + CHECK_THAT(d_isolines[1].value, WithinAbs(4.704765645221012, 1e-10) || WithinRel(4.704765645221012, 1e-8)); + CHECK_THAT(d_isolines[2].value, WithinAbs(32.793395048494105, 1e-10) || WithinRel(32.793395048494105, 1e-8)); + CHECK_THAT(d_isolines[3].value, WithinAbs(228.57817793729427, 1e-10) || WithinRel(228.57817793729427, 1e-8)); + CHECK_THAT(d_isolines[4].value, WithinAbs(1593.2471569921404, 1e-10) || WithinRel(1593.2471569921404, 1e-8)); const double expected_x[isoline_count][points_per_isoline] = { - {524.173878302998, 1911.09303197673, 2092.95299735844, 2262.71394473455, 2423.07169138421}, - {448.103089615505, 1715.11956249458, 1932.46627813425, 2103.15612327652, 2263.90953791769}, - {437.189451893868, 972.489749676145, 1758.36241052051, 1935.75228615955, 2099.2064319409}, - {435.623706482598, 865.946977105681, 1292.02339683129, 1720.27746043046, 1899.38158004687}, - {426.009483858917, 710.877062876878, 946.968704706707, 1151.91782375263, 1335.56507098392}, + {524.173878302998, 1911.09303197673, 2092.95299735844, 2262.71394473455, 2423.07169138421}, + {448.103089615505, 1715.11956249458, 1932.46627813425, 2103.15612327652, 2263.90953791769}, + {437.189451893868, 972.489749676145, 1758.36241052051, 1935.75228615955, 2099.2064319409}, + {435.623706482598, 865.946977105681, 1292.02339683129, 1720.27746043046, 1899.38158004687}, + {426.009483858917, 710.877062876878, 946.968704706707, 1151.91782375263, 1335.56507098392}, }; const double expected_y[isoline_count][points_per_isoline] = { - {173.15, 243.6125, 314.075, 384.5375, 455}, {173.15, 243.6125, 314.075, 384.5375, 455}, {173.15, 243.6125, 314.075, 384.5375, 455}, - {173.15, 243.6125, 314.075, 384.5375, 455}, {173.15, 243.6125, 314.075, 384.5375, 455}, + {173.15, 243.6125, 314.075, 384.5375, 455}, + {173.15, 243.6125, 314.075, 384.5375, 455}, + {173.15, 243.6125, 314.075, 384.5375, 455}, + {173.15, 243.6125, 314.075, 384.5375, 455}, + {173.15, 243.6125, 314.075, 384.5375, 455}, }; for (int i = 0; i < d_isolines.size(); ++i) { REQUIRE(d_isolines[i].size() == points_per_isoline);