# WhenEvent missing closely spaced roots

Background: In the code that I am running I have a large number of differential equations that are dependent on several parameters and I am solving these using NDSolve. As expected, as I change one of the key parameters in NDSolve the nature of the solutions changes.

To cut a long story short, I am hoping to find solutions to a wavefunction that has to be decaying so it can be normalised. By tuning the right parameters, I can find the values that allow the wavefunction to have evanescent behaviour. This involves using WhenEvent procedures to rule out solutions that become diverging or do not display the behaviour I want.

The Problem: I noticed that I wasn't getting the behaviour I expected in one given set of parameters. My WhenEvent was set up to count the number of roots a given function went through and to stop integration at the 2n+1th root (for some integer n that I control).

I noticed that the function crossed ever so slightly below the axes and indeed I checked it crossed by finding some small but distinctly negative values. However, WhenEvent did not recognise these crossings and consequently did not stop the integration as expected.

I browsed the Help Files to the section on WhenEvent and under Possible Issues I found the section on Arbitrarily Close Events. I followed the advice there to no avail, trying all the methods suggested and combinations thereof.

When I use the "DetectionMethod" -> "Interpolation" setting I get the error

NDSolve::ecboo: The value of event condition function at r = 0.0001000000000000632503453769700203791282421485553848150. was not True or False. The event will be considered inactive.

Minimal Working Example:

Copying my entire code into this page would not be of much use. I have come up with a small example in the form of a parabola that is just dipping below the origin:

NDSolve[{y'[x] - x^3 == 0, y[0] == -.0001,
WhenEvent[y[x] < 0, {"StopIntegration"}]}, y, {x, -3, 3}]


Plotting the above solution from -3 to 3 gives me the whole parabola, whereas I am expecting the solution to stop at x=0. The domain of y[x] also shows me that the range is [-3,3].

Why is the WhenEvent not picking up the two roots?

I know this is a very simplistic example and some of the solutions on the Help file could work but I am also looking for advice on what might be going wrong in my case. My solution does a very similar thing but its gradient is much more pronounced.

Reading up on the issue in other threads did not highlight a proper solution but this seems to be an issue on other versions too. I am working on version 10.3.0

Edit: So Michael2 fixed the problem with the minimal working example (never knew integration started from the boundary conditions!). However, the problems in my code are still present (the integration range is always positive so it was a bad example to choose).

In particular, whenever I let the Detection Method be Automatic the code runs and WhenEvents detect most root crossings. However, trying to change the method to Linear Interpolation I get:

NDSolve::ecboo: The value of event condition function at r = 0.0001000000000000632503453769700203791282421485553848150. was not True or False. The event will be considered inactive.

I have no idea what the error is telling me and why the condition is not evaluating as True or False with LinearInterpolation when it did before. For this reason I have not marked the question as answered.

• It's not clear to me why you would expect the integration to stop at x == 0, since this is not where the event you seem to be considering takes place. (I assume this is just a lack of precision; otherwise the simple way to stop is by integrating over {x, -3, 0}. See if I interpreted it right in my answer. However, I wasn't sure exactly what interval of integration you were seeking.) – Michael E2 Sep 24 '16 at 0:15
• The example was meant to mimic my code where a function dips very slightly below the axes so that WhenEvents cannot detect it. My actual interval is always positive. Thanks though :). – OldTomMorris Sep 24 '16 at 8:07
• One guess is that the step size is too large when the solution changes sign. You can control it with MaxStepFraction, MaxStepSize, PrecisionGoal, and AccuracyGoal. -- But it is also possible that there is an error in your code for WhenEvent, because that is what tends to lead to the error you report. One would have to have the code to examine to see whether that is the case. – Michael E2 Sep 24 '16 at 18:12
• I have tried playing with all those options but did not get rid of the instance. In particular, as expected, MaxStepSize slowed the computation right down. – OldTomMorris Sep 29 '16 at 9:18
• I have come up with a similar issue. Being related to the comment of @MichaelE2 I was playing with AccuracyGoal and PrecissionGoal. Surprisingly, when these two are small enough WhenEvent captures the crossing and stops the integration. However, when I crank up AG and PG for some other reasons, WhenEvent starts to miss some cases when the integration should be stopped. Any idea? – Boson Bear Jan 29 '19 at 16:25

First, one must realize that integration starts from the initial condition, which in the OP's case is at x == 0.

Second, the event y[x] < 0 is detected when y[x] changes from positive to negative, and not when it changes from negative to positive. Since initial condition y[0] is negative, the event won't happen unless y[x] becomes negative again, after it is positive.

Putting the first with the second, the event never happens. The standard way mathematics is taught has the independent variable almost always increasing. What's a little counter-intuitive, therefore, is that two integrations are performed by NDSolve, and one runs backwards from x == 0 to x == -3. In this direction, y[x] changes from negative to positive at around x == 0.141. Thereafter, as x decreases, y[x] never changes sign again. So the only times the sign of y[x] changes sign in the integrations as performed by NDSolve[] are when it changes from negative to positive.

The fix is to use the either y[x] == 0 or y[x] > 0, or possibly a composite event incorporating the initial condition, such as y[x] > 0 && x < 0.

Examples:

NDSolve[{y'[x] - x^3 == 0, y[0] == -.0001,
WhenEvent[y[x] > 0, {"StopIntegration"}]}, y, {x, -3, 3}]


NDSolve[{y'[x] - x^3 == 0, y[0] == -.0001,
WhenEvent[y[x] > 0 && x < 0, {"StopIntegration"}]}, y, {x, -3, 3}]


• Not quite the problem I was having, although I did learn something new today, thanks :). I guess the minimal working example was too minimal. The integration in my true code runs from 10^-6 to Infinity and I use WhenEvents to stop integration. Since that range is positive the above problem never comes up. – OldTomMorris Sep 24 '16 at 8:03