How to implement a stopping condition for scipy.solve_ivp (rather than integrating for a set time)? - scipy

Currently my solve_ivp call requires a temperature range, i.e.
sol = solve_ivp(df, t, x0, args=system_constants, method='Radau')
where t is the time range solve_ivp should integrate across, df is the differential equation (the right hand side), and x0 is the initial condition.
However I would like to integrate until the solution of the differential equation being integrated reaches a certain value.
One thought I had on doing this was using a for loop with small time intervals, and checking the solution after each integration time interval, with the condition that integration should stop if the solution exceeds a certain value.
The system in question is actually a solid heating up. I want to heat until the solid reaches a certain temperature. I could manually check the solution array for this but I need it in code format also
Is there a standard way to implement a stopping condition like this?

Related

Solving Delayed Differential Equations using ode45 Matlab

I am trying to solve DDE using ode45 in Matlab. My question is about the way that I am solving this equation. I don't know if I am right or I am wrong and I should use dde23 instead.
I have a following equation:
xdot(t)=Ax+BU(t-td)+E(t) & U(t-td)=Kx(t-td) & K=constant
Normally, when I don’t have delay on my equation, I solve this using ode45. Now with delay on my equation, again I am using ode45 to get the result. I have the exact amount of U(t-td) at each step and I replace its amount and solve the equation.
Is my solution correct or should I use dde23?
You have two problems here:
ode45 is a solver with adaptive step size. This means that your sampling steps are not necessarily equivalent to the actual integration steps. Instead, the integrator splits a sampling step into several integration steps as needed to achieve the desired accuracy (see this question on Scientific Computing for more information).
As a consequence, you may not provide correct delayed value of U at each step of the integration, even if you believe to do so.
However, if your sampling steps are sufficiently small, you will indeed have one time step per sampling step. The reason for this is that you effectively disable the adaptive integration by making your time step smaller than needed (and thus waste computation time).
Higher-order Runge–Kutta methods such as ode45 do not only make use of the value of the derivative at each integration step, but also evaluate it in-between (and no, they cannot provide a usable solution for this in-between time step).
For example, suppose that your delay and integration step are td=16. To make the integration step from t=32 to t=48, you need to evaluate U not only at t = 32−16 = 16 and t = 48−16 = 32, but also at t = 40−16 = 24. Now, you might say: Okay, let’s integrate such that we have an integration step at all those time points. But for these integration steps, you again need steps in the middle, e.g., if you want to integrate from t=16 to t=24, you need to evaluate U at t=0, t=4, and t=8. You get a never-ending cascades of smaller and smaller time steps.
Due to problem 2, it is impossible to provide the exact states from the past with any but a one-step integrator – using which is probably not a good idea in your case. For this reason, it is inevitable to use some sort of interpolation to obtain past values if you want to integrate DDEs with a multi-step integrator. dde23 does this in a sophisticated way using a good interpolation.
If you only provide U at the integration steps, you are essentially performing a piecewise-constant interpolation, which is the worst possible interpolation and therefore requires you to use very small integration steps. While you can do this if you really want to, dde23 with its more sophisticated piecewise cubic Hermite interpolation can work with much larger time steps and integrate adaptively, and therefore will be much faster. Also, it’s less likely that you somehow make a mistake. Finally, dde23 can deal with very small delays (smaller than the integration step), if you’re into that sort of thing.

Solving ODEs in NetLogo, Eulers vs R-K vs R solver

