sparse BuildAdvection(const DataStructure& Domain, double velocity) {
	
	int Npts = Domain.GetNpts();
	sparse Advection(Npts,Npts,3*Npts);

	int nnz = 0;

	if(velocity > .0)
		for(int i = 0; i < Npts; i++) {
		
			Advection.Val(nnz) = - 1.0 / hx - 1.0 / hy;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = i;
			nnz++;

			if(Domain(Domain[i],Domain(i)+1) != -4) {
				Advection.Val(nnz) = 1.0 / hx;
				Advection.Row(nnz) = i;
				Advection.Col(nnz) = Domain(Domain[i],Domain(i)+1);
				nnz++;
			}
			else {
				Advection.Val(nnz) = 1.0 / hx;
				Advection.Row(nnz) = i;
				Advection.Col(nnz) = i;
				nnz++;
			}

			if(Domain(Domain[i] + 1,Domain(i)) != -3) {
				Advection.Val(nnz) = 1.0/hy;
				Advection.Row(nnz) = i;
				Advection.Col(nnz) = Domain(Domain[i]+1,Domain(i));
				nnz++;
			}
			else {
				Advection.Val(nnz) = 1.0/hy;
				Advection.Row(nnz) = i;
				Advection.Col(nnz) = i;
				nnz++;
			}
	}
	else
		for(int i = 0; i < Npts; i++) {
		
			Advection.Val(nnz) = 1.0 / hx + 1.0 / hy;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = i;
			nnz++;
			
		if(Domain(Domain[i],Domain(i) - 1) != -2) {
			Advection.Val(nnz) = - 1.0 / hx;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = Domain(Domain[i],Domain(i)-1);
			nnz++;
		}
		else {
			Advection.Val(nnz) = - 1.0 / hx;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = i;
			nnz++;
		}

		if(Domain(Domain[i]-1,Domain(i)) != -1) {
			Advection.Val(nnz) = - 1.0/hy;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = Domain(Domain[i]-1,Domain(i));
			nnz++;
		}
		else {
			Advection.Val(nnz) = - 1.0/hy;
			Advection.Row(nnz) = i;
			Advection.Col(nnz) = i;
			nnz++;
		}
	}

	Advection.CreateSparse();	
	return Advection;
}
sparse AssembleAdvection(DataStructure& Data, double velocity, char* BCType) {
	/* Dirichlet BC is implemented inefficiently here */
	
	int Nverts = Data.GetNverts(), nnz = 0, NNZMAX = 0, nBC = 0, uBC;
	bool DirichletIsTrue = false;
	
	if(!strcmp(BCType,"Dirichlet"))
		DirichletIsTrue = true;
		
	for(int i = 0; i < Data.GetNverts(); i++)
		NNZMAX += Data.GetNeigh(i,0);

	sparse Advection(Nverts,Nverts,2*NNZMAX);
	ifstream file;
	
	if(DirichletIsTrue) {	
		file.open("Dirichlet.dat");
		file >> nBC >> uBC;
	}
		 
	vector BoundPts(nBC);
	
	if(DirichletIsTrue) 
		for(int i = 0; i < nBC; i++)
			file >> BoundPts(i);
			 
	file.close();
	
	for(int i = 0; i < Nverts; i++) {
		int n = Data.GetNeigh(i,0);
		double Area_C = .0;
		
		for(int k = 1; k <= n; k++)
			Area_C += Data.GetArea(Data.GetNeigh(i,k)); 

		Area_C *= 1.0/3.0;
		
		for(int j = 1; j <= n; j++) {
			double x[3], y[3]; vector nodes(3); 

			for(int k = 0; k < 3; k++)
				nodes(k) = Data.GetTris(Data.GetNeigh(i,j),k);

			int index1 = find(nodes,i), index2 = 1, index3 = 2;
	
			if(index1 == 1) {
				index2 = 2;
				index3 = 0;
			}

			if(index1 == 2) {
				index2 = 0;
				index3 = 1;
			}

			x[0] = Data.GetVerts(nodes(index1),0);
			y[0] = Data.GetVerts(nodes(index1),1);

			x[1] = Data.GetVerts(nodes(index2),0);
			y[1] = Data.GetVerts(nodes(index2),1);

			x[2] = Data.GetVerts(nodes(index3),0);
			y[2] = Data.GetVerts(nodes(index3),1);

			bool IsBoundary1 = CheckBC(nodes(index1),BoundPts),
				 IsBoundary2 = CheckBC(nodes(index2),BoundPts),
				 IsBoundary3 = CheckBC(nodes(index3),BoundPts);
				 
			double delta_x1 = x[2]/3.0 - x[1]/6.0 - x[0]/6.0,
				   delta_y1 = y[2]/3.0 - y[1]/6.0 - y[0]/6.0,

				   delta_x2 = x[2]/6.0 - x[1]/3.0 + x[0]/6.0,
				   delta_y2 = y[2]/6.0 - y[1]/3.0 + y[0]/6.0;
					
			double qf1 = velocity * (delta_y1 - delta_x1),
			       qf2 = velocity * (delta_y2 - delta_x2);
			
			if(qf1 > 0) {
				   Advection.Row(nnz) = i;
				   Advection.Col(nnz) = Data.GetTris(Data.GetNeigh(i,j),index1);
				   if(IsBoundary1)
						Advection.Val(nnz) = .0;
				   else
						Advection.Val(nnz) = - qf1 / Area_C;
				   nnz++;
			}
			else {
				   Advection.Row(nnz) = i;
				   Advection.Col(nnz) = Data.GetTris(Data.GetNeigh(i,j),index2);
				   if(IsBoundary2)
						Advection.Val(nnz) = .0;
				   else
						Advection.Val(nnz) = - qf1 / Area_C;
				   nnz++;
			}
			
			if(qf2 > 0) {
				   Advection.Row(nnz) = i;
				   Advection.Col(nnz) = Data.GetTris(Data.GetNeigh(i,j),index1);
				   if(IsBoundary1)
						Advection.Val(nnz) = .0;
				   else
						Advection.Val(nnz) = - qf2 / Area_C;
				   nnz++;
        	}
        	else {
				   Advection.Row(nnz) = i;
				   Advection.Col(nnz) = Data.GetTris(Data.GetNeigh(i,j),index3);
				   if(IsBoundary3)
						Advection.Val(nnz) = .0;
				   else
						Advection.Val(nnz) = - qf2 / Area_C;
				   nnz++;
        	}
        }
	}
	Advection.CreateSparse();
	return Advection;
}
    void MappingExtrapolate::v_CalcNeumannPressureBCs(
        const Array<OneD, const Array<OneD, NekDouble> > &fields,
        const Array<OneD, const Array<OneD, NekDouble> >  &N,
        NekDouble kinvis)
    {
        if (m_mapping->HasConstantJacobian() && !m_implicitViscous)
        {
            Extrapolate::v_CalcNeumannPressureBCs( fields, N, kinvis);
        }
        else
        {
            int physTot = m_fields[0]->GetTotPoints();
            int nvel = m_fields.num_elements()-1;
            
            Array<OneD, NekDouble> Pvals;
            StdRegions::StdExpansionSharedPtr Pbc;
            StdRegions::StdExpansionSharedPtr elmt;

            Array<OneD, Array<OneD, const NekDouble> > Velocity(m_bnd_dim);
            Array<OneD, Array<OneD, const NekDouble> > Advection(m_bnd_dim);
            // Get transformation Jacobian
            Array<OneD, NekDouble> Jac(physTot,0.0);
            m_mapping->GetJacobian(Jac);
            // Declare variables
            Array<OneD, Array<OneD, NekDouble> > BndValues(m_bnd_dim);
            Array<OneD, Array<OneD, NekDouble> > Q(m_bnd_dim);
            Array<OneD, Array<OneD, NekDouble> > Q_field(nvel);
            Array<OneD, Array<OneD, NekDouble> > fields_new(nvel);
            Array<OneD, Array<OneD, NekDouble> > N_new(m_bnd_dim);
            // Temporary variables
            Array<OneD, NekDouble> tmp(physTot,0.0);
            Array<OneD, NekDouble> tmp2(physTot,0.0);
            for(int i = 0; i < m_bnd_dim; i++)
            {
                BndValues[i] = Array<OneD, NekDouble> (m_pressureBCsMaxPts,0.0);
                Q[i]         = Array<OneD, NekDouble> (m_pressureBCsElmtMaxPts,0.0);
                N_new[i]   = Array<OneD, NekDouble> (physTot,0.0);
            }
            for(int i = 0; i < nvel; i++)
            {
                Q_field[i]   = Array<OneD, NekDouble> (physTot,0.0);
                fields_new[i]   = Array<OneD, NekDouble> (physTot,0.0);
            }
            
            // Multiply convective terms by Jacobian
            for(int i = 0; i < m_bnd_dim; i++)
            {
                if (m_fields[0]->GetWaveSpace())
                {
                    m_fields[0]->HomogeneousBwdTrans(N[i],N_new[i]);
                }
                else
                {
                    Vmath::Vcopy(physTot, N[i], 1, N_new[i], 1);
                }
                Vmath::Vmul(physTot, Jac, 1, N_new[i], 1, N_new[i], 1);
                if (m_fields[0]->GetWaveSpace())
                {
                    m_fields[0]->HomogeneousFwdTrans(N_new[i],N_new[i]);
                }                          
            }
            
            // Get velocity in physical space
            for(int i = 0; i < nvel; i++)
            {
                if (m_fields[0]->GetWaveSpace())
                {
                    m_fields[0]->HomogeneousBwdTrans(fields[i],fields_new[i]);
                }        
                else
                {
                    Vmath::Vcopy(physTot, fields[i], 1, fields_new[i], 1);
                }
            }
            
            // Calculate appropriate form of the CurlCurl operator
            m_mapping->CurlCurlField(fields_new, Q_field, m_implicitViscous);
            
            // If viscous terms are treated explicitly,
            //     add grad(U/J \dot grad J) to CurlCurl
            if ( !m_implicitViscous)
            {
                m_mapping->DotGradJacobian(fields_new, tmp);
                Vmath::Vdiv(physTot, tmp, 1, Jac, 1, tmp, 1);
                
                bool wavespace = m_fields[0]->GetWaveSpace();
                m_fields[0]->SetWaveSpace(false);
                for(int i = 0; i < m_bnd_dim; i++)
                {
                    m_fields[0]->PhysDeriv(MultiRegions::DirCartesianMap[i], 
                                            tmp, tmp2);
                    Vmath::Vadd(physTot, Q_field[i], 1, tmp2, 1, Q_field[i], 1);
                }     
                m_fields[0]->SetWaveSpace(wavespace);
            }        
            
            // Multiply by Jacobian and convert to wavespace (if necessary)
            for(int i = 0; i < m_bnd_dim; i++)
            {
                Vmath::Vmul(physTot, Jac, 1, fields_new[i], 1, fields_new[i], 1);
                Vmath::Vmul(physTot, Jac, 1, Q_field[i]   , 1, Q_field[i]   , 1);
                if (m_fields[0]->GetWaveSpace())
                {
                    m_fields[0]->HomogeneousFwdTrans(fields_new[i],fields_new[i]);
                    m_fields[0]->HomogeneousFwdTrans(Q_field[i],Q_field[i]);
                }                          
            }            

            for(int j = 0 ; j < m_HBCdata.num_elements() ; j++)
            {
                /// Casting the boundary expansion to the specific case
                Pbc =  boost::dynamic_pointer_cast<StdRegions::StdExpansion> 
                            (m_PBndExp[m_HBCdata[j].m_bndryID]
                                ->GetExp(m_HBCdata[j].m_bndElmtID));

                /// Picking up the element where the HOPBc is located
                elmt = m_pressure->GetExp(m_HBCdata[j].m_globalElmtID);

                /// Assigning
                for(int i = 0; i < m_bnd_dim; i++)
                {
                    Velocity[i]  = fields_new[i] + m_HBCdata[j].m_physOffset;
                    Advection[i] = N_new[i]      + m_HBCdata[j].m_physOffset;
                    Q[i]         = Q_field[i]   + m_HBCdata[j].m_physOffset;
                }

                // Mounting advection component into the high-order condition
                for(int i = 0; i < m_bnd_dim; i++)
                {
                    MountHOPBCs(m_HBCdata[j].m_ptsInElmt,kinvis,Q[i],Advection[i]);
                }

                Pvals = m_pressureHBCs[0] + m_HBCdata[j].m_coeffOffset;

                // Getting values on the edge and filling the pressure boundary
                // expansion and the acceleration term. Multiplication by the
                // normal is required
                switch(m_pressure->GetExpType())
                {
                    case MultiRegions::e2D:
                    case MultiRegions::e3DH1D:
                    {                                                         
                        elmt->GetEdgePhysVals(m_HBCdata[j].m_elmtTraceID, Pbc,
                                              Q[0], BndValues[0]);                    
                        elmt->GetEdgePhysVals(m_HBCdata[j].m_elmtTraceID, Pbc,
                                              Q[1], BndValues[1]);

                        // InnerProduct 
                        Pbc->NormVectorIProductWRTBase(BndValues[0], BndValues[1],
                                                       Pvals);
                    }
                    break;
                    case MultiRegions::e3DH2D:
                    {
                        if(m_HBCdata[j].m_elmtTraceID == 0)
                        {
                            (m_PBndExp[m_HBCdata[j].m_bndryID]->UpdateCoeffs()
                                + m_PBndExp[m_HBCdata[j].m_bndryID]
                                    ->GetCoeff_Offset(
                                        m_HBCdata[j].m_bndElmtID))[0]
                                                                    = -1.0*Q[0][0];
                        }
                        else if (m_HBCdata[j].m_elmtTraceID == 1)
                        {
                            (m_PBndExp[m_HBCdata[j].m_bndryID]->UpdateCoeffs()
                                + m_PBndExp[m_HBCdata[j].m_bndryID]
                                    ->GetCoeff_Offset(
                                        m_HBCdata[j].m_bndElmtID))[0] 
                                                = Q[0][m_HBCdata[j].m_ptsInElmt-1];
                        }
                        else
                        {
                            ASSERTL0(false,
                                     "In the 3D homogeneous 2D approach BCs edge "
                                     "ID can be just 0 or 1 ");
                        }
                    }
                    break;
                    case MultiRegions::e3D:
                    {
                        elmt->GetFacePhysVals(m_HBCdata[j].m_elmtTraceID, Pbc, 
                                              Q[0], BndValues[0]);
                        elmt->GetFacePhysVals(m_HBCdata[j].m_elmtTraceID, Pbc,
                                              Q[1], BndValues[1]);
                        elmt->GetFacePhysVals(m_HBCdata[j].m_elmtTraceID, Pbc,
                                              Q[2], BndValues[2]);
                        Pbc->NormVectorIProductWRTBase(BndValues[0], BndValues[1],
                                              BndValues[2], Pvals);
                    }
                    break;
                default:
                    ASSERTL0(0,"Dimension not supported");
                    break;
                }
            }            
        }
        // If pressure terms are treated implicitly, we need to multiply
        //     by the relaxation parameter, and zero the correction term
        if (m_implicitPressure)
        {
            Vmath::Smul(m_pressureHBCs[0].num_elements(), m_pressureRelaxation,
                            m_pressureHBCs[0],  1,
                            m_pressureHBCs[0], 1);
        } 
        m_bcCorrection  = Array<OneD, NekDouble> (m_pressureHBCs[0].num_elements(), 0.0);
    }