59 template <
class Po
ints>
60void LagrangePointSetBuilder<K,0>::operator() (GeometryType gt,
int , Points& points)
const
62 assert(
gt.isVertex());
63 points.push_back(LP{Vec{},Key{0,0,0}});
68 template <
class Po
ints>
69void LagrangePointSetBuilder<K,1>::operator() (GeometryType gt,
int order, Points& points)
const
74 auto refElem = Dune::referenceElement<K,1>(gt);
75 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
80 points.push_back(LP{Vec{0.0}, Key{0,
dim,0}});
81 points.push_back(LP{Vec{1.0}, Key{1,
dim,0}});
86 for (
int i = 0; i < order-1; i++)
89 points.push_back(LP{p,Key{0,
dim-1,(
unsigned int)(i)}});
96 template <
class Po
ints>
97void LagrangePointSetBuilder<K,2>::operator() (GeometryType gt,
int order, Points& points)
const
100 auto refElem = Dune::referenceElement<K,2>(gt);
101 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
106 buildTriangle(order, points);
107 else if (
gt.isQuadrilateral())
108 buildQuad(order, order, points);
111 "Lagrange points not yet implemented for this GeometryType.");
114 [[maybe_unused]]
std::size_t nPoints = numLagrangePoints(gt, order);
115 assert(points.size() == nPoints);
122 template <
class Po
ints>
123void LagrangePointSetBuilder<K,2>::buildTriangle (
int order, Points& points)
const
125 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(2), order);
126 points.reserve(nPoints);
128 const int nVertexDOFs = 3;
129 const int nEdgeDOFs = 3 * (order-1);
131 static const unsigned int vertexPerm[3] = {0,1,2};
132 static const unsigned int edgePerm[3] = {0,2,1};
134 auto calcKey = [&](
int p) -> Key
136 if (p < nVertexDOFs) {
137 return Key{vertexPerm[p],
dim, 0};
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};
145 unsigned int index = p - (nVertexDOFs + nEdgeDOFs);
152 K order_d = K(order);
154 barycentricIndex(p, bindex, order);
155 Vec point{bindex[0] / order_d, bindex[1] / order_d};
156 points.push_back(LP{point, calcKey(p)});
182 bindex[
index] = bindex[(
index + 1) % 3] = min;
183 bindex[(
index + 2) % 3] = max;
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;
202 template <
class Po
ints>
203void LagrangePointSetBuilder<K,2>::buildQuad(
int orderx,
int ordery, Points& points)
const
205 if (orderx == 0 && ordery == 0) {
206 points.push_back(LP{Vec{0.5, 0.5}});
209 else if (orderx == 0) {
211 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line, ordery, linePoints);
213 for (
auto& p : linePoints)
214 points.
push_back(LP{Vec{0.5, p.point()[0]}});
217 else if (ordery == 0) {
219 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line, orderx, linePoints);
221 for (
auto& p : linePoints)
222 points.
push_back(LP{Vec{p.point()[0], 0.5}});
226 std::size_t nPoints = numLagrangePoints(GeometryTypes::line, orderx);
227 nPoints *= numLagrangePoints(GeometryTypes::line, ordery);
228 points.resize(nPoints);
230 assert(orderx > 0 && ordery > 0);
234 for (
int n = 0; n <= orders[1]; ++n) {
235 for (
int m = 0; m <= orders[0]; ++m) {
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));
243 auto [idx,key] = calcQuadKey(m,n,orders);
244 points[idx] = LP{p, key};
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);
262 unsigned int entityIndex = 0;
263 unsigned int index = 0;
267 dof = (i ? (j ? 2 : 1) : (j ? 3 : 0));
268 entityIndex = (j ? (i ? 3 : 2) : (i ? 1 : 0));
276 dof = (i - 1) + (j ? order[0]-1 + order[1]-1 : 0) + offset;
277 entityIndex = j ? 3 : 2;
281 dof = (j - 1) + (i ? order[0]-1 : 2 * (order[0]-1) + order[1]-1) + offset;
282 entityIndex = i ? 1 : 0;
288 offset += 2 * (order[0]-1 + order[1]-1);
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;
299 template <
class Po
ints>
300void LagrangePointSetBuilder<K,3>::operator() (GeometryType gt,
unsigned int order, Points& points)
const
303 auto refElem = Dune::referenceElement<K,3>(gt);
304 points.push_back(LP{refElem.position(0,0), Key{0,0,0}});
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);
316 "Lagrange points not yet implemented for this GeometryType.");
319 [[maybe_unused]]
std::size_t nPoints = numLagrangePoints(gt, order);
320 assert(points.size() == nPoints);
328 template <
class Po
ints>
329void LagrangePointSetBuilder<K,3>::buildTetra (
int order, Points& points)
const
331 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(3), order);
332 points.reserve(nPoints);
334 const int nVertexDOFs = 4;
335 const int nEdgeDOFs = 6 * (order-1);
336 const int nFaceDOFs = 4 * (order-1)*(order-2)/2;
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};
342 auto calcKey = [&](
int p) -> Key
344 if (p < nVertexDOFs) {
345 return Key{vertexPerm[p],
dim, 0};
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};
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};
358 unsigned int index = p - (nVertexDOFs + nEdgeDOFs + nFaceDOFs);
365 K order_d = K(order);
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)});
378void LagrangePointSetBuilder<K,3>::barycentricIndex (
int p,
std::array<int,4>& bindex,
int order)
380 const int nVertexDOFs = 4;
381 const int nEdgeDOFs = 6 * (order-1);
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};
393 while (p >= 2 * (order * order + 1) && p != 0 && order > 3)
395 p -= 2 * (order * order + 1);
404 for (
int coord = 0; coord < 4; ++coord)
405 bindex[coord] = (coord == vertexMaxCoords[p] ? max :
min);
408 else if (p < nVertexDOFs+nEdgeDOFs)
410 int edgeId = (p - nVertexDOFs) / (order-1);
411 int vertexId = (p - nVertexDOFs) % (order-1);
412 for (
int coord = 0; coord < 4; ++coord)
414 bindex[coord] =
min +
415 (linearVertices[edgeVertices[edgeId][0]][coord] * (
max -
min - 1 - vertexId) +
416 linearVertices[edgeVertices[edgeId][1]][coord] * (1 + vertexId));
422 int faceId = (p - (nVertexDOFs+nEdgeDOFs)) / ((order-2)*(order-1)/2);
423 int vertexId = (p - (nVertexDOFs+nEdgeDOFs)) % ((order-2)*(order-1)/2);
427 projectedBIndex[0] = projectedBIndex[1] = projectedBIndex[2] = 0;
429 LagrangePointSetBuilder<K,2>::barycentricIndex(vertexId, projectedBIndex, order-3);
431 for (
int i = 0; i < 3; i++)
432 bindex[faceBCoords[faceId][i]] = (min + 1 + projectedBIndex[i]);
434 bindex[faceMinCoord[faceId]] =
min;
443 template <
class Po
ints>
444void LagrangePointSetBuilder<K,3>::buildHex (
int order, Points& points)
const
446 std::size_t nPoints = numLagrangePoints(GeometryTypes::cube(3), order);
447 points.resize(nPoints);
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.}};
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));
462 auto [idx,key] = calcHexKey(m,n,p,orders);
463 points[idx] = LP{point, key};
473LagrangePointSetBuilder<K,3>::calcHexKey (
int i,
int j,
int k,
std::array<int,3> order)
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);
481 unsigned int entityIndex = 0;
482 unsigned int index = 0;
486 dof = (i ? (j ? 2 : 1) : (j ? 3 : 0)) + (k ? 4 : 0);
487 entityIndex = (i ? 1 : 0) + (j ? 2 : 0) + (k ? 4 : 0);
494 entityIndex = (k ? 8 : 4);
497 dof = (i - 1) + (j ? order[0]-1 + order[1]-1 : 0) + (k ? 2 * (order[0]-1 + order[1]-1) : 0) + offset;
499 entityIndex += (i ? 1 : 0);
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;
505 entityIndex += (j ? 3 : 2);
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;
512 entityIndex = (i ? 1 : 0) + (j ? 2 : 0);
517 offset += 4 * (order[0]-1 + order[1]-1 + order[2]-1);
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;
528 offset += 2 * (order[1] - 1) * (order[2] - 1);
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;
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;
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;
554 template <
class Po
ints>
555void LagrangePointSetBuilder<K,3>::buildWedge (
int order_tri,
int order_quad, Points& points)
const
557 auto refElem = Dune::referenceElement<K,3>(GeometryTypes::prism);
560 auto flip = [](
auto x) { x[1] = 1-x[1];
return x; };
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};
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};
581 auto embed = [&](
auto const& entityPoints,
auto const& perm,
auto codim,
auto shrink) {
583 unsigned int s = std::abs(p);
584 constexpr unsigned int c = codim.value;
585 auto geo = refElem.template geometry<c>(s);
588 for (
auto& lp : entityPoints) {
590 points.push_back(LP{Vec{flip(geo.global(shrink(lp.point())))}, Key{s,c,i}});
592 points.push_back(LP{Vec{geo.global(shrink(lp.point()))}, Key{s,c,i}});
598 std::size_t nPoints = numLagrangePoints(GeometryTypes::simplex(2), order_tri);
599 nPoints *= numLagrangePoints(GeometryTypes::line, order_quad);
600 points.reserve(nPoints);
602 if (order_tri >= 0 && order_quad >= 0) {
605 LagrangePointSetBuilder<K,2>{}(GeometryTypes::simplex(2),
std::min(order_tri,1), triPoints);
608 LagrangePointSetBuilder<K,1>{}(GeometryTypes::line,
std::min(order_quad,1), linePoints);
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}});
619 LexicographicPointSetBuilder<K,1>::buildLine(order_tri-2, linePoints);
620 embed(linePoints,
std::array{3,5,-4,6,8,-7}, Codim<2>{}, shrink_linexy);
623 if (order_quad > 1) {
626 LexicographicPointSetBuilder<K,1>::buildLine(order_quad-2, linePoints);
628 embed(linePoints,
std::array{0}, Codim<2>{}, shrink_linez);
630 embed(linePoints,
std::array{0,1,2}, Codim<2>{}, shrink_linez);
636 LagrangePointSetBuilder<K,2>{}(GeometryTypes::simplex(2), order_tri-3, triPoints);
637 embed(triPoints,
std::array{3,4}, Codim<1>{}, shrink_tri);
640 if (order_tri > 1 && order_quad > 1) {
643 LexicographicPointSetBuilder<K,2>::buildQuad(order_tri-2, order_quad-2, quadPoints);
644 embed(quadPoints,
std::array{0,2,-1}, Codim<1>{}, shrink_quad);
647 if (order_tri >= 3 && order_quad >= 2) {
650 buildWedge(order_tri-3, order_quad-2, prismPoints);
651 embed(prismPoints,
std::array{0}, Codim<0>{}, shrink_prism);
656template <
class K,
unsigned int dim>
657 template <
class Po
ints>
658void LexicographicPointSetBuilder<K,dim>::buildLine (
int a, Points& points)
660 static_assert(
dim == 1);
661 using Point =
typename Points::value_type;
662 using Vec =
typename Point::Vector;
665 auto coord = [a](
int i) {
return a == 0 ? K(0.5) : K(i)/a; };
667 for (
int i = 0; i < a+1; ++i) {
668 auto key = (i == 0 || i == a)
669 ? Key(0u + (i > 0), 1, 0)
671 points.push_back(Point{Vec{coord(i)}, key});
676template <
class K,
unsigned int dim>
677 template <
class Po
ints>
678void LexicographicPointSetBuilder<K,dim>::buildQuad (
int a,
int b, Points& points)
680 static_assert(
dim == 2);
681 using Point =
typename Points::value_type;
682 using Vec =
typename Point::Vector;
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; };
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)
692 : (i == 0 || i == a) ? Key(0u + (i > 0), 1, j-1)
693 : (j == 0 || j == b) ? Key(2u + (j > 0), 1, i-1)
696 points.push_back(Point{Vec{coord_a(i), coord_b(j)}, key});
702template <
class K,
unsigned int dim>
703 template <
class Po
ints>
704void LexicographicPointSetBuilder<K,dim>::buildHex (
int a,
int b,
int c, Points& points)
706 static_assert(
dim == 3);
707 using Point =
typename Points::value_type;
708 using Vec =
typename Point::Vector;
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; };
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)
720 : (i == 0 || i == a) ? Key(0u + (i > 0), 2, (k-1)*(b-1) + (j-1))
721 : (j == 0 || j == b) ? Key(2u + (j > 0), 2, (k-1)*(a-1) + (i-1))
722 : (k == 0 || k == c) ? Key(4u + (k > 0), 2, (j-1)*(a-1) + (i-1))
723 : (i == 0 && j == 0) ? Key(0,1,k-1)
724 : (i == a && j == 0) ? Key(1,1,k-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)
735 : Key(0, 0, (k-1)*(b-1)*(a-1) + (j-1)*(a-1) + (i-1));
737 points.push_back(Point{Vec{coord_a(i), coord_b(j), coord_c(k)}, key});
bool gt(const T &first, const T &second, typename EpsilonType< T >::Type epsilon=DefaultEpsilon< T, style >::value())
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 >={})