diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h
index bc829bd231b0accfa99f840253acb5a7d0e2e94d..b4561cb25cd847ba7c556af82d7c3de6627e57c2 100644
--- a/Numeric/fullMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -103,6 +103,14 @@ class fullMatrix
   }
   fullMatrix() : _own_data(false),_r(0), _c(0), _data(0) {}
   ~fullMatrix() { if(_data && _own_data) delete [] _data; }
+  void setAsProxy(fullMatrix<scalar> &original, int c_start, int c) {
+    if(_data && _own_data)
+      delete [] _data;
+    _c = c;
+    _r = original._r;
+    _own_data = false;
+    _data = original._data + c_start * _r;
+  }
   inline int size1() const { return _r; }
   inline int size2() const { return _c; }
   fullMatrix<scalar> & operator = (const fullMatrix<scalar> &other)
diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index 5aaaf3e1de364f275a56a40c964474a995dc20aa..abe4b8c5fb33045e246534bab257df4a99046d2d 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -60,9 +60,9 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
   // ----- 2.3 --- iterate on elements
   for (int iElement=0 ; iElement<group.getNbElements() ;++iElement) {
     // ----- 2.3.1 --- build a small object that contains elementary solution, jacobians, gmsh element
-    solutionQPe.set(fullMatrix<double>(solutionQP, iElement*nbFields, nbFields ));
+    solutionQPe.setAsProxy(solutionQP, iElement*nbFields, nbFields );
     if (gradSolutionQPe.somethingDependOnMe())
-      gradSolutionQPe.set(fullMatrix<double>(*gradientSolutionQP, 3*iElement*nbFields,3*nbFields ));
+      gradSolutionQPe.setAsProxy(*gradientSolutionQP, 3*iElement*nbFields,3*nbFields );
     cacheElement.set(group.getElement(iElement));
     if(convectiveFlux || diffusiveFlux) {
       // ----- 2.3.3 --- compute fluxes in UVW coordinates
@@ -120,43 +120,97 @@ void dgAlgorithm::residualInterface ( //dofManager &dof, // the DOF manager (may
 				   const dgConservationLaw &claw,   // the conservation law
 				   const dgGroupOfFaces &group, 
            const fullMatrix<double> &solution, // solution !! at faces nodes
+           fullMatrix<double> &solutionLeft, 
+           fullMatrix<double> &solutionRight, 
            fullMatrix<double> &residual // residual !! at faces nodes
            )
 { 
+  // A) global operations before entering the loop over the faces
+  // A1 ) copy locally some references from the group for the sake of lisibility
   int nbFields = claw.nbFields();
+  int nbNodesLeft = group.getGroupLeft().getNbNodes();
+  int nbNodesRight = group.getGroupRight().getNbNodes();
+  int nbFaces = group.getNbElements();
+  //get matrices needed to compute the gradient on both sides
+  fullMatrix<double> &DPsiLeftDx = group.getDPsiLeftDxMatrix();
+  fullMatrix<double> &DPsiRightDx = group.getDPsiRightDxMatrix();
+
   // ----- 1 ----  get the solution at quadrature points
-  fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields*2);
+  fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),nbFaces * nbFields*2);
   group.getCollocationMatrix().mult(solution, solutionQP); 
-  // ----- 2 ----  compute normal fluxes  at integration points
-  fullMatrix<double> NormalFluxQP ( group.getNbIntegrationPoints(), group.getNbElements()*nbFields*2);
+  // needed tocompute normal fluxes  at integration points
+  fullMatrix<double> NormalFluxQP ( group.getNbIntegrationPoints(), nbFaces*nbFields*2);
+
+  // create one dataCache for each side
   dataCacheMap cacheMapLeft, cacheMapRight;
-  // provided dataCache
-  cacheMapLeft.provideData("UVW").set(group.getIntegrationPointsMatrix());
-  dataCacheDouble &solutionQPLeft = cacheMapLeft.provideData("Solution");
-  dataCacheDouble &solutionQPRight = cacheMapRight.provideData("Solution");
+
+  // data this algorithm provide to the cache map (we can maybe move each data to a separate function but
+  // I think It's easier like this)
   dataCacheDouble &normals = cacheMapLeft.provideData("Normals");
   dataCacheElement &cacheElementLeft = cacheMapLeft.getElement();
   dataCacheElement &cacheElementRight = cacheMapRight.getElement();
