From 6b601adb10ccb68ea98e1b3941b694badfec0042 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 30 Dec 2014 16:07:19 -0500 Subject: [PATCH] PropsSImulti takes vector of strings as inputs Signed-off-by: Ian Bell --- include/CoolProp.h | 4 +- .../Helmholtz/HelmholtzEOSMixtureBackend.cpp | 2 +- .../Helmholtz/HelmholtzEOSMixtureBackend.h | 2 +- .../Incompressible/IncompressibleBackend.cpp | 9 +- src/CoolProp.cpp | 141 ++++++++++++------ 5 files changed, 107 insertions(+), 51 deletions(-) diff --git a/include/CoolProp.h b/include/CoolProp.h index 00bbc8b2..5586a69d 100644 --- a/include/CoolProp.h +++ b/include/CoolProp.h @@ -42,7 +42,7 @@ You might want to start by looking at CoolProp.h * @param Name2 The name of the second input variable * @param Prop2 A vector of the second input values * @param backend The string representation of the backend (HEOS, REFPROP, INCOMP, etc.) - * @param fluid The fluid name + * @param fluids The fluid name(s) * @param fractions The fractions (molar, mass, volume, etc.) of the components */ std::vector > PropsSImulti(const std::vector &Outputs, @@ -51,7 +51,7 @@ You might want to start by looking at CoolProp.h const std::string &Name2, const std::vector &Prop2, const std::string &backend, - const std::string &fluid, + const std::vector &fluids, const std::vector &fractions); /// Get the debug level diff --git a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp index 6ee3689b..042fd421 100644 --- a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp +++ b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.cpp @@ -35,7 +35,7 @@ static int deriv_counter = 0; namespace CoolProp { -HelmholtzEOSMixtureBackend::HelmholtzEOSMixtureBackend(std::vector &component_names, bool generate_SatL_and_SatV) { +HelmholtzEOSMixtureBackend::HelmholtzEOSMixtureBackend(const std::vector &component_names, bool generate_SatL_and_SatV) { std::vector components; components.resize(component_names.size()); diff --git a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h index df4f9562..71c15ba7 100644 --- a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h +++ b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h @@ -36,7 +36,7 @@ public: HelmholtzEOSMixtureBackend(){ imposed_phase_index = iphase_not_imposed; _phase = iphase_unknown;}; HelmholtzEOSMixtureBackend(std::vector components, bool generate_SatL_and_SatV = true); - HelmholtzEOSMixtureBackend(std::vector &component_names, bool generate_SatL_and_SatV = true); + HelmholtzEOSMixtureBackend(const std::vector &component_names, bool generate_SatL_and_SatV = true); virtual ~HelmholtzEOSMixtureBackend(){}; shared_ptr Reducing; ExcessTerm Excess; diff --git a/src/Backends/Incompressible/IncompressibleBackend.cpp b/src/Backends/Incompressible/IncompressibleBackend.cpp index 1a3c475d..2b7b7403 100644 --- a/src/Backends/Incompressible/IncompressibleBackend.cpp +++ b/src/Backends/Incompressible/IncompressibleBackend.cpp @@ -488,7 +488,8 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi // Compare different inputs // ... as vector expected = 9.6212e+02; - std::vector > IO = CoolProp::PropsSImulti(std::vector(1,"D"),"T",std::vector(1,T),"P",std::vector(1,p),"INCOMP",fluid,std::vector(1,x)); + std::vector fluid_Melinder(1,fluid); + std::vector > IO = CoolProp::PropsSImulti(std::vector(1,"D"),"T",std::vector(1,T),"P",std::vector(1,p),"INCOMP",fluid_Melinder,std::vector(1,x)); actual = IO[0][0]; { CAPTURE(T); @@ -526,7 +527,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi } std::string backend = "INCOMP"; - fluid = std::string("ExampleSecCool"); + std::vector fluids(1,"ExampleSecCool"); T = -5 + 273.15; p = 10e5; x = 0.4; @@ -537,7 +538,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi // Compare d expected = 9.4844e+02; - IO = CoolProp::PropsSImulti(std::vector(1,"D"),"T",T_vec,"P",p_vec,backend,fluid,x_vec); + IO = CoolProp::PropsSImulti(std::vector(1,"D"),"T",T_vec,"P",p_vec,backend,fluids,x_vec); actual = IO[0][0]; { CAPTURE(T); @@ -552,7 +553,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi // Compare cp expected = 3.6304e+03; - actual = CoolProp::PropsSImulti(std::vector(1,"C"),"T",T_vec,"P",p_vec,backend,fluid,x_vec)[0][0]; + actual = CoolProp::PropsSImulti(std::vector(1,"C"),"T",T_vec,"P",p_vec,backend,fluids,x_vec)[0][0]; { CAPTURE(T); CAPTURE(p); diff --git a/src/CoolProp.cpp b/src/CoolProp.cpp index 6871875c..f133f1b7 100644 --- a/src/CoolProp.cpp +++ b/src/CoolProp.cpp @@ -176,40 +176,64 @@ std::string extract_fractions(const std::string &fluid_string, std::vector &fluid_names, const std::vector &z, shared_ptr &State){ - std::vector fractions(1,1); - std::string fluid = Ref; + + if (fluid_names.empty()){throw ValueError("fluid_names cannot be empty");} + + std::vector fluids = fluids; Dictionary dict; - // If a predefined mixture, set it up - if (is_predefined_mixture(fluid, dict)){ - fractions = dict.get_double_vector("mole_fractions"); - fluid = strjoin(dict.get_string_vector("fluids"),"&"); - } + // If a predefined mixture, set it up. Fractions and names are given + if (is_predefined_mixture(fluid_names[0], dict)){ - if (!z.empty()){ - // Make a copy of the provided fractions - fractions = z; + // Retrieve the information on the predefined mixture + std::vector fractions = dict.get_double_vector("mole_fractions"); + std::vector fluid_names = dict.get_string_vector("fluids"); + + // Reset the state + State.reset(AbstractState::factory(backend, fluid_names)); + + // Set the fraction for the state + if (State->using_mole_fractions()){ + State->set_mole_fractions(fractions); + } else if (State->using_mass_fractions()){ + State->set_mass_fractions(fractions); + } else if (State->using_volu_fractions()){ + State->set_volu_fractions(fractions); + } else { + if (get_debug_level()>50) std::cout << format("%s:%d: _PropsSI, could not set composition to %s, defaulting to mole fraction.\n",__FILE__,__LINE__, vec_to_string(z).c_str()).c_str(); + } + } + else{ + std::vector fractions; + std::string fluid_string; + + if (!z.empty()){ + // Make a copy of the provided fractions + fractions = z; + } + if (fluid_names.size() == 1){ + // Extract fractions from the string if you can + fluid_string = extract_fractions(fluid_names[0], fractions); + } + + // Reset the state + State.reset(AbstractState::factory(backend, fluid_string)); + + // Set the fraction for the state + if (State->using_mole_fractions()){ + State->set_mole_fractions(fractions); + } else if (State->using_mass_fractions()){ + State->set_mass_fractions(fractions); + } else if (State->using_volu_fractions()){ + State->set_volu_fractions(fractions); + } else { + if (get_debug_level()>50) std::cout << format("%s:%d: _PropsSI, could not set composition to %s, defaulting to mole fraction.\n",__FILE__,__LINE__, vec_to_string(z).c_str()).c_str(); + } } - - // Extract fractions from the string if you can - std::string fluid_string = extract_fractions(Ref, fractions); - // Reset the state - State.reset(AbstractState::factory(backend, fluid_string)); - - // Set the fraction for the state - if (State->using_mole_fractions()){ - State->set_mole_fractions(fractions); - } else if (State->using_mass_fractions()){ - State->set_mass_fractions(fractions); - } else if (State->using_volu_fractions()){ - State->set_volu_fractions(fractions); - } else { - if (get_debug_level()>50) std::cout << format("%s:%d: _PropsSI, could not set composition to %s, defaulting to mole fraction.\n",__FILE__,__LINE__, vec_to_string(z).c_str()).c_str(); - } } struct output_parameter{ @@ -289,7 +313,7 @@ std::vector > PropsSImulti(const std::vector &O const std::string &Name2, const std::vector &Prop2, const std::string &backend, - const std::string &fluid, + const std::vector &fluids, const std::vector &fractions) { shared_ptr State; @@ -304,11 +328,11 @@ std::vector > PropsSImulti(const std::vector &O try{ // Initialize the State class - _PropsSI_initialize(backend, fluid, fractions, State); + _PropsSI_initialize(backend, fluids, fractions, State); } catch(std::exception &e){ // Initialization failed. Stop. - throw ValueError(format("_PropsSI_initialize failed for backend: \"%s\", fluid: \"%s\" fractions \"%s\"",backend.c_str(), fluid.c_str(), vec_to_string(fractions, "0.10f").c_str()) ); + throw ValueError(format("_PropsSI_initialize failed for backend: \"%s\", fluid: \"%s\" fractions \"%s\"",backend.c_str(), strjoin(fluids,"&").c_str(), vec_to_string(fractions, "0.10f").c_str()) ); } try{ @@ -354,7 +378,7 @@ std::vector > PropsSImulti(const std::vector &O } double PropsSI(const std::string &Output, const std::string &Name1, double Prop1, const std::string &Name2, double Prop2, const std::string &Ref) { - std::string backend, fluid; std::vector fractions(1, 1.0); + std::string backend, fluid; std::vector fractions(1,1.0); #if !defined(NO_ERROR_CATCHING) try{ #endif @@ -370,7 +394,7 @@ double PropsSI(const std::string &Output, const std::string &Name1, double Prop1 extract_fractions(fluid, fractions); } - IO = PropsSImulti(strsplit(Output,'&'), Name1, std::vector(1, Prop1), Name2, std::vector(1, Prop2), backend, fluid, fractions); + IO = PropsSImulti(strsplit(Output,'&'), Name1, std::vector(1, Prop1), Name2, std::vector(1, Prop2), backend, std::vector(1, fluid), fractions); if (IO.size()!= 1 || IO[0].size() != 1){ throw ValueError(format("output should be 1x1; error was %s", get_global_param_string("errstring").c_str())); } double val = IO[0][0]; @@ -399,45 +423,73 @@ TEST_CASE("Check inputs to PropsSI","[PropsSI]") SECTION("Single state, single output"){ CHECK(ValidNumber(CoolProp::PropsSI("T","P",101325,"Q",0,"Water"))); }; + SECTION("Single state, single output, pure incompressible"){ + CHECK(ValidNumber(CoolProp::PropsSI("D","P",101325,"T",300,"INCOMP::DowQ"))); + }; + SECTION("Single state, single output, 40% incompressible"){ + CHECK(ValidNumber(CoolProp::PropsSI("D","P",101325,"T",300,"INCOMP::MEG[0.40]"))); + }; + SECTION("Single state, single output, predefined CoolProp mixture"){ + CHECK(ValidNumber(CoolProp::PropsSI("T","Q",1,"P",3e6,"HEOS::R125[0.7]&R32[0.3]"))); + }; + SECTION("Single state, single output"){ + CHECK(ValidNumber(CoolProp::PropsSI("T","P",101325,"Q",0,"HEOS::Water"))); + }; + SECTION("Single state, single output, predefined mixture"){ + CHECK(ValidNumber(CoolProp::PropsSI("T","P",101325,"Q",0,"R410A.mix"))); + }; + SECTION("Predefined mixture"){ + std::vector p(1, 101325), Q(1, 1.0), z; + std::vector outputs(1,"T"); outputs.push_back("Dmolar"); + std::vector > IO; + std::vector fluids(1, "R410A.mix"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); + }; SECTION("Single state, two outputs"){ std::vector p(1, 101325), Q(1, 1.0), z(1, 1.0); std::vector outputs(1,"T"); outputs.push_back("Dmolar"); - CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); }; SECTION("Single state, two bad outputs"){ std::vector p(1, 101325), Q(1, 1.0), z(1, 1.0); std::vector > IO; std::vector outputs(1,"???????"); outputs.push_back("?????????"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); CHECK(IO.size() == 0); }; SECTION("Two states, one output"){ std::vector p(2, 101325), Q(2, 1.0), z(1, 1.0); std::vector outputs(1,"T"); - CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); }; SECTION("Two states, two outputs"){ std::vector p(2, 101325), Q(2, 1.0), z(1, 1.0); std::vector outputs(1,"T"); outputs.push_back("Dmolar"); - CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(std::vector > IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); }; SECTION("cp and its derivative representation"){ std::vector p(1, 101325), Q(1, 1.0), z(1, 1.0); std::vector > IO; std::vector outputs(1,"Cpmolar"); outputs.push_back("d(Hmolar)/d(T)|P"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); std::string errstring = get_global_param_string("errstring"); CAPTURE(errstring); REQUIRE(!IO.empty()); - CHECK(IO[0][0]); - CHECK(IO[0][1]); + CAPTURE(IO[0][0]); + CAPTURE(IO[0][1]); CHECK(std::abs(IO[0][0] - IO[0][1]) < 1e-5); }; SECTION("bad fluid"){ std::vector p(1, 101325), Q(1, 1.0), z(1, 1.0); std::vector > IO; std::vector outputs(1,"Cpmolar"); outputs.push_back("d(Hmolar)/d(T)|P"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","????????????",z);); + std::vector fluids(1, "????????"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); std::string errstring = get_global_param_string("errstring"); CAPTURE(errstring); REQUIRE(IO.empty()); @@ -446,7 +498,8 @@ TEST_CASE("Check inputs to PropsSI","[PropsSI]") std::vector p(1, 101325), Q(1, 1.0), z(100, 1.0); std::vector > IO; std::vector outputs(1,"T"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); std::string errstring = get_global_param_string("errstring"); CAPTURE(errstring); REQUIRE(IO.empty()); @@ -455,7 +508,8 @@ TEST_CASE("Check inputs to PropsSI","[PropsSI]") std::vector p(1, 101325), Q(2, 1.0), z(100, 1.0); std::vector > IO; std::vector outputs(1,"Cpmolar"); outputs.push_back("d(Hmolar)/d(T)|P"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"P",p,"Q",Q,"HEOS",fluids,z);); std::string errstring = get_global_param_string("errstring"); CAPTURE(errstring); REQUIRE(IO.empty()); @@ -464,7 +518,8 @@ TEST_CASE("Check inputs to PropsSI","[PropsSI]") std::vector Q(2, 1.0), z(100, 1.0); std::vector > IO; std::vector outputs(1,"Cpmolar"); outputs.push_back("d(Hmolar)/d(T)|P"); - CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"Q",Q,"Q",Q,"HEOS","Water",z);); + std::vector fluids(1, "Water"); + CHECK_NOTHROW(IO = CoolProp::PropsSImulti(outputs,"Q",Q,"Q",Q,"HEOS",fluids,z);); std::string errstring = get_global_param_string("errstring"); CAPTURE(errstring); REQUIRE(IO.empty());