diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2811157548c3e93532c8d78237af09659ca1938b..535bb6112f5507b72a099ee90f0b1b944a2709f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,7 +81,6 @@ set(GMSH_API
   Solver/dofManager.h Solver/femTerm.h Solver/laplaceTerm.h Solver/elasticityTerm.h
     Solver/linearSystem.h Solver/linearSystemGMM.h Solver/linearSystemCSR.h 
     Solver/linearSystemFull.h Solver/elasticitySolver.h
-Solver/c0DgPlateSolver.h 
   Post/PView.h Post/PViewData.h Plugin/PluginManager.h
   Graphics/drawContext.h
   contrib/kbipack/gmp_normal_form.h contrib/kbipack/gmp_matrix.h 
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index b0c0db81d442b4de2caad31494b621a978241cc2..eff51558df748c26d7e1052f5ee6b7189ba3bd8e 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -350,6 +350,7 @@ int GModel::readMSH(const std::string &name)
       if(!fgets(str, sizeof(str), fp)) return 0;
       int numElements;
       std::map<int, MElement*> parents;
+      std::set<MElement*> parentsOwned;
       sscanf(str, "%d", &numElements);
       Msg::Info("%d elements", numElements);
       Msg::ResetProgressMeter();
@@ -367,7 +368,6 @@ int GModel::readMSH(const std::string &name)
           else{
             int numTags;
             if(fscanf(fp, "%d %d %d", &num, &type, &numTags) != 3) return 0;
-            std::vector<int> tags(numTags);
             int numPartitions = 0;
             for(int j = 0; j < numTags; j++){
               int tag;
@@ -375,9 +375,9 @@ int GModel::readMSH(const std::string &name)
               if(j == 0) physical = tag;
               else if(j == 1) elementary = tag;
               else if(version < 2.2 && j == 2) partition = tag;
-              else if(version >= 2.2 && j == 2) numPartitions = tag;
+              else if(version >= 2.2 && j == 2 && numTags > 3) numPartitions = tag;
               else if(version >= 2.2 && j == 3) partition = tag;
-              else if(j >= 4 && j < 4 + numPartitions) ghosts.push_back(-tag);
+              else if(j >= 4 && j < 4 + numPartitions - 1) ghosts.push_back(-tag);
               else if(j == numTags - 1) parent = tag;
             }
             if(!(numVertices = MElement::getInfoMSH(type))) {
@@ -407,7 +407,12 @@ int GModel::readMSH(const std::string &name)
               else Msg::Error("Parent element %d not found", parent);
             }
             else p = parents.find(parent)->second;
-            e->setParent(p);
+            if(parentsOwned.find(p) == parentsOwned.end()) {
+              e->setParent(p, true);
+              parentsOwned.insert(p);
+            }
+            else 
+              e->setParent(p, false);
           }
           if(numElements > 100000)
             Msg::ProgressMeter(i + 1, numElements, "Reading elements");
@@ -432,9 +437,13 @@ int GModel::readMSH(const std::string &name)
             int num = data[0];
             int physical = (numTags > 0) ? data[1] : 0;
             int elementary = (numTags > 1) ? data[2] : 0;
-            int numPartitions = (version >= 2.2 && numTags > 2) ? data[3] : 0;
+            int numPartitions = (version >= 2.2 && numTags > 3) ? data[3] : 0;
             int partition = (version < 2.2 && numTags > 2) ? data[3] : 
               (version >= 2.2 && numTags > 3) ? data[4] : 0;
+            int parent = (version < 2.2 && numTags > 3) || 
+              (version >= 2.2 && numPartitions && numTags > 3 + numPartitions) ||
+              (version >= 2.2 && !numPartitions && numTags > 2) ?
+              data[numTags] : 0;
             int *indices = &data[numTags + 1];
             std::vector<MVertex*> vertices;
             if(vertexVector.size()){
@@ -448,6 +457,21 @@ int GModel::readMSH(const std::string &name)
             if(numPartitions > 1)
               for(int j = 0; j < numPartitions - 1; j++)
                 _ghostCells.insert(std::pair<MElement*, short>(e, -data[5 + j]));
+            if(parent) {
+              MElement *p = 0;
+              if(parents.find(parent) == parents.end()){
+                p = getParent(parent, e->getDim(), elements);
+                if(p) parents[parent] = p;
+                else Msg::Error("Parent element %d not found", parent);
+              }
+              else p = parents.find(parent)->second;
+              if(parentsOwned.find(p) == parentsOwned.end()) {
+                e->setParent(p, true);
+                parentsOwned.insert(p);
+              }
+              else 
+                e->setParent(p, false);
+            }
             if(numElements > 100000)
               Msg::ProgressMeter(numElementsPartial + i + 1, numElements,
                                  "Reading elements");
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 082a3841081be467c6fcb43c6677b341dd36045f..026b4b419ce089f07b4a087b6a00e3e7feb62302 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -403,23 +403,29 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
   // if necessary, change the ordering of the vertices to get positive
   // volume
   setVolumePositive();
-  int n = getNumVertices();
+  int n = getNumVerticesForMSH();
+  int par = (parentNum) ? 1 : 0;
+  bool poly = (type == MSH_POLYG_ || type == MSH_POLYH_);
 
   if(!binary){
     fprintf(fp, "%d %d", num ? num : _num, type);
     if(version < 2.0)
       fprintf(fp, " %d %d %d", abs(physical), elementary, n);
     else if(!_partition)
-      fprintf(fp, " 2 %d %d", abs(physical), elementary);
+      fprintf(fp, " %d %d %d", 2 + par, abs(physical), elementary);
     else if(!ghosts)
-      fprintf(fp, " 4 %d %d 1 %d", abs(physical), elementary, _partition);
+      fprintf(fp, " %d %d %d 1 %d", 4 + par, abs(physical), elementary, _partition);
     else{
       int numGhosts = ghosts->size();
-      fprintf(fp, " %d %d %d %d %d", 4 + numGhosts, abs(physical), elementary, 
+      fprintf(fp, " %d %d %d %d %d", 4 + numGhosts + par, abs(physical), elementary, 
               1 + numGhosts, _partition);
       for(unsigned int i = 0; i < ghosts->size(); i++)
         fprintf(fp, " %d", -(*ghosts)[i]);
     }
+    if(version >= 2.0 && parentNum)
+      fprintf(fp, " %d", parentNum);
+    if(version >= 2.0 && poly)
+      fprintf(fp, " %d", n);
   }
   else{
     int numTags, numGhosts = 0;
@@ -429,6 +435,7 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
       numGhosts = ghosts->size();
       numTags = 4 + numGhosts;
     }
+    numTags += par;
     // we write elements in blobs of single elements; this will lead
     // to suboptimal reads, but it's much simpler when the number of
     // tags change from element to element (third-party codes can
@@ -438,14 +445,14 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
                     1 + numGhosts, _partition};
     if(ghosts)
       for(int i = 0; i < numGhosts; i++) blob[8 + i] = -(*ghosts)[i];
+    if(par) blob[8 + numGhosts] = par;
+    if(poly) Msg::Error("Unable to write polygons/polyhedra in binary files.");
     fwrite(blob, sizeof(int), 4 + numTags, fp);
   }
 
   if(physical < 0) revert();
 
-  int verts[60];
-  for(int i = 0; i < n; i++)
-    verts[i] = getVertex(i)->getIndex();
+  int *verts = getVerticesIdForMSH();
 
   if(!binary){
     for(int i = 0; i < n; i++)
@@ -457,6 +464,8 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num,
   }
 
   if(physical < 0) revert();
+
+  delete [] verts;
 }
 
 void MElement::writePOS(FILE *fp, bool printElementary, bool printElementNumber,
@@ -764,6 +773,15 @@ int MElement::getInfoMSH(const int typeMSH, const char **const name)
   }
 }
 
