Nektar++
Tetrahedron.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Tetrahedron.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Mesh tet object.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
36 #include <LocalRegions/TetExp.h>
37 #include <SpatialDomains/TetGeom.h>
38 
41 
44 
45 using namespace std;
46 
47 namespace Nektar
48 {
49 namespace NekMeshUtils
50 {
51 
52 LibUtilities::ShapeType Tetrahedron::m_type =
54  LibUtilities::eTetrahedron, Tetrahedron::create, "Tetrahedron");
55 
56 /// Local vertices that make up each tetrahedral edge.
57 int Tetrahedron::m_edgeVertMap[6][2] = {
58  {0, 1}, {1, 2}, {0, 2}, {0, 3}, {1, 3}, {2, 3}
59 };
60 
61 /// Local vertices that make up each tetrahedral face.
62 int Tetrahedron::m_faceVertMap[4][3] = {
63  {0, 1, 2}, {0, 1, 3}, {1, 2, 3}, {0, 2, 3}
64 };
65 
66 /// Local edges that make up each tetrahedral face.
67 int Tetrahedron::m_faceEdgeMap[4][3] = {
68  {0, 1, 2}, {0, 4, 3}, {1, 5, 4}, {2, 5, 3}
69 };
70 
71 /**
72  * @brief Create a tetrahedron element.
73  */
74 Tetrahedron::Tetrahedron(ElmtConfig pConf,
75  vector<NodeSharedPtr> pNodeList,
76  vector<int> pTagList)
77  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
78 {
79  m_tag = "A";
80  m_dim = 3;
81  m_taglist = pTagList;
82  int n = m_conf.m_order - 1;
83 
84  m_vertex.resize(4);
85  // Add vertices
86  for (int i = 0; i < 4; ++i)
87  {
88  m_vertex[i] = pNodeList[i];
89  }
90 
91  // Reorient the tet to ensure collapsed coordinates align between
92  // adjacent elements.
93  if (m_conf.m_reorient)
94  {
95  OrientTet();
96  }
97  else
98  {
99  // If we didn't need to orient the tet then set up the
100  // orientation map as the identity mapping.
101  for (int i = 0; i < 4; ++i)
102  {
103  m_orientationMap[i] = i;
104  }
105  }
106 
107  // Create edges (with corresponding set of edge points). Apply orientation
108  // logic to get the right interior points for each edge.
109  m_edge.resize(6);
110  for (int i = 0; i < 6; ++i)
111  {
112  std::vector<NodeSharedPtr> edgeNodes(n);
113 
114  int origEdge = -1;
115  bool rev = false;
116  for (int j = 0; j < 6; ++j)
117  {
118  if (m_edgeVertMap[i][0] == m_origVertMap[m_edgeVertMap[j][0]] &&
119  m_edgeVertMap[i][1] == m_origVertMap[m_edgeVertMap[j][1]])
120  {
121  origEdge = j;
122  break;
123  }
124  else if (m_edgeVertMap[i][0] == m_origVertMap[m_edgeVertMap[j][1]] &&
125  m_edgeVertMap[i][1] == m_origVertMap[m_edgeVertMap[j][0]])
126  {
127  origEdge = j;
128  rev = true;
129  break;
130  }
131  }
132 
133  for (int j = 0; j < n; ++j)
134  {
135  edgeNodes[j] = pNodeList[4 + origEdge * n + j];
136  }
137  if (rev)
138  {
139  m_edge[i] = std::make_shared<Edge>(
140  m_vertex[m_edgeVertMap[i][1]],
141  m_vertex[m_edgeVertMap[i][0]],
142  edgeNodes,
144  }
145  else
146  {
147  m_edge[i] = std::make_shared<Edge>(
148  m_vertex[m_edgeVertMap[i][0]],
149  m_vertex[m_edgeVertMap[i][1]],
150  edgeNodes,
152  }
153  }
154 
155  m_face.resize(4);
156 
157  // Create faces
158  for (int j = 0; j < 4; ++j)
159  {
160  vector<NodeSharedPtr> faceVertices(3);
161  vector<EdgeSharedPtr> faceEdges(3);
162  vector<NodeSharedPtr> faceNodes;
163 
164  for (int k = 0; k < 3; ++k)
165  {
166  faceVertices[k] = m_vertex[m_faceVertMap[j][k]];
167  faceEdges[k] = m_edge[m_faceEdgeMap[j][k]];
168  }
169 
170  // When face curvature is supplied, it may have been the case
171  // that our tetrahedron was reoriented. In this case, faces have
172  // different vertex IDs and so we have to rotate the face
173  // curvature so that the two align appropriately.
174  if (m_conf.m_faceNodes)
175  {
176  const int nFaceNodes = n * (n - 1) / 2;
177 
178  // Get the vertex IDs of whatever face we are processing.
179  vector<int> faceVertIds(3);
180  faceVertIds[0] = faceVertices[0]->m_id;
181  faceVertIds[1] = faceVertices[1]->m_id;
182  faceVertIds[2] = faceVertices[2]->m_id;
183 
184  // Find out the original face number as we were given it in
185  // the constructor using the orientation map.
186  int origFace = -1;
187  for (int i = 0; i < 4; ++i)
188  {
189  if (m_orientationMap[i] == j)
190  {
191  origFace = i;
192  break;
193  }
194  }
195 
196  ASSERTL0(origFace >= 0, "Couldn't find face");
197 
198  // Now get the face nodes for the original face.
199  int N = 4 + 6 * n + origFace * nFaceNodes;
200  for (int i = 0; i < nFaceNodes; ++i)
201  {
202  faceNodes.push_back(pNodeList[N + i]);
203  }
204 
205  // Find the original face vertex IDs.
206  vector<int> origFaceIds(3);
207  origFaceIds[0] = pNodeList[m_faceVertMap[origFace][0]]->m_id;
208  origFaceIds[1] = pNodeList[m_faceVertMap[origFace][1]]->m_id;
209  origFaceIds[2] = pNodeList[m_faceVertMap[origFace][2]]->m_id;
210 
211  // Construct a HOTriangle object which performs the
212  // orientation magically for us.
213  HOTriangle<NodeSharedPtr> hoTri(origFaceIds, faceNodes);
214  hoTri.Align(faceVertIds);
215 
216  // Copy the face nodes back again.
217  faceNodes = hoTri.surfVerts;
218  }
219 
220  m_face[j] = std::make_shared<Face>(
221  faceVertices, faceNodes, faceEdges, m_conf.m_faceCurveType);
222  }
223 
224  if (m_conf.m_volumeNodes)
225  {
226  const int nFaceNodes = n * (n - 1) / 2;
227  for (int i = 4 + 6 * n + 4 * nFaceNodes; i < pNodeList.size(); ++i)
228  {
229  m_volumeNodes.push_back(pNodeList[i]);
230  }
231  }
232 }
233 
235 {
238 
239  for (int i = 0; i < 4; ++i)
240  {
241  tfaces[i] = std::dynamic_pointer_cast<SpatialDomains::TriGeom>(
242  m_face[i]->GetGeom(coordDim));
243  }
244 
246  m_id, tfaces);
247  ret->Setup();
248 
249  return ret;
250 }
251 
253  int edgeId, EdgeSharedPtr edge)
254 {
255  if (edge->m_n1 == m_vertex[m_edgeVertMap[edgeId][0]])
256  {
257  return StdRegions::eForwards;
258  }
259  else if (edge->m_n1 == m_vertex[m_edgeVertMap[edgeId][1]])
260  {
261  return StdRegions::eBackwards;
262  }
263  else
264  {
265  ASSERTL1(false, "Edge is not connected to this quadrilateral.");
266  }
267 
269 }
270 
271 void Tetrahedron::MakeOrder(int order,
274  int coordDim,
275  int &id,
276  bool justConfig)
277 {
278  m_conf.m_order = order;
279  m_curveType = pType;
280  m_volumeNodes.clear();
281 
282  if (order == 1 || order == 2)
283  {
285  return;
286  }
287  else if (order == 2)
288  {
289  m_conf.m_faceNodes = true;
290  m_conf.m_volumeNodes = false;
291  return;
292  }
293  else if (order == 3)
294  {
295  m_conf.m_volumeNodes = false;
296  return;
297  }
298 
299  m_conf.m_faceNodes = true;
300  m_conf.m_volumeNodes = true;
301 
302  if (justConfig)
303  {
304  return;
305  }
306 
307  int nPoints = order + 1;
308  StdRegions::StdExpansionSharedPtr xmap = geom->GetXmap();
309 
310  Array<OneD, NekDouble> px, py, pz;
311  LibUtilities::PointsKey pKey(nPoints, pType);
312  ASSERTL1(pKey.GetPointsDim() == 3, "Points distribution must be 3D");
313  LibUtilities::PointsManager()[pKey]->GetPoints(px, py, pz);
314 
315  Array<OneD, Array<OneD, NekDouble> > phys(coordDim);
316 
317  for (int i = 0; i < coordDim; ++i)
318  {
319  phys[i] = Array<OneD, NekDouble>(xmap->GetTotPoints());
320  xmap->BwdTrans(geom->GetCoeffs(i), phys[i]);
321  }
322 
323  const int nTetPts = nPoints * (nPoints + 1) * (nPoints + 2) / 6;
324  const int nTetIntPts = (nPoints - 4) * (nPoints - 3) * (nPoints - 2) / 6;
325  m_volumeNodes.resize(nTetIntPts);
326 
327  for (int i = nTetPts - nTetIntPts, cnt = 0; i < nTetPts; ++i, ++cnt)
328  {
330  xp[0] = px[i];
331  xp[1] = py[i];
332  xp[2] = pz[i];
333 
334  Array<OneD, NekDouble> x(3, 0.0);
335  for (int j = 0; j < coordDim; ++j)
336  {
337  x[j] = xmap->PhysEvaluate(xp, phys[j]);
338  }
339 
341  id++, x[0], x[1], x[2]);
342  }
343 }
344 
345 /**
346  * @brief Return the number of nodes defining a tetrahedron.
347  */
349 {
350  int n = pConf.m_order;
351  if (pConf.m_volumeNodes && pConf.m_faceNodes)
352  return (n + 1) * (n + 2) * (n + 3) / 6;
353  else if (!pConf.m_volumeNodes && pConf.m_faceNodes)
354  return 4 * (n + 1) * (n + 2) / 2 - 6 * (n + 1) + 4;
355  else
356  return 6 * (n + 1) - 8;
357 }
358 
359 void Tetrahedron::GetCurvedNodes(std::vector<NodeSharedPtr> &nodeList) const
360 {
361  int n = m_edge[0]->GetNodeCount();
362  nodeList.resize(n*(n+1)*(n+2)/6);
363 
364  nodeList[0] = m_vertex[0];
365  nodeList[1] = m_vertex[1];
366  nodeList[2] = m_vertex[2];
367  nodeList[3] = m_vertex[3];
368  int k = 4;
369 
370  for(int i = 0; i < 6; i++)
371  {
372  bool reverseEdge = false;
373  if(i < 3)
374  {
375  reverseEdge = m_edge[i]->m_n1 == m_vertex[i];
376  }
377  else
378  {
379  reverseEdge = m_edge[i]->m_n1 == m_vertex[i-3];
380  }
381 
382  if (reverseEdge)
383  {
384  for(int j = 0; j < n-2; j++)
385  {
386  nodeList[k++] = m_edge[i]->m_edgeNodes[j];
387  }
388  }
389  else
390  {
391  for(int j = n-3; j >= 0; j--)
392  {
393  nodeList[k++] = m_edge[i]->m_edgeNodes[j];
394  }
395  }
396  }
397 
398  vector<vector<int> > ts;
399  vector<int> t(3);
400  t[0] = m_vertex[0]->m_id;
401  t[1] = m_vertex[1]->m_id;
402  t[2] = m_vertex[2]->m_id;
403  ts.push_back(t);
404  t[0] = m_vertex[0]->m_id;
405  t[1] = m_vertex[1]->m_id;
406  t[2] = m_vertex[3]->m_id;
407  ts.push_back(t);
408  t[0] = m_vertex[1]->m_id;
409  t[1] = m_vertex[2]->m_id;
410  t[2] = m_vertex[3]->m_id;
411  ts.push_back(t);
412  t[0] = m_vertex[0]->m_id;
413  t[1] = m_vertex[2]->m_id;
414  t[2] = m_vertex[3]->m_id;
415  ts.push_back(t);
416 
417  for(int i = 0; i < 4; i++)
418  {
419  vector<int> fcid;
420  fcid.push_back(m_face[i]->m_vertexList[0]->m_id);
421  fcid.push_back(m_face[i]->m_vertexList[1]->m_id);
422  fcid.push_back(m_face[i]->m_vertexList[2]->m_id);
423 
424  HOTriangle<NodeSharedPtr> hot(fcid, m_face[i]->m_faceNodes);
425 
426  hot.Align(ts[i]);
427 
428  std::copy(hot.surfVerts.begin(),
429  hot.surfVerts.end(),
430  nodeList.begin() + k);
431  k+= hot.surfVerts.size();
432  }
433 
434  std::copy(m_volumeNodes.begin(),
435  m_volumeNodes.end(),
436  nodeList.begin() + k);
437 }
438 
439 /**
440  * @brief Helper function to sort 3 numbers using sorting network.
441  */
442 template<typename K>
443 void sort3(K& x, K& y, K& z)
444 {
445 #define SWAP(a,b) if (a > b) std::swap(a,b);
446  SWAP(y, z);
447  SWAP(x, z);
448  SWAP(x, y);
449 #undef SWAP
450 }
451 
452 /**
453  * @brief Orient tetrahedron to align degenerate vertices.
454  *
455  * Orientation of tetrahedral elements is required so that the
456  * singular vertices of triangular faces (which occur as a part of the
457  * collapsed co-ordinate system) align. The algorithm is based on that
458  * used in T. Warburton's thesis and in the original Nektar source.
459  *
460  * First the vertices are ordered with the highest global vertex at
461  * the top degenerate point, and the base degenerate point has second
462  * lowest ID. These vertices are swapped if the element is incorrectly
463  * oriented.
464  */
466 {
467  // Create a copy of the original vertex ordering. This is used to
468  // construct a mapping, #orientationMap, which maps the original
469  // face ordering to the new face ordering.
470  int orig_faces[4][3];
471  for (int i = 0; i < 4; ++i)
472  {
473  int v0id = m_vertex[m_faceVertMap[i][0]]->m_id;
474  int v1id = m_vertex[m_faceVertMap[i][1]]->m_id;
475  int v2id = m_vertex[m_faceVertMap[i][2]]->m_id;
476  sort3(v0id, v1id, v2id);
477  orig_faces[i][0] = v0id;
478  orig_faces[i][1] = v1id;
479  orig_faces[i][2] = v2id;
480  }
481 
482  // Store a copy of the original vertex ordering so we can create a
483  // permutation map later.
484  vector<NodeSharedPtr> origVert = m_vertex;
485 
486  // Order vertices with highest global vertex at top degenerate
487  // point. Place second highest global vertex at base degenerate
488  // point.
489  sort(m_vertex.begin(), m_vertex.end());
490 
491  // Calculate a.(b x c) if negative, reverse order of
492  // non-degenerate points to correctly orientate the tet.
493 
494  NekDouble ax = m_vertex[1]->m_x - m_vertex[0]->m_x;
495  NekDouble ay = m_vertex[1]->m_y - m_vertex[0]->m_y;
496  NekDouble az = m_vertex[1]->m_z - m_vertex[0]->m_z;
497  NekDouble bx = m_vertex[2]->m_x - m_vertex[0]->m_x;
498  NekDouble by = m_vertex[2]->m_y - m_vertex[0]->m_y;
499  NekDouble bz = m_vertex[2]->m_z - m_vertex[0]->m_z;
500  NekDouble cx = m_vertex[3]->m_x - m_vertex[0]->m_x;
501  NekDouble cy = m_vertex[3]->m_y - m_vertex[0]->m_y;
502  NekDouble cz = m_vertex[3]->m_z - m_vertex[0]->m_z;
503 
504  NekDouble nx = (ay * bz - az * by);
505  NekDouble ny = (az * bx - ax * bz);
506  NekDouble nz = (ax * by - ay * bx);
507  NekDouble nmag = sqrt(nx * nx + ny * ny + nz * nz);
508  nx /= nmag;
509  ny /= nmag;
510  nz /= nmag;
511 
512  NekDouble area = 0.5 * nmag;
513 
514  // distance of top vertex from base
515  NekDouble dist = cx * nx + cy * ny + cz * nz;
516 
517  if (fabs(dist) / area <= 1e-4 )
518  {
519  cerr << "Warning: degenerate tetrahedron, 3rd vertex is = " << dist
520  << " from face" << endl;
521  }
522 
523  if (dist < 0)
524  {
525  swap(m_vertex[0], m_vertex[1]);
526  }
527 
528  nx = (ay * cz - az * cy);
529  ny = (az * cx - ax * cz);
530  nz = (ax * cy - ay * cx);
531  nmag = sqrt(nx * nx + ny * ny + nz * nz);
532  nx /= nmag;
533  ny /= nmag;
534  nz /= nmag;
535 
536  area = 0.5 * nmag;
537 
538  // distance of top vertex from base
539  dist = bx * nx + by * ny + bz * nz;
540 
541  if (fabs(dist) / area <= 1e-4)
542  {
543  cerr << "Warning: degenerate tetrahedron, 2nd vertex is = " << dist
544  << " from face" << endl;
545  }
546 
547  nx = (by * cz - bz * cy);
548  ny = (bz * cx - bx * cz);
549  nz = (bx * cy - by * cx);
550  nmag = sqrt(nx * nx + ny * ny + nz * nz);
551  nx /= nmag;
552  ny /= nmag;
553  nz /= nmag;
554 
555  area = 0.5 * nmag;
556 
557  // distance of top vertex from base
558  dist = ax * nx + ay * ny + az * nz;
559 
560  if (fabs(dist) / area <= 1e-4)
561  {
562  cerr << "Warning: degenerate tetrahedron, 1st vertex is = " << dist
563  << " from face" << endl;
564  }
565 
566  // Search for the face in the original set of face nodes. Then use
567  // this to construct the #orientationMap.
568  for (int i = 0; i < 4; ++i)
569  {
570  int v0id = m_vertex[m_faceVertMap[i][0]]->m_id;
571  int v1id = m_vertex[m_faceVertMap[i][1]]->m_id;
572  int v2id = m_vertex[m_faceVertMap[i][2]]->m_id;
573  sort3(v0id, v1id, v2id);
574 
575  for (int j = 0; j < 4; ++j)
576  {
577  if (v0id == orig_faces[j][0] && v1id == orig_faces[j][1] &&
578  v2id == orig_faces[j][2])
579  {
580  m_orientationMap[j] = i;
581  break;
582  }
583  }
584 
585  for (int j = 0; j < 4; ++j)
586  {
587  if (m_vertex[i]->m_id == origVert[j]->m_id)
588  {
589  m_origVertMap[j] = i;
590  break;
591  }
592  }
593  }
594 }
595 }
596 }
bool m_faceNodes
Denotes whether the element contains face nodes. For 2D elements, if this is true then the element co...
Definition: ElementConfig.h:81
static int m_faceEdgeMap[4][3]
Local edges that make up each tetrahedral face.
Definition: Tetrahedron.h:99
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Basic information about an element.
Definition: ElementConfig.h:49
LibUtilities::PointsType m_faceCurveType
Distribution of points in faces.
Definition: ElementConfig.h:95
static int m_faceVertMap[4][3]
Local vertices that make up each tetrahedral face.
Definition: Tetrahedron.h:98
virtual NEKMESHUTILS_EXPORT StdRegions::Orientation GetEdgeOrient(int edgeId, EdgeSharedPtr edge)
Get the edge orientation of edge with respect to the local element, which lies at edge index edgeId...
void Align(std::vector< int > vertId)
Align this surface to a given vertex ID.
Definition: HOAlignment.h:134
std::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:88
virtual NEKMESHUTILS_EXPORT SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
STL namespace.
std::vector< T > surfVerts
The triangle surface vertices – templated so that this can either be nodes or IDs.
Definition: HOAlignment.h:64
unsigned int GetPointsDim() const
Definition: Points.h:150
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
static int m_edgeVertMap[6][2]
Local vertices that make up each tetrahedral edge.
Definition: Tetrahedron.h:97
def copy(self)
Definition: pycml.py:2663
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
ElmtConfig m_conf
Contains configuration of the element.
Definition: Element.h:462
std::vector< int > m_taglist
List of integers specifying properties of the element.
Definition: Element.h:466
LibUtilities::PointsType m_edgeCurveType
Distribution of points in edges.
Definition: ElementConfig.h:93
unsigned int m_order
Order of the element.
Definition: ElementConfig.h:88
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
std::vector< NodeSharedPtr > m_vertex
List of element vertex nodes.
Definition: Element.h:468
std::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
unsigned int m_dim
Dimension of the element.
Definition: Element.h:460
bool m_volumeNodes
Denotes whether the element contains volume (i.e. interior) nodes. These are not supported by either ...
Definition: ElementConfig.h:86
std::vector< EdgeSharedPtr > m_edge
List of element edges.
Definition: Element.h:470
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
virtual NEKMESHUTILS_EXPORT void GetCurvedNodes(std::vector< NodeSharedPtr > &nodeList) const
get list of volume interior nodes
PointsManagerT & PointsManager(void)
Defines a specification for a set of points.
Definition: Points.h:59
double NekDouble
std::vector< NodeSharedPtr > m_volumeNodes
List of element volume nodes.
Definition: Element.h:474
void OrientTet()
Orient tetrahedron to align degenerate vertices.
A lightweight struct for dealing with high-order triangle alignment.
Definition: HOAlignment.h:49
std::string m_tag
Tag character describing the element.
Definition: Element.h:464
static NEKMESHUTILS_EXPORT unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a tetrahedron.
unsigned int m_id
ID of the element.
Definition: Element.h:458
virtual NEKMESHUTILS_EXPORT void MakeOrder(int order, SpatialDomains::GeometrySharedPtr geom, LibUtilities::PointsType pType, int coordDim, int &id, bool justConfig=false)
Insert interior (i.e. volume) points into this element to make the geometry an order order representa...
LibUtilities::PointsType m_curveType
Volume curve type.
Definition: Element.h:476
std::vector< FaceSharedPtr > m_face
List of element faces.
Definition: Element.h:472
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
bool m_reorient
Denotes whether the element needs to be re-orientated for a spectral element framework.
Definition: ElementConfig.h:91
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
#define SWAP(a, b)
void sort3(K &x, K &y, K &z)
Helper function to sort 3 numbers using sorting network.
Base class for element definitions.
Definition: Element.h:60