Is there any possibility to implement a structure like a ProgressIndicator into NDSolve?

Monitor[NDSolve[{eq, bc1, bc2, ic}, 
  z, {t, 0, 100}, {x, -Lx, Lx}, {y, -Ly, Ly}, Method -> mol, 
  StepMonitor :> (time = t)], 
 ProgressIndicator[time/100]]

enter image description here

This doesn't appear to slow down the evaluation in any significant way:

RepeatedTiming[
  NDSolve[{eq, bc1, bc2, ic}, 
   z, {t, 0, 100}, {x, -Lx, Lx}, {y, -Ly, Ly}, Method -> mol], 60]

RepeatedTiming[
 Monitor[NDSolve[{eq, bc1, bc2, ic}, 
   z, {t, 0, 100}, {x, -Lx, Lx}, {y, -Ly, Ly}, Method -> mol, 
   StepMonitor :> (time = t)], ProgressIndicator[time/100]], 60]

RepeatedTiming[
 Monitor[NDSolve[{eq, bc1, bc2, ic}, 
   z, {t, 0, 100}, {x, -Lx, Lx}, {y, -Ly, Ly}, Method -> mol, 
   EvaluationMonitor :> (time = t)], ProgressIndicator[time/100]], 60]

11.46

12.

11.9


Here are a few versions I use:

1)

showStatus[status_] := 
  LinkWrite[$ParentLink, 
   SetNotebookStatusLine[FrontEnd`EvaluationNotebook[], 
    ToString[status]]];
clearStatus[] := showStatus[""];
clearStatus[]

NDSolve[{D[u[t, x], t] == D[u[t, x], x, x], u[0, x] == 0, 
  u[t, 0] == Sin[t], u[t, 5] == 0}, u, {t, 0, 10}, {x, 0, 5}, 
 EvaluationMonitor :> showStatus["t = " <> ToString[CForm[t]]]];

clearStatus[]

The status is reported in the lower left corner of the notebook.

2)

tEnd = 100;
ProgressIndicator[Dynamic[currentTime], {0, tEnd}]

currentTime = 0;
NDSolve[{D[u[t, x], t] == D[u[t, x], x, x], u[0, x] == 0, 
  u[t, 0] == Sin[t], u[t, 5] == 0}, u, {t, 0, tEnd}, {x, 0, 5}, 
 EvaluationMonitor :> (currentTime = t;)]

3)

Monitor[NDSolve[{D[u[t, x], t] == D[u[t, x], x, x], u[0, x] == 0, 
   u[t, 0] == Sin[t], u[t, 5] == 0}, u, {t, 0, 100}, {x, 0, 5}, 
  MaxStepSize -> 0.01, 
  EvaluationMonitor :> (monitor = Row[{"t = ", CForm[t]}])], monitor]

I hope you find something to your liking.


You should be aware of the fact that using either StepMonitor or EvaluationMonitor could considerably slow down the execution of NDSolve, so the progress indication might come at a price. As there might be several evaluations per step, StepMonitor will be excecuted less often than EvaluationMonitor so might be a better choice in most cases. It also is one of those cases where restricting the update of the progress indiciation might make sense. Of course, the more expensive a single step/evaluation within NDSolve is, the less will the percentual effort for the updates. Here are some example with which you can experiment, of course timings might be very different for different problems...

A simple example from the documentation:

 p = 20; tmax = 100;
 runNDSolve[opts___] := NDSolve[
   {x''[t] + x'[t]/10 + x[t]/(1 + x[t]^2) == Sin[t], x[0] == 1, 
   x'[0] == 0}, x, {t, 0, tmax},
   PrecisionGoal -> p, AccuracyGoal -> p, WorkingPrecision -> 2*p,
   MaxSteps -> Infinity, 
   Method -> {"ExplicitRungeKutta", "DifferenceOrder" -> 8},
   opts
]

you might adjust the precision to adjust runtimes to a few seconds so you can see what actually happens. Here is a run with no monitoring at all as a reference:

 AbsoluteTiming[runNDSolve[];]

Compare EvaluationMonitor to StepMonitor:

 AbsoluteTiming[runNDSolve[EvaluationMonitor :> (tt = t)];]
 AbsoluteTiming[runNDSolve[StepMonitor :> (tt = t)];]

For this example on my computer the restriction of dynamic updating doesn't make much difference, but I have seen examples where doing this was crucial to not slow down the evaluation unacceptably, which can easily happen if you do something more expensive than update a progressbar, like e.g. show a plot.

 tt = 0;
 PrintTemporary@ProgressIndicator[Dynamic[tt], {0, tmax}];
 AbsoluteTiming[runNDSolve[StepMonitor :> (tt = t)];]


 tt = 0;
 PrintTemporary@ProgressIndicator[Dynamic[
    Refresh[tt, UpdateInterval -> 1, TrackedSymbols :> {}]
 ], {0, tmax}];
 AbsoluteTiming[runNDSolve[StepMonitor :> (tt = t)];]

Here is a version of Feyre's elegant solution using Monitor which restricts the update to a given interval. AFAIK this is not really documented but doesn't come as a surprise when assuming that the second argument will be wrapped in a Dynamic at some point:

 AbsoluteTiming[
   Monitor[runNDSolve[StepMonitor :> (tt = t)], 
     Refresh[ProgressIndicator[tt/tmax], UpdateInterval -> 1, 
       TrackedSymbols :> {}]];]