Brent的方法包含在while循环中

时间:2016-11-20 14:08:14

标签: python python-2.7

我正在尝试使用python 2来解决一个非常复杂的函数,该函数依赖于两个变量ne_b和T,使用Brent的scipy方法。为了确保输入功能的准确性,我将其分解为几个函数,所有变量都是ne_b。对于某个温度T,我已经成功地使用布伦特的方法来找到主函数f的最小值。

现在,我想在f(ne_b)= 0时找到ne_b的解,但是对于不同的温度值。所以我创建了一个超过1500的交互循环< t_3< 25000,并列出了完全相同的功能,仅重命名以避免冗余,因此对于每个值t_3,计算ne_b的新函数。

整个代码:

import scipy.optimize as op
from scipy.optimize import fsolve 
from scipy.optimize import minimize_scalar
from scipy.optimize import bisect

#Defining constants for computation.
kB = 8.6173303e-5 # eV/K
k = 1.38065e-16 #dyne * cm / K
a = 7.566e-15 #erg cm^-3 K^-4
Rn = 13.598 #eV
X = 0.71
Y = 0.27
Z = 0.02
me = 9.110e-28 #grams
ma = 1.661e-24 #grams
C = 4.83e15 #Saha constant in cm^-3 K^-3/2
He_1 = 24.5873876 #Ionization potential of helium in eV.
He_2 = 54.4177630 #Ionization potential of ionized helium in eV.
Ca_1 = 6.113158 #ionization potential of neutral calcium in eV.
Ca_2 = 11.87172 #Ionization potential of ionized calcium.
T=[] #Temperature in kelvin. 
#U_11=0 #Partition function for neutral hydrogen.
U_21 = 1. #Partition function for ionized hydrogen.
U_12 = 1. #Partition function for neutral helium.
U_22 = 1.9999 #Partition function for ionized helium.
U_32 = 1. #Partition function of doubly ionized helium.
#U_120=0 #Partition function for neutral calcium.
#U_220=0 #Partition function for ionized calcium.
U_320 = 1. #Partition function for doubly ionized calcium.
P_gas = 100. #dyne cm^-2
A_1 = 1.00790 #Atomic mass of hydrogen.
A_2 = 4.00260 #Atomic mass of helium.
A_20 = 40.08 #Atomic mass of calcium. 
a_1 = float((X/A_1) / ((X/A_1) + (Y/A_2) + (Z/A_20))) 
a_2 = float((Y/A_2) / ((X/A_1) + (Y/A_2) + (Z/A_20)))
a_20 = float((Z/A_20) / ((X/A_1) + (Y/A_2) + (Z/A_20)))
mu_n = float(1. / ((X/A_1) + (Y/A_2) + (Z/A_20)))

#Defining arrays for problem 3 plots. 
N = [] #total number density of gas.
T_3 = [] #Temperature in kelvin.
ne_3 = [] #Brent-solved electron density.


