diff --git a/Numeric/polynomialBasis.cpp b/Numeric/polynomialBasis.cpp
index 6a82c3809b1086887eb129742460b5d302665174..46f7c9e38e88ea4883b0a4ab7948ea879abaae58 100644
--- a/Numeric/polynomialBasis.cpp
+++ b/Numeric/polynomialBasis.cpp
@@ -749,19 +749,17 @@ static void generate3dFaceClosure(polynomialBasis::clCont &closure, int order)
 static void generate2dEdgeClosure(polynomialBasis::clCont &closure, int order)
 {
   closure.clear();
-  // first give edge nodes of the three edges in direct order
-  int index = 3;
-  std::vector<int> c0,c1,c2;
-  for (int i = 0; i < order - 1; i++, index++) c0.push_back(index);
-  for (int i = 0; i < order - 1; i++, index++) c1.push_back(index);
-  for (int i = 0; i < order - 1; i++, index++) c2.push_back(index);
-  closure.push_back(c0);closure.push_back(c1);closure.push_back(c2);
-  // then give edge nodes in reverse order
-  std::vector<int> c3,c4,c5;
-  for (int i = c0.size() - 1; i >= 0; i--) c3.push_back(c0[i]);
-  for (int i = c1.size() - 1; i >= 0; i--) c4.push_back(c1[i]);
-  for (int i = c2.size() - 1; i >= 0; i--) c5.push_back(c2[i]);
-  closure.push_back(c3); closure.push_back(c4); closure.push_back(c5);
+  closure.resize(6);
+  for (int j = 0; j < 3 ; j++){
+    closure[j].push_back(j);
+    closure[j].push_back((j+1)%3);
+    closure[3+j].push_back((j+1)%3);
+    closure[3+j].push_back(j);
+    for (int i=0; i < order-1; i++){
+      closure[j].push_back( 3 + (order-1)*j + i );
+      closure[3+j].push_back(3 + (order-1)*(j+1) -i -1);
+    }
+  }
 }
 
 std::map<int, polynomialBasis> polynomialBases::fs;
diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index 8025824daed907c7fb0ebbe45d2daa5fd3ac1854..6e119af54709816b96470916f81004cd8ba8241a 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -1,7 +1,11 @@
+#include <set>
 #include "dgAlgorithm.h"
 #include "dgGroupOfElements.h"
 #include "dgConservationLaw.h"