+int *MElement::getVerticesIdForMSH()
+{
+  int n = getNumVerticesForMSH();
+  int *verts = new int[n];
+  for(int i = 0; i < n; i++)
+    verts[i] = getVertex(i)->getIndex();
+  return verts;
+}
+
 MElement *MElementFactory::create(int type, std::vector<MVertex*> &v,
                                   int num, int part)
 {
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 9292dee6071a44253ee83bb445d426ecf163a2fb..e026ace7c606ef147bfebcd7ce8dfc9305e244a3 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -152,7 +152,7 @@ class MElement
 
   // get parent and children for hierarchial grids
   virtual MElement *getParent() const { return NULL; }
-  virtual void setParent(MElement *p) {}
+  virtual void setParent(MElement *p, bool owner = false) {}
   virtual int getNumChildren() const { return 0; }
   virtual MElement *getChild(int i) const { return NULL; }
   virtual bool ownsParent() const { return false; }
@@ -274,6 +274,8 @@ class MElement
   // return the number of vertices, as well as the element name if
   // 'name' != 0
   static int getInfoMSH(const int typeMSH, const char **const name=0);
+  virtual int getNumVerticesForMSH() { return getNumVertices(); }
+  virtual int *getVerticesIdForMSH();
   static void registerBindings(binding *b);
 };
 
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index 6fa792afbb74ab2002d2604f53d2c4bdb82bc8da..e26e93cf5d3cf1cdfe5e6d902ba0af61533708db 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -136,57 +136,6 @@ void MPolyhedron::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = _intpt;
 }
 
