# Inconsistent behavior of WhenEvent[ ]

Consider the following simple example:

sol = NDSolve[ {x''[t] == 1, x'[0] == 0, x[0] == 0,
WhenEvent[Abs[x[t]] > 1 && x[t] > 2, {x'[t] -> -3 x'[t]}]},
x[t], {t, 0, 4}];
Plot[x[t] /. sol[[1]], {t, 0, 4}]


Clearly WhenEvent[] is missing the x[t] > 2 occurrence. This may happens (my interpretation) if the event detection routine checks for the occurrence of the first part of the AND clause and then for the other AND components, instead of checking them as an OR event trigger. As the Abs[x[t]] > 1 event isn't fired again between 1 and 2, the rest of the AND clause doesn't get tested again.

In testing this interpretation, we can reverse the clause:

sol = NDSolve[{x''[t] == 1, x'[0] == 0, x[0] == 0,
WhenEvent[x[t] > 2 && Abs[x[t]] > 1, {x'[t] -> -3 x'[t]}]},
x[t], {t, 0, 4}];
Plot[x[t] /. sol[[1]], {t, 0, 4}]


which now works as expected. Of course this isn't a proof.

But the strange thing is that reverting to the first version, but encapsulating the clause in a function, also works as expected:

clause[p_] := Abs[p] > 1 && p > 2
sol = NDSolve[{x''[t] == 1, x'[0] == 0, x[0] == 0,
WhenEvent[clause[x[t]], {x'[t] -> -3 x'[t]}]}, x[t], {t, 0, 4}];
Plot[x[t] /. sol[[1]], {t, 0, 4}]


So, what is the moral? Always put your WhenEvent[] clause as a function?

• Even weirder: try WhenEvent[Null;Abs[x[t]]>1&&x[t]>2,{x'[t]->-3x'[t]}].. Commented Dec 24, 2013 at 18:28
• @Silvia That's crazy. Perhaps the WhenEvent[ ] thing isn't mature enough Commented Dec 24, 2013 at 19:25

From WhenEvent:

Examples of events and how $$t_a$$ is determined include:
...
f == 0 && pred -- f crosses zero and pred is True

I believe that the same special case is applied to And for forms f > 0 && pred, etc.

So

WhenEvent[Abs[x[t]] > 1 && x[t] > 2, {x'[t] -> -3 x'[t]}]


means the event will be triggered when Abs[x[t]] crosses 1 and x[t] > 2, which is never.

Next,

 WhenEvent[x[t] > 2 && Abs[x[t]] > 1, {x'[t] -> -3 x'[t]}]


means the event will be triggered when x[t] crosses 2 and Abs[x[t]] > 1, which will be whenever x[t] crosses 2.

Finally, both

WhenEvent[clause[x[t]], {x'[t] -> -3 x'[t]}]
WhenEvent[Null; Abs[x[t]] > 1 && x[t] > 2, {x'[t] -> -3x'[t]}]


do not have the head And, so the special case is not applied; they will trigger an event whenever they change from False to True.

• I've read the docs, but I understood them as a simple application of logic. Your interpretation (probably correct) seems dangerous because you have to be sure to cover all the possible timelines with OR clauses ... or just encapsulate the whole thing as a function which is probably worse from the performance POV Commented Dec 25, 2013 at 4:23
• @belisarius It could be that only crossings, such as f == 0, were meant to be special-cased, and you've found a bug. Clearly f == 0 has to be a special case, and one would want to allow conditions to be placed on which crossings trigger events. But && here seems to behave logically like "when", and that's unintuitive. Commented Dec 25, 2013 at 4:42
• @belisarius Practically speaking, the Equal statements are never true. The solver looks for a change in sign (or a crossing). Try it with clause[p_] := p == 2 && Abs[p] > 1. Commented Dec 25, 2013 at 5:01
• There is a saying in Spanish. I don't really know if it makes sense in English "Among firefighters we will not step on the hose." Commented Dec 25, 2013 at 5:13
• @belisarius I didn't mean that either. I just meant I don't think my friends will understand it. :) Commented Dec 25, 2013 at 5:16