GAMS技术问询:逻辑条件变量使用及热储能罐运行策略建模
解决GAMS中热分层罐充放电模式的MINLP建模问题
作为经常在GAMS里折腾光热储能MINLP模型的人,我太懂你卡在热分层罐充放电逻辑判断上的痛苦了!结合SCIP求解器的特性,我给你梳理一套实用的建模思路:
1. 先用二进制变量标记运行模式
首先得用二进制变量明确每个时刻的运行状态——充电、放电还是待机。在GAMS里这么定义:
Binary Variables x_charge(t) ! 1表示时刻t处于充电模式,0则不是 x_discharge(t); ! 1表示时刻t处于放电模式,0则不是
然后加个互斥约束,确保同一时刻只能是一种模式(或者待机):
Equation eq_mode_mutual_exclusion(t); eq_mode_mutual_exclusion(t).. x_charge(t) + x_discharge(t) =l= 1;
2. 用大M法绑定流量与运行模式
接下来要把流量变量和运行模式挂钩:充电时只有罐顶进高温HTF、罐底出低温HTF;放电则相反。这里用大M法来实现逻辑约束,M选你模型里的最大允许流量(比如Q_max),数值别太夸张,不然SCIP求解会变慢。
比如定义流量变量:
Variables Q_in_top(t) ! 罐顶流入流量 Q_out_bottom(t) ! 罐底流出流量 Q_in_bottom(t) ! 罐底流入流量 Q_out_top(t); ! 罐顶流出流量
然后加约束:
! 充电模式下:仅顶进、底出有流量,其余为0 Equation eq_charge_flow_top(t), eq_charge_flow_bottom(t), eq_charge_flow_zero1(t), eq_charge_flow_zero2(t); eq_charge_flow_top(t).. Q_in_top(t) =l= Q_max * x_charge(t); eq_charge_flow_bottom(t).. Q_out_bottom(t) =l= Q_max * x_charge(t); eq_charge_flow_zero1(t).. Q_in_bottom(t) =l= Q_max * (1 - x_charge(t)); eq_charge_flow_zero2(t).. Q_out_top(t) =l= Q_max * (1 - x_charge(t)); ! 放电模式下:仅底进、顶出有流量,其余为0 Equation eq_discharge_flow_bottom(t), eq_discharge_flow_top(t), eq_discharge_flow_zero1(t), eq_discharge_flow_zero2(t); eq_discharge_flow_bottom(t).. Q_in_bottom(t) =l= Q_max * x_discharge(t); eq_discharge_flow_top(t).. Q_out_top(t) =l= Q_max * x_discharge(t); eq_discharge_flow_zero1(t).. Q_in_top(t) =l= Q_max * (1 - x_discharge(t)); eq_discharge_flow_zero2(t).. Q_out_bottom(t) =l= Q_max * (1 - x_discharge(t));
如果要更严格的“等于0”约束,可以把上面的=l=改成=e=,但要确保M足够大,不会限制正常流量。
3. 温度变量的逻辑绑定
充放电模式下,流体温度是固定的(充电顶进是高温T_hot,底出是低温T_cold;放电则相反),同样用大M法约束:
Variables T_in_top(t) ! 罐顶流入温度 T_out_bottom(t) ! 罐底流出温度 T_in_bottom(t) ! 罐底流入温度 T_out_top(t); ! 罐顶流出温度 ! 充电模式下的温度约束 Equation eq_charge_temp_top(t), eq_charge_temp_bottom(t); eq_charge_temp_top(t).. T_in_top(t) =e= T_hot - M_temp*(1 - x_charge(t)); eq_charge_temp_bottom(t).. T_out_bottom(t) =e= T_cold - M_temp*(1 - x_charge(t)); ! 放电模式下的温度约束 Equation eq_discharge_temp_bottom(t), eq_discharge_temp_top(t); eq_discharge_temp_bottom(t).. T_in_bottom(t) =e= T_cold - M_temp*(1 - x_discharge(t)); eq_discharge_temp_top(t).. T_out_top(t) =e= T_hot - M_temp*(1 - x_discharge(t));
这里M_temp选温度的最大可能差值(比如T_hot - T_cold的2倍),同样要选紧一点的数值。
4. 结合模式的罐内能量平衡
最后把运行模式和罐的能量变化绑定。如果是离散时间步长dt,能量平衡方程可以这么写:
Variables E_tank(t); ! 时刻t罐内存储的热能 Equation eq_energy_balance(t); eq_energy_balance(t).. E_tank(t) =e= E_tank(t-1) ! 充电时的能量变化:输入高温能量 - 输出低温能量 + (Q_in_top(t)*T_hot - Q_out_bottom(t)*T_cold)*cp*dt * x_charge(t) ! 放电时的能量变化:输入低温能量 - 输出高温能量(相当于释放存储的热能) + (Q_in_bottom(t)*T_cold - Q_out_top(t)*T_hot)*cp*dt * x_discharge(t);
cp是HTF的比热容,根据你的模型参数调整就行。
5. SCIP求解器的小提示
- 调用SCIP时可以设置一些选项加速求解,比如限制时间、开启启发式算法:
option solver=scip; scip_options = "limits/time 3600 heuristics/freq 10"; ! 3600秒时间限制,每10步跑启发式 - 给二进制变量设置初始值:如果有已知的初始运行状态,比如初始时刻是待机,就给
x_charge(t)和x_discharge(t)设0,帮助SCIP更快找到可行解。 - 尽量缩小变量的上下界:比如给流量、能量变量设置合理的范围,减少求解器的搜索空间。
如果还有具体的代码冲突或者变量定义问题,把你的片段贴出来,我们再细化!
内容的提问来源于stack exchange,提问作者Help621
相关产品推荐
相关产品推荐

