0

The overall problem that I am trying to solve is to develop code which accepts string equations from user input or files, parses the equations, and solves the equations given a valid set of known values for variables. The approach must allow the user to enter a thermophysical function (such as CoolProp's PropsSI or HAPropsSI) in equation(s), and ideally, any user-defined function or object. Based on initial work I thought Sympy was a way to go.

Therefore, I have been trying to understand how to sympify a numerical function for use in systems of equations in Sympy.

The function is HAPropsSI from the CoolProp library. The Coolprops functions are implemented in C++ and wrapped for use in Python. It is not built on numpy per se, but is vectorized to accept 1D numpy arrays in addition to ints, floats, and lists.

Here is an example of what I tried:

from CoolProp.HumidAirProp import HAPropsSI
from sympy import symbols, sympify 

# Example calculating enthalpy as a function of temp., pressure, % RH:
T = 298.15
P = 101325
RH = 0.5

h = HAPropsSI("H", "T", T, "P", P, "R", RH)
print(h) # returns the float value h = 50423.45

# Example using Sympy:
Temp, Press, RH = symbols('Temp Press RH')
sym_h = sympify('HAPropsSI("H", "T", Temp, "P", Press, "R", RH)', {'HAPropsSI':HAPropsSI}) 

Sympify tries to parse the expression and then use eval on the function with symbols which results in the following traceback:

ValueError                                Traceback (most recent call last)
ValueError: Error from parse_expr with transformed code: 'HAPropsSI ("H","T",Symbol (\'Temp\' ),"P",Symbol (\'Press\' ),"R",Symbol (\'RH\' ))'

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
C:\Users\JIMCAR~1\AppData\Local\Temp/ipykernel_3076/1321321868.py in <module>
     12 
     13 Temp, Press, RH = symbols('Temp Press RH')
---> 14 sym_h = sympify('HAPropsSI("H", "T", Temp, "P", Press, "R", RH)', {'HAPropsSI':HAPropsSI})
     15 
     16 '''

~\AppData\Roaming\Python\Python38\site-packages\sympy\core\sympify.py in sympify(a, locals, convert_xor, strict, rational, evaluate)
    470     try:
    471         a = a.replace('\n', '')
--> 472         expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate)
    473     except (TokenError, SyntaxError) as exc:
    474         raise SympifyError('could not parse %r' % a, exc)

~\AppData\Roaming\Python\Python38\site-packages\sympy\parsing\sympy_parser.py in parse_expr(s, local_dict, transformations, global_dict, evaluate)
   1024         for i in local_dict.pop(None, ()):
   1025             local_dict[i] = None
-> 1026         raise e from ValueError(f"Error from parse_expr with transformed code: {code!r}")
   1027 
   1028 

~\AppData\Roaming\Python\Python38\site-packages\sympy\parsing\sympy_parser.py in parse_expr(s, local_dict, transformations, global_dict, evaluate)
   1015 
   1016     try:
-> 1017         rv = eval_expr(code, local_dict, global_dict)
   1018         # restore neutral definitions for names
   1019         for i in local_dict.pop(None, ()):

~\AppData\Roaming\Python\Python38\site-packages\sympy\parsing\sympy_parser.py in eval_expr(code, local_dict, global_dict)
    909     Generally, ``parse_expr`` should be used.
    910     """
--> 911     expr = eval(
    912         code, global_dict, local_dict)  # take local objects in preference
    913     return expr

<string> in <module>

CoolProp\HumidAirProp.pyx in CoolProp.CoolProp.HAPropsSI()

CoolProp\HumidAirProp.pyx in CoolProp.CoolProp.HAPropsSI()

TypeError: Numerical inputs to HAPropsSI must be ints, floats, lists, or 1D numpy arrays.

An example application would be to create an equation and solve for an unknown (Press, Temp, or RH) given the value of h:

eqn = Eq(sym_h, 50423.45)
nsolve(eqn, Press, 1e5)

What I am trying to accomplish is not so different from:

Python: Using sympy.sympify to perform a safe eval() on mathematical functions

Though I admit I am unclear on the details of the subclassing.

Thanks for any insights.

carowjp
  • 1
  • 1
  • 2
    I don't know this `CoolProp`, but the error suggests it is built on `numpy`. Don't try to mix `sympy` with `numpy` or other numeric packages. `sympy` creates symbolic expressions, which cannot, as rule, be used in numeric calculations. And numeric functions don't work in `sympy` expressions. – hpaulj Jan 30 '22 at 19:50
  • What did the first `h` display? Looks like the function expects strings and numeric arguments. `symbols` are not numeric. – hpaulj Jan 30 '22 at 21:48
  • It's not clear if this is possible. More information is needed about what `HAPropsSI` is. Also this might not be the best approach to solving whatever your original problem is. – Oscar Benjamin Jan 31 '22 at 00:19
  • @hpaulj I have edited the original post to add some clarifications. ps. I understand that HAPropsSI does not work with symbols. Can a generic function like h(P,T,RH) be used as a placeholder in the expressions and replaced when the numeric solution is needed? – carowjp Jan 31 '22 at 19:32
  • @OscarBenjamin Original post edited to add more detail on original problem. – carowjp Jan 31 '22 at 19:33
  • I think you are imagining that both sympy and coolprop have some magic capabilities that don't exist. The only point of sympifying the expression would be to creatre a symbolic representation of it but how would sympy get that information from coolprop which is just a numerical function? – Oscar Benjamin Jan 31 '22 at 21:31
  • @OscarBenjamin What I am trying to do is learn and solve a problem so unfortunately, your comment isn't very helpful. What I want to do is almost identical to the linked post regarding sympy with scipy's wofz function. However, instead of sympify("Wofz(2)",{'Wofz':Wofz}) I want to do sympify("Wofz(foo)",{'Wofz':Wofz}), where foo is a symbol to be given a value later and at some point evaluated to a numerical value. – carowjp Feb 18 '22 at 21:34
  • I think that you have misunderstood what the `sympify` function is for. If what you are trying to do is what is described in the linked post then why doesn't that approach work? (Note that it doesn't use sympify) – Oscar Benjamin Feb 19 '22 at 00:13

0 Answers0