From f8576b1d492cff65bb801919a87ec9c84d0461e6 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 30 Dec 2014 20:08:35 -0500 Subject: [PATCH] PropsSImulti is integrated into Python wrapper; extract_fractions is exported Signed-off-by: Ian Bell --- include/CoolProp.h | 8 ++++ src/CoolProp.cpp | 64 ++++++++++++++++----------- wrappers/Python/CoolProp/CoolProp.pxd | 5 ++- wrappers/Python/CoolProp/CoolProp.pyx | 60 ++++++++++++++++++------- 4 files changed, 93 insertions(+), 44 deletions(-) diff --git a/include/CoolProp.h b/include/CoolProp.h index c9953199..bcc4ddae 100644 --- a/include/CoolProp.h +++ b/include/CoolProp.h @@ -176,6 +176,14 @@ You might want to start by looking at CoolProp.h */ void extract_backend(const std::string &fluid_string, std::string &backend, std::string &fluid); + /** + * @brief Extract fractions (molar, mass, etc.) encoded in the string if any + * @param fluid_string The input string + * @param fractions The fractions + * @return The fluids, as a '&' delimited string + */ + std::string extract_fractions(const std::string &fluid_string, std::vector &fractions); + } /* namespace CoolProp */ #endif diff --git a/src/CoolProp.cpp b/src/CoolProp.cpp index 6209767f..f19ecad7 100644 --- a/src/CoolProp.cpp +++ b/src/CoolProp.cpp @@ -292,26 +292,36 @@ void _PropsSI_outputs(shared_ptr &State, // Iterate over the state variable inputs for (std::size_t i = 0; i < IO.size(); ++i){ - - if (input_pair != INPUT_PAIR_INVALID){ - // Update the state since it is a valid set of inputs - State->update(input_pair, in1[i], in2[i]); - } - - for (std::size_t j = 0; j < IO[i].size(); ++j){ - output_parameter &output = output_parameters[j]; - switch (output.type){ - case output_parameter::OUTPUT_TYPE_TRIVIAL: - case output_parameter::OUTPUT_TYPE_NORMAL: - IO[i][j] = State->keyed_output(output.Of1); break; - case output_parameter::OUTPUT_TYPE_FIRST_DERIVATIVE: - IO[i][j] = State->first_partial_deriv(output.Of1, output.Wrt1, output.Constant1); break; - case output_parameter::OUTPUT_TYPE_SECOND_DERIVATIVE: - IO[i][j] = State->second_partial_deriv(output.Of1, output.Wrt1, output.Constant1, output.Wrt2, output.Constant2); break; - default: - throw ValueError(format("")); break; - } - } + try{ + if (input_pair != INPUT_PAIR_INVALID){ + // Update the state since it is a valid set of inputs + State->update(input_pair, in1[i], in2[i]); + } + } + catch(std::exception &){ + // All the outputs are filled with _HUGE + for (std::size_t j = 0; j < IO[i].size(); ++j){ IO[i][j] = _HUGE; } + } + + for (std::size_t j = 0; j < IO[i].size(); ++j){ + try{ + output_parameter &output = output_parameters[j]; + switch (output.type){ + case output_parameter::OUTPUT_TYPE_TRIVIAL: + case output_parameter::OUTPUT_TYPE_NORMAL: + IO[i][j] = State->keyed_output(output.Of1); break; + case output_parameter::OUTPUT_TYPE_FIRST_DERIVATIVE: + IO[i][j] = State->first_partial_deriv(output.Of1, output.Wrt1, output.Constant1); break; + case output_parameter::OUTPUT_TYPE_SECOND_DERIVATIVE: + IO[i][j] = State->second_partial_deriv(output.Of1, output.Wrt1, output.Constant1, output.Wrt2, output.Constant2); break; + default: + throw ValueError(format("")); break; + } + } + catch(std::exception &){ + IO[i][j] = _HUGE; + } + } } } std::vector > PropsSImulti(const std::vector &Outputs, @@ -339,7 +349,7 @@ std::vector > PropsSImulti(const std::vector &O } catch(std::exception &e){ // Initialization failed. Stop. - 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()) ); + throw ValueError(format("_PropsSI_initialize failed for backend: \"%s\", fluid: \"%s\" fractions \"%s\"; error: %s",backend.c_str(), strjoin(fluids,"&").c_str(), vec_to_string(fractions, "%0.10f").c_str(), e.what()) ); } try{ @@ -350,17 +360,17 @@ std::vector > PropsSImulti(const std::vector &O is_valid_parameter(Name2, key2); input_pair = generate_update_pair(key1, Prop1, key2, Prop2, v1, v2); } - catch (std::exception &){ - // Initialization failed. Stop. - throw ValueError(format("_PropsSI input pair parsing failed for Name1: \"%s\", Name2: \"%s\"", Name1.c_str(), Name2.c_str())); + catch (std::exception &e){ + // Input parameter parsing failed. Stop + throw ValueError(format("_PropsSI input pair parsing failed for Name1: \"%s\", Name2: \"%s\"; error: %s", Name1.c_str(), Name2.c_str(),e.what())); } try{ output_parameters = output_parameter::get_output_parameters(Outputs); } - catch (std::exception &){ - // Initialization failed. Stop. - throw ValueError(format("_PropsSI output parameter parsing failed")); + catch (std::exception &e){ + // Output parameter parsing failed. Stop. + throw ValueError(format("_PropsSI output parameter parsing failed; error: %s", e.what())); } // Calculate the output(s). In the case of a failure, all values will be filled with _HUGE diff --git a/wrappers/Python/CoolProp/CoolProp.pxd b/wrappers/Python/CoolProp/CoolProp.pxd index 3bf1c10c..11289575 100644 --- a/wrappers/Python/CoolProp/CoolProp.pxd +++ b/wrappers/Python/CoolProp/CoolProp.pxd @@ -33,12 +33,13 @@ cdef extern from "CoolProp.h" namespace "CoolProp": double _Props1SI "CoolProp::Props1SI"(string Ref, string Output) double _PropsSI "CoolProp::PropsSI"(string Output, string Name1, double Prop1, string Name2, double Prop2, string FluidName) string _PhaseSI "CoolProp::PhaseSI"(string Name1, double Prop1, string Name2, double Prop2, string FluidName) - vector[double] _PropsSI "CoolProp::PropsSI"(string Output, string Name1, vector[double] Prop1, string Name2, vector[double] Prop2, string FluidName, vector[double] fractions) - vector[double] _PropsSII "CoolProp::PropsSI"(string Output, string Name1, vector[double] Prop1, string Name2, vector[double] Prop2, string FluidName) + vector[vector[double]] _PropsSImulti "CoolProp::PropsSImulti"(vector[string] Outputs, string Name1, vector[double] Prop1, string Name2, vector[double] Prop2, string backend, vector[string] FluidName, vector[double] fractions) string _get_global_param_string "CoolProp::get_global_param_string"(string ParamName) except + int _get_debug_level "CoolProp::get_debug_level"() except + void _set_debug_level "CoolProp::set_debug_level"(int level) except + string _get_fluid_param_string "CoolProp::get_fluid_param_string"(string ParamName, string FluidName) except + + void _extract_backend "CoolProp::extract_backend"(string input, string backend, string fluids) except + + string _extract_fractions "CoolProp::extract_fractions"(string input, vector[double] fractions) except + void _set_reference_stateS "CoolProp::set_reference_stateS"(string, string) except + void _set_reference_stateD "CoolProp::set_reference_stateD"(string, double, double, double, double) except + diff --git a/wrappers/Python/CoolProp/CoolProp.pyx b/wrappers/Python/CoolProp/CoolProp.pyx index 4a815cb0..4360ba40 100644 --- a/wrappers/Python/CoolProp/CoolProp.pyx +++ b/wrappers/Python/CoolProp/CoolProp.pyx @@ -205,7 +205,11 @@ cpdef PropsSI(in1, in2, in3 = None, in4 = None, in5 = None, in6 = None, in7 = No """ A Python wrapper of C++ function :cpapi:`CoolProp::PropsSI` . """ + cdef vector[string] vin1 + cdef vector[double] fractions cdef double val + cdef string backend, fluid, delimitedfluids + cdef bool is_iterable1, is_iterable3, is_iterable5 # Two parameter inputs if in3 is None and in4 is None and in5 is None and in6 is None and in7 is None: @@ -216,19 +220,47 @@ cpdef PropsSI(in1, in2, in3 = None, in4 = None, in5 = None, in6 = None, in7 = No return val # Six parameter inputs elif in7 is None: - if iterable(in3) and iterable(in5): - if len(in3) != len(in5): - raise TypeError("Sizes of Prop1 {n1:d} and Prop2 {n2:d} to PropsSI are not the same".format(n1 = len(in3), n2 = len(in5))) - # This version takes iterables - return ndarray_or_iterable(_PropsSII(in1, in2, in3, in4, in5, in6)) - elif iterable(in3) and not(iterable(in5)): - i5 = [in5]*len(in3) - # This version takes iterables - return ndarray_or_iterable(_PropsSII(in1, in2, in3, in4, i5, in6)) - elif iterable(in5) and not(iterable(in3)): - i3 = [in3]*len(in5) - # This version takes iterables - return ndarray_or_iterable(_PropsSII(in1, in2, i3, in4, in5, in6)) + is_iterable1 = iterable(in1) + is_iterable3 = iterable(in3) + is_iterable5 = iterable(in5) + if is_iterable1 or is_iterable3 or is_iterable5: + # Prepare the output datatype + if not is_iterable1: + vin1.push_back(in1) + else: + vin1 = in1 + # Resize state variable inputs + if is_iterable3 and is_iterable5: + if len(in3) != len(in5): + raise TypeError("Sizes of Prop1 {n1:d} and Prop2 {n2:d} to PropsSI are not the same".format(n1 = len(in3), n2 = len(in5))) + else: + vval1 = in3 + vval2 = in5 + elif is_iterable3 and not is_iterable5: + vval1 = in3 + vval2 = [in5]*len(in3) + elif is_iterable5 and not is_iterable3: + vval1 = [in3]*len(in5) + vval2 = in5 + + # Extract the backend and the fluid from the input string + _extract_backend(in6, backend, fluid) + + # Extract the fractions + fractions.push_back(1.0) + delimitedfluids = _extract_fractions(fluid, fractions) + + # Extract the fluids + fluids = delimitedfluids.split('&') + + # Call the function - this version takes iterables + outmat = _PropsSImulti(in1, in2, vval1, in4, vval2, backend, fluids, fractions) + + # Check that we got some output + if outmat.empty(): + raise ValueError(_get_global_param_string('errstring')) + + return outmat else: # This version takes doubles val = _PropsSI(in1, in2, in3, in4, in5, in6) @@ -236,8 +268,6 @@ cpdef PropsSI(in1, in2, in3 = None, in4 = None, in5 = None, in6 = None, in7 = No __Props_err2("PropsSI", in1, in2, in3, in4, in5, in6) else: return val - else: - return _PropsSI(in1, in2, in3, in4, in5, in6, in7) cpdef list FluidsList(): """