diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 24cbd629c339e8169723d817f32ef4e74936f68b..fe360b96af57a4ad8e6903c69028f796de953c4d 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -31,6 +31,14 @@
 #include "MElement.h"
 #include "GEdgeCompound.h"
 #include "GFaceCompound.h"
+#include "simpleFunction.h"
+#include "distanceTerm.h"
+#include "Context.h"
+#include "Numeric.h"
+#include "dofManager.h"
+#include "linearSystemGMM.h"
+#include "linearSystemCSR.h"
+#include "linearSystemFull.h"
 
 #if defined(HAVE_ANN)
 #include "ANN/ANN.h"
@@ -827,6 +835,7 @@ int GModel::writePartitionedMSH(const std::string &baseName, bool binary,
 int GModel::writeDistanceMSH(const std::string &name, double version, bool binary,
 			     bool saveAll, bool saveParametric, double scalingFactor)
 {
+ 
   std::vector<GEntity*> entities;
   getEntities(entities);
 
@@ -835,12 +844,8 @@ int GModel::writeDistanceMSH(const std::string &name, double version, bool binar
     numnodes += entities[i]->mesh_vertices.size();
   int totNumNodes = numnodes + entities[entities.size()-1]->mesh_vertices.size();
 
-  // CG: Emi -- pourquoi ne pas en faire un plugin, plutot ?
-
-  //geometrical distance
-
-  //Compute distance for akk
   std::map<MVertex*,double* > distance_map; 
+  std::map<MVertex*,double > distance_map2;
   std::vector<SPoint3> pts;
   std::vector<double> distances;
   pts.clear(); 
@@ -850,60 +855,146 @@ int GModel::writeDistanceMSH(const std::string &name, double version, bool binar
   for (int i = 0; i< totNumNodes; i++)   distances.push_back(1.e22);
 
   int k=0;
+  int maxDim = 0;
   for(unsigned int i = 0; i < entities.size(); i++){
     GEntity* ge = entities[i]; 
+    maxDim = std::max(maxDim, ge->dim());
     for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
       MVertex *v = ge->mesh_vertices[j];
       pts.push_back(SPoint3(v->x(), v->y(),v->z()));
       distance_map.insert(std::make_pair(v, &(distances[k])));
+      distance_map2.insert(std::make_pair(v, 0.0));
       k++;
     }
   }
 
-//   GEntity* g2 = entities[entities.size()-2];//faces
-//   for(unsigned int i = 0; i < g2->getNumMeshElements(); i++){ 
-//     std::vector<double> iDistances;
-//     std::vector<SPoint3> iClosePts;
-//     MElement *e = g2->getMeshElement(i);
-//     MVertex *v1 = e->getVertex(0);
-//     MVertex *v2 = e->getVertex(1);
-//     MVertex *v3 = e->getVertex(2);
-//     SPoint3 p1 (v1->x(),v1->y(),v1->z());
-//     SPoint3 p2 (v2->x(),v2->y(),v2->z());
-//     SPoint3 p3 (v3->x(),v3->y(),v3->z());
-//     //signedDistancesPointsTriangle(iDistances, iClosePts, pts, p1,p2,p3);
-//     signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
-//     signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p3);
-//     signedDistancesPointsLine(iDistances, iClosePts, pts, p2,p3);
-//     for (int k = 0; k< pts.size(); k++) {
-//       if (std::abs(iDistances[k]) < distances[k] ) 
-// 	distances[k] = std::abs(iDistances[k]);
+  //Compute geometrical distance to mesh boundaries
+  //-------------------------------------------------
+
+  for(unsigned int i = 0; i < entities.size(); i++){
+    if(entities[i]->dim() == (maxDim-1)) {
+      GEntity* g2 = entities[i];
+      for(unsigned int k = 0; k < g2->getNumMeshElements(); k++){ 
+	std::vector<double> iDistances;
+	std::vector<SPoint3> iClosePts;
+	MElement *e = g2->getMeshElement(k);
+	MVertex *v1 = e->getVertex(0);
+	MVertex *v2 = e->getVertex(1);
+	SPoint3 p1 (v1->x(),v1->y(),v1->z());
+	SPoint3 p2 (v2->x(),v2->y(),v2->z());
+	if( e->getNumVertices() == 2){
+	  signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
+	}
+	else if( e->getNumVertices() == 3){
+	  MVertex *v3 = e->getVertex(2);
+	  SPoint3 p3 (v3->x(),v3->y(),v3->z());
+	  signedDistancesPointsTriangle(iDistances, iClosePts, pts, p1,p2,p3);
+	}
+	for (int kk = 0; kk< pts.size(); kk++) {
+	  if (std::abs(iDistances[kk]) < distances[kk] ) 
+	    distances[kk] = std::abs(iDistances[kk]);
+	}
+      }
+    }
+  }
+
+//   std::map<int, std::vector<GEntity*> > groups[4];
+//   getPhysicalGroups(groups);
+//   std::map<int, std::vector<GEntity*> >::const_iterator it = groups[1].find(100);//Physical Line(100)={...}
+//   if(it == groups[1].end()) return 0;
+//   const std::vector<GEntity *> &physEntities = it->second;
+//   for(unsigned int i = 0; i < physEntities.size(); i++){
+//     GEntity* g2 = physEntities[i];
+//     for(unsigned int i = 0; i < g2->getNumMeshElements(); i++){ 
+//       std::vector<double> iDistances;
+//       std::vector<SPoint3> iClosePts;
+//       MElement *e = g2->getMeshElement(i);
+//       MVertex *v1 = e->getVertex(0);
+//       MVertex *v2 = e->getVertex(1);
+//       SPoint3 p1 (v1->x(),v1->y(),v1->z());
+//       SPoint3 p2 (v2->x(),v2->y(),v2->z());
+//       signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);     
+//       for (int k = 0; k< pts.size(); k++) {
+// 	if (std::abs(iDistances[k]) < distances[k] ) 
+// 	  distances[k] = std::abs(iDistances[k]);
+//       }
 //     }
 //   }
 
-  std::map<int, std::vector<GEntity*> > groups[4];
-  getPhysicalGroups(groups);
-  std::map<int, std::vector<GEntity*> >::const_iterator it = groups[1].find(100);//Physical Line(100)={...}
-  if(it == groups[1].end()) return 0;
-  const std::vector<GEntity *> &physEntities = it->second;
-  for(unsigned int i = 0; i < physEntities.size(); i++){
-    GEntity* g2 = physEntities[i];
-    for(unsigned int i = 0; i < g2->getNumMeshElements(); i++){ 
-      std::vector<double> iDistances;
-      std::vector<SPoint3> iClosePts;
-      MElement *e = g2->getMeshElement(i);
-      MVertex *v1 = e->getVertex(0);
-      MVertex *v2 = e->getVertex(1);
-      SPoint3 p1 (v1->x(),v1->y(),v1->z());
-      SPoint3 p2 (v2->x(),v2->y(),v2->z());
-      signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);     
-      for (int k = 0; k< pts.size(); k++) {
-	if (std::abs(iDistances[k]) < distances[k] ) 
-	  distances[k] = std::abs(iDistances[k]);
+
+  //Compute PDE for distance function
+  //-------------------------------------------------
+  
+#ifdef HAVE_TAUCS
+  linearSystemCSRTaucs<double> *lsys = new linearSystemCSRTaucs<double>;
+#else
+  linearSystemCSRGmm<double> *lsys = new linearSystemCSRGmm<double>;
+  lsys->setNoisy(1);
+  lsys->setGmres(1);
+  lsys->setPrec(5.e-8);
+#endif
+
+  dofManager<double> myAssembler(lsys);
+
+  SBoundingBox3d bbox;
+  for(unsigned int i = 0; i < entities.size(); i++){
+    if(entities[i]->dim() < maxDim) {
+      GEntity *ge = entities[i];
+      for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
+	MVertex *v = ge->mesh_vertices[j];
+	myAssembler.fixVertex(v, 0, 1, 0.0);
+	bbox += SPoint3(v->x(),v->y(),v->z());
+      }
+    }
+  }
+
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      GEntity *ge = entities[ii];
+      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
+	MElement *t = ge->getMeshElement(i);
+	for (int k = 0; k < t->getNumVertices(); k++){
+	    myAssembler.numberVertex(t->getVertex(k), 0, 1);
+	}
+      }    
+    }  
+  }
+
+  double L = norm(SVector3(bbox.max(), bbox.min())); 
+  double mu = L/28;
+  printf("L=%g \n", L);
+
+  simpleFunction<double> DIFF(mu * mu), MONE(1.0);
+  distanceTerm distance(this, 1, &DIFF, &MONE);
+  
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      GEntity *ge = entities[ii];
+      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
+	SElement se(ge->getMeshElement(i));
+	distance.addToMatrix(myAssembler, &se);
       }
