You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

函数中使用数组时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,实现逐元素的条件判断和修改:

  1. 用np.where处理基于T的分支判断,直接生成对应每个温度的lambda_e7值。
  2. 用布尔掩码筛选满足条件的数组元素,仅对这些元素应用缩放因子,不满足条件的元素保持原值。

完整修正代码

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()

说明

  1. 用np.where替换了原代码中判断T<1e6的if-else,直接生成与T长度一致的lambda_e7数组,实现逐元素分支计算。
  2. 对于r_pp、r_34等数组的条件修改,通过布尔掩码筛选满足条件的元素,仅对这些元素应用缩放因子,避免了对整个数组的错误修改。
  3. 加入np.any(mask)判断,防止当没有元素满足条件时执行无效的数组索引操作。

修改后的代码可以正常运行,生成符合预期的相对能量随温度变化的曲线,低温下PP链主导,高温下CNO循环逐渐成为能量主要来源,与核聚变的物理规律一致。

内容的提问来源于stack exchange,提问作者Lise Anette Granheim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:04:56