4

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
Kimusubi
  • 155
  • 1
  • 8

2 Answers2

4

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.

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
  • While I understand why the if-statements would create a discontinuity, why does "abs()" do that? Also, could this problem be mitigated by replacing "abs(X)" with "sqrt(X^2)"? – Kimusubi May 16 '13 at 17:14
  • 1
    @Kimusubi: Suppose your derivative was `dfdx = abs(x).^(1/8)`. What would the solution look like? You can solve this analytically: `fx = 8/9*abs(x).^(9/8)`. Now look at the plot for these functions, with and without the `abs()`, and you'll understand the 'damage' the `abs()` can do. As for mitigating the problem with the square root: those two functions are mathematically defined to be the same :) So no, you won't be able to mitigate the problem with that substitution. – Rody Oldenhuis May 21 '13 at 06:01
0

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.

Jan
  • 4,932
  • 1
  • 26
  • 30
  • I'm not sure if your answer answers my question. Why does this specifically have to do with variable time step solvers and not fixed time steps? Also, just because you have an if-statement, it doesn't mean there is a jump in your solution. As long as the variable under the "if-statement" have converging limits between the if statements, there should be no jump in the solution. Same thing for "abs()". – Kimusubi May 16 '13 at 09:09
  • It is the step size control that decreases the step size. With fixed time step solvers you just run over these nonsmooth points. But what you observe then is a breakdown of the order of convergence. – Jan May 16 '13 at 09:12
  • Yes, if the `if` never applies, these effects will not occur. – Jan May 16 '13 at 09:13