-
+#include "GEntity.h"
+#include "MElement.h"
+#include "GModel.h"
+#include "MEdge.h"
 /*
   compute 
     \int \vec{f} \cdot \grad \phi dv   
@@ -136,3 +140,124 @@ void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
     solEl.gemm(group.getInverseMassMatrix(i),residuEl);
   }
 }
+
+void dgAlgorithm::residualBoundary ( //dofManager &dof, // the DOF manager (maybe useless here)
+				   const dgConservationLaw &claw,   // the conservation law
+				   const dgGroupOfFaces &group, 
+           const fullMatrix<double> &solution, // solution !! at faces nodes
+           fullMatrix<double> &residual // residual !! at faces nodes
+           )
+{ 
+  int nbFields = claw.nbFields();
+  const dgBoundaryCondition *boundaryCondition = claw.boundaryCondition(group.getBoundaryTag());
+  // ----- 1 ----  get the solution at quadrature points
+  fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields);
+  group.getCollocationMatrix().mult(solution, solutionQP); 
+  // ----- 2 ----  compute normal fluxes  at integration points
+  fullMatrix<double> NormalFluxQP ( group.getNbIntegrationPoints(), group.getNbElements()*nbFields);
+  fullMatrix<double> solutionQPRight(group.getNbIntegrationPoints(), nbFields);
+  for (int iFace=0 ; iFace<group.getNbElements() ;++iFace) {
+    // ----- 2.3.1 --- build a small object that contains elementary solution, jacobians, gmsh element
+    fullMatrix<double> solutionQPLeft (solutionQP, iFace*nbFields, nbFields);
+    fullMatrix<double> normalFluxQP (NormalFluxQP, iFace*nbFields, nbFields);
+    dgFace DGF( group.getFace(iFace), group.getElementLeft(iFace), NULL,
+                solutionQPLeft, solutionQPRight, group.getIntegrationPointsMatrix(),group.getNormals(iFace));
+    // ----- 2.3.2 --- compute fluxes
+    switch (boundaryCondition->type()){
+      case dgBoundaryCondition::EXTERNAL_VALUES : {
+        (*boundaryCondition)(DGF, &solutionQPRight);
+        (*claw.riemannSolver())(DGF, &normalFluxQP);
+        break;
+      }
+      case dgBoundaryCondition::FLUX :{
+        (*boundaryCondition)(DGF, &normalFluxQP);
+      }
+      default :
+        throw;
+    }
+    for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) {
+      const double detJ = group.getDetJ (iFace, iPt);
+      for (int k=0;k<nbFields;k++)
+        normalFluxQP(iPt,k) *= detJ;
+    }
+  }
+  // ----- 3 ---- do the redistribution at face nodes using BLAS3
+  residual.gemm(group.getRedistributionMatrix(),NormalFluxQP);
+}
+
+void dgAlgorithm::buildGroups(GModel *model, int dim, int order,
+    std::vector<dgGroupOfElements*> &eGroups,
+    std::vector<dgGroupOfFaces*> &fGroups,
+    std::vector<dgGroupOfFaces*> &bGroups) 
+{
+  std::map<const std::string,std::set<MEdge, Less_Edge> > boundaryEdges;
+  std::map<const std::string,std::set<MFace, Less_Face> > boundaryFaces;
+  std::vector<GEntity*> entities;
+  model->getEntities(entities);
+  std::vector<MElement *> allElements;
+  for(unsigned int i = 0; i < entities.size(); i++){
+    GEntity *entity = entities[i];
+    if(entity->dim() == dim-1){
+      for(unsigned int j = 0; j < entity->physicals.size(); j++){
+        const std::string physicalName = model->getPhysicalName(entity->dim(), entity->physicals[j]);
+        for (int k = 0; k < entity->getNumMeshElements(); k++) {
+          MElement *element = entity->getMeshElement(k);
+          if(dim==2)
+            boundaryEdges[physicalName].insert( MEdge(element->getVertex(0), element->getVertex(1)) );
+          else
+            boundaryFaces[physicalName].insert( MFace(element->getVertex(0), element->getVertex(1),element->getVertex(2)) );
+        }
+      }
+    }else if(entity->dim() == dim){
+      for (int iel=0; iel<entity->getNumMeshElements(); iel++)
+        allElements.push_back(entity->getMeshElement(iel));
+    }
+  }
+  eGroups.push_back(new dgGroupOfElements(allElements,order));
+  fGroups.push_back(new dgGroupOfFaces(*eGroups[0],order));
+  if(dim==2){
+    std::map<const std::string, std::set<MEdge, Less_Edge> >::iterator mapIt;
+    for(mapIt=boundaryEdges.begin(); mapIt!=boundaryEdges.end(); mapIt++) {
+      bGroups.push_back(new dgGroupOfFaces(*eGroups[0],mapIt->first,order,mapIt->second));
+    }
+  }else if(dim=3){
+    std::map<const std::string, std::set<MFace, Less_Face> >::iterator mapIt;
+    for(mapIt=boundaryFaces.begin(); mapIt!=boundaryFaces.end(); mapIt++) {
+      bGroups.push_back(new dgGroupOfFaces(*eGroups[0],mapIt->first,order,mapIt->second));
+    }
+  }else throw;
+}
+
+// works only if there is only 1 group of element
+void dgAlgorithm::residual( const dgConservationLaw &claw,
+    std::vector<dgGroupOfElements*> &eGroups, //group of elements
+    std::vector<dgGroupOfFaces*> &fGroups,  // group of interfacs
+    std::vector<dgGroupOfFaces*> &bGroups, // group of boundaries
+    const fullMatrix<double> &solution, // solution
+    fullMatrix<double> &residu) // residual
+{
+  dgAlgorithm algo;
+  residu.scale(0);
+  //volume term
+  for(size_t i=0;i<eGroups.size() ; i++) {
+    algo.residualVolume(claw,*eGroups[i],solution,residu);
+  }
+  //interface term
+  for(size_t i=0;i<fGroups.size() ; i++) {
+    dgGroupOfFaces &faces = *fGroups[i];
+    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2);
+    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2);
+    faces.mapToInterface(1, solution, solution, solInterface);
+    algo.residualInterface(claw,faces,solInterface,residuInterface);
+    faces.mapFromInterface(1, residuInterface, residu, residu);
+  }
+  //boundaries
+  for(size_t i=0;i<bGroups.size() ; i++) {
+    dgGroupOfFaces &faces = *bGroups[i];
+    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements());
+    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements());
+    faces.mapToInterface(1, solution, solution, solInterface);
+    algo.residualBoundary(claw,faces,solInterface,residuInterface);
+    faces.mapFromInterface(1, residuInterface, residu, residu);
+  }
+}
diff --git a/Solver/dgAlgorithm.h b/Solver/dgAlgorithm.h
index 2af608c6df2d32098b24556d7dde4194e05a508c..9a0c3c96b123ec03ae4d904e0e07ac45809fda52 100644
--- a/Solver/dgAlgorithm.h
+++ b/Solver/dgAlgorithm.h
@@ -1,8 +1,9 @@
 #ifndef _DG_ALGORITHM_H_
 #define _DG_ALGORITHM_H_
 
-#include "dofManager.h"
-
+#include "fullMatrix.h"
+#include <vector>
+class GModel;
 class dgGroupOfElements;
 class dgGroupOfFaces;
 class dgConservationLaw;
@@ -20,13 +21,28 @@ class dgAlgorithm {
 				   const dgGroupOfFaces & group, 
            const fullMatrix<double> &solution, // ! at face nodes
            fullMatrix<double> &residual); // ! at face nodes
-  void residualBoundaryConditions ( /*dofManager &dof,*/
-				    const dgConservationLaw &law,
-				    const dgGroupOfElements & group);
+   void residualBoundary ( //dofManager &dof, // the DOF manager (maybe useless here)
+				   const dgConservationLaw &claw,   // the conservation law
+				   const dgGroupOfFaces &group, 
+           const fullMatrix<double> &solution, // solution !! at faces nodes
+           fullMatrix<double> &residual // residual !! at faces nodes
+           );
+   // works only if there is only 1 group of element
+  void residual( const dgConservationLaw &claw,
+      std::vector<dgGroupOfElements*> &eGroups, //group of elements
+      std::vector<dgGroupOfFaces*> &fGroups,  // group of interfacs
+      std::vector<dgGroupOfFaces*> &bGroups, // group of boundaries
+      const fullMatrix<double> &solution, // solution !! at faces nodes
+      fullMatrix<double> &residual // residual !! at faces nodes
+      );
   void multAddInverseMassMatrix ( /*dofManager &dof,*/
       const dgGroupOfElements & group,
       fullMatrix<double> &residu,
       fullMatrix<double> &sol);
