dune-vtk 2.12
Loading...
Searching...
No Matches
lagrangepoints.impl.hh
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <array>
5
11
12namespace Dune::Vtk {
13namespace Impl {
14
58template <class K>
59 template <class Points>
60void LagrangePointSetBuilder<K,0>::operator() (GeometryType gt, int /*order*/, Points& points) const
61{
62 assert(gt.isVertex());
63 points.push_back(LP{Vec{},Key{0,0,0}});
64}
65
66
67template <class K>
68 template <class Points>
69void LagrangePointSetBuilder<K,1>::operator() (GeometryType gt, int order, Points& points) const
70{
71 assert(gt.isLine());
72
73 if (order == 0) {
74 auto refElem = Dune::referenceElement<K,1>(gt);
75 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
76 return;
77 }
78
79 // Vertex nodes
80 points.push_back(LP{Vec{0.0}, Key{0,dim,0}});
81 points.push_back(LP{Vec{1.0}, Key{1,dim,0}});
82
83 if (order > 1) {
84 // Inner nodes
85 Vec p{0.0};
86 for (int i = 0; i < order-1; i++)
87 {
88 p[0] += 1.0 / order;
89 points.push_back(LP{p,Key{0,dim-1,(unsigned int)(i)}});
90 }
91 }
92}
93
94
95template <class K>
96 template <class Points>
97void LagrangePointSetBuilder<K,2>::operator() (GeometryType gt, int order, Points& points) const
98{
99 if (order == 0) {
100 auto refElem = Dune::referenceElement<K,2>(gt);
101 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
102 return;
103 }
104
105 if (gt.isTriangle())
106 buildTriangle(order, points);
107 else if (gt.isQuadrilateral())
108 buildQuad(order, order, points);
109 else {
111 "Lagrange points not yet implemented for this GeometryType.");
112 }
113
114 [[maybe_unused]] std::size_t nPoints = numLagrangePoints(gt, order);
115 assert(points.size() == nPoints);
116}
117
118
119// Construct the point set in a triangle element.
120// Loop from the outside to the inside
121template <class K>
122 template <class Points>
123void LagrangePointSetBuilder<K,2>::buildTriangle (int order, Points& points) const
124{
125 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(2), order);
126 points.reserve(nPoints);
127
128 const int nVertexDOFs = 3;
129 const int nEdgeDOFs = 3 * (order-1);
130
131 static const unsigned int vertexPerm[3] = {0,1,2};
132 static const unsigned int edgePerm[3] = {0,2,1};
133
134 auto calcKey = [&](int p) -> Key
135 {
136 if (p < nVertexDOFs) {
137 return Key{vertexPerm[p], dim, 0};
138 }
139 else if (p < nVertexDOFs+nEdgeDOFs) {
140 unsigned int entityIndex = (p - nVertexDOFs) / (order-1);
141 unsigned int index = (p - nVertexDOFs) % (order-1);
142 return Key{edgePerm[entityIndex], dim-1, index};
143 }
144 else {
145 unsigned int index = p - (nVertexDOFs + nEdgeDOFs);
146 return Key{0, dim-2, index};
147 }
148 };
149
150 std::array<int,3> bindex;
151
152 K order_d = K(order);
153 for (std::size_t p = 0; p < nPoints; ++p) {
154 barycentricIndex(p, bindex, order);
155 Vec point{bindex[0] / order_d, bindex[1] / order_d};
156 points.push_back(LP{point, calcKey(p)});
157 }
158}
159
160
161// "Barycentric index" is a triplet of integers, each running from 0 to
162// <Order>. It is the index of a point on the triangle in barycentric
163// coordinates.
164template <class K>
165void LagrangePointSetBuilder<K,2>::barycentricIndex (int index, std::array<int,3>& bindex, int order)
166{
167 int max = order;
168 int min = 0;
169
170 // scope into the correct triangle
171 while (index != 0 && index >= 3 * order)
172 {
173 index -= 3 * order;
174 max -= 2;
175 min++;
176 order -= 3;
177 }
178
179 // vertex DOFs
180 if (index < 3)
181 {
182 bindex[index] = bindex[(index + 1) % 3] = min;
183 bindex[(index + 2) % 3] = max;
184 }
185 // edge DOFs
186 else
187 {
188 index -= 3;
189 int dim = index / (order - 1);
190 int offset = (index - dim * (order - 1));
191 bindex[(dim + 1) % 3] = min;
192 bindex[(dim + 2) % 3] = (max - 1) - offset;
193 bindex[dim] = (min + 1) + offset;
194 }
195}
196
197
198// Construct the point set in the quad element
199// 1. build equispaced points with index tuple (i,j)
200// 2. map index tuple to DOF index and LocalKey
201template <class K>
202 template <class Points>
203void LagrangePointSetBuilder<K,2>::buildQuad(int orderx, int ordery, Points& points) const
204{
205 if (orderx == 0 && ordery == 0) {
206 points.push_back(LP{Vec{0.5, 0.5}});
207 return;
208 }
209 else if (orderx == 0) {
211 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line, ordery, linePoints);
212 points.reserve(linePoints.size());
213 for (auto& p : linePoints)
214 points.push_back(LP{Vec{0.5, p.point()[0]}});
215 return;
216 }
217 else if (ordery == 0) {
219 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line, orderx, linePoints);
220 points.reserve(linePoints.size());
221 for (auto& p : linePoints)
222 points.push_back(LP{Vec{p.point()[0], 0.5}});
223 return;
224 }
225
226 std::size_t nPoints = numLagrangePoints(GeometryTypes::line, orderx);
227 nPoints *= numLagrangePoints(GeometryTypes::line, ordery);
228 points.resize(nPoints);
229
230 assert(orderx > 0 && ordery > 0);
231 std::array<int,2> orders{orderx, ordery};
232 std::array<Vec,4> nodes{Vec{0., 0.}, Vec{1., 0.}, Vec{1., 1.}, Vec{0., 1.}};
233
234 for (int n = 0; n <= orders[1]; ++n) {
235 for (int m = 0; m <= orders[0]; ++m) {
236 // int idx = pointIndexFromIJ(m,n,orders);
237
238 const K r = K(m) / orders[0];
239 const K s = K(n) / orders[1];
240 Vec p = K(1.0-r) * (nodes[3] * s + nodes[0] * K(1.0 - s)) +
241 r * (nodes[2] * s + nodes[1] * K(1.0 - s));
242
243 auto [idx,key] = calcQuadKey(m,n,orders);
244 points[idx] = LP{p, key};
245 // points[idx] = LP{p, calcQuadKey(n,m,orders)};
246 }
247 }
248}
249
250
251// Obtain the VTK DOF index of the node (i,j) in the quad element
252// and construct a LocalKey
253template <class K>
255LagrangePointSetBuilder<K,2>::calcQuadKey (int i, int j, std::array<int,2> order)
256{
257 const bool ibdy = (i == 0 || i == order[0]);
258 const bool jbdy = (j == 0 || j == order[1]);
259 const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0); // How many boundaries do we lie on at once?
260
261 int dof = 0;
262 unsigned int entityIndex = 0;
263 unsigned int index = 0;
264
265 if (nbdy == 2) // Vertex DOF
266 {
267 dof = (i ? (j ? 2 : 1) : (j ? 3 : 0));
268 entityIndex = (j ? (i ? 3 : 2) : (i ? 1 : 0));
269 return std::make_pair(dof,Key{entityIndex, dim, 0});
270 }
271
272 int offset = 4;
273 if (nbdy == 1) // Edge DOF
274 {
275 if (!ibdy) {
276 dof = (i - 1) + (j ? order[0]-1 + order[1]-1 : 0) + offset;
277 entityIndex = j ? 3 : 2;
278 index = i-1;
279 }
280 else if (!jbdy) {
281 dof = (j - 1) + (i ? order[0]-1 : 2 * (order[0]-1) + order[1]-1) + offset;
282 entityIndex = i ? 1 : 0;
283 index = j-1;
284 }
285 return std::make_pair(dof, Key{entityIndex, dim-1, index});
286 }
287
288 offset += 2 * (order[0]-1 + order[1]-1);
289
290 // nbdy == 0: Face DOF
291 dof = offset + (i - 1) + (order[0]-1) * ((j - 1));
292 Key innerKey = LagrangePointSetBuilder<K,2>::calcQuadKey(i-1,j-1,{order[0]-2, order[1]-2}).second;
293 return std::make_pair(dof, Key{0, dim-2, innerKey.index()});
294}
295
296
297// Lagrange points on 3d geometries
298template <class K>
299 template <class Points>
300void LagrangePointSetBuilder<K,3>::operator() (GeometryType gt, unsigned int order, Points& points) const
301{
302 if (order == 0) {
303 auto refElem = Dune::referenceElement<K,3>(gt);
304 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
305 return;
306 }
307
308 if (gt.isTetrahedron())
309 buildTetra(order, points);
310 else if (gt.isHexahedron())
311 buildHex(order, points);
312 else if (gt.isPrism())
313 buildWedge(order, order, points);
314 else {
316 "Lagrange points not yet implemented for this GeometryType.");
317 }
318
319 [[maybe_unused]] std::size_t nPoints = numLagrangePoints(gt, order);
320 assert(points.size() == nPoints);
321}
322
323
324// Construct the point set in the tetrahedron element
325// 1. construct barycentric (index) coordinates
326// 2. obtains the DOF index, LocalKey and actual coordinate from barycentric index
327template <class K>
328 template <class Points>
329void LagrangePointSetBuilder<K,3>::buildTetra (int order, Points& points) const
330{
331 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(3), order);
332 points.reserve(nPoints);
333
334 const int nVertexDOFs = 4;
335 const int nEdgeDOFs = 6 * (order-1);
336 const int nFaceDOFs = 4 * (order-1)*(order-2)/2;
337
338 static const unsigned int vertexPerm[4] = {0,1,2,3};
339 static const unsigned int edgePerm[6] = {0,2,1,3,4,5};
340 static const unsigned int facePerm[4] = {1,2,0,3};
341
342 auto calcKey = [&](int p) -> Key
343 {
344 if (p < nVertexDOFs) {
345 return Key{vertexPerm[p], dim, 0};
346 }
347 else if (p < nVertexDOFs+nEdgeDOFs) {
348 unsigned int entityIndex = (p - nVertexDOFs) / (order-1);
349 unsigned int index = (p - nVertexDOFs) % (order-1);
350 return Key{edgePerm[entityIndex], dim-1, index};
351 }
352 else if (p < nVertexDOFs+nEdgeDOFs+nFaceDOFs) {
353 unsigned int index = (p - (nVertexDOFs + nEdgeDOFs)) % ((order-1)*(order-2)/2);
354 unsigned int entityIndex = (p - (nVertexDOFs + nEdgeDOFs)) / ((order-1)*(order-2)/2);
355 return Key{facePerm[entityIndex], dim-2, index};
356 }
357 else {
358 unsigned int index = p - (nVertexDOFs + nEdgeDOFs + nFaceDOFs);
359 return Key{0, dim-3, index};
360 }
361 };
362
363 std::array<int,4> bindex;
364
365 K order_d = K(order);
366 for (std::size_t p = 0; p < nPoints; ++p) {
367 barycentricIndex(p, bindex, order);
368 Vec point{bindex[0] / order_d, bindex[1] / order_d, bindex[2] / order_d};
369 points.push_back(LP{point, calcKey(p)});
370 }
371}
372
373
374// "Barycentric index" is a set of 4 integers, each running from 0 to
375// <Order>. It is the index of a point in the tetrahedron in barycentric
376// coordinates.
377template <class K>
378void LagrangePointSetBuilder<K,3>::barycentricIndex (int p, std::array<int,4>& bindex, int order)
379{
380 const int nVertexDOFs = 4;
381 const int nEdgeDOFs = 6 * (order-1);
382
383 static const int edgeVertices[6][2] = {{0,1}, {1,2}, {2,0}, {0,3}, {1,3}, {2,3}};
384 static const int linearVertices[4][4] = {{0,0,0,1}, {1,0,0,0}, {0,1,0,0}, {0,0,1,0}};
385 static const int vertexMaxCoords[4] = {3,0,1,2};
386 static const int faceBCoords[4][3] = {{0,2,3}, {2,0,1}, {2,1,3}, {1,0,3}};
387 static const int faceMinCoord[4] = {1,3,0,2};
388
389 int max = order;
390 int min = 0;
391
392 // scope into the correct tetra
393 while (p >= 2 * (order * order + 1) && p != 0 && order > 3)
394 {
395 p -= 2 * (order * order + 1);
396 max -= 3;
397 min++;
398 order -= 4;
399 }
400
401 // vertex DOFs
402 if (p < nVertexDOFs)
403 {
404 for (int coord = 0; coord < 4; ++coord)
405 bindex[coord] = (coord == vertexMaxCoords[p] ? max : min);
406 }
407 // edge DOFs
408 else if (p < nVertexDOFs+nEdgeDOFs)
409 {
410 int edgeId = (p - nVertexDOFs) / (order-1);
411 int vertexId = (p - nVertexDOFs) % (order-1);
412 for (int coord = 0; coord < 4; ++coord)
413 {
414 bindex[coord] = min +
415 (linearVertices[edgeVertices[edgeId][0]][coord] * (max - min - 1 - vertexId) +
416 linearVertices[edgeVertices[edgeId][1]][coord] * (1 + vertexId));
417 }
418 }
419 // face DOFs
420 else
421 {
422 int faceId = (p - (nVertexDOFs+nEdgeDOFs)) / ((order-2)*(order-1)/2);
423 int vertexId = (p - (nVertexDOFs+nEdgeDOFs)) % ((order-2)*(order-1)/2);
424
425 std::array<int,3> projectedBIndex;
426 if (order == 3)
427 projectedBIndex[0] = projectedBIndex[1] = projectedBIndex[2] = 0;
428 else
429 LagrangePointSetBuilder<K,2>::barycentricIndex(vertexId, projectedBIndex, order-3);
430
431 for (int i = 0; i < 3; i++)
432 bindex[faceBCoords[faceId][i]] = (min + 1 + projectedBIndex[i]);
433
434 bindex[faceMinCoord[faceId]] = min;
435 }
436}
437
438
439// Construct the point set in the hexahedral element
440// 1. build equispaced points with index tuple (i,j,k)
441// 2. map index tuple to DOF index and LocalKey
442template <class K>
443 template <class Points>
444void LagrangePointSetBuilder<K,3>::buildHex (int order, Points& points) const
445{
446 std::size_t nPoints = numLagrangePoints(GeometryTypes::cube(3), order);
447 points.resize(nPoints);
448
449 std::array<int,3> orders{order, order, order};
450 std::array<Vec,8> nodes{Vec{0., 0., 0.}, Vec{1., 0., 0.}, Vec{1., 1., 0.}, Vec{0., 1., 0.},
451 Vec{0., 0., 1.}, Vec{1., 0., 1.}, Vec{1., 1., 1.}, Vec{0., 1., 1.}};
452
453 for (int p = 0; p <= orders[2]; ++p) {
454 for (int n = 0; n <= orders[1]; ++n) {
455 for (int m = 0; m <= orders[0]; ++m) {
456 const K r = K(m) / orders[0];
457 const K s = K(n) / orders[1];
458 const K t = K(p) / orders[2];
459 Vec point = K(1.0-r) * ((nodes[3] * K(1.0-t) + nodes[7] * t) * s + (nodes[0] * K(1.0-t) + nodes[4] * t) * K(1.0-s)) +
460 r * ((nodes[2] * K(1.0-t) + nodes[6] * t) * s + (nodes[1] * K(1.0-t) + nodes[5] * t) * K(1.0-s));
461
462 auto [idx,key] = calcHexKey(m,n,p,orders);
463 points[idx] = LP{point, key};
464 }
465 }
466 }
467}
468
469
470// Obtain the VTK DOF index of the node (i,j,k) in the hexahedral element
471template <class K>
473LagrangePointSetBuilder<K,3>::calcHexKey (int i, int j, int k, std::array<int,3> order)
474{
475 const bool ibdy = (i == 0 || i == order[0]);
476 const bool jbdy = (j == 0 || j == order[1]);
477 const bool kbdy = (k == 0 || k == order[2]);
478 const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0) + (kbdy ? 1 : 0); // How many boundaries do we lie on at once?
479
480 int dof = 0;
481 unsigned int entityIndex = 0;
482 unsigned int index = 0;
483
484 if (nbdy == 3) // Vertex DOF
485 {
486 dof = (i ? (j ? 2 : 1) : (j ? 3 : 0)) + (k ? 4 : 0);
487 entityIndex = (i ? 1 : 0) + (j ? 2 : 0) + (k ? 4 : 0);
488 return std::make_pair(dof, Key{entityIndex, dim, 0});
489 }
490
491 int offset = 8;
492 if (nbdy == 2) // Edge DOF
493 {
494 entityIndex = (k ? 8 : 4);
495 if (!ibdy)
496 { // On i axis
497 dof = (i - 1) + (j ? order[0]-1 + order[1]-1 : 0) + (k ? 2 * (order[0]-1 + order[1]-1) : 0) + offset;
498 index = i;
499 entityIndex += (i ? 1 : 0);
500 }
501 else if (!jbdy)
502 { // On j axis
503 dof = (j - 1) + (i ? order[0]-1 : 2 * (order[0]-1) + order[1]-1) + (k ? 2 * (order[0]-1 + order[1]-1) : 0) + offset;
504 index = j;
505 entityIndex += (j ? 3 : 2);
506 }
507 else
508 { // !kbdy, On k axis
509 offset += 4 * (order[0]-1) + 4 * (order[1]-1);
510 dof = (k - 1) + (order[2]-1) * (i ? (j ? 3 : 1) : (j ? 2 : 0)) + offset;
511 index = k;
512 entityIndex = (i ? 1 : 0) + (j ? 2 : 0);
513 }
514 return std::make_pair(dof, Key{entityIndex, dim-1, index});
515 }
516
517 offset += 4 * (order[0]-1 + order[1]-1 + order[2]-1);
518 if (nbdy == 1) // Face DOF
519 {
520 Key faceKey;
521 if (ibdy) // On i-normal face
522 {
523 dof = (j - 1) + ((order[1]-1) * (k - 1)) + (i ? (order[1]-1) * (order[2]-1) : 0) + offset;
524 entityIndex = (i ? 1 : 0);
525 faceKey = LagrangePointSetBuilder<K,2>::calcQuadKey(j-1,k-1,{order[1]-2, order[2]-2}).second;
526 }
527 else {
528 offset += 2 * (order[1] - 1) * (order[2] - 1);
529 if (jbdy) // On j-normal face
530 {
531 dof = (i - 1) + ((order[0]-1) * (k - 1)) + (j ? (order[2]-1) * (order[0]-1) : 0) + offset;
532 entityIndex = (j ? 3 : 2);
533 faceKey = LagrangePointSetBuilder<K,2>::calcQuadKey(i-1,k-1,{order[0]-2, order[2]-2}).second;
534 }
535 else
536 { // kbdy, On k-normal face
537 offset += 2 * (order[2]-1) * (order[0]-1);
538 dof = (i - 1) + ((order[0]-1) * (j - 1)) + (k ? (order[0]-1) * (order[1]-1) : 0) + offset;
539 entityIndex = (k ? 5 : 4);
540 faceKey = LagrangePointSetBuilder<K,2>::calcQuadKey(i-1,j-1,{order[0]-2, order[1]-2}).second;
541 }
542 }
543 return std::make_pair(dof, Key{entityIndex, dim-2, faceKey.index()});
544 }
545
546 // nbdy == 0: Body DOF
547 offset += 2 * ((order[1]-1) * (order[2]-1) + (order[2]-1) * (order[0]-1) + (order[0]-1) * (order[1]-1));
548 dof = offset + (i - 1) + (order[0]-1) * ((j - 1) + (order[1]-1) * ((k - 1)));
549 Key innerKey = LagrangePointSetBuilder<K,3>::calcHexKey(i-1,j-1,k-1,{order[0]-2, order[1]-2, order[2]-2}).second;
550 return std::make_pair(dof, Key{0, dim-3, innerKey.index()});
551}
552
553template <class K>
554 template <class Points>
555void LagrangePointSetBuilder<K,3>::buildWedge (int order_tri, int order_quad, Points& points) const
556{
557 auto refElem = Dune::referenceElement<K,3>(GeometryTypes::prism);
558
559 // flip the y-axis
560 auto flip = [](auto x) { x[1] = 1-x[1]; return x; };
561
562 // transform the coordinates by shifting and scaling
563 auto shrink_linexy = [order_tri](auto x) { x *= (1-K(2)/order_tri); x += decltype(x)(K(1)/order_tri); return x; };
564 auto shrink_linez = [order_quad](auto x) { x *= (1-K(2)/order_quad); x += decltype(x)(K(1)/order_quad); return x; };
565 auto shrink_tri = [order_tri](auto x) { x *= (1-K(3)/order_tri); x += decltype(x)(K(1)/order_tri); return x; };
566 auto shrink_quad = [order_tri,order_quad](auto x) {
567 x[0] *= (1-K(2)/order_tri);
568 x[1] *= (1-K(2)/order_quad);
569 x += decltype(x){K(1)/order_tri, K(1)/order_quad};
570 return x;
571 };
572 auto shrink_prism = [order_tri,order_quad](auto x) {
573 x[0] *= (1-K(3)/order_tri);
574 x[1] *= (1-K(3)/order_tri);
575 x[2] *= (1-K(2)/order_quad);
576 x += decltype(x){K(1)/order_tri, K(1)/order_tri, K(1)/order_quad};
577 return x;
578 };
579
580 // embed the point set into a sub-area of a subentity of the prism element
581 auto embed = [&](auto const& entityPoints, auto const& perm, auto codim, auto shrink) {
582 for (int p : perm) {
583 unsigned int s = std::abs(p);
584 constexpr unsigned int c = codim.value;
585 auto geo = refElem.template geometry<c>(s);
586
587 unsigned int i = 0;
588 for (auto& lp : entityPoints) {
589 if (p < 0)
590 points.push_back(LP{Vec{flip(geo.global(shrink(lp.point())))}, Key{s,c,i}});
591 else
592 points.push_back(LP{Vec{geo.global(shrink(lp.point()))}, Key{s,c,i}});
593 i++;
594 }
595 }
596 };
597
598 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(2), order_tri);
599 nPoints *= numLagrangePoints(GeometryTypes::line, order_quad);
600 points.reserve(nPoints);
601
602 if (order_tri >= 0 && order_quad >= 0) {
603 // 1. vertex and inner DOFs
605 LagrangePointSetBuilder<K,2>{}(GeometryTypes::simplex(2), std::min(order_tri,1), triPoints);
606
608 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line, std::min(order_quad,1), linePoints);
609
610 unsigned int i = 0;
611 for (auto& p0 : linePoints)
612 for (auto& p1 : triPoints)
613 points.push_back(LP{Vec{p1.point()[0], p1.point()[1], p0.point()[0]},Key{i++,3,0}});
614 }
615
616 if (order_tri > 1) {
617 // 2. edge DOFs on horizontal
619 LexicographicPointSetBuilder<K,1>::buildLine(order_tri-2, linePoints);
620 embed(linePoints, std::array{3,5,-4,6,8,-7}, Codim<2>{}, shrink_linexy);
621 }
622
623 if (order_quad > 1) {
624 // 2. edge DOFs on vertical edges
626 LexicographicPointSetBuilder<K,1>::buildLine(order_quad-2, linePoints);
627 if (order_tri == 0)
628 embed(linePoints, std::array{0}, Codim<2>{}, shrink_linez);
629 else
630 embed(linePoints, std::array{0,1,2}, Codim<2>{}, shrink_linez);
631 }
632
633 if (order_tri > 2) {
634 // 3. triangular face DOFs
636 LagrangePointSetBuilder<K,2>{}(GeometryTypes::simplex(2), order_tri-3, triPoints);
637 embed(triPoints, std::array{3,4}, Codim<1>{}, shrink_tri);
638 }
639
640 if (order_tri > 1 && order_quad > 1) {
641 // 4. quad face DOFs
643 LexicographicPointSetBuilder<K,2>::buildQuad(order_tri-2, order_quad-2, quadPoints);
644 embed(quadPoints, std::array{0,2,-1}, Codim<1>{}, shrink_quad);
645 }
646
647 if (order_tri >= 3 && order_quad >= 2) {
648 // 5. volume DOFs
650 buildWedge(order_tri-3, order_quad-2, prismPoints);
651 embed(prismPoints, std::array{0}, Codim<0>{}, shrink_prism);
652 }
653}
654
655
656template <class K, unsigned int dim>
657 template <class Points>
658void LexicographicPointSetBuilder<K,dim>::buildLine (int a, Points& points)
659{
660 static_assert(dim == 1);
661 using Point = typename Points::value_type;
662 using Vec = typename Point::Vector;
663 using Key = Dune::LocalKey;
664
665 auto coord = [a](int i) { return a == 0 ? K(0.5) : K(i)/a; };
666
667 for (int i = 0; i < a+1; ++i) {
668 auto key = (i == 0 || i == a)
669 ? Key(0u + (i > 0), 1, 0) // vertex
670 : Key(0, 0, i-1); // edge
671 points.push_back(Point{Vec{coord(i)}, key});
672 }
673}
674
675
676template <class K, unsigned int dim>
677 template <class Points>
678void LexicographicPointSetBuilder<K,dim>::buildQuad (int a, int b, Points& points)
679{
680 static_assert(dim == 2);
681 using Point = typename Points::value_type;
682 using Vec = typename Point::Vector;
683 using Key = Dune::LocalKey;
684
685 auto coord_a = [a](int i) { return a == 0 ? K(0.5) : K(i)/a; };
686 auto coord_b = [b](int i) { return b == 0 ? K(0.5) : K(i)/b; };
687
688 for (int j = 0; j < b+1; ++j) {
689 for (int i = 0; i < a+1; ++i) {
690 auto key = ((i == 0 || i == a) && (j == 0 || j == b))
691 ? Key((i > 0) + 2u * (j > 0), 2, 0) // vertex
692 : (i == 0 || i == a) ? Key(0u + (i > 0), 1, j-1) // left/right edge
693 : (j == 0 || j == b) ? Key(2u + (j > 0), 1, i-1) // bottom/top edge
694 : Key(0, 0, i-1); // face
695
696 points.push_back(Point{Vec{coord_a(i), coord_b(j)}, key});
697 }
698 }
699}
700
701
702template <class K, unsigned int dim>
703 template <class Points>
704void LexicographicPointSetBuilder<K,dim>::buildHex (int a, int b, int c, Points& points)
705{
706 static_assert(dim == 3);
707 using Point = typename Points::value_type;
708 using Vec = typename Point::Vector;
709 using Key = Dune::LocalKey;
710
711 auto coord_a = [a](int i) { return a == 0 ? K(0.5) : K(i)/a; };
712 auto coord_b = [b](int i) { return b == 0 ? K(0.5) : K(i)/b; };
713 auto coord_c = [c](int i) { return c == 0 ? K(0.5) : K(i)/c; };
714
715 for (int k = 0; k < c+1; ++k) {
716 for (int j = 0; j < b+1; ++j) {
717 for (int i = 0; i < a+1; ++i) {
718 auto key = ((i == 0 || i == a) && (j == 0 || j == b) && (k == 0 | k == c))
719 ? Key((i > 0) + 2u * (j > 0) + 4u * (k > 0), 3, 0) // vertex
720 : (i == 0 || i == a) ? Key(0u + (i > 0), 2, (k-1)*(b-1) + (j-1)) // left/right face
721 : (j == 0 || j == b) ? Key(2u + (j > 0), 2, (k-1)*(a-1) + (i-1)) // front/rear face
722 : (k == 0 || k == c) ? Key(4u + (k > 0), 2, (j-1)*(a-1) + (i-1)) // bottom/top face
723 : (i == 0 && j == 0) ? Key(0,1,k-1) // edge 0
724 : (i == a && j == 0) ? Key(1,1,k-1) // edge 1
725 : (i == 0 && j == b) ? Key(2,1,k-1)
726 : (i == a && j == b) ? Key(3,1,k-1)
727 : (i == 0 && k == 0) ? Key(4,1,j-1)
728 : (i == a && k == 0) ? Key(5,1,j-1)
729 : (j == 0 && k == 0) ? Key(6,1,i-1)
730 : (j == b && k == 0) ? Key(7,1,i-1)
731 : (i == 0 && k == c) ? Key(8,1,j-1)
732 : (i == a && k == c) ? Key(9,1,j-1)
733 : (j == 0 && k == c) ? Key(10,1,i-1)
734 : (j == b && k == c) ? Key(11,1,i-1) // edge 11
735 : Key(0, 0, (k-1)*(b-1)*(a-1) + (j-1)*(a-1) + (i-1)); // cell
736
737 points.push_back(Point{Vec{coord_a(i), coord_b(j), coord_c(k)}, key});
738 }
739 }
740 }
741}
742
743}} // end namespace Dune::Vtk::Impl
Definition writer.hh:16
constexpr auto max
constexpr auto min
bool gt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon=DefaultEpsilon< T, style >::value())
size_type dim() const
std::ptrdiff_t index() const
#define DUNE_THROW(E,...)
constexpr std::integer_sequence< T, II..., T(IN)> push_back(std::integer_sequence< T, II... >, std::integral_constant< T, IN >={})
T make_pair(T... args)
T min(T... args)
T reserve(T... args)
T size(T... args)