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;
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;