3#include "nlohmann/json.hpp"
23 const std::optional<std::size_t>& alternative_pure_index = std::nullopt,
const std::optional<std::size_t>& alternative_length = std::nullopt) {
26 if (!alternative_pure_index) {
27 z = (Eigen::ArrayXd(1) << 1.0).finished();
30 z = Eigen::ArrayXd(alternative_length.value()); z.setZero();
31 auto index = alternative_pure_index.value();
32 if (index >= 0 && index <
static_cast<std::size_t
>(z.size())){
36 throw teqp::InvalidArgument(
"The provided alternative index of " + std::to_string(index) +
" is out of range");
39 auto R = model.
get_R(z);
43 auto dpdrho = R * T * (1 + 2 * ders[1] + ders[2]);
44 auto d2pdrho2 = R * T / rho * (2 * ders[1] + 4 * ders[2] + ders[3]);
46 auto resids = (Eigen::ArrayXd(2) << dpdrho, d2pdrho2).finished();
63 auto Ar11 = model.
get_Ar11(T, rho, z);
64 auto Ar12 = model.
get_Ar12(T, rho, z);
65 auto Ar13 = model.
get_Ar13(T, rho, z);
67 auto d3pdrho3 = R * T / (rho * rho) * (6 * ders[2] + 6 * ders[3] + ders[4]);
68 auto d_dpdrho_dT = R * (-(Ar12 + 2 * Ar11) + ders[2] + 2 * ders[1] + 1);
69 auto d_d2pdrho2_dT = R / rho * (-(Ar13 + 4 * Ar12 + 2 * Ar11) + ders[3] + 4 * ders[2] + 2 * ders[1]);
72 Eigen::MatrixXd J(2, 2);
73 J(0, 0) = d_dpdrho_dT;
75 J(1, 0) = d_d2pdrho2_dT;
78 return std::make_tuple(resids, J);
82 typename =
typename std::enable_if<not std::is_base_of<teqp::cppinterface::AbstractModel, Model>::value>::type>
84 const std::optional<std::size_t>& alternative_pure_index = std::nullopt,
const std::optional<std::size_t>& alternative_length = std::nullopt) {
86 auto view_ = std::unique_ptr<AbstractModel>(
view(model));
91 template<typename Model, typename Scalar, ADBackends backend = ADBackends::autodiff, typename = typename std::enable_if<not std::is_base_of<teqp::cppinterface::AbstractModel, Model>::value>::type>
92 auto solve_pure_critical(
const Model& model,
const Scalar T0,
const Scalar rho0,
const std::optional<nlohmann::json>& flags = std::nullopt) {
93 auto x = (Eigen::ArrayXd(2) << T0, rho0).finished();
95 std::optional<std::size_t> alternative_pure_index;
96 std::optional<std::size_t> alternative_length;
98 if (flags.value().contains(
"maxsteps")){
99 maxsteps = flags.value().at(
"maxsteps");
101 if (flags.value().contains(
"alternative_pure_index")){
102 auto i = flags.value().at(
"alternative_pure_index").get<
int>();
104 alternative_pure_index = i;
106 if (flags.value().contains(
"alternative_length")){
107 auto i = flags.value().at(
"alternative_length").get<
int>();
109 alternative_length = i;
114 auto linsolve = [](
const auto& a,
const auto& b) {
115 return a.matrix().colPivHouseholderQr().solve(b.matrix()).array().eval();
117 for (
auto counter = 0; counter < maxsteps; ++counter) {
119 auto v =
linsolve(Jacobian, -resids);
122 return std::make_tuple(x[0], x[1]);
126 auto x = (Eigen::ArrayXd(2) << T0, rho0).finished();
128 std::optional<std::size_t> alternative_pure_index;
129 std::optional<std::size_t> alternative_length;
131 if (flags.value().contains(
"maxsteps")){
132 maxsteps = flags.value().at(
"maxsteps");
134 if (flags.value().contains(
"alternative_pure_index")){
135 auto i = flags.value().at(
"alternative_pure_index").get<
int>();
137 alternative_pure_index = i;
139 if (flags.value().contains(
"alternative_length")){
140 auto i = flags.value().at(
"alternative_length").get<
int>();
142 alternative_length = i;
147 auto linsolve = [](
const auto& a,
const auto& b) {
148 return a.matrix().colPivHouseholderQr().solve(b.matrix()).array().eval();
150 for (
auto counter = 0; counter < maxsteps; ++counter) {
152 auto v =
linsolve(Jacobian, -resids);
155 return std::make_tuple(x[0], x[1]);
158 template <typename Model, typename Scalar, typename = typename std::enable_if<not std::is_base_of<teqp::cppinterface::AbstractModel, Model>::value>::type>
159 Scalar
get_Brho_critical_extrap(
const Model& model,
const Scalar& Tc,
const Scalar& rhoc,
const std::optional<Eigen::ArrayXd>& z = std::nullopt) {
162 auto z_ = (Eigen::ArrayXd(1) << 1.0).finished();
166 auto R = model.R(z_);
167 auto ders = tdx::template get_Ar0n<4>(model, Tc, rhoc, z_);
170 auto d3pdrho3 = R * Tc / (rhoc * rhoc) * (6 * ders[2] + 6 * ders[3] + ders[4]);
171 auto Ar11 = tdx::template get_Ar11(model, Tc, rhoc, z_);
172 auto Ar12 = tdx::template get_Ar12(model, Tc, rhoc, z_);
173 auto d2pdrhodT = R * (1 + 2 * ders[1] + ders[2] - 2 * Ar11 - Ar12);
174 auto Brho = sqrt(6 * d2pdrhodT * Tc / d3pdrho3);
179 template <typename Model, typename Scalar, typename = typename std::enable_if<not std::is_base_of<teqp::cppinterface::AbstractModel, Model>::value>::type>
180 Eigen::Array<double, 2, 1>
extrapolate_from_critical(
const Model& model,
const Scalar& Tc,
const Scalar& rhoc,
const Scalar& T,
const std::optional<Eigen::ArrayXd>& z = std::nullopt) {
183 auto drhohat_dT = Brho / Tc;
186 auto drhohat = dT * drhohat_dT;
187 auto rholiq = -drhohat / sqrt(1 - T / Tc) + rhoc;
188 auto rhovap = drhohat / sqrt(1 - T / Tc) + rhoc;
189 return (Eigen::ArrayXd(2) << rholiq, rhovap).finished();
196 auto z_ = (Eigen::ArrayXd(1) << 1.0).finished();
200 auto R = model.
get_R(z_);
201 auto ders = model.
get_Ar04n(Tc, rhoc, z_);
204 auto d3pdrho3 = R * Tc / (rhoc * rhoc) * (6 * ders[2] + 6 * ders[3] + ders[4]);
205 auto Ar11 = model.
get_Ar11(Tc, rhoc, z_);
206 auto Ar12 = model.
get_Ar12(Tc, rhoc, z_);
207 auto d2pdrhodT = R * (1 + 2 * ders[1] + ders[2] - 2 * Ar11 - Ar12);
208 auto Brho = sqrt(6 * d2pdrhodT * Tc / d3pdrho3);
216 auto drhohat_dT = Brho / Tc;
219 auto drhohat = dT * drhohat_dT;
220 auto rholiq = -drhohat / sqrt(1 - T / Tc) + rhoc;
221 auto rhovap = drhohat / sqrt(1 - T / Tc) + rhoc;
222 return (Eigen::ArrayXd(2) << rholiq, rhovap).finished();
virtual double get_R(const EArrayd &) const =0
virtual double get_Ar12(const double T, const double rho, const REArrayd &molefrac) const =0
virtual double get_Ar11(const double T, const double rho, const REArrayd &molefrac) const =0
virtual EArrayd get_Ar04n(const double T, const double rho, const REArrayd &molefrac) const =0
virtual double get_Ar13(const double T, const double rho, const REArrayd &molefrac) const =0
auto view(const TemplatedModel &tp)
auto linsolve(const A &a, const B &b)
auto solve_pure_critical(const Model &model, const Scalar T0, const Scalar rho0, const std::optional< nlohmann::json > &flags=std::nullopt)
Eigen::Array< double, 2, 1 > extrapolate_from_critical(const Model &model, const Scalar &Tc, const Scalar &rhoc, const Scalar &T, const std::optional< Eigen::ArrayXd > &z=std::nullopt)
auto get_pure_critical_conditions_Jacobian(const AbstractModel &model, const double T, const double rho, const std::optional< std::size_t > &alternative_pure_index=std::nullopt, const std::optional< std::size_t > &alternative_length=std::nullopt)
Scalar get_Brho_critical_extrap(const Model &model, const Scalar &Tc, const Scalar &rhoc, const std::optional< Eigen::ArrayXd > &z=std::nullopt)