This handles the "Local Taylor series"
and "Chebyshev"
interpolation methods, but not the packed or unpacked "Hermite"
ones. One thing I would recommend, and implemented below, is not to worry about cutting off the interpolation exactly at tmin
or tmax
. Rather, take the smallest interval containing tmin
and tmax
with endpoints on the interpolation grid. Actually the code below might include one more grid point at each end than is necessary. This adds very little overhead. On the other hand, dealing with dividing a subinterval with these methods might be a much bigger pain than it's worth. In any case, the function below preserves these (more accurate!) interpolation methods. It seems a shame to throw away the extra accuracy. One might do it if speed is more important than accuracy.
ClearAll[ifTake];
dupeLast[list_] := Append[list, Last@list];
ifTake[if_InterpolatingFunction, {tmin_?NumericQ, tmax_?NumericQ}] /;
MatchQ[if["InterpolationMethod"], "Local Taylor series" | "Chebyshev"] :=
Module[{coords, newif = Hold @@ if, span},
coords = First@if["Coordinates"];
span = Clip[
SparseArray[UnitStep[coords - tmin] UnitStep[tmax - coords]][
"AdjacencyLists"][[{1, -1}]] + {-1, 1}, {1, Length@coords}];
newif[[1]] = {coords[[span]]};
(*newif[[2,{2,3}]]={??};*) (* might need to update flags/deriv. order? *)
newif[[2, 4]] = 1 + Differences@span;
newif[[3]] = Developer`ToPackedArray@{coords[[Span @@ span]]};
newif[[4]] = Join[
{if[[4, First@span, 1 ;; 2]]},
if[[4, First@span + 1 ;; Last@span]]
];
newif[[5, 1, 1]] = Join[
{{1}},
1 + if[[5, 1, 1, First@span + 1 ;; Last@span]] -
if[[5, 1, 1, First@span, -1]] // dupeLast
];
newif[[5, 1, 2]] = Join[
{Automatic},
if[[5, 1, 2, First@span + 1 ;; Last@span]] // dupeLast
];
InterpolatingFunction @@ newif
];
OP's first example:
if1 = n /.
NDSolve[{n'[t] == n[t] (1 - n[t - 2]), n[0] == 0.1},
n, {t, 0, 20000}, MaxSteps -> ∞][[1]];
if1["InterpolationMethod"]
(* "Local Taylor series" *)
ifTake[if1, {0.5, 1.5}] // AbsoluteTiming
(* {0.028446, InterpolatingFunction[{{0.478428, 1.53819}}, <>]} *)
ifTake[if1, {1000.5, 1010.5}] // AbsoluteTiming
(* {0.03142, InterpolatingFunction[{{1000.46, 1010.55}}, <>]} *)
Chebyshev example:
if3 = NDSolveValue[{y''[x] + y[x] == 0, y[0] == 1, y'[0] == 0},
y, {x, 0, 100}, InterpolationOrder -> All, Method -> "Extrapolation"];
if3["InterpolationMethod"]
(* "Chebyshev" *)
ifTake[if3, {10.5, 11.5}]
(* InterpolatingFunction[{{9.03213, 12.7461}}, <>] *)