diff --git a/Solver/_ b/Solver/_
new file mode 100644
index 0000000000000000000000000000000000000000..0f2c8223facb9a348b52c3edb0df2d2cb909cfed
--- /dev/null
+++ b/Solver/_
@@ -0,0 +1,330 @@
+#include "dgGroupOfElements.h"
+#include "MElement.h"
+#include "functionSpace.h"
+#include "Numeric.h"
+#include "MTriangle.h"
+#include "MLine.h"
+
+static fullMatrix<double> * dgGetIntegrationRule (MElement *e, int p){
+  int npts;
+  IntPt *pts;
+  e->getIntegrationPoints(2*p+1, &npts, &pts);
+  fullMatrix<double> *m = new fullMatrix<double> (npts, 4);
+  for (int i=0;i<npts;i++){
+    (*m)(i,0) = pts[i].pt[0];
+    (*m)(i,1) = pts[i].pt[1];
+    (*m)(i,2) = pts[i].pt[2];
+    (*m)(i,3) = pts[i].weight;
+  }
+  return m;
+}
+
+static fullMatrix<double> * dgGetFaceIntegrationRuleOnElement (
+      const functionSpace *fsFace,
+      const fullMatrix<double> &intgFace,
+      const functionSpace *fsElement,
+      const std::vector <int> *closure) {
+  int npts=intgFace.size1();
+  fullMatrix<double> *m = new fullMatrix<double> (npts, 4);
+  double f[256];
+  for (int i=0;i<npts;i++){
+    fsFace->f(intgFace(i,0),intgFace(i,1),intgFace(i,2),f);
+    for(size_t j=0; j<closure->size();j++){
+      int jNod=(*closure)[j];
+      (*m)(i,0) += f[j] * fsElement->points(jNod,0);
+      (*m)(i,1) += f[j] * fsElement->points(jNod,1);
+      (*m)(i,2) += f[j] * fsElement->points(jNod,2);
+      (*m)(i,3) = intgFace(i,3);
+    }
+  }
+  return m;
+}
+
+
+dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOrder)
+  : _elements(e), 
+    _fs(*_elements[0]->getFunctionSpace(polyOrder)),
+    _integration(dgGetIntegrationRule (_elements[0], polyOrder)
+    )
+{
+  _dimUVW = _dimXYZ = e[0]->getDim();
+  // this is the biggest piece of data ... the mappings
+  int nbNodes = _fs.coefficients.size1();
+  _redistributionFluxes[0] = new fullMatrix<double> (nbNodes,_integration->size1());
+  _redistributionFluxes[1] = new fullMatrix<double> (nbNodes,_integration->size1());
+  _redistributionFluxes[2] = new fullMatrix<double> (nbNodes,_integration->size1());
+  _redistributionSource = new fullMatrix<double> (nbNodes,_integration->size1());
+  _collocation = new fullMatrix<double> (_integration->size1(),nbNodes);
+  _mapping = new fullMatrix<double> (e.size(), 10 * _integration->size1());
+  _imass = new fullMatrix<double> (nbNodes,nbNodes*e.size()); 
+  double g[256][3],f[256];
+  for (int i=0;i<_elements.size();i++){
+    MElement *e = _elements[i];
+    fullMatrix<double> imass(*_imass,nbNodes*i,nbNodes);
+    for (int j=0;j< _integration->size1() ; j++ ){
+      _fs.f((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), f);
+      double jac[3][3],ijac[3][3],detjac;
+      (*_mapping)(i,10*j + 9) =  
+        e->getJacobian ((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), jac);
+      const double weight = (*_integration)(j,3);
+      detjac=inv3x3(jac,ijac);
+      (*_mapping)(i,10*j + 0) = ijac[0][0]; 
+      (*_mapping)(i,10*j + 1) = ijac[0][1]; 
+      (*_mapping)(i,10*j + 2) = ijac[0][2]; 
+      (*_mapping)(i,10*j + 3) = ijac[1][0]; 
+      (*_mapping)(i,10*j + 4) = ijac[1][1]; 
+      (*_mapping)(i,10*j + 5) = ijac[1][2]; 
+      (*_mapping)(i,10*j + 6) = ijac[2][0]; 
+      (*_mapping)(i,10*j + 7) = ijac[2][1]; 
+      (*_mapping)(i,10*j + 8) = ijac[2][2]; 
+      (*_mapping)(i,10*j + 9) = detjac; 
+      for (int k=0;k<_fs.coefficients.size1();k++){ 
+        for (int l=0;l<_fs.coefficients.size1();l++) { 
+          imass(k,l) += f[k]*f[l]*weight*detjac;
+        }
+      }
+    }
+    imass.invertInPlace();
+  }
+  // redistribution matrix
+  // quadrature weight x parametric gradients in quadrature points
+
+  for (int j=0;j<_integration->size1();j++) {
+    _fs.df((*_integration)(j,0),
+	   (*_integration)(j,1),
+	   (*_integration)(j,2), g);
+    _fs.f((*_integration)(j,0),
+	   (*_integration)(j,1),
+	   (*_integration)(j,2), f);
+    const double weight = (*_integration)(j,3);
+    for (int k=0;k<_fs.coefficients.size1();k++){ 
+      (*_redistributionFluxes[0])(k,j) = g[k][0] * weight;
+      (*_redistributionFluxes[1])(k,j) = g[k][1] * weight;
+      (*_redistributionFluxes[2])(k,j) = g[k][2] * weight;
+      (*_redistributionSource)(k,j) = f[k] * weight;
+      (*_collocation)(j,k) = f[k];
+    }
+  }
+}
+
+dgGroupOfElements::~dgGroupOfElements(){
+  delete _integration;
+  delete _redistributionFluxes[0];
+  delete _redistributionFluxes[1];
+  delete _redistributionFluxes[2];
+  delete _redistributionSource;
+  delete _mapping;
+  delete _collocation;
+  delete _imass;
+}
+
+
+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);
+    for (int j=0; j<intLeft->size1(); j++){
+      _fsLeft->df((*intLeft)(j,0),(*intLeft)(j,1),(*intLeft)(j,2),g);
+      double &nx=(*_normals)(0,index);
+      double &ny=(*_normals)(1,index);
+      double &nz=(*_normals)(2,index);
+      for (size_t k=0; k<closure.size(); k++){
+        nx += g[closure[k]][0];
+        ny += g[closure[k]][1];
+        nz += g[closure[k]][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
+  _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;
+}
+static std::vector<int> *fakeClosure2d(const functionSpace *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);
+  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);
+  _redistribution = new fullMatrix<double> (_fsFace->coefficients.size1(),_integration->size1());
+  _collocation = new fullMatrix<double> (_fsFace->coefficients.size1(), _integration->size1());
+  _detJac = new fullMatrix<double> (_integration->size1(), _faces.size());
+  double f[256];
+  for (int j=0;j<_integration->size1();j++) {
+    _fsFace->f((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), f);
+    const double weight = (*_integration)(j,3);
+    for (int k=0;k<_fsFace->coefficients.size1();k++){ 
+      (*_redistribution)(k,j) = f[j] * weight;
+      (*_collocation)(k,j) = f[k];
+    }
+  }
+  for (int i=0;i<_faces.size();i++){
+    MElement *f = _faces[i];
+    for (int j=0;j< _integration->size1() ; j++ ){
+      double jac[3][3],ijac[3][3],detjac;
+      f->getJacobian ((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), jac);
+      const double weight = (*_integration)(j,3);
+      (*_detJac)(j,i) = inv3x3(jac,ijac);
+    }
+  }
+  computeFaceNormals();
+}
+
+dgGroupOfFaces::~dgGroupOfFaces()
+{
+  
+}
+
+dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, int pOrder):
+  _groupLeft(elGroup),_groupRight(elGroup)
+{
+  _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);
+}
+
+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++){
+    printf("closure size=%i\n",closureLeft.size());
+      for(size_t j =0; j < closureLeft.size(); j++){
+        v(j, i*2*nFields + iField) = vLeft(closureLeft[j], _left[i]*nFields + iField);
+        printf("vv=%e\n",v(j, i*2*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);
+    }
+  }
+  v.print();
+}
+
+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/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index 085b5d20dcf58427181afd46d52bbb98ac140624..8025824daed907c7fb0ebbe45d2daa5fd3ac1854 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -37,9 +37,9 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
 				 fullMatrix<double>( group.getNbIntegrationPoints(), nbFields )};
   fullMatrix<double> Source = fullMatrix<double> (group.getNbIntegrationPoints(),group.getNbElements() * nbFields);
   // ----- 2.2 --- allocate parametric fluxes (computed in UVW coordinates) for all elements at all integration points
