Python使用scipy.integrate.quad优化计算(需要很长时间)

时间:2018-10-24 16:58:09

标签: python scipy

我目前正在用python编写一个程序,用于根据通过测量材料的定向半球发射率获得的测量数据,计算不同温度(200K-500K)下任何给定材料的总光谱发射率(红外波)使用红外分光镜在许多不同的波长下使用Plancks定律作为加权函数,通过对所有波长上的测量强度进行积分来完成计算(这对我自己的问题本身并不重要;我只想解释一下背景知识,以便使代码更易于理解) 。这是我的代码:

from scipy import integrate
from scipy.interpolate import CubicSpline
import numpy as np
import math as m


def planck_blackbody(lambda_, T):  # wavelength, temperature
    h = float(6.6260755e-34)
    c = float(2.99792458e+8)
    k = float(1.380658e-23)
    try:
        a = 2.0 * h * (c ** 2)
        b = h * c / (lambda_ * k * T)
        intensity = a / ((lambda_ ** 5) * (m.exp(b) - 1.0))
        return float(intensity)
    except OverflowError:  # for lower temperatures
        pass


def spectral_emissivity(emifilename, t, lambda_1, lambda_2):
    results = []

    with open(emifilename, 'r') as emifile:
       emilines = emifile.readlines()
       try:
           w = [float(x.split('\t')[0].strip('\n')) * 1e-6 for x in emilines]
           e = [float(x.split('\t')[1].strip('\n')) for x in emilines]
       except ValueError:
           pass
    w = np.asarray(w)  # wavelength
    e = np.asarray(e)  # measured intensity

    def part_1(lambda_, T):
        E = interp1d(w, e, fill_value = 'extrapolate')(lambda_)
        return E * planck_blackbody(lambda_, T)

    def E_complete(T):
        E_complete_part_1 = integrate.quad(part_1, lambda_1, lambda_2, args=T, limit=50)
        E_complete_part_2 = integrate.quad(planck_blackbody, lambda_1, lambda_2, args=T, limit=50)
        return E_complete_part_1[0] / E_complete_part_2[0]

    for T in t:
        results.append([T, E_complete(T)])

    with open("{}.plk".format(emifilename[:-4]), 'w') as resultfile:
        for item in results:
            resultfile.write("{}\t{}\n".format(item[0], item[1]))

t = np.arange(200, 501, 1)
spectral_emissivity('C:\test.dat', t, 1.4e-6, 35e-6)

测得的强度存储在具有两列的文本文件中,第一列是红外线的波长,第二列是在该波长下被测材料的定向半球发射率。

当我运行这段代码时,虽然它产生正确的结果,但我仍然遇到2个问题:

  1. 我从scipy.integrate.quad收到一条错误消息:

      IntegrationWarning: The maximum number of subdivisions (50) has been achieved.
      If increasing the limit yields no improvement it is advised to analyze 
      the integrand in order to determine the difficulties.  If the position of a 
      local difficulty can be determined (singularity, discontinuity) one will 
      probably gain from splitting up the interval and calling the integrator 
      on the subranges.  Perhaps a special-purpose integrator should be used.
      warnings.warn(msg, IntegrationWarning)
    

有人可以向我解释这到底是什么意思吗?我知道Integrated.quad是一种数值迭代方法,我的函数似乎需要进行50次以上的迭代,但是有没有解决的办法?我尝试增加限制,但即使使用200,我仍然会收到此错误消息...鉴于被积函数是非常简单的函数,这特别奇怪...

  1. 与第一个问题密切相关:该程序需要花一些时间(大约5分钟!)来完成一个文件,但是我每小时需要处理多个文件。 cProfile显示此时间的98%用于集成功能。 MathCad程序执行完全相同的操作并产生相同的输出仅需花费几秒钟即可完成。即使我花了上个星期的时间来寻求解决方案,但我只是没有设法加快该程序的速度,而且在stackoverflow和其他地方,没有其他人似乎对Integrated.quad有类似的时间问题。

所以,最后,我的问题是:有什么明显的方法可以优化此代码以使其运行得更快(除了将其编译为C +或类似的东西之外)?我尝试将所有浮点数都减少到6位(我的精度不能降低),但没有任何改变。

更新:进一步研究它,我发现大部分时间实际上并没有被Integration本身占用,而是由我以前进行插值的CubicSpline操作占用了我的数据。我尝试了不同的方法,由于某种原因,CubicSpline似乎是唯一可行的方法(即使我的数据单调增加,我尝试的所有其他方法也都出错了,并指出某些值高于或低于该值。插值范围)。也就是说,直到我发现外推with scipy.interpolate.interp1d(fill_value = 'extrapolate'为止。这为我解决了问题,使我能够使用耗费更少的interp1d方法,并有效地将程序的运行时间从280秒减少到49秒(还为w和{{1}添加了列表理解功能) }。尽管这是一个很大的改进,但我仍然想知道为什么我的程序需要近1分钟来计算一些积分...而我仍然得到上面提到的e。因此,任何建议都将受到高度赞赏!

(顺便说一句,因为我对python还是很陌生,所以我对我能得到的任何提示或批评感到高兴!)

0 个答案:

没有答案