+  void buildGroups(GModel *model, int dim, int order,
+      std::vector<dgGroupOfElements*> &eGroups,
+      std::vector<dgGroupOfFaces*> &fGroups,
+      std::vector<dgGroupOfFaces*> &bGroups);
 };
 
 
diff --git a/Solver/dgConservationLaw.h b/Solver/dgConservationLaw.h
index 05eb28348a0b8fe5ca81e921b3e58551dd08240c..fd1441f14e9b1dab4a6f5a3a893803d88e91b382 100644
--- a/Solver/dgConservationLaw.h
+++ b/Solver/dgConservationLaw.h
@@ -22,11 +22,20 @@ class dgFaceTerm{
   virtual void operator () (const dgFace &, fullMatrix<double> fcx[]) const = 0;
 };
 
+class dgBoundaryCondition {
+public:
+  virtual ~dgBoundaryCondition () {}
+  typedef enum {FLUX=0,EXTERNAL_VALUES}boundaryType;
+  virtual void operator () (const dgFace&, fullMatrix<double> fcx[]) const = 0;
+  virtual boundaryType  type() const =0;
+};
+
 class dgConservationLaw {
   protected :
   int _nbf;
   dgTerm *_diffusive, *_convective, *_source, *_maxConvectiveSpeed;
   dgFaceTerm *_riemannSolver;
+  std::map<const std::string,dgBoundaryCondition*> _boundaryConditions;
 public:
   dgConservationLaw () : _diffusive(0), _convective(0), _source (0), 
 			 _riemannSolver(0),_maxConvectiveSpeed (0) {}
@@ -39,10 +48,15 @@ public:
   inline const dgTerm     * sourceTerm     () const {return _source;}
   inline const dgFaceTerm * riemannSolver  () const {return _riemannSolver;}
   inline const dgTerm     * maxConvectiveSpeed () const {return _maxConvectiveSpeed;}
+  inline const dgBoundaryCondition *boundaryCondition(const std::string tag) const {
+    std::map<const std::string,dgBoundaryCondition*>::const_iterator it = _boundaryConditions.find(tag);
+    if(it==_boundaryConditions.end())
+      throw;
+    return it->second;
+  }
 
 };
 
