I recently had this problem with some code of mine. The 'simplest' solution is to do the following, firstly once the solution reaches 0, you have to keep it at 0,
thus change
dx = 1/(1+y*z) - x;
to (notice where the x == 0
case is evaluated)
if x > 0
dx = 1/(1+y*z) - x;
else % if x <= 0
dx = 0;
end
or maybe to (depending on why it may never be 0)
dxTmp = 1/(1+y*z) - x;
if x > 0
dx = dxTmp;
elseif dxTmp > 0
% x becomes positive again
dx = dxTmp;
else
dx = 0;
end
Note however that this creates a jump discontinuity in the first derivative, which when the DDE solver reaches the point of having t - delay
near this point, it does not solve it very efficiently unless it knows the exact spot where this discontinuity is (usually you have use an extra option of telling Matlab where it is, but if you follow the steps below, then that will not be needed).
To determine the place of this discontinuity you need to use the DDE option of events (scroll down to 'Event Location Property', you can also look at these examples, one of those examples actually deals with a similar system where negative values are not allowed in an ODE - events for ODEs and DDEs are almost identical). Basically an event is a Matlab function with a vector output, each one of the entries of the vector is some or other evaluation of your variables; at each step Matlab checks if one of them eqauls 0, when one of them equal 0 the DDE stops and returns a solution up to that point, from which you must restart the DDE with that partial solution as your history, i.e. instead of running
sol = dde23(ddefun, lags, history, [t0 tEnd], options);
you run (notice sol
and t0
changed)
sol = dde23(ddefun, lags, sol, [tCurrent tEnd], options);
In this case one of the vector's entries is going to be x
(as you want the DDE to stop when x
equals 0). Also the line of code elseif dxTmp <= 0
creates another discontinuity, thus you need an event for when dxTmp
becomes 0, i.e. 1/(1+y*z) - x
will be another component of the vector output.
Now when you restart the ODE, Matlab automatically assumes that there is a discontinuity at that point, hence you do not have to worry about telling Matlab that there is one there.
The next problem is that Matlab never quite achieves it right, the values of x
, y
, z
and X
will be slightly negative. Thus if it is going to create a problem, you will want to correct the value of x
(and the other values similarly) with
if x < 0
x = 0;
end
before calculating the derivatives. But this only changes the value of x
locally. So you might want to change all negative values of x
in the final solution to 0 as well. I suggest that you do not try to change sol
before inputting it into sol = dde23(ddefun, lags, sol, [tCurrent tEnd], options);
as I made a number of attempts at that and I could not get it to work.