-  fullMatrix<double> Fuvw[3] = {fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints()),
-				fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints()),
-				fullMatrix<double> (group.getNbElements() * nbFields, group.getNbIntegrationPoints())};
+  fullMatrix<double> Fuvw[3] = {fullMatrix<double> ( group.getNbIntegrationPoints(), group.getNbElements() * nbFields),
+				fullMatrix<double> (group.getNbIntegrationPoints(), group.getNbElements() * nbFields),
+				fullMatrix<double> (group.getNbIntegrationPoints(), group.getNbElements() * nbFields)};
   // ----- 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
@@ -48,11 +48,10 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
     if (claw.diffusiveFlux()) gradSolutionQPe = new fullMatrix<double>(*gradientSolutionQP, 3*iElement*nbFields,3*nbFields );      
     else gradSolutionQPe = new fullMatrix<double>;
     dgElement DGE( group.getElement(iElement), solutionQPe, *gradSolutionQPe, group.getIntegrationPointsMatrix());
-    if(claw.convectiveFlux() || claw.diffusiveFlux()){
+    if(claw.convectiveFlux() || claw.diffusiveFlux()) {
       // ----- 2.3.2 --- compute fluxes in XYZ coordinates
       if (claw.convectiveFlux()) (*claw.convectiveFlux())(DGE,fConv);
       if (claw.diffusiveFlux()) (*claw.diffusiveFlux())(DGE,fDiff);
-
       // ----- 2.3.3 --- compute fluxes in UVW coordinates
       for (int iUVW=0;iUVW<group.getDimUVW();iUVW++) {
         // ----- 2.3.3.1 --- get a proxy on the big local flux matrix
@@ -61,14 +60,13 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
         for (int iXYZ=0;iXYZ<group.getDimXYZ();iXYZ++) {
           for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) {
             // get the right inv jacobian matrix dU/dX element
-            const double invJ = group.getInvJ (iElement, iPt, iXYZ, iUVW);
+            const double invJ = group.getInvJ (iElement, iPt, iUVW, iXYZ);
             // get the detJ at this point
             const double detJ = group.getDetJ (iElement, iPt);
             const double factor = invJ * detJ;
             // compute fluxes in the reference coordinate system at this integration point
-            for (int k=0;k<nbFields;k++) {
+            for (int k=0;k<nbFields;k++)
               fuvwe(iPt,k) += ( fConv[iXYZ](iPt,k) + fDiff[iXYZ](iPt,k)) * factor;
-            }
           }
         } 
       }
@@ -86,8 +84,9 @@ void dgAlgorithm::residualVolume ( //dofManager &dof, // the DOF manager (maybe
   }
   // ----- 3 ---- do the redistribution at nodes using as many BLAS3 operations as there are local coordinates
   if(claw.convectiveFlux() || claw.diffusiveFlux()){
-    for (int iUVW=0;iUVW<group.getDimUVW();iUVW++)
+    for (int iUVW=0;iUVW<group.getDimUVW();iUVW++){
       residual.gemm(group.getFluxRedistributionMatrix(iUVW),Fuvw[iUVW]);
+    }
   }
   if(claw.sourceTerm()){
     residual.gemm(group.getSourceRedistributionMatrix(),Source);
@@ -103,7 +102,7 @@ void dgAlgorithm::residualInterface ( //dofManager &dof, // the DOF manager (may
 { 
   int nbFields = claw.nbFields();
   // ----- 1 ----  get the solution at quadrature points
-  fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields);
+  fullMatrix<double> solutionQP (group.getNbIntegrationPoints(),group.getNbElements() * nbFields*2);
   group.getCollocationMatrix().mult(solution, solutionQP); 
   // ----- 2 ----  compute normal fluxes  at integration points
   fullMatrix<double> NormalFluxQP ( group.getNbIntegrationPoints(), group.getNbElements()*nbFields*2);
@@ -113,17 +112,27 @@ void dgAlgorithm::residualInterface ( //dofManager &dof, // the DOF manager (may
     fullMatrix<double> solutionQPRight (solutionQP, (iFace*2+1)*nbFields, nbFields );
     fullMatrix<double> normalFluxQP (NormalFluxQP, iFace*2*nbFields, nbFields*2);
     dgFace DGF( group.getFace(iFace), group.getElementLeft(iFace), group.getElementRight(iFace),
-                solutionQPLeft, solutionQPRight, group.getIntegrationPointsMatrix());
+                solutionQPLeft, solutionQPRight, group.getIntegrationPointsMatrix(),group.getNormals(iFace));
     // ----- 2.3.2 --- compute fluxes
     (*claw.riemannSolver())(DGF,&normalFluxQP);
     for (int iPt =0; iPt< group.getNbIntegrationPoints(); iPt++) {
       const double detJ = group.getDetJ (iFace, iPt);
-      for (int k=0;k<nbFields*2;k++) {
+      for (int k=0;k<nbFields*2;k++)
         normalFluxQP(iPt,k) *= detJ;
-      }
     }
   }
   // ----- 3 ---- do the redistribution at face nodes using BLAS3
   residual.gemm(group.getRedistributionMatrix(),NormalFluxQP);
 }
 
+void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
+          const dgGroupOfElements & group,
+          fullMatrix<double> &residu,
+          fullMatrix<double> &sol)
+{
+  for(int i=0;i<group.getNbElements();i++) {
+    fullMatrix<double> residuEl(residu,i,1);
+    fullMatrix<double> solEl(sol,i,1);
+    solEl.gemm(group.getInverseMassMatrix(i),residuEl);
+  }
+}
diff --git a/Solver/dgAlgorithm.h b/Solver/dgAlgorithm.h
index 555b745c4246fd817aca13bbfd30d1e087dc1f1b..2af608c6df2d32098b24556d7dde4194e05a508c 100644
--- a/Solver/dgAlgorithm.h
+++ b/Solver/dgAlgorithm.h
@@ -6,6 +6,7 @@
 class dgGroupOfElements;
 class dgGroupOfFaces;
 class dgConservationLaw;
