diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index ce37386e01ba0dcf06e5bc192b54b84da32b9dea..d65699fe20659b1c5d4aad0286eea0be789e046f 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -45,8 +45,75 @@
 #include "meshGFaceLloyd.h"
 #include "meshGFaceBoundaryLayers.h"
 
+struct myPlane {
+  SPoint3 p;
+  SVector3 n;
+  double a;
+  /// nx x + ny y + nz z + a = 0
+  myPlane(SPoint3 _p, SVector3 _n) : p(_p),n(_n) 
+  {
+    //    printf("plane passing through %12.5E %12.5E %12.5E\n",p.x(),p.y(),p.z());
+    n.normalize();
+    a = -(n.x()*p.x()+n.y()*p.y()+n.z()*p.z());
+  }
+  double eval (double x, double y, double z){
+    return n.x() * x + n.y() * y + n.z() * z + a;
+  }
+};
+
+struct myLine {
+  SPoint3 p;
+  SVector3 t;
+  myLine() : p(0,0,0) , t (0,0,1) {}
+  myLine(myPlane &p1, myPlane &p2)
+  {
+    t = crossprod(p1.n,p2.n);
+    if (t.norm() == 0.0){
+      Msg::Error("parallel planes do not intersect");
+    }
+    else
+      t.normalize();    
+    // find a point, assume z = 0
+    double a[2][2] = {{p1.n.x(),p1.n.y()},{p2.n.x(),p2.n.y()}};
+    double b[2] = {-p1.a,-p2.a},x[2];
+    if (!sys2x2(a,b,x)){
+      // assume x = 0
+      double az[2][2] = {{p1.n.y(),p1.n.z()},{p2.n.y(),p2.n.z()}};
+      double bz[2] = {-p1.a,-p2.a};
+      if (!sys2x2(az,bz,x)){
+	// assume y = 0
+	double ay[2][2] = {{p1.n.x(),p1.n.z()},{p2.n.x(),p2.n.z()}};
+	double by[2] = {-p1.a,-p2.a};
+	//	printf("%g %g %g %g\n",p1.n.y(),p1.n.z(),p2.n.y(),p2.n.z());
+	if (!sys2x2(ay,by,x)){
+	  Msg::Error("parallel planes do not intersect");
+	}
+	else {
+	  p = SPoint3(x[0],0.0,x[1]);	
+	}
+      }
+      else{
+	p = SPoint3(0.0,x[0],x[1]);	
+      }
+    }
+    else{
+      p = SPoint3(x[0],x[1],0.0);	
+    }	   
+  }
+  SPoint3 orthogonalProjection (SPoint3 &a){
+    // (x - a) * t = 0 --> 
+    // x = p + u t --> (p + ut - a) * t = 0 --> u = (a-p) * t  
+    const double u = dot(a-p,t);
+    return SPoint3(p.x() + t.x() * u,p.y() + t.y() * u,p.z() + t.z() * u);
+  }
+
+};
+
+
 static void copyMesh(GFace *source, GFace *target)
 {
+  //  printf("%d %d \n",source->tag(),target->tag());
+  
   std::map<MVertex*, MVertex*> vs2vt;
   std::list<GEdge*> edges = target->edges();
   {
@@ -81,7 +148,8 @@ static void copyMesh(GFace *source, GFace *target)
       // iterate on source vertices
       for (unsigned i = 0; i < te->mesh_vertices.size(); i++){
 	MVertex *vt = te->mesh_vertices[i];
-	MVertex *vs = 0;
+	MVertex *vs = se->mesh_vertices[source_e * sign > 0 ? i : te->mesh_vertices.size() - i - 1];
+	/*
 	MVertex *vt_on_master;
 	if (te->meshMaster() == te->tag())vt_on_master =vt;
 	else vt_on_master = te->correspondingVertices[vt];
@@ -96,31 +164,135 @@ static void copyMesh(GFace *source, GFace *target)
 	    if (vs_on_master == vt_on_master)break;
 	  }
 	}
+	*/
 	vs2vt[vs] = vt;
       }
     }
   }
 
