Search code examples
pythonfunctionsympylambdify

SyntaxError converting sympy expression to a python function


I am trying to convert the sympy expression for q_IN_w_sym (very long expression that can't be accommodated here) into a python function so I can evaluate its numerical value. I checked the number of symbols in q_IN_w_sym by using q_IN_w_sym.atoms(sym.Symbol) and q_IN_w_sym.free_symbols, both of which give the same number of variables/symbols (13 in number). Following that, I tried using the suggestion in this answer to convert the sympy expression into a python function as follow:

q_IN_w = sym.lambdify(((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), ), \
    q_IN_w_sym)

However, I get the following error:

(*list(__flatten_args__([_0])))
                                       ^
SyntaxError: invalid syntax

I also tried the following command, but it gives the same error (though slightly different)

q_IN_w = sym.lambdify((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), q_IN_w_sym)

Error:

(*list(__flatten_args__([_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12])))
                                                              ^
SyntaxError: invalid syntax

Not sure what's the problem in above commands. Below, you can find a minimal example that you can run to see the problem I am facing:

from __future__ import division
import numpy as np
import sympy as sym

def deg_to_rad(theta_deg):
    theta_rad = (sym.pi/180)*theta_deg
    return theta_rad


def q_IN_NS_sym():
    #======= define variables as symbols
    r, a_w, a_o, a_g, b_IN_w, b_IN_o, b_IN_g, c_IN_2w, c_IN_2o, c_IN_2g, u_IN_w, u_IN_o, u_IN_g, r_g, r_o, R, \
    sigma_dia, IFT_ow, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, mu_w, deltaP = \
    sym.symbols('r, a_w, a_o, a_g, b_IN_w, b_IN_o, b_IN_g, c_IN_2w, c_IN_2o, c_IN_2g, u_IN_w, u_IN_o, u_IN_g, r_g, r_o, R, \
    sigma_dia, IFT_ow, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, mu_w, deltaP')

    #======= 
    l_IN_slip = sigma_dia/((sym.pi - deg_to_rad(theta_IN_CA_deg))**4)
    W_IN_egy = IFT_ow*(1 + sym.cos(deg_to_rad(theta_IN_CA_deg)))
    u_IN_s = (l_IN_slip*R*nablaP)/(2*mu_w)
    u_IN_ads = (D_IN_ads_coeff/W_IN_egy)*deltaP
    u_IN_s_eff = (u_IN_s - u_IN_ads)

    #======= parameter b
    b_IN_g = 0
    b_IN_o = 2*(a_g - a_o)*(r_g**2)
    b_IN_w = b_IN_o + 2*(a_o - a_w)*(r_o**2)

    #======= parameter c
    c_IN_2w = u_IN_s_eff - a_w*(R**2) - b_IN_w*sym.log(R)
    c_IN_2o = c_IN_2w - (a_o - a_w)*(r_o**2)*(1 - 2*sym.log(r_o))
    c_IN_2g = b_IN_o*sym.log(r_g) + c_IN_2o - (a_g - a_o)*(r_g**2)

    #======= 
    u_IN_w = a_w*(r**2) + b_IN_w*sym.log(r) + c_IN_2w
    u_IN_o = a_o*(r**2) + b_IN_o*sym.log(r) + c_IN_2o
    u_IN_g = a_g*(r**2) + b_IN_g*sym.log(r) + c_IN_2g

    #======= 
    q_IN_w = sym.integrate((u_IN_w)*(2*sym.pi*r), (r, r_o, R))
    q_IN_o = sym.integrate((u_IN_o)*(2*sym.pi*r), (r, r_g, r_o))
    q_IN_g = sym.integrate((u_IN_g)*(2*sym.pi*r), (r, 0, r_g))

    return q_IN_w, q_IN_o, q_IN_g


#========= get sympy expression
q_IN_w_sym, q_IN_o_sym, q_IN_g_sym = q_IN_NS_sym()
q_IN_w_sym.atoms(sym.Symbol)

#========= change sympy expression to a python function
r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP = \
sym.symbols('r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP')
q_IN_w_fn = sym.lambdify(((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), ), \
q_IN_w_sym)

#======= constants
mu_w, mu_o, mu_g = 1e-3, 43-3, 2e-5
R = 10e-06 
M_g, R_gas, g = 16e-3, 8.314, 9.80
P_avg, T = 3.0e+6, 275
D_IN_m, s_IN, D_OR_m, s_OR = 1e-8, 2*R, 1e-7, 2*R
deltaP = 1.5e+6
L = 0.5
nablaP = (deltaP/L)

a_w = (-nablaP)/(4*mu_w)
a_o = (-nablaP)/(4*mu_o)
a_g = (-nablaP)/(4*mu_g)

IFT_ow = 0.05 
theta_IN_CA_deg, theta_OR_CA_deg = 15, 10
sigma_dia = 1e-9
D_IN_ads_coeff = 1e-8 
D_OR_ads_coeff = 1e-8 
tmp = np.linspace(1e-06, 1 - 0.01 - 0.2, num=50)
r_g = np.sqrt((R**2)*0.01)
r_o = np.sqrt((R**2)*(0.01 + tmp))

#========= calculate numerical value of lambdified sympy function
q_IN_w_num = q_IN_w_fn(r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP)

Note: Although I am interested in using an array as an input (r_o in this case), even taking its single element as an input throws an error. Also, in order to reproduce a simple example here, the error is different, but the problem of finding a numerical value still persists.


Solution

  • I don't think it's the commands themselves; for me both work fine.

    vars = sym.symbols("r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP")
    
    r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP = vars
    
    q_IN_w_sym = sum(vars)
    

    (The above just defines sympy vars with the according names taken from your post, and an expression made from them for demonstration).

    Now I run your line:

    q_IN_w = sym.lambdify(((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), ), q_IN_w_sym)
    In [50]: q_IN_w([1]*13)
    Out[50]: 13
    

    Or the second:

    q_IN_w = sym.lambdify((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), q_IN_w_sym)
    
    In [53]: q_IN_w(*[1]*13)
    Out[53]: 13
    

    So it should work as you state it, I believe. You should be able to just run the code I pasted to see whether you still get the errors. Maybe the problem is somewhere else in your code? Did you check whether all of the variables you pass as arguments are actually sympy symbols?


    Edit: Ran the now pasted code, runs fine for me, except the final call; if I do this:

    q_IN_w_num = q_IN_w_fn(np.array([r_g, r_o[0], R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP]))
    

    I get

    In [18]: q_IN_w_num
    Out[18]: -2.5016487930770088e-11
    

    Edit2:

    How to get your function to work with the array r_o as input, and output a value for each of its elements:

    First, I suggest to change the step a little where you lambdify your function. Rather than the line you have, use:

    q_IN_w_fn = sym.lambdify((r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP), q_IN_w_sym)
    

    Now you set up a vectorized version of this function. Add this line, fter the previous one:

    q_IN_w_vec = np.vectorize(q_IN_w_fn)
    

    And now, at the very end, you can call the vectorized function like you originally intended to:

    q_IN_w_vec(r_g, r_o, R, a_w, a_o, a_g, mu_w, IFT_ow, sigma_dia, theta_IN_CA_deg, D_IN_ads_coeff, nablaP, deltaP)
    

    The output is now an array with one function value for each element in r_o.