-  // required data
+  cacheMapLeft.provideData("UVW").set(group.getIntegrationPointsMatrix());
+  dataCacheDouble &solutionQPLeft = cacheMapLeft.provideData("Solution");
+  dataCacheDouble &solutionQPRight = cacheMapRight.provideData("Solution");
+  dataCacheDouble &gradientSolutionLeft = cacheMapLeft.provideData("GradientSolution");
+  dataCacheDouble &gradientSolutionRight = cacheMapRight.provideData("GradientSolution");
+  //resize gradientSolutionLeft and Right
+  gradientSolutionLeft.set(fullMatrix<double>(group.getNbIntegrationPoints()*3,nbFields));
+  gradientSolutionRight.set(fullMatrix<double>(group.getNbIntegrationPoints()*3,nbFields));
+
+  // A2 ) ask the law to provide the fluxes (possibly NULL)
   dataCacheDouble *riemannSolver = claw.newRiemannSolver(cacheMapLeft,cacheMapRight);
-  for (int iFace=0 ; iFace<group.getNbElements() ;++iFace) {
-    // ----- 2.3.1 --- build a small object that contains elementary solution, jacobians, gmsh element
-    solutionQPLeft.set(fullMatrix<double>(solutionQP, iFace*2*nbFields, nbFields));
-    solutionQPRight.set(fullMatrix<double>(solutionQP, (iFace*2+1)*nbFields, nbFields));
-    normals.set(group.getNormals(iFace));
+  dataCacheDouble *diffusiveFluxLeft = claw.newDiffusiveFlux(cacheMapLeft);
+  dataCacheDouble *diffusiveFluxRight = claw.newDiffusiveFlux(cacheMapRight);
+
+  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));
+    // proxies for the solution
+    solutionQPLeft.setAsProxy(solutionQP, iFace*2*nbFields, nbFields);
+    solutionQPRight.setAsProxy(solutionQP, (iFace*2+1)*nbFields, nbFields);
+    // this should be changed to use a proxy instead of copying the normals values
+    normals.set(group.getNormals(iFace));
+    // proxies needed to compute the gradient of the solution and the IP term
+    fullMatrix<double> dPsiLeftDx (DPsiLeftDx,iFace*nbNodesLeft,nbNodesLeft);
+    fullMatrix<double> dPsiRightDx (DPsiLeftDx,iFace*nbNodesRight,nbNodesRight);
+    fullMatrix<double> dofsLeft (solutionLeft, nbFields*group.getElementLeftId(iFace), nbFields);
+    fullMatrix<double> dofsRight (solutionRight, nbFields*group.getElementRightId(iFace), nbFields);
+    // proxies for the flux
     fullMatrix<double> normalFluxQP (NormalFluxQP, iFace*nbFields*2, nbFields*2);
-    // ----- 2.3.2 --- compute fluxes
+
+    // B2 ) compute the gradient of the solution
+    if(gradientSolutionLeft.somethingDependOnMe()){
+      dPsiLeftDx.mult(dofsLeft, gradientSolutionLeft.set());
+      dPsiRightDx.mult(dofsRight, gradientSolutionRight.set());
+    }
+
+    // B3 ) compute fluxes
+
+    //JF : here you can test (diffusiveFluxLeft!=NULL) to know if the law is diffusive
+    //you can access the values by (*diffusiveFluxLeft)(iQP*3+iXYZ, iField)
+    //use gradientSolutionLef(IQP*3+IXYZ, iField) and dPsiLeftDx(iQP*3+iXYZ, iPsi)
+
     for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) {
       const double detJ = group.getDetJ (iFace, iPt);
       for (int k=0;k<nbFields*2;k++)
         normalFluxQP(iPt,k) = (*riemannSolver)(iPt,k)*detJ;
     }
   }
-  // ----- 3 ---- do the redistribution at face nodes using BLAS3
+
+  // C ) redistribute the flux to the residual (at Faces nodes)
   residual.gemm(group.getRedistributionMatrix(),NormalFluxQP);
+
+  // D ) delete the dataCacheDouble provided by the law
   delete riemannSolver;
+  if(diffusiveFluxLeft) {
+    delete diffusiveFluxLeft;
+    delete diffusiveFluxRight;
+  }
 }
 
 void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
