“Add” object has no attribute “sinh” error in numerical and symbolic expression?

前端 未结 2 678
面向向阳花
面向向阳花 2021-01-16 19:00

Ultimately, my goal is to numerically differentiate the expression \'u\' (see code) with respect to t, with respect to X and three times with respect to X.

First ide

相关标签:
2条回答
  • 2021-01-16 19:35

    SymPy and NumPy are completely separate libraries. SymPy flourishes in the world of symbolic math and works with its own symbols for every part of mathematical expressions.

    The only place where SymPy and NumPy touch, is lambdify where everything is converted to NumPy symbols, ready to go number crunching.

    The function u doesn't need a symbol: it gets its SymPy representation via its definition based on t and X.

    The differentiation happens completely inside SymPy, e.g. diff(u, X, 3) calculates the third derivative of u with respect to X. simplify helps to reduce the size of the expression. However, the expression for du_ffffdX seems so long that simplification takes a huge amount of time. If you don't need to call the function millions of times, you can leave it without simplification.

    import numpy as np
    import sympy as sp
    c_1 = 1.35
    c_2 = 0.7
    X = sp.Symbol('X', real=True)
    t = sp.Symbol('t', real=True)
    u = 2*(c_1-c_2)*(c_1*(sp.cosh(sp.sqrt(c_2)*(X-c_2*t)/2))**2 + c_2*(sp.sinh(sp.sqrt(c_1)*(-X-c_1*t)/2))**2)/((sp.sqrt(c_1)-sp.sqrt(c_2))*sp.cosh((sp.sqrt(c_1)*(-X-c_1*t) + sp.sqrt(c_2)*(X-c_2*t))/2)+ (sp.sqrt(c_1)+sp.sqrt(c_2))*sp.cosh((sp.sqrt(c_1)*(-X-c_1*t)-sp.sqrt(c_2)*(X-c_2*t))/2))**2
    du_dt = sp.simplify(sp.diff(u, t))
    du_dX = sp.simplify(sp.diff(u, X))
    du_ffffdX = sp.diff(u, X, 3)
    #du_ffffdX = sp.simplify(du_ffffdX)
    
    U = sp.lambdify((X,t), u, "numpy")
    U1 = sp.lambdify((X,t), du_dt, "numpy")
    U2 = sp.lambdify((X,t), du_dX, "numpy")
    U3 = sp.lambdify((X,t), du_ffffdX, "numpy")
    
    # before this line, everything happened in SymPy
    # now the NumPy part starts
    
    Y = np.linspace(-20, 20, 20)
    T = np.linspace(-35, 35, 20)
    
    print(U(Y, T))
    print(U1(Y, T))
    print(U2(Y, T))
    print(U3(Y, T))
    

    Note that the linspace for Y and for T need to have the same size if you want to call the lambdified functions directly on them. You probably want to extend the 1D linspaces to a 2D mesh using np.meshgrid(). The mesh can have a different number of divisions in the two directions. An example with your function:

    import matplotlib.pyplot as plt
    Y = np.linspace(-20, 20, 100)
    T = np.linspace(-35, 35, 300)
    YY, TT = np.meshgrid(Y, T)
    z = U1(YY, TT)
    h = plt.contourf(Y,T,z)
    plt.show()
    

    PS: To convert the expressions to LaTeX, although the are quite long:

    print(sp.latex(du_dt))
    print(sp.latex(du_dX))
    
    0 讨论(0)
  • 2021-01-16 19:36

    u is sympy expression. U in python/numpy. The sp.sinh etc are translated to np.sinh etc.

    U(Y) evaluates this with the numpy array, but t is still a symbol. That produces a numpy object dtype array, with some sort of mix of numbers and symbols. np.sinh(x) is evaluated as [z.sinh() for z in x]. Since most objects, including symbols don't have a sinh method, this raises your error.

    I'm not sure about this, but I suspect you need to lambdify both X and t at once, and evaluate with (Y,T) together, rather than in two steps.

    (Later I may try to demonstrate this with a isympy session.)

    0 讨论(0)
提交回复
热议问题