我正在使用以下代码为spherical harmonics functions Y_l ^ m(在整个球体上标准化为4-pi)及其theta衍生物创建符号Sympy表达式,然后想要对它们进行均匀评估θ和phi坐标中的间隔网格:
import numpy as np
from math import pi, cos, sin
import sympy
from sympy import Ynm, simplify, diff, lambdify
from sympy.abc import n,m,theta,phi
resol = 2.5
dtheta_rad_ylm = -resol * pi/180.0
dphi_rad_ylm = resol * pi/180.0
thetaarr_rad_ylm_symm = np.arange(pi+dtheta_rad_ylm/2.0,dtheta_rad_ylm/2.0,dtheta_rad_ylm)
phiarr_rad_ylm = np.arange(0.0,2*pi,dphi_rad_ylm)
phi_grid_rad_ylm, theta_grid_rad_ylm_symm = np.meshgrid(phiarr_rad_ylm, thetaarr_rad_ylm_symm)
lmax = len(thetaarr_rad_ylm_symm)/2 - 1
nmax = (lmax+1)*(lmax+2)/2
ylms_symm_full = np.zeros((lmax+1, lmax+1, len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((lmax+1, lmax+1, len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
for n in np.arange(0,lmax+1):
for m in np.arange(0,n+1):
print "generating resol %s, y_%d_%d" % (resol,n,m)
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(n,m,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
# activate and deactivate comments for second-question-related error
# error appears later than the first-question-related error!
ylm_lambda = lambdify((theta,phi), sympy.N(ylm_symbolic), "numpy")
dylm_lambda = lambdify((theta,phi), sympy.N(dylm_symbolic), "numpy")
# ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
# dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
# activate and deactivate comments for first-question-related error
ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
dylm_symm_full = np.asarray(dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
# ylm_symm_full = ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
# dylm_symm_full = dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
if n == 0 and m == 0:
ylm_symm_full = np.tile(ylm_symm_full, (len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylm_symm_full = np.tile(dylm_symm_full, (len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[n,m,:,:] = np.real(ylm_symm_full)
dylms_symm_full[n,m,:,:] = np.real(dylm_symm_full)
还有其他一些软件包提供了生成数字Y_l ^ m而没有符号表达式的功能,例如scipy.special.sph_harm。然而,对我来说,获得一个"确切的"衍生物,即不使用任何数值微分方法,例如,有限差分(np.gradient)。因此,在获得Y_l ^ m的符号公式并尽可能地简化那些""之后,使用numpy后端创建lambda函数(以便能够进行矢量化计算),然后在网格。最后我只需要球谐波的真实部分(我知道我也可以用Znm而不是Ynm创建真正的球谐波,但是......)。
两个问题:
np.sqrt(9L) = 3.0
),但在这种情况下,会出现一条错误消息,指出 long对象没有属性sqrt 。我想这也与lambda函数生成有关。是否有任何方法可以告诉Sympy每次都以浮点格式给出符号表达式?或者,更好的是,以某种方式修改lambdify调用?如果要检查这些问题,代码块应该是独立且可测试的。只需删除sympy.N和np.asarray表达式。第一个问题涉及前面出现的错误。 Y_l ^ m生成到lmax,这是35,大约需要10-15分钟。
提前感谢您的帮助!
更新:以下是一些最小,完整且可验证的示例。两者都请导入所需的包:
import numpy as np
from math import pi, cos, sin
import sympy
from sympy import Ynm, simplify, diff, lambdify
from sympy.abc import n,m,theta,phi
错误#1:对象dtype问题= = 31,m = 1:
# minimal, complete and verifiable example (MCVe) #1
# error message:
#---> 43 dylms_symm_full[n,m,:,:] = np.real(dylm_symm_full)
#TypeError: can't convert complex to float
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(31,1,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
ylm_symm_full = ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
dylm_symm_full = dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm)
ylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[:,:] = np.real(ylm_symm_full)
dylms_symm_full[:,:] = np.real(dylm_symm_full)
print ylm_symm_full
print dylm_symm_full
错误#2: n = 32时长sqrt属性问题,m = 29:
# minimal, complete and verifiable example (MCVe) #2
# error message:
#---> 33 ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
#/opt/local/anaconda/anaconda-2.2.0/lib/python2.7/site-packages/numpy/__init__.pyc in <lambda>(_Dummy_4374, _Dummy_4375)
#AttributeError: 'long' object has no attribute 'sqrt'
ylm_symbolic = simplify(2 * sympy.sqrt(sympy.pi) * Ynm(32,29,theta,phi).expand(func=True))
dylm_symbolic = simplify(diff(ylm_symbolic, theta))
ylm_lambda = lambdify((theta,phi), ylm_symbolic, "numpy")
dylm_lambda = lambdify((theta,phi), dylm_symbolic, "numpy")
ylm_symm_full = np.asarray(ylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
dylm_symm_full = np.asarray(dylm_lambda(theta_grid_rad_ylm_symm, phi_grid_rad_ylm), dtype=complex)
ylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
dylms_symm_full = np.zeros((len(thetaarr_rad_ylm_symm), len(phiarr_rad_ylm)))
ylms_symm_full[:,:] = np.real(ylm_symm_full)
dylms_symm_full[:,:] = np.real(dylm_symm_full)
print ylm_symbolic # the symbolic Y_32^29 expression
print type(175844649714253329810) # the number that causes the problem
答案 0 :(得分:0)
为什么你的代码偶尔产生一个对象数组的问题并不是我们在没有MCVe的情况下不能轻易回答的问题 - 它不可能偶尔发生,它必须是可重现的。
但是,如果数组是对象,则可以使用
轻松转换为复数arr.astype(np.complex)
使用copy=False
参数,您可以将其应用于所有结果而无需太多计算成本。
arr.astype(np.complex, copy=False).real
对象版本的元素不是元组;它们是标量复杂的值,只是以这种方式打印。
In [187]: arr=np.random.rand(3)+np.random.rand(3)*1j
In [188]: arrO=arr.astype(object)
In [189]: arrO
Out[189]:
array([(0.6129476673822528+0.09323924558124808j),
(0.9540542895309456+0.81929476753951j),
(0.8068967867200485+0.9494305517611881j)], dtype=object)
In [190]: type(arrO[0])
Out[190]: complex
In [191]: arr.real
Out[191]: array([ 0.61294767, 0.95405429, 0.80689679])
In [193]: arrO[0]
Out[193]: (0.6129476673822528+0.09323924558124808j)
In [194]: arrO.astype(np.complex).real
Out[194]: array([ 0.61294767, 0.95405429, 0.80689679])
某些数学运算会对对象数组的元素进行“渗透”,但real
不是其中之一。所以当你注意到np.real(arrO)
没有产生你想要的东西时。
仔细查看您的代码,包括滚动屏幕的内容,我看到您正在使用:
np.asarray(dylm_lambda(...), dtype=complex)
这与我的astype(complex, copy=False)
相同。
对于已经很复杂的阵列,计算成本很低。对于一个对象数组,它必须创建一个新数组,并且成本更高。但是,如果你无法通过sympy
计算出创建对象数组,那么你必须承担成本。