函数中使用数组时If-else语句报错:数组真值判断歧义求解
解决核聚变PP链与CNO循环能量计算代码的数组条件判断问题
问题概述
编写了计算核聚变PP链与CNO循环产生的能量及相对能量的Python代码,目标是绘制能量随温度区间的变化曲线,但运行时出现错误:'The truth value of an array with more than one element is ambiguous'。排查发现问题源于输入的温度T是数组而非标量,导致普通if-else语句无法正确进行逐元素判断。尝试过np.all/np.any但结果不符合预期,使用np.where时不确定如何处理r_pp和r_34相关的条件判断,需要正确实现条件判断的方法以让代码正常运行并得到正确绘图结果。
错误原因
Python的普通if-else语句只能处理单个布尔值判断,而当T是numpy数组时,T<1e6返回的是一个布尔数组,直接用if判断会触发歧义错误,因为无法将整个布尔数组视为单个True/False值。同理,后续基于r_pp、r_34等数组的条件判断也会遇到同样问题。
修正方案
使用numpy的向量化操作和布尔掩码来替代普通if-else,实现逐元素的条件判断和修改:
- 用
np.where处理基于T的分支判断,直接生成对应每个温度的lambda_e7值。 - 用布尔掩码筛选满足条件的数组元素,仅对这些元素应用缩放因子,不满足条件的元素保持原值。
完整修正代码
import numpy as np import matplotlib.pyplot as plt def pp_chain(rho,T): N_A = 6.022e23 # Avogadro's constant inverse mu = 1.6605e-27 # Units of [kg] Joule = 1.60217e-13 # Converting Mev to Joule (SI) # Mass fraction of each nuclei X= 0.7 Y = 0.29 Y3He = 1e-10 Z7Li = 1e-7 Z7Be = 1e-7 Z14N = 1e-11 # Q-values of the different reactions, i.e. energy released Q_pp = 1.177*Joule Q_pd = 5.494*Joule Q_33 = 12.86*Joule Q_34 = 1.586*Joule Q_e7 = 0.049*Joule Q_17s = 17.346*Joule Q_17 = 0.137*Joule Q_CNO = (1.944 + 1.513+7.551 + 7.297+1.757 + 4.966)*Joule # Number density of each nuclei (in each reaction) n_p = ((rho*X)/(mu)) nHe3 = (rho*Y3He)/(3*mu) nHe4 = ((rho*Y)/(4*mu)) ne7 = (rho*Z7Be/(7*mu)) n17s = ((rho*Z7Li)/(7*mu)) nCNO = ((rho*Z14N)/(14*mu)) n_e = n_p+ 2*nHe4 + 2*nHe3 + 4*ne7 + 3*n17s + 7*nCNO T9 = T/(1e9) # Reaction rates (per unit mass) for each reaction lambda_pp = ((4.01e-15*T9**(-2/3)*np.exp(-3.380*T9**(-1/3))*(1+0.123*T9**(1/3)+1.09*T9**(2/3)+0.938*T9))/N_A)*0.000001 lambda_33 = ((6.04e10*T9**(-2/3)*np.exp(-12.276*T9**(-1/3))*(1+0.034*T9**(1/3)-0.522*T9**(2/3)-0.124*T9+0.353*T9**(4/3)+0.213*T9**(5/3)))/N_A)*0.000001 Ts = T9/(1+4.95e-2*T9) lambda_34 = ((5.61e6*Ts**(5/6)*T9**(-3/2)*np.exp(-12.826*Ts**(-1/3)))/N_A)*0.000001 # 用np.where替代if-else,处理T<1e6的分支 lambda_e7 = np.where( T < 1e6, ((1.57e-7/n_e)/N_A)*0.000001, ((1.34e-10*T9**(-1/2)*(1-0.537*T9**(1/3)+3.86*T9**(2/3)+0.0027*T9**(-1)*np.exp(2.515e-3*T9**(-1))))/N_A)*0.000001 ) Tss = T9/(1+0.759*T9) lambda_71Li = ((1.096e9*T9**(-2/3)*np.exp(-8.472*T9**(-1/3))-4.830e8*Tss*(5/6)*T9**(-3/2)*np.exp(-8.472*Tss**(-1/3))+1.06e10*T9**(-3/2)*np.exp(-30.442*T9**(-1)))/N_A)*0.000001 lambda_71Be = ((3.11e5*T9**(-2/3)*np.exp(-10.262*T9**(-1/3))+2.53e3*T9**(-3/2)*np.exp(-7.306*T9**(-1)))/N_A)*0.000001 lambda_CNO = ((4.90e7*T9**(-2/3)*np.exp(-15.228*T9**(-1/3)-0.092*T9**2)*(1+0.027*T9**(1/3)-0.778*T9**(2/3)-0.149*T9+0.261*T9**(4/3)+0.127*T9**(5/3)) + 2.37e3*T9**(-3/2)*np.exp(-3.011*T9**(-1))+2.19e4*np.exp(-12.53*T9**(-1)))/N_A)*0.000001 # Reaction rates for each reaction r_pp = (n_p*n_p)/(2*rho)*lambda_pp r_33 = (nHe3*nHe3)/(2*rho)*lambda_33 r_34 = ((nHe4*nHe3)/rho)*lambda_34 r_e7 = ((ne7*n_e)/rho)*lambda_e7 r_71Li = ((n17s*n_p)/rho)*lambda_71Li r_71Be = ((ne7*n_p)/rho)*lambda_71Be r_CNO = ((nCNO*n_p)/rho)*lambda_CNO # 用布尔掩码处理r_pp相关条件 mask1 = r_pp < (r_34 + 2*r_33) if np.any(mask1): R1 = r_pp[mask1] / (2*r_33[mask1] + r_34[mask1]) r_33[mask1] *= R1 r_34[mask1] *= R1 # 用布尔掩码处理r_34相关条件 mask2 = r_34 < (r_e7 + r_71Be) if np.any(mask2): R2 = r_34[mask2] / (r_e7[mask2] + r_71Be[mask2]) r_e7[mask2] *= R2 r_71Be[mask2] *= R2 # 用布尔掩码处理r_e7相关条件 mask3 = r_e7 < r_71Li if np.any(mask3): R3 = r_e7[mask3] / r_71Li[mask3] r_71Li[mask3] *= R3 # Energy generation per unit mass from PP1,PP2, PP3 and CNO PP1 = r_33*Q_33 + r_33*2*(Q_pp+Q_pd) PP2 = r_34*Q_34 + r_e7*Q_e7 + r_71Li*Q_17s + r_34*(Q_pp+Q_pd) PP3 = r_34*Q_34 + r_71Be*Q_17 + r_34*(Q_pp + Q_pd) CNO = r_CNO*Q_CNO epsilon = PP1+PP2+PP3+CNO # Relative energy E_rel1= PP1/epsilon E_rel2= PP2/epsilon E_rel3 = PP3/epsilon E_rel4 = CNO/epsilon return E_rel1, E_rel2,E_rel3,E_rel4 # Defining the different temperatures used in function rho = 1.62e5 T = np.arange(1e4,1e9,100) # Calling the function for energy generated in each branch energy_prod = pp_chain(rho, T) rel_energy1 = energy_prod[0] rel_energy2 = energy_prod[1] rel_energy3 = energy_prod[2] rel_energy4 = energy_prod[3] plt.plot(T, rel_energy1,label = 'PP1') plt.plot(T, rel_energy2,label = 'PP2') plt.plot(T, rel_energy3,label = 'PP3') plt.plot(T, rel_energy4,label = 'CNO') plt.title('Energy produced in each PP chain/CNO cycle') plt.ylabel('Relative Energy') plt.xlabel('T [K]') plt.xscale('log') plt.legend() plt.show()
说明
- 用
np.where替换了原代码中判断T<1e6的if-else,直接生成与T长度一致的lambda_e7数组,实现逐元素分支计算。 - 对于r_pp、r_34等数组的条件修改,通过布尔掩码筛选满足条件的元素,仅对这些元素应用缩放因子,避免了对整个数组的错误修改。
- 加入
np.any(mask)判断,防止当没有元素满足条件时执行无效的数组索引操作。
修改后的代码可以正常运行,生成符合预期的相对能量随温度变化的曲线,低温下PP链主导,高温下CNO循环逐渐成为能量主要来源,与核聚变的物理规律一致。
内容的提问来源于stack exchange,提问作者Lise Anette Granheim
相关产品推荐
相关产品推荐

