1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 #ifndef MINT_UNSTRUCTUREDMESH_HPP_
7 #define MINT_UNSTRUCTUREDMESH_HPP_
8
9 // Axom includes
10 #include "axom/core/Macros.hpp"
11 #include "axom/core/Types.hpp"
12
13 // Mint includes
14 #include "axom/mint/config.hpp"
15 #include "axom/mint/mesh/CellTypes.hpp"
16 #include "axom/mint/mesh/ConnectivityArray.hpp"
17 #include "axom/mint/mesh/Mesh.hpp"
18 #include "axom/mint/mesh/MeshCoordinates.hpp"
19 #include "axom/mint/mesh/MeshTypes.hpp"
20 #include "axom/mint/mesh/internal/MeshHelpers.hpp"
21
22 // Slic includes
23 #include "axom/slic/interface/slic.hpp"
24
25 // C/C++ includes
26 #include <cstring> // for std::memcpy
27
28 namespace axom
29 {
30 namespace mint
31 {
32 enum Topology
33 {
34 SINGLE_SHAPE,
35 MIXED_SHAPE
36 };
37
38 template <Topology TOPO>
39 struct topology_traits
40 { };
41
42 template <>
43 struct topology_traits<SINGLE_SHAPE>
44 {
45 constexpr static ConnectivityType cell_to_nodes = NO_INDIRECTION;
46 constexpr static ConnectivityType cell_to_faces = NO_INDIRECTION;
47 constexpr static ConnectivityType face_to_nodes = NO_INDIRECTION;
48 };
49
50 template <>
51 struct topology_traits<MIXED_SHAPE>
52 {
53 constexpr static ConnectivityType cell_to_nodes = TYPED_INDIRECTION;
54 constexpr static ConnectivityType cell_to_faces = INDIRECTION;
55 constexpr static ConnectivityType face_to_nodes = TYPED_INDIRECTION;
56 };
57
58 /*!
59 * \class UnstructuredMesh
60 *
61 * \brief Provides the ability to store and operate on Unstructured meshes.
62 *
63 * An <em> unstructured mesh </em> stores both node and topology information
64 * explicitly. This allows the flexibility of discretizing the solution
65 * domain using a variety of cell types not just quadrilateral (in 2D) or
66 * hexahedral (in 3D) cells. Due to this added flexibility, the use of
67 * <em> unstructured meshes </em> is more common when dealing with complex
68 * geometries. However, <em> unstructured meshes </em> require additional
69 * storage and generally incur some performance penalty to store, create and
70 * access mesh topology information respectively.
71 *
72 * Mint classifies <em> unstructured meshes </em> in two basic types based on
73 * the underlying mesh topology:
74 *
75 * * <b> Single Shape Topology </b>
76 *
77 * In this case, the <em> unstructured mesh </em> consists of a single cell
78 * type, e.g., a quad or triangle mesh in 2D, or, a hex or tet mesh in 3D.
79 * In this case the underlying implementation is optimized for the
80 * specified cell type (specified in the constructor).
81 *
82 * * <b> Mixed Shape Topology </b>
83 *
84 * When <em> mixed cell topology </em> is specified, the <em> unstructured
85 * mesh </em> can be composed of any of the supported cell types, e.g.,
86 * a mesh consisting of both quads and triangles. This mode incurs
87 * additional overhead for storage and access to mesh topology information,
88 * since it requires indirection.
89 *
90 * The list of supported cell types for an <em> unstructured mesh </em> is
91 * available in CellTypes.hpp
92 *
93 * An UnstructuredMesh object may be constructed using (a) native storage,
94 * (b) external storage, or, (c) with Sidre storage when Mint is compiled
95 * with Sidre support:
96 *
97 * * <b> Native Storage </b> <br />
98 *
99 * When using native storage, the Unstructured object owns all memory
100 * associated with the particle data. The storage can grow dynamically as
101 * needed by the application, i.e., adding more nodes/cells. Once the
102 * mesh object goes out-of-scope, all memory associated with it is
103 * returned to the system.
104 *
105 * * <b> External Storage </b> <br />
106 *
107 * An UnstructuredMesh may also be constructed from external, user-supplied
108 * buffers. In this case, all memory associated with the mesh data
109 * is owned by the caller. Consequently, the mesh cannot grow dynamically.
110 * All calls to resize(), append(), etc. will fail with an error.
111 *
112 * * <b> Sidre </b> <br />
113 *
114 * An UnstructuredMesh may also be constructed using Sidre as the back-end
115 * data-store manager. The mesh data is laid out in Sidre according to the
116 * <a href="http://llnl-conduit.readthedocs.io/en/latest/"> computational
117 * mesh blueprint </a> conventions. In this case, all operations are
118 * supported, including dynamically resizing the mesh and growing the
119 * associated storage as needed. However, Sidre owns all the memory. Once the
120 * mesh object goes out-of-scope, the data remains persistent in Sidre.
121 *
122 * \see mint::Mesh
123 * \see mint::CellTypes
124 */
125 template <Topology TOPO>
126 class UnstructuredMesh : public Mesh
127 {
128 AXOM_STATIC_ASSERT(TOPO == SINGLE_SHAPE || TOPO == MIXED_SHAPE);
129
130 public:
131 /*! \brief The types for face-cell and cell-face connectivity.
132 *
133 * Usually, each face will connect two cells. The exceptions are
134 * - edge faces, which will connect to one cell. The other will be -1.
135 * - some faces in a malformed mesh, which may join more than two cells.
136 * The concensus is that storing such a non-manifold mesh is not useful
137 * so we only store the first two incident cells and return an error.
138 *
139 * Face types are stored in the face-node connectivity.
140 */
141 using CellToNodeConnectivity =
142 ConnectivityArray<topology_traits<TOPO>::cell_to_nodes>;
143 using CellToFaceConnectivity =
144 ConnectivityArray<topology_traits<TOPO>::cell_to_faces>;
145 using FaceToCellConnectivity = ConnectivityArray<NO_INDIRECTION>;
146 using FaceToNodeConnectivity =
147 ConnectivityArray<topology_traits<TOPO>::face_to_nodes>;
148
149 /*!
150 * \brief Default constructor. Disabled.
151 */
152 UnstructuredMesh() = delete;
153
154 /// \name Native Storage Constructors
155 /// @{
156
157 /*!
158 * \brief Constructs an Unstructured single topology mesh.
159 *
160 * \param [in] ndims the number of dimensions.
161 * \param [in] cell_type the cell type of the mesh.
162 * \param [in] node_capacity the number of nodes to allocate space for.
163 * \param [in] cell_capacity the number of cells to allocate space for.
164 *
165 * \note This constructor is only active when TOPO == SINGLE_SHAPE.
166 *
167 * \post getCellType() == cell_type
168 * \post getNumberOfNodes() == 0
169 * \post getNumberOfCells() == 0
170 */
UnstructuredMesh(int ndims,CellType cell_type,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT)171 UnstructuredMesh(int ndims,
172 CellType cell_type,
173 IndexType node_capacity = USE_DEFAULT,
174 IndexType cell_capacity = USE_DEFAULT)
175 : Mesh(ndims, UNSTRUCTURED_MESH)
176 , m_coordinates(new MeshCoordinates(ndims, 0, node_capacity))
177 , m_cell_to_node(new CellToNodeConnectivity(cell_type, cell_capacity))
178 , m_cell_to_face(initializeCellToFace(cell_type))
179 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
180 , m_face_to_node(initializeFaceToNode(cell_type))
181 {
182 AXOM_STATIC_ASSERT_MSG(
183 TOPO == SINGLE_SHAPE,
184 "This constructor is only active for single topology meshes.");
185
186 SLIC_ERROR_IF(
187 cell_type == PRISM || cell_type == PYRAMID,
188 "Single shape unstructured meshes do not support prisms or pyramids");
189
190 initialize();
191 }
192
193 /*!
194 * \brief Constructs an Unstructured mixed topology mesh.
195 *
196 * \param [in] ndims the number of dimensions.
197 * \param [in] node_capacity the number of nodes to allocate space for.
198 * \param [in] cell_capacity the number of cells to allocate space for.
199 * \param [in] connectivity_capacity the number of vertices to allocate space
200 * for in the cell connectivity array.
201 *
202 * \note This constructor is only active when TOPO == MIXED_SHAPE.
203 *
204 * \post getCellType() == UNDEFINED_CELL
205 * \post getNumberOfNodes() == 0
206 * \post getNumberOfCells() == 0
207 */
UnstructuredMesh(int ndims,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT,IndexType connectivity_capacity=USE_DEFAULT)208 UnstructuredMesh(int ndims,
209 IndexType node_capacity = USE_DEFAULT,
210 IndexType cell_capacity = USE_DEFAULT,
211 IndexType connectivity_capacity = USE_DEFAULT)
212 : Mesh(ndims, UNSTRUCTURED_MESH)
213 , m_coordinates(new MeshCoordinates(ndims, 0, node_capacity))
214 , m_cell_to_node(
215 new CellToNodeConnectivity(cell_capacity, connectivity_capacity))
216 , m_cell_to_face(initializeCellToFace())
217 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
218 , m_face_to_node(initializeFaceToNode())
219 {
220 AXOM_STATIC_ASSERT_MSG(
221 TOPO == MIXED_SHAPE,
222 "This constructor is only active for mixed topology meshes.");
223
224 m_has_mixed_topology = true;
225 initialize();
226 }
227
228 /// @}
229
230 /// \name External Storage Constructors
231 /// @{
232
233 /*!
234 * \brief Constructs an Unstructured single topology mesh using the provided
235 * external buffers.
236 *
237 * \param [in] cell_type the cell type of the mesh.
238 * \param [in] n_cells the number of cells in the mesh.
239 * \param [in] cell_capacity max number of cells the mesh is able to hold.
240 * \param [in] connectivity the cell connectivity array.
241 * \param [in] n_nodes the number of nodes in the mesh.
242 * \param [in] node_capacity max number of nodes the mesh is able to hold
243 * \param [in] x pointer to the x-coordinates
244 * \param [in] y pointer to the y-coordinates (required only for 2D and 3D)
245 * \param [in] z pointer to the z-coordinates (required only for 3D)
246 *
247 * \note The length of the connectivity array must be at least
248 * cell_capacity * getCellInfo( cell_type ).num_nodes.
249 * \note The provided coordinate arrays have to be of length at least
250 * node_capacity.
251 *
252 * \note This constructor is only supported when TOPO == SINGLE_SHAPE.
253 *
254 * \post getCellType() == cell_type
255 * \post getNumberOfCells() == n_cells
256 * \post getCellCapacity == cell_capacity
257 * \post getNumberOfNodes() == n_nodes
258 * \post getNodeCapacity() == node_capacity
259 * \post isExternal() == true
260 */
UnstructuredMesh(CellType cell_type,IndexType n_cells,IndexType cell_capacity,IndexType * connectivity,IndexType n_nodes,IndexType node_capacity,double * x,double * y=nullptr,double * z=nullptr)261 UnstructuredMesh(CellType cell_type,
262 IndexType n_cells,
263 IndexType cell_capacity,
264 IndexType* connectivity,
265 IndexType n_nodes,
266 IndexType node_capacity,
267 double* x,
268 double* y = nullptr,
269 double* z = nullptr)
270 : Mesh(internal::dim(x, y, z), UNSTRUCTURED_MESH)
271 , m_coordinates(new MeshCoordinates(n_nodes, node_capacity, x, y, z))
272 , m_cell_to_node(
273 new CellToNodeConnectivity(cell_type, n_cells, connectivity, cell_capacity))
274 , m_cell_to_face(initializeCellToFace(cell_type))
275 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
276 , m_face_to_node(initializeFaceToNode(cell_type))
277 {
278 AXOM_STATIC_ASSERT_MSG(
279 TOPO == SINGLE_SHAPE,
280 "This constructor is only active for single topology meshes.");
281
282 SLIC_ERROR_IF(
283 cell_type == PRISM || cell_type == PYRAMID,
284 "Single shape unstructured meshes do not support prisms or pyramids");
285
286 SLIC_ASSERT(x != nullptr);
287 SLIC_ASSERT(m_ndims < 2 || y != nullptr);
288 SLIC_ASSERT(m_ndims < 3 || z != nullptr);
289
290 initialize();
291 }
292
293 /*!
294 * \brief Constructs an Unstructured single topology mesh using the provided
295 * external buffers.
296 *
297 * \param [in] cell_type the cell type of the mesh
298 * \param [in] n_cells the number of cells in the mesh
299 * \param [in] connectivity the cell connectivity array.
300 * \param [in] n_nodes the number of nodes in the mesh
301 * \param [in] x pointer to the x-coordinates
302 * \param [in] y pointer to the y-coordinates (required only for 2D or 3D)
303 * \param [in] z pointer to the z-coordinates (required only for 3D)
304 *
305 * \note This constructor is only supported when TOPO == SINGLE_SHAPE.
306 *
307 * \post getCellType() == cell_type
308 * \post getNumberOfCells() == n_cells
309 * \post getCellCapacity == n_cells
310 * \post getNumberOfNodes() == n_nodes
311 * \post getNodeCapacity() == n_nodes
312 * \post isExternal() == true
313 */
UnstructuredMesh(CellType cell_type,IndexType n_cells,IndexType * connectivity,IndexType n_nodes,double * x,double * y=nullptr,double * z=nullptr)314 UnstructuredMesh(CellType cell_type,
315 IndexType n_cells,
316 IndexType* connectivity,
317 IndexType n_nodes,
318 double* x,
319 double* y = nullptr,
320 double* z = nullptr)
321 : UnstructuredMesh(cell_type,
322 n_cells,
323 n_cells,
324 connectivity,
325 n_nodes,
326 n_nodes,
327 x,
328 y,
329 z)
330 { }
331
332 /*!
333 * \brief Constructs an Unstructured mixed topology mesh using the provided
334 * external buffers.
335 *
336 * \param [in] n_cells the number of cells in the mesh.
337 * \param [in] cell_capacity max number of cells the mesh is able to hold
338 * \param [in] connectivity_capacity max capacity of the connectivity array
339 * \param [in] connectivity the connectivity array.
340 * \param [in] offsets array of cell offsets (of length cell_capacity + 1)
341 * \param [in] types array of cell types (of length cell_capacity)
342 * \param [in] n_nodes the number of nodes in the mesh.
343 * \param [in] node_capacity max number of nodes the mesh can hold
344 * \param [in] x pointer to the x-coordinates
345 * \param [in] y pointer to the y-coordinates (required only for 2D and 3D)
346 * \param [in] z pointer to the z-coordinates (required only 3D)
347 *
348 * \note The supplied connectivity array must have a length that is at least
349 * equal to the specified connectivity_capacity.
350 * \note the provided coordinate arrays are to be of length at least
351 * node_capacity.
352 *
353 * \note This constructor is only supported when TOPO == MIXED_SHAPE.
354 *
355 * \post getCellType() == UNDEFINED_CELL
356 * \post getNumberOfCells() == n_cells
357 * \post getCellCapacity == cell_capacity
358 * \post getNumberOfNodes() == n_nodes
359 * \post getNodeCapacity() == node_capacity
360 * \post isExternal() == true
361 */
UnstructuredMesh(IndexType n_cells,IndexType cell_capacity,IndexType connectivity_capacity,IndexType * connectivity,IndexType * offsets,CellType * types,IndexType n_nodes,IndexType node_capacity,double * x,double * y=nullptr,double * z=nullptr)362 UnstructuredMesh(IndexType n_cells,
363 IndexType cell_capacity,
364 IndexType connectivity_capacity,
365 IndexType* connectivity,
366 IndexType* offsets,
367 CellType* types,
368 IndexType n_nodes,
369 IndexType node_capacity,
370 double* x,
371 double* y = nullptr,
372 double* z = nullptr)
373 : Mesh(internal::dim(x, y, z), UNSTRUCTURED_MESH)
374 , m_coordinates(new MeshCoordinates(n_nodes, node_capacity, x, y, z))
375 , m_cell_to_node(new CellToNodeConnectivity(n_cells,
376 connectivity,
377 offsets,
378 types,
379 cell_capacity,
380 connectivity_capacity))
381 , m_cell_to_face(initializeCellToFace())
382 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
383 , m_face_to_node(initializeFaceToNode())
384 {
385 AXOM_STATIC_ASSERT_MSG(
386 TOPO == MIXED_SHAPE,
387 "This constructor is only active for mixed topology meshes.");
388
389 SLIC_ASSERT(x != nullptr);
390 SLIC_ASSERT(m_ndims < 2 || y != nullptr);
391 SLIC_ASSERT(m_ndims < 3 || z != nullptr);
392
393 m_has_mixed_topology = true;
394 initialize();
395 }
396
397 /*!
398 * \brief Constructs an Unstructured mixed topology mesh using the provided
399 * external mesh buffers.
400 *
401 * \param [in] n_cells the number of cells in the mesh.
402 * \param [in] connectivity_size the size of the connectivity array
403 * \param [in] connectivity the connectivity array
404 * \param [in] offsets array of cell offsets (of length n_cells+1)
405 * \param [in] types array of cell types (of length n_cells)
406 * \param [in] n_nodes the number of nodes in the mesh
407 * \param [in] x pointer to the x-coordinates
408 * \param [in] y pointer to the y-coordinates (required only for 2D and 3D)
409 * \param [in] z pointer to the z-coordinates (required only for 3D)
410 *
411 * \note The supplied connectivity array must have a length that is at least
412 * equal to the specified connectivity_capacity.
413 * \note the provided coordinate arrays are to be of length at least
414 * node_capacity.
415 *
416 * \post getCellType() == UNDEFINED_CELL
417 * \post getNumberOfCells() == n_cells
418 * \post getCellCapacity == n_cells
419 * \post getNumberOfNodes() == n_nodes
420 * \post getNodeCapacity() == n_cells
421 * \post isExternal() == true
422 */
UnstructuredMesh(IndexType n_cells,IndexType connectivity_size,IndexType * connectivity,IndexType * offsets,CellType * types,IndexType n_nodes,double * x,double * y=nullptr,double * z=nullptr)423 UnstructuredMesh(IndexType n_cells,
424 IndexType connectivity_size,
425 IndexType* connectivity,
426 IndexType* offsets,
427 CellType* types,
428 IndexType n_nodes,
429 double* x,
430 double* y = nullptr,
431 double* z = nullptr)
432 : UnstructuredMesh(n_cells,
433 n_cells,
434 connectivity_size,
435 connectivity,
436 offsets,
437 types,
438 n_nodes,
439 n_nodes,
440 x,
441 y,
442 z)
443 { }
444
445 /// @}
446
447 /// \name Sidre Storage Constructors
448 /// @{
449
450 #ifdef AXOM_MINT_USE_SIDRE
451
452 /*!
453 * \brief Creates an UnstructuredMesh instance from a given Sidre group that
454 * holds mesh data for an unstructured mesh according to the conventions
455 * described in the computational mesh blueprint.
456 *
457 * \param [in] group the sidre::Group to use.
458 * \param [in] topo optional argument specifying the name of the topology
459 * associated with this Mesh instance.
460 *
461 * \note If a topology name is not provided, the implementation will construct
462 * a mesh based on the 1st topology group under the parent "topologies"
463 * group.
464 *
465 * \pre group != nullptr.
466 * \pre blueprint::isValidRootGroup( group ) == true
467 * \post isInSidre() == true
468 */
UnstructuredMesh(sidre::Group * group,const std::string & topo="")469 UnstructuredMesh(sidre::Group* group, const std::string& topo = "")
470 : Mesh(group, topo)
471 , m_coordinates(new MeshCoordinates(getCoordsetGroup()))
472 , m_cell_to_node(new CellToNodeConnectivity(getTopologyGroup()))
473 , m_cell_to_face(nullptr)
474 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
475 , m_face_to_node(nullptr)
476 {
477 SLIC_ERROR_IF(
478 m_type != UNSTRUCTURED_MESH,
479 "Supplied sidre::Group does not correspond to a UnstructuredMesh.");
480
481 if(TOPO == MIXED_SHAPE)
482 {
483 m_has_mixed_topology = true;
484 m_cell_to_face = initializeCellToFace();
485 m_face_to_node = initializeFaceToNode();
486 }
487 else
488 {
489 SLIC_ERROR_IF(
490 getCellType() == PRISM || getCellType() == PYRAMID,
491 "Single shape unstructured meshes do not support prisms or pyramids");
492 m_cell_to_face = initializeCellToFace(getCellType());
493 m_face_to_node = initializeFaceToNode(getCellType());
494 }
495
496 initialize();
497 }
498
499 /*!
500 * \brief Creates an UnstructuredMesh instance on an empty Sidre group.
501 *
502 * \param [in] ndims the number of dimensions.
503 * \param [in] cell_type the cell type of the mesh.
504 * \param [in] group the sidre::Group to use.
505 * \param [in] topo the name of the associated topology group.
506 * \param [in] coordset the name of the associated coordset group.
507 * \param [in] node_capacity the number of nodes to allocate space for.
508 * \param [in] cell_capacity the number of cells to allocate space for.
509 * \param [in] connectivity_capacity the number of vertices to allocate space
510 * for in the cell connectivity array.
511 *
512 * \note If a topology and coordset name are not provided a default name is
513 * used by the implementation.
514 * \note The first two constructors are only active when
515 * TOPO == SINGLE_SHAPE and the last two are active only when
516 * TOPO == MIXED_SHAPE.
517 *
518 * \pre group != nullptr.
519 * \pre group->getNumGroups() == 0
520 * \pre group->getNumViews() == 0
521 * \post blueprint::isValidRootGroup( group )
522 * \post getNumberOfNodes() == 0
523 * \post getNumberOfCells() == 0
524 * \post isInSidre() == true
525 */
526 /// @{
527
UnstructuredMesh(int ndims,CellType cell_type,sidre::Group * group,const std::string & topo,const std::string & coordset,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT)528 UnstructuredMesh(int ndims,
529 CellType cell_type,
530 sidre::Group* group,
531 const std::string& topo,
532 const std::string& coordset,
533 IndexType node_capacity = USE_DEFAULT,
534 IndexType cell_capacity = USE_DEFAULT)
535 : Mesh(ndims, UNSTRUCTURED_MESH, group, topo, coordset)
536 , m_coordinates(
537 new MeshCoordinates(getCoordsetGroup(), ndims, 0, node_capacity))
538 , m_cell_to_node(new CellToNodeConnectivity(cell_type,
539 getTopologyGroup(),
540 getCoordsetName(),
541 cell_capacity))
542 , m_cell_to_face(initializeCellToFace(cell_type))
543 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
544 , m_face_to_node(initializeFaceToNode(cell_type))
545 {
546 AXOM_STATIC_ASSERT_MSG(
547 TOPO == SINGLE_SHAPE,
548 "This constructor is only active for single topology meshes.");
549
550 SLIC_ERROR_IF(
551 cell_type == PRISM || cell_type == PYRAMID,
552 "Single shape unstructured meshes do not support prisms or pyramids");
553
554 initialize();
555 }
556
UnstructuredMesh(int ndims,CellType cell_type,sidre::Group * group,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT)557 UnstructuredMesh(int ndims,
558 CellType cell_type,
559 sidre::Group* group,
560 IndexType node_capacity = USE_DEFAULT,
561 IndexType cell_capacity = USE_DEFAULT)
562 : UnstructuredMesh(ndims, cell_type, group, "", "", node_capacity, cell_capacity)
563 { }
564
UnstructuredMesh(int ndims,sidre::Group * group,const std::string & topo,const std::string & coordset,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT,IndexType connectivity_capacity=USE_DEFAULT)565 UnstructuredMesh(int ndims,
566 sidre::Group* group,
567 const std::string& topo,
568 const std::string& coordset,
569 IndexType node_capacity = USE_DEFAULT,
570 IndexType cell_capacity = USE_DEFAULT,
571 IndexType connectivity_capacity = USE_DEFAULT)
572 : Mesh(ndims, UNSTRUCTURED_MESH, group, topo, coordset)
573 , m_coordinates(
574 new MeshCoordinates(getCoordsetGroup(), ndims, 0, node_capacity))
575 , m_cell_to_node(new CellToNodeConnectivity(getTopologyGroup(),
576 getCoordsetName(),
577 cell_capacity,
578 connectivity_capacity))
579 , m_cell_to_face(initializeCellToFace())
580 , m_face_to_cell(new FaceToCellConnectivity(2, 0))
581 , m_face_to_node(initializeFaceToNode())
582 {
583 AXOM_STATIC_ASSERT_MSG(
584 TOPO == MIXED_SHAPE,
585 "This constructor is only active for mixed topology meshes.");
586
587 m_has_mixed_topology = true;
588 initialize();
589 }
590
UnstructuredMesh(int ndims,sidre::Group * group,IndexType node_capacity=USE_DEFAULT,IndexType cell_capacity=USE_DEFAULT,IndexType connectivity_capacity=USE_DEFAULT)591 UnstructuredMesh(int ndims,
592 sidre::Group* group,
593 IndexType node_capacity = USE_DEFAULT,
594 IndexType cell_capacity = USE_DEFAULT,
595 IndexType connectivity_capacity = USE_DEFAULT)
596 : UnstructuredMesh(ndims,
597 group,
598 "",
599 "",
600 node_capacity,
601 cell_capacity,
602 connectivity_capacity)
603 { }
604
605 /// @}
606
607 #endif /* AXOM_MINT_USE_SIDRE */
608
609 /// @}
610
611 /// \name Virtual methods
612 /// @{
613
614 /*!
615 * \brief Destructor, deletes the MeshCoordinates and ConnectivityArray.
616 */
~UnstructuredMesh()617 virtual ~UnstructuredMesh()
618 {
619 delete m_coordinates;
620 m_coordinates = nullptr;
621
622 delete m_cell_to_node;
623 m_cell_to_node = nullptr;
624
625 delete m_cell_to_face;
626 m_cell_to_face = nullptr;
627
628 delete m_face_to_cell;
629 m_face_to_cell = nullptr;
630
631 delete m_face_to_node;
632 m_face_to_node = nullptr;
633 }
634
635 /// \name Cells
636 /// @{
637
638 /*!
639 * \brief Return the number of cells in the mesh.
640 */
getNumberOfCells() const641 virtual IndexType getNumberOfCells() const final override
642 {
643 return m_cell_to_node->getNumberOfIDs();
644 }
645
646 /*!
647 * \brief Return the capacity for cells.
648 */
getCellCapacity() const649 virtual IndexType getCellCapacity() const final override
650 {
651 return m_cell_to_node->getIDCapacity();
652 }
653
654 /*!
655 * \brief Return the type of the given cell.
656 *
657 * \param [in] cellID the ID of the cell in question, this parameter is
658 * ignored if TOPO == SINGLE_SHAPE. If TOPO == MIXED_SHAPE and no
659 * cellID is provided the returned type is UNDEFINED_CELL.
660 *
661 * \pre 0 <= cellID < getNumberOfCells()
662 */
getCellType(IndexType cellID=-1) const663 virtual CellType getCellType(IndexType cellID = -1) const final override
664 {
665 return m_cell_to_node->getIDType(cellID);
666 }
667
668 /*!
669 * \brief Return the number of nodes associated with the given cell.
670 *
671 * \param [in] cellID the ID of the cell in question, this parameter is
672 * ignored if TOPO == SINGLE_SHAPE.
673 *
674 * \pre 0 <= cellID < getNumberOfCells()
675 */
getNumberOfCellNodes(IndexType cellID=0) const676 virtual IndexType getNumberOfCellNodes(IndexType cellID = 0) const final override
677 {
678 return m_cell_to_node->getNumberOfValuesForID(cellID);
679 }
680
681 /*!
682 * \brief Copy the connectivity of the given cell into the provided buffer.
683 * The buffer must be of length at least getNumberOfCellNodes( cellID ).
684 *
685 * \param [in] cellID the ID of the cell in question.
686 * \param [out] nodes the buffer into which the connectivity is copied.
687 *
688 * \return The number of nodes for the given cell.
689 *
690 * \pre nodes != nullptr
691 * \pre 0 <= cellID < getNumberOfCells()
692 */
getCellNodeIDs(IndexType cellID,IndexType * nodes) const693 virtual IndexType getCellNodeIDs(IndexType cellID,
694 IndexType* nodes) const final override
695 {
696 SLIC_ASSERT(nodes != nullptr);
697 const IndexType n_nodes = getNumberOfCellNodes(cellID);
698 std::memcpy(nodes, getCellNodeIDs(cellID), n_nodes * sizeof(IndexType));
699 return n_nodes;
700 }
701
702 /*!
703 * \brief Return the number of faces associated with the given cell.
704 *
705 * \param [in] cellID the ID of the cell in question.
706 *
707 * \note Codes must call initializeFaceConnectivity() before calling
708 * this method.
709 */
getNumberOfCellFaces(IndexType cellID=0) const710 virtual IndexType getNumberOfCellFaces(IndexType cellID = 0) const final override
711 {
712 return getCellInfo(getCellType(cellID)).num_faces;
713 }
714
715 /*!
716 * \brief Copy the face IDs of the given cell into the provided buffer.
717 * The buffer must be of length at least getNumberOfCellFaces( cellID ).
718 *
719 * \param [in] cellID the ID of the cell in question
720 * \param [out] faces the buffer into which the face IDs are copied.
721 *
722 * \return The number of faces for the given cell.
723 *
724 * \note Codes must call initializeFaceConnectivity() before calling
725 * this method.
726 *
727 * \pre faces != nullptr
728 * \pre 0 <= cellID < getNumberOfCells()
729 */
getCellFaceIDs(IndexType cellID,IndexType * faces) const730 virtual IndexType getCellFaceIDs(IndexType cellID,
731 IndexType* faces) const final override
732 {
733 SLIC_ASSERT(faces != nullptr);
734 const IndexType n_faces = getNumberOfCellFaces(cellID);
735 std::memcpy(faces, getCellFaceIDs(cellID), n_faces * sizeof(IndexType));
736 return n_faces;
737 }
738
739 /// @}
740
741 /// \name Nodes
742 /// @{
743
744 /*!
745 * \brief Return the number of nodes in the mesh.
746 */
getNumberOfNodes() const747 virtual IndexType getNumberOfNodes() const final override
748 {
749 return m_coordinates->numNodes();
750 }
751
752 /*!
753 * \brief Return the capacity for nodes.
754 */
getNodeCapacity() const755 virtual IndexType getNodeCapacity() const final override
756 {
757 return m_coordinates->capacity();
758 }
759
760 /*!
761 * \brief Copy the coordinates of the given node into the provided buffer.
762 *
763 * \param [in] nodeID the ID of the node in question.
764 * \param [in] coords the buffer to copy the coordinates into, of length at
765 * least getDimension().
766 *
767 * \pre 0 <= nodeID < getNumberOfNodes()
768 * \pre coords != nullptr
769 */
getNode(IndexType nodeID,double * coords) const770 virtual void getNode(IndexType nodeID, double* coords) const final override
771 {
772 m_coordinates->getCoordinates(nodeID, coords);
773 }
774
775 /*!
776 * \brief Return a pointer to the array of nodal coordinates of the
777 * given dimension.
778 *
779 * \param [in] dim the dimension to return.
780 *
781 * \pre 0 <= dim < getDimension()
782 */
783 /// @{
784
getCoordinateArray(int dim)785 virtual double* getCoordinateArray(int dim) final override
786 {
787 return m_coordinates->getCoordinateArray(dim);
788 }
789
getCoordinateArray(int dim) const790 virtual const double* getCoordinateArray(int dim) const final override
791 {
792 return m_coordinates->getCoordinateArray(dim);
793 }
794
795 /// @}
796
797 /// @}
798
799 /// \name Faces
800 /// @{
801
802 /*!
803 * \brief Return the number of faces in the mesh.
804 *
805 * \note Codes must call initializeFaceConnectivity() before calling
806 * this method.
807 */
getNumberOfFaces() const808 virtual IndexType getNumberOfFaces() const final override
809 {
810 return m_face_to_cell->getNumberOfIDs();
811 }
812
813 /*!
814 * \brief Return the capacity for faces.
815 *
816 * \note Codes must call initializeFaceConnectivity() before calling
817 * this method.
818 */
getFaceCapacity() const819 virtual IndexType getFaceCapacity() const final override
820 {
821 return m_face_to_cell->getIDCapacity();
822 }
823
824 /*!
825 * \brief Return the type of the given face.
826 *
827 * \param [in] faceID the ID of the face in question.
828 *
829 * \note Codes must call initializeFaceConnectivity() before calling
830 * this method.
831 */
getFaceType(IndexType faceID) const832 virtual CellType getFaceType(IndexType faceID) const final override
833 {
834 return m_face_to_node->getIDType(faceID);
835 }
836
837 /*!
838 * \brief Return the number of nodes associated with the given face.
839 *
840 * \param [in] faceID the ID of the face in question.
841 *
842 * \note Codes must call initializeFaceConnectivity() before calling
843 * this method.
844 */
getNumberOfFaceNodes(IndexType faceID=0) const845 virtual IndexType getNumberOfFaceNodes(IndexType faceID = 0) const final override
846 {
847 return m_face_to_node->getNumberOfValuesForID(faceID);
848 }
849
850 /*!
851 * \brief Copy the IDs of the nodes that compose the given face into the
852 * provided buffer.
853 *
854 * \param [in] faceID the ID of the face in question.
855 * \param [out] nodes the buffer into which the node IDs are copied, must
856 * be of length at least getNumberOfFaceNodes().
857 *
858 * \return The number of nodes for the given face.
859 *
860 * A face with ID faceID will have a normal pointing outward from the
861 * first cell it is adjacent to, as returned by
862 * getFaceCellIDs(faceID, cellID1, cellID2).
863 *
864 * \pre nodes != nullptr
865 * \pre 0 <= faceID < getNumberOfCells()
866 */
getFaceNodeIDs(IndexType faceID,IndexType * nodes) const867 virtual IndexType getFaceNodeIDs(IndexType faceID,
868 IndexType* nodes) const final override
869 {
870 SLIC_ASSERT(nodes != nullptr);
871 const IndexType n_nodes = getNumberOfFaceNodes(faceID);
872 std::memcpy(nodes, getFaceNodeIDs(faceID), n_nodes * sizeof(IndexType));
873 return n_nodes;
874 }
875
876 /*!
877 * \brief Copy the IDs of the cells adjacent to the given face into the
878 * provided indices.
879 *
880 * \param [in] faceID the ID of the face in question.
881 * \param [out] cellIDOne the ID of the first cell.
882 * \param [out] cellIDTwo the ID of the second cell.
883 *
884 * \note A face can be associated with one or two cells, depending on whether
885 * it is an external boundary face or interior face. By convention, if a face
886 * is an external boundary face, then only cellIDOne exists and cellIDTwo
887 * will be set to -1.
888 *
889 * \note Codes must call initializeFaceConnectivity() before calling
890 * this method.
891 *
892 * \pre 0 <= faceID < getNumberOfFaces()
893 */
getFaceCellIDs(IndexType faceID,IndexType & cellIDOne,IndexType & cellIDTwo) const894 virtual void getFaceCellIDs(IndexType faceID,
895 IndexType& cellIDOne,
896 IndexType& cellIDTwo) const final override
897 {
898 IndexType* faces = (*m_face_to_cell)[faceID];
899 cellIDOne = faces[0];
900 cellIDTwo = faces[1];
901 }
902
903 /// @}
904
905 /// \name Edges
906 /// @{
907
908 /*!
909 * \brief Return the number of edges in the mesh.
910 */
getNumberOfEdges() const911 virtual IndexType getNumberOfEdges() const final override
912 {
913 SLIC_ERROR("NOT IMPLEMENTED!!!");
914 return 0;
915 }
916
917 /*!
918 * \brief Return the capacity for edges.
919 */
getEdgeCapacity() const920 virtual IndexType getEdgeCapacity() const final override
921 {
922 SLIC_ERROR("NOT IMPLEMENTED!!!");
923 return 0;
924 }
925
926 /// @}
927
928 /*!
929 * \brief Return true iff both the connectivity and coordinates are stored in
930 * external arrays.
931 */
isExternal() const932 virtual bool isExternal() const final override
933 {
934 bool connec_external = m_cell_to_node->isExternal();
935 bool coords_external = m_coordinates->isExternal();
936
937 if(connec_external != coords_external)
938 {
939 SLIC_WARNING("External state not consistent.");
940 return false;
941 }
942
943 return connec_external;
944 }
945
946 /// @}
947
948 /// \name Attribute get/set Methods
949 /// @{
950
951 /// \name Cells
952 /// @{
953
954 /*!
955 * \brief Return the cell resize ratio.
956 */
getCellResizeRatio() const957 double getCellResizeRatio() const { return m_cell_to_node->getResizeRatio(); }
958
959 /*!
960 * \brief Set the cell resize ratio.
961 *
962 * \param [in] ratio the new cell resize ratio.
963 *
964 * \post getCellResizeRatio() == ratio
965 */
setCellResizeRatio(double ratio)966 void setCellResizeRatio(double ratio)
967 {
968 m_cell_to_node->setResizeRatio(ratio);
969 m_mesh_fields[CELL_CENTERED]->setResizeRatio(ratio);
970 }
971
972 /*!
973 * \brief Return the size of the connectivity array.
974 */
getCellNodesSize() const975 IndexType getCellNodesSize() const
976 {
977 return m_cell_to_node->getNumberOfValues();
978 }
979
980 /*!
981 * \brief Return the capacity of the connectivity array.
982 */
getCellNodesCapacity() const983 IndexType getCellNodesCapacity() const
984 {
985 return m_cell_to_node->getValueCapacity();
986 }
987
988 /*!
989 * \brief Resizes the cell connectivity array and cell-centered fields of this
990 * mesh instance to hold the specified number of cells.
991 *
992 * \param [in] cell_size the number of cells to resize to.
993 *
994 * \post getNumberOfCells() == cell_size
995 */
resizeCells(IndexType cell_size)996 void resizeCells(IndexType cell_size)
997 {
998 IndexType connectivity_size =
999 (hasMixedCellTypes()) ? USE_DEFAULT : getNumberOfCellNodes() * cell_size;
1000 m_cell_to_node->resize(cell_size, connectivity_size);
1001 m_mesh_fields[CELL_CENTERED]->resize(cell_size);
1002 }
1003
1004 /*!
1005 * \brief Reserve space for the given number of cells.
1006 *
1007 * \param [in] cell_capacity the number of cells to reserve space for.
1008 * \param [in] connectivity_capacity the ammount of space to reserve in the
1009 * connectivity array. Ignored if TOPO == SINGLE_SHAPE.
1010 *
1011 * \post getCellCapacity() >= cell_capacity
1012 */
reserveCells(IndexType cell_capacity,IndexType connectivity_capacity=USE_DEFAULT)1013 void reserveCells(IndexType cell_capacity,
1014 IndexType connectivity_capacity = USE_DEFAULT)
1015 {
1016 m_cell_to_node->reserve(cell_capacity, connectivity_capacity);
1017 m_mesh_fields[CELL_CENTERED]->reserve(cell_capacity);
1018 }
1019
1020 /*!
1021 * \brief Shrink the cell capacity to be equal to the number of cells.
1022 *
1023 * \post getCellCapacity() == getNumberOfCells()
1024 * \post getCellNodesCapacity() == getCellNodesSize()
1025 */
shrinkCells()1026 void shrinkCells()
1027 {
1028 m_cell_to_node->shrink();
1029 m_mesh_fields[CELL_CENTERED]->shrink();
1030 }
1031
1032 /// @}
1033
1034 /// \name Nodes
1035 /// @{
1036
1037 /*!
1038 * \brief Return the node resize ratio.
1039 */
getNodeResizeRatio() const1040 double getNodeResizeRatio() const { return m_coordinates->getResizeRatio(); }
1041
1042 /*!
1043 * \brief Set the node resize ratio.
1044 *
1045 * \param [in] ratio the new node resize ratio.
1046 *
1047 * \post getNodeResizeRatio() == ratio
1048 */
setNodeResizeRatio(double ratio)1049 void setNodeResizeRatio(double ratio)
1050 {
1051 m_coordinates->setResizeRatio(ratio);
1052 m_mesh_fields[NODE_CENTERED]->setResizeRatio(ratio);
1053 }
1054
1055 /*!
1056 * \brief Resizes the nodal coordinates and fields of this mesh instance to
1057 * the specified number of nodes.
1058 *
1059 * \param [in] nodes_size the number of nodes to resize to.
1060 *
1061 * \post getNumberOfNodes() == nodes_size
1062 */
resizeNodes(IndexType nodes_size)1063 void resizeNodes(IndexType nodes_size)
1064 {
1065 m_coordinates->resize(nodes_size);
1066 m_mesh_fields[NODE_CENTERED]->resize(nodes_size);
1067 }
1068
1069 /*!
1070 * \brief Reserve space for the given number of nodes.
1071 *
1072 * \param [in] node_capacity the number of nodes to reserve space for.
1073 *
1074 * \post getNodeCapacity() >= node_capacity
1075 */
reserveNodes(IndexType node_capacity)1076 void reserveNodes(IndexType node_capacity)
1077 {
1078 m_coordinates->reserve(node_capacity);
1079 m_mesh_fields[NODE_CENTERED]->reserve(node_capacity);
1080 }
1081
1082 /*!
1083 * \brief Shrink the node capacity to be equal to the number of nodes.
1084 *
1085 * \post getNodeCapacity() == getNumberOfNodes()
1086 */
shrinkNodes()1087 void shrinkNodes()
1088 {
1089 m_coordinates->shrink();
1090 m_mesh_fields[NODE_CENTERED]->shrink();
1091 }
1092
1093 /// @}
1094
1095 /// \name Faces
1096 /// @{
1097
1098 /*!
1099 * \brief Return the face resize ratio.
1100 */
getFaceResizeRatio() const1101 double getFaceResizeRatio() const
1102 {
1103 const double ratio = m_face_to_node->getResizeRatio();
1104 SLIC_WARNING_IF(m_face_to_cell->getResizeRatio() != ratio,
1105 "Resize ratios are inconsistent");
1106 return ratio;
1107 }
1108
1109 /*!
1110 * \brief Return the size of the connectivity array.
1111 */
getFaceNodesSize() const1112 IndexType getFaceNodesSize() const
1113 {
1114 return m_face_to_node->getNumberOfValues();
1115 }
1116
1117 /*!
1118 * \brief Return the capacity of the connectivity array.
1119 */
getFaceNodesCapacity() const1120 IndexType getFaceNodesCapacity() const
1121 {
1122 return m_face_to_node->getValueCapacity();
1123 }
1124
1125 /// @}
1126
1127 /// \name Edges
1128 /// @{
1129
1130 /*!
1131 * \brief Return the edge resize ratio.
1132 */
getEdgeResizeRatio() const1133 double getEdgeResizeRatio() const
1134 {
1135 SLIC_ERROR("NOT IMPLEMENTED!!!");
1136 return 0.0;
1137 }
1138
1139 /// @}
1140
1141 /*!
1142 * \brief Resizes this mesh instance to the specified number of nodes & cells.
1143 *
1144 * \param [in] node_size the desired number of nodes
1145 * \param [in] cell_size the desired number of cells
1146 *
1147 * \note This method will also resize the node-centered and cell-centered
1148 * fields accordingly.
1149 *
1150 * \post getNumberOfNodes() == nodes_size
1151 * \post getNumberOfCells() == cell_size
1152 *
1153 * \see resizeNodes()
1154 * \see resizeCells()
1155 */
resize(IndexType node_size,IndexType cell_size)1156 void resize(IndexType node_size, IndexType cell_size)
1157 {
1158 resizeNodes(node_size);
1159 resizeCells(cell_size);
1160 }
1161
1162 /*!
1163 * \brief Reserve space for the given number of nodes and cells.
1164 *
1165 * \param [in] node_capacity the number of nodes to reserve space for.
1166 * \param [in] cell_capacity the number of cells to reserve space for.
1167 * \param [in] connectivity_capacity the ammount of space to reserve in the
1168 * connectivity array. Ignored if TOPO == SINGLE_SHAPE.
1169 *
1170 * \post getNodeCapacity() >= node_capacity
1171 * \post getCellCapacity() >= cell_capacity
1172 */
reserve(IndexType node_capacity,IndexType cell_capacity,IndexType connectivity_capacity=USE_DEFAULT)1173 void reserve(IndexType node_capacity,
1174 IndexType cell_capacity,
1175 IndexType connectivity_capacity = USE_DEFAULT)
1176 {
1177 reserveNodes(node_capacity);
1178 reserveCells(cell_capacity, connectivity_capacity);
1179 }
1180
1181 /*!
1182 * \brief Shrink the node capacity to be equal to the number of nodes and the
1183 * cell capacity to be equal to the number of cells.
1184 *
1185 * \post getNodeCapacity() == getNumberOfNodes()
1186 * \post getCellCapacity() == getNumberOfCells()
1187 * \post getCellNodesCapacity() == getCellNodesSize()
1188 */
shrink()1189 void shrink()
1190 {
1191 shrinkNodes();
1192 shrinkCells();
1193 }
1194
1195 /*!
1196 * \brief Return true iff the mesh holds no nodes and no cells.
1197 */
empty() const1198 bool empty() const
1199 {
1200 return m_coordinates->empty() && m_cell_to_node->empty();
1201 }
1202
1203 /*!
1204 * \brief Return true iff both the connectivity and coordinates are stored in
1205 * sidre.
1206 */
isInSidre() const1207 bool isInSidre() const
1208 {
1209 bool connec_sidre = m_cell_to_node->isInSidre();
1210 bool coords_sidre = m_coordinates->isInSidre();
1211
1212 if(connec_sidre != coords_sidre)
1213 {
1214 SLIC_WARNING("Sidre state not consistent.");
1215 return false;
1216 }
1217
1218 return connec_sidre;
1219 }
1220
1221 /// @}
1222
1223 /// \name Data Access Methods
1224 /// @{
1225
1226 /// \name Cells
1227 /// @{
1228
1229 /*!
1230 * \brief Return a pointer to the connectivity of the given cell. The
1231 * buffer is guarenteed to be of length at least
1232 * getNumberOfCellNodes( cellID ).
1233 *
1234 * \param [in] cellID the ID of the cell in question.
1235 *
1236 * \pre 0 <= cellID < getNumberOfCells()
1237 */
1238 /// @{
1239
getCellNodeIDs(IndexType cellID)1240 IndexType* getCellNodeIDs(IndexType cellID)
1241 {
1242 return (*m_cell_to_node)[cellID];
1243 }
1244
getCellNodeIDs(IndexType cellID) const1245 const IndexType* getCellNodeIDs(IndexType cellID) const
1246 {
1247 return (*m_cell_to_node)[cellID];
1248 }
1249
1250 /*!
1251 * \brief Return a pointer to the faces of the given cell. The
1252 * buffer is guarenteed to be of length at least
1253 * getNumberOfCellFaces( cellID ).
1254 *
1255 * \param [in] cellID the ID of the cell in question.
1256 *
1257 * \note Codes must call initializeFaceConnectivity() before calling
1258 * this method.
1259 *
1260 * \pre 0 <= cellID < getNumberOfCells()
1261 */
1262 /// @{
1263
getCellFaceIDs(IndexType cellID)1264 IndexType* getCellFaceIDs(IndexType cellID)
1265 {
1266 return (*m_cell_to_face)[cellID];
1267 }
1268
getCellFaceIDs(IndexType cellID) const1269 const IndexType* getCellFaceIDs(IndexType cellID) const
1270 {
1271 return (*m_cell_to_face)[cellID];
1272 }
1273
1274 /// @}
1275
1276 /*!
1277 * \brief Return a pointer to the cell nodes array, of length
1278 * getCellNodesSize().
1279 */
1280 /// @{
1281
getCellNodesArray()1282 IndexType* getCellNodesArray() { return m_cell_to_node->getValuePtr(); }
1283
getCellNodesArray() const1284 const IndexType* getCellNodesArray() const
1285 {
1286 return m_cell_to_node->getValuePtr();
1287 }
1288
1289 /// @}
1290
1291 /*!
1292 * \brief Return a pointer to the cell nodes offset array, of length
1293 * getNumberOfCells() + 1. Returns nullptr if
1294 * TOPO == SINGLE_SHAPE.
1295 */
1296 /// @{
1297
getCellNodesOffsetsArray()1298 IndexType* getCellNodesOffsetsArray()
1299 {
1300 return m_cell_to_node->getOffsetPtr();
1301 }
1302
getCellNodesOffsetsArray() const1303 const IndexType* getCellNodesOffsetsArray() const
1304 {
1305 return m_cell_to_node->getOffsetPtr();
1306 }
1307
1308 /// @}
1309
1310 /*!
1311 * \brief Return a pointer to the cell types array, of length
1312 * getNumberOfCells(). Returns nullptr if
1313 * TOPO == SINGLE_SHAPE.
1314 */
1315 /// @{
1316
getCellTypesArray()1317 CellType* getCellTypesArray() { return m_cell_to_node->getTypePtr(); }
1318
getCellTypesArray() const1319 const CellType* getCellTypesArray() const
1320 {
1321 return m_cell_to_node->getTypePtr();
1322 }
1323
1324 /// @}
1325
1326 /*!
1327 * \brief Return a pointer to the cell faces array, of length
1328 * getCellNodesSize().
1329 */
1330 /// @{
1331
getCellFacesArray()1332 IndexType* getCellFacesArray() { return m_cell_to_face->getValuePtr(); }
1333
getCellFacesArray() const1334 const IndexType* getCellFacesArray() const
1335 {
1336 return m_cell_to_face->getValuePtr();
1337 }
1338
1339 /// @}
1340
1341 /*!
1342 * \brief Return a pointer to the cell faces offset array, of length
1343 * getNumberOfCells() + 1.
1344 */
1345 /// @{
1346
getCellFacesOffsetsArray()1347 IndexType* getCellFacesOffsetsArray()
1348 {
1349 return m_cell_to_face->getOffsetPtr();
1350 }
1351
getCellFacesOffsetsArray() const1352 const IndexType* getCellFacesOffsetsArray() const
1353 {
1354 return m_cell_to_face->getOffsetPtr();
1355 }
1356
1357 /// @}
1358
1359 /*!
1360 * \brief Append a cell to the mesh.
1361 *
1362 * \param [in] connec the connectivity of the new cell.
1363 * \param [in] type the type of the new cell, ignored if
1364 * TOPO == SINGLE_SHAPE.
1365 *
1366 * \pre connec != nullptr
1367 */
appendCell(const IndexType * connec,CellType type=UNDEFINED_CELL)1368 void appendCell(const IndexType* connec, CellType type = UNDEFINED_CELL)
1369 {
1370 IndexType n_values =
1371 (type == UNDEFINED_CELL) ? 0 : getCellInfo(type).num_nodes;
1372 m_cell_to_node->append(connec, n_values, type);
1373 m_mesh_fields[CELL_CENTERED]->resize(getNumberOfCells());
1374 }
1375
1376 /*!
1377 * \brief Append multiple cells to the mesh.
1378 *
1379 * \param [in] connec the connectivity of the new cells.
1380 * \param [in] n_cells the number of cells to append.
1381 * \param [in] offsets the offsets array of the cells to append, ignored
1382 * if TOPO == SINGLE_SHAPE.
1383 * \param [in] types the types array of the new cells, ignored if
1384 * TOPO == SINGLE_SHAPE.
1385 *
1386 * \pre connec != nullptr
1387 * \pre n_cells >= 0
1388 */
appendCells(const IndexType * connec,IndexType n_cells,const IndexType * offsets=nullptr,const CellType * types=nullptr)1389 void appendCells(const IndexType* connec,
1390 IndexType n_cells,
1391 const IndexType* offsets = nullptr,
1392 const CellType* types = nullptr)
1393 {
1394 m_cell_to_node->appendM(connec, n_cells, offsets, types);
1395 m_mesh_fields[CELL_CENTERED]->resize(getNumberOfCells());
1396 }
1397
1398 /*!
1399 * \brief Insert a cell in to the mesh at the given position.
1400 *
1401 * \param [in] connec the connectivity of the new cell.
1402 * \param [in] ID the position to insert at.
1403 * \param [in] n_values the number of values in the connectivity, ignored
1404 * if TOPO == SINGLE_SHAPE.
1405 * \param [in] type the type of the new cells, ignored if
1406 * TOPO == SINGLE_SHAPE.
1407 *
1408 * \pre connec != nullptr
1409 * \pre 0 <= ID <= getNumberOfCells()
1410 */
insertCell(const IndexType * connec,IndexType ID,CellType type=UNDEFINED_CELL)1411 void insertCell(const IndexType* connec,
1412 IndexType ID,
1413 CellType type = UNDEFINED_CELL)
1414 {
1415 IndexType n_values =
1416 (type == UNDEFINED_CELL) ? 0 : getCellInfo(type).num_nodes;
1417 m_cell_to_node->insert(connec, ID, n_values, type);
1418 m_mesh_fields[CELL_CENTERED]->emplace(ID, 1);
1419 }
1420
1421 /*!
1422 * \brief Insert multiple cells in to the mesh at the given position.
1423 *
1424 * \param [in] connec the connectivity of the new cells.
1425 * \param [in] start_ID the position to insert at.
1426 * \param [in] n_cells the number of cells to insert
1427 * \param [in] offsets the offsets array of the cells to append, ignored
1428 * if TOPO == SINGLE_SHAPE.
1429 * \param [in] types the types array of the new cells, ignored if
1430 * TOPO == SINGLE_SHAPE.
1431 *
1432 * \pre connec != nullptr
1433 * \pre 0 <= start_ID <= getNumberOfCells()
1434 */
insertCells(const IndexType * connec,IndexType start_ID,IndexType n_cells,const IndexType * offsets=nullptr,const CellType * types=nullptr)1435 void insertCells(const IndexType* connec,
1436 IndexType start_ID,
1437 IndexType n_cells,
1438 const IndexType* offsets = nullptr,
1439 const CellType* types = nullptr)
1440 {
1441 m_cell_to_node->insertM(connec, start_ID, n_cells, offsets, types);
1442 m_mesh_fields[CELL_CENTERED]->emplace(start_ID, n_cells);
1443 }
1444
1445 /// @}
1446
1447 /// \name Nodes
1448 /// @{
1449
1450 /*!
1451 * \brief Return the coordinate of the given dimension of the given node.
1452 *
1453 * \param [in] nodeID the ID of the node in question.
1454 * \param [in] dim the dimension to return.
1455 *
1456 * \pre 0 <= nodeID < getNumberOfNodes()
1457 * \pre 0 <= dim < getDimension()
1458 */
getNodeCoordinate(IndexType nodeID,int dim) const1459 double getNodeCoordinate(IndexType nodeID, int dim) const
1460 {
1461 return m_coordinates->getCoordinate(nodeID, dim);
1462 }
1463
1464 /*!
1465 * \brief Appends a new node to the mesh.
1466 *
1467 * \param [in] x the first coordinate to append.
1468 * \param [in] y the second coordinate to append.
1469 * \param [in] z the third coordinate to append.
1470 *
1471 * \note Each method is valid only for the appropriate dimension of the mesh.
1472 */
1473 /// @{
1474
appendNode(double x)1475 IndexType appendNode(double x)
1476 {
1477 IndexType n_index = m_coordinates->append(x);
1478 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1479 return n_index;
1480 }
1481
appendNode(double x,double y)1482 IndexType appendNode(double x, double y)
1483 {
1484 IndexType n_index = m_coordinates->append(x, y);
1485 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1486 return n_index;
1487 }
1488
appendNode(double x,double y,double z)1489 IndexType appendNode(double x, double y, double z)
1490 {
1491 IndexType n_index = m_coordinates->append(x, y, z);
1492 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1493 return n_index;
1494 }
1495
1496 /// @}
1497
1498 /*!
1499 * \brief Appends multiple nodes to the mesh.
1500 *
1501 * \param [in] coords pointer to the nodes to append, of length
1502 * n * getDimension().
1503 * \param [in] n the number of nodes to append.
1504 *
1505 * \note coords is assumed to be in the array of structs format, ie
1506 * coords = {x0, y0, z0, x1, y1, z1, ..., xn, yn, zn}.
1507 *
1508 * \pre coords != nullptr
1509 * \pre n >= 0
1510 */
appendNodes(const double * coords,IndexType n=1)1511 void appendNodes(const double* coords, IndexType n = 1)
1512 {
1513 m_coordinates->append(coords, n);
1514 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1515 }
1516
1517 /*!
1518 * \brief Appends new nodes to the mesh.
1519 *
1520 * \param [in] x array of the first coordinates to append, of length n.
1521 * \param [in] y array of the second coordinates to append, of length n.
1522 * \param [in] z array of the third coordinates to append, of length n.
1523 * \param [in] n the number of coordinates to append.
1524 *
1525 * \note The first method is only valid for 2D meshes while the second
1526 * is only for 3D.
1527 * \pre x != nullptr
1528 * \pre y != nullptr
1529 * \pre z != nullptr
1530 * \pre n >= 0
1531 */
1532 /// @{
1533
appendNodes(const double * x,const double * y,IndexType n)1534 void appendNodes(const double* x, const double* y, IndexType n)
1535 {
1536 m_coordinates->append(x, y, n);
1537 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1538 }
1539
appendNodes(const double * x,const double * y,const double * z,IndexType n)1540 void appendNodes(const double* x, const double* y, const double* z, IndexType n)
1541 {
1542 m_coordinates->append(x, y, z, n);
1543 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1544 }
1545
1546 /// @}
1547
1548 /*!
1549 * \brief Insert a node to the mesh.
1550 *
1551 * \param [in] nodeID the position to insert at.
1552 * \param [in] x the value of the first coordinate to insert.
1553 * \param [in] y the value of the second coordinate to insert.
1554 * \param [in] z the value of the third coordinate to insert.
1555 * \param [in] update_connectivity if true will update the connectivity so
1556 * that all elements remain connected to the same coordinates as before.
1557 *
1558 * \note Each method is valid only for the appropriate dimension of the mesh.
1559 * \pre 0 <= nodeID <= getNumberOfNodes
1560 */
1561 /// @{
1562
insertNode(IndexType nodeID,double x,bool update_connectivity=true)1563 void insertNode(IndexType nodeID, double x, bool update_connectivity = true)
1564 {
1565 m_coordinates->insert(nodeID, x);
1566 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, 1);
1567 if(update_connectivity)
1568 {
1569 cellConnectivityUpdateInsert(nodeID, 1);
1570 }
1571 }
1572
insertNode(IndexType nodeID,double x,double y,bool update_connectivity=true)1573 void insertNode(IndexType nodeID,
1574 double x,
1575 double y,
1576 bool update_connectivity = true)
1577 {
1578 m_coordinates->insert(nodeID, x, y);
1579 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, 1);
1580 if(update_connectivity)
1581 {
1582 cellConnectivityUpdateInsert(nodeID, 1);
1583 }
1584 }
1585
insertNode(IndexType nodeID,double x,double y,double z,bool update_connectivity=true)1586 void insertNode(IndexType nodeID,
1587 double x,
1588 double y,
1589 double z,
1590 bool update_connectivity = true)
1591 {
1592 m_coordinates->insert(nodeID, x, y, z);
1593 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, 1);
1594 if(update_connectivity)
1595 {
1596 cellConnectivityUpdateInsert(nodeID, 1);
1597 }
1598 }
1599
1600 /// @}
1601
1602 /*!
1603 * \brief Inserts multiple nodes to the mesh.
1604 *
1605 * \param [in] coords pointer to the nodes to insert, of length
1606 * n * getDimension().
1607 * \param [in] n the number of nodes to append.
1608 * \param [in] update_connectivity if true will update the connectivity so
1609 * that all elements remain connected to the same coordinates as before.
1610 *
1611 * \note coords is assumed to be in the array of structs format, ie
1612 * coords = {x0, y0, z0, x1, y1, z1, ..., xn, yn, zn}.
1613 *
1614 * \pre 0 <= nodeID <= getNumberOfNodes
1615 * \pre coords != nullptr
1616 * \pre n >= 0
1617 */
insertNodes(IndexType nodeID,const double * coords,IndexType n=1,bool update_connectivity=true)1618 void insertNodes(IndexType nodeID,
1619 const double* coords,
1620 IndexType n = 1,
1621 bool update_connectivity = true)
1622 {
1623 m_coordinates->insert(nodeID, coords, n);
1624 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, n);
1625 if(update_connectivity)
1626 {
1627 cellConnectivityUpdateInsert(nodeID, n);
1628 }
1629 }
1630
1631 /*!
1632 * \brief Insert multiple nodes to the mesh.
1633 *
1634 * \param [in] nodeID the position to insert at.
1635 * \param [in] x the array of the first coordinates to insert.
1636 * \param [in] y the array of the second coordinates to insert.
1637 * \param [in] z the array of the third coordinates to insert.
1638 * \param [in] n the number of nodes to insert.
1639 * \param [in] update_connectivity if true will update the connectivity so
1640 * that all elements remain connected to the same coordinates as before.
1641 *
1642 * \note The first method is only valid for 2D meshes while the second
1643 * is only for 3D.
1644 * \pre 0 <= nodeID <= getNumberOfNodes
1645 * \pre x != nullptr
1646 * \pre y != nullptr if 2-D or 3-D
1647 * \pre z != nullptr if 3-D
1648 * \pre n >= 0
1649 */
1650 /// @{
1651
insertNodes(IndexType nodeID,const double * x,const double * y,IndexType n,bool update_connectivity=true)1652 void insertNodes(IndexType nodeID,
1653 const double* x,
1654 const double* y,
1655 IndexType n,
1656 bool update_connectivity = true)
1657 {
1658 m_coordinates->insert(nodeID, x, y, n);
1659 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, n);
1660 if(update_connectivity)
1661 {
1662 cellConnectivityUpdateInsert(nodeID, n);
1663 }
1664 }
1665
insertNodes(IndexType nodeID,const double * x,const double * y,const double * z,IndexType n,bool update_connectivity=true)1666 void insertNodes(IndexType nodeID,
1667 const double* x,
1668 const double* y,
1669 const double* z,
1670 IndexType n,
1671 bool update_connectivity = true)
1672 {
1673 m_coordinates->insert(nodeID, x, y, z, n);
1674 m_mesh_fields[NODE_CENTERED]->emplace(nodeID, n);
1675 if(update_connectivity)
1676 {
1677 cellConnectivityUpdateInsert(nodeID, n);
1678 }
1679 }
1680
1681 /// @}
1682
1683 /// @}
1684
1685 /// \name Faces
1686 /// @{
1687
1688 /*!
1689 * \brief Sets up cell-face, face-cell, and face-node connectivity.
1690 *
1691 * \param [in] force re-initialize face-related connectivity, even if it
1692 * has already been done.
1693 */
initializeFaceConnectivity(bool force=false)1694 bool initializeFaceConnectivity(bool force = false)
1695 {
1696 if(getDimension() == 1)
1697 {
1698 return true;
1699 }
1700
1701 if(!force && getNumberOfFaces() > 0)
1702 {
1703 return true;
1704 }
1705
1706 if(force)
1707 {
1708 m_cell_to_face->resize(0, 0);
1709 m_face_to_cell->resize(0, 0);
1710 m_face_to_node->resize(0, 0);
1711 }
1712
1713 IndexType facecount = 0;
1714 IndexType* f2cdata = nullptr;
1715 IndexType* c2fdata = nullptr;
1716 IndexType* c2ndata = nullptr;
1717 IndexType* c2foffsets = nullptr;
1718 IndexType* f2ndata = nullptr;
1719 IndexType* f2noffsets = nullptr;
1720 CellType* f2ntypes = nullptr;
1721
1722 bool retval = internal::initFaces(this,
1723 facecount,
1724 f2cdata,
1725 c2fdata,
1726 c2ndata,
1727 c2foffsets,
1728 f2ndata,
1729 f2noffsets,
1730 f2ntypes);
1731
1732 if(retval)
1733 {
1734 // Copy in the face connectivity data.
1735 const IndexType cellCount = getNumberOfCells();
1736 m_cell_to_face->reserve(cellCount, c2foffsets[cellCount]);
1737 m_cell_to_face->appendM(c2fdata, cellCount, c2foffsets);
1738
1739 m_face_to_cell->reserve(facecount);
1740 m_face_to_cell->appendM(f2cdata, facecount);
1741
1742 m_face_to_node->reserve(facecount, f2noffsets[facecount]);
1743 m_face_to_node->appendM(f2ndata, facecount, f2noffsets, f2ntypes);
1744 }
1745
1746 m_mesh_fields[FACE_CENTERED]->resize(getNumberOfFaces());
1747
1748 delete[] f2cdata;
1749 delete[] c2fdata;
1750 delete[] c2ndata;
1751 delete[] c2foffsets;
1752 delete[] f2ndata;
1753 delete[] f2noffsets;
1754 delete[] f2ntypes;
1755
1756 return retval;
1757 }
1758
1759 /*!
1760 * \brief Return a pointer to the nodes of the given face. The
1761 * buffer is guaranteed to be of length at least
1762 * getNumberOfFaceNodes( faceID ).
1763 *
1764 * \param [in] faceID the ID of the face in question.
1765 *
1766 * \note Codes must call initializeFaceConnectivity() before calling
1767 * this method.
1768 *
1769 * \pre 0 <= faceID < getNumberOfFaces()
1770 */
1771 /// @{
1772
getFaceNodeIDs(IndexType faceID)1773 IndexType* getFaceNodeIDs(IndexType faceID)
1774 {
1775 return (*m_face_to_node)[faceID];
1776 }
1777
getFaceNodeIDs(IndexType faceID) const1778 const IndexType* getFaceNodeIDs(IndexType faceID) const
1779 {
1780 return (*m_face_to_node)[faceID];
1781 }
1782
1783 /// @}
1784
1785 /*!
1786 * \brief Return a pointer to the face nodes array, of length
1787 * getFaceNodesSize().
1788 */
1789 /// @{
1790
getFaceNodesArray()1791 IndexType* getFaceNodesArray() { return m_face_to_node->getValuePtr(); }
1792
getFaceNodesArray() const1793 const IndexType* getFaceNodesArray() const
1794 {
1795 return m_face_to_node->getValuePtr();
1796 }
1797
1798 /// @}
1799
1800 /*!
1801 * \brief Return a pointer to the face nodes offset array, of length
1802 * getNumberOfFaces() + 1.
1803 */
1804 /// @{
1805
getFaceNodesOffsetsArray()1806 IndexType* getFaceNodesOffsetsArray()
1807 {
1808 return m_face_to_node->getOffsetPtr();
1809 }
1810
getFaceNodesOffsetsArray() const1811 const IndexType* getFaceNodesOffsetsArray() const
1812 {
1813 return m_face_to_node->getOffsetPtr();
1814 }
1815
1816 /// @}
1817
1818 /*!
1819 * \brief Return a pointer to the face cells array, of length
1820 * 2 * getNumberOfFaces().
1821 */
1822 /// @{
1823
getFaceCellsArray()1824 IndexType* getFaceCellsArray() { return m_face_to_cell->getValuePtr(); }
1825
getFaceCellsArray() const1826 const IndexType* getFaceCellsArray() const
1827 {
1828 return m_face_to_cell->getValuePtr();
1829 }
1830
1831 /// @}
1832
1833 /// @}
1834
1835 /// @}
1836
1837 private:
1838 /*! \brief Construct and fill the cell-to-face connectivity. */
1839 void buildCellFaceConnectivity(IndexType* c2fdata, IndexType* c2foffsets);
1840
1841 /*! \brief Return a new empty CellToFaceConnectivity instance. */
1842 CellToFaceConnectivity* initializeCellToFace(
1843 CellType cell_type = UNDEFINED_CELL) const;
1844
1845 /*! \brief Return a new empty FaceToNodeConnectivity instance. */
1846 FaceToNodeConnectivity* initializeFaceToNode(
1847 CellType cell_type = UNDEFINED_CELL) const;
1848
1849 /*!
1850 * \brief Update the connectivity given an nodal insert at position pos of
1851 * length n.
1852 *
1853 * \param [in] pos the position of the insert.
1854 * \param [in] n the length of the insert.
1855 */
cellConnectivityUpdateInsert(IndexType pos,IndexType n)1856 void cellConnectivityUpdateInsert(IndexType pos, IndexType n)
1857 {
1858 SLIC_ASSERT(0 <= pos && pos < getNumberOfNodes());
1859
1860 const IndexType n_values = getCellNodesSize();
1861 IndexType* values = getCellNodesArray();
1862 SLIC_ASSERT(n_values == 0 || values != nullptr);
1863
1864 for(IndexType i = 0; i < n_values; ++i)
1865 {
1866 if(values[i] >= pos)
1867 {
1868 values[i] += n;
1869 }
1870 }
1871 }
1872
1873 /*!
1874 * \brief Performs common initialization.
1875 */
initialize()1876 void initialize()
1877 {
1878 m_explicit_coords = true;
1879 m_explicit_connectivity = true;
1880 m_mesh_fields[NODE_CENTERED]->setResizeRatio(getNodeResizeRatio());
1881 m_mesh_fields[CELL_CENTERED]->setResizeRatio(getCellResizeRatio());
1882 m_mesh_fields[FACE_CENTERED]->setResizeRatio(getFaceResizeRatio());
1883
1884 m_mesh_fields[NODE_CENTERED]->reserve(getNodeCapacity());
1885 m_mesh_fields[CELL_CENTERED]->reserve(getCellCapacity());
1886 m_mesh_fields[FACE_CENTERED]->reserve(getFaceCapacity());
1887
1888 m_mesh_fields[NODE_CENTERED]->resize(getNumberOfNodes());
1889 m_mesh_fields[CELL_CENTERED]->resize(getNumberOfCells());
1890 m_mesh_fields[FACE_CENTERED]->resize(getNumberOfFaces());
1891 }
1892
1893 MeshCoordinates* m_coordinates;
1894
1895 /*! \brief The nodes for each cell */
1896 CellToNodeConnectivity* m_cell_to_node;
1897
1898 /*! \brief Each cell's faces */
1899 CellToFaceConnectivity* m_cell_to_face;
1900
1901 /*! \brief Each face's cells */
1902 FaceToCellConnectivity* m_face_to_cell;
1903
1904 /*! \brief Each face's nodes */
1905 FaceToNodeConnectivity* m_face_to_node;
1906
1907 DISABLE_COPY_AND_ASSIGNMENT(UnstructuredMesh);
1908 DISABLE_MOVE_AND_ASSIGNMENT(UnstructuredMesh);
1909 };
1910
1911 /*!
1912 * \brief Return a new CellToFaceConnectivity. This instance is for
1913 * SINGLE_SHAPE meshes. If the mesh has cell type VERTEX or SEGMENT then the
1914 * stride of the returned connectivity is 1 instead of 0 which is the proper
1915 * number of cell faces, this avoids an error with 0 stride.
1916 *
1917 * \param [in] cell_type the cell_type of the mesh.
1918 */
1919 template <>
1920 inline UnstructuredMesh<SINGLE_SHAPE>::CellToFaceConnectivity*
initializeCellToFace(CellType cell_type) const1921 UnstructuredMesh<SINGLE_SHAPE>::initializeCellToFace(CellType cell_type) const
1922 {
1923 IndexType num_faces = getCellInfo(cell_type).num_faces;
1924 if(num_faces == 0)
1925 {
1926 num_faces = 1;
1927 }
1928
1929 return new UnstructuredMesh<SINGLE_SHAPE>::CellToFaceConnectivity(num_faces, 0);
1930 }
1931
1932 /*!
1933 * \brief Return a new CellToFaceConnectivity. This instance is for
1934 * MIXED_SHAPE meshes.
1935 */
1936 template <>
1937 inline UnstructuredMesh<MIXED_SHAPE>::CellToFaceConnectivity*
initializeCellToFace(CellType) const1938 UnstructuredMesh<MIXED_SHAPE>::initializeCellToFace(CellType) const
1939 {
1940 return new UnstructuredMesh<MIXED_SHAPE>::CellToFaceConnectivity(UNDEFINED_CELL,
1941 0,
1942 0);
1943 }
1944
1945 /*!
1946 * \brief Return a new FaceToNodeConnectivity. This instance is for
1947 * SINGLE_SHAPE meshes. If the mesh has cell type VERTEX or SEGMENT then the
1948 * cell type of the returned ConnectivityArray is UNDEFINED_CELL with stride 1.
1949 *
1950 * \param [in] cell_type the cell_type of the mesh.
1951 */
1952 template <>
1953 inline UnstructuredMesh<SINGLE_SHAPE>::FaceToNodeConnectivity*
initializeFaceToNode(CellType cell_type) const1954 UnstructuredMesh<SINGLE_SHAPE>::initializeFaceToNode(CellType cell_type) const
1955 {
1956 const CellType face_type = getCellInfo(cell_type).face_types[0];
1957 if(face_type == UNDEFINED_CELL)
1958 {
1959 return new UnstructuredMesh<SINGLE_SHAPE>::FaceToNodeConnectivity(1, 0);
1960 }
1961
1962 return new UnstructuredMesh<SINGLE_SHAPE>::FaceToNodeConnectivity(face_type, 0);
1963 }
1964
1965 /*!
1966 * \brief Return a new FaceToNodeConnectivity. This instance is for
1967 * MIXED_SHAPE meshes.
1968 */
1969 template <>
1970 inline UnstructuredMesh<MIXED_SHAPE>::FaceToNodeConnectivity*
initializeFaceToNode(CellType) const1971 UnstructuredMesh<MIXED_SHAPE>::initializeFaceToNode(CellType) const
1972 {
1973 return new UnstructuredMesh<MIXED_SHAPE>::FaceToNodeConnectivity(0, 0);
1974 }
1975
1976 } /* namespace mint */
1977 } /* namespace axom */
1978
1979 #endif /* MINT_UNSTRUCTUREDMESH_HPP_ */
1980