-
 dgConservationLaw *dgNewConservationLawAdvection();
 
 #endif
diff --git a/Solver/dgConservationLawAdvection.cpp b/Solver/dgConservationLawAdvection.cpp
index 269d43538a685a3740f2dc32c5b62909546815ab..8f4677c9bc248eba70297de1fae432bcf19b7531 100644
--- a/Solver/dgConservationLawAdvection.cpp
+++ b/Solver/dgConservationLawAdvection.cpp
@@ -4,10 +4,13 @@
 #include "SPoint3.h"
 #include "MElement.h"
 void getV(SPoint3 &p, double (&v)[3]){
-  double r=hypot(p.x(),p.y());
+  /*double r=hypot(p.x(),p.y());
   double alpha=atan2(p.y(),p.x());
   v[0]=r*sin(alpha);
   v[1]=-r*cos(alpha);
+  v[2]=0;*/
+  v[0]=0.15;
+  v[1]=0;
   v[2]=0;
 }
 
@@ -44,14 +47,27 @@ class dgAdvectionRiemanTerm : public dgFaceTerm{
       double un=v[0]*normals(0,i)+v[1]*normals(1,i)+v[2]*normals(2,i);
       if(un>0){
         fcx[0](i,0) = -solLeft(i,0)*un;
-        fcx[0](i,1) = solLeft(i,0)*un;
+        if(fcx[0].size2()==2)
+          fcx[0](i,1) = solLeft(i,0)*un;
       }else{
         fcx[0](i,0) = -solRight(i,0)*un;
-        fcx[0](i,1) = solRight(i,0)*un;
+        if(fcx[0].size2()==2)
+          fcx[0](i,1) = solRight(i,0)*un;
       }
     }
   }
 };
+class dgAdvectionBoundary0External : public dgBoundaryCondition {
+  boundaryType  type() const {
+    return EXTERNAL_VALUES;
+  }
+  void operator () (const dgFace &face, fullMatrix<double> fcx[]) const{
+    const fullMatrix<double> &solLeft = face.solutionLeft();
+    for(int i=0; i< solLeft.size1(); i++) {
+      fcx[0](i,0) = 0;
+    }
+  }
+};
 
 class dgConservationLawAdvection : public dgConservationLaw {
   public:
@@ -60,11 +76,19 @@ class dgConservationLawAdvection : public dgConservationLaw {
     _nbf = 1;
     _convective = new dgAdvectionFluxTerm;
     _riemannSolver = new dgAdvectionRiemanTerm;
+    _boundaryConditions["Left"] = new dgAdvectionBoundary0External();
+    _boundaryConditions["Right"] = new dgAdvectionBoundary0External();
+    _boundaryConditions["Top"] = new dgAdvectionBoundary0External();
+    _boundaryConditions["Bottom"] = new dgAdvectionBoundary0External();
   }
   ~dgConservationLawAdvection()
   {
     delete _convective;
     delete _riemannSolver;
+    delete _boundaryConditions["Left"];
+    delete _boundaryConditions["Right"];
+    delete _boundaryConditions["Top"];
+    delete _boundaryConditions["Bottom"];
   }
 };
 
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index 6d10a34e4ebbc1a8a716ca4af83cb84355afaea4..abbb35e3263bfcbad7c79518962598707147abf7 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -4,6 +4,7 @@
 #include "Numeric.h"
 #include "MTriangle.h"
 #include "MLine.h"
