teqp 0.22.0
Loading...
Searching...
No Matches
derivs.hpp
Go to the documentation of this file.
1#pragma once
2
3#if defined(TEQP_COMPLEXSTEP_ENABLED)
4#include <complex>
5#endif
6#include <map>
7#include <tuple>
8#include <numeric>
9#include <concepts>
10
11#include "teqp/types.hpp"
12#include "teqp/exceptions.hpp"
13
14#if defined(TEQP_MULTICOMPLEX_ENABLED)
15#include "MultiComplex/MultiComplex.hpp"
16#endif
17
18// autodiff include
19#include <autodiff/forward/dual.hpp>
20#include <autodiff/forward/dual/eigen.hpp>
21#include <autodiff/forward/real.hpp>
22#include <autodiff/forward/real/eigen.hpp>
23
24using namespace autodiff;
25
26namespace teqp {
27
32template <typename TType, typename ContainerType, typename FuncType>
33typename ContainerType::value_type derivT(const FuncType& f, TType T, const ContainerType& rho) {
34 double h = 1e-100;
35 return f(std::complex<TType>(T, h), rho).imag() / h;
36}
37
38#if defined(TEQP_MULTICOMPLEX_ENABLED)
43template <typename TType, typename ContainerType, typename FuncType>
44typename ContainerType::value_type derivTmcx(const FuncType& f, TType T, const ContainerType& rho) {
45 using fcn_t = std::function<mcx::MultiComplex<double>(const mcx::MultiComplex<double>&)>;
46 fcn_t wrapper = [&rho, &f](const auto& T_) {return f(T_, rho); };
47 auto ders = diff_mcx1(wrapper, T, 1);
48 return ders[0];
49}
50#endif
51
56template <typename TType, typename ContainerType, typename FuncType, typename Integer>
57typename ContainerType::value_type derivrhoi(const FuncType& f, TType T, const ContainerType& rho, Integer i) {
58 double h = 1e-100;
59 using comtype = std::complex<typename ContainerType::value_type>;
60 Eigen::ArrayX<comtype> rhocom(rho.size());
61 for (auto j = 0; j < rho.size(); ++j) {
62 rhocom[j] = comtype(rho[j], 0.0);
63 }
64 rhocom[i] = comtype(rho[i], h);
65 return f(T, rhocom).imag() / h;
66}
67
70template<typename T, size_t ... I>
71auto build_duplicated_tuple_impl(const T& val, std::index_sequence<I...>) {
72 return std::make_tuple((static_cast<void>(I), val)...); // The comma operator (a,b) evaluates the first argument and discards it, and keeps the second argument
73}
74
76template<int N, typename T>
77auto build_duplicated_tuple(const T& val) {
78 return build_duplicated_tuple_impl(val, std::make_index_sequence<N>());
79}
80
84struct wrt_helper {
85 template<typename... Args>
86 auto operator()(Args&&... args) const
87 {
88 return Wrt<Args&&...>{ std::forward_as_tuple(std::forward<Args>(args)...) };
89 }
90};
91
92enum class ADBackends { autodiff
93#if defined(TEQP_MULTICOMPLEX_ENABLED)
94 ,multicomplex
95#endif
96#if defined(TEQP_COMPLEXSTEP_ENABLED)
97 ,complex_step
98#endif
99};
100
101template<typename T, typename U, typename V, typename W>
102concept CallableAlpha = requires(T t, U u, V v, W w) {
103 { t.alpha(u,v,w) };
104};
105
106template<typename T, typename U, typename V, typename W>
107concept CallableAlphar = requires(T t, U u, V v, W w) {
108 { t.alphar(u,v,w) };
109};
110
111template<typename T, typename U, typename V, typename W>
112concept CallableAlpharTauDelta = requires(T t, U u, V v, W w) {
113 { t.alphar_taudelta(u,v,w) };
114};
115
116template<typename Model, typename Scalar = double, typename VectorType = Eigen::ArrayXd>
118
119 static auto get_Ar00(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
120 return model.alphar(T, rho, molefrac);
121 }
122
123 template<typename AlphaWrapper, typename S1, typename S2, typename Vec>
124 static auto AlphaCaller(const AlphaWrapper& w, const S1& T, const S2& rho, const Vec& molefrac) requires CallableAlpha<AlphaWrapper, S1, S2, Vec>{
125 return w.alpha(T, rho, molefrac);
126 }
127 template<typename AlphaWrapper, typename S1, typename S2, typename Vec>
128 static auto AlphaCaller(const AlphaWrapper& w, const S1& T, const S2& rho, const Vec& molefrac) requires CallableAlphar<AlphaWrapper, S1, S2, Vec>{
129 return w.alphar(T, rho, molefrac);
130 }
131
132 template<typename AlphaWrapper, typename S1, typename S2, typename Vec>
133 static auto AlpharTauDeltaCaller(const AlphaWrapper& w, const S1& T, const S2& rho, const Vec& molefrac) requires CallableAlpharTauDelta<AlphaWrapper, S1, S2, Vec>{
134 return w.alphar_taudelta(T, rho, molefrac);
135 }
136 template<typename AlphaWrapper, typename S1, typename S2, typename Vec>
137 static auto AlpharTauDeltaCaller(const AlphaWrapper& , const S1&, const S2&, const Vec& molefrac){
138 throw teqp::NotImplementedError("Cannot take derivatives of a class that doesn't define the alphar_taudelta method");
139 return std::common_type_t<S1, S2, decltype(molefrac[0])>(1e99);
140 }
141
150 template<int iT, int iD, ADBackends be = ADBackends::autodiff, class AlphaWrapper>
151 static auto get_Agenxy(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
152
153 if constexpr (iT == 0 && iD == 0){
154 return AlphaCaller(w, T, rho, molefrac);
155 }
156 else if constexpr (iT == 0 && iD > 0) {
157 if constexpr (be == ADBackends::autodiff) {
158 // If a pure derivative, then we can use autodiff::Real for that variable and Scalar for other variable
159 autodiff::Real<iD, Scalar> rho_ = rho;
160 auto f = [&w, &T, &molefrac](const auto& rho__) { return AlphaCaller(w, T, rho__, molefrac); };
161 return powi(rho, iD)*derivatives(f, along(1), at(rho_))[iD];
162 }
163#if defined(TEQP_COMPLEXSTEP_ENABLED)
164 else if constexpr (iD == 1 && be == ADBackends::complex_step) {
165 double h = 1e-100;
166 auto rho_ = std::complex<Scalar>(rho, h);
167 return powi(rho, iD) * AlphaCaller(w, T, rho_, molefrac).imag() / h;
168 }
169#endif
170#if defined(TEQP_MULTICOMPLEX_ENABLED)
171 else if constexpr (be == ADBackends::multicomplex) {
172 using fcn_t = std::function<mcx::MultiComplex<Scalar>(const mcx::MultiComplex<Scalar>&)>;
173 fcn_t f = [&](const auto& rhomcx) { return AlphaCaller(w, T, rhomcx, molefrac); };
174 auto ders = diff_mcx1(f, rho, iD, true /* and_val */);
175 return powi(rho, iD)*ders[iD];
176 }
177#endif
178 else {
179 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Agenxy for iT == 0");
180 }
181 }
182 else if constexpr (iT > 0 && iD == 0) {
183 Scalar Trecip = 1.0 / T;
184 if constexpr (be == ADBackends::autodiff) {
185 // If a pure derivative, then we can use autodiff::Real for that variable and Scalar for other variable
186 autodiff::Real<iT, Scalar> Trecipad = Trecip;
187 auto f = [&w, &rho, &molefrac](const auto& Trecip__) {return AlphaCaller(w, forceeval(1.0/Trecip__), rho, molefrac); };
188 return powi(Trecip, iT)*derivatives(f, along(1), at(Trecipad))[iT];
189 }
190#if defined(TEQP_COMPLEXSTEP_ENABLED)
191 else if constexpr (iT == 1 && be == ADBackends::complex_step) {
192 double h = 1e-100;
193 auto Trecipcsd = std::complex<Scalar>(Trecip, h);
194 return powi(Trecip, iT)* w.alpha(1/Trecipcsd, rho, molefrac).imag()/h;
195 }
196#endif
197#if defined(TEQP_MULTICOMPLEX_ENABLED)
198 else if constexpr (be == ADBackends::multicomplex) {
199 using fcn_t = std::function<mcx::MultiComplex<Scalar>(const mcx::MultiComplex<Scalar>&)>;
200 fcn_t f = [&](const auto& Trecipmcx) { return AlphaCaller(w, 1.0/Trecipmcx, rho, molefrac); };
201 auto ders = diff_mcx1(f, Trecip, iT, true /* and_val */);
202 return powi(Trecip, iT)*ders[iT];
203 }
204#endif
205 else {
206 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Agenxy for iD == 0");
207 }
208 }
209 else { // iT > 0 and iD > 0
210 if constexpr (be == ADBackends::autodiff) {
211 using adtype = autodiff::HigherOrderDual<iT + iD, double>;
212 adtype Trecipad = 1.0 / T, rhoad = rho;
213 auto f = [&w, &molefrac](const adtype& Trecip, const adtype& rho_) {
214 adtype T_ = 1.0/Trecip;
215 return forceeval(AlphaCaller(w, T_, rho_, molefrac)); };
216 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(Trecipad)), build_duplicated_tuple<iD>(std::ref(rhoad)));
217 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(Trecipad, rhoad));
218 return powi(forceeval(1.0 / T), iT) * powi(rho, iD) * der[der.size() - 1];
219 }
220#if defined(TEQP_MULTICOMPLEX_ENABLED)
221 else if constexpr (be == ADBackends::multicomplex) {
222 using fcn_t = std::function< mcx::MultiComplex<double>(const std::valarray<mcx::MultiComplex<double>>&)>;
223 const fcn_t func = [&w, &molefrac](const auto& zs) {
224 auto Trecip = zs[0], rhomolar = zs[1];
225 return AlphaCaller(w, 1.0 / Trecip, rhomolar, molefrac);
226 };
227 std::vector<double> xs = { 1.0 / T, rho};
228 std::vector<int> order = { iT, iD };
229 auto der = mcx::diff_mcxN(func, xs, order);
230 return powi(1.0 / T, iT)*powi(rho, iD)*der;
231 }
232#endif
233 else {
234 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Agenxy for iD > 0 and iT > 0");
235 }
236 }
237 // return static_cast<Scalar>(-999999999*T); // This will never hit, only to make compiler happy because it doesn't know the return type
238 }
239
247 template<int iT, int iD, int iXi, typename AlphaWrapper>
248 static auto get_ATrhoXi(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac, int i){
249 using adtype = autodiff::HigherOrderDual<iT + iD + iXi, double>;
250 adtype Trecipad = 1.0 / T, rhoad = rho, xi = molefrac[i];
251 auto f = [&w, &molefrac, &i](const adtype& Trecip, const adtype& rho_, const adtype& xi_) {
252 adtype T_ = 1.0/Trecip;
253 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
254 molefracdual[i] = xi_;
255 return forceeval(AlphaCaller(w, T_, rho_, molefracdual)); };
256 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(Trecipad)), build_duplicated_tuple<iD>(std::ref(rhoad)), build_duplicated_tuple<iXi>(std::ref(xi)));
257 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(Trecipad, rhoad, xi));
258 return powi(forceeval(1.0 / T), iT) * powi(rho, iD) * der[der.size() - 1];
259 }
260
261 #define get_ATrhoXi_runtime_combinations \
262 X(0,0,1) \
263 X(0,0,2) \
264 X(0,0,3) \
265 X(1,0,0) \
266 X(1,0,1) \
267 X(1,0,2) \
268 X(1,0,3) \
269 X(0,1,0) \
270 X(0,1,1) \
271 X(0,1,2) \
272 X(0,1,3) \
273 X(2,0,0) \
274 X(2,0,1) \
275 X(2,0,2) \
276 X(2,0,3) \
277 X(1,1,0) \
278 X(1,1,1) \
279 X(1,1,2) \
280 X(1,1,3) \
281 X(0,2,0) \
282 X(0,2,1) \
283 X(0,2,2) \
284 X(0,2,3)
285
286 template<typename AlphaWrapper>
287 static auto get_ATrhoXi_runtime(const AlphaWrapper& w, const Scalar& T, int iT, const Scalar& rho, int iD, const VectorType& molefrac, int i, int iXi){
288 #define X(a,b,c) if (iT == a && iD == b && iXi == c) { return get_ATrhoXi<a,b,c>(w, T, rho, molefrac, i); }
290 #undef X
291 throw teqp::InvalidArgument("Can't match these derivative counts");
292 }
293
294 #define get_ATrhoXiXj_runtime_combinations \
295 X(0,0,1,0) \
296 X(0,0,2,0) \
297 X(0,0,0,1) \
298 X(0,0,0,2) \
299 X(0,0,1,1) \
300 X(1,0,1,0) \
301 X(1,0,2,0) \
302 X(1,0,0,1) \
303 X(1,0,0,2) \
304 X(1,0,1,1) \
305 X(0,1,1,0) \
306 X(0,1,2,0) \
307 X(0,1,0,1) \
308 X(0,1,0,2) \
309 X(0,1,1,1)
310
311 template<typename AlphaWrapper>
312 static auto get_ATrhoXiXj_runtime(const AlphaWrapper& w, const Scalar& T, int iT, const Scalar& rho, int iD, const VectorType& molefrac, int i, int iXi, int j, int iXj){
313 #define X(a,b,c,d) if (iT == a && iD == b && iXi == c && iXj == d) { return get_ATrhoXiXj<a,b,c,d>(w, T, rho, molefrac, i, j); }
315 #undef X
316 throw teqp::InvalidArgument("Can't match these derivative counts");
317 }
318
319 #define get_ATrhoXiXjXk_runtime_combinations \
320 X(0,0,0,1,1) \
321 X(0,0,1,0,1) \
322 X(0,0,1,1,0) \
323 X(0,0,1,1,1) \
324 X(1,0,0,1,1) \
325 X(1,0,1,0,1) \
326 X(1,0,1,1,0) \
327 X(1,0,1,1,1) \
328 X(0,1,0,1,1) \
329 X(0,1,1,0,1) \
330 X(0,1,1,1,0) \
331 X(0,1,1,1,1)
332
333 template<typename AlphaWrapper>
334 static auto get_ATrhoXiXjXk_runtime(const AlphaWrapper& w, const Scalar& T, int iT, const Scalar& rho, int iD, const VectorType& molefrac, int i, int iXi, int j, int iXj, int k, int iXk){
335 #define X(a,b,c,d,e) if (iT == a && iD == b && iXi == c && iXj == d && iXk == e) { return get_ATrhoXiXjXk<a,b,c,d,e>(w, T, rho, molefrac, i, j, k); }
337 #undef X
338 throw teqp::InvalidArgument("Can't match these derivative counts");
339 }
340
341 template<int iT, int iD, int iXi, typename AlphaWrapper>
342 static auto get_AtaudeltaXi(const AlphaWrapper& w, const Scalar& tau, const Scalar& delta, const VectorType& molefrac, const int i) {
343 using adtype = autodiff::HigherOrderDual<iT + iD + iXi, double>;
344 adtype tauad = tau, deltaad = delta, xi = molefrac[i];
345 auto f = [&w, &molefrac, &i](const adtype& tau_, const adtype& delta_, const adtype& xi_) {
346 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
347 molefracdual[i] = xi_;
348 return forceeval(AlpharTauDeltaCaller(w, tau_, delta_, molefracdual)); };
349 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(tauad)), build_duplicated_tuple<iD>(std::ref(deltaad)), build_duplicated_tuple<iXi>(std::ref(xi)));
350 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(tauad, deltaad, xi));
351 return powi(tau, iT) * powi(delta, iD) * der[der.size() - 1];
352 }
353
354 template<int iT, int iD, int iXi, int iXj, typename AlphaWrapper>
355 static auto get_AtaudeltaXiXj(const AlphaWrapper& w, const Scalar& tau, const Scalar& delta, const VectorType& molefrac, const int i, const int j) {
356 using adtype = autodiff::HigherOrderDual<iT + iD + iXi + iXj, double>;
357 if (i == j){
358 throw teqp::InvalidArgument("i cannot equal j");
359 }
360 adtype tauad = tau, deltaad = delta, xi = molefrac[i], xj = molefrac[j];
361 auto f = [&w, &molefrac, i, j](const adtype& tau_, const adtype& delta_, const adtype& xi_, const adtype& xj_) {
362 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
363 molefracdual[i] = xi_;
364 molefracdual[j] = xj_;
365 return forceeval(AlpharTauDeltaCaller(w, tau_, delta_, molefracdual)); };
366 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(tauad)), build_duplicated_tuple<iD>(std::ref(deltaad)), build_duplicated_tuple<iXi>(std::ref(xi)), build_duplicated_tuple<iXj>(std::ref(xj)));
367 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(tauad, deltaad, xi, xj));
368 return powi(tau, iT) * powi(delta, iD) * der[der.size() - 1];
369 }
370
371 template<int iT, int iD, int iXi, int iXj, int iXk, typename AlphaWrapper>
372 static auto get_AtaudeltaXiXjXk(const AlphaWrapper& w, const Scalar& tau, const Scalar& delta, const VectorType& molefrac, const int i, const int j, const int k) {
373 using adtype = autodiff::HigherOrderDual<iT + iD + iXi + iXj + iXk, double>;
374 if (i == j || j == k || i == k){
375 throw teqp::InvalidArgument("i, j, and k must all be unique");
376 }
377 adtype tauad = tau, deltaad = delta, xi = molefrac[i], xj = molefrac[j], xk = molefrac[k];
378 auto f = [&w, &molefrac, i, j, k](const adtype& tau_, const adtype& delta_, const adtype& xi_, const adtype& xj_, const adtype& xk_) {
379 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
380 molefracdual[i] = xi_;
381 molefracdual[j] = xj_;
382 molefracdual[k] = xk_;
383 return forceeval(AlpharTauDeltaCaller(w, tau_, delta_, molefracdual)); };
384 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(tauad)), build_duplicated_tuple<iD>(std::ref(deltaad)), build_duplicated_tuple<iXi>(std::ref(xi)), build_duplicated_tuple<iXj>(std::ref(xj)), build_duplicated_tuple<iXk>(std::ref(xk)));
385 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(tauad, deltaad, xi, xj, xk));
386 return powi(tau, iT) * powi(delta, iD) * der[der.size() - 1];
387 }
388
389 template<typename AlphaWrapper>
390 static auto get_AtaudeltaXi_runtime(const AlphaWrapper& w, const Scalar& tau, const int iT, const Scalar& delta, const int iD, const VectorType& molefrac, const int i, const int iXi){
391 if (iT == 0 && iD == 0 && iXi == 0){
392 return AlpharTauDeltaCaller(w, tau, delta, molefrac);
393 }
394 #define X(a,b,c) if (iT == a && iD == b && iXi == c) { return get_AtaudeltaXi<a,b,c>(w, tau, delta, molefrac, i); }
396 #undef X
397 throw teqp::InvalidArgument("Can't match these derivative counts");
398 }
399
400 template<typename AlphaWrapper>
401 static auto get_AtaudeltaXiXj_runtime(const AlphaWrapper& w, const Scalar& tau, const int iT, const Scalar& delta, const int iD, const VectorType& molefrac, const int i, const int iXi, const int j, const int iXj){
402 #define X(a,b,c,d) if (iT == a && iD == b && iXi == c && iXj == d) { return get_AtaudeltaXiXj<a,b,c,d>(w, tau, delta, molefrac, i, j); }
404 #undef X
405 throw teqp::InvalidArgument("Can't match these derivative counts");
406 }
407
408 template<typename AlphaWrapper>
409 static auto get_AtaudeltaXiXjXk_runtime(const AlphaWrapper& w, const Scalar& tau, const int iT, const Scalar& delta, const int iD, const VectorType& molefrac, const int i, int iXi, const int j, const int iXj, const int k, const int iXk){
410 #define X(a,b,c,d,e) if (iT == a && iD == b && iXi == c && iXj == d && iXk == e) { return get_AtaudeltaXiXjXk<a,b,c,d,e>(w, tau, delta, molefrac, i, j, k); }
412 #undef X
413 throw teqp::InvalidArgument("Can't match these derivative counts");
414 }
415
423 template<int iT, int iD, int iXi, int iXj, typename AlphaWrapper>
424 static auto get_ATrhoXiXj(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac, int i, int j){
425 if (i == j){
426 throw teqp::InvalidArgument("i cannot equal j");
427 }
428 using adtype = autodiff::HigherOrderDual<iT + iD + iXi + iXj, double>;
429 adtype Trecipad = 1.0 / T, rhoad = rho, xi = molefrac[i], xj = molefrac[j];
430 auto f = [&w, &molefrac, i, j](const adtype& Trecip, const adtype& rho_, const adtype& xi_, const adtype& xj_) {
431 adtype T_ = 1.0/Trecip;
432 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
433 molefracdual[i] = xi_;
434 molefracdual[j] = xj_;
435 return forceeval(AlphaCaller(w, T_, rho_, molefracdual)); };
436 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(Trecipad)), build_duplicated_tuple<iD>(std::ref(rhoad)), build_duplicated_tuple<iXi>(std::ref(xi)), build_duplicated_tuple<iXj>(std::ref(xj)));
437 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(Trecipad, rhoad, xi, xj));
438 return powi(forceeval(1.0 / T), iT) * powi(rho, iD) * der[der.size() - 1];
439 }
440
448 template<int iT, int iD, int iXi, int iXj, int iXk, typename AlphaWrapper>
449 static auto get_ATrhoXiXjXk(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac, int i, int j, int k){
450 if (i == j || j == k || i == k){
451 throw teqp::InvalidArgument("i, j, and k must all be unique");
452 }
453 using adtype = autodiff::HigherOrderDual<iT + iD + iXi + iXj + iXk, double>;
454 adtype Trecipad = 1.0 / T, rhoad = rho, xi = molefrac[i], xj = molefrac[j], xk = molefrac[k];
455 auto f = [&w, &molefrac, i, j, k](const adtype& Trecip, const adtype& rho_, const adtype& xi_, const adtype& xj_, const adtype& xk_) {
456 adtype T_ = 1.0/Trecip;
457 Eigen::ArrayX<adtype> molefracdual = molefrac.template cast<adtype>();
458 molefracdual[i] = xi_;
459 molefracdual[j] = xj_;
460 molefracdual[k] = xk_;
461 return forceeval(AlphaCaller(w, T_, rho_, molefracdual)); };
462 auto wrts = std::tuple_cat(build_duplicated_tuple<iT>(std::ref(Trecipad)), build_duplicated_tuple<iD>(std::ref(rhoad)), build_duplicated_tuple<iXi>(std::ref(xi)), build_duplicated_tuple<iXj>(std::ref(xj)), build_duplicated_tuple<iXk>(std::ref(xk)));
463 auto der = derivatives(f, std::apply(wrt_helper(), wrts), at(Trecipad, rhoad, xi, xj, xk));
464 return powi(forceeval(1.0 / T), iT) * powi(rho, iD) * der[der.size() - 1];
465 }
466
475 template<int iT, int iD, ADBackends be = ADBackends::autodiff>
476 static auto get_Arxy(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
477 return get_Agenxy<iT, iD, be>(model, T, rho, molefrac);
478 }
479
488 template<int iT, int iD, ADBackends be = ADBackends::autodiff>
489 static auto get_Aigxy(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
490 return get_Agenxy<iT, iD, be>(model, T, rho, molefrac);
491 }
492
493 template<ADBackends be = ADBackends::autodiff>
494 static auto get_Ar10(const Model& model, const Scalar &T, const Scalar &rho, const VectorType& molefrac) {
495 return get_Arxy<1, 0, be>(model, T, rho, molefrac);
496 }
497
498 template<ADBackends be = ADBackends::autodiff>
499 static Scalar get_Ar01(const Model& model, const Scalar&T, const Scalar &rho, const VectorType& molefrac){
500 return get_Arxy<0, 1, be>(model, T, rho, molefrac);
501 }
502
503 template<ADBackends be = ADBackends::autodiff>
504 static auto get_Ar02(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
505 return get_Arxy<0, 2, be>(model, T, rho, molefrac);
506 }
507
508 template<ADBackends be = ADBackends::autodiff>
509 static auto get_Ar03(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
510 return get_Arxy<0, 3, be>(model, T, rho, molefrac);
511 }
512
513 template<ADBackends be = ADBackends::autodiff>
514 static auto get_Ar20(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
515 return get_Arxy<2, 0, be>(model, T, rho, molefrac);
516 }
517
518 template<ADBackends be = ADBackends::autodiff>
519 static auto get_Ar30(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
520 return get_Arxy<3, 0, be>(model, T, rho, molefrac);
521 }
522
523 template<ADBackends be = ADBackends::autodiff>
524 static auto get_Ar21(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
525 return get_Arxy<2, 1, be>(model, T, rho, molefrac);
526 }
527
528 template<ADBackends be = ADBackends::autodiff>
529 static auto get_Ar12(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
530 return get_Arxy<1, 2, be>(model, T, rho, molefrac);
531 }
532
533 template<ADBackends be = ADBackends::autodiff>
534 static auto get_Ar11(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
535 return get_Arxy<1, 1, be>(model, T, rho, molefrac);
536 }
537
538 template<ADBackends be = ADBackends::autodiff>
539 static auto get_Aig11(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
540 return get_Aigxy<1, 1, be>(model, T, rho, molefrac);
541 }
542
543 template<int Nderiv, ADBackends be = ADBackends::autodiff, class AlphaWrapper>
544 static auto get_Agen0n(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
545 std::valarray<Scalar> o(Nderiv+1);
546 if constexpr (be == ADBackends::autodiff) {
547 // If a pure derivative, then we can use autodiff::Real for that variable and Scalar for other variable
548 autodiff::Real<Nderiv, Scalar> rho_ = rho;
549 auto f = [&w, &T, &molefrac](const auto& rho__) { return AlphaCaller(w, T, rho__, molefrac); };
550 auto ders = derivatives(f, along(1), at(rho_));
551 for (auto n = 0; n <= Nderiv; ++n) {
552 o[n] = forceeval(powi(rho, n) * ders[n]);
553 }
554 return o;
555 }
556#if defined(TEQP_MULTICOMPLEX_ENABLED)
557 else {
558 using fcn_t = std::function<mcx::MultiComplex<Scalar>(const mcx::MultiComplex<Scalar>&)>;
559 bool and_val = true;
560 fcn_t f = [&w, &T, &molefrac](const auto& rhomcx) { return AlphaCaller(w, T, rhomcx, molefrac); };
561 auto ders = diff_mcx1(f, rho, Nderiv, and_val);
562 for (auto n = 0; n <= Nderiv; ++n) {
563 o[n] = powi(rho, n) * ders[n];
564 }
565 return o;
566 }
567#endif
568// throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Ar0n");
569 }
570
571 template<int Nderiv, ADBackends be = ADBackends::autodiff, class AlphaWrapper>
572 static auto get_Agenn0(const AlphaWrapper& w, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
573 std::valarray<Scalar> o(Nderiv+1);
574 Scalar Trecip = 1.0 / T;
575 if constexpr (be == ADBackends::autodiff) {
576 // If a pure derivative, then we can use autodiff::Real for that variable and Scalar for other variable
577 autodiff::Real<Nderiv, Scalar> Trecipad = Trecip;
578 auto f = [&w, &rho, &molefrac](const auto& Trecip__) {return AlphaCaller(w, forceeval(1.0/Trecip__), rho, molefrac); };
579 auto ders = derivatives(f, along(1), at(Trecipad));
580 for (auto n = 0; n <= Nderiv; ++n) {
581 o[n] = powi(Trecip, n) * ders[n];
582 }
583 }
584#if defined(TEQP_MULTICOMPLEX_ENABLED)
585 else if constexpr (be == ADBackends::multicomplex) {
586 using fcn_t = std::function<mcx::MultiComplex<Scalar>(const mcx::MultiComplex<Scalar>&)>;
587 fcn_t f = [&](const auto& Trecipmcx) { return AlphaCaller(w, 1.0/Trecipmcx, rho, molefrac); };
588 auto ders = diff_mcx1(f, Trecip, Nderiv+1, true /* and_val */);
589 for (auto n = 0; n <= Nderiv; ++n) {
590 o[n] = powi(Trecip, n) * ders[n];
591 }
592 }
593#endif
594 else {
595 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Agenn0");
596 }
597 return o;
598 }
599
608 template<int iT, ADBackends be = ADBackends::autodiff>
609 static auto get_Arn0(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
610 return get_Agenn0<iT, be>(model, T, rho, molefrac);
611 }
612
621 template<int iD, ADBackends be = ADBackends::autodiff>
622 static auto get_Ar0n(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
623 return get_Agen0n<iD, be>(model, T, rho, molefrac);
624 }
625
626
627 template<ADBackends be = ADBackends::autodiff>
628 static auto get_Ar(const int itau, const int idelta, const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
629 if (itau == 0) {
630 if (idelta == 0) {
631 return get_Ar00(model, T, rho, molefrac);
632 }
633 else if (idelta == 1) {
634 return get_Ar01(model, T, rho, molefrac);
635 }
636 else if (idelta == 2) {
637 return get_Ar02(model, T, rho, molefrac);
638 }
639 else if (idelta == 3) {
640 return get_Ar03(model, T, rho, molefrac);
641 }
642 else {
643 throw std::invalid_argument("Invalid value for idelta");
644 }
645 }
646 else if (itau == 1){
647 if (idelta == 0) {
648 return get_Ar10(model, T, rho, molefrac);
649 }
650 else if (idelta == 1) {
651 return get_Ar11(model, T, rho, molefrac);
652 }
653 else if (idelta == 2) {
654 return get_Ar12(model, T, rho, molefrac);
655 }
656 else {
657 throw std::invalid_argument("Invalid value for idelta");
658 }
659 }
660 else if (itau == 2) {
661 if (idelta == 0) {
662 return get_Ar20(model, T, rho, molefrac);
663 }
664 else if (idelta == 1) {
665 return get_Ar21(model, T, rho, molefrac);
666 }
667 else {
668 throw std::invalid_argument("Invalid value for idelta");
669 }
670 }
671 else if (itau == 3) {
672 if (idelta == 0) {
673 return get_Ar30(model, T, rho, molefrac);
674 }
675 else {
676 throw std::invalid_argument("Invalid value for idelta");
677 }
678 }
679 else {
680 throw std::invalid_argument("Invalid value for itau");
681 }
682 }
683
684 template<ADBackends be = ADBackends::autodiff>
685 static auto get_neff(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
686 auto Ar01 = get_Ar01<be>(model, T, rho, molefrac);
687 auto Ar11 = get_Ar11<be>(model, T, rho, molefrac);
688 auto Ar20 = get_Ar20<be>(model, T, rho, molefrac);
689 return -3*(Ar01-Ar11)/Ar20;
690 }
691};
692
693template<typename Model, typename Scalar = double, typename VectorType = Eigen::ArrayXd>
695
696 static auto get_B2vir(const Model& model, const Scalar &T, const VectorType& molefrac) {
697 Scalar h = 1e-100;
698 // B_2 = dalphar/drho|T,z at rho=0
699 auto B2 = model.alphar(T, std::complex<Scalar>(0.0, h), molefrac).imag()/h;
700 return B2;
701 }
702
713 template <int Nderiv, ADBackends be = ADBackends::autodiff>
714 static auto get_Bnvir(const Model& model, const Scalar &T, const VectorType& molefrac)
715 {
716 std::map<int, double> dnalphardrhon;
717 if constexpr(be == ADBackends::autodiff){
718 auto f = [&model, &T, &molefrac](const auto& rho_) { return model.alphar(T, rho_, molefrac); };
719 autodiff::Real<Nderiv, Scalar> rhoreal = 0.0;
720 auto derivs = derivatives(f, along(1), at(rhoreal));
721
722 for (auto n = 1; n < Nderiv; ++n){
723 dnalphardrhon[n] = derivs[n];
724 }
725 }
726#if defined(TEQP_MULTICOMPLEX_ENABLED)
727 else if constexpr(be == ADBackends::multicomplex){
728 using namespace mcx;
729 using fcn_t = std::function<MultiComplex<double>(const MultiComplex<double>&)>;
730 fcn_t f = [&model, &T, &molefrac](const auto& rho_) { return model.alphar(T, rho_, molefrac); };
731 auto derivs = diff_mcx1(f, 0.0, Nderiv, true /* and_val */);
732 for (auto n = 1; n < Nderiv; ++n){
733 dnalphardrhon[n] = derivs[n];
734 }
735 }
736#endif
737 else{
738 //static_assert(false, "algorithmic differentiation backend is invalid");
739 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Bnvir");
740 }
741
742 std::map<int, Scalar> o;
743 for (int n = 2; n <= Nderiv; ++n) {
744 o[n] = dnalphardrhon[n-1];
745 // 0! = 1, 1! = 1, so only n>3 terms need factorial correction
746 if (n > 3) {
747 auto factorial = [](int N) {return tgamma(N + 1); };
748 o[n] /= factorial(n-2);
749 }
750 }
751 return o;
752 }
753
756 template <ADBackends be = ADBackends::autodiff>
757 static auto get_Bnvir_runtime(const int Nderiv, const Model& model, const Scalar &T, const VectorType& molefrac) {
758 switch(Nderiv){
759 case 2: return get_Bnvir<2,be>(model, T, molefrac);
760 case 3: return get_Bnvir<3,be>(model, T, molefrac);
761 case 4: return get_Bnvir<4,be>(model, T, molefrac);
762 case 5: return get_Bnvir<5,be>(model, T, molefrac);
763 case 6: return get_Bnvir<6,be>(model, T, molefrac);
764 case 7: return get_Bnvir<7,be>(model, T, molefrac);
765 case 8: return get_Bnvir<8,be>(model, T, molefrac);
766 case 9: return get_Bnvir<9,be>(model, T, molefrac);
767 default: throw std::invalid_argument("Only Nderiv up to 9 is supported, get_Bnvir templated function allows more");
768 }
769 }
770
783 template <int Nderiv, int NTderiv, ADBackends be = ADBackends::autodiff>
784 static auto get_dmBnvirdTm(const Model& model, const Scalar& T, const VectorType& molefrac)
785 {
786 std::map<int, Scalar> o;
787 auto factorial = [](int N) {return tgamma(N + 1); };
788 if constexpr (be == ADBackends::autodiff) {
789 autodiff::HigherOrderDual<NTderiv + Nderiv-1, double> rhodual = 0.0, Tdual = T;
790 auto f = [&model, &molefrac](const auto& T_, const auto& rho_) { return model.alphar(T_, rho_, molefrac); };
791 auto wrts = std::tuple_cat(build_duplicated_tuple<NTderiv>(std::ref(Tdual)), build_duplicated_tuple<Nderiv-1>(std::ref(rhodual)));
792 auto derivs = derivatives(f, std::apply(wrt_helper(), wrts), at(Tdual, rhodual));
793 return derivs.back() / factorial(Nderiv - 2);
794 }
795#if defined(TEQP_MULTICOMPLEX_ENABLED)
796 else if constexpr (be == ADBackends::multicomplex) {
797 using namespace mcx;
798 using fcn_t = std::function<MultiComplex<double>(const std::valarray<MultiComplex<double>>&)>;
799 fcn_t f = [&model, &molefrac](const auto& zs) {
800 auto T_ = zs[0], rho_ = zs[1];
801 return model.alphar(T_, rho_, molefrac);
802 };
803 std::valarray<double> at = { T, 0.0 };
804 auto deriv = diff_mcxN(f, at, { NTderiv, Nderiv-1});
805 return deriv / factorial(Nderiv - 2);
806 }
807#endif
808 else {
809 //static_assert(false, "algorithmic differentiation backend is invalid");
810 throw std::invalid_argument("algorithmic differentiation backend is invalid in get_Bnvir");
811 }
812 }
813
816 template <ADBackends be = ADBackends::autodiff>
817 static auto get_dmBnvirdTm_runtime(const int Nderiv, const int NTderiv, const Model& model, const Scalar& T, const VectorType& molefrac) {
818 if (Nderiv == 2) { // B_2
819 switch (NTderiv) {
820 case 0: return get_Bnvir<2, be>(model, T, molefrac)[2];
821 case 1: return get_dmBnvirdTm<2, 1, be>(model, T, molefrac);
822 case 2: return get_dmBnvirdTm<2, 2, be>(model, T, molefrac);
823 case 3: return get_dmBnvirdTm<2, 3, be>(model, T, molefrac);
824 default: throw std::invalid_argument("NTderiv is invalid in get_dmBnvirdTm_runtime");
825 }
826 }
827 else if (Nderiv == 3) { // B_3
828 switch (NTderiv) {
829 case 0: return get_Bnvir<3, be>(model, T, molefrac)[3];
830 case 1: return get_dmBnvirdTm<3, 1, be>(model, T, molefrac);
831 case 2: return get_dmBnvirdTm<3, 2, be>(model, T, molefrac);
832 case 3: return get_dmBnvirdTm<3, 3, be>(model, T, molefrac);
833 default: throw std::invalid_argument("NTderiv is invalid in get_dmBnvirdTm_runtime");
834 }
835 }
836 else if (Nderiv == 4) { // B_4
837 switch (NTderiv) {
838 case 0: return get_Bnvir<4, be>(model, T, molefrac)[4];
839 case 1: return get_dmBnvirdTm<4, 1, be>(model, T, molefrac);
840 case 2: return get_dmBnvirdTm<4, 2, be>(model, T, molefrac);
841 case 3: return get_dmBnvirdTm<4, 3, be>(model, T, molefrac);
842 default: throw std::invalid_argument("NTderiv is invalid in get_dmBnvirdTm_runtime");
843 }
844 }
845 else {
846 throw std::invalid_argument("Nderiv is invalid in get_dmBnvirdTm_runtime");
847 }
848 }
849
856 static auto get_B12vir(const Model& model, const Scalar &T, const VectorType& molefrac) {
857 if (molefrac.size() != 2) { throw std::invalid_argument("length of mole fraction vector must be 2 in get_B12vir"); }
858 auto B2 = get_B2vir(model, T, molefrac); // Overall B2 for mixture
859 const auto xpure0 = (Eigen::ArrayXd(2) << 1,0).finished();
860 const auto xpure1 = (Eigen::ArrayXd(2) << 0,1).finished();
861 auto B20 = get_B2vir(model, T, xpure0); // Pure first component with index 0
862 auto B21 = get_B2vir(model, T, xpure1); // Pure second component with index 1
863 auto z0 = molefrac[0];
864 auto B12 = (B2 - z0*z0*B20 - (1-z0)*(1-z0)*B21)/(2*z0*(1-z0));
865 return B12;
866 }
867};
868
956template<typename Model, typename Scalar = double, typename VectorType = Eigen::ArrayXd>
958
962 static auto get_splus(const Model& model, const Scalar &T, const VectorType& rhovec) {
963 auto rhotot = rhovec.sum();
964 auto molefrac = rhovec / rhotot;
965 return model.alphar(T, rhotot, molefrac) - get_Ar10(model, T, rhovec);
966 }
967
971 static auto get_pr(const Model& model, const Scalar &T, const VectorType& rhovec)
972 {
973 auto rhotot_ = rhovec.sum();
974 auto molefrac = (rhovec / rhotot_).eval();
975 auto h = 1e-100;
976 auto Ar01 = model.alphar(T, std::complex<double>(rhotot_, h), molefrac).imag() / h * rhotot_;
977 return Ar01*rhotot_*model.R(molefrac)*T;
978 }
979
980 static auto get_Ar00(const Model& model, const Scalar& T, const VectorType& rhovec) {
981 auto rhotot = rhovec.sum();
982 auto molefrac = (rhovec / rhotot).eval();
983 return model.alphar(T, rhotot, molefrac);
984 }
985
986 static auto get_Ar10(const Model& model, const Scalar& T, const VectorType& rhovec) {
987 auto rhotot = rhovec.sum();
988 auto molefrac = (rhovec / rhotot).eval();
989 return -T * derivT([&model, &rhotot, &molefrac](const auto& T, const auto& /*rhovec*/) { return model.alphar(T, rhotot, molefrac); }, T, rhovec);
990 }
991
992 static auto get_Ar01(const Model& model, const Scalar &T, const VectorType& rhovec) {
993 auto rhotot_ = std::accumulate(std::begin(rhovec), std::end(rhovec), (decltype(rhovec[0]))0.0);
994 decltype(rhovec[0] * T) Ar01 = 0.0;
995 for (auto i = 0; i < rhovec.size(); ++i) {
996 auto Ar00 = [&model](const auto &T, const auto&rhovec) {
997 auto rhotot = rhovec.sum();
998 auto molefrac = rhovec / rhotot;
999 return model.alphar(T, rhotot, molefrac);
1000 };
1001 Ar01 += rhovec[i] * derivrhoi(Ar00, T, rhovec, i);
1002 }
1003 return Ar01;
1004 }
1005
1009 static auto get_Psir(const Model& model, const Scalar &T, const VectorType& rhovec) {
1010 auto rhotot_ = rhovec.sum();
1011 auto molefrac = rhovec / rhotot_;
1012 return model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_;
1013 }
1014
1018 static auto get_dPsirdT_constrhovec(const Model& model, const Scalar& T, const VectorType& rhovec) {
1019 auto rhotot_ = rhovec.sum();
1020 auto molefrac = (rhovec / rhotot_).eval();
1021 autodiff::Real<1, Scalar> Tad = T;
1022 auto f = [&model, &rhotot_, &molefrac](const auto& T_) {return rhotot_*model.R(molefrac)*T_*model.alphar(T_, rhotot_, molefrac); };
1023 return derivatives(f, along(1), at(Tad))[1];
1024 }
1025
1031 static auto build_Psir_Hessian_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1032 // Double derivatives in each component's concentration
1033 // N^N matrix (symmetric)
1034
1035 dual2nd u; // the output scalar u = f(x), evaluated together with Hessian below
1036 ArrayXdual2nd g;
1037 ArrayXdual2nd rhovecc(rho.size()); for (auto i = 0; i < rho.size(); ++i) { rhovecc[i] = rho[i]; }
1038 auto hfunc = [&model, &T](const ArrayXdual2nd& rho_) {
1039 auto rhotot_ = rho_.sum();
1040 auto molefrac = (rho_ / rhotot_).eval();
1041 return forceeval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1042 };
1043 return autodiff::hessian(hfunc, wrt(rhovecc), at(rhovecc), u, g).eval(); // evaluate the function value u, its gradient, and its Hessian matrix H
1044 }
1045
1051 static auto build_Psir_fgradHessian_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1052 // Double derivatives in each component's concentration
1053 // N^N matrix (symmetric)
1054
1055 dual2nd u; // the output scalar u = f(x), evaluated together with Hessian below
1056 ArrayXdual g;
1057 ArrayXdual2nd rhovecc(rho.size()); for (auto i = 0; i < rho.size(); ++i) { rhovecc[i] = rho[i]; }
1058 auto hfunc = [&model, &T](const ArrayXdual2nd& rho_) {
1059 auto rhotot_ = rho_.sum();
1060 auto molefrac = (rho_ / rhotot_).eval();
1061 return forceeval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1062 };
1063 // Evaluate the function value u, its gradient, and its Hessian matrix H
1064 Eigen::MatrixXd H = autodiff::hessian(hfunc, wrt(rhovecc), at(rhovecc), u, g);
1065 // Remove autodiff stuff from the numerical values
1066 auto f = getbaseval(u);
1067 auto gg = g.cast<double>().eval();
1068 return std::make_tuple(f, gg, H);
1069 }
1070
1076 static auto build_Psi_Hessian_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1077 auto rhotot_ = rho.sum();
1078 auto molefrac = (rho / rhotot_).eval();
1079 auto H = build_Psir_Hessian_autodiff(model, T, rho).eval();
1080 for (auto i = 0; i < rho.size(); ++i) {
1081 H(i, i) += model.R(molefrac) * T / rho[i];
1082 }
1083 return H;
1084 }
1085
1086#if defined(TEQP_MULTICOMPLEX_ENABLED)
1092 static auto build_Psir_Hessian_mcx(const Model& model, const Scalar& T, const VectorType& rho) {
1093 // Double derivatives in each component's concentration
1094 // N^N matrix (symmetric)
1095 using namespace mcx;
1096
1097 // Lambda function for getting Psir with multicomplex concentrations
1098 using fcn_t = std::function< MultiComplex<double>(const Eigen::ArrayX<MultiComplex<double>>&)>;
1099 fcn_t func = [&model, &T](const auto& rhovec) {
1100 auto rhotot_ = rhovec.sum();
1101 auto molefrac = (rhovec / rhotot_).eval();
1102 return model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_;
1103 };
1104 using mattype = Eigen::ArrayXXd;
1105 auto H = get_Hessian<mattype, fcn_t, VectorType, HessianMethods::Multiple>(func, rho);
1106 return H;
1107 }
1108#endif
1109
1115 static auto build_Psir_gradient_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1116 ArrayXdual rhovecc(rho.size()); for (auto i = 0; i < rho.size(); ++i) { rhovecc[i] = rho[i]; }
1117 auto psirfunc = [&model, &T](const ArrayXdual& rho_) {
1118 auto rhotot_ = rho_.sum();
1119 auto molefrac = (rho_ / rhotot_).eval();
1120 return forceeval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1121 };
1122 auto val = autodiff::gradient(psirfunc, wrt(rhovecc), at(rhovecc)).eval(); // evaluate the gradient
1123 return val;
1124 }
1125
1126#if defined(TEQP_MULTICOMPLEX_ENABLED)
1132 static auto build_Psir_gradient_multicomplex(const Model& model, const Scalar& T, const VectorType& rho) {
1133 using rho_type = typename VectorType::value_type;
1134 Eigen::ArrayX<mcx::MultiComplex<rho_type>> rhovecc(rho.size()); //for (auto i = 0; i < rho.size(); ++i) { rhovecc[i] = rho[i]; }
1135 auto psirfunc = [&model](const auto &T, const auto& rho_) {
1136 auto rhotot_ = rho_.sum();
1137 auto molefrac = (rho_ / rhotot_).eval();
1138 return eval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1139 };
1140 VectorType out(rho.size());
1141 for (int i = 0; i < rho.size(); ++i) {
1142 out[i] = derivrhoi(psirfunc, T, rho, i);
1143 }
1144 return out;
1145 }
1146#endif
1152 static auto build_Psir_gradient_complex_step(const Model& model, const Scalar& T, const VectorType& rho) {
1153 using rho_type = typename VectorType::value_type;
1154 Eigen::ArrayX<std::complex<rho_type>> rhovecc(rho.size()); for (auto i = 0; i < rho.size(); ++i) { rhovecc[i] = rho[i]; }
1155 auto psirfunc = [&model](const auto& T, const auto& rho_) {
1156 auto rhotot_ = rho_.sum();
1157 auto molefrac = (rho_ / rhotot_).eval();
1158 return forceeval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1159 };
1160 VectorType out(rho.size());
1161 for (int i = 0; i < rho.size(); ++i) {
1162 auto rhocopy = rhovecc;
1163 rho_type h = 1e-100;
1164 rhocopy[i] = rhocopy[i] + std::complex<rho_type>(0,h);
1165 auto calc = psirfunc(T, rhocopy);
1166 out[i] = calc.imag / static_cast<double>(h);
1167 }
1168 return out;
1169 }
1170
1171 /* Convenience function to select the correct implementation at compile-time */
1172 template<ADBackends be = ADBackends::autodiff>
1173 static auto build_Psir_gradient(const Model& model, const Scalar& T, const VectorType& rho) {
1174 if constexpr (be == ADBackends::autodiff) {
1175 return build_Psir_gradient_autodiff(model, T, rho);
1176 }
1177#if defined(TEQP_MULTICOMPLEX_ENABLED)
1178 else if constexpr (be == ADBackends::multicomplex) {
1179 return build_Psir_gradient_multicomplex(model, T, rho);
1180 }
1181#endif
1182#if defined(TEQP_COMPLEXSTEP_ENABLED)
1183 else if constexpr (be == ADBackends::complex_step) {
1184 return build_Psir_gradient_complex_step(model, T, rho);
1185 }
1186#endif
1187 }
1188
1196 static auto get_chempotVLE_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1197 typename VectorType::value_type rhotot = rho.sum();
1198 auto molefrac = (rho / rhotot).eval();
1199 auto rhorefideal = 1.0;
1200 return (build_Psir_gradient_autodiff(model, T, rho).array() + model.R(molefrac)*T*(rhorefideal + log(rho / rhorefideal))).eval();
1201 }
1202
1208 template<ADBackends be = ADBackends::autodiff>
1209 static auto get_fugacity_coefficients(const Model& model, const Scalar& T, const VectorType& rhovec) {
1210 VectorType lnphi = get_ln_fugacity_coefficients<be>(model, T, rhovec);
1211 return exp(lnphi).eval();
1212 }
1213
1219 template<ADBackends be = ADBackends::autodiff>
1220 static auto get_ln_fugacity_coefficients(const Model& model, const Scalar& T, const VectorType& rhovec) {
1221 auto rhotot = forceeval(rhovec.sum());
1222 auto molefrac = (rhovec / rhotot).eval();
1223 auto R = model.R(molefrac);
1225 auto Z = 1.0 + tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1226 auto grad = build_Psir_gradient<be>(model, T, rhovec).eval();
1227 auto RT = R * T;
1228 auto lnphi = ((grad / RT).array() - log(Z)).eval();
1229 return forceeval(lnphi.eval());
1230 }
1231
1232 template<ADBackends be = ADBackends::autodiff>
1233 static auto get_ln_fugacity_coefficients_Trhomolefracs(const Model& model, const Scalar& T, const Scalar& rhotot, const VectorType& molefrac) {
1234 auto R = model.R(molefrac);
1236 auto Z = 1.0 + tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1237 auto rhovec = (rhotot*molefrac).eval();
1238 auto grad = build_Psir_gradient<be>(model, T, rhovec).eval();
1239 auto RT = R * T;
1240 auto lnphi = ((grad / RT).array() - log(Z)).eval();
1241 return forceeval(lnphi.eval());
1242 }
1243
1244 template<ADBackends be = ADBackends::autodiff>
1245 static auto get_ln_fugacity_coefficients1(const Model& model, const Scalar& T, const VectorType& rhovec) {
1246 auto rhotot = forceeval(rhovec.sum());
1247 auto molefrac = (rhovec / rhotot).eval();
1248 auto R = model.R(molefrac);
1249 auto grad = build_Psir_gradient<be>(model, T, rhovec).eval();
1250 auto RT = R * T;
1251 auto lnphi = ((grad / RT).array()).eval();
1252 return forceeval(lnphi);
1253 }
1254
1255 template<ADBackends be = ADBackends::autodiff>
1256 static auto get_ln_fugacity_coefficients2(const Model& model, const Scalar& T, const VectorType& rhovec) {
1257 auto rhotot = forceeval(rhovec.sum());
1258 auto molefrac = (rhovec / rhotot).eval();
1260 auto Z = 1.0 + tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1261 return forceeval(-log(Z));
1262 }
1263
1264 static Eigen::ArrayXd build_d2PsirdTdrhoi_autodiff(const Model& model, const Scalar& T, const VectorType& rho) {
1265 Eigen::ArrayXd deriv(rho.size());
1266 // d^2psir/dTdrho_i
1267 for (auto i = 0; i < rho.size(); ++i) {
1268 auto psirfunc = [&model, &rho, i](const auto& T, const auto& rhoi) {
1269 ArrayXdual2nd rhovecc(rho.size()); for (auto j = 0; j < rho.size(); ++j) { rhovecc[j] = rho[j]; }
1270 rhovecc[i] = rhoi;
1271 auto rhotot_ = rhovecc.sum();
1272 auto molefrac = (rhovecc / rhotot_).eval();
1273 return forceeval(model.alphar(T, rhotot_, molefrac) * model.R(molefrac) * T * rhotot_);
1274 };
1275 dual2nd Tdual = T, rhoidual = rho[i];
1276 auto [u00, u10, u11] = derivatives(psirfunc, wrt(Tdual, rhoidual), at(Tdual, rhoidual));
1277 deriv[i] = u11;
1278 }
1279 return deriv;
1280 }
1281
1282 static Eigen::ArrayXd build_d2alphardrhodxi_constT(const Model& model, const Scalar& T, const Scalar& rhomolar, const VectorType& molefrac) {
1283 Eigen::ArrayXd deriv(molefrac.size());
1284 // d^2alphar/drhodx_i|T
1285 for (auto i = 0; i < molefrac.size(); ++i) {
1286 auto alpharfunc = [&model, &T, &molefrac, i](const auto& rho, const auto& xi) {
1287 ArrayXdual2nd molefracdual = molefrac.template cast<autodiff::dual2nd>();
1288 molefracdual[i] = xi;
1289 return forceeval(model.alphar(T, rho, molefracdual));
1290 };
1291 dual2nd rhodual = rhomolar, xidual = molefrac[i];
1292 auto [u00, u10, u11] = derivatives(alpharfunc, wrt(rhodual, xidual), at(rhodual, xidual));
1293 deriv[i] = u11;
1294 }
1295 return deriv;
1296 }
1297
1306 template<ADBackends be = ADBackends::autodiff>
1307 static auto get_d_ln_fugacity_coefficients_dT_constrhovec(const Model& model, const Scalar& T, const VectorType& rhovec) {
1308 auto rhotot = forceeval(rhovec.sum());
1309 auto molefrac = (rhovec / rhotot).eval();
1310 auto R = model.R(molefrac);
1312 auto Z = 1.0 + tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1313 auto dZdT_Z = tdx::template get_Ar11<be>(model, T, rhotot, molefrac)/(-T)/Z; // Note: (1/T)dX/d(1/T) = -TdX/dT, the deriv in RHS is what we want, the left is what we get, so divide by -T
1314 VectorType grad = build_Psir_gradient<be>(model, T, rhovec).eval();
1315 VectorType Tgrad = build_d2PsirdTdrhoi_autodiff(model, T, rhovec);
1316 return forceeval((1/(R*T)*(Tgrad - 1.0/T*grad)-dZdT_Z).eval());
1317 }
1318
1324 template<ADBackends be = ADBackends::autodiff>
1325 static auto get_lnZ_Z_dZdrho(const Model& model, const Scalar& T, const VectorType& rhovec) {
1326 auto rhotot = forceeval(rhovec.sum());
1327 auto molefrac = (rhovec / rhotot).eval();
1329 auto Ar01 = tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1330 auto Ar02 = tdx::template get_Ar02<be>(model, T, rhotot, molefrac);
1331 auto Z = 1.0 + Ar01;
1332 auto dZdrho = (Ar01 + Ar02)/rhotot; // (dZ/rhotot)_{T,x}
1333 return std::make_tuple(log(Z), Z, dZdrho);
1334 }
1335
1343 template<ADBackends be = ADBackends::autodiff>
1344 static auto get_d_ln_fugacity_coefficients_drho_constTmolefracs(const Model& model, const Scalar& T, const VectorType& rhovec) {
1345 auto rhotot = forceeval(rhovec.sum());
1346 auto molefrac = (rhovec / rhotot).eval();
1347 auto R = model.R(molefrac);
1348 auto [lnZ, Z, dZdrho] = get_lnZ_Z_dZdrho(model, T, rhovec);
1349 auto hessian = build_Psir_Hessian_autodiff(model, T, rhovec);
1350 return forceeval((1/(R*T)*(hessian*molefrac.matrix()).array() - dZdrho/Z).eval());
1351 }
1352
1360 template<ADBackends be = ADBackends::autodiff>
1361 static auto get_d_ln_fugacity_coefficients_dv_constTmolefracs(const Model& model, const Scalar& T, const VectorType& rhovec) {
1362 auto rhotot = forceeval(rhovec.sum());
1363 auto drhodv = -rhotot*rhotot; // rho = 1/v; drho/dv = -1/v^2 = -rho^2
1364 return get_d_ln_fugacity_coefficients_drho_constTmolefracs(model, T, rhovec)*drhodv;
1365 }
1366
1374 template<ADBackends be = ADBackends::autodiff>
1375 static auto get_d_ln_fugacity_coefficients_dmolefracs_constTrho(const Model& model, const Scalar& T, const VectorType& rhovec) {
1376 auto rhotot = forceeval(rhovec.sum());
1377 auto molefrac = (rhovec / rhotot).eval();
1378 auto R = model.R(molefrac);
1379
1381 auto Ar01 = tdx::template get_Ar01<be>(model, T, rhotot, molefrac);
1382 auto Z = 1.0 + Ar01;
1383 VectorType dZdx = rhotot*build_d2alphardrhodxi_constT(model, T, rhotot, molefrac);
1384 Eigen::RowVector<decltype(rhotot), Eigen::Dynamic> dZdx_Z = dZdx/Z;
1385
1386 // Starting matrix is from the first term
1387 auto hessian = build_Psir_Hessian_autodiff(model, T, rhovec);
1388 Eigen::ArrayXXd out = rhotot/(R*T)*hessian;
1389
1390 // Then each row gets the second part
1391 out.rowwise() -= dZdx_Z.array();
1392 return out;
1393 }
1394
1395 template<ADBackends be = ADBackends::autodiff>
1396 static auto get_d_ln_fugacity_coefficients_dmolefracs_constTrho1(const Model& model, const Scalar& T, const VectorType& rhovec) {
1397 auto rhotot = forceeval(rhovec.sum());
1398 auto molefrac = (rhovec / rhotot).eval();
1399 auto R = model.R(molefrac);
1400
1401 auto hessian = build_Psir_Hessian_autodiff(model, T, rhovec);
1402 // Starting matrix is from the first term
1403 Eigen::ArrayXXd out = 1/(R*T)*rhotot*hessian;
1404 return out;
1405 }
1406
1411 static auto get_dchempotdT_autodiff(const Model& model, const Scalar& T, const VectorType& rhovec) {
1412 auto rhotot = rhovec.sum();
1413 auto molefrac = (rhovec / rhotot).eval();
1414 auto rhorefideal = 1.0;
1415 return (build_d2PsirdTdrhoi_autodiff(model, T, rhovec) + model.R(molefrac)*(rhorefideal + log(rhovec/rhorefideal))).eval();
1416 }
1417
1421 static auto get_dpdT_constrhovec(const Model& model, const Scalar& T, const VectorType& rhovec) {
1422 auto rhotot = rhovec.sum();
1423 auto molefrac = (rhovec / rhotot).eval();
1424 auto dPsirdT = get_dPsirdT_constrhovec(model, T, rhovec);
1425 return rhotot*model.R(molefrac) - dPsirdT + rhovec.matrix().dot(build_d2PsirdTdrhoi_autodiff(model, T, rhovec).matrix());
1426 }
1427
1431 static auto get_dpdrhovec_constT(const Model& model, const Scalar& T, const VectorType& rhovec) {
1432 auto rhotot = rhovec.sum();
1433 auto molefrac = (rhovec / rhotot).eval();
1434 auto RT = model.R(molefrac)*T;
1435 auto [func, grad, hessian] = build_Psir_fgradHessian_autodiff(model, T, rhovec); // The hessian matrix
1436 return (RT + (hessian*rhovec.matrix()).array()).eval(); // at constant temperature
1437 }
1438
1482 static auto get_partial_molar_volumes(const Model& model, const Scalar& T, const VectorType& rhovec) {
1483 auto rhotot = rhovec.sum();
1484 auto molefrac = (rhovec / rhotot).eval();
1486 auto RT = model.R(molefrac)*T;
1487
1488 auto dpdrhovec = get_dpdrhovec_constT(model, T, rhovec);
1489 auto numerator = -rhotot*dpdrhovec;
1490
1491 auto ders = tdx::template get_Ar0n<2>(model, T, rhotot, molefrac);
1492 auto denominator = -pow2(rhotot)*RT*(1 + 2*ders[1] + ders[2]);
1493 return (numerator/denominator).eval();
1494 }
1495
1496 static VectorType get_Psir_sigma_derivs(const Model& model, const Scalar& T, const VectorType& rhovec, const VectorType& v) {
1497 autodiff::Real<4, double> sigma = 0.0;
1498 auto rhovecad = rhovec.template cast<decltype(sigma)>(), vad = v.template cast<decltype(sigma)>();
1499 auto wrapper = [&rhovecad, &vad, &T, &model](const auto& sigma_1) {
1500 auto rhovecused = (rhovecad + sigma_1 * vad).eval();
1501 auto rhotot = rhovecused.sum();
1502 auto molefrac = (rhovecused / rhotot).eval();
1503 return forceeval(model.alphar(T, rhotot, molefrac) * model.R(molefrac) * T * rhotot);
1504 };
1505 auto der = derivatives(wrapper, along(1), at(sigma));
1506 VectorType ret(der.size());
1507 for (auto i = 0; i < ret.size(); ++i){ ret[i] = der[i];}
1508 return ret;
1509 }
1510};
1511
1512template<int Nderivsmax>
1514
1515public:
1516 Eigen::Array<double, Nderivsmax+1, Nderivsmax+1> derivs;
1517
1518 template<typename Model, typename Scalar, typename VecType>
1519 DerivativeHolderSquare(const Model& model, const Scalar& T, const Scalar& rho, const VecType& z) {
1520 using tdx = TDXDerivatives<decltype(model), Scalar, VecType>;
1521 static_assert(Nderivsmax == 2, "It's gotta be 2 for now");
1522
1523
1524 auto AX02 = tdx::template get_Agen0n<2>(model, T, rho, z);
1525 derivs(0, 0) = AX02[0];
1526 derivs(0, 1) = AX02[1];
1527 derivs(0, 2) = AX02[2];
1528
1529 auto AX20 = tdx::template get_Agenn0<2>(model, T, rho, z);
1530 derivs(0, 0) = AX20[0];
1531 derivs(1, 0) = AX20[1];
1532 derivs(2, 0) = AX20[2];
1533
1534 derivs(1, 1) = tdx::template get_Agenxy<1,1>(model, T, rho, z);
1535 }
1536};
1537
1538
1539
1540}; // namespace teqp
DerivativeHolderSquare(const Model &model, const Scalar &T, const Scalar &rho, const VecType &z)
Definition derivs.hpp:1519
Eigen::Array< double, Nderivsmax+1, Nderivsmax+1 > derivs
Definition derivs.hpp:1516
#define get_ATrhoXiXjXk_runtime_combinations
Definition derivs.hpp:319
#define get_ATrhoXi_runtime_combinations
Definition derivs.hpp:261
#define get_ATrhoXiXj_runtime_combinations
Definition derivs.hpp:294
ContainerType::value_type derivT(const FuncType &f, TType T, const ContainerType &rho)
Given a function, use complex step derivatives to calculate the derivative with respect to the first ...
Definition derivs.hpp:33
auto getbaseval(const T &expr)
Definition types.hpp:90
T powi(const T &x, int n)
From Ulrich Deiters.
Definition types.hpp:139
T pow2(const T &x)
Definition types.hpp:7
ADBackends
Definition derivs.hpp:92
auto build_duplicated_tuple_impl(const T &val, std::index_sequence< I... >)
Definition derivs.hpp:71
auto build_duplicated_tuple(const T &val)
A function to generate a tuple of N repeated copies of argument val at compile-time.
Definition derivs.hpp:77
auto forceeval(T &&expr)
Definition types.hpp:52
ContainerType::value_type derivrhoi(const FuncType &f, TType T, const ContainerType &rho, Integer i)
Given a function, use complex step derivatives to calculate the derivative with respect to the given ...
Definition derivs.hpp:57
std::valarray< double > vad
Definition fwd.hpp:34
static auto get_dPsirdT_constrhovec(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate derivative w.r.t. T at constant molar concentrations.
Definition derivs.hpp:1018
static auto get_partial_molar_volumes(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the partial molar volumes of each component.
Definition derivs.hpp:1482
static auto build_Psir_Hessian_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Calculate the Hessian of w.r.t. the molar concentrations.
Definition derivs.hpp:1031
static auto get_d_ln_fugacity_coefficients_dv_constTmolefracs(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the derivative of the natural logarithm of fugacity coefficient of each component w....
Definition derivs.hpp:1361
static Eigen::ArrayXd build_d2alphardrhodxi_constT(const Model &model, const Scalar &T, const Scalar &rhomolar, const VectorType &molefrac)
Definition derivs.hpp:1282
static auto get_d_ln_fugacity_coefficients_dmolefracs_constTrho1(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:1396
static auto get_ln_fugacity_coefficients(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the natural logarithm of fugacity coefficient of each component.
Definition derivs.hpp:1220
static auto get_splus(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the residual entropy ( ) from derivatives of alphar.
Definition derivs.hpp:962
static Eigen::ArrayXd build_d2PsirdTdrhoi_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Definition derivs.hpp:1264
static auto build_Psi_Hessian_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Calculate the Hessian of w.r.t. the molar concentrations.
Definition derivs.hpp:1076
static auto get_d_ln_fugacity_coefficients_drho_constTmolefracs(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the derivative of the natural logarithm of fugacity coefficient of each component w....
Definition derivs.hpp:1344
static auto build_Psir_fgradHessian_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Calculate the function value, gradient, and Hessian of w.r.t. the molar concentrations.
Definition derivs.hpp:1051
static auto get_Ar10(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:986
static auto build_Psir_gradient_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Gradient of Psir = ar*rho w.r.t. the molar concentrations.
Definition derivs.hpp:1115
static auto get_d_ln_fugacity_coefficients_dmolefracs_constTrho(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the derivative of the natural logarithm of fugacity coefficient of each component w....
Definition derivs.hpp:1375
static auto get_pr(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the residual pressure from derivatives of alphar.
Definition derivs.hpp:971
static auto get_lnZ_Z_dZdrho(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate ln(Z), Z, and dZ/drho at constant temperature and mole fractions.
Definition derivs.hpp:1325
static auto get_Psir(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate .
Definition derivs.hpp:1009
static auto build_Psir_gradient_complex_step(const Model &model, const Scalar &T, const VectorType &rho)
Gradient of Psir = ar*rho w.r.t. the molar concentrations.
Definition derivs.hpp:1152
static auto get_d_ln_fugacity_coefficients_dT_constrhovec(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the derivative of the natural logarithm of fugacity coefficient of each component w....
Definition derivs.hpp:1307
static auto get_Ar01(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:992
static auto get_dpdT_constrhovec(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the temperature derivative of the pressure at constant molar concentrations.
Definition derivs.hpp:1421
static auto get_ln_fugacity_coefficients2(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:1256
static auto get_dpdrhovec_constT(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the molar concentration derivatives of the pressure at constant temperature.
Definition derivs.hpp:1431
static auto get_fugacity_coefficients(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the fugacity coefficient of each component.
Definition derivs.hpp:1209
static auto get_Ar00(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:980
static auto get_ln_fugacity_coefficients_Trhomolefracs(const Model &model, const Scalar &T, const Scalar &rhotot, const VectorType &molefrac)
Definition derivs.hpp:1233
static auto get_ln_fugacity_coefficients1(const Model &model, const Scalar &T, const VectorType &rhovec)
Definition derivs.hpp:1245
static auto get_chempotVLE_autodiff(const Model &model, const Scalar &T, const VectorType &rho)
Calculate the chemical potential of each component.
Definition derivs.hpp:1196
static auto get_dchempotdT_autodiff(const Model &model, const Scalar &T, const VectorType &rhovec)
Calculate the temperature derivative of the chemical potential of each component.
Definition derivs.hpp:1411
static VectorType get_Psir_sigma_derivs(const Model &model, const Scalar &T, const VectorType &rhovec, const VectorType &v)
Definition derivs.hpp:1496
static auto build_Psir_gradient(const Model &model, const Scalar &T, const VectorType &rho)
Definition derivs.hpp:1173
static auto get_ATrhoXiXj_runtime(const AlphaWrapper &w, const Scalar &T, int iT, const Scalar &rho, int iD, const VectorType &molefrac, int i, int iXi, int j, int iXj)
Definition derivs.hpp:312
static auto get_Agen0n(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:544
static auto get_Ar11(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:534
static auto get_ATrhoXiXj(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac, int i, int j)
Definition derivs.hpp:424
static auto get_Agenn0(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:572
static auto get_Aig11(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:539
static auto get_Aigxy(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:489
static auto get_ATrhoXiXjXk(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac, int i, int j, int k)
Definition derivs.hpp:449
static auto get_Ar03(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:509
static auto get_AtaudeltaXiXj_runtime(const AlphaWrapper &w, const Scalar &tau, const int iT, const Scalar &delta, const int iD, const VectorType &molefrac, const int i, const int iXi, const int j, const int iXj)
Definition derivs.hpp:401
static auto get_Ar20(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:514
static auto get_ATrhoXi_runtime(const AlphaWrapper &w, const Scalar &T, int iT, const Scalar &rho, int iD, const VectorType &molefrac, int i, int iXi)
Definition derivs.hpp:287
static auto AlphaCaller(const AlphaWrapper &w, const S1 &T, const S2 &rho, const Vec &molefrac)
Definition derivs.hpp:124
static auto get_Ar(const int itau, const int idelta, const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:628
static auto get_Ar12(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:529
static auto get_AtaudeltaXiXjXk_runtime(const AlphaWrapper &w, const Scalar &tau, const int iT, const Scalar &delta, const int iD, const VectorType &molefrac, const int i, int iXi, const int j, const int iXj, const int k, const int iXk)
Definition derivs.hpp:409
static auto get_AtaudeltaXi_runtime(const AlphaWrapper &w, const Scalar &tau, const int iT, const Scalar &delta, const int iD, const VectorType &molefrac, const int i, const int iXi)
Definition derivs.hpp:390
static auto AlphaCaller(const AlphaWrapper &w, const S1 &T, const S2 &rho, const Vec &molefrac)
Definition derivs.hpp:128
static auto AlpharTauDeltaCaller(const AlphaWrapper &, const S1 &, const S2 &, const Vec &molefrac)
Definition derivs.hpp:137
static Scalar get_Ar01(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:499
static auto get_neff(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:685
static auto get_Arn0(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:609
static auto get_AtaudeltaXi(const AlphaWrapper &w, const Scalar &tau, const Scalar &delta, const VectorType &molefrac, const int i)
Definition derivs.hpp:342
static auto get_Ar02(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:504
static auto AlpharTauDeltaCaller(const AlphaWrapper &w, const S1 &T, const S2 &rho, const Vec &molefrac)
Definition derivs.hpp:133
static auto get_AtaudeltaXiXj(const AlphaWrapper &w, const Scalar &tau, const Scalar &delta, const VectorType &molefrac, const int i, const int j)
Definition derivs.hpp:355
static auto get_ATrhoXi(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac, int i)
Definition derivs.hpp:248
static auto get_Ar0n(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:622
static auto get_Ar10(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:494
static auto get_Arxy(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:476
static auto get_Ar00(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:119
static auto get_AtaudeltaXiXjXk(const AlphaWrapper &w, const Scalar &tau, const Scalar &delta, const VectorType &molefrac, const int i, const int j, const int k)
Definition derivs.hpp:372
static auto get_ATrhoXiXjXk_runtime(const AlphaWrapper &w, const Scalar &T, int iT, const Scalar &rho, int iD, const VectorType &molefrac, int i, int iXi, int j, int iXj, int k, int iXk)
Definition derivs.hpp:334
static auto get_Ar30(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:519
static auto get_Ar21(const Model &model, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:524
static auto get_Agenxy(const AlphaWrapper &w, const Scalar &T, const Scalar &rho, const VectorType &molefrac)
Definition derivs.hpp:151
static auto get_dmBnvirdTm(const Model &model, const Scalar &T, const VectorType &molefrac)
Temperature derivatives of a virial coefficient.
Definition derivs.hpp:784
static auto get_B12vir(const Model &model, const Scalar &T, const VectorType &molefrac)
Calculate the cross-virial coefficient .
Definition derivs.hpp:856
static auto get_dmBnvirdTm_runtime(const int Nderiv, const int NTderiv, const Model &model, const Scalar &T, const VectorType &molefrac)
Definition derivs.hpp:817
static auto get_Bnvir(const Model &model, const Scalar &T, const VectorType &molefrac)
Definition derivs.hpp:714
static auto get_B2vir(const Model &model, const Scalar &T, const VectorType &molefrac)
Definition derivs.hpp:696
static auto get_Bnvir_runtime(const int Nderiv, const Model &model, const Scalar &T, const VectorType &molefrac)
Definition derivs.hpp:757
auto operator()(Args &&... args) const
Definition derivs.hpp:86