How to make ode45 store/return only results of every n-th time step to reduce memory use?

10 vues (au cours des 30 derniers jours)
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 commentaire
Torsten
Torsten le 21 Fév 2025
Modifié(e) : Torsten le 21 Fév 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.

Connectez-vous pour commenter.

Réponse acceptée

Torsten
Torsten le 21 Fév 2025
Modifié(e) : Torsten le 21 Fév 2025
You can specify the times when the solution should be saved in the input variable "tspan" to "ode45".
And you should test whether "ode15s" can make larger time steps - maybe your system is stiff so that "ode45" is not suited as solver.

Plus de réponses (2)

Walter Roberson
Walter Roberson le 21 Fév 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 commentaires
Torsten
Torsten le 22 Fév 2025
Modifié(e) : Torsten le 22 Fév 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);
t = 1×2
0 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 0.5000
t = 1
t = []
tspan = [0 1];
[T,Y] = ode45(f,tspan,y0,options);
t = 1×2
0 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.0250 0.0500 0.0750 0.1000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.1250 0.1500 0.1750 0.2000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.2250 0.2500 0.2750 0.3000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.3250 0.3500 0.3750 0.4000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.4250 0.4500 0.4750 0.5000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.5250 0.5500 0.5750 0.6000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.6250 0.6500 0.6750 0.7000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.7250 0.7500 0.7750 0.8000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.8250 0.8500 0.8750 0.9000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = 1×4
0.9250 0.9500 0.9750 1.0000
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
t = []
T
T = 41×1
0 0.0250 0.0500 0.0750 0.1000 0.1250 0.1500 0.1750 0.2000 0.2250
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
function status = myOutputFcn(t,y,flag)
status = 0;
t
end
Mike Hosea
Mike Hosea le 22 Fév 2025
Modifié(e) : Mike Hosea le 22 Fév 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.

Connectez-vous pour commenter.


Mike Croucher
Mike Croucher le 21 Fév 2025
Modifié(e) : Mike Croucher le 21 Fév 2025
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
solFcn = function_handle with value:
@ode.solutionFcn/interpolate
I can now evaluate this wherever I like within the interval defined in the solutionFcn. E.g.
solFcn(15)
ans = 1.3404
This way you can keep only the exact time points you want.
  2 commentaires
Torsten
Torsten le 21 Fév 2025
Modifié(e) : Torsten le 21 Fév 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.
Mike Croucher
Mike Croucher le 22 Fév 2025
Yes, you are right! Sorry for the noise

Connectez-vous pour commenter.

Produits


Version

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by