# Forcing NDSolve not to store full solution, in order to save memory

When using NDSolve to integrate a time-varying dynamical system (ie, an initial value problem), I often only care about the final value of the dependent variables at the end of integration. However, NDSolve returns interpolation functions, implying that it is storing all intermediate values of the dynamical variables in memory.

Is there a way to save memory by forcing NDSolve to only return the final values of the dependent variables?

• I assumed by using NIntegrate to integrate a time-varying dynamical system you mean you did NDSolve, right? if not, then it would be better to post MWE. – Nasser Jun 9 '20 at 12:31
• You are right, my regrets---I edited the question. – wil3 Jun 9 '20 at 19:29

## 3 Answers

Inspired from Nasser's answer:

It's possible to return only the last (or some other specific values) value from NDSolve.

Try

sol3 = NDSolveValue[{y''[x] + Sin[x]*x == 5, y == 1, y' ==0},y, {x, 4.5, 5}]
ByteCount[sol3](*16*)


Is there a way to save memory by forcing NIntegrate to only return the final values of the dependent variables?

One way could be to just give it the small end range of interest, this way the interpolation function will have much smaller size. You can still give initial conditions at say x=0 but tell it to given solution starting at much larger x value, and it will still work. The x_start in {x,x_start,x_end} does not have to be the same as the initial value of x.

For example, instead of

sol = NDSolveValue[{y''[x] + Sin[x]*x == 5, y == 1, y' == 0}, y, {x, 0, 5}]
Plot[sol[x], {x, 0, 5}] sol2 = NDSolveValue[{y''[x]+Sin[x]*x==5,y==1,y'==0},y,{x,4.5,5}]
Plot[sol2[x],{x,4.5,5},AxesOrigin->{0,0}] If you compare sol and sol2, you'll see sol2 has less data in it.

 ByteCount[sol]
(*3984*)

ByteCount[sol2]
(*1936*)

• It's possible to return only the last value of NDSolve: sol3 = NDSolveValue[{y''[x] + Sin[x]*x == 5, y == 1, y' == 0}, y, {x, 4.5, 5}] ! ByteCount[sol3](*16*) – Ulrich Neumann Jun 9 '20 at 15:22
• @UlrichNeumann That's a good point which would be worthy of its own answer, perhaps. – MarcoB Jun 9 '20 at 15:28
• @MarcoB Thanks for your hint. – Ulrich Neumann Jun 9 '20 at 15:31

I feel some clarification is needed to the answers by @Nasser and @UlrichNeumann. There's not really much difference in the memory used by either. @UlrichNewmann's sol3 = NDSolveValue[..., y,...] seems basically to be syntactic sugar for sol3 = NDSolveValue[..., y,...]; sol3 = sol3. The main memory saving comes from @Nasser's {x, 4.5, 5}, instead of which {x, 5, 5} would give even more memory savings.

Examples: I've extended the domain so that the differences would be more noticeable.

@UlrichNeumann's method:

Quit[]

$HistoryLength = 0; MaxMemoryUsed[] (* 65508912 -- baseline *) sol3 = NDSolveValue[{y''[x] + Sin[x]*x == 1/1000, y == 1, y' == 0}, y, {x, 100000, 200000}]; ByteCount[sol3] MaxMemoryUsed[] (* 16 235687584 *) MemoryInUse[] (* 82906632 *) Quit[]  @Nasser's method. Note that the max memory usage and the memory in use after sol3 = sol3 are similar. $HistoryLength = 0;
MaxMemoryUsed[]
(*  65508848 -- baseline  *)

sol3 = NDSolveValue[{y''[x] + Sin[x]*x == 1/20, y == 1,
y' == 0}, y, {x, 100000, 200000}];
ByteCount[sol3]
MaxMemoryUsed[]
(*
59626536
238685400
*)

MemoryInUse[]
(*  142533152  *)

sol3 = sol3;
ByteCount[sol3]
(*  16  *)

MemoryInUse[]
(*  82906320  *)


The equivalent of using {x, 5, 5} with @UlrichNeumann's method. Note that the max memory used is just a little above the memory in use.

Quit[]

\$HistoryLength = 0;
MaxMemoryUsed[]
(*  65508848 -- baseline  *)

sol3 = NDSolveValue[{y''[x] + Sin[x]*x == 1/20, y == 1,
y' == 0}, y, {x, 200000, 200000}];
ByteCount[sol3]
MaxMemoryUsed[]
(*
16
85011648
*)

MemoryInUse[]
(*  82640112  *)