diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index a0346fb8a74eacc80d33463be5c01eb7dfac23e7..085b5d20dcf58427181afd46d52bbb98ac140624 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -126,3 +126,4 @@ void dgAlgorithm::residualInterface ( //dofManager &dof, // the DOF manager (may
   // ----- 3 ---- do the redistribution at face nodes using BLAS3
   residual.gemm(group.getRedistributionMatrix(),NormalFluxQP);
 }
+
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index 420b6b667fcde6db3e579738ae4ea91815fda80c..30c269ab42fc75f257b5f0ad4a11c6a12c0463ef 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -117,44 +117,7 @@ dgGroupOfElements::~dgGroupOfElements(){
   delete _imass;
 }
 
-// dgGroupOfFaces
-void dgGroupOfFaces::createFaceElements (const std::vector<MFace> &topo_faces){
-  
-  _faces.resize(topo_faces.size());
-  // compute all closures
-  for (int i=0;i<topo_faces.size();i++){
-    // compute closures for the interpolation
-    int ithFace, sign, rot;
-    getElementLeft(i)->getFaceInfo (topo_faces[i], ithFace, sign, rot);
-    _closuresLeft.push_back(&(_fsLeft->getFaceClosure(ithFace, sign, rot)));
-    getElementRight(i)->getFaceInfo (topo_faces[i], 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;
-    const std::vector<int> & geomClosure = getElementRight(i)->getFunctionSpace()->getFaceClosure(ithFace, sign, rot);
-    for (int j=0; j<geomClosure.size() ; j++){
-      int iNod = geomClosure[j];
-      MVertex *v = getElementLeft(i)->getVertex(iNod);
-      _vertices.push_back(v);
-    }
-    // triangular face
-    if (topo_faces[i].getNumVertices() == 3){
-      switch(_vertices.size()){
-      case 3  : _faces.push_back(new MTriangle (_vertices) ); break;
-      case 6  : _faces.push_back(new MTriangle6 (_vertices) ); break;
-      case 10 : _faces.push_back(new MTriangleN (_vertices, 3) ); break;
-      case 15 : _faces.push_back(new MTriangleN (_vertices, 4) ); break;
-      case 21 : _faces.push_back(new MTriangleN (_vertices, 5) ); break;
-      default : throw;
-      }
-    }
-    // quad face 2 do
-    else throw;
-  }  
-}
 
-// dgGroupOfFaces
 void dgGroupOfFaces::computeFaceNormals () {
   double g[256][3];
   _normals = new fullMatrix<double> (_fsFace->points.size1()*_faces.size(),3);
@@ -182,31 +145,64 @@ void dgGroupOfFaces::computeFaceNormals () {
   }
 }
 
-void dgGroupOfFaces::createEdgeElements (const std::vector<MEdge> &topo_edges){
-  
-  _faces.resize(topo_edges.size());
+void dgGroupOfFaces::addFace(const MFace &topoFace, int iElLeft, int iElRight){
   // compute all closures
-  for (int i=0;i<topo_edges.size();i++){
-    int ithEdge, sign;
-    getElementLeft(i)->getEdgeInfo (topo_edges[i], ithEdge, sign);
-    _closuresLeft.push_back(&(_fsLeft->getEdgeClosure(ithEdge, sign)));
-    getElementRight(i)->getEdgeInfo (topo_edges[i], ithEdge, sign);
-    _closuresRight.push_back(&(_fsRight->getEdgeClosure(ithEdge, sign)));    
-    // get the vertices of the edge
-    const std::vector<int> & geomClosure = getElementRight(i)->getFunctionSpace()->getEdgeClosure(ithEdge, sign);
-    std::vector<MVertex*> _vertices;
-    for (int j=0; j<geomClosure.size() ; j++){
-      int iNod = geomClosure[j];
-      MVertex *v = getElementLeft(i)->getVertex(iNod);
-      _vertices.push_back(v);
-    }
-    switch(_vertices.size()){
-    case 2  : _faces.push_back(new MLine (_vertices) ); break;
-    case 3  : _faces.push_back(new MLine3 (_vertices) ); break;
-    default : _faces.push_back(new MLineN (_vertices) ); break;
+  // 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)));        
+  // 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]) );
+  // triangular face
+  if (topoFace.getNumVertices() == 3){
+    switch(vertices.size()){
+      case 3  : _faces.push_back(new MTriangle (vertices) ); break;
+      case 6  : _faces.push_back(new MTriangle6 (vertices) ); break;
+      case 10 : _faces.push_back(new MTriangleN (vertices, 3) ); break;
+      case 15 : _faces.push_back(new MTriangleN (vertices, 4) ); break;
+      case 21 : _faces.push_back(new MTriangleN (vertices, 5) ); break;
+      default : throw;
     }
   }
+  // quad face 2 do
+  else throw;
+}
+
+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(&(_fsLeft->getEdgeClosure(ithEdge, sign)));
+  elRight.getEdgeInfo (topoEdge, ithEdge, sign);
+  _closuresRight.push_back(&(_fsRight->getEdgeClosure(ithEdge, sign)));    
+  const std::vector<int> &geomClosure = elRight.getFunctionSpace()->getEdgeClosure(ithEdge, sign);
+  std::vector<MVertex*> vertices;
+  for(int j=0;j<topoEdge.getNumVertices();j++)
+    vertices.push_back(topoEdge.getVertex(j));
+  for (int j=0; j<geomClosure.size() ; j++)
+    vertices.push_back( elRight.getVertex(geomClosure[j]) );
+  switch(vertices.size()){
+    case 2  : _faces.push_back(new MLine (vertices) ); break;
+    case 3  : _faces.push_back(new MLine3 (vertices) ); break;
+    default : _faces.push_back(new MLineN (vertices) ); break;
+  }
 }
+
 void dgGroupOfFaces::init(int pOrder) {
   _fsFace = _faces[0]->getFunctionSpace (pOrder);
   _integration=dgGetIntegrationRule (_faces[0],pOrder);
@@ -223,29 +219,83 @@ void dgGroupOfFaces::init(int pOrder) {
   }
 }
 
-dgGroupOfFaces::dgGroupOfFaces (const std::vector<MFace> &topo_faces, 		  
-        const std::vector<dgGroupOfElements*> group_list,
-				const std::vector<std::pair<int,int> > &l, 
-				const std::vector<std::pair<int,int> > &r,
-				int pOrder) : _group_list(group_list),_left(l), _right(r),
-        _fsLeft(getElementLeft(0)->getFunctionSpace (pOrder)), _fsRight (getElementRight(0)->getFunctionSpace (pOrder))
+dgGroupOfFaces::~dgGroupOfFaces()
 {
-  createFaceElements (topo_faces);
-  init(pOrder);
+  
 }
 
-dgGroupOfFaces::dgGroupOfFaces (const std::vector<MEdge> &topo_edges, 		  
-        const std::vector<dgGroupOfElements*> group_list,
-				const std::vector<std::pair<int,int> > &l, 
-				const std::vector<std::pair<int,int> > &r,
-				int pOrder) : _group_list(group_list),_left(l), _right(r),
-        _fsLeft(getElementLeft(0)->getFunctionSpace (pOrder)), _fsRight (getElementRight(0)->getFunctionSpace (pOrder))
+dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, int pOrder):
+  _groupLeft(elGroup),_groupRight(elGroup)
 {
-  createEdgeElements (topo_edges);
+  _fsLeft=_groupLeft.getElement(0)->getFunctionSpace(pOrder);
+  _fsRight=_groupRight.getElement(0)->getFunctionSpace(pOrder);
+  switch (_groupLeft.getElement(0)->getDim()) {
+    case 2 : {
+      std::map<MEdge,int,Less_Edge> edgeMap;
+      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(edgeMap.find(edge) == edgeMap.end()){
+            edgeMap[edge] = i;
+          }else{
+            addEdge(edge,edgeMap[edge],i);
+          }
+        }
+      }
+      break;
+    }
+    case 3 : {
+      std::map<MFace,int,Less_Face> faceMap;
+      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(faceMap.find(face) == faceMap.end()){
+            faceMap[face] = i;
+          }else{
+            addFace(face,faceMap[face],i);
+          }
+        }
+      }
+      break;
+    }
+    default : throw;
+  }
   init(pOrder);
 }
 
