diff --git a/.gitmodules b/.gitmodules index 5534fb84..30525438 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "externals/json-schema-validator"] path = externals/json-schema-validator url = https://github.com/pboettch/json-schema-validator +[submodule "externals/REFPROP-interop"] + path = externals/REFPROP-interop + url = https://github.com/ianhbell/REFPROP-interop diff --git a/CMakeLists.txt b/CMakeLists.txt index e03f4ea1..c2e634bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ target_include_directories(teqpinterface INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/ target_include_directories(teqpinterface INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/externals/Eigen") target_include_directories(teqpinterface INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/externals/nlohmann_json") target_include_directories(teqpinterface INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/boost_teqp") +target_include_directories(teqpinterface INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/externals/REFPROP-interop/include") if (NOT TEQP_NO_TESTS) add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/externals/Catch2") diff --git a/externals/REFPROP-interop b/externals/REFPROP-interop new file mode 160000 index 00000000..66f3fd13 --- /dev/null +++ b/externals/REFPROP-interop @@ -0,0 +1 @@ +Subproject commit 66f3fd131c559a1b0be985ee48de9791cc0114ec diff --git a/include/teqp/models/multifluid.hpp b/include/teqp/models/multifluid.hpp index 285d5e31..1ef44c45 100644 --- a/include/teqp/models/multifluid.hpp +++ b/include/teqp/models/multifluid.hpp @@ -14,6 +14,8 @@ #include "teqp/json_tools.hpp" #include "teqp/exceptions.hpp" +#include "RPinterop/interop.hpp" + #if defined(TEQP_MULTICOMPLEX_ENABLED) #include "MultiComplex/MultiComplex.hpp" #endif @@ -747,17 +749,25 @@ inline auto collect_component_json(const std::vector& components, c inline auto collect_identifiers(const std::vector& pureJSON) { - std::vector CAS, Name, REFPROP; + std::vector CAS, Name, REFPROP, hash; for (auto j : pureJSON) { - Name.push_back(j.at("INFO").at("NAME")); - CAS.push_back(j.at("INFO").at("CAS")); - REFPROP.push_back(j.at("INFO").at("REFPROP_NAME")); + auto INFO = j.at("INFO"); + Name.push_back(INFO.at("NAME")); + CAS.push_back(INFO.at("CAS")); + REFPROP.push_back(INFO.at("REFPROP_NAME")); + if (INFO.contains("HASH")){ + hash.push_back(INFO.at("HASH")); + } } - return std::map>{ + std::map> result{ {"CAS", CAS}, {"Name", Name}, {"REFPROP", REFPROP} }; + if (hash.size() > 0){ + result["hash"] = hash; + } + return result; } /// Iterate over the possible options for identifiers to determine which one will satisfy all the binary pairs @@ -983,19 +993,32 @@ inline auto build_multifluid_model(const std::vector& components, c */ inline auto multifluidfactory(const nlohmann::json& spec) { - std::string root = (spec.contains("root")) ? spec.at("root") : ""; - - auto components = spec.at("components"); + nlohmann::json flags = (spec.contains("flags")) ? spec.at("flags") : nlohmann::json(); - nlohmann::json BIPcollection = nlohmann::json::array(); - nlohmann::json depcollection = nlohmann::json::array(); - if (components.size() > 1){ - BIPcollection = multilevel_JSON_load(spec.at("BIP"), root + "/dev/mixtures/mixture_binary_pairs.json"); - depcollection = multilevel_JSON_load(spec.at("departure"), root + "/dev/mixtures/mixture_departure_functions.json"); + // We are in the interop logical branch in which we will be invoking the REFPROP-interop code + if (spec.contains("HMX.BNC")){ + std::vector componentJSON; + for (auto comp : spec.at("components")){ + componentJSON.push_back(RPinterop::FLDfile(comp).make_json("")); + } + auto [BIPcollection, depcollection] = RPinterop::HMXBNCfile(spec.at("HMX.BNC")).make_jsons(); + return _build_multifluid_model(componentJSON, BIPcollection, depcollection, flags); + } + else{ + + std::string root = (spec.contains("root")) ? spec.at("root") : ""; + + auto components = spec.at("components"); + + nlohmann::json BIPcollection = nlohmann::json::array(); + nlohmann::json depcollection = nlohmann::json::array(); + if (components.size() > 1){ + BIPcollection = multilevel_JSON_load(spec.at("BIP"), root + "/dev/mixtures/mixture_binary_pairs.json"); + depcollection = multilevel_JSON_load(spec.at("departure"), root + "/dev/mixtures/mixture_departure_functions.json"); + } + + return _build_multifluid_model(make_pure_components_JSON(components, root), BIPcollection, depcollection, flags); } - nlohmann::json flags = (spec.contains("flags")) ? spec.at("flags") : nlohmann::json(); - - return _build_multifluid_model(make_pure_components_JSON(components, root), BIPcollection, depcollection, flags); } /// An overload of multifluidfactory that takes in a string inline auto multifluidfactory(const std::string& specstring) { diff --git a/include/teqp/models/multifluid_reducing.hpp b/include/teqp/models/multifluid_reducing.hpp index a7f64b38..46a01f46 100644 --- a/include/teqp/models/multifluid_reducing.hpp +++ b/include/teqp/models/multifluid_reducing.hpp @@ -30,9 +30,21 @@ namespace teqp { // convert string to upper case auto toupper = [](const std::string s) { auto data = s; std::for_each(data.begin(), data.end(), [](char& c) { c = ::toupper(c); }); return data; }; - // First pass, check names std::string comp0 = toupper(identifiers[0]); std::string comp1 = toupper(identifiers[1]); + // O-th pass, check the hashes + for (auto& el : collection) { + if (!el.contains("hash1")){ continue; } + std::string name1 = toupper(el.at("hash1")); + std::string name2 = toupper(el.at("hash2")); + if (comp0 == name1 && comp1 == name2) { + return std::make_tuple(el, false); + } + if (comp0 == name2 && comp1 == name1) { + return std::make_tuple(el, true); + } + } + // First pass, check names for (auto& el : collection) { std::string name1 = toupper(el.at("Name1")); std::string name2 = toupper(el.at("Name2")); diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp index aebb25cd..027188df 100644 --- a/interface/pybind11_wrapper.cpp +++ b/interface/pybind11_wrapper.cpp @@ -504,6 +504,9 @@ void init_teqp(py::module& m) { m.def("_make_model", &teqp::cppinterface::make_model, "json_data"_a, py::arg_v("validate", true)); m.def("attach_model_specific_methods", &attach_model_specific_methods); m.def("build_ancillaries", &teqp::ancillaries::build_ancillaries, "model"_a, "Tc"_a, "rhoc"_a, "Tmin"_a, py::arg_v("flags", std::nullopt, "None")); + m.def("convert_FLD", [](const std::string& component, const std::string& name){ return RPinterop::FLDfile(component).make_json(name); }, + "component"_a, "name"_a); + m.def("convert_HMXBNC", [](const std::string& path){ return RPinterop::HMXBNCfile(path).make_jsons(); }, "path"_a); using namespace teqp::iteration; py::class_(m, "NRIterator")