使用scipy.optimize.minimize()遇ValueError:目标函数需返回标量值
解决scipy.optimize.minimize()的ValueError问题
错误原因
scipy.optimize.minimize()是用于最小化标量目标函数的工具,要求传入的目标函数必须返回单个数值(标量)。但你的equations函数返回的是一个三元组(三个物料平衡方程的残差),属于向量类型,这直接触发了ValueError: The user-provided objective function must return a scalar value.错误。
你实际要解决的是非线性方程组求解问题,应该使用SciPy中专门的方程组求解函数,比如scipy.optimize.root()或scipy.optimize.least_squares()。
修改后的代码
import numpy as np from scipy.optimize import root # 替换minimize为root # 先定义所有平衡常数(示例值,根据实际情况替换) k1, k2, k3, k4, k5 = 1e-10, 1e-5, 1e-4, 1e-3, 1e2 k6, k7, k8, k9, k10 = 1e3, 1e4, 1e-9, 1e10, 1e15 PH = np.linspace(0, 14, 71) ni_total = 0.1 citrate_total = 0.9 ammonia_total = 0.3 def concs(citrate_total, ni_total, ammonia_total, PH): h = 10 ** (-PH) def equations(p): cit3, nio2, nh4 = p Hcit = h * cit3 * k4 H2cit = h * Hcit * k3 H3cit = h * H2cit * k2 ni2pfree = (nio2 * k1 * (h ** 2)) / (1 + ((nio2 * k1 * (h ** 2)) / ni_total)) NiH2cit = k7 * ni2pfree * H2cit NiHcit = k6 * ni2pfree * Hcit Nicit = k5 * ni2pfree * cit3 nh3 = k8 * nh4 / h nin4p2 = k9 * (nh4 ** 4) / (h ** 2) nin6p2 = k10 * (nh4 ** 6) / (h ** 4) # 返回残差向量,root会寻找使所有残差趋近于0的解 return ( citrate_total - Hcit - H2cit - H3cit - Nicit - NiHcit - NiH2cit - cit3, ni_total - Nicit - NiHcit - NiH2cit - ni2pfree - nin4p2 - nin6p2 - nio2, ammonia_total - nh3 - 4 * nin4p2 - 6 * nin6p2 - nh4 ) initial_guess = [0.1, 0.1, 0.1] # 使用root求解方程组 res = root(equations, initial_guess) # 检查求解是否成功 if not res.success: raise RuntimeError(f"求解失败: {res.message}") cit3 = res.x[0] nio2 = res.x[1] nh4 = res.x[2] # 重新计算各物种浓度 ni2pfree = (nio2 * k1 * (h ** 2)) / (1 + ((nio2 * k1 * (h ** 2)) / ni_total)) Hcit = h * cit3 * k4 H2cit = h * Hcit * k3 H3cit = h * H2cit * k2 NiH2cit = k7 * ni2pfree * H2cit NiHcit = k6 * ni2pfree * Hcit Nicit = k5 * ni2pfree * cit3 nh3 = k8 * nh4 / h nin4p2 = k9 * (nh4 ** 4) / (h ** 2) nin6p2 = k10 * (nh4 ** 6) / (h ** 4) return [cit3, nio2, nh4, ni2pfree, Hcit, H2cit, H3cit, NiH2cit, NiHcit, Nicit, nh3, nin4p2, nin6p2] # 遍历PH数组计算每个pH下的浓度 all_concs = [concs(citrate_total, ni_total, ammonia_total, ph) for ph in PH]
关键注意事项
- 平衡常数定义:代码中添加了示例平衡常数
k1至k10,请根据实际热力学数据替换为准确值,否则求解结果无意义。 - 求解成功检查:添加了
res.success判断,避免使用未成功求解的结果。 - 批量处理PH:原代码中
PH是数组,需要通过循环逐个传入concs函数计算。 - 替代方案:如果需要最小化残差的平方和,可改用
scipy.optimize.least_squares(),用法与root类似,同样接受返回向量的目标函数。
内容的提问来源于stack exchange,提问作者Robert_T119
相关产品推荐
相关产品推荐