+#include "GModel.h"
 
 static fullMatrix<double> * dgGetIntegrationRule (MElement *e, int p){
   int npts;
@@ -156,22 +157,24 @@ void dgGroupOfFaces::addFace(const MFace &topoFace, int iElLeft, int iElRight){
   // compute all closures
   // compute closures for the interpolation
   _left.push_back(iElLeft);
-  _right.push_back(iElRight);
-  MElement &elRight = *_groupRight.getElement(iElRight);
   MElement &elLeft = *_groupLeft.getElement(iElLeft);
   int ithFace, sign, rot;
   elLeft.getFaceInfo (topoFace, ithFace, sign, rot);
   _closuresLeft.push_back(&(_fsLeft->getFaceClosure(ithFace, sign, rot)));
-  elRight.getFaceInfo (topoFace, ithFace, sign, rot);
-  _closuresRight.push_back(&(_fsRight->getFaceClosure(ithFace, sign, rot)));        
+  const std::vector<int> & geomClosure = elLeft.getFunctionSpace()->getFaceClosure(ithFace, sign, rot);
+  if(iElRight>=0){
+    MElement &elRight = *_groupRight.getElement(iElRight);
+    _right.push_back(iElRight);
+    elRight.getFaceInfo (topoFace, ithFace, sign, rot);
+    _closuresRight.push_back(&(_fsRight->getFaceClosure(ithFace, sign, rot)));        
+  }
   // compute the face element that correspond to the geometrical closure
   // get the vertices of the face
   std::vector<MVertex*> vertices;
   for(int j=0;j<topoFace.getNumVertices();j++)
     vertices.push_back(topoFace.getVertex(j));
-  const std::vector<int> & geomClosure = elRight.getFunctionSpace()->getFaceClosure(ithFace, sign, rot);
   for (int j=0; j<geomClosure.size() ; j++)
-    vertices.push_back( elRight.getVertex(geomClosure[j]) );
+    vertices.push_back( elLeft.getVertex(geomClosure[j]) );
   // triangular face
   if (topoFace.getNumVertices() == 3){
     switch(vertices.size()){
@@ -186,31 +189,20 @@ void dgGroupOfFaces::addFace(const MFace &topoFace, int iElLeft, int iElRight){
   // quad face 2 do
   else throw;
 }
-static std::vector<int> *fakeClosure2d(const polynomialBasis *fs, int ithEdge, int sign){
-  std::vector<int> closure;
-  if(sign==1){
-    closure.push_back(ithEdge);
-    closure.push_back((ithEdge+1)%3);
-  }else{
-    closure.push_back((ithEdge+1)%3);
-    closure.push_back(ithEdge);
-  }
-  std::vector<int> closureHO = fs->getEdgeClosure(ithEdge, sign);
-  closure.insert(closure.end(),closureHO.begin(),closureHO.end());
-  return new std::vector<int>(closure);
-}
 
 void dgGroupOfFaces::addEdge(const MEdge &topoEdge, int iElLeft, int iElRight){
   _left.push_back(iElLeft);
-  _right.push_back(iElRight);
-  MElement &elRight = *_groupRight.getElement(iElRight);
   MElement &elLeft = *_groupLeft.getElement(iElLeft);
   int ithEdge, sign;
   elLeft.getEdgeInfo (topoEdge, ithEdge, sign);
-  _closuresLeft.push_back(fakeClosure2d(_fsLeft, ithEdge, sign));
-  elRight.getEdgeInfo (topoEdge, ithEdge, sign);
-  _closuresRight.push_back(fakeClosure2d(_fsRight, ithEdge, sign));
-  const std::vector<int> &geomClosure = elRight.getFunctionSpace()->getEdgeClosure(ithEdge, sign);
+  _closuresLeft.push_back(&_fsLeft->getEdgeClosure(ithEdge, sign));
+  const std::vector<int> &geomClosure = elLeft.getFunctionSpace()->getEdgeClosure(ithEdge, sign);
+  if(iElRight>=0){
+    _right.push_back(iElRight);
+    MElement &elRight = *_groupRight.getElement(iElRight);
+    elRight.getEdgeInfo (topoEdge, ithEdge, sign);
+    _closuresRight.push_back(&_fsRight->getEdgeClosure(ithEdge, sign));
+  }
   std::vector<MVertex*> vertices;
   if(sign==1)
     for(int j=0;j<topoEdge.getNumVertices();j++)
@@ -219,7 +211,7 @@ void dgGroupOfFaces::addEdge(const MEdge &topoEdge, int iElLeft, int iElRight){
     for(int j=topoEdge.getNumVertices()-1;j>=0;j--)
       vertices.push_back(topoEdge.getVertex(j));
   for (int j=0; j<geomClosure.size() ; j++)
-    vertices.push_back( elRight.getVertex(geomClosure[j]) );
+    vertices.push_back( elLeft.getVertex(geomClosure[j]) );
   switch(vertices.size()){
     case 2  : _faces.push_back(new MLine (vertices) ); break;
     case 3  : _faces.push_back(new MLine3 (vertices) ); break;
@@ -258,6 +250,42 @@ dgGroupOfFaces::~dgGroupOfFaces()
   delete _collocation;
   delete _detJac;
 }
+dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, std::string boundaryTag, int pOrder,std::set<MEdge,Less_Edge> &boundaryEdges):
+  _groupLeft(elGroup),_groupRight(elGroup)
+{
+  _boundaryTag=boundaryTag;
+  if(boundaryTag=="")
+    throw;
+  _fsLeft=_groupLeft.getElement(0)->getFunctionSpace(pOrder);
+  _fsRight=NULL;
+  for(int i=0; i<elGroup.getNbElements(); i++){
+    MElement &el = *elGroup.getElement(i);
+    for (int j=0; j<el.getNumEdges(); j++){
+      MEdge edge = el.getEdge(j);
+      if(boundaryEdges.find(edge)!=boundaryEdges.end())
+        addEdge(edge,i,-1);
+    }
+  }
+  init(pOrder);
+}
+dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, std::string boundaryTag, int pOrder,std::set<MFace,Less_Face> &boundaryFaces):
+  _groupLeft(elGroup),_groupRight(elGroup)
+{
+  _boundaryTag=boundaryTag;
+  if(boundaryTag=="")
+    throw;
+  _fsLeft=_groupLeft.getElement(0)->getFunctionSpace(pOrder);
+  _fsRight=NULL;
+  for(int i=0; i<elGroup.getNbElements(); i++){
+    MElement &el = *elGroup.getElement(i);
+    for (int j=0; j<el.getNumFaces(); j++){
+      MFace face = el.getFace(j);
+      if(boundaryFaces.find(face)!=boundaryFaces.end())
+        addFace(face,i,-1);
+    }
+  }
+  init(pOrder);
+}
 
 dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, int pOrder):
   _groupLeft(elGroup),_groupRight(elGroup)
@@ -305,15 +333,27 @@ void dgGroupOfFaces::mapToInterface ( int nFields,
     const fullMatrix<double> &vRight,
     fullMatrix<double> &v)
 {
-  for(int i=0; i<getNbElements(); i++) {
-    const std::vector<int> &closureRight = *getClosureRight(i);
-    const std::vector<int> &closureLeft = *getClosureLeft(i);
-    for (int iField=0; iField<nFields; iField++){
-      for(size_t j =0; j < closureLeft.size(); j++){
-        v(j, i*2*nFields + iField) = vLeft(closureLeft[j], _left[i]*nFields + iField);
+  if(isBoundary()){
+    for(int i=0; i<getNbElements(); i++) {
+      const std::vector<int> &closureLeft = *getClosureLeft(i);
+      for (int iField=0; iField<nFields; iField++){
+        for(size_t j =0; j < closureLeft.size(); j++){
+          v(j, i*nFields + iField) = vLeft(closureLeft[j], _left[i]*nFields + iField);
+        }
+      }
+    }
+    
+  }else{
+    for(int i=0; i<getNbElements(); i++) {
+      const std::vector<int> &closureRight = *getClosureRight(i);
+      const std::vector<int> &closureLeft = *getClosureLeft(i);
+      for (int iField=0; iField<nFields; iField++){
+        for(size_t j =0; j < closureLeft.size(); j++){
+          v(j, i*2*nFields + iField) = vLeft(closureLeft[j], _left[i]*nFields + iField);
+        }
+        for(size_t j =0; j < closureRight.size(); j++)
+          v(j, (i*2+1)*nFields + iField) = vRight(closureRight[j], _right[i]*nFields + iField);
       }
-      for(size_t j =0; j < closureRight.size(); j++)
-        v(j, (i*2+1)*nFields + iField) = vRight(closureRight[j], _right[i]*nFields + iField);
     }
   }
 }
@@ -324,14 +364,25 @@ void dgGroupOfFaces::mapFromInterface ( int nFields,
     fullMatrix<double> &vRight
     )
 {
-  for(int i=0; i<getNbElements(); i++) {
-    const std::vector<int> &closureRight = *getClosureRight(i);
-    const std::vector<int> &closureLeft = *getClosureLeft(i);
-    for (int iField=0; iField<nFields; iField++){
-      for(size_t j =0; j < closureLeft.size(); j++)
-        vLeft(closureLeft[j], _left[i]*nFields + iField) += v(j, i*2*nFields + iField);
-      for(size_t j =0; j < closureRight.size(); j++)
-        vRight(closureRight[j], _right[i]*nFields + iField) += v(j, (i*2+1)*nFields + iField);
+  if(isBoundary()){
+    for(int i=0; i<getNbElements(); i++) {
+      const std::vector<int> &closureLeft = *getClosureLeft(i);
+      for (int iField=0; iField<nFields; iField++){
+        for(size_t j =0; j < closureLeft.size(); j++)
+          vLeft(closureLeft[j], _left[i]*nFields + iField) += v(j, i*nFields + iField);
+      }
+    }
+  }else{
+    for(int i=0; i<getNbElements(); i++) {
+      const std::vector<int> &closureRight = *getClosureRight(i);
+      const std::vector<int> &closureLeft = *getClosureLeft(i);
+      for (int iField=0; iField<nFields; iField++){
+        for(size_t j =0; j < closureLeft.size(); j++)
+          vLeft(closureLeft[j], _left[i]*nFields + iField) += v(j, i*2*nFields + iField);
+        for(size_t j =0; j < closureRight.size(); j++)
+          vRight(closureRight[j], _right[i]*nFields + iField) += v(j, (i*2+1)*nFields + iField);
+      }
     }
   }
 }
+
diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h
index a2f5035d5a72d4eb7074ad7fac40f8d547a9e708..da35c02100acbff7c886136eeb5ada8f5d07b68e 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -13,10 +13,11 @@
   we DO NOT store N, Ni or Nv (matrices and vectors 
   have the right sizes)
 */
+#include "MFace.h"
+#include "MEdge.h"
 class MElement;
-class MFace;
-class MEdge;
 class polynomialBasis;
+class GEntity;
 
 class dgElement {
   MElement *_element;
@@ -105,6 +106,8 @@ public:
 };
 
 class dgGroupOfFaces {
+  // only used if this is a group of boundary faces
+  std::string _boundaryTag;
   const dgGroupOfElements &_groupLeft,&_groupRight;
   void addFace(const MFace &topoFace, int iElLeft, int iElRight);
   void addEdge(const MEdge &topoEdge, int iElLeft, int iElRight);
@@ -143,7 +146,11 @@ public:
   const std::vector<int> * getClosureRight(int iFace) const{ return _closuresRight[iFace];}
   inline fullMatrix<double> getNormals (int iFace) const {return fullMatrix<double>(*_normals,iFace*getNbIntegrationPoints(),getNbIntegrationPoints());}
   dgGroupOfFaces (const dgGroupOfElements &elements,int pOrder);
+  dgGroupOfFaces (const dgGroupOfElements &elGroup, std::string boundaryTag, int pOrder,std::set<MEdge,Less_Edge> &boundaryEdges);
+  dgGroupOfFaces (const dgGroupOfElements &elGroup, std::string boundaryTag, int pOrder,std::set<MFace,Less_Face> &boundaryFaces);
   virtual ~dgGroupOfFaces ();
+  inline bool isBoundary() const {return !_boundaryTag.empty();}
+  inline const std::string getBoundaryTag() const {return _boundaryTag;}
   //this part is common with dgGroupOfElements, we should try polymorphism
   inline int getNbElements() const {return _faces.size();}
   inline int getNbNodes() const {return _collocation->size1();}
@@ -158,5 +165,4 @@ public:
 };
 
 
-
 #endif
diff --git a/Solver/dgMainTest.cpp b/Solver/dgMainTest.cpp
index d162aa98ff196865da2d6f5c484698c54a77d47b..cd53ba9c7ac9c1caf47a3d25a6102de78d95c421 100644
--- a/Solver/dgMainTest.cpp
+++ b/Solver/dgMainTest.cpp
@@ -9,7 +9,6 @@
 
 #include "MElement.h"
 void print (const char *filename,const dgGroupOfElements &els, double *v);
-std::vector<MElement *> getAllTri(GModel *model);
 
 class testSourceTerm : public dgTerm {
   void operator () (const dgElement &el, fullMatrix<double> fcx[]) const{
@@ -18,7 +17,7 @@ class testSourceTerm : public dgTerm {
     SPoint3 p;
     for(int i=0; i< sol.size1(); i++) {
       el.element()->pnt(qp(i,0),qp(i,1),qp(i,2),p);
-      fcx[0](i,0)=exp(-(pow(p.x()-0.2,2)+pow(p.y(),2))*100);
+      fcx[0](i,0)=exp(-(pow(p.x()-0.2,2)+pow(p.y()-0.3,2))*100);
     }
   }
 };
@@ -35,60 +34,43 @@ class dgConservationLawInitialCondition : public dgConservationLaw {
 };
 
 int main(int argc, char **argv){
-  GmshMergeFile("mesh1.msh");
-  //GmshMergeFile("square2.msh");
-  std::vector<MElement *> allTri=getAllTri(GModel::current());
+  GmshMergeFile("square1.msh");
+  //we probably need a class to group those three ones
+  std::vector<dgGroupOfElements*> elementGroups;
+  std::vector<dgGroupOfFaces*> faceGroups;
+  std::vector<dgGroupOfFaces*> boundaryGroups;
   int order=1;
-  dgGroupOfElements elements(allTri,order);
-  dgGroupOfFaces faces(elements,order);
-  //dgGroupOfFaces faces(elements0,elements1,order);
-  int nbNodes = elements.getNbNodes();
-  fullMatrix<double> sol(nbNodes,elements.getNbElements());
-  fullMatrix<double> residu(nbNodes,elements.getNbElements());
+  int dimension=2;
   dgAlgorithm algo;
+  algo.buildGroups(GModel::current(),dimension,order,elementGroups,faceGroups,boundaryGroups);
+
+  //for now, we suppose there is only one group of elements
+  int nbNodes = elementGroups[0]->getNbNodes();
+  fullMatrix<double> sol(nbNodes,elementGroups[0]->getNbElements());
+  fullMatrix<double> residu(nbNodes,elementGroups[0]->getNbElements());
   // initial condition
   {
     dgConservationLawInitialCondition initLaw;
-    algo.residualVolume(initLaw,elements,sol,residu);
-    algo.multAddInverseMassMatrix(elements,residu,sol);
+    algo.residualVolume(initLaw,*elementGroups[0],sol,residu);
+    algo.multAddInverseMassMatrix(*elementGroups[0],residu,sol);
   }
-  print("init.pos",elements,&sol(0,0));
+  print("init.pos",*elementGroups[0],&sol(0,0));
   //advection
   dgConservationLaw *law = dgNewConservationLawAdvection();
   for(int iT=0; iT<1000; iT++) {
-    residu.scale(0);
-    algo.residualVolume(*law,elements,sol,residu);
-    { //interface term
-      fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2);
-      fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2);
-      faces.mapToInterface(1, sol, sol, solInterface);
-      algo.residualInterface(*law,faces,solInterface,residuInterface);
-      faces.mapFromInterface(1, residuInterface, residu, residu);
-    }
+    algo.residual(*law,elementGroups,faceGroups,boundaryGroups,sol,residu);
     residu.scale(0.01);
-    algo.multAddInverseMassMatrix(elements,residu,sol);
+    algo.multAddInverseMassMatrix(*elementGroups[0],residu,sol);
     if(iT%10==0){
       char name[100];
       sprintf(name,"test_%05i.pos",iT/10);
       printf("%i\n",iT);
-      print(name,elements,&sol(0,0));
+      print(name,*elementGroups[0],&sol(0,0));
     }
   }
   delete law;
 }
 
-std::vector<MElement *> getAllTri(GModel *model){
-  std::vector<GEntity*> entities;
-  model->getEntities(entities);
-  std::vector<MElement *> all_tri;
-  for(std::vector<GEntity *>::iterator itent=entities.begin(); itent!=entities.end(); itent++){
-    if ((*itent)->dim()!=2) continue;
-    for (int iel=0; iel<(*itent)->getNumMeshElements(); iel++)
-      all_tri.push_back((*itent)->getMeshElement(iel));
-  }
-  return all_tri;
-}
-
 void print (const char *filename,const dgGroupOfElements &els, double *v) {
   FILE *file = fopen(filename,"w");
   fprintf(file,"View \"%s\" {\n", filename);