Nektar++
MeshElements.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: MeshElements.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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Mesh manipulation objects.
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 #include <iostream>
37 #include <vector>
38 #include <loki/Singleton.h>
39 
43 #include <LocalRegions/TriExp.h>
44 #include <LocalRegions/QuadExp.h>
45 #include <LocalRegions/TetExp.h>
46 #include <LocalRegions/PrismExp.h>
47 #include <SpatialDomains/SegGeom.h>
48 #include <SpatialDomains/TetGeom.h>
49 #include <SpatialDomains/PyrGeom.h>
51 #include <SpatialDomains/HexGeom.h>
52 
53 #include "MeshElements.h"
54 using namespace std;
55 
56 namespace Nektar
57 {
58  namespace Utilities
59  {
61  {
62  typedef Loki::SingletonHolder<ElementFactory,
63  Loki::CreateUsingNew,
64  Loki::NoDestroy > Type;
65  return Type::Instance();
66  }
67 
68  Element::Element(ElmtConfig pConf,
69  unsigned int pNumNodes,
70  unsigned int pGotNodes)
71  : m_conf(pConf),
72  m_curveType(LibUtilities::ePolyEvenlySpaced),
73  m_geom()
74  {
75  if (pNumNodes != pGotNodes)
76  {
77  cerr << "Number of modes mismatch for type "
78  << pConf.m_e << "! Should be " << pNumNodes
79  << " but got " << pGotNodes << " nodes." << endl;
80  abort();
81  }
82  }
83 
84  /**
85  * @brief Return the number of elements of the expansion dimension.
86  */
87  unsigned int Mesh::GetNumElements()
88  {
89  return m_element[m_expDim].size();
90  }
91 
92  /**
93  * @brief Return the number of boundary elements (i.e. one below the
94  * expansion dimension).
95  */
97  {
98  unsigned int i, nElmt = 0;
99 
100  for (i = 0; i < m_expDim; ++i)
101  nElmt += m_element[i].size();
102 
103  return nElmt;
104  }
105 
106  /**
107  * @brief Return the total number of entities in the mesh (i.e. all
108  * elements, regardless of dimension).
109  */
110  unsigned int Mesh::GetNumEntities()
111  {
112  unsigned int nEnt = 0;
113 
114  for (unsigned int d = 0; d <= m_expDim; ++d)
115  {
116  nEnt += m_element[d].size();
117  }
118 
119  return nEnt;
120  }
121 
122  /**
123  * @brief Test equality of two conditions - i.e. compare types, fields
124  * and values but _not_ composite ids.
125  */
127  {
128  int i, n = c1->type.size();
129 
130  if (n != c2->type.size())
131  {
132  return false;
133  }
134 
135  for (i = 0; i < n; ++i)
136  {
137  if (c1->type[i] != c2->type[i])
138  {
139  return false;
140  }
141 
142  if (c1->field[i] != c2->field[i] || c1->value[i] != c2->value[i])
143  {
144  return false;
145  }
146  }
147 
148  return true;
149  }
150 
151  /**
152  * @brief Defines equality between two #NodeSharedPtr objects.
153  */
154  bool operator==(NodeSharedPtr const &p1, NodeSharedPtr const &p2)
155  {
156  return *p1 == *p2;
157  }
158 
159  /**
160  * @brief Defines ordering between two #NodeSharedPtr objects.
161  */
162  bool operator< (NodeSharedPtr const &p1, NodeSharedPtr const &p2)
163  {
164  return *p1 < *p2;
165  }
166 
167  std::ostream &operator<<(std::ostream &os, const NodeSharedPtr &n)
168  {
169  os << n->m_x << " " << n->m_y << " " << n->m_z;
170  return os;
171  }
172 
173  /**
174  * @brief Defines equality of two edges (equal if IDs of end nodes
175  * match in either ordering).
176  */
177  bool operator==(EdgeSharedPtr const &p1, EdgeSharedPtr const &p2)
178  {
179  return ( ((*(p1->m_n1) == *(p2->m_n1)) && (*(p1->m_n2) == *(p2->m_n2)))
180  || ((*(p1->m_n2) == *(p2->m_n1)) && (*(p1->m_n1) == *(p2->m_n2))));
181  }
182 
183  /**
184  * @brief Defines ordering between two edges (based on ID of edges).
185  */
186  bool operator< (EdgeSharedPtr const &p1, EdgeSharedPtr const &p2)
187  {
188  return p1->m_id < p2->m_id;
189  }
190 
191  /**
192  * @brief Defines equality of two faces (equal if IDs of vertices are
193  * the same.)
194  */
195  bool operator==(FaceSharedPtr const &p1, FaceSharedPtr const &p2)
196  {
198  for (it1 = p1->m_vertexList.begin(); it1 != p1->m_vertexList.end(); ++it1)
199  {
200  if (find(p2->m_vertexList.begin(), p2->m_vertexList.end(), *it1)
201  == p2->m_vertexList.end())
202  {
203  return false;
204  }
205  }
206  return true;
207  }
208 
209  /**
210  * @brief Defines ordering between two faces (depending on ID of
211  * faces).
212  */
213  bool operator< (FaceSharedPtr const &p1, FaceSharedPtr const &p2)
214  {
215  return p1->m_id < p2->m_id;
216  }
217 
218  /**
219  * @brief Replace a vertex in the element.
220  *
221  * When a vertex is replaced, the element edges and faces are also
222  * searched and the corresponding edge/face nodes are updated to
223  * maintain consistency.
224  *
225  * @param p Index of the vertex to replace.
226  * @param pNew New vertex.
227  */
228  void Element::SetVertex(unsigned int p, NodeSharedPtr pNew)
229  {
230  NodeSharedPtr vOld = m_vertex[p];
231  m_vertex[p] = pNew;
232  for (unsigned int i = 0; i < m_edge.size(); ++i)
233  {
234  if (m_edge[i]->m_n1 == vOld)
235  {
236  m_edge[i]->m_n1 = pNew;
237  }
238  else if (m_edge[i]->m_n2 == vOld)
239  {
240  m_edge[i]->m_n2 = pNew;
241  }
242  }
243  for (unsigned int i = 0; i < m_face.size(); ++i)
244  {
245  // Replace vertices in faces
246  for (unsigned int j = 0; j < m_face[i]->m_vertexList.size(); ++j)
247  {
248  if (m_face[i]->m_vertexList[j] == vOld)
249  {
250  m_face[i]->m_vertexList[j] = pNew;
251  }
252  }
253  for (unsigned int j = 0; j < m_face[i]->m_edgeList.size(); ++j)
254  {
255  if (m_face[i]->m_edgeList[j]->m_n1 == vOld)
256  {
257  m_face[i]->m_edgeList[j]->m_n1 = pNew;
258  }
259  else if (m_face[i]->m_edgeList[j]->m_n2 == vOld)
260  {
261  m_face[i]->m_edgeList[j]->m_n2 = pNew;
262  }
263  }
264  }
265  }
266 
267  /**
268  * @brief Replace an edge in the element.
269  *
270  * When an edge is replaced, the element faces are also searched and
271  * the corresponding face edges are updated to maintain consistency.
272  *
273  * @param p Index of the edge to replace.
274  * @param pNew New edge.
275  */
276  void Element::SetEdge(unsigned int p, EdgeSharedPtr pNew)
277  {
278  EdgeSharedPtr vOld = m_edge[p];
279  m_edge[p] = pNew;
280  for (unsigned int i = 0; i < m_face.size(); ++i)
281  {
282  for (unsigned int j = 0; j < m_face[i]->m_edgeList.size(); ++j)
283  {
284  if (m_face[i]->m_edgeList[j] == vOld)
285  {
286  m_face[i]->m_edgeList[j] = pNew;
287  }
288  }
289  }
290  }
291 
292  /**
293  * @brief Replace a face in the element.
294  *
295  * When a face is replaced, no other consistency checks are required.
296  *
297  * @param p Index of the face to replace.
298  * @param pNew New face.
299  */
300  void Element::SetFace(unsigned int p, FaceSharedPtr pNew)
301  {
302  m_face[p] = pNew;
303  }
304 
305  /**
306  * @brief Obtain the order of an element by looking at edges.
307  */
309  {
310  int i, ret = 1;
311 
312  for (i = 0; i < m_edge.size(); ++i)
313  {
314  int edgeOrder = m_edge[i]->GetNodeCount()-1;
315  if (edgeOrder > ret)
316  {
317  ret = edgeOrder;
318  }
319  }
320 
321  return ret;
322  }
323 
324  /**
325  * @brief Generate a Nektar++ string describing the composite.
326  *
327  * The list of composites may include individual element IDs or ranges
328  * of element IDs.
329  */
330  string Composite::GetXmlString(bool doSort)
331  {
332 
333 #if 0 // turn this option off since causes problem with InputNekpp.cpp
334  if (doSort)
335  {
336  element_id_less_than sortOperator;
337  sort(m_items.begin(), m_items.end(), sortOperator);
338  }
339 #endif
340 
341  stringstream st;
343  bool range = false;
344  int vId = m_items[0]->GetId();
345  int prevId = vId;
346 
347  st << " " << m_tag << "[" << vId;
348 
349  for (it = m_items.begin()+1; it != m_items.end(); ++it){
350  // store previous element ID and get current one
351  prevId = vId;
352  vId = (*it)->GetId();
353 
354  // continue an already started range
355  if (prevId > -1 && vId == prevId + 1)
356  {
357  range = true;
358  // if this is the last element, it's the end of a range, so write
359  if (*it == m_items.back())
360  {
361  st << "-" << vId;
362  }
363  continue;
364  }
365 
366  // terminate a range, if present
367  if (range)
368  {
369  st << "-" << prevId;
370  range = false;
371  }
372 
373  // write what will be either a single entry or start of new range
374  st << "," << vId;
375  }
376  // terminate
377  st << "] ";
378  return st.str();
379  }
380 
382  RegisterCreatorFunction(LibUtilities::ePoint, Point::create, "Point");
383 
384  /**
385  * @brief Create a point element.
386  */
388  vector<NodeSharedPtr> pNodeList,
389  vector<int> pTagList)
390  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
391  {
392  m_tag = "";
393  m_dim = 0;
394  m_taglist = pTagList;
395  m_vertex.push_back(pNodeList[0]);
396  }
397 
398  /**
399  * @brief Return the number of nodes defining a point (i.e. return 1).
400  */
401  unsigned int Point::GetNumNodes(ElmtConfig pConf)
402  {
403  return 1;
404  }
405 
406 
408  RegisterCreatorFunction(LibUtilities::eSegment, Line::create, "Line");
409 
410  /**
411  * @brief Create a line element.
412  */
414  vector<NodeSharedPtr> pNodeList,
415  vector<int> pTagList)
416  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
417  {
418  m_tag = "S";
419  m_dim = 1;
420  m_taglist = pTagList;
421  int n = m_conf.m_order-1;
422 
423  // Add vertices
424  for (int i = 0; i < 2; ++i) {
425  m_vertex.push_back(pNodeList[i]);
426  }
427  vector<NodeSharedPtr> edgeNodes;
428  if (m_conf.m_order > 1) {
429  for (int j = 0; j<n; ++j) {
430  edgeNodes.push_back(pNodeList[2+j]);
431  }
432  }
433  m_edge.push_back(boost::shared_ptr<Edge>(
434  new Edge(pNodeList[0], pNodeList[1], edgeNodes, m_conf.m_edgeCurveType)));
435  }
436 
438  {
439  // Create edge vertices.
442 
443  p[0] = m_vertex[0]->GetGeom(coordDim);
444  p[1] = m_vertex[1]->GetGeom(coordDim);
445 
446  if (m_edge[0]->m_edgeNodes.size() > 0)
447  {
451 
452  c->m_points.push_back(p[0]);
453  for (int i = 0; i < m_edge[0]->m_edgeNodes.size(); ++i)
454  {
455  c->m_points.push_back(m_edge[0]->m_edgeNodes[i]->GetGeom(coordDim));
456  }
457  c->m_points.push_back(p[1]);
458 
460  AllocateSharedPtr(m_id, 2, p, c);
461  }
462  else
463  {
465  AllocateSharedPtr(m_id, 2, p);
466  }
467 
468  return ret;
469  }
470 
471  /**
472  * @brief Return the number of nodes defining a line.
473  */
474  unsigned int Line::GetNumNodes(ElmtConfig pConf)
475  {
476  return pConf.m_order+1;
477  }
478 
479 
481  RegisterCreatorFunction(LibUtilities::eTriangle, Triangle::create, "Triangle");
482 
483  /**
484  * @brief Create a triangle element.
485  */
487  vector<NodeSharedPtr> pNodeList,
488  vector<int> pTagList)
489  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
490  {
491  m_tag = "T";
492  m_dim = 2;
493  m_taglist = pTagList;
495  int n = m_conf.m_order-1;
496 
497  // Create a map to relate edge nodes to a pair of vertices
498  // defining an edge. This is based on the ordering produced by
499  // gmsh.
500  map<pair<int,int>, int> edgeNodeMap;
501  map<pair<int,int>, int>::iterator it;
502  edgeNodeMap[pair<int,int>(1,2)] = 4;
503  edgeNodeMap[pair<int,int>(2,3)] = 4 + n;
504  edgeNodeMap[pair<int,int>(3,1)] = 4 + 2*n;
505 
506  // Add vertices. This logic will determine (in 2D) whether the
507  // element is clockwise (sum > 0) or counter-clockwise (sum < 0).
508  NekDouble sum = 0.0;
509  for (int i = 0; i < 3; ++i) {
510  int o = (i+1) % 3;
511  m_vertex.push_back(pNodeList[i]);
512  sum += (pNodeList[o]->m_x - pNodeList[i]->m_x) *
513  (pNodeList[o]->m_y + pNodeList[i]->m_y);
514  }
515 
516  // Create edges (with corresponding set of edge points)
517  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
518  {
519  vector<NodeSharedPtr> edgeNodes;
520  if (m_conf.m_order > 1) {
521  for (int j = it->second; j < it->second + n; ++j) {
522  edgeNodes.push_back(pNodeList[j-1]);
523  }
524  }
525  m_edge.push_back(EdgeSharedPtr(new Edge(pNodeList[it->first.first-1],
526  pNodeList[it->first.second-1],
527  edgeNodes,
529  }
530 
531  if (pConf.m_reorient)
532  {
533  if (sum > 0.0)
534  {
535  reverse(m_edge.begin(), m_edge.end());
536  }
537  }
538 
539  if (m_conf.m_faceNodes)
540  {
541  m_volumeNodes.insert(m_volumeNodes.begin(),
542  pNodeList.begin()+3*m_conf.m_order,
543  pNodeList.end());
544  }
545  }
546 
548  {
552 
553  for (int i = 0; i < 3; ++i)
554  {
555  edges[i] = m_edge [i]->GetGeom(coordDim);
556  verts[i] = m_vertex[i]->GetGeom(coordDim);
557  }
558 
559  StdRegions::Orientation edgeorient[3] = {
560  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[0], *edges[1]),
561  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[1], *edges[2]),
562  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[2], *edges[0])
563  };
564 
566  AllocateSharedPtr(m_id, verts, edges, edgeorient);
567 
568  return ret;
569  }
570 
571  /**
572  * @brief Return the number of nodes defining a triangle.
573  */
574  unsigned int Triangle::GetNumNodes(ElmtConfig pConf)
575  {
576  int n = pConf.m_order;
577  if (!pConf.m_faceNodes)
578  return (n+1)+2*(n-1)+1;
579  else
580  return (n+1)*(n+2)/2;
581  }
582 
583  void Triangle::Complete(int order)
584  {
585  int i, j;
586 
587  // Create basis key for a nodal tetrahedron.
589  LibUtilities::eOrtho_A, order+1,
593  LibUtilities::eOrtho_B, order+1,
596 
597  // Create a standard nodal triangle in order to get the
598  // Vandermonde matrix to perform interpolation to nodal points.
602 
604  boost::dynamic_pointer_cast<SpatialDomains::TriGeom>(
605  this->GetGeom(3));
606 
607  // Create basis key for a triangle.
609  LibUtilities::eOrtho_A, order+1,
613  LibUtilities::eOrtho_B, order+1,
616 
617  // Create a triangle.
620  C0, C1, geom);
621 
622  // Get coordinate array for tetrahedron.
623  int nqtot = tri->GetTotPoints();
624  Array<OneD, NekDouble> alloc(6*nqtot);
625  Array<OneD, NekDouble> xi(alloc);
626  Array<OneD, NekDouble> yi(alloc+ nqtot);
627  Array<OneD, NekDouble> zi(alloc+2*nqtot);
628  Array<OneD, NekDouble> xo(alloc+3*nqtot);
629  Array<OneD, NekDouble> yo(alloc+4*nqtot);
630  Array<OneD, NekDouble> zo(alloc+5*nqtot);
632 
633  tri->GetCoords(xi, yi, zi);
634 
635  for (i = 0; i < 3; ++i)
636  {
637  Array<OneD, NekDouble> coeffs(nodalTri->GetNcoeffs());
638  tri->FwdTrans(alloc+i*nqtot, coeffs);
639  // Apply Vandermonde matrix to project onto nodal space.
640  nodalTri->ModalToNodal(coeffs, tmp=alloc+(i+3)*nqtot);
641  }
642 
643  // Now extract points from the co-ordinate arrays into the
644  // edge/face/volume nodes. First, extract edge-interior nodes.
645  for (i = 0; i < 3; ++i)
646  {
647  int pos = 3 + i*(order-1);
648  m_edge[i]->m_edgeNodes.clear();
649  for (j = 0; j < order-1; ++j)
650  {
651  m_edge[i]->m_edgeNodes.push_back(
652  NodeSharedPtr(new Node(0, xo[pos+j], yo[pos+j], zo[pos+j])));
653  }
654  }
655 
656  // Extract face-interior nodes.
657  int pos = 3 + 3*(order-1);
658  for (i = pos; i < (order+1)*(order+2)/2; ++i)
659  {
660  m_volumeNodes.push_back(
661  NodeSharedPtr(new Node(0, xo[i], yo[i], zo[i])));
662  }
663 
664  m_conf.m_order = order;
665  m_conf.m_faceNodes = true;
666  m_conf.m_volumeNodes = true;
667  }
668 
669 
671  RegisterCreatorFunction(LibUtilities::eQuadrilateral, Quadrilateral::create,
672  "Quadrilateral");
673 
674  /**
675  * @brief Create a quadrilateral element.
676  */
678  vector<NodeSharedPtr> pNodeList,
679  vector<int> pTagList)
680  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
681  {
682  m_tag = "Q";
683  m_dim = 2;
684  m_taglist = pTagList;
685  int n = m_conf.m_order-1;
686 
687  // Create a map to relate edge nodes to a pair of vertices
688  // defining an edge. This is based on the ordering produced by
689  // gmsh.
690  map<pair<int,int>, int> edgeNodeMap;
691  map<pair<int,int>, int>::iterator it;
692  edgeNodeMap[pair<int,int>(1,2)] = 5;
693  edgeNodeMap[pair<int,int>(2,3)] = 5 + n;
694  edgeNodeMap[pair<int,int>(3,4)] = 5 + 2*n;
695  edgeNodeMap[pair<int,int>(4,1)] = 5 + 3*n;
696 
697  // Add vertices. This logic will determine (in 2D) whether the
698  // element is clockwise (sum > 0) or counter-clockwise (sum < 0).
699  NekDouble sum = 0.0;
700  for (int i = 0; i < 4; ++i) {
701  int o = (i+1) % 4;
702  m_vertex.push_back(pNodeList[i]);
703  sum += (pNodeList[o]->m_x - pNodeList[i]->m_x) *
704  (pNodeList[o]->m_y + pNodeList[i]->m_y);
705  }
706 
707  // Create edges (with corresponding set of edge points)
708  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
709  {
710  vector<NodeSharedPtr> edgeNodes;
711  if (m_conf.m_order > 1) {
712  for (int j = it->second; j < it->second + n; ++j) {
713  edgeNodes.push_back(pNodeList[j-1]);
714  }
715  }
716  m_edge.push_back(EdgeSharedPtr(new Edge(pNodeList[it->first.first-1],
717  pNodeList[it->first.second-1],
718  edgeNodes,
720  }
721 
722  if (pConf.m_reorient)
723  {
724  if (sum > 0.0)
725  {
726  reverse(m_edge.begin(), m_edge.end());
727  }
728  }
729 
730  if (m_conf.m_faceNodes)
731  {
732  m_volumeNodes.insert(m_volumeNodes.begin(),
733  pNodeList.begin()+4*m_conf.m_order,
734  pNodeList.end());
735  }
736  }
737 
738  void Quadrilateral::Complete(int order)
739  {
741  LibUtilities::eOrtho_A, order+1,
744 
746  boost::dynamic_pointer_cast<SpatialDomains::QuadGeom>(
747  this->GetGeom(3));
748 
749  // Create a quad.
752  C0, C0, geom);
753 
754  // Get coordinate array for quadrilateral.
755  int nqtot = quad->GetTotPoints();
756  Array<OneD, NekDouble> alloc(3*nqtot);
757  Array<OneD, NekDouble> x (alloc );
758  Array<OneD, NekDouble> y (alloc+1*nqtot);
759  Array<OneD, NekDouble> z (alloc+2*nqtot);
760 
761  quad->GetCoords(x, y, z);
762 
763  // Now extract points from the co-ordinate arrays into the edge
764  // and face nodes. First, extract edge-interior nodes.
765  int edgeMap[4][2] = {{0,1},{order,order+1},
766  {nqtot-1,-1},{order*(order+1),-order-1}};
767 
768  for (int i = 0; i < 4; ++i)
769  {
770  int pos = edgeMap[i][0] + edgeMap[i][1];
771  m_edge[i]->m_edgeNodes.clear();
772  for (int j = 1; j < order; ++j, pos += edgeMap[i][1])
773  {
774  m_edge[i]->m_edgeNodes.push_back(
775  NodeSharedPtr(new Node(0, x[pos], y[pos], z[pos])));
776  }
777  }
778 
779  // Extract face-interior nodes.
780  m_volumeNodes.clear();
781  for (int i = 1; i < order; ++i)
782  {
783  int pos = i*(order+1);
784  for (int j = 1; j < order; ++j)
785  {
786  m_volumeNodes.push_back(
787  NodeSharedPtr(new Node(0, x[pos+j], y[pos+j], z[pos+j])));
788  }
789  }
790 
791  m_conf.m_order = order;
792  m_conf.m_faceNodes = true;
793  m_conf.m_volumeNodes = true;
794  }
795 
797  {
801 
802  for (int i = 0; i < 4; ++i)
803  {
804  edges[i] = m_edge [i]->GetGeom(coordDim);
805  verts[i] = m_vertex[i]->GetGeom(coordDim);
806  }
807 
808  StdRegions::Orientation edgeorient[4] = {
809  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[0], *edges[1]),
810  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[1], *edges[2]),
811  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[2], *edges[3]),
812  SpatialDomains::SegGeom::GetEdgeOrientation(*edges[3], *edges[0])
813  };
814 
816  AllocateSharedPtr(m_id, verts, edges, edgeorient);
817 
818  return ret;
819  }
820 
821  /**
822  * @brief Return the number of nodes defining a quadrilateral.
823  */
825  {
826  int n = pConf.m_order;
827  if (!pConf.m_faceNodes)
828  return 4*n;
829  else
830  return (n+1)*(n+1);
831  }
832 
833 
835  RegisterCreatorFunction(LibUtilities::eTetrahedron, Tetrahedron::create, "Tetrahedron");
836 
837  /**
838  * @brief Create a tetrahedron element.
839  */
841  vector<NodeSharedPtr> pNodeList,
842  vector<int> pTagList)
843  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
844  {
845  m_tag = "A";
846  m_dim = 3;
847  m_taglist = pTagList;
848  int n = m_conf.m_order-1;
849 
850  // Create a map to relate edge nodes to a pair of vertices
851  // defining an edge.
852  map<pair<int,int>, int> edgeNodeMap;
853  map<pair<int,int>, int>::iterator it;
854  edgeNodeMap[pair<int,int>(1,2)] = 5;
855  edgeNodeMap[pair<int,int>(2,3)] = 5 + n;
856  edgeNodeMap[pair<int,int>(1,3)] = 5 + 2*n;
857  edgeNodeMap[pair<int,int>(1,4)] = 5 + 3*n;
858  edgeNodeMap[pair<int,int>(2,4)] = 5 + 4*n;
859  edgeNodeMap[pair<int,int>(3,4)] = 5 + 5*n;
860 
861  // Add vertices
862  for (int i = 0; i < 4; ++i)
863  {
864  m_vertex.push_back(pNodeList[i]);
865  }
866 
867  // Create edges (with corresponding set of edge points)
868  int eid = 0;
869  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
870  {
871  vector<NodeSharedPtr> edgeNodes;
872  if (m_conf.m_order > 1) {
873  for (int j = it->second; j < it->second + n; ++j) {
874  edgeNodes.push_back(pNodeList[j-1]);
875  }
876  }
877  m_edge.push_back(
878  EdgeSharedPtr(new Edge(pNodeList[it->first.first-1],
879  pNodeList[it->first.second-1],
880  edgeNodes,
882  m_edge.back()->m_id = eid++;
883  }
884 
885  // Reorient the tet to ensure collapsed coordinates align between
886  // adjacent elements.
887  if (m_conf.m_reorient)
888  {
889  OrientTet();
890  }
891  else
892  {
893  // If we didn't need to orient the tet then set up the
894  // orientation map as the identity mapping.
895  for (int i = 0; i < 4; ++i)
896  {
897  m_orientationMap[i] = i;
898  }
899  }
900 
901  // Face-vertex IDs
902  int face_ids[4][3] = {
903  {0,1,2}, {0,1,3}, {1,2,3}, {0,2,3}
904  };
905 
906  // Face-edge IDs
907  int face_edges[4][3];
908 
909  // Create faces
910  for (int j = 0; j < 4; ++j)
911  {
912  vector<NodeSharedPtr> faceVertices;
913  vector<EdgeSharedPtr> faceEdges;
914  vector<NodeSharedPtr> faceNodes;
915 
916  // Extract the edges for this face. We need to do this because
917  // of the reorientation which might have been applied (see the
918  // additional note below).
919  for (int k = 0; k < 3; ++k)
920  {
921  faceVertices.push_back(m_vertex[face_ids[j][k]]);
922  NodeSharedPtr a = m_vertex[face_ids[j][k]];
923  NodeSharedPtr b = m_vertex[face_ids[j][(k+1)%3]];
924  for (unsigned int i = 0; i < m_edge.size(); ++i)
925  {
926  if ( ((*(m_edge[i]->m_n1)==*a) && (*(m_edge[i]->m_n2)==*b))
927  || ((*(m_edge[i]->m_n1)==*b) && (*(m_edge[i]->m_n2) == *a)) )
928  {
929  face_edges[j][k] = i;
930  faceEdges.push_back(m_edge[i]);
931  break;
932  }
933  }
934  }
935 
936  // When face curvature is supplied, it may have been the case
937  // that our tetrahedron was reoriented. In this case, faces have
938  // different vertex IDs and so we have to rotate the face
939  // curvature so that the two align appropriately.
940  if (m_conf.m_faceNodes)
941  {
942  const int nFaceNodes = n*(n-1)/2;
943 
944  // Get the vertex IDs of whatever face we are processing.
945  vector<int> faceIds(3);
946  faceIds[0] = faceVertices[0]->m_id;
947  faceIds[1] = faceVertices[1]->m_id;
948  faceIds[2] = faceVertices[2]->m_id;
949 
950  // Find out the original face number as we were given it in
951  // the constructor using the orientation map.
952  int origFace = -1;
953  for (int i = 0; i < 4; ++i)
954  {
955  if (m_orientationMap[i] == j)
956  {
957  origFace = i;
958  break;
959  }
960  }
961 
962  ASSERTL0(origFace >= 0, "Couldn't find face");
963 
964  // Now get the face nodes for the original face.
965  int N = 4 + 6*n + origFace * nFaceNodes;
966  for (int i = 0; i < nFaceNodes; ++i)
967  {
968  faceNodes.push_back(pNodeList[N+i]);
969  }
970 
971  // Find the original face vertex IDs.
972  vector<int> origFaceIds(3);
973  origFaceIds[0] = pNodeList[face_ids[origFace][0]]->m_id;
974  origFaceIds[1] = pNodeList[face_ids[origFace][1]]->m_id;
975  origFaceIds[2] = pNodeList[face_ids[origFace][2]]->m_id;
976 
977  // Construct a HOTriangle object which performs the
978  // orientation magically for us.
979  HOTriangle<NodeSharedPtr> hoTri(origFaceIds, faceNodes);
980  hoTri.Align(faceIds);
981 
982  // Copy the face nodes back again.
983  faceNodes = hoTri.surfVerts;
984  }
985 
986  m_face.push_back(FaceSharedPtr(
987  new Face(faceVertices, faceNodes, faceEdges, m_conf.m_faceCurveType)));
988  }
989 
990  vector<EdgeSharedPtr> tmp(6);
991  tmp[0] = m_edge[face_edges[0][0]];
992  tmp[1] = m_edge[face_edges[0][1]];
993  tmp[2] = m_edge[face_edges[0][2]];
994  tmp[3] = m_edge[face_edges[1][2]];
995  tmp[4] = m_edge[face_edges[1][1]];
996  tmp[5] = m_edge[face_edges[2][1]];
997  m_edge = tmp;
998  }
999 
1001  {
1004 
1005  for (int i = 0; i < 4; ++i)
1006  {
1007  tfaces[i] = boost::dynamic_pointer_cast
1008  <SpatialDomains::TriGeom>(m_face[i]->GetGeom(coordDim));
1009  }
1010 
1012  AllocateSharedPtr(tfaces);
1013 
1014  return ret;
1015  }
1016 
1017  /**
1018  * @brief Return the number of nodes defining a tetrahedron.
1019  */
1021  {
1022  int n = pConf.m_order;
1023  if (pConf.m_volumeNodes && pConf.m_faceNodes)
1024  return (n+1)*(n+2)*(n+3)/6;
1025  else if (!pConf.m_volumeNodes && pConf.m_faceNodes)
1026  return 4*(n+1)*(n+2)/2-6*(n+1)+4;
1027  else
1028  return 6*(n+1)-8;
1029  }
1030 
1031  /**
1032  * @brief .
1033  */
1034  void Tetrahedron::Complete(int order)
1035  {
1036  int i, j;
1037 
1038  // Create basis key for a nodal tetrahedron.
1040  LibUtilities::eOrtho_A, order+1,
1044  LibUtilities::eOrtho_B, order+1,
1048  LibUtilities::eOrtho_C, order+1,
1051 
1052  // Create a standard nodal tetrahedron in order to get the
1053  // Vandermonde matrix to perform interpolation to nodal points.
1057 
1058  Array<OneD, NekDouble> x, y, z;
1059 
1060  nodalTet->GetNodalPoints(x,y,z);
1061 
1063  boost::dynamic_pointer_cast<SpatialDomains::TetGeom>(
1064  this->GetGeom(3));
1065 
1066  // Create basis key for a tetrahedron.
1068  LibUtilities::eOrtho_A, order+1,
1072  LibUtilities::eOrtho_B, order+1,
1076  LibUtilities::eOrtho_C, order+1,
1079 
1080  // Create a tet.
1083  C0, C1, C2, geom);
1084 
1085  // Get coordinate array for tetrahedron.
1086  int nqtot = tet->GetTotPoints();
1087  Array<OneD, NekDouble> alloc(6*nqtot);
1088  Array<OneD, NekDouble> xi(alloc);
1089  Array<OneD, NekDouble> yi(alloc+ nqtot);
1090  Array<OneD, NekDouble> zi(alloc+2*nqtot);
1091  Array<OneD, NekDouble> xo(alloc+3*nqtot);
1092  Array<OneD, NekDouble> yo(alloc+4*nqtot);
1093  Array<OneD, NekDouble> zo(alloc+5*nqtot);
1095 
1096  tet->GetCoords(xi, yi, zi);
1097 
1098  for (i = 0; i < 3; ++i)
1099  {
1100  Array<OneD, NekDouble> coeffs(nodalTet->GetNcoeffs());
1101  tet->FwdTrans(alloc+i*nqtot, coeffs);
1102  // Apply Vandermonde matrix to project onto nodal space.
1103  nodalTet->ModalToNodal(coeffs, tmp=alloc+(i+3)*nqtot);
1104  }
1105 
1106  // Now extract points from the co-ordinate arrays into the
1107  // edge/face/volume nodes. First, extract edge-interior nodes.
1108  for (i = 0; i < 6; ++i)
1109  {
1110  int pos = 4 + i*(order-1);
1111  m_edge[i]->m_edgeNodes.clear();
1112  for (j = 0; j < order-1; ++j)
1113  {
1114  m_edge[i]->m_edgeNodes.push_back(
1115  NodeSharedPtr(new Node(0, xo[pos+j], yo[pos+j], zo[pos+j])));
1116  }
1117  }
1118 
1119  // Now extract face-interior nodes.
1120  for (i = 0; i < 4; ++i)
1121  {
1122  int pos = 4 + 6*(order-1) + i*(order-2)*(order-1)/2;
1123  m_face[i]->m_faceNodes.clear();
1124  for (j = 0; j < (order-2)*(order-1)/2; ++j)
1125  {
1126  m_face[i]->m_faceNodes.push_back(
1127  NodeSharedPtr(new Node(0, xo[pos+j], yo[pos+j], zo[pos+j])));
1128  }
1129  }
1130 
1131  // Finally extract volume nodes.
1132  int pos = 4 + 6*(order-1) + 4*(order-2)*(order-1)/2;
1133  for (i = pos; i < (order+1)*(order+2)*(order+3)/6; ++i)
1134  {
1135  m_volumeNodes.push_back(
1136  NodeSharedPtr(new Node(0, xo[i], yo[i], zo[i])));
1137  }
1138 
1139  m_conf.m_order = order;
1140  m_conf.m_faceNodes = true;
1141  m_conf.m_volumeNodes = true;
1142  }
1143 
1144  struct TetOrient
1145  {
1146  TetOrient(vector<int> nid, int fid) : nid(nid), fid(fid) {}
1147  vector<int> nid;
1148  int fid;
1149  };
1150 
1151  struct TetOrientHash : std::unary_function<struct TetOrient, std::size_t>
1152  {
1153  std::size_t operator()(struct TetOrient const& p) const
1154  {
1155  return boost::hash_range(p.nid.begin(), p.nid.end());
1156  }
1157  };
1158  typedef boost::unordered_set<struct TetOrient, TetOrientHash> TetOrientSet;
1159 
1160  bool operator==(const struct TetOrient &a, const struct TetOrient &b)
1161  {
1162  if (a.nid.size() != b.nid.size())
1163  {
1164  return false;
1165  }
1166 
1167  for (int i = 0; i < a.nid.size(); ++i)
1168  {
1169  if (a.nid[i] != b.nid[i])
1170  {
1171  return false;
1172  }
1173  }
1174 
1175  return true;
1176  }
1177 
1178  /**
1179  * @brief Orient tetrahedron to align degenerate vertices.
1180  *
1181  * Orientation of tetrahedral elements is required so that the
1182  * singular vertices of triangular faces (which occur as a part of the
1183  * collapsed co-ordinate system) align. The algorithm is based on that
1184  * used in T. Warburton's thesis and in the original Nektar source.
1185  *
1186  * First the vertices are ordered with the highest global vertex at
1187  * the top degenerate point, and the base degenerate point has second
1188  * lowest ID. These vertices are swapped if the element is incorrectly
1189  * oriented.
1190  */
1192  {
1193  static int face_ids[4][3] = {
1194  {0,1,2},{0,1,3},{1,2,3},{0,2,3}};
1195 
1196  TetOrientSet faces;
1197 
1198  // Create a copy of the original vertex ordering. This is used to
1199  // construct a mapping, #orientationMap, which maps the original
1200  // face ordering to the new face ordering.
1201  for (int i = 0; i < 4; ++i)
1202  {
1203  vector<int> nodes(3);
1204 
1205  nodes[0] = m_vertex[face_ids[i][0]]->m_id;
1206  nodes[1] = m_vertex[face_ids[i][1]]->m_id;
1207  nodes[2] = m_vertex[face_ids[i][2]]->m_id;
1208 
1209  sort(nodes.begin(), nodes.end());
1210  struct TetOrient faceNodes(nodes, i);
1211  faces.insert(faceNodes);
1212  }
1213 
1214  // Store a copy of the original vertex ordering so we can create a
1215  // permutation map later.
1216  vector<NodeSharedPtr> origVert = m_vertex;
1217 
1218  // Order vertices with highest global vertex at top degenerate
1219  // point. Place second highest global vertex at base degenerate
1220  // point.
1221  sort(m_vertex.begin(), m_vertex.end());
1222 
1223  // Calculate a.(b x c) if negative, reverse order of
1224  // non-degenerate points to correctly orientate the tet.
1225 
1226  NekDouble ax = m_vertex[1]->m_x-m_vertex[0]->m_x;
1227  NekDouble ay = m_vertex[1]->m_y-m_vertex[0]->m_y;
1228  NekDouble az = m_vertex[1]->m_z-m_vertex[0]->m_z;
1229  NekDouble bx = m_vertex[2]->m_x-m_vertex[0]->m_x;
1230  NekDouble by = m_vertex[2]->m_y-m_vertex[0]->m_y;
1231  NekDouble bz = m_vertex[2]->m_z-m_vertex[0]->m_z;
1232  NekDouble cx = m_vertex[3]->m_x-m_vertex[0]->m_x;
1233  NekDouble cy = m_vertex[3]->m_y-m_vertex[0]->m_y;
1234  NekDouble cz = m_vertex[3]->m_z-m_vertex[0]->m_z;
1235 
1236  NekDouble nx = (ay*bz-az*by);
1237  NekDouble ny = (az*bx-ax*bz);
1238  NekDouble nz = (ax*by-ay*bx);
1239  NekDouble nmag = sqrt(nx*nx+ny*ny+nz*nz);
1240  nx /= nmag; ny /= nmag; nz /= nmag;
1241 
1242  // distance of top vertex from base
1243  NekDouble dist = cx*nx+cy*ny+cz*nz;
1244 
1245  if (fabs(dist) <= 1e-4)
1246  {
1247  cerr << "Warning: degenerate tetrahedron, 3rd vertex is = " << dist <<" from face" << endl;
1248  }
1249 
1250  if (dist < 0)
1251  {
1252  swap(m_vertex[0], m_vertex[1]);
1253  }
1254 
1255  nx = (ay*cz-az*cy);
1256  ny = (az*cx-ax*cz);
1257  nz = (ax*cy-ay*cx);
1258  nmag = sqrt(nx*nx+ny*ny+nz*nz);
1259  nx /= nmag; ny /= nmag; nz /= nmag;
1260 
1261  // distance of top vertex from base
1262  dist = bx*nx+by*ny+bz*nz;
1263 
1264  if (fabs(dist) <= 1e-4)
1265  {
1266  cerr << "Warning: degenerate tetrahedron, 2nd vertex is = " << dist <<" from face" << endl;
1267  }
1268 
1269  nx = (by*cz-bz*cy);
1270  ny = (bz*cx-bx*cz);
1271  nz = (bx*cy-by*cx);
1272  nmag = sqrt(nx*nx+ny*ny+nz*nz);
1273  nx /= nmag; ny /= nmag; nz /= nmag;
1274 
1275  // distance of top vertex from base
1276  dist = ax*nx+ay*ny+az*nz;
1277 
1278  if (fabs(dist) <= 1e-4)
1279  {
1280  cerr << "Warning: degenerate tetrahedron, 1st vertex is = " << dist <<" from face" << endl;
1281  }
1282 
1283 
1285 
1286  // Search for the face in the original set of face nodes. Then use
1287  // this to construct the #orientationMap.
1288  for (int i = 0; i < 4; ++i)
1289  {
1290  vector<int> nodes(3);
1291 
1292  nodes[0] = m_vertex[face_ids[i][0]]->m_id;
1293  nodes[1] = m_vertex[face_ids[i][1]]->m_id;
1294  nodes[2] = m_vertex[face_ids[i][2]]->m_id;
1295  sort(nodes.begin(), nodes.end());
1296 
1297  struct TetOrient faceNodes(nodes, 0);
1298 
1299  it = faces.find(faceNodes);
1300  m_orientationMap[it->fid] = i;
1301 
1302  for (int j = 0; j < 4; ++j)
1303  {
1304  if (m_vertex[i]->m_id == origVert[j]->m_id)
1305  {
1306  m_origVertMap[j] = i;
1307  break;
1308  }
1309  }
1310  }
1311  }
1312 
1314  RegisterCreatorFunction(LibUtilities::ePyramid, Pyramid::create, "Pyramid");
1315 
1316  /**
1317  * @brief Create a pyramidic element.
1318  */
1320  vector<NodeSharedPtr> pNodeList,
1321  vector<int> pTagList)
1322  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
1323  {
1324  m_tag = "P";
1325  m_dim = 3;
1326  m_taglist = pTagList;
1327  int n = m_conf.m_order-1;
1328 
1329  // This edge-node map is based on Nektar++ ordering.
1330  map<pair<int,int>, int> edgeNodeMap;
1331  map<pair<int,int>, int>::iterator it;
1332  edgeNodeMap[pair<int,int>(1,2)] = 6;
1333  edgeNodeMap[pair<int,int>(2,3)] = 6 + n;
1334  edgeNodeMap[pair<int,int>(4,3)] = 6 + 2*n;
1335  edgeNodeMap[pair<int,int>(1,4)] = 6 + 3*n;
1336  edgeNodeMap[pair<int,int>(1,5)] = 6 + 4*n;
1337  edgeNodeMap[pair<int,int>(2,5)] = 6 + 5*n;
1338  edgeNodeMap[pair<int,int>(3,5)] = 6 + 6*n;
1339  edgeNodeMap[pair<int,int>(4,5)] = 6 + 7*n;
1340 
1341  // Add vertices
1342  for (int i = 0; i < 5; ++i)
1343  {
1344  m_vertex.push_back(pNodeList[i]);
1345  }
1346 
1347  // Create edges (with corresponding set of edge points)
1348  int eid = 0;
1349  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
1350  {
1351  vector<NodeSharedPtr> edgeNodes;
1352  if (m_conf.m_order > 1)
1353  {
1354  for (int j = it->second; j < it->second + n; ++j)
1355  {
1356  edgeNodes.push_back(pNodeList[j-1]);
1357  }
1358  }
1359  m_edge.push_back(
1360  EdgeSharedPtr(new Edge(pNodeList[it->first.first-1],
1361  pNodeList[it->first.second-1],
1362  edgeNodes,
1364  m_edge.back()->m_id = eid++;
1365  }
1366 
1367  // Create faces
1368  int face_ids[5][4] = {
1369  {0,1,2,3}, {0,1,4,-1}, {1,2,4,-1}, {3,2,4,-1}, {0,3,4,-1}
1370  };
1371  int face_edges[5][4];
1372  int faceoffset = 5 + 8*n;
1373  for (int j = 0; j < 5; ++j)
1374  {
1375  vector<NodeSharedPtr> faceVertices;
1376  vector<EdgeSharedPtr> faceEdges;
1377  vector<NodeSharedPtr> faceNodes;
1378  int nEdge = j > 0 ? 3 : 4;
1379 
1380  for (int k = 0; k < nEdge; ++k)
1381  {
1382  faceVertices.push_back(m_vertex[face_ids[j][k]]);
1383  NodeSharedPtr a = m_vertex[face_ids[j][k]];
1384  NodeSharedPtr b = m_vertex[face_ids[j][(k+1) % nEdge]];
1385  for (unsigned int i = 0; i < m_edge.size(); ++i)
1386  {
1387  if ((m_edge[i]->m_n1 == a && m_edge[i]->m_n2 == b) ||
1388  (m_edge[i]->m_n1 == b && m_edge[i]->m_n2 == a))
1389  {
1390  faceEdges.push_back(m_edge[i]);
1391  face_edges[j][k] = i;
1392  break;
1393  }
1394  }
1395  }
1396 
1397  if (m_conf.m_faceNodes)
1398  {
1399  int facenodes = j == 0 ? n*n : n*(n-1)/2;
1400  for (int i = 0; i < facenodes; ++i)
1401  {
1402  faceNodes.push_back(pNodeList[faceoffset+i]);
1403  }
1404  faceoffset += facenodes;
1405  }
1406  m_face.push_back(FaceSharedPtr(
1407  new Face(faceVertices, faceNodes, faceEdges, m_conf.m_faceCurveType)));
1408  }
1409 
1410  // Reorder edges to align with Nektar++ order.
1411  vector<EdgeSharedPtr> tmp(8);
1412  tmp[0] = m_edge[face_edges[0][0]];
1413  tmp[1] = m_edge[face_edges[0][1]];
1414  tmp[2] = m_edge[face_edges[0][2]];
1415  tmp[3] = m_edge[face_edges[0][3]];
1416  tmp[4] = m_edge[face_edges[1][2]];
1417  tmp[5] = m_edge[face_edges[1][1]];
1418  tmp[6] = m_edge[face_edges[3][1]];
1419  tmp[7] = m_edge[face_edges[3][2]];
1420  m_edge = tmp;
1421  }
1422 
1424  {
1426 
1427  for (int i = 0; i < 5; ++i)
1428  {
1429  faces[i] = m_face[i]->GetGeom(coordDim);
1430  }
1431 
1433  AllocateSharedPtr(faces);
1434 
1435  return m_geom;
1436  }
1437 
1438  /**
1439  * @brief Return the number of nodes defining a pyramid.
1440  */
1441  unsigned int Pyramid::GetNumNodes(ElmtConfig pConf)
1442  {
1443  int n = pConf.m_order;
1444  return 5 + 8*(n-1);
1445  }
1446 
1448  RegisterCreatorFunction(LibUtilities::ePrism, Prism::create, "Prism");
1449 
1450  /**
1451  * @brief Create a prism element.
1452  */
1454  vector<NodeSharedPtr> pNodeList,
1455  vector<int> pTagList)
1456  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
1457  {
1458  m_tag = "R";
1459  m_dim = 3;
1460  m_taglist = pTagList;
1461  int n = m_conf.m_order-1;
1462 
1463  // Create a map to relate edge nodes to a pair of vertices
1464  // defining an edge. This is based on the ordering produced by
1465  // gmsh.
1466  map<pair<int,int>, int> edgeNodeMap;
1467  map<pair<int,int>, int>::iterator it;
1468 
1469  // This edge-node map is based on Nektar++ ordering.
1470  edgeNodeMap[pair<int,int>(1,2)] = 7;
1471  edgeNodeMap[pair<int,int>(2,3)] = 7 + n;
1472  edgeNodeMap[pair<int,int>(4,3)] = 7 + 2*n;
1473  edgeNodeMap[pair<int,int>(1,4)] = 7 + 3*n;
1474  edgeNodeMap[pair<int,int>(1,5)] = 7 + 4*n;
1475  edgeNodeMap[pair<int,int>(2,5)] = 7 + 5*n;
1476  edgeNodeMap[pair<int,int>(3,6)] = 7 + 6*n;
1477  edgeNodeMap[pair<int,int>(4,6)] = 7 + 7*n;
1478  edgeNodeMap[pair<int,int>(5,6)] = 7 + 8*n;
1479 
1480  // Add vertices
1481  for (int i = 0; i < 6; ++i)
1482  {
1483  m_vertex.push_back(pNodeList[i]);
1484  }
1485 
1486  int eid = 0;
1487  // Create edges (with corresponding set of edge points)
1488  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
1489  {
1490  vector<NodeSharedPtr> edgeNodes;
1491  if (m_conf.m_order > 1) {
1492  for (int j = it->second; j < it->second + n; ++j) {
1493  edgeNodes.push_back(pNodeList[j-1]);
1494  }
1495  }
1496  m_edge.push_back(EdgeSharedPtr(
1497  new Edge(pNodeList[it->first.first-1],
1498  pNodeList[it->first.second-1],
1499  edgeNodes,
1501  m_edge.back()->m_id = eid++;
1502  }
1503 
1504  if (m_conf.m_reorient)
1505  {
1506  OrientPrism();
1507  }
1508  else
1509  {
1510  m_orientation = 0;
1511  }
1512 
1513  // Create faces
1514  int face_ids[5][4] = {
1515  {0,1,2,3},{0,1,4,-1},{1,2,5,4},{3,2,5,-1},{0,3,5,4}};
1516  int face_edges[5][4];
1517 
1518  int face_offset[5];
1519  face_offset[0] = 6 + 9*n;
1520  for (int j = 0; j < 4; ++j)
1521  {
1522  int facenodes = j % 2 == 0 ? n*n : n*(n-1)/2;
1523  face_offset[j+1] = face_offset[j] + facenodes;
1524  }
1525 
1526  for (int j = 0; j < 5; ++j)
1527  {
1528  vector<NodeSharedPtr> faceVertices;
1529  vector<EdgeSharedPtr> faceEdges;
1530  vector<NodeSharedPtr> faceNodes;
1531  int nEdge = 3 - (j % 2 - 1);
1532 
1533  for (int k = 0; k < nEdge; ++k)
1534  {
1535  faceVertices.push_back(m_vertex[face_ids[j][k]]);
1536  NodeSharedPtr a = m_vertex[face_ids[j][k]];
1537  NodeSharedPtr b = m_vertex[face_ids[j][(k+1) % nEdge]];
1538  unsigned int i;
1539  for (i = 0; i < m_edge.size(); ++i)
1540  {
1541  if ((m_edge[i]->m_n1->m_id == a->m_id
1542  && m_edge[i]->m_n2->m_id == b->m_id) ||
1543  (m_edge[i]->m_n1->m_id == b->m_id
1544  && m_edge[i]->m_n2->m_id == a->m_id))
1545  {
1546  faceEdges.push_back(m_edge[i]);
1547  face_edges[j][k] = i;
1548  break;
1549  }
1550  }
1551 
1552  if(i == m_edge.size())
1553  {
1554  face_edges[j][k] = -1;
1555  }
1556  }
1557 
1558  if (m_conf.m_faceNodes)
1559  {
1560  int face = j, facenodes;
1561 
1562  if (j % 2 == 0)
1563  {
1564  facenodes = n*n;
1565  if (m_orientation == 1)
1566  {
1567  face = (face+4) % 6;
1568  }
1569  else if (m_orientation == 2)
1570  {
1571  face = (face+2) % 6;
1572  }
1573  }
1574  else
1575  {
1576  // TODO: need to rotate these too.
1577  facenodes = n*(n-1)/2;
1578  }
1579 
1580  for (int i = 0; i < facenodes; ++i)
1581  {
1582  faceNodes.push_back(pNodeList[face_offset[face]+i]);
1583  }
1584  }
1585  m_face.push_back(FaceSharedPtr(
1586  new Face(faceVertices, faceNodes, faceEdges, m_conf.m_faceCurveType)));
1587  }
1588 
1589  // Re-order edge array to be consistent with Nektar++ ordering.
1590  vector<EdgeSharedPtr> tmp(9);
1591  ASSERTL1(face_edges[0][0] != -1,"face_edges[0][0] == -1");
1592  tmp[0] = m_edge[face_edges[0][0]];
1593  ASSERTL1(face_edges[0][1] != -1,"face_edges[0][1] == -1");
1594  tmp[1] = m_edge[face_edges[0][1]];
1595  ASSERTL1(face_edges[0][2] != -1,"face_edges[0][2] == -1");
1596  tmp[2] = m_edge[face_edges[0][2]];
1597  ASSERTL1(face_edges[0][3] != -1,"face_edges[0][3] == -1");
1598  tmp[3] = m_edge[face_edges[0][3]];
1599  ASSERTL1(face_edges[1][2] != -1,"face_edges[1][2] == -1");
1600  tmp[4] = m_edge[face_edges[1][2]];
1601  ASSERTL1(face_edges[1][1] != -1,"face_edges[1][1] == -1");
1602  tmp[5] = m_edge[face_edges[1][1]];
1603  ASSERTL1(face_edges[2][1] != -1,"face_edges[2][1] == -1");
1604  tmp[6] = m_edge[face_edges[2][1]];
1605  ASSERTL1(face_edges[3][2] != -1,"face_edges[3][2] == -1");
1606  tmp[7] = m_edge[face_edges[3][2]];
1607  ASSERTL1(face_edges[4][2] != -1,"face_edges[4][2] == -1");
1608  tmp[8] = m_edge[face_edges[4][2]];
1609  m_edge = tmp;
1610  }
1611 
1612  /**
1613  * @brief Return the number of nodes defining a prism.
1614  */
1615  unsigned int Prism::GetNumNodes(ElmtConfig pConf)
1616  {
1617  int n = pConf.m_order;
1618  if (pConf.m_faceNodes && pConf.m_volumeNodes)
1619  return (n+1)*(n+1)*(n+2)/2;
1620  else if (pConf.m_faceNodes && !pConf.m_volumeNodes)
1621  return 3*(n+1)*(n+1)+2*(n+1)*(n+2)/2-9*(n+1)+6;
1622  else
1623  return 9*(n+1)-12;
1624  }
1625 
1627  {
1630 
1631  for (int i = 0; i < 5; ++i)
1632  {
1633  faces[i] = m_face[i]->GetGeom(coordDim);
1634  }
1635 
1637  AllocateSharedPtr(faces);
1638 
1639  return ret;
1640  }
1641 
1642  /**
1643  * @brief .
1644  */
1645  void Prism::Complete(int order)
1646  {
1647  int i, j, pos;
1648 
1649  // Create basis key for a nodal tetrahedron.
1651  LibUtilities::eOrtho_A, order+1,
1655  LibUtilities::eOrtho_A, order+1,
1659  LibUtilities::eOrtho_B, order+1,
1662 
1663  // Create a standard nodal prism in order to get the Vandermonde
1664  // matrix to perform interpolation to nodal points.
1668 
1669  Array<OneD, NekDouble> x, y, z;
1670  nodalPrism->GetNodalPoints(x,y,z);
1671 
1673  boost::dynamic_pointer_cast<SpatialDomains::PrismGeom>(
1674  this->GetGeom(3));
1675 
1676  // Create basis key for a prism.
1678  LibUtilities::eOrtho_A, order+1,
1682  LibUtilities::eOrtho_A, order+1,
1686  LibUtilities::eOrtho_B, order+1,
1689 
1690  // Create a prism.
1693  C0, C1, C2, geom);
1694 
1695  // Get coordinate array for tetrahedron.
1696  int nqtot = prism->GetTotPoints();
1697  Array<OneD, NekDouble> alloc(6*nqtot);
1698  Array<OneD, NekDouble> xi(alloc);
1699  Array<OneD, NekDouble> yi(alloc+ nqtot);
1700  Array<OneD, NekDouble> zi(alloc+2*nqtot);
1701  Array<OneD, NekDouble> xo(alloc+3*nqtot);
1702  Array<OneD, NekDouble> yo(alloc+4*nqtot);
1703  Array<OneD, NekDouble> zo(alloc+5*nqtot);
1705 
1706  prism->GetCoords(xi, yi, zi);
1707 
1708  for (i = 0; i < 3; ++i)
1709  {
1710  Array<OneD, NekDouble> coeffs(nodalPrism->GetNcoeffs());
1711  prism->FwdTrans(alloc+i*nqtot, coeffs);
1712  // Apply Vandermonde matrix to project onto nodal space.
1713  nodalPrism->ModalToNodal(coeffs, tmp=alloc+(i+3)*nqtot);
1714  }
1715 
1716  // Now extract points from the co-ordinate arrays into the
1717  // edge/face/volume nodes. First, extract edge-interior nodes.
1718  for (i = 0; i < 9; ++i)
1719  {
1720  pos = 6 + i*(order-1);
1721  m_edge[i]->m_edgeNodes.clear();
1722  for (j = 0; j < order-1; ++j)
1723  {
1724  m_edge[i]->m_edgeNodes.push_back(
1725  NodeSharedPtr(new Node(0, xo[pos+j], yo[pos+j], zo[pos+j])));
1726  }
1727  }
1728 
1729  // Now extract face-interior nodes.
1730  pos = 6 + 9*(order-1);
1731  for (i = 0; i < 5; ++i)
1732  {
1733  int facesize = i % 2 ? (order-2)*(order-1)/2 : (order-1)*(order-1);
1734  m_face[i]->m_faceNodes.clear();
1735  for (j = 0; j < facesize; ++j)
1736  {
1737  m_face[i]->m_faceNodes.push_back(
1738  NodeSharedPtr(new Node(0, xo[pos+j], yo[pos+j], zo[pos+j])));
1739  }
1740  pos += facesize;
1741  }
1742 
1743  // Finally extract volume nodes.
1744  for (i = pos; i < (order+1)*(order+1)*(order+2)/2; ++i)
1745  {
1746  m_volumeNodes.push_back(
1747  NodeSharedPtr(new Node(0, xo[i], yo[i], zo[i])));
1748  }
1749 
1750  m_conf.m_order = order;
1751  m_conf.m_faceNodes = true;
1752  m_conf.m_volumeNodes = true;
1753  }
1754 
1755  /**
1756  * @brief Orient prism to align degenerate vertices.
1757  *
1758  * Orientation of prismatric elements is required so that the singular
1759  * vertices of triangular faces (which occur as a part of the
1760  * collapsed co-ordinate system) align. The algorithm is based on that
1761  * used in T. Warburton's thesis and in the original Nektar source.
1762  *
1763  * First the points are re-ordered so that the highest global IDs
1764  * represent the two singular points of the prism. Then, if necessary,
1765  * the nodes are rotated either clockwise or counter-clockwise (w.r.t
1766  * to the p-r plane) to correctly align the prism. The #orientation
1767  * variable is set to:
1768  *
1769  * - 0 if the prism is not rotated;
1770  * - 1 if the prism is rotated clockwise;
1771  * - 2 if the prism is rotated counter-clockwise.
1772  *
1773  * This is necessary for some input modules (e.g. #InputNek) which add
1774  * high-order information or bounary conditions to faces.
1775  */
1777  {
1778  int lid[6], gid[6];
1779 
1780  // Re-order vertices.
1781  for (int i = 0; i < 6; ++i)
1782  {
1783  lid[i] = i;
1784  gid[i] = m_vertex[i]->m_id;
1785  }
1786 
1787  gid[0] = gid[3] = max(gid[0], gid[3]);
1788  gid[1] = gid[2] = max(gid[1], gid[2]);
1789  gid[4] = gid[5] = max(gid[4], gid[5]);
1790 
1791  for (int i = 1; i < 6; ++i)
1792  {
1793  if (gid[0] < gid[i])
1794  {
1795  swap(gid[i], gid[0]);
1796  swap(lid[i], lid[0]);
1797  }
1798  }
1799 
1800  if (lid[0] == 4 || lid[0] == 5)
1801  {
1802  m_orientation = 0;
1803  }
1804  else if (lid[0] == 1 || lid[0] == 2)
1805  {
1806  // Rotate prism clockwise in p-r plane
1807  vector<NodeSharedPtr> vertexmap(6);
1808  vertexmap[0] = m_vertex[4];
1809  vertexmap[1] = m_vertex[0];
1810  vertexmap[2] = m_vertex[3];
1811  vertexmap[3] = m_vertex[5];
1812  vertexmap[4] = m_vertex[1];
1813  vertexmap[5] = m_vertex[2];
1814  m_vertex = vertexmap;
1815  m_orientation = 1;
1816  }
1817  else if (lid[0] == 0 || lid[0] == 3)
1818  {
1819  // Rotate prism counter-clockwise in p-r plane
1820  vector<NodeSharedPtr> vertexmap(6);
1821  vertexmap[0] = m_vertex[1];
1822  vertexmap[1] = m_vertex[4];
1823  vertexmap[2] = m_vertex[5];
1824  vertexmap[3] = m_vertex[2];
1825  vertexmap[4] = m_vertex[0];
1826  vertexmap[5] = m_vertex[3];
1827  m_vertex = vertexmap;
1828  m_orientation = 2;
1829  }
1830  else
1831  {
1832  cerr << "Warning: possible prism orientation problem." << endl;
1833  }
1834  }
1835 
1836 
1838  RegisterCreatorFunction(LibUtilities::eHexahedron, Hexahedron::create, "Hexahedron");
1839 
1840  /**
1841  * @brief Create a hexahedral element.
1842  */
1844  vector<NodeSharedPtr> pNodeList,
1845  vector<int> pTagList)
1846  : Element(pConf, GetNumNodes(pConf), pNodeList.size())
1847  {
1848  m_tag = "H";
1849  m_dim = 3;
1850  m_taglist = pTagList;
1851  int n = m_conf.m_order-1;
1852 
1853  // Create a map to relate edge nodes to a pair of vertices defining an edge
1854  // This is based on the ordering produced by gmsh.
1855  map<pair<int,int>, int> edgeNodeMap;
1856  map<pair<int,int>, int>::iterator it;
1857  edgeNodeMap[pair<int,int>(1,2)] = 9;
1858  edgeNodeMap[pair<int,int>(2,3)] = 9 + n;
1859  edgeNodeMap[pair<int,int>(3,4)] = 9 + 2*n;
1860  edgeNodeMap[pair<int,int>(4,1)] = 9 + 3*n;
1861  edgeNodeMap[pair<int,int>(1,5)] = 9 + 4*n;
1862  edgeNodeMap[pair<int,int>(2,6)] = 9 + 5*n;
1863  edgeNodeMap[pair<int,int>(3,7)] = 9 + 6*n;
1864  edgeNodeMap[pair<int,int>(4,8)] = 9 + 7*n;
1865  edgeNodeMap[pair<int,int>(5,6)] = 9 + 8*n;
1866  edgeNodeMap[pair<int,int>(6,7)] = 9 + 9*n;
1867  edgeNodeMap[pair<int,int>(7,8)] = 9 + 10*n;
1868  edgeNodeMap[pair<int,int>(8,5)] = 9 + 11*n;
1869 
1870  // Add vertices
1871  for (int i = 0; i < 8; ++i) {
1872  m_vertex.push_back(pNodeList[i]);
1873  }
1874 
1875  // Create edges (with corresponding set of edge points)
1876  for (it = edgeNodeMap.begin(); it != edgeNodeMap.end(); ++it)
1877  {
1878  vector<NodeSharedPtr> edgeNodes;
1879  if (m_conf.m_order > 1) {
1880  for (int j = it->second; j < it->second + n; ++j) {
1881  edgeNodes.push_back(pNodeList[j-1]);
1882  }
1883  }
1884  m_edge.push_back(EdgeSharedPtr(new Edge(pNodeList[it->first.first-1],
1885  pNodeList[it->first.second-1],
1886  edgeNodes,
1888  }
1889 
1890  // Create faces
1891  int face_edges[6][4];
1892  int face_ids[6][4] = {
1893  {0,1,2,3},{0,1,5,4},{1,2,6,5},{3,2,6,7},{0,3,7,4},{4,5,6,7}};
1894  for (int j = 0; j < 6; ++j)
1895  {
1896  vector<NodeSharedPtr> faceVertices;
1897  vector<EdgeSharedPtr> faceEdges;
1898  vector<NodeSharedPtr> faceNodes;
1899  for (int k = 0; k < 4; ++k)
1900  {
1901  faceVertices.push_back(m_vertex[face_ids[j][k]]);
1902  NodeSharedPtr a = m_vertex[face_ids[j][k]];
1903  NodeSharedPtr b = m_vertex[face_ids[j][(k+1)%4]];
1904  for (unsigned int i = 0; i < m_edge.size(); ++i)
1905  {
1906  if ( ((*(m_edge[i]->m_n1)==*a) && (*(m_edge[i]->m_n2)==*b))
1907  || ((*(m_edge[i]->m_n1)==*b) && (*(m_edge[i]->m_n2) == *a)) )
1908  {
1909  face_edges[j][k] = i;
1910  faceEdges.push_back(m_edge[i]);
1911  break;
1912  }
1913  }
1914  }
1915 
1916  if (m_conf.m_faceNodes)
1917  {
1918  int N = 8 + 12*n + j*n*n;
1919  for (int i = 0; i < n*n; ++i)
1920  {
1921  faceNodes.push_back(pNodeList[N+i]);
1922  }
1923  }
1924  m_face.push_back(FaceSharedPtr(
1925  new Face(faceVertices, faceNodes, faceEdges, m_conf.m_faceCurveType)));
1926  }
1927 
1928  // Reorder edges to be consistent with Nektar++ ordering.
1929  vector<EdgeSharedPtr> tmp(12);
1930  tmp[ 0] = m_edge[face_edges[0][0]];
1931  tmp[ 1] = m_edge[face_edges[0][1]];
1932  tmp[ 2] = m_edge[face_edges[0][2]];
1933  tmp[ 3] = m_edge[face_edges[0][3]];
1934  tmp[ 4] = m_edge[face_edges[1][3]];
1935  tmp[ 5] = m_edge[face_edges[1][1]];
1936  tmp[ 6] = m_edge[face_edges[2][1]];
1937  tmp[ 7] = m_edge[face_edges[4][1]];
1938  tmp[ 8] = m_edge[face_edges[5][0]];
1939  tmp[ 9] = m_edge[face_edges[5][1]];
1940  tmp[10] = m_edge[face_edges[5][2]];
1941  tmp[11] = m_edge[face_edges[5][3]];
1942  m_edge = tmp;
1943  }
1944 
1946  {
1949 
1950  for (int i = 0; i < 6; ++i)
1951  {
1952  faces[i] = boost::dynamic_pointer_cast
1953  <SpatialDomains::QuadGeom>(m_face[i]->GetGeom(coordDim));
1954  }
1955 
1957  AllocateSharedPtr(faces);
1958 
1959  return ret;
1960  }
1961 
1962  /**
1963  * @brief Return the number of nodes defining a hexahedron.
1964  */
1966  {
1967  int n = pConf.m_order;
1968  if (pConf.m_faceNodes && pConf.m_volumeNodes)
1969  return (n+1)*(n+1)*(n+1);
1970  else if (pConf.m_faceNodes && !pConf.m_volumeNodes)
1971  return 6*(n+1)*(n+1)-12*(n+1)+8;
1972  else
1973  return 12*(n+1)-16;
1974  }
1975  }
1976 }
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
Define element ordering based on ID.
static LibUtilities::ShapeType m_type
Element type.
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:135
bool m_volumeNodes
Denotes whether the element contains volume (i.e. interior) nodes. These are not supported by either ...
Definition: MeshElements.h:627
std::ostream & operator<<(std::ostream &os, const ModuleKey &rhs)
LibUtilities::PointsType m_curveType
Volume curve type.
Definition: MeshElements.h:994
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a prism.
TetOrient(vector< int > nid, int fid)
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
Represents an edge which joins two points.
Definition: MeshElements.h:227
static LibUtilities::ShapeType type
Element type.
unsigned int GetNumEntities()
Returns the total number of entities in the mesh.
std::vector< NodeSharedPtr > m_volumeNodes
List of element volume nodes.
Definition: MeshElements.h:992
std::vector< int > m_taglist
List of integers specifying properties of the element.
Definition: MeshElements.h:984
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
boost::shared_ptr< QuadGeom > QuadGeomSharedPtr
Definition: QuadGeom.h:54
Hexahedron(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a hexahedral element.
virtual void Complete(int order)
Complete this object.
boost::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: MeshElements.h:318
std::vector< FaceSharedPtr > m_face
List of element faces.
Definition: MeshElements.h:990
STL namespace.
virtual void Complete(int order)
Complete this object.
std::vector< ElementSharedPtr > m_items
List of elements in this composite.
Nektar::LibUtilities::NekFactory< LibUtilities::ShapeType, Element, ElmtConfig, std::vector< NodeSharedPtr >, std::vector< int > > ElementFactory
Element factory definition.
boost::shared_ptr< Face > FaceSharedPtr
Shared pointer to a face.
Definition: MeshElements.h:550
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
vector< T > surfVerts
The triangle surface vertices – templated so that this can either be nodes or IDs.
std::size_t operator()(struct TetOrient const &p) const
int GetMaxOrder()
Obtain the order of an element by looking at edges.
boost::shared_ptr< HexGeom > HexGeomSharedPtr
Definition: HexGeom.h:110
boost::shared_ptr< Node > NodeSharedPtr
Shared pointer to a Node.
Definition: MeshElements.h:195
boost::shared_ptr< TetExp > TetExpSharedPtr
Definition: TetExp.h:234
boost::shared_ptr< StdNodalTriExp > StdNodalTriExpSharedPtr
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
static StdRegions::Orientation GetEdgeOrientation(const SegGeom &edge1, const SegGeom &edge2)
Get the orientation of edge1.
Definition: SegGeom.cpp:293
boost::shared_ptr< Curve > CurveSharedPtr
Definition: Curve.hpp:62
static LibUtilities::ShapeType m_type
Element type.
SpatialDomains::GeometrySharedPtr m_geom
Nektar++ geometry object for this element.
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:57
boost::shared_ptr< Condition > ConditionSharedPtr
Quadrilateral(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a quadrilateral element.
Principle Orthogonal Functions .
Definition: BasisType.h:47
1D Evenly-spaced points using Lagrange polynomial
Definition: PointsType.h:63
void SetVertex(unsigned int p, NodeSharedPtr pNew)
Replace a vertex with another vertex object.
virtual void Complete(int order)
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
bool m_reorient
Denotes whether the element needs to be re-orientated for a spectral element framework.
Definition: MeshElements.h:632
boost::shared_ptr< StdNodalPrismExp > StdNodalPrismExpSharedPtr
void SetFace(unsigned int p, FaceSharedPtr pNew)
Replace a face with another face object.
LibUtilities::ShapeType m_e
Element type (e.g. triangle, quad, etc).
Definition: MeshElements.h:618
unsigned int m_order
Order of the element.
Definition: MeshElements.h:629
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a line.
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a pyramid.
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a hexahedron.
Point(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a point element.
boost::shared_ptr< SegGeom > SegGeomSharedPtr
Definition: Geometry2D.h:60
unsigned int m_id
ID of the element.
Definition: MeshElements.h:976
void SetEdge(unsigned int p, EdgeSharedPtr pNew)
Replace an edge with another edge object.
std::string m_tag
Element type tag.
static LibUtilities::ShapeType m_type
Element type.
LibUtilities::PointsType m_faceCurveType
Distribution of points in faces.
Definition: MeshElements.h:636
bool m_faceNodes
Denotes whether the element contains face nodes. For 2D elements, if this is true then the element co...
Definition: MeshElements.h:622
Principle Orthogonal Functions .
Definition: BasisType.h:48
Principle Orthogonal Functions .
Definition: BasisType.h:46
static LibUtilities::ShapeType m_type
Element type.
Defines a specification for a set of points.
Definition: Points.h:58
boost::shared_ptr< QuadExp > QuadExpSharedPtr
Definition: QuadExp.h:284
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a point (i.e. return 1).
double NekDouble
bool operator<(NodeSharedPtr const &p1, NodeSharedPtr const &p2)
Defines ordering between two NodeSharedPtr objects.
static LibUtilities::ShapeType m_type
Element type.
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
Basic information about an element.
Definition: MeshElements.h:583
boost::shared_ptr< StdNodalTetExp > StdNodalTetExpSharedPtr
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
boost::shared_ptr< PrismExp > PrismExpSharedPtr
Definition: PrismExp.h:226
ElementMap m_element
Map for elements.
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a tetrahedron.
std::string m_tag
Tag character describing the element.
Definition: MeshElements.h:982
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
static LibUtilities::ShapeType m_type
Element type.
unsigned int m_dim
Dimension of the element.
Definition: MeshElements.h:978
Represents a point in the domain.
Definition: MeshElements.h:74
3D Evenly-spaced points on a Tetrahedron
Definition: PointsType.h:71
unsigned int m_expDim
Dimension of the expansion.
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
Prism(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a prism element.
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
unsigned int GetNumBndryElements()
Returns the total number of elements in the mesh with dimension < expDim.
LibUtilities::PointsType m_edgeCurveType
Distribution of points in edges.
Definition: MeshElements.h:634
boost::shared_ptr< Geometry2D > Geometry2DSharedPtr
Definition: Geometry2D.h:59
Tetrahedron(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a tetrahedron element.
static LibUtilities::ShapeType m_type
Element type.
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
Pyramid(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a pyramidic element.
bool operator==(TriFaceIDs const &p1, TriFaceIDs const &p2)
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
void OrientPrism()
Orient prism to align degenerate vertices.
std::vector< NodeSharedPtr > m_vertex
List of element vertex nodes.
Definition: MeshElements.h:986
boost::shared_ptr< PrismGeom > PrismGeomSharedPtr
Definition: PrismGeom.h:109
Gauss Radau pinned at x=-1, .
Definition: PointsType.h:58
boost::shared_ptr< TetGeom > TetGeomSharedPtr
Definition: TetGeom.h:106
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
boost::shared_ptr< TriGeom > TriGeomSharedPtr
Definition: TriGeom.h:58
std::string GetXmlString(bool doSort=true)
Generate the list of IDs of elements within this composite.
3D Evenly-spaced points on a Prism
Definition: PointsType.h:73
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:312
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
Line(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a line element.
virtual void Complete(int order)
2D Evenly-spaced points on a Triangle
Definition: PointsType.h:70
Represents a face comprised of three or more edges.
Definition: MeshElements.h:352
void Align(vector< int > vertId)
Align this surface to a given vertex ID.
boost::unordered_set< struct TetOrient, TetOrientHash > TetOrientSet
unsigned int GetNumElements()
Returns the total number of elements in the mesh with dimension expDim.
static ElementSharedPtr create(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Creates an instance of this class.
A lightweight struct for dealing with high-order triangle alignment.
std::vector< EdgeSharedPtr > m_edge
List of element edges.
Definition: MeshElements.h:988
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:165
Triangle(ElmtConfig pConf, std::vector< NodeSharedPtr > pNodeList, std::vector< int > pTagList)
Create a triangle element.
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a triangle.
boost::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
Describes the specification for a Basis.
Definition: Basis.h:50
void OrientTet()
Orient tetrahedron to align degenerate vertices.
virtual SpatialDomains::GeometrySharedPtr GetGeom(int coordDim)
Generate a Nektar++ geometry object for this element.
ElementFactory & GetElementFactory()
boost::shared_ptr< PointGeom > PointGeomSharedPtr
Definition: Geometry.h:60
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:50
static unsigned int GetNumNodes(ElmtConfig pConf)
Return the number of nodes defining a quadrilateral.
Base class for element definitions.
Definition: MeshElements.h:647
Provides a generic Factory class.
Definition: NekFactory.hpp:116
boost::shared_ptr< TriExp > TriExpSharedPtr
Definition: TriExp.h:283
ElmtConfig m_conf
Contains configuration of the element.
Definition: MeshElements.h:980