From 6af628b3dfdddd279aaa29862925ef69abf8c230 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 16 Oct 2013 19:45:55 +0000
Subject: [PATCH] new PostProcessing.ForceNodeData to force saving NodeData
 datasets, even for potentially discontinuous list-type datasets

---
 Common/Context.h           |   2 +-
 Common/DefaultOptions.h    |   3 +
 Common/Options.cpp         |   7 ++
 Common/Options.h           |   1 +
 Post/PViewData.h           |   5 +-
 Post/PViewDataGModel.h     |   3 +-
 Post/PViewDataGModelIO.cpp |  11 +--
 Post/PViewDataIO.cpp       |   4 +-
 Post/PViewDataList.h       |   3 +-
 Post/PViewDataListIO.cpp   | 140 ++++++++++++++++++++++++-------------
 Post/PViewIO.cpp           |   6 +-
 doc/texinfo/opt_post.texi  |   5 ++
 doc/texinfo/opt_view.texi  |   2 +-
 13 files changed, 131 insertions(+), 61 deletions(-)

diff --git a/Common/Context.h b/Common/Context.h
index 2c21f2c4ee..14337412ec 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -229,7 +229,7 @@ class CTX {
   struct{
     int draw, link, horizontalScales;
     int smooth, animCycle, animStep, combineTime, combineRemoveOrig;
-    int fileFormat, plugins;
+    int fileFormat, plugins, forceNodeData;
     double animDelay;
   }post;
   // solver options
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 2b131522be..a54ea64ec1 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1226,6 +1226,9 @@ StringXNumber PostProcessingOptions_Number[] = {
   { F|O, "CombineRemoveOriginal" , opt_post_combine_remove_orig , 1. ,
     "Remove original views after a Combine operation" },
 
+  { F|O, "ForceNodeData" , opt_post_force_node_data , 0. ,
+    "Try to force saving datasets as NodeData" },
+
   { F|O, "Format" , opt_post_file_format , 10. ,
     "Default file format for post-processing views (0=ASCII view, 1=binary "
     "view, 2=parsed view, 3=STL triangulation, 4=raw text, 5=Gmsh mesh, 6=MED file, "
diff --git a/Common/Options.cpp b/Common/Options.cpp
index f980418be9..378842645f 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -6293,6 +6293,13 @@ double opt_post_file_format(OPT_ARGS_NUM)
   return CTX::instance()->post.fileFormat;
 }
 
+double opt_post_force_node_data(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->post.forceNodeData = (int)val;
+  return CTX::instance()->post.forceNodeData;
+}
+
 double opt_view_nb_timestep(OPT_ARGS_NUM)
 {
 #if defined(HAVE_POST)
diff --git a/Common/Options.h b/Common/Options.h
index 1007a85cad..7829fa9b84 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -519,6 +519,7 @@ double opt_post_combine_remove_orig(OPT_ARGS_NUM);
 double opt_post_plugins(OPT_ARGS_NUM);
 double opt_post_nb_views(OPT_ARGS_NUM);
 double opt_post_file_format(OPT_ARGS_NUM);
+double opt_post_force_node_data(OPT_ARGS_NUM);
 double opt_view_nb_timestep(OPT_ARGS_NUM);
 double opt_view_nb_non_empty_timestep(OPT_ARGS_NUM);
 double opt_view_timestep(OPT_ARGS_NUM);
diff --git a/Post/PViewData.h b/Post/PViewData.h
index b572b48328..a4ef4f1bb3 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -270,8 +270,9 @@ class PViewData {
   virtual bool writePOS(const std::string &fileName, bool binary=false,
                         bool parsed=true, bool append=false);
   virtual bool writeMSH(const std::string &fileName, double version=2.2, bool binary=false,
-                        bool savemesh=true, bool multipleView=false,
-                        int partitionNum=0, bool saveInterpolationMatrices=true);
+                        bool saveMesh=true, bool multipleView=false,
+                        int partitionNum=0, bool saveInterpolationMatrices=true,
+                        bool forceNodeData=false);
   virtual bool writeMED(const std::string &fileName);
   virtual bool toVector(std::vector<std::vector<double> > &vec);
   virtual bool fromVector(const std::vector<std::vector<double> > &vec);
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index 8eab94d303..e1d94fdfe8 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -251,7 +251,8 @@ class PViewDataGModel : public PViewData {
                const std::string &interpolationScheme);
   virtual bool writeMSH(const std::string &fileName, double version=2.2, bool binary=false,
                         bool savemesh=true, bool multipleView=false,
-                        int partitionNum=0, bool saveInterpolationMatrices=true);
+                        int partitionNum=0, bool saveInterpolationMatrices=true,
+                        bool forceNodeData=false);
   bool readMED(const std::string &fileName, int fileIndex);
   bool writeMED(const std::string &fileName);
 };
diff --git a/Post/PViewDataGModelIO.cpp b/Post/PViewDataGModelIO.cpp
index 6efae75ded..acfc0df79f 100644
--- a/Post/PViewDataGModelIO.cpp
+++ b/Post/PViewDataGModelIO.cpp
@@ -133,8 +133,8 @@ bool PViewDataGModel::readMSH(const std::string &viewName, const std::string &fi
 }
 
 bool PViewDataGModel::writeMSH(const std::string &fileName, double version, bool binary,
-                               bool savemesh, bool multipleView, int partitionNum,
-                               bool saveInterpolationMatrices)
+                               bool saveMesh, bool multipleView, int partitionNum,
+                               bool saveInterpolationMatrices, bool forceNodeData)
 {
   if(_steps.empty()) return true;
 
@@ -143,11 +143,14 @@ bool PViewDataGModel::writeMSH(const std::string &fileName, double version, bool
     return false;
   }
 
+  if(forceNodeData && _type != NodeData){
+    Msg::Warning("Cannot force NodeData for this dataset: saving native data");
+  }
+
   GModel *model = _steps[0]->getModel();
 
-  bool writeNodesAndElements = savemesh;
   FILE *fp;
-  if(writeNodesAndElements){
+  if(saveMesh){
     if(!model->writeMSH(fileName, version, binary, false, false, 1.0, 0,
                         0, multipleView)) return false;
     // append data
diff --git a/Post/PViewDataIO.cpp b/Post/PViewDataIO.cpp
index 9e3eac75e8..bff69ef56c 100644
--- a/Post/PViewDataIO.cpp
+++ b/Post/PViewDataIO.cpp
@@ -179,8 +179,8 @@ bool PViewData::writePOS(const std::string &fileName, bool binary, bool parsed,
 }
 
 bool PViewData::writeMSH(const std::string &fileName, double version, bool binary,
-                         bool savemesh, bool multipleView, int partitionNum,
-                         bool saveInterpolationMatrices)
+                         bool saveMesh, bool multipleView, int partitionNum,
+                         bool saveInterpolationMatrices, bool forceNodeData)
 {
   Msg::Error("MSH export not implemented for this view type");
   return false;
diff --git a/Post/PViewDataList.h b/Post/PViewDataList.h
index 5b2dd2abb1..dd2d763a29 100644
--- a/Post/PViewDataList.h
+++ b/Post/PViewDataList.h
@@ -128,7 +128,8 @@ class PViewDataList : public PViewData {
                 bool append=false);
   virtual bool writeMSH(const std::string &fileName, double version=2.2, bool binary=false,
                         bool savemesh=true, bool multipleView=false,
-                        int partitionNum=0, bool saveInterpolationMatrices=true);
+                        int partitionNum=0, bool saveInterpolationMatrices=true,
+                        bool forceNodeData=false);
   virtual void importLists(int N[24], std::vector<double> *V[24]);
   virtual void getListPointers(int N[24], std::vector<double> *V[24]);
 };
diff --git a/Post/PViewDataListIO.cpp b/Post/PViewDataListIO.cpp
index 6ad08a7f14..03dda33b1c 100644
--- a/Post/PViewDataListIO.cpp
+++ b/Post/PViewDataListIO.cpp
@@ -450,9 +450,21 @@ static void createVertices(std::vector<double> &list, int nbelm, int nbnod,
   }
 }
 
