diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index b11f31a513ac45dcf7a9e6c9471152de8bebbb2b..3f5d7fbaa34286c8856ee3a4d0c30f0591c05559 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1706,6 +1706,7 @@ int GModel::removeDuplicateMeshVertices(double tolerance)
     return 0;
   }
 
+  std::map<MVertex*,MVertex*> newVertex;
   std::map<int, std::vector<MElement*> > elements[11];
   for(unsigned int i = 0; i < entities.size(); i++){
     for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
@@ -1714,7 +1715,10 @@ int GModel::removeDuplicateMeshVertices(double tolerance)
       for(int k = 0; k < e->getNumVertices(); k++){
         MVertex *v = e->getVertex(k);
         MVertex *v2 = pos.find(v->x(), v->y(), v->z());
-        if(v2) verts.push_back(v2);
+        if(v2) {
+          verts.push_back(v2);
+          newVertex[v] = v2;
+        }
       }
       if((int)verts.size() == e->getNumVertices()){
         MElementFactory factory;
@@ -1739,6 +1743,39 @@ int GModel::removeDuplicateMeshVertices(double tolerance)
     }
   }
 
+  // --- replace vertices in the periodic copies
+  
+  for(unsigned int i = 0; i < entities.size(); i++){
+
+    GEntity* ge = entities[i];
+
+    std::map<MVertex*,MVertex*>& corrVtcs = ge->correspondingVertices;
+    std::map<MVertex*,MVertex*>::iterator cIter;
+    
+    for (cIter=newVertex.begin();cIter!=newVertex.end();++cIter) {
+      MVertex* oldTgt = cIter->first;
+      MVertex* newTgt = cIter->second;
+      std::map<MVertex*,MVertex*>::iterator cvIter = corrVtcs.find(oldTgt);
+      if (cvIter != corrVtcs.end()) {
+        MVertex* src = cvIter->second;
+        corrVtcs.erase(cvIter);
+        corrVtcs[newTgt] = src;
+      }
+    }
+    
+    for (cIter=corrVtcs.begin();cIter!=corrVtcs.end();++cIter) {
+
+      MVertex* oldSrc = cIter->second;
+      std::map<MVertex*,MVertex*>::iterator nIter = newVertex.find(oldSrc);
+
+      if (nIter != newVertex.end()) {
+        MVertex* tgt = cIter->first;
+        MVertex* newSrc = nIter->second;
+        corrVtcs[tgt] = newSrc;
+      }
+    }
+  }
+  
   for(unsigned int i = 0; i < entities.size(); i++)
     entities[i]->deleteMesh();
 
diff --git a/Geo/GModelIO_CGNS.cpp b/Geo/GModelIO_CGNS.cpp
index 9570e831e2ea8a2f0752c47e0317ec48b3f9ca2f..079837517a9b2e66f94d93e8676f7c2cbb402ec9 100644
--- a/Geo/GModelIO_CGNS.cpp
+++ b/Geo/GModelIO_CGNS.cpp
@@ -266,8 +266,8 @@ static MElement *createElementMSH(GModel *m, int num, int typeMSH, int reg, int
   default : Msg::Error("Wrong type of element"); return NULL;
   }
 
-  int dim = e->getDim();
   /*
+  int dim = e->getDim();
   if(physical && (!physicals[dim].count(reg) || !physicals[dim][reg].count(physical)))
     physicals[dim][reg][physical] = "unnamed";
   */
@@ -348,15 +348,22 @@ static int getIndicesQuad(int i1, int i2, int i3, int i4,
   int koffset = (k3-k1)/abs(k2-k1);
   */
   added += getIndicesQuad(i1+offset[f][0][0], i2+offset[f][1][0], i3+offset[f][2][0], i4+offset[f][3][0],
-			  j1+offset[f][0][1], j2+offset[f][1][1], j3+offset[f][2][1], j4+offset[f][3][1],
-			  k1+offset[f][0][2], k2+offset[f][1][2], k3+offset[f][2][2], k4+offset[f][3][2],
-			  ind_i, ind_j, ind_k, order-2, f);
+                          j1+offset[f][0][1], j2+offset[f][1][1], j3+offset[f][2][1], j4+offset[f][3][1],
+                          k1+offset[f][0][2], k2+offset[f][1][2], k3+offset[f][2][2], k4+offset[f][3][2],
+                          ind_i, ind_j, ind_k, order-2, f);
   /**/
   }
   return added;
 }
 
