循环中函数返回数组致if判断报错,求解决(Use a.any()/a.all())
修复中子滴线绘制代码中的数组比较错误
我要绘制原子核的中子滴线(neutron drip line),这条线代表每个原子序数(Z)对应的中子数(N)极限值,超过该值添加中子会使原子核不稳定,表现为分离能为负(分离能是(Z,N)与(Z,N+1)的结合能差值)。
实现步骤:
- 从A值列表生成Z值数组和N值数组,通过
zmin()函数获取Z值,N值由A与Z的差值得到。 - 遍历每个Z值,递增计算一系列N值的结合能,直到结合能差为负,记录此时的N值,完成所有Z值的处理后绘图。
原代码
import numpy as np import matplotlib.pyplot as plt avol = 15.5 # Initializing the coefficients asurf = 16.8 acol = 0.72 asym = 23 def bind_en (Z, N): #Defining a function to calculate binding energy #curve using semi-emperical mass formulae if ((Z+N)%2)!=0 and (Z%2)==0: apar=0 elif ((Z+N)%2)==0 and (Z%2)!=0: apar=0 elif ((Z+N)%2)==0 and (Z%2)==0: apar=34 elif ((Z+N)%2)!=0 and (Z%2)!=0: apar=-34 b = avol*(Z+N)-asurf*((Z+N)**(2/3))-(acol*Z*(Z-1))/((Z+N)**(1/3))-asym*(((Z+N)-2*Z)**2)/(Z+N)+apar/((Z+N)**(3/4)) return b/A def zmin(A): z = (A / 2) * (1 / (1 + 0.25 * (A ** (2 / 3)) * (acol / asym))) z = int(z) return z A = np.arange(1, 261, 1) Z = [] N = [] NM=[] for i in range(len(A)): Z.append(zmin(A[i])) N.append(A[i]-Z[i]) flag=False for j in range(len(Z)): for k in range(len(N)): s=bind_en(Z[j],N[k+1])-bind_en(Z[j],N[k]) '''if isinstance(s, np.ndarray): print("s is an array.")''' if s<0: NM.append(N[k]) flag=True break if flag: break plt.plot(NM, Z) plt.xlabel('Number of Neutrons (N)') plt.ylabel('Number of Protons (Z)') plt.grid(True) plt.show()
运行错误信息
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[27], line 45 42 s=bind_en(Z[j],N[k+1])-bind_en(Z[j],N[k]) 43 '''if isinstance(s, np.ndarray): 44 print("s is an array.")''' ---> 45 if s<0: 46 NM.append(N[k]) 47 flag=True ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
问题原因分析
错误核心在于bind_en函数的返回值:你在函数里返回了b/A,这里的A是全局定义的numpy数组np.arange(1, 261, 1),所以每次调用bind_en都会返回一个长度为260的数组,而非单个数值。后续计算s时自然得到数组,无法直接和0比较,导致报错。
另外原代码的遍历逻辑也有问题:flag=True后直接跳出所有循环,只能处理第一个Z值,无法完成所有Z的计算。
修复后的代码
import numpy as np import matplotlib.pyplot as plt avol = 15.5 # 初始化半经验质量公式系数 asurf = 16.8 acol = 0.72 asym = 23 def bind_en(Z, N): # 计算单个原子核的核子结合能 A_val = Z + N # 简化对能项判断逻辑 if (A_val % 2) != 0: apar = 0 else: apar = 34 if (Z % 2) == 0 else -34 b = (avol * A_val - asurf * (A_val ** (2/3)) - (acol * Z * (Z - 1)) / (A_val ** (1/3)) - asym * ((A_val - 2 * Z) ** 2) / A_val + apar / (A_val ** (3/4))) return b / A_val # 返回单个数值:每个核子的结合能 def zmin(A): z = (A / 2) * (1 / (1 + 0.25 * (A ** (2/3)) * (acol / asym))) return int(z) # 提取所有唯一的Z值,避免重复计算 unique_Z = sorted(list(set(zmin(a) for a in np.arange(1, 261, 1)))) NM = [] for z in unique_Z: n = z # 从N=Z开始逐步递增,寻找滴线位置 while True: # 计算中子分离能:S_n = B(Z,N+1) - B(Z,N) s = bind_en(z, n+1) - bind_en(z, n) if s < 0: NM.append(n) break n += 1 plt.plot(NM, unique_Z) plt.xlabel('Number of Neutrons (N)') plt.ylabel('Number of Protons (Z)') plt.title('Neutron Drip Line') plt.grid(True) plt.show()
关键修复点
- 修正结合能返回值:将
return b/A改为return b/(Z+N),确保返回单个数值而非全局数组。 - 简化对能项判断:优化
apar的条件逻辑,提升可读性。 - 重构遍历逻辑:
- 提取唯一Z值,避免重复处理相同原子序数。
- 对每个Z从N=Z开始逐步递增,直到分离能为负,确保所有Z都能找到对应的极限N。
- 移除错误终止逻辑:删除原代码中导致提前终止循环的
flag,保证遍历完整。
内容的提问来源于stack exchange,提问作者Ashik Lal Krishna
相关产品推荐
相关产品推荐