-dgGroupOfFaces::~dgGroupOfFaces()
+void dgGroupOfFaces::mapToInterface ( int nFields,
+    const fullMatrix<double> &vLeft,
+    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);
+      for(size_t j =0; j < closureRight.size(); j++)
+        v(j, (i*2+1)*nFields + iField) = vRight(closureRight[j], _right[i]*nFields + iField);
+    }
+  }
+}
+
+void dgGroupOfFaces::mapFromInterface ( int nFields,
+    const fullMatrix<double> &v,
+    fullMatrix<double> &vLeft,
+    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);
+    }
+  }
 }
diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h
index 2b34680d6c53ce28713439131345d9230f42942c..6277359e3412fb8dc8addcff47660360c252c59a 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -104,15 +104,15 @@ public:
 };
 
 class dgGroupOfFaces {
-  std::vector<dgGroupOfElements*> _group_list;
-  void createFaceElements (const std::vector<MFace> &topo_faces);
-  void createEdgeElements (const std::vector<MEdge> &topo_faces);
+  const dgGroupOfElements &_groupLeft,&_groupRight;
+  void addFace(const MFace &topoFace, int iElLeft, int iElRight);
+  void addEdge(const MEdge &topoEdge, int iElLeft, int iElRight);
   void computeFaceNormals();
   // Two functionSpaces for left and right elements
   // the group has always the same types for left and right
   const functionSpace *_fsLeft,*_fsRight, *_fsFace;
   // N elements in the group
-  std::vector<std::pair<int,int> >_left, _right;
+  std::vector<int>_left, _right;
   std::vector<MElement *>_faces;
   // Ni integration points, matrix of size Ni x 3 (u,v,weight)
   fullMatrix<double> *_integration;
@@ -135,21 +135,12 @@ class dgGroupOfFaces {
   //common part of the 3 constructors
   void init(int pOrder);
 public:
-  inline MElement* getElementLeft (int i) const {return _group_list[_left[i].first]->getElement(_left[i].second);}  
-  inline MElement* getElementRight (int i) const {return _group_list[_right[i].first]->getElement(_right[i].second);}  
+  inline MElement* getElementLeft (int i) const {return _groupLeft.getElement(_left[i]);}  
+  inline MElement* getElementRight (int i) const {return _groupRight.getElement(_right[i]);}  
   inline MElement* getFace (int iElement) const {return _faces[iElement];}  
   const std::vector<int> * getClosureLeft(int iFace) const{ return _closuresLeft[iFace];}
   const std::vector<int> * getClosureRight(int iFace) const{ return _closuresRight[iFace];}
-  dgGroupOfFaces (const std::vector<MFace> &faces, 		  
-      const std::vector<dgGroupOfElements*> group_list,
-		  const std::vector<std::pair<int,int> > &l, 
-		  const std::vector<std::pair<int,int> > &r,
-		  int pOrder);
-  dgGroupOfFaces (const std::vector<MEdge> &edges, 		  
-      const std::vector<dgGroupOfElements*> group_list,
-		  const std::vector<std::pair<int,int> > &l, 
-		  const std::vector<std::pair<int,int> > &r,
-		  int pOrder);
+  dgGroupOfFaces (const dgGroupOfElements &elements,int pOrder);
   virtual ~dgGroupOfFaces ();
   //this part is common with dgGroupOfElements, we should try polymorphism
   inline int getNbElements() const {return _faces.size();}
@@ -159,6 +150,9 @@ public:
   inline const fullMatrix<double> & getIntegrationPointsMatrix () const {return *_integration;}
   inline const fullMatrix<double> & getRedistributionMatrix () const {return *_redistribution;}
   inline double getDetJ (int iElement, int iGaussPoint) const {return (*_detJac)(iElement, iGaussPoint);}
+  //keep this outside the Algorithm because this is the only place where data overlap
+  void mapToInterface(int nFields, const fullMatrix<double> &vLeft, const fullMatrix<double> &vRight, fullMatrix<double> &v);
+  void mapFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vLeft, fullMatrix<double> &vRight);
 };
 
 