+  bool translation = true;
+  bool rotation = false;
+
   SVector3 DX;
   int count = 0;
   for (std::map<MVertex*, MVertex*>::iterator it = vs2vt.begin(); it != vs2vt.end() ; ++it){
     MVertex *vs = it->first;
     MVertex *vt = it->second;
-    DX = SVector3(vt->x() - vs->x(), vt->y() - vs->y(), vt->z() - vs->z());
-    if (count == 2) break;
+    if (count == 0)
+      DX = SVector3(vt->x() - vs->x(), vt->y() - vs->y(), vt->z() - vs->z());
+    else {
+      SVector3 DX2 = DX - SVector3 (vt->x() - vs->x(), vt->y() - vs->y(), vt->z() - vs->z());
+      if (DX2.norm() > DX.norm() * 1.e-8)translation = false;
+    }
+    count ++;
+  }
+
+  double rot[3][3] ;
+  myLine LINE;
+  double ANGLE=0;
+  if (!translation){
+    count = 0;
+    rotation = true;
+    std::vector<SPoint3> mps,mpt;
+    for (std::map<MVertex*, MVertex*>::iterator it = vs2vt.begin(); it != vs2vt.end() ; ++it){
+      MVertex *vs = it->first;
+      MVertex *vt = it->second;
+      mps.push_back(SPoint3(vs->x(),vs->y(),vs->z()));
+      //      printf("klax %d point %g %g %g\n",vs->onWhat()->tag(),vs->x(),vs->y(),vs->z());
+      mpt.push_back(SPoint3(vt->x(),vt->y(),vt->z()));
+    }
+    mean_plane mean_source,mean_target;
+    computeMeanPlaneSimple(mps,mean_source);
+    computeMeanPlaneSimple(mpt,mean_target);
+    myPlane PLANE_SOURCE (SPoint3(mean_source.x,mean_source.y,mean_source.z),
+			  SVector3(mean_source.a,mean_source.b,mean_source.c));
+    myPlane PLANE_TARGET (SPoint3(mean_target.x,mean_target.y,mean_target.z),
+			  SVector3(mean_target.a,mean_target.b,mean_target.c));
+    //    printf("%g %g %g vs %g %g %g \n",PLANE_SOURCE.n.x(),PLANE_SOURCE.n.y(),PLANE_SOURCE.n.z(),
+    //    	   PLANE_TARGET.n.x(),PLANE_TARGET.n.y(),PLANE_TARGET.n.z());
+    LINE = myLine (PLANE_SOURCE,PLANE_TARGET);
+
+    // LINE is the axis of rotation
+    // let us compute the angle of rotation
+    count = 0;
+    for (std::map<MVertex*, MVertex*>::iterator it = vs2vt.begin(); it != vs2vt.end() ; ++it){
+      MVertex *vs = it->first;
+      MVertex *vt = it->second;
+      // project both points on the axis : that should be the same point !
+      SPoint3 ps = SPoint3(vs->x(),vs->y(),vs->z());
+      SPoint3 pt = SPoint3(vt->x(),vt->y(),vt->z());      
+      SPoint3 p_ps = LINE.orthogonalProjection (ps);
+      SPoint3 p_pt = LINE.orthogonalProjection (pt);
+      SVector3 dist1 = ps - pt;
+      SVector3 dist2 = p_ps - p_pt;
+      if (dist2.norm() > 1.e-8*dist1.norm()){
+	//	printf("%g %g %g vs %g %g %g\n",ps.x(),ps.y(),ps.z(),pt.x(),pt.y(),pt.z());
+	//	printf("%g %g %g vs %g %g %g\n",p_ps.x(),p_ps.y(),p_ps.z(),p_pt.x(),p_pt.y(),p_pt.z());
+	rotation = false;
+      }
+      SVector3 t1 = ps - p_ps;
+      SVector3 t2 = pt - p_pt;
+      if (t1.norm() > 1.e-8 * dist1.norm()){
+	if (count == 0)ANGLE = angle (t1,t2);
+	else {
+	  double ANGLE2 = angle (t1,t2);
+	  ///	  printf("ANGLE2 = %12.5E\n",ANGLE2);
+	  if (fabs (ANGLE2-ANGLE) > 1.e-8)rotation = false;
+	}
+	count++;
+      }
+    }
+
+    
+    if (rotation){
+      Msg::Info("COPYMESH : Rotation found AXIS (%g,%g,%g) POINT (%g %g %g) ANGLE %g",LINE.t.x(),LINE.t.y(),LINE.t.z(),LINE.p.x(),LINE.p.y(),LINE.p.z(),ANGLE*180/M_PI);
+      double ux = LINE.t.x();
+      double uy = LINE.t.y();
+      double uz = LINE.t.z();
+      rot[0][0] = cos (ANGLE) + ux*ux*(1.-cos(ANGLE));
+      rot[0][1] = ux*uy*(1.-cos(ANGLE)) - uz * sin(ANGLE);
+      rot[0][2] = ux*uz*(1.-cos(ANGLE)) + uy * sin(ANGLE);
+      rot[1][0] = ux*uy*(1.-cos(ANGLE)) + uz * sin(ANGLE);
+      rot[1][1] = cos (ANGLE) + uy*uy*(1.-cos(ANGLE));
+      rot[1][2] = uy*uz*(1.-cos(ANGLE)) - ux * sin(ANGLE);
+      rot[2][0] = ux*uz*(1.-cos(ANGLE)) - uy * sin(ANGLE);
+      rot[2][1] = uy*uz*(1.-cos(ANGLE)) + ux * sin(ANGLE);
+      rot[2][2] = cos (ANGLE) + uz*uz*(1.-cos(ANGLE));
+    }
+    else {
+      Msg::Error ("COPYMESH : Only rotations or translations can be taken into account for peridic faces, face %d not meshed",target->tag());
+      return;
+    }
+  }
+  else{
+    Msg::Info("COPYMESH : Translation found DX = (%g,%g,%g)",DX.x(),DX.y(),DX.z());
   }
 
