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 <math.h>
7 #include <list>
8 #include <set>
9 #include <algorithm>
10 #include "adaptiveData.h"
11 #include "PViewDataGModel.h"
12 #include "Plugin.h"
13 #include "OS.h"
14 #include "GmshDefines.h"
15
16 //#define TIMER
17
18 std::set<adaptiveVertex> adaptivePoint::allVertices;
19 std::set<adaptiveVertex> adaptiveLine::allVertices;
20 std::set<adaptiveVertex> adaptiveTriangle::allVertices;
21 std::set<adaptiveVertex> adaptiveQuadrangle::allVertices;
22 std::set<adaptiveVertex> adaptiveTetrahedron::allVertices;
23 std::set<adaptiveVertex> adaptiveHexahedron::allVertices;
24 std::set<adaptiveVertex> adaptivePrism::allVertices;
25 std::set<adaptiveVertex> adaptivePyramid::allVertices;
26
27 std::list<adaptivePoint *> adaptivePoint::all;
28 std::list<adaptiveLine *> adaptiveLine::all;
29 std::list<adaptiveTriangle *> adaptiveTriangle::all;
30 std::list<adaptiveQuadrangle *> adaptiveQuadrangle::all;
31 std::list<adaptiveTetrahedron *> adaptiveTetrahedron::all;
32 std::list<adaptiveHexahedron *> adaptiveHexahedron::all;
33 std::list<adaptivePrism *> adaptivePrism::all;
34 std::list<adaptivePyramid *> adaptivePyramid::all;
35
36 int adaptivePoint::numNodes = 1;
37 int adaptiveLine::numNodes = 2;
38 int adaptiveTriangle::numNodes = 3;
39 int adaptiveQuadrangle::numNodes = 4;
40 int adaptivePrism::numNodes = 6;
41 int adaptiveTetrahedron::numNodes = 4;
42 int adaptiveHexahedron::numNodes = 8;
43 int adaptivePyramid::numNodes = 5;
44
45 int adaptivePoint::numEdges = 0;
46 int adaptiveLine::numEdges = 1;
47 int adaptiveTriangle::numEdges = 3;
48 int adaptiveQuadrangle::numEdges = 4;
49 int adaptivePrism::numEdges = 9;
50 int adaptiveTetrahedron::numEdges = 6;
51 int adaptiveHexahedron::numEdges = 12;
52 int adaptivePyramid::numEdges = 8;
53
54 std::vector<vectInt> globalVTKData::vtkGlobalConnectivity;
55 std::vector<int> globalVTKData::vtkGlobalCellType;
56 std::vector<PCoords> globalVTKData::vtkGlobalCoords;
57 std::vector<PValues> globalVTKData::vtkGlobalValues;
58
cleanElement()59 template <class T> static void cleanElement()
60 {
61 for(auto it = T::all.begin(); it != T::all.end(); ++it) delete *it;
62 T::all.clear();
63 T::allVertices.clear();
64 }
65
computeShapeFunctions(fullMatrix<double> * coeffs,fullMatrix<double> * eexps,double u,double v,double w,fullVector<double> * sf,fullVector<double> * tmp)66 static void computeShapeFunctions(fullMatrix<double> *coeffs,
67 fullMatrix<double> *eexps, double u, double v,
68 double w, fullVector<double> *sf,
69 fullVector<double> *tmp)
70 {
71 for(int i = 0; i < eexps->size1(); i++) {
72 (*tmp)(i) = pow(u, (*eexps)(i, 0));
73 if(eexps->size2() > 1) (*tmp)(i) *= pow(v, (*eexps)(i, 1));
74 if(eexps->size2() > 2) (*tmp)(i) *= pow(w, (*eexps)(i, 2));
75 }
76 coeffs->mult(*tmp, *sf);
77 }
78
79 /*! Bergot space is characterised by polynomials
80 \f$ \mathcal B_{ijk} =
81 \mathcal P_i \left(\frac{\xi }{1-\zeta}\right)
82 \mathcal P_j \left(\frac{\eta}{1-\zeta}\right)
83 \left(1-\zeta\right)^{max(i,j)}
84 \mathcal P^{2 max(i,j),0}_k \left(2 \zeta -1\right)~|~i,j \leq p, k \leq p -
85 max(i,j) \f$ and hence by the "monomials" \f$ \mu_{ijk} = \left(\frac{\xi
86 }{1-\zeta}\right)^i \left(\frac{\eta}{1-\zeta}\right)^j
87 \left(1-\zeta\right)^{max(i,j)} \zeta^k~|~i,j \leq p~,~k \leq p-max(i,j)
88 \f$
89 */
computeShapeFunctionsPyramid(fullMatrix<double> * coeffs,fullMatrix<double> * eexps,double u,double v,double w,fullVector<double> * sf,fullVector<double> * tmp)90 static void computeShapeFunctionsPyramid(fullMatrix<double> *coeffs,
91 fullMatrix<double> *eexps, double u,
92 double v, double w,
93 fullVector<double> *sf,
94 fullVector<double> *tmp)
95 {
96 double oneMinW = (w == 1) ? 1e-12 : 1 - w;
97 for(int l = 0; l < eexps->size1(); l++) {
98 int i = (*eexps)(l, 0);
99 int j = (*eexps)(l, 1);
100 int k = (*eexps)(l, 2);
101 int m = std::max(i, j);
102 (*tmp)(l) = pow(u, i);
103 (*tmp)(l) *= pow(v, j);
104 (*tmp)(l) *= pow(w, k);
105 (*tmp)(l) *= pow(oneMinW, m - i - j);
106 }
107 coeffs->mult(*tmp, *sf);
108 }
109
add(double x,double y,double z,std::set<adaptiveVertex> & allVertices)110 adaptiveVertex *adaptiveVertex::add(double x, double y, double z,
111 std::set<adaptiveVertex> &allVertices)
112 {
113 adaptiveVertex p;
114 p.x = x;
115 p.y = y;
116 p.z = z;
117 auto it = allVertices.find(p);
118 if(it == allVertices.end()) {
119 allVertices.insert(p);
120 it = allVertices.find(p);
121 }
122 return (adaptiveVertex *)&(*it);
123 }
124
create(int maxlevel)125 void adaptivePoint::create(int maxlevel)
126 {
127 cleanElement<adaptivePoint>();
128 adaptiveVertex *p1 = adaptiveVertex::add(0, 0, 0, allVertices);
129 adaptivePoint *t = new adaptivePoint(p1);
130 recurCreate(t, maxlevel, 0);
131 }
132
recurCreate(adaptivePoint * e,int maxlevel,int level)133 void adaptivePoint::recurCreate(adaptivePoint *e, int maxlevel, int level)
134 {
135 all.push_back(e);
136 }
137
error(double AVG,double tol)138 void adaptivePoint::error(double AVG, double tol)
139 {
140 adaptivePoint *e = *all.begin();
141 recurError(e, AVG, tol);
142 }
143
recurError(adaptivePoint * e,double AVG,double tol)144 void adaptivePoint::recurError(adaptivePoint *e, double AVG, double tol)
145 {
146 e->visible = true;
147 }
148
create(int maxlevel)149 void adaptiveLine::create(int maxlevel)
150 {
151 cleanElement<adaptiveLine>();
152 adaptiveVertex *p1 = adaptiveVertex::add(-1, 0, 0, allVertices);
153 adaptiveVertex *p2 = adaptiveVertex::add(1, 0, 0, allVertices);
154 adaptiveLine *t = new adaptiveLine(p1, p2);
155 recurCreate(t, maxlevel, 0);
156 }
157
recurCreate(adaptiveLine * e,int maxlevel,int level)158 void adaptiveLine::recurCreate(adaptiveLine *e, int maxlevel, int level)
159 {
160 all.push_back(e);
161 if(level++ >= maxlevel) return;
162
163 // p1 p12 p2
164 adaptiveVertex *p1 = e->p[0];
165 adaptiveVertex *p2 = e->p[1];
166 adaptiveVertex *p12 =
167 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
168 (p1->z + p2->z) * 0.5, allVertices);
169 adaptiveLine *e1 = new adaptiveLine(p1, p12);
170 recurCreate(e1, maxlevel, level);
171 adaptiveLine *e2 = new adaptiveLine(p12, p2);
172 recurCreate(e2, maxlevel, level);
173 e->e[0] = e1;
174 e->e[1] = e2;
175 }
176
error(double AVG,double tol)177 void adaptiveLine::error(double AVG, double tol)
178 {
179 adaptiveLine *e = *all.begin();
180 recurError(e, AVG, tol);
181 }
182
recurError(adaptiveLine * e,double AVG,double tol)183 void adaptiveLine::recurError(adaptiveLine *e, double AVG, double tol)
184 {
185 if(!e->e[0])
186 e->visible = true;
187 else {
188 double vr;
189 if(!e->e[0]->e[0]) {
190 double v1 = e->e[0]->V();
191 double v2 = e->e[1]->V();
192 vr = (v1 + v2) / 2.;
193 double v = e->V();
194 if(fabs(v - vr) > AVG * tol) {
195 e->visible = false;
196 recurError(e->e[0], AVG, tol);
197 recurError(e->e[1], AVG, tol);
198 }
199 else
200 e->visible = true;
201 }
202 else {
203 double v11 = e->e[0]->e[0]->V();
204 double v12 = e->e[0]->e[1]->V();
205 double v21 = e->e[1]->e[0]->V();
206 double v22 = e->e[1]->e[1]->V();
207 double vr1 = (v11 + v12) / 2.;
208 double vr2 = (v21 + v22) / 2.;
209 vr = (vr1 + vr2) / 2.;
210 if(fabs(e->e[0]->V() - vr1) > AVG * tol ||
211 fabs(e->e[1]->V() - vr2) > AVG * tol ||
212 fabs(e->V() - vr) > AVG * tol) {
213 e->visible = false;
214 recurError(e->e[0], AVG, tol);
215 recurError(e->e[1], AVG, tol);
216 }
217 else
218 e->visible = true;
219 }
220 }
221 }
222
create(int maxlevel)223 void adaptiveTriangle::create(int maxlevel)
224 {
225 cleanElement<adaptiveTriangle>();
226 adaptiveVertex *p1 = adaptiveVertex::add(0, 0, 0, allVertices);
227 adaptiveVertex *p2 = adaptiveVertex::add(0, 1, 0, allVertices);
228 adaptiveVertex *p3 = adaptiveVertex::add(1, 0, 0, allVertices);
229 adaptiveTriangle *t = new adaptiveTriangle(p1, p2, p3);
230 recurCreate(t, maxlevel, 0);
231 }
232
recurCreate(adaptiveTriangle * t,int maxlevel,int level)233 void adaptiveTriangle::recurCreate(adaptiveTriangle *t, int maxlevel, int level)
234 {
235 all.push_back(t);
236 if(level++ >= maxlevel) return;
237
238 // p3
239 // p13 p23
240 // p1 p12 p2
241 adaptiveVertex *p1 = t->p[0];
242 adaptiveVertex *p2 = t->p[1];
243 adaptiveVertex *p3 = t->p[2];
244 adaptiveVertex *p12 =
245 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
246 (p1->z + p2->z) * 0.5, allVertices);
247 adaptiveVertex *p13 =
248 adaptiveVertex::add((p1->x + p3->x) * 0.5, (p1->y + p3->y) * 0.5,
249 (p1->z + p3->z) * 0.5, allVertices);
250 adaptiveVertex *p23 =
251 adaptiveVertex::add((p3->x + p2->x) * 0.5, (p3->y + p2->y) * 0.5,
252 (p3->z + p2->z) * 0.5, allVertices);
253 adaptiveTriangle *t1 = new adaptiveTriangle(p1, p12, p13);
254 recurCreate(t1, maxlevel, level);
255 adaptiveTriangle *t2 = new adaptiveTriangle(p2, p23, p12);
256 recurCreate(t2, maxlevel, level);
257 adaptiveTriangle *t3 = new adaptiveTriangle(p3, p13, p23);
258 recurCreate(t3, maxlevel, level);
259 adaptiveTriangle *t4 = new adaptiveTriangle(p12, p23, p13);
260 recurCreate(t4, maxlevel, level);
261 t->e[0] = t1;
262 t->e[1] = t2;
263 t->e[2] = t3;
264 t->e[3] = t4;
265 }
266
error(double AVG,double tol)267 void adaptiveTriangle::error(double AVG, double tol)
268 {
269 adaptiveTriangle *t = *all.begin();
270 recurError(t, AVG, tol);
271 }
272
recurError(adaptiveTriangle * t,double AVG,double tol)273 void adaptiveTriangle::recurError(adaptiveTriangle *t, double AVG, double tol)
274 {
275 if(!t->e[0])
276 t->visible = true;
277 else {
278 double vr;
279 if(!t->e[0]->e[0]) {
280 double v1 = t->e[0]->V();
281 double v2 = t->e[1]->V();
282 double v3 = t->e[2]->V();
283 double v4 = t->e[3]->V();
284 vr = (2 * v1 + 2 * v2 + 2 * v3 + v4) / 7.;
285 double v = t->V();
286 if(fabs(v - vr) > AVG * tol) {
287 t->visible = false;
288 recurError(t->e[0], AVG, tol);
289 recurError(t->e[1], AVG, tol);
290 recurError(t->e[2], AVG, tol);
291 recurError(t->e[3], AVG, tol);
292 }
293 else
294 t->visible = true;
295 }
296 else {
297 double v11 = t->e[0]->e[0]->V();
298 double v12 = t->e[0]->e[1]->V();
299 double v13 = t->e[0]->e[2]->V();
300 double v14 = t->e[0]->e[3]->V();
301 double v21 = t->e[1]->e[0]->V();
302 double v22 = t->e[1]->e[1]->V();
303 double v23 = t->e[1]->e[2]->V();
304 double v24 = t->e[1]->e[3]->V();
305 double v31 = t->e[2]->e[0]->V();
306 double v32 = t->e[2]->e[1]->V();
307 double v33 = t->e[2]->e[2]->V();
308 double v34 = t->e[2]->e[3]->V();
309 double v41 = t->e[3]->e[0]->V();
310 double v42 = t->e[3]->e[1]->V();
311 double v43 = t->e[3]->e[2]->V();
312 double v44 = t->e[3]->e[3]->V();
313 double vr1 = (2 * v11 + 2 * v12 + 2 * v13 + v14) / 7.;
314 double vr2 = (2 * v21 + 2 * v22 + 2 * v23 + v24) / 7.;
315 double vr3 = (2 * v31 + 2 * v32 + 2 * v33 + v34) / 7.;
316 double vr4 = (2 * v41 + 2 * v42 + 2 * v43 + v44) / 7.;
317 vr = (2 * vr1 + 2 * vr2 + 2 * vr3 + vr4) / 7.;
318 if(fabs(t->e[0]->V() - vr1) > AVG * tol ||
319 fabs(t->e[1]->V() - vr2) > AVG * tol ||
320 fabs(t->e[2]->V() - vr3) > AVG * tol ||
321 fabs(t->e[3]->V() - vr4) > AVG * tol ||
322 fabs(t->V() - vr) > AVG * tol) {
323 t->visible = false;
324 recurError(t->e[0], AVG, tol);
325 recurError(t->e[1], AVG, tol);
326 recurError(t->e[2], AVG, tol);
327 recurError(t->e[3], AVG, tol);
328 }
329 else
330 t->visible = true;
331 }
332 }
333 }
334
create(int maxlevel)335 void adaptiveQuadrangle::create(int maxlevel)
336 {
337 cleanElement<adaptiveQuadrangle>();
338 adaptiveVertex *p1 = adaptiveVertex::add(-1, -1, 0, allVertices);
339 adaptiveVertex *p2 = adaptiveVertex::add(1, -1, 0, allVertices);
340 adaptiveVertex *p3 = adaptiveVertex::add(1, 1, 0, allVertices);
341 adaptiveVertex *p4 = adaptiveVertex::add(-1, 1, 0, allVertices);
342 adaptiveQuadrangle *q = new adaptiveQuadrangle(p1, p2, p3, p4);
343 recurCreate(q, maxlevel, 0);
344 }
345
recurCreate(adaptiveQuadrangle * q,int maxlevel,int level)346 void adaptiveQuadrangle::recurCreate(adaptiveQuadrangle *q, int maxlevel,
347 int level)
348 {
349 all.push_back(q);
350 if(level++ >= maxlevel) return;
351
352 // p4 p34 p3
353 // p14 pc p23
354 // p1 p12 p2
355 adaptiveVertex *p1 = q->p[0];
356 adaptiveVertex *p2 = q->p[1];
357 adaptiveVertex *p3 = q->p[2];
358 adaptiveVertex *p4 = q->p[3];
359 adaptiveVertex *p12 =
360 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
361 (p1->z + p2->z) * 0.5, allVertices);
362 adaptiveVertex *p23 =
363 adaptiveVertex::add((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5,
364 (p2->z + p3->z) * 0.5, allVertices);
365 adaptiveVertex *p34 =
366 adaptiveVertex::add((p3->x + p4->x) * 0.5, (p3->y + p4->y) * 0.5,
367 (p3->z + p4->z) * 0.5, allVertices);
368 adaptiveVertex *p14 =
369 adaptiveVertex::add((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5,
370 (p1->z + p4->z) * 0.5, allVertices);
371 adaptiveVertex *pc =
372 adaptiveVertex::add((p1->x + p2->x + p3->x + p4->x) * 0.25,
373 (p1->y + p2->y + p3->y + p4->y) * 0.25,
374 (p1->z + p2->z + p3->z + p4->z) * 0.25, allVertices);
375 adaptiveQuadrangle *q1 = new adaptiveQuadrangle(p1, p12, pc, p14);
376 recurCreate(q1, maxlevel, level);
377 adaptiveQuadrangle *q2 = new adaptiveQuadrangle(p2, p23, pc, p12);
378 recurCreate(q2, maxlevel, level);
379 adaptiveQuadrangle *q3 = new adaptiveQuadrangle(p3, p34, pc, p23);
380 recurCreate(q3, maxlevel, level);
381 adaptiveQuadrangle *q4 = new adaptiveQuadrangle(p4, p14, pc, p34);
382 recurCreate(q4, maxlevel, level);
383 q->e[0] = q1;
384 q->e[1] = q2;
385 q->e[2] = q3;
386 q->e[3] = q4;
387 }
388
error(double AVG,double tol)389 void adaptiveQuadrangle::error(double AVG, double tol)
390 {
391 adaptiveQuadrangle *q = *all.begin();
392 recurError(q, AVG, tol);
393 }
394
recurError(adaptiveQuadrangle * q,double AVG,double tol)395 void adaptiveQuadrangle::recurError(adaptiveQuadrangle *q, double AVG,
396 double tol)
397 {
398 if(!q->e[0])
399 q->visible = true;
400 else {
401 double vr;
402 double vd = (q->p[0]->val + q->p[2]->val) / 2.;
403 if(!q->e[0]->e[0]) {
404 double v1 = q->e[0]->V();
405 double v2 = q->e[1]->V();
406 double v3 = q->e[2]->V();
407 double v4 = q->e[3]->V();
408 vr = (v1 + v2 + v3 + v4) / 4.;
409 double v = q->V();
410 if(fabs(v - vr) > AVG * tol || fabs(vd - vr) > AVG * tol) {
411 q->visible = false;
412 recurError(q->e[0], AVG, tol);
413 recurError(q->e[1], AVG, tol);
414 recurError(q->e[2], AVG, tol);
415 recurError(q->e[3], AVG, tol);
416 }
417 else
418 q->visible = true;
419 }
420 else {
421 double v11 = q->e[0]->e[0]->V();
422 double v12 = q->e[0]->e[1]->V();
423 double v13 = q->e[0]->e[2]->V();
424 double v14 = q->e[0]->e[3]->V();
425 double v21 = q->e[1]->e[0]->V();
426 double v22 = q->e[1]->e[1]->V();
427 double v23 = q->e[1]->e[2]->V();
428 double v24 = q->e[1]->e[3]->V();
429 double v31 = q->e[2]->e[0]->V();
430 double v32 = q->e[2]->e[1]->V();
431 double v33 = q->e[2]->e[2]->V();
432 double v34 = q->e[2]->e[3]->V();
433 double v41 = q->e[3]->e[0]->V();
434 double v42 = q->e[3]->e[1]->V();
435 double v43 = q->e[3]->e[2]->V();
436 double v44 = q->e[3]->e[3]->V();
437 double vr1 = (v11 + v12 + v13 + v14) / 4.;
438 double vr2 = (v21 + v22 + v23 + v24) / 4.;
439 double vr3 = (v31 + v32 + v33 + v34) / 4.;
440 double vr4 = (v41 + v42 + v43 + v44) / 4.;
441 vr = (vr1 + vr2 + vr3 + vr4) / 4.;
442 if(fabs(q->e[0]->V() - vr1) > AVG * tol ||
443 fabs(q->e[1]->V() - vr2) > AVG * tol ||
444 fabs(q->e[2]->V() - vr3) > AVG * tol ||
445 fabs(q->e[3]->V() - vr4) > AVG * tol ||
446 fabs(q->V() - vr) > AVG * tol || fabs(vd - vr) > AVG * tol) {
447 q->visible = false;
448 recurError(q->e[0], AVG, tol);
449 recurError(q->e[1], AVG, tol);
450 recurError(q->e[2], AVG, tol);
451 recurError(q->e[3], AVG, tol);
452 }
453 else
454 q->visible = true;
455 }
456 }
457 }
458
create(int maxlevel)459 void adaptiveTetrahedron::create(int maxlevel)
460 {
461 cleanElement<adaptiveTetrahedron>();
462 adaptiveVertex *p1 = adaptiveVertex::add(0, 0, 0, allVertices);
463 adaptiveVertex *p2 = adaptiveVertex::add(0, 1, 0, allVertices);
464 adaptiveVertex *p3 = adaptiveVertex::add(1, 0, 0, allVertices);
465 adaptiveVertex *p4 = adaptiveVertex::add(0, 0, 1, allVertices);
466 adaptiveTetrahedron *t = new adaptiveTetrahedron(p1, p2, p3, p4);
467 recurCreate(t, maxlevel, 0);
468 }
469
recurCreate(adaptiveTetrahedron * t,int maxlevel,int level)470 void adaptiveTetrahedron::recurCreate(adaptiveTetrahedron *t, int maxlevel,
471 int level)
472 {
473 all.push_back(t);
474 if(level++ >= maxlevel) return;
475
476 adaptiveVertex *p0 = t->p[0];
477 adaptiveVertex *p1 = t->p[1];
478 adaptiveVertex *p2 = t->p[2];
479 adaptiveVertex *p3 = t->p[3];
480 adaptiveVertex *pe0 =
481 adaptiveVertex::add((p0->x + p1->x) * 0.5, (p0->y + p1->y) * 0.5,
482 (p0->z + p1->z) * 0.5, allVertices);
483 adaptiveVertex *pe1 =
484 adaptiveVertex::add((p0->x + p2->x) * 0.5, (p0->y + p2->y) * 0.5,
485 (p0->z + p2->z) * 0.5, allVertices);
486 adaptiveVertex *pe2 =
487 adaptiveVertex::add((p0->x + p3->x) * 0.5, (p0->y + p3->y) * 0.5,
488 (p0->z + p3->z) * 0.5, allVertices);
489 adaptiveVertex *pe3 =
490 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
491 (p1->z + p2->z) * 0.5, allVertices);
492 adaptiveVertex *pe4 =
493 adaptiveVertex::add((p1->x + p3->x) * 0.5, (p1->y + p3->y) * 0.5,
494 (p1->z + p3->z) * 0.5, allVertices);
495 adaptiveVertex *pe5 =
496 adaptiveVertex::add((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5,
497 (p2->z + p3->z) * 0.5, allVertices);
498 adaptiveTetrahedron *t1 = new adaptiveTetrahedron(p0, pe0, pe1, pe2);
499 recurCreate(t1, maxlevel, level);
500 adaptiveTetrahedron *t2 = new adaptiveTetrahedron(pe0, p1, pe3, pe4);
501 recurCreate(t2, maxlevel, level);
502 adaptiveTetrahedron *t3 = new adaptiveTetrahedron(pe1, pe3, p2, pe5);
503 recurCreate(t3, maxlevel, level);
504 adaptiveTetrahedron *t4 = new adaptiveTetrahedron(pe2, pe4, pe5, p3);
505 recurCreate(t4, maxlevel, level);
506 adaptiveTetrahedron *t5 = new adaptiveTetrahedron(pe3, pe5, pe2, pe4);
507 recurCreate(t5, maxlevel, level);
508 adaptiveTetrahedron *t6 = new adaptiveTetrahedron(pe3, pe2, pe0, pe4);
509 recurCreate(t6, maxlevel, level);
510 adaptiveTetrahedron *t7 = new adaptiveTetrahedron(pe2, pe5, pe3, pe1);
511 recurCreate(t7, maxlevel, level);
512 adaptiveTetrahedron *t8 = new adaptiveTetrahedron(pe0, pe2, pe3, pe1);
513 recurCreate(t8, maxlevel, level);
514 t->e[0] = t1;
515 t->e[1] = t2;
516 t->e[2] = t3;
517 t->e[3] = t4;
518 t->e[4] = t5;
519 t->e[5] = t6;
520 t->e[6] = t7;
521 t->e[7] = t8;
522 }
523
error(double AVG,double tol)524 void adaptiveTetrahedron::error(double AVG, double tol)
525 {
526 adaptiveTetrahedron *t = *all.begin();
527 recurError(t, AVG, tol);
528 }
529
recurError(adaptiveTetrahedron * t,double AVG,double tol)530 void adaptiveTetrahedron::recurError(adaptiveTetrahedron *t, double AVG,
531 double tol)
532 {
533 if(!t->e[0])
534 t->visible = true;
535 else {
536 const double v1 = t->e[0]->V();
537 const double v2 = t->e[1]->V();
538 const double v3 = t->e[2]->V();
539 const double v4 = t->e[3]->V();
540 const double v5 = t->e[4]->V();
541 const double v6 = t->e[5]->V();
542 const double v7 = t->e[6]->V();
543 const double v8 = t->e[7]->V();
544 const double vr = (v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8) * .125;
545 const double v = t->V();
546 if(!t->e[0]->e[0]) {
547 if(fabs(v - vr) > AVG * tol) {
548 t->visible = false;
549 recurError(t->e[0], AVG, tol);
550 recurError(t->e[1], AVG, tol);
551 recurError(t->e[2], AVG, tol);
552 recurError(t->e[3], AVG, tol);
553 recurError(t->e[4], AVG, tol);
554 recurError(t->e[5], AVG, tol);
555 recurError(t->e[6], AVG, tol);
556 recurError(t->e[7], AVG, tol);
557 }
558 else
559 t->visible = true;
560 }
561 else {
562 double vi[8][8];
563 for(int k = 0; k < 8; k++)
564 for(int l = 0; l < 8; l++) vi[k][l] = t->e[k]->e[l]->V();
565 double vri[8];
566 for(int k = 0; k < 8; k++) {
567 vri[k] = 0.0;
568 for(int l = 0; l < 8; l++) { vri[k] += vi[k][l]; }
569 vri[k] /= 8.0;
570 }
571 if(fabs(t->e[0]->V() - vri[0]) > AVG * tol ||
572 fabs(t->e[1]->V() - vri[1]) > AVG * tol ||
573 fabs(t->e[2]->V() - vri[2]) > AVG * tol ||
574 fabs(t->e[3]->V() - vri[3]) > AVG * tol ||
575 fabs(t->e[4]->V() - vri[4]) > AVG * tol ||
576 fabs(t->e[5]->V() - vri[5]) > AVG * tol ||
577 fabs(t->e[6]->V() - vri[6]) > AVG * tol ||
578 fabs(t->e[7]->V() - vri[7]) > AVG * tol || fabs(v - vr) > AVG * tol) {
579 t->visible = false;
580 recurError(t->e[0], AVG, tol);
581 recurError(t->e[1], AVG, tol);
582 recurError(t->e[2], AVG, tol);
583 recurError(t->e[3], AVG, tol);
584 recurError(t->e[4], AVG, tol);
585 recurError(t->e[5], AVG, tol);
586 recurError(t->e[6], AVG, tol);
587 recurError(t->e[7], AVG, tol);
588 }
589 else
590 t->visible = true;
591 }
592 }
593 }
594
create(int maxlevel)595 void adaptiveHexahedron::create(int maxlevel)
596 {
597 cleanElement<adaptiveHexahedron>();
598 adaptiveVertex *p1 = adaptiveVertex::add(-1, -1, -1, allVertices);
599 adaptiveVertex *p2 = adaptiveVertex::add(-1, 1, -1, allVertices);
600 adaptiveVertex *p3 = adaptiveVertex::add(1, 1, -1, allVertices);
601 adaptiveVertex *p4 = adaptiveVertex::add(1, -1, -1, allVertices);
602 adaptiveVertex *p11 = adaptiveVertex::add(-1, -1, 1, allVertices);
603 adaptiveVertex *p21 = adaptiveVertex::add(-1, 1, 1, allVertices);
604 adaptiveVertex *p31 = adaptiveVertex::add(1, 1, 1, allVertices);
605 adaptiveVertex *p41 = adaptiveVertex::add(1, -1, 1, allVertices);
606 adaptiveHexahedron *h =
607 new adaptiveHexahedron(p1, p2, p3, p4, p11, p21, p31, p41);
608 recurCreate(h, maxlevel, 0);
609 }
610
recurCreate(adaptiveHexahedron * h,int maxlevel,int level)611 void adaptiveHexahedron::recurCreate(adaptiveHexahedron *h, int maxlevel,
612 int level)
613 {
614 all.push_back(h);
615 if(level++ >= maxlevel) return;
616
617 adaptiveVertex *p0 = h->p[0];
618 adaptiveVertex *p1 = h->p[1];
619 adaptiveVertex *p2 = h->p[2];
620 adaptiveVertex *p3 = h->p[3];
621 adaptiveVertex *p4 = h->p[4];
622 adaptiveVertex *p5 = h->p[5];
623 adaptiveVertex *p6 = h->p[6];
624 adaptiveVertex *p7 = h->p[7];
625 adaptiveVertex *p01 =
626 adaptiveVertex::add((p0->x + p1->x) * 0.5, (p0->y + p1->y) * 0.5,
627 (p0->z + p1->z) * 0.5, allVertices);
628 adaptiveVertex *p12 =
629 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
630 (p1->z + p2->z) * 0.5, allVertices);
631 adaptiveVertex *p23 =
632 adaptiveVertex::add((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5,
633 (p2->z + p3->z) * 0.5, allVertices);
634 adaptiveVertex *p03 =
635 adaptiveVertex::add((p3->x + p0->x) * 0.5, (p3->y + p0->y) * 0.5,
636 (p3->z + p0->z) * 0.5, allVertices);
637 adaptiveVertex *p45 =
638 adaptiveVertex::add((p4->x + p5->x) * 0.5, (p4->y + p5->y) * 0.5,
639 (p4->z + p5->z) * 0.5, allVertices);
640 adaptiveVertex *p56 =
641 adaptiveVertex::add((p5->x + p6->x) * 0.5, (p5->y + p6->y) * 0.5,
642 (p5->z + p6->z) * 0.5, allVertices);
643 adaptiveVertex *p67 =
644 adaptiveVertex::add((p6->x + p7->x) * 0.5, (p6->y + p7->y) * 0.5,
645 (p6->z + p7->z) * 0.5, allVertices);
646 adaptiveVertex *p47 =
647 adaptiveVertex::add((p7->x + p4->x) * 0.5, (p7->y + p4->y) * 0.5,
648 (p7->z + p4->z) * 0.5, allVertices);
649 adaptiveVertex *p04 =
650 adaptiveVertex::add((p4->x + p0->x) * 0.5, (p4->y + p0->y) * 0.5,
651 (p4->z + p0->z) * 0.5, allVertices);
652 adaptiveVertex *p15 =
653 adaptiveVertex::add((p5->x + p1->x) * 0.5, (p5->y + p1->y) * 0.5,
654 (p5->z + p1->z) * 0.5, allVertices);
655 adaptiveVertex *p26 =
656 adaptiveVertex::add((p6->x + p2->x) * 0.5, (p6->y + p2->y) * 0.5,
657 (p6->z + p2->z) * 0.5, allVertices);
658 adaptiveVertex *p37 =
659 adaptiveVertex::add((p7->x + p3->x) * 0.5, (p7->y + p3->y) * 0.5,
660 (p7->z + p3->z) * 0.5, allVertices);
661 adaptiveVertex *p0145 =
662 adaptiveVertex::add((p45->x + p01->x) * 0.5, (p45->y + p01->y) * 0.5,
663 (p45->z + p01->z) * 0.5, allVertices);
664 adaptiveVertex *p1256 =
665 adaptiveVertex::add((p12->x + p56->x) * 0.5, (p12->y + p56->y) * 0.5,
666 (p12->z + p56->z) * 0.5, allVertices);
667 adaptiveVertex *p2367 =
668 adaptiveVertex::add((p23->x + p67->x) * 0.5, (p23->y + p67->y) * 0.5,
669 (p23->z + p67->z) * 0.5, allVertices);
670 adaptiveVertex *p0347 =
671 adaptiveVertex::add((p03->x + p47->x) * 0.5, (p03->y + p47->y) * 0.5,
672 (p03->z + p47->z) * 0.5, allVertices);
673 adaptiveVertex *p4756 =
674 adaptiveVertex::add((p47->x + p56->x) * 0.5, (p47->y + p56->y) * 0.5,
675 (p47->z + p56->z) * 0.5, allVertices);
676 adaptiveVertex *p0312 =
677 adaptiveVertex::add((p03->x + p12->x) * 0.5, (p03->y + p12->y) * 0.5,
678 (p03->z + p12->z) * 0.5, allVertices);
679 adaptiveVertex *pc = adaptiveVertex::add(
680 (p0->x + p1->x + p2->x + p3->x + p4->x + p5->x + p6->x + p7->x) * 0.125,
681 (p0->y + p1->y + p2->y + p3->y + p4->y + p5->y + p6->y + p7->y) * 0.125,
682 (p0->z + p1->z + p2->z + p3->z + p4->z + p5->z + p6->z + p7->z) * 0.125,
683 allVertices);
684
685 adaptiveHexahedron *h1 =
686 new adaptiveHexahedron(p0, p01, p0312, p03, p04, p0145, pc, p0347); // p0
687 recurCreate(h1, maxlevel, level);
688 adaptiveHexahedron *h2 =
689 new adaptiveHexahedron(p01, p0145, p15, p1, p0312, pc, p1256, p12); // p1
690 recurCreate(h2, maxlevel, level);
691 adaptiveHexahedron *h3 =
692 new adaptiveHexahedron(p04, p4, p45, p0145, p0347, p47, p4756, pc); // p4
693 recurCreate(h3, maxlevel, level);
694 adaptiveHexahedron *h4 =
695 new adaptiveHexahedron(p0145, p45, p5, p15, pc, p4756, p56, p1256); // p5
696 recurCreate(h4, maxlevel, level);
697 adaptiveHexahedron *h5 =
698 new adaptiveHexahedron(p0347, p47, p4756, pc, p37, p7, p67, p2367); // p7
699 recurCreate(h5, maxlevel, level);
700 adaptiveHexahedron *h6 =
701 new adaptiveHexahedron(pc, p4756, p56, p1256, p2367, p67, p6, p26); // p6
702 recurCreate(h6, maxlevel, level);
703 adaptiveHexahedron *h7 =
704 new adaptiveHexahedron(p03, p0347, pc, p0312, p3, p37, p2367, p23); // p3
705 recurCreate(h7, maxlevel, level);
706 adaptiveHexahedron *h8 =
707 new adaptiveHexahedron(p0312, pc, p1256, p12, p23, p2367, p26, p2); // p2
708 recurCreate(h8, maxlevel, level);
709 h->e[0] = h1;
710 h->e[1] = h2;
711 h->e[2] = h3;
712 h->e[3] = h4;
713 h->e[4] = h5;
714 h->e[5] = h6;
715 h->e[6] = h7;
716 h->e[7] = h8;
717 }
718
error(double AVG,double tol)719 void adaptiveHexahedron::error(double AVG, double tol)
720 {
721 adaptiveHexahedron *h = *all.begin();
722 recurError(h, AVG, tol);
723 }
724
recurError(adaptiveHexahedron * h,double AVG,double tol)725 void adaptiveHexahedron::recurError(adaptiveHexahedron *h, double AVG,
726 double tol)
727 {
728 if(!h->e[0])
729 h->visible = true;
730 else {
731 const double v1 = h->e[0]->V();
732 const double v2 = h->e[1]->V();
733 const double v3 = h->e[2]->V();
734 const double v4 = h->e[3]->V();
735 const double v5 = h->e[4]->V();
736 const double v6 = h->e[5]->V();
737 const double v7 = h->e[6]->V();
738 const double v8 = h->e[7]->V();
739 const double vr = (v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8) * .125;
740 const double v = h->V();
741 // we use diagonal 1-7 because it's the one used for drawing
742 const double vd = (h->p[1]->val + h->p[7]->val) / 2.;
743 if(!h->e[0]->e[0]) {
744 if(fabs(v - vr) > AVG * tol || fabs(vd - vr) > AVG * tol) {
745 h->visible = false;
746 recurError(h->e[0], AVG, tol);
747 recurError(h->e[1], AVG, tol);
748 recurError(h->e[2], AVG, tol);
749 recurError(h->e[3], AVG, tol);
750 recurError(h->e[4], AVG, tol);
751 recurError(h->e[5], AVG, tol);
752 recurError(h->e[6], AVG, tol);
753 recurError(h->e[7], AVG, tol);
754 }
755 else
756 h->visible = true;
757 }
758 else {
759 double vii[8][8];
760 for(int i = 0; i < 8; i++)
761 for(int j = 0; j < 8; j++) vii[i][j] = h->e[i]->e[j]->V();
762 double vri[8];
763 for(int k = 0; k < 8; k++) {
764 vri[k] = 0.0;
765 for(int l = 0; l < 8; l++) { vri[k] += vii[k][l]; }
766 vri[k] /= 8.0;
767 }
768 if(fabs(h->e[0]->V() - vri[0]) > AVG * tol ||
769 fabs(h->e[1]->V() - vri[1]) > AVG * tol ||
770 fabs(h->e[2]->V() - vri[2]) > AVG * tol ||
771 fabs(h->e[3]->V() - vri[3]) > AVG * tol ||
772 fabs(h->e[4]->V() - vri[4]) > AVG * tol ||
773 fabs(h->e[5]->V() - vri[5]) > AVG * tol ||
774 fabs(h->e[6]->V() - vri[6]) > AVG * tol ||
775 fabs(h->e[7]->V() - vri[7]) > AVG * tol || fabs(v - vr) > AVG * tol ||
776 fabs(vd - vr) > AVG * tol) {
777 h->visible = false;
778 recurError(h->e[0], AVG, tol);
779 recurError(h->e[1], AVG, tol);
780 recurError(h->e[2], AVG, tol);
781 recurError(h->e[3], AVG, tol);
782 recurError(h->e[4], AVG, tol);
783 recurError(h->e[5], AVG, tol);
784 recurError(h->e[6], AVG, tol);
785 recurError(h->e[7], AVG, tol);
786 }
787 else
788 h->visible = true;
789 }
790 }
791 }
792
create(int maxlevel)793 void adaptivePrism::create(int maxlevel)
794 {
795 cleanElement<adaptivePrism>();
796 adaptiveVertex *p1 = adaptiveVertex::add(0, 0, -1, allVertices);
797 adaptiveVertex *p2 = adaptiveVertex::add(1, 0, -1, allVertices);
798 adaptiveVertex *p3 = adaptiveVertex::add(0, 1, -1, allVertices);
799 adaptiveVertex *p4 = adaptiveVertex::add(0, 0, 1, allVertices);
800 adaptiveVertex *p5 = adaptiveVertex::add(1, 0, 1, allVertices);
801 adaptiveVertex *p6 = adaptiveVertex::add(0, 1, 1, allVertices);
802 adaptivePrism *p = new adaptivePrism(p1, p2, p3, p4, p5, p6);
803 recurCreate(p, maxlevel, 0);
804 }
805
recurCreate(adaptivePrism * p,int maxlevel,int level)806 void adaptivePrism::recurCreate(adaptivePrism *p, int maxlevel, int level)
807 {
808 all.push_back(p);
809 if(level++ >= maxlevel) return;
810
811 // p4 p34 p3
812 // p14 pc p23
813 // p1 p12 p2
814 adaptiveVertex *p1 = p->p[0];
815 adaptiveVertex *p2 = p->p[1];
816 adaptiveVertex *p3 = p->p[2];
817 adaptiveVertex *p4 = p->p[3];
818 adaptiveVertex *p5 = p->p[4];
819 adaptiveVertex *p6 = p->p[5];
820 adaptiveVertex *p14 =
821 adaptiveVertex::add((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5,
822 (p1->z + p4->z) * 0.5, allVertices);
823 adaptiveVertex *p25 =
824 adaptiveVertex::add((p2->x + p5->x) * 0.5, (p2->y + p5->y) * 0.5,
825 (p2->z + p5->z) * 0.5, allVertices);
826 adaptiveVertex *p36 =
827 adaptiveVertex::add((p3->x + p6->x) * 0.5, (p3->y + p6->y) * 0.5,
828 (p3->z + p6->z) * 0.5, allVertices);
829 adaptiveVertex *p12 =
830 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
831 (p1->z + p2->z) * 0.5, allVertices);
832 adaptiveVertex *p23 =
833 adaptiveVertex::add((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5,
834 (p2->z + p3->z) * 0.5, allVertices);
835 adaptiveVertex *p31 =
836 adaptiveVertex::add((p3->x + p1->x) * 0.5, (p3->y + p1->y) * 0.5,
837 (p3->z + p1->z) * 0.5, allVertices);
838 adaptiveVertex *p1425 =
839 adaptiveVertex::add((p14->x + p25->x) * 0.5, (p14->y + p25->y) * 0.5,
840 (p14->z + p25->z) * 0.5, allVertices);
841 adaptiveVertex *p2536 =
842 adaptiveVertex::add((p25->x + p36->x) * 0.5, (p25->y + p36->y) * 0.5,
843 (p25->z + p36->z) * 0.5, allVertices);
844 adaptiveVertex *p3614 =
845 adaptiveVertex::add((p36->x + p14->x) * 0.5, (p36->y + p14->y) * 0.5,
846 (p36->z + p14->z) * 0.5, allVertices);
847 adaptiveVertex *p45 =
848 adaptiveVertex::add((p4->x + p5->x) * 0.5, (p4->y + p5->y) * 0.5,
849 (p4->z + p5->z) * 0.5, allVertices);
850 adaptiveVertex *p56 =
851 adaptiveVertex::add((p5->x + p6->x) * 0.5, (p5->y + p6->y) * 0.5,
852 (p5->z + p6->z) * 0.5, allVertices);
853 adaptiveVertex *p64 =
854 adaptiveVertex::add((p6->x + p4->x) * 0.5, (p6->y + p4->y) * 0.5,
855 (p6->z + p4->z) * 0.5, allVertices);
856 p->e[0] = new adaptivePrism(p1, p12, p31, p14, p1425, p3614);
857 recurCreate(p->e[0], maxlevel, level);
858 p->e[1] = new adaptivePrism(p2, p23, p12, p25, p2536, p1425);
859 recurCreate(p->e[1], maxlevel, level);
860 p->e[2] = new adaptivePrism(p3, p31, p23, p36, p3614, p2536);
861 recurCreate(p->e[2], maxlevel, level);
862 p->e[3] = new adaptivePrism(p12, p23, p31, p1425, p2536, p3614);
863 recurCreate(p->e[3], maxlevel, level);
864 p->e[4] = new adaptivePrism(p14, p1425, p3614, p4, p45, p64);
865 recurCreate(p->e[4], maxlevel, level);
866 p->e[5] = new adaptivePrism(p25, p2536, p1425, p5, p56, p45);
867 recurCreate(p->e[5], maxlevel, level);
868 p->e[6] = new adaptivePrism(p36, p3614, p2536, p6, p64, p56);
869 recurCreate(p->e[6], maxlevel, level);
870 p->e[7] = new adaptivePrism(p1425, p2536, p3614, p45, p56, p64);
871 recurCreate(p->e[7], maxlevel, level);
872 }
873
error(double AVG,double tol)874 void adaptivePrism::error(double AVG, double tol)
875 {
876 adaptivePrism *p = *all.begin();
877 recurError(p, AVG, tol);
878 }
879
recurError(adaptivePrism * p,double AVG,double tol)880 void adaptivePrism::recurError(adaptivePrism *p, double AVG, double tol)
881 {
882 if(!p->e[0])
883 p->visible = true;
884 else {
885 double vi[8];
886 for(int i = 0; i < 8; i++) vi[i] = p->e[i]->V();
887 const double vr =
888 (vi[0] + vi[1] + vi[2] + vi[3] / 2 + vi[4] + vi[5] + vi[6] + vi[7] / 2) /
889 7;
890 const double v = p->V();
891 if(!p->e[0]->e[0]) {
892 if(fabs(v - vr) > AVG * tol) {
893 p->visible = false;
894 recurError(p->e[0], AVG, tol);
895 recurError(p->e[1], AVG, tol);
896 recurError(p->e[2], AVG, tol);
897 recurError(p->e[3], AVG, tol);
898 recurError(p->e[4], AVG, tol);
899 recurError(p->e[5], AVG, tol);
900 recurError(p->e[6], AVG, tol);
901 recurError(p->e[7], AVG, tol);
902 }
903 else
904 p->visible = true;
905 }
906 else {
907 bool err = false;
908 for(int i = 0; i < 8; i++) {
909 double vi1 = p->e[i]->e[0]->V();
910 double vi2 = p->e[i]->e[1]->V();
911 double vi3 = p->e[i]->e[2]->V();
912 double vi4 = p->e[i]->e[3]->V();
913 double vi5 = p->e[i]->e[4]->V();
914 double vi6 = p->e[i]->e[5]->V();
915 double vi7 = p->e[i]->e[6]->V();
916 double vi8 = p->e[i]->e[7]->V();
917 double vri =
918 (vi1 + vi2 + vi3 + vi4 / 2 + vi5 + vi6 + vi7 + vi8 / 2) / 7;
919 err |= (fabs((vi[i] - vri)) > AVG * tol);
920 }
921 err |= (fabs((v - vr)) > AVG * tol);
922 if(err) {
923 p->visible = false;
924 for(int i = 0; i < 8; i++) recurError(p->e[i], AVG, tol);
925 }
926 else
927 p->visible = true;
928 }
929 }
930 }
931
create(int maxlevel)932 void adaptivePyramid::create(int maxlevel)
933 {
934 cleanElement<adaptivePyramid>();
935 adaptiveVertex *p1 = adaptiveVertex::add(-1, -1, 0, allVertices);
936 adaptiveVertex *p2 = adaptiveVertex::add(1, -1, 0, allVertices);
937 adaptiveVertex *p3 = adaptiveVertex::add(1, 1, 0, allVertices);
938 adaptiveVertex *p4 = adaptiveVertex::add(-1, 1, 0, allVertices);
939 adaptiveVertex *p5 = adaptiveVertex::add(0, 0, 1, allVertices);
940 adaptivePyramid *p = new adaptivePyramid(p1, p2, p3, p4, p5);
941 recurCreate(p, maxlevel, 0);
942 }
943
recurCreate(adaptivePyramid * p,int maxlevel,int level)944 void adaptivePyramid::recurCreate(adaptivePyramid *p, int maxlevel, int level)
945 {
946 all.push_back(p);
947 if(level++ >= maxlevel) return;
948
949 // quad points
950 adaptiveVertex *p1 = p->p[0];
951 adaptiveVertex *p2 = p->p[1];
952 adaptiveVertex *p3 = p->p[2];
953 adaptiveVertex *p4 = p->p[3];
954
955 // apex
956 adaptiveVertex *p5 = p->p[4];
957
958 // center of the quad
959
960 adaptiveVertex *p1234 =
961 adaptiveVertex::add((p1->x + p2->x + p3->x + p4->x) * 0.25,
962 (p1->y + p2->y + p3->y + p4->y) * 0.25,
963 (p1->z + p2->z + p3->z + p4->z) * 0.25, allVertices);
964
965 // quad edge points
966
967 adaptiveVertex *p12 =
968 adaptiveVertex::add((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5,
969 (p1->z + p2->z) * 0.5, allVertices);
970
971 adaptiveVertex *p23 =
972 adaptiveVertex::add((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5,
973 (p2->z + p3->z) * 0.5, allVertices);
974
975 adaptiveVertex *p34 =
976 adaptiveVertex::add((p3->x + p4->x) * 0.5, (p3->y + p4->y) * 0.5,
977 (p3->z + p4->z) * 0.5, allVertices);
978
979 adaptiveVertex *p41 =
980 adaptiveVertex::add((p4->x + p1->x) * 0.5, (p4->y + p1->y) * 0.5,
981 (p4->z + p1->z) * 0.5, allVertices);
982
983 // quad vertex to apex edge points
984
985 adaptiveVertex *p15 =
986 adaptiveVertex::add((p1->x + p5->x) * 0.5, (p1->y + p5->y) * 0.5,
987 (p1->z + p5->z) * 0.5, allVertices);
988
989 adaptiveVertex *p25 =
990 adaptiveVertex::add((p2->x + p5->x) * 0.5, (p2->y + p5->y) * 0.5,
991 (p2->z + p5->z) * 0.5, allVertices);
992
993 adaptiveVertex *p35 =
994 adaptiveVertex::add((p3->x + p5->x) * 0.5, (p3->y + p5->y) * 0.5,
995 (p3->z + p5->z) * 0.5, allVertices);
996
997 adaptiveVertex *p45 =
998 adaptiveVertex::add((p4->x + p5->x) * 0.5, (p4->y + p5->y) * 0.5,
999 (p4->z + p5->z) * 0.5, allVertices);
1000
1001 // four base pyramids on the quad base
1002
1003 p->e[0] = new adaptivePyramid(p1, p12, p1234, p41, p15);
1004 recurCreate(p->e[0], maxlevel, level);
1005 p->e[1] = new adaptivePyramid(p2, p23, p1234, p12, p25);
1006 recurCreate(p->e[1], maxlevel, level);
1007 p->e[2] = new adaptivePyramid(p3, p34, p1234, p23, p35);
1008 recurCreate(p->e[2], maxlevel, level);
1009 p->e[3] = new adaptivePyramid(p4, p41, p1234, p34, p45);
1010 recurCreate(p->e[3], maxlevel, level);
1011
1012 // top pyramids
1013
1014 p->e[4] = new adaptivePyramid(p15, p25, p35, p45, p5);
1015 recurCreate(p->e[4], maxlevel, level);
1016 p->e[5] = new adaptivePyramid(p15, p45, p35, p25, p1234);
1017 recurCreate(p->e[5], maxlevel, level);
1018
1019 // degenerated pyramids to replace the remaining tetrahedral holes
1020 // degenerated quad in the interior of the element, apices on the quad edges
1021
1022 p->e[6] = new adaptivePyramid(p1234, p25, p15, p1234, p12);
1023 recurCreate(p->e[6], maxlevel, level);
1024 p->e[7] = new adaptivePyramid(p1234, p35, p25, p1234, p23);
1025 recurCreate(p->e[7], maxlevel, level);
1026 p->e[8] = new adaptivePyramid(p1234, p45, p35, p1234, p34);
1027 recurCreate(p->e[8], maxlevel, level);
1028 p->e[9] = new adaptivePyramid(p1234, p15, p45, p1234, p41);
1029 recurCreate(p->e[9], maxlevel, level);
1030 }
1031
error(double AVG,double tol)1032 void adaptivePyramid::error(double AVG, double tol)
1033 {
1034 adaptivePyramid *p = *all.begin();
1035 recurError(p, AVG, tol);
1036 }
1037
recurError(adaptivePyramid * p,double AVG,double tol)1038 void adaptivePyramid::recurError(adaptivePyramid *p, double AVG, double tol)
1039 {
1040 if(!p->e[0])
1041 p->visible = true;
1042 else {
1043 double vi[10];
1044 for(int i = 0; i < 10; i++) vi[i] = p->e[i]->V();
1045 double vr = 0;
1046 for(int i = 0; i < 6; i++) vr += vi[i]; // pyramids have volume V/8
1047 for(int i = 6; i < 10; i++)
1048 vr += vi[i] * 0.5; // tetrahedra have volume V/16
1049 vr /= 8.;
1050 const double v = p->V();
1051 if(!p->e[0]->e[0]) {
1052 if(fabs(v - vr) > AVG * tol) {
1053 p->visible = false;
1054 for(int i = 0; i < 10; i++) recurError(p->e[i], AVG, tol);
1055 }
1056 else
1057 p->visible = true;
1058 }
1059 else {
1060 bool err = false;
1061 for(int i = 0; i < 10; i++) {
1062 double vj[10];
1063 for(int j = 0; j < 10; j++) vj[j] = p->e[i]->e[j]->V();
1064 double vri = 0;
1065 for(int j = 0; j < 6; j++) vri += vj[j];
1066 for(int j = 6; j < 10; j++) vri += vj[j] * 0.5;
1067 vri /= 8.;
1068 err |= (fabs((vi[i] - vri)) > AVG * tol);
1069 }
1070 err |= (fabs((v - vr)) > AVG * tol);
1071 if(err) {
1072 p->visible = false;
1073 for(int i = 0; i < 10; i++) recurError(p->e[i], AVG, tol);
1074 }
1075 else
1076 p->visible = true;
1077 }
1078 }
1079 }
1080
1081 template <class T>
adaptiveElements(std::vector<fullMatrix<double> * > & p)1082 adaptiveElements<T>::adaptiveElements(std::vector<fullMatrix<double> *> &p)
1083 : _coeffsVal(nullptr), _eexpsVal(nullptr), _interpolVal(nullptr),
1084 _coeffsGeom(nullptr), _eexpsGeom(nullptr), _interpolGeom(nullptr)
1085 {
1086 if(p.size() >= 2) {
1087 _coeffsVal = p[0];
1088 _eexpsVal = p[1];
1089 }
1090 if(p.size() == 4) {
1091 _coeffsGeom = p[2];
1092 _eexpsGeom = p[3];
1093 }
1094 }
1095
~adaptiveElements()1096 template <class T> adaptiveElements<T>::~adaptiveElements()
1097 {
1098 if(_interpolVal) delete _interpolVal;
1099 if(_interpolGeom) delete _interpolGeom;
1100 cleanElement<T>();
1101 }
1102
init(int level)1103 template <class T> void adaptiveElements<T>::init(int level)
1104 {
1105 #ifdef TIMER
1106 double t1 = TimeOfDay();
1107 #endif
1108
1109 T::create(level);
1110 int numVals = _coeffsVal ? _coeffsVal->size1() : T::numNodes;
1111 int numNodes = _coeffsGeom ? _coeffsGeom->size1() : T::numNodes;
1112
1113 if(_interpolVal) delete _interpolVal;
1114 _interpolVal = new fullMatrix<double>(T::allVertices.size(), numVals);
1115
1116 if(_interpolGeom) delete _interpolGeom;
1117 _interpolGeom = new fullMatrix<double>(T::allVertices.size(), numNodes);
1118
1119 fullVector<double> sfv(numVals), *tmpv = nullptr;
1120 fullVector<double> sfg(numNodes), *tmpg = nullptr;
1121 if(_eexpsVal) tmpv = new fullVector<double>(_eexpsVal->size1());
1122 if(_eexpsGeom) tmpg = new fullVector<double>(_eexpsGeom->size1());
1123
1124 int i = 0;
1125 for(auto it = T::allVertices.begin(); it != T::allVertices.end(); ++it) {
1126 if(_coeffsVal && _eexpsVal)
1127 computeShapeFunctions(_coeffsVal, _eexpsVal, it->x, it->y, it->z, &sfv,
1128 tmpv);
1129 else
1130 T::GSF(it->x, it->y, it->z, sfv);
1131 for(int j = 0; j < numVals; j++) (*_interpolVal)(i, j) = sfv(j);
1132
1133 if(_coeffsGeom && _eexpsGeom)
1134 computeShapeFunctions(_coeffsGeom, _eexpsGeom, it->x, it->y, it->z, &sfg,
1135 tmpg);
1136 else
1137 T::GSF(it->x, it->y, it->z, sfg);
1138 for(int j = 0; j < numNodes; j++) (*_interpolGeom)(i, j) = sfg(j);
1139
1140 i++;
1141 }
1142
1143 if(tmpv) delete tmpv;
1144 if(tmpg) delete tmpg;
1145
1146 #ifdef TIMER
1147 adaptiveData::timerInit += TimeOfDay() - t1;
1148 return;
1149 #endif
1150 }
1151
init(int level)1152 template <> void adaptiveElements<adaptivePyramid>::init(int level)
1153 {
1154 #ifdef TIMER
1155 double t1 = TimeOfDay();
1156 #endif
1157
1158 adaptivePyramid::create(level);
1159 int numVals = _coeffsVal ? _coeffsVal->size1() : adaptivePyramid::numNodes;
1160 int numNodes = _coeffsGeom ? _coeffsGeom->size1() : adaptivePyramid::numNodes;
1161
1162 if(_interpolVal) delete _interpolVal;
1163 _interpolVal =
1164 new fullMatrix<double>(adaptivePyramid::allVertices.size(), numVals);
1165
1166 if(_interpolGeom) delete _interpolGeom;
1167 _interpolGeom =
1168 new fullMatrix<double>(adaptivePyramid::allVertices.size(), numNodes);
1169
1170 fullVector<double> sfv(numVals), *tmpv = nullptr;
1171 fullVector<double> sfg(numNodes), *tmpg = nullptr;
1172 if(_eexpsVal) tmpv = new fullVector<double>(_eexpsVal->size1());
1173 if(_eexpsGeom) tmpg = new fullVector<double>(_eexpsGeom->size1());
1174
1175 int i = 0;
1176 for(auto it = adaptivePyramid::allVertices.begin();
1177 it != adaptivePyramid::allVertices.end(); ++it) {
1178 if(_coeffsVal && _eexpsVal)
1179 computeShapeFunctionsPyramid(_coeffsVal, _eexpsVal, it->x, it->y, it->z,
1180 &sfv, tmpv);
1181 else
1182 adaptivePyramid::GSF(it->x, it->y, it->z, sfv);
1183
1184 for(int j = 0; j < numVals; j++) (*_interpolVal)(i, j) = sfv(j);
1185
1186 if(_coeffsGeom && _eexpsGeom)
1187 computeShapeFunctionsPyramid(_coeffsGeom, _eexpsGeom, it->x, it->y, it->z,
1188 &sfg, tmpg);
1189 else
1190 adaptivePyramid::GSF(it->x, it->y, it->z, sfg);
1191 for(int j = 0; j < numNodes; j++) (*_interpolGeom)(i, j) = sfg(j);
1192
1193 i++;
1194 }
1195
1196 if(tmpv) delete tmpv;
1197 if(tmpg) delete tmpg;
1198
1199 #ifdef TIMER
1200 adaptiveData::timerInit += TimeOfDay() - t1;
1201 return;
1202 #endif
1203 }
1204
1205 template <class T>
adapt(double tol,int numComp,std::vector<PCoords> & coords,std::vector<PValues> & values,double & minVal,double & maxVal,GMSH_PostPlugin * plug,bool onlyComputeMinMax)1206 bool adaptiveElements<T>::adapt(double tol, int numComp,
1207 std::vector<PCoords> &coords,
1208 std::vector<PValues> &values, double &minVal,
1209 double &maxVal, GMSH_PostPlugin *plug,
1210 bool onlyComputeMinMax)
1211 {
1212 int numVertices = T::allVertices.size();
1213
1214 if(!numVertices) {
1215 Msg::Warning("No adapted vertices to interpolate");
1216 return false;
1217 }
1218
1219 int numVals = _coeffsVal ? _coeffsVal->size1() : T::numNodes;
1220
1221 if(numVals != (int)values.size()) {
1222 Msg::Warning("Wrong number of values in adaptation %d != %i", numVals,
1223 values.size());
1224 return false;
1225 }
1226
1227 #ifdef TIMER
1228 double t1 = TimeOfDay();
1229 #endif
1230
1231 fullVector<double> val(numVals), res(numVertices);
1232 switch(numComp) {
1233 case 1: {
1234 for(int i = 0; i < numVals; i++) val(i) = values[i].v[0];
1235 break;
1236 }
1237 case 3:
1238 case 9: {
1239 for(int i = 0; i < numVals; i++) {
1240 val(i) = 0;
1241 for(int k = 0; k < numComp; k++)
1242 val(i) += values[i].v[k] * values[i].v[k];
1243 }
1244 break;
1245 }
1246 default: {
1247 Msg::Error("Can only adapt scalar, vector or tensor data");
1248 return false;
1249 }
1250 }
1251
1252 _interpolVal->mult(val, res);
1253
1254 // minVal = VAL_INF;
1255 // maxVal = -VAL_INF;
1256 for(int i = 0; i < numVertices; i++) {
1257 minVal = std::min(minVal, res(i));
1258 maxVal = std::max(maxVal, res(i));
1259 }
1260 if(onlyComputeMinMax) return true;
1261
1262 fullMatrix<double> *resxyz = nullptr;
1263 if(numComp == 3 || numComp == 9) {
1264 fullMatrix<double> valxyz(numVals, numComp);
1265 resxyz = new fullMatrix<double>(numVertices, numComp);
1266 for(int i = 0; i < numVals; i++) {
1267 for(int k = 0; k < numComp; k++) { valxyz(i, k) = values[i].v[k]; }
1268 }
1269 _interpolVal->mult(valxyz, *resxyz);
1270 }
1271
1272 int numNodes = _coeffsGeom ? _coeffsGeom->size1() : T::numNodes;
1273 if(numNodes != (int)coords.size()) {
1274 Msg::Error("Wrong number of nodes in adaptation %d != %i", numNodes,
1275 coords.size());
1276 if(resxyz) delete resxyz;
1277 return false;
1278 }
1279
1280 fullMatrix<double> xyz(numNodes, 3), XYZ(numVertices, 3);
1281 for(int i = 0; i < numNodes; i++) {
1282 xyz(i, 0) = coords[i].c[0];
1283 xyz(i, 1) = coords[i].c[1];
1284 xyz(i, 2) = coords[i].c[2];
1285 }
1286 _interpolGeom->mult(xyz, XYZ);
1287
1288 #ifdef TIMER
1289 adaptiveData::timerAdapt += TimeOfDay() - t1;
1290 return true;
1291 #endif
1292
1293 int i = 0;
1294 for(auto it = T::allVertices.begin(); it != T::allVertices.end(); ++it) {
1295 // ok because we know this will not change the set ordering
1296 adaptiveVertex *p = (adaptiveVertex *)&(*it);
1297 p->val = res(i);
1298 if(resxyz) {
1299 p->val = (*resxyz)(i, 0);
1300 p->valy = (*resxyz)(i, 1);
1301 p->valz = (*resxyz)(i, 2);
1302 if(numComp == 9) {
1303 p->valyx = (*resxyz)(i, 3);
1304 p->valyy = (*resxyz)(i, 4);
1305 p->valyz = (*resxyz)(i, 5);
1306 p->valzx = (*resxyz)(i, 6);
1307 p->valzy = (*resxyz)(i, 7);
1308 p->valzz = (*resxyz)(i, 8);
1309 }
1310 }
1311 p->X = XYZ(i, 0);
1312 p->Y = XYZ(i, 1);
1313 p->Z = XYZ(i, 2);
1314 i++;
1315 }
1316
1317 if(resxyz) delete resxyz;
1318
1319 for(auto it = T::all.begin(); it != T::all.end(); it++)
1320 (*it)->visible = false;
1321
1322 if(!plug || tol != 0.) {
1323 double avg = fabs(maxVal - minVal);
1324 if(tol < 0) avg = 1.; // force visibility to the smallest subdivision
1325 T::error(avg, tol);
1326 }
1327
1328 if(plug) plug->assignSpecificVisibility();
1329
1330 coords.clear();
1331 values.clear();
1332 for(auto it = T::all.begin(); it != T::all.end(); it++) {
1333 if((*it)->visible) {
1334 adaptiveVertex **p = (*it)->p;
1335 for(int i = 0; i < T::numNodes; i++) {
1336 coords.push_back(PCoords(p[i]->X, p[i]->Y, p[i]->Z));
1337 switch(numComp) {
1338 case 1: values.push_back(PValues(p[i]->val)); break;
1339 case 3:
1340 values.push_back(PValues(p[i]->val, p[i]->valy, p[i]->valz));
1341 break;
1342 case 9:
1343 values.push_back(PValues(p[i]->val, p[i]->valy, p[i]->valz,
1344 p[i]->valyx, p[i]->valyy, p[i]->valyz,
1345 p[i]->valzx, p[i]->valzy, p[i]->valzz));
1346 break;
1347 }
1348 }
1349 }
1350 }
1351
1352 return true;
1353 }
1354
1355 template <class T>
addInView(double tol,int step,PViewData * in,PViewDataList * out,GMSH_PostPlugin * plug)1356 void adaptiveElements<T>::addInView(double tol, int step, PViewData *in,
1357 PViewDataList *out, GMSH_PostPlugin *plug)
1358 {
1359 int numComp = in->getNumComponents(0, 0, 0);
1360 if(numComp != 1 && numComp != 3 && numComp != 9) return;
1361
1362 int numEle = 0, *outNb = nullptr;
1363 std::vector<double> *outList = nullptr;
1364 switch(T::numEdges) {
1365 case 0:
1366 numEle = in->getNumPoints();
1367 outNb =
1368 (numComp == 1) ? &out->NbSP : ((numComp == 3) ? &out->NbVP : &out->NbTP);
1369 outList =
1370 (numComp == 1) ? &out->SP : ((numComp == 3) ? &out->VP : &out->TP);
1371 break;
1372 case 1:
1373 numEle = in->getNumLines();
1374 outNb =
1375 (numComp == 1) ? &out->NbSL : ((numComp == 3) ? &out->NbVL : &out->NbTL);
1376 outList =
1377 (numComp == 1) ? &out->SL : ((numComp == 3) ? &out->VL : &out->TL);
1378 break;
1379 case 3:
1380 numEle = in->getNumTriangles();
1381 outNb =
1382 (numComp == 1) ? &out->NbST : ((numComp == 3) ? &out->NbVT : &out->NbTT);
1383 outList =
1384 (numComp == 1) ? &out->ST : ((numComp == 3) ? &out->VT : &out->TT);
1385 break;
1386 case 4:
1387 numEle = in->getNumQuadrangles();
1388 outNb =
1389 (numComp == 1) ? &out->NbSQ : ((numComp == 3) ? &out->NbVQ : &out->NbTQ);
1390 outList =
1391 (numComp == 1) ? &out->SQ : ((numComp == 3) ? &out->VQ : &out->TQ);
1392 break;
1393 case 6:
1394 numEle = in->getNumTetrahedra();
1395 outNb =
1396 (numComp == 1) ? &out->NbSS : ((numComp == 3) ? &out->NbVS : &out->NbTS);
1397 outList =
1398 (numComp == 1) ? &out->SS : ((numComp == 3) ? &out->VS : &out->TS);
1399 break;
1400 case 9:
1401 numEle = in->getNumPrisms();
1402 outNb =
1403 (numComp == 1) ? &out->NbSI : ((numComp == 3) ? &out->NbVI : &out->NbTI);
1404 outList =
1405 (numComp == 1) ? &out->SI : ((numComp == 3) ? &out->VI : &out->TI);
1406 break;
1407 case 8:
1408 numEle = in->getNumPyramids();
1409 outNb =
1410 (numComp == 1) ? &out->NbSY : ((numComp == 3) ? &out->NbVY : &out->NbTY);
1411 outList =
1412 (numComp == 1) ? &out->SY : ((numComp == 3) ? &out->VY : &out->TY);
1413 break;
1414 case 12:
1415 numEle = in->getNumHexahedra();
1416 outNb =
1417 (numComp == 1) ? &out->NbSH : ((numComp == 3) ? &out->NbVH : &out->NbTH);
1418 outList =
1419 (numComp == 1) ? &out->SH : ((numComp == 3) ? &out->VH : &out->TH);
1420 break;
1421 }
1422 if(!numEle) return;
1423
1424 outList->clear();
1425 *outNb = 0;
1426
1427 for(int ent = 0; ent < in->getNumEntities(step); ent++) {
1428 for(int ele = 0; ele < in->getNumElements(step, ent); ele++) {
1429 if(in->skipElement(step, ent, ele) ||
1430 in->getNumEdges(step, ent, ele) != T::numEdges)
1431 continue;
1432 int numNodes = in->getNumNodes(step, ent, ele);
1433 std::vector<PCoords> coords;
1434 for(int i = 0; i < numNodes; i++) {
1435 double x, y, z;
1436 in->getNode(step, ent, ele, i, x, y, z);
1437 coords.push_back(PCoords(x, y, z));
1438 }
1439 int numVal = in->getNumValues(step, ent, ele);
1440 std::vector<PValues> values;
1441
1442 switch(numComp) {
1443 case 1:
1444 for(int i = 0; i < numVal; i++) {
1445 double val;
1446 in->getValue(step, ent, ele, i, val);
1447 values.push_back(PValues(val));
1448 }
1449 break;
1450 case 3: {
1451 for(int i = 0; i < numVal / 3; i++) {
1452 double vx, vy, vz;
1453 in->getValue(step, ent, ele, 3 * i + 0, vx);
1454 in->getValue(step, ent, ele, 3 * i + 1, vy);
1455 in->getValue(step, ent, ele, 3 * i + 2, vz);
1456 values.push_back(PValues(vx, vy, vz));
1457 }
1458 break;
1459 }
1460 case 9: {
1461 for(int i = 0; i < numVal / 9; i++) {
1462 double vxx, vxy, vxz, vyx, vyy, vyz, vzx, vzy, vzz;
1463 in->getValue(step, ent, ele, 9 * i + 0, vxx);
1464 in->getValue(step, ent, ele, 9 * i + 1, vxy);
1465 in->getValue(step, ent, ele, 9 * i + 2, vxz);
1466 in->getValue(step, ent, ele, 9 * i + 3, vyx);
1467 in->getValue(step, ent, ele, 9 * i + 4, vyy);
1468 in->getValue(step, ent, ele, 9 * i + 5, vyz);
1469 in->getValue(step, ent, ele, 9 * i + 6, vzx);
1470 in->getValue(step, ent, ele, 9 * i + 7, vzy);
1471 in->getValue(step, ent, ele, 9 * i + 8, vzz);
1472 values.push_back(
1473 PValues(vxx, vxy, vxz, vyx, vyy, vyz, vzx, vzy, vzz));
1474 }
1475 break;
1476 }
1477 }
1478 if(adapt(tol, numComp, coords, values, out->Min, out->Max, plug)) {
1479 *outNb += coords.size() / T::numNodes;
1480 for(std::size_t i = 0; i < coords.size() / T::numNodes; i++) {
1481 for(int k = 0; k < T::numNodes; ++k)
1482 outList->push_back(coords[T::numNodes * i + k].c[0]);
1483 for(int k = 0; k < T::numNodes; ++k)
1484 outList->push_back(coords[T::numNodes * i + k].c[1]);
1485 for(int k = 0; k < T::numNodes; ++k)
1486 outList->push_back(coords[T::numNodes * i + k].c[2]);
1487 for(int k = 0; k < T::numNodes; ++k)
1488 for(int l = 0; l < numComp; ++l)
1489 outList->push_back(values[T::numNodes * i + k].v[l]);
1490 }
1491 }
1492 }
1493 }
1494 }
1495
adaptiveData(PViewData * data,bool outDataInit)1496 adaptiveData::adaptiveData(PViewData *data, bool outDataInit)
1497 : _step(-1), _level(-1), _tol(-1.), _inData(data), _points(nullptr),
1498 _lines(nullptr), _triangles(nullptr), _quadrangles(nullptr),
1499 _tetrahedra(nullptr), _hexahedra(nullptr), _prisms(nullptr),
1500 _pyramids(nullptr)
1501 {
1502 if(outDataInit ==
1503 true) { // For visualization of the adapted view in GMSH GUI only
1504 _outData = new PViewDataList(true);
1505 _outData->setName(data->getName() + "_adapted");
1506 }
1507 else {
1508 _outData = nullptr; // For external used
1509 }
1510 std::vector<fullMatrix<double> *> p;
1511 if(_inData->getNumPoints()) {
1512 _inData->getInterpolationMatrices(TYPE_PNT, p);
1513 _points = new adaptiveElements<adaptivePoint>(p);
1514 }
1515 if(_inData->getNumLines()) {
1516 _inData->getInterpolationMatrices(TYPE_LIN, p);
1517 _lines = new adaptiveElements<adaptiveLine>(p);
1518 }
1519 if(_inData->getNumTriangles()) {
1520 _inData->getInterpolationMatrices(TYPE_TRI, p);
1521 _triangles = new adaptiveElements<adaptiveTriangle>(p);
1522 }
1523 if(_inData->getNumQuadrangles()) {
1524 _inData->getInterpolationMatrices(TYPE_QUA, p);
1525 _quadrangles = new adaptiveElements<adaptiveQuadrangle>(p);
1526 }
1527 if(_inData->getNumTetrahedra()) {
1528 _inData->getInterpolationMatrices(TYPE_TET, p);
1529 _tetrahedra = new adaptiveElements<adaptiveTetrahedron>(p);
1530 }
1531 if(_inData->getNumPrisms()) {
1532 _inData->getInterpolationMatrices(TYPE_PRI, p);
1533 _prisms = new adaptiveElements<adaptivePrism>(p);
1534 }
1535 if(_inData->getNumHexahedra()) {
1536 _inData->getInterpolationMatrices(TYPE_HEX, p);
1537 _hexahedra = new adaptiveElements<adaptiveHexahedron>(p);
1538 }
1539 if(_inData->getNumPyramids()) {
1540 _inData->getInterpolationMatrices(TYPE_PYR, p);
1541 _pyramids = new adaptiveElements<adaptivePyramid>(p);
1542 }
1543 upWriteVTK(true); // By default, write VTK data if called...
1544 upBuildStaticData(false); // ... and do not generated global static data
1545 // structure (only useful for ParaView plugin).
1546 }
1547
~adaptiveData()1548 adaptiveData::~adaptiveData()
1549 {
1550 if(_points) delete _points;
1551 if(_lines) delete _lines;
1552 if(_triangles) delete _triangles;
1553 if(_quadrangles) delete _quadrangles;
1554 if(_tetrahedra) delete _tetrahedra;
1555 if(_prisms) delete _prisms;
1556 if(_hexahedra) delete _hexahedra;
1557 if(_pyramids) delete _pyramids;
1558 if(_outData) delete _outData;
1559 }
1560
1561 double adaptiveData::timerInit = 0.;
1562 double adaptiveData::timerAdapt = 0.;
1563
changeResolution(int step,int level,double tol,GMSH_PostPlugin * plug)1564 void adaptiveData::changeResolution(int step, int level, double tol,
1565 GMSH_PostPlugin *plug)
1566 {
1567 timerInit = timerAdapt = 0.;
1568
1569 if(_level != level) {
1570 if(_points) _points->init(level);
1571 if(_lines) _lines->init(level);
1572 if(_triangles) _triangles->init(level);
1573 if(_quadrangles) _quadrangles->init(level);
1574 if(_tetrahedra) _tetrahedra->init(level);
1575 if(_prisms) _prisms->init(level);
1576 if(_hexahedra) _hexahedra->init(level);
1577 if(_pyramids) _pyramids->init(level);
1578 }
1579 if(plug || _step != step || _level != level || _tol != tol) {
1580 _outData->setDirty(true);
1581 if(_points) _points->addInView(tol, step, _inData, _outData, plug);
1582 if(_lines) _lines->addInView(tol, step, _inData, _outData, plug);
1583 if(_triangles) _triangles->addInView(tol, step, _inData, _outData, plug);
1584 if(_quadrangles)
1585 _quadrangles->addInView(tol, step, _inData, _outData, plug);
1586 if(_tetrahedra) _tetrahedra->addInView(tol, step, _inData, _outData, plug);
1587 if(_prisms) _prisms->addInView(tol, step, _inData, _outData, plug);
1588 if(_hexahedra) _hexahedra->addInView(tol, step, _inData, _outData, plug);
1589 if(_pyramids) _pyramids->addInView(tol, step, _inData, _outData, plug);
1590 _outData->finalize();
1591 }
1592 _step = step;
1593 _level = level;
1594 _tol = tol;
1595
1596 #ifdef TIMER
1597 printf("init time = %g\n", timerInit);
1598 printf("adapt time = %g\n", timerAdapt);
1599 #endif
1600 }
1601
isLittleEndian()1602 bool VTKData::isLittleEndian()
1603 {
1604 int num = 1;
1605 if(*(char *)&num == 1)
1606 return true; // Little Endian
1607 else
1608 return false; // Big Endian
1609 }
1610
SwapArrayByteOrder(void * array,int nbytes,int nItems)1611 void VTKData::SwapArrayByteOrder(void *array, int nbytes, int nItems)
1612 {
1613 // This swaps the byte order for the array of nItems each of size nbytes
1614 int i, j;
1615 unsigned char *ucDst = (unsigned char *)array;
1616
1617 for(i = 0; i < nItems; i++) {
1618 for(j = 0; j < (nbytes / 2); j++)
1619 std::swap(ucDst[j], ucDst[(nbytes - 1) - j]);
1620 ucDst += nbytes;
1621 }
1622 }
1623
writeVTKElmData()1624 void VTKData::writeVTKElmData()
1625 {
1626 // This routine writes vtu files (ascii or binary) from a elemental data base
1627 // of nodes coordinates, cell connectivity, type and offset, and point data
1628 // (either scalar or vector field)
1629
1630 // Format choice
1631 if(vtkFormat == "vtu") {
1632 if(vtkCountTotElmLev0 <= numPartMinElm * minElmPerPart) {
1633 if((vtkCountTotElmLev0 - 1) % minElmPerPart == 0) { // new filename
1634 vtkCountFile = (vtkCountTotElmLev0 - 1) / minElmPerPart;
1635 initVTKFile();
1636 }
1637 }
1638 else {
1639 if((vtkCountTotElmLev0 - 1 - numPartMinElm * minElmPerPart) %
1640 maxElmPerPart ==
1641 0) {
1642 // new filename
1643 vtkCountFile = numPartMinElm + (vtkCountTotElmLev0 - 1 -
1644 numPartMinElm * minElmPerPart) /
1645 maxElmPerPart;
1646 initVTKFile();
1647 }
1648 }
1649
1650 if(vtkIsBinary == true) { // Use appended format for raw binary
1651
1652 // Write raw binary data to separate files first. Text headers will be
1653 // added later, as wall as raw data size (needs to know the size before)
1654
1655 int counter;
1656 uint64_t *i64array;
1657 uint8_t *i8array;
1658 double *darray;
1659
1660 // Node value
1661 counter = 0;
1662 darray = new double[vtkNumComp * vtkLocalValues.size()];
1663 for(auto it = vtkLocalValues.begin(); it != vtkLocalValues.end(); ++it) {
1664 for(int i = 0; i < vtkNumComp; i++) { darray[counter + i] = it->v[i]; }
1665 counter += vtkNumComp;
1666 vtkCountTotVal += vtkNumComp;
1667 }
1668 assert(counter == vtkNumComp * (int)vtkLocalValues.size());
1669 fwrite(darray, sizeof(double), vtkNumComp * vtkLocalValues.size(),
1670 vtkFileNodVal);
1671 delete[] darray;
1672
1673 // Points
1674 int sizeArray = (int)vtkLocalCoords.size();
1675 darray = new double[3 * sizeArray];
1676 counter = 0;
1677 for(auto it = vtkLocalCoords.begin(); it != vtkLocalCoords.end(); ++it) {
1678 for(int i = 0; i < 3; i++) { darray[counter + i] = (*it).c[i]; }
1679 counter += 3;
1680 vtkCountCoord += 3;
1681 }
1682 fwrite(darray, sizeof(double), 3 * sizeArray, vtkFileCoord);
1683 delete[] darray;
1684
1685 // Cells
1686
1687 // First count the number of integers that described the cell data in
1688 // vtkConnectivity See
1689 // http://www.vtk.org/wp-content/uploads/2015/04/file-formats.pdf (page 4)
1690 int cellSizeData = 0;
1691 for(auto it = vtkLocalConnectivity.begin();
1692 it != vtkLocalConnectivity.end(); ++it) {
1693 // Contrary to vtk format, no +1 required for the number of nodes in the
1694 // element
1695 cellSizeData += (int)it->size();
1696 }
1697
1698 // Connectivity (and build offset at the same time)
1699 counter = 0;
1700 int cellcounter = 0;
1701 i64array = new uint64_t[cellSizeData];
1702 uint64_t *cellOffset = new uint64_t[vtkLocalConnectivity.size()];
1703 for(auto it = vtkLocalConnectivity.begin();
1704 it != vtkLocalConnectivity.end(); ++it) {
1705 for(auto jt = it->begin(); jt != it->end(); ++jt) {
1706 i64array[counter] = *jt;
1707 counter++;
1708 vtkCountTotNodConnect++;
1709 }
1710 cellOffset[cellcounter] = vtkCountTotNodConnect; // build the offset
1711 cellcounter++;
1712 }
1713 fwrite(i64array, sizeof(uint64_t), cellSizeData, vtkFileConnect);
1714 delete[] i64array;
1715
1716 // Cell offset
1717 fwrite(cellOffset, sizeof(uint64_t), vtkLocalConnectivity.size(),
1718 vtkFileCellOffset);
1719 delete[] cellOffset;
1720
1721 // Cell type
1722 counter = 0;
1723 i8array = new uint8_t[vtkLocalConnectivity.size()];
1724 for(auto it = vtkLocalCellType.begin(); it != vtkLocalCellType.end();
1725 it++) {
1726 i8array[counter] = *it;
1727 counter++;
1728 }
1729 fwrite(i8array, sizeof(uint8_t), vtkLocalConnectivity.size(),
1730 vtkFileCellType);
1731 delete[] i8array;
1732 }
1733 else { // ascii
1734
1735 // Node values
1736 for(auto it = vtkLocalValues.begin(); it != vtkLocalValues.end(); ++it) {
1737 for(int i = 0; i < vtkNumComp; i++) {
1738 fprintf(vtkFileNodVal, "%23.16e ", (*it).v[i]);
1739 vtkCountTotVal++;
1740 if(vtkCountTotVal % 6 == 0) fprintf(vtkFileNodVal, "\n");
1741 }
1742 }
1743
1744 for(auto it = vtkLocalCoords.begin(); it != vtkLocalCoords.end(); it++) {
1745 fprintf(vtkFileCoord, "%23.16e %23.16e %23.16e ", (*it).c[0],
1746 (*it).c[1], (*it).c[2]);
1747 vtkCountCoord += 3;
1748 if(vtkCountCoord % 6 == 0) fprintf(vtkFileCoord, "\n");
1749 }
1750
1751 // Cells
1752 // Connectivity
1753 int *cellOffset = new int[vtkLocalConnectivity.size()];
1754 int cellcounter = 0;
1755 for(auto it = vtkLocalConnectivity.begin();
1756 it != vtkLocalConnectivity.end(); ++it) {
1757 for(auto jt = it->begin(); jt != it->end(); ++jt) {
1758 fprintf(vtkFileConnect, "%d ", *jt);
1759 vtkCountTotNodConnect++;
1760 if(vtkCountTotNodConnect % 6 == 0) fprintf(vtkFileConnect, "\n");
1761 }
1762 cellOffset[cellcounter] = vtkCountTotNodConnect; // build the offset
1763 cellcounter++;
1764 }
1765
1766 // Cell offset
1767 for(uint64_t i = 0; i < vtkLocalConnectivity.size(); i++) {
1768 fprintf(vtkFileCellOffset, "%d ", cellOffset[i]);
1769 vtkCountCellOffset++;
1770 if(vtkCountCellOffset % 6 == 0) fprintf(vtkFileCellOffset, "\n");
1771 }
1772 delete[] cellOffset;
1773
1774 // Cell type
1775 for(auto it = vtkLocalCellType.begin(); it != vtkLocalCellType.end();
1776 it++) {
1777 fprintf(vtkFileCellType, "%d ", *it);
1778 vtkCountCellType++;
1779 if(vtkCountCellType % 6 == 0) fprintf(vtkFileCellType, "\n");
1780 }
1781
1782 } // if ascii
1783
1784 // finalize and close current vtu file
1785 if(vtkCountTotElmLev0 <= numPartMinElm * minElmPerPart) {
1786 if(vtkCountTotElmLev0 % minElmPerPart == 0) { finalizeVTKFile(); }
1787 }
1788 else {
1789 if((vtkCountTotElmLev0 - numPartMinElm * minElmPerPart) % maxElmPerPart ==
1790 0) {
1791 finalizeVTKFile();
1792 }
1793 }
1794
1795 } // vtu format
1796 else
1797 Msg::Error("Unknown format");
1798 }
1799
initVTKFile()1800 void VTKData::initVTKFile()
1801 {
1802 // Temporary files
1803 vtkFileCoord = fopen("vtkCoords.vtu", "wb");
1804 vtkFileConnect = fopen("vtkConnectivity.vtu", "wb");
1805 vtkFileCellOffset = fopen("vtkCellOffset.vtu", "wb");
1806 vtkFileCellType = fopen("vtkCellType.vtu", "wb");
1807 vtkFileNodVal = fopen("vtkNodeValue.vtu", "wb");
1808
1809 if(vtkCountFile == 0) {
1810 // write the pvtu file and create the corresponding directory for vtu files
1811
1812 if(vtkUseDefaultName == 1) {
1813 vtkDirName = vtkFieldName + "_step" + ToString<int>(vtkStep) + "_level" +
1814 ToString<int>(vtkLevel) + "_tol" + ToString<double>(vtkTol) +
1815 "_npart" + ToString<int>(vtkNpart);
1816 }
1817 else {
1818 // Remove existing extension here to avoid duplicate
1819 std::size_t found = vtkFileName.find_last_of('.');
1820 // remove extension
1821 if(found != std::string::npos) vtkFileName = vtkFileName.substr(0, found);
1822 vtkDirName = vtkFileName;
1823 }
1824
1825 CreateSingleDir(vtkDirName);
1826
1827 vtkFileName =
1828 vtkDirName + ".p" + vtkFormat; // add pvtu extension to file name
1829 vtkFile = fopen(vtkFileName.c_str(), "w");
1830
1831 bool littleEndian = isLittleEndian(); // Determine endianess
1832 if(littleEndian == true)
1833 fprintf(vtkFile, "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" "
1834 "byte_order=\"LittleEndian\">\n");
1835 else
1836 fprintf(vtkFile, "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" "
1837 "byte_order=\"BigEndian\">\n");
1838
1839 fprintf(vtkFile, "<PUnstructuredGrid GhostLevel=\"0\">\n");
1840 fprintf(vtkFile, "<PPoints>\n");
1841 fprintf(vtkFile, "<DataArray type=\"Float64\" Name=\"Points\" "
1842 "NumberOfComponents=\"3\"/>\n");
1843 fprintf(vtkFile, "</PPoints>\n");
1844
1845 fprintf(vtkFile, "<PCells>\n");
1846 fprintf(vtkFile, "<PDataArray type=\"Int64\" Name=\"connectivity\" "
1847 "NumberOfComponents=\"1\"/>\n");
1848 fprintf(vtkFile, "<PDataArray type=\"Int64\" Name=\"offsets\" "
1849 "NumberOfComponents=\"1\"/>\n");
1850 fprintf(
1851 vtkFile,
1852 "<PDataArray type=\"UInt8\" Name=\"types\" NumberOfComponents=\"1\"/>\n");
1853 fprintf(vtkFile, "</PCells>\n");
1854
1855 fprintf(vtkFile, "<PPointData>\n");
1856 fprintf(
1857 vtkFile,
1858 "<PDataArray type=\"Float64\" Name=\"%s\" NumberOfComponents=\"%d\"/>\n",
1859 vtkFieldName.c_str(), vtkNumComp);
1860 fprintf(vtkFile, "</PPointData>\n");
1861
1862 fprintf(vtkFile, "<PCellData>\n");
1863 fprintf(vtkFile, "</PCellData>\n");
1864
1865 for(int i = 0; i < vtkNpart; i++)
1866 fprintf(vtkFile, "<Piece Source=\"%s/data%d.vtu\"/>\n",
1867 vtkDirName.c_str(), i);
1868 fprintf(vtkFile, "</PUnstructuredGrid>\n");
1869 fprintf(vtkFile, "</VTKFile>\n");
1870 fclose(vtkFile);
1871 }
1872 }
1873
finalizeVTKFile()1874 void VTKData::finalizeVTKFile()
1875 {
1876 // This routine writes vtu files (ascii or binary) from a complete data base
1877 // of nodes coordinates, cell connectivity, type and offset, and point data
1878 // (either scalar or vector field)
1879
1880 // Close first temporary files. Todo: Avoid multiple open/close actions and
1881 // keep the file open to write all information
1882 fclose(vtkFileCoord);
1883 fclose(vtkFileConnect);
1884 fclose(vtkFileCellOffset);
1885 fclose(vtkFileCellType);
1886 fclose(vtkFileNodVal);
1887
1888 bool littleEndian = isLittleEndian(); // Determine endianess
1889
1890 // Open final file
1891 std::string filename;
1892 filename = vtkDirName + "/data" + ToString(vtkCountFile) + "." + vtkFormat;
1893
1894 Msg::StatusBar(true,
1895 "Writing VTK data in %s: fieldname = %s - numElm = %d - "
1896 "numNod = %d nodes\n",
1897 filename.c_str(), vtkFieldName.c_str(), vtkCountTotElm,
1898 vtkCountTotNod);
1899
1900 assert(vtkCountTotNod == vtkCountCoord / 3);
1901
1902 // Now concatenate headers with data files
1903 if(vtkFormat == "vtu") { // Format choice
1904
1905 if(vtkIsBinary == true) { // Binary or ascii
1906
1907 vtkFile = fopen(filename.c_str(), "wb");
1908 if(vtkFile == nullptr) {
1909 printf("Could not open file %s\n", filename.c_str());
1910 return;
1911 }
1912
1913 uint64_t byteoffset = 0;
1914
1915 // Headers first
1916
1917 if(littleEndian == true)
1918 fprintf(vtkFile, "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" "
1919 "byte_order=\"LittleEndian\" "
1920 "header_type=\"UInt64\">\n");
1921 else
1922 fprintf(vtkFile, "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" "
1923 "byte_order=\"BigEndian\" header_type=\"UInt64\">\n");
1924 fprintf(vtkFile, "<UnstructuredGrid>\n");
1925 fprintf(vtkFile, "<Piece NumberOfPoints=\"%d\" NumberOfCells=\"%d\">\n",
1926 vtkCountTotNod, vtkCountTotElm);
1927
1928 // Node value
1929 fprintf(vtkFile, "<PointData>\n");
1930 fprintf(vtkFile,
1931 "<DataArray type=\"Float64\" Name=\"%s\" "
1932 "NumberOfComponents=\"%d\" format=\"appended\" offset=\"%" PRIu64
1933 "\"/>\n",
1934 vtkFieldName.c_str(), vtkNumComp, byteoffset);
1935 fprintf(vtkFile, "</PointData>\n");
1936 byteoffset = byteoffset + (vtkCountTotNod * vtkNumComp + 1) *
1937 sizeof(double); // +1 for datasize in bytes
1938
1939 // Cell values (none here but may change)
1940 fprintf(vtkFile, "<CellData>\n");
1941 fprintf(vtkFile,
1942 "</CellData>\n"); // no offset here because empty cell data
1943
1944 // Nodes
1945 fprintf(vtkFile, "<Points>\n");
1946 fprintf(vtkFile,
1947 "<DataArray type=\"Float64\" Name=\"Points\" "
1948 "NumberOfComponents=\"3\" format=\"appended\" offset=\"%" PRIu64
1949 "\"/>\n",
1950 byteoffset);
1951 fprintf(vtkFile, "</Points>\n");
1952 byteoffset = byteoffset + (vtkCountCoord + 1) *
1953 sizeof(double); // +1 for datasize in bytes
1954
1955 // Cells
1956 fprintf(vtkFile, "<Cells>\n");
1957 fprintf(vtkFile,
1958 "<DataArray type=\"Int64\" Name=\"connectivity\" "
1959 "format=\"appended\" offset=\"%" PRIu64 "\"/>\n",
1960 byteoffset);
1961 byteoffset = byteoffset + (vtkCountTotNodConnect + 1) * sizeof(uint64_t);
1962 fprintf(vtkFile,
1963 "<DataArray type=\"Int64\" Name=\"offsets\" format=\"appended\" "
1964 "offset=\"%" PRIu64 "\"/>\n",
1965 byteoffset);
1966 byteoffset = byteoffset + (vtkCountTotElm + 1) * sizeof(uint64_t);
1967 fprintf(vtkFile,
1968 "<DataArray type=\"UInt8\" Name=\"types\" format=\"appended\" "
1969 "offset=\"%" PRIu64 "\"/>\n",
1970 byteoffset);
1971 byteoffset = byteoffset + (vtkCountTotElm + 1) * sizeof(uint8_t);
1972 fprintf(vtkFile, "</Cells>\n");
1973
1974 fprintf(vtkFile, "</Piece>\n");
1975 fprintf(vtkFile, "</UnstructuredGrid>\n");
1976
1977 fprintf(vtkFile, "<AppendedData encoding=\"raw\">\n");
1978 fprintf(vtkFile, "_");
1979
1980 uint64_t datasize;
1981
1982 // Node values
1983 datasize = vtkNumComp * vtkCountTotNod * sizeof(double);
1984 fwrite(&datasize, sizeof(uint64_t), 1, vtkFile);
1985 fclose(vtkFile);
1986
1987 std::ifstream if_vtkNodeValue("vtkNodeValue.vtu", std::ios_base::binary);
1988 std::ofstream of_vtkfile(filename.c_str(),
1989 std::ios_base::binary | std::ios_base::app);
1990 of_vtkfile << if_vtkNodeValue.rdbuf();
1991 if_vtkNodeValue.close();
1992 of_vtkfile.close();
1993
1994 // Points
1995 vtkFile = fopen(filename.c_str(), "ab");
1996 datasize = vtkCountTotNod * 3 * sizeof(double);
1997 fwrite(&datasize, sizeof(uint64_t), 1, vtkFile);
1998 fclose(vtkFile);
1999
2000 std::ifstream if_vtkCoords("vtkCoords.vtu", std::ios_base::binary);
2001 of_vtkfile.open(filename.c_str(),
2002 std::ios_base::binary | std::ios_base::app);
2003 of_vtkfile << if_vtkCoords.rdbuf();
2004 if_vtkCoords.close();
2005 of_vtkfile.close();
2006
2007 // Cells
2008 // Connectivity
2009 vtkFile = fopen(filename.c_str(), "ab");
2010 datasize = vtkCountTotNodConnect * sizeof(uint64_t);
2011 fwrite(&datasize, sizeof(uint64_t), 1, vtkFile);
2012 fclose(vtkFile);
2013
2014 std::ifstream if_vtkConnectivity("vtkConnectivity.vtu",
2015 std::ios_base::binary);
2016 of_vtkfile.open(filename.c_str(),
2017 std::ios_base::binary | std::ios_base::app);
2018 of_vtkfile << if_vtkConnectivity.rdbuf();
2019 if_vtkConnectivity.close();
2020 of_vtkfile.close();
2021
2022 // Cell offset
2023 vtkFile = fopen(filename.c_str(), "ab");
2024 datasize = vtkCountTotElm * sizeof(uint64_t);
2025 fwrite(&datasize, sizeof(uint64_t), 1, vtkFile);
2026 fclose(vtkFile);
2027
2028 std::ifstream if_vtkCellOffset("vtkCellOffset.vtu",
2029 std::ios_base::binary);
2030 of_vtkfile.open(filename.c_str(),
2031 std::ios_base::binary | std::ios_base::app);
2032 of_vtkfile << if_vtkCellOffset.rdbuf();
2033 if_vtkCellOffset.close();
2034 of_vtkfile.close();
2035
2036 // Cell type
2037 vtkFile = fopen(filename.c_str(), "ab");
2038 datasize = vtkCountTotElm * sizeof(uint8_t);
2039 fwrite(&datasize, sizeof(uint64_t), 1, vtkFile);
2040 fclose(vtkFile);
2041
2042 std::ifstream if_vtkCellType("vtkCellType.vtu", std::ios_base::binary);
2043 of_vtkfile.open(filename.c_str(),
2044 std::ios_base::binary | std::ios_base::app);
2045 of_vtkfile << if_vtkCellType.rdbuf();
2046 if_vtkCellType.close();
2047 of_vtkfile.close();
2048
2049 vtkFile = fopen(filename.c_str(), "ab");
2050 fprintf(vtkFile, "\n");
2051 fprintf(vtkFile, "</AppendedData>\n");
2052 fprintf(vtkFile, "</VTKFile>\n"); // for both binary and ascii
2053 fclose(vtkFile);
2054 }
2055 else { // ascii
2056
2057 vtkFile = fopen(filename.c_str(), "w");
2058 if(vtkFile == nullptr) {
2059 printf("Could not open file %s\n", filename.c_str());
2060 return;
2061 }
2062
2063 if(littleEndian == true)
2064 fprintf(vtkFile, "<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" "
2065 "byte_order=\"LittleEndian\" "
2066 "header_type=\"UInt64\">\n");
2067 else
2068 fprintf(vtkFile, "<VTKFile type=\"PUnstructuredGrid\" version=\"1.0\" "
2069 "byte_order=\"BigEndian\" header_type=\"UInt64\">\n");
2070 fprintf(vtkFile, "<UnstructuredGrid>\n");
2071 fprintf(vtkFile, "<Piece NumberOfPoints=\"%d\" NumberOfCells=\"%d\">\n",
2072 vtkCountTotNod, vtkCountTotElm);
2073
2074 // Node values
2075 fprintf(vtkFile, "<PointData>\n");
2076 fprintf(vtkFile,
2077 "<DataArray type=\"Float64\" Name=\"%s\" "
2078 "NumberOfComponents=\"%d\" format=\"ascii\">\n",
2079 vtkFieldName.c_str(), vtkNumComp);
2080 fclose(vtkFile); // close file for binary concatenation
2081
2082 std::ifstream if_vtkNodeValue("vtkNodeValue.vtu", std::ios_base::binary);
2083 std::ofstream of_vtkfile(filename.c_str(),
2084 std::ios_base::binary | std::ios_base::app);
2085 of_vtkfile << if_vtkNodeValue.rdbuf();
2086 if_vtkNodeValue.close();
2087 of_vtkfile.close();
2088
2089 vtkFile = fopen(filename.c_str(), "a");
2090 fprintf(vtkFile, "</DataArray>\n");
2091 fprintf(vtkFile, "</PointData>\n");
2092
2093 // Cell values
2094 fprintf(vtkFile, "<CellData>\n");
2095 fprintf(vtkFile, "</CellData>\n");
2096
2097 // Nodes
2098 fprintf(vtkFile, "<Points>\n");
2099 fprintf(vtkFile, "<DataArray type=\"Float64\" Name=\"Points\" "
2100 "NumberOfComponents=\"3\" format=\"ascii\">\n");
2101 fclose(vtkFile); // close file for binary concatenation
2102
2103 of_vtkfile.open(filename.c_str(),
2104 std::ios_base::binary | std::ios_base::app);
2105 std::ifstream if_vtkCoords("vtkCoords.vtu", std::ios_base::binary);
2106 of_vtkfile << if_vtkCoords.rdbuf();
2107 if_vtkCoords.close();
2108 of_vtkfile.close();
2109
2110 vtkFile = fopen(filename.c_str(), "a");
2111 fprintf(vtkFile, "</DataArray>\n");
2112 fprintf(vtkFile, "</Points>\n");
2113
2114 // Cells
2115 fprintf(vtkFile, "<Cells>\n");
2116 fprintf(
2117 vtkFile,
2118 "<DataArray type=\"Int64\" Name=\"connectivity\" format=\"ascii\">\n");
2119 fclose(vtkFile); // close file for binary concatenation
2120
2121 // Connectivity
2122 of_vtkfile.open(filename.c_str(),
2123 std::ios_base::binary | std::ios_base::app);
2124 std::ifstream if_vtkConnectivity("vtkConnectivity.vtu",
2125 std::ios_base::binary);
2126 of_vtkfile << if_vtkConnectivity.rdbuf();
2127 if_vtkConnectivity.close();
2128 of_vtkfile.close();
2129
2130 vtkFile = fopen(filename.c_str(), "a");
2131 fprintf(vtkFile, "</DataArray>\n");
2132
2133 // Cell offset
2134 fprintf(vtkFile,
2135 "<DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\">\n");
2136 fclose(vtkFile); // close file for binary concatenation
2137
2138 of_vtkfile.open(filename.c_str(),
2139 std::ios_base::binary | std::ios_base::app);
2140 std::ifstream if_vtkCellOffset("vtkCellOffset.vtu",
2141 std::ios_base::binary);
2142 of_vtkfile << if_vtkCellOffset.rdbuf();
2143 if_vtkCellOffset.close();
2144 of_vtkfile.close();
2145
2146 vtkFile = fopen(filename.c_str(), "a");
2147 fprintf(vtkFile, "</DataArray>\n");
2148
2149 // Cell type
2150 fprintf(vtkFile,
2151 "<DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n");
2152 fclose(vtkFile); // close file for binary concatenation
2153
2154 of_vtkfile.open(filename.c_str(),
2155 std::ios_base::binary | std::ios_base::app);
2156 std::ifstream if_vtkCellType("vtkCellType.vtu", std::ios_base::binary);
2157 of_vtkfile << if_vtkCellType.rdbuf();
2158 if_vtkCellType.close();
2159 of_vtkfile.close();
2160
2161 vtkFile = fopen(filename.c_str(), "a");
2162 fprintf(vtkFile, "</DataArray>\n");
2163 fprintf(vtkFile, "</Cells>\n");
2164
2165 fprintf(vtkFile, "</Piece>\n");
2166 fprintf(vtkFile, "</UnstructuredGrid>\n");
2167
2168 fprintf(vtkFile, "</VTKFile>\n"); // for both binary and ascii
2169 fclose(vtkFile);
2170 } // if binary/ascii
2171
2172 // Remove temporary files now
2173 if(remove("vtkCoords.vtu") != 0)
2174 printf("ERROR: Could not remove vtkCoords.vtu\n");
2175 if(remove("vtkConnectivity.vtu") != 0)
2176 printf("ERROR: Could not remove vtkConnectivity.vtu\n");
2177 if(remove("vtkCellOffset.vtu") != 0)
2178 printf("ERROR: Could not remove vtkCellOffset.vtu\n");
2179 if(remove("vtkCellType.vtu") != 0)
2180 printf("ERROR: Could not remove vtkCellType.vtu\n");
2181 if(remove("vtkNodeValue.vtu") != 0)
2182 printf("ERROR: Could not remove vtkNodeValue.vtu\n");
2183
2184 // Reset counters for next file
2185 vtkCountTotNod = 0;
2186 vtkCountTotElm = 0;
2187 vtkCountCoord = 0;
2188 vtkCountTotNodConnect = 0;
2189 vtkCountTotVal = 0;
2190 vtkCountCellOffset = 0;
2191 vtkCountCellType = 0;
2192 }
2193
2194 else
2195 Msg::Error("File format unknown: %s", vtkFormat.c_str());
2196 }
2197
getPVCellType(int numEdges)2198 int VTKData::getPVCellType(int numEdges)
2199 {
2200 int cellType; // Convention for cell types in ParaView
2201 switch(numEdges) {
2202 case 0:
2203 printf(
2204 "WARNING: Trying to write a node to the ParaView data base and file\n");
2205 cellType = -1;
2206 break;
2207 case 1:
2208 printf(
2209 "WARNING: Trying to write a node to the ParaView data base and file\n");
2210 cellType = -2;
2211 break;
2212 case 3:
2213 cellType = 5; // 2D VTK triangle
2214 break;
2215 case 4:
2216 cellType = 9; // 2D VTK quadrangle
2217 break;
2218 case 6:
2219 cellType = 10; // 3D VTK tetrahedron
2220 break;
2221 case 9:
2222 cellType = 13; // 3D VTK prism/wedge
2223 break;
2224 case 8:
2225 cellType = 14; // 3D VTK pyramid
2226 break;
2227 case 12:
2228 cellType = 12; // 3D VTK hexahedron
2229 break;
2230 default:
2231 printf("ERROR: No cell type was detected\n");
2232 cellType = -1;
2233 break;
2234 }
2235
2236 return cellType;
2237 }
2238
2239 template <class T>
adaptForVTK(double tol,int numComp,std::vector<PCoords> & coords,std::vector<PValues> & values,double & minVal,double & maxVal)2240 void adaptiveElements<T>::adaptForVTK(double tol, int numComp,
2241 std::vector<PCoords> &coords,
2242 std::vector<PValues> &values,
2243 double &minVal, double &maxVal)
2244 {
2245 int numVertices = T::allVertices.size();
2246
2247 if(!numVertices) {
2248 Msg::Error("No adapted vertices to interpolate");
2249 return;
2250 }
2251
2252 int numVals = _coeffsVal ? _coeffsVal->size1() : T::numNodes;
2253 if(numVals != (int)values.size()) {
2254 Msg::Error("Wrong number of values in adaptation %d != %i", numVals,
2255 values.size());
2256 return;
2257 }
2258
2259 #ifdef TIMER
2260 double t1 = TimeOfDay();
2261 #endif
2262
2263 fullVector<double> val(numVals), res(numVertices);
2264 switch(numComp) {
2265 case 1: {
2266 for(int i = 0; i < numVals; i++) val(i) = values[i].v[0];
2267 break;
2268 }
2269 case 3:
2270 case 9: {
2271 for(int i = 0; i < numVals; i++) {
2272 val(i) = 0;
2273 for(int k = 0; k < numComp; k++)
2274 val(i) += values[i].v[k] * values[i].v[k];
2275 }
2276 break;
2277 }
2278 default: {
2279 Msg::Error("Can only adapt scalar, vector or tensor data");
2280 return;
2281 }
2282 }
2283
2284 _interpolVal->mult(val, res);
2285
2286 for(int i = 0; i < numVertices; i++) {
2287 minVal = std::min(minVal, res(i));
2288 maxVal = std::max(maxVal, res(i));
2289 }
2290
2291 fullMatrix<double> *resxyz = nullptr;
2292 if(numComp == 3 || numComp == 9) {
2293 fullMatrix<double> valxyz(numVals, numComp);
2294 resxyz = new fullMatrix<double>(numVertices, numComp);
2295 for(int i = 0; i < numVals; i++) {
2296 for(int k = 0; k < numComp; k++) { valxyz(i, k) = values[i].v[k]; }
2297 }
2298 _interpolVal->mult(valxyz, *resxyz);
2299 }
2300
2301 int numNodes = _coeffsGeom ? _coeffsGeom->size1() : T::numNodes;
2302 if(numNodes != (int)coords.size()) {
2303 Msg::Error("Wrong number of nodes in adaptation %d != %i", numNodes,
2304 coords.size());
2305 if(resxyz) delete resxyz;
2306 return;
2307 }
2308
2309 fullMatrix<double> xyz(numNodes, 3), XYZ(numVertices, 3);
2310 for(int i = 0; i < numNodes; i++) {
2311 xyz(i, 0) = coords[i].c[0];
2312 xyz(i, 1) = coords[i].c[1];
2313 xyz(i, 2) = coords[i].c[2];
2314 }
2315 _interpolGeom->mult(xyz, XYZ);
2316
2317 #ifdef TIMER
2318 adaptiveData::timerAdapt += TimeOfDay() - t1;
2319 return;
2320 #endif
2321
2322 int i = 0;
2323 for(auto it = T::allVertices.begin(); it != T::allVertices.end(); ++it) {
2324 // ok because we know this will not change the set ordering
2325 adaptiveVertex *p = (adaptiveVertex *)&(*it);
2326 p->val = res(i);
2327 if(resxyz) {
2328 p->val = (*resxyz)(i, 0);
2329 p->valy = (*resxyz)(i, 1);
2330 p->valz = (*resxyz)(i, 2);
2331 if(numComp == 9) {
2332 p->valyx = (*resxyz)(i, 3);
2333 p->valyy = (*resxyz)(i, 4);
2334 p->valyz = (*resxyz)(i, 5);
2335 p->valzx = (*resxyz)(i, 6);
2336 p->valzy = (*resxyz)(i, 7);
2337 p->valzz = (*resxyz)(i, 8);
2338 }
2339 }
2340 p->X = XYZ(i, 0);
2341 p->Y = XYZ(i, 1);
2342 p->Z = XYZ(i, 2);
2343 i++;
2344 }
2345
2346 if(resxyz) delete resxyz;
2347
2348 for(auto it = T::all.begin(); it != T::all.end(); it++)
2349 (*it)->visible = false;
2350
2351 if(tol != 0.) {
2352 double avg = fabs(maxVal - minVal);
2353 if(tol < 0) avg = 1.; // force visibility to the smallest subdivision
2354 T::error(avg, tol);
2355 }
2356
2357 coords.clear();
2358 values.clear();
2359 for(auto it = T::all.begin(); it != T::all.end(); it++) {
2360 if((*it)->visible) {
2361 adaptiveVertex **p = (*it)->p;
2362 for(int i = 0; i < T::numNodes; i++) {
2363 coords.push_back(PCoords(p[i]->X, p[i]->Y, p[i]->Z));
2364 switch(numComp) {
2365 case 1: values.push_back(PValues(p[i]->val)); break;
2366 case 3:
2367 values.push_back(PValues(p[i]->val, p[i]->valy, p[i]->valz));
2368 break;
2369 case 9:
2370 values.push_back(PValues(p[i]->val, p[i]->valy, p[i]->valz,
2371 p[i]->valyx, p[i]->valyy, p[i]->valyz,
2372 p[i]->valzx, p[i]->valzy, p[i]->valzz));
2373 break;
2374 }
2375 }
2376 }
2377 }
2378 }
2379
2380 template <class T>
buildMapping(nodMap<T> & myNodMap,double tol,int & numNodInsert)2381 void adaptiveElements<T>::buildMapping(nodMap<T> &myNodMap, double tol,
2382 int &numNodInsert)
2383 {
2384 if(tol > 0.0 || myNodMap.getSize() == 0) {
2385 // Either this is not a uniform refinement and we need to rebuild the whole
2386 // mapping for each canonical element, or this is the first time we try to
2387 // build the mapping
2388
2389 myNodMap
2390 .cleanMapping(); // Required if tol > 0 (local error based adaptation)
2391
2392 for(auto itleaf = T::all.begin(); itleaf != T::all.end(); itleaf++) {
2393 // Visit all the leaves of the refined canonical element
2394
2395 if((*itleaf)->visible == true) {
2396 // Find the leaves that are flagged for visibility
2397
2398 for(int i = 0; i < T::numNodes; i++) {
2399 // Visit each nodes of the leaf (3 for triangles, 4 for quadrangle,
2400 // etc)
2401 adaptiveVertex pquery;
2402 pquery.x = (*itleaf)->p[i]->x;
2403 pquery.y = (*itleaf)->p[i]->y;
2404 pquery.z = (*itleaf)->p[i]->z;
2405 auto it = T::allVertices.find(pquery);
2406 if(it == T::allVertices.end()) {
2407 Msg::Error("Could not find adaptive Vertex in "
2408 "adaptiveElements<T>::buildMapping %f %f %f",
2409 pquery.x, pquery.y, pquery.z);
2410 }
2411 else {
2412 // Compute the distance in the list to get the mapping for
2413 // the canonical element (note std:distance returns long int
2414 int dist = (int)std::distance(T::allVertices.begin(), it);
2415 myNodMap.mapping.push_back(dist);
2416 }
2417 // quit properly if vertex not found - Should not happen though
2418 assert(it != T::allVertices.end());
2419 } // for
2420 } // if
2421 } // for
2422
2423 if(myNodMap.mapping.size() == 0) {
2424 Msg::Error("Node mapping in buildMapping has zero size");
2425 }
2426
2427 // Count number of unique nodes from the mapping
2428 // Use an ordered set for efficiency
2429 // This set is also used in case of partiel refinement
2430 std::set<int> uniqueNod;
2431 for(auto it = myNodMap.mapping.begin(); it != myNodMap.mapping.end();
2432 it++) {
2433 uniqueNod.insert(*it);
2434 }
2435 numNodInsert = (int)uniqueNod.size();
2436
2437 // Renumber the elm in the mapping in case of partial refinement (when vis
2438 // tolerance > 0) so that we have a continuous numbering starting from 0
2439 // with no missing node id in the connectivity This require a new local and
2440 // temporary mapping, based on uniqueNod already generated above
2441 if(tol > 0.0) {
2442 for(auto it = myNodMap.mapping.begin(); it != myNodMap.mapping.end();
2443 ++it) {
2444 auto jt = uniqueNod.find(*it);
2445 *it = std::distance(uniqueNod.begin(), jt);
2446 }
2447 }
2448 }
2449 }
2450
2451 template <class T>
addInViewForVTK(int step,PViewData * in,VTKData & myVTKData,bool writeVTK,bool buildStaticData)2452 void adaptiveElements<T>::addInViewForVTK(int step, PViewData *in,
2453 VTKData &myVTKData, bool writeVTK,
2454 bool buildStaticData)
2455 {
2456 int numComp = in->getNumComponents(0, 0, 0);
2457 if(numComp != 1 && numComp != 3 && numComp != 9) return;
2458
2459 int numEle = 0;
2460 switch(T::numEdges) {
2461 case 0: numEle = in->getNumPoints(); break;
2462 case 1: numEle = in->getNumLines(); break;
2463 case 3: numEle = in->getNumTriangles(); break;
2464 case 4: numEle = in->getNumQuadrangles(); break;
2465 case 6: numEle = in->getNumTetrahedra(); break;
2466 case 9: numEle = in->getNumPrisms(); break;
2467 case 8: numEle = in->getNumPyramids(); break;
2468 case 12: numEle = in->getNumHexahedra(); break;
2469 }
2470 if(!numEle) return;
2471
2472 // New variables for high order visualiztion through vtk files
2473 int numNodInsert = 0;
2474 nodMap<T> myNodMap;
2475
2476 double minVal = in->getMin(step);
2477 double maxVal = in->getMax(step);
2478
2479 for(int ent = 0; ent < in->getNumEntities(step); ent++) {
2480 for(int ele = 0; ele < in->getNumElements(step, ent); ele++) {
2481 if(in->skipElement(step, ent, ele) ||
2482 in->getNumEdges(step, ent, ele) != T::numEdges)
2483 continue;
2484 int numNodes = in->getNumNodes(step, ent, ele);
2485 std::vector<PCoords> coords;
2486 for(int i = 0; i < numNodes; i++) {
2487 double x, y, z;
2488 in->getNode(step, ent, ele, i, x, y, z);
2489 coords.push_back(PCoords(x, y, z));
2490 }
2491 int numVal = in->getNumValues(step, ent, ele);
2492 std::vector<PValues> values;
2493
2494 switch(numComp) {
2495 case 1:
2496 for(int i = 0; i < numVal; i++) {
2497 double val;
2498 in->getValue(step, ent, ele, i, val);
2499 values.push_back(PValues(val));
2500 }
2501 break;
2502 case 3:
2503 for(int i = 0; i < numVal / 3; i++) {
2504 double vx, vy, vz;
2505 in->getValue(step, ent, ele, 3 * i, vx);
2506 in->getValue(step, ent, ele, 3 * i + 1, vy);
2507 in->getValue(step, ent, ele, 3 * i + 2, vz);
2508 values.push_back(PValues(vx, vy, vz));
2509 }
2510 break;
2511 case 9:
2512 for(int i = 0; i < numVal / 9; i++) {
2513 double vxx, vxy, vxz, vyx, vyy, vyz, vzx, vzy, vzz;
2514 in->getValue(step, ent, ele, 9 * i + 0, vxx);
2515 in->getValue(step, ent, ele, 9 * i + 1, vxy);
2516 in->getValue(step, ent, ele, 9 * i + 2, vxz);
2517 in->getValue(step, ent, ele, 9 * i + 3, vyx);
2518 in->getValue(step, ent, ele, 9 * i + 4, vyy);
2519 in->getValue(step, ent, ele, 9 * i + 5, vyz);
2520 in->getValue(step, ent, ele, 9 * i + 6, vzx);
2521 in->getValue(step, ent, ele, 9 * i + 7, vzy);
2522 in->getValue(step, ent, ele, 9 * i + 8, vzz);
2523 values.push_back(
2524 PValues(vxx, vxy, vxz, vyx, vyy, vyz, vzx, vzy, vzz));
2525 }
2526 break;
2527 }
2528
2529 adaptForVTK(myVTKData.vtkTol, numComp, coords, values, minVal,
2530 maxVal); // ,plug);
2531
2532 // Inside initial element, after adapt() has been called
2533
2534 // Build the mapping of the canonical element,
2535 // or recycle existing one in case of uniform refinement
2536 buildMapping(myNodMap, myVTKData.vtkTol, numNodInsert);
2537
2538 // Pre-allocate some space for the local coordinates and connectivity
2539 // in order to write to any component of the vector later through vec[i]
2540
2541 myVTKData.vtkLocalCoords.resize(numNodInsert, PCoords(0.0, 0.0, 0.0));
2542 myVTKData.vtkLocalValues.resize(numNodInsert, PValues(numComp));
2543
2544 for(std::size_t i = 0; i < coords.size() / T::numNodes; i++) {
2545 // Loop over
2546 // - all refined elements if refinement level > 0
2547 // - single initial element when refinement box is checked for the
2548 // first time (ref level =0)
2549
2550 // local connectivity for the considered sub triangle
2551 vectInt vtkElmConnectivity;
2552
2553 for(int k = 0; k < T::numNodes; ++k) {
2554 // Connectivity of the considered sub-element
2555 int countTotNodloc = T::numNodes * i + k; // Nodes are duplicate here
2556 int vtkNodeId =
2557 myVTKData.vtkCountTotNod + myNodMap.mapping[countTotNodloc];
2558 vtkElmConnectivity.push_back(vtkNodeId);
2559
2560 // Coordinates of the nodes of the considered sub-element
2561 double px, py, pz;
2562 px = coords[T::numNodes * i + k].c[0];
2563 py = coords[T::numNodes * i + k].c[1];
2564 pz = coords[T::numNodes * i + k].c[2];
2565 PCoords tmpCoords = PCoords(px, py, pz);
2566 myVTKData.vtkLocalCoords[myNodMap.mapping[countTotNodloc]] =
2567 tmpCoords;
2568
2569 // Value associated with each nodes of the sub-element
2570 myVTKData.vtkLocalValues[myNodMap.mapping[countTotNodloc]] =
2571 values[T::numNodes * i + k];
2572 }
2573
2574 // Add elm connectivity to vector
2575 myVTKData.vtkLocalConnectivity.push_back(vtkElmConnectivity);
2576
2577 // Increment global elm number
2578 myVTKData.incrementTotElm(1);
2579
2580 // Save element type
2581 myVTKData.vtkLocalCellType.push_back(
2582 myVTKData.getPVCellType(T::numEdges));
2583
2584 // Global variables
2585 if(buildStaticData == true) {
2586 globalVTKData::vtkGlobalConnectivity.push_back(vtkElmConnectivity);
2587 globalVTKData::vtkGlobalCellType.push_back(
2588 myVTKData.getPVCellType(T::numEdges));
2589 }
2590
2591 // Clear existing structure (safer)
2592 vtkElmConnectivity.clear();
2593 }
2594
2595 // Increment global node and elm-lev0 number
2596 myVTKData.incrementTotNod(numNodInsert);
2597 myVTKData.incrementTotElmLev0(1);
2598
2599 // Write the VTK data structure of the consider element to vtu file
2600
2601 if(writeVTK == true) { myVTKData.writeVTKElmData(); }
2602
2603 if(buildStaticData == true) {
2604 for(int i = 0; i < numNodInsert; i++) {
2605 globalVTKData::vtkGlobalCoords.push_back(myVTKData.vtkLocalCoords[i]);
2606 }
2607
2608 for(int i = 0; i < numNodInsert; i++) {
2609 globalVTKData::vtkGlobalValues.push_back(myVTKData.vtkLocalValues[i]);
2610 }
2611 }
2612
2613 myVTKData.clearLocalData();
2614
2615 } // loop over mesh element
2616 }
2617 }
2618
2619 template <class T>
countElmLev0(int step,PViewData * in)2620 int adaptiveElements<T>::countElmLev0(int step, PViewData *in)
2621 {
2622 int sum = 0;
2623 for(int ent = 0; ent < in->getNumEntities(step); ent++) {
2624 for(int ele = 0; ele < in->getNumElements(step, ent); ele++) {
2625 if(in->skipElement(step, ent, ele) ||
2626 in->getNumEdges(step, ent, ele) != T::numEdges)
2627 continue;
2628 else
2629 sum++;
2630 }
2631 }
2632 return sum;
2633 }
2634
countTotElmLev0(int step,PViewData * in)2635 int adaptiveData::countTotElmLev0(int step, PViewData *in)
2636 {
2637 int sumElm = 0;
2638
2639 if(_triangles) sumElm += _triangles->countElmLev0(step, in);
2640 if(_quadrangles) sumElm += _quadrangles->countElmLev0(step, in);
2641 if(_tetrahedra) sumElm += _tetrahedra->countElmLev0(step, in);
2642 if(_prisms) sumElm += _prisms->countElmLev0(step, in);
2643 if(_hexahedra) sumElm += _hexahedra->countElmLev0(step, in);
2644 if(_pyramids) sumElm += _pyramids->countElmLev0(step, in);
2645
2646 return sumElm;
2647 }
2648
changeResolutionForVTK(int step,int level,double tol,int npart,bool isBinary,const std::string & guiFileName,int useDefaultName)2649 void adaptiveData::changeResolutionForVTK(int step, int level, double tol,
2650 int npart, bool isBinary,
2651 const std::string &guiFileName,
2652 int useDefaultName)
2653 {
2654 // clean global VTK data structure before (re)generating it
2655 if(buildStaticData == true) globalVTKData::clearGlobalData();
2656
2657 VTKData myVTKData(_inData->getName(), _inData->getNumComponents(0, 0, 0),
2658 step, level, tol, guiFileName, useDefaultName, npart,
2659 isBinary);
2660 myVTKData.vtkTotNumElmLev0 = countTotElmLev0(step, _inData);
2661 myVTKData.setFileDistribution();
2662
2663 // Views of 2D and 3D elements only supported for VTK. _points and _lines are
2664 // currently ignored.
2665 if(_triangles) _triangles->init(myVTKData.vtkLevel);
2666 if(_quadrangles) _quadrangles->init(myVTKData.vtkLevel);
2667 if(_tetrahedra) _tetrahedra->init(myVTKData.vtkLevel);
2668 if(_prisms) _prisms->init(myVTKData.vtkLevel);
2669 if(_hexahedra) _hexahedra->init(myVTKData.vtkLevel);
2670 if(_pyramids) _pyramids->init(myVTKData.vtkLevel);
2671
2672 if(_triangles)
2673 _triangles->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2674 buildStaticData);
2675 if(_quadrangles)
2676 _quadrangles->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2677 buildStaticData);
2678 if(_tetrahedra)
2679 _tetrahedra->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2680 buildStaticData);
2681 if(_prisms)
2682 _prisms->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2683 buildStaticData);
2684 if(_hexahedra)
2685 _hexahedra->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2686 buildStaticData);
2687 if(_pyramids)
2688 _pyramids->addInViewForVTK(step, _inData, myVTKData, writeVTK,
2689 buildStaticData);
2690
2691 Msg::StatusBar(true, "Done writing VTK data");
2692 }
2693