% This program solves a transient Navier-Stokes problem
% using Chorin-Temam projection method
% the first step includes the viscous and convective terms
% whereas in the second one, pressure and the incompressibility 
% constraint for velocity are considered.
%

clear all, close all, home

global nu;

disp(' ')
disp('CAVITY FLOW TRANSIENT NAVIER-STOKES PROBLEM')

disp(' ')
Re = input('Reynolds number = ');
nu = 1/Re;

% MIXED ELEMENT USED FOR THE SOLUTION
disp(' ')
disp('The problem is solved using a mixed fomulation.')
disp('The following elements are available: ')
disp('Quadrilaterals')
disp('         [0]: Q1P0    [1]: Q1Q1    [2]: Q2Q1   [3]: Q2Q2')
disp('Triangles')
disp('         [4]: P1P0    [5]: P1P1    [6]: P1+P1 (MINI)    [7]: P2P1   [8]: P2P2')
imix = input('Choose the element for the solution :  ');
% Type of element (0 for quadrilaterals and 1 for triangles)
% and number of element nodes for velocity (nen) and pressure (nenP).
if imix == 0
    elem = 0;
    nen = 4; nenP = 1;
elseif imix == 1
    elem = 0;
    nen = 4; nenP = 4;
elseif imix == 2
    elem = 0;
    nen = 9; nenP = 4;
elseif imix == 3
    elem = 0;
    nen = 9; nenP = 9;
elseif imix == 4
    elem = 1;
    nen = 3; nenP = 1;
elseif imix == 5
    elem = 1;
    nen = 3; nenP = 3;
elseif imix == 6
    elem = 1;
    nen = 4; nenP = 3;
elseif imix == 7
    elem = 1;
    nen = 6; nenP = 3;
elseif imix == 8
    elem = 1;
    nen = 6; nenP = 6;
else
    error('Unavailable element')
end

% GEOMETRY
% Number of nodes on each direction
disp(' ')
npx = input('Number of nodes in X direction (default: 31)= ');
npy = input('Number of nodes in Y direction (default: npx)= ');
if isempty(npx)  npx = 31;     end
if isempty(npy)  npy = npx;    end
% Number of elements on each direction
nx = npx-1; ny = npy-1;
npt = npx*npy;

% Coordinates of domain's vertices
x_lo = 0; x_up = 1; 
y_lo = 0; y_up = 1; 
% Nodal coordinates matrix and connectivities for velocity 
disp('Problem is solved on an structured mesh.')
disp('It can be uniform ([1]) or adapted to the problem ([2]).')
meshtype = input('Choose a computational mesh (default: uniform): ');
if isempty(meshtype)
    meshtype = 1;
end
if meshtype == 1
    [X,T] = CreateUniformMesh(elem,nen,x_lo,x_up,y_lo,y_up,npx,npy);      
elseif meshtype == 2
    [X,T] = CreateMesh(elem,nen,x_lo,x_up,y_lo,y_up,npx,npy);    
else
    error('Unavailable mesh option')
end
% Nodal coordinates matrix and connectivities for pressure
[XP,TP] = CreatePresNod(elem,nenP,X,T,npx,npy);

% Total number of nodes and degrees of freedom
if elem == 1 & nen == 4     % MINI
    numnp = size(X,1) + size(T,1);
    nunk = 2*numnp;
else
    numnp = size(X,1); 
    nunk = 2*numnp;
end
nunkP = size(XP,1);


% Meshes plots
figure('Name','Mesh for velocity','NumberTitle','off'); clf;
PlotMesh(T,X,elem,'b')
figure('Name','Mesh for pressure','NumberTitle','off'); clf;
PlotMesh(TP,XP,elem,'r')
figure('Name','Meshes','NumberTitle','off'); clf;
PlotMesh(T,X,elem,'b'),     hold on
PlotMesh(TP,XP,elem,'r'),   hold off

% BOUNDARY CONDITIONS
[Accd1, bccd1,velo_ini] = BC_Cavity(nx,ny,nunk);
[Accd2, bccd2] =  NBC_Cavity(nx,ny,nunk);
% confined flow (only essential conditions on the velocity are imposed)
confined = 1;     
% number of prescribed degrees of freedom
nDir1 = size(Accd1,1);
nDir2 = size(Accd2,1);

% SOLUTION
% Computation of matrices for the transient analysis
[M,K,G,f] = CreMats(X,T,XP,TP,elem);

disp(' ')
disp('The problem is solved using a fractional-step method.')
disp('First step includes viscous and convective terms.')
disp('It can be solved using: ')
disp('  [0] Explicit Euler method')
disp('  [1] Implicit backward Euler method')
method = input('Choose a method to be used (default: 0) = ');
if isempty(method) | (method~=0 & method~=1)
    method = 0;
