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_UNIFORMMESH_HPP_ 7 #define MINT_UNIFORMMESH_HPP_ 8 9 #include "axom/core/StackArray.hpp" 10 #include "axom/mint/config.hpp" 11 #include "axom/mint/mesh/StructuredMesh.hpp" 12 13 #include "axom/slic/interface/slic.hpp" 14 15 namespace axom 16 { 17 namespace mint 18 { 19 /*! 20 * \class UniformMesh 21 * 22 * \brief Provides the ability to represent and operate on a UniformMesh 23 * 24 * The UniformMesh extends from the StructuredMesh base class and provides the 25 * ability to represent and operate on a uniform mesh and associated data. 26 * 27 * A <em> uniform mesh </em>, also called a regular mesh, subdivides the domain 28 * in cells that have uniform spacing across each coordinate axis.The nodes and 29 * cells of a <em> uniform </em> mesh are arranged on a regular grid lattice, 30 * where the topology is implicitly defined according to the ordering of the 31 * nodes in the logical i-j-k index space. Moreover, the geometry is also 32 * implicitly defined on a <em> uniform mesh </em>. Given an origin point, 33 * \f$ \hat{x_0} \f$ and spacing, \f$ \hat{h} \f$, along each axis, the 34 * coordinates of a node can be evaluated algebraically by the following: 35 * 36 * \f$ \hat{p} = \hat{x_0} + \hat{i} \times \hat{h} \f$, 37 * 38 * where \f$\hat{i}\f$ is the logical i-j-k index of the corresponding node. 39 * 40 * A UniformMesh object may be constructed using (a) a native constructor, or 41 * (b) from a a Sidre group when Mint is compiled with Sidre support. 42 * 43 * * <b> Native Constructor </b> <br /> 44 * 45 * When using native constructor, the UniformMesh object owns all memory 46 * that is associated with the mesh. Once the UniformMesh object goes 47 * out-of-scope all memory associated with it is returned to the system. 48 * 49 * * <b> Sidre Constructor </b> <br /> 50 * 51 * When a UniformMesh is associated with a Sidre Group, Sidre owns all the 52 * memory. Once the UniformMesh goes out-of-scope the data remains persistent 53 * in Sidre. 54 * 55 * \note When using Sidre, the specified group must conform to the conventions 56 * defined by the <a href="http://llnl-conduit.readthedocs.io/en/latest/"> 57 * computational mesh blueprint </a> 58 * 59 * \see StructuredMesh 60 * \see Extent 61 */ 62 class UniformMesh : public StructuredMesh 63 { 64 public: 65 /*! 66 * \brief Default constructor. Disabled. 67 */ 68 UniformMesh() = delete; 69 70 /// \name Native Constructors 71 /// @{ 72 73 /*! 74 * \brief Constructs a uniform mesh within a specified rectangular region, 75 * defined by its lower and upper corner points, and mesh dimensions, Ni, 76 * Nj, Nk. 77 * 78 * \param [in] lower_bound lower corner coordinates of rectangular region. 79 * \param [in] upper_bound upper corner coordinates of rectangular region. 80 * \param [in] Ni the number of nodes in the i-direction 81 * \param [in] Nj the number of nodes in the j-direction (if dimension >= 2) 82 * \param [in] Nk the number of nodes in the k-direction (if dimension == 3) 83 * 84 * \pre lower_bound != nullptr 85 * \pre upper_bound != nullptr 86 * \pre Ni >= 1 87 * \pre Nj >= 1 iff dimension >= 2 88 * \pre Nk >= 1 iff dimension == 3 89 * 90 * \post getOrigin() != nullptr 91 * \post getSpacing() != nullptr 92 * \post getOrigin()[ i ] == lower_bound[ i ] \f$ \forall i \f$ 93 */ 94 UniformMesh(const double* lower_bound, 95 const double* upper_bound, 96 IndexType Ni, 97 IndexType Nj = -1, 98 IndexType Nk = -1); 99 /// @} 100 101 #ifdef AXOM_MINT_USE_SIDRE 102 103 /// \name Sidre Constructors 104 /// @{ 105 106 /*! 107 * \brief Creates a uniform mesh instance from the given Sidre group that 108 * holds uniform mesh data according to the computational mesh blueprint 109 * conventions. 110 * 111 * \param [in] group pointer to the root group within a Sidre hierarchy. 112 * \param [in] topo the name of the topology for this mesh (optional). 113 * 114 * \note The supplied group is expected to contain uniform mesh data that is 115 * valid & conforming to the conventions described by conduit's 116 * <a href="http://llnl-conduit.readthedocs.io/en/latest/"> computational 117 * mesh blueprint </a>. 118 * 119 * \note If a topology name is not provided, the implementation will use the 120 * 1st topology group under the parent "topologies" group. 121 * 122 * \note When using this constructor, all data is owned by Sidre. Once the 123 * mesh object goes out-of-scope, the data will remain persistent in Sidre. 124 * 125 * \pre group != nullptr 126 * \pre blueprint::isValidRootGroup( group ) 127 * \post hasSidreGroup() == true 128 */ 129 explicit UniformMesh(sidre::Group* group, const std::string& topo = ""); 130 131 /*! 132 * \brief Constructs a uniform mesh object, on an empty Sidre group, that 133 * covers a rectangular region, defined by its lower and upper corner points, 134 * and desired mesh dimensions, \f$ N_i, N_j, N_k f\$ 135 * 136 * \param [in] group pointer to the Sidre group 137 * \param [in] topo the name of the topology (optional) 138 * \param [in] coordset name of the corresponding coordset group (optional) 139 * \param [in] lower_bound lower corner coordinates of rectangular region 140 * \param [in] upper_bound upper corner coordinates of rectangular region 141 * \param [in] Ni number of nodes in the i-direction 142 * \param [in] Nj number of nodes in the j-direction (if dimension >= 2) 143 * \param [in] Nk number of nodes in the k-direction (if dimension == 3) 144 * 145 * \note The supplied `lower_bound` and `upper_bound` must point to buffer 146 * that have at least N entries, where N is the dimension of the mesh. 147 * 148 * \note When using this constructor, all data is owned by Sidre. Once the 149 * UniformMesh object goes out-of-scope, the data will remain persistent in 150 * Sidre. 151 * 152 * \note If a topology and/or coordset name are not provided by the caller, 153 * internal defaults will be used by the implementation. 154 * 155 * \pre lower_bound != nullptr 156 * \pre upper_bound != nullptr 157 * \pre Ni >= 1 158 * \pre Nj >= 1 iff dimension >= 2 159 * \pre Nk >= 1 iff dimension == 3 160 * \pre group != nullptr 161 * \pre group->getNumViews()==0 162 * \pre group->getNumGroups()==0 163 * 164 * \post getOrigin() != nullptr 165 * \post getSpacing() != nullptr 166 * \post getOrigin()[ i ] == lower_bound[ i ] \f$ \forall i \f$ 167 * \post hasSidreGroup() == true 168 */ 169 /// @{ 170 UniformMesh(sidre::Group* group, 171 const std::string& topo, 172 const std::string& coordset, 173 const double* lower_bound, 174 const double* upper_bound, 175 IndexType Ni, 176 IndexType Nj = -1, 177 IndexType Nk = -1); 178 UniformMesh(sidre::Group * group,const double * lower_bound,const double * upper_bound,IndexType Ni,IndexType Nj=-1,IndexType Nk=-1)179 UniformMesh(sidre::Group* group, 180 const double* lower_bound, 181 const double* upper_bound, 182 IndexType Ni, 183 IndexType Nj = -1, 184 IndexType Nk = -1) 185 : UniformMesh(group, "", "", lower_bound, upper_bound, Ni, Nj, Nk) 186 { } 187 /// @} 188 189 /// @} 190 #endif 191 192 /// \name Virtual methods 193 /// @{ 194 195 /*! 196 * \brief Destructor. 197 */ ~UniformMesh()198 virtual ~UniformMesh() { } 199 200 /// \name Nodes 201 /// @{ 202 203 /*! 204 * \brief Copy the coordinates of the given node into the provided buffer. 205 * 206 * \param [in] nodeID the ID of the node in question. 207 * \param [in] coords the buffer to copy the coordinates into, of length at 208 * least getDimension(). 209 * 210 * \note provided only for convenience, do not use inside a loop. Instead use 211 * getOrigin() and getSpacing() to calculate the nodal coordinates. 212 * 213 * \pre 0 <= nodeID < getNumberOfNodes() 214 * \pre coords != nullptr 215 */ 216 virtual void getNode(IndexType nodeID, double* node) const final override; 217 218 /*! 219 * \brief Return a pointer to the nodal positions in the specified dimension. 220 * Since the UniformMesh holds no such array it return nullptr. 221 */ 222 /// @{ 223 getCoordinateArray(int AXOM_UNUSED_PARAM (dim))224 virtual double* getCoordinateArray(int AXOM_UNUSED_PARAM(dim)) final override 225 { 226 SLIC_ERROR("getCoordinateArray() is not supported for UniformMesh"); 227 return nullptr; 228 } 229 getCoordinateArray(int AXOM_UNUSED_PARAM (dim)) const230 virtual const double* getCoordinateArray(int AXOM_UNUSED_PARAM(dim)) const final override 231 { 232 SLIC_ERROR("getCoordinateArray() is not supported for UniformMesh"); 233 return nullptr; 234 } 235 236 /// @} 237 238 /// @} 239 240 /// @} 241 242 /// \name Attribute Querying Methods 243 /// @{ 244 245 /*! 246 * \brief Returns a const pointer to origin of the Uniform Mesh 247 * \return origin pointer to the buffer storing the coordinates of the origin 248 * \post origin != nullptr 249 */ getOrigin() const250 const StackArray<double, 3>& getOrigin() const { return m_origin; } 251 252 /*! 253 * \brief Returns a const pointer to spacing of the Uniform Mesh. 254 * \return h user-supplied buffer to store the spacing of the mesh. 255 */ getSpacing() const256 const StackArray<double, 3>& getSpacing() const { return m_h; } 257 258 /// @} 259 260 /*! 261 * \brief Evaluates the physical coordinate of a node along a given diction. 262 * 263 * \param [in] i the node's logical grid index along the specified direction 264 * \param [in] direction the direction in query, e.g, I_DIRECTION, etc. 265 * 266 * \return x the physical coordinate of the node in the specified direction. 267 * 268 * \pre i >= 0 && i < getNumberNodeAlongDim( direction ) 269 * \pre direction >= 0 && direction < getDimension() 270 */ evaluateCoordinate(IndexType i,int direction) const271 inline double evaluateCoordinate(IndexType i, int direction) const 272 { 273 SLIC_ASSERT(direction >= 0 && direction < getDimension()); 274 SLIC_ASSERT(i >= 0 && i < getNodeResolution(direction)); 275 276 const double* x0 = getOrigin(); 277 const double* h = getSpacing(); 278 return x0[direction] + i * h[direction]; 279 } 280 281 private: 282 void setSpacingAndOrigin(const double* lo, const double* hi); 283 284 StackArray<double, 3> m_origin = {{0.0, 0.0, 0.0}}; 285 StackArray<double, 3> m_h = {{1.0, 1.0, 1.0}}; 286 287 DISABLE_COPY_AND_ASSIGNMENT(UniformMesh); 288 DISABLE_MOVE_AND_ASSIGNMENT(UniformMesh); 289 }; 290 291 } /* namespace mint */ 292 } /* namespace axom */ 293 294 #endif /* MINT_UNIFORMMESH_HPP_ */ 295