-void MPolyhedron::writeMSH(FILE *fp, double version, bool binary, int num,
-                           int elementary, int physical, int parentNum,
-                           std::vector<short> *ghosts)
-{
-  int type = getTypeForMSH();
-
-  if(!type) return;
-
-  // if necessary, change the ordering of the vertices to get positive
-  // volume
-  setVolumePositive();
-  int n = _parts.size() * 4;
-  int numE = getNum();
-  int partE = getPartition();
-
-  if(!binary){
-    fprintf(fp, "%d %d", num ? num : numE, type);
-    if(version < 2.0)
-      fprintf(fp, " %d %d", abs(physical), elementary);
-    else {
-      if(parentNum)
-        fprintf(fp, " 5 %d %d 1 %d %d", abs(physical), elementary, partE, parentNum);
-      else
-        fprintf(fp, " 4 %d %d 1 %d", abs(physical), elementary, partE);
-    }
-  }
-  else{
-    Msg::Error("Binary output not coded for polyhedra");
-  }
-
-  if(physical < 0) revert();
-
-  fprintf(fp, " %d", n);
-  int *verts = new int[n];
-  for(unsigned int i = 0; i < _parts.size(); i++)
-    for(int j = 0; j < 4; j++)
-      verts[i * 4 + j] = _parts[i]->getVertex(j)->getIndex();
-
-  if(!binary){
-    for(int i = 0; i < n; i++)
-      fprintf(fp, " %d", verts[i]);
-    fprintf(fp, "\n");
-  }
-  else{
-    fwrite(verts, sizeof(int), n, fp);
-  }
-
-  if(physical < 0) revert();
-  delete [] verts;
-}
-
 //------------------------------------------- MPolygon ------------------------------
 
 void MPolygon::_initVertices()
@@ -274,57 +223,6 @@ void MPolygon::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = _intpt;
 }
 
-void MPolygon::writeMSH(FILE *fp, double version, bool binary, int num,
-                        int elementary, int physical, int parentNum,
-                        std::vector<short> *ghosts)
-{
-  int type = getTypeForMSH();
-
-  if(!type) return;
-
-  // if necessary, change the ordering of the vertices to get positive
-  // volume
-  setVolumePositive();
-  int n = _parts.size() * 3;
-  int numE = getNum();
-  int partE = getPartition();
-
-  if(!binary){
-    fprintf(fp, "%d %d", num ? num : numE, type);
-    if(version < 2.0)
-      fprintf(fp, " %d %d", abs(physical), elementary);
-    else {
-      if(parentNum)
-        fprintf(fp, " 5 %d %d 1 %d %d", abs(physical), elementary, partE, parentNum);
-      else
-        fprintf(fp, " 4 %d %d 1 %d", abs(physical), elementary, partE);
-    }
-  }
-  else{
-    Msg::Error("Binary output not coded for polygons");
-  }
-
-  if(physical < 0) revert();
-
-  fprintf(fp, " %d", n);
-  int *verts = new int[n];
-  for(unsigned int i = 0; i < _parts.size(); i++)
-    for(int j = 0; j < 3; j++)
-      verts[i * 3 + j] = _parts[i]->getVertex(j)->getIndex();
-
-  if(!binary){
-    for(int i = 0; i < n; i++)
-      fprintf(fp, " %d", verts[i]);
-    fprintf(fp, "\n");
-  }
-  else{
-    fwrite(verts, sizeof(int), n, fp);
-  }
-
-  if(physical < 0) revert();
-  delete [] verts;
-}
-
 //----------------------------------- MTriangleBorder ------------------------------
 
 void MTriangleBorder::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index dc4da84e41c0ef9edcb867764aa5298f6dff67ed..438ab40c99c41b549b643189319162ba689c8efd 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -97,6 +97,16 @@ class MPolyhedron : public MElement {
   }
   virtual int getType() const { return TYPE_POLYH; }
   virtual int getTypeForMSH() const { return MSH_POLYH_; }
