diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd581fe4a275c56fd5a18321e6bebd8977bda340..89bfd3a0ce46bfcef0bc49303f1458e4c48fe9b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -993,3 +993,9 @@ mark_as_advanced(BISON FLEX GMP_LIB GMSH_EXTRA_VERSION HDF5_LIB MAKEINFO
 
 add_executable(gmshdg EXCLUDE_FROM_ALL Solver/dgMainTest.cpp ${GMSH_SRC})
 target_link_libraries(gmshdg ${LINK_LIBRARIES})
+
+add_executable(gmshdgsw EXCLUDE_FROM_ALL Solver/dgMainShallowWater2d.cpp ${GMSH_SRC})
+target_link_libraries(gmshdgsw ${LINK_LIBRARIES})
+
+add_executable(gmshdgwave EXCLUDE_FROM_ALL Solver/dgMainWaveEquation.cpp ${GMSH_SRC})
+target_link_libraries(gmshdgwave ${LINK_LIBRARIES})
diff --git a/Solver/CMakeLists.txt b/Solver/CMakeLists.txt
index 6d74439f89799caab25ef00ef62645192e83d27e..fec707a71f6b5ea62edab9ca52daef95dbc03ef9 100644
--- a/Solver/CMakeLists.txt
+++ b/Solver/CMakeLists.txt
@@ -15,6 +15,8 @@ set(SRC
   dgAlgorithm.cpp
   dgConservationLaw.cpp
   dgConservationLawAdvection.cpp
+  dgConservationLawShallowWater2d.cpp
+  dgConservationLawWaveEquation.cpp
   function.cpp
 )
 
diff --git a/Solver/dgAlgorithm.cpp b/Solver/dgAlgorithm.cpp
index 6b0d57058e7d9cc4c2b822ac27bdb61f0c337179..d9cf8edb5b69bb973c7e65da5a8c18d08698f715 100644
--- a/Solver/dgAlgorithm.cpp
+++ b/Solver/dgAlgorithm.cpp
@@ -223,9 +223,10 @@ void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
   fullMatrix<double> residuEl;
   fullMatrix<double> solEl;
   fullMatrix<double> iMassEl;
+  int nFields=sol.size2()/group.getNbElements();
   for(int i=0;i<group.getNbElements();i++) {
-    residuEl.setAsProxy(residu,i,1);
-    solEl.setAsProxy(sol,i,1);
+    residuEl.setAsProxy(residu,i*nFields,nFields);
+    solEl.setAsProxy(sol,i*nFields,nFields);
     iMassEl.setAsProxy(group.getInverseMassMatrix(),i*group.getNbNodes(),group.getNbNodes());
     solEl.gemm(iMassEl,residuEl);
   }
@@ -241,8 +242,6 @@ void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
 			fullMatrix<double> &sol,					
 			int orderRK)								// order of RK integrator
 {
-
-
   // U_{n+1}=U_n+h*(SUM_i a_i*K_i)
   // K_i=M^(-1)R(U_n+b_i*K_{i-1})
 
@@ -255,7 +254,8 @@ void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
   fullMatrix<double> residuEl, KEl;
   fullMatrix<double> iMassEl;
 
-  int nbNodes=eGroups[0]->getNbNodes();
+  int nbNodes = eGroups[0]->getNbNodes();
+  int nbFields = sol.size2()/eGroups[0]->getNbElements(); 
 
   for(int j=0; j<orderRK;j++){
     if(j!=0){
@@ -265,8 +265,8 @@ void dgAlgorithm::multAddInverseMassMatrix ( /*dofManager &dof,*/
     this->residual(claw,eGroups,fGroups,bGroups,K,residu);
     K.scale(0.);
     for(int i=0;i<eGroups[0]->getNbElements();i++) {
-      residuEl.setAsProxy(residu,i,1);
-      KEl.setAsProxy(K,i,1);
+      residuEl.setAsProxy(residu,i*nbFields,nbFields);
+      KEl.setAsProxy(K,i*nbFields,nbFields);
       iMassEl.setAsProxy(eGroups[0]->getInverseMassMatrix(),i*nbNodes,nbNodes);
       iMassEl.mult(residuEl,KEl);
     }
@@ -372,6 +372,7 @@ void dgAlgorithm::residual( const dgConservationLaw &claw,
     fullMatrix<double> &solution, // solution
     fullMatrix<double> &residu) // residual
 {
+  int nbFields=claw.nbFields();
   dgAlgorithm algo;
   residu.scale(0);
   //volume term
@@ -381,19 +382,19 @@ void dgAlgorithm::residual( const dgConservationLaw &claw,
   //interface term
   for(size_t i=0;i<fGroups.size() ; i++) {
     dgGroupOfFaces &faces = *fGroups[i];
-    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2);
-    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2);
-    faces.mapToInterface(1, solution, solution, solInterface);
+    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*2*nbFields);
+    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*2*nbFields);
+    faces.mapToInterface(nbFields, solution, solution, solInterface);
     algo.residualInterface(claw,faces,solInterface,solution,solution,residuInterface);
-    faces.mapFromInterface(1, residuInterface, residu, residu);
+    faces.mapFromInterface(nbFields, residuInterface, residu, residu);
   }
   //boundaries
   for(size_t i=0;i<bGroups.size() ; i++) {
     dgGroupOfFaces &faces = *bGroups[i];
-    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements());
-    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements());
-    faces.mapToInterface(1, solution, solution, solInterface);
+    fullMatrix<double> solInterface(faces.getNbNodes(),faces.getNbElements()*nbFields);
+    fullMatrix<double> residuInterface(faces.getNbNodes(),faces.getNbElements()*nbFields);
+    faces.mapToInterface(nbFields, solution, solution, solInterface);
     algo.residualBoundary(claw,faces,solInterface,solution,residuInterface);
-    faces.mapFromInterface(1, residuInterface, residu, residu);
+    faces.mapFromInterface(nbFields, residuInterface, residu, residu);
   }
 }