@@ -217,6 +271,7 @@ void dgAlgorithm::residualBoundary ( //dofManager &dof, // the DOF manager (mayb
 				   const dgConservationLaw &claw,   // the conservation law
 				   const dgGroupOfFaces &group, 
            const fullMatrix<double> &solution, // solution !! at faces nodes
+           fullMatrix<double> &solutionLeft, 
            fullMatrix<double> &residual // residual !! at faces nodes
            )
 { 
@@ -304,7 +359,7 @@ 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> &solution, // solution
     fullMatrix<double> &residu) // residual
 {
   dgAlgorithm algo;
@@ -319,7 +374,7 @@ void dgAlgorithm::residual( const dgConservationLaw &claw,
     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);
+    algo.residualInterface(claw,faces,solInterface,solution,solution,residuInterface);
     faces.mapFromInterface(1, residuInterface, residu, residu);
   }
   //boundaries
@@ -328,7 +383,7 @@ void dgAlgorithm::residual( const dgConservationLaw &claw,
     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);
+    algo.residualBoundary(claw,faces,solInterface,solution,residuInterface);
     faces.mapFromInterface(1, residuInterface, residu, residu);
   }
 }
diff --git a/Solver/dgAlgorithm.h b/Solver/dgAlgorithm.h
index 4d1c81bb080f3a260745d19bc1380f400def381e..f51f050e423634c154b1258b472f86b835b0a0ef 100644
--- a/Solver/dgAlgorithm.h
+++ b/Solver/dgAlgorithm.h
@@ -11,34 +11,33 @@ class dgTerm;
 
 class dgAlgorithm {
  public :
-   void residualVolume ( //dofManager &dof, // the DOF manager (maybe useless here)
+   static void residualVolume ( //dofManager &dof, // the DOF manager (maybe useless here)
 				   const dgConservationLaw &claw,   // the conservation law
 				   const dgGroupOfElements & group, 
            const fullMatrix<double> &solution,
            fullMatrix<double> &residual);
-   void residualInterface ( //dofManager &dof, // the DOF manager (maybe useless here)
+   static void residualInterface ( //dofManager &dof, // the DOF manager (maybe useless here)
 				   const dgConservationLaw &claw,   // the conservation law
 				   const dgGroupOfFaces & group, 
            const fullMatrix<double> &solution, // ! at face nodes
+           fullMatrix<double> &solutionRight,
+           fullMatrix<double> &solutionLeft,
            fullMatrix<double> &residual); // ! at face nodes
-   void residualBoundary ( //dofManager &dof, // the DOF manager (maybe useless here)
+   static 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> &solutionLeft,
            fullMatrix<double> &residual // residual !! at faces nodes
            );
    // works only if there is only 1 group of element
-  void residual( const dgConservationLaw &claw,
+  static 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> &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 rungeKutta (
 	  const dgConservationLaw &claw,
       std::vector<dgGroupOfElements*> &eGroups, //group of elements
@@ -48,7 +47,11 @@ class dgAlgorithm {
       fullMatrix<double> &residu,
       fullMatrix<double> &sol,
 	  int orderRK=4);
-  void buildGroups(GModel *model, int dim, int order,
+  static void multAddInverseMassMatrix ( /*dofManager &dof,*/
+      const dgGroupOfElements & group,
+      fullMatrix<double> &residu,
+      fullMatrix<double> &sol);
+  static void buildGroups(GModel *model, int dim, int order,
       std::vector<dgGroupOfElements*> &eGroups,
       std::vector<dgGroupOfFaces*> &fGroups,
       std::vector<dgGroupOfFaces*> &bGroups);
diff --git a/Solver/dgConservationLawAdvection.cpp b/Solver/dgConservationLawAdvection.cpp
index a886ef5bf8aeb7c0eb2c3e1088eb1485b8de8d7d..ce654004be7002c474f720a3a34b58ca59ccdaf3 100644
--- a/Solver/dgConservationLawAdvection.cpp
+++ b/Solver/dgConservationLawAdvection.cpp
@@ -16,7 +16,7 @@ class dgConservationLawAdvection : public dgConservationLaw {
       v(cacheMap.get(vFunctionName,this))
       {};
     void _eval () { 
-      if(_value.size1() !=sol().size1())
+      if(_value.size1() != sol().size1())
         _value=fullMatrix<double>(sol().size1(),3);
       for(int i=0; i< sol().size1(); i++) {
         _value(i,0) = sol(i,0)*v(i,0);
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index 5b28f8acbea95df7043dcc448f284768369edf70..7694e1c065ef8709f0f01fb414203c7183074be5 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -119,40 +119,6 @@ dgGroupOfElements::~dgGroupOfElements(){
 }
 
 
-void dgGroupOfFaces::computeFaceNormals () {
-  double g[256][3];
-  _normals = new fullMatrix<double> (3,_fsFace->points.size1()*_faces.size());
-  int index = 0;
-  for (size_t i=0; i<_faces.size();i++){
-    const std::vector<int> &closure=*_closuresLeft[i];
-    fullMatrix<double> *intLeft=dgGetFaceIntegrationRuleOnElement(_fsFace,*_integration,_fsLeft,&closure);
-    double jac[3][3],ijac[3][3];
-    for (int j=0; j<intLeft->size1(); j++){
-      _fsLeft->df((*intLeft)(j,0),(*intLeft)(j,1),(*intLeft)(j,2),g);
-      getElementLeft(i)->getJacobian ((*intLeft)(j,0), (*intLeft)(j,1), (*intLeft)(j,2), jac);
-      inv3x3(jac,ijac);
-      double &nx=(*_normals)(0,index);
-      double &ny=(*_normals)(1,index);
-      double &nz=(*_normals)(2,index);
-      double nu=0,nv=0,nw=0;
-      for (size_t k=0; k<closure.size(); k++){
-        nu += g[closure[k]][0];
-        nv += g[closure[k]][1];
-        nw += g[closure[k]][2];
-      }
-      nx = nu*ijac[0][0]+nv*ijac[0][1]+nw*ijac[0][2];
-      ny = nu*ijac[1][0]+nv*ijac[1][1]+nw*ijac[1][2];
-      nz = nu*ijac[2][0]+nv*ijac[2][1]+nw*ijac[2][2];
-      double norm = sqrt(nx*nx+ny*ny+nz*nz);
-      nx/=norm;
-      ny/=norm;
-      nz/=norm;
-      index++;
-    }
-    delete intLeft;
-  }
-}
-
 void dgGroupOfFaces::addFace(const MFace &topoFace, int iElLeft, int iElRight){
   // compute all closures
   // compute closures for the interpolation
@@ -221,7 +187,7 @@ void dgGroupOfFaces::addEdge(const MEdge &topoEdge, int iElLeft, int iElRight){
 
 void dgGroupOfFaces::init(int pOrder) {
   _fsFace = _faces[0]->getFunctionSpace (pOrder);
-  _integration=dgGetIntegrationRule (_faces[0],pOrder);
+  _integration = dgGetIntegrationRule (_faces[0],pOrder);
   _redistribution = new fullMatrix<double> (_fsFace->coefficients.size1(),_integration->size1());
   _collocation = new fullMatrix<double> (_integration->size1(), _fsFace->coefficients.size1());
   _detJac = new fullMatrix<double> (_integration->size1(), _faces.size());
@@ -241,7 +207,71 @@ void dgGroupOfFaces::init(int pOrder) {
       (*_detJac)(j,i)=f->getJacobian ((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), jac);
     }
   }
-  computeFaceNormals();
+
+  // compute data on quadrature points : normals and dPsidX
+  double g[256][3];
+  _normals = new fullMatrix<double> (3,_fsFace->points.size1()*_faces.size());
+  _dPsiLeftDxOnQP = new fullMatrix<double> ( _integration->size1()*3,_fsLeft->points.size1()*_faces.size());
+  if(_fsRight){
+    _dPsiRightDxOnQP = new fullMatrix<double> ( _integration->size1()*3,_fsRight->points.size1()*_faces.size());
+  }
+  int index = 0;
+  for (size_t i=0; i<_faces.size();i++){
+    const std::vector<int> &closureLeft=*_closuresLeft[i];
+    fullMatrix<double> *intLeft=dgGetFaceIntegrationRuleOnElement(_fsFace,*_integration,_fsLeft,&closureLeft);
+    double jac[3][3],ijac[3][3];
+    for (int j=0; j<intLeft->size1(); j++){
+      _fsLeft->df((*intLeft)(j,0),(*intLeft)(j,1),(*intLeft)(j,2),g);
+      getElementLeft(i)->getJacobian ((*intLeft)(j,0), (*intLeft)(j,1), (*intLeft)(j,2), jac);
+      inv3x3(jac,ijac);
+      //compute dPsiLeftDxOnQP
+      //(iPsi*3+iXYZ,iQP+iFace*NQP);
+      int nPsi = _fsLeft->coefficients.size1();
+      for (int iPsi=0; iPsi< nPsi; iPsi++) {
+        (*_dPsiLeftDxOnQP)(j*3  ,i*nPsi+iPsi) = g[iPsi][0]*ijac[0][0]+g[iPsi][1]*ijac[0][1]+g[iPsi][2]*ijac[0][2];
+        (*_dPsiLeftDxOnQP)(j*3+1,i*nPsi+iPsi) = g[iPsi][0]*ijac[1][0]+g[iPsi][1]*ijac[1][1]+g[iPsi][2]*ijac[1][2];
+        (*_dPsiLeftDxOnQP)(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);
+      double &ny=(*_normals)(1,index);
+      double &nz=(*_normals)(2,index);
+      double nu=0,nv=0,nw=0;
+      for (size_t k=0; k<closureLeft.size(); k++){
+        nu += g[closureLeft[k]][0];
+        nv += g[closureLeft[k]][1];
+        nw += g[closureLeft[k]][2];
+      }
+      nx = nu*ijac[0][0]+nv*ijac[0][1]+nw*ijac[0][2];
+      ny = nu*ijac[1][0]+nv*ijac[1][1]+nw*ijac[1][2];
+      nz = nu*ijac[2][0]+nv*ijac[2][1]+nw*ijac[2][2];
+      double norm = sqrt(nx*nx+ny*ny+nz*nz);
+      nx/=norm;
+      ny/=norm;
+      nz/=norm;
+      index++;
+    }
+    delete intLeft;
+    // there is nothing on the right for boundary groups
+    if(_fsRight){
+      fullMatrix<double> *intRight=dgGetFaceIntegrationRuleOnElement(_fsFace,*_integration,_fsRight,_closuresRight[i]);
+      for (int j=0; j<intRight->size1(); j++){
+        _fsRight->df((*intRight)(j,0),(*intRight)(j,1),(*intRight)(j,2),g);
+        getElementRight(i)->getJacobian ((*intRight)(j,0), (*intRight)(j,1), (*intRight)(j,2), jac);
+        inv3x3(jac,ijac);
+        //compute dPsiRightDxOnQP
+        // (iQP*3+iXYZ , iFace*NPsi+iPsi)
+        int nPsi = _fsRight->coefficients.size1();
+        for (int iPsi=0; iPsi< nPsi; iPsi++) {
+          (*_dPsiRightDxOnQP)(j*3  ,i*nPsi+iPsi) = g[iPsi][0]*ijac[0][0]+g[iPsi][1]*ijac[0][1]+g[iPsi][2]*ijac[0][2];
+          (*_dPsiRightDxOnQP)(j*3+1,i*nPsi+iPsi) = g[iPsi][0]*ijac[1][0]+g[iPsi][1]*ijac[1][1]+g[iPsi][2]*ijac[1][2];
+          (*_dPsiRightDxOnQP)(j*3+2,i*nPsi+iPsi) = g[iPsi][0]*ijac[2][0]+g[iPsi][1]*ijac[2][1]+g[iPsi][2]*ijac[2][2];
+        }
+      }
+      delete intRight;
+    }
+  }
+
 }
 
 dgGroupOfFaces::~dgGroupOfFaces()
@@ -249,6 +279,9 @@ dgGroupOfFaces::~dgGroupOfFaces()
   delete _redistribution;
   delete _collocation;
   delete _detJac;
+  delete _normals;
+  delete _dPsiLeftDxOnQP;
+  delete _dPsiRightDxOnQP;
 }
 dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, std::string boundaryTag, int pOrder,std::set<MEdge,Less_Edge> &boundaryEdges):
   _groupLeft(elGroup),_groupRight(elGroup)
diff --git a/Solver/dgGroupOfElements.h b/Solver/dgGroupOfElements.h
index da35c02100acbff7c886136eeb5ada8f5d07b68e..45d51672836e7f6b01228d8bd7a143eee79334c9 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -83,35 +83,12 @@ public:
   inline const fullMatrix<double> getMapping (int iElement) const {return fullMatrix<double>(*_mapping, iElement, 1);}
 };
 
-class dgFace {
-  int nbGaussPoints;
-  MElement *_left, *_right;
-  MElement *_face;
-  const fullMatrix<double> *_solutionRight, *_solutionLeft, *_integration,*_normals;
-public:
-  dgFace (MElement *face,MElement *left, MElement *right,
-    const fullMatrix<double> &solLeft,
-    const fullMatrix<double> &solRight,
-    const fullMatrix<double> &integration,
-    const fullMatrix<double> &normals
-    ) : _left(left), _right(right), _face(face),_solutionRight(&solRight),_solutionLeft(&solLeft),_integration(&integration),_normals(&normals)
-  {}
-  inline const fullMatrix<double> &solutionRight() const { return *_solutionRight; }
-  inline const fullMatrix<double> &solutionLeft() const { return *_solutionLeft; }
-  inline const fullMatrix<double> &integration() const { return *_integration; }
-  inline const fullMatrix<double> &normals() const { return *_normals; }
-  inline MElement *left() const { return _left;}
-  inline MElement *right() const { return _right;}
-  inline MElement *face() const { return _face;}
-};
-
 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);
-  void computeFaceNormals();
   // Two polynomialBases for left and right elements
   // the group has always the same types for left and right
   const polynomialBasis *_fsLeft,*_fsRight, *_fsFace;
@@ -127,6 +104,10 @@ class dgGroupOfFaces {
   // GEOMETRICAL CLOSURE !!!
   std::vector<const std::vector<int> * > _closuresLeft; 
   std::vector<const std::vector<int> * > _closuresRight; 
+  // XYZ gradient of the shape functions of both elements on the integrations points of the face
+  // (iQP*3+iXYZ , iFace*NPsi+iPsi)
+  fullMatrix<double> *_dPsiLeftDxOnQP;
+  fullMatrix<double> *_dPsiRightDxOnQP;
   // normals at integration points  (N*Ni) x 3
   fullMatrix<double> *_normals;
   // detJac at integration points (N*Ni) x 1
@@ -139,6 +120,10 @@ class dgGroupOfFaces {
   //common part of the 3 constructors
   void init(int pOrder);
 public:
+  inline const dgGroupOfElements &getGroupLeft()const {return _groupLeft; }
+  inline const dgGroupOfElements &getGroupRight()const {return _groupRight; }
+  inline int getElementLeftId (int i) const {return _left[i];};
+  inline int getElementRightId (int i) const {return _right[i];};
   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];}  
@@ -151,6 +136,8 @@ public:
   virtual ~dgGroupOfFaces ();
   inline bool isBoundary() const {return !_boundaryTag.empty();}
   inline const std::string getBoundaryTag() const {return _boundaryTag;}
+  inline fullMatrix<double> & getDPsiLeftDxMatrix() const { return *_dPsiLeftDxOnQP;}
+  inline fullMatrix<double> & getDPsiRightDxMatrix() const { return *_dPsiRightDxOnQP;}
   //this part is common with dgGroupOfElements, we should try polymorphism
   inline int getNbElements() const {return _faces.size();}
   inline int getNbNodes() const {return _collocation->size1();}
diff --git a/Solver/function.h b/Solver/function.h
index 4f64dfe1fcc1f5ca5f124c505aa8ba03d2685d94..28c725378a24a42e8ed9a2fbe67b1bddb761b256 100644
--- a/Solver/function.h
+++ b/Solver/function.h
@@ -48,6 +48,21 @@ class dataCacheDouble : public dataCache {
     _value=mat;
     _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, int cShift, int c) {
+    _invalidateDependencies();
+    _value.setAsProxy(mat,cShift,c);
+    _valid=true;
+  }
+  // this function is needed to be able to pass the _value to functions like gemm or mult
+  // but you cannot keep the reference to the _value, you should always use the set function 
+  // to modify the _value
+  inline fullMatrix<double> &set() {
+    _invalidateDependencies();
+    _valid=true;
+    return _value;
+  }
   inline const double &operator () (int i, int j)
   {
     if(!_valid) {