在Pyomo模型中将时间作为约束中的显式变量

时间:2016-08-31 20:02:22

标签: matlab pyomo

我正在使用PyOMO模拟半批次反应。

考虑一个描述半间歇反应器的ODE系统,其中一个反应物以给定的体积流量供给 t1 单位时间,反应一直持续到 t 结束 ,显然 t1 < t end

要指定流程中的停止,我可以使用条件规则(假设 t1 = 3.5 * 60):

def _vol_flow_in_schedule(mod,t):
 if t<=3.5*60:
  return mod.vol_flow_in[t] == (12.3/1000)/(3.5*60)
 else:
  return mod.vol_flow_in[t] == 0
m1.vol_flow_in_schedule = Constraint(m1.time,rule=_vol_flow_in_schedule)

会产生不连续性(然后我的模型不会收敛)。我想要做的是使用一个sigmoidal函数,将流量转换为零,没有不连续性。

实现sigmoidal虽然我需要引用时间变量本身。

以下MATLAB代码给出了我想要的结果:

t=[0:1:500];
acc=2;  %Acceleration parameter, higher values yields sharper change.
time_of_step=3.5*60;
init_value = (12.3/1000)/(3.5*60);
end_value = 0;
sigmoidal=(init_value+(end_value-init_value)/2)...
          +((end_value-init_value)/2)*atan((t-time_of_step)*acc)/atan(max(t));

然而,此实现需要在函数中显式地显示时间变量。如何访问PyOMO规则中的时间变量?我尝试了以下,但我得到了一个&#34;无法处理标量组件&t'of_step&#39;作为一个阵列&#34;错误:

m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))
m1.end_value  = Param(initialize = 0)
m1.t_of_step  = Param(initialize = 210)
m1.acc        = Param(initialize = 5)
.
.

def _vol_flow_sigmoidal (mod,t):
 return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)

希望我已经清楚地描述了我的追求。任何提示都是最受欢迎的,

谢谢! 萨尔

1 个答案:

答案 0 :(得分:1)

您如何声明m1.time索引?

我的猜测是你正在使用NumPy数组来初始化m1.time索引。 Pyomo中存在一个已知问题(参见Issue #31),其中NumPy运算符重载和Pyomo运算符重载最终会相互争斗(基本上,NumPy被欺骗,认为Pyomo标量实际上被索引并试图像对待它们一样对待它们阵列)。

我能够通过以下完整示例重现错误:

# pyomo 4.4.1
from pyomo.environ import *                                                     
import numpy as np                                                              

m1 = ConcreteModel()                                                            
m1.time = Set(initialize=np.array([0,100,200,300,400,500]))                     
m1.vol_flow_in = Var(m1.time)                                                   

m1.init_value = Param(initialize = (12.3/1000)/(3.5*60))                        
m1.end_value  = Param(initialize = 0)                                           
m1.t_of_step  = Param(initialize = 210)                                         
m1.acc        = Param(initialize = 5)                                           

def _vol_flow_sigmoidal (mod,t):                                                
 return mod.vol_flow_in[t] == (mod.init_value+(mod.end_value-mod.init_value)/2)\
+((mod.end_value-mod.init_value)/2)*atan((t-mod.t_of_step)*mod.acc)/atan(1500)  
m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)            

有两种方法可行,都基于避免使用NumPy数组来初始化Pyomo Sets。你可以完全避免Numpy:

m1.time = Set(initialize=[0,100,200,300,400,500])

或显式地将NumPy数组转换为列表:

timeArray = np.array([0,100,200,300,400,500])
m1.time = Set(initialize=timeArray.tolist())

最后,为了完整性,另外两个注意事项:

  1. 这也适用于初始化ContinuousSet

  2. 中的pyomo.dae个对象
  3. 即使您避免显式的Pyomo Set声明,您也会看到相同的行为。也就是说,以下内容也会生成错误:

  4.  
    m1.time = np.array([0,100,200,300,400,500])
    # ...
    m1.vol_flow_sigmoidal = Constraint(m1.time,rule=_vol_flow_sigmoidal)            
    

    这是因为Pyomo将在幕后为m1.vol_flow_sibmodial_index安静地创建Set对象,然后使用该Set来为Constraint编制索引。