-static int getIndicesFace(int i1, int i2, int i3, int i4, int j1, int j2, int j3, int j4, int k1, int k2, int k3, int k4, std::vector<int>& ind_i, std::vector<int>& ind_j, std::vector<int>& ind_k, int order, int f) {
+// --- get ijk indices for a high order face defined by principal vertices 1-4
+
+static int getIndicesFace(int i1, int i2, int i3, int i4, 
+                          int j1, int j2, int j3, int j4, 
+                          int k1, int k2, int k3, int k4, 
+                          std::vector<int>& ind_i, 
+                          std::vector<int>& ind_j, 
+                          std::vector<int>& ind_k, int order, int f) {
 
   static const int offset[6][4][3] = {
     {{ 1, 1, 0}, { 1,-1, 0}, {-1,-1, 0}, {-1, 1, 0}},
@@ -429,7 +436,13 @@ static int getIndicesFace(int i1, int i2, int i3, int i4, int j1, int j2, int j3
   return added;
 }
 
-static void getIndices(int i, int j, int k, std::vector<int>& ind_i, std::vector<int>& ind_j, std::vector<int>& ind_k, int order, int startpoint=0) {
+// --- get ijk indices for a high order hexahedral element
+
+static void getIndices(int i, int j, int k, 
+                       std::vector<int>& ind_i, 
+                       std::vector<int>& ind_j, 
+                       std::vector<int>& ind_k, 
+                       int order, int startpoint=0) {
 
   static const int edges[12][2] = {
     {0, 1},
@@ -493,10 +506,10 @@ static void getIndices(int i, int j, int k, std::vector<int>& ind_i, std::vector
       int p1_k = ind_k[startpoint+edges[e][1]];
 
       for (int v = 1; v < order; v++) {
-	ind_i.push_back(p0_i + v*((p1_i-p0_i)/order));
-	ind_j.push_back(p0_j + v*((p1_j-p0_j)/order));
-	ind_k.push_back(p0_k + v*((p1_k-p0_k)/order));
-	initial_point++;
+        ind_i.push_back(p0_i + v*((p1_i-p0_i)/order));
+        ind_j.push_back(p0_j + v*((p1_j-p0_j)/order));
+        ind_k.push_back(p0_k + v*((p1_k-p0_k)/order));
+        initial_point++;
       }
     }
 
@@ -517,10 +530,10 @@ static void getIndices(int i, int j, int k, std::vector<int>& ind_i, std::vector
       int k3 = ind_k[startpoint+faces[f][2]] + offset[f][2][2];
       int k4 = ind_k[startpoint+faces[f][3]] + offset[f][3][2];
       initial_point+= getIndicesFace(i1, i2, i3, i4,
-				      j1, j2, j3, j4,
-				      k1, k2, k3, k4,
-				     ind_i, ind_j, ind_k,
-				     order-2, f);
+                                     j1, j2, j3, j4,
+                                     k1, k2, k3, k4,
+                                     ind_i, ind_j, ind_k,
+                                     order-2, f);
     }
 
     // interior
@@ -545,11 +558,355 @@ static void getIndices(int i, int j, int k, std::vector<int>& ind_i, std::vector
  *
  ******************************************************************************/
 
+// --- compute the face index in the block from the index range ----------------
+
+
+int computeCGNSFace(const cgsize_t* range) {
+
+  int face = -1;
+  
+  if (range[0] == range[3]) {
+    if (range[0] == 1)
+      face = 4;
+    else
+      face = 5;
+  } else if (range[1] == range[4]) {
+    if (range[1] == 1)
+      face = 2;
+    else
+      face = 3;
+  } else if (range[2] == range[5]) {
+    if (range[2] == 1)
+      face = 0;
+    else
+      face = 1;
+  }
+  return face;
+}
+
+// --- structure for storing periodic connections ------------------------------
+
+struct CGNSPeriodic {
+
+  
+  // the data that are modified on the fly by looping on the CGNSPeriodicSet
+  // 
+  // - should not affect the ordering in CGNSPeriodicLess 
+  // - should be modified with a const operation (STL only returns const data)
+  // - should hence be mutable
+  //
+  // Currently this data includes the vectors of source and target vertices 
+  // 
+  // All ordering data should only be modified in constructor-like operations
+  
+  friend class CGNSPeriodicLess;
+  
+public:
+
+  struct IJK {
+    
+    IJK() {for (int k=0;k<3;k++) ijk[k] = -1;}
+    IJK(int i,int j,int k){ijk[0]=i;ijk[1]=j;ijk[2]=k;}
+    IJK(const IJK& other) {std::memcpy(ijk,other.ijk,3*sizeof(int));}
+    
+    int& operator[](int k)       {return ijk[k];}
+    int  operator[](int k) const {return ijk[k];}
+    
+    int ijk[3];
+
+    string print() const {
+      std::ostringstream printout;
+      printout << "(" << ijk[0] << "," << ijk[1] << "," << ijk[2] << ")";
+      return printout.str();
+    }
+
+  };
+
+  string targetZone;           // cgns name of the block
+  int targetFace;              // index of the face in the block
+  mutable int targetFaceId;    // elementary tag corresponding to the face
+  mutable
+  vector<MVertex*> targetVertices; // ordered vertices in the target
+  vector<IJK>   targetIJK;    // ijk indices of the face points in the block
+
+
+  string sourceZone;           // cgns name of the block
+  int sourceFace;              // index of the face in the block
+  mutable int sourceFaceId;    // elementary tag corresponding to the face  
+  mutable 
+  vector<MVertex*> sourceVertices; // ordered vertices in the source
+  vector<IJK>   sourceIJK;  // ijk indices in the source face, ordered following target
+
+  std::vector<double> tfo;     // transformation 
+
+public:
+  
+  void print(ostream& out) const {
+
+    out << "Connection of face " << targetFace << " (" << targetFaceId << ")"
+        << " of domain " << targetZone << " to " 
+        << sourceFace << " (" << sourceFaceId << ")" << " of " 
+        << sourceZone << std::endl;
+  }
+      
+
+public: // constructors 
+
+  
+  // -- empty constructor
+
+  CGNSPeriodic() { setUnitTransformation(); }
+
+  // -- standard constructor
+
+  CGNSPeriodic(const char* tn,const cgsize_t* tr,
+               const char* sn,const cgsize_t* sr,const int* iTfo,int o,
+               int tfid,
+               const float* rotationCenter,
+               const float* rotationAngle,
+               const float* translation):
+    
+    targetZone(tn),targetFace(computeCGNSFace(tr)),targetFaceId(tfid),
+    sourceZone(sn),sourceFace(computeCGNSFace(sr)),sourceFaceId(-1) {
+    
+    // compute the structured grid indices 
+
+    int dIJKTgt[3] = {(tr[3] > tr[0] ? o : - o),
+                      (tr[4] > tr[1] ? o : - o),
+                      (tr[5] > tr[2] ? o : - o)};
+    
+    int dIJKSrc[3] = {(sr[3] > sr[0] ? o : - o),
+                      (sr[4] > sr[1] ? o : - o),
+                      (sr[5] > sr[2] ? o : - o)};
+
+    int idx[3] = {abs(iTfo[0])-1,abs(iTfo[1])-1,abs(iTfo[2])-1};
+
+    int nbPoints = 1;
+    IJK nbIJK;
+    for (int k=0;k<3;k++) nbIJK[k] = (tr[k]==tr[k+3])?1:((abs(tr[k]-tr[k+3]))/o +1);
+    for (int k=0;k<3;k++) nbPoints *= nbIJK[k];
+    
+    targetIJK.reserve(nbPoints);
+    sourceIJK.reserve(nbPoints);
+
+    targetVertices.resize(nbPoints,NULL);
+    sourceVertices.resize(nbPoints,NULL);
+    
+    IJK src(sr[idx[0]],sr[idx[1]],sr[idx[2]]);
+    IJK tgt(tr[0],tr[1],tr[2]);
+        
+    for (int i=0;i<nbIJK[0];i++) {
+      
+      tgt[1] = tr[1];
+      src[1] = sr[idx[1]];
+      
+      for (int j=0;j<nbIJK[1];j++) {
+        
+        tgt[2] = tr[2];
+        src[2] = sr[idx[2]];
+        
+        for (int k=0;k<nbIJK[2];k++) {
+          
+          targetIJK.push_back(tgt);
+          sourceIJK.push_back(src);
+          
+          tgt[2]      += dIJKTgt[2];
+          src[idx[2]] += dIJKSrc[idx[2]];
+        }
+        tgt[1]      += dIJKTgt[1];
+        src[idx[1]] += dIJKSrc[idx[1]]; 
+      }
+      tgt[0]      += dIJKTgt[0];
+      src[idx[0]] += dIJKSrc[idx[0]];
+    }
+   
+    // now compute the transformation
+    
+    computeTransformation(rotationCenter,rotationAngle,translation);
+  }
+
+  
+  // -- copy constructor
+
+  CGNSPeriodic(const CGNSPeriodic& old) {
+    
+    targetVertices.resize(old.getNbPoints(),NULL);
+    sourceVertices.resize(old.getNbPoints(),NULL);
+
+    targetZone     = old.targetZone;
+    targetFace     = old.targetFace;
+    targetFaceId   = old.targetFaceId;
+    targetIJK      = old.targetIJK;
+    targetVertices = old.targetVertices;
+
+    sourceZone     = old.sourceZone;
+    sourceFace     = old.sourceFace;
+    sourceFaceId   = old.sourceFaceId;
+    sourceIJK      = old.sourceIJK;
+    sourceVertices = old.sourceVertices;
+    
+    tfo = old.tfo;
+  }
+
+  // -- constructor of the inverse connection
+
+  CGNSPeriodic getInverse() const {
+
+    CGNSPeriodic inv;
+
+    inv.targetVertices.resize(getNbPoints(),NULL);
+    inv.sourceVertices.resize(getNbPoints(),NULL);
+
+    inv.targetZone     = sourceZone;
+    inv.targetFace     = sourceFace;
+    inv.targetFaceId   = sourceFaceId;
+    inv.targetIJK      = sourceIJK;
+    inv.targetVertices = sourceVertices;
+
+    inv.sourceZone     = targetZone;
+    inv.sourceFace     = targetFace;
+    inv.sourceFaceId   = targetFaceId;
+    inv.sourceIJK      = targetIJK;
+    inv.sourceVertices = targetVertices;
+    
+    inv.tfo = tfo;
+    invertTransformation(inv.tfo);
+    
+    return inv;
+  }
+
+public: // vertex functions 
+
+  
+  size_t getNbPoints() const {return targetIJK.size();}
+  
+
+  bool getTargetIJK(size_t ip,int& i,int& j,int& k) const {
+    if (ip > targetIJK.size())  return false;
+    i = targetIJK[ip][0] - 1;
+    j = targetIJK[ip][1] - 1;
+    k = targetIJK[ip][2] - 1;
+    return true;
+  }
+
+  bool getSourceIJK(size_t ip,int& i,int& j,int& k) const {
+    if (ip > sourceIJK.size())  return false;
+    i = sourceIJK[ip][0] - 1;
+    j = sourceIJK[ip][1] - 1;
+    k = sourceIJK[ip][2] - 1;
+    return true;
+  }
+
+  bool insertTargetVertex(size_t ip,MVertex* v) const {
+    if (ip > targetVertices.size()) return false;
+    targetVertices[ip] = v;
+    return true;
+  }
+
+  bool insertSourceVertex(size_t ip,MVertex* v) const {
+    if (ip > sourceVertices.size()) return false;
+    sourceVertices[ip] = v;
+    return true;
+  }
+  
+
+public: // transformation operations
+
+  bool setUnitTransformation() {
+    tfo.resize(16,0);
+    for (int i=0;i<16;i+=5) tfo[i] = 1;
+    return true;
+  }
+
+  bool computeTransformation(const float* rc,const float* ra,const float *tr) {
+    
+    fullMatrix<double> compoundRotation(3,3);
+    for (int i=0;i<3;i++) compoundRotation(i,i) = 1;
+
+    for (int i=0;i<3;i++) {
+      
+      if (ra[i] != 0) {
+        
+        fullMatrix<double> tmp(compoundRotation);
+        
+        fullMatrix<double> rotation(3,3);
+        rotation(i,i) = 1;
+
+        int ii = (i+1)%3;
+        int jj = (i+2)%3;
+
+        double ca = cos(ra[i]);
+        double sa = sin(ra[i]);
+        
+        // rotation with -alpha
+        
+        rotation(ii,ii) = ca;
+        rotation(ii,jj) = -sa;
+        rotation(jj,ii) = sa;
+        rotation(jj,jj) = ca;
+        
+        compoundRotation.gemm(rotation,tmp,1,0);
+      }
+    }
+    
+    // compute displacement from rotation center
+    
+    fullVector<double> disp(3);
+
+    fullVector<double> center(3);
+    for (int i=0;i<3;i++) center(i) = rc[i];
+    compoundRotation.mult(center,disp);
+    
+    // add specified translation
+
+    for (int i=0;i<3;i++) disp(i) = - tr[i];
+
+    // copy to tfo
+
+    tfo.clear();
+    
+    for (int i=0;i<3;i++) {
+      for (int j=0;j<3;j++) tfo.push_back(compoundRotation(i,j));
+      tfo.push_back(disp(i));
+    }
+    for (int i=0;i<3;i++) tfo.push_back(0);
+    tfo.push_back(1);
+    
+    return true;
+  }
+  
+  bool invertTransformation(std::vector<double>& newTfo) const {
+
+    fullMatrix<double> inv(4,4);
+    for (int i=0;i<4;i++) for (int j=0;j<4;j++) inv(i,j) = tfo[i*4+j];    
+    inv.invertInPlace();
+    newTfo.clear();
+    for (int i=0;i<4;i++) for (int j=0;j<4;j++) newTfo.push_back(inv(i,j));
+    return true;
+  } 
+};
+
+// --- definition of a set for storing periodic connections --------------------
+
+struct CGNSPeriodicLess {
+
+  bool operator() (const CGNSPeriodic& f,const CGNSPeriodic& d) {
+    int s = f.sourceZone.compare(d.sourceZone);
+    if (s != 0) return (s < 0);
+    return (f.sourceFace < d.sourceFace);
+  }
+};
+
+typedef set<CGNSPeriodic,CGNSPeriodicLess> CGNSPeriodicSet;
+
+
+// -----------------------------------------------------------------------------
+
 int GModel::readCGNS(const std::string &name)
 {
-
-  cgsize_t isize[9];
-  char basename[33],zonename[33];
+  
+  // cgsize_t isize[9];
+  // char basename[33],zonename[33];
   std::map<int, std::vector<MElement*> > elements[10];
 
 
@@ -565,7 +922,8 @@ int GModel::readCGNS(const std::string &name)
   cg_nbases(index_file, &nBases);
   Msg::Debug("Found %i base(s).", nBases);
   if (nBases > 1) {
-    Msg::Warning("Found %i bases in the file, but only the first one will be used to build mesh.", nBases);
+    Msg::Warning("Found %i bases in the file, "
+                 "but only the first one will be used to build mesh.", nBases);
   }
   int index_base = 1;
 
@@ -609,17 +967,17 @@ int GModel::readCGNS(const std::string &name)
     double ielem = irmax[0] - 1;
     double jelem = irmax[1] - 1;
     double kelem = irmax[2] - 1;
-    printf("Elems %g %g %g\n", ielem, jelem, kelem);
+    // printf("Elems %g %g %g\n", ielem, jelem, kelem);
     int order = 1;
-    bool done = false;
-    while(fmod(ielem / 2.0, 1.0) == 0.0 && fmod(jelem / 2.0, 1.0) == 0.0 && fmod(kelem / 2.0, 1.0) == 0.0 and order < 5) {
-	order*=2;
-	ielem = ielem / 2.0;
-	jelem = jelem / 2.0;
-	kelem = kelem / 2.0;
+    while(fmod(ielem / 2.0, 1.0) == 0.0 && 
+          fmod(jelem / 2.0, 1.0) == 0.0 && 
+          fmod(kelem / 2.0, 1.0) == 0.0 and order < 5) {
+      order*=2;
+      ielem = ielem / 2.0;
+      jelem = jelem / 2.0;
+      kelem = kelem / 2.0;
     }
     max_order = min(order, max_order);
-
   }
 
   Msg::Debug("Maximum import order : %i", max_order);
@@ -636,8 +994,10 @@ int GModel::readCGNS(const std::string &name)
   // for entity numbering
   int elementary_region = getNumRegions();
   int elementary_face = getNumFaces();
-  int elementary_edge = getNumEdges();
-  int elementary_vertex = getNumVertices();
+  // int elementary_edge = getNumEdges();
+  // int elementary_vertex = getNumVertices();
+
+  CGNSPeriodicSet periodicConnections;
 
   // Read the zones
   for (int index_zone = 1; index_zone <= nZones; index_zone++) {
@@ -665,9 +1025,9 @@ int GModel::readCGNS(const std::string &name)
     irmin[2] = 1; irmax[2] = zoneSizes[2];
 
     // Compute max multigrid level
-    double ielem = irmax[0] - 1;
-    double jelem = irmax[1] - 1;
-    double kelem = irmax[2] - 1;
+    // double ielem = irmax[0] - 1;
+    // double jelem = irmax[1] - 1;
+    // double kelem = irmax[2] - 1;
 
     int nnodesZone;
     int nelements;
@@ -675,7 +1035,8 @@ int GModel::readCGNS(const std::string &name)
     nnodesZone        = zoneSizes[0]*zoneSizes[1]*zoneSizes[2];
     nelements         = zoneSizes[3]*zoneSizes[4]*zoneSizes[5];
     nBoundaryVertices = zoneSizes[6]*zoneSizes[7]*zoneSizes[8];
-    Msg::Debug("%i nodes, %i elements, and %i vertices on the zone boundary.", nnodesZone, nelements, nBoundaryVertices);
+    Msg::Debug("%i nodes, %i elements, and %i vertices on the zone boundary.", 
+               nnodesZone, nelements, nBoundaryVertices);
 
     // Reading the coordinates
     int nCoords;
@@ -687,46 +1048,53 @@ int GModel::readCGNS(const std::string &name)
     double nodes[nnodesZone][nCoords];
 
     for ( int iCoord = 0; iCoord < nCoords; iCoord++ ) {
-      if ( cg_coord_info(index_file, index_base, index_zone, iCoord+1, &dataType, coordName) ) {
-	Msg::Error("Could not read coordinate %i.", iCoord+1);
-	cg_close (index_file);
-	return 0;
+      if ( cg_coord_info(index_file, index_base, index_zone, 
+                         iCoord+1, &dataType, coordName) ) {
+        Msg::Error("Could not read coordinate %i.", iCoord+1);
+        cg_close (index_file);
+        return 0;
       }
-
+      
       Msg::Debug("Reading coordinate %i : %s.", iCoord+1, coordName);
-
+      
       switch(dataType) {
-        case RealSingle:
-	  Msg::Debug("        [Type is float]");
-	  coord = new float[nnodesZone];
-	  if ( cg_coord_read(index_file, index_base, index_zone, coordName, dataType, irmin, irmax, coord)) {
-	    Msg::Error("Could not read coordinate %i.", iCoord+1);
-	    cg_close(index_file);
-	    return 0;
-	  }
-	  for (int iNode = 0; iNode < nnodesZone; iNode++) {
-	    nodes[iNode][iCoord] = (double)((float*)coord)[iNode];
-	  }
-	  delete [] (float*)coord;
-	  break;
-        case RealDouble:
-	  Msg::Debug("        [Type is double]");
-	  coord = new double[nnodesZone];
-	  if ( cg_coord_read(index_file, index_base, index_zone, coordName, dataType, irmin, irmax, coord)) {
-	    Msg::Error("Could not read coordinate %i.", iCoord+1);
-	    cg_close(index_file);
-	    return 0;
-	  }
-	  for (int iNode = 0; iNode < nnodesZone; iNode++) {
-	    nodes[iNode][iCoord] = ((double*) coord)[iNode];
-	  }
-	  delete [] (double*)coord;
-	  break;
+      case RealSingle:
+        Msg::Debug("        [Type is float]");
+        coord = new float[nnodesZone];
+        if ( cg_coord_read(index_file, index_base, index_zone, 
+                           coordName, dataType, irmin, irmax, coord)) {
+          Msg::Error("Could not read coordinate %i.", iCoord+1);
+          cg_close(index_file);
+          return 0;
+        }
+        for (int iNode = 0; iNode < nnodesZone; iNode++) {
+          nodes[iNode][iCoord] = (double)((float*)coord)[iNode];
+        }
+        delete [] (float*)coord;
+        break;
+      case RealDouble:
+        Msg::Debug("        [Type is double]");
+        coord = new double[nnodesZone];
+        if ( cg_coord_read(index_file, index_base, index_zone, 
+                           coordName, dataType, irmin, irmax, coord)) {
+          Msg::Error("Could not read coordinate %i.", iCoord+1);
+          cg_close(index_file);
+          return 0;
+        }
+        for (int iNode = 0; iNode < nnodesZone; iNode++) {
+          nodes[iNode][iCoord] = ((double*) coord)[iNode];
+        }
+        delete [] (double*)coord;
+        break;
+      default:
+        Msg::Error("Wrong data type for reading coordinates in CGNS file");
+        break;
       }
     }
 
     for (int iNode = 0; iNode < nnodesZone; iNode++) {
-      MVertex* mv = new MVertex(nodes[iNode][0], nodes[iNode][1], nodes[iNode][2], 0, vnum);
+      MVertex* mv = new MVertex(nodes[iNode][0], nodes[iNode][1], 
+                                nodes[iNode][2], 0, vnum);
       minVertex = std::min(minVertex, vnum);
       maxVertex = std::max(maxVertex, vnum);
       vertexMap[vnum] = mv;
@@ -739,7 +1107,7 @@ int GModel::readCGNS(const std::string &name)
     int type_hex = 5;
     int type_quad = 3;
     int type_line = 1;
-    int type_pnt = 15;
+    // int type_pnt = 15;
     if (order == 2) {
       type_hex = 12;
       type_line = 8;
@@ -758,33 +1126,34 @@ int GModel::readCGNS(const std::string &name)
     int partition = 0;
     for (int i = 0; i < zoneSizes[3]; i+=order) {
       for (int j = 0; j < zoneSizes[4]; j+=order) {
-	for (int k = 0; k < zoneSizes[5]; k+=order) {
-	  std::vector<MVertex*> vertices;
-	  std::vector<int> ind_i, ind_j, ind_k;
-
-	  getIndices(i, j, k, ind_i, ind_j, ind_k, order);
-
-	  for (int v = 0; v < ind_i.size(); v++) {
-	    vertices.push_back(vertexMap[offset+to1D(ind_i[v], ind_j[v], ind_k[v],   irmax[0], irmax[1], irmax[2])]);
-	  }
-	  MElement* e = createElementMSH(this, num, type_hex, elementary_region,
-					 partition, vertices, elements);
-	  num_elements++;
-	  num++;
-	}
+        for (int k = 0; k < zoneSizes[5]; k+=order) {
+          std::vector<MVertex*> vertices;
+          std::vector<int> ind_i, ind_j, ind_k;
+          
+          getIndices(i, j, k, ind_i, ind_j, ind_k, order);
+          
+          for (size_t v = 0; v < ind_i.size(); v++) {
+            vertices.push_back(vertexMap[offset+to1D(ind_i[v],ind_j[v],ind_k[v],
+                                                     irmax[0],irmax[1],irmax[2])]);
+          }
+          createElementMSH(this, num, type_hex, elementary_region,
+                           partition, vertices, elements);
+          num_elements++;
+          num++;
+        }
       }
     }
 
-    // Create surface mesh
+    // Create surface mesh, remove internal connections and encode periodicity 
+
+    
     std::map<int, std::vector<int*> > forbidden;
 
     int nconnectivity;
     cg_n1to1(index_file, index_base, index_zone, &nconnectivity);
     Msg::Debug("Found %i connectivity zones.", nconnectivity);
     for (int index_section = 1; index_section <= nconnectivity; index_section++) {
-
-      printf("ping\n");
-
+      
       char ConnectionName[30];
       char DonorName[30];
       cgsize_t range[6];
@@ -792,53 +1161,68 @@ int GModel::readCGNS(const std::string &name)
       int transform[3];
       cg_1to1_read(index_file, index_base, index_zone,index_section,
 		   ConnectionName, DonorName, range, donor_range, transform);
-
-
-      // Checking on which face it is
-      int face = 0;
-      if (range[0] == range[3]) {
-	if (range[0] == 1)
-	  face = 4;
-	else
-	  face = 5;
-      } else if (range[1] == range[4]) {
-        if (range[1] == 1)
-	  face = 2;
-	else
-	  face = 3;
-      } else if (range[2] == range[5]) {
-        if (range[2] == 1)
-	  face = 0;
-	else
-	  face = 1;
-      }
-
-      printf("Face %i\n", face);
-
-      int* range_int = new int[6];
-
-      // Do not ignore periodic boundaries when creating elements later on.
+      
+      // --- face indices in the block and in the global geometry
+      
+      int face      = computeCGNSFace(range);
+      int faceIndex = elementary_face + face +  1;
+
+      // --- encode periodic boundary transformation  / connection information
+      
       float RotationCenter[3];
       float RotationAngle[3];
       float Translation[3];
-      if (cg_1to1_periodic_read(index_file, index_base, index_zone, index_section,
-				RotationCenter, RotationAngle, Translation) != CG_NODE_NOT_FOUND) {
-	continue;
-      }
-
 
-      for (int r = 0; r < 6; r++) {
-	range_int[r] = (int)range[r];
-	printf("%i ", range_int[r]);
+      if (cg_1to1_periodic_read(index_file, 
+                                index_base, 
+                                index_zone, 
+                                index_section,
+                                RotationCenter, 
+                                RotationAngle, 
+                                Translation) != CG_NODE_NOT_FOUND) {
+
+        CGNSPeriodic pnew(zoneName,range,
+                          DonorName,donor_range,transform,order,faceIndex,
+                          RotationCenter,RotationAngle,Translation);
+        
+        CGNSPeriodic pinv(pnew.getInverse());
+        CGNSPeriodicSet::iterator pIter = periodicConnections.find(pinv);
+
+        // create a new connection if inverse not found
+        if (pIter == periodicConnections.end()) {          
+          for (size_t ip=0;ip<pnew.getNbPoints();ip++) {
+            int i,j,k;
+            pnew.getTargetIJK(ip,i,j,k);
+            pnew.insertTargetVertex(ip,vertexMap[offset+to1D(i,j,k,
+                                                             irmax[0],
+                                                             irmax[1],
+                                                             irmax[2])]);
+          } 
+          periodicConnections.insert(pnew);
+        }
+        // if inverse is found, we need to complete
+        else { 
+          pIter->sourceFaceId = faceIndex;
+          for (size_t ip=0;ip<pIter->getNbPoints();ip++) {
+            int i,j,k;
+            pIter->getSourceIJK(ip,i,j,k);
+            pIter->insertSourceVertex(ip,vertexMap[offset+to1D(i,j,k,
+                                                               irmax[0],
+                                                               irmax[1],
+                                                               irmax[2])]);
+          }
+        }
       }
-      forbidden[face].push_back(range_int);
+      
+      // --- ignore internal connections
 
-      printf("\npong\n");
+      else {
+        int* range_int = new int[6];
+        for (int r = 0; r < 6; r++) range_int[r] = (int)range[r];
+        forbidden[face].push_back(range_int);
+      } 
     }
 
-
-
-
     for(int face = 0; face < 6; face++) {
       int imin, imax, jmin, jmax, kmin, kmax;
       int igrow = order;
@@ -848,102 +1232,104 @@ int GModel::readCGNS(const std::string &name)
       switch(face) {
       case 0:
        	imin = 0; imax = zoneSizes[3];
-	jmin = 0; jmax = zoneSizes[4];
-	kmin = 0; kmax = 1; kgrow = 0;
-	move[0][0] = 0; move[0][1] = 0;     move[0][2] = igrow; move[0][3] = igrow;
-	move[1][0] = 0; move[1][1] = jgrow; move[1][2] = jgrow; move[1][3] = 0;
-	move[2][0] = 0; move[2][1] = 0;     move[2][2] = 0;     move[2][3] = 0;
-	break;
+        jmin = 0; jmax = zoneSizes[4];
+        kmin = 0; kmax = 1; kgrow = 0;
+        move[0][0] = 0; move[0][1] = 0;     move[0][2] = igrow; move[0][3] = igrow;
+        move[1][0] = 0; move[1][1] = jgrow; move[1][2] = jgrow; move[1][3] = 0;
+        move[2][0] = 0; move[2][1] = 0;     move[2][2] = 0;     move[2][3] = 0;
+        break;
       case 1:
-	imin = 0; imax = zoneSizes[3];
-	jmin = 0; jmax = zoneSizes[4];
-	kmin = zoneSizes[2]-1; kmax = zoneSizes[2]; kgrow = 0;
-	move[0][0] = 0; move[0][1] = igrow; move[0][2] = igrow; move[0][3] = 0;
-	move[1][0] = 0; move[1][1] = 0;     move[1][2] = jgrow; move[1][3] = jgrow;
-	move[2][0] = 0; move[2][1] = 0;     move[2][2] = 0;     move[2][3] = 0;
-	break;
+        imin = 0; imax = zoneSizes[3];
+        jmin = 0; jmax = zoneSizes[4];
+        kmin = zoneSizes[2]-1; kmax = zoneSizes[2]; kgrow = 0;
+        move[0][0] = 0; move[0][1] = igrow; move[0][2] = igrow; move[0][3] = 0;
+        move[1][0] = 0; move[1][1] = 0;     move[1][2] = jgrow; move[1][3] = jgrow;
+        move[2][0] = 0; move[2][1] = 0;     move[2][2] = 0;     move[2][3] = 0;
+        break;
       case 2:
-	imin = 0; imax = zoneSizes[3];
-	jmin = 0; jmax = 1; jgrow = 0;
-	kmin = 0; kmax = zoneSizes[5];
-	move[0][0] = 0; move[0][1] = igrow; move[0][2] = igrow; move[0][3] = 0;
-	move[1][0] = 0; move[1][1] = 0;     move[1][2] = 0; move[1][3] = 0;
-	move[2][0] = 0; move[2][1] = 0;     move[2][2] = kgrow;     move[2][3] = kgrow;
-	break;
+        imin = 0; imax = zoneSizes[3];
+        jmin = 0; jmax = 1; jgrow = 0;
+        kmin = 0; kmax = zoneSizes[5];
+        move[0][0] = 0; move[0][1] = igrow; move[0][2] = igrow; move[0][3] = 0;
+        move[1][0] = 0; move[1][1] = 0;     move[1][2] = 0; move[1][3] = 0;
+        move[2][0] = 0; move[2][1] = 0;     move[2][2] = kgrow;     move[2][3] = kgrow;
+        break;
       case 3:
-	imin = 0; imax = zoneSizes[3];
-	jmin = zoneSizes[1]-1; jmax = zoneSizes[1]; jgrow = 0;
-	kmin = 0; kmax = zoneSizes[5];
-	move[0][0] = 0; move[0][1] = 0; move[0][2] = igrow; move[0][3] = igrow;
-	move[1][0] = 0; move[1][1] = 0;     move[1][2] = 0; move[1][3] = 0;
-	move[2][0] = 0; move[2][1] = kgrow;     move[2][2] = kgrow;     move[2][3] = 0;
-	break;
+        imin = 0; imax = zoneSizes[3];
+        jmin = zoneSizes[1]-1; jmax = zoneSizes[1]; jgrow = 0;
+        kmin = 0; kmax = zoneSizes[5];
+        move[0][0] = 0; move[0][1] = 0; move[0][2] = igrow; move[0][3] = igrow;
+        move[1][0] = 0; move[1][1] = 0;     move[1][2] = 0; move[1][3] = 0;
+        move[2][0] = 0; move[2][1] = kgrow;     move[2][2] = kgrow;     move[2][3] = 0;
+        break;
       case 4:
-	imin = 0; imax = 1; igrow = 0;
-	jmin = 0; jmax = zoneSizes[4];
-	kmin = 0; kmax = zoneSizes[5];
-	move[0][0] = 0; move[0][1] = 0; move[0][2] = 0; move[0][3] = 0;
-	move[1][0] = 0; move[1][1] = 0; move[1][2] = jgrow; move[1][3] = jgrow;
-	move[2][0] = 0; move[2][1] = kgrow;     move[2][2] = kgrow;     move[2][3] = 0;
-	break;
+        imin = 0; imax = 1; igrow = 0;
+        jmin = 0; jmax = zoneSizes[4];
+        kmin = 0; kmax = zoneSizes[5];
+        move[0][0] = 0; move[0][1] = 0; move[0][2] = 0; move[0][3] = 0;
+        move[1][0] = 0; move[1][1] = 0; move[1][2] = jgrow; move[1][3] = jgrow;
+        move[2][0] = 0; move[2][1] = kgrow;     move[2][2] = kgrow;     move[2][3] = 0;
+        break;
       case 5:
-	imin = zoneSizes[0]-1; imax = zoneSizes[0]; igrow = 0;
-	jmin = 0; jmax = zoneSizes[4];
-	kmin = 0; kmax = zoneSizes[5];
-	move[0][0] = 0; move[0][1] = 0; move[0][2] = 0; move[0][3] = 0;
-	move[1][0] = 0; move[1][1] = jgrow; move[1][2] = jgrow; move[1][3] = 0;
-	move[2][0] = 0; move[2][1] = 0;     move[2][2] = kgrow;     move[2][3] = kgrow;
-	break;
+        imin = zoneSizes[0]-1; imax = zoneSizes[0]; igrow = 0;
+        jmin = 0; jmax = zoneSizes[4];
+        kmin = 0; kmax = zoneSizes[5];
+        move[0][0] = 0; move[0][1] = 0; move[0][2] = 0; move[0][3] = 0;
+        move[1][0] = 0; move[1][1] = jgrow; move[1][2] = jgrow; move[1][3] = 0;
+        move[2][0] = 0; move[2][1] = 0;     move[2][2] = kgrow;     move[2][3] = kgrow;
+        break;
       }
-
+      
       GRegion* gr = getRegionByTag(elementary_region);
       elementary_face++;
+      
       num = 1;
       for (int i = imin; i < imax; i += order) {
-	for (int j = jmin; j < jmax;  j += order) {
-	  //printf("Creating surface element\n");
-	  for (int k = kmin; k < kmax; k += order) {
-
-	    bool ok = true;
-	    for (int ff=0; ff < forbidden[face].size(); ff++) {
-	      int* lim = forbidden[face][ff];
-
-	      if ((i >= fmin(lim[0], lim[3])-1 && i < fmax(lim[0], lim[3])-1) || (igrow == 0) ) {
-		if ((j >= fmin(lim[1], lim[4])-1 && j < fmax(lim[1],lim[4])-1) || (jgrow == 0) ) {
-		  if ((k >= fmin(lim[2], lim[5])-1 && k < fmax(lim[2], lim[5])-1) || (kgrow == 0) ) {
-		    ok = false;
-		  }
-		}
-	      }
-	      //if (!ok) continue;
-
-	    }
-	    if (!ok) continue;
-
-	    std::vector<MVertex*> vertices;
-	    std::vector<int> ind_i, ind_j, ind_k;
-
-	    getIndicesQuad(i+move[0][0],i+move[0][1], i+move[0][2], i+move[0][3],
-			   j+move[1][0],j+move[1][1], j+move[1][2], j+move[1][3],
-			   k+move[2][0],k+move[2][1], k+move[2][2], k+move[2][3],
-			   ind_i, ind_j, ind_k, order, face);
-
-	    for (int v = 0; v < ind_i.size(); v++) {
-	      vertices.push_back(vertexMap[offset+to1D(ind_i[v], ind_j[v], ind_k[v],   irmax[0], irmax[1], irmax[2])]);
-	    }
-	    MElement* e = createElementMSH(this, num, type_quad, elementary_face,
-					   partition, vertices, elements);
-	    num_elements++;
-	    num++;
-	  }
-	}
+        for (int j = jmin; j < jmax;  j += order) {
+          //printf("Creating surface element\n");
+          for (int k = kmin; k < kmax; k += order) {
+            
+            bool ok = true;
+            for (size_t ff=0; ff < forbidden[face].size(); ff++) {
+              int* lim = forbidden[face][ff];
+              
+              if ((i >= fmin(lim[0], lim[3])-1 && i < fmax(lim[0], lim[3])-1) || (igrow == 0) ) {
+                if ((j >= fmin(lim[1], lim[4])-1 && j < fmax(lim[1],lim[4])-1) || (jgrow == 0) ) {
+                  if ((k >= fmin(lim[2], lim[5])-1 && k < fmax(lim[2], lim[5])-1) || (kgrow == 0) ) {
+                    ok = false;
+                  }
+                }
+              }
+              //if (!ok) continue;
+              
+            }
+            if (!ok) continue;
+            
+            std::vector<MVertex*> vertices;
+            std::vector<int> ind_i, ind_j, ind_k;
+            
+            getIndicesQuad(i+move[0][0],i+move[0][1], i+move[0][2], i+move[0][3],
+                           j+move[1][0],j+move[1][1], j+move[1][2], j+move[1][3],
+                           k+move[2][0],k+move[2][1], k+move[2][2], k+move[2][3],
+                           ind_i, ind_j, ind_k, order, face);
+            
+            for (size_t v = 0; v < ind_i.size(); v++) {
+              vertices.push_back(vertexMap[offset+to1D(ind_i[v], ind_j[v], ind_k[v],
+                                                       irmax[0], irmax[1], irmax[2])]);
+            }
+            
+            createElementMSH(this, num, type_quad, elementary_face,
+                             partition, vertices, elements);
+            num_elements++;
+            num++;
+          }
+        }
       }
       GFace* gf = getFaceByTag(elementary_face);
-      if (gf)
-	gf->addRegion(gr);
-
-      for (int ff = 0; ff < forbidden[face].size(); ff++)
-	  delete[] forbidden[face][ff];
+      if (gf) gf->addRegion(gr);
+      
+      for (size_t ff = 0; ff < forbidden[face].size(); ff++)
+        delete[] forbidden[face][ff];
     }
   }
 
@@ -954,10 +1340,28 @@ int GModel::readCGNS(const std::string &name)
 
   // associate the correct geometrical entity with each mesh vertex
   _associateEntityWithMeshVertices();
-
   // store the vertices in their associated geometrical entity
   _storeVerticesInEntities(vertexMap);
-
+  
+  // --- now encode the periodic boundaries 
+  
+  CGNSPeriodicSet::iterator pIter = periodicConnections.begin();
+  
+  for (;pIter!=periodicConnections.end();++pIter) {
+    
+    GFace* target = getFaceByTag(pIter->targetFaceId);
+    GFace* source = getFaceByTag(pIter->sourceFaceId);
+    
+    target->setMeshMaster(source,pIter->tfo);
+
+    std::vector<MVertex*>::const_iterator tIter = pIter->targetVertices.begin();
+    std::vector<MVertex*>::const_iterator sIter = pIter->sourceVertices.begin();
+    
+    for (;tIter!=pIter->targetVertices.end();++tIter,++sIter) {
+      target->correspondingVertices[*tIter] = *sIter;
+    }
+  }
+  
   removeDuplicateMeshVertices(1e-8);
   //createTopologyFromMesh();
 
@@ -968,9 +1372,6 @@ int GModel::readCGNS(const std::string &name)
   return 1;
 }
 
-
-
-
 /*******************************************************************************
  *
  * Routine writeCGNS
@@ -1399,7 +1800,9 @@ int get_zone_definition(GModel &model, const int zoneDefinition,
 
 //--Get indices for the zonex
 
+#ifdef _OPENMP
 #pragma omp critical (get_zone_definition)
+#endif
   {
     if(globalZoneIndex >= numZone) status = 1;
     else {
@@ -1491,7 +1894,9 @@ struct ZoneTask
   ZoneTask() : status(0), indexInOwner(0) { }
   void change_status(const int _status)
   {
+#ifdef _OPENMP
 #pragma omp atomic
+#endif
     status = _status;
   }
 };
@@ -1516,10 +1921,10 @@ int write_CGNS_zones(GModel &model, const int zoneDefinition, const int numZone,
 
   int threadsWorking = omp_get_num_threads();
                                         // Semaphore for working threads
-  omp_lock_t threadWLock;
+  // ** omp_lock_t threadWLock;
   std::queue<ZoneTask<DIM>*> zoneQueue; // Queue for zones that have been
                                         // defined and are ready to be written
-  omp_lock_t queueLock;
+  // ** omp_lock_t queueLock;
   // Next two are locked by an omp critical
   int globalZoneIndex = 0;
   PhysGroupMap::const_iterator globalPhysicalIt = group.begin();
@@ -1784,7 +2189,7 @@ int write_CGNS_zones(GModel &model, const int zoneDefinition, const int numZone,
         else {
           PhysGroupMap::const_iterator physicalItBegin;
           PhysGroupMap::const_iterator physicalItEnd;
-          int zoneIndex;
+          // --- int zoneIndex;
           int partition;
           if(get_zone_definition
              (model, zoneDefinition, numZone, options, DIM, group,