Python Scipy:加速二维复积分的计算

Python Scipy:加速二维复积分的计算,python,numpy,scipy,integration,complex-numbers,Python,Numpy,Scipy,Integration,Complex Numbers,我想使用scipy.integrate中的dblquad重复计算二维复积分。由于评估的数量将相当高,我想提高我的代码的评估速度 DBLQUARD似乎无法处理复杂的被积函数。因此,我将复被积函数分为实部和虚部: def integrand_real(x, y): R1=sqrt(x**2 + (y-y0)**2 + z**2) R2=sqrt(x**2 + y**2 + zxp**2) return real(exp(1j*k*(R1-R2)) * (-1j*z/lam/R

我想使用scipy.integrate中的dblquad重复计算二维复积分。由于评估的数量将相当高,我想提高我的代码的评估速度

DBLQUARD似乎无法处理复杂的被积函数。因此,我将复被积函数分为实部和虚部:

def integrand_real(x, y):
    R1=sqrt(x**2 + (y-y0)**2 + z**2)
    R2=sqrt(x**2 + y**2 + zxp**2)
    return real(exp(1j*k*(R1-R2)) * (-1j*z/lam/R2/R1**2) * (1+1j/k/R1))

def integrand_imag(x,y):
    R1=sqrt(x**2 + (y-y0)**2 + z**2)
    R2=sqrt(x**2 + y**2 + zxp**2)
    return imag(exp(1j*k*(R1-R2)) * (-1j*z/lam/R2/R1**2) * (1+1j/k/R1))
y0、z、zxp、k和lam是预先定义的变量。要计算半径为ra的圆面积上的积分,请使用以下命令:

from __future__ import division
from scipy.integrate import dblquad
from pylab import *

def ymax(x):
    return sqrt(ra**2-x**2)

lam = 0.000532
zxp = 5.
z = 4.94
k = 2*pi/lam
ra = 1.0

res_real = dblquad(integrand_real, -ra, ra, lambda x: -ymax(x), lambda x: ymax(x))
res_imag = dblquad(integrand_imag, -ra, ra, lambda x: -ymax(x), lambda x: ymax(x))
res = res_real[0]+ 1j*res_imag[0]
根据轮廓仪,这两个被积函数的评估次数约为35000次。总的计算大约需要一秒钟,这对于我心目中的应用程序来说太长了

我是一名使用Python和Scipy进行科学计算的初学者,如果有评论指出提高计算速度的方法,我会很高兴。有没有办法重写被积函数实函数和被积函数复函数中的命令,从而显著提高速度


使用Cython之类的工具编译这些函数有意义吗?如果是:哪个工具最适合此应用程序?

您考虑过多处理(多线程)吗?似乎您不需要(在整个集合上)进行最终集成,因此简单的并行处理可能是答案。即使必须进行集成,也可以等待运行的线程完成计算,然后再进行最终集成。也就是说,可以阻止主线程,直到所有工作线程都完成


使用Cython可以获得约10倍的速度,请参见以下内容:

In [87]: %timeit cythonmodule.doit(lam=lam, y0=y0, zxp=zxp, z=z, k=k, ra=ra)
1 loops, best of 3: 501 ms per loop
In [85]: %timeit doit()
1 loops, best of 3: 4.97 s per loop
这可能是不够的,坏消息是这可能是不够的 C/Fortran速度非常接近(最多可能是2倍) ---如果使用相同的算法进行自适应积分。(scipy.integrate.quad) 它本身已经是Fortran语言了。)

<> P>为了进一步,你需要考虑不同的方法来做。 整合。这需要一些思考——我们不能提供太多 现在我的头顶

或者,您可以减小积分的最大公差 进行了评估

# Do in Python # # >>> import pyximport; pyximport.install(reload_support=True) # >>> import cythonmodule cimport numpy as np cimport cython cdef extern from "complex.h": double complex csqrt(double complex z) nogil double complex cexp(double complex z) nogil double creal(double complex z) nogil double cimag(double complex z) nogil from libc.math cimport sqrt from scipy.integrate import dblquad cdef class Params: cdef public double lam, y0, k, zxp, z, ra def __init__(self, lam, y0, k, zxp, z, ra): self.lam = lam self.y0 = y0 self.k = k self.zxp = zxp self.z = z self.ra = ra @cython.cdivision(True) def integrand_real(double x, double y, Params p): R1 = sqrt(x**2 + (y-p.y0)**2 + p.z**2) R2 = sqrt(x**2 + y**2 + p.zxp**2) return creal(cexp(1j*p.k*(R1-R2)) * (-1j*p.z/p.lam/R2/R1**2) * (1+1j/p.k/R1)) @cython.cdivision(True) def integrand_imag(double x, double y, Params p): R1 = sqrt(x**2 + (y-p.y0)**2 + p.z**2) R2 = sqrt(x**2 + y**2 + p.zxp**2) return cimag(cexp(1j*p.k*(R1-R2)) * (-1j*p.z/p.lam/R2/R1**2) * (1+1j/p.k/R1)) def ymax(double x, Params p): return sqrt(p.ra**2 + x**2) def doit(lam, y0, k, zxp, z, ra): p = Params(lam=lam, y0=y0, k=k, zxp=zxp, z=z, ra=ra) rr, err = dblquad(integrand_real, -ra, ra, lambda x: -ymax(x, p), lambda x: ymax(x, p), args=(p,)) ri, err = dblquad(integrand_imag, -ra, ra, lambda x: -ymax(x, p), lambda x: ymax(x, p), args=(p,)) return rr + 1j*ri #用Python做什么 # #>>>导入pyximport;pyximport.install(重新加载支持=True) #>>>导入cythonmodule cimport numpy作为np 西姆波特赛顿酒店 “complex.h”中的cdef外部: 双复合物csqrt(双复合物z)nogil 双复形cexp(双复形z)nogil 双C(双复合z)nogil 双cimag(双复合z)nogil 来自libc.math cimport sqrt 从scipy.integrate导入dblquad cdef类参数: cdef公共双林,y0,k,zxp,z,ra 定义初始值(self,lam,y0,k,zxp,z,ra): self.lam=lam self.y0=y0 self.k=k self.zxp=zxp self.z=z self.ra=ra @cython.cdivision(真) def被积函数_实(双x,双y,参数p): R1=sqrt(x**2+(y-p.y0)**2+p.z**2) R2=sqrt(x**2+y**2+p.zxp**2) 返回creal(cexp(1j*p.k*(R1-R2))*(-1j*p.z/p.lam/R2/R1**2)*(1+1j/p.k/R1)) @cython.cdivision(真) def被积函数(双x,双y,参数p): R1=sqrt(x**2+(y-p.y0)**2+p.z**2) R2=sqrt(x**2+y**2+p.zxp**2) 返回cimag(cexp(1j*p.k*(R1-R2))*(-1j*p.z/p.lam/R2/R1**2)*(1+1j/p.k/R1)) def ymax(双x,参数p): 返回sqrt(p.ra**2+x**2) def doit(lam、y0、k、zxp、z、ra): p=参数(lam=lam,y0=y0,k=k,zxp=zxp,z=z,ra=ra) rr,err=dblquad(被积函数实-ra,ra,lambda x:-ymax(x,p),lambda x:ymax(x,p),args=(p,) ri,err=dblquad(被积函数_imag,-ra,ra,lambda x:-ymax(x,p),lambda x:ymax(x,p),args=(p,) 返回rr+1j*ri (我的一个项目)支持多种磁盘功能集成方案。它支持复数函数,并且完全矢量化。例如,第83号命令:

从numpy导入sqrt、pi、exp
导入四边形
lam=0.000532
zxp=5.0
z=4.94
k=2*pi/lam
ra=1.0
y0=0.0
def f(X):
x、 y=x
R1=sqrt(x**2+(y-y0)**2+z**2)
R2=sqrt(x**2+y**2+zxp**2)
返回经验(1j*k*(R1-R2))*(-1j*z/lam/R2/R1**2)*(1+1j/k/R1)
scheme=quadpy.disk.peirce_1957(20)
val=方案积分(f[0.0,0.0],ra)
打印(val)

你的函数在x中是偶数。只需将积分限制更改为
(0,ra)
即可将计算时间减少一半以上。出色的注释Jaime!我只是跟着,现在是原来计算时间的50%。谢谢谢谢你的建议。我想计算空间中各个点的积分,所有这些计算相互独立。因此,我非常乐观,我将能够在我的代码的下一个版本中实现多处理。哇,这就是我一直在寻找的答案。我绝对不希望有人像你那样严格地重写我的代码。非常感谢你!明天早上我将首先测试你的代码。一个问题:代码的最后几行被截断了。args=(p)正确吗?我花了一些时间让编译器运行,但这是值得的。代码现在运行速度快了十倍。再次感谢!
(18.57485726096671+9.619636385589759j)