end
if method == 0
    dt_aux = 1e-3;
    nstep_aux = 250;
else
    dt_aux = 1e-2;
    nstep_aux = 25;    
end
dt    = input(strcat('Time step (default: ',num2str(dt_aux),') =  '));
nstep = input(strcat('Number of time-steps (default: ',num2str(nstep_aux),') =  '));
if isempty(dt)
    dt = dt_aux;
end
if isempty(nstep)
    nstep = nstep_aux;
end
nb_dib = 25;
step_dib = round(nstep/nb_dib);


disp(' ')
disp('Second step involves pressure and incompresibility constraint.')
disp('It can be solved in two ways: ')
disp('  [0]: solve a Poisson equation to compute pressure and'); 
disp('       use the solution to determine velocity')
disp('  [1]: solve an equation for pressure coupled with');
disp('       the incompressibility equation')
disp('Note that the first option is only valid for continuous pressure. ')
Stokes = input('Choose the way you prefer to solve second step = ');
if isempty(Stokes)
    if imix == 1 | imix == 3 | imix == 5 |imix == 8  
        Stokes = 0;
    else
        Stokes = 1;
    end
end

% Matrices for the second step
if Stokes == 1
    G(1,:)=[];
    Atot = [M       Accd2'                  dt*G'; ...
            Accd2   zeros(nDir2,nDir2)      zeros(nDir2,nunkP-1); ...
            dt*G    zeros(nunkP-1,nDir2)    zeros(nunkP-1,nunkP-1)];
    [L2nd,U2nd] = lu(Atot);
    btot2nd = [bccd2 ; zeros(nunkP-1,1)];   % the first components of this vector
                                            % are not considered now (velocity)
    aux  = zeros(nunk+length(btot2nd),1);
    clear NC NP NxiP NetaP G Accd2 bccd2; 
    pack
else
    % Pressure is the solution of a Poisson equation
    L = CreLaplace(XP,TP,elem);
    Accd = [1, zeros(1,size(L,1)-1)];
    Atot = [L       Accd'; ...
            Accd    0];
    [L2nd,U2nd] = lu(Atot);
    % and once it is computed, velocity can be determined
    Atot = [M       Accd2'; ...
            Accd2   zeros(nDir2,nDir2)];
    [LM,UM] = lu(Atot);
    btot2nd = bccd2; 
    aux  = zeros(nunkP+1,1);
    clear L NP NxiP NetaP; pack
end

% First step
btot1st = bccd1;    % the first components of this vector
                    % are not considered now (velocity)
if method == 0
    Atot = [M       Accd1'; ...
            Accd1   zeros(nDir1,nDir1)];
    [L1st,U1st] = lu(Atot);
    clear Accd1 Atot; pack
end

aux1 = zeros(nunk+length(btot1st),1);
velo = zeros(numnp,2);
pres = zeros(nunkP,1);

% Initial velocity field
% If there is no initial velocity available, we use a field which is 
% zero everywhere but on the boundary, where Dirichlet conditions are imposed
inivelfile = input('Initial velocity file (RETURN: No) = ','s');
if isempty(inivelfile)
    velo = velo_ini;
else
   disp(inivelfile); load(inivelfile);
