Pyomo调用Ipopt求解燃气管网优化时v_dot下界低于30收敛失败怎么办
问题根因分析
核心bug:压降约束符号不匹配
你当前的压降等式存在逻辑漏洞:
# 原错误写法 return ((model.pi[i] - model.pi[j]) * model.d[i, j] ** 5) == (a * model.v_dot[i, j]**2 * model.lengths[i, j])
等式右侧的v_dot[i,j]**2永远是非负数,因此左侧model.pi[i] - model.pi[j]必须也为非负数,等于强制所有管线只能从i节点流向j节点、流量必须为正。
- 当
v_dot下界设为30时,所有管线强制有正向流量,求解器可以通过构造循环流量满足节点守恒,因此能得到局部可行解,但非主路径管线因为必须过30的流量,管径无法收敛到最小值 - 当
v_dot下界低于30时,会出现流量为负/零的场景,此时右侧为正、左侧可能为负/零,等式完全无法成立,Ipopt找不到任何可行点,直接报Restoration Failed错误。
修复方案
1. 修正压降约束的符号逻辑
将v_dot的平方改为带符号的绝对值乘积,匹配流向和压降的对应关系:
def flow_rule(model, i, j): return (model.pi[i] - model.pi[j]) * model.d[i, j] ** 5 == a * model.v_dot[i,j] * abs(model.v_dot[i,j]) * model.lengths[i,j]
修改后流量为负时右侧也为负,对应pi[i] < pi[j]的反向流动场景,逻辑自洽。
2. 调整变量边界
将v_dot的边界调整为允许反向流动,或者根据你的管网需求设为非负:
# 允许反向流 model.v_dot = pyo.Var(model.edges, bounds=(-1500, 1500), within=pyo.Reals) # 仅允许正向流就设为(0, 1500)
3. 优化求解器配置
开启Ipopt自适应缩放解决变量尺度差异过大的问题(你当前pi是压力平方,数值范围百万级,和d、v_dot的尺度差超过6个数量级,极易导致收敛失败):
solver = SolverFactory("ipopt") # 开梯度缩放适配多尺度变量 solver.options["nlp_scaling_method"] = "gradient-based" # 放松边界容忍度避免数值奇异 solver.options["bound_relax_factor"] = 1e-8 results = solver.solve(model, tee=True)
4. 可选优化:避免零值数值奇异
如果设v_dot下界为0时仍有收敛问题,可以将下界调整为极小的正数(如1e-6),对最终结果的影响可以忽略。
预期效果
修复后非主路径的管线流量会收敛到0,对应管径自动取到0.01的最小值,目标函数值会低于之前的1091.8,且不会再出现可行域不存在的报错。
内容的提问来源于stack exchange,提问作者Khalilbs
相关产品推荐
相关产品推荐

