我目前正在用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个问题:
我从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,我仍然会收到此错误消息...鉴于被积函数是非常简单的函数,这特别奇怪...
所以,最后,我的问题是:有什么明显的方法可以优化此代码以使其运行得更快(除了将其编译为C +或类似的东西之外)?我尝试将所有浮点数都减少到6位(我的精度不能降低),但没有任何改变。
更新:进一步研究它,我发现大部分时间实际上并没有被Integration本身占用,而是由我以前进行插值的CubicSpline
操作占用了我的数据。我尝试了不同的方法,由于某种原因,CubicSpline
似乎是唯一可行的方法(即使我的数据单调增加,我尝试的所有其他方法也都出错了,并指出某些值高于或低于该值。插值范围)。也就是说,直到我发现外推with scipy.interpolate.interp1d
和(fill_value = 'extrapolate'
为止。这为我解决了问题,使我能够使用耗费更少的interp1d
方法,并有效地将程序的运行时间从280秒减少到49秒(还为w
和{{1}添加了列表理解功能) }。尽管这是一个很大的改进,但我仍然想知道为什么我的程序需要近1分钟来计算一些积分...而我仍然得到上面提到的e
。因此,任何建议都将受到高度赞赏!
(顺便说一句,因为我对python还是很陌生,所以我对我能得到的任何提示或批评感到高兴!)