+  virtual void revert()
+  {
+    for(int i = 0; i < _parts.size(); i++)
+      _parts[i]->revert();
+    _vertices.clear();
+    _innerVertices.clear();
+    _edges.clear();
+    _faces.clear();
+    _init();
+  }
   virtual double getVolume()
   {
     double vol = 0;
@@ -123,14 +133,21 @@ class MPolyhedron : public MElement {
   }
   virtual bool isInside(double u, double v, double w);
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
-  virtual void writeMSH(FILE *fp, double version=1.0, bool binary=false,
-                        int num=0, int elementary=1, int physical=1,
-                        int parentNum=0, std::vector<short> *ghosts=0);
   virtual MElement *getParent() const { return _orig; }
-  virtual void setParent(MElement *p) { _orig = p; }
+  virtual void setParent(MElement *p, bool owner = false) { _orig = p; _owner = owner; }
   virtual int getNumChildren() const { return _parts.size(); }
   virtual MElement *getChild(int i) const { return _parts[i]; }
   virtual bool ownsParent() const { return _owner; }
+  virtual int getNumVerticesForMSH() {return _parts.size() * 4;}
+  virtual int *getVerticesIdForMSH()
+  {
+    int n = getNumVerticesForMSH();
+    int *verts = new int [n];
+    for(unsigned int i = 0; i < _parts.size(); i++)
+      for(int j = 0; j < 4; j++)
+        verts[i * 4 + j] = _parts[i]->getVertex(j)->getIndex();
+    return verts;
+  }
 };
 
 class MPolygon : public MElement {
@@ -208,6 +225,15 @@ class MPolygon : public MElement {
   }
   virtual int getType() const { return TYPE_POLYG; }
   virtual int getTypeForMSH() const { return MSH_POLYG_; }
+  virtual void revert()
+  {
+    for(int i = 0; i < _parts.size(); i++)
+      _parts[i]->revert();
+    _vertices.clear();
+    _innerVertices.clear();
+    _edges.clear();
+    _initVertices();
+  }
   virtual const polynomialBasis* getFunctionSpace(int order=-1) const 
   {
     return _orig->getFunctionSpace(order);
@@ -226,14 +252,21 @@ class MPolygon : public MElement {
   }
   virtual bool isInside(double u, double v, double w);
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
-  virtual void writeMSH(FILE *fp, double version=1.0, bool binary=false,
-                        int num=0, int elementary=1, int physical=1,
-                        int parentNum=0, std::vector<short> *ghosts=0);
   virtual MElement *getParent() const { return _orig; }
-  virtual void setParent(MElement *p) { _orig = p; }
+  virtual void setParent(MElement *p, bool owner = false) { _orig = p; _owner = owner; }
   virtual int getNumChildren() const { return _parts.size(); }
   virtual MElement *getChild(int i) const { return _parts[i]; }
   virtual bool ownsParent() const { return _owner; }
+  virtual int getNumVerticesForMSH() {return _parts.size() * 3;}
+  virtual int *getVerticesIdForMSH()
+  {
+    int n = getNumVerticesForMSH();
+    int *verts = new int[n];
+    for(unsigned int i = 0; i < _parts.size(); i++)
+      for(int j = 0; j < 3; j++)
+        verts[i * 3 + j] = _parts[i]->getVertex(j)->getIndex();
+    return verts;
+  }
 };
 
 class MTriangleBorder : public MTriangle {