+      groupOfElements g((GFace*)ge);
+      distance.addToRightHandSide(myAssembler, g);
     }
   }
 
+   Msg::Info("Distance Computation: Assembly done");
+   lsys->systemSolve();
+   Msg::Info("Distance Computation: System solved");
+ 
+   for(std::map<MVertex*,double >::iterator itv = distance_map2.begin(); itv !=distance_map2.end() ; ++itv){
+    MVertex *v = itv->first;
+    double value =  std::min(0.9999, myAssembler.getDofValue(v, 0, 1));
+    double dist = -mu * log(1. - value);
+    itv->second = dist;
+   }
+
+  lsys->clear();
+
+  //Writing pos files
+  //----------------------
+
   Msg::Info("Writing distance-GEOM.pos");
   FILE * f2 = fopen("distance-GEOM.pos","w");
   fprintf(f2,"View \"distance GEOM\"{\n");
@@ -920,28 +1011,62 @@ int GModel::writeDistanceMSH(const std::string &name, double version, bool binar
   Msg::Info("Writing distance-bgm.pos");
   FILE * f3 = fopen("distance-bgm.pos","w");
   fprintf(f3,"View \"distance\"{\n");
-  GEntity* ge = entities[entities.size()-1];
-  for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ 
-    MElement *e = ge->getMeshElement(i);
-    fprintf(f3,"SS(");
-    std::vector<double> dist;
-    for(int j = 0; j < e->getNumVertices(); j++) {
-      MVertex *v =  e->getVertex(j);
-      if(j) fprintf(f3,",%g,%g,%g",v->x(),v->y(), v->z());
-      else fprintf(f3,"%g,%g,%g", v->x(),v->y(), v->z());
-      std::map<MVertex*, double*>::iterator it = distance_map.find(v);
-      printf("dist =%g \n",*(it->second) );
-      dist.push_back(*(it->second));
-    }
-    fprintf(f3,"){");
-    for (int i=0; i<dist.size(); i++){
-      if (i) fprintf(f3,",%g", dist[i]);
-      else fprintf(f3,"%g", dist[i]);
-    }   
-    fprintf(f3,"};\n");
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
+	MElement *e = entities[ii]->getMeshElement(i);
+	if (maxDim == 3) fprintf(f3,"SS(");
+	else if (maxDim == 2) fprintf(f3,"ST(");
+	std::vector<double> dist;
+	for(int j = 0; j < e->getNumVertices(); j++) {
+	  MVertex *v =  e->getVertex(j);
+	  if(j) fprintf(f3,",%g,%g,%g",v->x(),v->y(), v->z());
+	  else fprintf(f3,"%g,%g,%g", v->x(),v->y(), v->z());
+	  std::map<MVertex*, double*>::iterator it = distance_map.find(v);
+	  dist.push_back(*(it->second));
+	}
+	fprintf(f3,"){");
+	for (int i=0; i<dist.size(); i++){
+	  if (i) fprintf(f3,",%g", dist[i]);
+	  else fprintf(f3,"%g", dist[i]);
+	}   
+	fprintf(f3,"};\n");
+      }
+    }
   }
   fprintf(f3,"};\n");
   fclose(f3);
