3#include "nlohmann/json.hpp"
17#include "RPinterop/interop.hpp"
19#if defined(TEQP_MULTICOMPLEX_ENABLED)
20#include "MultiComplex/MultiComplex.hpp"
27#include <boost/algorithm/string/join.hpp>
29#if defined(TEQP_MULTICOMPLEX_ENABLED)
32 template<
typename TN>
struct NumTraits<mcx::MultiComplex<TN>> : NumTraits<double>
38 RequireInitialization = 1,
49template<
typename EOSCollection>
53 const EOSCollection EOSs;
57 auto size()
const {
return EOSs.size(); }
59 template<
typename TauType,
typename DeltaType,
typename MoleFractions>
60 auto alphar(
const TauType& tau,
const DeltaType& delta,
const MoleFractions& molefracs)
const {
61 using resulttype = std::common_type_t<
decltype(tau),
decltype(molefracs[0]),
decltype(delta)>;
63 auto N = molefracs.size();
64 for (
auto i = 0U; i < N; ++i) {
65 alphar += molefracs[i] * EOSs[i].alphar(tau, delta);
70 template<
typename TauType,
typename DeltaType>
71 auto alphari(
const TauType& tau,
const DeltaType& delta, std::size_t i)
const {
72 return EOSs[i].alphar(tau, delta);
80template<
typename FCollection,
typename DepartureFunctionCollection>
85 const DepartureFunctionCollection funcs;
89 const auto&
get_F()
const {
return F; }
91 template<
typename TauType,
typename DeltaType,
typename MoleFractions>
92 auto alphar(
const TauType& tau,
const DeltaType& delta,
const MoleFractions& molefracs)
const {
93 using resulttype = std::decay_t<std::common_type_t<
decltype(tau),
decltype(molefracs[0]),
decltype(delta)>>;
95 std::size_t N = molefracs.size();
96 for (
auto i = 0U; i < N; ++i) {
97 for (
auto j = i+1; j < N; ++j) {
98 alphar += molefracs[i] * molefracs[j] * F(i, j) * funcs[i][j].alphar(tau, delta);
105 template<
typename TauType,
typename DeltaType>
106 auto get_alpharij(
const std::size_t i,
const std::size_t j,
const TauType& tau,
const DeltaType& delta)
const {
107 std::size_t N = funcs.size();
111 if (i >= N || j >= N){
118template<
typename CorrespondingTerm,
typename DepartureTerm>
122 std::string meta =
"";
130 template<
class VecType>
131 auto R(
const VecType& molefracs)
const {
132 return std::visit([&molefracs](
const auto& el){
return el.get_R(molefracs); },
Rcalc);
140 const std::variant<double, std::string>
get_BIP(
const std::size_t &i,
const std::size_t &j,
const std::string& key)
const{
141 if (key ==
"F" || key ==
"Fij"){
142 auto F =
dep.get_F();
143 if (0 <= i && i < F.rows() && 0 <= j && j < F.cols()){
147 return redfunc.get_BIP(i, j, key);
152 template<
typename TType,
typename RhoType>
154 const RhoType& rhovec,
155 const std::optional<typename RhoType::value_type> rhotot = std::nullopt)
const
157 typename RhoType::value_type rhotot_ = (rhotot.has_value()) ? rhotot.value() : std::accumulate(std::begin(rhovec), std::end(rhovec), (
decltype(rhovec[0]))0.0);
158 auto molefrac = rhovec / rhotot_;
159 return alphar(T, rhotot_, molefrac);
162 template<
typename TType,
typename RhoType,
typename MoleFracType>
165 const MoleFracType& molefrac)
const
167 if (
static_cast<std::size_t
>(molefrac.size()) !=
corr.size()){
168 throw teqp::InvalidArgument(
"Wrong size of mole fractions; "+std::to_string(
corr.size()) +
" are loaded but "+std::to_string(molefrac.size()) +
" were provided");
172 if (molefrac.size() == 1){
174 return corr.alphari(tau, delta, 0);
176 return forceeval(
corr.alphar(tau, delta, molefrac) +
dep.alphar(tau, delta, molefrac));
179 template<
typename TType,
typename RhoType,
typename MoleFracType>
181 const RhoType &delta,
182 const MoleFracType& molefrac)
const
184 if (
static_cast<std::size_t
>(molefrac.size()) !=
corr.size()){
185 throw teqp::InvalidArgument(
"Wrong size of mole fractions; "+std::to_string(
corr.size()) +
" are loaded but "+std::to_string(molefrac.size()) +
" were provided");
187 if (molefrac.size() == 1){
188 return corr.alphari(tau, delta, 0U);
190 return forceeval(
corr.alphar(tau, delta, molefrac) +
dep.alphar(tau, delta, molefrac));
193 template<
typename TType,
typename RhoType>
194 inline auto alphar_taudeltai(
const TType &tau,
const RhoType &delta,
const std::size_t i)
const
196 return corr.alphari(tau, delta, i);
199 template<
typename MoleFracType>
204 template<
typename MoleFracType>
217 std::string filepath = std::filesystem::is_regular_file(path) ? path : path +
"/dev/mixtures/mixture_departure_functions.json";
219 std::string js = j.dump(2);
222 if (el.at(
"Name") == name) {
228 for (
auto &alias : el.at(
"aliases")) {
234 throw std::invalid_argument(
"Could not match the name: " + name +
"when looking up departure function");
238 auto build_power = [&](
auto term,
auto& dep) {
239 std::size_t N = term[
"n"].size();
248 auto eigorzero = [&term, &N](
const std::string& name) -> Eigen::ArrayXd {
249 if (!term[name].empty()) {
250 return toeig(term[name]);
253 return Eigen::ArrayXd::Zero(N);
258 eos.
n = eigorzero(
"n");
259 eos.
t = eigorzero(
"t");
260 eos.
d = eigorzero(
"d");
262 Eigen::ArrayXd c(N), l(N); c.setZero();
264 int Nlzero = 0, Nlnonzero = 0;
265 bool contiguous_lzero =
false;
267 if (term[
"l"].empty()) {
271 throw std::invalid_argument(
"Lengths are not all identical in polynomial-like term");
276 throw std::invalid_argument(
"Lengths are not all identical in exponential term");
278 l =
toeig(term[
"l"]);
279 if (term.contains(
"c")){
282 throw std::invalid_argument(
"Lengths are not all identical in exponential term");
287 c = (l > 0).cast<double>();
291 contiguous_lzero = (l[0] == 0);
292 for (
auto i = 0; i < c.size(); ++i) {
298 Nlnonzero =
static_cast<int>(l.size()) - Nlzero;
300 if (contiguous_lzero && (l.tail(Nlnonzero) == 0).any()) {
301 throw std::invalid_argument(
"If l_i has zero and non-zero values, the zero values need to come first");
307 eos.
l_i = eos.
l.cast<
int>();
309 if (Nlzero + Nlnonzero != l.size()) {
310 throw std::invalid_argument(
"Somehow the l lengths don't add up");
314 if (((eos.
l_i.cast<
double>() - eos.
l).cwiseAbs() > 0.0).any()) {
315 throw std::invalid_argument(
"Non-integer entry in l found");
330 else if (l.sum() > 0 && contiguous_lzero){
332 poly.
n = eos.
n.head(Nlzero);
333 poly.
t = eos.
t.head(Nlzero);
334 poly.
d = eos.
d.head(Nlzero);
338 e.
n = eos.
n.tail(Nlnonzero);
339 e.
t = eos.
t.tail(Nlnonzero);
340 e.
d = eos.
d.tail(Nlnonzero);
341 e.
c = eos.
c.tail(Nlnonzero);
342 e.
l = eos.
l.tail(Nlnonzero);
343 e.
l_i = eos.
l_i.tail(Nlnonzero);
352 auto build_doubleexponential = [&](
auto& term,
auto& dep) {
354 throw std::invalid_argument(
"Lengths are not all identical in double exponential term");
357 eos.
n =
toeig(term.at(
"n"));
358 eos.
t =
toeig(term.at(
"t"));
359 eos.
d =
toeig(term.at(
"d"));
364 eos.
ld_i = eos.
ld.cast<
int>();
367 auto build_Chebyshev2D = [&](
auto& term,
auto& dep) {
369 int Ntau = term.at(
"Ntau");
370 int Ndelta = term.at(
"Ndelta");
371 Eigen::ArrayXd c =
toeig(term.at(
"a"));
372 if ((Ntau + 1)*(Ndelta + 1) != c.size()){
373 throw std::invalid_argument(
"Provided length [" + std::to_string(c.size()) +
"] is not equal to (Ntau+1)*(Ndelta+1)");
375 eos.
a = c.reshaped(Ntau+1, Ndelta+1).eval();
376 eos.
taumin = term.at(
"taumin");
377 eos.
taumax = term.at(
"taumax");
396 auto build_GERG2004 = [&](
const auto& term,
auto& dep) {
397 if (!
all_same_length(term, {
"n",
"t",
"d",
"eta",
"beta",
"gamma",
"epsilon" })) {
398 throw std::invalid_argument(
"Lengths are not all identical in GERG term");
400 int Npower = term[
"Npower"];
401 auto NGERG =
static_cast<int>(term[
"n"].size()) - Npower;
404 eos.
n =
toeig(term[
"n"]).head(Npower);
405 eos.
t =
toeig(term[
"t"]).head(Npower);
406 eos.
d =
toeig(term[
"d"]).head(Npower);
407 if (term.contains(
"l")) {
408 eos.
l =
toeig(term[
"l"]).head(Npower);
413 eos.
c = (eos.
l > 0).cast<int>().cast<
double>();
414 eos.
l_i = eos.
l.cast<
int>();
418 e.
n =
toeig(term[
"n"]).tail(NGERG);
419 e.
t =
toeig(term[
"t"]).tail(NGERG);
420 e.
d =
toeig(term[
"d"]).tail(NGERG);
421 e.
eta =
toeig(term[
"eta"]).tail(NGERG);
422 e.
beta =
toeig(term[
"beta"]).tail(NGERG);
427 auto build_GaussianExponential = [&](
const auto& term,
auto& dep) {
428 if (!
all_same_length(term, {
"n",
"t",
"d",
"eta",
"beta",
"gamma",
"epsilon" })) {
429 throw std::invalid_argument(
"Lengths are not all identical in Gaussian+Exponential term");
431 int Npower = term[
"Npower"];
432 auto NGauss =
static_cast<int>(term[
"n"].size()) - Npower;
435 eos.
n =
toeig(term[
"n"]).head(Npower);
436 eos.
t =
toeig(term[
"t"]).head(Npower);
437 eos.
d =
toeig(term[
"d"]).head(Npower);
438 if (term.contains(
"l")) {
439 eos.
l =
toeig(term[
"l"]).head(Npower);
444 eos.
c = (eos.
l > 0).cast<int>().cast<
double>();
445 eos.
l_i = eos.
l.cast<
int>();
449 e.
n =
toeig(term[
"n"]).tail(NGauss);
450 e.
t =
toeig(term[
"t"]).tail(NGauss);
451 e.
d =
toeig(term[
"d"]).tail(NGauss);
452 e.
eta =
toeig(term[
"eta"]).tail(NGauss);
453 e.
beta =
toeig(term[
"beta"]).tail(NGauss);
459 std::string type = j.at(
"type");
461 if (type ==
"Exponential") {
464 else if (type ==
"DoubleExponential") {
465 build_doubleexponential(j, dep);
467 else if (type ==
"GERG-2004" || type ==
"GERG-2008") {
468 build_GERG2004(j, dep);
470 else if (type ==
"Gaussian+Exponential") {
471 build_GaussianExponential(j, dep);
473 else if (type ==
"Chebyshev2D") {
474 build_Chebyshev2D(j, dep);
476 else if (type ==
"none") {
481 std::vector<std::string> options = {
"Exponential",
"GERG-2004",
"GERG-2008",
"Gaussian+Exponential",
"none",
"DoubleExponential",
"Chebyshev2D"};
482 throw std::invalid_argument(
"Bad departure term type: " + type +
". Options are {" + boost::algorithm::join(options,
",") +
"}");
487inline auto get_departure_function_matrix(
const nlohmann::json& depcollection,
const nlohmann::json& BIPcollection,
const std::vector<std::string>& components,
const nlohmann::json& flags) {
490 std::vector<std::vector<DepartureTerms>> funcs(components.size());
for (
auto i = 0U; i < funcs.size(); ++i) { funcs[i].resize(funcs.size()); }
495 for (
auto& el : depcollection) {
496 if (el[
"Name"] == Name) {
return el; }
498 throw std::invalid_argument(
"Bad departure function name: "+Name);
501 auto funcsmeta = nlohmann::json::object();
503 for (
auto i = 0U; i < funcs.size(); ++i) {
504 std::string istr = std::to_string(i);
505 if (funcsmeta.contains(istr)) { funcsmeta[istr] = {}; }
506 for (
auto j = i + 1; j < funcs.size(); ++j) {
507 std::string jstr = std::to_string(j);
508 auto [BIP, swap_needed] =
reducing::get_BIPdep(BIPcollection, { components[i], components[j] }, flags);
509 std::string funcname = BIP.contains(
"function") ? BIP[
"function"] :
"";
511 if (!funcname.empty()) {
512 if (depcollection.empty()){
513 throw teqp::InvalidArgument(
"No departure functions were loaded, unable to select requested function: " + funcname);
523 funcsmeta[istr][jstr] = { {
"departure", jj}, {
"BIP", BIP} };
524 funcsmeta[istr][jstr][
"BIP"][
"swap_needed"] = swap_needed;
527 return std::make_tuple(funcs, funcsmeta);
532 auto alphar = j[
"EOS"][0][
"alphar"];
539 const std::vector<std::string> allowed_types = {
"ResidualHelmholtzPower",
"ResidualHelmholtzGaussian",
"ResidualHelmholtzNonAnalytic",
"ResidualHelmholtzGaoB",
"ResidualHelmholtzLemmon2005",
"ResidualHelmholtzExponential",
"ResidualHelmholtzDoubleExponential",
"ResidualHelmholtzGenericCubic",
"ResidualHelmholtzPCSAFTGrossSadowski2001" };
541 auto isallowed = [&](
const auto& conventional_types,
const std::string& name) {
542 for (
auto& a : conventional_types) {
if (name == a) {
return true; }; }
return false;
545 for (
auto& term : alphar) {
546 std::string type = term[
"type"];
547 if (!isallowed(allowed_types, type)) {
548 std::string a = allowed_types[0];
for (
auto i = 1U; i < allowed_types.size(); ++i) { a +=
"," + allowed_types[i]; }
549 throw std::invalid_argument(
"Bad type:" + type +
"; allowed types are: {" + a +
"}");
555 auto build_power = [&](
auto term,
auto & container) {
556 std::size_t N = term[
"n"].size();
560 auto eigorzero = [&term, &N](
const std::string& name) -> Eigen::ArrayXd {
561 if (!term[name].empty()) {
562 return toeig(term[name]);
565 return Eigen::ArrayXd::Zero(N);
570 eos.
n = eigorzero(
"n");
571 eos.
t = eigorzero(
"t");
572 eos.
d = eigorzero(
"d");
574 Eigen::ArrayXd c(N), l(N); c.setZero();
575 int Nlzero = 0, Nlnonzero = 0;
576 bool contiguous_lzero;
577 if (term[
"l"].empty()) {
582 l =
toeig(term[
"l"]);
584 for (
auto i = 0; i < c.size(); ++i) {
591 contiguous_lzero = (l[0] == 0);
592 for (
auto i = 0; i < c.size(); ++i) {
598 Nlnonzero =
static_cast<int>(l.size()) - Nlzero;
603 eos.
l_i = eos.
l.cast<
int>();
605 if (Nlzero + Nlnonzero != l.size()) {
606 throw std::invalid_argument(
"Somehow the l lengths don't add up");
609 if (((eos.
l_i.cast<
double>() - eos.
l).cwiseAbs() > 0.0).any()) {
610 throw std::invalid_argument(
"Non-integer entry in l found");
625 else if (l.sum() > 0 && contiguous_lzero) {
627 poly.
n = eos.
n.head(Nlzero);
628 poly.
t = eos.
t.head(Nlzero);
629 poly.
d = eos.
d.head(Nlzero);
633 e.
n = eos.
n.tail(Nlnonzero);
634 e.
t = eos.
t.tail(Nlnonzero);
635 e.
d = eos.
d.tail(Nlnonzero);
636 e.
c = eos.
c.tail(Nlnonzero);
637 e.
l = eos.
l.tail(Nlnonzero);
638 e.
l_i = eos.
l_i.tail(Nlnonzero);
647 auto build_Lemmon2005 = [&](
auto term,
auto & container) {
649 throw std::invalid_argument(
"Lengths are not all identical in Lemmon2005 term");
658 eos.
l_i = eos.
l.cast<
int>();
659 if (((eos.
l_i.cast<
double>() - eos.
l).cwiseAbs() > 0.0).any()) {
660 throw std::invalid_argument(
"Non-integer entry in l found");
663 auto getindices = [](
const auto& mask){
664 std::vector<int> indices;
665 for (
auto i = 0; i < mask.size(); ++i){
666 if (mask[i]){ indices.push_back(i); }
670 auto pow_indices = getindices((eos.
m == 0 ) && (eos.
l == 0));
671 auto mzerolpos_indices = getindices((eos.
m == 0) && (eos.
l > 0));
672 auto mzero_indices = getindices((eos.
m > 0) && (eos.
l > 0));
674 if (pow_indices.size() + mzerolpos_indices.size() + mzero_indices.size() !=
static_cast<std::size_t
>(eos.
m.size())) {
675 throw std::invalid_argument(
"Term subdivision failed in Lemmon2005 term");
678 if (!pow_indices.empty()){
680 poly.
n = eos.
n(pow_indices);
681 poly.
t = eos.
t(pow_indices);
682 poly.
d = eos.
d(pow_indices);
685 if (!mzerolpos_indices.empty()){
687 e.
n = eos.
n(mzerolpos_indices);
688 e.
t = eos.
t(mzerolpos_indices);
689 e.
d = eos.
d(mzerolpos_indices);
690 e.
l = eos.
l(mzerolpos_indices);
691 e.
c = (1 + 0*eos.
l).cast<double>();
692 e.
l_i = eos.
l_i(mzerolpos_indices);
695 if (!mzero_indices.empty()){
697 e.
n = eos.
n(mzero_indices);
698 e.
t = eos.
t(mzero_indices);
699 e.
d = eos.
d(mzero_indices);
700 e.
m = eos.
m(mzero_indices);
701 e.
l = eos.
l(mzero_indices);
702 e.
l_i = e.
l.cast<
int>();
707 auto build_gaussian = [&](
auto term) {
716 if (!
all_same_length(term, {
"n",
"t",
"d",
"eta",
"beta",
"gamma",
"epsilon" })) {
717 throw std::invalid_argument(
"Lengths are not all identical in Gaussian term");
722 auto build_exponential = [&](
auto term) {
729 eos.
l_i = eos.
l.cast<
int>();
731 throw std::invalid_argument(
"Lengths are not all identical in exponential term");
736 auto build_doubleexponential = [&](
auto& term) {
738 throw std::invalid_argument(
"Lengths are not all identical in double exponential term");
741 eos.
n =
toeig(term.at(
"n"));
742 eos.
t =
toeig(term.at(
"t"));
743 eos.
d =
toeig(term.at(
"d"));
748 eos.
ld_i = eos.
ld.cast<
int>();
752 auto build_GaoB = [&](
auto term) {
762 if (!
all_same_length(term, {
"n",
"t",
"d",
"eta",
"beta",
"gamma",
"epsilon",
"b" })) {
763 throw std::invalid_argument(
"Lengths are not all identical in GaoB term");
769 auto build_na = [&](
auto& term) {
780 throw std::invalid_argument(
"Lengths are not all identical in nonanalytic term");
785 for (
auto& term : alphar) {
786 std::string type = term.at(
"type");
787 if (type ==
"ResidualHelmholtzPower") {
788 build_power(term, container);
790 else if (type ==
"ResidualHelmholtzGaussian") {
791 container.
add_term(build_gaussian(term));
793 else if (type ==
"ResidualHelmholtzNonAnalytic") {
796 else if (type ==
"ResidualHelmholtzLemmon2005") {
797 build_Lemmon2005(term, container);
799 else if (type ==
"ResidualHelmholtzGaoB") {
800 container.
add_term(build_GaoB(term));
802 else if (type ==
"ResidualHelmholtzExponential") {
803 container.
add_term(build_exponential(term));
805 else if (type ==
"ResidualHelmholtzDoubleExponential") {
806 container.
add_term(build_doubleexponential(term));
808 else if (type ==
"ResidualHelmholtzGenericCubic") {
811 else if (type ==
"ResidualHelmholtzPCSAFTGrossSadowski2001") {
815 throw std::invalid_argument(
"Bad term type: "+type);
821inline auto get_EOSs(
const std::vector<nlohmann::json>& pureJSON) {
822 std::vector<EOSTerms> EOSs;
823 for (
auto& j : pureJSON) {
825 EOSs.emplace_back(term);
832 std::vector<nlohmann::json> out;
833 for (
auto c : components) {
835 std::vector<std::filesystem::path> candidates = { c, root +
"/dev/fluids/" + c +
".json" };
836 std::filesystem::path selected_path =
"";
837 for (
auto candidate : candidates) {
838 if (std::filesystem::is_regular_file(candidate)) {
839 selected_path = candidate;
843 if (selected_path !=
"") {
847 throw std::invalid_argument(
"Could not load any of the candidates:" + c);
855 std::vector<std::string> CAS, Name, REFPROP, hash;
856 for (
auto j : pureJSON) {
857 auto INFO = j.at(
"INFO");
858 Name.push_back(INFO.at(
"NAME"));
859 CAS.push_back(INFO.at(
"CAS"));
860 REFPROP.push_back(INFO.at(
"REFPROP_NAME"));
861 if (INFO.contains(
"HASH")){
862 hash.push_back(INFO.at(
"HASH"));
865 std::map<std::string, std::vector<std::string>> result{
870 if (hash.size() == result[
"CAS"].size()){
871 result[
"hash"] = hash;
877template<
typename mapvec
string>
878inline auto select_identifier(
const nlohmann::json& BIPcollection,
const mapvecstring& identifierset,
const nlohmann::json& flags){
879 for (
const auto &ident: identifierset){
880 std::string key; std::vector<std::string> identifiers;
881 std::tie(key, identifiers) = ident;
883 for (
auto i = 0U; i < identifiers.size(); ++i){
884 for (
auto j = i+1; j < identifiers.size(); ++j){
885 const std::vector<std::string> pair = {identifiers[i], identifiers[j]};
896 for (
const auto& [k,v] : identifierset){
903 throw std::invalid_argument(
"Unable to match any of the identifier options: " + errmsg);
908 std::map<std::string, std::string> aliasmap;
909 for (
auto path : get_files_in_folder(root +
"/dev/fluids",
".json")) {
911 std::string REFPROP_name = j.at(
"INFO").at(
"REFPROP_NAME");
912 std::string name = j.at(
"INFO").at(
"NAME");
913 for (std::string k : {
"NAME",
"CAS",
"REFPROP_NAME"}) {
914 std::string val = j.at(
"INFO").at(k);
916 if (k ==
"REFPROP_NAME" && val == name) {
920 if (k ==
"REFPROP_NAME" && val ==
"N/A") {
923 if (aliasmap.count(val) > 0) {
924 throw std::invalid_argument(
"Duplicated reverse lookup identifier ["+k+
"] found in file:" + path.string());
927 aliasmap[val] = std::filesystem::absolute(path).string();
930 std::vector<std::string> aliases = j.at(
"INFO").at(
"ALIASES");
932 for (std::string alias : aliases) {
933 if (alias != REFPROP_name && alias != name) {
934 if (aliasmap.count(alias) > 0) {
935 throw std::invalid_argument(
"Duplicated alias [" + alias +
"] found in file:" + path.string());
938 aliasmap[alias] = std::filesystem::absolute(path).string();
948inline auto _build_multifluid_model(
const std::vector<nlohmann::json> &pureJSON,
const nlohmann::json& BIPcollection,
const nlohmann::json& depcollection,
const nlohmann::json& flags = {}) {
950 auto get_Rvals = [](
const std::vector<nlohmann::json> &pureJSON) -> std::vector<double>{
951 std::vector<double> o;
952 for (
auto pure : pureJSON){
953 o.push_back(pure.at(
"EOS")[0].at(
"gas_constant"));
961 auto Rvals = get_Rvals(pureJSON);
966 auto identifiers = identifierset[
select_identifier(BIPcollection, identifierset, flags)];
975 if (flags.contains(
"Rmodel") && flags.at(
"Rmodel") ==
"CODATA"){
980 nlohmann::json meta = {
993 model.set_meta(meta.dump(1));
998inline auto build_multifluid_JSONstr(
const std::vector<std::string>& componentJSON,
const std::string& BIPJSON,
const std::string& departureJSON,
const nlohmann::json& flags = {}) {
1001 const auto BIPcollection = nlohmann::json::parse(BIPJSON);
1002 const auto depcollection = nlohmann::json::parse(departureJSON);
1005 std::vector<nlohmann::json> pureJSON;
1006 for (
auto& c : componentJSON) {
1007 pureJSON.emplace_back(nlohmann::json::parse(c));
1022 std::vector<nlohmann::json> pureJSON;
1023 if (!components.is_array()){
1024 throw std::invalid_argument(
"Must be an array");
1027 for (
const nlohmann::json& comp : components){
1028 auto get_or_aliasmap = [&](){
1034 if (!optaliasmap && root){
1036 if (optaliasmap.value().count(comp) != 1){
1037 std::string scomp = comp.get<std::string>();
1038 std::string errname = (scomp.size() > 200) ? scomp.substr(0, 200)+
"..." : scomp;
1039 throw teqp::InvalidArgument(
"Alias map constructed, but component name is not found in alias map: " + errname);
1043 std::string scomp = comp.get<std::string>();
1044 std::string errname = (scomp.size() > 200) ? scomp.substr(0, 200)+
"..." : scomp;
1045 teqp::InvalidArgument(
"It was not possible to load the alias map because no path was provided. Failure to load: " + errname);
1050 if (comp.is_string()){
1051 std::string contents = comp;
1053 if (contents.find(
"PATH::") == 0){
1056 else if (contents.find(
"FLDPATH::") == 0){
1057 pureJSON.push_back(RPinterop::FLDfile(contents.substr(9)).make_json(
""));
1059 else if (contents.find(
"FLD::") == 0){
1060 pureJSON.push_back(RPinterop::FLDfile(contents.substr(5)).make_json(
""));
1063 pureJSON.push_back(get_or_aliasmap());
1067 pureJSON.push_back(get_or_aliasmap());
1073inline auto build_multifluid_model(
const std::vector<std::string>& components,
const std::string& root,
const std::string& BIPcollectionpath = {},
const nlohmann::json& flags = {},
const std::string& departurepath = {}) {
1076 nlohmann::json BIPcollection = nlohmann::json::array();
1077 nlohmann::json depcollection = nlohmann::json::array();
1078 if (components.size() > 1){
1079 nlohmann::json B = BIPcollectionpath, D = departurepath;
1081 depcollection =
multilevel_JSON_load(D, root +
"/dev/mixtures/mixture_departure_functions.json");
1097 nlohmann::json flags = (spec.contains(
"flags")) ? spec.at(
"flags") : nlohmann::json();
1100 if (spec.contains(
"HMX.BNC")){
1101 std::vector<nlohmann::json> componentJSON;
1102 for (
auto comp : spec.at(
"components")){
1103 componentJSON.push_back(RPinterop::FLDfile(comp).make_json(
""));
1105 auto [BIPcollection, depcollection] = RPinterop::HMXBNCfile(spec.at(
"HMX.BNC")).make_jsons();
1110 std::string root = (spec.contains(
"root")) ? spec.at(
"root") :
"";
1112 auto components = spec.at(
"components");
1114 nlohmann::json BIPcollection = nlohmann::json::array();
1115 nlohmann::json depcollection = nlohmann::json::array();
1116 if (components.size() > 1){
1117 BIPcollection =
multilevel_JSON_load(spec.at(
"BIP"), root +
"/dev/mixtures/mixture_binary_pairs.json");
1119 if (spec.contains(
"departure")){
1120 std::string msg =
"departure was provided but is invalid; options are non-empty array, path to file as string, or JSON data encoded as string";
1121 auto load_departure = [&msg](
const nlohmann::json& j){
1122 if (j.is_array() && j.size() > 0){
1125 else if (j.is_string()){
1126 const std::string& s = j;
1127 if (s.find(
"PATH::") == 0){
1136 return nlohmann::json::parse(s);
1150 depcollection = load_departure(spec.at(
"departure"));
1153 depcollection =
multilevel_JSON_load(spec.at(
"departure"), root +
"/dev/mixtures/mixture_departure_functions.json");
CorrespondingStatesContribution(EOSCollection &&EOSs)
auto alphari(const TauType &tau, const DeltaType &delta, std::size_t i) const
auto alphar(const TauType &tau, const DeltaType &delta, const MoleFractions &molefracs) const
auto get_EOS(std::size_t i) const
DepartureContribution(FCollection &&F, DepartureFunctionCollection &&funcs)
auto alphar(const TauType &tau, const DeltaType &delta, const MoleFractions &molefracs) const
auto get_alpharij(const std::size_t i, const std::size_t j, const TauType &tau, const DeltaType &delta) const
Call a single departure term at i,j.
const auto & get_F() const
auto add_term(Instance &&instance)
auto alphar(const TType &T, const RhoType &rho, const MoleFracType &molefrac) const
auto get_reducing_density(const MoleFracType &molefrac) const
const std::variant< double, std::string > get_BIP(const std::size_t &i, const std::size_t &j, const std::string &key) const
Return a binary interaction parameter.
const CorrespondingTerm corr
auto get_meta() const
Get the metadata stored in string form.
void set_meta(const std::string &m)
Store some sort of metadata in string form (perhaps a JSON representation of the model?...
MultiFluid(ReducingFunctions &&redfunc, CorrespondingTerm &&corr, DepartureTerm &&dep, GasConstantCalculator &&Rcalc)
multifluid::gasconstant::GasConstantCalculator GasConstantCalculator
const ReducingFunctions redfunc
const GasConstantCalculator Rcalc
auto get_reducing_temperature(const MoleFracType &molefrac) const
auto alphar(TType T, const RhoType &rhovec, const std::optional< typename RhoType::value_type > rhotot=std::nullopt) const
auto alphar_taudelta(const TType &tau, const RhoType &delta, const MoleFracType &molefrac) const
auto alphar_taudeltai(const TType &tau, const RhoType &delta, const std::size_t i) const
auto R(const VecType &molefracs) const
std::variant< MoleFractionWeighted, CODATA > GasConstantCalculator
auto get_Tcvc(const std::vector< nlohmann::json > &pureJSON)
auto get_F_matrix(const nlohmann::json &collection, const std::vector< std::string > &identifiers, const nlohmann::json &flags)
Get the matrix F of Fij factors multiplying the departure functions.
auto get_BIPdep(const nlohmann::json &collection, const std::vector< std::string > &identifiers, const nlohmann::json &flags)
auto get_BIP_matrices(const nlohmann::json &collection, const std::vector< std::string > &components, const nlohmann::json &flags, const Tcvec &Tc, const vcvec &vc)
Build the matrices of betaT, gammaT, betaV, gammaV for the multi-fluid model.
auto _build_multifluid_model(const std::vector< nlohmann::json > &pureJSON, const nlohmann::json &BIPcollection, const nlohmann::json &depcollection, const nlohmann::json &flags={})
Internal method for actually constructing the model with the provided JSON data structures.
auto get_EOS_terms(const nlohmann::json &j)
auto get_EOSs(const std::vector< nlohmann::json > &pureJSON)
auto build_alias_map(const std::string &root)
Build a reverse-lookup map for finding a fluid JSON structure given a backup identifier.
auto toeig(const std::vector< double > &v) -> Eigen::ArrayXd
nlohmann::json load_a_JSON_file(const std::string &path)
Load a JSON file from a specified file.
auto collect_identifiers(const std::vector< nlohmann::json > &pureJSON)
EOSTermContainer< JustPowerEOSTerm, PowerEOSTerm, GaussianEOSTerm, NonAnalyticEOSTerm, Lemmon2005EOSTerm, GaoBEOSTerm, ExponentialEOSTerm, DoubleExponentialEOSTerm, GenericCubicTerm, PCSAFTGrossSadowski2001Term > EOSTerms
auto build_multifluid_JSONstr(const std::vector< std::string > &componentJSON, const std::string &BIPJSON, const std::string &departureJSON, const nlohmann::json &flags={})
A builder function where the JSON-formatted strings are provided explicitly rather than file paths.
auto get_departure_json(const std::string &name, const std::string &path)
EOSTermContainer< JustPowerEOSTerm, PowerEOSTerm, GaussianEOSTerm, GERG2004EOSTerm, NullEOSTerm, DoubleExponentialEOSTerm, Chebyshev2DEOSTerm > DepartureTerms
auto get_departure_function_matrix(const nlohmann::json &depcollection, const nlohmann::json &BIPcollection, const std::vector< std::string > &components, const nlohmann::json &flags)
auto build_departure_function(const nlohmann::json &j)
auto all_same_length(const nlohmann::json &j, const std::vector< std::string > &ks)
auto select_identifier(const nlohmann::json &BIPcollection, const mapvecstring &identifierset, const nlohmann::json &flags)
Iterate over the possible options for identifiers to determine which one will satisfy all the binary ...
auto multifluidfactory(const nlohmann::json &spec)
Load a model from a JSON data structure.
auto make_pure_components_JSON(const nlohmann::json &components, const std::optional< std::string > &root=std::nullopt)
auto build_multifluid_model(const std::vector< std::string > &components, const std::string &root, const std::string &BIPcollectionpath={}, const nlohmann::json &flags={}, const std::string &departurepath={})
ReducingTermContainer< MultiFluidReducingFunction, MultiFluidInvariantReducingFunction > ReducingFunctions
auto collect_component_json(const std::vector< std::string > &components, const std::string &root)
auto multilevel_JSON_load(const nlohmann::json &j, const std::optional< std::string > &default_path=std::nullopt)