ODE - Save variables for every time step
Show older comments
Hello Guys,
I am stuck with saving time dependent variables inside a model function ... I was browing some already answered questions but none seems to help.
I have the following:
[t, f_val] = ode15s(@model,tspan,yeq);
That yields my f_val as a function of time.
But inside my model function I have also yy variable (time dependent) I would like to trace
function [f, yy] = model(t,yeq)
f= ... %some expression
yy= ... %some expression
How can I extract yy as a function of time?
Cordially
Answers (2)
Bjorn Gustavsson
on 8 Mar 2021
This is something that is (simplest?) done by calculating the second output once after you've integrated the ODE-system. Either in one fell swoop if your ODE-function can handle arrays for input of t and f:
[f_second_time_around_or_tilde, yy] = model(t,f_val);
Or you can quickly loop over t:
for i_t = numel(t):-1:1,
yy(i_t,:) = model(t(i_t),f_val(i_t,:));
end
Since the odeNN-functions take cunningly adaptive steps in time we cannot trivially save all the values of yy along the steps...
HTH
3 Comments
sko
on 8 Mar 2021
Bjorn Gustavsson
on 8 Mar 2021
What with the second loop-based suggestion? That explicitly calculates yy for every step in the solution you have...
sko
on 8 Mar 2021
sko
on 22 Apr 2021
10 Comments
Bjorn Gustavsson
on 22 Apr 2021
Write your function something like this:
[dcdt,Par1,Par2] = model(t,C_of_t,reaction_coeffs_etc)
k1 = reaction_coeffs_etc(1);
k2 = reaction_coeffs_etc(2);
dcdt = [-k1*C_of_t(1)*C_of_t(2);
-k1*C_of_t(1)*C_of_t(2);
k1*(k2/(1+k2))*C_of_t(1)*C_of_t(2);
k1*(1/(1+k2))*C_of_t(1)*C_of_t(2)]; % or whatever reactions you have...
par1 = something;
par2 = something_else;
if nargout > 1
Par1 = par1;
end
if nargout > 2
Par2 = par2;
end
HTH
sko
on 22 Apr 2021
Bjorn Gustavsson
on 22 Apr 2021
You simply loop over the solution (time, concentration) a second time after the call to ode15s:
[time,concentration] = ode15s(@(t,yeq)model(t,yeq,dr,nrp,Deff),timespan,yeq);
c=concentration';
for i_t = numel(t):-1:1,
[yy(i_t,:),PAR1(i_t),PAR2(i_t,:)] = model(time(i_t),concentration(i_t,:),dr,nrp,Deff);
end
Walter Roberson
on 22 Apr 2021
Therefore, I need to correct my model function so that not only it provides me calculated concentrations but also those other parameters.
NO . It is very unlikely you want to do what you are asking for.
Each step of ode45() invokes the ode function multiple times, with different parameters -- different boundary conditions and different times. ode45() in particular invokes the ode function 6 times for each step. A prediction is made using the results of the first 5 calls, and then cross-checked with a prediction made using the result of the 6th call included. If the 4th order projection agrees within tolerance with the 5th order projection, then the step is accepted and recorded, and if the 4th disagrees with the 5th too much, then the step is rejected and another attempt is made from the same starting point but with a shorter step. In areas that are changing rapidly, it is normal for several trials to be rejected.
The ode function is called for all of those locations -- the 5 intermediate locations at the best of times, and possibly a number of more times as a step fails as it encounters a steep region and has to "slow down" to accomodate.
Furthermore, the places that ode45 emits into the outputs are not necessarily anywhere that ode45 has called the ode function for; ode45 periodically makes projections and saves the output of the projections.
So, we have a situation where the ode function gets invoked many times at locations that will not be used in the final output, plus the final outputs might be at locations that the ode function was never called for.
You are asking for the intermediate values for all of the calls to be reported back to you. Which will include at locations that ode45 decided were too steep and never tried to travel to. And which will not include at locations tha ode45 reported back for but never actually evaluated at.
You are unlikely to have any use for all that output: it tells you about places you do not need to know about, and it does not tell you about places you need to know about.
On the other hand, the strategy @Bjorn Gustavsson is recommending is very effective: it gives you back information for exactly the locations that were reported back to you by ode45(), which is much more likely to be what you want to know.
sko
on 22 Apr 2021
Walter Roberson
on 22 Apr 2021
When you call
for i_t = numel(time):-1:1,
[yy(i_t,:),PAR1(i_t),PAR2(i_t,:)] = model(time(i_t),concentration(i_t,:),dr,nrp,Deff);
end
is it complaining about dimension mismatches in the assignments? Could you confirm that numel(t) > 1 ? After that loop, what do you see in the code as size(PAR1) and size(PAR2) ?
sko
on 22 Apr 2021
Bjorn Gustavsson
on 22 Apr 2021
Yes, the in solution I provided I couldn't now what the dimensions of your additional outputs were expected to be, therefore I opted to provide something that you could easily adjust to match the dimensions of your outputs (one or the other parameter might even have different dimensions at different time-steps as far as I could see...).
Categories
Find more on Structural Mechanics 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!