Code covered by the BSD License  

Highlights from
Program to Solve initial value problems by various methods

image thumbnail
from Program to Solve initial value problems by various methods by Daniel Klawitter
initial value problem solver enter >>IVPsolve to start

[RESULT, SETTINGS]=ivp_solve(SETTINGS)
function [RESULT, SETTINGS]=ivp_solve(SETTINGS)
% function thal solves the initial value problem
% by using the specified parameters out of SETTINGS
%
% input:   o SETTINGS....struct containing all information about the
%                        current program run
%
% example  o SETTINGS = 
% 
%                              step: 0.1000
%                            method: {'explicit Euler-method'}
%     calculate_region_of_stability: 0
%                          equation: @(x,y)(cos(y)).^2./sin(y).*x.*exp(1/2.*x)
%                          fu_exact: @(x)acos(1/(4*exp(1/2*x)*(1/2*x-1)+1/cos(pi/2-0.2626)*(14*exp(-5/2)*cos(pi/2-0.2626)+1)))
%                        beginvalue: -5
%                          endvalue: 4
%                        startvalue: 1.3082
%                             isRKV: 1
%                      step_control: 0
%
% output:  o RESULT....struct containing all needed information about the
%                      numerical soltuion
%
% example: o RESULT = 
% 
%     numerical_solution: [1x91 double]
%         exact_solution: [1x91 double]
%             gridpoints: [1x91 double]
%
% notes:   o 
%
% authors: o Christian Jkel (University of Technology Dresden)
%          o Daniel Klawitter (University of Technology Dresden)


stop_calculation = 0;
f = SETTINGS.equation;

