Search code examples
modelicaopenmodelica

How to prevent unnecessary event detection in Modelica?


How can I achieve event detection for y>1 in the S1=... statement only when S2 is true and otherwise prevent it since it only slows down simulation in the general case?

model zeroCrossingTest
// BOOLEAN VARIABLE DECLARATIONS 
Boolean S1(start=true, fixed=true);
Boolean S2(start=false, fixed=true);
Boolean S3(start=false, fixed=true);
Real y;
equation
der(y) = -y + 2;

// ================= 
// TRANSITIONS START 
S1 = if pre(S2) then (y>1) else 
        if pre(S1) then not ( (y>0.2)  )
 else false;

S2 = if pre(S1) then (y>0.2) else 
        if pre(S2) then not ( (y>0.5)  or  (y>1)  )
 else false;

S3 = if pre(S2) then (y>0.5) else 
        pre(S3);
end zeroCrossingTest; 

The zero crossing from S1 = if pre(S2) then (y>1).. is still computed in OpenModelica (state event at time=0.69), although pre(S2) is false

UPDATE1: Alternative Implementation which does not generate unnecessary events.. thanks @marco

model zeroCrossingTest_OriginalImplementation
  // BOOLEAN VARIABLE DECLARATIONS
  Boolean S1(start = true, fixed = true);
  Boolean S2(start = false, fixed = true);
  Boolean S3(start = false, fixed = true);
  Real y;
equation
  der(y) = -y + 2;
// =================
// TRANSITIONS START 
S1 = pre(S2) and y>1 or 
        pre(S1) and not y>0.2;
 
S2 = pre(S1) and y>0.2 or 
        pre(S2) and not ( y>0.5  or  y>1  );
 
S3 = pre(S2) and y>0.5 or 
        pre(S3);
end zeroCrossingTest_OriginalImplementation;

UPDATE2: a more complex model, which gives the same behaviour of the boolean variables generates unnecessary state events (for y>0.7, y>0.8):

model zeroCrossingTest_OriginalImplementation
Boolean S1(start=true, fixed=true);
Boolean S2(start=false, fixed=true);
Boolean S3(start=false, fixed=true);
Boolean S4(start=false, fixed=true);
Boolean S5(start=false, fixed=true);
Boolean S6(start=false, fixed=true);
  Real y;
equation
  der(y) = -y + 2;
// ================= 
// TRANSITIONS START 
S1 = pre(S2) and (y>1) or 
        pre(S6) and (y>0.8) or 
        pre(S1) and not ( (y>0.2)  );
 
S2 = pre(S1) and (y>0.2) or 
        pre(S2) and not ( (y>0.5)  or  (y>1)  or  (y>0.6)  );
 
S3 = pre(S2) and (y>0.5) or 
        pre(S3);

S4 = pre(S2) and (y>0.6) or 
        pre(S4) and not ( (y>0.65)  );
 
S5 = pre(S4) and (y>0.65) or 
        pre(S5) and not ( (y>0.7)  );
 
S6 = pre(S5) and (y>0.7) or 
        pre(S6) and not ( (y>0.8)  );
end zeroCrossingTest_OriginalImplementation;

UPDATE 3: This implementation generates only the necessary events (2 events in total). Any reason against this approach?

model zeroCrossingTest_OriginalImplementation
Boolean S1(start=true, fixed=true);
Boolean S2(start=false, fixed=true);
Boolean S3(start=false, fixed=true);
Boolean S4(start=false, fixed=true);
Boolean S5(start=false, fixed=true);
Boolean S6(start=false, fixed=true);

Real inS1;
Real inS2;
Real inS3;
Real inS4;
Real inS5;
Real inS6;

  Real y;
equation
  der(y) = -y + 2;
  
// ===================== 
// inState Variables 
inS1= if pre(S1) then 1 else 0;
inS2= if pre(S2) then 1 else 0;
inS3= if pre(S3) then 1 else 0;
inS4= if pre(S4) then 1 else 0;
inS5= if pre(S5) then 1 else 0;
inS6= if pre(S6) then 1 else 0;
  
// ================= 
// TRANSITIONS START 
S1 = pre(S2) and (inS2*y>1) or 
        pre(S6) and (inS6*y>0.8) or 
        pre(S1) and not ( (inS1*y>0.2)  );
 
S2 = pre(S1) and (inS1*y>0.2) or 
        pre(S2) and not ( (inS2*y>0.5)  or  (inS2*y>1)  or  (inS2*y>0.6)  );
 
S3 = pre(S2) and (inS2*y>0.5) or 
        pre(S3);

S4 = pre(S2) and (inS2*y>0.6) or 
        pre(S4) and not ( (inS4*y>0.65)  );
 
S5 = pre(S4) and (inS4*y>0.65) or 
        pre(S5) and not ( (inS5*y>0.7)  );
 
S6 = pre(S5) and (inS5*y>0.7) or 
        pre(S6) and not ( (inS6*y>0.8)  );
end zeroCrossingTest_OriginalImplementation;

Solution

  • I am no OpenModelica expert and I don't know why S1 generates and event at 0.69s in OpenModelica (but not in Dymola, as Markus A. already noted).

    But in this case the unnecessary event can be prevented by moving the y > 1 comparison into the if condition:

      S1 = if pre(S2) and y > 1 then true 
           else if pre(S1) and not y > 0.2 then true 
           else false;
    

    Note that I removed most braces by considering the precedence of operators.

    You could also remove the else if branch:

      S1 = if pre(S2) and y > 1 or 
              pre(S1) and not y > 0.2 
           then true 
           else false;
    

    Since the comparison already returns true or false, we can remove the if and simply write:

      S1 = pre(S2) and y > 1 or 
           pre(S1) and not y > 0.2;