Nektar++
Mesh.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Mesh.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 object.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
38 
41 
42 using namespace std;
43 
44 namespace Nektar
45 {
46 namespace NekMeshUtils
47 {
48 
49 /**
50  * @brief Return the number of elements of the expansion dimension.
51  */
52 unsigned int Mesh::GetNumElements()
53 {
54  return m_element[m_expDim].size();
55 }
56 
57 /**
58  * @brief Return the number of boundary elements (i.e. one below the
59  * expansion dimension).
60  */
61 unsigned int Mesh::GetNumBndryElements()
62 {
63  unsigned int i, nElmt = 0;
64 
65  for (i = 0; i < m_expDim; ++i)
66  nElmt += m_element[i].size();
67 
68  return nElmt;
69 }
70 
71 /**
72  * @brief Return the total number of entities in the mesh (i.e. all
73  * elements, regardless of dimension).
74  */
75 unsigned int Mesh::GetNumEntities()
76 {
77  unsigned int nEnt = 0;
78 
79  for (unsigned int d = 0; d <= m_expDim; ++d)
80  {
81  nEnt += m_element[d].size();
82  }
83 
84  return nEnt;
85 }
86 
87 /**
88  * @brief Convert this mesh into a mesh of uniform polynomial order @p order
89  * with a curve point distribution @p distType.
90  *
91  * This routine adds curvature points into a mesh so that the resulting elements
92  * are all of a uniform order @p order and all high-order vertices are
93  * consistently ordered. It proceeds in a bottom-up fashion:
94  *
95  * - First construct all edge, face and elemental geometry mappings.
96  * - Then call the local MakeOrder functions on each edge, face and element of
97  * dimension Mesh::m_expDim.
98  * - Finally, any boundary elements are updated so that they have the same
99  * interior degrees of freedom as their corresponding edge or face links.
100  */
101 void Mesh::MakeOrder(int order, LibUtilities::PointsType distType)
102 {
103  // Going to make a copy of the curavture information, since this is cheaper
104  // than using Nektar's Geometry objects. Currently, the geometry objects
105  // which make up a 3D element dont use the volume nodes, they are just
106  // stored, so we can get away without copying them.
107 
108  int id = m_vertexSet.size();
109 
110  EdgeSet::iterator eit;
111  FaceSet::iterator fit;
112 
113  std::unordered_map<int, EdgeSharedPtr> edgeCopies;
114  std::unordered_map<int, FaceSharedPtr> faceCopies;
115 
116  // Decide on distribution of points to use for each shape type based on the
117  // input we've been supplied.
118  std::map<LibUtilities::ShapeType, LibUtilities::PointsType> pTypes;
119  if (distType == LibUtilities::ePolyEvenlySpaced)
120  {
128  }
129  else if (distType == LibUtilities::eGaussLobattoLegendre)
130  {
138  }
139  else
140  {
141  ASSERTL1(false, "Mesh::MakeOrder does not support this points type.");
142  }
143 
144  // Begin by copying mesh objects for edges and faces so that we don't affect
145  // any neighbouring elements in the mesh as we process each element. At the
146  // same time we delete the curvature from the original edge and face, which
147  // will be re-added with the MakeOrder routine.
148 
149  // First, we fill in the volume-interior nodes. This preserves the original
150  // curvature of the mesh.
151  const int nElmt = m_element[m_expDim].size();
152  int tmpId = 0;
153  for (int i = 0; i < nElmt; ++i)
154  {
155  if (m_verbose)
156  {
157  LibUtilities::PrintProgressbar(i, nElmt, "MakeOrder: Elements: ");
158  }
159  ElementSharedPtr el = m_element[m_expDim][i];
160  SpatialDomains::GeometrySharedPtr geom = el->GetGeom(m_spaceDim);
161  geom->FillGeom();
162  el->MakeOrder(order, geom, pTypes[el->GetConf().m_e], m_spaceDim,
163  tmpId);
164  }
165 
166  // Now make copies of each of the edges.
167  for (eit = m_edgeSet.begin(); eit != m_edgeSet.end(); eit++)
168  {
169  edgeCopies[(*eit)->m_id] = EdgeSharedPtr(new Edge(*(*eit)));
170  (*eit)->m_edgeNodes.clear();
171  }
172 
173  // Now copy faces. Make sure that this is a "deep copy", so that the face's
174  // edge list corresponds to the copied edges, otherwise we end up in a
175  // non-consistent state.
176  for (fit = m_faceSet.begin(); fit != m_faceSet.end(); fit++)
177  {
178  FaceSharedPtr tmpFace = FaceSharedPtr(new Face(*(*fit)));
179 
180  for (int i = 0; i < tmpFace->m_edgeList.size(); ++i)
181  {
182  tmpFace->m_edgeList[i] = edgeCopies[tmpFace->m_edgeList[i]->m_id];
183  }
184 
185  faceCopies[(*fit)->m_id] = tmpFace;
186  (*fit)->m_faceNodes.clear();
187  }
188 
189  std::unordered_set<int> processedEdges, processedFaces, processedVolumes;
190 
191  // note if CAD previously existed on the face or edge, the new points need
192  // to be projected onto the CAD entity.
193 
194  // Call MakeOrder with our generated geometries on each edge to fill in edge
195  // interior nodes.
196  int ct = 0;
197  for (eit = m_edgeSet.begin(); eit != m_edgeSet.end(); eit++, ct++)
198  {
199  if (m_verbose)
200  {
201  LibUtilities::PrintProgressbar(ct, m_edgeSet.size(),
202  "MakeOrder: Edges: ");
203  }
204  int edgeId = (*eit)->m_id;
205 
206  if (processedEdges.find(edgeId) != processedEdges.end())
207  {
208  continue;
209  }
210 
211  EdgeSharedPtr cpEdge = edgeCopies[edgeId];
212  SpatialDomains::GeometrySharedPtr geom = cpEdge->GetGeom(m_spaceDim);
213  geom->FillGeom();
214 
215  (*eit)->MakeOrder(order, geom, pTypes[LibUtilities::eSegment],
216  m_spaceDim, id);
217  processedEdges.insert(edgeId);
218  }
219 
220  // Call MakeOrder with our generated geometries on each face to fill in face
221  // interior nodes.
222  ct = 0;
223  for (fit = m_faceSet.begin(); fit != m_faceSet.end(); fit++, ct++)
224  {
225  if (m_verbose)
226  {
227  LibUtilities::PrintProgressbar(ct, m_faceSet.size(),
228  "MakeOrder: Faces: ");
229  }
230  int faceId = (*fit)->m_id;
231 
232  if (processedFaces.find(faceId) != processedFaces.end())
233  {
234  continue;
235  }
236 
237  FaceSharedPtr cpFace = faceCopies[faceId];
238  SpatialDomains::GeometrySharedPtr geom = cpFace->GetGeom(m_spaceDim);
239  geom->FillGeom();
240 
241  LibUtilities::ShapeType type = (*fit)->m_vertexList.size() == 3
244  (*fit)->MakeOrder(order, geom, pTypes[type], m_spaceDim, id);
245  processedFaces.insert(faceId);
246  }
247 
248  // Copy curvature into boundary conditions
249  for (int i = 0; i < m_element[1].size(); ++i)
250  {
251  ElementSharedPtr el = m_element[1][i];
252  EdgeSharedPtr edge = el->GetEdgeLink();
253 
254  if (!edge)
255  {
256  continue;
257  }
258 
259  // Copy face curvature
260  el->MakeOrder(order, SpatialDomains::GeometrySharedPtr(),
261  pTypes[el->GetConf().m_e], m_spaceDim, id, true);
262  el->SetVolumeNodes(edge->m_edgeNodes);
263  }
264 
265  for (int i = 0; i < m_element[2].size(); ++i)
266  {
267  ElementSharedPtr el = m_element[2][i];
268  FaceSharedPtr face = el->GetFaceLink();
269 
270  if (!face)
271  {
272  continue;
273  }
274 
275  // Copy face curvature
276  el->MakeOrder(order, SpatialDomains::GeometrySharedPtr(),
277  pTypes[el->GetConf().m_e], m_spaceDim, id, true);
278  el->SetVolumeNodes(face->m_faceNodes);
279  }
280 
281  for (int i = 0; i < nElmt; ++i)
282  {
283  vector<NodeSharedPtr> tmp = m_element[m_expDim][i]->GetVolumeNodes();
284  for (int j = 0; j < tmp.size(); ++j)
285  {
286  tmp[j]->m_id = id++;
287  }
288  }
289 
290  if (m_verbose)
291  {
292  cout << endl;
293  }
294 }
295 
296 /**
297  * @brief Print out basic statistics of this mesh.
298  */
299 void Mesh::PrintStats(std::ostream &out)
300 {
301  out << "Mesh statistics" << std::endl
302  << "---------------" << std::endl
303  << std::endl;
304 
305  out << "Mesh dimension : " << m_spaceDim << std::endl
306  << "Element dimension : " << m_expDim << std::endl
307  << "Has CAD attached : " << (m_cad ? "yes" : "no") << std::endl
308  << "Node count : " << m_vertexSet.size() << std::endl;
309 
310  if (m_edgeSet.size() > 0)
311  {
312  out << "Edge count : " << m_edgeSet.size() << std::endl;
313  }
314 
315  if (m_faceSet.size() > 0)
316  {
317  out << "Face count : " << m_faceSet.size() << std::endl;
318  }
319 
320  out << "Elements : " << m_element[m_expDim].size() << std::endl
321  << "Bnd elements : " << m_element[m_expDim - 1].size()
322  << std::endl;
323 
324  // Print out number of composites
325 
326  out << "Number of composites : " << m_composite.size() << std::endl;
327 
328  // Calculate domain extent
329  auto extent = m_element[m_expDim][0]->GetBoundingBox();
330  for (int i = 1; i < m_element[m_expDim].size(); ++i)
331  {
332  auto el = m_element[m_expDim][i]->GetBoundingBox();
333  extent.first.m_x = std::min(extent.first.m_x, el.first.m_x);
334  extent.first.m_y = std::min(extent.first.m_y, el.first.m_y);
335  extent.first.m_z = std::min(extent.first.m_z, el.first.m_z);
336  extent.second.m_x = std::max(extent.second.m_x, el.second.m_x);
337  extent.second.m_y = std::max(extent.second.m_y, el.second.m_y);
338  extent.second.m_z = std::max(extent.second.m_z, el.second.m_z);
339  }
340 
341  out << "Lower mesh extent : " << extent.first.m_x << " "
342  << extent.first.m_y << " " << extent.first.m_z << std::endl
343  << "Upper mesh extent : " << extent.second.m_x << " "
344  << extent.second.m_y << " " << extent.second.m_z << std::endl;
345 
346  std::map<LibUtilities::ShapeType, std::pair<int, int>> elmtCounts;
347 
348  for (int i = 1; i < LibUtilities::SIZE_ShapeType; ++i)
349  {
350  elmtCounts[(LibUtilities::ShapeType)i] = std::make_pair(0, 0);
351  }
352 
353  for (int dim = 0; dim <= 3; ++dim)
354  {
355  for (auto &elmt : m_element[dim])
356  {
357  auto &counts = elmtCounts[elmt->GetShapeType()];
358 
359  if (elmt->IsDeformed())
360  {
361  counts.second++;
362  }
363  else
364  {
365  counts.first++;
366  }
367  }
368  }
369 
370  out << std::endl << "Element counts (regular/deformed/total):" << std::endl;
371  for (int i = 1; i < LibUtilities::SIZE_ShapeType; ++i)
372  {
373  auto shapeType = (LibUtilities::ShapeType)i;
374  auto counts = elmtCounts[shapeType];
375 
376  if (counts.first + counts.second == 0)
377  {
378  continue;
379  }
380 
381  out << " " << std::setw(14)
383  << setw(12) << counts.first << " " << setw(12) << counts.second
384  << " " << setw(12) << counts.first + counts.second << std::endl;
385  }
386 }
387 
388 } // namespace NekMeshUtils
389 } // namespace Nektar
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
Definition: Progressbar.hpp:67
Represents an edge which joins two points.
Definition: Edge.h:58
Represents a face comprised of three or more edges.
Definition: Face.h:63
STL namespace.
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
const char *const ShapeTypeMap[]
Definition: ShapeType.hpp:67
std::shared_ptr< Face > FaceSharedPtr
Definition: Face.h:155
1D Evenly-spaced points using Lagrange polynomial
Definition: PointsType.h:64
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
3D Nodal Electrostatic Points on a Tetrahedron
Definition: PointsType.h:73
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
3D Evenly-spaced points on a Tetrahedron
Definition: PointsType.h:72
3D Evenly-spaced points on a Prism
Definition: PointsType.h:74
2D Evenly-spaced points on a Triangle
Definition: PointsType.h:71
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:69
3D electrostatically spaced points on a Prism
Definition: PointsType.h:75