In my model each agent solves a system of ODEs at each tick. I have employed Eulers method (similar to the systems dynamics modeler in NetLogo) to solve these first order ODEs. However, for a stable solution, I am forced to use a very small time step (dt), which means the simulation proceeds very slowly with this method. I´m curious if anyone has advice on a method to solve the ODEs more quickly? I am considering implementing Runge-Kutta (with a larger time step?) as was done here (http://academic.evergreen.edu/m/mcavityd/netlogo/Bouncing_Ball.html). I would also consider using the R extension and using an ODE solver in R. But again, the ODEs are solved by each agent, so I don´t know if this is an efficient method.
I´m hoping someone has a feel for the performance of these methods and could offer some advice. If not, I will try to share what I find out.
In general your idea is correct. For a method of order p to reach a global error level tol over an integration interval of length T you will need a step size in the magnitude range
h=pow(tol/T,1.0/p).
However, not only the discretization error accumulates over the N=T/h steps, but also the floating point error. This gives a lower bound for useful step sizes of magnitude h=pow(T*mu,1.0/(p+1)).
Example: For T=1, mu=1e-15 and tol=1e-6
the Euler method of order 1 would need a step size of about h=1e-6 and thus N=1e+6 steps and function evaluations. The range of step sizes where reasonable results can be expected is bounded below by h=3e-8.
the improved Euler or Heun method has order 2, which implies a step size 1e-3, N=1000 steps and 2N=2000 function evaluations, the lower bound for useful step sizes is 1e-3.
the classical Runge-Kutta method has order 4, which gives a required step size of about h=3e-2 with about N=30 steps and 4N=120 function evaluations. The lower bound is 1e-3.
So there is a significant gain to be had by using higher order methods. At the same time the range where step size reduction results in a lower global error also gets significantly narrower for increasing order. But at the same time the achievable accuracy increases. So one has to knowingly care when the point is reached to leave well enough alone.
The implementation of RK4 in the ball example, as in general for the numerical integration of ODE, is for an ODE system x'=f(t,x), where x is the, possibly very large, state vector
A second order ODE (system) is transformed to a first order system by making the velocities members of the state vector. x''=a(x,x') gets transformed to [x',v']=[v, a(x,v)]. The big vector of the agent system is then composed of the collection of the pairs [x,v] or, if desired, as the concatenation of the collection of all x components and the collection of all v components.
In an agent based system it is reasonable to store the components of the state vector belonging to the agent as internal variables of the agent. Then the vector operations are performed by iterating over the agent collection and computing the operation tailored to the internal variables.
Taking into consideration that in the LOGO language there are no explicit parameters for function calls, the evaluation of dotx = f(t,x) needs to first fix the correct values of t and x before calling the function evaluation of f
save t0=t, x0=x
evaluate k1 = f_of_t_x
set t=t0+h/2, x=x0+h/2*k1
evaluate k2=f_of_t_x
set x=x0+h/2*k2
evaluate k3=f_of_t_x
set t=t+h, x=x0+h*k3
evaluate k4=f_of_t_x
set x=x0+h/6*(k1+2*(k2+k3)+k4)

3rd-order rate limiter in Simulink? How to generate smooth triggered signals?

First for those, who are not familiar with Simulink, there is a imaginable outside-Simulink partial solution:
I need to create a vector satisfying the following conditions:
known initial value a1
known final value a2
it has a pre-defined step size, but the length is not pre-determined
the first derivative over the whole range is limited to v_max resp. -v_max
the second derivative over the whole range is limited to a_max resp. -a_max
the third derivative over the whole range is limited to j_max resp. -j_max
at the first and the final point all derivatives are zero.
Before you ask "what have you tried so far", I just had the idea to solve it outside Simulink and I tried the whole stuff below ;)
But maybe you guys have a good idea, while I keep working on my own solution.
I'd like to generate smooth ramp signals (3rd derivative limited) based on a trigger signal in Simulink.
To get a triggered step I created a triggered subsystem propagating the trigger output. It looks like that:
But I actually don't want a step, I need a very smooth ramp with limited derivatives up to the 3rd order. The math behind is:
displacement: x
speed: v = x'
acceleration: a = v' = x''
jerk: j = a' = v'' = x'''
(If this looks familiar to you, I once had a very similar question. I thought about a bounty on it, but after the necessary edit of the question both answers would have been invalid)
As there are just rate limiters of 1st order, I used two derivates and a double integration to resolve my problem. But there is a mayor drawback, I can not ignore anymore. For the sake of illustration I chose a relatively big step size of 0.1.
The complete minimal example (Fixed Step, stepsize: 0.1, ode4): Download here
It can be seen, that the signal not even reaches the intended step height of 10 and furthermore is not constant at the end.
Over the development process of my whole model, this approach was satisfactory enough for small step sizes. But I reached the point where I really need the smooth ramp as intended. That means I need a finally constant signal at exactly the value, specified by the step height gain.
I already spent days to resolve the problem, and hope to fine some help here now.
Some of my ideas:
dynamically increase the step height over the actual desired value and saturate the final output. If the rate limits,step height and the simulation step size wouldn't be flexible one could probably find a satisfying solution. But as everything has to be flexible, there are too much cases where the acceleration and jerk limit is violated.
I tried to use the Matlab function block and write my own 3rd order rate limiter. Though it seems possible for me for the trigger moment, I have no solution how to smooth the "deceleration" at the end of the ramp. Also I'd need C-compilers, which would make it hard to use my model on other systems without problems. (At least I think so.)
The solver can not be changed siginificantly (either ode3 or ode4) and a fixed step size is mandatory (0.00001 to 0.01).
Currently used, not really useful approach:
For a dynamic amplification of 1.07 I get the following output (all values normalised on their limits):
Though the displacement looks nice, the violation of the acceleration limit is very harmful.
For a dynamic amplification of 1.05 I get the following output (all values normalised on their limits):
The acceleration stays in its boundaries, but the displacement does not reach the intended value. (not really clear in the picture) The jerk is still to big. (I could live with that, but it's not nice)
So it appears to me that a inside-Simulink solutions is far from reality. Any ideas how to create a well-behaving custom function block?
Simulation step size, step height, and the rate limits are known before the simulation starts. (But I have a lot of these triggered smooth ramps in a row, it should feed a event-discrete control). So I could imagine to create the whole smooth ramp outside simulink and save it as a timeseries object and append it on the current signal when the trigger is activated.
The problems you see are because the difference is not conditioned very well.
Taking the difference amplifies the numerical that exists in your simulation.
Also the jerk will always be large if you try to apply an actual step.
I guess for your approach it would be better to work the other way around:
i.e. make a jerk, acceleration and velocity with which your step is achieved.
I think your looking for something like the ref3 block:
http://www.dct.tue.nl/home_of_ref3.htm
Note the disclaimer on the site and that it is a little cumbersome to use.
An easy (yet to be improved) way is to use a rate limiter and then a state space model with a filter. From the filter you get the velocity, which in turn you can apply a rate limiter to. You continue with rate-limiter and filters until you have the desired curve.
Otherwise you can come up with numerical rate-limiters of higher order using ie runge kutta formulas or finite differences. However it was pointed out, that they may suffer from bad conditioning.
What I usually do is to use one rate limiter and a filter of 3rd Order and just tune the time constant (1 tripple pole), such that my needs are met. This works well, esp
Integrator chains of length > 1 are unstable!
There is a huge field of research dealing with trajectory planning. The easiest way might be to use FIR filters (Biagotti et al) or to implement an online trajectory planner (Ezair et al 2014 / Knierim et al 2012).

How to smooth rectangular signal with high order rate-limiter in Simulink?

Imagine I have a rectangular reference value for the position/displacement x and I need to smooth it.
The math for translatoric movements is quite simple:
speed: v = x'
acceleration: a = v' = x''
jerk. j = a' = v'' = x'''
I need to limit all these values. So I thought about using rate limiters in Simulink:
This approach works perfect for ramp signals, as you can see in the following output:
BUT, my reference signals for x are no ramps, they are rectangles/steps. Hence the rate limiters are not working, because the derivatives they get to limit are already infinite and Simulink throws an error. How can I resolve this problem? Is there actually a more elegant way to implement the high order rate-limiters? I guess this approach could be unstable in some cases.
continue reading: related question
Even though it seems absurd, the following approach is working: integration and instant derivation does the trick:
leading to:
More elegant, faster and simpler solutions for the whole smoothing problem are highly appreciated!
It's generally not a good idea to differentiate signals in Simulink because of numerical issues, I would advise to start with the higher order derivatives (e.g. acceleration) and integrate, much more robust numerically. This is what the doc about the derivative block says:
The Derivative block output might be very sensitive to the dynamics of
the entire model. The accuracy of the output signal depends on the
size of the time steps taken in the simulation. Smaller steps allow a
smoother and more accurate output curve from this block. However,
unlike with blocks that have continuous states, the solver does not
take smaller steps when the input to this block changes rapidly.
Depending on the dynamics of the driving signal and model, the output
signal of this block might contain unexpected fluctuations. These
fluctuations are primarily due to the driving signal output and solver
step size.
Because of these sensitivities, structure your models to use
integrators (such as Integrator blocks) instead of Derivative blocks.
Integrator blocks have states that allow solvers to adjust step size
and improve accuracy of the simulation. See Circuit Model for an
example of choosing the best-form mathematical model to avoid using
Derivative blocks in your models.
See also Best-Form Mathematical Models for more details.
I was trying to do something similar. I was looking for a "Smooth Ramp". Here is what I found:
A simpler approach is to combine ramp with a second order lag. Then the signal approachs s-shape. And your derivatives will exist and be smooth as well. Only thing to remember is that the 2nd or lag must be critically damped.
Y(s) = H(s)*X(s) where H(s) = K*wo^2/(s^2 + 2*zeta*wo*s + wo^2). Here you define zeta = 1.0. Then the s-shape is retained for any K and wo value. Note that X(s) has already been hit by a ramp. In matlab or any other tools, linear ramp and 2nd lag are standard blocks.
Good luck!
I think the 'Transfer Fcn' block is what you're looking for.
If you leave the equation in the default form 1/(s+1) you have a low-pass filter which can be tuned to what you need by changing the numerator and denominator coefficients.

Accuracy of "Events" in ode45 in Matlab

I'm consider a problem of integrating until an event occurs using ode45 in Matlab, as in here:
http://www.mathworks.com/help/techdoc/math/f1-662913.html#f1-670140
Is there a way to control how accurately Matlab computes the event location? More specifically, the events tell you to solve on ODE until one finds a zero of the value parameter, but how small is value? Is there a way to specify how small I want value to be when the integration terminates?
Is there a way to control how accurately Matlab computes the event
location?
The short answer appears to be "no, but it's at machine precision anyway". Matlab's ode45 (and the rest, like ode15s, ode23, etc.) calls a function called odezero, which does the work of computing the zero events of the ODE integrators. Here are the relevant lines in odezero where the tolerance is set:
tol = 128*max(eps(t),eps(tnew));
tol = min(tol, abs(tnew - t));
From this, you can see two things: (1) there is no dependence on any user options and (2) even if you had control, you couldn't set it any smaller because the tolerance is 128*eps.
Is there a way to specify how small I want value to be when the
integration terminates?
Matlab's ODE event detectors don't look for value going to zero or getting close to zero, it looks for it crossing zero. If you want to look for a particular value of the ODE crossing a certain value, then have the event function return the difference between the solution and the desired threshold.