1

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.

user11
  • 191
  • 1
  • 3
  • 11
  • is that the entire error message or is there more detail? If there is a traceback please show it. Also what version of python are you running and what version of sympy? It's possible you are using a version of sympy that uses syntax not valid in your version of python. – Tadhg McDonald-Jensen Jun 01 '17 at 20:04
  • Please check the minimal example I have provided now. – user11 Jun 01 '17 at 20:11

1 Answers1

3

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.

DavidP
  • 105
  • 3
  • 12
  • The question is why `lambdify` is not working for a large expression I obtain from sympy. Please try running the minimal example I have provided now. – user11 Jun 01 '17 at 20:13
  • Ran your code unchanged, and it lambdifies correctly on my machine. -- Only your final call of `q_IN_w_fn` does not work -- first of all, as you have set it up, it expects the arguments to come in an array. (Also, as currently set up, r_o IS an array - if you want braodcasting, i.e. evaluate the lamdbified function for each of those values, that's not going to work like this.) – DavidP Jun 01 '17 at 20:24
  • I am interested in finding a numerical value of the sympy expression, so that final call is one of the salient step. Regarding array/scalar value, I mentioned in a note at the end that you could take a single element of the array for a basic case. But, it does not work for that case either. – user11 Jun 01 '17 at 20:34
  • As I'm saying, the lambdified function works nicely for me. (Of course I can't say whether the output is as intended). See my edit for a working call of the function. (Edit: for clarification: In my earlier comment I was trying to say that your final line is not the correct way to call the function as you have constructed it.) – DavidP Jun 01 '17 at 20:42
  • Yes, what you suggest works. Can I ask follow-up questions please: i) the online manual for [lambdify](http://docs.sympy.org/dev/modules/utilities/lambdify.html) does not indicate using square brackets for the input, and ii) is there a way to use `r_o` as an array in input in order to get corresponding output array? – user11 Jun 01 '17 at 20:55
  • In the given case, the input has to be given as a np.array, because of the way you provided the arguments to lambdify: You there gave a tuple of your symbols. If you had run the second version in your OP -- without the extra brackets etc. -- the lambdified function would want the arguments provided without any extra brackets, such as `q_IN_w_fn(np.array([r_g, r_o[0], R, a_w, a_o, ... )`. I'll add another edit on getting a vector of outputs. – DavidP Jun 01 '17 at 21:04
  • 1
    I added how to vectorize your lambdified function. I also noted a typo in the last comment, the code part should have been `q_IN_w_fn( r_g, r_o[0], R, a_w, a_o, ... )`. Hope it didn't cause any confusion. – DavidP Jun 01 '17 at 21:22