diff --git a/Solver/dgConservationLaw.h b/Solver/dgConservationLaw.h
index f1b666a2809b9c160f668546a816ea72ed820095..f2370de706cb1b0f09dc60204754696cecd82fdf 100644
--- a/Solver/dgConservationLaw.h
+++ b/Solver/dgConservationLaw.h
@@ -52,5 +52,8 @@ class dgConservationLaw {
 };
 
 dgConservationLaw *dgNewConservationLawAdvection(const std::string vname);
+dgConservationLaw *dgNewConservationLawShallowWater2d();
+dgConservationLaw *dgNewConservationLawWaveEquation();
+dgBoundaryCondition *dgNewBoundaryConditionWaveEquationWall();
 
 #endif
diff --git a/Solver/dgConservationLawShallowWater2d.cpp b/Solver/dgConservationLawShallowWater2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb2caa205221d97c8a2b7b38b1c6a9338b7a7c4e
--- /dev/null
+++ b/Solver/dgConservationLawShallowWater2d.cpp
@@ -0,0 +1,118 @@
+#include "dgConservationLaw.h"
+#include "function.h"
+static double g = 9.81;
+class dgConservationLawShallowWater2d : public dgConservationLaw {
+  class advection : public dataCacheDouble {
+    dataCacheDouble &sol;
+    public:
+    advection(dataCacheMap &cacheMap):
+      sol(cacheMap.get("Solution",this))
+      {};
+    void _eval () { 
+      int nQP = sol().size1();
+      if(_value.size1() != nQP)
+        _value=fullMatrix<double>(nQP,9);
+      for(int i=0; i< nQP; i++) {
+        double H = sol(i,0);
+        double U = sol(i,1);
+        double V = sol(i,2);
+        // flux_x
+        _value(i,0) = U;
+        _value(i,1) = U*U/H + g*H*H/2;
+        _value(i,2) = U*V/H;
+        // flux_y
+        _value(i,3) = V;
+        _value(i,4) = V*U/H;
+        _value(i,5) = V*V/H + g*H*H/2;
+        // flux_z
+        _value(i,6) = 0;
+        _value(i,7) = 0;
+        _value(i,8) = 0;
+      }
+      _value.scale(0);
+    }
+  };
+  class source : public dataCacheDouble {
+    dataCacheDouble &xyz, &solution;
+    public :
+    source(dataCacheMap &cacheMap) : 
+      xyz(cacheMap.get("XYZ",this)),
+      solution(cacheMap.get("Solution",this))
+    {}
+    void _eval () {
+      int nQP = xyz().size1();
+      if(_value.size1() != nQP)
+        _value = fullMatrix<double>(nQP,3);
+      for (int i=0; i<nQP; i++) {
+        double H = solution(i,0);
+        double U = solution(i,1);
+        double V = solution(i,2);
+        double wind = 0.1*sin(xyz(i,1)/1e6*M_PI)/H/1000;
+        double f = 1e-4+xyz(i,1)*2e-11;
+        double gamma = 1e-6;
+        f=0;
+        _value (i,0) = 0;
+        _value (i,1) = -gamma*U - f*V + wind;
+        _value (i,2) = -gamma*V + f*U;
+      }
+    }
+  };
+  class riemann : public dataCacheDouble {
+    dataCacheDouble &normals, &solL, &solR;
+    public:
+    riemann(dataCacheMap &cacheMapLeft, dataCacheMap &cacheMapRight):
+      normals(cacheMapLeft.get("Normals", this)),
+      solL(cacheMapLeft.get("Solution", this)),
+      solR(cacheMapRight.get("Solution", this))
+      {};
+    void _eval () { 
+      int nQP = solL().size1();
+      if(_value.size1() != nQP)
+        _value = fullMatrix<double>(nQP,6);
+      for(int i=0; i< nQP; i++) {
+        double nx = normals(0,i);
+        double ny = normals(1,i);
+        double UnL = nx*solL(i,1) + ny*solL(i,2);
+        double UnR = nx*solR(i,1) + ny*solR(i,2);
+        double UtL = ny*solL(i,1) - nx*solL(i,2);
+        double UtR = ny*solR(i,1) - nx*solR(i,2);
+        double HR = solR(i,0);
+        double HL = solL(i,0);
+        double c = sqrt(g*(HR+HL)/2);
+        double FUn = -(UnL*UnL/HL + g*HL*HL/2 + UnR*UnR/HR + g*HR*HR/2)/2 + c*(UnL-UnR)/2;
+        double FUt = -(UnL*UtL/HL + UnR*UtR/HR)/2 + c*(UtL-UtR)/2;
+        double FH = -(UnL+UnR)/2 + c*(HL-HR)/2;
+        _value(i,0) = FH;
+        _value(i,1) = FUn*nx + FUt*ny;
+        _value(i,2) = FUn*ny - FUt*nx;
+
+      _value(i,1)=0;
+      _value(i,2)=0;
+        _value(i,3) = -_value(i,0);
+        _value(i,4) = -_value(i,1);
+        _value(i,5) = -_value(i,2);
+      }
+    }
+  };
+  public:
+  dataCacheDouble *newConvectiveFlux( dataCacheMap &cacheMap) const {
+    return new advection(cacheMap);
+  }
+  dataCacheDouble *newRiemannSolver( dataCacheMap &cacheMapLeft, dataCacheMap &cacheMapRight) const {
+    return new riemann(cacheMapLeft, cacheMapRight);
+  }
+  dataCacheDouble *newDiffusiveFlux( dataCacheMap &cacheMap) const {
+    return 0;
+  }
+  dataCacheDouble *newSourceTerm (dataCacheMap &cacheMap) const {
+    return new source(cacheMap);
+  }
+  dgConservationLawShallowWater2d() 
+  {
+    _nbf = 3; // H U(=Hu) V(=Hv)
+  }
+};
+
+dgConservationLaw *dgNewConservationLawShallowWater2d() {
+  return new dgConservationLawShallowWater2d();
+}
diff --git a/Solver/dgConservationLawWaveEquation.cpp b/Solver/dgConservationLawWaveEquation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb9223c232961092616e09edac522c6382cfaa7f
--- /dev/null
+++ b/Solver/dgConservationLawWaveEquation.cpp
@@ -0,0 +1,127 @@
+#include "dgConservationLaw.h"
+#include "function.h"
+// dp/dt - rho*c^2  div(u,v) = 0
+// du/dt + 1/rho  dp/dx = 0
+// dv/dt + 1/rho  dp/dy = 0
+static double c=1;
+static double rho=1;
+class dgConservationLawWaveEquation : public dgConservationLaw {
+  class hyperbolicFlux : public dataCacheDouble {
+    dataCacheDouble &sol;
+    public:
+    hyperbolicFlux(dataCacheMap &cacheMap):
+      sol(cacheMap.get("Solution",this))
+      {};
+    void _eval () { 
+      int nQP = sol().size1();
+      if(_value.size1() != nQP)
+        _value=fullMatrix<double>(nQP,9);
+      for(int i=0; i< nQP; i++) {
+        double p = sol(i,0);
+        double u = sol(i,1);
+        double v = sol(i,2);
+        // flux_x
+        _value(i,0) = c*c*rho*u;
+        _value(i,1) = p/rho; 
+        _value(i,2) = 0;
+        // flux_y
+        _value(i,3) = c*c*rho*v;
+        _value(i,4) = 0;
+        _value(i,5) = p/rho;
+        // flux_z
+        _value(i,6) = 0;
+        _value(i,7) = 0;
+        _value(i,8) = 0;
+      }
+    }
+  };
+  class riemann : public dataCacheDouble {
+    dataCacheDouble &normals, &solL, &solR;
+    public:
+    riemann(dataCacheMap &cacheMapLeft, dataCacheMap &cacheMapRight):
+      normals(cacheMapLeft.get("Normals", this)),
+      solL(cacheMapLeft.get("Solution", this)),
+      solR(cacheMapRight.get("Solution", this))
+      {};
+    void _eval () { 
+      int nQP = solL().size1();
+      if(_value.size1() != nQP)
+        _value = fullMatrix<double>(nQP,6);
+      for(int i=0; i< nQP; i++) {
+        double nx = normals(0,i);
+        double ny = normals(1,i);
+        double unL = nx*solL(i,1) + ny*solL(i,2);
+        double unR = nx*solR(i,1) + ny*solR(i,2);
+        double pR = solR(i,0);
+        double pL = solL(i,0);
+
+        double pRiemann =  0.5 * (pL+pR - (unR-unL)*(rho*c));
+        double unRiemann =  0.5 * (unL+unR - (pR-pL)/(rho*c));
+
+        double Fp = -rho*c*c*unRiemann;
+        double Fun = -pRiemann/rho;
+
+        _value(i,0) = Fp;
+        _value(i,1) = Fun*nx;
+        _value(i,2) = Fun*ny;
+
+        _value(i,3) = -_value(i,0);
+        _value(i,4) = -_value(i,1);
+        _value(i,5) = -_value(i,2);
+      }
+    }
+  };
+  public:
+  dataCacheDouble *newConvectiveFlux( dataCacheMap &cacheMap) const {
+    return new hyperbolicFlux(cacheMap);
+  }
+  dataCacheDouble *newRiemannSolver( dataCacheMap &cacheMapLeft, dataCacheMap &cacheMapRight) const {
+    return new riemann(cacheMapLeft, cacheMapRight);
+  }
+  dataCacheDouble *newDiffusiveFlux( dataCacheMap &cacheMap) const {
+    return 0;
+  }
+  dataCacheDouble *newSourceTerm (dataCacheMap &cacheMap) const {
+    return 0;
+  }
+  dgConservationLawWaveEquation() 
+  {
+    _nbf = 3; // H U(=Hu) V(=Hv)
+  }
+};
+
+class dgBoundaryConditionWaveEquationWall : public dgBoundaryCondition {
+  class term : public dataCacheDouble {
+    dataCacheDouble &sol,&normals;
+    public:
+    term(dataCacheMap &cacheMap):
+    sol(cacheMap.get("Solution",this)),
+    normals(cacheMap.get("Normals",this)){}
+    void _eval () { 
+      int nQP = sol().size1();
+      if(_value.size1() != nQP)
+        _value = fullMatrix<double>(nQP,3);
+      for(int i=0; i< nQP; i++) {
+        double nx = normals(0,i);
+        double ny = normals(1,i);
+        double p = sol(i,0);
+
+        _value(i,0) = 0;
+        _value(i,1) = -p/rho*nx;
+        _value(i,2) = -p/rho*ny;
+      }
+    }
+  };
+  public:
+  dgBoundaryConditionWaveEquationWall(){}
+  dataCacheDouble *newBoundaryTerm(dataCacheMap &cacheMapLeft) const {
+    return new term(cacheMapLeft);
+  }
+};
+
+dgConservationLaw *dgNewConservationLawWaveEquation() {
+  return new dgConservationLawWaveEquation();
+}
+dgBoundaryCondition *dgNewBoundaryConditionWaveEquationWall() {
+  return new dgBoundaryConditionWaveEquationWall();
+}
diff --git a/Solver/dgMainShallowWater2d.cpp b/Solver/dgMainShallowWater2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..efb8462689239f97ba18396e0e6e5cd9d1730bce
--- /dev/null
+++ b/Solver/dgMainShallowWater2d.cpp
@@ -0,0 +1,183 @@
+#include <stdio.h>
+#include <vector>
+#include "GModel.h"
+#include "dgGroupOfElements.h"
+#include "dgAlgorithm.h"
+#include "dgConservationLaw.h"
+#include "Gmsh.h"
+#include "function.h"
+
+
+#include "MElement.h"
+void print (const char *filename,const dgGroupOfElements &els, double *v,int iField=1, int nbFields=1);
+
+class dgConservationLawInitialCondition : public dgConservationLaw {
+  class gaussian : public dataCacheDouble {
+    dataCacheDouble &xyz;
+    double _xc,_yc;
+    public:
+    gaussian(dataCacheMap &cacheMap,double xc, double yc):xyz(cacheMap.get("XYZ",this)),_xc(xc),_yc(yc){};
+    void _eval () { 
+      if(_value.size1() != xyz().size1())
+        _value=fullMatrix<double>(xyz().size1(),1);
+      for(int i=0; i< _value.size1(); i++) {
+        _value(i,0)=exp(-(pow(xyz(i,0)-_xc,2)+pow(xyz(i,1)-_yc,2))*100);
+      }
+    }
+  };
+  public:
+  dgConservationLawInitialCondition() {
+    _nbf = 1;
+  }
+  dataCacheDouble *newSourceTerm(dataCacheMap &cacheMap)const {
+    return new gaussian(cacheMap,0.2,0.3);
+  }
+};
+
+/*int main(int argc, char **argv) {
+  GmshMergeFile("input/square1.msh");
+  //we probably need a class to group those three ones
+  std::vector<dgGroupOfElements*> elementGroups;
+  std::vector<dgGroupOfFaces*> faceGroups;
+  std::vector<dgGroupOfFaces*> boundaryGroups;
+  int order=1;
+  int dimension=2;
+  dgAlgorithm algo;
+  function::registerDefaultFunctions();
+  algo.buildGroups(GModel::current(),dimension,order,elementGroups,faceGroups,boundaryGroups);
+
+  //for now, we suppose there is only one group of elements
+  int nbNodes = elementGroups[0]->getNbNodes();
+  fullMatrix<double> sol(nbNodes,elementGroups[0]->getNbElements());
+  fullMatrix<double> residu(nbNodes,elementGroups[0]->getNbElements());
+  // initial condition
+  {
+    dgConservationLawInitialCondition initLaw;
+    algo.residualVolume(initLaw,*elementGroups[0],sol,residu);
+    algo.multAddInverseMassMatrix(*elementGroups[0],residu,sol);
+  }
+
+  fullMatrix<double> advectionSpeed(3,1);
+  advectionSpeed(0,0)=0.15;
+  advectionSpeed(1,0)=0.05;
+  advectionSpeed(2,0)=0.;
+  function::add("advectionSpeed",function::newFunctionConstant(advectionSpeed));
+
+  dgConservationLaw *law = dgNewConservationLawAdvection("advectionSpeed");
+
+  fullMatrix<double> outsideValue(1,1);
+  outsideValue(0,0)=0;
+  function::add("outsideValue",function::newFunctionConstant(outsideValue));
+  law->addBoundaryCondition("Left",dgBoundaryCondition::newOutsideValueCondition(*law,"outsideValue"));
+  law->addBoundaryCondition("Right",dgBoundaryCondition::newOutsideValueCondition(*law,"outsideValue"));
+
+  law->addBoundaryCondition("Top",dgBoundaryCondition::new0FluxCondition(*law));
+  law->addBoundaryCondition("Bottom",dgBoundaryCondition::new0FluxCondition(*law));
+
+  
+  
+ print("output/init.pos",*elementGroups[0],&sol(0,0));
+  for(int iT=0; iT<100; iT++) {
+    algo.rungeKutta(*law,elementGroups,faceGroups,boundaryGroups,0.01,residu,sol);
+    if(iT%10==0){
+      char name[100];
+      sprintf(name,"output/test_%05i.pos",iT/10);
+      printf("%i\n",iT);
+      print(name,*elementGroups[0],&sol(0,0));
+    }
+  }
+  delete law;
+}*/
+class dgConservationLawStommel : public dgConservationLaw {
+  class initbath : public dataCacheDouble {
+    dataCacheDouble &uvw;
+    public:
+    initbath(dataCacheMap &cacheMap):
+      uvw(cacheMap.get("UVW"))
+    {}
+    void _eval () { 
+      if(_value.size1() != uvw().size1())
+        _value=fullMatrix<double>(uvw().size1(),3);
+      for(int i=0; i< _value.size1(); i++) {
+        _value(i,0)=1000;
+        _value(i,1)=0;
+        _value(i,2)=0;
+      }
+    }
+  };
+  public:
+  dgConservationLawStommel() {
+    _nbf = 3;
+  }
+  dataCacheDouble *newSourceTerm(dataCacheMap &cacheMap)const {
+    return new initbath(cacheMap);
+  }
+};
+int main(int argc, char **argv) {
+  GmshMergeFile("input/stommel.msh");
+  //we probably need a class to group those three ones
+  std::vector<dgGroupOfElements*> elementGroups;
+  std::vector<dgGroupOfFaces*> faceGroups;
+  std::vector<dgGroupOfFaces*> boundaryGroups;
+  int order=1;
+  int dimension=2;
+  dgAlgorithm algo;
+  function::registerDefaultFunctions();
+  algo.buildGroups(GModel::current(),dimension,order,elementGroups,faceGroups,boundaryGroups);
+
+  //for now, we suppose there is only one group of elements
+  int nbNodes = elementGroups[0]->getNbNodes();
+  fullMatrix<double> sol(nbNodes,elementGroups[0]->getNbElements()*3);
+  fullMatrix<double> residu(nbNodes,elementGroups[0]->getNbElements()*3);
+  // initial condition
+  {
+    dgConservationLawStommel initLaw;
+    algo.residualVolume(initLaw,*elementGroups[0],sol,residu);
+    algo.multAddInverseMassMatrix(*elementGroups[0],residu,sol);
+  }
+
+  dgConservationLaw *law = dgNewConservationLawShallowWater2d();
+
+  law->addBoundaryCondition("Top",dgBoundaryCondition::new0FluxCondition(*law));
+  law->addBoundaryCondition("Bottom",dgBoundaryCondition::new0FluxCondition(*law));
+  law->addBoundaryCondition("Left",dgBoundaryCondition::new0FluxCondition(*law));
+  law->addBoundaryCondition("Right",dgBoundaryCondition::new0FluxCondition(*law));
+  
+  for(int iT=0; iT<100; iT++) {
+    if(iT%10==0){
+      printf("%i\n",iT);
+      char name[100];
+      sprintf(name,"output/H_%05i.pos",iT/10);
+      print(name,*elementGroups[0],&sol(0,0),0,3);
+      sprintf(name,"output/U_%05i.pos",iT/10);
+      print(name,*elementGroups[0],&sol(0,0),1,3);
+      sprintf(name,"output/V_%05i.pos",iT/10);
+      print(name,*elementGroups[0],&sol(0,0),2,3);
+    }
+    algo.rungeKutta(*law,elementGroups,faceGroups,boundaryGroups,1e-8,residu,sol);
+  }
+  delete law;
+}
+
+void print (const char *filename,const dgGroupOfElements &els, double *v,int iField, int nbFields) {
+  FILE *file = fopen(filename,"w");
+  fprintf(file,"View \"%s\" {\n", filename);
+  for(int iel=0;iel<els.getNbElements();iel++){
+    MElement *el = els.getElement(iel);
+    fprintf(file,"ST (");
+    for (int iv=0; iv<el->getNumVertices(); iv++) {
+      MVertex *vertex = el->getVertex(iv);
+      SPoint3 coord = vertex->point();
+      fprintf(file,"%e, %e, %e%c ",coord.x(),coord.y(),coord.z(),iv==el->getNumVertices()-1?')':',');
+    }
+    fprintf(file,"{");
+    v+=(iField)*el->getNumVertices();
+    for (int iv=0; iv<el->getNumVertices(); iv++){
+      fprintf(file,"%e%c ",*(v++),iv==el->getNumVertices()-1?'}':',');
+    }
+    v+=(nbFields-1-iField)*el->getNumVertices();
+    fprintf(file,";\n");
+  }
+  fprintf(file,"};");
+  fclose(file);
+}
diff --git a/Solver/dgMainWaveEquation.cpp b/Solver/dgMainWaveEquation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fff9e99f01b9b61589eab368e1db8edc615fedc3
--- /dev/null
+++ b/Solver/dgMainWaveEquation.cpp
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include <vector>
+#include "GModel.h"
+#include "dgGroupOfElements.h"
+#include "dgAlgorithm.h"
+#include "dgConservationLaw.h"
+#include "Gmsh.h"
+#include "function.h"
+
+
+#include "MElement.h"
+void print (const char *filename,const dgGroupOfElements &els, double *v,int iField=1, int nbFields=1);
+void print_vector (const char *filename,const dgGroupOfElements &els, double *v,int iField, int nbFields);
+
+class dgConservationLawInitialCondition : public dgConservationLaw {
+  class gaussian : public dataCacheDouble {
+    dataCacheDouble &xyz;
+    double _xc,_yc;
+    public:
+    gaussian(dataCacheMap &cacheMap,double xc, double yc):xyz(cacheMap.get("XYZ",this)),_xc(xc),_yc(yc){};
+    void _eval () { 
+      if(_value.size1() != xyz().size1())
+        _value=fullMatrix<double>(xyz().size1(),3);
+      for(int i=0; i< _value.size1(); i++) {
+        _value(i,0)=exp(-(pow(xyz(i,0)-_xc,2)+pow(xyz(i,1)-_yc,2))*100)+1;
+      }
+    }
+  };
+  public:
+  dgConservationLawInitialCondition() {
+    _nbf = 3;
+  }
+  dataCacheDouble *newSourceTerm(dataCacheMap &cacheMap)const {
+    //return new gaussian(cacheMap,0.2,0.3);
+    return new gaussian(cacheMap,0.5,0.5);
+  }
+};
+
+int main(int argc, char **argv){
+  GmshMergeFile("input/square1.msh");
+  //we probably need a class to group those three ones
+  std::vector<dgGroupOfElements*> elementGroups;
+  std::vector<dgGroupOfFaces*> faceGroups;
+  std::vector<dgGroupOfFaces*> boundaryGroups;
+  int order=1;
+  int dimension=2;
+  dgAlgorithm algo;
+  function::registerDefaultFunctions();
+  algo.buildGroups(GModel::current(),dimension,order,elementGroups,faceGroups,boundaryGroups);
+
+  //for now, we suppose there is only one group of elements
+  int nbNodes = elementGroups[0]->getNbNodes();
+  dgConservationLaw *law = dgNewConservationLawWaveEquation();
+  fullMatrix<double> sol(nbNodes,elementGroups[0]->getNbElements()*law->nbFields());
+  fullMatrix<double> residu(nbNodes,elementGroups[0]->getNbElements()*law->nbFields());
+  // initial condition
+  {
+    dgConservationLawInitialCondition initLaw;
+    algo.residualVolume(initLaw,*elementGroups[0],sol,residu);
+    algo.multAddInverseMassMatrix(*elementGroups[0],residu,sol);
+  }
+ 
+
+  law->addBoundaryCondition("Left",dgNewBoundaryConditionWaveEquationWall());
+  law->addBoundaryCondition("Right",dgNewBoundaryConditionWaveEquationWall());
+  law->addBoundaryCondition("Top",dgNewBoundaryConditionWaveEquationWall());
+  law->addBoundaryCondition("Bottom",dgNewBoundaryConditionWaveEquationWall());
+  
+  
+ print("output/p.pos",*elementGroups[0],&sol(0,0),0,3);
+ print_vector("output/uv.pos",*elementGroups[0],&sol(0,0),1,3);
+  for(int iT=0; iT<10000; iT++) {
+    algo.rungeKutta(*law,elementGroups,faceGroups,boundaryGroups,1e-3,residu,sol);
+    if(iT%10==0){
+      char name[100];
+      printf("%i\n",iT);
+      sprintf(name,"output/p_%05i.pos",iT);
+      print(name,*elementGroups[0],&sol(0,0),0,3);
+      sprintf(name,"output/uv_%05i.pos",iT);
+      print_vector(name,*elementGroups[0],&sol(0,0),1,3);
+      sprintf(name,"output/v_%05i.pos",iT);
+      print(name,*elementGroups[0],&sol(0,0),2,3);
+      sprintf(name,"output/u_%05i.pos",iT);
+      print(name,*elementGroups[0],&sol(0,0),1,3);
+    }
+  }
+  delete law;
+}
+
+void print (const char *filename,const dgGroupOfElements &els, double *v,int iField, int nbFields) {
+  FILE *file = fopen(filename,"w");
+  fprintf(file,"View \"%s\" {\n", filename);
+  for(int iel=0;iel<els.getNbElements();iel++){
+    MElement *el = els.getElement(iel);
+    fprintf(file,"ST (");
+    for (int iv=0; iv<el->getNumVertices(); iv++) {
+      MVertex *vertex = el->getVertex(iv);
+      SPoint3 coord = vertex->point();
+      fprintf(file,"%e, %e, %e%c ",coord.x(),coord.y(),coord.z(),iv==el->getNumVertices()-1?')':',');
+    }
+    fprintf(file,"{");
+    v+=(iField)*el->getNumVertices();
+    for (int iv=0; iv<el->getNumVertices(); iv++){
+      fprintf(file,"%e%c ",*(v++),iv==el->getNumVertices()-1?'}':',');
+    }
+    v+=(nbFields-1-iField)*el->getNumVertices();
+    fprintf(file,";\n");
+  }
+  fprintf(file,"};");
+  fclose(file);
+}
+void print_vector (const char *filename,const dgGroupOfElements &els, double *v,int iField, int nbFields) {
+  FILE *file = fopen(filename,"w");
+  fprintf(file,"View \"%s\" {\n", filename);
+  for(int iel=0;iel<els.getNbElements();iel++){
+    MElement *el = els.getElement(iel);
+    fprintf(file,"VT (");
+    for (int iv=0; iv<el->getNumVertices(); iv++) {
+      MVertex *vertex = el->getVertex(iv);
+      SPoint3 coord = vertex->point();
+      fprintf(file,"%e, %e, %e%c ",coord.x(),coord.y(),coord.z(),iv==el->getNumVertices()-1?')':',');
+    }
+    v+=(iField)*el->getNumVertices();
+    fprintf(file,"{%e, %e, 0, %e, %e, 0, %e, %e, 0};\n", v[0],v[3],v[1],v[4],v[2],v[5]);
+    v+=(nbFields-iField)*el->getNumVertices();
+  }
+  fprintf(file,"};");
+  fclose(file);
+}