2
$\begingroup$

I've got a problem where WhenEvent successfully detects an event, but then performs only some of the actions.

In this minimal example, x[t] can not exceed 1 (driven by If). If x[t] equals 1 in the time window from 0.1 to 0.9, it should be reduced to 0.2, toggle a DiscreteVariable, and print the time.

sol = NDSolve[{x'[t] == If[x[t] < 1, 4 x[t], 0],
  WhenEvent[0.1 < t < 0.9 && x[t] >= 1,
    {Print[t], x[t] -> 0.2, dv[t] -> 1 - dv[t]}],
  x[0] == 0.9, dv[0] == 0}, {x, dv}, {t, 0, 1},
  DiscreteVariables -> {dv}][[1]];
(* 0.1 *)
(* 0.502359 *)

The two printed times show that the WhenEvent was correctly triggered twice -- once when the time window opens at t == 0.1 and another time later. But plotting x[t] shows that it was not correctly reduced to 0.2 at the second event at t = 0.502359.

Plot[Evaluate[x[t] /. sol], {t, 0, 1}]

Mathematica graphics

However the DiscreteVariable dv[t] was successfully toggled twice:

Plot[Evaluate[dv[t] /. sol], {t, 0, 1}]

Mathematica graphics

This seems to be an unfortunate interaction with the If statement, because changing x'[t] == 4 x[t] causes it to work fine.

Bug or just my improper use of WhenEvent? Any ideas for a workaround?

$\endgroup$
0

2 Answers 2

2
$\begingroup$

A slightly change of the dgl makes your program working:

{X, DV} = 
NDSolveValue[{x'[t] == Boole[x[t] < 1.01] 10 x[t] , 
WhenEvent[0.1 < t < 0.9 && x[t] >= 1, {Print[t], x[t] -> 0.2, dv[t] -> 1 - dv[t]}], x[0] == 0.9, dv[0] == 0}, {x, dv} , {t, 0, 1}, DiscreteVariables -> {dv}] ;
Plot[{X[t], DV[t]} , {t, 0, 1}, GridLines -> {None, {1}}]

enter image description here

$\endgroup$
1
  • $\begingroup$ Thanks! Seems like the secret sauce in your answer is the 1.01, not the Boole, because changing my original code to If[x[t] < 1.01 works the same way. So does x[t] < 1.00000000001 which is an easy fix and close enough. $\endgroup$
    – Chris K
    Commented May 29, 2019 at 19:16
2
$\begingroup$

I don't know enough about WhenEvent to say whether the behavior is a bug or not. As a workaround, you can introduce an auxiliary function, and modify the WhenEvent condition:

f[t_] = Piecewise[{{1, .1<t<.9}}, 2];
sol = NDSolveValue[
    {
    x'[t] == If[x[t] < 1, 4 x[t], 0], x[0] == .9,
    h[t] == x[t], h[0] == x[0],
    dv[0] == 0,
    WhenEvent[x[t]>=f[t], {Print[t], h[t] -> .2, dv[t] -> 1 - dv[t]}]
    },
    {x, dv},
    {t, 0, 1},
    DiscreteVariables -> {dv}
];

0.1

0.502359

Visualization:

Plot[First @ Through @ sol[t], {t, 0, 1}]

enter image description here

$\endgroup$
1
  • $\begingroup$ Interesting approach! I wonder if this forces NDSolve to use a DAE solver. $\endgroup$
    – Chris K
    Commented May 29, 2019 at 19:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.