end
clear velo_ini; pack;
% Initial velociy plot
figure('Name','Initial velocity','NumberTitle','off'); clf;
v = quiver(X(1:npt,1),X(1:npt,2),velo(1:npt,1),velo(1:npt,2),2);
set(v, 'Color','b'),
hold on
plot([x_lo,x_up,x_up,x_lo,x_lo],[y_lo,y_lo,y_up,y_up,y_lo],'k','LineWidth',2);
v = quiver(X(1:npt,1),X(1:npt,2),velo(1:npt,1),velo(1:npt,2),3);
axis equal; axis([0,1,0,1]);
set(gca,'FontSize',12,'Box','on','XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
pause(1)

tri = delaunay(XP(:,1),XP(:,2));
istep = 0; tt = 0;

while istep < nstep
    istep = istep + 1;
    tt = tt + dt;
    fprintf('Time Step = %4d,  Time = %g\n',istep,tt);
   
    % FIRST STEP
    % Convection matrix
    Cv = CreConv(velo,X,T,elem);
    if method == 0  % explicit
        btot =[dt*f+(M-dt*(Cv+K))*reshape(velo',nunk,1) ; btot1st];
        aux1 = U1st\(L1st\btot);
        clear btot;
    else            % implicit
        btot = [dt*f+M*reshape(velo',nunk,1) ; btot1st];
        Atot = [M+dt*(Cv+K)     Accd1'; ...
                Accd1           zeros(nDir1,nDir1)];
        aux1 = Atot\btot;
    end
    clear btot;
        
    % SECOND STEP
    if Stokes == 1
        btot = [M*aux1(1:nunk) ; btot2nd];
        aux = U2nd\(L2nd\btot);
        clear btot;
        velo = reshape(aux(1:nunk),2,numnp)';
        pres = [0;aux(nunk+nDir2+1:nunk+nDir2+nunkP-1)];
    else
        btot = [G*aux1(1:nunk); 0]/dt;
        aux = U2nd\(L2nd\btot);
        pres = aux(1:nunkP);
        btot = [M*aux1(1:nunk)-dt*G'*pres; btot2nd];
        aux1 = UM\(LM\btot);
        velo = reshape(aux1(1:nunk),2,numnp)';
    end
    % Comment following for faster computation   
    if rem(istep-1,step_dib) == 0
        StreamLines(X,velo,npx,npy,[],[],5) 
        hold on
        plot([x_lo,x_up,x_up,x_lo,x_lo],[y_lo,y_lo,y_up,y_up,y_lo],'k','LineWidth',2);
        v = quiver(X(1:npt,1),X(1:npt,2),velo(1:npt,1),velo(1:npt,2),4);
        axis equal; axis([0,1,0,1]);
        set(gca,'FontSize',12,'Box','on','XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
        figure(6); clf;
        tri=delaunay(XP(:,1),XP(:,2));
        trisurf(tri,XP(:,1),XP(:,2),pres);   
        pause(0.5)
    end
    if istep == 1
        h = msgbox('Arrange windows in order to see reults properly');
        uiwait(h)
    end
end


% POSTPROCESS

% Velocity 
figure('Name','Velocity field','NumberTitle','off'); clf;
quiver(X(1:npt,1),X(1:npt,2),velo(1:npt,1),velo(1:npt,2));
box on; axis equal tight;
set(gca, 'FontSize', 12,...
    'XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
axis([0,1,0,1])

% Pressure 
if elem == 0
    if (imix == 0)
        x = []; y = []; z = [];
        for e = 1:nx*ny
            x = [x, X(T(e,:),1)];
            y = [y, X(T(e,:),2)];
            z = [z, pres(e)*ones(4,1)];
        end
        figure('Name','Pressure field','NumberTitle','off'); clf;
        patch(x,y,z,z)
        view(3); grid on;
        set(gca, 'FontSize', 12,...
            'XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
    elseif (imix == 1 | imix == 3)
        aux_x = ones(npy,1)*X(1:npx,1)';
        aux_y = X(1:npx:npt,2)*ones(1,npx);
        aux_p = reshape(pres,npx,npy)';
        figure('Name','Pressure field','NumberTitle','off'); clf;
        surface(aux_x, aux_y, aux_p,'FaceColor','interp')       
        view(3); grid on;
        set(gca, 'FontSize', 12,...
            'XTick', [0:0.25:1], 'YTick', [0:0.25:1]);        
    elseif (imix == 2)
        aux_x = ones(ny/2+1,1)*X(1:2:npx,1)';
        aux_y = X(1:2*npx:npt,2)*ones(1,nx/2+1);
        aux_p = reshape(pres, nx/2+1, ny/2+1)';
        figure('Name','Pressure field','NumberTitle','off'); clf;
        surface(aux_x, aux_y, aux_p,'FaceColor','interp')
        view(3); grid on;
        set(gca, 'FontSize', 12,...
            'XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
    end
else
    figure('Name','Pressure field','NumberTitle','off'); clf;
    tri = delaunay(XP(:,1),XP(:,2));
    trisurf(tri,XP(:,1),XP(:,2),pres);
    view(3); grid on;
    set(gca, 'FontSize', 12,...
        'XTick', [0:0.25:1], 'YTick', [0:0.25:1]);
end
% Streamlines (computed as level sets)
phi = StreamLines_ls(X,T,elem,velo,npx,npy);

% Streamlines (using Matlab function)
sx = [0:0.1:1, 0.5*ones(1,11), 0:0.1:1, 1:-0.1:0];
sy = [0.5*ones(1,11), 0:0.1:1, 0:0.1:1, 0:0.1:1];
StreamLines(X,velo,npx,npy,sx,sy), hold on
plot([x_lo,x_up,x_up,x_lo,x_lo],[y_lo,y_lo,y_up,y_up,y_lo],'k','LineWidth',2)
axis equal; axis([0,1,0,1]); box on;
hold off
