如何在 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 使用这些构建块:

主模型简单地启动一个stockinitialValue = 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 = 0StopTime = 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.]