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