+  // now transform !!!
   for(unsigned int i = 0; i < source->mesh_vertices.size(); i++){
     MVertex *vs = source->mesh_vertices[i];
-    SPoint3 tp (vs->x() + DX.x(),vs->y() + DX.y(),vs->z() + DX.z());
-    SPoint2 XXX = target->parFromPoint(tp);
-    GPoint gp = target->point(XXX);
     
+    SPoint2 XXX;
+    if (translation) {
+      SPoint3 tp (vs->x() + DX.x(),vs->y() + DX.y(),vs->z() + DX.z());
+      XXX = target->parFromPoint(tp);
+    }
+    else if (rotation){
+      SPoint3 ps = SPoint3(vs->x(),vs->y(),vs->z());
+      SPoint3 p_ps = LINE.orthogonalProjection (ps);
+      SPoint3 P = ps - p_ps, res;
+      matvec(rot, P, res);
+      res += p_ps;
+      XXX = target->parFromPoint(res);
+    }
+    GPoint gp = target->point(XXX);
     MVertex *vt = new MFaceVertex(gp.x(), gp.y(), gp.z(), target, gp.u(), gp.v());
     target->mesh_vertices.push_back(vt);
     target->correspondingVertices[vt] = vs;
     vs2vt[vs] = vt;
   }
