/// Parse a '&' separated string into a data structure with one entry per output /// Covers both normal and derivative outputs static std::vector<output_parameter> get_output_parameters(const std::vector<std::string> &Outputs){ std::vector<output_parameter> outputs; for (std::vector<std::string>::const_iterator str = Outputs.begin(); str != Outputs.end(); ++str){ output_parameter out; CoolProp::parameters iOutput; if (is_valid_parameter(*str, iOutput)){ out.Of1 = iOutput; if (is_trivial_parameter(iOutput)){ out.type = OUTPUT_TYPE_TRIVIAL; } else{ out.type = OUTPUT_TYPE_NORMAL; } } else if (is_valid_first_saturation_derivative(*str, out.Of1, out.Wrt1)){ out.type = OUTPUT_TYPE_FIRST_SATURATION_DERIVATIVE; } else if (is_valid_first_derivative(*str, out.Of1, out.Wrt1, out.Constant1)){ out.type = OUTPUT_TYPE_FIRST_DERIVATIVE; } else if (is_valid_second_derivative(*str, out.Of1, out.Wrt1, out.Constant1, out.Wrt2, out.Constant2)){ out.type = OUTPUT_TYPE_SECOND_DERIVATIVE; } else{ throw ValueError(format("Output string is invalid [%s]", str->c_str())); } outputs.push_back(out); } return outputs; };
bool is_valid_second_derivative(const std::string & name, parameters &iOf1, parameters &iWrt1, parameters &iConstant1, parameters &iWrt2, parameters &iConstant2) { if (get_debug_level() > 5){std::cout << format("is_valid_second_derivative(%s)",name.c_str());} // Suppose we start with "d(d(P)/d(Dmolar)|T)/d(Dmolar)|T" std::size_t i_bar = name.rfind('|'); if (i_bar == std::string::npos){return false;} std::string constant2 = name.substr(i_bar+1); // "T" if (!is_valid_parameter(constant2, iConstant2)){return false;}; std::string left_of_bar = name.substr(0, i_bar); // "d(d(P)/d(Dmolar)|T)/d(Dmolar)" std::size_t i_slash = left_of_bar.rfind('/'); if (i_slash == std::string::npos){return false;} std::string left_of_slash = left_of_bar.substr(0, i_slash); // "d(d(P)/d(Dmolar)|T)" std::size_t iN0 = left_of_slash.find("("); std::size_t iN1 = left_of_slash.rfind(")"); if (!(iN0 > 0 && iN1 > 0 && iN1 > iN0)){return false;} std::string num = left_of_slash.substr(iN0+1, iN1-2); // "d(P)/d(Dmolar)|T" if (!is_valid_first_derivative(num, iOf1, iWrt1, iConstant1)){return false;} std::string right_of_slash = left_of_bar.substr(i_slash+1); // "d(Dmolar)" std::size_t iD0 = right_of_slash.find("("); std::size_t iD1 = right_of_slash.rfind(")"); if (!(iD0 > 0 && iD1 > 0 && iD1 > iD0)){return false;} std::string den = right_of_slash.substr(iD0+1, iD1-2); // "Dmolar" if (!is_valid_parameter(den, iWrt2)){return false;} // If we haven't quit yet, all is well return true; }
bool is_valid_second_derivative(const std::string &name, parameters &iOf1, parameters &iWrt1, parameters &iConstant1, parameters &iWrt2, parameters &iConstant2) { if (get_debug_level() > 5){std::cout << format("is_valid_second_derivative(%s)",name.c_str());} // Suppose we start with "d(d(P)/d(Dmolar)|T)/d(Dmolar)|T" std::size_t i = name.rfind('|'); if ((i == 0) || (i == std::string::npos)){return false;} std::string constant2 = name.substr(i+1); // "T" if (!is_valid_parameter(constant2, iConstant2)){return false;}; std::string left_of_bar = name.substr(0, i); // "d(d(P)/d(Dmolar)|T)/d(Dmolar)" i = left_of_bar.rfind('/'); if ((i == 0) || (i == std::string::npos)){return false;} std::string left_of_slash = left_of_bar.substr(0, i); // "d(d(P)/d(Dmolar)|T)" std::string right_of_slash = left_of_bar.substr(i + 1); // "d(Dmolar)" i = left_of_slash.find("("); std::size_t i1 = left_of_slash.rfind(")"); if (!((i > 0) && (i != std::string::npos) && (i1 > (i+1)) && (i1 != std::string::npos))){return false;} std::string num = left_of_slash.substr(i+1, i1-i-1); // "d(P)/d(Dmolar)|T" if (!is_valid_first_derivative(num, iOf1, iWrt1, iConstant1)){return false;} i = right_of_slash.find("("); i1 = right_of_slash.rfind(")"); if (!((i > 0) && (i != std::string::npos) && (i1 > (i+1)) && (i1 != std::string::npos))){return false;} std::string den = right_of_slash.substr(i+1, i1-i-1); // "Dmolar" if (!is_valid_parameter(den, iWrt2)){return false;} // If we haven't quit yet, all is well return true; }
// Internal function to do the actual calculations, make this a wrapped function so // that error bubbling can be done properly double _PropsSI(const std::string &Output, const std::string &Name1, double Prop1, const std::string &Name2, double Prop2, const std::string &backend, const std::string &Ref, const std::vector<double> &z) { parameters iOutput = iundefined_parameter; parameters iOf = iundefined_parameter, iWrt = iundefined_parameter, iConstant = iundefined_parameter, iOf1 = iundefined_parameter, iWrt1 = iundefined_parameter, iConstant1 = iundefined_parameter, iWrt2 = iundefined_parameter, iConstant2 = iundefined_parameter; double x1, x2; if (get_debug_level()>5){ std::cout << format("%s:%d: _PropsSI(%s,%s,%g,%s,%g,%s,%s)\n",__FILE__,__LINE__,Output.c_str(),Name1.c_str(),Prop1,Name2.c_str(),Prop2,backend.c_str(),Ref.c_str(), vec_to_string(z).c_str()).c_str(); } // The state we are going to use shared_ptr<AbstractState> State; // If the fractions of the components have been encoded in the string, extract them // If they have not, this function does nothing std::vector<double> fractions; if (z.empty()) { // Make a one-element vector fractions = std::vector<double>(1, 1); } else{ // Make a copy fractions = z; } std::string fluid_string = extract_fractions(Ref, fractions); // We are going to let the factory function load the state State.reset(AbstractState::factory(backend, fluid_string)); // First check if it is a trivial input (critical/max parameters for instance) if (is_valid_parameter(Output, iOutput) && is_trivial_parameter(iOutput)) { double val = State->trivial_keyed_output(iOutput); return val; } long iName1 = get_parameter_index(Name1); long iName2 = get_parameter_index(Name2); 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(); } // Obtain the input pair CoolProp::input_pairs pair = generate_update_pair(iName1, Prop1, iName2, Prop2, x1, x2); // Update the state State->update(pair, x1, x2); if (iOutput != iundefined_parameter){ // Get the desired output double val = State->keyed_output(iOutput); // Return the value return val; } else if (is_valid_first_derivative(Output, iOf, iWrt, iConstant)){ // Return the desired output double val = State->first_partial_deriv(iOf, iWrt, iConstant); // Return the value return val; } else if (is_valid_second_derivative(Output, iOf1, iWrt1, iConstant1, iWrt2, iConstant2)){ // Return the desired output double val = State->second_partial_deriv(iOf1, iWrt1, iConstant1, iWrt2, iConstant2); // Return the value return val; } else{ throw ValueError(format("Output [%s] is not a parameter or a string representation of a derivative",Output.c_str()).c_str()); } }