27template<
typename KType,
typename RhoType,
typename Txy>
28auto get_Kijk(
const KType& Kint,
const RhoType& rhostar,
const Txy &Tstarij,
const Txy &Tstarik,
const Txy &Tstarjk){
29 return forceeval(
pow(
forceeval(Kint.get_K(Tstarij, rhostar)*Kint.get_K(Tstarik, rhostar)*Kint.get_K(Tstarjk, rhostar)), 1.0/3.0));
35template<
typename KType,
typename RhoType,
typename Txy>
36auto get_Kijk_334445(
const KType& Kint,
const RhoType& rhostar,
const Txy &Tstarij,
const Txy &Tstarik,
const Txy &Tstarjk){
37 return forceeval(-
pow(-
forceeval(Kint.get_K(Tstarij, rhostar)*Kint.get_K(Tstarik, rhostar)*Kint.get_K(Tstarjk, rhostar)), 1.0/3.0));
46template<
class JIntegral,
class KIntegral>
51 const Eigen::ArrayXd sigma_m, epsilon_over_k, mubar2, Qbar2;
52 const bool has_a_polar;
53 const Eigen::ArrayXd sigma_m3, sigma_m5;
55 const JIntegral J6{6};
56 const JIntegral J8{8};
57 const JIntegral J10{10};
58 const JIntegral J11{11};
59 const JIntegral J13{13};
60 const JIntegral J15{15};
61 const KIntegral K222_333{222, 333};
62 const KIntegral K233_344{233, 344};
63 const KIntegral K334_445{334, 445};
64 const KIntegral K444_555{444, 555};
65 const double epsilon_0 = 8.8541878128e-12;
66 const double PI_ =
static_cast<double>(EIGEN_PI);
67 Eigen::MatrixXd SIGMAIJ, EPSKIJ;
71 MultipolarContributionGubbinsTwu(
const Eigen::ArrayX<double> &sigma_m,
const Eigen::ArrayX<double> &epsilon_over_k,
const Eigen::ArrayX<double> &mubar2,
const Eigen::ArrayX<double> &Qbar2,
multipolar_rhostar_approach approach) : sigma_m(sigma_m), epsilon_over_k(epsilon_over_k), mubar2(mubar2), Qbar2(Qbar2), has_a_polar(mubar2.cwiseAbs().sum() > 0 || Qbar2.cwiseAbs().sum() > 0), sigma_m3(sigma_m.
pow(3)), sigma_m5(sigma_m.
pow(5)), approach(approach) {
73 if (sigma_m.size() != mubar2.size()){
76 if (sigma_m.size() != Qbar2.size()){
80 const std::size_t N = sigma_m.size();
81 SIGMAIJ.resize(N, N); EPSKIJ.resize(N, N);
82 for (std::size_t i = 0; i < N; ++i){
83 for (std::size_t j = 0; j < N; ++j){
85 double epskij = sqrt(epsilon_over_k[i]*epsilon_over_k[j]);
86 double sigmaij = (sigma_m[i]+sigma_m[j])/2;
87 SIGMAIJ(i, j) = sigmaij;
88 EPSKIJ(i, j) = epskij;
94 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType>
95 auto get_alpha2(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions)
const{
96 const auto& x = mole_fractions;
98 const std::size_t N = mole_fractions.size();
99 using XTtype = std::common_type_t<TTYPE,
decltype(mole_fractions[0])>;
100 std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0])> alpha2_112 = 0.0, alpha2_123 = 0.0, alpha2_224 = 0.0;
102 const RhoType factor_112 = -2.0*PI_*rhoN/3.0;
103 const RhoType factor_123 = -PI_*rhoN;
104 const RhoType factor_224 = -14.0*PI_*rhoN/5.0;
106 for (std::size_t i = 0; i < N; ++i){
107 for (std::size_t j = 0; j < N; ++j){
110 XTtype leading =
forceeval(x[i]*x[j]/(Tstari*Tstarj));
111 TTYPE Tstarij =
forceeval(T/EPSKIJ(i, j));
112 double sigmaij = SIGMAIJ(i,j);
114 double dbl = sigma_m3[i]*sigma_m3[j]/
powi(sigmaij,3)*mubar2[i]*mubar2[j];
115 alpha2_112 += leading*dbl*J6.get_J(Tstarij, rhostar);
118 double dbl = sigma_m3[i]*sigma_m5[j]/
powi(sigmaij,5)*mubar2[i]*Qbar2[j];
119 alpha2_123 += leading*dbl*J8.get_J(Tstarij, rhostar);
122 double dbl = sigma_m5[i]*sigma_m5[j]/
powi(sigmaij,7)*Qbar2[i]*Qbar2[j];
123 alpha2_224 += leading*dbl*J10.get_J(Tstarij, rhostar);
127 return forceeval(factor_112*alpha2_112 + 2.0*factor_123*alpha2_123 + factor_224*alpha2_224);
131 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType>
132 auto get_alpha3(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions)
const{
133 const VecType& x = mole_fractions;
134 const std::size_t N = mole_fractions.size();
135 using type = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0])>;
136 using XTtype = std::common_type_t<TTYPE,
decltype(mole_fractions[0])>;
137 type summerA_112_112_224 = 0.0, summerA_112_123_213 = 0.0, summerA_123_123_224 = 0.0, summerA_224_224_224 = 0.0;
138 type summerB_112_112_112 = 0.0, summerB_112_123_123 = 0.0, summerB_123_123_224 = 0.0, summerB_224_224_224 = 0.0;
140 for (std::size_t i = 0; i < N; ++i){
141 for (std::size_t j = 0; j < N; ++j){
144 TTYPE Tstarij =
forceeval(T/EPSKIJ(i,j));
147 double sigmaij = SIGMAIJ(i,j);
148 double POW4sigmaij =
powi(sigmaij, 4);
149 double POW8sigmaij = POW4sigmaij*POW4sigmaij;
150 double POW10sigmaij =
powi(sigmaij, 10);
151 double POW12sigmaij = POW4sigmaij*POW8sigmaij;
154 double dbl =
pow(sigma_m[i]*sigma_m[j], 11.0/2.0)/POW8sigmaij*mubar2[i]*mubar2[j]*sqrt(Qbar2[i]*Qbar2[j]);
155 summerA_112_112_224 += leading*dbl*J11.get_J(Tstarij, rhostar);
158 double dbl =
pow(sigma_m[i]*sigma_m[j], 11.0/2.0)/POW8sigmaij*mubar2[i]*mubar2[j]*sqrt(Qbar2[i]*Qbar2[j]);
159 summerA_112_123_213 += leading*dbl*J11.get_J(Tstarij, rhostar);
162 double dbl =
pow(sigma_m[i], 11.0/2.0)*
pow(sigma_m[j], 15.0/2.0)/POW10sigmaij*mubar2[i]*sqrt(Qbar2[i])*
pow(Qbar2[j], 3.0/2.0);
163 summerA_123_123_224 += leading*dbl*J13.get_J(Tstarij, rhostar);
166 double dbl =
pow(sigma_m[i]*sigma_m[j], 15.0/2.0)/POW12sigmaij*
pow(Qbar2[i], 3.0/2.0)*
pow(Qbar2[j], 3.0/2.0);
167 summerA_224_224_224 += leading*dbl*J15.get_J(Tstarij, rhostar);
170 for (std::size_t k = 0; k < N; ++k){
172 TTYPE Tstarik =
forceeval(T/EPSKIJ(i,k));
173 TTYPE Tstarjk =
forceeval(T/EPSKIJ(j,k));
174 double sigmaik = SIGMAIJ(i,k), sigmajk = SIGMAIJ(j,k);
177 XTtype leadingijk =
forceeval(x[i]*x[j]*x[k]/(Tstari*Tstarj*Tstark));
179 if (std::abs(mubar2[i]*mubar2[j]*mubar2[k]) > 0){
180 auto K222333 =
get_Kijk(K222_333, rhostar, Tstarij, Tstarik, Tstarjk);
181 double dbl = sigma_m3[i]*sigma_m3[j]*sigma_m3[k]/(sigmaij*sigmaik*sigmajk)*mubar2[i]*mubar2[j]*mubar2[k];
182 summerB_112_112_112 +=
forceeval(leadingijk*dbl*K222333);
184 if (std::abs(mubar2[i]*mubar2[j]*Qbar2[k]) > 0){
185 auto K233344 =
get_Kijk(K233_344, rhostar, Tstarij, Tstarik, Tstarjk);
186 double dbl = sigma_m3[i]*sigma_m3[j]*sigma_m5[k]/(sigmaij*
POW2(sigmaik*sigmajk))*mubar2[i]*mubar2[j]*Qbar2[k];
187 summerB_112_123_123 += leadingijk*dbl*K233344;
189 if (std::abs(mubar2[i]*Qbar2[j]*Qbar2[k]) > 0){
190 auto K334445 =
get_Kijk_334445(K334_445, rhostar, Tstarij, Tstarik, Tstarjk);
191 double dbl = sigma_m3[i]*sigma_m5[j]*sigma_m5[k]/(
POW2(sigmaij*sigmaik)*
POW3(sigmajk))*mubar2[i]*Qbar2[j]*Qbar2[k];
192 summerB_123_123_224 += leadingijk*dbl*K334445;
194 if (std::abs(Qbar2[i]*Qbar2[j]*Qbar2[k]) > 0){
195 auto K444555 =
get_Kijk(K444_555, rhostar, Tstarij, Tstarik, Tstarjk);
196 double dbl =
POW5(sigma_m[i]*sigma_m[j]*sigma_m[k])/(
POW3(sigmaij*sigmaik*sigmajk))*Qbar2[i]*Qbar2[j]*Qbar2[k];
197 summerB_224_224_224 += leadingijk*dbl*K444555;
203 type alpha3A_112_112_224 = 8.0*PI_*rhoN/25.0*summerA_112_112_224;
204 type alpha3A_112_123_213 = 8.0*PI_*rhoN/75.0*summerA_112_123_213;
205 type alpha3A_123_123_224 = 8.0*PI_*rhoN/35.0*summerA_123_123_224;
206 type alpha3A_224_224_224 = 144.0*PI_*rhoN/245.0*summerA_224_224_224;
208 type alpha3A = 3.0*alpha3A_112_112_224 + 6.0*alpha3A_112_123_213 + 6.0*alpha3A_123_123_224 + alpha3A_224_224_224;
210 RhoType rhoN2 = rhoN*rhoN;
212 type alpha3B_112_112_112 = 32.0*
POW3(PI_)*rhoN2/135.0*sqrt(14*PI_/5.0)*summerB_112_112_112;
213 type alpha3B_112_123_123 = 64.0*
POW3(PI_)*rhoN2/315.0*sqrt(3.0*PI_)*summerB_112_123_123;
214 type alpha3B_123_123_224 = -32.0*
POW3(PI_)*rhoN2/45.0*sqrt(22.0*PI_/63.0)*summerB_123_123_224;
215 type alpha3B_224_224_224 = 32.0*
POW3(PI_)*rhoN2/2025.0*sqrt(2002.0*PI_)*summerB_224_224_224;
217 type alpha3B = alpha3B_112_112_112 + 3.0*alpha3B_112_123_123 + 3.0*alpha3B_123_123_224 + alpha3B_224_224_224;
222 template<
typename RhoType,
typename PFType,
typename MoleFractions>
223 auto get_rhostar(
const RhoType rhoN,
const PFType& packing_fraction,
const MoleFractions& mole_fractions)
const{
224 using type = std::common_type_t<RhoType, PFType,
decltype(mole_fractions[0])>;
226 if (approach == multipolar_rhostar_approach::calculate_Gubbins_rhostar){
231 auto N = mole_fractions.size();
232 for (
auto i = 0; i < N; ++i){
233 for (
auto j = 0; j < N; ++j){
234 auto sigmaij = (sigma_m[i] + sigma_m[j])/2;
235 sigma_x3 += mole_fractions[i]*mole_fractions[j]*
POW3(sigmaij);
240 else if (approach == multipolar_rhostar_approach::use_packing_fraction){
242 rhostar =
forceeval(packing_fraction/(
static_cast<double>(EIGEN_PI)/6.0));
253 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType>
254 auto eval(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions)
const {
256 using type = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0])>;
258 type alpha2 = 0.0, alpha3 = 0.0, alpha = 0.0;
260 alpha2 =
get_alpha2(T, rhoN, rhostar, mole_fractions);
261 alpha3 =
get_alpha3(T, rhoN, rhostar, mole_fractions);
262 alpha =
forceeval(alpha2/(1.0-alpha3/alpha2));
264 return MultipolarContributionGubbinsTwuTermsGT<type>{alpha2, alpha3, alpha};
278template<
class JIntegral,
class KIntegral>
283 const Eigen::ArrayXd sigma_m, epsilon_over_k;
284 Eigen::MatrixXd SIGMAIJ, EPSKIJ;
285 const Eigen::ArrayXd mu, Q, mu2, Q2, Q3;
286 const bool has_a_polar;
287 const Eigen::ArrayXd sigma_m3, sigma_m5;
289 const JIntegral J6{6};
290 const JIntegral J8{8};
291 const JIntegral J10{10};
292 const JIntegral J11{11};
293 const JIntegral J13{13};
294 const JIntegral J15{15};
295 const KIntegral K222_333{222, 333};
296 const KIntegral K233_344{233, 344};
297 const KIntegral K334_445{334, 445};
298 const KIntegral K444_555{444, 555};
300 const double PI_ =
static_cast<double>(EIGEN_PI);
301 const double PI3 = PI_*PI_*PI_;
302 const double epsilon_0 = 8.8541878128e-12;
310 const double C3, C3b;
311 std::optional<PolarizableArrays> polarizable;
313 double get_C3(
const std::optional<nlohmann::json>& flags,
double default_value=1.0){
314 if (flags){
return flags.value().value(
"C3", default_value); }
315 return default_value;
317 double get_C3b(
const std::optional<nlohmann::json>& flags,
double default_value=1.0){
318 if (flags){
return flags.value().value(
"C3b", default_value); }
319 return default_value;
322 if (flags){
return flags.value().value(
"approach", multipolar_rhostar_approach::use_packing_fraction); }
323 return multipolar_rhostar_approach::use_packing_fraction;
325 std::optional<PolarizableArrays> get_polarizable(
const std::optional<nlohmann::json>& flags){
326 if (flags && flags.value().contains(
"polarizable")){
327 PolarizableArrays arrays;
328 auto toeig = [](
const std::valarray<double>& x) -> Eigen::ArrayXd{
return Eigen::Map<const Eigen::ArrayXd>(&(x[0]), x.size());};
329 auto alpha_symm_m3 =
toeig(flags.value()[
"polarizable"].at(
"alpha_symm / m^3"));
330 auto alpha_asymm_m3 =
toeig(flags.value()[
"polarizable"].at(
"alpha_asymm / m^3"));
331 arrays.alpha_symm_C2m2J = alpha_symm_m3/
k_e;
332 arrays.alpha_asymm_C2m2J = alpha_asymm_m3/
k_e;
333 arrays.alpha_isotropic_C2m2J = 1.0/3.0*(arrays.alpha_symm_C2m2J + 2.0*arrays.alpha_asymm_C2m2J);
334 arrays.alpha_anisotropic_C2m2J = arrays.alpha_symm_C2m2J - arrays.alpha_asymm_C2m2J;
341 MultipolarContributionGrayGubbins(
const Eigen::ArrayX<double> &sigma_m,
const Eigen::ArrayX<double> &epsilon_over_k,
const Eigen::MatrixXd& SIGMAIJ,
const Eigen::MatrixXd& EPSKIJ,
const Eigen::ArrayX<double> &mu,
const Eigen::ArrayX<double> &Q,
const std::optional<nlohmann::json>& flags)
343 : sigma_m(sigma_m), epsilon_over_k(epsilon_over_k), SIGMAIJ(SIGMAIJ), EPSKIJ(EPSKIJ), mu(mu), Q(Q), mu2(mu.
pow(2)), Q2(Q.
pow(2)), Q3(Q.
pow(3)), has_a_polar(Q.cwiseAbs().sum() > 0 || mu.cwiseAbs().sum() > 0), sigma_m3(sigma_m.
pow(3)), sigma_m5(sigma_m.
pow(5)), approach(get_approach(flags)), C3(get_C3(flags)), C3b(get_C3b(flags)), polarizable(get_polarizable(flags)) {
345 if (sigma_m.size() != mu.size()){
348 if (sigma_m.size() != Q.size()){
352 if (polarizable.value().alpha_symm_C2m2J.size() != sigma_m.size() || polarizable.value().alpha_asymm_C2m2J.size() != sigma_m.size()){
360 template<
typename J
integral,
typename TTYPE,
typename RhoStarType>
361 auto get_In(
const Jintegral& J,
int n,
double sigmaij,
const TTYPE& Tstar,
const RhoStarType& rhostar)
const{
362 return 4.0*PI_/
pow(sigmaij, n-3)*J.get_J(Tstar, rhostar);
366 template<
typename TTYPE,
typename RhoStarType>
367 auto Immm(std::size_t i, std::size_t j, std::size_t k,
const TTYPE& T,
const RhoStarType& rhostar)
const {
368 auto Tstarij = T/EPSKIJ(i,j), Tstarik = T/EPSKIJ(i,k), Tstarjk = T/EPSKIJ(j, k);
369 const double coeff = 64.0*PI3/5.0*sqrt(14*PI_/5.0)/SIGMAIJ(i,j)/SIGMAIJ(i,k)/SIGMAIJ(j,k);
370 return coeff*
get_Kijk(K222_333, rhostar, Tstarij, Tstarik, Tstarjk);
372 template<
typename TTYPE,
typename RhoStarType>
373 auto ImmQ(std::size_t i, std::size_t j, std::size_t k,
const TTYPE& T,
const RhoStarType& rhostar)
const {
374 auto Tstarij = T/EPSKIJ(i,j), Tstarik = T/EPSKIJ(i,k), Tstarjk = T/EPSKIJ(j, k);
375 const double coeff = 2048.0*PI3/7.0*sqrt(3.0*PI_)/SIGMAIJ(i,j)/
POW2(SIGMAIJ(i,k)*SIGMAIJ(j,k));
376 return coeff*
get_Kijk(K233_344, rhostar, Tstarij, Tstarik, Tstarjk);
378 template<
typename TTYPE,
typename RhoStarType>
379 auto ImQQ(std::size_t i, std::size_t j, std::size_t k,
const TTYPE& T,
const RhoStarType& rhostar)
const {
380 auto Tstarij = T/EPSKIJ(i,j), Tstarik = T/EPSKIJ(i,k), Tstarjk = T/EPSKIJ(j, k);
381 const double coeff = -4096.0*PI3/9.0*sqrt(22.0*PI_/7.0)/
POW2(SIGMAIJ(i,j)*SIGMAIJ(i,k))/
POW3(SIGMAIJ(j,k));
382 return coeff*
get_Kijk_334445(K334_445, rhostar, Tstarij, Tstarik, Tstarjk);
384 template<
typename TTYPE,
typename RhoStarType>
385 auto IQQQ(std::size_t i, std::size_t j, std::size_t k,
const TTYPE& T,
const RhoStarType& rhostar)
const {
386 auto Tstarij = T/EPSKIJ(i,j), Tstarik = T/EPSKIJ(i,k), Tstarjk = T/EPSKIJ(j, k);
387 const double coeff = 8192.0*PI3/81.0*sqrt(2002.0*PI_)/
POW3(SIGMAIJ(i,j)*SIGMAIJ(i,k)*SIGMAIJ(j,k));
388 return coeff*
get_Kijk(K444_555, rhostar, Tstarij, Tstarik, Tstarjk);
392 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
393 auto get_alpha2(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& muprime)
const{
394 const auto& x = mole_fractions;
396 const std::size_t N = mole_fractions.size();
398 std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0]),
decltype(muprime[0])> summer = 0.0;
400 const TTYPE beta =
forceeval(1.0/(k_B*T));
401 const auto muprime2 =
POW2(muprime).eval();
403 using ztype = std::common_type_t<TTYPE,
decltype(muprime[0])>;
408 Eigen::ArrayX<ztype> z1 = 1.0/3.0*(muprime2.template cast<ztype>()*
static_cast<ztype
>(beta));
409 Eigen::ArrayX<ztype> z2 = 0.0*z1;
411 z1 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
412 z2 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
415 for (std::size_t i = 0; i < N; ++i){
416 for (std::size_t j = 0; j < N; ++j){
417 TTYPE Tstarij =
forceeval(T/EPSKIJ(i, j));
418 double sigmaij = SIGMAIJ(i,j);
419 summer += x[i]*x[j]*(
420 3.0/2.0*(z1[i]*z1[j] - z2[i]*z2[j])*
get_In(J6, 6, sigmaij, Tstarij, rhostar)
421 + 3.0/2.0*z1[i]*beta*Q2[j]*
get_In(J8, 8, sigmaij, Tstarij, rhostar)
422 +7.0/10.0*beta*beta*Q2[i]*Q2[j]*
get_In(J10, 10, sigmaij, Tstarij, rhostar)
430 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
431 auto get_alpha2_muprime_gradient(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& muprime)
const{
432 const auto& x = mole_fractions;
433 const std::size_t N = mole_fractions.size();
435 using type_ = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0]),
decltype(muprime[0])>;
437 const TTYPE beta = 1.0/(k_B*T);
438 using ztype = std::common_type_t<TTYPE,
decltype(muprime[0])>;
441 Eigen::ArrayX<ztype> z1 = 1.0/3.0*(
POW2(muprime).template cast<ztype>()*
static_cast<ztype
>(beta));
443 z1 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
447 Eigen::ArrayX<type_> Eprime2(N);
448 for (std::size_t i = 0; i < N; ++i){
450 for (std::size_t j = 0; j < N; ++j){
451 TTYPE Tstarij = T/EPSKIJ(i, j);
452 double sigmaij = SIGMAIJ(i, j);
453 auto rhoj = rhoN*x[j];
454 summer += rhoj*(2.0*z1[i]*
get_In(J6, 6, sigmaij, Tstarij, rhostar) + beta*Q2[j]*
get_In(J8, 8, sigmaij, Tstarij, rhostar) );
456 Eprime2[i] = muprime[i]*summer;
459 return (-k_e*k_e*Eprime2*mole_fractions.template cast<type_>()*beta).
eval();
463 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
464 auto get_alpha3(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& muprime)
const{
465 const VecType& x = mole_fractions;
466 const std::size_t N = mole_fractions.size();
467 using type = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0]),
decltype(muprime[0])>;
468 type summer_a = 0.0, summer_b = 0.0;
470 const TTYPE beta =
forceeval(1.0/(k_B*T));
471 const auto muprime2 =
POW2(muprime).eval();
474 using ztype = std::common_type_t<TTYPE,
decltype(muprime[0])>;
475 Eigen::ArrayX<ztype> z1 = 1.0/3.0*(muprime2.template cast<ztype>()*
static_cast<ztype
>(beta));
476 Eigen::ArrayX<ztype> z2 = 0.0*z1;
477 Eigen::ArrayX<ztype> gamma = 0.0*z1;
479 z1 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
480 z2 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
481 gamma += polarizable.value().alpha_symm_C2m2J.template cast<ztype>() - polarizable.value().alpha_asymm_C2m2J.template cast<ztype>();
484 for (std::size_t i = 0; i < N; ++i){
485 for (std::size_t j = 0; j < N; ++j){
487 TTYPE Tstarij =
forceeval(T/EPSKIJ(i,j));
488 double sigmaij = SIGMAIJ(i,j);
490 auto a_ij = ((2.0/5.0*beta*beta*muprime2[i]*muprime2[j] + 4.0/5.0*gamma[i]*beta*muprime2[j] + 4.0/25.0*gamma[i]*gamma[j])*beta*Q[i]*Q[j]*
get_In(J11, 11, sigmaij, Tstarij, rhostar)
491 +12.0/35.0*(beta*muprime2[i] + gamma[i])*beta*beta*Q[i]*
POW3(Q[j])*
get_In(J13, 13, sigmaij, Tstarij, rhostar)
492 + 36.0/245.0*
POW3(beta)*Q3[i]*Q3[j]*
get_In(J15, 15, sigmaij, Tstarij, rhostar)
494 summer_a += x[i]*x[j]*a_ij;
496 for (std::size_t k = 0; k < N; ++k){
498 1.0/2.0*(z1[i]*z1[j]*z1[k] - z2[i]*z2[j]*z2[k])*
Immm(i, j, k, T, rhostar)
499 +C3b*(3.0/160.0*z1[i]*z1[j]*beta*Q2[k]*
ImmQ(i, j, k, T, rhostar) + 3.0/640.0*z1[i]*
POW2(beta)*Q2[j]*Q2[k]*
ImQQ(i,j,k,T, rhostar))
500 +1.0/6400.0*
POW3(beta)*Q2[i]*Q2[j]*Q2[k]*
IQQQ(i, j, k, T, rhostar)
502 summer_b += x[i]*x[j]*x[k]*b_ijk;
507 return forceeval(C3*(rhoN*summer_a + rhoN*rhoN*summer_b)*k_e*k_e*k_e);
511 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
512 auto get_alpha3_muprime_gradient(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& muprime)
const{
513 const VecType& x = mole_fractions;
514 const std::size_t N = mole_fractions.size();
515 using type_ = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0]),
decltype(muprime[0])>;
517 const TTYPE beta =
forceeval(1.0/(k_B*T));
518 const auto muprime2 =
POW2(muprime).eval();
521 using ztype = std::common_type_t<TTYPE,
decltype(muprime[0])>;
522 Eigen::ArrayX<ztype> z1 = 1.0/3.0*(muprime2.template cast<ztype>()*
static_cast<ztype
>(beta));
523 Eigen::ArrayX<ztype> gamma = 0.0*z1;
525 z1 += polarizable.value().alpha_isotropic_C2m2J.template cast<ztype>();
526 gamma += polarizable.value().alpha_symm_C2m2J.template cast<ztype>() - polarizable.value().alpha_asymm_C2m2J.template cast<ztype>();
530 Eigen::ArrayX<type_> Eprime3(N);
531 type_ summer_ij = 0, summer_ijk = 0;
532 for (std::size_t i = 0; i < N; ++i){
533 for (std::size_t j = 0; j < N; ++j){
535 TTYPE Tstarij =
forceeval(T/EPSKIJ(i,j));
536 double sigmaij = SIGMAIJ(i,j);
537 auto p_ij = 8.0/5.0*(beta*muprime2[j] + gamma[j])*beta*Q[i]*Q[j]*
get_In(J11, 11, sigmaij, Tstarij, rhostar) + 24.0/35.0*beta*beta*Q[i]*Q3[j]*
get_In(J13, 13, sigmaij, Tstarij, rhostar);
538 summer_ij += (rhoN*x[j]*p_ij);
540 for (std::size_t k = 0; k < N; ++k){
542 z1[j]*z1[k]*
Immm(i, j, k, T, rhostar)
543 +C3b*1.0/40.0*z1[j]*beta*Q2[k]*
ImmQ(i, j, k, T, rhostar)
544 + 1.0/320.0*
POW2(beta)*Q2[j]*Q2[k]*
ImQQ(i,j,k,T, rhostar)
546 summer_ijk +=
POW2(rhoN)*x[j]*x[k]*q_ijk;
549 Eprime3[i] = -muprime[i]*(summer_ij + summer_ijk);
552 return (-C3*Eprime3*k_e*k_e*k_e*mole_fractions.template cast<type_>()*beta).
eval();
555 template<
typename RhoType,
typename PFType,
typename MoleFractions>
556 auto get_rhostar(
const RhoType rhoN,
const PFType& packing_fraction,
const MoleFractions& mole_fractions)
const{
557 using type = std::common_type_t<RhoType, PFType,
decltype(mole_fractions[0])>;
559 if (approach == multipolar_rhostar_approach::calculate_Gubbins_rhostar){
564 auto N = mole_fractions.size();
565 for (
auto i = 0; i < N; ++i){
566 for (
auto j = 0; j < N; ++j){
567 auto sigmaij = (sigma_m[i] + sigma_m[j])/2;
568 sigma_x3 += mole_fractions[i]*mole_fractions[j]*
POW3(sigmaij);
573 else if (approach == multipolar_rhostar_approach::use_packing_fraction){
575 rhostar =
forceeval(packing_fraction/(
static_cast<double>(EIGEN_PI)/6.0));
584 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
585 auto get_Eprime(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& muprime)
const{
621 auto alpha2 =
get_alpha2(T, rhoN, rhostar, mole_fractions, muprime);
622 auto alpha3 =
get_alpha3(T, rhoN, rhostar, mole_fractions, muprime);
625 auto dalphaperturb_dmuprime = (((1.0-2.0*alpha3/alpha2)*dalphaperturb2_dmuprime + dalphaperturb3_dmuprime)/
POW2(1.0-alpha3/alpha2)).
eval();
627 return (-k_B*T*dalphaperturb_dmuprime).eval();
631 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType,
typename MuPrimeType>
632 auto iterate_muprime_SS(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions,
const MuPrimeType& mu,
const int max_steps)
const{
636 using otype = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0]),
decltype(mu[0])>;
637 Eigen::ArrayX<otype> muprime = mu.template cast<otype>();
638 for (
auto counter = 0; counter < max_steps; ++counter){
639 auto Eprime =
get_Eprime(T, rhoN, rhostar, mole_fractions, muprime);
641 muprime = mu.template cast<otype>() + polarizable.value().alpha_symm_C2m2J.template cast<otype>()*Eprime.template cast<otype>();
649 template<
typename TTYPE,
typename RhoType,
typename RhoStarType,
typename VecType>
650 auto eval(
const TTYPE& T,
const RhoType& rhoN,
const RhoStarType& rhostar,
const VecType& mole_fractions)
const {
652 using type = std::common_type_t<TTYPE, RhoType, RhoStarType,
decltype(mole_fractions[0])>;
655 type alpha2 = 0.0, alpha3 = 0.0, alpha = 0.0;
657 alpha2 =
get_alpha2(T, rhoN, rhostar, mole_fractions, mu);
658 alpha3 =
get_alpha3(T, rhoN, rhostar, mole_fractions, mu);
659 alpha =
forceeval(alpha2/(1.0-alpha3/alpha2));
666 return MultipolarContributionGubbinsTwuTermsGT<type>{alpha2, alpha3, alpha};
672 auto Eprime =
get_Eprime(T, rhoN, rhostar, mole_fractions, muprime);
673 using Eprime_t = std::decay_t<
decltype(Eprime[0])>;
675 auto U_p_over_rhoN = 0.5*(mole_fractions.template cast<Eprime_t>()*polarizable.value().alpha_symm_C2m2J.template cast<Eprime_t>()*Eprime*Eprime).
eval().sum();
676 auto alpha_polarization = U_p_over_rhoN/(k_B*T);
678 auto alpha2 =
get_alpha2(T, rhoN, rhostar, mole_fractions, muprime);
679 auto alpha3 =
get_alpha3(T, rhoN, rhostar, mole_fractions, muprime);
680 auto alpha =
forceeval(alpha2/(1.0-alpha3/alpha2));
681 return MultipolarContributionGubbinsTwuTermsGT<type>{alpha2, alpha3, alpha + alpha_polarization};
auto get_rhostar(const RhoType rhoN, const PFType &packing_fraction, const MoleFractions &mole_fractions) const
auto IQQQ(std::size_t i, std::size_t j, std::size_t k, const TTYPE &T, const RhoStarType &rhostar) const
auto get_alpha2(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &muprime) const
Return , thus this is a nondimensional term. This is equivalent to from Gray et al.
auto get_alpha2_muprime_gradient(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &muprime) const
Return , thus this is a nondimensional term. This is equivalent to from Gray et al.
auto iterate_muprime_SS(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &mu, const int max_steps) const
Use successive substitution to obtain the effective dipole moment based solely on the perturbation te...
auto get_alpha3_muprime_gradient(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &muprime) const
Return , thus this is a nondimensional term. This is equivalent to from Gray et al.
MultipolarContributionGrayGubbins & operator=(const MultipolarContributionGrayGubbins &)=delete
static constexpr multipolar_argument_spec arg_spec
auto ImmQ(std::size_t i, std::size_t j, std::size_t k, const TTYPE &T, const RhoStarType &rhostar) const
auto get_alpha3(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &muprime) const
Return , thus this is a nondimensional term. This is equivalent to from Gray et al.
MultipolarContributionGrayGubbins(const Eigen::ArrayX< double > &sigma_m, const Eigen::ArrayX< double > &epsilon_over_k, const Eigen::MatrixXd &SIGMAIJ, const Eigen::MatrixXd &EPSKIJ, const Eigen::ArrayX< double > &mu, const Eigen::ArrayX< double > &Q, const std::optional< nlohmann::json > &flags)
auto get_Eprime(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions, const MuPrimeType &muprime) const
Get the polarization term .
auto get_In(const Jintegral &J, int n, double sigmaij, const TTYPE &Tstar, const RhoStarType &rhostar) const
Appendix B of Gray et al.
auto Immm(std::size_t i, std::size_t j, std::size_t k, const TTYPE &T, const RhoStarType &rhostar) const
Appendix B of Gray et al.
auto eval(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions) const
auto ImQQ(std::size_t i, std::size_t j, std::size_t k, const TTYPE &T, const RhoStarType &rhostar) const
static constexpr multipolar_argument_spec arg_spec
auto get_alpha2(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions) const
auto get_alpha3(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions) const
auto eval(const TTYPE &T, const RhoType &rhoN, const RhoStarType &rhostar, const VecType &mole_fractions) const
MultipolarContributionGubbinsTwu(const Eigen::ArrayX< double > &sigma_m, const Eigen::ArrayX< double > &epsilon_over_k, const Eigen::ArrayX< double > &mubar2, const Eigen::ArrayX< double > &Qbar2, multipolar_rhostar_approach approach)
auto get_rhostar(const RhoType rhoN, const PFType &packing_fraction, const MoleFractions &mole_fractions) const
MultipolarContributionGubbinsTwu & operator=(const MultipolarContributionGubbinsTwu &)=delete
std::variant< teqp::saft::polar_terms::GrossVrabec::MultipolarContributionGrossVrabec, MultipolarContributionGrayGubbins< GubbinsTwuJIntegral, GubbinsTwuKIntegral >, MultipolarContributionGrayGubbins< GottschalkJIntegral, GottschalkKIntegral >, MultipolarContributionGrayGubbins< LuckasJIntegral, LuckasKIntegral >, MultipolarContributionGubbinsTwu< LuckasJIntegral, LuckasKIntegral >, MultipolarContributionGubbinsTwu< GubbinsTwuJIntegral, GubbinsTwuKIntegral >, MultipolarContributionGubbinsTwu< GottschalkJIntegral, GottschalkKIntegral > > multipolar_contributions_variant
The variant containing the multipolar types that can be provided.
auto get_Kijk_334445(const KType &Kint, const RhoType &rhostar, const Txy &Tstarij, const Txy &Tstarik, const Txy &Tstarjk)
auto get_Kijk(const KType &Kint, const RhoType &rhostar, const Txy &Tstarij, const Txy &Tstarik, const Txy &Tstarjk)
const double k_e
Coulomb constant, with units of N m^2 / C^2.
const double k_B
Boltzmann constant.
multipolar_rhostar_approach
auto toeig(const std::vector< double > &v) -> Eigen::ArrayXd
auto getbaseval(const T &expr)
T powi(const T &x, int n)
From Ulrich Deiters.
auto pow(const double &x, const double &e)
Eigen::ArrayXd alpha_symm_C2m2J
Eigen::ArrayXd alpha_anisotropic_C2m2J
Eigen::ArrayXd alpha_isotropic_C2m2J
Eigen::ArrayXd alpha_asymm_C2m2J