diff --git a/Solver/dgMainTest.cc b/Solver/dgMainTest.cc
index cc0ea70b0f7c678f7c18e069dfc7577b70d902a6..a0ca1d73709dea69ec2b6f8142d5a15d90c56712 100644
--- a/Solver/dgMainTest.cc
+++ b/Solver/dgMainTest.cc
@@ -9,32 +9,34 @@
 
 #include "MElement.h"
 void print (const char *filename,const dgGroupOfElements &els, double *v);
-void buildGroupAllTri(GModel *model, int order, //in
-                         std::vector<dgGroupOfElements*> &elements, //out
-                         std::vector<dgGroupOfFaces*> &faces); //out
+std::vector<MElement *> getAllTri(GModel *model);
 
 int main(int argc, char **argv){
   GmshMergeFile("input/mesh1.msh");
-  std::vector<dgGroupOfElements*> elements;
-  std::vector<dgGroupOfFaces*> faces;
-  buildGroupAllTri(GModel::current(),1,elements,faces);
-  int nbNodes=elements[0]->getNbNodes();
-  fullMatrix<double> sol(nbNodes,elements[0]->getNbElements());
-  fullMatrix<double> residu(nbNodes,elements[0]->getNbElements());
+  std::vector<MElement *> allTri=getAllTri(GModel::current());
+  int order=1;
+  dgGroupOfElements elements(allTri,order);
+  dgGroupOfFaces faces(elements,order);
+  int nbNodes=elements.getNbNodes();
+  fullMatrix<double> sol(nbNodes,elements.getNbElements());
+  fullMatrix<double> solInterface(nbNodes,faces.getNbElements()*2);
+  fullMatrix<double> residu(nbNodes,elements.getNbElements());
+  fullMatrix<double> residuInterface(nbNodes,faces.getNbElements()*2);
   dgAlgorithm algo;
   dgConservationLaw *law = dgNewConservationLawAdvection();
-  algo.residualVolume(*law,*elements[0],sol,residu);
-  for(int i=0;i<elements[0]->getNbElements();i++) {
+  algo.residualVolume(*law,elements,sol,residu);
+  faces.mapToInterface(1, sol, sol, solInterface);
+  algo.residualInterface(*law,faces,solInterface,residuInterface);
+  faces.mapFromInterface(1, residuInterface, residu, residu);
+  for(int i=0;i<elements.getNbElements();i++) {
     fullMatrix<double> residuEl(residu,i,1);
     fullMatrix<double> solEl(sol,i,1);
-    solEl.gemm(elements[0]->getInverseMassMatrix(i),residuEl);
+    solEl.gemm(elements.getInverseMassMatrix(i),residuEl);
   }
-  print("test.pos",*elements[0],&sol(0,0));
+  print("test.pos",elements,&sol(0,0));
 }
 
-void buildGroupAllTri(GModel *model, int order, //in
-                         std::vector<dgGroupOfElements*> &elements, //out
-                         std::vector<dgGroupOfFaces*> &faces){ //out
+std::vector<MElement *> getAllTri(GModel *model){
   std::vector<GEntity*> entities;
   model->getEntities(entities);
   std::vector<MElement *> all_tri;
@@ -43,7 +45,7 @@ void buildGroupAllTri(GModel *model, int order, //in
     for (int iel=0; iel<(*itent)->getNumMeshElements(); iel++)
       all_tri.push_back((*itent)->getMeshElement(iel));
   }
-  elements.push_back(new dgGroupOfElements(all_tri,order));
+  return all_tri;
 }
 
 void print (const char *filename,const dgGroupOfElements &els, double *v) {