function [M,K,K_diff,C,S_t,S_x] = FEM_matrices(X,T,Conv,div_Conv,sigma,nu,dt,referenceElement,sp_meth) 


% reference element information
nen = referenceElement.nen; 
ngaus = referenceElement.ngaus; 
wgp = referenceElement.GaussWeights; 
N = referenceElement.N; 
Nxi = referenceElement.Nxi; 
Neta = referenceElement.Neta; 

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

M = zeros(nPt);
K = zeros(nPt);
K_diff = zeros(nPt);
C = zeros(nPt);
S_t = zeros(nPt);
S_x = zeros(nPt);

% Loop on elements
for ielem=1:nElem
    Te = T(ielem,:); 
    Xe = X(Te,:); 
    Conve = Conv(Te,:);
    div_Conve = div_Conv(Te) ;
    [Me,Ke,Ke_diff,Ce,Se_t,Se_x] = EleMat(Xe,Conve,div_Conve,sigma,nu,dt,nen,ngaus,wgp,N,Nxi,Neta,sp_meth);
    % Assembly
    M(Te,Te) = M(Te,Te) + Me; 
    K(Te,Te) = K(Te,Te) + Ke; 
    K_diff(Te,Te) = K_diff(Te,Te) + Ke_diff; 
    C(Te,Te) = C(Te,Te) + Ce; 
    S_t(Te,Te) = S_t(Te,Te) + Se_t; 
    S_x(Te,Te) = S_x(Te,Te) + Se_x; 
end



function [Me,Ke,Ke_diff,Ce,Se_t,Se_x] = EleMat(Xe,Conve,div_Conve,sigma,nu,dt,nen,ngaus,wgp,N,Nxi,Neta,sp_meth)
%

Me = zeros(nen);
Ke = zeros(nen);
Se_t = zeros(nen);
Se_x = zeros(nen);
Ke_diff = zeros(nen);
Ce = zeros(nen);


% Loop on Gauss points 
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))];
    hx = max(Xe(:,1)) - min(Xe(:,1)) ;
    hy = max(Xe(:,2)) - min(Xe(:,2)) ;
    dvolu = wgp(ig)*det(Jacob);
    res = Jacob\[Nxi_ig;Neta_ig];
    Nx = res(1,:);
    Ny = res(2,:);
    a = N_ig*Conve; ax = a(1); ay = a(2); 
    div_a = N_ig*div_Conve;
    aGradN = ax*Nx + ay*Ny; 
    Div_aN = ax*Nx + ay*Ny + div_a * N_ig ;
    % Elemental Mass matrix
    Me = Me + N_ig'*N_ig*dvolu; 
    % Elemental Stiffness matrix with a.grad(N)(Div.a)
    Ke = Ke + aGradN'*Div_aN*dvolu;
    % Elemental Stiffness matrix with diffusion coefficient
    Ke_diff = Ke_diff  + [Nx' Ny']*[Nx ; Ny] *nu*dvolu; 
    Ce = Ce + N_ig'*aGradN*dvolu;
    
    % Galerkin
    if sp_meth == 0 
        tau = 0 ;
    % SUPG
    elseif sp_meth ==1
    tau = 2/dt + 2*sqrt((ax^2+ay^2)/(hx^2+hy^2)) + 4*nu/(hx^2+hy^2) + sigma ;
    tau = 1/tau ;
    Se_t = Se_t + 1/2*tau*( (ax+ay)*N_ig+ ax*Nx+ay*Ny)'* N_ig *dvolu;        
    Se_x = Se_x + 1/2*tau*( (ax+ay)*N_ig+ ax*Nx+ay*Ny)' ...
                *((ax+ay)*N_ig+ ax*Nx+ay*Ny + N_ig*sigma)*dvolu;
    end
end

