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