+class dgTerm;
 
 class dgAlgorithm {
  public :
@@ -22,6 +23,10 @@ class dgAlgorithm {
   void residualBoundaryConditions ( /*dofManager &dof,*/
 				    const dgConservationLaw &law,
 				    const dgGroupOfElements & group);
+  void multAddInverseMassMatrix ( /*dofManager &dof,*/
+      const dgGroupOfElements & group,
+      fullMatrix<double> &residu,
+      fullMatrix<double> &sol);
 };
 
 
diff --git a/Solver/dgConservationLawAdvection.cpp b/Solver/dgConservationLawAdvection.cpp
index 3c1d9eb7d4cd8151d12402f2f220b7ebc1fb1ec8..269d43538a685a3740f2dc32c5b62909546815ab 100644
--- a/Solver/dgConservationLawAdvection.cpp
+++ b/Solver/dgConservationLawAdvection.cpp
@@ -3,24 +3,68 @@
 #include "dgGroupOfElements.h"
 #include "SPoint3.h"
 #include "MElement.h"
-class testSourceTerm : public dgTerm {
-  void operator () (const dgElement &el, fullMatrix<double> fcx[]) const{
+void getV(SPoint3 &p, double (&v)[3]){
+  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;
+}
+
+class dgAdvectionFluxTerm : public dgTerm {
+  void operator () (const dgElement &el, fullMatrix<double> fcx[]) const
+  {
     const fullMatrix<double> &sol = el.solution();
-    const fullMatrix<double> &qp = el.integration();
-    SPoint3 p;
+    const fullMatrix<double> &QP = el.integration();
     for(int i=0; i< sol.size1(); i++) {
-      el.element()->pnt(qp(i,0),qp(i,1),qp(i,2),p);
-      //printf("%e -  %e (%i)\n",p.x(),sol(i,0),sol.size2());
-      fcx[0](i,0) = (p.x()*p.x()+p.y()*p.y()) - sol(i,0);
+      SPoint3 p;
+      el.element()->pnt(QP(i,0),QP(i,1),QP(i,2),p);
+      double v[3];
+      getV(p,v);
+      fcx[0](i,0) = sol(i,0)*v[0];
+      fcx[1](i,0) = sol(i,0)*v[1];
+      fcx[2](i,0) = sol(i,0)*v[2];
+    }
+  }
+};
+
+class dgAdvectionRiemanTerm : public dgFaceTerm{
+ public:
+  void operator () (const dgFace &face, fullMatrix<double> fcx[]) const
+  {
+    const fullMatrix<double> &solLeft = face.solutionLeft();
+    const fullMatrix<double> &solRight = face.solutionRight();
+    const fullMatrix<double> &normals = face.normals();
+    const fullMatrix<double> &QP = face.integration();
+    for(int i=0; i< solLeft.size1(); i++) {
+      SPoint3 p;
+      face.face()->pnt(QP(i,0),QP(i,1),QP(i,2),p);
+      double v[3];
+      getV(p,v);
+      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;
+      }else{
+        fcx[0](i,0) = -solRight(i,0)*un;
+        fcx[0](i,1) = solRight(i,0)*un;
+      }
     }
   }
 };
 
 class dgConservationLawAdvection : public dgConservationLaw {
   public:
-  dgConservationLawAdvection() {
+  dgConservationLawAdvection() 
+  {
     _nbf = 1;
-    _source = new testSourceTerm;
+    _convective = new dgAdvectionFluxTerm;
+    _riemannSolver = new dgAdvectionRiemanTerm;
+  }
+  ~dgConservationLawAdvection()
+  {
+    delete _convective;
+    delete _riemannSolver;
   }
 };
 
diff --git a/Solver/dgGroupOfElements.cpp b/Solver/dgGroupOfElements.cpp
index de8bfe3ddb0ed0699672a47a8bea0153fa8e0424..6d10a34e4ebbc1a8a716ca4af83cb84355afaea4 100644
--- a/Solver/dgGroupOfElements.cpp
+++ b/Solver/dgGroupOfElements.cpp
@@ -31,9 +31,8 @@ static fullMatrix<double> * dgGetFaceIntegrationRuleOnElement (
     fsFace->f(intgFace(i,0),intgFace(i,1),intgFace(i,2),f);
     for(size_t j=0; j<closure->size();j++){
       int jNod=(*closure)[j];
-      (*m)(i,0) += f[j] * fsElement->points(jNod,0);
-      (*m)(i,1) += f[j] * fsElement->points(jNod,1);
-      (*m)(i,2) += f[j] * fsElement->points(jNod,2);
+      for(int k=0;k<fsElement->points.size2();k++)
+        (*m)(i,k) += f[j] * fsElement->points(jNod,k);
       (*m)(i,3) = intgFace(i,3);
     }
   }
@@ -47,6 +46,7 @@ dgGroupOfElements::dgGroupOfElements(const std::vector<MElement*> &e, int polyOr
     _integration(dgGetIntegrationRule (_elements[0], polyOrder)
     )
 {
+  _dimUVW = _dimXYZ = e[0]->getDim();
   // this is the biggest piece of data ... the mappings
   int nbNodes = _fs.coefficients.size1();
   _redistributionFluxes[0] = new fullMatrix<double> (nbNodes,_integration->size1());
@@ -120,21 +120,28 @@ dgGroupOfElements::~dgGroupOfElements(){
 
 void dgGroupOfFaces::computeFaceNormals () {
   double g[256][3];
-  _normals = new fullMatrix<double> (_fsFace->points.size1()*_faces.size(),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);
-      double &nx=(*_normals)(index,0);
-      double &ny=(*_normals)(index,1);
-      double &nz=(*_normals)(index,2);
+      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++){
-        nx += g[closure[k]][0];
-        ny += g[closure[k]][1];
-        nz += g[closure[k]][2];
+        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;
@@ -179,6 +186,19 @@ 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);
@@ -187,13 +207,17 @@ void dgGroupOfFaces::addEdge(const MEdge &topoEdge, int iElLeft, int iElRight){
   MElement &elLeft = *_groupLeft.getElement(iElLeft);
   int ithEdge, sign;
   elLeft.getEdgeInfo (topoEdge, ithEdge, sign);
-  _closuresLeft.push_back(&(_fsLeft->getEdgeClosure(ithEdge, sign)));
+  _closuresLeft.push_back(fakeClosure2d(_fsLeft, ithEdge, sign));
   elRight.getEdgeInfo (topoEdge, ithEdge, sign);
-  _closuresRight.push_back(&(_fsRight->getEdgeClosure(ithEdge, sign)));    
+  _closuresRight.push_back(fakeClosure2d(_fsRight, 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));
+  if(sign==1)
+    for(int j=0;j<topoEdge.getNumVertices();j++)
+      vertices.push_back(topoEdge.getVertex(j));
+  else
+    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]) );
   switch(vertices.size()){
@@ -207,21 +231,32 @@ void dgGroupOfFaces::init(int pOrder) {
   _fsFace = _faces[0]->getFunctionSpace (pOrder);
   _integration=dgGetIntegrationRule (_faces[0],pOrder);
   _redistribution = new fullMatrix<double> (_fsFace->coefficients.size1(),_integration->size1());
-  _collocation = 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());
   double f[256];
   for (int j=0;j<_integration->size1();j++) {
     _fsFace->f((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), f);
     const double weight = (*_integration)(j,3);
     for (int k=0;k<_fsFace->coefficients.size1();k++){ 
-      (*_redistribution)(k,j) = f[j] * weight;
-      (*_collocation)(k,j) = f[k];
+      (*_redistribution)(k,j) = f[k] * weight;
+      (*_collocation)(j,k) = f[k];
     }
   }
+  for (int i=0;i<_faces.size();i++){
+    MElement *f = _faces[i];
+    for (int j=0;j< _integration->size1() ; j++ ){
+      double jac[3][3];
+      (*_detJac)(j,i)=f->getJacobian ((*_integration)(j,0), (*_integration)(j,1), (*_integration)(j,2), jac);
+    }
+  }
+  computeFaceNormals();
 }
 
 dgGroupOfFaces::~dgGroupOfFaces()
 {
-  
+  delete _redistribution;
+  delete _collocation;
+  delete _detJac;
 }
 
 dgGroupOfFaces::dgGroupOfFaces (const dgGroupOfElements &elGroup, int pOrder):
@@ -274,8 +309,9 @@ void dgGroupOfFaces::mapToInterface ( int nFields,
     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++)
+      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);
     }
@@ -293,9 +329,9 @@ void dgGroupOfFaces::mapFromInterface ( int nFields,
     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);
+        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);
+        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 f00b80a7b4802b3d9c0f365e8d14456b526cf6d2..a2f5035d5a72d4eb7074ad7fac40f8d547a9e708 100644
--- a/Solver/dgGroupOfElements.h
+++ b/Solver/dgGroupOfElements.h
@@ -86,18 +86,19 @@ class dgFace {
   int nbGaussPoints;
   MElement *_left, *_right;
   MElement *_face;
-  double *_normals;
-  const fullMatrix<double> *_solutionRight, *_solutionLeft, *_integration;
+  const fullMatrix<double> *_solutionRight, *_solutionLeft, *_integration,*_normals;
 public:
   dgFace (MElement *face,MElement *left, MElement *right,
-    const fullMatrix<double> &solRight,
     const fullMatrix<double> &solLeft,
-    const fullMatrix<double> &integration
-    ) : _left(left), _right(right), _face(face),_solutionRight(&solRight),_solutionLeft(&solLeft),_integration(&integration)
+    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;}
@@ -140,6 +141,7 @@ public:
   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];}
