Newer
Older
#include "teqp/models/multifluid.hpp"
//#include "autodiff/forward.hpp"
//#include "autodiff/reverse.hpp"
auto build_multifluid_model(const std::vector<std::string>& components, const std::string &coolprop_root, const nlohmann::json &BIPcollection) {
auto [Tc, vc] = MultiFluidReducingFunction::get_Tcvc(coolprop_root, components);
auto F = MultiFluidReducingFunction::get_F_matrix(BIPcollection, components);
Ian Bell
committed
auto funcs = get_departure_function_matrix(coolprop_root, BIPcollection, components);
auto EOSs = get_EOSs(coolprop_root, components);
auto [betaT, gammaT, betaV, gammaV] = MultiFluidReducingFunction::get_BIP_matrices(BIPcollection, components);
auto redfunc = MultiFluidReducingFunction(betaT, gammaT, betaV, gammaV, Tc, vc);
return MultiFluid(
std::move(redfunc),
std::move(CorrespondingStatesContribution(std::move(EOSs))),
std::move(DepartureContribution(std::move(F), std::move(funcs)))
);
template<typename ModelType>
void trace(std::vector<std::string> fluids, const ModelType& model, int i){
auto rhoc0 = 1.0/model.redfunc.vc[0];
auto T = model.redfunc.Tc[0];
std::valarray<double> rhovec = { rhoc0, 0.0 };
for (auto iter = 0; iter < 1000; ++iter) {
auto drhovecdT = get_drhovec_dT_crit(model, T, rhovec);
rhovec += drhovecdT * dT;
T += dT;
int rr = 0;
auto z0 = rhovec[0] / rhovec.sum();
std::cout << z0 << " ," << rhovec[0] << "," << T << std::endl;
if (z0 < 0) {
break;
}
}
}
template<typename Callable, typename Inputs>
auto NewtonRaphson(Callable f, const Inputs &args, double tol) {
// Jacobian matrix
Eigen::ArrayXd x = args, r0;
Eigen::MatrixXd J(args.size(), args.size());
for (int iter = 0; iter < 30; ++iter){
r0 = f(x);
for (auto i = 0; i < args.size(); ++i) {
auto dri = std::max(1e-3*x[i], 1e-8);
auto argsplus = x;
argsplus[i] += dri;
J.col(i) = (f(argsplus) - r0)/dri; // Forward centered diff to avoid negative composition possibility
}
Eigen::ArrayXd v = J.colPivHouseholderQr().solve(-r0.matrix());
x += v;
auto err = r0.matrix().norm();
if (err < tol) {
break;
}
}
return x;
}
template<typename ModelType>
void trace_arclength(std::vector<std::string> fluids, const ModelType &model, std::size_t i) {
auto rhoc0 = 1.0 / model.redfunc.vc[i];
auto T = model.redfunc.Tc[i];
double t = 0.0, dt = 100;
std::valarray<double> rhovec(2); rhovec[i] = { rhoc0 }; rhovec[1L-i] = 0.0;
// Non-analytic terms make it impossible to initialize AT the pure components
if (fluids[0] == "CarbonDioxide" || fluids[1] == "CarbonDioxide"){
if (i == 0) {
rhovec[i] *= 0.9999;
}
else {
rhovec[i] *= 1.0001;
}
double zi = rhovec[i]/rhovec.sum();
T = zi* model.redfunc.Tc[i] + (1-zi)* model.redfunc.Tc[1L-i];
auto dot = [](const auto& v1, const auto& v2) { return (v1 * v2).sum(); };
auto norm = [](const auto &v){ return sqrt((v*v).sum()); };
std::string filename = fluids[0] + "_" + fluids[1] + ".csv";
std::ofstream ofs(filename);
double c = 1.0;
ofs << "z0 / mole frac.,rho0 / mol/m^3,rho1 / mol/m^3,T / K,p / Pa,c" << std::endl;
auto rhotot = rhovec.sum();
auto z0 = rhovec[0] / rhotot;
if (fluids[0] == "CarbonDioxide" || fluids[1] == "CarbonDioxide") {
auto polish_x_resid = [&model, &z0](const auto& x) {
auto T = x[0];
std::valarray<double> rhovec = { x[1], x[2] };
auto z0new = rhovec[0] / rhovec.sum();
auto derivs = get_derivs(model, T, rhovec);
// First two are residuals on critical point, third is residual on composition
return (Eigen::ArrayXd(3) << derivs.tot[2], derivs.tot[3], z0new - z0).finished();
};
try {
Eigen::ArrayXd x0(3); x0 << T, rhovec[0], rhovec[1];
auto r0 = polish_x_resid(x0);
auto x = NewtonRaphson(polish_x_resid, x0, 1e-10);
auto r = polish_x_resid(x);
Eigen::ArrayXd change = x0 - x;
if (!std::isfinite(T) || !std::isfinite(x[1]) || !std::isfinite(x[2])) {
throw std::invalid_argument("Something not finite; aborting polishing");
}
T = x[0]; rhovec[0] = x[1]; rhovec[1] = x[2];
}
catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
}
auto write_line = [&rhovec, &rhotot, &z0, &model, &T, &c, &ofs](){
std::stringstream out;
out << z0 << "," << rhovec[0] << "," << rhovec[1] << "," << T << "," << rhotot*model.R*T + get_pr(model, T, rhovec) << "," << c << std::endl;
std::string sout(out.str());
ofs << sout;
std::cout << sout;
};
if (iter == 0) {
write_line();
}
auto drhodT = get_drhovec_dT_crit(model, T, rhovec);
auto dTdt = 1.0 / norm(drhodT);
auto drhodt = drhodT * dTdt;
// Flip the sign if the tracing wants to go backwards, or if the first step would take you to negative concentrations
if (iter == 0 && any(rhovec + c*drhodt*dt < 0)) {
c *= -1;
else if (iter > 0 && dot(c*drhodt, last_drhodt) < 0){
c *= -1;
rhovec += c*drhodt*dt;
T += c*dTdt*dt;
z0 = rhovec[0] / rhovec.sum();
if (z0 < 0 || z0 > 1) {
break;
}
auto polish_x_resid = [&model, &z0](const auto& x) {
auto T = x[0];
std::valarray<double> rhovec = { x[1], x[2] };
auto z0new = rhovec[0] / rhovec.sum();
auto derivs = get_derivs(model, T, rhovec);
// First two are residuals on critical point, third is residual on composition
return (Eigen::ArrayXd(3) << derivs.tot[2], derivs.tot[3], z0new - z0).finished();
};
try {
Eigen::ArrayXd x0(3); x0 << T, rhovec[0], rhovec[1];
auto r0 = polish_x_resid(x0);
auto x = NewtonRaphson(polish_x_resid, x0, 1e-10);
auto r = polish_x_resid(x);
Eigen::ArrayXd change = x0 - x;
if (!std::isfinite(T) || !std::isfinite(x[1]) || !std::isfinite(x[2])) {
throw std::invalid_argument("Something not finite; aborting polishing");
}
T = x[0]; rhovec[0] = x[1]; rhovec[1] = x[2];
}
catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
rhotot = rhovec.sum();
z0 = rhovec[0] / rhotot;
if (z0 < 0 || z0 > 1) {
break;
}
Ian Bell
committed
//test_dummy();
//trace();
std::string coolprop_root = "C:/Users/ihb/Code/CoolProp";
coolprop_root = "../mycp";
auto BIPcollection = nlohmann::json::parse(
std::ifstream(coolprop_root + "/dev/mixtures/mixture_binary_pairs.json")
);
std::vector<std::vector<std::string>> pairs = {
{ "CarbonDioxide", "R1234YF" }, { "CarbonDioxide","R1234ZE(E)" }, { "ETHYLENE","R1243ZF" },
{ "R1234YF","R1234ZE(E)" }, { "R134A","R1234YF" }, { "R23","R1234YF" },
{ "R32","R1123" }, { "R32","R1234YF" }, { "R32","R1234ZE(E)" }
};
for (auto &pp : pairs) {
using ModelType = decltype(build_multifluid_model(pp, coolprop_root, BIPcollection));
std::optional<ModelType> model{std::nullopt};
try {
model.emplace(build_multifluid_model(pp, coolprop_root, BIPcollection));
}
catch (std::exception &e) {
std::cout << e.what() << std::endl;
std::cout << pp[0] << "&" << pp[1] << std::endl;
continue;
}
for (int i : {0, 1}){
trace_arclength(pp, model.value(), i);
}
}
/*auto model = build_multifluid_model({ "methane", "ethane" });
double T = 300;
auto alphar = model.alphar(T, rhovec);
double h = 1e-100;
auto alpharcom = model.alphar(std::complex<double>(T, h), rhovec).imag()/h;
MultiComplex<double> Th{{T, h}};
auto alpharcom2 = model.alphar(Th, rhovec).complex().imag()/h;*/
//autodiff::dual varT;
//auto dalphardT = derivative([&model, &rhovec](auto &T){return model.alphar(T, rhovec); }, wrt(varT), at(varT));