用Python进行三重积分的数值计算

时间:2016-11-22 23:16:26

标签: python numpy numerical-methods integral numerical-integration

我非常需要计算this积分。我一直试图这样做几个月,使用Python中的numpy包,特别是integrate.tplquad函数。

from __future__ import division
from math import *
import numpy as np
import scipy.special as special
import scipy.integrate as integrate

a=1.e-19
b=1.e-09
zo=1.e7
H=1.e15

v=1.e18

def integrand(v,z,x,u):
    value=x**(-0.5)*special.kv(5/3,u)*(a*v*z/x-1/2.)*exp(-b*sqrt(z*v/x))
    return value

i=integrate.tplquad(lambda u,x,z: integrand(v,z,x,u),1.e7,1.e15,lambda z:0.,lambda z:np.inf, lambda x,z : x, lambda x,z : np.inf)

print i

在上面的代码中,我尝试了一个v = 10 ^ 18的值,以便规范化指数的参数,而不是得到太小或太大的系数。

然而,无论我插入什么价值,我总是得到

out: (0.0, 0.0)

我不知道如何超越这个问题。

我也尝试将指数函数扩展为幂级数,但我得到了相同的结果。

现在,我知道积分必须对所有v都有一个有限的正值。事实上,如果我可以为任何v计算它,我会很高兴。

如果有人遇到过类似的问题,如果他们能分享他们的智慧,我会很高兴。欢迎任何帮助。感谢。

1 个答案:

答案 0 :(得分:4)

首先,u和z积分可以完全解决。结果是涉及指数,伽马函数和广义超几何级数的相当复杂的函数。优点是它只在一个变量上,因此可以很容易地以图形方式进行检查。以下是针对\ nu:

的不同值的一些曲线

enter image description here

以下是表达式:

Iuz

集成功能非常方便,因为它可以更快,更准确地完成。但是,这是第二点,由于机器精度的原因,这会受到数值问题的影响,因为x - > \ inf文件。以下是一些清晰显示问题的图表:

Iuz_plot1

Iuz_plot2

当以任意工作精度进行绘图时,问题就会消失:

Iuz_plot3

因此,在Python下使用像mpmath这样的任意精度库,和/或通过忽略/丢弃积分区间的大腿,即在这种情况下通过例如,在0到19/20之间进行积分,而不是0和\ inf。

下面是一个Python程序,使用mpmath,在x = 0和x = 20之间集成上面的表达式(等效的)

#!/usr/bin/env python3
#encoding: utf

from mpmath import mp, mpf, sqrt, besselk, exp, quad, pi, hyper, gamma

maxprecision = 64 # significant digits
maxdegree    = 3  # maximum degree of the quadrature rule

mp.dps = maxprecision

# z0 = mpf(1.e7)
# H  = mpf(1.e15)
a  = mpf(1.e-19)
b  = mpf(1.e-9)

sqrt3 = sqrt(3.)
sqrt10 = sqrt(10.)
inf = mpf('inf')

epsilon=10.**-maxprecision

def integrand(z, x, u):
  value = 1./sqrt(x) * besselk(5./3, u) * (a*z*nu/x - 1./2) * exp(-b * sqrt(z*nu/x))
  return value

def integrand3(x):
  value = 1. / (960. * b**4 * x**(19./6) * (nu / x)**(3./2)) * exp(-10000000. * sqrt10 * b * sqrt(nu/x)) * (-b**2 * x * (1000. * sqrt10 * b * (-10000. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * nu + (-1. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * x * sqrt(nu/x)) + 4. * a * (3000. * sqrt10 * b * (-10000. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * x * nu + 5000000000. * sqrt10 * b**3 * (-1000000000000. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * nu**2 + 3. * (-1. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * x**2 * sqrt(nu/x) + 15000000. * b**2 * (-100000000. + exp(9999000. * sqrt10 * b * sqrt(nu/x))) * x * nu * sqrt(nu/x))) * (-320. * sqrt3 * pi * x**(2./3) + 960. * 2.**(2./3) * gamma(2./3) * hyper([-1./3], [-2./3, 2./3], x**2 / 4.) + 27. * 2.**(1./3) * x**(10./3) * gamma(-2./3) * hyper([4./3], [7./3, 8./3], x**2 / 4.))
  return value

for e in range(0, 19):
  nu = mpf(10**e)
#   I1 = quad(lambda x: quad(lambda u, z: integrand(z, x, u), [x, inf], [z0, H], method='tanh-sinh', maxdegree=maxdegree), [0., inf], method='tanh-sinh', maxdegree=maxdegree)
#   print("ν = 10^%d: NI(x, u, z) = %f" % (e, I1))
  I3 = quad(lambda x: integrand3(x), [0., 20.], method='tanh-sinh', maxdegree=maxdegree)
  print("ν = 10^%d: NI(x)       = %f" % (e, I3))
#   print("ν = 10^%d: error       = %.2f%% " % (e, (I3-I1)/(I1+epsilon)*100.))

结果是:

ν = 10^0: NI(x)       = -12118569382494810.000000
ν = 10^1: NI(x)       = -6061688705992958.000000
ν = 10^2: NI(x)       = -2359248732202052.500000
ν = 10^3: NI(x)       = -535994574128436.812500
ν = 10^4: NI(x)       = -26417279314541.281250
ν = 10^5: NI(x)       = 3636613281577.158203
ν = 10^6: NI(x)       = 416805025513.477356
ν = 10^7: NI(x)       = 41860949922.522430
ν = 10^8: NI(x)       = 4285965504.873075
ν = 10^9: NI(x)       = 477094892.498829
ν = 10^10: NI(x)       = 65240304.226613
ν = 10^11: NI(x)       = 9524738.222360
ν = 10^12: NI(x)       = 680659.198974
ν = 10^13: NI(x)       = 5287.165984
ν = 10^14: NI(x)       = 0.224778
ν = 10^15: NI(x)       = 0.000000
ν = 10^16: NI(x)       = -0.000000
ν = 10^17: NI(x)       = -0.000000
ν = 10^18: NI(x)       = -0.000000