I'd like to transform an InterpolatingFunction from NDSolve but can't figure out how. Here's an example. The equation I want to solve is
sol1 = NDSolve[{n'[t] == n[t] (1 - n[t]), n[0] == 10^-5}, n, {t, 0, 20}]
but for numerical reasons (not in this toy example), the log transformed equation
sol2 = NDSolve[{ln'[t] == (1 - E^ln[t]), ln[0] == Log[10^-5]}, ln, {t, 0, 20}]
works better. How can I transform the result in sol2 to match sol1 by taking E^sol2, without losing any accuracy?
EDIT: A slightly less minimal example:
This is in response to @MichaelE2's comment below. It's still a toy example, but illustrates the problem with interpolating only on the original grid.
This is the original model in natural units. The output is wrong because extra AccuracyGoal is needed.
sol3 = NDSolve[{n'[t] ==
Piecewise[{{n[t] (1 - n[t]), Mod[t, 100] < 60}, {-n[t], Mod[t, 100] >= 60}}],
n[0] == 10^-15}, n, {t, 0, 100}][[1]];
Plot[n[t] /. sol3, {t, 0, 100}]
Here's a better solution of the model:
sol3b = NDSolve[{n'[t] ==
Piecewise[{{n[t] (1 - n[t]), Mod[t, 100] < 60}, {-n[t], Mod[t, 100] >= 60}}],
n[0] == 10^-15}, n, {t, 0, 100}, AccuracyGoal -> \[Infinity]][[1]];
Plot[n[t] /. sol3b, {t, 0, 100}]
Here's a solution of the log-transformed model:
sol4 = NDSolve[{ln'[t] ==
Piecewise[{{(1 - E^ln[t]), Mod[t, 100] < 60}, {-1, Mod[t, 100] >= 60}}],
ln[0] == Log[10^-15]}, ln, {t, 0, 100}][[1]];
Plot[E^ln[t] /. sol4, {t, 0, 100}]
Now to try the two different ways to create an exponentiated InterpolatingFunction. This one uses the original grid and leads to a big artifact.
sol5IFN = Interpolation[Transpose[{ln["Grid"], Exp[ln["ValuesOnGrid"]]} /.First@sol4]];
Plot[sol5IFN[t], {t, 0, 100}]
Looking at the underlying grid makes it obvious what the problem is:
ListPlot[Transpose[{ln["Grid"][[All, 1]], Exp[ln["ValuesOnGrid"]]} /. First@sol4]]
The alternative approach of making your own grid suggested by @bbgodfrey works better:
sol6 = Interpolation[Table[{t, E^ln[t] /. sol4}, {t, 0, 100, 0.1}], InterpolationOrder -> 1];
Plot[sol6[t], {t, 0, 100}]
UPDATE 2: Higher InterpolationOrder
sol5IFN = Interpolation[Transpose[{ln["Grid"], Exp[ln["ValuesOnGrid"]]} /. First@sol4], InterpolationOrder -> 8];
Plot[sol5IFN[t], {t, 0, 100}, PlotRange -> {0, 1}]
sol3IFN
withInterpolationOrder -> 8
. With that change the corresponding relative error plot looks essentially identical to the second plot in my answer. Perhaps, you could rerun your comparison above with this change. $\endgroup$