function [K,f] = FEM_system(X,T,referenceElement,example)
% [K,f] = FEM_system(X,T,referenceElement,example)
% Matrix K and r.h.s vector f obtained after discretizong a 2D convection-diffusion equation
%
% X:            nodal coordinates
% T:            connectivities (elements)
% referenceElement: reference element properti%C = [nodesDir1, zeros(length(nodesDir1),1);
 %    nodesDir0, zeros(length(nodesDir0),1)];es (quadrature, shape functions...)
% example: example properties



velo = example.velo;
a = example.a;
nu = example.nu;
sigma= cinput('enter the value of sigma =',0.001);
method = example.method; 
ax = velo(1);
ay = velo(2);
Te = T(1,:); Xe = X(Te,:); 
hx = max(Xe(:,1)) - min(Xe(:,1)); 
hy = max(Xe(:,2)) - min(Xe(:,2)); 
h = (hx+hy)/2; 


nen = referenceElement.nen;
ngaus = referenceElement.ngaus;
wgp = referenceElement.GaussWeights;
N = referenceElement.N;
Nxi = referenceElement.Nxi;
Neta = referenceElement.Neta;

% Number of elements and number of nodes in the mesh
nElem = size(T,1);
nPt = size(X,1);

K = zeros(nPt,nPt);
f = zeros(nPt,1);

if method == 0
    % Galerkin
    tau = 0;
elseif method == 1
    % SUPG
    disp('SUPG');
    Pe = a*h/(2*nu);
    tau_p = ((1 + 9/Pe^2 +(sigma*h)/(2*a))^(-1/2))*(h/(2*a));
    disp(strcat('Recommended stabilization parameter = ',num2str(tau_p)));
    tau = cinput('Stabilization parameter',tau_p);
    if isempty(tau)
        tau = tau_p;
    end
   
    % Artificial Diffusion
%     Pe_x = ax*h/(2*nu);
%     Pe_y = ay*h/(2*nu);
%     %Pe= h*a/(2*nu);
%     alpha_x = coth(Pe_x)-1/Pe_x;
%     alpha_y = coth(Pe_y)-1/Pe_y;
%     %tau = h*(ax*alpha_x + ay*alpha_y)/2;
%     %tau= h*(1 + 9/Pe^2 +(sigma*h)/(2*a))^(-1/2)/(2*a);
%     nubar_p = h*(ax*alpha_x*ax + ay*alpha_y*ay)/2*a^2;  
%     %nubar_p = tau*a*a;
%     disp(strcat('Recommended value for the artificial diffusion = ',num2str(nubar_p)));
%     nubar = cinput('Artificial diffusion to be used', nubar_p);
%     if isempty(nubar)
%         nubar = nubar_p;
%     end
%     nu = nu + nubar;
%     tau=0;
elseif method == 2
       %%%  GLS    
       disp('GLS');
        Pe = a*h/(2*nu);
    tau_p = ((1 + 9/Pe^2 +(sigma*h)/(2*a))^(-1/2))*(h/(2*a));
    disp(strcat('Recommended stabilization parameter = ',num2str(tau_p)));
    tau = cinput('Stabilization parameter',tau_p);
    if isempty(tau)
        tau = tau_p;
    end
      
       
else
    error ('Unavailable method')
end%         % Artifficial diffusion
%         Ke = Ke + (nu*(Nx'*Nx+Ny'*Ny) + N_ig'*(ax*Nx+ay*Ny)+ N_ig'*sigma*N_ig )*dvolu;
%         aux = N_ig*Xe; 
%         f_ig = SourceTerm(aux);
%         fe = fe + N_ig'*(f_ig*dvolu);


% Loop on elements
for ielem = 1:nElem
    % Te: global number of the nodes in the current element
    Te = T(ielem,:);
    % Xe: coordenates of the nodes in the current element
    Xe = X(Te,:);
    % Element matrices
    [Ke,fe] = EleMat(Xe,nen,ngaus,wgp,N,Nxi,Neta,method,tau,velo,nu,sigma);
    % Assemble the element matrices
    K(Te,Te) = K(Te,Te) + Ke;
    f(Te) = f(Te) + fe;
end






function [Ke,fe] = EleMat(Xe,nen,ngaus,wgp,N,Nxi,Neta,method,tau,velo,nu,sigma)
%

ax = velo(1);
ay = velo(2);

Ke = zeros(nen,nen);
fe = zeros(nen,1);

-SourceTerm
% Loop on Gauss points (computation of integrals on the current element)
for ig = 1:ngaus
    N_ig = N(ig,:);
    Nxi_ig = Nxi(ig,:);
    Neta_ig = Neta(ig,:);
    Jacob = [Nxi_ig*(Xe(:,1))	Nxi_ig*(Xe(:,2))
        Neta_ig*(Xe(:,1))	Neta_ig*(Xe(:,2))];
    dvolu = wgp(ig)*det(Jacob);
    res = Jacob\[Nxi_ig;Neta_ig];
    Nx = res(1,:);
    Ny = res(2,:);
    
    if method == 0
        % Galerkin
        Ke = Ke + (nu*(Nx'*Nx+Ny'*Ny) + N_ig'*(ax*Nx+ay*Ny)+ N_ig'*sigma*N_ig )*dvolu;
        aux = N_ig*Xe; 
        f_ig = SourceTerm(aux);
        fe = fe + N_ig'*(f_ig*dvolu);
    elseif method == 1
         % SUPG
        Ke = Ke + (nu*(Nx'*Nx+Ny'*Ny) + N_ig'*(ax*Nx+ay*Ny)+ N_ig'*sigma*N_ig + ...
            tau*(ax*Nx+ay*Ny)'*(ax*Nx+ay*Ny + N_ig*sigma-SourceTerm))*dvolu;   
        aux = N_ig*Xe; 
        f_ig = SourceTerm(aux);
        fe = fe + (N_ig+tau*(ax*Nx+ay*Ny))'*(f_ig*dvolu);
        
        
        %         % Artifficial diffusion
%         Ke = Ke + (nu*(Nx'*Nx+Ny'*Ny) + N_ig'*(ax*Nx+ay*Ny)+ N_ig'*sigma*N_ig )*dvolu;
%         aux = N_ig*Xe; 
%         f_ig = SourceTerm(aux);
%         fe = fe + N_ig'*(f_ig*dvolu);
    else
        % GLS    
        Ke = Ke + (nu*(Nx'*Nx+Ny'*Ny) + N_ig'*(ax*Nx+ay*Ny)+ N_ig'*sigma*N_ig + ...
            tau*(ax*Nx+ay*Ny + N_ig*sigma)'*(ax*Nx+ay*Ny + N_ig*sigma-SourceTerm))*dvolu;    
        aux = N_ig*Xe; 
        f_ig = SourceTerm(aux);
        fe = fe + (N_ig+tau*(ax*Nx+ay*Ny))'*(f_ig*dvolu);
    end
end