+  inline fullMatrix<double> getNormals (int iFace) const {return fullMatrix<double>(*_normals,iFace*getNbIntegrationPoints(),getNbIntegrationPoints());}
   dgGroupOfFaces (const dgGroupOfElements &elements,int pOrder);
   virtual ~dgGroupOfFaces ();
   //this part is common with dgGroupOfElements, we should try polymorphism
@@ -149,7 +151,7 @@ public:
   inline const fullMatrix<double> & getCollocationMatrix () const {return *_collocation;}
   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);}
+  inline double getDetJ (int iElement, int iGaussPoint) const {return (*_detJac)(iGaussPoint,iElement);}
   //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 a0ca1d73709dea69ec2b6f8142d5a15d90c56712..451bfde1b889cf96f8364e8e9a297c4eae78a8f6 100644
--- a/Solver/dgMainTest.cc
+++ b/Solver/dgMainTest.cc
@@ -11,29 +11,70 @@
 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{
+    const fullMatrix<double> &sol = el.solution();
+    const fullMatrix<double> &qp = el.integration();
+    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);
+    }
+  }
+};
+
+class dgConservationLawInitialCondition : public dgConservationLaw {
+  public:
+  dgConservationLawInitialCondition() {
+    _nbf = 1;
+    _source = new testSourceTerm;
+  }
+  ~dgConservationLawInitialCondition() {
+    delete _source;
+  }
+};
+
 int main(int argc, char **argv){
   GmshMergeFile("input/mesh1.msh");
+  //GmshMergeFile("square2.msh");
   std::vector<MElement *> allTri=getAllTri(GModel::current());
   int order=1;
   dgGroupOfElements elements(allTri,order);
   dgGroupOfFaces faces(elements,order);
-  int nbNodes=elements.getNbNodes();
+  //dgGroupOfFaces faces(elements0,elements1,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;
+  // initial condition
+  {
+    dgConservationLawInitialCondition initLaw;
+    algo.residualVolume(initLaw,elements,sol,residu);
+    algo.multAddInverseMassMatrix(elements,residu,sol);
+  }
+  print("init.pos",elements,&sol(0,0));
+  //advection
   dgConservationLaw *law = dgNewConservationLawAdvection();
-  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.getInverseMassMatrix(i),residuEl);
+  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);
+    }
+    residu.scale(0.01);
+    algo.multAddInverseMassMatrix(elements,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("test.pos",elements,&sol(0,0));
+  delete law;
 }
 
 std::vector<MElement *> getAllTri(GModel *model){