From 2e163534d8a425241d13c6f7da35eefd462de9a7 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 19 May 2010 09:25:41 +0000
Subject: [PATCH] - speedup reading of multi-step/partition .msh datasets -
 Plugin(Skin) now works on adapted datasets - addData() should now also work
 for high order datasets [we still need to   add a new type+ref to FS in
 PViewDataGModel]

---
 Plugin/Skin.cpp            |  2 +-
 Post/PView.cpp             |  8 ++---
 Post/PViewData.cpp         |  2 +-
 Post/PViewData.h           |  2 +-
 Post/PViewDataGModel.cpp   | 62 ++++++++++++++++++++------------------
 Post/PViewDataGModel.h     |  7 ++---
 Post/PViewDataGModelIO.cpp | 33 ++++++++++----------
 Post/PViewDataList.cpp     |  2 +-
 Post/PViewDataList.h       |  2 +-
 9 files changed, 61 insertions(+), 59 deletions(-)

diff --git a/Plugin/Skin.cpp b/Plugin/Skin.cpp
index 5335388e8a..a9f32f9639 100644
--- a/Plugin/Skin.cpp
+++ b/Plugin/Skin.cpp
@@ -143,7 +143,7 @@ PView *GMSH_SkinPlugin::execute(PView *v)
 
   PView *v1 = getView(iView, v);
   if(!v1) return v;
-  PViewData *data1 = v1->getData();
+  PViewData *data1 = v1->getData(true); // get adaptive data if available
 
   if(data1->hasMultipleMeshes()){
     Msg::Error("Skin plugin cannot be applied to multi-mesh views");
diff --git a/Post/PView.cpp b/Post/PView.cpp
index f580e63d8c..3135456160 100644
--- a/Post/PView.cpp
+++ b/Post/PView.cpp
@@ -112,7 +112,7 @@ PView::PView(std::string xname, std::string yname,
 
 PView::PView(std::string name, std::string type, 
              GModel *model, std::map<int, std::vector<double> > &data,
-             double time, int numC)
+             double time, int numComp)
 {
   _init();
   PViewDataGModel::DataType t;
@@ -127,7 +127,7 @@ PView::PView(std::string name, std::string type,
     return;
   }
   PViewDataGModel *d = new PViewDataGModel(t);
-  d->addData(model, data, 0, time, 1, numC);
+  d->addData(model, data, 0, time, 1, numComp);
   d->setName(name);
   d->setFileName(name + ".msh");
   _data = d;
@@ -138,10 +138,10 @@ PView::PView(std::string name, std::string type,
 }
 
 void PView::addStep(GModel *model, std::map<int, std::vector<double> > &data, 
-                    double time, int numC)
+                    double time, int numComp)
 {
   PViewDataGModel *d = dynamic_cast<PViewDataGModel*>(_data);
-  if(d) d->addData(model, data, d->getNumTimeSteps(), time, 1, numC);
+  if(d) d->addData(model, data, d->getNumTimeSteps(), time, 1, numComp);
   else Msg::Error("Can only add step data to model-based datasets");
 }
 
diff --git a/Post/PViewData.cpp b/Post/PViewData.cpp
index cffc18491d..93f6cfaa4d 100644
--- a/Post/PViewData.cpp
+++ b/Post/PViewData.cpp
@@ -22,7 +22,7 @@ PViewData::~PViewData()
       delete it->second[i];
 }
 
