How to make ode45 store/return only results of every n-th time step to reduce memory use?
10 views (last 30 days)
Show older comments
Hi,
I am trying to run a relatively long simulation with a small time step with ode45, meaning the resulting y matrix is very big. I want to keep the time step small for accuracy, but I do not need the result at each time step. When running a longer simulation the memory becomes a problem so makin the output sparser would be very beneficial.
Thank you!
1 Comment
Torsten
on 21 Feb 2025
Edited: Torsten
on 21 Feb 2025
I assumed that with "keeping the time step small" the OP meant that "RelTol" and "AbsTol" in his simulation were chosen small, not that the large output was a consequence of setting the "tspan" vector accordingly. The latter will not enhance precision as you correctly pointed out.
Accepted Answer
More Answers (2)
Walter Roberson
on 21 Feb 2025
Set your tspan to be a vector of three elements (more correctly, use more than 2 elements). When you call ode45(), set it up to ignore the t and y outputs.
Use odeset to create ode*() options that include OutputFcn . Have the output function use a persistent variable to count how many times it has been invoked. "most" of the time throw away the data. Every N'th time it is called, store the data in an accessible place.
OutputFcn will be called for each successful time step; you ignore most of the time steps and record every N'th.
Meanwhile the internal recording of the outputs will only happen at the times in your tspan, and you will have stripped down your tspan to the minimum needed so that it does not choose to record everything (tspan with 2 entries.)
11 Comments
Torsten
on 22 Feb 2025
Edited: Torsten
on 22 Feb 2025
For the given example, OutputFcn is called for the three times specified in "tspan". You can see the difference if you replace "tspan" by the vector that only contains the endpoints of the integration interval.
f = @(t,y) exp(-0.05*t)*sin(t);
options = odeset('OutputFcn',@myOutputFcn);
y0 = 0;
tspan = [0 0.5 1];
[T,Y] = ode45(f,tspan,y0,options);
tspan = [0 1];
[T,Y] = ode45(f,tspan,y0,options);
T
function status = myOutputFcn(t,y,flag)
status = 0;
t
end
Mike Hosea
on 22 Feb 2025
Edited: Mike Hosea
on 22 Feb 2025
Yes, it turns out that the outputFcn is only called if there is a non-empty set of outputs to transmit to it. I guess that is in keeping with it being literally an "output function" and not, more generically, a step callback function. Probably most use cases involve length(tspan)==2.
I have reported the documentation issue.
Mike Croucher
on 21 Feb 2025
Edited: Mike Croucher
on 21 Feb 2025
I would suggest trying the new ode interface The new solution framework for Ordinary Differential Equations (ODEs) in MATLAB R2023b » The MATLAB Blog - MATLAB & Simulink
One approach that might work for you is the new solutionFcn. This is covered in the blog post above but, for completeness, here's the example I used
myODE = ode(ODEFcn=@(t,y) exp(-0.05*t)*sin(t),InitialTime=0,InitialValue=0); % Define the ODE problem
solFcn = solutionFcn(myODE,0,20) % Use it to create a solutionFcn
I can now evaluate this wherever I like within the interval defined in the solutionFcn. E.g.
solFcn(15)
This way you can keep only the exact time points you want.
2 Comments
Torsten
on 21 Feb 2025
Edited: Torsten
on 21 Feb 2025
The OP's problem is that the ode integrator internally saves the solution for too many time steps such that available memory becomes low during a computation. I think this problem is not solved by your suggestion. Somewhere, the solution of the ODE must be saved at discrete times in order to make interpolation using the function handle "solFcn" after the computation has finished - and I don't see that this solution is somehow reduced in size by the code.
See Also
Categories
Find more on Ordinary Differential Equations in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!