% This program solves a convection problem 
% in a square domain [-0.5,0.5]x[-0.5,0.5] 

disp('The following velocity fields can be considered');
disp('   [1] v(x,y) = (-y,x)'); %%%%Use domain 1 for case1,2,3%%%%%
disp('   [2] v(x,y) = (1,0)');
disp('   [3] v(x,y) = (1,1)/sqrt(2)'); 
%%%%%% Modified Outflow Boundaries for exe2(2,4 BC) %%%% 
disp('   [4] v(x,y) = (-x,-y)'); 
disp('   [5] v(x,y) = (x,y) with different initial conditions'); 
velo = 4 ;

sigma = 1 ;
nu = 0.01;
disp(['Diffusion coefficient : ' num2str(nu)])
disp(['Reaction coefficient : ' num2str(sigma)])

 if velo ~= 4
     dom = [-0.5,0.5,-0.5,0.5]; 
 else
     dom = [0,2,0,3];
 end
dom_str = ['[ ' num2str(dom(1)) ',' num2str(dom(2)) '] x [' num2str(dom(3)) ',' num2str(dom(4)) ']'] ;

% Element type
disp(' ')
elem = 0; p = 1; 
referenceElement = SetReferenceElement(elem,p); 

% hx = 0.18 ;
% hy = 0.18 ;
% nx = ceil((dom(2)-dom(1))/hx/p) ;
% ny = ceil((dom(4)-dom(3))/hy/p) ;
% hx = (dom(2)-dom(1))/nx/p ;
% hy = (dom(4)-dom(3))/ny/p ;
h = min(hx,hy) ;

[X,T] = CreateMesh(dom,nx,ny,referenceElement);
% figure; PlotMesh(T,X,'b-');

[Conv,div_Conv] = ComputeVelocity(X,velo);

% figure(1); hold on; 
% quiver(X(:,1),X(:,2),Conv(:,1),Conv(:,2))
% plot(dom([1,2,2,1,1]), dom([3,3,4,4,3]), 'k')
% axis equal

% Time discretization
tEnd = 4.5;
nStep = 50;
dt = tEnd / nStep; 
a = sqrt(max(Conv(:,1).^2+Conv(:,1).^2)) ;
Courant = a*dt/h; 
disp(['Courant number: ', num2str(Courant)]); 

 
% Initial condition
u0 = InitialCondition(X,velo); 

xx  = reshape(X(:,1), p*nx+1, p*ny+1)'; 
yy  = reshape(X(:,2), p*nx+1, p*ny+1)'; 
u0_dib = reshape(u0, p*nx+1, p*ny+1)';  
% figure(2); clf; 
% surface(xx,yy,u0_dib,'FaceColor','interp');
% set(gca,'FontSize',16)
% grid on
% view(3)


% Boundary conditions (Lagrange multipliers)
[ADir,bDir,nDir] = BoundaryConditions(X,velo);



% Method used for solving the problem
disp(' ')
disp ('The problem can be solved using one of the following methods: ');
disp ('    [1] Lax-Wendroff + Galerkin')
disp ('    [2] Lax-Wendroff with lumped mass matrix + Galerkin')
disp ('    [3] Crank-Nicolson ')
disp ('    [4] TG3 2step')
method = 3 ;

disp ('    [0] Galerkin')
disp ('    [1] SUPG')
sp_meth = 1 ;

[M,K,K_diff,C,S_t,S_x] = FEM_matrices(X,T,Conv,div_Conv,sigma,nu,dt,referenceElement,sp_meth);
M_rn = M * sigma ;
[Mout,Cout] = Boundary_matrices(X,T,Conv,div_Conv,referenceElement,velo);

% Removing boundary matrices for diffusive case
if nu~= 0
    Mout = Mout*0 ;
    Cout = Cout*0 ;
end

[A,B,methodName] = system_matrix(method,M,M_rn,K,K_diff,C,Mout,Cout,S_t,S_x,dt); 

L=[A,ADir';ADir,zeros(nDir,nDir)];


% Solution at each time step
nPt = length(u0);
u = zeros(nPt,nStep+1); 
u(:,1) = u0;
u_m = zeros(nStep,2) ;
u_sol=cell(nStep,1);
u_sol{1}= reshape(u0, p*nx+1, p*ny+1)';

if method ~=4
    for n = 1:nStep
        Lb = [B*u(:,n); bDir] ;
        Du = L\Lb;
        u(:,n+1) = u(:,n) + Du(1:end-nDir);
        
        u_sol{n+1} = reshape(u(:,n+1), p*nx+1, p*ny+1)';
        u_m(n+1,:) = [min(u(:,n+1)) max(u(:,n+1))] ;
    end
else 
    for n = 1:nStep
        % TG3 1st step
        Lb1 = [B{1}*u(:,n); bDir] ;
        Dunt = L\Lb1;
        unt = u(:,n) + Dunt(1:end-nDir);
        
        % TG3 2nd step
        Lb2 = [B{2}*u(:,n) + B{3}*unt ; bDir] ;
        Du = L\Lb2;
        u(:,n+1) = u(:,n) + Du(1:end-nDir);
        u_m(n+1,:) = [min(u(:,n+1)) max(u(:,n+1))] ;
        u_sol{n+1} = reshape(u(:,n+1), p*nx+1, p*ny+1)';
    end
end

    tim = (1:nStep)*dt ;
    ind = find(abs(tim-2)<dt) ;
    ind = ind(1) ;