t_3 = 1500 #Kelvin.
while t_3 <= 25000:
    xp20 = [100, 2520, 2800, 3150, 3600, 4200, 5040, 6300, 8400, 12600, 25200]
    fp11 = [1.9999, 1.9999, 1.9999, 1.9999, 1.9999, 1.9999, 1.9999, 1.9999, 1.9999, 2.0091, 2.3334]
    U_11b = np.interp(t_3, xp20, fp11)

    fp120 = [1, 1, 1.0023, 1.0069, 1.02329, 1.06660, 1.183, 1.5171, 2.9174, 21.4783, 172981.636]
    U_120b = np.interp(t_3, xp20, fp120)

    fp220 = [1.9999, 1.9999, 2.0045, 2.0137, 2.037, 2.0893, 2.208, 2.4604, 3.0409, 4.5499, 6.6834]
    U_220b = np.interp(t_3, xp20, fp220) #Partition function of ionized calcium.

    n_3 = (P_gas) / (k*t_3) #Finding total number density.
    N.append(n_3)

    #Neutral hydrogen.
    prod_11b = Rn / (kB * t_3)
    exp_11b = np.exp(-prod_11b)
    def Y_11b(ne_b):
            return (1/ne_b) * (C*t_3**1.5*(U_21 / U_11b)*exp_11b)
    def f_11b(ne_b):
            return (1 + Y_11b(ne_b))**-1

    #Ionized hydrogen.
    def f_21b(ne_b):
            return Y_11b(ne_b) / (1 + Y_11b(ne_b))

    #Neutral helium.
    prod_12b = He_1 / (kB * t_3)
    exp_12b = float(np.exp(-prod_12b))
    def Y_12b(ne_b):
            return (1/ne_b) * (C * t_3**1.5 * (U_22 / U_12) * exp_12b)

    #Ionized helium.
    prod_22b = He_2 / (kB * t_3)
    exp_22b = float(np.exp(-prod_22b))
    def Y_22b(ne_b):
            return (1/ne_b) * (C * t_3**1.5 * (U_32 / U_22) * exp_22b)

    #For neutral helium.
    def f_12b(ne_b):
            return (1 + Y_12b(ne_b) + Y_22b(ne_b)*Y_12b(ne_b))**-1

    #Final ionized helium expression.
    def f_22b(ne_b):
            return Y_12b(ne_b) * (1 + Y_12b(ne_b) + (Y_12b(ne_b) * Y_22b(ne_b)))**-1

    #Doubly ionized helium.
    def f_32b(ne_b):
            return (Y_22b(ne_b) * Y_12b(ne_b)) / (1 + Y_12b(ne_b) + (Y_22b(ne_b) * Y_12b(ne_b)))

    #Neutral calcium.
    prod_120b = Ca_1 / (kB * t_3)
    exp_120b = float(np.exp(-prod_120b))
    def Y_120b(ne_b):
            return (1/ne_b) * (C * t_3**1.5 * (U_220b / U_120b) * exp_120b)

    #Singly ionized calcium.
    prod_220b = Ca_2 / (kB * t_3)

    #For neutral calcium:
    def f_120b(ne_b):
            return (1 + Y_120b(ne_b) + (Y_120b(ne_b) * Y_220b(ne_b)))**-1

    #For ionized calcium.
    def f_220b(ne_b):
            return f_120b(ne_b) * Y_120b(ne_b)

    #Doubly ionized calcium.
    def f_320b(ne_b):
            return f_220b(ne_b) * Y_220b(ne_b)

    #Creating the master sum function.
    def sum(ne_b):
            return (a_1 * f_21b(ne_b)) + (a_2 * (f_22b(ne_b) + 2.*f_32b(ne_b))) + (a_20 * (f_220b(ne_b) + 2.*f_320b(ne_b)))

    #Creating the final function g(ne_b).
    def g(ne_b):
            return ((n_3 - ne_b) * sum(ne_b)) - ne_b

    #Attempting to minimize complicated function using Brent's method.
    #ne_bf = op.minimize_scalar(g, bounds=(1, 1e15), method='brent', tol=1e-08)
    ne_bf = op.brentq(g, -1e15, 1e15) #Just guessing at values, one near total suspected density, one opposite for bounds.
    ne_3.append(ne_bf)

    t_3 = t_3 + 50 #Steps of 50 kelvin.
    T_3.append(t_3)

print "End of code so far."

当我运行循环时,错误是:

  

追踪(最近一次呼叫最后一次):

     

文件&#34; hw6.py&#34;,第444行,in   ne_bf = float(op.brentq(g,-1e15,1e15))#正在猜测值,一个接近总可疑密度,一个是相反的边界。

     

文件&#34; /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/optimize/zeros.py" ;,第415行,在brentq       r = _zeros._brentq(f,a,b,xtol,rtol,maxiter,args,full_output,disp)

     

文件&#34; hw6.py&#34;,第440行,以g为单位       return((n_3 - ne_b)* sum(ne_b)) - ne_b

     

文件&#34; hw6.py&#34;,第436行,总之       return(a_1 * f_21b(ne_b))+(a_2 *(f_22b(ne_b)+ 2. * f_32b(ne_b)))+(a_20 *(f_220b(ne_b)+ 2. * f_320b(ne_b)))

     

文件&#34; hw6.py&#34;,第384行,f_21b       返回Y_11b(ne_b)/(1 + Y_11b(ne_b))

     

文件&#34; hw6.py&#34;,第378行,在Y_11b中       return(1 / ne_b)*(C * t_3 ** 1.5 *(U_21 / U_11b)* exp_11b)

     

ZeroDivisionError:浮点除零

我只需将每个新函数归零,然后将该值附加到数组以便稍后进行绘图。

我已经测试了这些函数中的每个函数以获得一些随机浮点值,如g(12.78432),它们分别进行计算。只有当我尝试将每个函数归零时才会出现此错误。任何建议表示赞赏。如果需要,我还可以提供更多信息,或者如果请求,还可以提供成功的代码(运行t_3的离散值的代码)。谢谢!

1 个答案:

答案 0 :(得分:1)

问题在于你试图除以零。如果分母为零,可以计算出每个函数要返回的内容,可能是Nonefloat("Inf")numpy.nan。然后让每个函数在尝试除法之前检查分母是否为