function Sol = GLSSOlution(X,T,Conv,W,w,s,Element,nu,sigma,Accd1,bccd1,c,dt,nstep, tau, nodesDir0, nodesDir1)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This function computes the GLS solution of the transient convection
% diffusion reaction equation for a multistage scheme (Pade type)
%
% Inputs:
%  X --> nodal coordinates
%  T --> nodal connectivities
%  Conv --> convective velocity of the problem
%  W --> Pade matrix
%  w --> Pade vector
%  s --> source term reference
%  Element --> data structure containing element information such as shape
%  functions, derivatives, Gauss points, etc...
%  nu --> diffusion parameter
%  sigma --> reaction coefficient
%  Accd1 --> matrix of boundary conditions
%  bccd1 --> r.h.s of boundary conditions
%  c --> initial condition
%  dt --> time step
%  nstep --> number of steps for time integration
%  tau --> stabilization matrix
%  nodesDir0 --> nodes on the boundary where the solution is u=0
%  nodesDir1 --> nodes on the boundary wher the solution is u=1
%
% Outputs:
%  Sol --> solution of the GLS stabilization formulation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

f = SourceTerm(s);
% Number of points used in the discretization
npoin = size(X,1);

%FEM Matrices obtained by discretizing the Galerking weak form
[M,K,C] = FEM_matrices(X,T,Conv,Element); 
%Discretize the term (agrad(w), agrad(u))
[K2] = CreK2Mat(X,T,Conv,Element.GaussPoints,Element.GaussWeights,Element.N, Element.Nxi, Element.Neta);
f = f * ones(size(M,1),1); 

% Integration matrix
[n,m] = size(W);
Id = eye(n,m);
tauW = tau*W; % this computations will be needed later
tauW_W = tauW'*W;
tauW_w = tauW'*w;
tauw = tau*w;

if size(tau) == [1,1] % adjust dimentions of tau if needed
    tau = tau*ones(size(T));
end

% Computation of the matrix necessary to obtain solution at each time-step: A du = F
disp(' ')
disp('Computation of total matrices for the time-integration scheme')
A = [];
for i = 1:n
    row = [];
    for j = 1:m
        % from the weak form...
        row = [ row, Id(i,j)*M  + dt*W(i,j)*(C + nu*K + sigma*M) + ...
                     tau(i,j)*(1/dt)*M + tauW(i,j)*(C + sigma*M) + ...
                     tauW(j,i)*(C' + sigma*M) + dt*tauW_W(i,j)*(K2+sigma*C') + dt*tauW_W(i,j)*sigma*(C + sigma*M)];    
         end
     A = [A; row];
end
 
% Adjust boundary conditions matrix for Lagrage multipliers method (for
% instance, for the 4th order Padr, the systems needs to be enlarged)
nccd = size(Accd1,1);
Accd = []; bccd = [];
for i = 1:n
    row = [];
    for j = 1:m
        row = [row, Id(i,j)*Accd1];
    end
    Accd = [Accd; row];
    bccd = [bccd; bccd1];
end

% Set up the system
nccd = n*nccd;
Atot = [A Accd'; Accd zeros(nccd)];

% Initial condition
Sol = c;

% Loop to compute the transient solution
disp(' ')
disp('Transient analysis: computation of the solution at each time step')
for i=1:nstep
    aux1 = dt*(-(C+nu*K+sigma*M)*c); 
    aux2 = -(C + sigma*M)*c;
    aux3 = dt*(-(K2 + sigma*C' + sigma*(C + sigma*M))*c);
    F = [];
    for j =1:n
        F = [F; w(j)*aux1 + tauw(j)*aux2 + tauW_w(j)*aux3];
    end
    F = [F;bccd];   % total r.h.s 
    dc  = Atot\F; % get multistage solution
    dc = reshape(dc(1:n*npoin),npoin,n);
        for k = 1 : size(dc,1)
          if any(nodesDir1 == k )
            c(k) = 1; % To avoid summing in the boundary condition nodes
          elseif any(nodesDir0 ==k)
            c(k) = 0; % Same here
          else
            c(k) = c(k) + sum(dc(k,:),2);
          end
        end
    Sol = [Sol c];    
end
end

function [K2] = CreK2Mat(X,T,Conv,pospg,wpg,N, Nxi, Neta)
% K2 = CreK2Mat (X,T,Conv,pospg,wpg,N,Nxi,Neta);
% Computation of the matrix K2 obtained by discretizing (agrad(w), agrad(u))
%

% Total number of elements and number of nodes in each element
[numel,nen] = size(T); 
% Total number of nodes
numnp = size(X,1); 
% Number of Gauss points in one element
ngaus = size(pospg,1); 

% Allocation 
K2 = zeros(numnp,numnp); 

% Loop on the elements
for ielem = 1:numel 
    % Te: global number of nodes on the current element
    Te = T(ielem,:); 
    % Xe: coordinates of the nodes in Te
    Xe = X(Te,:); 
    % Conve: velocity field on Te
    Conve = Conv(Te,:);
    % Element Matrix
    K2e = zeros(nen,nen);
    % Loop on Gauss points (numerical quadrature)
    for igaus = 1:ngaus
        % Shape functions on Gauss point igaus
        N_igaus    = N(igaus,:);     
        Nxi_igaus  = Nxi(igaus,:);   
        Neta_igaus = Neta(igaus,:);
        % Jacobian matrix on the Gauss point
        Jacob = [Nxi_igaus*(Xe(:,1))	Nxi_igaus*(Xe(:,2))   
                Neta_igaus*(Xe(:,1))	Neta_igaus*(Xe(:,2))];
        %
        dvolu = wpg(igaus)*det(Jacob); 
        % Derivatives of shape functions in global coordinates
        res = Jacob\[Nxi_igaus;Neta_igaus]; 
        Nx = res(1,:); 
        Ny = res(2,:); 
        % Contribution at the element matrix
        a = N_igaus*Conve;
        K2e = K2e + (a(1)*Nx+a(2)*Ny)'*(a(1)*Nx+a(2)*Ny)*dvolu;  
    end   
    % Assembly of the element matrix
    K2(Te,Te) = K2(Te,Te) + K2e; 
    clear K2e  
end 
end