2
votes

I would like to ask a Modelica question about when function, and the following source code cannot be properly functioned. The variable Pstart_CONV is an initial condition for der(x_calc) in the if statement, and the Pstart_CONV value is given by x when the "when statement" becomes true. Because x is a step function, I want to assign an initial condition for der(x_calc) so x can be continued for the whole domain.

Thank you very much,

Source:

model Unnamed4
  Real  Pstart_CONV;

  Real P_crit_ratio;
  parameter Real P_crit_ratio_criteria = 2.00;

  Real x;
  Real x_calc(start=0);

equation 
  P_crit_ratio = 10-time;

  when P_crit_ratio <= P_crit_ratio_criteria then
    Pstart_CONV = x;
  end when;

  if P_crit_ratio >= P_crit_ratio_criteria then
    x = time^2;
    x_calc = 0;
  else
    der(x_calc) = time * 5;
    x = x_calc + Pstart_CONV;
  end if;   
end Unnamed4;
1

1 Answers

4
votes

There are two issues I see with this code. The main one has to do with the fact that this is what is called a "variable index" problem. I'll address that. But first, I want to point out that your if and when clauses are not properly synchronized. What I mean by that is that the change in behavior represented by your if statement will not necessarily occur at the same instant that the when clause is activated.

To address this, you can easily refactor your model to look like this:

model Model1
  Real Pstart_CONV;
  Real P_crit_ratio;
  parameter Real P_crit_ratio_criteria=2.00;
  Real x;
  Real x_calc(start=0);
  Boolean trigger(start=false);
equation 
  P_crit_ratio = 10-time;

  when P_crit_ratio <= P_crit_ratio_criteria then
    Pstart_CONV = x;
    trigger = true;
  end when;

  if trigger then
    der(x_calc) = time * 5;
    x = x_calc + Pstart_CONV;
  else
    x_calc = 0;
    x = time^2;
  end if;
end Model1;

Now, both the if and when clauses are tied to the trigger variable. Now we can address your main problem which is that on one side of your if statement you have:

der(x_calc) = time * 5;

...and on the other side you have:

x_calc = 0;

In practice, what this means is that for part of the simulation you solve x_calc using a differential equation while during the other part of the simulation you solve x_calc using an algebraic equation. This leads to the "variable index" problem because the "index" of the DAE changes depending on whether the value of trigger is true or false.

One approach to this is to modify the equations slightly. Instead of using the equation x_calc = 0 we specify an initial condition of 0 for x_calc and then enforce a differential equation that says the value of x_calc doesn't change, i.e., der(x_calc) = 0. In other words, get the same behavior by removing an algebraic equation settings x_calc to a constant and replacing it with an equation where we set the initial value of x_calc to be the desired value and then add a differential equation that, in effect, simply says the value of x_calc doesn't change.

Making such a change in your case leads to the following model:

model Model2
  Real Pstart_CONV;
  Real P_crit_ratio;
  parameter Real P_crit_ratio_criteria=2.0;
  Real x;
  Real x_calc(start=0);
  Boolean trigger(start=false);
initial equation
  x_calc = 0;
equation
  P_crit_ratio = 10-time;

  when P_crit_ratio <= P_crit_ratio_criteria then
    Pstart_CONV = x;
    trigger = true;
  end when;

  if trigger then
    der(x_calc) = time * 5;
    x = x_calc + Pstart_CONV;
  else
    der(x_calc) = 0;
    x = time^2;
  end if;
end Model2;

I tested it, and this model ran using SystemModeler (although I don't know enough about your problem or the expected results to truly validate the results).

I hope that helps.