Scipy integrate.quad不返回预期值

时间:2016-11-10 20:30:29

标签: python numpy scipy numerical

我有以下功能,我想用python,

进行数字整合

enter image description here

使用scipy,我写了这段代码:

def voigt(a,u):

fi = 1
er = Cerfc(a)*np.exp(np.square(a))
c1 = np.exp(-np.square(u))*np.cos(2*a*u)
c1 = c1*er  #first constant term
pis = np.sqrt(np.pi) 

c2 = 2./pis    #second constant term    

integ  = inter.quad(lambda x: np.exp(-(np.square(u)-   
 np.square(x)))*np.sin(2*a*(u-x)), 0, u)

print integ
ing = c1+c2*integ[0]

return ing

对于Cerfc(a)函数,我只使用scipy.erfc来计算互补误差函数。

所以这个函数对于u的低值非常有效,但是大的u值(超过60 ish)会破坏代码并且我的数字非常小。例如,如果我输入a = 0.01且u = 200,则结果为1.134335928072937e-40,其中的真实答案为:1.410526851411200e-007

除此之外,四元组计算的错误scipy返回与答案的顺序相似。我真的很难过,真的很感激帮助。

这是一项家庭作业,但这是一门物理课程。所以这个计算只是物理学中一个更广泛问题的一步。如果你帮助我,你不会帮我作弊:)

1 个答案:

答案 0 :(得分:1)

根据维基百科文章Voigt profileVoigt functions U(x,t)和V(x,t)可以用复数Faddeeva function w(z)表示:

U(x,t) + i*V(x,t) = sqrt(pi/(4*t))*w(i*z)

Voigt函数H(a,u)可以用U(x,t)表示为

H(a,u) = U(u/a, 1/(4*a**2))/(a*sqrt(pi))

(另请参阅DLMF section on Voigt functions。)

scipyscipy.special.wofz中实现了Faddeeva功能。 使用它,这是Voigt函数的实现:

from __future__ import division

import numpy as np
from scipy.special import wofz


_SQRTPI = np.sqrt(np.pi)
_SQRTPI2 = _SQRTPI/2

def voigtuv(x, t):
    """
    Voigt functions U(x,t) and V(x,t).

    The return value is U(x,t) + 1j*V(x,t).
    """
    sqrtt = np.sqrt(t)
    z = (1j + x)/(2*sqrtt)                    
    w = wofz(z) * _SQRTPI2 / sqrtt
    return w

def voigth(a, u):
    """
    Voigt function H(a, u).
    """
    x = u/a
    t = 1/(4*a**2)
    voigtU = voigtuv(x, t).real
    h = voigtU/(a*_SQRTPI)
    return h

你说你知道当a = 0.01和u = 200时,H(a,u)的值是1.410526851411200e-007。我们可以查看:

In [109]: voigth(0.01, 200)
Out[109]: 1.41052685142231e-07

以上内容并未回答u较大时代码无效的原因。要成功使用quad,最好是充分了解您的被积函数。在您的情况下,当u很大时,x = u附近只有非常小的间隔对积分做出了重要贡献。 quad没有检测到这一点,因此它错过了积分的很大一部分并返回了一个太小的值。

解决此问题的一种方法是使用points的{​​{1}}参数,其中一个点非常接近间隔的终点。例如,我将quad的调用更改为:

quad

有了这个改变,这就是你的函数为integ = inter.quad(lambda x: np.exp(-(np.square(u)-np.square(x))) * np.sin(2*a*(u-x)), 0, u, points=[0.999*u]) 返回的内容:

voigt(0.01, 200)

我对价值In [191]: voigt(0.01, 200) Out[191]: 1.4105268514252487e-07 没有严格的理由;这只是一个足够接近间隔结束的点,为大约200左右的0.999*u提供合理的答案。对被积函数的进一步调查可以为您提供更好的选择。 (例如,你能找到一个关于被积函数最大值位置的解析表达式吗?如果是这样,那将比u好得多。)

您还可以尝试调整0.999*uepsabs的值,但在我的几个实验中,添加epsrel参数产生了最大的影响。