+
+  Msg::Info("Writing distance-bgm2.pos");
+  FILE * f4 = fopen("distance-bgm2.pos","w");
+  fprintf(f4,"View \"distance\"{\n");
+  //GEntity* ge = entities[entities.size()-1];
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
+	MElement *e = entities[ii]->getMeshElement(i);
+	if (maxDim == 3) fprintf(f4,"SS(");
+	else if (maxDim == 2) fprintf(f4,"ST(");
+	std::vector<double> dist;
+	for(int j = 0; j < e->getNumVertices(); j++) {
+	  MVertex *v =  e->getVertex(j);
+	  if(j) fprintf(f4,",%g,%g,%g",v->x(),v->y(), v->z());
+	  else fprintf(f4,"%g,%g,%g", v->x(),v->y(), v->z());
+	  std::map<MVertex*, double>::iterator it = distance_map2.find(v);
+	  dist.push_back(it->second);
+	}
+	fprintf(f4,"){");
+	for (int i=0; i<dist.size(); i++){
+	  if (i) fprintf(f4,",%g", dist[i]);
+	  else fprintf(f4,"%g", dist[i]);
+	}   
+	fprintf(f4,"};\n");
+      }
+    }
+  }
+  fprintf(f4,"};\n");
+  fclose(f4);
+
       
 // #if defined(HAVE_ANN)
 //   Msg::Info("Computing Distance function to the boundaries with ANN");
diff --git a/Solver/TESTCASES/Advection3D.lua b/Solver/TESTCASES/Advection3D.lua
index 45172ddfccf91a5ed9e1ec35daab4773be9b24b2..9c9ab2873352e4b7e54bf44922f6026f138fc431 100644
--- a/Solver/TESTCASES/Advection3D.lua
+++ b/Solver/TESTCASES/Advection3D.lua
@@ -47,7 +47,7 @@ dg:exportSolution('output/Adv3D-00000')
 print'***exporting init solution ***'
 
 -- main loop
-n = 5
+n = 10
 for i=1,100*n do
   norm = dg:RK44(0.03)
   if (i % n == 0) then