如何在 Modelica 中使用布尔开关来防止库存耗尽至零以下?
How to use boolean switches in Modelica to prevent draining a stock below zero?
问题描述
我正在建立一个库来支持 Cellier 等人的 System Dynamics (SD) like modeling in Modelica. Unlike the freely available library。我相信人们可以很好地利用非因果连接器:通过连接器将股票价值传输为 "potential" 可以构建紧凑的组件(例如流 = 进程)。
在 SD 中,我们可能会将 material ("mass") 股票与可能变为负值的信息股票区分开来。为了支持这一点,我对 大容量端口 使用了以下定义(这里给出了 StockPort
的定义 - 它的对应物 FlowPort
只是布尔输入变量而不是输出变量,稍后给出):
connector StockPort "Used to represent stock and flow connections"
Real stock "Current value of material in the stock";
flow Real rate "Flow that affects the stock";
// Boolean switches
output Boolean stopInflow "True indicates that nothing can flow into the stock";
output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end StockPort;
布尔开关指示 库存 的每个端口是否允许填充或排放。
对于“material 库存”,stopOutflow
开关应防止库存耗尽至零以下。不幸的是,在以下示例中,这将无法解决:库存将在略低于零的情况下被耗尽。
使用连接器的最小示例
以下 TestModel
使用这些构建块:
function constrainedRate( indicated rate, stopInflow, stopOutflow)
用于 return 符合给定约束的速率(即布尔开关)
connector StockPort
如上所述
connector FlowPort
对应 StockPort
model MaterialStock
具有一个 StockPort
的库存组件不应在零以下消耗
model LinearDecline
一个带有一个 FlowPort
(即汇)的流元素,它模拟以恒定速率(这里设置为 1)排出连接的存量
主模型简单地启动一个stock
和initialValue = 5
连接到一个process
的线性下降declineRate = 1
.
model TestModel "Stop draining a stock below zero"
function constrainedRate "Set rate for a port according to signals from stock"
input Real indicatedRate "Proposed rate for port of flow element";
input Boolean stopInflow "Signal from connected stock";
input Boolean stopOutflow "Signal from connected stock";
output Real actualRate "The rate to use";
protected
// check whether indicated rate is negative (e.g. an inflow to the connected stock)
Boolean indRateIsInflow = indicatedRate < 0;
algorithm
// set rate to zero if stopSignal matches character of flow
actualRate := if indRateIsInflow and stopInflow
then 0
elseif not indRateIsInflow and stopOutflow
then 0
else indicatedRate;
end constrainedRate;
connector FlowPort "Used to represent stock and flow connections"
Real stock "The current stock level (e.g. Potential) of a connected stock or flow data for special stocks";
flow Real rate "Flows that affect the material stock";
input Boolean stopInflow "True indicates that nothing can flow into the stock";
input Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end FlowPort;
connector StockPort "Used to represent stock and flow connections"
Real stock "Current value of stock";
flow Real rate "Flow that affects the stock";
output Boolean stopInflow "True indicates that nothing can flow into the stock";
output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end StockPort;
model MaterialStock "Stock that cannot be drained below zero"
StockPort outflow;
parameter Real initialValue;
protected
Real x(start = initialValue);
equation
// rate of change for the stock
der(x) = outflow.rate;
// ports shall have level information for stock
outflow.stock = x;
// inflow to stock is unrestricted
outflow.stopInflow = false;
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= 0;
end MaterialStock;
model LinearDecline "Decline of stock at a constant rate"
FlowPort massPort;
parameter Real declineRate(min = 0) "Rate of decline (positive rate diminishes stock)";
protected
// a positive rate should drain the stock (which here matches Modelica's rule for flows)
Real rate(min = 0);
equation
rate = declineRate;
// observe stock signals and constraints
assert(rate >= 0, "Rate must be positive and will be set to zero", level = AssertionLevel.warning);
// set the rate according to constraints given by stock
massPort.rate = constrainedRate( max(rate, 0), massPort.stopInflow, massPort.stopOutflow );
end LinearDecline;
// main model
MaterialStock stock( initialValue = 5 );
LinearDecline process( declineRate = 1 );
equation
connect( stock.outflow, process.massPort );
end TestModel;
使用 DASSL 模拟从 StartTime = 0
到 StopTime = 10
的模型揭示了变量 stock.outflow.stock
:
的预期行为
不幸的是,该值在 t = 5.0
及以后略低于零。
以某种方式检测到事件(股票价值 <= 0)为时已晚。我能做什么?
(到目前为止,imo 不优雅的治疗方法是使用 when
事件(状态事件)将 reinit
股票价值归零。我使用 noEvent
包装器的实验if
语句和布尔条件也没有成功。)
你能测试这个解决方案吗?使用 Modelica.Constants.eps 对我有用。我还使用了 Dassl,它适用于不同的步长。
我更改了以下行:
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= 0;
至
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= Modelica.Constants.eps;
然后,输出数组(在 python 中查看 post):
Output using a zero instead of eps:
[ 5.00000000e+00 4.00000000e+00 3.00000000e+00 2.00000000e+00
1.00000000e+00 0.00000000e+00 -7.37276906e-12 -7.37276906e-12
-7.37276906e-12 -7.37276906e-12 -7.37276906e-12 -7.37276906e-12
-7.37276906e-12 -7.37276906e-12]
Output using eps:
[5. 4. 3. 2. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
问题描述
我正在建立一个库来支持 Cellier 等人的 System Dynamics (SD) like modeling in Modelica. Unlike the freely available library。我相信人们可以很好地利用非因果连接器:通过连接器将股票价值传输为 "potential" 可以构建紧凑的组件(例如流 = 进程)。
在 SD 中,我们可能会将 material ("mass") 股票与可能变为负值的信息股票区分开来。为了支持这一点,我对 大容量端口 使用了以下定义(这里给出了 StockPort
的定义 - 它的对应物 FlowPort
只是布尔输入变量而不是输出变量,稍后给出):
connector StockPort "Used to represent stock and flow connections"
Real stock "Current value of material in the stock";
flow Real rate "Flow that affects the stock";
// Boolean switches
output Boolean stopInflow "True indicates that nothing can flow into the stock";
output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end StockPort;
布尔开关指示 库存 的每个端口是否允许填充或排放。
对于“material 库存”,stopOutflow
开关应防止库存耗尽至零以下。不幸的是,在以下示例中,这将无法解决:库存将在略低于零的情况下被耗尽。
使用连接器的最小示例
以下 TestModel
使用这些构建块:
function constrainedRate( indicated rate, stopInflow, stopOutflow)
用于 return 符合给定约束的速率(即布尔开关)connector StockPort
如上所述connector FlowPort
对应StockPort
model MaterialStock
具有一个StockPort
的库存组件不应在零以下消耗model LinearDecline
一个带有一个FlowPort
(即汇)的流元素,它模拟以恒定速率(这里设置为 1)排出连接的存量
主模型简单地启动一个stock
和initialValue = 5
连接到一个process
的线性下降declineRate = 1
.
model TestModel "Stop draining a stock below zero"
function constrainedRate "Set rate for a port according to signals from stock"
input Real indicatedRate "Proposed rate for port of flow element";
input Boolean stopInflow "Signal from connected stock";
input Boolean stopOutflow "Signal from connected stock";
output Real actualRate "The rate to use";
protected
// check whether indicated rate is negative (e.g. an inflow to the connected stock)
Boolean indRateIsInflow = indicatedRate < 0;
algorithm
// set rate to zero if stopSignal matches character of flow
actualRate := if indRateIsInflow and stopInflow
then 0
elseif not indRateIsInflow and stopOutflow
then 0
else indicatedRate;
end constrainedRate;
connector FlowPort "Used to represent stock and flow connections"
Real stock "The current stock level (e.g. Potential) of a connected stock or flow data for special stocks";
flow Real rate "Flows that affect the material stock";
input Boolean stopInflow "True indicates that nothing can flow into the stock";
input Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end FlowPort;
connector StockPort "Used to represent stock and flow connections"
Real stock "Current value of stock";
flow Real rate "Flow that affects the stock";
output Boolean stopInflow "True indicates that nothing can flow into the stock";
output Boolean stopOutflow "True indicates that nothing can flow out of the stock";
end StockPort;
model MaterialStock "Stock that cannot be drained below zero"
StockPort outflow;
parameter Real initialValue;
protected
Real x(start = initialValue);
equation
// rate of change for the stock
der(x) = outflow.rate;
// ports shall have level information for stock
outflow.stock = x;
// inflow to stock is unrestricted
outflow.stopInflow = false;
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= 0;
end MaterialStock;
model LinearDecline "Decline of stock at a constant rate"
FlowPort massPort;
parameter Real declineRate(min = 0) "Rate of decline (positive rate diminishes stock)";
protected
// a positive rate should drain the stock (which here matches Modelica's rule for flows)
Real rate(min = 0);
equation
rate = declineRate;
// observe stock signals and constraints
assert(rate >= 0, "Rate must be positive and will be set to zero", level = AssertionLevel.warning);
// set the rate according to constraints given by stock
massPort.rate = constrainedRate( max(rate, 0), massPort.stopInflow, massPort.stopOutflow );
end LinearDecline;
// main model
MaterialStock stock( initialValue = 5 );
LinearDecline process( declineRate = 1 );
equation
connect( stock.outflow, process.massPort );
end TestModel;
使用 DASSL 模拟从 StartTime = 0
到 StopTime = 10
的模型揭示了变量 stock.outflow.stock
:
不幸的是,该值在 t = 5.0
及以后略低于零。
以某种方式检测到事件(股票价值 <= 0)为时已晚。我能做什么?
(到目前为止,imo 不优雅的治疗方法是使用 when
事件(状态事件)将 reinit
股票价值归零。我使用 noEvent
包装器的实验if
语句和布尔条件也没有成功。)
你能测试这个解决方案吗?使用 Modelica.Constants.eps 对我有用。我还使用了 Dassl,它适用于不同的步长。 我更改了以下行:
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= 0;
至
// provide Boolean signal in case of negative stock
outflow.stopOutflow = x <= Modelica.Constants.eps;
然后,输出数组(在 python 中查看 post):
Output using a zero instead of eps:
[ 5.00000000e+00 4.00000000e+00 3.00000000e+00 2.00000000e+00
1.00000000e+00 0.00000000e+00 -7.37276906e-12 -7.37276906e-12
-7.37276906e-12 -7.37276906e-12 -7.37276906e-12 -7.37276906e-12
-7.37276906e-12 -7.37276906e-12]
Output using eps:
[5. 4. 3. 2. 1. 0. 0. 0. 0. 0. 0. 0. 0.]