+class nodeData{
+public:
+  int nbnod;
+  int nod;
+  double *data;
+  nodeData()
+    : nbnod(0), nod(0), data(0) {}
+  nodeData(int _nbnod, int _nod, double *_data)
+    : nbnod(_nbnod), nod(_nod), data(_data) {}
+};
+
 static void createElements(std::vector<double> &list, int nbelm, int nbnod,
                            MVertexPositionSet &pos, std::vector<MElement*> &elements,
-                           double eps, int type)
+                           double eps, int type,
+                           std::map<MVertex*, nodeData> *vertexData)
 {
   if(!nbelm) return;
   int t = 0;
@@ -519,16 +531,20 @@ static void createElements(std::vector<double> &list, int nbelm, int nbnod,
     double *y = &list[i + nbnod];
     double *z = &list[i + 2 * nbnod];
     std::vector<MVertex*> verts(nbnod);
-    for(int j = 0; j < nbnod; j++)
+    for(int j = 0; j < nbnod; j++){
       verts[j] = pos.find(x[j], y[j], z[j], eps);
+      if(vertexData)
+        (*vertexData)[verts[j]] = nodeData(nbnod, j, &list[i + 3 * nbnod]);
+    }
     MElement *e = factory.create(t, verts);
     elements.push_back(e);
   }
 }
 
 bool PViewDataList::writeMSH(const std::string &fileName, double version, bool binary,
-                             bool savemesh, bool multipleView,
-                             int partitionNum, bool saveInterpolationMatrices)
+                             bool saveMesh, bool multipleView,
+                             int partitionNum, bool saveInterpolationMatrices,
+                             bool forceNodeData)
 {
   if(_adaptive){
     Msg::Warning("Writing adapted dataset (will only export current time step)");
@@ -557,39 +573,45 @@ bool PViewDataList::writeMSH(const std::string &fileName, double version, bool b
   }
   MVertexPositionSet pos(vertices);
 
+  std::map<MVertex *, nodeData> vertexData;
+
   for(int i = 0; i < 24; i++){
     std::vector<double> *list = 0;
     int *numEle = 0, numComp, numNodes;
     int typ = _getRawData(i, &list, &numEle, &numComp, &numNodes);
-    createElements(*list, *numEle, numNodes, pos, elements, eps, typ);
+    createElements(*list, *numEle, numNodes, pos, elements, eps, typ,
+                   forceNodeData ? &vertexData : 0);
   }
 
-  int num = 0;
+  int globalNumNodes = 0;
   for(unsigned int i = 0; i < vertices.size(); i++)
     if(vertices[i]->getIndex() < 0)
-      vertices[i]->setIndex(++num);
+      vertices[i]->setIndex(++globalNumNodes);
 
   fprintf(fp, "$MeshFormat\n2.2 0 8\n$EndMeshFormat\n");
-  fprintf(fp, "$Nodes\n");
-  fprintf(fp, "%d\n", num);
-  for(unsigned int i = 0; i < vertices.size(); i++){
-    MVertex *v = vertices[i];
-    if(v->getIndex() > 0)
-      fprintf(fp, "%d %.16g %.16g %.16g\n", v->getIndex(), v->x(), v->y(), v->z());
-  }
-  fprintf(fp, "$EndNodes\n");
-
-  fprintf(fp, "$Elements\n");
-  fprintf(fp, "%d\n", (int)elements.size());
-  for(unsigned int i = 0; i < elements.size(); i++){
-    if(version > 2.2)
-      Msg::Warning("Unable to write file in version '%g': using version 2.2",
-                   version);
-    elements[i]->writeMSH2(fp, 2.2, false, i + 1);
-  }
-  fprintf(fp, "$EndElements\n");
-
-  if(saveInterpolationMatrices && haveInterpolationMatrices()){
+
+  if(saveMesh){
+    fprintf(fp, "$Nodes\n");
+    fprintf(fp, "%d\n", globalNumNodes);
+    for(unsigned int i = 0; i < vertices.size(); i++){
+      MVertex *v = vertices[i];
+      if(v->getIndex() > 0)
+        fprintf(fp, "%d %.16g %.16g %.16g\n", v->getIndex(), v->x(), v->y(), v->z());
+    }
+    fprintf(fp, "$EndNodes\n");
+
+    fprintf(fp, "$Elements\n");
+    fprintf(fp, "%d\n", (int)elements.size());
+    for(unsigned int i = 0; i < elements.size(); i++){
+      if(version > 2.2)
+        Msg::Warning("Unable to write file in version '%g': using version 2.2",
+                     version);
+      elements[i]->writeMSH2(fp, 2.2, false, i + 1);
+    }
+    fprintf(fp, "$EndElements\n");
+  }
+
+  if(saveInterpolationMatrices && haveInterpolationMatrices() && !forceNodeData){
     fprintf(fp, "$InterpolationScheme\n");
     fprintf(fp, "\"INTERPOLATION_SCHEME\"\n");
     fprintf(fp, "%d\n", (int)_interpolation.size());
@@ -612,37 +634,61 @@ bool PViewDataList::writeMSH(const std::string &fileName, double version, bool b
   }
 
   for(int ts = 0; ts < NbTimeStep; ts++){
-    fprintf(fp, "$ElementNodeData\n");
-    if(saveInterpolationMatrices && haveInterpolationMatrices())
+    if(forceNodeData)
+      fprintf(fp, "$NodeData\n");
+    else
+      fprintf(fp, "$ElementNodeData\n");
+    if(saveInterpolationMatrices && haveInterpolationMatrices() && !forceNodeData)
       fprintf(fp, "2\n\"%s\"\n\"INTERPOLATION_SCHEME\"\n", getName().c_str());
     else
       fprintf(fp, "1\n\"%s\"\n", getName().c_str());
     fprintf(fp, "1\n%.16g\n", getTime(ts));
+    int size = forceNodeData ? globalNumNodes : (int)elements.size();
     if(partitionNum)
-      fprintf(fp, "4\n%d\n%d\n%d\n%d\n", ts, numComponents, (int)elements.size(),
+      fprintf(fp, "4\n%d\n%d\n%d\n%d\n", ts, numComponents, size,
               partitionNum);
     else
-      fprintf(fp, "3\n%d\n%d\n%d\n", ts, numComponents, (int)elements.size());
-    num = 0;
-    for(int i = 0; i < 24; i++){
-      std::vector<double> *list = 0;
-      int *numEle = 0, numComp, numNodes;
-      int typ = _getRawData(i, &list, &numEle, &numComp, &numNodes);
-      if(*numEle){
-        int mult = numNodes;
-        if(_interpolation.count(typ))
-          mult = _interpolation[typ][0]->size1();
-        int nb = list->size() / *numEle;
-        for(unsigned int i = 0; i < list->size(); i += nb){
-          double *v = &(*list)[i + 3 * numNodes];
-          fprintf(fp, "%d %d", ++num, mult);
-          for(int j = 0; j < numComponents * mult; j++)
-            fprintf(fp, " %.16g", v[numComponents * mult * ts + j]);
+      fprintf(fp, "3\n%d\n%d\n%d\n", ts, numComponents, size);
+
+    if(forceNodeData){
+      for(unsigned int i = 0; i < vertices.size(); i++){
+        MVertex *v = vertices[i];
+        if(v->getIndex() > 0){
+          fprintf(fp, "%d", v->getIndex());
+          int nbnod = vertexData[v].nbnod;
+          int nod = vertexData[v].nod;
+          double *d = vertexData[v].data;
+          for(int j = 0; j < numComponents; j++)
+            fprintf(fp, " %.16g",
+                    d[numComponents * nbnod * ts + numComponents * nod + j]);
           fprintf(fp, "\n");
         }
       }
+      fprintf(fp, "$EndNodeData\n");
+    }
+    else{
+      int num = 0;
+      for(int i = 0; i < 24; i++){
+        std::vector<double> *list = 0;
+        int *numEle = 0, numComp, numNodes;
+        int typ = _getRawData(i, &list, &numEle, &numComp, &numNodes);
+        if(*numEle){
+          int mult = numNodes;
+          if(_interpolation.count(typ))
+            mult = _interpolation[typ][0]->size1();
+          int nb = list->size() / *numEle;
+          for(unsigned int i = 0; i < list->size(); i += nb){
+            double *v = &(*list)[i + 3 * numNodes];
+            fprintf(fp, "%d %d", ++num, mult);
+            for(int j = 0; j < numComponents * mult; j++)
+              fprintf(fp, " %.16g", v[numComponents * mult * ts + j]);
+            fprintf(fp, "\n");
+          }
+        }
+      }
+      fprintf(fp, "$EndElementNodeData\n");
     }
-    fprintf(fp, "$EndElementNodeData\n");
+
   }
 
   fclose(fp);
diff --git a/Post/PViewIO.cpp b/Post/PViewIO.cpp
index df3e0edaee..c0f8f972ce 100644
--- a/Post/PViewIO.cpp
+++ b/Post/PViewIO.cpp
@@ -295,7 +295,8 @@ bool PView::write(const std::string &fileName, int format, bool append)
   case 3: ret = _data->writeSTL(fileName); break;
   case 4: ret = _data->writeTXT(fileName); break;
   case 5: ret = _data->writeMSH(fileName, CTX::instance()->mesh.mshFileVersion,
-                                CTX::instance()->mesh.binary); break;
+                                CTX::instance()->mesh.binary, true, false,
+                                0, true, CTX::instance()->post.forceNodeData); break;
   case 6: ret = _data->writeMED(fileName); break;
   case 10:
     {
@@ -306,7 +307,8 @@ bool PView::write(const std::string &fileName, int format, bool append)
         ret = _data->writeSTL(fileName);
       else if(ext == ".msh")
         ret = _data->writeMSH(fileName, CTX::instance()->mesh.mshFileVersion,
-                              CTX::instance()->mesh.binary);
+                              CTX::instance()->mesh.binary, true, false,
+                              0, true, CTX::instance()->post.forceNodeData);
       else if(ext == ".med")
         ret = _data->writeMED(fileName);
       else
diff --git a/doc/texinfo/opt_post.texi b/doc/texinfo/opt_post.texi
index 0534f4c266..7a1b034137 100644
--- a/doc/texinfo/opt_post.texi
+++ b/doc/texinfo/opt_post.texi
@@ -24,6 +24,11 @@ Remove original views after a Combine operation@*
 Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
+@item PostProcessing.ForceNodeData
+Try to force saving datasets as NodeData@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
 @item PostProcessing.Format
 Default file format for post-processing views (0=ASCII view, 1=binary view, 2=parsed view, 3=STL triangulation, 4=raw text, 5=Gmsh mesh, 6=MED file, 10=automatic)@*
 Default value: @code{10}@*
diff --git a/doc/texinfo/opt_view.texi b/doc/texinfo/opt_view.texi
index 81a5db1afd..f4d30b6676 100644
--- a/doc/texinfo/opt_view.texi
+++ b/doc/texinfo/opt_view.texi
@@ -216,7 +216,7 @@ Saved in: @code{General.OptionsFileName}
 
 @item View.CenterGlyphs
 Center glyphs (arrows, numbers, etc.)? (0=left, 1=centered, 2=right)@*
-Default value: @code{0}@*
+Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
 @item View.Clip
-- 
GitLab