+
+
   for (unsigned i = 0; i < source->triangles.size(); i++){
     MVertex *vt[3];
     for (int j = 0; j < 3; j++){
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index 5a4aabbc9dc716ac9a352f4df37859888abdb075..003f3413e21616d22446f5726ec8a771bdd042f1 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -1284,8 +1284,9 @@ void computeMeanPlaneSimple(const std::vector<SPoint3> &points, mean_plane &mean
   res[0] = V(0, min);
   res[1] = V(1, min);
   res[2] = V(2, min);
-  norme(res);
-
+  
+  double xxx = norme(res);
+  res[3] /= xxx;
   double ex[3], t1[3], t2[3];
 
   ex[0] = ex[1] = ex[2] = 0.0;
@@ -1313,7 +1314,7 @@ void computeMeanPlaneSimple(const std::vector<SPoint3> &points, mean_plane &mean
   meanPlane.a = res[0];
   meanPlane.b = res[1];
   meanPlane.c = res[2];
-  meanPlane.d = -res[3];//BUG HERE
+  meanPlane.d = res[3];//BUG HERE
 
   meanPlane.x = meanPlane.y = meanPlane.z = 0.;
   if(fabs(meanPlane.a) >= fabs(meanPlane.b) &&
diff --git a/benchmarks/3d/CubeFullPeriodic.geo b/benchmarks/3d/CubeFullPeriodic.geo
new file mode 100644
index 0000000000000000000000000000000000000000..7f94b5b5150e6a1071de4b2194f43f812680118f
--- /dev/null
+++ b/benchmarks/3d/CubeFullPeriodic.geo
@@ -0,0 +1,22 @@
+//Mesh.Dual = 1;
+//Mesh.Voronoi=1;
+
+lc = 0.08;
+Point(1) = {0.0,0.0,0.0,lc};         
+Point(2) = {1,0.0,0.0,lc};         
+Point(3) = {1,1,0.0,lc};         
+Point(4) = {0,1,0.0,lc};         
+Line(1) = {4,3};         
+Line(2) = {3,2};         
+Line(3) = {2,1};         
+Line(4) = {1,4};         
+Line Loop(5) = {2,3,4,1};         
+Plane Surface(6) = {5};         
+Extrude Surface { 6, {0,0.0,1} };         
+
+
+Periodic Surface 28 {11, 10, 9, 8} = 6 {1, 4, 3, 2} ;
+Periodic Surface 19 {-3,18,-9,14} = 27 {1, 22,11,13} ;
+Periodic Surface 23 {-4,18,-10,22} = 15 {2,14,8,13} ;
+
+//Periodic Surface 23 {22, 4, -18, -10} = 6 {1, 4, 3, 2} ;
diff --git a/benchmarks/3d/PeriodicRotationAndTranslation.geo b/benchmarks/3d/PeriodicRotationAndTranslation.geo
new file mode 100644
index 0000000000000000000000000000000000000000..1b2652bad48cb475fa4ed814c5d83a446a181b9c
--- /dev/null
+++ b/benchmarks/3d/PeriodicRotationAndTranslation.geo
@@ -0,0 +1,32 @@
+
+lc = 1.0;
+R = 5;
+R_rotation = 15;
+
+Point(1) = {0, 0, 0, lc};
+Point(2) = {R, 0, 0, lc};
+Point(3) = {-R, 0, 0, lc};
+Point(4) = {0, R, 0, lc};
+Point(5) = {0, -R, 0, lc};
+Circle(1) = {4, 1, 3};
+Circle(2) = {3, 1, 5};
+Circle(3) = {5, 1, 2};
+Circle(4) = {2, 1, 4};
+
+Line Loop(5) = {1, 2, 3, 4};
+Plane Surface(6) = {5};
+
+Extrude {0, 0, 1} {
+  Surface{6};
+}
+
+// C'est cette opŽration (d'extrusion autour d'un axe) qui fait planter periodic surface
+// le bug Žtant dependant de l'angle d'extrusion specifie
+
+Extrude {{0, 1, 0}, {-R_rotation, 0, 0}, Pi/3} {
+  Surface{6};
+}
+
+Periodic Surface 28 {8, 9, 10, 11} = 6 {1, 2, 3, 4} ;
+Periodic Surface  50 {30, 31, 32, 33} = 6 {1, 2, 3, 4} ;
+