CoolProp 7.2.0
An open-source fluid property and humid air property database
Helmholtz.cpp
Go to the documentation of this file.
1#include <numeric>
2#include "Helmholtz.h"
3
4#ifdef __ANDROID__
5# undef _A
6# undef _B
7# undef _C
8# undef _D
9#endif
10
11namespace CoolProp {
12
13CoolPropDbl kahanSum(const std::vector<CoolPropDbl>& x) {
14 CoolPropDbl sum = x[0], y, t;
15 CoolPropDbl c = 0.0; //A running compensation for lost low-order bits.
16 for (std::size_t i = 1; i < x.size(); ++i) {
17 y = x[i] - c; //So far, so good: c is zero.
18 t = sum + y; //Alas, sum is big, y small, so low-order digits of y are lost.
19 c = (t - sum) - y; //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
20 sum = t; //Algebraically, c should always be zero. Beware eagerly optimising compilers!
21 }
22 return sum;
23}
25 return std::abs(i) > std::abs(j);
26}
27
28// define function to be applied coefficient-wise
29double ramp(double x) {
30 if (x > 0)
31 return x;
32 else
33 return 0;
34}
35
36/*
37void ResidualHelmholtzGeneralizedExponential::allEigen(const CoolPropDbl &tau, const CoolPropDbl &delta, HelmholtzDerivatives &derivs) throw()
38{
39 double log_tau = log(tau), log_delta = log(delta),
40 one_over_delta = 1/delta, one_over_tau = 1/tau; // division is much slower than multiplication, so do one division here
41
42 Eigen::Map<Eigen::ArrayXd> nE(&(n[0]), elements.size());
43 Eigen::Map<Eigen::ArrayXd> dE(&(d[0]), elements.size());
44 Eigen::Map<Eigen::ArrayXd> tE(&(t[0]), elements.size());
45 Eigen::Map<Eigen::ArrayXd> cE(&(c[0]), elements.size());
46 Eigen::Map<Eigen::ArrayXi> l_intE(&(l_int[0]), elements.size());
47 Eigen::Map<Eigen::ArrayXd> l_doubleE(&(l_double[0]), elements.size());
48 Eigen::Map<Eigen::ArrayXd> eta1E(&(eta1[0]), elements.size());
49 Eigen::Map<Eigen::ArrayXd> eta2E(&(eta2[0]), elements.size());
50 Eigen::Map<Eigen::ArrayXd> epsilon1E(&(epsilon1[0]), elements.size());
51 Eigen::Map<Eigen::ArrayXd> epsilon2E(&(epsilon2[0]), elements.size());
52 Eigen::Map<Eigen::ArrayXd> beta1E(&(beta1[0]), elements.size());
53 Eigen::Map<Eigen::ArrayXd> beta2E(&(beta2[0]), elements.size());
54 Eigen::Map<Eigen::ArrayXd> gamma1E(&(gamma1[0]), elements.size());
55 Eigen::Map<Eigen::ArrayXd> gamma2E(&(gamma2[0]), elements.size());
56
57 // ****************************************
58 // The u part in exp(u) and its derivatives
59 // ****************************************
60
61 #if defined(EIGEN_VECTORIZE_SSE2)
62 //std::cout << "EIGEN_VECTORIZE_SSE2" << std::endl;
63 #endif
64
65 // Set the u part of exp(u) to zero
66 uE.fill(0);
67 du_ddeltaE.fill(0);
68 du_dtauE.fill(0);
69 d2u_ddelta2E.fill(0);
70 d2u_dtau2E.fill(0);
71 d3u_ddelta3E.fill(0);
72 d3u_dtau3E.fill(0);
73
74 if (delta_li_in_u){
75 Eigen::ArrayXd u_increment = -cE*(log_delta*l_doubleE).exp(); //pow(delta,L) -> exp(L*log(delta))
76 uE += u_increment;
77 du_ddeltaE += l_doubleE*u_increment*one_over_delta;
78 d2u_ddelta2E += (l_doubleE-1)*l_doubleE*u_increment*one_over_delta*one_over_delta;
79 d3u_ddelta3E += (l_doubleE-2)*(l_doubleE-1)*l_doubleE*u_increment*one_over_delta*one_over_delta*one_over_delta;
80 }
81
82// if (tau_mi_in_u){
83// CoolPropDbl omegai = el.omega, m_double = el.m_double;
84// if (std::abs(m_double) > 0){
85// CoolPropDbl u_increment = -omegai*pow(tau, m_double);
86// CoolPropDbl du_dtau_increment = m_double*u_increment*one_over_tau;
87// CoolPropDbl d2u_dtau2_increment = (m_double-1)*du_dtau_increment*one_over_tau;
88// CoolPropDbl d3u_dtau3_increment = (m_double-2)*d2u_dtau2_increment*one_over_tau;
89// u += u_increment;
90// du_dtau += du_dtau_increment;
91// d2u_dtau2 += d2u_dtau2_increment;
92// d3u_dtau3 += d3u_dtau3_increment;
93// }
94// }
95 if (eta1_in_u){
96 uE += -eta1E*(delta-epsilon1E);
97 du_ddeltaE += -eta1E;
98 }
99 if (eta2_in_u){
100 uE += -eta2E*POW2(delta-epsilon2E);
101 du_ddeltaE += -2*eta2E*(delta-epsilon2E);
102 d2u_ddelta2E += -2*eta2E;
103 }
104 if (beta1_in_u){
105 uE += -beta1E*(tau-gamma1E);
106 du_dtauE += -beta1E;
107 }
108 if (beta2_in_u){
109 uE += -beta2E*POW2(tau-gamma2E);
110 du_dtauE += -2*beta2E*(tau-gamma2E);
111 d2u_dtau2E += -2*beta2E;
112 }
113
114 Eigen::ArrayXd ndteuE = nE*exp(tE*log_tau + dE*log_delta + uE);
115 Eigen::ArrayXd B_deltaE = delta*du_ddeltaE + dE;
116 Eigen::ArrayXd B_tauE = tau*du_dtauE + tE;
117 Eigen::ArrayXd B_delta2E = POW2(delta)*(d2u_ddelta2E + du_ddeltaE.square()) + 2*dE*delta*du_ddeltaE + dE*(dE-1);
118 Eigen::ArrayXd B_tau2E = POW2(tau)*(d2u_dtau2E + du_dtauE.square()) + 2*tE*tau*du_dtauE + tE*(tE-1);
119 Eigen::ArrayXd B_delta3E = POW3(delta)*d3u_ddelta3E + 3*dE*POW2(delta)*d2u_ddelta2E+3*POW3(delta)*d2u_ddelta2E*du_ddeltaE+3*dE*POW2(delta*du_ddeltaE)+3*dE*(dE-1)*delta*du_ddeltaE+dE*(dE-1)*(dE-2)+POW3(delta*du_ddeltaE);
120 Eigen::ArrayXd B_tau3E = POW3(tau)*d3u_dtau3E + 3*tE*POW2(tau)*d2u_dtau2E+3*POW3(tau)*d2u_dtau2E*du_dtauE+3*tE*POW2(tau*du_dtauE)+3*tE*(tE-1)*tau*du_dtauE+tE*(tE-1)*(tE-2)+POW3(tau*du_dtauE);
121
122 derivs.alphar += ndteuE.sum();
123 derivs.dalphar_ddelta += (ndteuE*B_deltaE).sum()*one_over_delta;
124 derivs.dalphar_dtau += (ndteuE*B_tauE).sum()*one_over_tau;
125 derivs.d2alphar_ddelta2 += (ndteuE*B_delta2E).sum()*POW2(one_over_delta);
126 derivs.d2alphar_dtau2 += (ndteuE*B_tau2E).sum()*POW2(one_over_tau);
127 derivs.d2alphar_ddelta_dtau += (ndteuE*B_deltaE*B_tauE).sum()*one_over_delta*one_over_tau;
128
129 derivs.d3alphar_ddelta3 += (ndteuE*B_delta3E).sum()*POW3(one_over_delta);
130 derivs.d3alphar_dtau3 += (ndteuE*B_tau3E).sum()*POW3(one_over_tau);
131 derivs.d3alphar_ddelta2_dtau += (ndteuE*B_delta2E*B_tauE).sum()*POW2(one_over_delta)*one_over_tau;
132 derivs.d3alphar_ddelta_dtau2 += (ndteuE*B_deltaE*B_tau2E).sum()*one_over_delta*POW2(one_over_tau);
133
134 return;
135};
136*/
138 CoolPropDbl log_tau = log(tau), log_delta = log(delta), ndteu, one_over_delta = 1 / delta,
139 one_over_tau = 1 / tau; // division is much slower than multiplication, so do one division here
140
141 // Maybe split the construction of u and other parts into two separate loops?
142 // If both loops can get vectorized, could be worth it.
143 const std::size_t N = elements.size();
144 for (std::size_t i = 0; i < N; ++i) {
146 CoolPropDbl ni = el.n, di = el.d, ti = el.t;
147
148 // Set the u part of exp(u) to zero
149 CoolPropDbl u = 0;
150 CoolPropDbl du_ddelta = 0;
151 CoolPropDbl du_dtau = 0;
152 CoolPropDbl d2u_ddelta2 = 0;
153 CoolPropDbl d2u_dtau2 = 0;
154 CoolPropDbl d3u_ddelta3 = 0;
155 CoolPropDbl d3u_dtau3 = 0;
156 CoolPropDbl d4u_ddelta4 = 0;
157 CoolPropDbl d4u_dtau4 = 0;
158
159 if (delta_li_in_u) {
160 CoolPropDbl ci = el.c, l_double = el.l_double;
161 if (ValidNumber(l_double) && l_double > 0 && std::abs(ci) > DBL_EPSILON) {
162 const CoolPropDbl u_increment = (el.l_is_int) ? -ci * powInt(delta, el.l_int) : -ci * pow(delta, l_double);
163 const CoolPropDbl du_ddelta_increment = l_double * u_increment * one_over_delta;
164 const CoolPropDbl d2u_ddelta2_increment = (l_double - 1) * du_ddelta_increment * one_over_delta;
165 const CoolPropDbl d3u_ddelta3_increment = (l_double - 2) * d2u_ddelta2_increment * one_over_delta;
166 const CoolPropDbl d4u_ddelta4_increment = (l_double - 3) * d3u_ddelta3_increment * one_over_delta;
167 u += u_increment;
168 du_ddelta += du_ddelta_increment;
169 d2u_ddelta2 += d2u_ddelta2_increment;
170 d3u_ddelta3 += d3u_ddelta3_increment;
171 d4u_ddelta4 += d4u_ddelta4_increment;
172 }
173 }
174 if (tau_mi_in_u) {
175 CoolPropDbl omegai = el.omega, m_double = el.m_double;
176 if (std::abs(m_double) > 0) {
177 const CoolPropDbl u_increment = -omegai * pow(tau, m_double);
178 const CoolPropDbl du_dtau_increment = m_double * u_increment * one_over_tau;
179 const CoolPropDbl d2u_dtau2_increment = (m_double - 1) * du_dtau_increment * one_over_tau;
180 const CoolPropDbl d3u_dtau3_increment = (m_double - 2) * d2u_dtau2_increment * one_over_tau;
181 const CoolPropDbl d4u_dtau4_increment = (m_double - 3) * d3u_dtau3_increment * one_over_tau;
182 u += u_increment;
183 du_dtau += du_dtau_increment;
184 d2u_dtau2 += d2u_dtau2_increment;
185 d3u_dtau3 += d3u_dtau3_increment;
186 d4u_dtau4 += d4u_dtau4_increment;
187 }
188 }
189 if (eta1_in_u) {
191 if (ValidNumber(eta1)) {
192 u += -eta1 * (delta - epsilon1);
193 du_ddelta += -eta1;
194 }
195 }
196 if (eta2_in_u) {
198 if (ValidNumber(eta2)) {
199 u += -eta2 * POW2(delta - epsilon2);
200 du_ddelta += -2 * eta2 * (delta - epsilon2);
201 d2u_ddelta2 += -2 * eta2;
202 }
203 }
204 if (beta1_in_u) {
206 if (ValidNumber(beta1)) {
207 u += -beta1 * (tau - gamma1);
208 du_dtau += -beta1;
209 }
210 }
211 if (beta2_in_u) {
213 if (ValidNumber(beta2)) {
214 u += -beta2 * POW2(tau - gamma2);
215 du_dtau += -2 * beta2 * (tau - gamma2);
216 d2u_dtau2 += -2 * beta2;
217 }
218 }
219
220 ndteu = ni * exp(ti * log_tau + di * log_delta + u);
221
222 const CoolPropDbl dB_delta_ddelta = delta * d2u_ddelta2 + du_ddelta;
223 const CoolPropDbl d2B_delta_ddelta2 = delta * d3u_ddelta3 + 2 * d2u_ddelta2;
224 const CoolPropDbl d3B_delta_ddelta3 = delta * d4u_ddelta4 + 3 * d3u_ddelta3;
225
226 const CoolPropDbl B_delta = (delta * du_ddelta + di);
227 const CoolPropDbl B_delta2 = delta * dB_delta_ddelta + (B_delta - 1) * B_delta;
228 const CoolPropDbl dB_delta2_ddelta = delta * d2B_delta_ddelta2 + 2 * B_delta * dB_delta_ddelta;
229 const CoolPropDbl B_delta3 = delta * dB_delta2_ddelta + (B_delta - 2) * B_delta2;
230 const CoolPropDbl dB_delta3_ddelta = delta * delta * d3B_delta_ddelta3 + 3 * delta * B_delta * d2B_delta_ddelta2
231 + 3 * delta * POW2(dB_delta_ddelta) + 3 * B_delta * (B_delta - 1) * dB_delta_ddelta;
232 const CoolPropDbl B_delta4 = delta * dB_delta3_ddelta + (B_delta - 3) * B_delta3;
233
234 const CoolPropDbl dB_tau_dtau = tau * d2u_dtau2 + du_dtau;
235 const CoolPropDbl d2B_tau_dtau2 = tau * d3u_dtau3 + 2 * d2u_dtau2;
236 const CoolPropDbl d3B_tau_dtau3 = tau * d4u_dtau4 + 3 * d3u_dtau3;
237
238 const CoolPropDbl B_tau = (tau * du_dtau + ti);
239 const CoolPropDbl B_tau2 = tau * dB_tau_dtau + (B_tau - 1) * B_tau;
240 const CoolPropDbl dB_tau2_dtau = tau * d2B_tau_dtau2 + 2 * B_tau * dB_tau_dtau;
241 const CoolPropDbl B_tau3 = tau * dB_tau2_dtau + (B_tau - 2) * B_tau2;
242 const CoolPropDbl dB_tau3_dtau =
243 tau * tau * d3B_tau_dtau3 + 3 * tau * B_tau * d2B_tau_dtau2 + 3 * tau * POW2(dB_tau_dtau) + 3 * B_tau * (B_tau - 1) * dB_tau_dtau;
244 const CoolPropDbl B_tau4 = tau * dB_tau3_dtau + (B_tau - 3) * B_tau3;
245
246 derivs.alphar += ndteu;
247
248 derivs.dalphar_ddelta += ndteu * B_delta;
249 derivs.dalphar_dtau += ndteu * B_tau;
250
251 derivs.d2alphar_ddelta2 += ndteu * B_delta2;
252 derivs.d2alphar_ddelta_dtau += ndteu * B_delta * B_tau;
253 derivs.d2alphar_dtau2 += ndteu * B_tau2;
254
255 derivs.d3alphar_ddelta3 += ndteu * B_delta3;
256 derivs.d3alphar_ddelta2_dtau += ndteu * B_delta2 * B_tau;
257 derivs.d3alphar_ddelta_dtau2 += ndteu * B_delta * B_tau2;
258 derivs.d3alphar_dtau3 += ndteu * B_tau3;
259
260 derivs.d4alphar_ddelta4 += ndteu * B_delta4;
261 derivs.d4alphar_ddelta3_dtau += ndteu * B_delta3 * B_tau;
262 derivs.d4alphar_ddelta2_dtau2 += ndteu * B_delta2 * B_tau2;
263 derivs.d4alphar_ddelta_dtau3 += ndteu * B_delta * B_tau3;
264 derivs.d4alphar_dtau4 += ndteu * B_tau4;
265 }
266 derivs.dalphar_ddelta *= one_over_delta;
267 derivs.dalphar_dtau *= one_over_tau;
268 derivs.d2alphar_ddelta2 *= POW2(one_over_delta);
269 derivs.d2alphar_dtau2 *= POW2(one_over_tau);
270 derivs.d2alphar_ddelta_dtau *= one_over_delta * one_over_tau;
271
272 derivs.d3alphar_ddelta3 *= POW3(one_over_delta);
273 derivs.d3alphar_dtau3 *= POW3(one_over_tau);
274 derivs.d3alphar_ddelta2_dtau *= POW2(one_over_delta) * one_over_tau;
275 derivs.d3alphar_ddelta_dtau2 *= one_over_delta * POW2(one_over_tau);
276
277 derivs.d4alphar_ddelta4 *= POW4(one_over_delta);
278 derivs.d4alphar_dtau4 *= POW4(one_over_tau);
279 derivs.d4alphar_ddelta3_dtau *= POW3(one_over_delta) * one_over_tau;
280 derivs.d4alphar_ddelta2_dtau2 *= POW2(one_over_delta) * POW2(one_over_tau);
281 derivs.d4alphar_ddelta_dtau3 *= one_over_delta * POW3(one_over_tau);
282
283 return;
284};
285
286#if ENABLE_CATCH
287mcx::MultiComplex<double> ResidualHelmholtzGeneralizedExponential::one_mcx(const mcx::MultiComplex<double>& tau,
288 const mcx::MultiComplex<double>& delta) const {
289 //throw CoolProp::NotImplementedError("Nope");
290 mcx::MultiComplex<double> sum00 = 0.0 * tau * delta;
291 auto ln_tau = log(tau);
292 auto ln_delta = log(delta);
293 const std::size_t N = elements.size();
294 for (std::size_t i = 0; i < N; ++i) {
296
297 mcx::MultiComplex<double> u = 0.0 * tau * delta;
298 if (delta_li_in_u) {
299 CoolPropDbl ci = el.c, l_double = el.l_double;
300 if (ValidNumber(l_double) && l_double > 0 && std::abs(ci) > DBL_EPSILON) {
301 const auto u_increment = -ci * pow(delta, l_double);
302 u += u_increment;
303 }
304 }
305 if (tau_mi_in_u) {
306 CoolPropDbl omegai = el.omega, m_double = el.m_double;
307 if (std::abs(m_double) > 0) {
308 const auto u_increment = -omegai * pow(tau, m_double);
309 u += u_increment;
310 }
311 }
312 if (eta1_in_u) {
314 if (ValidNumber(eta1)) {
315 u += -eta1 * (delta - epsilon1);
316 }
317 }
318 if (eta2_in_u) {
320 if (ValidNumber(eta2)) {
321 u += -eta2 * POW2(delta - epsilon2);
322 }
323 }
324 if (beta1_in_u) {
326 if (ValidNumber(beta1)) {
327 u += -beta1 * (tau - gamma1);
328 }
329 }
330 if (beta2_in_u) {
332 if (ValidNumber(beta2)) {
333 u += -beta2 * POW2(tau - gamma2);
334 }
335 }
336 sum00 += el.n * exp(el.t * ln_tau + el.d * ln_delta + u);
337 }
338 return sum00;
339}
340#endif
341
342void ResidualHelmholtzGeneralizedExponential::to_json(rapidjson::Value& el, rapidjson::Document& doc) {
343 el.AddMember("type", "GeneralizedExponential", doc.GetAllocator());
344 cpjson::set_double_array("n", n, el, doc);
345 cpjson::set_double_array("t", t, el, doc);
346 cpjson::set_double_array("d", d, el, doc);
347 cpjson::set_double_array("eta1", eta1, el, doc);
348 cpjson::set_double_array("eta2", eta2, el, doc);
349 cpjson::set_double_array("beta1", beta1, el, doc);
350 cpjson::set_double_array("beta2", beta2, el, doc);
351 cpjson::set_double_array("gamma1", gamma1, el, doc);
352 cpjson::set_double_array("gamma2", gamma2, el, doc);
353 cpjson::set_double_array("epsilon1", epsilon1, el, doc);
354 cpjson::set_double_array("epsilon2", epsilon2, el, doc);
355 cpjson::set_double_array("l_double", l_double, el, doc);
356 cpjson::set_int_array("l_int", l_int, el, doc);
357}
358
359void ResidualHelmholtzNonAnalytic::to_json(rapidjson::Value& el, rapidjson::Document& doc) {
360 el.AddMember("type", "ResidualHelmholtzNonAnalytic", doc.GetAllocator());
361
362 rapidjson::Value _n(rapidjson::kArrayType), _a(rapidjson::kArrayType), _b(rapidjson::kArrayType), _beta(rapidjson::kArrayType),
363 _A(rapidjson::kArrayType), _B(rapidjson::kArrayType), _C(rapidjson::kArrayType), _D(rapidjson::kArrayType);
364 for (unsigned int i = 0; i <= N; ++i) {
366 _n.PushBack((double)elem.n, doc.GetAllocator());
367 _a.PushBack((double)elem.a, doc.GetAllocator());
368 _b.PushBack((double)elem.b, doc.GetAllocator());
369 _beta.PushBack((double)elem.beta, doc.GetAllocator());
370 _A.PushBack((double)elem.A, doc.GetAllocator());
371 _B.PushBack((double)elem.B, doc.GetAllocator());
372 _C.PushBack((double)elem.C, doc.GetAllocator());
373 _D.PushBack((double)elem.D, doc.GetAllocator());
374 }
375 el.AddMember("n", _n, doc.GetAllocator());
376 el.AddMember("a", _a, doc.GetAllocator());
377 el.AddMember("b", _b, doc.GetAllocator());
378 el.AddMember("beta", _beta, doc.GetAllocator());
379 el.AddMember("A", _A, doc.GetAllocator());
380 el.AddMember("B", _B, doc.GetAllocator());
381 el.AddMember("C", _C, doc.GetAllocator());
382 el.AddMember("D", _D, doc.GetAllocator());
383}
384
386 if (N == 0) {
387 return;
388 }
389
390 // Here we want to hack this function just a tiny bit to avoid evaluation AT the critical point
391 // If we are VERY close to the critical point, just offset us a tiny bit away
392 CoolPropDbl tau = tau_in, delta = delta_in;
393 if (std::abs(tau_in - 1) < 10 * DBL_EPSILON) {
394 tau = 1.0 + 10 * DBL_EPSILON;
395 }
396 if (std::abs(delta_in - 1) < 10 * DBL_EPSILON) {
397 delta = 1.0 + 10 * DBL_EPSILON;
398 }
399
400 for (unsigned int i = 0; i < N; ++i) {
402 const CoolPropDbl ni = el.n, ai = el.a, bi = el.b, betai = el.beta;
403 const CoolPropDbl Ai = el.A, Bi = el.B, Ci = el.C, Di = el.D;
404
405 // Derivatives of theta (all others are zero) (OK - checked)
406 // Do not factor because then when delta = 1 you are dividing by 0
407 const CoolPropDbl theta = (1.0 - tau) + Ai * pow(POW2(delta - 1.0), 1.0 / (2.0 * betai));
408 const CoolPropDbl dtheta_dTau = -1;
409 const CoolPropDbl dtheta_dDelta = Ai / (betai)*pow(POW2(delta - 1), 1 / (2 * betai) - 1) * (delta - 1);
410
411 const CoolPropDbl d2theta_dDelta2 = Ai / betai * (1 / betai - 1) * pow(POW2(delta - 1), 1 / (2 * betai) - 1);
412 const CoolPropDbl d3theta_dDelta3 = Ai / betai * (2 - 3 / betai + 1 / POW2(betai)) * pow(POW2(delta - 1), 1 / (2 * betai)) / POW3(delta - 1);
413 const CoolPropDbl d4theta_dDelta4 =
414 Ai / betai * (-6 + 11 / betai - 6 / POW2(betai) + 1 / POW3(betai)) * pow(POW2(delta - 1), 1 / (2 * betai) - 2);
415
416 // Derivatives of PSI (OK - checked)
417 const CoolPropDbl PSI = exp(-Ci * POW2(delta - 1.0) - Di * POW2(tau - 1.0));
418 const CoolPropDbl dPSI_dDelta_over_PSI = -2.0 * Ci * (delta - 1.0);
419 const CoolPropDbl dPSI_dDelta = dPSI_dDelta_over_PSI * PSI;
420 const CoolPropDbl dPSI_dTau_over_PSI = -2.0 * Di * (tau - 1.0);
421 const CoolPropDbl dPSI_dTau = dPSI_dTau_over_PSI * PSI;
422 const CoolPropDbl d2PSI_dDelta2_over_PSI = (2.0 * Ci * POW2(delta - 1.0) - 1.0) * 2.0 * Ci;
423 const CoolPropDbl d2PSI_dDelta2 = d2PSI_dDelta2_over_PSI * PSI;
424 const CoolPropDbl d3PSI_dDelta3 = 2 * Ci * PSI * (-4 * Ci * Ci * POW3(delta - 1) + 6 * Ci * (delta - 1));
425 const CoolPropDbl d4PSI_dDelta4 = 4 * Ci * Ci * PSI * (4 * Ci * Ci * POW4(delta - 1) - 12 * Ci * POW2(delta - 1) + 3);
426 const CoolPropDbl d2PSI_dTau2 = (2.0 * Di * POW2(tau - 1.0) - 1.0) * 2.0 * Di * PSI;
427 const CoolPropDbl d3PSI_dTau3 = 2.0 * Di * PSI * (-4 * Di * Di * POW3(tau - 1) + 6 * Di * (tau - 1));
428 const CoolPropDbl d4PSI_dTau4 = 4 * Di * Di * PSI * (4 * Di * Di * POW4(tau - 1) - 12 * Di * POW2(tau - 1) + 3);
429 const CoolPropDbl d2PSI_dDelta_dTau = dPSI_dDelta * dPSI_dTau_over_PSI;
430 const CoolPropDbl d3PSI_dDelta2_dTau = d2PSI_dDelta2 * dPSI_dTau_over_PSI;
431 const CoolPropDbl d3PSI_dDelta_dTau2 = d2PSI_dTau2 * dPSI_dDelta_over_PSI;
432 const CoolPropDbl d4PSI_dDelta_dTau3 = d3PSI_dTau3 * dPSI_dDelta_over_PSI;
433 const CoolPropDbl d4PSI_dDelta2_dTau2 = d2PSI_dTau2 * d2PSI_dDelta2_over_PSI;
434 const CoolPropDbl d4PSI_dDelta3_dTau = d3PSI_dDelta3 * dPSI_dTau_over_PSI;
435
436 // Derivatives of DELTA (OK - Checked)
437 const CoolPropDbl DELTA = POW2(theta) + Bi * pow(POW2(delta - 1.0), ai);
438 const CoolPropDbl dDELTA_dTau = 2 * theta * dtheta_dTau;
439 const CoolPropDbl dDELTA_dDelta = 2 * theta * dtheta_dDelta + 2 * Bi * ai * pow(POW2(delta - 1.0), ai - 1.0) * (delta - 1);
440 const CoolPropDbl d2DELTA_dTau2 = 2; // d2theta_dTau2 is zero and (dtheta_dtau)^2 = 1
441 const CoolPropDbl d2DELTA_dDelta_dTau = 2 * dtheta_dTau * dtheta_dDelta; // d2theta_dDelta2 is zero
442 const CoolPropDbl d2DELTA_dDelta2 =
443 2 * (theta * d2theta_dDelta2 + POW2(dtheta_dDelta) + Bi * (2 * ai * ai - ai) * pow(POW2(delta - 1.0), ai - 1.0));
444 const CoolPropDbl d3DELTA_dTau3 = 0;
445 const CoolPropDbl d3DELTA_dDelta_dTau2 = 0;
446 const CoolPropDbl d3DELTA_dDelta2_dTau = 2 * dtheta_dTau * d2theta_dDelta2;
447 const CoolPropDbl d3DELTA_dDelta3 = 2
448 * (theta * d3theta_dDelta3 + 3 * dtheta_dDelta * d2theta_dDelta2
449 + 2 * Bi * ai * (2 * ai * ai - 3 * ai + 1) * pow(POW2(delta - 1.0), ai - 1.0) / (delta - 1));
450
451 const CoolPropDbl d4DELTA_dTau4 = 0;
452 const CoolPropDbl d4DELTA_dDelta_dTau3 = 0;
453 const CoolPropDbl d4DELTA_dDelta2_dTau2 = 0;
454 const CoolPropDbl d4DELTA_dDelta3_dTau = 2 * dtheta_dTau * d3theta_dDelta3;
455 const CoolPropDbl d4DELTA_dDelta4 = 2
456 * (theta * d4theta_dDelta4 + 4 * dtheta_dDelta * d3theta_dDelta3 + 3 * POW2(d2theta_dDelta2)
457 + 2 * Bi * ai * (4 * ai * ai * ai - 12 * ai * ai + 11 * ai - 3) * pow(POW2(delta - 1.0), ai - 2.0));
458
459 const CoolPropDbl dDELTAbi_dDelta = bi * pow(DELTA, bi - 1.0) * dDELTA_dDelta;
460 const CoolPropDbl dDELTAbi_dTau = -2.0 * theta * bi * pow(DELTA, bi - 1.0);
461 const CoolPropDbl d2DELTAbi_dDelta2 = bi * (pow(DELTA, bi - 1) * d2DELTA_dDelta2 + (bi - 1.0) * pow(DELTA, bi - 2.0) * pow(dDELTA_dDelta, 2));
462 const CoolPropDbl d3DELTAbi_dDelta3 =
463 bi
464 * (pow(DELTA, bi - 1) * d3DELTA_dDelta3 + d2DELTA_dDelta2 * (bi - 1) * pow(DELTA, bi - 2) * dDELTA_dDelta
465 + (bi - 1)
466 * (pow(DELTA, bi - 2) * 2 * dDELTA_dDelta * d2DELTA_dDelta2
467 + pow(dDELTA_dDelta, 2) * (bi - 2) * pow(DELTA, bi - 3) * dDELTA_dDelta));
468 const CoolPropDbl d2DELTAbi_dDelta_dTau =
469 -Ai * bi * 2.0 / betai * pow(DELTA, bi - 1.0) * (delta - 1.0) * pow(pow(delta - 1.0, 2), 1.0 / (2.0 * betai) - 1.0)
470 - 2.0 * theta * bi * (bi - 1.0) * pow(DELTA, bi - 2.0) * dDELTA_dDelta;
471 const CoolPropDbl d2DELTAbi_dTau2 = 2.0 * bi * pow(DELTA, bi - 1.0) + 4.0 * pow(theta, 2) * bi * (bi - 1.0) * pow(DELTA, bi - 2.0);
472 const CoolPropDbl d3DELTAbi_dTau3 =
473 -12.0 * theta * bi * (bi - 1.0) * pow(DELTA, bi - 2) - 8 * pow(theta, 3) * bi * (bi - 1) * (bi - 2) * pow(DELTA, bi - 3);
474 const CoolPropDbl d3DELTAbi_dDelta_dTau2 = 2 * bi * (bi - 1) * pow(DELTA, bi - 2) * dDELTA_dDelta
475 + 4 * pow(theta, 2) * bi * (bi - 1) * (bi - 2) * pow(DELTA, bi - 3) * dDELTA_dDelta
476 + 8 * theta * bi * (bi - 1) * pow(DELTA, bi - 2) * dtheta_dDelta;
477 const CoolPropDbl d3DELTAbi_dDelta2_dTau =
478 bi
479 * ((bi - 1) * pow(DELTA, bi - 2) * dDELTA_dTau * d2DELTA_dDelta2 + pow(DELTA, bi - 1) * d3DELTA_dDelta2_dTau
480 + (bi - 1)
481 * ((bi - 2) * pow(DELTA, bi - 3) * dDELTA_dTau * pow(dDELTA_dDelta, 2)
482 + pow(DELTA, bi - 2) * 2 * dDELTA_dDelta * d2DELTA_dDelta_dTau));
483
484 // Fourth partials
485 const CoolPropDbl DELTA_bi = pow(DELTA, bi);
486 const CoolPropDbl d4DELTAbi_dTau4 =
487 bi * DELTA_bi / DELTA
488 * ((POW3(bi) - 6 * POW2(bi) + 11 * bi - 6) * POW4(dDELTA_dTau) / POW3(DELTA)
489 + 6 * (bi * bi - 3 * bi + 2) * POW2(dDELTA_dTau / DELTA) * d2DELTA_dTau2 + 4 * (bi - 1) * dDELTA_dTau / DELTA * d3DELTA_dTau3
490 + 3 * (bi - 1) * POW2(d2DELTA_dTau2) / DELTA + d4DELTA_dTau4);
491 const CoolPropDbl d4DELTAbi_dDelta4 =
492 bi * DELTA_bi / DELTA
493 * ((POW3(bi) - 6 * POW2(bi) + 11 * bi - 6) * POW4(dDELTA_dDelta) / POW3(DELTA)
494 + 6 * (bi * bi - 3 * bi + 2) * POW2(dDELTA_dDelta / DELTA) * d2DELTA_dDelta2 + 4 * (bi - 1) * dDELTA_dDelta / DELTA * d3DELTA_dDelta3
495 + 3 * (bi - 1) * POW2(d2DELTA_dDelta2) / DELTA + d4DELTA_dDelta4);
496 const CoolPropDbl d4DELTAbi_dDelta_dTau3 =
497 bi * (bi - 1) * DELTA_bi / POW2(DELTA) * dDELTA_dDelta
498 * ((bi - 1) * (bi - 2) * POW3(dDELTA_dTau) / POW2(DELTA) + 3 * (bi - 1) * dDELTA_dTau / DELTA * d2DELTA_dTau2 + d3DELTA_dTau3)
499 + bi * DELTA_bi / DELTA
500 * ((bi - 1) * (bi - 2)
501 * (3 * POW2(dDELTA_dTau) / POW2(DELTA) * d2DELTA_dDelta_dTau - 2 * POW3(dDELTA_dTau) / POW3(DELTA) * dDELTA_dDelta)
502 + 3 * (bi - 1)
503 * (dDELTA_dTau / DELTA * d3DELTA_dDelta_dTau2 + d2DELTA_dTau2 / DELTA * d2DELTA_dDelta_dTau
504 - dDELTA_dDelta / POW2(DELTA) * dDELTA_dTau * d2DELTA_dTau2)
505 + d4DELTA_dDelta_dTau3);
506 const CoolPropDbl d4DELTAbi_dDelta3_dTau =
507 bi * (bi - 1) * DELTA_bi / POW2(DELTA) * dDELTA_dTau
508 * ((bi - 1) * (bi - 2) * POW3(dDELTA_dDelta) / POW2(DELTA) + 3 * (bi - 1) * dDELTA_dDelta / DELTA * d2DELTA_dDelta2 + d3DELTA_dDelta3)
509 + bi * DELTA_bi / DELTA
510 * ((bi - 1) * (bi - 2)
511 * (3 * POW2(dDELTA_dDelta) / POW2(DELTA) * d2DELTA_dDelta_dTau - 2 * POW3(dDELTA_dDelta) / POW3(DELTA) * dDELTA_dTau)
512 + 3 * (bi - 1)
513 * (dDELTA_dDelta / DELTA * d3DELTA_dDelta2_dTau + d2DELTA_dDelta2 / DELTA * d2DELTA_dDelta_dTau
514 - dDELTA_dTau / POW2(DELTA) * dDELTA_dDelta * d2DELTA_dDelta2)
515 + d4DELTA_dDelta3_dTau);
516 const CoolPropDbl d4DELTAbi_dDelta2_dTau2 = bi * DELTA_bi / POW4(DELTA)
517 * ((POW3(bi) - 6 * bi * bi + 11 * bi - 6) * POW2(dDELTA_dDelta) * POW2(dDELTA_dTau) // Yellow
518 + (bi - 1) * (bi - 2) * DELTA * POW2(dDELTA_dDelta) * d2DELTA_dTau2 // Orange
519 + (bi - 1) * (bi - 2) * DELTA * POW2(dDELTA_dTau) * d2DELTA_dDelta2 // Pink
520 + 4 * (bi - 1) * (bi - 2) * DELTA * dDELTA_dDelta * dDELTA_dTau * d2DELTA_dDelta_dTau // Green
521 + 2 * (bi - 1) * POW2(DELTA * d2DELTA_dDelta_dTau) // Blue hi
522 + 2 * (bi - 1) * POW2(DELTA) * dDELTA_dTau * d3DELTA_dDelta2_dTau // Blue sharp
523 + 2 * (bi - 1) * POW2(DELTA) * dDELTA_dDelta * d3DELTA_dDelta_dTau2 // Red sharp
524 + (bi - 1) * POW2(DELTA) * d2DELTA_dDelta2 * d2DELTA_dTau2 // black sharp
525 + POW3(DELTA) * d4DELTA_dDelta2_dTau2);
526
527 derivs.alphar += delta * ni * DELTA_bi * PSI;
528
529 // First partials
530 derivs.dalphar_dtau += ni * delta * (DELTA_bi * dPSI_dTau + dDELTAbi_dTau * PSI);
531 derivs.dalphar_ddelta += ni * (DELTA_bi * (PSI + delta * dPSI_dDelta) + dDELTAbi_dDelta * delta * PSI);
532
533 // Second partials
534 derivs.d2alphar_dtau2 += ni * delta * (d2DELTAbi_dTau2 * PSI + 2 * dDELTAbi_dTau * dPSI_dTau + DELTA_bi * d2PSI_dTau2);
535 derivs.d2alphar_ddelta_dtau += ni
536 * (DELTA_bi * (dPSI_dTau + delta * d2PSI_dDelta_dTau) + delta * dDELTAbi_dDelta * dPSI_dTau
537 + dDELTAbi_dTau * (PSI + delta * dPSI_dDelta) + d2DELTAbi_dDelta_dTau * delta * PSI);
538 derivs.d2alphar_ddelta2 += ni
539 * (DELTA_bi * (2.0 * dPSI_dDelta + delta * d2PSI_dDelta2) + 2.0 * dDELTAbi_dDelta * (PSI + delta * dPSI_dDelta)
540 + d2DELTAbi_dDelta2 * delta * PSI);
541
542 // Third partials
543 derivs.d3alphar_dtau3 +=
544 ni * delta * (d3DELTAbi_dTau3 * PSI + 3 * d2DELTAbi_dTau2 * dPSI_dTau + 3 * dDELTAbi_dTau * d2PSI_dTau2 + DELTA_bi * d3PSI_dTau3);
545 derivs.d3alphar_ddelta_dtau2 +=
546 ni * delta
547 * (d2DELTAbi_dTau2 * dPSI_dDelta + d3DELTAbi_dDelta_dTau2 * PSI + 2 * dDELTAbi_dTau * d2PSI_dDelta_dTau
548 + 2.0 * d2DELTAbi_dDelta_dTau * dPSI_dTau + DELTA_bi * d3PSI_dDelta_dTau2 + dDELTAbi_dDelta * d2PSI_dTau2)
549 + ni * (d2DELTAbi_dTau2 * PSI + 2.0 * dDELTAbi_dTau * dPSI_dTau + DELTA_bi * d2PSI_dTau2);
550 derivs.d3alphar_ddelta3 +=
551 ni
552 * (DELTA_bi * (3 * d2PSI_dDelta2 + delta * d3PSI_dDelta3) + 3 * dDELTAbi_dDelta * (2 * dPSI_dDelta + delta * d2PSI_dDelta2)
553 + 3 * d2DELTAbi_dDelta2 * (PSI + delta * dPSI_dDelta) + d3DELTAbi_dDelta3 * PSI * delta);
554 CoolPropDbl Line1 =
555 DELTA_bi * (2 * d2PSI_dDelta_dTau + delta * d3PSI_dDelta2_dTau) + dDELTAbi_dTau * (2 * dPSI_dDelta + delta * d2PSI_dDelta2);
556 CoolPropDbl Line2 = 2 * dDELTAbi_dDelta * (dPSI_dTau + delta * d2PSI_dDelta_dTau) + 2 * d2DELTAbi_dDelta_dTau * (PSI + delta * dPSI_dDelta);
557 CoolPropDbl Line3 = d2DELTAbi_dDelta2 * delta * dPSI_dTau + d3DELTAbi_dDelta2_dTau * delta * PSI;
558 derivs.d3alphar_ddelta2_dtau += ni * (Line1 + Line2 + Line3);
559
560 // Fourth partials
561 derivs.d4alphar_dtau4 += ni * delta
562 * (DELTA_bi * d4PSI_dTau4 + 4 * dDELTAbi_dTau * d3PSI_dTau3 + 6 * d2DELTAbi_dTau2 * d2PSI_dTau2
563 + 4 * d3DELTAbi_dTau3 * dPSI_dTau + PSI * d4DELTAbi_dTau4);
564 derivs.d4alphar_ddelta4 +=
565 ni
566 * (delta * DELTA_bi * d4PSI_dDelta4 + delta * PSI * d4DELTAbi_dDelta4 + 4 * delta * dDELTAbi_dDelta * d3PSI_dDelta3
567 + 4 * delta * dPSI_dDelta * d3DELTAbi_dDelta3 + 6 * delta * d2DELTAbi_dDelta2 * d2PSI_dDelta2 + 4 * DELTA_bi * d3PSI_dDelta3
568 + 4 * PSI * d3DELTAbi_dDelta3 + 12 * dDELTAbi_dDelta * d2PSI_dDelta2 + 12 * dPSI_dDelta * d2DELTAbi_dDelta2);
569
570 derivs.d4alphar_ddelta_dtau3 +=
571 ni
572 * (delta * DELTA_bi * d4PSI_dDelta_dTau3 + delta * PSI * d4DELTAbi_dDelta_dTau3 + delta * dDELTAbi_dDelta * d3PSI_dTau3
573 + 3 * delta * dDELTAbi_dTau * d3PSI_dDelta_dTau2 + delta * dPSI_dDelta * d3DELTAbi_dTau3 + 3 * delta * dPSI_dTau * d3DELTAbi_dDelta_dTau2
574 + 3 * delta * d2DELTAbi_dDelta_dTau * d2PSI_dTau2 + 3 * delta * d2DELTAbi_dTau2 * d2PSI_dDelta_dTau + DELTA_bi * d3PSI_dTau3
575 + PSI * d3DELTAbi_dTau3 + 3 * dDELTAbi_dTau * d2PSI_dTau2 + 3 * dPSI_dTau * d2DELTAbi_dTau2);
576 derivs.d4alphar_ddelta3_dtau +=
577 ni
578 * (delta * DELTA_bi * d4PSI_dDelta3_dTau + delta * PSI * d4DELTAbi_dDelta3_dTau + 3 * delta * dDELTAbi_dDelta * d3PSI_dDelta2_dTau
579 + delta * dDELTAbi_dTau * d3PSI_dDelta3 + 3 * delta * dPSI_dDelta * d3DELTAbi_dDelta2_dTau + delta * dPSI_dTau * d3DELTAbi_dDelta3
580 + 3 * delta * d2DELTAbi_dDelta2 * d2PSI_dDelta_dTau + 3 * delta * d2DELTAbi_dDelta_dTau * d2PSI_dDelta2
581 + 3 * DELTA_bi * d3PSI_dDelta2_dTau + 3 * PSI * d3DELTAbi_dDelta2_dTau + 6 * dDELTAbi_dDelta * d2PSI_dDelta_dTau
582 + 3 * dDELTAbi_dTau * d2PSI_dDelta2 + 6 * dPSI_dDelta * d2DELTAbi_dDelta_dTau + 3 * dPSI_dTau * d2DELTAbi_dDelta2);
583 derivs.d4alphar_ddelta2_dtau2 +=
584 ni
585 * (delta * DELTA_bi * d4PSI_dDelta2_dTau2 + delta * PSI * d4DELTAbi_dDelta2_dTau2 + 2 * delta * dDELTAbi_dDelta * d3PSI_dDelta_dTau2
586 + 2 * delta * dDELTAbi_dTau * d3PSI_dDelta2_dTau + 2 * delta * dPSI_dDelta * d3DELTAbi_dDelta_dTau2
587 + 2 * delta * dPSI_dTau * d3DELTAbi_dDelta2_dTau + delta * d2DELTAbi_dDelta2 * d2PSI_dTau2
588 + 4 * delta * d2DELTAbi_dDelta_dTau * d2PSI_dDelta_dTau + delta * d2DELTAbi_dTau2 * d2PSI_dDelta2 + 2 * DELTA_bi * d3PSI_dDelta_dTau2
589 + 2 * PSI * d3DELTAbi_dDelta_dTau2 + 2 * dDELTAbi_dDelta * d2PSI_dTau2 + 4 * dDELTAbi_dTau * d2PSI_dDelta_dTau
590 + 2 * dPSI_dDelta * d2DELTAbi_dTau2 + 4 * dPSI_dTau * d2DELTAbi_dDelta_dTau);
591 }
592}
593
594#if ENABLE_CATCH
595mcx::MultiComplex<double> ResidualHelmholtzNonAnalytic::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
596
597 mcx::MultiComplex<double> sum00 = 0.0 * tau * delta;
598 for (unsigned int i = 0; i < N; ++i) {
600 const CoolPropDbl ni = el.n, ai = el.a, bi = el.b, betai = el.beta;
601 const CoolPropDbl Ai = el.A, Bi = el.B, Ci = el.C, Di = el.D;
602
603 const auto theta = (1.0 - tau) + Ai * pow(POW2(delta - 1.0), 1.0 / (2.0 * betai));
604 const auto PSI = exp(-Ci * POW2(delta - 1.0) - Di * POW2(tau - 1.0));
605 const auto DELTA = POW2(theta) + Bi * pow(POW2(delta - 1.0), ai);
606 const auto DELTA_bi = pow(DELTA, bi);
607
608 sum00 += delta * ni * DELTA_bi * PSI;
609 }
610 return sum00;
611}
612#endif
613
615 if (!enabled) {
616 return;
617 }
618
619 derivs.alphar += m_abstractcubic->alphar(tau, delta, z, 0, 0);
620
621 derivs.dalphar_ddelta += m_abstractcubic->alphar(tau, delta, z, 0, 1);
622 derivs.dalphar_dtau += m_abstractcubic->alphar(tau, delta, z, 1, 0);
623
624 derivs.d2alphar_ddelta2 += m_abstractcubic->alphar(tau, delta, z, 0, 2);
625 derivs.d2alphar_ddelta_dtau += m_abstractcubic->alphar(tau, delta, z, 1, 1);
626 derivs.d2alphar_dtau2 += m_abstractcubic->alphar(tau, delta, z, 2, 0);
627
628 derivs.d3alphar_ddelta3 += m_abstractcubic->alphar(tau, delta, z, 0, 3);
629 derivs.d3alphar_ddelta2_dtau += m_abstractcubic->alphar(tau, delta, z, 1, 2);
630 derivs.d3alphar_ddelta_dtau2 += m_abstractcubic->alphar(tau, delta, z, 2, 1);
631 derivs.d3alphar_dtau3 += m_abstractcubic->alphar(tau, delta, z, 3, 0);
632
633 derivs.d4alphar_ddelta4 += m_abstractcubic->alphar(tau, delta, z, 0, 4);
634 derivs.d4alphar_ddelta3_dtau += m_abstractcubic->alphar(tau, delta, z, 1, 3);
635 derivs.d4alphar_ddelta2_dtau2 += m_abstractcubic->alphar(tau, delta, z, 2, 2);
636 derivs.d4alphar_ddelta_dtau3 += m_abstractcubic->alphar(tau, delta, z, 3, 1);
637 derivs.d4alphar_dtau4 += m_abstractcubic->alphar(tau, delta, z, 4, 0);
638}
639
665 if (!enabled) {
666 return;
667 }
668
669 CoolPropDbl Ftau = 0, Fdelta = 0, taudFtaudtau = 0, tau2d2Ftaudtau2 = 0, tau3d3Ftaudtau3 = 0, tau4d4Ftaudtau4 = 0, deltadFdeltaddelta = 0,
670 delta2d2Fdeltaddelta2 = 0, delta3d3Fdeltaddelta3 = 0, delta4d4Fdeltaddelta4 = 0;
671
672 for (int i = 0; i < static_cast<int>(n.size()); ++i) {
673
674 const CoolPropDbl n = this->n[i], t = this->t[i], d = this->d[i], eta = this->eta[i], beta = this->beta[i], gamma = this->gamma[i],
675 epsilon = this->epsilon[i], b = this->b[i];
676
677 Ftau = pow(tau, t) * exp(1.0 / (b + beta * pow(-gamma + tau, 2)));
678 Fdelta = pow(delta, d) * exp(eta * pow(delta - epsilon, 2));
679 taudFtaudtau = (2 * beta * pow(tau, t + 1) * (gamma - tau) + t * pow(tau, t) * pow(b + beta * pow(gamma - tau, 2), 2))
680 * exp(1.0 / (b + beta * pow(gamma - tau, 2))) / pow(b + beta * pow(gamma - tau, 2), 2);
681 tau2d2Ftaudtau2 = pow(tau, t)
682 * (4 * beta * t * tau * pow(b + beta * pow(gamma - tau, 2), 2) * (gamma - tau)
683 + 2 * beta * pow(tau, 2)
684 * (4 * beta * (b + beta * pow(gamma - tau, 2)) * pow(gamma - tau, 2) + 2 * beta * pow(gamma - tau, 2)
685 - pow(b + beta * pow(gamma - tau, 2), 2))
686 + t * pow(b + beta * pow(gamma - tau, 2), 4) * (t - 1))
687 * exp(1.0 / (b + beta * pow(gamma - tau, 2))) / pow(b + beta * pow(gamma - tau, 2), 4);
688 tau3d3Ftaudtau3 =
689 pow(tau, t)
690 * (4 * pow(beta, 2) * pow(tau, 3) * (gamma - tau)
691 * (12 * beta * (b + beta * pow(gamma - tau, 2)) * pow(gamma - tau, 2) + 2 * beta * pow(gamma - tau, 2)
692 - 6 * pow(b + beta * pow(gamma - tau, 2), 3) + pow(b + beta * pow(gamma - tau, 2), 2) * (12 * beta * pow(gamma - tau, 2) - 3))
693 + 6 * beta * t * pow(tau, 2) * pow(b + beta * pow(gamma - tau, 2), 2)
694 * (4 * beta * (b + beta * pow(gamma - tau, 2)) * pow(gamma - tau, 2) + 2 * beta * pow(gamma - tau, 2)
695 - pow(b + beta * pow(gamma - tau, 2), 2))
696 + 6 * beta * t * tau * pow(b + beta * pow(gamma - tau, 2), 4) * (gamma - tau) * (t - 1)
697 + t * pow(b + beta * pow(gamma - tau, 2), 6) * (pow(t, 2) - 3 * t + 2))
698 * exp(1.0 / (b + beta * pow(gamma - tau, 2))) / pow(b + beta * pow(gamma - tau, 2), 6);
699 tau4d4Ftaudtau4 =
700 pow(tau, t)
701 * (16 * pow(beta, 2) * t * pow(tau, 3) * pow(b + beta * pow(gamma - tau, 2), 2) * (gamma - tau)
702 * (12 * beta * (b + beta * pow(gamma - tau, 2)) * pow(gamma - tau, 2) + 2 * beta * pow(gamma - tau, 2)
703 - 6 * pow(b + beta * pow(gamma - tau, 2), 3) + pow(b + beta * pow(gamma - tau, 2), 2) * (12 * beta * pow(gamma - tau, 2) - 3))
704 + pow(beta, 2) * pow(tau, 4)
705 * (pow(beta, 2) * (192 * b + 192 * beta * pow(gamma - tau, 2)) * pow(gamma - tau, 4) + 16 * pow(beta, 2) * pow(gamma - tau, 4)
706 + 96 * beta * pow(b + beta * pow(gamma - tau, 2), 3) * pow(gamma - tau, 2) * (4 * beta * pow(gamma - tau, 2) - 3)
707 + 48 * beta * pow(b + beta * pow(gamma - tau, 2), 2) * pow(gamma - tau, 2) * (12 * beta * pow(gamma - tau, 2) - 1)
708 + 24 * pow(b + beta * pow(gamma - tau, 2), 5) + pow(b + beta * pow(gamma - tau, 2), 4) * (-288 * beta * pow(gamma - tau, 2) + 12))
709 + 12 * beta * t * pow(tau, 2) * pow(b + beta * pow(gamma - tau, 2), 4) * (t - 1)
710 * (4 * beta * (b + beta * pow(gamma - tau, 2)) * pow(gamma - tau, 2) + 2 * beta * pow(gamma - tau, 2)
711 - pow(b + beta * pow(gamma - tau, 2), 2))
712 + 8 * beta * t * tau * pow(b + beta * pow(gamma - tau, 2), 6) * (gamma - tau) * (pow(t, 2) - 3 * t + 2)
713 + t * pow(b + beta * pow(gamma - tau, 2), 8) * (pow(t, 3) - 6 * pow(t, 2) + 11 * t - 6))
714 * exp(1.0 / (b + beta * pow(gamma - tau, 2))) / pow(b + beta * pow(gamma - tau, 2), 8);
715 deltadFdeltaddelta = (d * pow(delta, d) + 2 * pow(delta, d + 1) * eta * (delta - epsilon)) * exp(eta * pow(delta - epsilon, 2));
716 delta2d2Fdeltaddelta2 =
717 pow(delta, d) * (4 * d * delta * eta * (delta - epsilon) + d * (d - 1) + 2 * pow(delta, 2) * eta * (2 * eta * pow(delta - epsilon, 2) + 1))
718 * exp(eta * pow(delta - epsilon, 2));
719 delta3d3Fdeltaddelta3 =
720 pow(delta, d)
721 * (6 * d * pow(delta, 2) * eta * (2 * eta * pow(delta - epsilon, 2) + 1) + 6 * d * delta * eta * (d - 1) * (delta - epsilon)
722 + d * (pow(d, 2) - 3 * d + 2) + 4 * pow(delta, 3) * pow(eta, 2) * (delta - epsilon) * (2 * eta * pow(delta - epsilon, 2) + 3))
723 * exp(eta * pow(delta - epsilon, 2));
724 delta4d4Fdeltaddelta4 =
725 pow(delta, d)
726 * (16 * d * pow(delta, 3) * pow(eta, 2) * (delta - epsilon) * (2 * eta * pow(delta - epsilon, 2) + 3)
727 + 12 * d * pow(delta, 2) * eta * (d - 1) * (2 * eta * pow(delta - epsilon, 2) + 1)
728 + 8 * d * delta * eta * (delta - epsilon) * (pow(d, 2) - 3 * d + 2) + d * (pow(d, 3) - 6 * pow(d, 2) + 11 * d - 6)
729 + pow(delta, 4) * pow(eta, 2) * (16 * pow(eta, 2) * pow(delta - epsilon, 4) + 48 * eta * pow(delta - epsilon, 2) + 12))
730 * exp(eta * pow(delta - epsilon, 2));
731
732 derivs.alphar += n * Ftau * Fdelta;
733
734 derivs.dalphar_ddelta += n * Ftau * deltadFdeltaddelta / delta;
735 derivs.dalphar_dtau += n * Fdelta * taudFtaudtau / tau;
736
737 derivs.d2alphar_ddelta2 += n * Ftau * delta2d2Fdeltaddelta2 / POW2(delta);
738 derivs.d2alphar_ddelta_dtau += n * taudFtaudtau * deltadFdeltaddelta / tau / delta;
739 derivs.d2alphar_dtau2 += n * Fdelta * tau2d2Ftaudtau2 / POW2(tau);
740
741 derivs.d3alphar_ddelta3 += n * Ftau * delta3d3Fdeltaddelta3 / POW3(delta);
742 derivs.d3alphar_ddelta2_dtau += n * taudFtaudtau * delta2d2Fdeltaddelta2 / POW2(delta) / tau;
743 derivs.d3alphar_ddelta_dtau2 += n * tau2d2Ftaudtau2 * deltadFdeltaddelta / POW2(tau) / delta;
744 derivs.d3alphar_dtau3 += n * Fdelta * tau3d3Ftaudtau3 / POW3(tau);
745
746 derivs.d4alphar_ddelta4 += n * Ftau * delta4d4Fdeltaddelta4 / POW4(delta);
747 derivs.d4alphar_ddelta3_dtau += n * taudFtaudtau * delta3d3Fdeltaddelta3 / POW3(delta) / tau;
748 derivs.d4alphar_ddelta2_dtau2 += n * tau2d2Ftaudtau2 * delta2d2Fdeltaddelta2 / POW2(delta) / POW2(tau);
749 derivs.d4alphar_ddelta_dtau3 += n * tau3d3Ftaudtau3 * deltadFdeltaddelta / POW3(tau) / delta;
750 derivs.d4alphar_dtau4 += n * Fdelta * tau4d4Ftaudtau4 / POW4(tau);
751 }
752}
753
754#if ENABLE_CATCH
755mcx::MultiComplex<double> ResidualHelmholtzGaoB::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
756 mcx::MultiComplex<double> sum00 = 0.0;
757 for (std::size_t i = 0; i < static_cast<int>(n.size()); ++i) {
758 auto u = b[i] + beta[i] * (tau - gamma[i]) * (tau - gamma[i]);
759 auto Ftau = pow(tau, t[i]) * exp(1.0 / u);
760 auto Fdelta = pow(delta, d[i]) * exp(eta[i] * pow(delta - epsilon[i], 2));
761 sum00 += n[i] * Ftau * Fdelta;
762 }
763 return sum00;
764}
765#endif
766
768 const CoolPropDbl acentric, const CoolPropDbl R)
769 : Tc(Tc), pc(pc), rhomolarc(rhomolarc), acentric(acentric), R(R) {
770 double Zc = pc / (R * Tc * rhomolarc);
771 theta = POW2(Zc - 0.29);
772
773 // From Xiang & Deiters, doi:10.1016/j.ces.2007.11.029
774 double _d[] = {1, 1, 1, 2, 3, 7, 1, 1, 2, 5, 1, 1, 4, 2};
775 std::vector<CoolPropDbl> d(_d, _d + sizeof(_d) / sizeof(double));
776 double _t[] = {0.25, 1.25, 1.5, 1.375, 0.25, 0.875, 0, 2.375, 2, 2.125, 3.5, 6.5, 4.75, 12.5};
777 std::vector<CoolPropDbl> t(_t, _t + sizeof(_t) / sizeof(double));
778 double _l[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3};
779 std::vector<CoolPropDbl> l(_l, _l + sizeof(_l) / sizeof(double));
780 double _g[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1};
781 std::vector<CoolPropDbl> g(_g, _g + sizeof(_g) / sizeof(double));
782 double _a0[] = {8.5740489E-01, -3.2863233E+00, 1.6480939E+00, -5.4524817E-02, 6.1623592E-02, 2.7389266E-04, -6.0655087E-02,
783 -3.1811852E-02, -1.1550422E-01, -1.8610466E-02, -1.8348671E-01, 5.5071325E-03, -1.2268039E-02, -5.0433436E-03};
784 std::vector<CoolPropDbl> a0(_a0, _a0 + sizeof(_a0) / sizeof(double));
785 double _a1[] = {5.6200117E-01, 3.2439544E+00, -4.9628768E+00, -2.2132851E-01, 9.3388356E-02, 2.4940171E-05, -1.7519204E-01,
786 8.9325660E-01, 2.9886613E+00, 1.0881387E-01, -6.7166746E-01, 1.4477326E-01, -2.8716809E-01, -1.1478402E-01};
787 std::vector<CoolPropDbl> a1(_a1, _a1 + sizeof(_a1) / sizeof(double));
788 double _a2[] = {-8.1680511E+01, 4.6384732E+02, -2.7970850E+02, 2.9317364E+01, -2.2324825E+01, -5.0932691E-02, -7.2836590E+00,
789 -2.2063100E+02, -3.0435126E+02, 5.8514719E+00, 1.7995451E+02, -1.0178400E+02, 4.0848053E+01, 1.2411984E+01};
790 std::vector<CoolPropDbl> a2(_a2, _a2 + sizeof(_a2) / sizeof(double));
791
792 phi0.add_Exponential(a0, d, t, g, l);
793 phi1.add_Exponential(a1, d, t, g, l);
794 phi2.add_Exponential(a2, d, t, g, l);
795
796 enabled = true;
797};
798
800 if (!enabled) {
801 return;
802 }
803
804 HelmholtzDerivatives derivs0, derivs1, derivs2;
805
806 // Calculate each of the derivative terms
807 phi0.all(tau, delta, derivs0);
808 phi1.all(tau, delta, derivs1);
809 phi2.all(tau, delta, derivs2);
810
811 // Add up the contributions
812 derivs = derivs + derivs0 + derivs1 * acentric + derivs2 * theta;
813}
814#if ENABLE_CATCH
815mcx::MultiComplex<double> ResidualHelmholtzXiangDeiters::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
816
817 return phi0.one_mcx(tau, delta) + phi1.one_mcx(tau, delta) * acentric + phi2.one_mcx(tau, delta) * theta;
818}
819#endif
820
821void ResidualHelmholtzSAFTAssociating::to_json(rapidjson::Value& el, rapidjson::Document& doc) {
822 el.AddMember("type", "ResidualHelmholtzSAFTAssociating", doc.GetAllocator());
823 el.AddMember("a", a, doc.GetAllocator());
824 el.AddMember("m", m, doc.GetAllocator());
825 el.AddMember("epsilonbar", epsilonbar, doc.GetAllocator());
826 el.AddMember("vbarn", vbarn, doc.GetAllocator());
827 el.AddMember("kappabar", kappabar, doc.GetAllocator());
828}
830 return this->g(this->eta(delta)) * (exp(this->epsilonbar * tau) - 1) * this->kappabar;
831}
833 return this->dg_deta(this->eta(delta)) * (exp(this->epsilonbar * tau) - 1) * this->kappabar * this->vbarn;
834}
836 return this->d2g_deta2(this->eta(delta)) * (exp(this->epsilonbar * tau) - 1) * this->kappabar * pow(this->vbarn, (int)2);
837}
839 return this->g(this->eta(delta)) * this->kappabar * exp(this->epsilonbar * tau) * this->epsilonbar;
840}
842 return this->g(this->eta(delta)) * this->kappabar * exp(this->epsilonbar * tau) * pow(this->epsilonbar, (int)2);
843}
845 return this->dg_deta(this->eta(delta)) * exp(this->epsilonbar * tau) * this->epsilonbar * this->kappabar * this->vbarn;
846}
848 return this->g(this->eta(delta)) * this->kappabar * exp(this->epsilonbar * tau) * pow(this->epsilonbar, (int)3);
849}
851 return this->dg_deta(this->eta(delta)) * this->kappabar * exp(this->epsilonbar * tau) * pow(this->epsilonbar, (int)2) * this->vbarn;
852}
854 return this->d2g_deta2(this->eta(delta)) * exp(this->epsilonbar * tau) * this->epsilonbar * this->kappabar * pow(this->vbarn, (int)2);
855}
857 return this->d3g_deta3(this->eta(delta)) * (exp(this->epsilonbar * tau) - 1) * this->kappabar * pow(this->vbarn, (int)3);
858}
859
861 return 2 / (sqrt(1 + 4 * Deltabar * delta) + 1);
862}
864 CoolPropDbl X = this->X(delta, Deltabar);
865 return -delta * X * X / (2 * Deltabar * delta * X + 1);
866}
868 CoolPropDbl X = this->X(delta, Deltabar);
869 return -Deltabar * X * X / (2 * Deltabar * delta * X + 1);
870}
872 CoolPropDbl Deltabar = this->Deltabar(tau, delta);
873 return this->dX_dDeltabar__constdelta(delta, Deltabar) * this->dDeltabar_dtau__constdelta(tau, delta);
874}
876 CoolPropDbl Deltabar = this->Deltabar(tau, delta);
877 return (this->dX_ddelta__constDeltabar(delta, Deltabar)
878 + this->dX_dDeltabar__constdelta(delta, Deltabar) * this->dDeltabar_ddelta__consttau(tau, delta));
879}
881 CoolPropDbl Deltabar = this->Deltabar(tau, delta);
882 CoolPropDbl X = this->X(delta, Deltabar);
883 CoolPropDbl beta = this->dDeltabar_dtau__constdelta(tau, delta);
884 CoolPropDbl d_dXdtau_dbeta = -delta * X * X / (2 * Deltabar * delta * X + 1);
885 CoolPropDbl d_dXdtau_dDeltabar = 2 * delta * delta * X * X * X / pow(2 * Deltabar * delta * X + 1, 2) * beta;
886 CoolPropDbl d_dXdtau_dX = -2 * beta * delta * X * (Deltabar * delta * X + 1) / pow(2 * Deltabar * delta * X + 1, 2);
887 CoolPropDbl dbeta_dtau = this->d2Deltabar_dtau2__constdelta(tau, delta);
888 CoolPropDbl dX_dDeltabar = this->dX_dDeltabar__constdelta(delta, Deltabar);
889 return d_dXdtau_dX * dX_dDeltabar * beta + d_dXdtau_dDeltabar * beta + d_dXdtau_dbeta * dbeta_dtau;
890}
892 CoolPropDbl Deltabar = this->Deltabar(tau, delta);
893 CoolPropDbl X = this->X(delta, Deltabar);
894 CoolPropDbl alpha = this->dDeltabar_ddelta__consttau(tau, delta);
895 CoolPropDbl beta = this->dDeltabar_dtau__constdelta(tau, delta);
896 CoolPropDbl dalpha_dtau = this->d2Deltabar_ddelta_dtau(tau, delta);
897 CoolPropDbl d_dXddelta_dDeltabar = X * X * (2 * delta * delta * X * alpha - 1) / pow(2 * Deltabar * delta * X + 1, 2);
898 CoolPropDbl d_dXddelta_dalpha = -delta * X * X / (2 * Deltabar * delta * X + 1);
899 CoolPropDbl d_dXddelta_dX = -(Deltabar + delta * alpha) * 2 * (Deltabar * delta * X * X + X) / pow(2 * Deltabar * delta * X + 1, 2);
900 CoolPropDbl dX_dDeltabar = this->dX_dDeltabar__constdelta(delta, Deltabar);
901 return d_dXddelta_dX * dX_dDeltabar * beta + d_dXddelta_dDeltabar * beta + d_dXddelta_dalpha * dalpha_dtau;
902}
904 CoolPropDbl Deltabar = this->Deltabar(tau, delta);
905 CoolPropDbl X = this->X(delta, Deltabar);
906 CoolPropDbl alpha = this->dDeltabar_ddelta__consttau(tau, delta);
907 CoolPropDbl dalpha_ddelta = this->d2Deltabar_ddelta2__consttau(tau, delta);
908
909 CoolPropDbl dX_ddelta_constall = X * X * (2 * Deltabar * Deltabar * X - alpha) / pow(2 * Deltabar * delta * X + 1, 2);
910 CoolPropDbl d_dXddelta_dX = -(Deltabar + delta * alpha) * 2 * (Deltabar * delta * X * X + X) / pow(2 * Deltabar * delta * X + 1, 2);
911 CoolPropDbl d_dXddelta_dDeltabar = X * X * (2 * delta * delta * X * alpha - 1) / pow(2 * Deltabar * delta * X + 1, 2);
912 CoolPropDbl d_dXddelta_dalpha = -delta * X * X / (2 * Deltabar * delta * X + 1);
913
914 CoolPropDbl dX_dDeltabar = this->dX_dDeltabar__constdelta(delta, Deltabar);
916
917 CoolPropDbl val = (dX_ddelta_constall + d_dXddelta_dX * dX_ddelta + d_dXddelta_dX * dX_dDeltabar * alpha + d_dXddelta_dDeltabar * alpha
918 + d_dXddelta_dalpha * dalpha_ddelta);
919 return val;
920}
922 CoolPropDbl Delta = this->Deltabar(tau, delta);
923 CoolPropDbl X = this->X(delta, Delta);
924 CoolPropDbl dX_dDelta = this->dX_dDeltabar__constdelta(delta, Delta);
925 CoolPropDbl Delta_t = this->dDeltabar_dtau__constdelta(tau, delta);
926 CoolPropDbl Delta_tt = this->d2Deltabar_dtau2__constdelta(tau, delta);
927 CoolPropDbl Delta_ttt = this->d3Deltabar_dtau3__constdelta(tau, delta);
928 CoolPropDbl dXtt_dX = 2 * X * delta
929 * (-6 * Delta * pow(Delta_t, 2) * pow(X, 2) * pow(delta, 2) * (Delta * X * delta + 1)
930 + 3 * pow(Delta_t, 2) * X * delta * (2 * Delta * X * delta + 1) - Delta_tt * pow(2 * Delta * X * delta + 1, 3)
931 + X * delta * (Delta * Delta_tt + 3 * pow(Delta_t, 2)) * pow(2 * Delta * X * delta + 1, 2))
932 / pow(2 * Delta * X * delta + 1, 4);
933 CoolPropDbl dXtt_dDelta = 2 * pow(X, 3) * pow(delta, 2)
934 * (-6 * pow(Delta_t, 2) * X * delta * (Delta * X * delta + 1)
935 - 3 * pow(Delta_t, 2) * X * delta * (2 * Delta * X * delta + 1) + Delta_tt * pow(2 * Delta * X * delta + 1, 2))
936 / pow(2 * Delta * X * delta + 1, 4);
937 CoolPropDbl dXtt_dDelta_t = 4 * Delta_t * pow(X, 3) * pow(delta, 2) * (3 * Delta * X * delta + 2) / pow(2 * Delta * X * delta + 1, 3);
938 CoolPropDbl dXtt_dDelta_tt = -pow(X, 2) * delta / (2 * Delta * X * delta + 1);
939 return dXtt_dX * dX_dDelta * Delta_t + dXtt_dDelta * Delta_t + dXtt_dDelta_t * Delta_tt + dXtt_dDelta_tt * Delta_ttt;
940}
942 CoolPropDbl Delta = this->Deltabar(tau, delta);
943 CoolPropDbl X = this->X(delta, Delta);
944 CoolPropDbl dX_ddelta = this->dX_ddelta__constDeltabar(delta, Delta);
945 CoolPropDbl dX_dDelta = this->dX_dDeltabar__constdelta(delta, Delta);
946 CoolPropDbl Delta_t = this->dDeltabar_dtau__constdelta(tau, delta);
947 CoolPropDbl Delta_d = this->dDeltabar_ddelta__consttau(tau, delta);
948 CoolPropDbl Delta_dt = this->d2Deltabar_ddelta_dtau(tau, delta);
949 CoolPropDbl Delta_tt = this->d2Deltabar_dtau2__constdelta(tau, delta);
950 CoolPropDbl Delta_dtt = this->d3Deltabar_ddelta_dtau2(tau, delta);
951 CoolPropDbl dXtt_ddelta =
952 pow(X, 2)
953 * (-12 * Delta * pow(Delta_t, 2) * pow(X, 2) * pow(delta, 2) * (Delta * X * delta + 1)
954 + 2 * pow(Delta_t, 2) * X * delta * (-Delta * X * delta + 2) * (2 * Delta * X * delta + 1) - Delta_tt * pow(2 * Delta * X * delta + 1, 3)
955 + 2 * X * delta * (Delta * Delta_tt + 2 * pow(Delta_t, 2)) * pow(2 * Delta * X * delta + 1, 2))
956 / pow(2 * Delta * X * delta + 1, 4);
957 CoolPropDbl dXtt_dX = 2 * X * delta
958 * (-6 * Delta * pow(Delta_t, 2) * pow(X, 2) * pow(delta, 2) * (Delta * X * delta + 1)
959 + 3 * pow(Delta_t, 2) * X * delta * (2 * Delta * X * delta + 1) - Delta_tt * pow(2 * Delta * X * delta + 1, 3)
960 + X * delta * (Delta * Delta_tt + 3 * pow(Delta_t, 2)) * pow(2 * Delta * X * delta + 1, 2))
961 / pow(2 * Delta * X * delta + 1, 4);
962 CoolPropDbl dXtt_dDelta = 2 * pow(X, 3) * pow(delta, 2)
963 * (-6 * pow(Delta_t, 2) * X * delta * (Delta * X * delta + 1)
964 - 3 * pow(Delta_t, 2) * X * delta * (2 * Delta * X * delta + 1) + Delta_tt * pow(2 * Delta * X * delta + 1, 2))
965 / pow(2 * Delta * X * delta + 1, 4);
966 CoolPropDbl dXtt_dDelta_t = 4 * Delta_t * pow(X, 3) * pow(delta, 2) * (3 * Delta * X * delta + 2) / pow(2 * Delta * X * delta + 1, 3);
967 CoolPropDbl dXtt_dDelta_tt = -pow(X, 2) * delta / (2 * Delta * X * delta + 1);
968 return dXtt_ddelta + dXtt_dX * dX_ddelta + dXtt_dX * dX_dDelta * Delta_d + dXtt_dDelta * Delta_d + dXtt_dDelta_t * Delta_dt
969 + dXtt_dDelta_tt * Delta_dtt;
970}
971
973 CoolPropDbl Delta = this->Deltabar(tau, delta);
974 CoolPropDbl X = this->X(delta, Delta);
975 CoolPropDbl dX_dDelta = this->dX_dDeltabar__constdelta(delta, Delta);
976 CoolPropDbl Delta_t = this->dDeltabar_dtau__constdelta(tau, delta);
977 CoolPropDbl Delta_d = this->dDeltabar_ddelta__consttau(tau, delta);
978 CoolPropDbl Delta_dd = this->d2Deltabar_ddelta2__consttau(tau, delta);
979 CoolPropDbl Delta_dt = this->d2Deltabar_ddelta_dtau(tau, delta);
980 CoolPropDbl Delta_ddt = this->d3Deltabar_ddelta2_dtau(tau, delta);
981 CoolPropDbl dXdd_dX =
982 2 * X
983 * (-6 * Delta * pow(X, 2) * delta * pow(Delta + Delta_d * delta, 2) * (Delta * X * delta + 1)
984 - Delta_dd * delta * pow(2 * Delta * X * delta + 1, 3)
985 + 2 * X * (2 * Delta * X * delta + 1)
986 * (-Delta * Delta_d * delta * (2 * Delta_d * X * pow(delta, 2) - 1) - Delta * delta * (2 * pow(Delta, 2) * X - Delta_d)
987 + Delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1) + Delta_d * delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1))
988 + pow(2 * Delta * X * delta + 1, 2)
989 * (3 * pow(Delta, 2) * X + Delta * Delta_dd * X * pow(delta, 2) + Delta * X * (Delta + Delta_d * delta)
990 + pow(Delta_d, 2) * X * pow(delta, 2) + Delta_d * X * delta * (Delta + Delta_d * delta)
991 + Delta_d * (2 * Delta_d * X * pow(delta, 2) - 1) - Delta_d))
992 / pow(2 * Delta * X * delta + 1, 4);
993 CoolPropDbl dXdd_dDelta = pow(X, 3)
994 * (-8 * pow(Delta, 2) * Delta_d * pow(X, 2) * pow(delta, 3) + 8 * pow(Delta, 2) * Delta_dd * pow(X, 2) * pow(delta, 4)
995 + 10 * pow(Delta, 2) * X * delta - 24 * Delta * pow(Delta_d, 2) * pow(X, 2) * pow(delta, 4)
996 + 8 * Delta * Delta_d * X * pow(delta, 2) + 8 * Delta * Delta_dd * X * pow(delta, 3) + 8 * Delta
997 - 18 * pow(Delta_d, 2) * X * pow(delta, 3) + 12 * Delta_d * delta + 2 * Delta_dd * pow(delta, 2))
998 / (16 * pow(Delta, 4) * pow(X, 4) * pow(delta, 4) + 32 * pow(Delta, 3) * pow(X, 3) * pow(delta, 3)
999 + 24 * pow(Delta, 2) * pow(X, 2) * pow(delta, 2) + 8 * Delta * X * delta + 1);
1000 CoolPropDbl dXdd_dDelta_d =
1001 2 * pow(X, 2)
1002 * (2 * X * delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1) + (2 * Delta * X * delta + 1) * (2 * Delta_d * X * pow(delta, 2) - 1))
1003 / pow(2 * Delta * X * delta + 1, 3);
1004 CoolPropDbl dXdd_dDelta_dd = -pow(X, 2) * delta / (2 * Delta * X * delta + 1);
1005
1006 return dXdd_dX * dX_dDelta * Delta_t + dXdd_dDelta * Delta_t + dXdd_dDelta_d * Delta_dt + dXdd_dDelta_dd * Delta_ddt;
1007}
1008
1009double Xdd(double X, double delta, double Delta, double Delta_d, double Delta_dd) {
1010 return Delta * pow(X, 2) * (2 * Delta + 2 * Delta_d * delta) * (Delta * pow(X, 2) * delta + X) / pow(2 * Delta * X * delta + 1, 3)
1011 + Delta_d * pow(X, 2) * delta * (2 * Delta + 2 * Delta_d * delta) * (Delta * pow(X, 2) * delta + X) / pow(2 * Delta * X * delta + 1, 3)
1012 + Delta_d * pow(X, 2) * (2 * Delta_d * X * pow(delta, 2) - 1) / pow(2 * Delta * X * delta + 1, 2)
1013 - Delta_dd * pow(X, 2) * delta / (2 * Delta * X * delta + 1)
1014 + pow(X, 2) * (2 * pow(Delta, 2) * X - Delta_d) / pow(2 * Delta * X * delta + 1, 2);
1015}
1016
1018 CoolPropDbl Delta = this->Deltabar(tau, delta);
1019 CoolPropDbl X = this->X(delta, Delta);
1020 CoolPropDbl dX_ddelta = this->dX_ddelta__constDeltabar(delta, Delta);
1021 CoolPropDbl dX_dDelta = this->dX_dDeltabar__constdelta(delta, Delta);
1022 CoolPropDbl Delta_d = this->dDeltabar_ddelta__consttau(tau, delta);
1023 CoolPropDbl Delta_dd = this->d2Deltabar_ddelta2__consttau(tau, delta);
1024 CoolPropDbl Delta_ddd = this->d3Deltabar_ddelta3__consttau(tau, delta);
1025
1026 CoolPropDbl dXdd_dX =
1027 2 * X
1028 * (-6 * Delta * pow(X, 2) * delta * pow(Delta + Delta_d * delta, 2) * (Delta * X * delta + 1)
1029 - Delta_dd * delta * pow(2 * Delta * X * delta + 1, 3)
1030 + 2 * X * (2 * Delta * X * delta + 1)
1031 * (-Delta * Delta_d * delta * (2 * Delta_d * X * pow(delta, 2) - 1) - Delta * delta * (2 * pow(Delta, 2) * X - Delta_d)
1032 + Delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1) + Delta_d * delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1))
1033 + pow(2 * Delta * X * delta + 1, 2)
1034 * (3 * pow(Delta, 2) * X + Delta * Delta_dd * X * pow(delta, 2) + Delta * X * (Delta + Delta_d * delta)
1035 + pow(Delta_d, 2) * X * pow(delta, 2) + Delta_d * X * delta * (Delta + Delta_d * delta)
1036 + Delta_d * (2 * Delta_d * X * pow(delta, 2) - 1) - Delta_d))
1037 / pow(2 * Delta * X * delta + 1, 4);
1038 CoolPropDbl dXdd_ddelta = pow(X, 2)
1039 * (-24 * pow(Delta, 4) * pow(X, 3) * delta - 8 * pow(Delta, 3) * Delta_d * pow(X, 3) * pow(delta, 2)
1040 - 18 * pow(Delta, 3) * pow(X, 2) + 8 * pow(Delta, 2) * Delta_d * pow(X, 2) * delta
1041 - 4 * pow(Delta, 2) * Delta_dd * pow(X, 2) * pow(delta, 2) + 10 * Delta * pow(Delta_d, 2) * pow(X, 2) * pow(delta, 2)
1042 + 12 * Delta * Delta_d * X - 4 * Delta * Delta_dd * X * delta + 8 * pow(Delta_d, 2) * X * delta - Delta_dd)
1043 / (16 * pow(Delta, 4) * pow(X, 4) * pow(delta, 4) + 32 * pow(Delta, 3) * pow(X, 3) * pow(delta, 3)
1044 + 24 * pow(Delta, 2) * pow(X, 2) * pow(delta, 2) + 8 * Delta * X * delta + 1);
1045 CoolPropDbl dXdd_dDelta = pow(X, 3)
1046 * (-8 * pow(Delta, 2) * Delta_d * pow(X, 2) * pow(delta, 3) + 8 * pow(Delta, 2) * Delta_dd * pow(X, 2) * pow(delta, 4)
1047 + 10 * pow(Delta, 2) * X * delta - 24 * Delta * pow(Delta_d, 2) * pow(X, 2) * pow(delta, 4)
1048 + 8 * Delta * Delta_d * X * pow(delta, 2) + 8 * Delta * Delta_dd * X * pow(delta, 3) + 8 * Delta
1049 - 18 * pow(Delta_d, 2) * X * pow(delta, 3) + 12 * Delta_d * delta + 2 * Delta_dd * pow(delta, 2))
1050 / (16 * pow(Delta, 4) * pow(X, 4) * pow(delta, 4) + 32 * pow(Delta, 3) * pow(X, 3) * pow(delta, 3)
1051 + 24 * pow(Delta, 2) * pow(X, 2) * pow(delta, 2) + 8 * Delta * X * delta + 1);
1052 CoolPropDbl dXdd_dDelta_d =
1053 2 * pow(X, 2)
1054 * (2 * X * delta * (Delta + Delta_d * delta) * (Delta * X * delta + 1) + (2 * Delta * X * delta + 1) * (2 * Delta_d * X * pow(delta, 2) - 1))
1055 / pow(2 * Delta * X * delta + 1, 3);
1056 CoolPropDbl dXdd_dDelta_dd = -pow(X, 2) * delta / (2 * Delta * X * delta + 1);
1057
1058 return dXdd_ddelta + dXdd_dX * (dX_ddelta + dX_dDelta * Delta_d) + dXdd_dDelta * Delta_d + dXdd_dDelta_d * Delta_dd + dXdd_dDelta_dd * Delta_ddd;
1059}
1061 return 0.5 * (2 - eta) / pow(1 - eta, (int)3);
1062}
1064 return 0.5 * (5 - 2 * eta) / pow(1 - eta, (int)4);
1065}
1067 return 3 * (3 - eta) / pow(1 - eta, (int)5);
1068}
1070 return 6 * (7 - 2 * eta) / pow(1 - eta, (int)6);
1071}
1073 return this->vbarn * delta;
1074}
1075
1077 if (disabled) {
1078 return;
1079 }
1080 CoolPropDbl X = this->X(delta, this->Deltabar(tau, delta));
1081 CoolPropDbl X_t = this->dX_dtau(tau, delta);
1082 CoolPropDbl X_d = this->dX_ddelta(tau, delta);
1083 CoolPropDbl X_tt = this->d2X_dtau2(tau, delta);
1084 CoolPropDbl X_dd = this->d2X_ddelta2(tau, delta);
1085 CoolPropDbl X_dt = this->d2X_ddeltadtau(tau, delta);
1086 CoolPropDbl X_ttt = this->d3X_dtau3(tau, delta);
1087 CoolPropDbl X_dtt = this->d3X_ddeltadtau2(tau, delta);
1088 CoolPropDbl X_ddt = this->d3X_ddelta2dtau(tau, delta);
1089 CoolPropDbl X_ddd = this->d3X_ddelta3(tau, delta);
1090
1091 deriv.alphar += this->m * this->a * ((log(X) - X / 2.0 + 0.5));
1092 deriv.dalphar_ddelta += this->m * this->a * (1 / X - 0.5) * this->dX_ddelta(tau, delta);
1093 deriv.dalphar_dtau += this->m * this->a * (1 / X - 0.5) * this->dX_dtau(tau, delta);
1094 deriv.d2alphar_dtau2 += this->m * this->a * ((1 / X - 0.5) * X_tt - pow(X_t / X, 2));
1095 deriv.d2alphar_ddelta2 += this->m * this->a * ((1 / X - 0.5) * X_dd - pow(X_d / X, 2));
1096 deriv.d2alphar_ddelta_dtau += this->m * this->a * ((-X_t / X / X) * X_d + X_dt * (1 / X - 0.5));
1097 deriv.d3alphar_dtau3 += this->m * this->a
1098 * ((1 / X - 1.0 / 2.0) * X_ttt + (-X_t / pow(X, (int)2)) * X_tt
1099 - 2 * (pow(X, (int)2) * (X_t * X_tt) - pow(X_t, (int)2) * (X * X_t)) / pow(X, (int)4));
1100 deriv.d3alphar_ddelta_dtau2 += this->m * this->a
1101 * ((1 / X - 1.0 / 2.0) * X_dtt - X_d / pow(X, (int)2) * X_tt
1102 - 2 * (pow(X, (int)2) * (X_t * X_dt) - pow(X_t, (int)2) * (X * X_d)) / pow(X, (int)4));
1103 deriv.d3alphar_ddelta2_dtau += this->m * this->a
1104 * ((1 / X - 1.0 / 2.0) * X_ddt - X_t / pow(X, (int)2) * X_dd
1105 - 2 * (pow(X, (int)2) * (X_d * X_dt) - pow(X_d, (int)2) * (X * X_t)) / pow(X, (int)4));
1106 deriv.d3alphar_ddelta3 += this->m * this->a
1107 * ((1 / X - 1.0 / 2.0) * X_ddd - X_d / pow(X, (int)2) * X_dd
1108 - 2 * (pow(X, (int)2) * (X_d * X_dd) - pow(X_d, (int)2) * (X * X_d)) / pow(X, (int)4));
1109}
1110
1111#if ENABLE_CATCH
1112mcx::MultiComplex<double> IdealHelmholtzCP0PolyT::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
1113 mcx::MultiComplex<double> sum = 0.0;
1114 for (std::size_t i = 0; i < N; ++i) {
1115 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1116 sum += c[i] - c[i] * tau / tau0 + c[i] * log(tau / tau0);
1117 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1118 sum += c[i] * tau / Tc * log(tau0 / tau) + c[i] / Tc * (tau - tau0);
1119 } else {
1120 sum += -c[i] * pow(Tc, t[i]) * pow(tau, -t[i]) / (t[i] * (t[i] + 1)) - c[i] * pow(T0, t[i] + 1) * tau / (Tc * (t[i] + 1))
1121 + c[i] * pow(T0, t[i]) / t[i];
1122 }
1123 }
1124 return sum;
1125}
1126#endif
1127
1128void IdealHelmholtzCP0PolyT::to_json(rapidjson::Value& el, rapidjson::Document& doc) {
1129 el.AddMember("type", "IdealGasCP0Poly", doc.GetAllocator());
1130
1131 rapidjson::Value _c(rapidjson::kArrayType), _t(rapidjson::kArrayType);
1132 for (std::size_t i = 0; i < N; ++i) {
1133 _c.PushBack(static_cast<double>(c[i]), doc.GetAllocator());
1134 _t.PushBack(static_cast<double>(t[i]), doc.GetAllocator());
1135 }
1136 el.AddMember("c", _c, doc.GetAllocator());
1137 el.AddMember("t", _t, doc.GetAllocator());
1138 el.AddMember("Tc", static_cast<double>(Tc), doc.GetAllocator());
1139 el.AddMember("T0", static_cast<double>(T0), doc.GetAllocator());
1140}
1141
1142void IdealHelmholtzLead::all(const CoolPropDbl& tau, const CoolPropDbl& delta, HelmholtzDerivatives& derivs) throw() {
1143 if (!enabled) {
1144 return;
1145 }
1146 derivs.alphar += log(delta) + a1 + a2 * tau;
1147 derivs.dalphar_ddelta += 1.0 / delta;
1148 derivs.dalphar_dtau += a2;
1149 derivs.d2alphar_ddelta2 += -1.0 / delta / delta;
1150 derivs.d3alphar_ddelta3 += 2 / delta / delta / delta;
1151 derivs.d4alphar_ddelta4 += -6 / POW4(delta);
1152}
1154 if (!enabled) {
1155 return;
1156 }
1157 derivs.alphar += a1 + a2 * tau;
1158 derivs.dalphar_dtau += a2;
1159}
1160void IdealHelmholtzLogTau::all(const CoolPropDbl& tau, const CoolPropDbl& delta, HelmholtzDerivatives& derivs) throw() {
1161
1162 if (!enabled) {
1163 return;
1164 }
1165 derivs.alphar += a1 * log(tau);
1166 derivs.dalphar_dtau += a1 / tau;
1167 derivs.d2alphar_dtau2 += -a1 / tau / tau;
1168 derivs.d3alphar_dtau3 += 2 * a1 / tau / tau / tau;
1169 derivs.d4alphar_dtau4 += -6 * a1 / POW4(tau);
1170}
1171void IdealHelmholtzPower::all(const CoolPropDbl& tau, const CoolPropDbl& delta, HelmholtzDerivatives& derivs) throw() {
1172 if (!enabled) {
1173 return;
1174 }
1175 {
1176 CoolPropDbl s = 0;
1177 for (std::size_t i = 0; i < N; ++i) {
1178 s += n[i] * pow(tau, t[i]);
1179 }
1180 derivs.alphar += s;
1181 }
1182 {
1183 CoolPropDbl s = 0;
1184 for (std::size_t i = 0; i < N; ++i) {
1185 s += n[i] * t[i] * pow(tau, t[i] - 1);
1186 }
1187 derivs.dalphar_dtau += s;
1188 }
1189 {
1190 CoolPropDbl s = 0;
1191 for (std::size_t i = 0; i < N; ++i) {
1192 s += n[i] * t[i] * (t[i] - 1) * pow(tau, t[i] - 2);
1193 }
1194 derivs.d2alphar_dtau2 += s;
1195 }
1196 {
1197 CoolPropDbl s = 0;
1198 for (std::size_t i = 0; i < N; ++i) {
1199 s += n[i] * t[i] * (t[i] - 1) * (t[i] - 2) * pow(tau, t[i] - 3);
1200 }
1201 derivs.d3alphar_dtau3 += s;
1202 }
1203 {
1204 CoolPropDbl s = 0;
1205 for (std::size_t i = 0; i < N; ++i) {
1206 s += n[i] * t[i] * (t[i] - 1) * (t[i] - 2) * (t[i] - 3) * pow(tau, t[i] - 4);
1207 }
1208 derivs.d4alphar_dtau4 += s;
1209 }
1210}
1212
1213 if (!enabled) {
1214 return;
1215 }
1216
1217 CoolPropDbl s00 = 0, s01 = 0, s02 = 0, s03 = 0, s04 = 0;
1218
1219 for (std::size_t i = 0; i < N; ++i) {
1220 const CoolPropDbl expthetataui = exp(theta[i] * tau);
1221 const CoolPropDbl para = c[i] + d[i] * expthetataui;
1222
1223 s00 += n[i] * log(para);
1224 s01 += n[i] * theta[i] * d[i] * expthetataui / para;
1225 s02 += n[i] * POW2(theta[i]) * c[i] * d[i] * expthetataui / POW2(para);
1226 s03 += n[i] * POW3(theta[i]) * c[i] * d[i] * (c[i] - d[i] * expthetataui) * expthetataui / POW3(para);
1227 const CoolPropDbl bracket =
1228 6 * POW3(d[i]) * POW3(expthetataui) - 12 * d[i] * d[i] * para * POW2(expthetataui) + 7 * d[i] * POW2(para) * expthetataui - POW3(para);
1229 s04 += -n[i] * d[i] * POW4(theta[i]) * bracket * expthetataui / POW4(para);
1230 }
1231 derivs.alphar += s00;
1232 derivs.dalphar_dtau += s01;
1233 derivs.d2alphar_dtau2 += s02;
1234 derivs.d3alphar_dtau3 += s03;
1235 derivs.d4alphar_dtau4 += s04;
1236}
1237void IdealHelmholtzCP0Constant::all(const CoolPropDbl& tau, const CoolPropDbl& delta, HelmholtzDerivatives& derivs) throw() {
1238 if (!enabled) {
1239 return;
1240 }
1241 derivs.alphar += cp_over_R - cp_over_R * tau / tau0 + cp_over_R * log(tau / tau0);
1242 derivs.dalphar_dtau += cp_over_R / tau - cp_over_R / tau0;
1243 derivs.d2alphar_dtau2 += -cp_over_R / (tau * tau);
1244 derivs.d3alphar_dtau3 += 2 * cp_over_R / (tau * tau * tau);
1245 derivs.d4alphar_dtau4 += -6 * cp_over_R / POW4(tau);
1246}
1248 if (!enabled) {
1249 return;
1250 }
1251 {
1252 double sum = 0;
1253 for (std::size_t i = 0; i < N; ++i) {
1254 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1255 sum += c[i] - c[i] * tau / tau0 + c[i] * log(tau / tau0);
1256 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1257 sum += c[i] * tau / Tc * log(tau0 / tau) + c[i] / Tc * (tau - tau0);
1258 } else {
1259 sum += -c[i] * pow(Tc, t[i]) * pow(tau, -t[i]) / (t[i] * (t[i] + 1)) - c[i] * pow(T0, t[i] + 1) * tau / (Tc * (t[i] + 1))
1260 + c[i] * pow(T0, t[i]) / t[i];
1261 }
1262 }
1263 derivs.alphar += sum;
1264 }
1265 {
1266 double sum = 0;
1267 for (std::size_t i = 0; i < N; ++i) {
1268 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1269 sum += c[i] / tau - c[i] / tau0;
1270 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1271 sum += c[i] / Tc * log(tau0 / tau);
1272 } else {
1273 sum += c[i] * pow(Tc, t[i]) * pow(tau, -t[i] - 1) / (t[i] + 1) - c[i] * pow(Tc, t[i]) / (pow(tau0, t[i] + 1) * (t[i] + 1));
1274 }
1275 }
1276 derivs.dalphar_dtau += sum;
1277 }
1278 {
1279 double sum = 0;
1280 for (std::size_t i = 0; i < N; ++i) {
1281 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1282 sum += -c[i] / (tau * tau);
1283 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1284 sum += -c[i] / (tau * Tc);
1285 } else {
1286 sum += -c[i] * pow(Tc / tau, t[i]) / (tau * tau);
1287 }
1288 }
1289 derivs.d2alphar_dtau2 += sum;
1290 }
1291 {
1292 double sum = 0;
1293 for (std::size_t i = 0; i < N; ++i) {
1294 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1295 sum += 2 * c[i] / (tau * tau * tau);
1296 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1297 sum += c[i] / (tau * tau * Tc);
1298 } else {
1299 sum += c[i] * pow(Tc / tau, t[i]) * (t[i] + 2) / (tau * tau * tau);
1300 }
1301 }
1302 derivs.d3alphar_dtau3 += sum;
1303 }
1304 {
1305 double sum = 0;
1306 for (std::size_t i = 0; i < N; ++i) {
1307 if (std::abs(t[i]) < 10 * DBL_EPSILON) {
1308 sum += -6 * c[i] / POW4(tau);
1309 } else if (std::abs(t[i] + 1) < 10 * DBL_EPSILON) {
1310 sum += -3 * c[i] / (POW3(tau) * Tc);
1311 } else {
1312 sum += -c[i] * (t[i] + 2) * (t[i] + 3) * pow(Tc / tau, t[i]) / (tau * tau * tau * tau);
1313 }
1314 }
1315 derivs.d4alphar_dtau4 += sum;
1316 }
1317}
1318
1320 if (!enabled) {
1321 return;
1322 }
1323 // Check that the reducing temperature value is provided
1324 CoolPropDbl T_red = _HUGE;
1325 if (ValidNumber(_Tr)) {
1326 T_red = _Tr; // Primarily useful for testing
1327 } else if (ValidNumber(derivs.T_red)) {
1328 T_red = derivs.T_red;
1329 } else {
1330 throw ValueError("T_red needs to be stored somewhere for GERG2004Sinh");
1331 }
1332 CoolPropDbl Tci_over_Tr = Tc / T_red;
1333
1334 double sum00 = 0, sum10 = 0, sum20 = 0, sum30 = 0, sum40 = 0;
1335 for (std::size_t i = 0; i < N; ++i) {
1336 CoolPropDbl t = theta[i] * Tci_over_Tr;
1337 sum00 += n[i] * log(std::abs(sinh(t * tau)));
1338 sum10 += n[i] * t / tanh(t * tau);
1339 sum20 += -n[i] * POW2(t) / POW2(sinh(t * tau));
1340 sum30 += -2 * n[i] * POW3(t) * (1 / tanh(t * tau) - 1 / POW3(tanh(t * tau)));
1341 sum40 += -2 * n[i] * POW4(t) * (1 - 4 / POW2(tanh(t * tau)) + 3 / POW4(tanh(t * tau)));
1342 }
1343 derivs.alphar += sum00;
1344 derivs.dalphar_dtau += sum10;
1345 derivs.d2alphar_dtau2 += sum20;
1346 derivs.d3alphar_dtau3 += sum30;
1347 derivs.d4alphar_dtau4 += sum40;
1348}
1349
1350#if ENABLE_CATCH
1351mcx::MultiComplex<double> IdealHelmholtzGERG2004Sinh::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
1352 // Check that the reducing temperature value is provided in the derivs structure
1353 CoolPropDbl T_red = _HUGE;
1354 if (ValidNumber(_Tr)) {
1355 T_red = _Tr; // Primarily useful for testing
1356 } else {
1357 throw ValueError("T_red needs to be stored somewhere for GERG2004Cosh");
1358 }
1359 auto Tci_over_Tr = Tc / T_red;
1360 auto diff_abs = [](const mcx::MultiComplex<double>& x) { return sqrt(x * x); }; // differentiable absolute value
1361
1362 mcx::MultiComplex<double> sum00 = 0.0;
1363 for (std::size_t i = 0; i < N; ++i) {
1364 auto t = theta[i] * Tci_over_Tr;
1365 sum00 += n[i] * log(diff_abs(sinh(t * tau)));
1366 }
1367 return sum00;
1368}
1369#endif
1370
1372 if (!enabled) {
1373 return;
1374 }
1375 // Check that the reducing temperature value is provided in the derivs structure
1376 CoolPropDbl T_red = _HUGE;
1377 if (ValidNumber(_Tr)) {
1378 T_red = _Tr; // Primarily useful for testing
1379 } else if (ValidNumber(derivs.T_red)) {
1380 T_red = derivs.T_red;
1381 } else {
1382 throw ValueError("T_red needs to be stored somewhere for GERG2004Cosh");
1383 }
1384 CoolPropDbl Tci_over_Tr = Tc / T_red;
1385
1386 double sum00 = 0, sum10 = 0, sum20 = 0, sum30 = 0, sum40 = 0;
1387 for (std::size_t i = 0; i < N; ++i) {
1388 CoolPropDbl t = theta[i] * Tci_over_Tr;
1389 sum00 += -n[i] * log(std::abs(cosh(t * tau)));
1390 sum10 += -n[i] * t * tanh(t * tau);
1391 sum20 += -n[i] * POW2(t) / POW2(cosh(t * tau));
1392 sum30 += -2 * n[i] * POW3(t) * (POW3(tanh(t * tau)) - tanh(t * tau));
1393 sum40 += 2 * n[i] * POW4(t) * (3 * POW4(tanh(t * tau)) - 4 * POW2(tanh(t * tau)) + 1);
1394 }
1395 derivs.alphar += sum00;
1396 derivs.dalphar_dtau += sum10;
1397 derivs.d2alphar_dtau2 += sum20;
1398 derivs.d3alphar_dtau3 += sum30;
1399 derivs.d4alphar_dtau4 += sum40;
1400}
1401
1402#if ENABLE_CATCH
1403mcx::MultiComplex<double> IdealHelmholtzGERG2004Cosh::one_mcx(const mcx::MultiComplex<double>& tau, const mcx::MultiComplex<double>& delta) const {
1404 // Check that the reducing temperature value is provided in the derivs structure
1405 CoolPropDbl T_red = _HUGE;
1406 if (ValidNumber(_Tr)) {
1407 T_red = _Tr; // Primarily useful for testing
1408 } else {
1409 throw ValueError("T_red needs to be stored somewhere for GERG2004Cosh");
1410 }
1411 auto Tci_over_Tr = Tc / T_red;
1412 auto diff_abs = [](const mcx::MultiComplex<double>& x) { return sqrt(x * x); }; // differentiable absolute value
1413
1414 mcx::MultiComplex<double> sum00 = 0.0;
1415 for (std::size_t i = 0; i < N; ++i) {
1416 auto t = theta[i] * Tci_over_Tr;
1417 sum00 += -n[i] * log(diff_abs(cosh(t * tau)));
1418 }
1419 return sum00;
1420}
1421#endif
1422
1423//void IdealHelmholtzCP0AlyLee::to_json(rapidjson::Value &el, rapidjson::Document &doc){
1424// el.AddMember("type","IdealGasHelmholtzCP0AlyLee",doc.GetAllocator());
1425// rapidjson::Value _n(rapidjson::kArrayType);
1426// for (std::size_t i=0; i<=4; ++i)
1427// {
1428// _n.PushBack(static_cast<double>(c[i]),doc.GetAllocator());
1429// }
1430// el.AddMember("c",_n,doc.GetAllocator());
1431// el.AddMember("Tc",static_cast<double>(Tc),doc.GetAllocator());
1432// el.AddMember("T0",static_cast<double>(T0),doc.GetAllocator());
1433//}
1434//CoolPropDbl IdealHelmholtzCP0AlyLee::base(const CoolPropDbl &tau, const CoolPropDbl &delta) throw()
1435//{
1436// if (!enabled){ return 0.0;}
1437// return -tau*(anti_deriv_cp0_tau2(tau)-anti_deriv_cp0_tau2(tau0))+(anti_deriv_cp0_tau(tau)-anti_deriv_cp0_tau(tau0));
1438//}
1439//CoolPropDbl IdealHelmholtzCP0AlyLee::dTau(const CoolPropDbl &tau, const CoolPropDbl &delta) throw()
1440//{
1441// if (!enabled){ return 0.0;}
1442// return -(anti_deriv_cp0_tau2(tau) - anti_deriv_cp0_tau2(tau0));
1443//}
1444//CoolPropDbl IdealHelmholtzCP0AlyLee::anti_deriv_cp0_tau2(const CoolPropDbl &tau)
1445//{
1446// return -c[0]/tau + 2*c[1]*c[2]/Tc/(exp(-2*c[2]*tau/Tc)-1) - 2*c[3]*c[4]/Tc*(exp(2*c[4]*tau/Tc)+1);
1447//}
1448//CoolPropDbl IdealHelmholtzCP0AlyLee::anti_deriv_cp0_tau(const CoolPropDbl &tau)
1449//{
1450// CoolPropDbl term1 = c[0]*log(tau);
1451// CoolPropDbl term2 = 2*c[1]*c[2]*tau/(-Tc + Tc*exp(-2*c[2]*tau/Tc)) + c[1]*log(-1 + exp(-2*c[2]*tau/Tc)) + 2*c[1]*c[2]*tau/Tc;
1452// CoolPropDbl term3 = -c[3]*(Tc*exp(2*c[4]*tau/Tc)*log(exp(2*c[4]*tau/Tc) + 1) + Tc*log(exp(2*c[4]*tau/Tc) + 1) - 2*c[4]*tau*exp(2*c[4]*tau/Tc))/(Tc*(exp(2*c[4]*tau/Tc) + 1));
1453// return term1 + term2 + term3;
1454//}
1455//CoolPropDbl IdealHelmholtzCP0AlyLee::dTau2(const CoolPropDbl &tau, const CoolPropDbl &delta) throw()
1456//{
1457// if (!enabled){ return 0.0;}
1458// return -c[0]/pow(tau,2) - c[1]*pow(c[2]/Tc/sinh(c[2]*tau/Tc),2) - c[3]*pow(c[4]/Tc/cosh(c[4]*tau/Tc),2);
1459//}
1460//CoolPropDbl IdealHelmholtzCP0AlyLee::dTau3(const CoolPropDbl &tau, const CoolPropDbl &delta) throw()
1461//{
1462// if (!enabled){ return 0.0;}
1463// return 2*c[0]/pow(tau,3) + 2*c[1]*pow(c[2]/Tc,3)*cosh(c[2]*tau/Tc)/pow(sinh(c[2]*tau/Tc),3) + 2*c[3]*pow(c[4]/Tc,3)*sinh(c[4]*tau/Tc)/pow(cosh(c[4]*tau/Tc),3);
1464//}
1465
1466}; /* namespace CoolProp */
1467
1468/*
1469IdealHelmholtzEnthalpyEntropyOffset EnthalpyEntropyOffset;
1470*/
1471
1472#ifdef ENABLE_CATCH
1473# include <math.h>
1474# include <catch2/catch_all.hpp>
1476
1477class HelmholtzConsistencyFixture
1478{
1479 public:
1480 CoolPropDbl numerical, analytic;
1481
1482 shared_ptr<CoolProp::BaseHelmholtzTerm> PlanckEinstein, Lead, LogTau, IGPower, CP0Constant, CP0PolyT, SAFT, NonAnalytic, Soave, PR, XiangDeiters,
1483 GaoB, GERG2004Cosh, GERG2004Sinh;
1484 shared_ptr<CoolProp::ResidualHelmholtzGeneralizedExponential> Gaussian, Lemmon2005, Exponential, GERG2008, Power;
1485
1486 HelmholtzConsistencyFixture() {
1487 shared_ptr<AbstractCubic> _SRK(new SRK(300, 4e6, 0.3, 8.314461));
1488 _SRK->set_Tr(300);
1489 _SRK->set_rhor(4000);
1490 Soave.reset(new CoolProp::ResidualHelmholtzGeneralizedCubic(_SRK));
1491
1492 shared_ptr<AbstractCubic> _PR(new PengRobinson(300, 4e6, 0.3, 8.314461));
1493 _PR->set_Tr(300);
1494 _PR->set_rhor(4000);
1496
1497 {
1498 // Signs of eta are flipped relative to paper from Gao et al., implemented with opposite sign in CoolProp
1499 std::vector<CoolPropDbl> beta = {0.3696, 0.2962}, epsilon = {0.4478, 0.44689}, eta = {-2.8452, -2.8342}, gamma = {1.108, 1.313},
1500 n = {-1.6909858, 0.93739074}, t = {4.3315, 4.015}, d = {1, 1}, b = {1.244, 0.6826};
1501 GaoB.reset(new CoolProp::ResidualHelmholtzGaoB(n, t, d, eta, beta, gamma, epsilon, b));
1502 }
1503
1504 XiangDeiters.reset(new CoolProp::ResidualHelmholtzXiangDeiters(300, 4e6, 4000, 0.3, 8.3144621));
1505
1506 Lead.reset(new CoolProp::IdealHelmholtzLead(1, 3));
1507 LogTau.reset(new CoolProp::IdealHelmholtzLogTau(1.5));
1508 {
1509 std::vector<CoolPropDbl> n(4, 0), t(4, 1);
1510 n[0] = -0.1;
1511 n[2] = 0.1;
1512 t[1] = -1;
1513 t[2] = -2;
1514 t[3] = 2;
1515 IGPower.reset(new CoolProp::IdealHelmholtzPower(n, t));
1516 }
1517 {
1518 std::vector<CoolPropDbl> n(4, 0), t(4, 1), c(4, 1), d(4, -1);
1519 n[0] = 0.1;
1520 n[2] = 0.5;
1521 t[0] = -1.5;
1522 t[1] = -1;
1523 t[2] = -2;
1524 t[3] = -2;
1525 PlanckEinstein.reset(new CoolProp::IdealHelmholtzPlanckEinsteinGeneralized(n, t, c, d));
1526 }
1527 {
1528 std::vector<CoolPropDbl> c(3, 1), t(3, 0);
1529 t[1] = 1;
1530 t[2] = 2;
1531 c[1] = 2;
1532 c[2] = 3;
1533 CoolPropDbl T0 = 273.15, Tc = 345.857;
1534 CP0PolyT.reset(new CoolProp::IdealHelmholtzCP0PolyT(c, t, Tc, T0));
1535 }
1536 CP0Constant.reset(new CoolProp::IdealHelmholtzCP0Constant(4 / 8.314472, 300, 250));
1537 {
1538 // Nitrogen
1539 std::vector<CoolPropDbl> n(2, 0.0);
1540 n[0] = 0.137320000;
1541 n[1] = 0.900660000;
1542 std::vector<CoolPropDbl> theta(2, 0.0);
1543 theta[0] = 5.251822620;
1544 theta[1] = 13.788988208;
1545 CoolPropDbl rhomolar_crit = 11183.900000, T_crit = 126.192000000;
1546 GERG2004Cosh.reset(new CoolProp::IdealHelmholtzGERG2004Cosh(n, theta, T_crit));
1547 static_cast<CoolProp::IdealHelmholtzGERG2004Cosh*>(GERG2004Cosh.get())->set_Tred(T_crit * 1.3);
1548 }
1549 {
1550 // Nitrogen
1551 std::vector<CoolPropDbl> n(1, 0.0);
1552 n[0] = -0.146600000;
1553 std::vector<CoolPropDbl> theta(1, 0.0);
1554 theta[0] = -5.393067706;
1555 CoolPropDbl rhomolar_crit = 11183.900000, T_crit = 126.192000000;
1556 GERG2004Sinh.reset(new CoolProp::IdealHelmholtzGERG2004Sinh(n, theta, T_crit));
1557 static_cast<CoolProp::IdealHelmholtzGERG2004Sinh*>(GERG2004Sinh.get())->set_Tred(T_crit * 1.3);
1558 }
1559
1560 {
1561 CoolPropDbl beta[] = {1.24, 0.821, 15.45, 2.21, 437, 0.743}, d[] = {1, 1, 2, 2, 3, 3},
1562 epsilon[] = {0.6734, 0.9239, 0.8636, 1.0507, 0.8482, 0.7522}, eta[] = {0.9667, 1.5154, 1.0591, 1.6642, 12.4856, 0.9662},
1563 gamma[] = {1.2827, 0.4317, 1.1217, 1.1871, 1.1243, 0.4203},
1564 n[] = {1.2198, -0.4883, -0.0033293, -0.0035387, -0.51172, -0.16882}, t[] = {1, 2.124, 0.4, 3.5, 0.5, 2.7};
1566 Gaussian->add_Gaussian(
1567 std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(d, d + sizeof(d) / sizeof(d[0])),
1568 std::vector<CoolPropDbl>(t, t + sizeof(t) / sizeof(t[0])), std::vector<CoolPropDbl>(eta, eta + sizeof(eta) / sizeof(eta[0])),
1569 std::vector<CoolPropDbl>(epsilon, epsilon + sizeof(epsilon) / sizeof(epsilon[0])),
1570 std::vector<CoolPropDbl>(beta, beta + sizeof(beta) / sizeof(beta[0])),
1571 std::vector<CoolPropDbl>(gamma, gamma + sizeof(gamma) / sizeof(gamma[0])));
1572 }
1573 {
1574 CoolPropDbl d[] = {1, 1, 1, 2, 4, 1, 1, 2, 2, 3, 4, 5, 1, 5, 1, 2, 3, 5}, l[] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 2, 3, 3},
1575 m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.7, 7, 6},
1576 n[] = {5.28076, -8.67658, 0.7501127, 0.7590023, 0.01451899, 4.777189, -3.330988, 3.775673, -2.290919,
1577 0.8888268, -0.6234864, -0.04127263, -0.08455389, -0.1308752, 0.008344962, -1.532005, -0.05883649, 0.02296658},
1578 t[] = {0.669, 1.05, 2.75, 0.956, 1, 2, 2.75, 2.38, 3.37, 3.47, 2.63, 3.45, 0.72, 4.23, 0.2, 4.5, 29, 24};
1580 Lemmon2005->add_Lemmon2005(
1581 std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(d, d + sizeof(d) / sizeof(d[0])),
1582 std::vector<CoolPropDbl>(t, t + sizeof(t) / sizeof(t[0])), std::vector<CoolPropDbl>(l, l + sizeof(l) / sizeof(l[0])),
1583 std::vector<CoolPropDbl>(m, m + sizeof(m) / sizeof(m[0])));
1584 }
1585 {
1586 CoolPropDbl d[] = {1, 1, 1, 3, 7, 1, 2, 5, 1, 1, 4, 2}, l[] = {0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3},
1587 n[] = {1.0038, -2.7662, 0.42921, 0.081363, 0.00024174, 0.48246, 0.75542, -0.00743, -0.4146, -0.016558, -0.10644, -0.021704},
1588 t[] = {0.25, 1.25, 1.5, 0.25, 0.875, 2.375, 2, 2.125, 3.5, 6.5, 4.75, 12.5};
1590 Power->add_Power(std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(d, d + sizeof(d) / sizeof(d[0])),
1591 std::vector<CoolPropDbl>(t, t + sizeof(t) / sizeof(t[0])), std::vector<CoolPropDbl>(l, l + sizeof(l) / sizeof(l[0])));
1592 }
1593 {
1594
1595 CoolPropDbl a = 1, epsilonbar = 12.2735737, kappabar = 1.09117041e-05, m = 1.01871348, vbarn = 0.0444215309;
1596 SAFT.reset(new CoolProp::ResidualHelmholtzSAFTAssociating(a, m, epsilonbar, vbarn, kappabar));
1597 }
1598 {
1599 CoolPropDbl n[] = {-0.666422765408, 0.726086323499, 0.0550686686128}, A[] = {0.7, 0.7, 0.7}, B[] = {0.3, 0.3, 1}, C[] = {10, 10, 12.5},
1600 D[] = {275, 275, 275}, a[] = {3.5, 3.5, 3}, b[] = {0.875, 0.925, 0.875}, beta[] = {0.3, 0.3, 0.3};
1601 NonAnalytic.reset(new CoolProp::ResidualHelmholtzNonAnalytic(
1602 std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(a, a + sizeof(a) / sizeof(a[0])),
1603 std::vector<CoolPropDbl>(b, b + sizeof(b) / sizeof(b[0])), std::vector<CoolPropDbl>(beta, beta + sizeof(beta) / sizeof(beta[0])),
1604 std::vector<CoolPropDbl>(A, A + sizeof(A) / sizeof(A[0])), std::vector<CoolPropDbl>(B, B + sizeof(B) / sizeof(B[0])),
1605 std::vector<CoolPropDbl>(C, C + sizeof(C) / sizeof(C[0])), std::vector<CoolPropDbl>(D, D + sizeof(D) / sizeof(D[0]))));
1606 }
1607 {
1608 CoolPropDbl d[] = {2, 2, 2, 0, 0, 0}, g[] = {1.65533788, 1.65533788, 1.65533788, 1.65533788, 1.65533788, 1.65533788},
1609 l[] = {2, 2, 2, 2, 2, 2},
1610 n[] = {-3.821884669859, 8.30345065618981, -4.4832307260286, -1.02590136933231, 2.20786016506394, -1.07889905203761},
1611 t[] = {3, 4, 5, 3, 4, 5};
1613 Exponential->add_Exponential(
1614 std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(d, d + sizeof(d) / sizeof(n[0])),
1615 std::vector<CoolPropDbl>(t, t + sizeof(t) / sizeof(d[0])), std::vector<CoolPropDbl>(g, g + sizeof(g) / sizeof(t[0])),
1616 std::vector<CoolPropDbl>(l, l + sizeof(l) / sizeof(l[0])));
1617 }
1618 {
1619 CoolPropDbl d[] = {1, 4, 1, 2, 2, 2, 2, 2, 3}, t[] = {0.0, 1.85, 7.85, 5.4, 0.0, 0.75, 2.8, 4.45, 4.25},
1620 n[] = {-0.0098038985517335, 0.00042487270143005, -0.034800214576142, -0.13333813013896, -0.011993694974627,
1621 0.069243379775168, -0.31022508148249, 0.24495491753226, 0.22369816716981},
1622 eta[] = {0.0, 0.0, 1.0, 1.0, 0.25, 0.0, 0.0, 0.0, 0.0}, epsilon[] = {0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5},
1623 beta[] = {0.0, 0.0, 1.0, 1.0, 2.5, 3.0, 3.0, 3.0, 3.0}, gamma[] = {0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5};
1625 GERG2008->add_GERG2008Gaussian(
1626 std::vector<CoolPropDbl>(n, n + sizeof(n) / sizeof(n[0])), std::vector<CoolPropDbl>(d, d + sizeof(d) / sizeof(n[0])),
1627 std::vector<CoolPropDbl>(t, t + sizeof(t) / sizeof(d[0])), std::vector<CoolPropDbl>(eta, eta + sizeof(eta) / sizeof(eta[0])),
1628 std::vector<CoolPropDbl>(epsilon, epsilon + sizeof(epsilon) / sizeof(epsilon[0])),
1629 std::vector<CoolPropDbl>(beta, beta + sizeof(beta) / sizeof(beta[0])),
1630 std::vector<CoolPropDbl>(gamma, gamma + sizeof(gamma) / sizeof(gamma[0])));
1631 }
1632 }
1633 void call(std::string d, shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1634 if (!d.compare("dTau")) {
1635 return dTau(term, tau, delta, ddelta);
1636 } else if (!d.compare("dTau2")) {
1637 return dTau2(term, tau, delta, ddelta);
1638 } else if (!d.compare("dTau3")) {
1639 return dTau3(term, tau, delta, ddelta);
1640 } else if (!d.compare("dTau4")) {
1641 return dTau4(term, tau, delta, ddelta);
1642 } else if (!d.compare("dDelta")) {
1643 return dDelta(term, tau, delta, ddelta);
1644 } else if (!d.compare("dDelta2")) {
1645 return dDelta2(term, tau, delta, ddelta);
1646 } else if (!d.compare("dDelta3")) {
1647 return dDelta3(term, tau, delta, ddelta);
1648 } else if (!d.compare("dDelta4")) {
1649 return dDelta4(term, tau, delta, ddelta);
1650 } else if (!d.compare("dDelta_dTau")) {
1651 return dDelta_dTau(term, tau, delta, ddelta);
1652 } else if (!d.compare("dDelta_dTau2")) {
1653 return dDelta_dTau2(term, tau, delta, ddelta);
1654 } else if (!d.compare("dDelta2_dTau")) {
1655 return dDelta2_dTau(term, tau, delta, ddelta);
1656 } else if (!d.compare("dDelta3_dTau")) {
1657 return dDelta3_dTau(term, tau, delta, ddelta);
1658 } else if (!d.compare("dDelta2_dTau2")) {
1659 return dDelta2_dTau2(term, tau, delta, ddelta);
1660 } else if (!d.compare("dDelta_dTau3")) {
1661 return dDelta_dTau3(term, tau, delta, ddelta);
1662 } else {
1663 throw CoolProp::ValueError("don't understand deriv type");
1664 }
1665 }
1666 shared_ptr<CoolProp::BaseHelmholtzTerm> get(std::string t) {
1667 if (!t.compare("Lead")) {
1668 return Lead;
1669 } else if (!t.compare("LogTau")) {
1670 return LogTau;
1671 } else if (!t.compare("IGPower")) {
1672 return IGPower;
1673 } else if (!t.compare("PlanckEinstein")) {
1674 return PlanckEinstein;
1675 } else if (!t.compare("CP0Constant")) {
1676 return CP0Constant;
1677 } else if (!t.compare("CP0PolyT")) {
1678 return CP0PolyT;
1679 } else if (!t.compare("GERG2004Cosh")) {
1680 return GERG2004Cosh;
1681 } else if (!t.compare("GERG2004Sinh")) {
1682 return GERG2004Sinh;
1683 } else if (!t.compare("SRK")) {
1684 return Soave;
1685 } else if (!t.compare("PengRobinson")) {
1686 return PR;
1687 } else if (!t.compare("XiangDeiters")) {
1688 return XiangDeiters;
1689 } else if (!t.compare("GaoB")) {
1690 return GaoB;
1691 }
1692
1693 else if (!t.compare("Gaussian")) {
1694 return Gaussian;
1695 } else if (!t.compare("Lemmon2005")) {
1696 return Lemmon2005;
1697 } else if (!t.compare("Power")) {
1698 return Power;
1699 } else if (!t.compare("SAFT")) {
1700 return SAFT;
1701 } else if (!t.compare("NonAnalytic")) {
1702 return NonAnalytic;
1703 } else if (!t.compare("Exponential")) {
1704 return Exponential;
1705 } else if (!t.compare("GERG2008")) {
1706 return GERG2008;
1707 } else {
1708 throw CoolProp::ValueError(format("don't understand helmholtz type: %s", t.c_str()));
1709 }
1710 }
1711 void dTau(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl dtau) {
1712 CoolPropDbl term_plus = term->base(tau + dtau, delta);
1713 CoolPropDbl term_minus = term->base(tau - dtau, delta);
1714 numerical = (term_plus - term_minus) / (2 * dtau);
1715 analytic = term->dTau(tau, delta);
1716 };
1717 void dTau2(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl dtau) {
1718 CoolPropDbl term_plus = term->dTau(tau + dtau, delta);
1719 CoolPropDbl term_minus = term->dTau(tau - dtau, delta);
1720 numerical = (term_plus - term_minus) / (2 * dtau);
1721 analytic = term->dTau2(tau, delta);
1722 };
1723 void dTau3(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl dtau) {
1724 CoolPropDbl term_plus = term->dTau2(tau + dtau, delta);
1725 CoolPropDbl term_minus = term->dTau2(tau - dtau, delta);
1726 numerical = (term_plus - term_minus) / (2 * dtau);
1727 analytic = term->dTau3(tau, delta);
1728 };
1729 void dTau4(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl dtau) {
1730 CoolPropDbl term_plus = term->dTau3(tau + dtau, delta);
1731 CoolPropDbl term_minus = term->dTau3(tau - dtau, delta);
1732 numerical = (term_plus - term_minus) / (2 * dtau);
1733 analytic = term->dTau4(tau, delta);
1734 };
1735 void dDelta(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1736 CoolPropDbl term_plus = term->base(tau, delta + ddelta);
1737 CoolPropDbl term_minus = term->base(tau, delta - ddelta);
1738 numerical = (term_plus - term_minus) / (2 * ddelta);
1739 analytic = term->dDelta(tau, delta);
1740 };
1741 void dDelta2(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1742 CoolPropDbl term_plus = term->dDelta(tau, delta + ddelta);
1743 CoolPropDbl term_minus = term->dDelta(tau, delta - ddelta);
1744 numerical = (term_plus - term_minus) / (2 * ddelta);
1745 analytic = term->dDelta2(tau, delta);
1746 };
1747 void dDelta3(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1748 CoolPropDbl term_plus = term->dDelta2(tau, delta + ddelta);
1749 CoolPropDbl term_minus = term->dDelta2(tau, delta - ddelta);
1750 numerical = (term_plus - term_minus) / (2 * ddelta);
1751 analytic = term->dDelta3(tau, delta);
1752 };
1753 void dDelta4(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1754 CoolPropDbl term_plus = term->dDelta3(tau, delta + ddelta);
1755 CoolPropDbl term_minus = term->dDelta3(tau, delta - ddelta);
1756 numerical = (term_plus - term_minus) / (2 * ddelta);
1757 analytic = term->dDelta4(tau, delta);
1758 };
1759 void dDelta_dTau(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1760 CoolPropDbl term_plus = term->dTau(tau, delta + ddelta);
1761 CoolPropDbl term_minus = term->dTau(tau, delta - ddelta);
1762 numerical = (term_plus - term_minus) / (2 * ddelta);
1763 analytic = term->dDelta_dTau(tau, delta);
1764 };
1765 void dDelta_dTau2(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1766 CoolPropDbl term_plus = term->dTau2(tau, delta + ddelta);
1767 CoolPropDbl term_minus = term->dTau2(tau, delta - ddelta);
1768 numerical = (term_plus - term_minus) / (2 * ddelta);
1769 analytic = term->dDelta_dTau2(tau, delta);
1770 };
1771 void dDelta2_dTau(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1772 CoolPropDbl term_plus = term->dDelta_dTau(tau, delta + ddelta);
1773 CoolPropDbl term_minus = term->dDelta_dTau(tau, delta - ddelta);
1774 numerical = (term_plus - term_minus) / (2 * ddelta);
1775 analytic = term->dDelta2_dTau(tau, delta);
1776 };
1777 void dDelta3_dTau(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1778 CoolPropDbl term_plus = term->dDelta2_dTau(tau, delta + ddelta);
1779 CoolPropDbl term_minus = term->dDelta2_dTau(tau, delta - ddelta);
1780 numerical = (term_plus - term_minus) / (2 * ddelta);
1781 analytic = term->dDelta3_dTau(tau, delta);
1782 };
1783 void dDelta2_dTau2(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1784 CoolPropDbl term_plus = term->dDelta_dTau2(tau, delta + ddelta);
1785 CoolPropDbl term_minus = term->dDelta_dTau2(tau, delta - ddelta);
1786 numerical = (term_plus - term_minus) / (2 * ddelta);
1787 analytic = term->dDelta2_dTau2(tau, delta);
1788 };
1789 void dDelta_dTau3(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, CoolPropDbl ddelta) {
1790 CoolPropDbl term_plus = term->dTau3(tau, delta + ddelta);
1791 CoolPropDbl term_minus = term->dTau3(tau, delta - ddelta);
1792 numerical = (term_plus - term_minus) / (2 * ddelta);
1793 analytic = term->dDelta_dTau3(tau, delta);
1794 };
1795 double get_analytic_mcx(shared_ptr<CoolProp::BaseHelmholtzTerm> term, CoolPropDbl tau, CoolPropDbl delta, int ntau, int ndelta) {
1796 try {
1797 using fcn_t = std::function<mcx::MultiComplex<double>(const std::vector<mcx::MultiComplex<double>>&)>;
1798 fcn_t f = [&term](const std::vector<mcx::MultiComplex<double>>& x) { return term->one_mcx(x[0], x[1]); };
1799 return mcx::diff_mcxN(f, std::vector<double>{tau, delta}, std::vector<int>{ntau, ndelta});
1800 } catch (CoolProp::NotImplementedError e) {
1801 return _HUGE;
1802 }
1803 }
1804 double err(double v1, double v2) {
1805 if (std::abs(v2) > 1e-15) {
1806 return std::abs((v1 - v2) / v2);
1807 } else {
1808 return std::abs(v1 - v2);
1809 }
1810 }
1811};
1812
1813std::string terms[] = {"Lead", "LogTau", "IGPower", "PlanckEinstein", "CP0Constant", "CP0PolyT", "Gaussian",
1814 "Lemmon2005", "Power", "SAFT", "NonAnalytic", "Exponential", "GERG2008", "SRK",
1815 "PengRobinson", "XiangDeiters", "GaoB", "GERG2004Cosh", "GERG2004Sinh"};
1816std::string derivs[] = {"dTau", "dTau2", "dTau3", "dDelta", "dDelta2", "dDelta3", "dDelta_dTau",
1817 "dDelta_dTau2", "dDelta2_dTau", "dTau4", "dDelta_dTau3", "dDelta2_dTau2", "dDelta3_dTau", "dDelta4"};
1818std::map<std::string, std::tuple<int, int>> counts = {
1819 {"dTau", {1, 0}}, {"dTau2", {2, 0}}, {"dTau3", {3, 0}}, {"dTau4", {4, 0}}, {"dDelta", {0, 1}},
1820 {"dDelta2", {0, 2}}, {"dDelta3", {0, 3}}, {"dDelta4", {0, 4}}, {"dDelta_dTau", {1, 1}}, {"dDelta_dTau2", {2, 1}},
1821 {"dDelta2_dTau", {1, 2}}, {"dDelta_dTau3", {3, 1}}, {"dDelta2_dTau2", {2, 2}}, {"dDelta3_dTau", {1, 3}},
1822};
1823
1824TEST_CASE_METHOD(HelmholtzConsistencyFixture, "Helmholtz energy derivatives", "[helmholtz]") {
1825 shared_ptr<CoolProp::BaseHelmholtzTerm> term;
1826 std::size_t n = sizeof(terms) / sizeof(terms[0]);
1827 for (std::size_t i = 0; i < n; ++i) {
1828 term = get(terms[i]);
1829 for (std::size_t j = 0; j < sizeof(derivs) / sizeof(derivs[0]); ++j) {
1830 if (terms[i] == "SAFT"
1831 && (derivs[j] == "dTau4" || derivs[j] == "dDelta_dTau3" || derivs[j] == "dDelta2_dTau2" || derivs[j] == "dDelta3_dTau"
1832 || derivs[j] == "dDelta4")) {
1833 continue;
1834 }
1835 double tau = 1.3, delta = 0.9;
1836 call(derivs[j], term, tau, delta, 1e-5);
1837 double alphar = term->base(tau, delta);
1838
1839 // Do calculations with multicomplex, if the one_mcx function has been implemented
1840 auto [ntau, ndelta] = counts.at(derivs[j]);
1841 double numerical_mcx = _HUGE;
1842 double alphar_mcx = _HUGE;
1843 try {
1844 numerical_mcx = get_analytic_mcx(term, tau, delta, ntau, ndelta);
1845 alphar_mcx = term->one_mcx(tau, delta).real();
1846 } catch (std::exception& /* e */) {
1847 //std::cout << e.what() << std::endl;
1848 }
1849 CAPTURE(alphar_mcx);
1850 CAPTURE(numerical_mcx);
1851
1852 CAPTURE(derivs[j]);
1853 CAPTURE(alphar);
1854 double numerical_finitediff = numerical;
1855 CAPTURE(numerical_finitediff);
1856 CAPTURE(analytic);
1857 CAPTURE(terms[i]);
1858 double deriv_tolerance = 1e-9;
1859 if (terms[i] == "GERG2004Cosh" || terms[i] == "GERG2004Sinh" || terms[i] == "CP0PolyT") {
1860 deriv_tolerance = 1e-7; // due to, I think, a loss in precision in the log function of multicomplex
1861 }
1862 double val_tolerance = 1e-14;
1863 if (terms[i] == "CP0PolyT") {
1864 val_tolerance = 1e-10; // due to, I think, a loss in precision in the log function of multicomplex
1865 }
1866 if (terms[i] == "GaoB") {
1867 val_tolerance = 1e-12; // due to, I think, a loss in precision in the log function of multicomplex
1868 }
1869
1870 if (std::isfinite(numerical_mcx)) {
1871 CHECK(err(analytic, numerical_mcx) < deriv_tolerance);
1872 CHECK(err(alphar, alphar_mcx) < val_tolerance);
1873 } else {
1874 CHECK(err(analytic, numerical_finitediff) < deriv_tolerance);
1875 }
1876 }
1877 }
1878}
1879
1880#endif