% calculates the k's for implicit RKV
    function [ka] = k_imp(j,age)
        function[Funktion] = F(x,y1,y2)
            Funktion       = y2-f(x+a*age,(y1'+age*B*y2')');
        end
        ka = fsolve(@(y)F(step_vec(j),u(j),y),ones(1,s),optimset('Display','off'));
        
    end


% calculates the k's for explicit RKV
    function [ka] = k(j,age)
        for i2 = 1:s
            ka(1)  = f(step_vec(j)+a(i2)*age,u(j));
            ka(i2) = f(step_vec(j)+a(i2)*age,u(j)+age*sum(B(i2,1:i2-1).*ka(1:i2-1)));
        end
    end

% this function calculates initial values for the linear multistep methods
    function[startwerte] = berechne_Startwerte(stufe)                                           
        a = [0, 1/5, 3/10, 4/5, 8/9, 1, 1];
        B = [0        ,           0,          0,        0,           0,     0,   0;
            1/5       ,           0,          0,        0,           0,     0,   0;
            3/40      ,        9/40,          0,        0,           0,     0,   0;
            44/45     ,      -56/15,       32/9,        0,           0,     0,   0;
            19372/6561, -25360/2187, 64448/6561, -212/729,           0,     0,   0;
            9017/3168 ,     -355/33, 46732/5247,   49/176, -5103/18656,     0,   0;
            35/384    ,           0,   500/1113,  125/192,  -2187/6784, 11/84,   0];
        c = [5179/57600,0,7571/16695,393/640,-92097/339200,187/2100,1/40];
        s = 7;
        p=5;
        tele(1)=SETTINGS.startvalue;
        
        function [ka] = kaa(j,age)
            for i2 = 1:s
                ka(1)  = f(step_vec(j)+a(i2)*age,tele(j));
                ka(i2) = f(step_vec(j)+a(i2)*age,tele(j)+age*sum(B(i2,1:i2-1).*ka(1:i2-1)));
            end
        end
        if SETTINGS.step_control==1
            i=2;
            method=@(sta,z,vector)(vector(z)+sta*sum(c.*kaa(z,sta)));
            while go==true
                u1 = method(h_old,i-1,tele);
                u2 = method(h_old/2,i-1,tele);  % extrapolation to estimate the error
                est=abs((2^p*u2-u1)/(2^p-1)-u1);
                if est<TOL & est>0.1*TOL   % step size will be accepted
                    RESULT.steps(i)=h_old;
                    step_vec(i)=step_vec(i-1)+h_old;
                    tele(i)=u1;
                    i=i+1;
                else
                    h_new=h_old*(0.5*TOL/est)^(1/(p+1));
                    if h_new<h_old  % decrease of the step size
                        h_old=h_new;
                        
                    elseif h_new>=h_old & est<0.1*TOL    % increase of the step size for the next step
                        tele(i)=u1;
                        step_vec(i)=step_vec(i-1)+h_old;
                        RESULT.steps(i)=h_old;
                        h_old=h_new;
                        i=i+1;
                    end
                end
                if i==length(rho)
                    go = false;
                    
                end
                
            end
        else
            for i = 2:stufe
                tele(i) = tele(i-1)+SETTINGS.step*sum(c.*kaa(i-1,SETTINGS.step));
            end
        end
        
        startwerte = tele;
    end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%     THE METHODS    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch char(SETTINGS.method)
    case {'explicit Euler-method'}
        % Euler explizit  --> explizit
        B = [0];
        a = [0];
        c = [1];
        s = 1;
        p=1;
    case {'Heun-Verfahren'}
        % Heun-Verfahren --> explizit
        B = [0, 0;
            1, 0];
        a = [0  , 1  ];
        c = [1/2, 1/2];
        s = 2;
        p=2;
    case {'Klassisches RKV'}
        % klassisches RKV --> explizit
        B = [0 , 0 , 0, 0;
            1/2, 0 , 0, 0;
            0  ,1/2, 0, 0;
            0  ,  0, 1, 0];
        a = [0  , 1/2, 1/2 ,  1];
        c = [1/6, 1/3, 1/3, 1/6];
        s = 4;
        p=4;
    case {'Dormand-Prince RKV'}
        % embedded RKV from Dormand-Prince sheme
        a = [0, 1/5, 3/10 , 4/5, 8/9, 1 , 1 ];
        B = [0        , 0          , 0          , 0       , 0            , 0       , 0;
            1/5       , 0          , 0          , 0       , 0            , 0       , 0;
            3/40      , 9/40       , 0          , 0       , 0            , 0       , 0;
            44/45     , -56/15     , 32/9       , 0       , 0            , 0       , 0;
            19372/6561, -25360/2187, 64448/6561 , -212/729, 0            , 0       , 0;
            9017/3168 , -355/33    , 46732/5247 , 49/176  , -5103/18656  , 0       , 0;
            35/384    , 0          , 500/1113   , 125/192 , -2187/6784   , 11/84   , 0];
        % with this c order4
        c = [5179/57600 , 0, 7571/16695 , 393/640, -92097/339200, 187/2100, 1/40];
        % and with this one order 5
        c = [35/384    , 0          , 500/1113   , 125/192 , -2187/6784   , 11/84   , 0];
        s = 7;
        p=5;
    case {'implicit Euler-method'}
        % implizites verfahren
        B = [1];
        a = [1];
        c = [1];
        s = 1;
        p=1;
    case {'Radau II RKV'}
        % Radau IIA method order 3 entnommen von
        % http://www-user.tu-chemnitz.de/~benner/Lehre/NumerikODE/Folie_IRK.pdf
        B = [5/12, -1/12;
            3/4 ,  1/4 ];
        a = [1/3,1];
        c = [3/4,1/4];
        s = 2;
        p=3;
    case {'Gau RKV'}
        % gauverfahren der ordnung 6 entnommen von
        % http://www-user.tu-chemnitz.de/~benner/Lehre/NumerikODE/Folie_IRK.pdf
        B = [5/36              , (10-3*sqrt(15))/45, (25-6*sqrt(15))/180;
            (10+3*sqrt(15))/72 ,  2/9              , (10-3*sqrt(15))/72;
            (25+6*sqrt(15))/180, (10+3*sqrt(15))/45,  5/36];
        a = [(5-sqrt(15))/10,1/2,(5+sqrt(15))/10];
        c = [5/18,4/9,5/18];
        s = 3;
        p=6;
end
%%%%%%%%%%%%%%%%%     calculation of the numerical solution      %%%%%%%%%%%%%%%%%%%%%%

step_vec(1)=SETTINGS.beginvalue;  % vector with grid points
h_old=SETTINGS.step;
if SETTINGS.step_control==1
    RESULT.steps(1)=SETTINGS.step;  % vektor with step size for each grid point
    go=true;
    TOL=SETTINGS.tolerance;
else
    step_vec = SETTINGS.beginvalue:SETTINGS.step:SETTINGS.endvalue;
end

switch char(SETTINGS.method)
    case {'explicit Euler-method','Heun-Verfahren','Klassisches RKV','Dormand-Prince RKV'}
        % explizite RKV
        u(1) = SETTINGS.startvalue;
        method=@(sta,z,vector,vector_step)(vector(z)+sta*sum(c.*k(z,sta)));
        i=2;
    case {'implicit Euler-method','Radau II RKV','Gau RKV','radauIIA'}
        u(1) = SETTINGS.startvalue;
        method=@(sta,z,vector,vector_step)(vector(z)+sta*sum(c.*k_imp(z,sta)));
        i=2;
    case {'Adams-Bashforth(2)'}
        % ein zweistufiges Adamsverfahren (explizit)
        rho        = [1, -1 ,  0  ];
        sigma      = [0, 3/2, -1/2];
        u(1)       = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(2);
        u(2)       = startwerte(2);
        method = @(sta,z,vector,vector_step)(vector(z)+sta/2*(3*f(vector_step(z),vector(z))-f(vector_step(z-1),vector(z-1))));
        i=3;
        go=true;
    case {'Adams-Bashforth(4)'}
        % ein vierstufiges Verfahren (explizit)
        rho        = [1, -1   , 0     , 0 ,0  ];
        sigma      = [0, 55/24, -59/24, 37/24,-9/24];
        u(1)       = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(4);
        u(2:4)     = startwerte(2:4);
        i=5;
        go=true;
        method = @(sta,z,vector,vector_step)(vector(z)+sta/24*(55*f(vector_step(z),vector(z))...
            -59*f(vector_step(z-1),vector(z-1))...
            +37*f(vector_step(z-2),vector(z-2))...
            -9*f(vector_step(z-3),vector(z-3))));
        
    case {'Adams-Moulton(2)'}
        % Adams-Moulton-verfahren, implizit, 2-stufig
        rho        = [1,-1,0];
        sigma      = [5/12,8/12,-1/12];
        u(1)       = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(2);
        u(2)       = startwerte(2);
        i=3;
        go=true;
        method = @(sta,z,vector,vector_step)(fzero(@(y) y-vector(z)-sta/12*(5*f(vector_step(z+1),y)...
            +8*f(vector_step(z),vector(z))...
            -f(vector_step(z-1),vector(z-1))),vector(z)));
        
    case {'Milne-Simpson(4)'}
        % Milne-Simpson-verfahren, implizit, 4-stufig
        rho        = [1    , 0     , -1   , 0   , 0    ];
        sigma      = [29/90, 124/90, 24/90, 4/90, -1/90];
        u(1)       = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(4);
        u(2:4)     = startwerte(2:4);
        i=5;
        go=true;
        method = @(sta,z,vector,vector_step) (fzero(@(y)y-vector(z-1)-sta/90*(29*f(vector_step(z+1),y)+...
            124*f(vector_step(z),vector(z))...
            +24*f(vector_step(z-1),vector(z-1))...
            +4*f(vector_step(z-2),vector(z-2))...
            -f(vector_step(z-3),vector(z-3))),vector(z)));
        
    case {'BDF 5'}
        % BDF-Verfahren, implizit, 5-stufig
        rho        = [137/60, -300/60, 300/60, -200/60, 75/60, -12/60];
        sigma      = [1     , 0      , 0     , 0      , 0    ,      0];
        u(1)       = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(5);
        u(2:5)     = startwerte(2:5);
        i=6;
        go=true;
        method = @(sta,z,vector,vector_step) (fzero(@(y) 1/60*(137*y-300*vector(z)+300*vector(z-1)-200*vector(z-2)+75*vector(z-3)-12*vector(z-4))...
            -sta*f(vector_step(z+1),y),vector(z)));
        
    case {'BDF 2'}
        % BDF Verfahren 2-stufig, A-Stabil!!!!
        rho=[3/2,-4/2,1/2];
        sigma=[1,0,0];
        u(1) = SETTINGS.startvalue;
        startwerte = berechne_Startwerte(2);
        u(2)=startwerte(2);
        i=3;
        go=true;
        method = @(sta,z,vector,vector_step)(fzero(@(y)3/2*y-4/2*vector(z)+1/2*vector(z-1)-sta*f(vector_step(z+1),y),vector(z)));
        
    case'eigenesRKV'
        
        B = SETTINGS.B;
        c = SETTINGS.c;
        a = SETTINGS.a;
        s = length(B);
        u(1) = SETTINGS.startvalue;
        i=2;
        p=length(B); % rough estimation for the order of convergence.
        method=@(sta,z,vector,vector_step)(vector(z)+sta*sum(c.*k_imp(z,sta)));
        
        
        %if abs(u(i))>10^200
        %      errordlg('Your method produces a solution which can not be displayed. Change the chosen parameters!','error')
        %      stop_calculation=1;
        %      break
        %
        %  end
        
    case'eigenesMSV'
        
        u(1)   = SETTINGS.startvalue;
        rho    = SETTINGS.rho;
        sigma  = SETTINGS.sigma;
        rho2   = fliplr(rho);
        sigma2 = fliplr(sigma);
        st     = length(rho)-1;
        startwerte = berechne_Startwerte(st);
        u(2:st)= startwerte(2:st);
        i=st+1;
        go=true;
        p=length(rho);
        
        
        %zwischenwert1 = sum(rho2(1:st).*u(i-st:i-1));
        %zwischenwert2 = sum(sigma2(1:st).*f(step_vec(i-st:i-1),u(i-st:i-1)));
        method = @(sta,z,vector,vector_step)(fzero(@(y) y*rho(1)+sum(rho2(1:st).*vector(z+1-st:z))-sta*sigma(1)*f(vector_step(z+1),y)+sta*sum(sigma2(1:st).*f(vector_step(z+1-st:z),vector(z+1-st:z))),vector(z)));
        
        %if abs(u(i))>10^200 | strcmp(num2str(u(i)),'NaN')
        %    errordlg('Your method produces a solution which can not be displayed. Change the chosen parameters!','error')
        %   stop_calculation=1;
        %   break
        %
        %end
        
        
end

if SETTINGS.step_control==1  % step control
    
    while go==true
        step_vec(i)=step_vec(i-1)+h_old; % this is for the implicit methods because they need this point for the error estimation
        u1 = method(h_old,i-1,u,step_vec);
        u2 = method(h_old/2,i-1,u,step_vec);  % extrapolation to estimate the error
        
        if abs(u2)>10^200 | strcmp(num2str(u2),'NaN')
            errordlg('Your method produces a solution which can not be displayed. Change the chosen parameters!','error')
            stop_calculation=1;
            break
            
        end
        
        est=abs((2^p*u2-u1)/(2^p-1)-u1);
        if est<TOL & est>0.1*TOL   % step size will be accepted
            RESULT.steps(i)=h_old;
            u(i)=u1;
            i=i+1;
        else
            h_new=h_old*(0.5*TOL/est)^(1/(p+1));
            if h_new<h_old  % decrease of the step size
                h_old=h_new;
                
            elseif h_new>=h_old & est<0.1*TOL    % increase of the step size for the next step
                u(i)=u1;
                RESULT.steps(i)=h_old;
                h_old=h_new;
                i=i+1;
            end
        end
        
        if step_vec(i-1)>SETTINGS.endvalue    % cancel because the interval end is crossed
            go = false;
            
        end
        
    end
    
else
    
    start=i;
    for i=start:length(step_vec)
        u(i)=method(SETTINGS.step,i-1,u,step_vec);
        if abs(u(i))>10^200 | strcmp(num2str(u(i)),'NaN')
            errordlg('Your method produces a solution which can not be displayed. Change the chosen parameters!','error')
            stop_calculation=1;
            break
            
        end
    end
    
    
end


%%%%%%%%%%%%%%%%%%%%%%%%     Die Stabilittsgebiete        %%%%%%%%%%%%%%%%%%%%%%%
if SETTINGS.calculate_region_of_stability==1
    % der Bereich der auf Stabilitt berprft wird
    X = -5:0.05:2;
    Y = -4:0.05:4;
    i = sqrt(-1);
    
    count_idx = 0;
    if SETTINGS.isRKV
        % Runge-Kutta-verfahren
        for x_idx = 1:length(X)
            for y_idx = 1:length(Y)
                if abs(1+c*(eye(s)-(X(x_idx)+i*Y(y_idx))*B)^(-1)*ones(1,s)'*(X(x_idx)+i*Y(y_idx)))<=1  % die Stabilitts Funktion eines RKV in allgemeiner Form wird
                    count_idx             = count_idx+1;                                                          % fr die verschiedenen Gitterpunkte ausgewertet.
                    plot_vec_x(count_idx) = X(x_idx);
                    plot_vec_y(count_idx) = Y(y_idx);
                end
            end
        end
    else
        % linear multi step methods
        for x_idx = 1:length(X)
            for y_idx = 1:length(Y)
                Wurzeln = roots(rho-(X(x_idx)+i*Y(y_idx))*sigma);
                if abs(Wurzeln) <= 1 & (length(find(Wurzeln==1))==1 | length(find(Wurzeln==1))==0)% Wurzelbedingung prfen
                    count_idx             = count_idx+1;
                    plot_vec_x(count_idx) = X(x_idx);
                    plot_vec_y(count_idx) = Y(y_idx);
                end
            end
        end
    end
    
    if exist('plot_vec_y','var')
        RESULT.x = plot_vec_x;
        RESULT.y = plot_vec_y;  
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if stop_calculation == 1
    RESULT.numerical_solution = 0;
    RESULT.gridpoints = 0;
    RESULT.exact_solution = 0;
    RESULT.steps = 0;
else
    RESULT.numerical_solution = u;
    if isfield(SETTINGS,'fu_exact')
        % exact solution is known:
        fu_exact = SETTINGS.fu_exact;
        for j=1:length(step_vec)
            u_exact(j) = fu_exact(step_vec(j));
        end
        RESULT.exact_solution = u_exact;
    end
    RESULT.gridpoints = step_vec;
    
    if SETTINGS.isRKV
        SETTINGS.B = B;
        SETTINGS.c = c;
        SETTINGS.a = a;
    else
        SETTINGS.rho = rho;
        SETTINGS.sigma = sigma;
    end
end

end

Contact us at files@mathworks.com