1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include "PView.h"
7 #include "PViewDataGModel.h"
8 #include "MPoint.h"
9 #include "MLine.h"
10 #include "MTriangle.h"
11 #include "MQuadrangle.h"
12 #include "MTetrahedron.h"
13 #include "MHexahedron.h"
14 #include "MPrism.h"
15 #include "MPyramid.h"
16 #include "MElementCut.h"
17 #include "Numeric.h"
18 #include "GmshMessage.h"
19 #include "pyramidalBasis.h"
20 
PViewDataGModel(DataType type)21 PViewDataGModel::PViewDataGModel(DataType type)
22   : PViewData(), _min(VAL_INF), _max(-VAL_INF), _type(type)
23 {
24 }
25 
~PViewDataGModel()26 PViewDataGModel::~PViewDataGModel()
27 {
28   for(std::size_t i = 0; i < _steps.size(); i++) delete _steps[i];
29 }
30 
_getOneElementOfGivenType(GModel * m,int type)31 static MElement *_getOneElementOfGivenType(GModel *m, int type)
32 {
33   switch(type) {
34   case TYPE_PNT:
35     for(auto it = m->firstVertex(); it != m->lastVertex(); it++) {
36       if((*it)->points.size()) return (*it)->points[0];
37     }
38     break;
39   case TYPE_LIN:
40     for(auto it = m->firstEdge(); it != m->lastEdge(); it++) {
41       if((*it)->lines.size()) return (*it)->lines[0];
42     }
43     break;
44   case TYPE_TRI:
45     for(auto it = m->firstFace(); it != m->lastFace(); it++) {
46       if((*it)->triangles.size()) return (*it)->triangles[0];
47     }
48     break;
49   case TYPE_QUA:
50     for(auto it = m->firstFace(); it != m->lastFace(); it++) {
51       if((*it)->quadrangles.size()) return (*it)->quadrangles[0];
52     }
53     break;
54   case TYPE_POLYG:
55     for(auto it = m->firstFace(); it != m->lastFace(); it++) {
56       if((*it)->polygons.size()) return (*it)->polygons[0];
57     }
58     break;
59   case TYPE_TET:
60     for(auto it = m->firstRegion(); it != m->lastRegion(); it++) {
61       if((*it)->tetrahedra.size()) return (*it)->tetrahedra[0];
62     }
63     break;
64   case TYPE_HEX:
65     for(auto it = m->firstRegion(); it != m->lastRegion(); it++) {
66       if((*it)->hexahedra.size()) return (*it)->hexahedra[0];
67     }
68     break;
69   case TYPE_PRI:
70     for(auto it = m->firstRegion(); it != m->lastRegion(); it++) {
71       if((*it)->prisms.size()) return (*it)->prisms[0];
72     }
73     break;
74   case TYPE_PYR:
75     for(auto it = m->firstRegion(); it != m->lastRegion(); it++) {
76       if((*it)->pyramids.size()) return (*it)->pyramids[0];
77     }
78     break;
79   case TYPE_POLYH:
80     for(auto it = m->firstRegion(); it != m->lastRegion(); it++) {
81       if((*it)->polyhedra.size()) return (*it)->polyhedra[0];
82     }
83     break;
84   }
85   return nullptr;
86 }
87 
finalize(bool computeMinMax,const std::string & interpolationScheme)88 bool PViewDataGModel::finalize(bool computeMinMax,
89                                const std::string &interpolationScheme)
90 {
91   if(computeMinMax) {
92     _min = VAL_INF;
93     _max = -VAL_INF;
94     int tensorRep = 0; // Von-Mises: we could/should be able to choose this
95     for(int step = 0; step < getNumTimeSteps(); step++) {
96       _steps[step]->setMin(VAL_INF);
97       _steps[step]->setMax(-VAL_INF);
98       if(_type == NodeData || _type == ElementData) {
99         // treat these 2 special cases separately for maximum efficiency
100         int numComp = _steps[step]->getNumComponents();
101         for(std::size_t i = 0; i < _steps[step]->getNumData(); i++) {
102           double *d = _steps[step]->getData(i);
103           if(d) {
104             double val = ComputeScalarRep(numComp, d, tensorRep);
105             _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
106             _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
107           }
108         }
109       }
110       else {
111         // general case (slower)
112         for(int ent = 0; ent < getNumEntities(step); ent++) {
113           for(int ele = 0; ele < getNumElements(step, ent); ele++) {
114             if(skipElement(step, ent, ele)) continue;
115             for(int nod = 0; nod < getNumNodes(step, ent, ele); nod++) {
116               double val;
117               getScalarValue(step, ent, ele, nod, val, tensorRep);
118               _steps[step]->setMin(std::min(_steps[step]->getMin(), val));
119               _steps[step]->setMax(std::max(_steps[step]->getMax(), val));
120             }
121           }
122         }
123       }
124       _min = std::min(_min, _steps[step]->getMin());
125       _max = std::max(_max, _steps[step]->getMax());
126     }
127   }
128 
129   // set up interpolation matrices
130   if(!haveInterpolationMatrices()) {
131     GModel *model = _steps[0]->getModel();
132 
133     // Required for ParaView plugin linked to GMSH as external library.
134     setInterpolationSchemeName(interpolationScheme);
135 
136     // if an interpolation scheme is explicitly provided, use it
137     if(interpolationScheme.size()) {
138       interpolationMatrices m = _interpolationSchemes[interpolationScheme];
139       if(m.size())
140         Msg::Info("Setting interpolation matrices from scheme '%s'",
141                   interpolationScheme.c_str());
142       else
143         Msg::Error("Could not find interpolation scheme '%s'",
144                    interpolationScheme.c_str());
145       for(auto it = m.begin(); it != m.end(); it++) {
146         if(it->second.size() == 2) {
147           // use provided interpolation matrices for field interpolation and use
148           // geometrical interpolation matrices from the mesh if the mesh is
149           // curved
150           MElement *e = _getOneElementOfGivenType(model, it->first);
151           if(e && e->getPolynomialOrder() > 1 && e->getFunctionSpace()) {
152             if(it->first ==
153                TYPE_PYR) { // nasty fix since pyramids /= polynomial
154               const pyramidalBasis *fs =
155                 (pyramidalBasis *)e->getFunctionSpace();
156               setInterpolationMatrices(it->first, *(it->second[0]),
157                                        *(it->second[1]), fs->coefficients,
158                                        fs->monomials);
159             }
160             else {
161               const polynomialBasis *fs =
162                 (polynomialBasis *)e->getFunctionSpace();
163               setInterpolationMatrices(it->first, *(it->second[0]),
164                                        *(it->second[1]), fs->coefficients,
165                                        fs->monomials);
166             }
167           }
168           else
169             setInterpolationMatrices(it->first, *(it->second[0]),
170                                      *(it->second[1]));
171         }
172         else if(it->second.size() == 4) {
173           // use provided matrices for field and geometry
174           Msg::Warning(
175             "You should not specify the geometrical interpolation "
176             "in ElementNodeData: the geometry is completely determined "
177             "by the mesh element type. This feature will be removed");
178           setInterpolationMatrices(it->first, *it->second[0], *it->second[1],
179                                    *it->second[2], *it->second[3]);
180         }
181         else
182           Msg::Error(
183             "Wrong number of interpolation matrices (%d) for scheme '%s'",
184             (int)it->second.size(), interpolationScheme.c_str());
185       }
186     }
187 
188     // if we don't have interpolation matrices for a given element type, assume
189     // isoparametric elements (except for ElementData, for which we know the
190     // interpolation: it's constant)
191     int types[] = {TYPE_PNT, TYPE_LIN, TYPE_TRI, TYPE_QUA,   TYPE_TET,
192                    TYPE_HEX, TYPE_PRI, TYPE_PYR, TYPE_POLYG, TYPE_POLYH};
193     for(std::size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) {
194       if(!haveInterpolationMatrices(types[i])) {
195         MElement *e = _getOneElementOfGivenType(model, types[i]);
196         if(e) {
197           const polynomialBasis *fs =
198             dynamic_cast<const polynomialBasis *>(e->getFunctionSpace());
199           if(fs) {
200             if(e->getPolynomialOrder() > 1) {
201               if(_type == ElementData) {
202                 // data is constant per element: force the interpolation matrix
203                 fullMatrix<double> coef(1, 1);
204                 coef(0, 0) = 1.;
205                 fullMatrix<double> mono(1, 3);
206                 mono(0, 0) = 0.;
207                 mono(0, 1) = 0.;
208                 mono(0, 2) = 0.;
209                 setInterpolationMatrices(types[i], coef, mono, fs->coefficients,
210                                          fs->monomials);
211               }
212               else
213                 setInterpolationMatrices(types[i], fs->coefficients,
214                                          fs->monomials, fs->coefficients,
215                                          fs->monomials);
216             }
217             else
218               setInterpolationMatrices(types[i], fs->coefficients,
219                                        fs->monomials);
220           }
221           else {
222             const pyramidalBasis *fs =
223               dynamic_cast<const pyramidalBasis *>(e->getFunctionSpace());
224             if(fs) {
225               if(e->getPolynomialOrder() > 1) {
226                 if(_type == ElementData) {
227                   // data is constant per element: force the interpolation
228                   // matrix
229                   fullMatrix<double> coef(1, 1);
230                   coef(0, 0) = 1.;
231                   fullMatrix<double> mono(1, 3);
232                   mono(0, 0) = 0.;
233                   mono(0, 1) = 0.;
234                   mono(0, 2) = 0.;
235                   setInterpolationMatrices(types[i], coef, mono,
236                                            fs->coefficients, fs->monomials);
237                 }
238                 else
239                   setInterpolationMatrices(types[i], fs->coefficients,
240                                            fs->monomials, fs->coefficients,
241                                            fs->monomials);
242               }
243               else
244                 setInterpolationMatrices(types[i], fs->coefficients,
245                                          fs->monomials);
246             }
247           }
248         }
249       }
250     }
251   }
252   return PViewData::finalize();
253 }
254 
_getElement(int step,int ent,int ele)255 MElement *PViewDataGModel::_getElement(int step, int ent, int ele)
256 {
257   static int lastStep = -1, lastEnt = -1, lastEle = -1;
258   static MElement *curr = nullptr;
259   if(step != lastStep || ent != lastEnt || ele != lastEle)
260     curr = _steps[step]->getEntity(ent)->getMeshElement(ele);
261   return curr;
262 }
263 
getFileName(int step)264 std::string PViewDataGModel::getFileName(int step)
265 {
266   if(step < 0 || step > (int)_steps.size() - 1) return PViewData::getFileName();
267   return _steps[step]->getFileName();
268 }
269 
getNumTimeSteps()270 int PViewDataGModel::getNumTimeSteps() { return _steps.size(); }
271 
getFirstNonEmptyTimeStep(int start)272 int PViewDataGModel::getFirstNonEmptyTimeStep(int start)
273 {
274   for(std::size_t i = start; i < _steps.size(); i++)
275     if(_steps[i]->getNumData()) return i;
276   return start;
277 }
278 
getTime(int step)279 double PViewDataGModel::getTime(int step)
280 {
281   if(_steps.empty()) return 0.;
282   return _steps[step]->getTime();
283 }
284 
getMin(int step,bool onlyVisible,int tensorRep,int forceNumComponents,int componentMap[9])285 double PViewDataGModel::getMin(int step, bool onlyVisible, int tensorRep,
286                                int forceNumComponents, int componentMap[9])
287 {
288   if(_steps.empty()) return _min;
289 
290   if(onlyVisible || forceNumComponents || tensorRep) {
291     double vmin = VAL_INF;
292     for(int ent = 0; ent < getNumEntities(step); ent++) {
293       if(onlyVisible && skipEntity(step, ent)) continue;
294       for(int ele = 0; ele < getNumElements(step, ent); ele++) {
295         if(skipElement(step, ent, ele, onlyVisible)) continue;
296         for(int nod = 0; nod < getNumNodes(step, ent, ele); nod++) {
297           double val;
298           getScalarValue(step, ent, ele, nod, val, tensorRep,
299                          forceNumComponents, componentMap);
300           vmin = std::min(vmin, val);
301         }
302       }
303     }
304     return vmin;
305   }
306 
307   if(step < 0) return _min;
308   return _steps[step]->getMin();
309 }
310 
getMax(int step,bool onlyVisible,int tensorRep,int forceNumComponents,int componentMap[9])311 double PViewDataGModel::getMax(int step, bool onlyVisible, int tensorRep,
312                                int forceNumComponents, int componentMap[9])
313 {
314   if(_steps.empty()) return _max;
315 
316   if(onlyVisible || forceNumComponents || tensorRep) {
317     double vmax = -VAL_INF;
318     for(int ent = 0; ent < getNumEntities(step); ent++) {
319       if(onlyVisible && skipEntity(step, ent)) continue;
320       for(int ele = 0; ele < getNumElements(step, ent); ele++) {
321         if(skipElement(step, ent, ele, onlyVisible)) continue;
322         for(int nod = 0; nod < getNumNodes(step, ent, ele); nod++) {
323           double val;
324           getScalarValue(step, ent, ele, nod, val, tensorRep,
325                          forceNumComponents, componentMap);
326           vmax = std::max(vmax, val);
327         }
328       }
329     }
330     return vmax;
331   }
332 
333   if(step < 0) return _max;
334   return _steps[step]->getMax();
335 }
336 
getBoundingBox(int step)337 SBoundingBox3d PViewDataGModel::getBoundingBox(int step)
338 {
339   if(step < 0 || _steps.empty()) {
340     SBoundingBox3d tmp;
341     for(std::size_t i = 0; i < _steps.size(); i++) {
342       if(!_steps[i]->getBoundingBox().empty())
343         tmp += _steps[i]->getBoundingBox();
344     }
345     return tmp;
346   }
347   return _steps[step]->getBoundingBox();
348 }
349 
getNumScalars(int step)350 int PViewDataGModel::getNumScalars(int step)
351 {
352   if(_steps.empty()) return 0;
353   // to generalize
354   if(_steps[0]->getNumComponents() == 1) return getNumElements(0);
355   return 0;
356 }
357 
getNumVectors(int step)358 int PViewDataGModel::getNumVectors(int step)
359 {
360   if(_steps.empty()) return 0;
361   // to generalize
362   if(_steps[0]->getNumComponents() == 3) return getNumElements(0);
363   return 0;
364 }
365 
getNumTensors(int step)366 int PViewDataGModel::getNumTensors(int step)
367 {
368   if(_steps.empty()) return 0;
369   // to generalize
370   if(_steps[0]->getNumComponents() == 9) return getNumElements(0);
371   return 0;
372 }
373 
getNumPoints(int step)374 int PViewDataGModel::getNumPoints(int step)
375 {
376   if(_steps.empty()) return 0;
377   GModel *m = _steps[0]->getModel(); // to generalize
378   int n = 0;
379   for(auto it = m->firstVertex(); it != m->lastVertex(); ++it)
380     n += (*it)->points.size();
381   return n;
382 }
383 
getNumLines(int step)384 int PViewDataGModel::getNumLines(int step)
385 {
386   if(_steps.empty()) return 0;
387   GModel *m = _steps[0]->getModel(); // to generalize
388   int n = 0;
389   for(auto it = m->firstEdge(); it != m->lastEdge(); ++it)
390     n += (*it)->lines.size();
391   return n;
392 }
393 
getNumTriangles(int step)394 int PViewDataGModel::getNumTriangles(int step)
395 {
396   if(_steps.empty()) return 0;
397   GModel *m = _steps[0]->getModel(); // to generalize
398   int n = 0;
399   for(auto it = m->firstFace(); it != m->lastFace(); ++it)
400     n += (*it)->triangles.size();
401   return n;
402 }
403 
getNumQuadrangles(int step)404 int PViewDataGModel::getNumQuadrangles(int step)
405 {
406   if(_steps.empty()) return 0;
407   GModel *m = _steps[0]->getModel(); // to generalize
408   int n = 0;
409   for(auto it = m->firstFace(); it != m->lastFace(); ++it)
410     n += (*it)->quadrangles.size();
411   return n;
412 }
413 
getNumPolygons(int step)414 int PViewDataGModel::getNumPolygons(int step)
415 {
416   if(_steps.empty()) return 0;
417   GModel *m = _steps[0]->getModel(); // to generalize
418   int n = 0;
419   for(auto it = m->firstFace(); it != m->lastFace(); ++it)
420     n += (*it)->polygons.size();
421   return n;
422 }
423 
getNumTetrahedra(int step)424 int PViewDataGModel::getNumTetrahedra(int step)
425 {
426   if(_steps.empty()) return 0;
427   GModel *m = _steps[0]->getModel(); // to generalize
428   int n = 0;
429   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
430     n += (*it)->tetrahedra.size();
431   return n;
432 }
433 
getNumHexahedra(int step)434 int PViewDataGModel::getNumHexahedra(int step)
435 {
436   if(_steps.empty()) return 0;
437   GModel *m = _steps[0]->getModel(); // to generalize
438   int n = 0;
439   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
440     n += (*it)->hexahedra.size();
441   return n;
442 }
443 
getNumPrisms(int step)444 int PViewDataGModel::getNumPrisms(int step)
445 {
446   if(_steps.empty()) return 0;
447   GModel *m = _steps[0]->getModel(); // to generalize
448   int n = 0;
449   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
450     n += (*it)->prisms.size();
451   return n;
452 }
453 
getNumPyramids(int step)454 int PViewDataGModel::getNumPyramids(int step)
455 {
456   if(_steps.empty()) return 0;
457   GModel *m = _steps[0]->getModel(); // to generalize
458   int n = 0;
459   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
460     n += (*it)->pyramids.size();
461   return n;
462 }
463 
getNumTrihedra(int step)464 int PViewDataGModel::getNumTrihedra(int step)
465 {
466   if(_steps.empty()) return 0;
467   GModel *m = _steps[0]->getModel(); // to generalize
468   int n = 0;
469   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
470     n += (*it)->trihedra.size();
471   return n;
472 }
473 
getNumPolyhedra(int step)474 int PViewDataGModel::getNumPolyhedra(int step)
475 {
476   if(_steps.empty()) return 0;
477   GModel *m = _steps[0]->getModel(); // to generalize
478   int n = 0;
479   for(auto it = m->firstRegion(); it != m->lastRegion(); ++it)
480     n += (*it)->polyhedra.size();
481   return n;
482 }
483 
getNumEntities(int step)484 int PViewDataGModel::getNumEntities(int step)
485 {
486   if(_steps.empty()) return 0;
487   // to generalize
488   if(step < 0) return _steps[0]->getNumEntities();
489   return _steps[step]->getNumEntities();
490 }
491 
getNumElements(int step,int ent)492 int PViewDataGModel::getNumElements(int step, int ent)
493 {
494   if(_steps.empty()) return 0;
495   // to generalize
496   if(step < 0 && ent < 0) return _steps[0]->getModel()->getNumMeshElements();
497   if(step < 0) return _steps[0]->getEntity(ent)->getNumMeshElements();
498   if(ent < 0) return _steps[step]->getModel()->getNumMeshElements();
499   return _steps[step]->getEntity(ent)->getNumMeshElements();
500 }
501 
getEntity(int step,int ent)502 GEntity *PViewDataGModel::getEntity(int step, int ent)
503 {
504   return _steps[step]->getEntity(ent);
505 }
506 
getElement(int step,int ent,int element)507 MElement *PViewDataGModel::getElement(int step, int ent, int element)
508 {
509   if(_steps.empty()) return nullptr;
510   // to generalize
511   if(step < 0) return _steps[0]->getEntity(ent)->getMeshElement(element);
512   return _steps[step]->getEntity(ent)->getMeshElement(element);
513 }
514 
getDimension(int step,int ent,int ele)515 int PViewDataGModel::getDimension(int step, int ent, int ele)
516 {
517   return _getElement(step, ent, ele)->getDim();
518 }
519 
getNumNodes(int step,int ent,int ele)520 int PViewDataGModel::getNumNodes(int step, int ent, int ele)
521 {
522   MElement *e = _getElement(step, ent, ele);
523   if(_type == GaussPointData) {
524     return _steps[step]->getGaussPoints(e->getTypeForMSH()).size() / 3;
525   }
526   else {
527     if(e->getNumChildren())
528       return e->getNumChildren() * e->getChild(0)->getNumVertices();
529     if(getAdaptiveData()) return e->getNumVertices();
530     return (int)e->getNumPrimaryVertices();
531   }
532 }
533 
_getNode(MElement * e,int nod)534 MVertex *PViewDataGModel::_getNode(MElement *e, int nod)
535 {
536   MVertex *v;
537   if(!e->getNumChildren())
538     v = e->getVertex(nod);
539   else {
540     int nbV = e->getChild(0)->getNumVertices();
541     v = e->getChild((int)(nod / nbV))->getVertex(nod % nbV);
542   }
543   return v;
544 }
545 
getNode(int step,int ent,int ele,int nod,double & x,double & y,double & z)546 int PViewDataGModel::getNode(int step, int ent, int ele, int nod, double &x,
547                              double &y, double &z)
548 {
549   MElement *e = _getElement(step, ent, ele);
550   MVertex *v = _getNode(e, nod);
551   if(_type == GaussPointData) {
552     std::vector<double> &p(_steps[step]->getGaussPoints(e->getTypeForMSH()));
553     if(p[0] == 1.e22) {
554       // hack: the points are the element vertices
555       x = v->x();
556       y = v->y();
557       z = v->z();
558     }
559     else {
560       double vx[8], vy[8], vz[8];
561       for(std::size_t i = 0; i < e->getNumPrimaryVertices(); i++) {
562         vx[i] = e->getVertex(i)->x();
563         vy[i] = e->getVertex(i)->y();
564         vz[i] = e->getVertex(i)->z();
565       }
566       x = e->interpolate(vx, p[3 * nod], p[3 * nod + 1], p[3 * nod + 2], 1, 1);
567       y = e->interpolate(vy, p[3 * nod], p[3 * nod + 1], p[3 * nod + 2], 1, 1);
568       z = e->interpolate(vz, p[3 * nod], p[3 * nod + 1], p[3 * nod + 2], 1, 1);
569     }
570     return 0;
571   }
572   else {
573     x = v->x();
574     y = v->y();
575     z = v->z();
576     return v->getIndex();
577   }
578 }
579 
setNode(int step,int ent,int ele,int nod,double x,double y,double z)580 void PViewDataGModel::setNode(int step, int ent, int ele, int nod, double x,
581                               double y, double z)
582 {
583   MElement *e = _getElement(step, ent, ele);
584   MVertex *v = _getNode(e, nod);
585   v->x() = x;
586   v->y() = y;
587   v->z() = z;
588 }
589 
tagNode(int step,int ent,int ele,int nod,int tag)590 void PViewDataGModel::tagNode(int step, int ent, int ele, int nod, int tag)
591 {
592   MElement *e = _getElement(step, ent, ele);
593   MVertex *v = _getNode(e, nod);
594   v->setIndex(tag);
595 }
596 
getNumComponents(int step,int ent,int ele)597 int PViewDataGModel::getNumComponents(int step, int ent, int ele)
598 {
599   return _steps[step]->getNumComponents();
600 }
601 
getNumValues(int step,int ent,int ele)602 int PViewDataGModel::getNumValues(int step, int ent, int ele)
603 {
604   if(_type == ElementNodeData) {
605     MElement *e = _getElement(step, ent, ele);
606     return _steps[step]->getMult(e->getNum()) *
607            getNumComponents(step, ent, ele);
608   }
609   else if(_type == NodeData) {
610     return getNumNodes(step, ent, ele) * getNumComponents(step, ent, ele);
611   }
612   else if(_type == ElementData) {
613     return getNumComponents(step, ent, ele);
614   }
615   else {
616     Msg::Error("getNumValues() should not be used on this type of view");
617     return getNumComponents(step, ent, ele);
618   }
619 }
620 
getValue(int step,int ent,int ele,int idx,double & val)621 void PViewDataGModel::getValue(int step, int ent, int ele, int idx, double &val)
622 {
623   MElement *e = _getElement(step, ent, ele);
624   if(_type == ElementNodeData || _type == ElementData) {
625     val = _steps[step]->getData(e->getNum())[idx];
626   }
627   else if(_type == NodeData) {
628     int numcomp = _steps[step]->getNumComponents();
629     int nod = idx / numcomp;
630     int comp = idx % numcomp;
631     int num = _getNode(e, nod)->getNum();
632     val = _steps[step]->getData(num)[comp];
633   }
634   else {
635     Msg::Error("getValue(index) should not be used on this type of view");
636   }
637 }
638 
getValue(int step,int ent,int ele,int nod,int comp,double & val)639 void PViewDataGModel::getValue(int step, int ent, int ele, int nod, int comp,
640                                double &val)
641 {
642   MElement *e = _getElement(step, ent, ele);
643   switch(_type) {
644   case NodeData: {
645     int num = _getNode(e, nod)->getNum();
646     val = _steps[step]->getData(num)[comp];
647   } break;
648   case ElementNodeData:
649   case GaussPointData:
650     if(_steps[step]->getMult(e->getNum()) < nod + 1) {
651       nod = 0;
652       static bool first = true;
653       if(first) {
654         Msg::Warning("Some elements in ElementNodeData have less values than "
655                      "number of nodes");
656         first = false;
657       }
658     }
659     val = _steps[step]->getData(
660       e->getNum())[_steps[step]->getNumComponents() * nod + comp];
661     break;
662   case ElementData:
663   default: val = _steps[step]->getData(e->getNum())[comp]; break;
664   }
665 }
666 
setValue(int step,int ent,int ele,int nod,int comp,double val)667 void PViewDataGModel::setValue(int step, int ent, int ele, int nod, int comp,
668                                double val)
669 {
670   MElement *e = _getElement(step, ent, ele);
671   switch(_type) {
672   case NodeData: {
673     int num = _getNode(e, nod)->getNum();
674     _steps[step]->getData(num)[comp] = val;
675   } break;
676   case ElementNodeData:
677   case GaussPointData:
678     if(_steps[step]->getMult(e->getNum()) < nod + 1) {
679       nod = 0;
680       static bool first = true;
681       if(first) {
682         Msg::Warning("Some elements in ElementNodeData have less values than "
683                      "number of nodes");
684         first = false;
685       }
686     }
687     _steps[step]->getData(
688       e->getNum())[_steps[step]->getNumComponents() * nod + comp] = val;
689     break;
690   case ElementData:
691   default: _steps[step]->getData(e->getNum())[comp] = val; break;
692   }
693 }
694 
getNumEdges(int step,int ent,int ele)695 int PViewDataGModel::getNumEdges(int step, int ent, int ele)
696 {
697   return _getElement(step, ent, ele)->getNumEdges();
698 }
699 
getType(int step,int ent,int ele)700 int PViewDataGModel::getType(int step, int ent, int ele)
701 {
702   return _getElement(step, ent, ele)->getType();
703 }
704 
reverseElement(int step,int ent,int ele)705 void PViewDataGModel::reverseElement(int step, int ent, int ele)
706 {
707   if(!step) _getElement(step, ent, ele)->reverse();
708 }
709 
smooth()710 void PViewDataGModel::smooth()
711 {
712   if(_type == NodeData || _type == GaussPointData) return;
713   std::vector<stepData<double> *> _steps2;
714   for(std::size_t step = 0; step < _steps.size(); step++) {
715     GModel *m = _steps[step]->getModel();
716     int numComp = _steps[step]->getNumComponents();
717     _steps2.push_back(new stepData<double>(
718       m, numComp, _steps[step]->getFileName(), _steps[step]->getFileIndex(),
719       _steps[step]->getTime()));
720     _steps2.back()->fillEntities();
721     _steps2.back()->computeBoundingBox();
722 
723     std::map<int, int> nodeConnect;
724     for(int ent = 0; ent < getNumEntities(step); ent++) {
725       for(int ele = 0; ele < getNumElements(step, ent); ele++) {
726         MElement *e = _steps[step]->getEntity(ent)->getMeshElement(ele);
727         double val;
728         if(!getValueByIndex(step, e->getNum(), 0, 0, val)) continue;
729         for(std::size_t nod = 0; nod < e->getNumVertices(); nod++) {
730           MVertex *v = e->getVertex(nod);
731           if(nodeConnect.count(v->getNum()))
732             nodeConnect[v->getNum()]++;
733           else
734             nodeConnect[v->getNum()] = 1;
735           double *d = _steps2.back()->getData(v->getNum(), true);
736           for(int j = 0; j < numComp; j++)
737             if(getValueByIndex(step, e->getNum(), nod, j, val)) d[j] += val;
738         }
739       }
740     }
741     for(std::size_t i = 0; i < _steps2.back()->getNumData(); i++) {
742       double *d = _steps2.back()->getData(i);
743       if(d) {
744         double f = nodeConnect[i];
745         if(f)
746           for(int j = 0; j < numComp; j++) d[j] /= f;
747       }
748     }
749   }
750   for(std::size_t i = 0; i < _steps.size(); i++) delete _steps[i];
751   _steps = _steps2;
752   _type = NodeData;
753   finalize();
754 }
755 
getMemoryInMb()756 double PViewDataGModel::getMemoryInMb()
757 {
758   double m = 0.;
759   for(std::size_t i = 0; i < _steps.size(); i++)
760     m += _steps[i]->getMemoryInMb();
761   return m;
762 }
763 
combineTime(nameData & nd)764 bool PViewDataGModel::combineTime(nameData &nd)
765 {
766   // sanity checks
767   if(nd.data.size() < 2) return false;
768   std::vector<PViewDataGModel *> data(nd.data.size());
769   for(std::size_t i = 0; i < nd.data.size(); i++) {
770     data[i] = dynamic_cast<PViewDataGModel *>(nd.data[i]);
771     if(!data[i]) {
772       Msg::Error("Cannot combine hybrid data");
773       return false;
774     }
775   }
776 
777   // copy interpolation matrices
778   for(auto it = data[0]->_interpolation.begin();
779       it != data[0]->_interpolation.end(); it++)
780     if(_interpolation[it->first].empty())
781       for(std::size_t i = 0; i < it->second.size(); i++)
782         _interpolation[it->first].push_back(
783           new fullMatrix<double>(*it->second[i]));
784 
785   // (deep) copy step data
786   for(std::size_t i = 0; i < data.size(); i++)
787     for(std::size_t j = 0; j < data[i]->_steps.size(); j++)
788       if(data[i]->hasTimeStep(j))
789         _steps.push_back(new stepData<double>(*data[i]->_steps[j]));
790 
791   std::string tmp;
792   if(nd.name == "__all__")
793     tmp = "all";
794   else if(nd.name == "__vis__")
795     tmp = "visible";
796   else
797     tmp = nd.name;
798   char name[256];
799   sprintf(name, "%s_Combine", tmp.c_str());
800 
801   setName(name);
802   setFileName(std::string(name) + ".msh");
803   return finalize();
804 }
805 
skipEntity(int step,int ent)806 bool PViewDataGModel::skipEntity(int step, int ent)
807 {
808   if(step >= getNumTimeSteps()) return true;
809   return !_steps[step]->getEntity(ent)->getVisibility();
810 }
811 
skipElement(int step,int ent,int ele,bool checkVisibility,int samplingRate)812 bool PViewDataGModel::skipElement(int step, int ent, int ele,
813                                   bool checkVisibility, int samplingRate)
814 {
815   if(step >= getNumTimeSteps()) return true;
816   stepData<double> *sd = _steps[step];
817   if(!_steps[step]->getNumData()) return true;
818   MElement *e = _getElement(step, ent, ele);
819   if(checkVisibility && !e->getVisibility()) return true;
820   if(_type == NodeData) {
821     for(int i = 0; i < getNumNodes(step, ent, ele); i++)
822       if(!sd->getData(_getNode(e, i)->getNum())) return true;
823   }
824   else {
825     if(!sd->getData(e->getNum())) return true;
826   }
827   return PViewData::skipElement(step, ent, ele, checkVisibility, samplingRate);
828 }
829 
hasTimeStep(int step)830 bool PViewDataGModel::hasTimeStep(int step)
831 {
832   if(step >= 0 && step < getNumTimeSteps() && _steps[step]->getNumData())
833     return true;
834   return false;
835 }
836 
hasPartition(int step,int part)837 bool PViewDataGModel::hasPartition(int step, int part)
838 {
839   if(step < 0 || step >= getNumTimeSteps()) return false;
840   return _steps[step]->getPartitions().find(part) !=
841          _steps[step]->getPartitions().end();
842 }
843 
hasMultipleMeshes()844 bool PViewDataGModel::hasMultipleMeshes()
845 {
846   if(_steps.size() <= 1) return false;
847   GModel *m = _steps[0]->getModel();
848   for(std::size_t i = 1; i < _steps.size(); i++)
849     if(m != _steps[i]->getModel()) return true;
850   return false;
851 }
852 
hasModel(GModel * model,int step)853 bool PViewDataGModel::hasModel(GModel *model, int step)
854 {
855   if(step < 0) {
856     for(std::size_t i = 0; i < _steps.size(); i++)
857       if(model == _steps[i]->getModel()) return true;
858     return false;
859   }
860   return (model == _steps[step]->getModel());
861 }
862 
getValueByIndex(int step,int dataIndex,int nod,int comp,double & val)863 bool PViewDataGModel::getValueByIndex(int step, int dataIndex, int nod,
864                                       int comp, double &val)
865 {
866   double *d = _steps[step]->getData(dataIndex);
867   if(!d) return false;
868 
869   if(_type == NodeData || _type == ElementData)
870     val = d[comp];
871   else
872     val = d[_steps[step]->getNumComponents() * nod + comp];
873   return true;
874 }
875