CoolProp  6.6.0
An open-source fluid property and humid air property database
CoolProp-Tests.cpp
Go to the documentation of this file.
1 
2 
3 #include "AbstractState.h"
4 #include "DataStructures.h"
5 #include "../Backends/Helmholtz/HelmholtzEOSMixtureBackend.h"
6 #include "../Backends/Helmholtz/HelmholtzEOSBackend.h"
7 // ############################################
8 // TESTS
9 // ############################################
10 
11 #if defined(ENABLE_CATCH)
12 
14 # include <catch2/catch_all.hpp>
15 # include "CoolPropTools.h"
16 # include "CoolProp.h"
17 
18 using namespace CoolProp;
19 
20 namespace TransportValidation {
21 
22 // A structure to hold the values for one validation call
23 struct vel
24 {
25  public:
26  std::string in1, in2, out, fluid;
27  double v1, v2, tol, expected;
28  vel(std::string fluid, std::string in1, double v1, std::string in2, double v2, std::string out, double expected, double tol) {
29  this->in1 = in1;
30  this->in2 = in2;
31  this->fluid = fluid;
32  this->v1 = v1;
33  this->v2 = v2;
34  this->expected = expected;
35  this->tol = tol;
36  };
37 };
38 
39 vel viscosity_validation_data[] = {
40  // From Vogel, JPCRD, 1998
41  vel("Propane", "T", 90, "Dmolar", 16.52e3, "V", 7388e-6, 1e-3),
42  vel("Propane", "T", 150, "Dmolar", 15.14e3, "V", 656.9e-6, 5e-3),
43  vel("Propane", "T", 600, "Dmolar", 10.03e3, "V", 73.92e-6, 5e-3),
44  vel("Propane", "T", 280, "Dmolar", 11.78e3, "V", 117.4e-6, 1e-3),
45 
46  // Huber, FPE, 2004
47  vel("n-Octane", "T", 300, "Dmolar", 6177.2, "V", 553.60e-6, 1e-3),
48  vel("n-Nonane", "T", 300, "Dmolar", 5619.1, "V", 709.53e-6, 1e-3),
49  vel("n-Decane", "T", 300, "Dmolar", 5150.4, "V", 926.44e-6, 1e-3),
50 
51  // Huber, Energy & Fuels, 2004
52  vel("n-Dodecane", "T", 300, "Dmolar", 4411.5, "V", 1484.8e-6, 1e-3),
53  vel("n-Dodecane", "T", 500, "Dmolar", 3444.7, "V", 183.76e-6, 1e-3),
54 
55  // Huber, I&ECR, 2006
56  vel("R125", "T", 300, "Dmolar", 10596.9998, "V", 177.37e-6, 1e-3),
57  vel("R125", "T", 400, "Dmolar", 30.631, "V", 17.070e-6, 1e-3),
58 
59  // From REFPROP 9.1 since Huber I&ECR 2003 does not provide validation data
60  vel("R134a", "T", 185, "Q", 0, "V", 0.0012698376398294414, 1e-3),
61  vel("R134a", "T", 185, "Q", 1, "V", 7.4290821400170869e-006, 1e-3),
62  vel("R134a", "T", 360, "Q", 0, "V", 7.8146319978982133e-005, 1e-3),
63  vel("R134a", "T", 360, "Q", 1, "V", 1.7140264998576107e-005, 1e-3),
64 
65  // From REFPROP 9.1 since Kiselev, IECR, 2005 does not provide validation data
66  vel("Ethanol", "T", 300, "Q", 0, "V", 0.0010439017679191723, 1e-3),
67  vel("Ethanol", "T", 300, "Q", 1, "V", 8.8293820936046416e-006, 1e-3),
68  vel("Ethanol", "T", 500, "Q", 0, "V", 6.0979347125450671e-005, 1e-3),
69  vel("Ethanol", "T", 500, "Q", 1, "V", 1.7229157141572511e-005, 1e-3),
70 
71  // From CoolProp v5 implementation of correlation - more or less agrees with REFPROP
72  // Errata in BibTeX File
73  vel("Hydrogen", "T", 35, "Dmass", 100, "V", 5.47889e-005, 1e-3),
74 
75  // From Meng 2012 experimental data (note erratum in BibTeX file)
76  vel("DimethylEther", "T", 253.146, "Dmass", 734.28, "V", 0.20444e-3, 3e-3),
77  vel("DimethylEther", "T", 373.132, "Dmass", 613.78, "V", 0.09991e-3, 3e-3),
78 
79  // From Fenghour, JPCRD, 1995
80  vel("Ammonia", "T", 200, "Dmolar", 3.9, "V", 6.95e-6, 1e-3),
81  vel("Ammonia", "T", 200, "Dmolar", 42754.4, "V", 507.28e-6, 1e-3),
82  vel("Ammonia", "T", 398, "Dmolar", 7044.7, "V", 17.67e-6, 1e-3),
83  vel("Ammonia", "T", 398, "Dmolar", 21066.7, "V", 43.95e-6, 1e-3),
84 
85  // From Lemmon and Jacobsen, JPCRD, 2004
86  vel("Nitrogen", "T", 100, "Dmolar", 1e-14, "V", 6.90349e-6, 1e-3),
87  vel("Nitrogen", "T", 300, "Dmolar", 1e-14, "V", 17.8771e-6, 1e-3),
88  vel("Nitrogen", "T", 100, "Dmolar", 25000, "V", 79.7418e-6, 1e-3),
89  vel("Nitrogen", "T", 200, "Dmolar", 10000, "V", 21.0810e-6, 1e-3),
90  vel("Nitrogen", "T", 300, "Dmolar", 5000, "V", 20.7430e-6, 1e-3),
91  vel("Nitrogen", "T", 126.195, "Dmolar", 11180, "V", 18.2978e-6, 1e-3),
92  vel("Argon", "T", 100, "Dmolar", 1e-14, "V", 8.18940e-6, 1e-3),
93  vel("Argon", "T", 300, "Dmolar", 1e-14, "V", 22.7241e-6, 1e-3),
94  vel("Argon", "T", 100, "Dmolar", 33000, "V", 184.232e-6, 1e-3),
95  vel("Argon", "T", 200, "Dmolar", 10000, "V", 25.5662e-6, 1e-3),
96  vel("Argon", "T", 300, "Dmolar", 5000, "V", 26.3706e-6, 1e-3),
97  vel("Argon", "T", 150.69, "Dmolar", 13400, "V", 27.6101e-6, 1e-3),
98  vel("Oxygen", "T", 100, "Dmolar", 1e-14, "V", 7.70243e-6, 1e-3),
99  vel("Oxygen", "T", 300, "Dmolar", 1e-14, "V", 20.6307e-6, 1e-3),
100  vel("Oxygen", "T", 100, "Dmolar", 35000, "V", 172.136e-6, 1e-3),
101  vel("Oxygen", "T", 200, "Dmolar", 10000, "V", 22.4445e-6, 1e-3),
102  vel("Oxygen", "T", 300, "Dmolar", 5000, "V", 23.7577e-6, 1e-3),
103  vel("Oxygen", "T", 154.6, "Dmolar", 13600, "V", 24.7898e-6, 1e-3),
104  vel("Air", "T", 100, "Dmolar", 1e-14, "V", 7.09559e-6, 1e-3),
105  vel("Air", "T", 300, "Dmolar", 1e-14, "V", 18.5230e-6, 1e-3),
106  vel("Air", "T", 100, "Dmolar", 28000, "V", 107.923e-6, 1e-3),
107  vel("Air", "T", 200, "Dmolar", 10000, "V", 21.1392e-6, 1e-3),
108  vel("Air", "T", 300, "Dmolar", 5000, "V", 21.3241e-6, 1e-3),
109  vel("Air", "T", 132.64, "Dmolar", 10400, "V", 17.7623e-6, 1e-3),
110 
111  // From Michailidou, JPCRD, 2013
112  vel("Hexane", "T", 250, "Dmass", 1e-14, "V", 5.2584e-6, 1e-3),
113  vel("Hexane", "T", 400, "Dmass", 1e-14, "V", 8.4149e-6, 1e-3),
114  vel("Hexane", "T", 550, "Dmass", 1e-14, "V", 11.442e-6, 1e-3),
115  vel("Hexane", "T", 250, "Dmass", 700, "V", 528.2e-6, 1e-3),
116  vel("Hexane", "T", 400, "Dmass", 600, "V", 177.62e-6, 1e-3),
117  vel("Hexane", "T", 550, "Dmass", 500, "V", 95.002e-6, 1e-3),
118 
119  // From Assael, JPCRD, 2014
120  vel("Heptane", "T", 250, "Dmass", 1e-14, "V", 4.9717e-6, 1e-3),
121  vel("Heptane", "T", 400, "Dmass", 1e-14, "V", 7.8361e-6, 1e-3),
122  vel("Heptane", "T", 550, "Dmass", 1e-14, "V", 10.7394e-6, 1e-3),
123  vel("Heptane", "T", 250, "Dmass", 720, "V", 725.69e-6, 1e-3),
124  vel("Heptane", "T", 400, "Dmass", 600, "V", 175.94e-6, 1e-3),
125  vel("Heptane", "T", 550, "Dmass", 500, "V", 95.105e-6, 1e-3),
126 
127  // From Fenghour, JPCRD, 1998
128  vel("CO2", "T", 220, "Dmass", 2.440, "V", 11.06e-6, 1e-3),
129  vel("CO2", "T", 300, "Dmass", 1.773, "V", 15.02e-6, 1e-3),
130  vel("CO2", "T", 800, "Dmass", 0.662, "V", 35.09e-6, 1e-3),
131  vel("CO2", "T", 304, "Dmass", 254.320, "V", 20.99e-6, 1e-2), // no critical enhancement
132  vel("CO2", "T", 220, "Dmass", 1194.86, "V", 269.37e-6, 1e-3),
133  vel("CO2", "T", 300, "Dmass", 1029.27, "V", 132.55e-6, 1e-3),
134  vel("CO2", "T", 800, "Dmass", 407.828, "V", 48.74e-6, 1e-3),
135 
136  // Tanaka, IJT, 1996
137  vel("R123", "T", 265, "Dmass", 1545.8, "V", 627.1e-6, 1e-3),
138  vel("R123", "T", 265, "Dmass", 1.614, "V", 9.534e-6, 1e-3),
139  vel("R123", "T", 415, "Dmass", 1079.4, "V", 121.3e-6, 1e-3),
140  vel("R123", "T", 415, "Dmass", 118.9, "V", 15.82e-6, 1e-3),
141 
142  // Krauss, IJT, 1996
143  vel("R152A", "T", 242, "Dmass", 1025.5, "V", 347.3e-6, 1e-3),
144  vel("R152A", "T", 242, "Dmass", 2.4868, "V", 8.174e-6, 1e-3),
145  vel("R152A", "T", 384, "Dmass", 504.51, "V", 43.29e-6, 5e-3),
146  vel("R152A", "T", 384, "Dmass", 239.35, "V", 21.01e-6, 10e-3),
147 
148  // Huber, JPCRD, 2008 and IAPWS
149  vel("Water", "T", 298.15, "Dmass", 998, "V", 889.735100e-6, 1e-7),
150  vel("Water", "T", 298.15, "Dmass", 1200, "V", 1437.649467e-6, 1e-7),
151  vel("Water", "T", 373.15, "Dmass", 1000, "V", 307.883622e-6, 1e-7),
152  vel("Water", "T", 433.15, "Dmass", 1, "V", 14.538324e-6, 1e-7),
153  vel("Water", "T", 433.15, "Dmass", 1000, "V", 217.685358e-6, 1e-7),
154  vel("Water", "T", 873.15, "Dmass", 1, "V", 32.619287e-6, 1e-7),
155  vel("Water", "T", 873.15, "Dmass", 100, "V", 35.802262e-6, 1e-7),
156  vel("Water", "T", 873.15, "Dmass", 600, "V", 77.430195e-6, 1e-7),
157  vel("Water", "T", 1173.15, "Dmass", 1, "V", 44.217245e-6, 1e-7),
158  vel("Water", "T", 1173.15, "Dmass", 100, "V", 47.640433e-6, 1e-7),
159  vel("Water", "T", 1173.15, "Dmass", 400, "V", 64.154608e-6, 1e-7),
160  vel("Water", "T", 647.35, "Dmass", 122, "V", 25.520677e-6, 1e-7),
161  vel("Water", "T", 647.35, "Dmass", 222, "V", 31.337589e-6, 1e-7),
162  vel("Water", "T", 647.35, "Dmass", 272, "V", 36.228143e-6, 1e-7),
163  vel("Water", "T", 647.35, "Dmass", 322, "V", 42.961579e-6, 1e-7),
164  vel("Water", "T", 647.35, "Dmass", 372, "V", 45.688204e-6, 1e-7),
165  vel("Water", "T", 647.35, "Dmass", 422, "V", 49.436256e-6, 1e-7),
166 
167  // Quinones-Cisneros, JPCRD, 2012
168  vel("SF6", "T", 300, "Dmass", 1e-14, "V", 15.2887e-6, 1e-4),
169  vel("SF6", "T", 300, "Dmass", 5.92, "V", 15.3043e-6, 1e-4),
170  vel("SF6", "T", 300, "Dmass", 1345.1, "V", 117.417e-6, 1e-4),
171  vel("SF6", "T", 400, "Dmass", 1e-14, "V", 19.6796e-6, 1e-4),
172  vel("SF6", "T", 400, "Dmass", 278.47, "V", 24.4272e-6, 1e-4),
173  vel("SF6", "T", 400, "Dmass", 1123.8, "V", 84.7835e-6, 1e-4),
174 
175  // Quinones-Cisneros, JCED, 2012, data from validation
176  vel("H2S", "T", 200, "P", 1000e5, "V", 0.000460287, 1e-3),
177  vel("H2S", "T", 200, "P", 0.251702e5, "V", 8.02322E-06, 1e-3),
178  vel("H2S", "T", 596.961, "P", 1000e5, "V", 6.94741E-05, 1e-3),
179  vel("H2S", "T", 596.961, "P", 1e5, "V", 2.38654E-05, 1e-3),
180 
181  // Geller, Purdue Conference, 2000
182  //vel("R410A", "T", 243.15, "Q", 0, "V", 238.61e-6, 5e-2),
183  //vel("R410A", "T", 243.15, "Q", 1, "V", 10.37e-6, 5e-2),
184  //vel("R410A", "T", 333.15, "Q", 0, "V", 70.71e-6, 5e-2),
185  //vel("R410A", "T", 333.15, "Q", 1, "V", 19.19e-6, 5e-2),
186  //vel("R407C", "T", 243.15, "Q", 0, "V", 304.18e-6, 1e-2),
187  //vel("R407C", "T", 243.15, "Q", 1, "V", 9.83e-6, 1e-2),
188  //vel("R407C", "T", 333.15, "Q", 0, "V", 95.96e-6, 1e-2),
189  //vel("R407C", "T", 333.15, "Q", 1, "V", 16.38e-6, 1e-2),
190  //vel("R404A", "T", 243.15, "Q", 0, "V", 264.67e-6, 1e-2),
191  //vel("R404A", "T", 243.15, "Q", 1, "V", 10.13e-6, 1e-2),
192  //vel("R404A", "T", 333.15, "Q", 0, "V", 73.92e-6, 1e-2),
193  //vel("R404A", "T", 333.15, "Q", 1, "V", 18.56e-6, 1e-2),
194  //vel("R507A", "T", 243.15, "Q", 0, "V", 284.59e-6, 3e-2),
195  //vel("R507A", "T", 243.15, "Q", 1, "V", 9.83e-6, 1e-2),
196  //vel("R507A", "T", 333.15, "Q", 0, "V", 74.37e-6, 1e-2),
197  //vel("R507A", "T", 333.15, "Q", 1, "V", 19.35e-6, 1e-2),
198 
199  // From Arp, NIST, 1998
200  vel("Helium", "T", 3.6, "P", 0.180e6, "V", 3.745e-6, 1e-2),
201  vel("Helium", "T", 50, "P", 0.180e6, "V", 6.376e-6, 1e-2),
202  vel("Helium", "T", 400, "P", 0.180e6, "V", 24.29e-6, 1e-2),
203 
204  // From Shan, ASHRAE, 2000
205  vel("R23", "T", 180, "Dmolar", 21097, "V", 353.88e-6, 1e-4),
206  vel("R23", "T", 420, "Dmolar", 7564, "V", 39.459e-6, 1e-4),
207  vel("R23", "T", 370, "Dmolar", 32.62, "V", 18.213e-6, 1e-4),
208 
209  // From Friend, JPCRD, 1991
210  vel("Ethane", "T", 100, "Dmolar", 21330, "V", 878.6e-6, 1e-2),
211  vel("Ethane", "T", 430, "Dmolar", 12780, "V", 58.70e-6, 1e-2),
212  vel("Ethane", "T", 500, "Dmolar", 11210, "V", 48.34e-6, 1e-2),
213 
214  // From Xiang, JPCRD, 2006
215  vel("Methanol", "T", 300, "Dmass", 0.12955, "V", 0.009696e-3, 1e-3),
216  vel("Methanol", "T", 300, "Dmass", 788.41, "V", 0.5422e-3, 1e-3),
217  vel("Methanol", "T", 630, "Dmass", 0.061183, "V", 0.02081e-3, 1e-3),
218  vel("Methanol", "T", 630, "Dmass", 888.50, "V", 0.2405e-3, 1e-1), // They use a different EOS in the high pressure region
219 
220  // From REFPROP 9.1 since no data provided
221  vel("n-Butane", "T", 150, "Q", 0, "V", 0.0013697657668, 1e-4),
222  vel("n-Butane", "T", 400, "Q", 1, "V", 1.2027464524762453e-005, 1e-4),
223  vel("IsoButane", "T", 120, "Q", 0, "V", 0.0060558450757844271, 1e-4),
224  vel("IsoButane", "T", 400, "Q", 1, "V", 1.4761041187617117e-005, 2e-4),
225  vel("R134a", "T", 175, "Q", 0, "V", 0.0017558494524138289, 1e-4),
226  vel("R134a", "T", 360, "Q", 1, "V", 1.7140264998576107e-005, 1e-4),
227 
228  // From Tariq, JPCRD, 2014
229  vel("Cyclohexane", "T", 300, "Dmolar", 1e-10, "V", 7.058e-6, 1e-4),
230  vel("Cyclohexane", "T", 300, "Dmolar", 0.0430e3, "V", 6.977e-6, 1e-4),
231  vel("Cyclohexane", "T", 300, "Dmolar", 9.1756e3, "V", 863.66e-6, 1e-4),
232  vel("Cyclohexane", "T", 300, "Dmolar", 9.9508e3, "V", 2850.18e-6, 1e-4),
233  vel("Cyclohexane", "T", 500, "Dmolar", 1e-10, "V", 11.189e-6, 1e-4),
234  vel("Cyclohexane", "T", 500, "Dmolar", 6.0213e3, "V", 94.842e-6, 1e-4),
235  vel("Cyclohexane", "T", 500, "Dmolar", 8.5915e3, "V", 380.04e-6, 1e-4),
236  vel("Cyclohexane", "T", 700, "Dmolar", 1e-10, "V", 15.093e-6, 1e-4),
237  vel("Cyclohexane", "T", 700, "Dmolar", 7.4765e3, "V", 176.749e-6, 1e-4),
238 
239  // From Avgeri, JPCRD, 2014
240  vel("Benzene", "T", 300, "Dmass", 1e-10, "V", 7.625e-6, 1e-4),
241  vel("Benzene", "T", 400, "Dmass", 1e-10, "V", 10.102e-6, 1e-4),
242  vel("Benzene", "T", 550, "Dmass", 1e-10, "V", 13.790e-6, 1e-4),
243  vel("Benzene", "T", 300, "Dmass", 875, "V", 608.52e-6, 1e-4),
244  vel("Benzene", "T", 400, "Dmass", 760, "V", 211.74e-6, 1e-4),
245  vel("Benzene", "T", 550, "Dmass", 500, "V", 60.511e-6, 1e-4),
246 
247  // From Cao, JPCRD, 2016
248  vel("m-Xylene", "T", 300, "Dmolar", 1e-10, "V", 6.637e-6, 1e-4),
249  vel("m-Xylene", "T", 300, "Dmolar", 0.04 * 1e3, "V", 6.564e-6, 1e-4),
250  vel("m-Xylene", "T", 300, "Dmolar", 8.0849 * 1e3, "V", 569.680e-6, 1e-4),
251  vel("m-Xylene", "T", 300, "Dmolar", 8.9421 * 1e3, "V", 1898.841e-6, 1e-4),
252  vel("m-Xylene", "T", 400, "Dmolar", 1e-10, "V", 8.616e-6, 1e-4),
253  vel("m-Xylene", "T", 400, "Dmolar", 0.04 * 1e3, "V", 8.585e-6, 1e-4),
254  vel("m-Xylene", "T", 400, "Dmolar", 7.2282 * 1e3, "V", 238.785e-6, 1e-4),
255  vel("m-Xylene", "T", 400, "Dmolar", 8.4734 * 1e3, "V", 718.950e-6, 1e-4),
256  vel("m-Xylene", "T", 600, "Dmolar", 1e-10, "V", 12.841e-6, 1e-4),
257  vel("m-Xylene", "T", 600, "Dmolar", 0.04 * 1e3, "V", 12.936e-6, 1e-4),
258  vel("m-Xylene", "T", 600, "Dmolar", 7.6591 * 1e3, "V", 299.164e-6, 1e-4),
259 
260  // From Cao, JPCRD, 2016
261  vel("o-Xylene", "T", 300, "Dmolar", 1e-10, "V", 6.670e-6, 1e-4),
262  vel("o-Xylene", "T", 300, "Dmolar", 0.04 * 1e3, "V", 6.598e-6, 1e-4),
263  vel("o-Xylene", "T", 300, "Dmolar", 8.2369 * 1e3, "V", 738.286e-6, 1e-4),
264  vel("o-Xylene", "T", 300, "Dmolar", 8.7845 * 1e3, "V", 1645.436e-6, 1e-4),
265  vel("o-Xylene", "T", 400, "Dmolar", 1e-10, "V", 8.658e-6, 1e-4),
266  vel("o-Xylene", "T", 400, "Dmolar", 0.04 * 1e3, "V", 8.634e-6, 1e-4),
267  vel("o-Xylene", "T", 400, "Dmolar", 7.4060 * 1e3, "V", 279.954e-6, 1e-4),
268  vel("o-Xylene", "T", 400, "Dmolar", 8.2291 * 1e3, "V", 595.652e-6, 1e-4),
269  vel("o-Xylene", "T", 600, "Dmolar", 1e-10, "V", 12.904e-6, 1e-4),
270  vel("o-Xylene", "T", 600, "Dmolar", 0.04 * 1e3, "V", 13.018e-6, 1e-4),
271  vel("o-Xylene", "T", 600, "Dmolar", 7.2408 * 1e3, "V", 253.530e-6, 1e-4),
272 
273  // From Balogun, JPCRD, 2016
274  vel("p-Xylene", "T", 300, "Dmolar", 1e-10, "V", 6.604e-6, 1e-4),
275  vel("p-Xylene", "T", 300, "Dmolar", 0.049 * 1e3, "V", 6.405e-6, 1e-4),
276  vel("p-Xylene", "T", 300, "Dmolar", 8.0548 * 1e3, "V", 593.272e-6, 1e-4),
277  vel("p-Xylene", "T", 300, "Dmolar", 8.6309 * 1e3, "V", 1266.337e-6, 1e-4),
278  vel("p-Xylene", "T", 400, "Dmolar", 1e-10, "V", 8.573e-6, 1e-4),
279  vel("p-Xylene", "T", 400, "Dmolar", 7.1995 * 1e3, "V", 239.202e-6, 1e-4),
280  vel("p-Xylene", "T", 400, "Dmolar", 8.0735 * 1e3, "V", 484.512e-6, 1e-4),
281  vel("p-Xylene", "T", 600, "Dmolar", 1e-10, "V", 12.777e-6, 1e-4),
282  vel("p-Xylene", "T", 600, "Dmolar", 7.0985 * 1e3, "V", 209.151e-6, 1e-4),
283 
284  // From Mylona, JPCRD, 2014
285  vel("EthylBenzene", "T", 617, "Dmass", 316, "V", 33.22e-6, 1e-2),
286 
287  // Heavy Water, IAPWS formulation
288  vel("HeavyWater", "T", 0.5000 * 643.847, "Dmass", 3.07 * 358, "V", 12.0604912273 * 55.2651e-6, 1e-5),
289  vel("HeavyWater", "T", 0.9000 * 643.847, "Dmass", 2.16 * 358, "V", 1.6561616211 * 55.2651e-6, 1e-5),
290  vel("HeavyWater", "T", 1.2000 * 643.847, "Dmass", 0.8 * 358, "V", 0.7651099154 * 55.2651e-6, 1e-5),
291 
292  // Toluene, Avgeri, JPCRD, 2015
293  vel("Toluene", "T", 300, "Dmass", 1e-10, "V", 7.023e-6, 1e-4),
294  vel("Toluene", "T", 400, "Dmass", 1e-10, "V", 9.243e-6, 1e-4),
295  vel("Toluene", "T", 550, "Dmass", 1e-10, "V", 12.607e-6, 1e-4),
296  vel("Toluene", "T", 300, "Dmass", 865, "V", 566.78e-6, 1e-4),
297  vel("Toluene", "T", 400, "Dmass", 770, "V", 232.75e-6, 1e-4),
298  vel("Toluene", "T", 550, "Dmass", 550, "V", 80.267e-6, 1e-4),
299 
300 };
301 
302 class TransportValidationFixture
303 {
304  protected:
305  CoolPropDbl actual, x1, x2;
306  shared_ptr<CoolProp::AbstractState> pState;
308 
309  public:
310  TransportValidationFixture() {}
311  ~TransportValidationFixture() {}
312  void set_backend(std::string backend, std::string fluid_name) {
313  pState.reset(CoolProp::AbstractState::factory(backend, fluid_name));
314  }
315  void set_pair(std::string& in1, double v1, std::string& in2, double v2) {
316  double o1, o2;
319  CoolProp::input_pairs pair = CoolProp::generate_update_pair(iin1, v1, iin2, v2, o1, o2);
320  pState->update(pair, o1, o2);
321  }
322  void get_value(parameters key) {
323  actual = pState->keyed_output(key);
324  }
325 };
326 
327 TEST_CASE_METHOD(TransportValidationFixture, "Compare viscosities against published data", "[viscosity],[transport]") {
328  int inputsN = sizeof(viscosity_validation_data) / sizeof(viscosity_validation_data[0]);
329  for (int i = 0; i < inputsN; ++i) {
330  vel el = viscosity_validation_data[i];
331  CHECK_NOTHROW(set_backend("HEOS", el.fluid));
332 
333  CAPTURE(el.fluid);
334  CAPTURE(el.in1);
335  CAPTURE(el.v1);
336  CAPTURE(el.in2);
337  CAPTURE(el.v2);
338  CHECK_NOTHROW(set_pair(el.in1, el.v1, el.in2, el.v2));
339  CHECK_NOTHROW(get_value(CoolProp::iviscosity));
340  CAPTURE(el.expected);
341  CAPTURE(actual);
342  CHECK(std::abs(actual / el.expected - 1) < el.tol);
343  }
344 }
345 
346 vel conductivity_validation_data[] = {
348 
349  // From Assael, JPCRD, 2013
350  vel("Hexane", "T", 250, "Dmass", 700, "L", 137.62e-3, 1e-4),
351  vel("Hexane", "T", 400, "Dmass", 2, "L", 23.558e-3, 1e-4),
352  vel("Hexane", "T", 400, "Dmass", 650, "L", 129.28e-3, 2e-4),
353  vel("Hexane", "T", 510, "Dmass", 2, "L", 36.772e-3, 1e-4),
354 
355  // From Assael, JPCRD, 2013
356  vel("Heptane", "T", 250, "Dmass", 720, "L", 137.09e-3, 1e-4),
357  vel("Heptane", "T", 400, "Dmass", 2, "L", 21.794e-3, 1e-4),
358  vel("Heptane", "T", 400, "Dmass", 650, "L", 120.75e-3, 1e-4),
359  vel("Heptane", "T", 535, "Dmass", 100, "L", 51.655e-3, 3e-3), // Relaxed tolerance because conductivity was fit using older viscosity correlation
360 
361  // From Assael, JPCRD, 2013
362  vel("Ethanol", "T", 300, "Dmass", 850, "L", 209.68e-3, 1e-4),
363  vel("Ethanol", "T", 400, "Dmass", 2, "L", 26.108e-3, 1e-4),
364  vel("Ethanol", "T", 400, "Dmass", 690, "L", 149.21e-3, 1e-4),
365  vel("Ethanol", "T", 500, "Dmass", 10, "L", 39.594e-3, 1e-4),
366 
368  //vel("Toluene", "T", 298.15, "Dmass", 1e-15, "L", 10.749e-3, 1e-4),
369  //vel("Toluene", "T", 298.15, "Dmass", 862.948, "L", 130.66e-3, 1e-4),
370  //vel("Toluene", "T", 298.15, "Dmass", 876.804, "L", 136.70e-3, 1e-4),
371  //vel("Toluene", "T", 595, "Dmass", 1e-15, "L", 40.538e-3, 1e-4),
372  //vel("Toluene", "T", 595, "Dmass", 46.512, "L", 41.549e-3, 1e-4),
373  //vel("Toluene", "T", 185, "Dmass", 1e-15, "L", 4.3758e-3, 1e-4),
374  //vel("Toluene", "T", 185, "Dmass", 968.821, "L", 158.24e-3, 1e-4),
375 
376  // From Assael, JPCRD, 2012
377  vel("SF6", "T", 298.15, "Dmass", 1e-13, "L", 12.952e-3, 1e-4),
378  vel("SF6", "T", 298.15, "Dmass", 100, "L", 14.126e-3, 1e-4),
379  vel("SF6", "T", 298.15, "Dmass", 1600, "L", 69.729e-3, 1e-4),
380  vel("SF6", "T", 310, "Dmass", 1e-13, "L", 13.834e-3, 1e-4),
381  vel("SF6", "T", 310, "Dmass", 1200, "L", 48.705e-3, 1e-4),
382  vel("SF6", "T", 480, "Dmass", 100, "L", 28.847e-3, 1e-4),
383 
385  //vel("Benzene", "T", 290, "Dmass", 890, "L", 147.66e-3, 1e-4),
386  //vel("Benzene", "T", 500, "Dmass", 2, "L", 30.174e-3, 1e-4),
387  //vel("Benzene", "T", 500, "Dmass", 32, "L", 32.175e-3, 1e-4),
388  //vel("Benzene", "T", 500, "Dmass", 800, "L", 141.24e-3, 1e-4),
389  //vel("Benzene", "T", 575, "Dmass", 1.7, "L", 37.763e-3, 1e-4),
390 
391  // From Assael, JPCRD, 2011
392  vel("Hydrogen", "T", 298.15, "Dmass", 1e-13, "L", 185.67e-3, 1e-4),
393  vel("Hydrogen", "T", 298.15, "Dmass", 0.80844, "L", 186.97e-3, 1e-4),
394  vel("Hydrogen", "T", 298.15, "Dmass", 14.4813, "L", 201.35e-3, 1e-4),
395  vel("Hydrogen", "T", 35, "Dmass", 1e-13, "L", 26.988e-3, 1e-4),
396  vel("Hydrogen", "T", 35, "Dmass", 30, "L", 0.0770177, 1e-4), // Updated since Assael uses a different viscosity correlation
397  vel("Hydrogen", "T", 18, "Dmass", 1e-13, "L", 13.875e-3, 1e-4),
398  vel("Hydrogen", "T", 18, "Dmass", 75, "L", 104.48e-3, 1e-4),
399  /*vel("ParaHydrogen", "T", 298.15, "Dmass", 1e-13, "L", 192.38e-3, 1e-4),
400 vel("ParaHydrogen", "T", 298.15, "Dmass", 0.80844, "L", 192.81e-3, 1e-4),
401 vel("ParaHydrogen", "T", 298.15, "Dmass", 14.4813, "L", 207.85e-3, 1e-4),
402 vel("ParaHydrogen", "T", 35, "Dmass", 1e-13, "L", 27.222e-3, 1e-4),
403 vel("ParaHydrogen", "T", 35, "Dmass", 30, "L", 70.335e-3, 1e-4),
404 vel("ParaHydrogen", "T", 18, "Dmass", 1e-13, "L", 13.643e-3, 1e-4),
405 vel("ParaHydrogen", "T", 18, "Dmass", 75, "L", 100.52e-3, 1e-4),*/
406 
407  // Some of these don't work
408  vel("R125", "T", 341, "Dmass", 600, "L", 0.0565642978494, 2e-4),
409  vel("R125", "T", 200, "Dmass", 1e-13, "L", 0.007036843623086, 2e-4),
410  vel("IsoButane", "T", 390, "Dmass", 387.09520158645068, "L", 0.063039, 2e-4),
411  vel("IsoButane", "T", 390, "Dmass", 85.76703973869482, "L", 0.036603, 2e-4),
412  vel("n-Butane", "T", 415, "Dmass", 360.01895129934866, "L", 0.067045, 2e-4),
413  vel("n-Butane", "T", 415, "Dmass", 110.3113177144, "L", 0.044449, 1e-4),
414 
415  // From Huber, FPE, 2005
416  vel("n-Octane", "T", 300, "Dmolar", 6177.2, "L", 0.12836, 1e-4),
417  vel("n-Nonane", "T", 300, "Dmolar", 5619.4, "L", 0.13031, 1e-4),
418  //vel("n-Decane", "T", 300, "Dmass", 5150.4, "L", 0.13280, 1e-4), // no viscosity
419 
420  // From Huber, EF, 2004
421  vel("n-Dodecane", "T", 300, "Dmolar", 4411.5, "L", 0.13829, 1e-4),
422  vel("n-Dodecane", "T", 500, "Dmolar", 3444.7, "L", 0.09384, 1e-4),
423  vel("n-Dodecane", "T", 660, "Dmolar", 1500.98, "L", 0.090346, 1e-4),
424 
425  // From REFPROP 9.1 since no data provided in Marsh, 2002
426  vel("n-Propane", "T", 368, "Q", 0, "L", 0.07282154952457, 1e-3),
427  vel("n-Propane", "T", 368, "Dmolar", 1e-10, "L", 0.0266135388745317, 1e-4),
428 
429  // From Perkins, JCED, 2011
430  //vel("R1234yf", "T", 250, "Dmass", 2.80006, "L", 0.0098481, 1e-4),
431  //vel("R1234yf", "T", 300, "Dmass", 4.671556, "L", 0.013996, 1e-4),
432  //vel("R1234yf", "T", 250, "Dmass", 1299.50, "L", 0.088574, 1e-4),
433  //vel("R1234yf", "T", 300, "Dmass", 1182.05, "L", 0.075245, 1e-4),
434  //vel("R1234ze(E)", "T", 250, "Dmass", 2.80451, "L", 0.0098503, 1e-4),
435  //vel("R1234ze(E)", "T", 300, "Dmass", 4.67948, "L", 0.013933, 1e-4),
436  //vel("R1234ze(E)", "T", 250, "Dmass", 1349.37, "L", 0.10066, 1e-4),
437  //vel("R1234ze(E)", "T", 300, "Dmass", 1233.82, "L", 0.085389, 1e-4),
438 
439  // From Laesecke, IJR 1995
440  vel("R123", "T", 180, "Dmass", 1739, "L", 110.9e-3, 2e-4),
441  vel("R123", "T", 180, "Dmass", 0.2873e-2, "L", 2.473e-3, 1e-3),
442  vel("R123", "T", 430, "Dmass", 996.35, "L", 45.62e-3, 1e-3),
443  vel("R123", "T", 430, "Dmass", 166.9, "L", 21.03e-3, 1e-3),
444 
445  // From Scalabrin, JPCRD, 2006
446  vel("CO2", "T", 218, "Q", 0, "L", 181.09e-3, 1e-4),
447  vel("CO2", "T", 218, "Q", 1, "L", 10.837e-3, 1e-4),
448  vel("CO2", "T", 304, "Q", 0, "L", 140.3e-3, 1e-4),
449  vel("CO2", "T", 304, "Q", 1, "L", 217.95e-3, 1e-4),
450  vel("CO2", "T", 225, "Dmass", 0.23555, "L", 11.037e-3, 1e-4),
451  vel("CO2", "T", 275, "Dmass", 1281.64, "L", 238.44e-3, 1e-4),
452 
453  // From Friend, JPCRD, 1991
454  vel("Ethane", "T", 100, "Dmass", 1e-13, "L", 3.46e-3, 1e-2),
455  vel("Ethane", "T", 230, "Dmolar", 16020, "L", 126.2e-3, 1e-2),
456  vel("Ethane", "T", 440, "Dmolar", 1520, "L", 45.9e-3, 1e-2),
457  vel("Ethane", "T", 310, "Dmolar", 4130, "L", 45.4e-3, 1e-2),
458 
459  // From Lemmon and Jacobsen, JPCRD, 2004
460  vel("Nitrogen", "T", 100, "Dmolar", 1e-14, "L", 9.27749e-3, 1e-4),
461  vel("Nitrogen", "T", 300, "Dmolar", 1e-14, "L", 25.9361e-3, 1e-4),
462  vel("Nitrogen", "T", 100, "Dmolar", 25000, "L", 103.834e-3, 1e-4),
463  vel("Nitrogen", "T", 200, "Dmolar", 10000, "L", 36.0099e-3, 1e-4),
464  vel("Nitrogen", "T", 300, "Dmolar", 5000, "L", 32.7694e-3, 1e-4),
465  vel("Nitrogen", "T", 126.195, "Dmolar", 11180, "L", 675.800e-3, 1e-4),
466  vel("Argon", "T", 100, "Dmolar", 1e-14, "L", 6.36587e-3, 1e-4),
467  vel("Argon", "T", 300, "Dmolar", 1e-14, "L", 17.8042e-3, 1e-4),
468  vel("Argon", "T", 100, "Dmolar", 33000, "L", 111.266e-3, 1e-4),
469  vel("Argon", "T", 200, "Dmolar", 10000, "L", 26.1377e-3, 1e-4),
470  vel("Argon", "T", 300, "Dmolar", 5000, "L", 23.2302e-3, 1e-4),
471  vel("Argon", "T", 150.69, "Dmolar", 13400, "L", 856.793e-3, 1e-4),
472  vel("Oxygen", "T", 100, "Dmolar", 1e-14, "L", 8.94334e-3, 1e-4),
473  vel("Oxygen", "T", 300, "Dmolar", 1e-14, "L", 26.4403e-3, 1e-4),
474  vel("Oxygen", "T", 100, "Dmolar", 35000, "L", 146.044e-3, 1e-4),
475  vel("Oxygen", "T", 200, "Dmolar", 10000, "L", 34.6124e-3, 1e-4),
476  vel("Oxygen", "T", 300, "Dmolar", 5000, "L", 32.5491e-3, 1e-4),
477  vel("Oxygen", "T", 154.6, "Dmolar", 13600, "L", 377.476e-3, 1e-4),
478  vel("Air", "T", 100, "Dmolar", 1e-14, "L", 9.35902e-3, 1e-4),
479  vel("Air", "T", 300, "Dmolar", 1e-14, "L", 26.3529e-3, 1e-4),
480  vel("Air", "T", 100, "Dmolar", 28000, "L", 119.221e-3, 1e-4),
481  vel("Air", "T", 200, "Dmolar", 10000, "L", 35.3185e-3, 1e-4),
482  vel("Air", "T", 300, "Dmolar", 5000, "L", 32.6062e-3, 1e-4),
483  vel("Air", "T", 132.64, "Dmolar", 10400, "L", 75.6231e-3, 1e-4),
484 
485  // Huber, JPCRD, 2012
486  vel("Water", "T", 298.15, "Dmass", 1e-14, "L", 18.4341883e-3, 1e-6),
487  vel("Water", "T", 298.15, "Dmass", 998, "L", 607.712868e-3, 1e-6),
488  vel("Water", "T", 298.15, "Dmass", 1200, "L", 799.038144e-3, 1e-6),
489  vel("Water", "T", 873.15, "Dmass", 1e-14, "L", 79.1034659e-3, 1e-6),
490  vel("Water", "T", 647.35, "Dmass", 1, "L", 51.9298924e-3, 1e-6),
491  vel("Water", "T", 647.35, "Dmass", 122, "L", 130.922885e-3, 2e-4),
492  vel("Water", "T", 647.35, "Dmass", 222, "L", 367.787459e-3, 2e-4),
493  vel("Water", "T", 647.35, "Dmass", 272, "L", 757.959776e-3, 2e-4),
494  vel("Water", "T", 647.35, "Dmass", 322, "L", 1443.75556e-3, 2e-4),
495  vel("Water", "T", 647.35, "Dmass", 372, "L", 650.319402e-3, 2e-4),
496  vel("Water", "T", 647.35, "Dmass", 422, "L", 448.883487e-3, 2e-4),
497  vel("Water", "T", 647.35, "Dmass", 750, "L", 600.961346e-3, 2e-4),
498 
499  // From Shan, ASHRAE, 2000
500  vel("R23", "T", 180, "Dmolar", 21097, "L", 143.19e-3, 1e-4),
501  vel("R23", "T", 420, "Dmolar", 7564, "L", 50.19e-3, 2e-4),
502  vel("R23", "T", 370, "Dmolar", 32.62, "L", 17.455e-3, 1e-4),
503 
504  // From REFPROP 9.1 since no sample data provided in Tufeu
505  vel("Ammonia", "T", 310, "Dmolar", 34320, "L", 0.45223303481784971, 1e-4),
506  vel("Ammonia", "T", 395, "Q", 0, "L", 0.2264480769301, 1e-4),
507 
508  // From Hands, Cryogenics, 1981
509  vel("Helium", "T", 800, "P", 1e5, "L", 0.3085, 1e-2),
510  vel("Helium", "T", 300, "P", 1e5, "L", 0.1560, 1e-2),
511  vel("Helium", "T", 20, "P", 1e5, "L", 0.0262, 1e-2),
512  vel("Helium", "T", 8, "P", 1e5, "L", 0.0145, 1e-2),
513  vel("Helium", "T", 4, "P", 20e5, "L", 0.0255, 1e-2),
514  vel("Helium", "T", 8, "P", 20e5, "L", 0.0308, 1e-2),
515  vel("Helium", "T", 20, "P", 20e5, "L", 0.0328, 1e-2),
516  vel("Helium", "T", 4, "P", 100e5, "L", 0.0385, 3e-2),
517  vel("Helium", "T", 8, "P", 100e5, "L", 0.0566, 3e-2),
518  vel("Helium", "T", 20, "P", 100e5, "L", 0.0594, 1e-2),
519  vel("Helium", "T", 4, "P", 1e5, "L", 0.0186, 1e-2),
520  vel("Helium", "T", 4, "P", 2e5, "L", 0.0194, 1e-2),
521  vel("Helium", "T", 5.180, "P", 2.3e5, "L", 0.0195, 1e-1),
522  vel("Helium", "T", 5.2, "P", 2.3e5, "L", 0.0202, 1e-1),
523  vel("Helium", "T", 5.230, "P", 2.3e5, "L", 0.0181, 1e-1),
524  vel("Helium", "T", 5.260, "P", 2.3e5, "L", 0.0159, 1e-1),
525  vel("Helium", "T", 5.3, "P", 2.3e5, "L", 0.0149, 1e-1),
526 
527  // Geller, IJT, 2001 - based on experimental data, no validation data provided
528  //vel("R404A", "T", 253.03, "P", 0.101e6, "L", 0.00991, 0.03),
529  //vel("R404A", "T", 334.38, "P", 2.176e6, "L", 19.93e-3, 0.03),
530  //vel("R407C", "T", 253.45, "P", 0.101e6, "L", 0.00970, 0.03),
531  //vel("R407C", "T", 314.39, "P", 0.458e6, "L", 14.87e-3, 0.03),
532  //vel("R410A", "T", 260.32, "P", 0.101e6, "L", 0.01043, 0.03),
533  //vel("R410A", "T", 332.09, "P", 3.690e6, "L", 22.76e-3, 0.03),
534  //vel("R507A", "T", 254.85, "P", 0.101e6, "L", 0.01007, 0.03),
535  //vel("R507A", "T", 333.18, "P", 2.644e6, "L", 21.31e-3, 0.03),
536 
537  // From REFPROP 9.1 since no data provided
538  vel("R134a", "T", 240, "D", 1e-10, "L", 0.008698768, 1e-4),
539  vel("R134a", "T", 330, "D", 1e-10, "L", 0.015907606, 1e-4),
540  vel("R134a", "T", 330, "Q", 0, "L", 0.06746432253, 1e-4),
541  vel("R134a", "T", 240, "Q", 1, "L", 0.00873242359, 1e-4),
542 
543  // Mylona, JPCRD, 2014
544  vel("o-Xylene", "T", 635, "D", 270, "L", 96.4e-3, 1e-2),
545  vel("m-Xylene", "T", 616, "D", 220, "L", 79.5232e-3, 1e-2), // CoolProp is correct, paper is incorrect (it seems)
546  vel("p-Xylene", "T", 620, "D", 287, "L", 107.7e-3, 1e-2),
547  vel("EthylBenzene", "T", 617, "D", 316, "L", 140.2e-3, 1e-2),
548  // dilute values
549  vel("o-Xylene", "T", 300, "D", 1e-12, "L", 13.68e-3, 1e-3),
550  vel("o-Xylene", "T", 600, "D", 1e-12, "L", 41.6e-3, 1e-3),
551  vel("m-Xylene", "T", 300, "D", 1e-12, "L", 9.45e-3, 1e-3),
552  vel("m-Xylene", "T", 600, "D", 1e-12, "L", 40.6e-3, 1e-3),
553  vel("p-Xylene", "T", 300, "D", 1e-12, "L", 10.57e-3, 1e-3),
554  vel("p-Xylene", "T", 600, "D", 1e-12, "L", 41.73e-3, 1e-3),
555  vel("EthylBenzene", "T", 300, "D", 1e-12, "L", 9.71e-3, 1e-3),
556  vel("EthylBenzene", "T", 600, "D", 1e-12, "L", 41.14e-3, 1e-3),
557 
558  // Friend, JPCRD, 1989
559  vel("Methane", "T", 100, "D", 1e-12, "L", 9.83e-3, 1e-3),
560  vel("Methane", "T", 400, "D", 1e-12, "L", 49.96e-3, 1e-3),
561  vel("Methane", "T", 182, "Q", 0, "L", 82.5e-3, 5e-3),
562  vel("Methane", "T", 100, "Dmolar", 28.8e3, "L", 234e-3, 1e-2),
563 
564  // Sykioti, JPCRD, 2013
565  vel("Methanol", "T", 300, "Dmass", 850, "L", 241.48e-3, 1e-2),
566  vel("Methanol", "T", 400, "Dmass", 2, "L", 25.803e-3, 1e-2),
567  vel("Methanol", "T", 400, "Dmass", 690, "L", 183.59e-3, 1e-2),
568  vel("Methanol", "T", 500, "Dmass", 10, "L", 40.495e-3, 1e-2),
569 
570  // Heavy Water, IAPWS formulation
571  vel("HeavyWater", "T", 0.5000 * 643.847, "Dmass", 3.07 * 358, "V", 835.786416818 * 0.742128e-3, 1e-5),
572  vel("HeavyWater", "T", 0.9000 * 643.847, "Dmass", 2.16 * 358, "V", 627.777590127 * 0.742128e-3, 1e-5),
573  vel("HeavyWater", "T", 1.2000 * 643.847, "Dmass", 0.8 * 358, "V", 259.605241187 * 0.742128e-3, 1e-5),
574 
575  // Vassiliou, JPCRD, 2015
576  vel("Cyclopentane", "T", 512, "Dmass", 1e-12, "L", 37.042e-3, 1e-5),
577  vel("Cyclopentane", "T", 512, "Dmass", 400, "L", 69.698e-3, 1e-1),
578  vel("Isopentane", "T", 460, "Dmass", 1e-12, "L", 35.883e-3, 1e-4),
579  vel("Isopentane", "T", 460, "Dmass", 329.914, "L", 59.649e-3, 1e-1),
580  vel("n-Pentane", "T", 460, "Dmass", 1e-12, "L", 34.048e-3, 1e-5),
581  vel("n-Pentane", "T", 460, "Dmass", 377.687, "L", 71.300e-3, 1e-1),
582 };
583 
584 TEST_CASE_METHOD(TransportValidationFixture, "Compare thermal conductivities against published data", "[conductivity],[transport]") {
585  int inputsN = sizeof(conductivity_validation_data) / sizeof(conductivity_validation_data[0]);
586  for (int i = 0; i < inputsN; ++i) {
587  vel el = conductivity_validation_data[i];
588  CHECK_NOTHROW(set_backend("HEOS", el.fluid));
589  CAPTURE(el.fluid);
590  CAPTURE(el.in1);
591  CAPTURE(el.v1);
592  CAPTURE(el.in2);
593  CAPTURE(el.v2);
594  CHECK_NOTHROW(set_pair(el.in1, el.v1, el.in2, el.v2));
595  get_value(CoolProp::iconductivity);
596  CAPTURE(el.expected);
597  CAPTURE(actual);
598  CHECK(std::abs(actual / el.expected - 1) < el.tol);
599  }
600 }
601 
602 }; /* namespace TransportValidation */
603 
604 static CoolProp::input_pairs inputs[] = {
606  //CoolProp::SmolarT_INPUTS,
607  //CoolProp::HmolarT_INPUTS,
608  //CoolProp::TUmolar_INPUTS,
609 
610  // CoolProp::DmolarP_INPUTS,
611  // CoolProp::DmolarHmolar_INPUTS,
612  // CoolProp::DmolarSmolar_INPUTS,
613  // CoolProp::DmolarUmolar_INPUTS,
614  //
615  // CoolProp::HmolarP_INPUTS,
616  // CoolProp::PSmolar_INPUTS,
617  // CoolProp::PUmolar_INPUTS,
618  //
619  /*
620  CoolProp::HmolarSmolar_INPUTS,
621  CoolProp::HmolarUmolar_INPUTS,
622  CoolProp::SmolarUmolar_INPUTS
623  */
624 };
625 
626 class ConsistencyFixture
627 {
628  protected:
629  CoolPropDbl hmolar, pmolar, smolar, umolar, rhomolar, T, p, x1, x2;
630  shared_ptr<CoolProp::AbstractState> pState;
632 
633  public:
634  ConsistencyFixture() {}
635  ~ConsistencyFixture() {}
636  void set_backend(std::string backend, std::string fluid_name) {
637  pState.reset(CoolProp::AbstractState::factory(backend, fluid_name));
638  }
639  void set_pair(CoolProp::input_pairs pair) {
640  this->pair = pair;
641  }
642  void set_TP(CoolPropDbl T, CoolPropDbl p) {
643  this->T = T;
644  this->p = p;
645  CoolProp::AbstractState& State = *pState;
646 
647  // Start with T,P as inputs, cycle through all the other pairs that are supported
648  State.update(CoolProp::PT_INPUTS, p, T);
649 
650  // Set the other state variables
651  rhomolar = State.rhomolar();
652  hmolar = State.hmolar();
653  smolar = State.smolar();
654  umolar = State.umolar();
655  }
656  void get_variables() {
657 
658  switch (pair) {
661  x1 = hmolar;
662  x2 = T;
663  break;
665  x1 = smolar;
666  x2 = T;
667  break;
669  x1 = T;
670  x2 = umolar;
671  break;
673  x1 = rhomolar;
674  x2 = T;
675  break;
676 
679  x1 = rhomolar;
680  x2 = hmolar;
681  break;
683  x1 = rhomolar;
684  x2 = smolar;
685  break;
687  x1 = rhomolar;
688  x2 = umolar;
689  break;
691  x1 = rhomolar;
692  x2 = p;
693  break;
694 
697  x1 = hmolar;
698  x2 = p;
699  break;
701  x1 = p;
702  x2 = smolar;
703  break;
705  x1 = p;
706  x2 = umolar;
707  break;
708 
710  x1 = hmolar;
711  x2 = smolar;
712  break;
714  x1 = smolar;
715  x2 = umolar;
716  break;
717 
718  default:
719  throw CoolProp::ValueError();
720  }
721  }
722  void single_phase_consistency_check() {
723  CoolProp::AbstractState& State = *pState;
724  State.update(pair, x1, x2);
725 
726  // Make sure we end up back at the same temperature and pressure we started out with
727  if (State.Q() < 1 && State.Q() > 0) throw CoolProp::ValueError(format("Q [%g] is between 0 and 1; two-phase solution", State.Q()));
728  if (std::abs(T - State.T()) > 1e-2) throw CoolProp::ValueError(format("Error on T [%Lg K] is greater than 1e-2", std::abs(State.T() - T)));
729  if (std::abs(p - State.p()) / p * 100 > 1e-2)
730  throw CoolProp::ValueError(format("Error on p [%Lg %%] is greater than 1e-2 %%", std::abs(p - State.p()) / p * 100));
731  }
732  void subcritical_pressure_liquid() {
733  // Subcritical pressure liquid
734  int inputsN = sizeof(inputs) / sizeof(inputs[0]);
735  for (double p = pState->p_triple() * 1.1; p < pState->p_critical(); p *= 3) {
736  double Ts = PropsSI("T", "P", p, "Q", 0, "Water");
737  double Tmelt = pState->melting_line(CoolProp::iT, CoolProp::iP, p);
738  for (double T = Tmelt; T < Ts - 0.1; T += 0.1) {
739  CHECK_NOTHROW(set_TP(T, p));
740 
741  for (int i = 0; i < inputsN; ++i) {
742  CoolProp::input_pairs pair = inputs[i];
743  std::string pair_desc = CoolProp::get_input_pair_short_desc(pair);
744  set_pair(pair);
745  CAPTURE(pair_desc);
746  CAPTURE(T);
747  CAPTURE(p);
748  get_variables();
749  CAPTURE(x1);
750  CAPTURE(x2);
751  CAPTURE(Ts);
752  CHECK_NOTHROW(single_phase_consistency_check());
753  double rhomolar_RP = PropsSI("Dmolar", "P", p, "T", T, "REFPROP::Water");
754  if (ValidNumber(rhomolar_RP)) {
755  CAPTURE(rhomolar_RP);
756  CAPTURE(rhomolar);
757  CHECK(std::abs((rhomolar_RP - rhomolar) / rhomolar) < 1e-3);
758  }
759  }
760  }
761  }
762  }
763 };
764 
765 TEST_CASE_METHOD(ConsistencyFixture, "Test all input pairs for Water using all valid backends", "[consistency]") {
766  CHECK_NOTHROW(set_backend("HEOS", "Water"));
767  subcritical_pressure_liquid();
768 
769  // int inputsN = sizeof(inputs)/sizeof(inputs[0]);
770  // for (double p = 600000; p < pState->pmax(); p *= 3)
771  // {
772  // for (double T = 220; T < pState->Tmax(); T += 1)
773  // {
774  // CHECK_NOTHROW(set_TP(T, p));
775  //
776  // for (int i = 0; i < inputsN; ++i)
777  // {
778  // CoolProp::input_pairs pair = inputs[i];
779  // std::string pair_desc = CoolProp::get_input_pair_short_desc(pair);
780  // set_pair(pair);
781  // CAPTURE(pair_desc);
782  // CAPTURE(T);
783  // CAPTURE(p);
784  // get_variables();
785  // CAPTURE(x1);
786  // CAPTURE(x2);
787  // CHECK_NOTHROW(single_phase_consistency_check());
788  // }
789  // }
790  // }
791 }
792 
793 TEST_CASE("Test saturation properties for a few fluids", "[saturation],[slow]") {
794  SECTION("sat_p") {
795  std::vector<double> pv = linspace(Props1SI("CO2", "ptriple"), Props1SI("CO2", "pcrit") - 1e-6, 5);
796 
797  SECTION("All pressures are ok")
798  for (std::size_t i = 0; i < pv.size(); ++i) {
799  CAPTURE(pv[i]);
800  double T = CoolProp::PropsSI("T", "P", pv[i], "Q", 0, "CO2");
801  }
802  }
803 }
804 
805 class HumidAirDewpointFixture
806 {
807  public:
808  shared_ptr<CoolProp::AbstractState> AS;
809  std::vector<std::string> fluids;
810  std::vector<double> z;
811  void setup(double zH2O) {
812  double z_Air[4] = {0.7810, 0.2095, 0.0092, 0.0003}; // N2, O2, Ar, CO2
813  z.resize(5);
814  z[0] = zH2O;
815  for (int i = 0; i < 4; ++i) {
816  z[i + 1] = (1 - zH2O) * z_Air[i];
817  }
818  }
819  void run_p(double p) {
820  CAPTURE(p);
821  for (double zH2O = 0.999; zH2O > 0; zH2O -= 0.001) {
822  setup(zH2O);
823  AS->set_mole_fractions(z);
824  CAPTURE(zH2O);
825  CHECK_NOTHROW(AS->update(PQ_INPUTS, p, 1));
826  if (AS->T() < 273.15) {
827  break;
828  }
829  }
830  }
831  void run_checks() {
832  fluids = strsplit("Water&Nitrogen&Oxygen&Argon&CO2", '&');
833  AS.reset(AbstractState::factory("HEOS", fluids));
834  run_p(1e5);
835  run_p(1e6);
836  run_p(1e7);
837  }
838 };
839 TEST_CASE_METHOD(HumidAirDewpointFixture, "Humid air dewpoint calculations", "[humid_air_dewpoint]") {
840  run_checks();
841 }
842 
843 TEST_CASE("Test consistency between Gernert models in CoolProp and Gernert models in REFPROP", "[Gernert]") {
844  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
845  std::string mixes[] = {"CO2[0.7]&Argon[0.3]", "CO2[0.7]&Water[0.3]", "CO2[0.7]&Nitrogen[0.3]"};
846  for (int i = 0; i < 3; ++i) {
847  const char* ykey = mixes[i].c_str();
848  std::ostringstream ss1;
849  ss1 << mixes[i];
850  SECTION(ss1.str(), "") {
851  double Tnbp_CP, Tnbp_RP;
852  CHECK_NOTHROW(Tnbp_CP = PropsSI("T", "P", 101325, "Q", 1, "HEOS::" + mixes[i]));
853  CAPTURE(Tnbp_CP);
854  CHECK_NOTHROW(Tnbp_RP = PropsSI("T", "P", 101325, "Q", 1, "REFPROP::" + mixes[i]));
855  CAPTURE(Tnbp_RP);
856  double diff = std::abs(Tnbp_CP / Tnbp_RP - 1);
857  CHECK(diff < 1e-6);
858  }
859  }
860 }
861 
862 TEST_CASE("Tests for solvers in P,T flash using Water", "[flash],[PT]") {
863  SECTION("Check that T,P for saturated state yields error") {
864  double Ts, ps, rho;
865  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
866  CHECK(ValidNumber(Ts));
867  CHECK_NOTHROW(ps = PropsSI("P", "T", Ts, "Q", 0, "Water"));
868  CHECK(ValidNumber(ps));
869  CAPTURE(Ts);
870  CAPTURE(ps);
871  CHECK_NOTHROW(rho = PropsSI("D", "T", Ts, "P", ps, "Water"));
872  CAPTURE(rho);
873  CHECK(!ValidNumber(rho));
874  }
875  SECTION("Subcritical p slightly subcooled should be ok") {
876  double Ts, rho, dT = 1e-4;
877  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
878  CAPTURE(Ts);
879  CHECK(ValidNumber(Ts));
880  CAPTURE(dT);
881  CHECK_NOTHROW(rho = PropsSI("D", "T", Ts - dT, "P", 101325, "Water"));
882  CAPTURE(rho);
883  CHECK(ValidNumber(rho));
884  }
885  SECTION("Subcritical p slightly superheated should be ok") {
886  double Ts, rho, dT = 1e-4;
887  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
888  CAPTURE(Ts);
889  CHECK(ValidNumber(Ts));
890  CAPTURE(dT);
891  CHECK_NOTHROW(rho = PropsSI("D", "T", Ts + dT, "P", 101325, "Water"));
892  CAPTURE(rho);
893  CHECK(ValidNumber(rho));
894  }
895 }
896 
897 TEST_CASE("Tests for solvers in P,Y flash using Water", "[flash],[PH],[PS],[PU]") {
898  double Ts, y, T2;
899  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
900  std::string Ykeys[] = {"H", "S", "U", "Hmass", "Smass", "Umass", "Hmolar", "Smolar", "Umolar"};
901  for (int i = 0; i < 9; ++i) {
902  const char* ykey = Ykeys[i].c_str();
903  std::ostringstream ss1;
904  ss1 << "Subcritical superheated P," << ykey;
905  SECTION(ss1.str(), "") {
906  double dT = 10;
907  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
908  CHECK(ValidNumber(Ts));
909  CAPTURE(Ts);
910  CHECK_NOTHROW(y = PropsSI(ykey, "T", Ts + dT, "P", 101325, "Water"));
911  CAPTURE(dT);
912  CAPTURE(y);
913  CHECK(ValidNumber(y));
914  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", 101325, "Water"));
915  CAPTURE(CoolProp::get_global_param_string("errstring"));
916  CAPTURE(T2);
917  CHECK(ValidNumber(T2));
918  }
919  std::ostringstream ss2;
920  ss2 << "Subcritical barely superheated P," << ykey;
921  SECTION(ss2.str(), "") {
922  double dT = 1e-3;
923  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
924  CHECK(ValidNumber(Ts));
925  CAPTURE(Ts);
926  CHECK_NOTHROW(y = PropsSI(ykey, "T", Ts + dT, "P", 101325, "Water"));
927  CAPTURE(dT);
928  CAPTURE(y);
929  CHECK(ValidNumber(y));
930  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", 101325, "Water"));
931  CAPTURE(CoolProp::get_global_param_string("errstring"));
932  CAPTURE(T2);
933  CHECK(ValidNumber(T2));
934  }
935  std::ostringstream ss3;
936  ss3 << "Subcritical subcooled P," << ykey;
937  SECTION(ss3.str(), "") {
938  double dT = -10;
939  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
940  CHECK(ValidNumber(Ts));
941  CAPTURE(Ts);
942  CHECK_NOTHROW(y = PropsSI(ykey, "T", Ts + dT, "P", 101325, "Water"));
943  CAPTURE(dT);
944  CAPTURE(y);
945  CHECK(ValidNumber(y));
946  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", 101325, "Water"));
947  CAPTURE(CoolProp::get_global_param_string("errstring"));
948  CAPTURE(T2);
949  CHECK(ValidNumber(T2));
950  }
951  std::ostringstream ss4;
952  ss4 << "Subcritical barely subcooled P," << ykey;
953  SECTION(ss4.str(), "") {
954  double dT = -1e-3;
955  CHECK_NOTHROW(Ts = PropsSI("T", "P", 101325, "Q", 0, "Water"));
956  CHECK(ValidNumber(Ts));
957  CAPTURE(Ts);
958  CHECK_NOTHROW(y = PropsSI(ykey, "T", Ts + dT, "P", 101325, "Water"));
959  CAPTURE(dT);
960  CAPTURE(y);
961  CHECK(ValidNumber(y));
962  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", 101325, "Water"));
963  CAPTURE(CoolProp::get_global_param_string("errstring"));
964  CAPTURE(T2);
965  CHECK(ValidNumber(T2));
966  }
967  std::ostringstream ss5;
968  ss5 << "Supercritical P," << ykey;
969  SECTION(ss5.str(), "") {
970  double Tc = Props1SI("Water", "Tcrit");
971  double pc = Props1SI("Water", "pcrit");
972  double p = pc * 1.3;
973  double T = Tc * 1.3;
974  CAPTURE(T);
975  CAPTURE(p);
976  CHECK(ValidNumber(T));
977  CHECK(ValidNumber(p));
978  CHECK_NOTHROW(y = PropsSI(ykey, "P", p, "T", T, "Water"));
979  CAPTURE(y);
980  CHECK(ValidNumber(y));
981  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", p, "Water"));
982  CAPTURE(CoolProp::get_global_param_string("errstring"));
983  CAPTURE(T2);
984  CHECK(ValidNumber(T2));
985  }
986  std::ostringstream ss6;
987  ss6 << "Supercritical \"gas\" P," << ykey;
988  SECTION(ss6.str(), "") {
989  double Tc = Props1SI("Water", "Tcrit");
990  double pc = Props1SI("Water", "pcrit");
991  double p = pc * 0.7;
992  double T = Tc * 1.3;
993  CAPTURE(T);
994  CAPTURE(p);
995  CHECK(ValidNumber(T));
996  CHECK(ValidNumber(p));
997  CHECK_NOTHROW(y = PropsSI(ykey, "P", p, "T", T, "Water"));
998  CAPTURE(y);
999  CHECK(ValidNumber(y));
1000  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", p, "Water"));
1001  CAPTURE(CoolProp::get_global_param_string("errstring"));
1002  CAPTURE(T2);
1003  CHECK(ValidNumber(T2));
1004  }
1005  std::ostringstream ss7;
1006  ss7 << "Supercritical \"liquid\" P," << ykey;
1007  SECTION(ss7.str(), "") {
1008  double Tc = Props1SI("Water", "Tcrit");
1009  double pc = Props1SI("Water", "pcrit");
1010  double p = pc * 2;
1011  double T = Tc * 0.5;
1012  CAPTURE(T);
1013  CAPTURE(p);
1014  CHECK(ValidNumber(T));
1015  CHECK(ValidNumber(p));
1016  CHECK_NOTHROW(y = PropsSI(ykey, "P", p, "T", T, "Water"));
1017  CAPTURE(y);
1018  CHECK(ValidNumber(y));
1019  CHECK_NOTHROW(T2 = PropsSI("T", ykey, y, "P", p, "Water"));
1020  CAPTURE(CoolProp::get_global_param_string("errstring"));
1021  CAPTURE(T2);
1022  CHECK(ValidNumber(T2));
1023  }
1024  }
1025 }
1026 
1027 TEST_CASE("Tests for solvers in P,H flash using Propane", "[flashdups],[flash],[PH],[consistency]") {
1028  double hmolar, hmass;
1029  SECTION("5 times PH with HEOS AbstractState yields same results every time", "") {
1030  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "n-Propane"));
1031 
1032  CHECK_NOTHROW(AS->update(CoolProp::PT_INPUTS, 101325, 300));
1033  hmolar = AS->hmolar();
1034  hmass = AS->hmass();
1035  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1036  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1037  hmolar = AS->hmolar();
1038  hmass = AS->hmass();
1039  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1040  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1041  hmolar = AS->hmolar();
1042  hmass = AS->hmass();
1043  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1044  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1045  hmolar = AS->hmolar();
1046  hmass = AS->hmass();
1047  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1048  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1049  hmolar = AS->hmolar();
1050  hmass = AS->hmass();
1051  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1052  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1053  }
1054 }
1055 
1056 TEST_CASE("Multiple calls to state class are consistent", "[flashdups],[flash],[PH],[consistency]") {
1057  double hmolar, hmass;
1058  SECTION("3 times PH with HEOS AbstractState yields same results every time", "") {
1059  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "n-Propane"));
1060 
1061  CHECK_NOTHROW(AS->update(CoolProp::PT_INPUTS, 101325, 300));
1062  hmolar = AS->hmolar();
1063  hmass = AS->hmass();
1064  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1065  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1066  hmolar = AS->hmolar();
1067  hmass = AS->hmass();
1068  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1069  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1070  hmolar = AS->hmolar();
1071  hmass = AS->hmass();
1072  CHECK_NOTHROW(AS->update(CoolProp::HmassP_INPUTS, hmass, 101325));
1073  CHECK_NOTHROW(AS->update(CoolProp::HmolarP_INPUTS, hmolar, 101325));
1074  }
1075 }
1076 
1077 TEST_CASE("Test first partial derivatives using PropsSI", "[derivatives]") {
1078  double T = 300;
1079  SECTION("Check drhodp|T 3 ways", "") {
1080  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "n-Propane"));
1081  AS->update(CoolProp::PT_INPUTS, 101325, T);
1082 
1083  double drhomolardp__T_AbstractState = AS->first_partial_deriv(CoolProp::iDmolar, CoolProp::iP, CoolProp::iT);
1084  double drhomolardp__T_PropsSI_num =
1085  (PropsSI("Dmolar", "T", T, "P", 101325 + 1e-3, "n-Propane") - PropsSI("Dmolar", "T", T, "P", 101325 - 1e-3, "n-Propane")) / (2 * 1e-3);
1086  double drhomolardp__T_PropsSI = PropsSI("d(Dmolar)/d(P)|T", "T", T, "P", 101325, "n-Propane");
1087 
1088  CAPTURE(drhomolardp__T_AbstractState);
1089  CAPTURE(drhomolardp__T_PropsSI_num);
1090  CAPTURE(drhomolardp__T_PropsSI);
1091  double rel_err_exact = std::abs((drhomolardp__T_AbstractState - drhomolardp__T_PropsSI) / drhomolardp__T_PropsSI);
1092  double rel_err_approx = std::abs((drhomolardp__T_PropsSI_num - drhomolardp__T_PropsSI) / drhomolardp__T_PropsSI);
1093  CHECK(rel_err_exact < 1e-7);
1094  CHECK(rel_err_approx < 1e-7);
1095  }
1096  SECTION("Check drhodp|T 3 ways for water", "") {
1097  T = 80 + 273.15;
1098  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1099  AS->update(CoolProp::PT_INPUTS, 101325, T);
1100 
1101  double drhomolardp__T_AbstractState = AS->first_partial_deriv(CoolProp::iDmolar, CoolProp::iP, CoolProp::iT);
1102  double drhomolardp__T_PropsSI_num =
1103  (PropsSI("Dmolar", "T", T, "P", 101325 + 1, "Water") - PropsSI("Dmolar", "T", T, "P", 101325 - 1, "Water")) / (2 * 1);
1104  double drhomolardp__T_PropsSI = PropsSI("d(Dmolar)/d(P)|T", "T", T, "P", 101325, "Water");
1105 
1106  CAPTURE(drhomolardp__T_AbstractState);
1107  CAPTURE(drhomolardp__T_PropsSI_num);
1108  CAPTURE(drhomolardp__T_PropsSI);
1109  double rel_err_exact = std::abs((drhomolardp__T_AbstractState - drhomolardp__T_PropsSI) / drhomolardp__T_PropsSI);
1110  double rel_err_approx = std::abs((drhomolardp__T_PropsSI_num - drhomolardp__T_PropsSI) / drhomolardp__T_PropsSI);
1111  CHECK(rel_err_exact < 1e-4);
1112  CHECK(rel_err_approx < 1e-4);
1113  }
1114  SECTION("Check dpdrho|T 3 ways for water", "") {
1115  T = 80 + 273.15;
1116  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1117  AS->update(CoolProp::PT_INPUTS, 101325, T);
1118  CoolPropDbl rhomolar = AS->rhomolar();
1119  double dpdrhomolar__T_AbstractState = AS->first_partial_deriv(CoolProp::iP, CoolProp::iDmolar, CoolProp::iT);
1120  double dpdrhomolar__T_PropsSI_num =
1121  (PropsSI("P", "T", T, "Dmolar", rhomolar + 1e-3, "Water") - PropsSI("P", "T", T, "Dmolar", rhomolar - 1e-3, "Water")) / (2 * 1e-3);
1122  double dpdrhomolar__T_PropsSI = PropsSI("d(P)/d(Dmolar)|T", "T", T, "P", 101325, "Water");
1123  CAPTURE(rhomolar);
1124  CAPTURE(dpdrhomolar__T_AbstractState);
1125  CAPTURE(dpdrhomolar__T_PropsSI_num);
1126  CAPTURE(dpdrhomolar__T_PropsSI);
1127  double rel_err_exact = std::abs((dpdrhomolar__T_AbstractState - dpdrhomolar__T_PropsSI) / dpdrhomolar__T_PropsSI);
1128  double rel_err_approx = std::abs((dpdrhomolar__T_PropsSI_num - dpdrhomolar__T_PropsSI) / dpdrhomolar__T_PropsSI);
1129  CHECK(rel_err_exact < 1e-6);
1130  CHECK(rel_err_approx < 1e-6);
1131  }
1132  SECTION("Check dpdrho|T 3 ways for water using mass based", "") {
1133  T = 80 + 273.15;
1134  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1135  AS->update(CoolProp::PT_INPUTS, 101325, T);
1136  CoolPropDbl rhomass = AS->rhomass();
1137  double dpdrhomass__T_AbstractState = AS->first_partial_deriv(CoolProp::iP, CoolProp::iDmass, CoolProp::iT);
1138  double dpdrhomass__T_PropsSI_num =
1139  (PropsSI("P", "T", T, "Dmass", rhomass + 1e-3, "Water") - PropsSI("P", "T", T, "Dmass", rhomass - 1e-3, "Water")) / (2 * 1e-3);
1140  double dpdrhomass__T_PropsSI = PropsSI("d(P)/d(Dmass)|T", "T", T, "P", 101325, "Water");
1141  CAPTURE(rhomass);
1142  CAPTURE(dpdrhomass__T_AbstractState);
1143  CAPTURE(dpdrhomass__T_PropsSI_num);
1144  CAPTURE(dpdrhomass__T_PropsSI);
1145  double rel_err_exact = std::abs((dpdrhomass__T_AbstractState - dpdrhomass__T_PropsSI) / dpdrhomass__T_PropsSI);
1146  double rel_err_approx = std::abs((dpdrhomass__T_PropsSI_num - dpdrhomass__T_PropsSI) / dpdrhomass__T_PropsSI);
1147  CHECK(rel_err_exact < 1e-7);
1148  CHECK(rel_err_approx < 1e-7);
1149  }
1150  SECTION("Invalid first partial derivatives", "") {
1151  CHECK(!ValidNumber(PropsSI("d()/d(P)|T", "T", 300, "P", 101325, "n-Propane")));
1152  CHECK(!ValidNumber(PropsSI("d(Dmolar)/d()|T", "T", 300, "P", 101325, "n-Propane")));
1153  CHECK(!ValidNumber(PropsSI("d(Dmolar)/d(P)|", "T", 300, "P", 101325, "n-Propane")));
1154  CHECK(!ValidNumber(PropsSI("d(XXXX)/d(P)|T", "T", 300, "P", 101325, "n-Propane")));
1155  CHECK(!ValidNumber(PropsSI("d(Dmolar)d(P)|T", "T", 300, "P", 101325, "n-Propane")));
1156  CHECK(!ValidNumber(PropsSI("d(Dmolar)/d(P)T", "T", 300, "P", 101325, "n-Propane")));
1157  CHECK(!ValidNumber(PropsSI("d(Bvirial)/d(P)T", "T", 300, "P", 101325, "n-Propane")));
1158  CHECK(!ValidNumber(PropsSI("d(Tcrit)/d(P)T", "T", 300, "P", 101325, "n-Propane")));
1159  }
1160 }
1161 
1162 TEST_CASE("Test second partial derivatives", "[derivatives]") {
1163  double T = 300;
1164  SECTION("Check d2pdrho2|T 3 ways", "") {
1165  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1166  double rhomolar = 60000;
1167  AS->update(CoolProp::DmolarT_INPUTS, rhomolar, T);
1168  double p = AS->p();
1169 
1170  double d2pdrhomolar2__T_AbstractState =
1172  // Centered second derivative
1173  double del = 1e0;
1174  double d2pdrhomolar2__T_PropsSI_num =
1175  (PropsSI("P", "T", T, "Dmolar", rhomolar + del, "Water") - 2 * PropsSI("P", "T", T, "Dmolar", rhomolar, "Water")
1176  + PropsSI("P", "T", T, "Dmolar", rhomolar - del, "Water"))
1177  / pow(del, 2);
1178  double d2pdrhomolar2__T_PropsSI = PropsSI("d(d(P)/d(Dmolar)|T)/d(Dmolar)|T", "T", T, "Dmolar", rhomolar, "Water");
1179 
1180  CAPTURE(d2pdrhomolar2__T_AbstractState);
1181  CAPTURE(d2pdrhomolar2__T_PropsSI_num);
1182  double rel_err_exact = std::abs((d2pdrhomolar2__T_AbstractState - d2pdrhomolar2__T_PropsSI) / d2pdrhomolar2__T_PropsSI);
1183  double rel_err_approx = std::abs((d2pdrhomolar2__T_PropsSI_num - d2pdrhomolar2__T_AbstractState) / d2pdrhomolar2__T_AbstractState);
1184  CHECK(rel_err_exact < 1e-5);
1185  CHECK(rel_err_approx < 1e-5);
1186  }
1187  SECTION("Valid second partial derivatives", "") {
1188  CHECK(ValidNumber(PropsSI("d(d(Hmolar)/d(P)|T)/d(T)|Dmolar", "T", 300, "P", 101325, "n-Propane")));
1189  }
1190  SECTION("Invalid second partial derivatives", "") {
1191  CHECK(!ValidNumber(PropsSI("d(d()/d(P)|T)/d()|", "T", 300, "P", 101325, "n-Propane")));
1192  CHECK(!ValidNumber(PropsSI("dd(Dmolar)/d()|T)|T", "T", 300, "P", 101325, "n-Propane")));
1193  }
1194  SECTION("Check derivatives with respect to T", "") {
1195  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Propane"));
1196  double rhomolar = 100, dT = 1e-1;
1197  AS->update(CoolProp::DmolarT_INPUTS, rhomolar, T);
1198 
1199  // base state
1200  CoolPropDbl T0 = AS->T(), rhomolar0 = AS->rhomolar(), hmolar0 = AS->hmolar(), smolar0 = AS->smolar(), umolar0 = AS->umolar(), p0 = AS->p();
1201  CoolPropDbl dhdT_rho_ana = AS->first_partial_deriv(CoolProp::iHmolar, CoolProp::iT, CoolProp::iDmolar);
1202  CoolPropDbl d2hdT2_rho_ana = AS->second_partial_deriv(CoolProp::iHmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar);
1203  CoolPropDbl dsdT_rho_ana = AS->first_partial_deriv(CoolProp::iSmolar, CoolProp::iT, CoolProp::iDmolar);
1204  CoolPropDbl d2sdT2_rho_ana = AS->second_partial_deriv(CoolProp::iSmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar);
1205  CoolPropDbl dudT_rho_ana = AS->first_partial_deriv(CoolProp::iUmolar, CoolProp::iT, CoolProp::iDmolar);
1206  CoolPropDbl d2udT2_rho_ana = AS->second_partial_deriv(CoolProp::iUmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar);
1207  CoolPropDbl dpdT_rho_ana = AS->first_partial_deriv(CoolProp::iP, CoolProp::iT, CoolProp::iDmolar);
1208  CoolPropDbl d2pdT2_rho_ana = AS->second_partial_deriv(CoolProp::iP, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar);
1209 
1210  // increment T
1211  AS->update(CoolProp::DmolarT_INPUTS, rhomolar, T + dT);
1212  CoolPropDbl Tpt = AS->T(), rhomolarpt = AS->rhomolar(), hmolarpt = AS->hmolar(), smolarpt = AS->smolar(), umolarpt = AS->umolar(),
1213  ppt = AS->p();
1214  // decrement T
1215  AS->update(CoolProp::DmolarT_INPUTS, rhomolar, T - dT);
1216  CoolPropDbl Tmt = AS->T(), rhomolarmt = AS->rhomolar(), hmolarmt = AS->hmolar(), smolarmt = AS->smolar(), umolarmt = AS->umolar(),
1217  pmt = AS->p();
1218 
1219  CoolPropDbl dhdT_rho_num = (hmolarpt - hmolarmt) / (2 * dT);
1220  CoolPropDbl d2hdT2_rho_num = (hmolarpt - 2 * hmolar0 + hmolarmt) / pow(dT, 2);
1221  CoolPropDbl dsdT_rho_num = (smolarpt - smolarmt) / (2 * dT);
1222  CoolPropDbl d2sdT2_rho_num = (smolarpt - 2 * smolar0 + smolarmt) / pow(dT, 2);
1223  CoolPropDbl dudT_rho_num = (umolarpt - umolarmt) / (2 * dT);
1224  CoolPropDbl d2udT2_rho_num = (umolarpt - 2 * umolar0 + umolarmt) / pow(dT, 2);
1225  CoolPropDbl dpdT_rho_num = (ppt - pmt) / (2 * dT);
1226  CoolPropDbl d2pdT2_rho_num = (ppt - 2 * p0 + pmt) / pow(dT, 2);
1227 
1228  CAPTURE(format("%0.15Lg", d2pdT2_rho_ana).c_str());
1229 
1230  double tol = 1e-4;
1231  CHECK(std::abs((dhdT_rho_num - dhdT_rho_ana) / dhdT_rho_ana) < tol);
1232  CHECK(std::abs((d2hdT2_rho_num - d2hdT2_rho_ana) / d2hdT2_rho_ana) < tol);
1233  CHECK(std::abs((dpdT_rho_num - dpdT_rho_ana) / dpdT_rho_ana) < tol);
1234  CHECK(std::abs((d2pdT2_rho_num - d2pdT2_rho_ana) / d2pdT2_rho_ana) < tol);
1235  CHECK(std::abs((dsdT_rho_num - dsdT_rho_ana) / dsdT_rho_ana) < tol);
1236  CHECK(std::abs((d2sdT2_rho_num - d2sdT2_rho_ana) / d2sdT2_rho_ana) < tol);
1237  CHECK(std::abs((dudT_rho_num - dudT_rho_ana) / dudT_rho_ana) < tol);
1238  CHECK(std::abs((d2udT2_rho_num - d2udT2_rho_ana) / d2udT2_rho_ana) < tol);
1239  }
1240 
1241  SECTION("Check derivatives with respect to rho", "") {
1242  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Propane"));
1243  double rhomolar = 100, drho = 1e-1;
1244  AS->update(CoolProp::DmolarT_INPUTS, rhomolar, T);
1245 
1246  // base state
1247  CoolPropDbl T0 = AS->T(), rhomolar0 = AS->rhomolar(), hmolar0 = AS->hmolar(), smolar0 = AS->smolar(), umolar0 = AS->umolar(), p0 = AS->p();
1248  CoolPropDbl dhdrho_T_ana = AS->first_partial_deriv(CoolProp::iHmolar, CoolProp::iDmolar, CoolProp::iT);
1249  CoolPropDbl d2hdrho2_T_ana = AS->second_partial_deriv(CoolProp::iHmolar, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT);
1250  CoolPropDbl dsdrho_T_ana = AS->first_partial_deriv(CoolProp::iSmolar, CoolProp::iDmolar, CoolProp::iT);
1251  CoolPropDbl d2sdrho2_T_ana = AS->second_partial_deriv(CoolProp::iSmolar, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT);
1252  CoolPropDbl dudrho_T_ana = AS->first_partial_deriv(CoolProp::iUmolar, CoolProp::iDmolar, CoolProp::iT);
1253  CoolPropDbl d2udrho2_T_ana = AS->second_partial_deriv(CoolProp::iUmolar, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT);
1254  CoolPropDbl dpdrho_T_ana = AS->first_partial_deriv(CoolProp::iP, CoolProp::iDmolar, CoolProp::iT);
1255  CoolPropDbl d2pdrho2_T_ana = AS->second_partial_deriv(CoolProp::iP, CoolProp::iDmolar, CoolProp::iT, CoolProp::iDmolar, CoolProp::iT);
1256 
1257  // increment rho
1258  AS->update(CoolProp::DmolarT_INPUTS, rhomolar + drho, T);
1259  CoolPropDbl Tpr = AS->T(), rhomolarpr = AS->rhomolar(), hmolarpr = AS->hmolar(), smolarpr = AS->smolar(), umolarpr = AS->umolar(),
1260  ppr = AS->p();
1261  // decrement rho
1262  AS->update(CoolProp::DmolarT_INPUTS, rhomolar - drho, T);
1263  CoolPropDbl Tmr = AS->T(), rhomolarmr = AS->rhomolar(), hmolarmr = AS->hmolar(), smolarmr = AS->smolar(), umolarmr = AS->umolar(),
1264  pmr = AS->p();
1265 
1266  CoolPropDbl dhdrho_T_num = (hmolarpr - hmolarmr) / (2 * drho);
1267  CoolPropDbl d2hdrho2_T_num = (hmolarpr - 2 * hmolar0 + hmolarmr) / pow(drho, 2);
1268  CoolPropDbl dsdrho_T_num = (smolarpr - smolarmr) / (2 * drho);
1269  CoolPropDbl d2sdrho2_T_num = (smolarpr - 2 * smolar0 + smolarmr) / pow(drho, 2);
1270  CoolPropDbl dudrho_T_num = (umolarpr - umolarmr) / (2 * drho);
1271  CoolPropDbl d2udrho2_T_num = (umolarpr - 2 * umolar0 + umolarmr) / pow(drho, 2);
1272  CoolPropDbl dpdrho_T_num = (ppr - pmr) / (2 * drho);
1273  CoolPropDbl d2pdrho2_T_num = (ppr - 2 * p0 + pmr) / pow(drho, 2);
1274 
1275  CAPTURE(format("%0.15Lg", d2pdrho2_T_ana).c_str());
1276 
1277  double tol = 1e-4;
1278  CHECK(std::abs((dhdrho_T_num - dhdrho_T_ana) / dhdrho_T_ana) < tol);
1279  CHECK(std::abs((d2hdrho2_T_num - d2hdrho2_T_ana) / d2hdrho2_T_ana) < tol);
1280  CHECK(std::abs((dpdrho_T_num - dpdrho_T_ana) / dpdrho_T_ana) < tol);
1281  CHECK(std::abs((d2pdrho2_T_num - d2pdrho2_T_ana) / d2pdrho2_T_ana) < tol);
1282  CHECK(std::abs((dsdrho_T_num - dsdrho_T_ana) / dsdrho_T_ana) < tol);
1283  CHECK(std::abs((d2sdrho2_T_num - d2sdrho2_T_ana) / d2sdrho2_T_ana) < tol);
1284  CHECK(std::abs((dudrho_T_num - dudrho_T_ana) / dudrho_T_ana) < tol);
1285  CHECK(std::abs((d2udrho2_T_num - d2udrho2_T_ana) / d2udrho2_T_ana) < tol);
1286  }
1287  SECTION("Check second mixed partial(h,p) with respect to rho", "") {
1288  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Propane"));
1289  double dhmass = 1.0, T = 300;
1290  AS->update(CoolProp::QT_INPUTS, 0.0, T);
1291  double deriv1 = AS->first_partial_deriv(iDmass, iP, iHmass);
1292  double deriv_analyt = AS->second_partial_deriv(iDmass, iP, iHmass, iHmass, iP);
1293  double deriv_analyt2 = AS->second_partial_deriv(iDmass, iHmass, iP, iP, iHmass);
1294  AS->update(CoolProp::HmassP_INPUTS, AS->hmass() - 1, AS->p());
1295  double deriv2 = AS->first_partial_deriv(iDmass, iP, iHmass);
1296  double deriv_num = (deriv1 - deriv2) / dhmass;
1297  CAPTURE(deriv_num);
1298  CAPTURE(deriv_analyt);
1299 
1300  double tol = 1e-4;
1301  CHECK(std::abs((deriv_num - deriv_analyt) / deriv_analyt) < tol);
1302  }
1303 }
1304 
1305 TEST_CASE("REFPROP names for coolprop fluids", "[REFPROPName]") {
1306  std::vector<std::string> fluids = strsplit(CoolProp::get_global_param_string("fluids_list"), ',');
1307  for (std::size_t i = 0; i < fluids.size(); ++i) {
1308  std::ostringstream ss1;
1309  ss1 << "Check that REFPROP fluid name for fluid " << fluids[i] << " is valid";
1310  SECTION(ss1.str(), "") {
1311  std::string RPName = get_fluid_param_string(fluids[i], "REFPROPName");
1312  CHECK(!RPName.empty());
1313  CAPTURE(RPName);
1314  if (!RPName.compare("N/A")) {
1315  break;
1316  }
1317  CHECK(ValidNumber(Props1SI("REFPROP::" + RPName, "molemass")));
1318  CHECK(ValidNumber(Props1SI(RPName, "molemass")));
1319  }
1320  }
1321 }
1322 TEST_CASE("Backwards compatibility for REFPROP v4 fluid name convention", "[REFPROP_backwards_compatibility]") {
1323  SECTION("REFPROP-", "") {
1324  double val = Props1SI("REFPROP-Water", "Tcrit");
1325  std::string err = get_global_param_string("errstring");
1326  CAPTURE(val);
1327  CAPTURE(err);
1328  CHECK(ValidNumber(val));
1329  }
1330  SECTION("REFPROP-MIX:", "") {
1331  double val = PropsSI("T", "P", 101325, "Q", 0, "REFPROP-MIX:Methane[0.5]&Ethane[0.5]");
1332  std::string err = get_global_param_string("errstring");
1333  CAPTURE(val);
1334  CAPTURE(err);
1335  CHECK(ValidNumber(val));
1336  }
1337 }
1338 
1339 class AncillaryFixture
1340 {
1341  public:
1342  std::string name;
1343  void run_checks() {
1344  std::vector<std::string> fluids = strsplit(CoolProp::get_global_param_string("fluids_list"), ',');
1345  for (std::size_t i = 0; i < fluids.size(); ++i) {
1346  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", fluids[i]));
1347  do_sat(AS);
1348  }
1349  }
1350  void do_sat(shared_ptr<CoolProp::AbstractState>& AS) {
1351  for (double f = 0.1; f < 1; f += 0.4) {
1352  double Tc = AS->T_critical();
1353  double Tt = AS->Ttriple();
1354  double T = f * Tc + (1 - f) * Tt;
1355  name = strjoin(AS->fluid_names(), "&");
1356 
1357  AS->update(CoolProp::QT_INPUTS, 0, T);
1358  check_rhoL(AS);
1359  check_pL(AS);
1360 
1361  AS->update(CoolProp::QT_INPUTS, 1, T);
1362  check_rhoV(AS);
1363  check_pV(AS);
1364  }
1365  }
1366  void check_pL(const shared_ptr<CoolProp::AbstractState>& AS) {
1367  double p_EOS = AS->saturated_liquid_keyed_output(iP);
1368  double p_anc = AS->saturation_ancillary(CoolProp::iP, 0, CoolProp::iT, AS->T());
1369  double err = std::abs(p_EOS - p_anc) / p_anc;
1370  CAPTURE(name);
1371  CAPTURE("pL");
1372  CAPTURE(p_EOS);
1373  CAPTURE(p_anc);
1374  CAPTURE(AS->T());
1375  CHECK(err < 0.02);
1376  }
1377  void check_pV(const shared_ptr<CoolProp::AbstractState>& AS) {
1378  double p_EOS = AS->saturated_liquid_keyed_output(iP);
1379  double p_anc = AS->saturation_ancillary(CoolProp::iP, 1, CoolProp::iT, AS->T());
1380  double err = std::abs(p_EOS - p_anc) / p_anc;
1381  CAPTURE(name);
1382  CAPTURE("pV");
1383  CAPTURE(p_EOS);
1384  CAPTURE(p_anc);
1385  CAPTURE(AS->T());
1386  CHECK(err < 0.02);
1387  }
1388  void check_rhoL(const shared_ptr<CoolProp::AbstractState>& AS) {
1389  double rho_EOS = AS->saturated_liquid_keyed_output(iDmolar);
1390  double rho_anc = AS->saturation_ancillary(CoolProp::iDmolar, 0, CoolProp::iT, AS->T());
1391  double err = std::abs(rho_EOS - rho_anc) / rho_anc;
1392  CAPTURE("rhoL");
1393  CAPTURE(name);
1394  CAPTURE(rho_EOS);
1395  CAPTURE(rho_anc);
1396  CAPTURE(AS->T());
1397  CHECK(err < 0.03);
1398  }
1399  void check_rhoV(const shared_ptr<CoolProp::AbstractState>& AS) {
1400  double rho_EOS = AS->saturated_vapor_keyed_output(iDmolar);
1401  double rho_anc = AS->saturation_ancillary(CoolProp::iDmolar, 1, CoolProp::iT, AS->T());
1402  double err = std::abs(rho_EOS - rho_anc) / rho_anc;
1403  CAPTURE("rhoV");
1404  CAPTURE(name);
1405  CAPTURE(rho_EOS);
1406  CAPTURE(rho_anc);
1407  CAPTURE(AS->T());
1408  CHECK(err < 0.03);
1409  }
1410 };
1411 TEST_CASE_METHOD(AncillaryFixture, "Ancillary functions", "[ancillary]") {
1412  run_checks();
1413 };
1414 
1415 TEST_CASE("Triple point checks", "[triple_point]") {
1416  std::vector<std::string> fluids = strsplit(CoolProp::get_global_param_string("fluids_list"), ',');
1417  for (std::size_t i = 0; i < fluids.size(); ++i) {
1418  std::vector<std::string> names(1, fluids[i]);
1419  shared_ptr<CoolProp::HelmholtzEOSMixtureBackend> HEOS(new CoolProp::HelmholtzEOSMixtureBackend(names));
1420  // Skip pseudo-pure
1421  if (!HEOS->is_pure()) {
1422  continue;
1423  }
1424 
1425  std::ostringstream ss1;
1426  ss1 << "Minimum saturation temperature state matches for liquid " << fluids[i];
1427  SECTION(ss1.str(), "") {
1428  REQUIRE_NOTHROW(HEOS->update(CoolProp::QT_INPUTS, 0, HEOS->Ttriple()));
1429  double p_EOS = HEOS->p();
1430  double p_sat_min_liquid = HEOS->get_components()[0].EOS().sat_min_liquid.p;
1431  double err_sat_min_liquid = std::abs(p_EOS - p_sat_min_liquid) / p_sat_min_liquid;
1432  CAPTURE(p_EOS);
1433  CAPTURE(p_sat_min_liquid);
1434  CAPTURE(err_sat_min_liquid);
1435  if (p_EOS < 1e-3) {
1436  continue;
1437  } // Skip very low pressure below 1 mPa
1438  CHECK(err_sat_min_liquid < 1e-3);
1439  }
1440  std::ostringstream ss2;
1441  ss2 << "Minimum saturation temperature state matches for vapor " << fluids[i];
1442  SECTION(ss2.str(), "") {
1443  REQUIRE_NOTHROW(HEOS->update(CoolProp::QT_INPUTS, 1, HEOS->Ttriple()));
1444 
1445  double p_EOS = HEOS->p();
1446  double p_sat_min_vapor = HEOS->get_components()[0].EOS().sat_min_vapor.p;
1447  double err_sat_min_vapor = std::abs(p_EOS - p_sat_min_vapor) / p_sat_min_vapor;
1448  CAPTURE(p_EOS);
1449  CAPTURE(p_sat_min_vapor);
1450  CAPTURE(err_sat_min_vapor);
1451  if (p_EOS < 1e-3) {
1452  continue;
1453  } // Skip very low pressure below 1 mPa
1454  CHECK(err_sat_min_vapor < 1e-3);
1455  }
1456  std::ostringstream ss3;
1457  ss3 << "Minimum saturation temperature state matches for vapor " << fluids[i];
1458  SECTION(ss3.str(), "") {
1459  REQUIRE_NOTHROW(HEOS->update(CoolProp::PQ_INPUTS, HEOS->p_triple(), 1));
1460 
1461  double T_EOS = HEOS->T();
1462  double T_sat_min_vapor = HEOS->get_components()[0].EOS().sat_min_vapor.T;
1463  double err_sat_min_vapor = std::abs(T_EOS - T_sat_min_vapor);
1464  CAPTURE(T_EOS);
1465  CAPTURE(T_sat_min_vapor);
1466  CAPTURE(err_sat_min_vapor);
1467  CHECK(err_sat_min_vapor < 1e-3);
1468  }
1469  std::ostringstream ss4;
1470  ss4 << "Minimum saturation temperature state matches for liquid " << fluids[i];
1471  SECTION(ss4.str(), "") {
1472  REQUIRE_NOTHROW(HEOS->update(CoolProp::PQ_INPUTS, HEOS->p_triple(), 0));
1473  double T_EOS = HEOS->T();
1474  double T_sat_min_vapor = HEOS->get_components()[0].EOS().sat_min_vapor.T;
1475  double err_sat_min_vapor = std::abs(T_EOS - T_sat_min_vapor);
1476  CAPTURE(T_EOS);
1477  CAPTURE(T_sat_min_vapor);
1478  CAPTURE(err_sat_min_vapor);
1479  CHECK(err_sat_min_vapor < 1e-3);
1480  }
1481  // std::ostringstream ss2;
1482  // ss2 << "Liquid density error < 3% for fluid " << fluids[i] << " at " << T << " K";
1483  // SECTION(ss2.str(), "")
1484  // {
1485  // double rho_EOS = AS->rhomolar();
1486  // double rho_anc = AS->saturation_ancillary(CoolProp::iDmolar, 0, CoolProp::iT, T);
1487  // double err = std::abs(rho_EOS-rho_anc)/rho_anc;
1488  // CAPTURE(rho_EOS);
1489  // CAPTURE(rho_anc);
1490  // CAPTURE(T);
1491  // CHECK(err < 0.03);
1492  // }
1493  // std::ostringstream ss3;
1494  // ss3 << "Vapor density error < 3% for fluid " << fluids[i] << " at " << T << " K";
1495  // SECTION(ss3.str(), "")
1496  // {
1497  // double rho_EOS = AS->rhomolar();
1498  // double rho_anc = AS->saturation_ancillary(CoolProp::iDmolar, 1, CoolProp::iT, T);
1499  // double err = std::abs(rho_EOS-rho_anc)/rho_anc;
1500  // CAPTURE(rho_EOS);
1501  // CAPTURE(rho_anc);
1502  // CAPTURE(T);
1503  // CHECK(err < 0.03);
1504  // }
1505  }
1506 }
1507 
1508 class SatTFixture
1509 {
1510  public:
1511  std::string name;
1512  double Tc;
1513  void run_checks() {
1514  std::vector<std::string> fluids = strsplit(CoolProp::get_global_param_string("fluids_list"), ',');
1515  for (std::size_t i = 0; i < fluids.size(); ++i) {
1516  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", fluids[i]));
1517  do_sat(AS);
1518  }
1519  }
1520  void do_sat(shared_ptr<CoolProp::AbstractState>& AS) {
1521  Tc = AS->T_critical();
1522  name = strjoin(AS->fluid_names(), "&");
1523  check_at_Tc(AS);
1524  double Tt = AS->Ttriple();
1525  if (AS->fluid_param_string("pure") == "true") {
1526  Tc = std::min(Tc, AS->T_reducing());
1527  }
1528  for (double j = 0.1; j > 1e-10; j /= 10) {
1529  check_QT(AS, Tc - j);
1530  }
1531  }
1532  void check_at_Tc(const shared_ptr<CoolProp::AbstractState>& AS) {
1533  CAPTURE("Check @ Tc");
1534  CAPTURE(name);
1535  CHECK_NOTHROW(AS->update(QT_INPUTS, 0, Tc));
1536  }
1537  void check_QT(const shared_ptr<CoolProp::AbstractState>& AS, double T) {
1538  std::string test_name = "Check --> Tc";
1539  CAPTURE(test_name);
1540  CAPTURE(name);
1541  CAPTURE(T);
1542  CHECK_NOTHROW(AS->update(QT_INPUTS, 0, T));
1543  }
1544 };
1545 TEST_CASE_METHOD(SatTFixture, "Test that saturation solvers solve all the way to T = Tc", "[sat_T_to_Tc]") {
1546  run_checks();
1547 };
1548 
1549 TEST_CASE("Check mixtures with fluid name aliases", "[mixture_name_aliasing]") {
1550  shared_ptr<CoolProp::AbstractState> AS1, AS2;
1551  AS1.reset(CoolProp::AbstractState::factory("HEOS", "EBENZENE&P-XYLENE"));
1552  AS2.reset(CoolProp::AbstractState::factory("HEOS", "EthylBenzene&P-XYLENE"));
1553  REQUIRE(AS1->fluid_names().size() == AS2->fluid_names().size());
1554  std::size_t N = AS1->fluid_names().size();
1555  for (std::size_t i = 0; i < N; ++i) {
1556  CAPTURE(i);
1557  CHECK(AS1->fluid_names()[i] == AS2->fluid_names()[i]);
1558  }
1559 }
1560 
1561 TEST_CASE("Predefined mixtures", "[predefined_mixtures]") {
1562  SECTION("PropsSI") {
1563  double val = PropsSI("Dmolar", "P", 101325, "T", 300, "Air.mix");
1564  std::string err = get_global_param_string("errstring");
1565  CAPTURE(val);
1566  CAPTURE(err);
1567  CHECK(ValidNumber(val));
1568  }
1569 }
1570 TEST_CASE("Test that reference states yield proper values using high-level interface", "[reference_states]") {
1571  struct ref_entry
1572  {
1573  std::string name;
1574  double hmass, smass;
1575  std::string in1;
1576  double val1;
1577  std::string in2;
1578  double val2;
1579  };
1580  std::string fluids[] = {"n-Propane", "R134a", "R124"};
1581  ref_entry entries[3] = {{"IIR", 200000, 1000, "T", 273.15, "Q", 0}, {"ASHRAE", 0, 0, "T", 233.15, "Q", 0}, {"NBP", 0, 0, "P", 101325, "Q", 0}};
1582  for (std::size_t i = 0; i < 3; ++i) {
1583  for (std::size_t j = 0; j < 3; ++j) {
1584  std::ostringstream ss1;
1585  ss1 << "Check state for " << fluids[i] << " for " + entries[j].name + " reference state ";
1586  SECTION(ss1.str(), "") {
1587  // First reset the reference state
1588  set_reference_stateS(fluids[i], "DEF");
1589  // Then set to desired reference state
1590  set_reference_stateS(fluids[i], entries[j].name);
1591  // Calculate the values
1592  double hmass = PropsSI("Hmass", entries[j].in1, entries[j].val1, entries[j].in2, entries[j].val2, fluids[i]);
1593  double smass = PropsSI("Smass", entries[j].in1, entries[j].val1, entries[j].in2, entries[j].val2, fluids[i]);
1594  CHECK(std::abs(hmass - entries[j].hmass) < 1e-8);
1595  CHECK(std::abs(smass - entries[j].smass) < 1e-8);
1596  // Then reset the reference state
1597  set_reference_stateS(fluids[i], "DEF");
1598  }
1599  }
1600  }
1601 }
1602 TEST_CASE("Test that reference states yield proper values using low-level interface", "[reference_states]") {
1603  struct ref_entry
1604  {
1605  std::string name;
1606  double hmass, smass;
1607  parameters in1;
1608  double val1;
1609  parameters in2;
1610  double val2;
1611  };
1612  std::string fluids[] = {"n-Propane", "R134a", "R124"};
1613  ref_entry entries[3] = {{"IIR", 200000, 1000, iT, 273.15, iQ, 0}, {"ASHRAE", 0, 0, iT, 233.15, iQ, 0}, {"NBP", 0, 0, iP, 101325, iQ, 0}};
1614  for (std::size_t i = 0; i < 3; ++i) {
1615  for (std::size_t j = 0; j < 3; ++j) {
1616  std::ostringstream ss1;
1617  ss1 << "Check state for " << fluids[i] << " for " + entries[j].name + " reference state ";
1618  SECTION(ss1.str(), "") {
1619  double val1, val2;
1620  input_pairs pair = generate_update_pair(entries[j].in1, entries[j].val1, entries[j].in2, entries[j].val2, val1, val2);
1621  // Generate a state instance
1622  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", fluids[i]));
1623  AS->update(pair, val1, val2);
1624  double hmass0 = AS->hmass();
1625  double smass0 = AS->smass();
1626  // First reset the reference state
1627  set_reference_stateS(fluids[i], "DEF");
1628  AS->update(pair, val1, val2);
1629  double hmass00 = AS->hmass();
1630  double smass00 = AS->smass();
1631  CHECK(std::abs(hmass00 - hmass0) < 1e-10);
1632  CHECK(std::abs(smass00 - smass0) < 1e-10);
1633 
1634  // Then set to desired reference state
1635  set_reference_stateS(fluids[i], entries[j].name);
1636 
1637  // Should not change existing instance
1638  AS->clear();
1639  AS->update(pair, val1, val2);
1640  double hmass1 = AS->hmass();
1641  double smass1 = AS->smass();
1642  CHECK(std::abs(hmass1 - hmass0) < 1e-10);
1643  CHECK(std::abs(smass1 - smass0) < 1e-10);
1644 
1645  // New instance - should get updated reference state
1646  shared_ptr<CoolProp::AbstractState> AS2(CoolProp::AbstractState::factory("HEOS", fluids[i]));
1647  AS2->update(pair, val1, val2);
1648  double hmass2 = AS2->hmass();
1649  double smass2 = AS2->smass();
1650  CHECK(std::abs(hmass2 - entries[j].hmass) < 1e-8);
1651  CHECK(std::abs(smass2 - entries[j].smass) < 1e-8);
1652 
1653  // Then reset the reference state
1654  set_reference_stateS(fluids[i], "DEF");
1655  }
1656  }
1657  }
1658 }
1659 
1660 class FixedStateFixture
1661 {
1662  public:
1663  void run_fluid(const std::string& fluid, const std::string& state, const std::string& ref_state) {
1664 
1665  // Skip impossible reference states
1666  if (Props1SI("Ttriple", fluid) > 233.15 && ref_state == "ASHRAE") {
1667  return;
1668  }
1669  if (Props1SI("Tcrit", fluid) < 233.15 && ref_state == "ASHRAE") {
1670  return;
1671  }
1672  if (Props1SI("Tcrit", fluid) < 273.15 && ref_state == "IIR") {
1673  return;
1674  }
1675  if (Props1SI("Ttriple", fluid) > 273.15 && ref_state == "IIR") {
1676  return;
1677  }
1678  if (Props1SI("ptriple", fluid) > 101325 && ref_state == "NBP") {
1679  return;
1680  }
1681 
1682  // First reset the reference state
1683  if (ref_state != "DEF") {
1684  set_reference_stateS(fluid, "DEF");
1685  try {
1686  // Then try to set to the specified reference state
1687  set_reference_stateS(fluid, ref_state);
1688  } catch (std::exception& e) {
1689  // Then set the reference state back to the default
1690  set_reference_stateS(fluid, "DEF");
1691  CAPTURE(e.what());
1692  REQUIRE(false);
1693  }
1694  }
1695 
1696  std::ostringstream name;
1697  name << "Check state for " << state << " for " << fluid << " for reference state " << ref_state;
1698  CAPTURE(name.str());
1699 
1700  std::vector<std::string> fl(1, fluid);
1701  shared_ptr<CoolProp::HelmholtzEOSMixtureBackend> HEOS(new CoolProp::HelmholtzEOSMixtureBackend(fl));
1702 
1703  // Skip the saturation maxima states for pure fluids
1704  if (HEOS->is_pure() && (state == "max_sat_T" || state == "max_sat_p")) {
1705  return;
1706  }
1707 
1708  // Get the state
1709  CoolProp::SimpleState _state = HEOS->calc_state(state);
1710  HEOS->specify_phase(iphase_gas); // something homogenous
1711  // Bump a tiny bit for EOS with non-analytic parts
1712  double f = 1.0;
1713  if ((fluid == "Water" || fluid == "CarbonDioxide") && (state == "reducing" || state == "critical")) {
1714  f = 1.00001;
1715  }
1716  HEOS->update(CoolProp::DmolarT_INPUTS, _state.rhomolar * f, _state.T * f);
1717  CAPTURE(_state.hmolar);
1718  CAPTURE(_state.smolar);
1719  CHECK(ValidNumber(_state.hmolar));
1720  CHECK(ValidNumber(_state.smolar));
1721  double EOS_hmolar = HEOS->hmolar();
1722  double EOS_smolar = HEOS->smolar();
1723  CAPTURE(EOS_hmolar);
1724  CAPTURE(EOS_smolar);
1725  CHECK(std::abs(EOS_hmolar - _state.hmolar) < 1e-2);
1726  CHECK(std::abs(EOS_smolar - _state.smolar) < 1e-2);
1727  // Then set the reference state back to the default
1728  set_reference_stateS(fluid, "DEF");
1729  };
1730  void run_checks() {
1731 
1732  std::vector<std::string> fluids = strsplit(CoolProp::get_global_param_string("fluids_list"), ',');
1733  for (std::size_t i = 0; i < fluids.size(); ++i) {
1734  std::string ref_state[4] = {"DEF", "IIR", "ASHRAE", "NBP"};
1735  for (std::size_t j = 0; j < 4; ++j) {
1736  std::string states[] = {"hs_anchor", "reducing", "critical", "max_sat_T", "max_sat_p", "triple_liquid", "triple_vapor"};
1737  for (std::size_t k = 0; k < 7; ++k) {
1738  run_fluid(fluids[i], states[k], ref_state[j]);
1739  }
1740  }
1741  }
1742  }
1743 };
1744 TEST_CASE_METHOD(FixedStateFixture, "Test that enthalpies and entropies are correct for fixed states for all reference states", "[fixed_states]") {
1745  run_checks();
1746 }; // !!!! check this
1747 
1748 TEST_CASE("Check the first partial derivatives", "[first_saturation_partial_deriv]") {
1749  const int number_of_pairs = 10;
1750  struct pair
1751  {
1752  parameters p1, p2;
1753  };
1754  pair pairs[number_of_pairs] = {{iP, iT}, {iDmolar, iT}, {iHmolar, iT}, {iSmolar, iT}, {iUmolar, iT},
1755  {iT, iP}, {iDmolar, iP}, {iHmolar, iP}, {iSmolar, iP}, {iUmolar, iP}};
1756  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "n-Propane"));
1757  for (std::size_t i = 0; i < number_of_pairs; ++i) {
1758  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
1759  std::ostringstream ss1;
1760  ss1 << "Check first partial derivative for d(" << get_parameter_information(pairs[i].p1, "short") << ")/d("
1761  << get_parameter_information(pairs[i].p2, "short") << ")|sat";
1762  SECTION(ss1.str(), "") {
1763  AS->update(QT_INPUTS, 1, 300);
1764  CoolPropDbl p = AS->p();
1765  CoolPropDbl analytical = AS->first_saturation_deriv(pairs[i].p1, pairs[i].p2);
1766  CAPTURE(analytical);
1767  CoolPropDbl numerical;
1768  if (pairs[i].p2 == iT) {
1769  AS->update(QT_INPUTS, 1, 300 + 1e-5);
1770  CoolPropDbl v1 = AS->keyed_output(pairs[i].p1);
1771  AS->update(QT_INPUTS, 1, 300 - 1e-5);
1772  CoolPropDbl v2 = AS->keyed_output(pairs[i].p1);
1773  numerical = (v1 - v2) / (2e-5);
1774  } else if (pairs[i].p2 == iP) {
1775  AS->update(PQ_INPUTS, p + 1e-2, 1);
1776  CoolPropDbl v1 = AS->keyed_output(pairs[i].p1);
1777  AS->update(PQ_INPUTS, p - 1e-2, 1);
1778  CoolPropDbl v2 = AS->keyed_output(pairs[i].p1);
1779  numerical = (v1 - v2) / (2e-2);
1780  } else {
1781  throw ValueError();
1782  }
1783  CAPTURE(numerical);
1784  CHECK(std::abs(numerical / analytical - 1) < 1e-4);
1785  }
1786  }
1787 }
1788 
1789 TEST_CASE("Check the second saturation derivatives", "[second_saturation_partial_deriv]") {
1790  const int number_of_pairs = 5;
1791  struct pair
1792  {
1793  parameters p1, p2, p3;
1794  };
1795  pair pairs[number_of_pairs] = {{iT, iP, iP}, {iDmolar, iP, iP}, {iHmolar, iP, iP}, {iSmolar, iP, iP}, {iUmolar, iP, iP}};
1796  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "n-Propane"));
1797  for (std::size_t i = 0; i < number_of_pairs; ++i) {
1798  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
1799  std::ostringstream ss1;
1800  ss1 << "Check second saturation derivative for d2(" << get_parameter_information(pairs[i].p1, "short") << ")/d("
1801  << get_parameter_information(pairs[i].p2, "short") << ")2|sat";
1802  SECTION(ss1.str(), "") {
1803  AS->update(QT_INPUTS, 1, 300);
1804  CoolPropDbl p = AS->p();
1805  CoolPropDbl analytical = AS->second_saturation_deriv(pairs[i].p1, pairs[i].p2, pairs[i].p3);
1806  CAPTURE(analytical);
1807  CoolPropDbl numerical;
1808  if (pairs[i].p2 == iT) {
1809  throw NotImplementedError();
1810  } else if (pairs[i].p2 == iP) {
1811  AS->update(PQ_INPUTS, p + 1e-2, 1);
1812  CoolPropDbl v1 = AS->first_saturation_deriv(pairs[i].p1, pairs[i].p2);
1813  AS->update(PQ_INPUTS, p - 1e-2, 1);
1814  CoolPropDbl v2 = AS->first_saturation_deriv(pairs[i].p1, pairs[i].p2);
1815  numerical = (v1 - v2) / (2e-2);
1816  } else {
1817  throw ValueError();
1818  }
1819  CAPTURE(numerical);
1820  CHECK(std::abs(numerical / analytical - 1) < 1e-4);
1821  }
1822  }
1823 }
1824 
1825 TEST_CASE("Check the first two-phase derivative", "[first_two_phase_deriv]") {
1826  const int number_of_pairs = 4;
1827  struct pair
1828  {
1829  parameters p1, p2, p3;
1830  };
1831  pair pairs[number_of_pairs] = {{iDmass, iP, iHmass}, {iDmolar, iP, iHmolar}, {iDmolar, iHmolar, iP}, {iDmass, iHmass, iP}};
1832  shared_ptr<CoolProp::HelmholtzEOSBackend> AS(new CoolProp::HelmholtzEOSBackend("n-Propane"));
1833  for (std::size_t i = 0; i < number_of_pairs; ++i) {
1834  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
1835  std::ostringstream ss1;
1836  ss1 << "for (" << get_parameter_information(pairs[i].p1, "short") << ", " << get_parameter_information(pairs[i].p2, "short") << ", "
1837  << get_parameter_information(pairs[i].p3, "short") << ")";
1838  SECTION(ss1.str(), "") {
1839  AS->update(QT_INPUTS, 0.3, 300);
1840  CoolPropDbl numerical;
1841  CoolPropDbl analytical = AS->first_two_phase_deriv(pairs[i].p1, pairs[i].p2, pairs[i].p3);
1842  CAPTURE(analytical);
1843 
1844  CoolPropDbl out1, out2;
1845  CoolPropDbl v2base, v3base;
1846  v2base = AS->keyed_output(pairs[i].p2);
1847  v3base = AS->keyed_output(pairs[i].p3);
1848  CoolPropDbl v2plus = v2base * 1.001;
1849  CoolPropDbl v2minus = v2base * 0.999;
1850  CoolProp::input_pairs input_pair1 = generate_update_pair(pairs[i].p2, v2plus, pairs[i].p3, v3base, out1, out2);
1851  AS->update(input_pair1, out1, out2);
1852  CoolPropDbl v1 = AS->keyed_output(pairs[i].p1);
1853  CoolProp::input_pairs input_pair2 = generate_update_pair(pairs[i].p2, v2minus, pairs[i].p3, v3base, out1, out2);
1854  AS->update(input_pair2, out1, out2);
1855  CoolPropDbl v2 = AS->keyed_output(pairs[i].p1);
1856 
1857  numerical = (v1 - v2) / (v2plus - v2minus);
1858  CAPTURE(numerical);
1859  CHECK(std::abs(numerical / analytical - 1) < 1e-4);
1860  }
1861  }
1862 }
1863 
1864 TEST_CASE("Check the second two-phase derivative", "[second_two_phase_deriv]") {
1865  SECTION("d2rhodhdp", "") {
1866  shared_ptr<CoolProp::HelmholtzEOSBackend> AS(new CoolProp::HelmholtzEOSBackend("n-Propane"));
1867  AS->update(QT_INPUTS, 0.3, 300);
1868  CoolPropDbl analytical = AS->second_two_phase_deriv(iDmolar, iHmolar, iP, iP, iHmolar);
1869  CAPTURE(analytical);
1870  CoolPropDbl pplus = AS->p() * 1.001, pminus = AS->p() * 0.999, h = AS->hmolar();
1871  AS->update(HmolarP_INPUTS, h, pplus);
1872  CoolPropDbl v1 = AS->first_two_phase_deriv(iDmolar, iHmolar, iP);
1873  AS->update(HmolarP_INPUTS, h, pminus);
1874  CoolPropDbl v2 = AS->first_two_phase_deriv(iDmolar, iHmolar, iP);
1875  CoolPropDbl numerical = (v1 - v2) / (pplus - pminus);
1876  CAPTURE(numerical);
1877  CHECK(std::abs(numerical / analytical - 1) < 1e-6);
1878  }
1879  SECTION("d2rhodhdp using mass", "") {
1880  shared_ptr<CoolProp::HelmholtzEOSBackend> AS(new CoolProp::HelmholtzEOSBackend("n-Propane"));
1881  AS->update(QT_INPUTS, 0.3, 300);
1882  CoolPropDbl analytical = AS->second_two_phase_deriv(iDmass, iHmass, iP, iP, iHmass);
1883  CAPTURE(analytical);
1884  CoolPropDbl pplus = AS->p() * 1.001, pminus = AS->p() * 0.999, h = AS->hmass();
1885  AS->update(HmassP_INPUTS, h, pplus);
1886  CoolPropDbl v1 = AS->first_two_phase_deriv(iDmass, iHmass, iP);
1887  AS->update(HmassP_INPUTS, h, pminus);
1888  CoolPropDbl v2 = AS->first_two_phase_deriv(iDmass, iHmass, iP);
1889  CoolPropDbl numerical = (v1 - v2) / (pplus - pminus);
1890  CAPTURE(numerical);
1891  CHECK(std::abs(numerical / analytical - 1) < 1e-6);
1892  }
1893 }
1894 
1895 TEST_CASE("Check the first two-phase derivative using splines", "[first_two_phase_deriv_splined]") {
1896  const int number_of_pairs = 4;
1897  struct pair
1898  {
1899  parameters p1, p2, p3;
1900  };
1901  pair pairs[number_of_pairs] = {{iDmass, iP, iHmass}, {iDmolar, iP, iHmolar}, {iDmolar, iHmolar, iP}, {iDmass, iHmass, iP}};
1902  shared_ptr<CoolProp::HelmholtzEOSBackend> AS(new CoolProp::HelmholtzEOSBackend("n-Propane"));
1903  for (std::size_t i = 0; i < number_of_pairs; ++i) {
1904  // See https://groups.google.com/forum/?fromgroups#!topic/catch-forum/mRBKqtTrITU
1905  std::ostringstream ss1;
1906  ss1 << "for (" << get_parameter_information(pairs[i].p1, "short") << ", " << get_parameter_information(pairs[i].p2, "short") << ", "
1907  << get_parameter_information(pairs[i].p3, "short") << ")";
1908  SECTION(ss1.str(), "") {
1909  AS->update(QT_INPUTS, 0.2, 300);
1910  CoolPropDbl numerical;
1911  CoolPropDbl analytical = AS->first_two_phase_deriv_splined(pairs[i].p1, pairs[i].p2, pairs[i].p3, 0.3);
1912  CAPTURE(analytical);
1913 
1914  CoolPropDbl out1, out2;
1915  CoolPropDbl v2base, v3base;
1916  v2base = AS->keyed_output(pairs[i].p2);
1917  v3base = AS->keyed_output(pairs[i].p3);
1918  CoolPropDbl v2plus = v2base * 1.00001;
1919  CoolPropDbl v2minus = v2base * 0.99999;
1920 
1921  CoolProp::input_pairs input_pair1 = generate_update_pair(pairs[i].p2, v2plus, pairs[i].p3, v3base, out1, out2);
1922  AS->update(input_pair1, out1, out2);
1923  CoolPropDbl v1 = AS->first_two_phase_deriv_splined(pairs[i].p1, pairs[i].p1, pairs[i].p1, 0.3);
1924 
1925  CoolProp::input_pairs input_pair2 = generate_update_pair(pairs[i].p2, v2minus, pairs[i].p3, v3base, out1, out2);
1926  AS->update(input_pair2, out1, out2);
1927  CoolPropDbl v2 = AS->first_two_phase_deriv_splined(pairs[i].p1, pairs[i].p1, pairs[i].p1, 0.3);
1928 
1929  numerical = (v1 - v2) / (v2plus - v2minus);
1930  CAPTURE(numerical);
1931  CHECK(std::abs(numerical / analytical - 1) < 1e-8);
1932  }
1933  }
1934 }
1935 
1936 TEST_CASE("Check the phase flags", "[phase]") {
1937  SECTION("subcooled liquid") {
1938  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1939  AS->update(PT_INPUTS, 101325, 300);
1940  CHECK(AS->phase() == iphase_liquid);
1941  }
1942  SECTION("superheated gas") {
1943  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1944  AS->update(PT_INPUTS, 101325, 400);
1945  CHECK(AS->phase() == iphase_gas);
1946  }
1947  SECTION("supercritical gas") {
1948  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1949  AS->update(PT_INPUTS, 1e5, 800);
1950  CHECK(AS->phase() == iphase_supercritical_gas);
1951  }
1952  SECTION("supercritical liquid") {
1953  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1954  AS->update(PT_INPUTS, 1e8, 500);
1955  CHECK(AS->phase() == iphase_supercritical_liquid);
1956  }
1957  SECTION("supercritical") {
1958  shared_ptr<CoolProp::AbstractState> AS(CoolProp::AbstractState::factory("HEOS", "Water"));
1959  AS->update(PT_INPUTS, 1e8, 800);
1960  CHECK(AS->phase() == iphase_supercritical);
1961  }
1962 }
1963 
1964 TEST_CASE("Check the changing of reducing function constants", "[reducing]") {
1965  double z0 = 0.2;
1966  std::vector<double> z(2);
1967  z[0] = z0;
1968  z[1] = 1 - z[0];
1969  shared_ptr<CoolProp::AbstractState> AS1(CoolProp::AbstractState::factory("HEOS", "Methane&Ethane"));
1970  shared_ptr<CoolProp::AbstractState> AS2(CoolProp::AbstractState::factory("HEOS", "Methane&Ethane"));
1971  AS1->set_mole_fractions(z);
1972  AS2->set_mole_fractions(z);
1973  std::vector<CoolProp::CriticalState> pts1 = AS1->all_critical_points();
1974  double gammaT = AS2->get_binary_interaction_double(0, 1, "gammaT");
1975  AS2->set_binary_interaction_double(0, 1, "gammaT", gammaT * 0.7);
1976  std::vector<CoolProp::CriticalState> pts2 = AS2->all_critical_points();
1977  double Tdiff = abs(pts2[0].T - pts1[0].T);
1978  CHECK(Tdiff > 1e-3); // Make sure that it actually got the change to the interaction parameters
1979 }
1980 
1981 TEST_CASE("Check the PC-SAFT pressure function", "[pcsaft_pressure]") {
1982  double p = 101325.;
1983  double p_calc = CoolProp::PropsSI("P", "T", 320., "Dmolar", 9033.114359706229, "PCSAFT::TOLUENE");
1984  CHECK(abs((p_calc / p) - 1) < 1e-5);
1985 
1986  p_calc = CoolProp::PropsSI("P", "T", 274., "Dmolar", 55530.40675319466, "PCSAFT::WATER");
1987  CHECK(abs((p_calc/p) - 1) < 1e-5);
1988 
1989  p_calc = CoolProp::PropsSI("P", "T", 305., "Dmolar", 16965.6697209874,"PCSAFT::ACETIC ACID");
1990  CHECK(abs((p_calc/p) - 1) < 1e-5);
1991 
1992  p_calc = CoolProp::PropsSI("P", "T", 240., "Dmolar", 15955.50941242, "PCSAFT::DIMETHYL ETHER");
1993  CHECK(abs((p_calc/p) - 1) < 1e-5);
1994 
1995  p_calc = CoolProp::PropsSI("P", "T", 298.15, "Dmolar", 9368.903838750752, "PCSAFT::METHANOL[0.055]&CYCLOHEXANE[0.945]");
1996  CHECK(abs((p_calc/p) - 1) < 1e-5);
1997 
1998  p_calc = CoolProp::PropsSI("P", "T", 298.15, "Dmolar", 55740.15826463244, "PCSAFT::Na+[0.010579869455908]&Cl-[0.010579869455908]&WATER[0.978840261088184]");
1999  CHECK(abs((p_calc/p) - 1) < 1e-5);
2000 
2001  p = CoolProp::PropsSI("P", "T", 100., "Q", 0, "PCSAFT::PROPANE");
2002  double rho = 300;
2003  double phase = CoolProp::PropsSI("Phase", "T", 100., "Dmolar", rho, "PCSAFT::PROPANE");
2004  CHECK(phase == get_phase_index("phase_twophase"));
2005  p_calc = CoolProp::PropsSI("P", "T", 100, "Dmolar", rho, "PCSAFT::PROPANE");
2006  CHECK(abs((p_calc / p) - 1) < 1e-4);
2007 }
2008 
2009 TEST_CASE("Check the PC-SAFT density function", "[pcsaft_density]") {
2010  double den = 9033.114209728405;
2011  double den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 320., "P", 101325., "PCSAFT::TOLUENE");
2012  CHECK(abs((den_calc / den) - 1) < 1e-5);
2013 
2014  den = 55530.40512318346;
2015  den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 274., "P", 101325, "PCSAFT::WATER");
2016  CHECK(abs((den_calc / den) - 1) < 1e-5);
2017 
2018  den = 17240.; // source: DIPPR correlation
2019  den_calc = CoolProp::PropsSI("Dmolar","T|liquid",305.,"P",101325,"PCSAFT::ACETIC ACID");
2020  CHECK(abs((den_calc/den) - 1) < 2e-2);
2021 
2022  den = 15955.509146801696;
2023  den_calc = CoolProp::PropsSI("Dmolar","T|liquid",240.,"P",101325,"PCSAFT::DIMETHYL ETHER");
2024  CHECK(abs((den_calc/den) - 1) < 1e-5);
2025 
2026  den = 9368.90368306872;
2027  den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 298.15, "P", 101325, "PCSAFT::METHANOL[0.055]&CYCLOHEXANE[0.945]");
2028  CHECK(abs((den_calc / den) - 1) < 1e-5);
2029 
2030  den = 55740.157290833515;
2031  den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 298.15, "P", 101325, "PCSAFT::Na+[0.010579869455908]&Cl-[0.010579869455908]&WATER[0.978840261088184]");
2032  CHECK(abs((den_calc / den) - 1) < 1e-5);
2033 
2034  den = 16621.0;
2035  den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 85.525, "P", 1.7551e-4, "PCSAFT::PROPANE");
2036  CHECK(abs((den_calc / den) - 1) < 1e-2);
2037 
2038  den = 1.9547e-7;
2039  den_calc = CoolProp::PropsSI("Dmolar", "T|gas", 85.525, "P", 1.39e-4, "PCSAFT::PROPANE");
2040  CHECK(abs((den_calc / den) - 1) < 1e-2);
2041 
2042  den = 11346.0;
2043  den_calc = CoolProp::PropsSI("Dmolar", "T|liquid", 293, "P", 833240, "PCSAFT::PROPANE");
2044  CHECK(abs((den_calc / den) - 1) < 1e-2);
2045 
2046  den = 623.59;
2047  den_calc = CoolProp::PropsSI("Dmolar","T|liquid", 430,"P", 2000000, "PCSAFT::PROPANE");
2048  CHECK(abs((den_calc/den) - 1) < 1e-2);
2049 }
2050 
2051 TEST_CASE("Check the PC-SAFT residual enthalpy function", "[pcsaft_enthalpy]") {
2052  double h = -36809.962122036086;
2053  double h_calc = CoolProp::PropsSI("Hmolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "PCSAFT::TOLUENE");
2054  CHECK(abs((h_calc / h) - 1) < 1e-5);
2055 
2056  h = -362.6832840695562;
2057  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "PCSAFT::TOLUENE");
2058  CHECK(abs((h_calc / h) - 1) < 1e-5);
2059 
2060  h = -38925.302571456035;
2061  h_calc = CoolProp::PropsSI("Hmolar_residual","T|liquid",325.,"Dmolar", 16655.853047419932,"PCSAFT::ACETIC ACID");
2062  CHECK(abs((h_calc/h) - 1) < 1e-5);
2063 
2064  h = -15393.870073928741;
2065  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 85.70199446609787, "PCSAFT::ACETIC ACID");
2066  CHECK(abs((h_calc / h) - 1) < 1e-5);
2067 
2068  h = -18242.128097841978;
2069  h_calc = CoolProp::PropsSI("Hmolar_residual","T|liquid",325.,"Dmolar", 13141.475980937616,"PCSAFT::DIMETHYL ETHER");
2070  CHECK(abs((h_calc/h) - 1) < 1e-5);
2071 
2072  h = -93.819615173017169;
2073  h_calc = CoolProp::PropsSI("Hmolar_residual","T|gas",325.,"Dmolar", 37.963459290365265,"PCSAFT::DIMETHYL ETHER");
2074  CHECK(abs((h_calc/h) - 1) < 1e-5);
2075 
2076  // checks based on values from the HEOS backend
2077  h = CoolProp::PropsSI("Hmolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "HEOS::TOLUENE");
2078  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "PCSAFT::TOLUENE");
2079  CHECK(abs(h_calc - h) < 600.);
2080 
2081  h = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "HEOS::TOLUENE");
2082  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "PCSAFT::TOLUENE");
2083  CHECK(abs(h_calc - h) < 600.);
2084 
2085  h = CoolProp::PropsSI("Hmolar_residual", "T|liquid", 325., "Dmolar", 54794.1, "HEOS::WATER");
2086  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|liquid", 325., "Dmolar", 54794.1, "PCSAFT::WATER");
2087  CHECK(abs(h_calc - h) < 600.);
2088 
2089  h = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 0.370207, "HEOS::WATER");
2090  h_calc = CoolProp::PropsSI("Hmolar_residual", "T|gas", 325., "Dmolar", 0.370207, "PCSAFT::WATER");
2091  CHECK(abs(h_calc - h) < 600.);
2092 }
2093 
2094 TEST_CASE("Check the PC-SAFT residual entropy function", "[pcsaft_entropy]") {
2095  // checks based on values from working PC-SAFT code
2096  double s = -50.81694890352192;
2097  double s_calc = CoolProp::PropsSI("Smolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "PCSAFT::TOLUENE");
2098  CHECK(abs((s_calc / s) - 1) < 1e-5);
2099 
2100  s = -0.2929618646219797;
2101  s_calc = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "PCSAFT::TOLUENE");
2102  CHECK(abs((s_calc / s) - 1) < 1e-5);
2103 
2104  s = -47.42736805661422;
2105  s_calc = CoolProp::PropsSI("Smolar_residual","T|liquid",325.,"Dmolar", 16655.853047419932,"PCSAFT::ACETIC ACID");
2106  CHECK(abs((s_calc/s) - 1) < 1e-5);
2107 
2108  s = -34.0021996393859;
2109  s_calc = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 85.70199446609787, "PCSAFT::ACETIC ACID");
2110  CHECK(abs((s_calc / s) - 1) < 1e-5);
2111 
2112  s = -26.42525828195748;
2113  s_calc = CoolProp::PropsSI("Smolar_residual","T|liquid",325.,"Dmolar", 13141.475980937616,"PCSAFT::DIMETHYL ETHER");
2114  CHECK(abs((s_calc/s) - 1) < 1e-5);
2115 
2116  s = -0.08427662199177874;
2117  s_calc = CoolProp::PropsSI("Smolar_residual","T|gas",325.,"Dmolar", 37.963459290365265,"PCSAFT::DIMETHYL ETHER");
2118  CHECK(abs((s_calc/s) - 1) < 1e-5);
2119 
2120  // checks based on values from the HEOS backend
2121  s = CoolProp::PropsSI("Smolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "HEOS::TOLUENE");
2122  s_calc = CoolProp::PropsSI("Smolar_residual", "T|liquid", 325., "Dmolar", 8983.377722763931, "PCSAFT::TOLUENE");
2123  CHECK(abs(s_calc - s) < 3.);
2124 
2125  s = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "HEOS::TOLUENE");
2126  s_calc = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 39.44490805826904, "PCSAFT::TOLUENE");
2127  CHECK(abs(s_calc - s) < 3.);
2128 
2129  s = CoolProp::PropsSI("Smolar_residual", "T|liquid", 325., "Dmolar", 54794.1, "HEOS::WATER");
2130  s_calc = CoolProp::PropsSI("Smolar_residual", "T|liquid", 325., "Dmolar", 54794.1, "PCSAFT::WATER");
2131  CHECK(abs(s_calc - s) < 3.);
2132 
2133  s = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 0.370207, "HEOS::WATER");
2134  s_calc = CoolProp::PropsSI("Smolar_residual", "T|gas", 325., "Dmolar", 0.370207, "PCSAFT::WATER");
2135  CHECK(abs(s_calc - s) < 3.);
2136 }
2137 
2138 TEST_CASE("Check the PC-SAFT residual gibbs energy function", "[pcsaft_gibbs]") {
2139  double g = -5489.471870270737;
2140  double g_calc = CoolProp::PropsSI("Gmolar_residual", "T|liquid", 325., "Dmolar", 8983.377872003264, "PCSAFT::TOLUENE");
2141  CHECK(abs((g_calc / g) - 1) < 1e-5);
2142 
2143  g = -130.63592030187894;
2144  g_calc = CoolProp::PropsSI("Gmolar_residual", "T|gas", 325., "Dmolar", 39.44491269148218, "PCSAFT::TOLUENE");
2145  CHECK(abs((g_calc / g) - 1) < 1e-5);
2146 
2147  g = -7038.128334100866;
2148  g_calc = CoolProp::PropsSI("Gmolar_residual","T|liquid",325.,"Dmolar", 16655.853314424,"PCSAFT::ACETIC ACID");
2149  CHECK(abs((g_calc/g) - 1) < 1e-5);
2150 
2151  g = -2109.4916554917604;
2152  g_calc = CoolProp::PropsSI("Gmolar_residual", "T|gas", 325., "Dmolar", 85.70199446609787, "PCSAFT::ACETIC ACID");
2153  CHECK(abs((g_calc / g) - 1) < 1e-5);
2154 
2155  g = 6178.973332408309;
2156  g_calc = CoolProp::PropsSI("Gmolar_residual","T|liquid",325.,"Dmolar", 13141.47619110254,"PCSAFT::DIMETHYL ETHER");
2157  CHECK(abs((g_calc/g) - 1) < 1e-5);
2158 
2159  g = -33.038791982589615;
2160  g_calc = CoolProp::PropsSI("Gmolar_residual","T|gas",325.,"Dmolar", 37.96344503293008,"PCSAFT::DIMETHYL ETHER");
2161  CHECK(abs((g_calc/g) - 1) < 1e-5);
2162 }
2163 
2164 TEST_CASE("Check vapor pressures calculated using PC-SAFT", "[pcsaft_vapor_pressure]") {
2165  double vp = 3290651.18080112;
2166  double vp_calc = CoolProp::PropsSI("P", "T", 572.6667, "Q", 0, "PCSAFT::TOLUENE");
2167  CHECK(abs((vp_calc / vp) - 1) < 1e-3);
2168 
2169  vp = 66917.67387203;
2170  vp_calc = CoolProp::PropsSI("P", "T", 362, "Q", 0, "PCSAFT::WATER");
2171  CHECK(abs((vp_calc / vp) - 1) < 1e-3);
2172 
2173  vp = 190061.78088909;
2174  vp_calc = CoolProp::PropsSI("P", "T", 413.5385, "Q", 0, "PCSAFT::ACETIC ACID");
2175  CHECK(abs((vp_calc / vp) - 1) < 1e-3);
2176 
2177  vp = 622763.506195;
2178  vp_calc = CoolProp::PropsSI("P","T", 300.,"Q", 0,"PCSAFT::DIMETHYL ETHER");
2179  CHECK(abs((vp_calc/vp) - 1) < 1e-3);
2180 
2181  // This test doesn't pass yet. The flash algorithm for the PC-SAFT backend is not yet robust enough.
2182  // vp = 1.7551e-4;
2183  // vp_calc = CoolProp::PropsSI("P","T",85.525,"Q", 0, "PCSAFT::PROPANE");
2184  // CHECK(abs((vp_calc/vp) - 1) < 0.1);
2185 
2186  vp = 8.3324e5;
2187  vp_calc = CoolProp::PropsSI("P", "T", 293, "Q", 0, "PCSAFT::PROPANE");
2188  CHECK(abs((vp_calc / vp) - 1) < 0.01);
2189 
2190  vp = 42.477e5;
2191  vp_calc = CoolProp::PropsSI("P", "T", 369.82, "Q", 0, "PCSAFT::PROPANE");
2192  CHECK(abs((vp_calc / vp) - 1) < 0.01);
2193 }
2194 
2195 TEST_CASE("Check PC-SAFT interaction parameter functions", "[pcsaft_binary_interaction]") {
2196  std::string CAS_water = get_fluid_param_string("WATER", "CAS");
2197  std::string CAS_aacid = "64-19-7";
2198  set_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij", -0.127);
2199  CHECK(atof(get_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij").c_str()) == -0.127);
2200 }
2201 
2202 TEST_CASE("Check bubble pressures calculated using PC-SAFT", "[pcsaft_bubble_pressure]")
2203 {
2204  double vp = 1816840.45112607; // source: H.-M. Lin, H. M. Sebastian, J. J. Simnick, and K.-C. Chao, “Gas-liquid equilibrium in binary mixtures of methane with N-decane, benzene, and toluene,” J. Chem. Eng. Data, vol. 24, no. 2, pp. 146–149, Apr. 1979.
2205  double vp_calc = CoolProp::PropsSI("P", "T", 421.05, "Q", 0, "PCSAFT::METHANE[0.0252]&BENZENE[0.9748]");
2206  CHECK(abs((vp_calc / vp) - 1) < 1e-3);
2207 
2208  // This test doesn't pass yet. The flash algorithm for the PC-SAFT backend cannot yet get a good enough initial guess value for the k values (vapor-liquid distribution ratios)
2209  // vp = 6691000; // source: Hughes TJ, Kandil ME, Graham BF, Marsh KN, Huang SH, May EF. Phase equilibrium measurements of (methane+ benzene) and (methane+ methylbenzene) at temperatures from (188 to 348) K and pressures to 13 MPa. The Journal of Chemical Thermodynamics. 2015 Jun 1;85:141-7.
2210  // vp_calc = CoolProp::PropsSI("P", "T", 348.15, "Q", 0, "PCSAFT::METHANE[0.119]&BENZENE[0.881]");
2211  // CHECK(abs((vp_calc/vp) - 1) < 1e-3);
2212 
2213  vp = 96634.2439079;
2214  vp_calc = CoolProp::PropsSI("P", "T", 327.48, "Q", 0, "PCSAFT::METHANOL[0.3]&CYCLOHEXANE[0.7]");
2215  CHECK(abs((vp_calc / vp) - 1) < 1e-3);
2216 
2217  // set binary interaction parameter
2218  std::string CAS_water = get_fluid_param_string("WATER", "CAS");
2219  std::string CAS_aacid = "64-19-7";
2220  try {
2221  get_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij");
2222  }
2223  catch (...) {
2224  set_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij", -0.127);
2225  }
2226 
2227  vp = 274890.39985918;
2228  vp_calc = CoolProp::PropsSI("P", "T", 403.574, "Q", 0, "PCSAFT::WATER[0.9898662364]&ACETIC ACID[0.0101337636]");
2229  CHECK(abs((vp_calc / vp) - 1) < 1e-2);
2230 
2231  vp = 72915.92217342;
2232  vp_calc = CoolProp::PropsSI("P", "T", 372.774, "Q", 0, "PCSAFT::WATER[0.2691800943]&ACETIC ACID[0.7308199057]");
2233  CHECK(abs((vp_calc / vp) - 1) < 2e-2);
2234 
2235  vp = 2387.42669687;
2236  vp_calc = CoolProp::PropsSI("P","T", 298.15,"Q", 0,"PCSAFT::Na+[0.0907304774758426]&Cl-[0.0907304774758426]&WATER[0.818539045048315]");
2237  CHECK(abs((vp_calc/vp) - 1) < 0.23);
2238 }
2239 
2240 TEST_CASE("Check bubble temperatures calculated using PC-SAFT", "[pcsaft_bubble_temperature]") {
2241  double t = 572.6667;
2242  double t_calc = CoolProp::PropsSI("T", "P", 3290651.18080112, "Q", 0, "PCSAFT::TOLUENE");
2243  CHECK(abs((t_calc / t) - 1) < 1e-3);
2244 
2245  t = 362;
2246  t_calc = CoolProp::PropsSI("T", "P", 66917.67387203, "Q", 0, "PCSAFT::WATER");
2247  CHECK(abs((t_calc / t) - 1) < 1e-3);
2248 
2249  t = 413.5385;
2250  t_calc = CoolProp::PropsSI("T", "P", 190061.78088909, "Q", 0, "PCSAFT::ACETIC ACID");
2251  CHECK(abs((t_calc / t) - 1) < 1e-3);
2252 
2253  t = 300.;
2254  t_calc = CoolProp::PropsSI("T", "P", 623027.07850612, "Q", 0, "PCSAFT::DIMETHYL ETHER");
2255  CHECK(abs((t_calc / t) - 1) < 1e-3);
2256 
2257  // This test doesn't pass yet. The flash algorithm for the PC-SAFT backend cannot yet get a good enough initial guess value for the k values (vapor-liquid distribution ratios)
2258  // t = 421.05;
2259  // t_calc = CoolProp::PropsSI("T", "P", 1816840.45112607, "Q", 0, "PCSAFT::METHANE[0.0252]&BENZENE[0.9748]");
2260  // CHECK(abs((t_calc/t) - 1) < 1e-3);
2261 
2262  t = 327.48;
2263  t_calc = CoolProp::PropsSI("T", "P", 96634.2439079, "Q", 0, "PCSAFT::METHANOL[0.3]&CYCLOHEXANE[0.7]");
2264  CHECK(abs((t_calc / t) - 1) < 1e-3);
2265 
2266  // set binary interaction parameter, if not already set
2267  std::string CAS_water = get_fluid_param_string("WATER","CAS");
2268  std::string CAS_aacid = "64-19-7";
2269  try {
2270  get_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij");
2271  }
2272  catch (...) {
2273  set_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij", -0.127);
2274  }
2275 
2276  t = 403.574;
2277  t_calc = CoolProp::PropsSI("T", "P", 274890.39985918, "Q", 0, "PCSAFT::WATER[0.9898662364]&ACETIC ACID[0.0101337636]");
2278  CHECK(abs((t_calc / t) - 1) < 1e-3);
2279 
2280  t = 372.774;
2281  t_calc = CoolProp::PropsSI("T", "P", 72915.92217342, "Q", 0, "PCSAFT::WATER[0.2691800943]&ACETIC ACID[0.7308199057]");
2282  CHECK(abs((t_calc / t) - 1) < 2e-3);
2283 
2284  t = 298.15;
2285  t_calc = CoolProp::PropsSI("T", "P", 2387.42669687, "Q", 0, "PCSAFT::Na+[0.0907304774758426]&Cl-[0.0907304774758426]&WATER[0.818539045048315]");
2286  CHECK(abs((t_calc / t) - 1) < 1e-2);
2287 }
2288 
2289 TEST_CASE("Check phase determination for PC-SAFT backend", "[pcsaft_phase]") {
2290  double den = 9033.114209728405;
2291  double den_calc = CoolProp::PropsSI("Dmolar", "T", 320., "P", 101325., "PCSAFT::TOLUENE");
2292  CHECK(abs((den_calc / den) - 1) < 1e-2);
2293  double phase = CoolProp::PropsSI("Phase", "T", 320., "P", 101325., "PCSAFT::TOLUENE");
2294  CHECK(phase == get_phase_index("phase_liquid"));
2295 
2296  den = 0.376013;
2297  den_calc = CoolProp::PropsSI("Dmolar", "T", 320., "P", 1000., "PCSAFT::TOLUENE");
2298  CHECK(abs((den_calc / den) - 1) < 1e-2);
2299  phase = CoolProp::PropsSI("Phase", "T", 320., "P", 1000., "PCSAFT::TOLUENE");
2300  CHECK(phase == get_phase_index("phase_gas"));
2301 }
2302 
2303 TEST_CASE("Check that indexes for mixtures are assigned correctly, especially for the association term", "[pcsaft_indexes]")
2304 {
2305  // The tests are performed by adding parameters for extra compounds that actually
2306  // are not present in the system and ensuring that the properties of the fluid do not change.
2307 
2308  // Binary mixture: water-acetic acid
2309  // set binary interaction parameter, if not already set
2310  std::string CAS_water = get_fluid_param_string("WATER","CAS");
2311  std::string CAS_aacid = "64-19-7";
2312  try {
2313  get_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij");
2314  }
2315  catch (...) {
2316  set_mixture_binary_pair_pcsaft(CAS_water, CAS_aacid, "kij", -0.127);
2317  }
2318 
2319  double t = 413.5385;
2320  double rho = 15107.481234283325;
2321  double p = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::ACETIC ACID"); // only parameters for acetic acid
2322  double p_extra = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::ACETIC ACID[1.0]&WATER[0]"); // same composition, but with mixture parameters
2323  CHECK(abs((p_extra - p)/ p * 100) < 1e-1);
2324 
2325  // Binary mixture: water-furfural
2326  t = 400; // K
2327  // p = 34914.37778265716; // Pa
2328  rho = 10657.129498214763;
2329  p = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::FURFURAL"); // only parameters for furfural
2330  p_extra = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::WATER[0]&FURFURAL[1.0]"); // same composition, but with mixture of components
2331  CHECK(abs((p_extra - p)/ p * 100) < 1e-1);
2332 
2333  // Mixture: NaCl in water with random 4th component
2334  t = 298.15; // K
2335  // p = 3153.417688548272; // Pa
2336  rho = 55320.89616248148;
2337  p = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::WATER"); // only parameters for water
2338  p_extra = CoolProp::PropsSI("P", "T", t, "Dmolar", rho, "PCSAFT::Na+[0]&Cl-[0]&WATER[1.0]&DIMETHOXYMETHANE[0]"); // same composition, but with mixture of components
2339  CHECK(abs((p_extra - p)/ p * 100) < 1e-1);
2340 }
2341 
2342 /*
2343 TEST_CASE("Test that HS solver works for a few fluids", "[HS_solver]")
2344 {
2345  std::vector<std::string> fluids; fluids.push_back("Propane"); fluids.push_back("D4"); fluids.push_back("Water");
2346  for (std::size_t i = 0; i < fluids.size(); ++i)
2347  {
2348  std::vector<std::string> fl(1,fluids[i]);
2349  shared_ptr<CoolProp::HelmholtzEOSMixtureBackend> HEOS(new CoolProp::HelmholtzEOSMixtureBackend(fl));
2350  for (double p = HEOS->p_triple()*10; p < HEOS->pmax(); p *= 10)
2351  {
2352  double Tmin = HEOS->Ttriple();
2353  double Tmax = HEOS->Tmax();
2354  for (double T = Tmin + 1; T < Tmax-1; T += 10)
2355  {
2356  std::ostringstream ss;
2357  ss << "Check HS for " << fluids[i] << " for T=" << T << ", p=" << p;
2358  SECTION(ss.str(),"")
2359  {
2360  CHECK_NOTHROW(HEOS->update(PT_INPUTS, p, T));
2361  std::ostringstream ss1;
2362  ss1 << "h=" << HEOS->hmolar() << ", s=" << HEOS->smolar();
2363  SECTION(ss1.str(),"")
2364  {
2365  CAPTURE(T);
2366  CAPTURE(p);
2367  CAPTURE(HEOS->hmolar());
2368  CAPTURE(HEOS->smolar());
2369  CHECK_NOTHROW(HEOS->update(HmolarSmolar_INPUTS, HEOS->hmolar(), HEOS->smolar()));
2370  double Terr = HEOS->T()- T;
2371  CAPTURE(Terr);
2372  CHECK(std::abs(Terr) < 1e-6);
2373  }
2374  }
2375  }
2376  }
2377  }
2378 }
2379 */
2380 #endif