44 double term1 = partial_molar_volumeval / (R_u * HEOS.
_T);
45 double term2 = 1.0 / HEOS.
p();
59 std::size_t N = x.size();
70 throw ValueError(
"dln_fugacity_dxj__constT_rho_xi only valid for xN_DEPENDENT for now");
83 std::size_t N = x.size();
90 line3 += -1 / x[N - 1];
96 return line1 + line2 + line3 + line4;
147 for (
unsigned int m = 0; m < mmax; ++m) {
219 for (
unsigned int k = 0; k < kmax; ++k) {
227 + HEOS.
_delta.
pt() * nd2alphar_dni_dDelta);
240 for (
unsigned int k = 0; k < kmax; k++) {
244 return term1 + term2 + term3 - s;
261 return -HEOS.
delta() / rhor
281 return HEOS.
tau() /
Tr
310 for (
unsigned int k = 0; k < kmax; k++) {
314 return line1 + line2 + line3 + line4 + line5;
332 for (
unsigned int k = 0; k < kmax; k++) {
335 return line1 + line2 + line3;
347 for (
unsigned int k = 0; k < kmax; k++) {
351 return line1 + line2 + line3;
363 for (
unsigned int k = 0; k < kmax; k++) {
367 return line1 + line2 + line3 + line4;
379 for (
unsigned int k = 0; k < kmax; k++) {
383 return line1 + line2 + line3 + line4;
396 for (
unsigned int k = 0; k < kmax; k++) {
400 return line1 + line2 + line3 + line4 + line5;
412 for (
unsigned int k = 0; k < kmax; k++) {
416 return line1 + line2 + line3;
433 for (
unsigned int m = 0; m < mmax; m++) {
436 return line1 + line2 + line3;
454 for (
unsigned int m = 0; m < mmax; m++) {
457 return line1 + line2 + line3;
474 for (
unsigned int m = 0; m < mmax; m++) {
477 return line1 + line2 + line3;
494 for (
unsigned int k = 0; k < kmax; k++) {
497 return term1 + term2 + term3;
507 for (
unsigned int k = 0; k < kmax; k++) {
510 return term1 + term2 + term3;
520 for (
unsigned int k = 0; k < kmax; k++) {
523 return term1 + term2 + term3;
534 for (
unsigned int k = 0; k < kmax; k++) {
537 return term1 + term2 + term3;
549 for (
unsigned int k = 0; k < kmax; k++) {
552 return term1 + term2 + term3;
564 for (
unsigned int k = 0; k < kmax; k++) {
567 return term1 + term2 + term3;
577 for (
unsigned int k = 0; k < kmax; k++) {
580 return term1 + term2 + term3;
590 for (
unsigned int k = 0; k < kmax; k++) {
593 return term1 + term2 + term3;
611 for (
unsigned int k = 0; k < kmax; k++) {
615 return term1 + term2 + term3 + term4 + term5;
631 for (
unsigned int k = 0; k < kmax; k++) {
635 return term1 + term2 + term3 + term4 + term5;
651 for (
unsigned int k = 0; k < kmax; k++) {
655 return term1 + term2 + term3 + term4 + term5;
667 double term5 = HEOS.
residual_helmholtz->d4alphar_dxi_dxj_dDelta2(HEOS, i, j, xN_flag);
672 for (
unsigned int k = 0; k < kmax; k++) {
676 return term1 + term2 + term3 + term4 + term5;
690 double term5 = HEOS.
residual_helmholtz->d4alphar_dxi_dxj_dDelta_dTau(HEOS, i, j, xN_flag);
695 for (
unsigned int k = 0; k < kmax; k++) {
699 return term1 + term2 + term3 + term4 + term5;
717 for (
unsigned int k = 0; k < kmax; k++) {
720 return term1 + term2 + term3;
747 for (
unsigned int m = 0; m < mmax; m++) {
751 return term1 + term2 + term3 + term4 + term5 + term6 + term7;
763 double term1 = term1a + term1b + term1c + term1d;
776 double term2 = term2a + term2b + term2c + term2d;
778 double term3 = HEOS.
residual_helmholtz->d4alphar_dxi_dxj_dxk_dTau(HEOS, i, j, k, xN_flag)
784 for (
unsigned int m = 0; m < mmax; m++) {
788 return term1 + term2 + term3;
804 double term1 = term1a + term1b + term1c + term1d;
813 double term2 = term2a + term2b + term2c + term2d;
815 double term3 = HEOS.
residual_helmholtz->d4alphar_dxi_dxj_dxk_dDelta(HEOS, i, j, k, xN_flag)
821 for (
unsigned int m = 0; m < mmax; m++) {
824 return term1 + term2 + term3;
835 double tau_oi = HEOS.
tau() * Tci /
Tr;
836 double delta_oi = HEOS.
delta() * rhor / rhoci;
840 double term = Rratioi * HEOS.
components[i].EOS().alpha0.base(tau_oi, delta_oi) + logxi + 1;
846 for (std::size_t k = 0; k < kmax; ++k) {
850 double tau_ok = HEOS.
tau() * Tck /
Tr;
851 double delta_ok = HEOS.
delta() * rhor / rhock;
853 double ddeltaok_dxi = delta_ok / rhor * HEOS.
Reducing->drhormolardxi__constxj(HEOS.
mole_fractions, i, xN_flag);
857 double dalpha0_ok_dxi = alpha0kterms.dalphar_dtau * dtauok_dxi + alpha0kterms.dalphar_ddelta * ddeltaok_dxi;
858 term += xk * (Rratiok * dalpha0_ok_dxi);
871 double tau_oi = HEOS.
tau() * Tci /
Tr;
872 double delta_oi = HEOS.
delta() * rhor / rhoci;
875 double term = rhor / rhoci * Rratioi * HEOS.
components[i].EOS().alpha0.dDelta(tau_oi, delta_oi);
881 for (std::size_t k = 0; k < kmax; ++k) {
885 double tau_ok = HEOS.
tau() * Tck /
Tr;
886 double delta_ok = HEOS.
delta() * rhor / rhock;
889 double ddeltaok_dxi = delta_ok / rhor * drhor_dxi;
893 double dalpha0ok_ddeltaok = alpha0kterms.dalphar_ddelta;
895 double d_dalpha0ok_ddeltaok_dxi = alpha0kterms.d2alphar_ddelta_dtau * dtauok_dxi + alpha0kterms.d2alphar_ddelta2 * ddeltaok_dxi;
896 term += xk / rhock * (rhor * d_dalpha0ok_ddeltaok_dxi + drhor_dxi * dalpha0ok_ddeltaok);
909 double tau_oi = HEOS.
tau() * Tci /
Tr;
910 double delta_oi = HEOS.
delta() * rhor / rhoci;
913 double term = Tci /
Tr * Rratioi * HEOS.
components[i].EOS().alpha0.dTau(tau_oi, delta_oi);
919 for (std::size_t k = 0; k < kmax; ++k) {
923 double tau_ok = HEOS.
tau() * Tck /
Tr;
924 double delta_ok = HEOS.
delta() * rhor / rhock;
926 double dtauok_dxi = -tau_ok /
Tr * dTr_dxi;
928 double ddeltaok_dxi = delta_ok / rhor * drhor_dxi;
932 double dalpha0ok_dtauok = alpha0kterms.dalphar_dtau;
933 double d_dalpha0ok_dTauok_dxi = alpha0kterms.d2alphar_dtau2 * dtauok_dxi + alpha0kterms.d2alphar_ddelta_dtau * ddeltaok_dxi;
934 term += xk * Tck * (1 /
Tr * d_dalpha0ok_dTauok_dxi + -1 /
POW2(
Tr) * dTr_dxi * dalpha0ok_dtauok);
947 double tau_oi = HEOS.
tau() * Tci /
Tr;
948 double delta_oi = HEOS.
delta() * rhor / rhoci;
955 double tau_oj = HEOS.
tau() * Tcj /
Tr;
956 double delta_oj = HEOS.
delta() * rhor / rhocj;
961 double dtauoi_dxj = -tau_oi /
Tr * dTr_dxj;
962 double ddeltaoi_dxj = delta_oi / rhor * drhor_dxj;
963 double dtauoj_dxi = -tau_oj /
Tr * dTr_dxi;
964 double ddeltaoj_dxi = delta_oj / rhor * drhor_dxi;
970 alpha0jterms = HEOS.
components[j].EOS().alpha0.all(tau_oj, delta_oj);
972 double d_dalpha0oi_dxj = alpha0iterms.dalphar_dtau * dtauoi_dxj + alpha0iterms.dalphar_ddelta * ddeltaoi_dxj;
973 double d_dalpha0oj_dxi = alpha0jterms.dalphar_dtau * dtauoj_dxi + alpha0jterms.dalphar_ddelta * ddeltaoj_dxi;
977 double term = d_dalpha0oi_dxj + d_dalpha0oj_dxi + Kronecker_delta_over_xi;
983 for (std::size_t k = 0; k < kmax; ++k) {
988 double tau_ok = HEOS.
tau() * Tck /
Tr;
989 double delta_ok = HEOS.
delta() * rhor / rhock;
991 double dtauok_dxj = -tau_ok /
Tr * dTr_dxj;
992 double ddeltaok_dxj = delta_ok / rhor * drhor_dxj;
993 double dtauok_dxi = -tau_ok /
Tr * dTr_dxi;
994 double ddeltaok_dxi = delta_ok / rhor * drhor_dxi;
997 double dalpha0ok_dtauok = alpha0kterms.dalphar_dtau;
998 double d2tauok_dxidxj = -Tck * HEOS.
tau() * (
POW2(
Tr) * d2Tr_dxidxj - dTr_dxi * (2 *
Tr * dTr_dxj)) /
POW4(
Tr);
999 double d_dalpha0ok_dtauok_dxj = alpha0kterms.d2alphar_dtau2 * dtauok_dxj + alpha0kterms.d2alphar_ddelta_dtau * ddeltaok_dxj;
1001 double dalpha0ok_ddeltaok = alpha0kterms.dalphar_ddelta;
1002 double d2deltaok_dxidxj = HEOS.
delta() / rhock * d2rhor_dxidxj;
1003 double d_dalpha0ok_ddeltaok_dxj = alpha0kterms.d2alphar_ddelta_dtau * dtauok_dxj + alpha0kterms.d2alphar_ddelta2 * ddeltaok_dxj;
1006 * (dalpha0ok_dtauok * d2tauok_dxidxj + d_dalpha0ok_dtauok_dxj * dtauok_dxi + dalpha0ok_ddeltaok * d2deltaok_dxidxj
1007 + d_dalpha0ok_ddeltaok_dxj * ddeltaok_dxi);
1106# include <catch2/catch_all.hpp>
1113double mix_deriv_err_func(
double numeric,
double analytic) {
1115 return std::abs(numeric - analytic);
1117 return std::abs(numeric / analytic - 1);
1146template <
class backend>
1147class DerivativeFixture
1150 shared_ptr<CoolProp::HelmholtzEOSMixtureBackend> HEOS, HEOS_plus_tau, HEOS_minus_tau, HEOS_plus_delta, HEOS_minus_delta, HEOS_plus_2tau, HEOS_minus_2tau, HEOS_plus_2delta, HEOS_minus_2delta, HEOS_plus_T__constp,
1151 HEOS_minus_T__constp, HEOS_plus_p__constT, HEOS_minus_p__constT, HEOS_plus_T__constrho, HEOS_minus_T__constrho, HEOS_plus_rho__constT,
1152 HEOS_minus_rho__constT;
1153 std::vector<shared_ptr<CoolProp::HelmholtzEOSMixtureBackend>> HEOS_plus_z, HEOS_minus_z, HEOS_plus_z__constTrho, HEOS_minus_z__constTrho,
1154 HEOS_plus_n, HEOS_minus_n, HEOS_plus_2z, HEOS_minus_2z, HEOS_plus_2z__constTrho, HEOS_minus_2z__constTrho;
1156 double dtau, ddelta, dz, dn, tol, dT, drho, dp;
1166 std::vector<std::string> names;
1167 names.push_back(
"n-Pentane");
1168 names.push_back(
"Ethane");
1169 names.push_back(
"n-Propane");
1170 names.push_back(
"n-Butane");
1171 std::vector<CoolPropDbl> mole_fractions;
1172 mole_fractions.push_back(0.1);
1173 mole_fractions.push_back(0.12);
1174 mole_fractions.push_back(0.18);
1175 mole_fractions.push_back(0.6);
1176 HEOS.reset(
new backend(names));
1177 HEOS->set_mole_fractions(mole_fractions);
1179 HEOS->update_DmolarT_direct(300, 300);
1181 init_state(HEOS_plus_tau);
1182 init_state(HEOS_minus_tau);
1183 init_state(HEOS_plus_2tau);
1184 init_state(HEOS_minus_2tau);
1185 init_state(HEOS_plus_delta);
1186 init_state(HEOS_minus_delta);
1187 init_state(HEOS_plus_2delta);
1188 init_state(HEOS_minus_2delta);
1189 init_state(HEOS_plus_T__constp);
1190 init_state(HEOS_minus_T__constp);
1191 init_state(HEOS_plus_p__constT);
1192 init_state(HEOS_minus_p__constT);
1193 init_state(HEOS_plus_T__constrho);
1194 init_state(HEOS_minus_T__constrho);
1195 init_state(HEOS_plus_rho__constT);
1196 init_state(HEOS_minus_rho__constT);
1198 HEOS_plus_tau->update(
CoolProp::DmolarT_INPUTS, HEOS->delta() * HEOS->rhomolar_reducing(), HEOS->T_reducing() / (HEOS->tau() + dtau));
1199 HEOS_minus_tau->update(
CoolProp::DmolarT_INPUTS, HEOS->delta() * HEOS->rhomolar_reducing(), HEOS->T_reducing() / (HEOS->tau() - dtau));
1200 HEOS_plus_2tau->update(
CoolProp::DmolarT_INPUTS, HEOS->delta() * HEOS->rhomolar_reducing(), HEOS->T_reducing() / (HEOS->tau() + 2*dtau));
1201 HEOS_minus_2tau->update(
CoolProp::DmolarT_INPUTS, HEOS->delta() * HEOS->rhomolar_reducing(), HEOS->T_reducing() / (HEOS->tau() - 2*dtau));
1202 HEOS_plus_delta->update(
CoolProp::DmolarT_INPUTS, (HEOS->delta() + ddelta) * HEOS->rhomolar_reducing(), HEOS->T_reducing() / HEOS->tau());
1203 HEOS_minus_delta->update(
CoolProp::DmolarT_INPUTS, (HEOS->delta() - ddelta) * HEOS->rhomolar_reducing(), HEOS->T_reducing() / HEOS->tau());
1204 HEOS_plus_2delta->update(
CoolProp::DmolarT_INPUTS, (HEOS->delta() + 2*ddelta) * HEOS->rhomolar_reducing(), HEOS->T_reducing() / HEOS->tau());
1205 HEOS_minus_2delta->update(
CoolProp::DmolarT_INPUTS, (HEOS->delta() - 2*ddelta) * HEOS->rhomolar_reducing(), HEOS->T_reducing() / HEOS->tau());
1216 HEOS_plus_z.resize(4);
1217 HEOS_minus_z.resize(4);
1218 HEOS_plus_z__constTrho.resize(4);
1219 HEOS_minus_z__constTrho.resize(4);
1220 HEOS_plus_2z.resize(4);
1221 HEOS_minus_2z.resize(4);
1222 HEOS_plus_2z__constTrho.resize(4);
1223 HEOS_minus_2z__constTrho.resize(4);
1224 for (
int i = 0; i < HEOS_plus_z.size(); ++i) {
1225 init_state(HEOS_plus_z[i]);
1226 init_state(HEOS_plus_2z[i]);
1227 init_state(HEOS_plus_z__constTrho[i]);
1228 std::vector<double> zz = HEOS->get_mole_fractions(), zz2 = HEOS->get_mole_fractions();
1232 zz[zz.size() - 1] -= dz;
1233 zz2[zz2.size() - 1] -= 2 * dz;
1235 HEOS_plus_z[i]->set_mole_fractions(zz);
1237 HEOS_plus_z[i]->T_reducing() / HEOS->tau());
1238 HEOS_plus_2z[i]->set_mole_fractions(zz2);
1240 HEOS_plus_2z[i]->T_reducing() / HEOS->tau());
1241 HEOS_plus_z__constTrho[i]->set_mole_fractions(zz);
1244 for (
int i = 0; i < HEOS_minus_z.size(); ++i) {
1245 init_state(HEOS_minus_z[i]);
1246 init_state(HEOS_minus_2z[i]);
1247 init_state(HEOS_minus_z__constTrho[i]);
1248 std::vector<double> zz = HEOS->get_mole_fractions(), zz2 = HEOS->get_mole_fractions();
1252 zz[zz.size() - 1] += dz;
1253 zz2[zz2.size() - 1] += 2 * dz;
1255 HEOS_minus_z[i]->set_mole_fractions(zz);
1257 HEOS_minus_z[i]->T_reducing() / HEOS->tau());
1258 HEOS_minus_2z[i]->set_mole_fractions(zz2);
1260 HEOS_minus_2z[i]->T_reducing() / HEOS->tau());
1261 HEOS_minus_z__constTrho[i]->set_mole_fractions(zz);
1266 HEOS_plus_n.resize(4);
1267 HEOS_minus_n.resize(4);
1268 for (
int i = 0; i < HEOS_plus_n.size(); ++i) {
1269 init_state(HEOS_plus_n[i]);
1270 std::vector<double> zz = HEOS->get_mole_fractions();
1272 for (
int j = 0; j < HEOS_minus_n.size(); ++j) {
1275 HEOS_plus_n[i]->set_mole_fractions(zz);
1277 HEOS_plus_n[i]->T_reducing() / HEOS->tau());
1279 for (
int i = 0; i < HEOS_plus_z.size(); ++i) {
1280 init_state(HEOS_minus_n[i]);
1281 std::vector<double> zz = HEOS->get_mole_fractions();
1283 for (
int j = 0; j < HEOS_minus_n.size(); ++j) {
1286 HEOS_minus_n[i]->set_mole_fractions(zz);
1288 HEOS_minus_n[i]->T_reducing() / HEOS->tau());
1291 void init_state(shared_ptr<CoolProp::HelmholtzEOSMixtureBackend>& other) {
1292 other.reset(HEOS->get_copy());
1293 other->set_mole_fractions(HEOS->get_mole_fractions());
1296 void zero(
const std::string& name, zero_mole_fraction_pointer f, zero_mole_fraction_pointer g = NULL, derivative wrt = NO_DERIV) {
1297 double analytic = f(*HEOS, xN);
1300 numeric = (g(*HEOS_plus_tau, xN) - g(*HEOS_minus_tau, xN)) / (2 * dtau);
1301 }
else if (wrt == DELTA) {
1302 numeric = (g(*HEOS_plus_delta, xN) - g(*HEOS_minus_delta, xN)) / (2 * ddelta);
1308 double error = mix_deriv_err_func(numeric, analytic);
1312 void one(
const std::string& name, one_mole_fraction_pointer f, one_mole_fraction_pointer g = NULL, derivative wrt = NO_DERIV) {
1313 for (
int i = 0; i < 4; ++i) {
1314 double analytic = f(*HEOS, i, xN);
1317 numeric = (g(*HEOS_plus_tau, i, xN) - g(*HEOS_minus_tau, i, xN)) / (2 * dtau);
1318 }
else if (wrt == DELTA) {
1319 numeric = (g(*HEOS_plus_delta, i, xN) - g(*HEOS_minus_delta, i, xN)) / (2 * ddelta);
1320 }
else if (wrt == T_CONSTP) {
1321 numeric = (g(*HEOS_plus_T__constp, i, xN) - g(*HEOS_minus_T__constp, i, xN)) / (2 * dT);
1322 }
else if (wrt == P_CONSTT) {
1323 numeric = (g(*HEOS_plus_p__constT, i, xN) - g(*HEOS_minus_p__constT, i, xN)) / (2 * dp);
1324 }
else if (wrt == T_CONSTRHO) {
1325 double g1 = g(*HEOS_plus_T__constrho, i, xN), g2 = g(*HEOS_minus_T__constrho, i, xN);
1326 numeric = (g1 - g2) / (2 * dT);
1327 }
else if (wrt == RHO_CONSTT) {
1328 numeric = (g(*HEOS_plus_rho__constT, i, xN) - g(*HEOS_minus_rho__constT, i, xN)) / (2 * drho);
1335 double error = mix_deriv_err_func(numeric, analytic);
1340 void one_comp(
const std::string& name, one_mole_fraction_pointer f, zero_mole_fraction_pointer g, derivative wrt = CONST_TAU_DELTA) {
1341 for (
int i = 0; i < 4; ++i) {
1343 CHECK_NOTHROW(analytic = f(*HEOS, i, xN));
1344 double numeric = -10000;
1345 if (wrt == CONST_TAU_DELTA) {
1346 if (HEOS->get_mole_fractions()[i] > dz) {
1347 CHECK_NOTHROW(numeric = (g(*HEOS_plus_z[i], xN) - g(*HEOS_minus_z[i], xN)) / (2 * dz));
1349 CHECK_NOTHROW(numeric = (-3 * g(*HEOS, xN) + 4 * g(*HEOS_plus_z[i], xN) - g(*HEOS_plus_2z[i], xN)) / (2 * dz));
1351 }
else if (wrt == CONST_TRHO) {
1352 CHECK_NOTHROW(numeric = (g(*HEOS_plus_z__constTrho[i], xN) - g(*HEOS_minus_z__constTrho[i], xN)) / (2 * dz));
1360 double error = mix_deriv_err_func(numeric, analytic);
1365 void two(
const std::string& name, two_mole_fraction_pointer f, two_mole_fraction_pointer g = NULL, derivative wrt = NO_DERIV) {
1366 for (
int i = 0; i < 4; ++i) {
1367 for (
int j = 0; j < 4; ++j) {
1368 double analytic = f(*HEOS, i, j, xN);
1369 bool is_other =
false;
1372 numeric = (g(*HEOS_plus_tau, i, j, xN) - g(*HEOS_minus_tau, i, j, xN)) / (2 * dtau);
1374 }
else if (wrt == DELTA) {
1375 numeric = (g(*HEOS_plus_delta, i, j, xN) - g(*HEOS_minus_delta, i, j, xN)) / (2 * ddelta);
1384 double error = mix_deriv_err_func(numeric, analytic);
1390 void two_comp(
const std::string& name, two_mole_fraction_pointer f, one_mole_fraction_pointer g, derivative wrt = NO_DERIV) {
1391 for (
int i = 0; i < 4; ++i) {
1392 for (
int j = 0; j < 4; ++j) {
1393 double analytic = f(*HEOS, i, j, xN);
1394 double numeric = 500;
1395 if (HEOS->get_mole_fractions()[j] > 2 * dz) {
1397 CHECK_NOTHROW(numeric = (g(*HEOS_plus_z[j], i, xN) - g(*HEOS_minus_z[j], i, xN)) / (2 * dz));
1400 CHECK_NOTHROW(numeric = (-3 * g(*HEOS, i, xN) + 4 * g(*HEOS_plus_z[j], i, xN) - g(*HEOS_plus_2z[j], i, xN)) / (2 * dz));
1408 double error = mix_deriv_err_func(numeric, analytic);
1414 void three(
const std::string& name, three_mole_fraction_pointer f, three_mole_fraction_pointer g = NULL, derivative wrt = NO_DERIV) {
1415 for (
int i = 0; i < 4; ++i) {
1416 for (
int j = 0; j < 4; ++j) {
1417 for (
int k = 0; k < 4; ++k) {
1418 double analytic = f(*HEOS, i, j, k, xN);
1421 numeric = (-1.0/12.0*g(*HEOS_plus_2tau, i, j, k, xN) + 2.0/3.0*g(*HEOS_plus_tau, i, j, k, xN) -2.0/3.0*g(*HEOS_minus_tau, i, j, k, xN) +1.0/12.0*g(*HEOS_minus_2tau, i, j, k, xN)) / dtau;
1422 }
else if (wrt == DELTA) {
1423 numeric = (-1.0/12.0*g(*HEOS_plus_2delta, i, j, k, xN) + 2.0/3.0*g(*HEOS_plus_delta, i, j, k, xN) -2.0/3.0*g(*HEOS_minus_delta, i, j, k, xN) +1.0/12.0*g(*HEOS_minus_2delta, i, j, k, xN)) / ddelta;
1431 double error = mix_deriv_err_func(numeric, analytic);
1438 void three_comp(
const std::string& name, three_mole_fraction_pointer f, two_mole_fraction_pointer g, derivative wrt = NO_DERIV) {
1439 for (
int i = 0; i < 4; ++i) {
1440 for (
int j = 0; j < 4; ++j) {
1441 for (
int k = 0; k < 4; ++k) {
1442 double analytic = f(*HEOS, i, j, k, xN);
1444 if (HEOS->get_mole_fractions()[i] > 2 * dz) {
1445 CHECK_NOTHROW(numeric = (g(*HEOS_plus_z[k], i, j, xN) - g(*HEOS_minus_z[k], i, j, xN)) / (2 * dz));
1447 CHECK_NOTHROW(numeric =
1448 (-3 * g(*HEOS, i, j, xN) + 4 * g(*HEOS_plus_z[k], i, j, xN) - g(*HEOS_plus_2z[k], i, j, xN)) / (2 * dz));
1457 double error = mix_deriv_err_func(numeric, analytic);
1465 Eigen::MatrixXd Lstar = MixtureDerivatives::Lstar(HEOS, xN);
1466 if (name ==
"Lstar") {
1468 }
else if (name ==
"Mstar") {
1469 return MixtureDerivatives::Mstar(HEOS, xN, Lstar);
1471 throw ValueError(
"Must be one of Lstar or Mstar");
1474 void matrix_derivative(
const std::string name,
const std::string& wrt) {
1478 Eigen::MatrixXd analytic, numeric, Lstar, dLstar_dTau, dLstar_dDelta;
1479 if (name ==
"Mstar") {
1480 Lstar = MixtureDerivatives::Lstar(*HEOS, xN);
1481 dLstar_dDelta = MixtureDerivatives::dLstar_dX(*HEOS, xN,
CoolProp::iDelta);
1482 dLstar_dTau = MixtureDerivatives::dLstar_dX(*HEOS, xN,
CoolProp::iTau);
1485 if (name ==
"Lstar") {
1486 analytic = MixtureDerivatives::dLstar_dX(*HEOS, xN,
CoolProp::iTau);
1487 }
else if (name ==
"Mstar") {
1488 analytic = MixtureDerivatives::dMstar_dX(*HEOS, xN,
CoolProp::iTau, Lstar, dLstar_dTau);
1492 numeric = (get_matrix(*HEOS_plus_tau, name) - get_matrix(*HEOS_minus_tau, name)) / (2 * dtau);
1493 }
else if (wrt ==
"delta") {
1494 if (name ==
"Lstar") {
1496 }
else if (name ==
"Mstar") {
1497 analytic = MixtureDerivatives::dMstar_dX(*HEOS, xN,
CoolProp::iDelta, Lstar, dLstar_dDelta);
1501 numeric = (get_matrix(*HEOS_plus_delta, name) - get_matrix(*HEOS_minus_delta, name)) / (2 * ddelta);
1507 Eigen::MatrixXd rel_error = ((analytic - numeric).cwiseQuotient(analytic));
1509 err = rel_error.squaredNorm();
1516 two_comp(
"d_PSI_rho_dxj", MD::d_PSI_rho_dxj, MD::PSI_rho);
1517 two_comp(
"d_PSI_T_dxj", MD::d_PSI_T_dxj, MD::PSI_T);
1519 one(
"d_ndalphardni_dDelta", MD::d_ndalphardni_dDelta, MD::ndalphar_dni__constT_V_nj, DELTA);
1520 one(
"d2_ndalphardni_dDelta2", MD::d2_ndalphardni_dDelta2, MD::d_ndalphardni_dDelta, DELTA);
1521 one(
"d3_ndalphardni_dDelta3", MD::d3_ndalphardni_dDelta3, MD::d2_ndalphardni_dDelta2, DELTA);
1522 one(
"d_ndalphardni_dTau", MD::d_ndalphardni_dTau, MD::ndalphar_dni__constT_V_nj, TAU);
1523 one(
"d2_ndalphardni_dTau2", MD::d2_ndalphardni_dTau2, MD::d_ndalphardni_dTau, TAU);
1524 one(
"d3_ndalphardni_dTau3", MD::d3_ndalphardni_dTau3, MD::d2_ndalphardni_dTau2, TAU);
1525 one(
"d2_ndalphardni_dDelta_dTau", MD::d2_ndalphardni_dDelta_dTau, MD::d_ndalphardni_dDelta, TAU);
1526 one(
"d3_ndalphardni_dDelta2_dTau", MD::d3_ndalphardni_dDelta2_dTau, MD::d2_ndalphardni_dDelta2, TAU);
1527 one(
"d3_ndalphardni_dDelta_dTau2", MD::d3_ndalphardni_dDelta_dTau2, MD::d2_ndalphardni_dDelta_dTau, TAU);
1529 zero(
"dalphar_dDelta", MD::dalphar_dDelta, MD::alphar, DELTA);
1530 zero(
"d2alphar_dDelta2", MD::d2alphar_dDelta2, MD::dalphar_dDelta, DELTA);
1531 zero(
"dalphar_dTau", MD::dalphar_dTau, MD::alphar, TAU);
1532 zero(
"d2alphar_dTau2", MD::d2alphar_dTau2, MD::dalphar_dTau, TAU);
1534 zero(
"dalpha0_dDelta", MD::dalpha0_dDelta, MD::alpha0, DELTA);
1535 zero(
"d2alpha0_dDelta2", MD::d2alpha0_dDelta2, MD::dalpha0_dDelta, DELTA);
1536 zero(
"dalpha0_dTau", MD::dalpha0_dTau, MD::alpha0, TAU);
1537 zero(
"d2alpha0_dTau2", MD::d2alpha0_dTau2, MD::dalpha0_dTau, TAU);
1539 one_comp(
"dalpha0_dxi", MD::dalpha0_dxi, MD::alpha0);
1540 one(
"d2alpha0_dxi_dDelta", MD::d2alpha0_dxi_dDelta, MD::dalpha0_dxi, DELTA);
1541 one(
"d2alpha0_dxi_dTau", MD::d2alpha0_dxi_dTau, MD::dalpha0_dxi, TAU);
1542 two_comp(
"d2alpha0dxidxj", MD::d2alpha0dxidxj, MD::dalpha0_dxi);
1544 one_comp(
"dalpha_dxi", MD::dalpha_dxi, MD::alpha);
1545 one(
"d2alpha_dxi_dDelta", MD::d2alpha_dxi_dDelta, MD::dalpha_dxi, DELTA);
1546 one(
"d2alpha_dxi_dTau", MD::d2alpha_dxi_dTau, MD::dalpha_dxi, TAU);
1547 two_comp(
"d2alphadxidxj", MD::d2alphadxidxj, MD::dalpha_dxi);
1549 zero(
"dpsi_dDelta", MD::dpsi_dDelta, MD::psi, DELTA);
1550 zero(
"dpsi_dTau", MD::dpsi_dTau, MD::psi, TAU);
1551 zero(
"d2psi_dDelta2", MD::d2psi_dDelta2, MD::dpsi_dDelta, DELTA);
1552 zero(
"d2psi_dDelta_dTau", MD::d2psi_dDelta_dTau, MD::dpsi_dDelta, TAU);
1553 zero(
"d2psi_dTau2", MD::d2psi_dTau2, MD::dpsi_dTau, TAU);
1554 one_comp(
"dpsi_dxi", MD::dpsi_dxi, MD::psi);
1555 one_comp(
"d2psi_dxi_dDelta", MD::d2psi_dxi_dDelta, MD::dpsi_dDelta);
1556 one_comp(
"d2psi_dxi_dTau", MD::d2psi_dxi_dTau, MD::dpsi_dTau);
1557 two_comp(
"d2psi_dxi_dxj", MD::d2psi_dxi_dxj, MD::dpsi_dxi);
1561 one_comp(
"dalphar_dxi", MD::dalphar_dxi, MD::alphar);
1562 two_comp(
"d2alphardxidxj", MD::d2alphardxidxj, MD::dalphar_dxi);
1563 three_comp(
"d3alphardxidxjdxk", MD::d3alphardxidxjdxk, MD::d2alphardxidxj);
1564 one(
"d2alphar_dxi_dTau", MD::d2alphar_dxi_dTau, MD::dalphar_dxi, TAU);
1565 one(
"d2alphar_dxi_dDelta", MD::d2alphar_dxi_dDelta, MD::dalphar_dxi, DELTA);
1566 one(
"d3alphar_dxi_dDelta2", MD::d3alphar_dxi_dDelta2, MD::d2alphar_dxi_dDelta, DELTA);
1567 one(
"d3alphar_dxi_dTau2", MD::d3alphar_dxi_dTau2, MD::d2alphar_dxi_dTau, TAU);
1568 one(
"d4alphar_dxi_dTau3", MD::d4alphar_dxi_dTau3, MD::d3alphar_dxi_dTau2, TAU);
1569 one(
"d3alphar_dxi_dDelta_dTau", MD::d3alphar_dxi_dDelta_dTau, MD::d2alphar_dxi_dDelta, TAU);
1570 one(
"d4alphar_dxi_dDelta_dTau2", MD::d4alphar_dxi_dDelta_dTau2, MD::d3alphar_dxi_dDelta_dTau, TAU);
1571 one(
"d4alphar_dxi_dDelta2_dTau", MD::d4alphar_dxi_dDelta2_dTau, MD::d3alphar_dxi_dDelta2, TAU);
1572 two(
"d3alphar_dxi_dxj_dDelta", MD::d3alphar_dxi_dxj_dDelta, MD::d2alphardxidxj, DELTA);
1573 two(
"d4alphar_dxi_dxj_dDelta2", MD::d4alphar_dxi_dxj_dDelta2, MD::d3alphar_dxi_dxj_dDelta, DELTA);
1574 two(
"d4alphar_dxi_dxj_dDelta_dTau", MD::d4alphar_dxi_dxj_dDelta_dTau, MD::d3alphar_dxi_dxj_dDelta, TAU);
1575 two(
"d3alphar_dxi_dxj_dTau", MD::d3alphar_dxi_dxj_dTau, MD::d2alphardxidxj, TAU);
1576 two(
"d4alphar_dxi_dxj_dTau2", MD::d4alphar_dxi_dxj_dTau2, MD::d3alphar_dxi_dxj_dTau, TAU);
1577 one_comp(
"d_dalpharddelta_dxj__constT_V_xi", MD::d_dalpharddelta_dxj__constT_V_xi, MD::dalphar_dDelta, CONST_TRHO);
1579 two_comp(
"d_ndalphardni_dxj__constdelta_tau_xi", MD::d_ndalphardni_dxj__constdelta_tau_xi, MD::ndalphar_dni__constT_V_nj);
1580 two(
"d2_ndalphardni_dxj_dDelta__consttau_xi", MD::d2_ndalphardni_dxj_dDelta__consttau_xi, MD::d_ndalphardni_dxj__constdelta_tau_xi, DELTA);
1581 two(
"d3_ndalphardni_dxj_dDelta2__consttau_xi", MD::d3_ndalphardni_dxj_dDelta2__consttau_xi, MD::d2_ndalphardni_dxj_dDelta__consttau_xi,
1583 two(
"d2_ndalphardni_dxj_dTau__constdelta_xi", MD::d2_ndalphardni_dxj_dTau__constdelta_xi, MD::d_ndalphardni_dxj__constdelta_tau_xi, TAU);
1584 two(
"d3_ndalphardni_dxj_dTau2__constdelta_xi", MD::d3_ndalphardni_dxj_dTau2__constdelta_xi, MD::d2_ndalphardni_dxj_dTau__constdelta_xi, TAU);
1585 two(
"d3_ndalphardni_dxj_dDelta_dTau__constxi", MD::d3_ndalphardni_dxj_dDelta_dTau__constxi, MD::d2_ndalphardni_dxj_dDelta__consttau_xi, TAU);
1586 three_comp(
"d2_ndalphardni_dxj_dxk__constdelta_tau_xi", MD::d2_ndalphardni_dxj_dxk__constdelta_tau_xi,
1587 MD::d_ndalphardni_dxj__constdelta_tau_xi);
1588 three(
"d3_ndalphardni_dxj_dxk_dTau__constdelta_xi", MD::d3_ndalphardni_dxj_dxk_dTau__constdelta_xi,
1589 MD::d2_ndalphardni_dxj_dxk__constdelta_tau_xi, TAU);
1590 three(
"d3_ndalphardni_dxj_dxk_dDelta__consttau_xi", MD::d3_ndalphardni_dxj_dxk_dDelta__consttau_xi,
1591 MD::d2_ndalphardni_dxj_dxk__constdelta_tau_xi, DELTA);
1594 two(
"d_nd_ndalphardni_dnj_dTau__constdelta_x", MD::d_nd_ndalphardni_dnj_dTau__constdelta_x, MD::nd_ndalphardni_dnj__constT_V, TAU);
1595 two(
"d2_nd_ndalphardni_dnj_dTau2__constdelta_x", MD::d2_nd_ndalphardni_dnj_dTau2__constdelta_x, MD::d_nd_ndalphardni_dnj_dTau__constdelta_x,
1597 two(
"d_nd_ndalphardni_dnj_dDelta__consttau_x", MD::d_nd_ndalphardni_dnj_dDelta__consttau_x, MD::nd_ndalphardni_dnj__constT_V, DELTA);
1598 two(
"d2_nd_ndalphardni_dnj_dDelta_dTau__constx", MD::d2_nd_ndalphardni_dnj_dDelta_dTau__constx, MD::d_nd_ndalphardni_dnj_dDelta__consttau_x,
1600 two(
"d2_nd_ndalphardni_dnj_dDelta2__consttau_x", MD::d2_nd_ndalphardni_dnj_dDelta2__consttau_x, MD::d_nd_ndalphardni_dnj_dDelta__consttau_x,
1602 three_comp(
"d_nd_ndalphardni_dnj_dxk__consttau_delta", MD::d_nd_ndalphardni_dnj_dxk__consttau_delta, MD::nd_ndalphardni_dnj__constT_V);
1603 three(
"d2_nd_ndalphardni_dnj_dxk_dTau__constdelta", MD::d2_nd_ndalphardni_dnj_dxk_dTau__constdelta,
1604 MD::d_nd_ndalphardni_dnj_dxk__consttau_delta, TAU);
1605 three(
"d2_nd_ndalphardni_dnj_dxk_dDelta__consttau", MD::d2_nd_ndalphardni_dnj_dxk_dDelta__consttau,
1606 MD::d_nd_ndalphardni_dnj_dxk__consttau_delta, DELTA);
1609 three(
"d2_ndln_fugacity_i_dnj_dxk_dDelta__consttau", MD::d2_ndln_fugacity_i_dnj_dxk_dDelta__consttau,
1610 MD::d_ndln_fugacity_i_dnj_ddxk__consttau_delta, DELTA);
1611 three(
"d2_ndln_fugacity_i_dnj_dxk_dTau__constdelta", MD::d2_ndln_fugacity_i_dnj_dxk_dTau__constdelta,
1612 MD::d_ndln_fugacity_i_dnj_ddxk__consttau_delta, TAU);
1613 two(
"d2_ndln_fugacity_i_dnj_ddelta_dtau__constx", MD::d2_ndln_fugacity_i_dnj_ddelta_dtau__constx,
1614 MD::d_ndln_fugacity_i_dnj_ddelta__consttau_x, TAU);
1615 two(
"d_ndln_fugacity_i_dnj_ddelta__consttau_x", MD::d_ndln_fugacity_i_dnj_ddelta__consttau_x, MD::ndln_fugacity_i_dnj__constT_V_xi, DELTA);
1616 two(
"d_ndln_fugacity_i_dnj_dtau__constdelta_x", MD::d_ndln_fugacity_i_dnj_dtau__constdelta_x, MD::ndln_fugacity_i_dnj__constT_V_xi, TAU);
1617 three_comp(
"d_ndln_fugacity_i_dnj_ddxk__consttau_delta", MD::d_ndln_fugacity_i_dnj_ddxk__consttau_delta, MD::ndln_fugacity_i_dnj__constT_V_xi,
1619 one(
"dln_fugacity_i_dT__constrho_n", MD::dln_fugacity_i_dT__constrho_n, MD::ln_fugacity, T_CONSTRHO);
1620 one(
"dln_fugacity_i_drho__constT_n", MD::dln_fugacity_i_drho__constT_n, MD::ln_fugacity, RHO_CONSTT);
1621 one(
"dln_fugacity_i_dT__constp_n", MD::dln_fugacity_i_dT__constp_n, MD::ln_fugacity, T_CONSTP);
1622 one(
"dln_fugacity_i_dp__constT_n", MD::dln_fugacity_i_dp__constT_n, MD::ln_fugacity, P_CONSTT);
1623 one(
"dln_fugacity_coefficient_dT__constp_n", MD::dln_fugacity_coefficient_dT__constp_n, MD::ln_fugacity_coefficient, T_CONSTP);
1624 one(
"dln_fugacity_coefficient_dp__constT_n", MD::dln_fugacity_coefficient_dp__constT_n, MD::ln_fugacity_coefficient, P_CONSTT);
1626 three_comp(
"d2_PSI_T_dxj_dxk", MD::d2_PSI_T_dxj_dxk, MD::d_PSI_T_dxj);
1627 three_comp(
"d2_PSI_rho_dxj_dxk", MD::d2_PSI_rho_dxj_dxk, MD::d_PSI_rho_dxj);
1629 three(
"d_n2Aijk_dTau", MD::d_n2Aijk_dTau, MD::n2Aijk, TAU);
1630 three(
"d_n2Aijk_dDelta", MD::d_n2Aijk_dDelta, MD::n2Aijk, DELTA);
1631 two(
"d_nAij_dTau", MD::d_nAij_dTau, MD::nAij, TAU);
1632 two(
"d_nAij_dDelta", MD::d_nAij_dDelta, MD::nAij, DELTA);
1634 two_comp(
"d_nddeltadni_dxj__constdelta_tau", MD::d_nddeltadni_dxj__constdelta_tau, MD::nddeltadni__constT_V_nj);
1635 two_comp(
"d_ndtaudni_dxj__constdelta_tau", MD::d_ndtaudni_dxj__constdelta_tau, MD::ndtaudni__constT_V_nj);
1636 two(
"d2_ndtaudni_dxj_dTau__constdelta", MD::d2_ndtaudni_dxj_dTau__constdelta, MD::d_ndtaudni_dxj__constdelta_tau, TAU);
1638 one_comp(
"dTrdxi__constxj", MD::dTrdxi__constxj, MD::Tr);
1639 one_comp(
"d2Tr_dxidbetaT", MD::d2Tr_dxidbetaT, MD::dTr_dbetaT);
1640 one_comp(
"d2Tr_dxidgammaT", MD::d2Tr_dxidgammaT, MD::dTr_dgammaT);
1642 two_comp(
"d2Trdxidxj", MD::d2Trdxidxj, MD::dTrdxi__constxj);
1643 three_comp(
"d3Trdxidxjdxk", MD::d3Trdxidxjdxk, MD::d2Trdxidxj);
1644 one_comp(
"dtaudxj__constT_V_xi", MD::dtau_dxj__constT_V_xi, MD::tau, CONST_TRHO);
1645 two_comp(
"d_ndTrdni_dxj__constxi", MD::d_ndTrdni_dxj__constxi, MD::ndTrdni__constnj);
1646 three_comp(
"d2_ndTrdni_dxj_dxk__constxi", MD::d2_ndTrdni_dxj_dxk__constxi, MD::d_ndTrdni_dxj__constxi);
1648 one_comp(
"drhormolardxi__constxj", MD::drhormolardxi__constxj, MD::rhormolar);
1649 one_comp(
"d2rhormolar_dxidbetaV", MD::d2rhormolar_dxidbetaV, MD::drhormolar_dbetaV);
1650 one_comp(
"d2rhormolar_dxidgammaV", MD::d2rhormolar_dxidgammaV, MD::drhormolar_dgammaV);
1652 two_comp(
"d2rhormolardxidxj", MD::d2rhormolardxidxj, MD::drhormolardxi__constxj);
1653 three_comp(
"d3rhormolardxidxjdxk", MD::d3rhormolardxidxjdxk, MD::d2rhormolardxidxj);
1654 one_comp(
"ddelta_dxj__constT_V_xi", MD::ddelta_dxj__constT_V_xi, MD::delta, CONST_TRHO);
1655 two_comp(
"d_ndrhorbardni_dxj__constxi", MD::d_ndrhorbardni_dxj__constxi, MD::ndrhorbardni__constnj);
1656 three_comp(
"d2_ndrhorbardni_dxj_dxk__constxi", MD::d2_ndrhorbardni_dxj_dxk__constxi, MD::d_ndrhorbardni_dxj__constxi);
1658 one_comp(
"dpdxj__constT_V_xi", MD::dpdxj__constT_V_xi, MD::p, CONST_TRHO);
1660 matrix_derivative(
"Lstar",
"tau");
1661 matrix_derivative(
"Lstar",
"delta");
1662 matrix_derivative(
"Mstar",
"tau");
1663 matrix_derivative(
"Mstar",
"delta");
1667TEST_CASE_METHOD(DerivativeFixture<HelmholtzEOSMixtureBackend>,
"Check derivatives for HEOS",
"[mixture_derivs2]") {
1671TEST_CASE_METHOD(DerivativeFixture<PengRobinsonBackend>,
"Check derivatives for Peng-Robinson",
"[mixture_derivs2]") {
1675TEST_CASE_METHOD(DerivativeFixture<SRKBackend>,
"Check derivatives for SRK",
"[mixture_derivs2]") {