Question

I was reading this post online where the person mentioned that using "if statements" and "abs()" functions can have negative repercussions in MATLAB's variable-step ODE solvers (like ODE45). According to the OP, it can significantly affect time-step (requiring too low of a time step) and give poor results when the differential equations are finally integrated. I was wondering whether this is true, and if so, why. Also, how can this problem be mitigated without resorting to fix-step solvers. I've given an example code below as to what I mean:

function [Z,Y] = sauters(We,Re,rhos,nu_G,Uinj,Dinj,theta,ts,SMDs0,Uzs0,...
Uts0,Vzs0,zspan,K)

Y0 = [SMDs0;Uzs0;Uts0;Vzs0]; %Initial Conditions
options = odeset('RelTol',1e-7,'AbsTol',1e-7); %Tolerance Levels
[Z,Y] = ode45(@func,zspan,Y0,options);

function DY = func(z,y)

    DY = zeros(4,1);

    %Calculate Local Droplet Reynolds Numbers
    Rez = y(1)*abs(y(2)-y(4))*Dinj*Uinj/nu_G;
    Ret = y(1)*abs(y(3))*Dinj*Uinj/nu_G;

    %Calculate Droplet Drag Coefficient
    Cdz = dragcof(Rez);
    Cdt = dragcof(Ret);

    %Calculate Total Relative Velocity and Droplet Reynolds Number
    Utot = sqrt((y(2)-y(4))^2 + y(3)^2);
    Red = y(1)*abs(Utot)*Dinj*Uinj/nu_G;

    %Calculate Derivatives
    %SMD
    if(Red > 1)
        DY(1) = -(We/8)*rhos*y(1)*(Utot*Utot/y(2))*(Cdz*(y(2)-y(4)) + ...
            Cdt*y(3)) + (We/6)*y(1)*y(1)*(y(2)*DY(2) + y(3)*DY(3)) + ...
            (We/Re)*K*(Red^0.5)*Utot*Utot/y(2);
    elseif(Red < 1)
        DY(1) = -(We/8)*rhos*y(1)*(Utot*Utot/y(2))*(Cdz*(y(2)-y(4)) + ...
        Cdt*y(3)) + (We/6)*y(1)*y(1)*(y(2)*DY(2) + y(3)*DY(3)) + ...
        (We/Re)*K*(Red)*Utot*Utot/y(2);
    end
    %Axial Droplet Velocity
    DY(2) = -(3/4)*rhos*(Cdz/y(1))*Utot*(1 - y(4)/y(2));
    %Tangential Droplet Velocity
    DY(3) = -(3/4)*rhos*(Cdt/y(1))*Utot*(y(3)/y(2));
    %Axial Gas Velocity
    DY(4) = (3/8)*((ts - ts^2)/(z^2))*(cos(theta)/(tan(theta)^2))*...
        (Cdz/y(1))*(Utot/y(4))*(1 - y(4)/y(2)) - y(4)/z;

end

end

Where the function "dragcof" is given by the following:

function Cd = dragcof(Re)    
if(Re <= 0.01)

    Cd = (0.1875) + (24.0/Re);

elseif(Re > 0.01 && Re <= 260.0)

    Cd = (24.0/Re)*(1.0 + 0.1315*Re^(0.32 - 0.05*log10(Re)));

else

    Cd = (24.0/Re)*(1.0 + 0.1935*Re^0.6305);
end
end
Was it helpful?

Solution

This is because derivatives that are computed using if-statements, modulus operations (abs()), or things like unit step functions, dirac delta's, etc., will introduce discontinuities in the value of the solution or its derivative(s), resulting in kinks, jumps, inflection points, etc.

This implies the solution to the ODE has a complete change in behavior at the relevant times. What variable step integrators will do is

  • detect this
  • recognize that they won't be able to use information directly beyond the "problem point"
  • decrease the step, and repeat from the top, until the problem point satisfies the accuracy demands

Therefore, there will be many failed steps and reductions in step size near the problem points, negatively affecting the overall integration time.

Variable step integrators will continue to produce good results, however. Constant step integrators are not a good remedy for this sort of problem, since they are not able to detect such problems in the first place (there's no error estimation).

What you could do is simply split the problem up in multiple parts. If you know beforehand at what points in time the changes will occur, you just start a new integration for each interval, each time using the output of the previous integration as the initial value for the next one.

If you don't know beforehand where the problems will be, you could use this very nice feature in Matlab's ODE solvers called event functions (see the documentation). You let one of Matlab's solvers detect the event (change of sign in the derivative, change of condition in the if-statement, or whatever), and terminate the integration when such events are detected. Then start a new integration, starting from the last time and with initial conditions of the previous integration, as before, until the final time is reached.

There will still be a slight penalty in overall execution time this way, since Matlab will try to detect the location of the event accurately. However, it is still much better than running the integration blindly when it comes to both execution time and accuracy of the results.

OTHER TIPS

Yes it is true and it happens because of your solution is not smooth enough at some points.

Assume you want to integrate. y'(t) = f(t,y). Then, what happens in f is getting integrated to become y. Thus, if in your definition of f there is

  • abs(), then f has a kink and y is still smooth and 1 times differentiable
  • if, then f has a jump and y a kink and no more differentiability

Matlab's ODE45 presumes that your solution is 5 times differentiable, and tries to ensure an accuracy of order 4. Nonsmooth points of your function are misinterpreted as stiffness what leads to small stepsizes and even to breakdowns.

What you can do: Because of the lack of smoothness you cannot expect a high accuracy anyways. Thus, ODE23 might be a better choice. In the worst case, you have to stick to first-order schemes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top