diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h
index dd6018c3209e9275bef5bd8045ac2e770c9a355e..7d3d7d1725d0bead863bbe28f972f9161ce1c5b0 100644
--- a/Numeric/fullMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -155,7 +155,7 @@ class fullMatrix
     }
     return false; // no reallocation
   }
-  void setAsProxy(fullMatrix<scalar> &original, int c_start, int c)
+  void setAsProxy(const fullMatrix<scalar> &original, int c_start, int c)
   {
     if(_data && _own_data)
       delete [] _data;
diff --git a/Solver/dgConservationLaw.h b/Solver/dgConservationLaw.h
index 8058c567ac9dd4bc6768f19be814a2cda06ede65..37c46b7d931ffa182a8597fac4407e6399bf4469 100644
--- a/Solver/dgConservationLaw.h
+++ b/Solver/dgConservationLaw.h
@@ -48,8 +48,10 @@ class dgConservationLaw {
 
   inline const dgBoundaryCondition *getBoundaryCondition(const std::string tag) const {
     std::map<const std::string,dgBoundaryCondition*>::const_iterator it = _boundaryConditions.find(tag);
-    if(it==_boundaryConditions.end())
+    if(it==_boundaryConditions.end()) {
+      Msg::Error("no boundary condition defined with tag '%s'", tag.c_str());
       throw;
+    }
     return it->second;
   }
 
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index aae4f59b214f11fd3a828885cd546956d9372ef8..1836721e214d16e51de15e55b158589ca65bf800 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -53,7 +53,6 @@ static fullMatrix<double> dgGetFaceIntegrationRuleOnElement (
   return intgElement;
 }
 
-
 dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, 
 				     int polyOrder,
 				     int ghostPartition)
@@ -175,9 +174,9 @@ void dgGroupOfFaces::mapToInterface ( int nFields,
     const fullMatrix<double> &vRight,
     fullMatrix<double> &v)
 {
-  if(isBoundary()){
+  if(_connections.size()==1){
     for(int i=0; i<getNbElements(); i++) {
-      const std::vector<int> &closureLeft = getClosureLeft(i);
+      const std::vector<int> &closureLeft = _connections[0]->getClosure(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], _connections[0]->getElementId(i)*nFields + iField);
@@ -187,8 +186,8 @@ void dgGroupOfFaces::mapToInterface ( int nFields,
     
   }else{
     for(int i=0; i<getNbElements(); i++) {
-      const std::vector<int> &closureRight = getClosureRight(i);
-      const std::vector<int> &closureLeft = getClosureLeft(i);
+      const std::vector<int> &closureLeft = _connections[0]->getClosure(i);
+      const std::vector<int> &closureRight = _connections[1]->getClosure(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],_connections[0]->getElementId(i)*nFields + iField);
@@ -206,9 +205,9 @@ void dgGroupOfFaces::mapFromInterface ( int nFields,
     fullMatrix<double> &vRight
     )
 {
-  if(isBoundary()){
+  if(_connections.size()==1){
     for(int i=0; i<getNbElements(); i++) {
-      const std::vector<int> &closureLeft = getClosureLeft(i);
+      const std::vector<int> &closureLeft = _connections[0]->getClosure(i);
       for (int iField=0; iField<nFields; iField++){
         for(size_t j =0; j < closureLeft.size(); j++)
           vLeft(closureLeft[j], _connections[0]->getElementId(i)*nFields + iField) += v(j, i*nFields + iField);
@@ -216,8 +215,8 @@ void dgGroupOfFaces::mapFromInterface ( int nFields,
     }
   }else{
     for(int i=0; i<getNbElements(); i++) {
-      const std::vector<int> &closureRight = getClosureRight(i);
-      const std::vector<int> &closureLeft = getClosureLeft(i);
+      const std::vector<int> &closureLeft = _connections[0]->getClosure(i);
+      const std::vector<int> &closureRight = _connections[1]->getClosure(i);
       for (int iField=0; iField<nFields; iField++){
         for(size_t j =0; j < closureLeft.size(); j++)
           vLeft(closureLeft[j], _connections[0]->getElementId(i)*nFields + iField) += v(j, i*2*nFields + iField);
@@ -227,14 +226,14 @@ void dgGroupOfFaces::mapFromInterface ( int nFields,
     }
   }
 }
+
 void dgGroupOfFaces::mapLeftFromInterface ( int nFields,
     const fullMatrix<double> &v,
     fullMatrix<double> &vLeft
     )
 {
   for(int i=0; i<getNbElements(); i++) {
-    const std::vector<int> &closureRight = getClosureRight(i);
-    const std::vector<int> &closureLeft = getClosureLeft(i);
+    const std::vector<int> &closureLeft = _connections[0]->getClosure(i);
     for (int iField=0; iField<nFields; iField++){
       for(size_t j =0; j < closureLeft.size(); j++)
         vLeft(closureLeft[j], _connections[0]->getElementId(i)*nFields + iField) += v(j, i*2*nFields + iField);
@@ -246,11 +245,10 @@ void dgGroupOfFaces::mapRightFromInterface ( int nFields,
     fullMatrix<double> &vRight
     )
 {
-  if(isBoundary())
+  if(_connections.size()==1)
     return;
   for(int i=0; i<getNbElements(); i++) {
-    const std::vector<int> &closureRight = getClosureRight(i);
-    const std::vector<int> &closureLeft = getClosureLeft(i);
+    const std::vector<int> &closureRight = _connections[1]->getClosure(i);
     for (int iField=0; iField<nFields; iField++){
       for(size_t j =0; j < closureRight.size(); j++)
         vRight(closureRight[j], _connections[1]->getElementId(i)*nFields + iField) += v(j, (i*2+1)*nFields + iField);
@@ -271,7 +269,7 @@ void dgGroupOfConnections::init() {
   // compute data on quadrature points : normals and dPsidX
   double g[256][3];
   _normals = fullMatrix<double> (3, nQP*size);
-  _dPsiDxOnQP = fullMatrix<double> ( nQP*3, nPsi*size);
+  _dPsiDx = fullMatrix<double> ( nQP*3, nPsi*size);
   int index = 0;
   for (size_t i=0; i<size;i++){
     const std::vector<int> &closure = getClosure(i);
@@ -284,9 +282,9 @@ void dgGroupOfConnections::init() {
       //compute dPsiDxOnQP
       // (iQP*3+iXYZ , iFace*NPsi+iPsi)
       for (int iPsi=0; iPsi< nPsi; iPsi++) {
-        _dPsiDxOnQP(j*3  ,i*nPsi+iPsi) = g[iPsi][0]*ijac[0][0]+g[iPsi][1]*ijac[0][1]+g[iPsi][2]*ijac[0][2];
-        _dPsiDxOnQP(j*3+1,i*nPsi+iPsi) = g[iPsi][0]*ijac[1][0]+g[iPsi][1]*ijac[1][1]+g[iPsi][2]*ijac[1][2];
-        _dPsiDxOnQP(j*3+2,i*nPsi+iPsi) = g[iPsi][0]*ijac[2][0]+g[iPsi][1]*ijac[2][1]+g[iPsi][2]*ijac[2][2];
+        _dPsiDx(j*3  ,i*nPsi+iPsi) = g[iPsi][0]*ijac[0][0]+g[iPsi][1]*ijac[0][1]+g[iPsi][2]*ijac[0][2];
+        _dPsiDx(j*3+1,i*nPsi+iPsi) = g[iPsi][0]*ijac[1][0]+g[iPsi][1]*ijac[1][1]+g[iPsi][2]*ijac[1][2];
+        _dPsiDx(j*3+2,i*nPsi+iPsi) = g[iPsi][0]*ijac[2][0]+g[iPsi][1]*ijac[2][1]+g[iPsi][2]*ijac[2][2];
       }
       //compute face normals
       double &nx=_normals(0,index);
@@ -311,14 +309,12 @@ void dgGroupOfConnections::init() {
   }
 }
 
-
 // this function creates groups of elements
 // First, groups of faces are created on every physical group
 // of dimension equal to the dimension of the problem minus one
 // Then, groups of elements are created 
 //  -) Elements of different types are separated
 //  -) Then those groups are split into partitions
-//  -) Finally, those groups are re-numbered 
  
 void dgGroupCollection::buildGroupsOfElements(GModel *model, int dim, int order)
 {
@@ -371,10 +367,10 @@ void dgGroupCollection::buildGroupsOfElements(GModel *model, int dim, int order)
   }
 }
 
-class dgMiniConnection {
+class dgMiniConnection 
+{
   public:
   int iGroup, iElement, iClosure;
-  int numVertices;
   dgMiniConnection (int iGroup_, int iElement_, int iClosure_)
   {
     iGroup = iGroup_;
@@ -392,7 +388,8 @@ class dgMiniConnection {
   }
 };
 
-class dgMiniInterface {
+class dgMiniInterface 
+{
   public:
   int physicalTag;
   int numVertices;
@@ -411,7 +408,8 @@ class dgMiniInterface {
   }
 };
 
-static std::vector<dgMiniInterface> *_createMiniInterfaces(dgGroupCollection &groups) {
+static std::vector<dgMiniInterface> *_createMiniInterfaces(dgGroupCollection &groups) 
+{
   std::vector<GEntity*> entities;
   groups.getModel()->getEntities(entities);
   std::map<MVertex*, dgMiniInterface> vertexInterfaces;
@@ -477,18 +475,24 @@ static std::vector<dgMiniInterface> *_createMiniInterfaces(dgGroupCollection &gr
   switch(dim) {
     case 1: 
       interfaces->reserve(vertexInterfaces.size());
-      for(std::map<MVertex*, dgMiniInterface>::iterator it = vertexInterfaces.begin(); it != vertexInterfaces.end(); it++)
+      for(std::map<MVertex*, dgMiniInterface>::iterator it = vertexInterfaces.begin(); it != vertexInterfaces.end(); it++) {
+        it->second.numVertices = 1;
         interfaces->push_back(it->second);
+      }
       break;
     case 2: 
       interfaces->reserve(edgeInterfaces.size());
-      for(std::map<MEdge, dgMiniInterface, Less_Edge>::iterator it = edgeInterfaces.begin(); it != edgeInterfaces.end(); it++)
+      for(std::map<MEdge, dgMiniInterface, Less_Edge>::iterator it = edgeInterfaces.begin(); it != edgeInterfaces.end(); it++) {
+        it->second.numVertices = it->first.getNumVertices();
         interfaces->push_back(it->second);
+      }
       break;
     case 3: 
       interfaces->reserve(faceInterfaces.size());
-      for(std::map<MFace, dgMiniInterface, Less_Face>::iterator it = faceInterfaces.begin(); it != faceInterfaces.end(); it++)
+      for(std::map<MFace, dgMiniInterface,Less_Face>::iterator it = faceInterfaces.begin(); it != faceInterfaces.end(); it++) {
+        it->second.numVertices = it->first.getNumVertices();
         interfaces->push_back(it->second);
+      }
       break;
   }
   for (size_t i = 0; i < interfaces->size(); i++) {
@@ -565,8 +569,13 @@ dgGroupOfFaces::dgGroupOfFaces (dgGroupCollection &groups, std::vector<dgMiniInt
   dgMiniInterface &first = interfaces.front();
   size_t nconnections = first.connections.size();
   int dim = groups.getElementGroup(first.connections[0].iGroup)->getElement(first.connections[0].iElement)->getDim()-1;
+  _physicalTag.clear();
   if(first.physicalTag>=0)
-    _boundaryTag = groups.getModel()->getPhysicalName(dim, first.physicalTag);
+    _physicalTag = groups.getModel()->getPhysicalName(dim, first.physicalTag);
+  if(nconnections==1 && (_physicalTag.empty() || _physicalTag=="")) {
+    Msg::Error("boundary face without tag in the mesh");
+    throw;
+  }
   for (size_t i=0; i<nconnections; i++) {
     _connections.push_back (new dgGroupOfConnections(*groups.getElementGroup(first.connections[i].iGroup), *this, pOrder));
   }
@@ -592,7 +601,7 @@ dgGroupOfFaces::dgGroupOfFaces (dgGroupCollection &groups, std::vector<dgMiniInt
         }
         break; 
       case 3 :
-        if (connection.numVertices == 3) {
+        if (interface.numVertices == 3) {
           switch(vertices.size()){
             case 3   : _faces.push_back (new MTriangle (vertices)); break;
             case 6   : _faces.push_back (new MTriangle6 (vertices)); break;
@@ -601,7 +610,7 @@ dgGroupOfFaces::dgGroupOfFaces (dgGroupCollection &groups, std::vector<dgMiniInt
             case 21  : _faces.push_back (new MTriangleN (vertices, 5)); break;
             default : throw;
           }
-        } else if (connection.numVertices == 4) {
+        } else if (interface.numVertices == 4) {
           switch(vertices.size()){
             case 4  : _faces.push_back (new MQuadrangle (vertices)); break;
             case 8  : _faces.push_back (new MQuadrangle8 (vertices)); break;
@@ -712,7 +721,6 @@ void dgGroupCollection::buildParallelStructure()
   delete []shiftRecv;
 }
 
-
 // Split the groups of elements depending on their local time step
 double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLaw *claw, dgDofContainer *solution) {
   // What are the levels/layers:
@@ -959,8 +967,6 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
     lowerLevelGroupIdEnd=currentNewGroupId;
     isOuterBufferLayer=!isOuterBufferLayer;
   }
-
-
   // Some stats
   int count=0;
   for(int i=0;i<newGroups.size();i++){
@@ -980,11 +986,11 @@ double dgGroupCollection::splitGroupsForMultirate(int maxLevels,dgConservationLa
   return dtRef;
 }
 
-
 dgGroupCollection::dgGroupCollection()
 {
   _groupsOfElementsBuilt=false;_groupsOfInterfacesBuilt=false;
 }
+
 dgGroupCollection::dgGroupCollection(GModel *model, int dimension, int order)
 {
   _groupsOfElementsBuilt=false;_groupsOfInterfacesBuilt=false;
@@ -1010,6 +1016,7 @@ void dgGroupCollection::find (MElement*e, int &ig, int &index)
     if (index != -1)return;
   }
 }
+
 #include "LuaBindings.h"
 void dgGroupCollection::registerBindings(binding *b)
 {
@@ -1019,7 +1026,6 @@ void dgGroupCollection::registerBindings(binding *b)
   cb->setDescription("a group of element sharing the same properties");
   cb = b->addClass<dgGroupOfFaces>("dgGroupOfFaces");
   cb->setDescription("a group of faces. All faces of this group are either interior of the same group of elements or at the boundary between two group of elements");
-
   cb = b->addClass<dgGroupCollection>("dgGroupCollection");
   cb->setDescription("The GroupCollection class let you access to group partitioning functions");
   cm = cb->setConstructor<dgGroupCollection,GModel*,int,int>();
diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h
index 3656a7055cd0b84599083b6d49a3129fe2ed1269..987e86593a50aad9b08d9235ece254d93d44a126 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -45,7 +45,6 @@ public:
 
 class dgGroupOfFaces;
 
-
 // store topological and geometrical data for 1 group for 1 discretisation
 class dgGroupOfElements {
   int _ghostPartition; // -1 : this is not a ghosted group, otherwise the id of the parent partition
@@ -142,7 +141,7 @@ class dgGroupOfConnections {
   std::vector<fullMatrix<double> > _integrationPoints;
   // XYZ gradient of the shape functions of both elements on the integrations points of the face
   // (iQP*3+iXYZ , iFace*NPsi+iPsi)
-  fullMatrix<double> _dPsiDxOnQP;
+  fullMatrix<double> _dPsiDx;
   const polynomialBasis *_fs;
   const dgGroupOfElements &_elementGroup;
   const dgGroupOfFaces &_faceGroup;
@@ -152,14 +151,14 @@ class dgGroupOfConnections {
   public:
   void addElement(int iElement, int iClosure);
   dgGroupOfConnections(const dgGroupOfElements &elementGroup, const dgGroupOfFaces &face, int pOrder);
-  inline const polynomialBasis *getFunctionSpace() {return _fs;}
-  inline const dgGroupOfElements &getGroupOfElements() {return _elementGroup;}
-  inline int getElementId(int i) {return _elementId[i];}
-  inline MElement *getElement(int i) {return _elementGroup.getElement(_elementId[i]);}
-  inline const std::vector<int>& getClosure(int i) {return _closures[_closuresId[i]];}
-  inline fullMatrix<double>& getIntegrationPointsOnElement(int i) {return _integrationPoints[_closuresId[i]];}
-  inline fullMatrix<double>& getDPsiDxOnQP() {return _dPsiDxOnQP;}
-  inline fullMatrix<double>& getNormals() {return _normals;}
+  inline const polynomialBasis *getFunctionSpace() const {return _fs;}
+  inline const dgGroupOfElements &getGroupOfElements() const {return _elementGroup;}
+  inline int getElementId(int i) const {return _elementId[i];}
+  inline MElement *getElement(int i) const {return _elementGroup.getElement(_elementId[i]);}
+  inline const std::vector<int>& getClosure(int i) const {return _closures[_closuresId[i]];}
+  inline const fullMatrix<double>& getIntegrationPointsOnElement(int i) const {return _integrationPoints[_closuresId[i]];}
+  inline const fullMatrix<double>& getDPsiDx() const {return _dPsiDx;}
+  inline const fullMatrix<double>& getNormals() const {return _normals;}
   void init();
 };
 
@@ -167,7 +166,7 @@ class dgGroupOfFaces {
   std::vector<dgGroupOfConnections*> _connections;
   // normals always point outside left to right
   // only used if this is a group of boundary faces
-  std::string _boundaryTag;
+  std::string _physicalTag;
   // Two polynomialBases for left and right elements
   // the group has always the same types for left and right
   const polynomialBasis *_fsFace;
@@ -187,7 +186,9 @@ class dgGroupOfFaces {
 public:
   dgGroupOfFaces (dgGroupCollection &groups, std::vector<dgMiniInterface> &interfaces, int pOrder);
   virtual ~dgGroupOfFaces ();
-  inline const std::string getBoundaryTag() const {return _boundaryTag;}
+  inline const std::string getPhysicalTag() const {return _physicalTag;}
+  inline const dgGroupOfConnections &getGroupOfConnections(int i) const {return *_connections[i];}
+  inline int getNbGroupOfConnections() const {return _connections.size();}
   //this part is common with dgGroupOfElements, we should try polymorphism
   inline int getNbElements() const {return _faces.size();}
   inline int getNbNodes() const {return _collocation->size2();}
@@ -199,28 +200,11 @@ public:
   inline double getInterfaceSurface (int iFace)const {return (*_interfaceSurface)(iFace,0);}
   const polynomialBasis * getPolynomialBasis() const {return _fsFace;}
   inline MElement* getFace (int iElement) const {return _faces[iElement];}  
-public:
-  // duplicate
-  bool isBoundary() {return _connections.size()==1;}
-  inline fullMatrix<double> &getNormals () const {return _connections[0]->getNormals();}
+public: // should be more generic on the number of connections
   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);
   void mapLeftFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vLeft);
   void mapRightFromInterface(int nFields, const fullMatrix<double> &v, fullMatrix<double> &vRight);
-  inline fullMatrix<double> & getDPsiLeftDxMatrix() const { return _connections[0]->getDPsiDxOnQP();}
-  inline fullMatrix<double> & getDPsiRightDxMatrix() const { return _connections[1]->getDPsiDxOnQP();}
-  inline const dgGroupOfElements &getGroupLeft()const {return _connections[0]->getGroupOfElements(); }
-  inline const dgGroupOfElements &getGroupRight()const {return _connections[1]->getGroupOfElements(); }
-  inline int getElementLeftId (int i) const {return _connections[0]->getElementId(i);}
-  inline int getElementRightId (int i) const {return _connections[1]->getElementId(i);}
-  inline MElement* getElementLeft (int i) const {return _connections[0]->getElement(i);}  
-  inline MElement* getElementRight (int i) const {return _connections[1]->getElement(i);}  
-  inline double getElementVolumeLeft(int iFace) const {return _connections[0]->getGroupOfElements().getElementVolume(getElementLeftId(iFace));}
-  inline double getElementVolumeRight(int iFace) const {return _connections[1]->getGroupOfElements().getElementVolume(getElementRightId(iFace));}
-  inline const std::vector<int> &getClosureLeft(int iFace) const{ return _connections[0]->getClosure(iFace);}
-  inline const std::vector<int> &getClosureRight(int iFace) const{ return _connections[1]->getClosure(iFace);}
-  inline fullMatrix<double> &getIntegrationOnElementLeft(int iFace) { return _connections[0]->getIntegrationPointsOnElement(iFace);}
-  inline fullMatrix<double> &getIntegrationOnElementRight(int iFace) { return _connections[1]->getIntegrationPointsOnElement(iFace);}
 };
 
 class dgGroupCollection {
diff --git a/Solver/dgLimiter.cpp b/Solver/dgLimiter.cpp
index 6b9c9fb2947ff07bf47eb639ef81026b93bcdd54..2bce19da120043de4576bd1d0bdc6ce05b677ebf 100644
--- a/Solver/dgLimiter.cpp
+++ b/Solver/dgLimiter.cpp
@@ -22,8 +22,10 @@ int dgSlopeLimiter::apply ( dgDofContainer *solution)
   fullMatrix<double> TempL, TempR;
   for( int iGFace=0; iGFace<groups->getNbFaceGroups(); iGFace++) {
     dgGroupOfFaces* group = groups->getFaceGroup(iGFace);  
-    const dgGroupOfElements *groupLeft = &group->getGroupLeft();
-    const dgGroupOfElements *groupRight = &group->getGroupRight();
+    const dgGroupOfConnections &left = group->getGroupOfConnections(0);
+    const dgGroupOfConnections &right = group->getGroupOfConnections(1);
+    const dgGroupOfElements *groupLeft = &left.getGroupOfElements();
+    const dgGroupOfElements *groupRight = &right.getGroupOfElements();
 
     fullMatrix<double> &solleft = solution->getGroupProxy(groupLeft);
     fullMatrix<double> &solright = solution->getGroupProxy(groupRight); 
@@ -34,8 +36,8 @@ int dgSlopeLimiter::apply ( dgDofContainer *solution)
 
     for(int iFace=0 ; iFace<group->getNbElements();iFace++)   {
 
-      iElementL = group->getElementLeftId(iFace);  
-      iElementR = group->getElementRightId(iFace); 
+      iElementL = left.getElementId(iFace);  
+      iElementR = right.getElementId(iFace); 
 
       TempL.setAsProxy(solleft, nbFields*iElementL, nbFields );
       TempR.setAsProxy(solright, nbFields*iElementR, nbFields );    	
diff --git a/Solver/dgResidual.cpp b/Solver/dgResidual.cpp
index 07d94b7d9fa7f0cb23bbee469b6c25d445c036b9..c8f34f56478c338ff6d994dfffbc9be741e099fa 100644
--- a/Solver/dgResidual.cpp
+++ b/Solver/dgResidual.cpp
@@ -146,12 +146,14 @@ void dgResidualInterface::compute1Group ( //dofManager &dof, // the DOF manager
 { 
   // A) global operations before entering the loop over the faces
   // A1 ) copy locally some references from the group for the sake of lisibility
-  int nbNodesLeft = group.getGroupLeft().getNbNodes();
-  int nbNodesRight = group.getGroupRight().getNbNodes();
+  const dgGroupOfConnections &left = group.getGroupOfConnections(0);
+  const dgGroupOfConnections &right = group.getGroupOfConnections(1);
+  const dgGroupOfElements &groupLeft = left.getGroupOfElements();
+  const dgGroupOfElements &groupRight = right.getGroupOfElements();
   int nbFaces = group.getNbElements();
   //get matrices needed to compute the gradient on both sides
-  fullMatrix<double> &DPsiLeftDx = group.getDPsiLeftDxMatrix();
-  fullMatrix<double> &DPsiRightDx = group.getDPsiRightDxMatrix();
+  const fullMatrix<double> &DPsiLeftDx = left.getDPsiDx();
+  const fullMatrix<double> &DPsiRightDx = right.getDPsiDx();
   // ----- 1 ----  get the solution at quadrature points
   fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),nbFaces * _nbFields*2);
   group.getCollocationMatrix().mult(solution, solutionQP); 
@@ -161,26 +163,26 @@ void dgResidualInterface::compute1Group ( //dofManager &dof, // the DOF manager
   _cacheMapLeft->setNbEvaluationPoints(group.getNbIntegrationPoints());
   _cacheMapRight->setNbEvaluationPoints(group.getNbIntegrationPoints());
   fullMatrix<double> dPsiLeftDx,dPsiRightDx,dofsLeft,dofsRight,normalFluxQP;
-  int p = group.getGroupLeft().getOrder();
-  int dim = group.getGroupLeft().getElement(0)->getDim();
+  int p = groupLeft.getOrder();
+  int dim = left.getElement(0)->getDim();
   for (int iFace=0 ; iFace < nbFaces ; ++iFace) {
     // B1 )  adjust the proxies for this element
     //      NB  : the B1 section will almost completely disapear 
     //      if we write a function (from the function class) for moving proxies across big matrices
     // give the current elements to the dataCacheMap 
-    _cacheElementLeft.set(group.getElementLeft(iFace));
-    _cacheElementRight.set(group.getElementRight(iFace));
+    _cacheElementLeft.set(left.getElement(iFace));
+    _cacheElementRight.set(left.getElement(iFace));
     // proxies for the solution
     _solutionQPLeft.setAsProxy(solutionQP, iFace*2*_nbFields, _nbFields);
     _solutionQPRight.setAsProxy(solutionQP, (iFace*2+1)*_nbFields, _nbFields);
-    _normals.setAsProxy(group.getNormals(), iFace*group.getNbIntegrationPoints(),group.getNbIntegrationPoints());
+    _normals.setAsProxy(left.getNormals(), iFace*group.getNbIntegrationPoints(),group.getNbIntegrationPoints());
     // proxies needed to compute the gradient of the solution and the IP term
-    dPsiLeftDx.setAsProxy(DPsiLeftDx,iFace*nbNodesLeft,nbNodesLeft);
-    dPsiRightDx.setAsProxy(DPsiRightDx,iFace*nbNodesRight,nbNodesRight);
-    dofsLeft.setAsProxy(solutionLeft, _nbFields*group.getElementLeftId(iFace), _nbFields);
-    dofsRight.setAsProxy(solutionRight, _nbFields*group.getElementRightId(iFace), _nbFields);
-    _uvwLeft.setAsProxy(group.getIntegrationOnElementLeft(iFace));
-    _uvwRight.setAsProxy(group.getIntegrationOnElementRight(iFace));
+    dPsiLeftDx.setAsProxy(DPsiLeftDx,iFace*groupLeft.getNbNodes(),groupLeft.getNbNodes());
+    dPsiRightDx.setAsProxy(DPsiRightDx,iFace*groupRight.getNbNodes(),groupRight.getNbNodes());
+    dofsLeft.setAsProxy(solutionLeft, _nbFields*left.getElementId(iFace), _nbFields);
+    dofsRight.setAsProxy(solutionRight, _nbFields*right.getElementId(iFace), _nbFields);
+    _uvwLeft.setAsProxy(left.getIntegrationPointsOnElement(iFace));
+    _uvwRight.setAsProxy(right.getIntegrationPointsOnElement(iFace));
     // proxies for the flux
     normalFluxQP.setAsProxy(NormalFluxQP, iFace*_nbFields*2, _nbFields*2);
     // B2 ) compute the gradient of the solution
@@ -200,8 +202,8 @@ void dgResidualInterface::compute1Group ( //dofManager &dof, // the DOF manager
               ((dfl(iPt,k+_nbFields*0 )+dfr(iPt,k+_nbFields*0)) * _normals(0,iPt)
               +(dfl(iPt,k+_nbFields*1 )+dfr(iPt,k+_nbFields*1)) * _normals(1,iPt)
               +(dfl(iPt,k+_nbFields*2 )+dfr(iPt,k+_nbFields*2)) * _normals(2,iPt))/2;
-          double minl = std::min(group.getElementVolumeLeft(iFace),
-                                 group.getElementVolumeRight(iFace)
+          double minl = std::min(groupLeft.getElementVolume(left.getElementId(iFace)),
+                                 groupRight.getElementVolume(right.getElementId(iFace))
                                 )/group.getInterfaceSurface(iFace);
           double nu = std::max((*_maximumDiffusivityRight)(iPt,0),(*_maximumDiffusivityLeft)(iPt,0));
           double mu = (p+1)*(p+dim)/dim*nu/minl;
@@ -229,9 +231,11 @@ void dgResidualInterface::computeAndMap1Group (dgGroupOfFaces &faces, dgDofConta
 {
   fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2*_nbFields);
   fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2*_nbFields);
-  faces.mapToInterface(_nbFields, solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupRight()), solInterface);
-  compute1Group(faces,solInterface,solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupRight()),residuInterface);
-  faces.mapFromInterface(_nbFields, residuInterface,residual.getGroupProxy(&faces.getGroupLeft()), residual.getGroupProxy(&faces.getGroupRight()));
+  const dgGroupOfElements *groupLeft = &faces.getGroupOfConnections(0).getGroupOfElements();
+  const dgGroupOfElements *groupRight = &faces.getGroupOfConnections(1).getGroupOfElements();
+  faces.mapToInterface(_nbFields, solution.getGroupProxy(groupLeft), solution.getGroupProxy(groupRight), solInterface);
+  compute1Group(faces,solInterface,solution.getGroupProxy(groupLeft), solution.getGroupProxy(groupRight),residuInterface);
+  faces.mapFromInterface(_nbFields, residuInterface,residual.getGroupProxy(groupLeft), residual.getGroupProxy(groupRight));
 }
 
 dgResidualInterface::~dgResidualInterface () 
@@ -253,10 +257,10 @@ void dgResidualBoundary::compute1Group(
 {
   //should be splitted like dgResidualInterface and dgResidualVolume
   //but i do not do it know because dgResidualBoundary will probably disapear when we will have list of elements on interfaces
-
+  const dgGroupOfConnections &left = group.getGroupOfConnections(0);
+  const dgGroupOfElements &groupLeft = left.getGroupOfElements();
   int nbFields = _claw.getNbFields();
-  int nbNodesLeft = group.getGroupLeft().getNbNodes();
-  const dgBoundaryCondition *boundaryCondition = _claw.getBoundaryCondition(group.getBoundaryTag());
+  const dgBoundaryCondition *boundaryCondition = _claw.getBoundaryCondition(group.getPhysicalTag());
   // ----- 1 ----  get the solution at quadrature points
   fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields);
   group.getCollocationMatrix().mult(solution, solutionQP); 
@@ -265,7 +269,7 @@ void dgResidualBoundary::compute1Group(
 
   dataCacheMap cacheMapLeft;
   cacheMapLeft.setNbEvaluationPoints(group.getNbIntegrationPoints());
-  fullMatrix<double> &DPsiLeftDx = group.getDPsiLeftDxMatrix();
+  const fullMatrix<double> &DPsiLeftDx = left.getDPsiDx();
   // provided dataCache
   dataCacheDouble &uvw=cacheMapLeft.provideData("UVW",1,3);
   dataCacheDouble &solutionQPLeft = cacheMapLeft.provideData("Solution",1,nbFields);
@@ -284,20 +288,20 @@ void dgResidualBoundary::compute1Group(
 
   fullMatrix<double> normalFluxQP,dPsiLeftDx,dofsLeft;
 
-  int p = group.getGroupLeft().getOrder();
-  int dim = group.getGroupLeft().getElement(0)->getDim();
+  int p = groupLeft.getOrder();
+  int dim = left.getElement(0)->getDim();
 
   for (int iFace=0 ; iFace<group.getNbElements() ;++iFace) {
     normalFluxQP.setAsProxy(NormalFluxQP, iFace*nbFields, nbFields);
     // ----- 2.3.1 --- provide the data to the cacheMap
     solutionQPLeft.setAsProxy(solutionQP, iFace*nbFields, nbFields);
-    normals.setAsProxy(group.getNormals(),iFace*group.getNbIntegrationPoints(),group.getNbIntegrationPoints());
+    normals.setAsProxy(left.getNormals(),iFace*group.getNbIntegrationPoints(),group.getNbIntegrationPoints());
     // proxies needed to compute the gradient of the solution and the IP term
-    dPsiLeftDx.setAsProxy(DPsiLeftDx,iFace*nbNodesLeft,nbNodesLeft);
-    dofsLeft.setAsProxy(solutionLeft, nbFields*group.getElementLeftId(iFace), nbFields);
+    dPsiLeftDx.setAsProxy(DPsiLeftDx,iFace*groupLeft.getNbNodes(), groupLeft.getNbNodes());
+    dofsLeft.setAsProxy(solutionLeft, nbFields*left.getElementId(iFace), nbFields);
 
-    uvw.setAsProxy(group.getIntegrationOnElementLeft(iFace));
-    cacheElementLeft.set(group.getElementLeft(iFace));
+    uvw.setAsProxy(left.getIntegrationPointsOnElement(iFace));
+    cacheElementLeft.set(left.getElement(iFace));
 
     // compute the gradient of the solution
     if(gradientSolutionLeft.somethingDependOnMe()){
@@ -317,7 +321,7 @@ void dgResidualBoundary::compute1Group(
         const double detJ = group.getDetJ (iFace, iPt);
         //just for the lisibility :
         for (int k=0;k<nbFields;k++) { 
-          double minl = group.getElementVolumeLeft(iFace)/group.getInterfaceSurface(iFace);
+          double minl = groupLeft.getElementVolume(left.getElementId(iFace))/group.getInterfaceSurface(iFace);
           double nu = (*maximumDiffusivityLeft)(iPt,0);
           if(maximumDiffusivityOut)
             nu = std::max(nu,(*maximumDiffusivityOut)(iPt,0));
@@ -337,9 +341,10 @@ void dgResidualBoundary::computeAndMap1Group(dgGroupOfFaces &faces, dgDofContain
   int _nbFields = _claw.getNbFields();
   fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*_nbFields);
   fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*_nbFields);
-  faces.mapToInterface(_nbFields, solution.getGroupProxy(&faces.getGroupLeft()), solution.getGroupProxy(&faces.getGroupLeft()), solInterface);
-  compute1Group(faces,solInterface,solution.getGroupProxy(&faces.getGroupLeft()),residuInterface);
-  faces.mapFromInterface(_nbFields, residuInterface, residual.getGroupProxy(&faces.getGroupLeft()), residual.getGroupProxy(&faces.getGroupLeft()));
+  const dgGroupOfElements &groupLeft = faces.getGroupOfConnections(0).getGroupOfElements();
+  faces.mapToInterface(_nbFields, solution.getGroupProxy(&groupLeft), solution.getGroupProxy(&groupLeft), solInterface);
+  compute1Group(faces,solInterface,solution.getGroupProxy(&groupLeft),residuInterface);
+  faces.mapFromInterface(_nbFields, residuInterface, residual.getGroupProxy(&groupLeft), residual.getGroupProxy(&groupLeft));
 }
 
 void dgResidual::compute(dgGroupCollection &groups, dgDofContainer &solution, dgDofContainer &residual)
diff --git a/Solver/dgRungeKutta.cpp b/Solver/dgRungeKutta.cpp
index ffcf59692b78a40d116f8ec05d0262a056704622..75a12708b1fa4890d5141a61ba3bb3591e2f8472 100644
--- a/Solver/dgRungeKutta.cpp
+++ b/Solver/dgRungeKutta.cpp
@@ -151,7 +151,7 @@ double dgRungeKutta::nonDiagonalRK(const dgConservationLaw *claw,
   double dt, 
   dgDofContainer *solution, 
   int nStages, 
-  fullMatrix<double>&A, //                          c | A
+  fullMatrix<double> &A, //                          c | A
   double *b, // Standard Butcher tableau notation :___|__
   double *c  //                                       |b^T  
   )
diff --git a/Solver/dgRungeKuttaMultirate.cpp b/Solver/dgRungeKuttaMultirate.cpp
index b5686bdecb34ad90310fc1c43843c986a171c357..ac99bd9d2777daf808ea6ae546d2b90ec969e508 100644
--- a/Solver/dgRungeKuttaMultirate.cpp
+++ b/Solver/dgRungeKuttaMultirate.cpp
@@ -48,8 +48,8 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio
   for(int iGroup=0;iGroup<gc->getNbFaceGroups();iGroup++){
     dgGroupOfFaces *gf=gc->getFaceGroup(iGroup);
     const dgGroupOfElements *ge[2];
-    ge[0]=&gf->getGroupLeft();
-    ge[1]=&gf->getGroupRight();
+    ge[0]=&gf->getGroupOfConnections(0).getGroupOfElements();
+    ge[1]=&gf->getGroupOfConnections(1).getGroupOfElements();
     for(int i=0;i<2;i++){
       if(ge[i]->getIsInnerMultirateBuffer()){
         _innerBufferGroupsOfElements[ge[i]->getMultirateExponent()].second.push_back(gf);
@@ -64,7 +64,7 @@ dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservatio
   for(int iGroup=0;iGroup<gc->getNbBoundaryGroups();iGroup++){
     dgGroupOfFaces *gf=gc->getBoundaryGroup(iGroup);
     const dgGroupOfElements *ge[1];
-    ge[0]=&gf->getGroupLeft();
+    ge[0]=&gf->getGroupOfConnections(0).getGroupOfElements();
     //ge[1]=&gf->getGroupRight();
     for(int i=0;i<1;i++){
       if(ge[i]->getIsInnerMultirateBuffer()){
@@ -121,13 +121,13 @@ void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){
     gOFSet.insert(vfi.begin(),vfi.end());
     for(std::set<dgGroupOfFaces *>::iterator it=gOFSet.begin();it!=gOFSet.end();it++){
       dgGroupOfFaces *faces=*it;
-      if(faces->isBoundary()){
+      if(faces->getNbGroupOfConnections()==1){
         _residualBoundary->computeAndMap1Group(*faces,*_currentInput,*_residual);
         //Msg::Info("Buffer face group %p is boundary in multirate",faces);
       }
       else{
-        const dgGroupOfElements *gL=&faces->getGroupLeft();
-        const dgGroupOfElements *gR=&faces->getGroupRight();
+        const dgGroupOfElements *gL = &faces->getGroupOfConnections(0).getGroupOfElements();
+        const dgGroupOfElements *gR = &faces->getGroupOfConnections(1).getGroupOfElements();
         fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields());
         fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields());
         faces->mapToInterface(_law->getNbFields(), _currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR), solInterface);
@@ -170,12 +170,12 @@ void dgRungeKuttaMultirate::computeK(int iK,int exponent,bool isBuffer){
     std::vector<dgGroupOfFaces *> &vf=_bulkGroupsOfElements[exponent].second;
     for(int i=0;i<vf.size();i++){
       dgGroupOfFaces *faces=vf[i];
-      if(faces->isBoundary()){
+      if(faces->getNbGroupOfConnections()==1){
         _residualBoundary->computeAndMap1Group(*faces,*_currentInput,*_residual);
       }
       else{
-        const dgGroupOfElements *gL=&faces->getGroupLeft();
-        const dgGroupOfElements *gR=&faces->getGroupRight();
+        const dgGroupOfElements *gL = &faces->getGroupOfConnections(0).getGroupOfElements();
+        const dgGroupOfElements *gR = &faces->getGroupOfConnections(1).getGroupOfElements();
         fullMatrix<double> solInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields());
         fullMatrix<double> residuInterface(faces->getNbNodes(),faces->getNbElements()*2*_law->getNbFields());
         faces->mapToInterface(_law->getNbFields(), _currentInput->getGroupProxy(gL), _currentInput->getGroupProxy(gR), solInterface);
diff --git a/Solver/function.h b/Solver/function.h
index bdfd9c64da7a4447e6402492021ad302549fa5cd..dbb42ef77ea8ea7a7ce9b0b8d6883d4701d12a82 100644
--- a/Solver/function.h
+++ b/Solver/function.h
@@ -80,14 +80,14 @@ class dataCacheDouble : public dataCache {
   }
   // take care if you use this you must ensure that the value pointed to are not modified
   // without further call to setAsProxy because the dependencies won't be invalidate
-  inline void setAsProxy(fullMatrix<double> &mat, int cShift, int c) {
+  inline void setAsProxy(const fullMatrix<double> &mat, int cShift, int c) {
     _invalidateDependencies();
     _value.setAsProxy(mat,cShift,c);
     _valid=true;
   }
   // take care if you use this you must ensure that the value pointed to are not modified
   // without further call to setAsProxy because the dependencies won't be invalidate
-  inline void setAsProxy(fullMatrix<double> &mat) {
+  inline void setAsProxy(const fullMatrix<double> &mat) {
     _invalidateDependencies();
     _value.setAsProxy(mat,0,mat.size2());
     _valid=true;