-bool PViewData::finalize()
+bool PViewData::finalize(bool computeMinMax)
 { 
   _dirty = false;
   return true;
diff --git a/Post/PViewData.h b/Post/PViewData.h
index baeacf25c0..d64e9982ab 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -45,7 +45,7 @@ class PViewData {
   virtual void setDirty(bool val){ _dirty = val; }
 
   // finalize the view data (compute min/max, etc.)
-  virtual bool finalize();
+  virtual bool finalize(bool computeMinMax=true);
 
   // get/set name
   virtual std::string getName(){ return _name; }
diff --git a/Post/PViewDataGModel.cpp b/Post/PViewDataGModel.cpp
index 882ba1df48..94fae4dda8 100644
--- a/Post/PViewDataGModel.cpp
+++ b/Post/PViewDataGModel.cpp
@@ -25,41 +25,43 @@ PViewDataGModel::~PViewDataGModel()
   for(unsigned int i = 0; i < _steps.size(); i++) delete _steps[i];
 }
 
-bool PViewDataGModel::finalize()
-{
-  _min = VAL_INF;
-  _max = -VAL_INF;
-  for(int step = 0; step < getNumTimeSteps(); step++){
-    _steps[step]->setMin(VAL_INF);
-    _steps[step]->setMax(-VAL_INF);
-    if(_type == NodeData || _type == ElementData){
-      // treat these 2 special cases separately for maximum efficiency
-      int numComp = _steps[step]->getNumComponents();
-      for(int i = 0; i < _steps[step]->getNumData(); i++){
-        double *d = _steps[step]->getData(i);
-        if(d){
-          double val = ComputeScalarRep(numComp, d);
-          _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
-          _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
-        }
-      }
-    }
-    else{
-      // general case (slower)
-      for(int ent = 0; ent < getNumEntities(step); ent++){
-        for(int ele = 0; ele < getNumElements(step, ent); ele++){
-          if(skipElement(step, ent, ele)) continue;
-          for(int nod = 0; nod < getNumNodes(step, ent, ele); nod++){
-            double val;
-            getScalarValue(step, ent, ele, nod, val);
+bool PViewDataGModel::finalize(bool computeMinMax)
+{
+  if(computeMinMax){
+    _min = VAL_INF;
+    _max = -VAL_INF;
+    for(int step = 0; step < getNumTimeSteps(); step++){
+      _steps[step]->setMin(VAL_INF);
+      _steps[step]->setMax(-VAL_INF);
+      if(_type == NodeData || _type == ElementData){
+        // treat these 2 special cases separately for maximum efficiency
+        int numComp = _steps[step]->getNumComponents();
+        for(int i = 0; i < _steps[step]->getNumData(); i++){
+          double *d = _steps[step]->getData(i);
+          if(d){
+            double val = ComputeScalarRep(numComp, d);
             _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
             _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
           }
         }
       }
+      else{
+        // general case (slower)
+        for(int ent = 0; ent < getNumEntities(step); ent++){
+          for(int ele = 0; ele < getNumElements(step, ent); ele++){
+            if(skipElement(step, ent, ele)) continue;
+            for(int nod = 0; nod < getNumNodes(step, ent, ele); nod++){
+              double val;
+              getScalarValue(step, ent, ele, nod, val);
+              _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
+              _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
+            }
+          }
+        }
+      }
+      _min = std::min(_min, _steps[step]->getMin());
+      _max = std::max(_max, _steps[step]->getMax());
     }
-    _min = std::min(_min, _steps[step]->getMin());
-    _max = std::max(_max, _steps[step]->getMax());
   }
 
   // add interpolation data for known element types (this might be
@@ -381,7 +383,7 @@ int PViewDataGModel::getNumValues(int step, int ent, int ele)
     return getNumComponents(step, ent, ele);
   }
   else{
-    Msg::Error("getNumValue() should not be used on this type of view");
+    Msg::Error("getNumValues() should not be used on this type of view");
     return getNumComponents(step, ent, ele);
   }
 }
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index 8a85a462db..75aa808e51 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -170,7 +170,7 @@ class PViewDataGModel : public PViewData {
  public:
   PViewDataGModel(DataType type=NodeData);
   ~PViewDataGModel();
-  bool finalize();
+  bool finalize(bool computeMinMax=true);
   std::string getFileName(int step=-1);
   int getNumTimeSteps();
   double getTime(int step);
@@ -228,10 +228,9 @@ class PViewDataGModel : public PViewData {
   GModel* getModel(int step){ return _steps[step]->getModel(); }
 
   // Add some data "on the fly" (data is stored in a map, indexed by
-  // node or element number depending on the type of dataset; all the
-  // vectors are supposed to have the same length)
+  // node or element number depending on the type of dataset)
   bool addData(GModel *model, std::map<int, std::vector<double> > &data,
-               int step, double time, int partition, int numC);
+               int step, double time, int partition, int numComp);
 
   // I/O routines
   bool readMSH(std::string fileName, int fileIndex, FILE *fp, bool binary, 
diff --git a/Post/PViewDataGModelIO.cpp b/Post/PViewDataGModelIO.cpp
index 9104575608..46dbc30e6e 100644
--- a/Post/PViewDataGModelIO.cpp
+++ b/Post/PViewDataGModelIO.cpp
@@ -12,18 +12,10 @@
 #include "StringUtils.h"
 
 bool PViewDataGModel::addData(GModel *model, std::map<int, std::vector<double> > &data,
-                              int step, double time, int partition, int numC)
+                              int step, double time, int partition, int numComp)
 {
   if(data.empty()) return false;
 
-  int numComp = 9;
-  if (numC < 0){
-    for(std::map<int, std::vector<double> >::iterator it = data.begin();
-        it != data.end(); it++)
-      numComp = std::min(numComp, (int)it->second.size());
-  }
-  else numComp = numC;
-
   while(step >= (int)_steps.size())
     _steps.push_back(new stepData<double>(model, numComp));
 
@@ -35,8 +27,9 @@ bool PViewDataGModel::addData(GModel *model, std::map<int, std::vector<double> >
 
   for(std::map<int, std::vector<double> >::iterator it = data.begin();
       it != data.end(); it++){
-    double *d  = _steps[step]->getData(it->first, true);
-    for(int j = 0; j < numComp; j++)
+    int mult = it->second.size() / numComp;
+    double *d  = _steps[step]->getData(it->first, true, mult);
+    for(int j = 0; j < numComp * mult; j++)
       d[j] = it->second[j];
   }
   _steps[step]->getPartitions().insert(partition);
@@ -96,17 +89,25 @@ bool PViewDataGModel::readMSH(std::string fileName, int fileIndex, FILE *fp,
       for(int j = 0; j < numComp * mult; j++)
         if(fscanf(fp, "%lf", &d[j]) != 1) return false;
     }
+    // compute min/max here to avoid calling finalize(true) later:
+    // this would be very slow for large multi-step, multi-partition
+    // datasets (since we would recompute the min/max for all the
+    // previously loaded steps/partitions, and thus loop over all the
+    // elements many times)
+    for(int j = 0; j < mult; j++){
+      double val = ComputeScalarRep(numComp, &d[numComp * j]);
+      _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
+      _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
+      _min = std::min(_min, val);
+      _max = std::max(_max, val);
+    }
     if(numEnt > 100000)
       Msg::ProgressMeter(i + 1, numEnt, "Reading data");
   }
 
   _steps[step]->getPartitions().insert(partition);
 
-  // FIXME: we should do this at a higher-level, since this will be
-  // very slow for large multi-step, multi-partition datasets (we
-  // recompute the min/max for all the previously loaded
-  // steps/partitions -> loop over all elements many many times...)
-  finalize();
+  finalize(false);
   return true;
 }
 
diff --git a/Post/PViewDataList.cpp b/Post/PViewDataList.cpp
index 3913a546b9..8c39b8d7f9 100644
--- a/Post/PViewDataList.cpp
+++ b/Post/PViewDataList.cpp
@@ -25,7 +25,7 @@ PViewDataList::PViewDataList()
   for(int i = 0; i < 24; i++) _index[i] = 0;
 }
 
-bool PViewDataList::finalize()
+bool PViewDataList::finalize(bool computeMinMax)
 {
   BBox.reset();
   Min = VAL_INF;
diff --git a/Post/PViewDataList.h b/Post/PViewDataList.h
index 9deec5dbe0..ef0bdbfd46 100644
--- a/Post/PViewDataList.h
+++ b/Post/PViewDataList.h
@@ -57,7 +57,7 @@ class PViewDataList : public PViewData {
  public:
   PViewDataList();
   ~PViewDataList(){}
-  bool finalize();
+  bool finalize(bool computeMinMax=true);
   int getNumTimeSteps(){ return NbTimeStep; }
   double getTime(int step);
   double getMin(int step=-1);
-- 
GitLab