TransWikia.com

When does NDSolve issue zero step size error NDSolve::ndsz?

Mathematica Asked on March 1, 2021

I want to detect directly when step size becomes "effectively" zero. The below example from the documentation throws the error message as expected:

s = {};
NDSolve[{(2 - f[x]) f'[x] == f[x], f[0] == 1}, f, {x, 0, 5}, StepMonitor :> AppendTo[s, x]];

NDSolve::ndsz: At x == 0.3862940268757776`, step size is effectively zero; singularity or stiff system suspected.

The below code indicates that none of the actual steps taken has zero length.

AnyTrue[Differences@s, PossibleZeroQ]

(* False *)

How does NDSolve decide that the step size is zero? I can of course capture the NDSolveValue::ndsz error, but I want to know when exactly (depending on what parameters) the error is issued. In some extreme cases, NDSolve may generate an InterpolatingFunction solution that has practically zero domain length (but not according to PossibleZeroQ).

One Answer

Update 2021.01.09: I figured out how to examine the step size that is effectively zero.

The NDSolve::ndsz results when adding the next step h to the current value of x results in a value equal to x. Since Equal is compared with tolerance, adding h is like adding zero. Hence the "step size is effectively zero." (This tolerance does not depend on Internal`$EqualTolerance. Either NDSolve resets Internal`$EqualTolerance or it is internally hard-coded. I've tested several examples, and the behavior is consistent with a tolerance equal to the default value of Internal`$EqualTolerance.)

{state} = 
  NDSolve`ProcessEquations[{(2 - f[x]) f'[x] == f[x], f[0] == 1}, 
   f, {x, 0, 5}];
NDSolve`Iterate[state, 5];
solIF = f /. NDSolve`ProcessSolutions[state];

NDSolve`Iterate::ndsz : At x == 0.3862940268757776, step size is effectively zero; singularity or stiff system suspected.

lastcoord = solIF@"Coordinates" // First // Last
nexth = state@"TimeStep"["Forward"]
lastcoord == lastcoord + nexth
(*
  0.386294        <-- x
  3.35604*10^-15  <-- h
  True            <-- x == x + h
*)

Original answer:

A short answer to support Akku14's remark: "...a step size that is too small for numerically reliable calculations." (docs for NDSolve::ndsz).

The last step when NDSolve stops (in this case, with LSODA method) is usually a few hundred times the relative epsilon for the working precision ($approx 2 times 10^{-p}$). I've seen a wide range from less than ten to almost 1000 times epsilon.

sol = NDSolve[{(2 - f[x]) f'[x] == f[x], f[0] == 1}, f, {x, 0, 5}];
With[{steps = f["Grid"] /. sol // Flatten},
 Last@Differences[steps]/(Last@steps*2*10^-Precision[sol])]
(*  385.069  *)

I think, at least with LSODA, the problem is that the following is probably true:

You do not see the step size that causes the integration to stop.

It's the next step that would be effectively zero. One can see the stiffness develop in the rather rapid decrease of step size, the large gaps being from repeated error test failures:

With[{steps = f["Grid"] /. sol // Flatten},
  Differences[steps]] // ListLogPlot

I don't know how (or if) you can get out of LSODA data about its current state. You could test when the steps size gets below 1000 times epsilon. That seems to be a possible threshold.

Correct answer by Michael E2 on March 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP