1 // Copyright(C) 1999-2021 National Technology & Engineering Solutions 2 // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with 3 // NTESS, the U.S. Government retains certain rights in this software. 4 // 5 // See packages/seacas/LICENSE for details 6 7 #ifndef IOSS_Ioss_StructuredBlock_h 8 #define IOSS_Ioss_StructuredBlock_h 9 10 #include "vtk_ioss_mangle.h" 11 12 #include <Ioss_BoundingBox.h> 13 #include <Ioss_CodeTypes.h> 14 #include <Ioss_EntityBlock.h> 15 #include <Ioss_NodeBlock.h> 16 #include <Ioss_Property.h> 17 #include <Ioss_ZoneConnectivity.h> 18 #include <array> 19 #include <cassert> 20 #include <string> 21 22 #if defined(SEACAS_HAVE_CGNS) && !defined(BUILT_IN_SIERRA) 23 using INT = std::int64_t; 24 #else 25 // If this is not being built with CGNS, then default to using 32-bit integers. 26 // Currently there is no way to input/output a structured mesh without CGNS, 27 // so this block is simply to get things to compile and probably has no use. 28 using INT = int; 29 #endif 30 31 namespace Ioss { 32 class Region; 33 34 struct BoundaryCondition 35 { BoundaryConditionBoundaryCondition36 BoundaryCondition(std::string name, std::string fam_name, Ioss::IJK_t range_beg, 37 Ioss::IJK_t range_end) 38 : m_bcName(std::move(name)), m_famName(std::move(fam_name)), m_rangeBeg(range_beg), 39 m_rangeEnd(range_end) 40 { 41 } 42 43 // Deprecated... Use the constructor above with both name and fam_name BoundaryConditionBoundaryCondition44 BoundaryCondition(std::string name, Ioss::IJK_t range_beg, Ioss::IJK_t range_end) 45 : m_bcName(name), m_famName(std::move(name)), m_rangeBeg(range_beg), m_rangeEnd(range_end) 46 { 47 } 48 49 // cereal requires a default constructor when de-serializing vectors of objects. Because 50 // StructuredBlock contains a vector of BoundaryCondition objects, this default constructor is 51 // necessary. 52 BoundaryCondition() = default; 53 54 BoundaryCondition(const BoundaryCondition ©_from) = default; 55 56 // Determine which "face" of the parent block this BC is applied to. 57 int which_face() const; 58 59 // Does range specify a valid face 60 bool is_valid() const; 61 62 // Return number of cell faces in the BC 63 size_t get_face_count() const; 64 65 bool operator==(const Ioss::BoundaryCondition &rhs) const; 66 bool operator!=(const Ioss::BoundaryCondition &rhs) const; 67 bool equal(const Ioss::BoundaryCondition &rhs) const; 68 69 std::string m_bcName{}; 70 std::string m_famName{}; 71 72 // These are potentially subsetted due to parallel decompositions... 73 Ioss::IJK_t m_rangeBeg{}; 74 Ioss::IJK_t m_rangeEnd{}; 75 76 mutable int m_face{-1}; 77 serializeBoundaryCondition78 template <class Archive> void serialize(Archive &archive) 79 { 80 archive(m_bcName, m_famName, m_rangeBeg, m_rangeEnd, m_face); 81 } 82 83 friend std::ostream &operator<<(std::ostream &os, const BoundaryCondition &bc); 84 85 private: 86 bool equal_(const Ioss::BoundaryCondition &rhs, bool quiet) const; 87 }; 88 89 class DatabaseIO; 90 91 /** \brief A structured zone -- i,j,k 92 */ 93 class StructuredBlock : public EntityBlock 94 { 95 public: 96 StructuredBlock(DatabaseIO *io_database, const std::string &my_name, int index_dim, int ni, 97 int nj, int nk, int off_i, int off_j, int off_k, int glo_ni, int glo_nj, 98 int glo_nk); 99 StructuredBlock(DatabaseIO *io_database, const std::string &my_name, int index_dim, 100 Ioss::IJK_t &ordinal, Ioss::IJK_t &offset, Ioss::IJK_t &global_ordinal); 101 102 // Useful for serial 103 StructuredBlock(DatabaseIO *io_database, const std::string &my_name, int index_dim, int ni, 104 int nj, int nk); 105 StructuredBlock(DatabaseIO *io_database, const std::string &my_name, int index_dim, 106 Ioss::IJK_t &ordinal); 107 108 StructuredBlock *clone(DatabaseIO *database) const; 109 110 ~StructuredBlock() override; 111 type_string()112 std::string type_string() const override { return "StructuredBlock"; } short_type_string()113 std::string short_type_string() const override { return "structuredblock"; } contains_string()114 std::string contains_string() const override { return "Cell"; } type()115 EntityType type() const override { return STRUCTUREDBLOCK; } 116 get_node_block()117 const Ioss::NodeBlock &get_node_block() const { return m_nodeBlock; } get_node_block()118 Ioss::NodeBlock & get_node_block() { return m_nodeBlock; } 119 120 /** \brief Does block contain any cells 121 */ is_active()122 bool is_active() const { return m_ni * m_nj * m_nk > 0; } 123 124 // Handle implicit properties -- These are calcuated from data stored 125 // in the grouping entity instead of having an explicit value assigned. 126 // An example would be 'element_block_count' for a region. 127 Property get_implicit_property(const std::string &my_name) const override; 128 129 AxisAlignedBoundingBox get_bounding_box() const; 130 131 /** \brief Set the 'offset' for the block. 132 * 133 * The 'offset' is used to map a cell or node location within a 134 * structured block to the model implicit cell or node location 135 * on a single processor. zero-based. 136 * 137 * The 'global' offsets do the same except for they apply over 138 * the entire model on all processors. zero-based. 139 * 140 * For example, the file descriptor (1-based) of 141 * the 37th cell in the 4th block is calculated by: 142 * 143 * file_descriptor = offset of block 4 + 37 144 * 145 * This can also be used to determine which structured block 146 * a cell with a file_descriptor maps into. An particular 147 * structured block contains all cells in the range: 148 * 149 * offset < file_descriptor <= offset+number_cells_per_block 150 * 151 * Note that for nodes, the nodeOffset does not take into account 152 * the nodes that are shared between blocks. 153 */ set_node_offset(size_t offset)154 void set_node_offset(size_t offset) { m_nodeOffset = offset; } set_cell_offset(size_t offset)155 void set_cell_offset(size_t offset) { m_cellOffset = offset; } set_node_global_offset(size_t offset)156 void set_node_global_offset(size_t offset) { m_nodeGlobalOffset = offset; } set_cell_global_offset(size_t offset)157 void set_cell_global_offset(size_t offset) { m_cellGlobalOffset = offset; } 158 get_node_offset()159 size_t get_node_offset() const { return m_nodeOffset; } get_cell_offset()160 size_t get_cell_offset() const { return m_cellOffset; } get_node_global_offset()161 size_t get_node_global_offset() const { return m_nodeGlobalOffset; } get_cell_global_offset()162 size_t get_cell_global_offset() const { return m_cellGlobalOffset; } 163 164 // Get the global (over all processors) cell 165 // id at the specified i,j,k location (1 <= i,j,k <= ni,nj,nk). 1-based. get_global_cell_id(int i,int j,int k)166 size_t get_global_cell_id(int i, int j, int k) const 167 { 168 return m_cellGlobalOffset + static_cast<size_t>(k - 1) * m_niGlobal * m_njGlobal + 169 static_cast<size_t>(j - 1) * m_niGlobal + i; 170 } 171 get_global_cell_id(IJK_t index)172 size_t get_global_cell_id(IJK_t index) const 173 { 174 return get_global_cell_id(index[0], index[1], index[2]); 175 } 176 177 // Get the global (over all processors) node 178 // offset at the specified i,j,k location (1 <= i,j,k <= ni,nj,nk). 0-based, does not account 179 // for shared nodes. get_global_node_offset(int i,int j,int k)180 size_t get_global_node_offset(int i, int j, int k) const 181 { 182 return m_nodeGlobalOffset + static_cast<size_t>(k - 1) * (m_niGlobal + 1) * (m_njGlobal + 1) + 183 static_cast<size_t>(j - 1) * (m_niGlobal + 1) + i - 1; 184 } 185 get_global_node_offset(IJK_t index)186 size_t get_global_node_offset(IJK_t index) const 187 { 188 return get_global_node_offset(index[0], index[1], index[2]); 189 } 190 191 // Get the local (relative to this block on this processor) node id at the specified 192 // i,j,k location (1 <= i,j,k <= ni+1,nj+1,nk+1). 0-based. get_block_local_node_offset(int ii,int jj,int kk)193 size_t get_block_local_node_offset(int ii, int jj, int kk) const 194 { 195 auto i = ii - m_offsetI; 196 auto j = jj - m_offsetJ; 197 auto k = kk - m_offsetK; 198 assert(i > 0 && i <= m_ni + 1 && j > 0 && j <= m_nj + 1 && k > 0 && k <= m_nk + 1); 199 return static_cast<size_t>(k - 1) * (m_ni + 1) * (m_nj + 1) + 200 static_cast<size_t>(j - 1) * (m_ni + 1) + i - 1; 201 } 202 get_block_local_node_offset(IJK_t index)203 size_t get_block_local_node_offset(IJK_t index) const 204 { 205 return get_block_local_node_offset(index[0], index[1], index[2]); 206 } 207 208 // Get the local (on this processor) cell-node offset at the specified 209 // i,j,k location (1 <= i,j,k <= ni+1,nj+1,nk+1). 0-based. get_local_node_offset(int i,int j,int k)210 size_t get_local_node_offset(int i, int j, int k) const 211 { 212 return get_block_local_node_offset(i, j, k) + m_nodeOffset; 213 } 214 get_local_node_offset(IJK_t index)215 size_t get_local_node_offset(IJK_t index) const 216 { 217 return get_local_node_offset(index[0], index[1], index[2]); 218 } 219 get_cell_node_ids(bool add_offset)220 std::vector<INT> get_cell_node_ids(bool add_offset) const 221 { 222 size_t node_count = get_property("node_count").get_int(); 223 std::vector<INT> ids(node_count); 224 get_cell_node_ids(ids.data(), add_offset); 225 return ids; 226 } 227 get_cell_node_ids(INT_t * idata,bool add_offset)228 template <typename INT_t> size_t get_cell_node_ids(INT_t *idata, bool add_offset) const 229 { 230 // Fill 'idata' with the cell node ids which are the 231 // 1-based location of each node in this zone 232 // The location is based on the "model" (all processors) zone. 233 // If this is a parallel decomposed model, then 234 // this block may be a subset of the "model" zone 235 // 236 // if 'add_offset' is true, then add the m_cellGlobalOffset 237 // which changes the location to be the location in the 238 // entire "mesh" instead of within a "zone" (all processors) 239 240 size_t index = 0; 241 size_t offset = add_offset ? m_nodeGlobalOffset : 0; 242 243 if (m_nk == 0 && m_nj == 0 && m_ni == 0) { 244 return index; 245 } 246 247 for (int kk = 0; kk < m_nk + 1; kk++) { 248 size_t k = m_offsetK + kk; 249 for (int jj = 0; jj < m_nj + 1; jj++) { 250 size_t j = m_offsetJ + jj; 251 for (int ii = 0; ii < m_ni + 1; ii++) { 252 size_t i = m_offsetI + ii; 253 254 size_t ind = k * (m_niGlobal + 1) * (m_njGlobal + 1) + j * (m_niGlobal + 1) + i; 255 256 idata[index++] = ind + offset + 1; 257 } 258 } 259 } 260 261 for (auto idx_id : m_globalIdMap) { 262 idata[idx_id.first] = idx_id.second; 263 } 264 265 return index; 266 } 267 get_cell_ids(INT_t * idata,bool add_offset)268 template <typename INT_t> size_t get_cell_ids(INT_t *idata, bool add_offset) const 269 { 270 // Fill 'idata' with the cell ids which are the 271 // 1-based location of each cell in this zone 272 // The location is based on the "model" zone. 273 // If this is a parallel decomposed model, then 274 // this block may be a subset of the "model" zone 275 // 276 // if 'add_offset' is true, then add the m_cellGlobalOffset 277 // which changes the location to be the location in the 278 // entire "mesh" instead of within a "zone" 279 280 size_t index = 0; 281 size_t offset = add_offset ? m_cellGlobalOffset : 0; 282 283 if (m_nk == 0 && m_nj == 0 && m_ni == 0) { 284 return index; 285 } 286 287 for (int kk = 0; kk < m_nk; kk++) { 288 size_t k = m_offsetK + kk; 289 for (int jj = 0; jj < m_nj; jj++) { 290 size_t j = m_offsetJ + jj; 291 for (int ii = 0; ii < m_ni; ii++) { 292 size_t i = m_offsetI + ii; 293 294 size_t ind = k * m_niGlobal * m_njGlobal + j * m_niGlobal + i; 295 296 idata[index++] = ind + offset + 1; 297 } 298 } 299 } 300 return index; 301 } 302 contains(size_t global_offset)303 bool contains(size_t global_offset) const 304 { 305 return (global_offset >= m_nodeOffset && 306 global_offset < m_nodeOffset + get_property("node_count").get_int()); 307 } 308 309 /* COMPARE two StructuredBlocks */ 310 bool operator==(const Ioss::StructuredBlock &rhs) const; 311 bool operator!=(const Ioss::StructuredBlock &rhs) const; 312 bool equal(const Ioss::StructuredBlock &rhs) const; 313 314 protected: 315 int64_t internal_get_field_data(const Field &field, void *data, 316 size_t data_size) const override; 317 318 int64_t internal_put_field_data(const Field &field, void *data, 319 size_t data_size) const override; 320 321 private: 322 bool equal_(const Ioss::StructuredBlock &rhs, bool quiet) const; 323 int m_ni{}; 324 int m_nj{}; 325 int m_nk{}; 326 327 int m_offsetI{}; // Valid 'i' ordinal runs from m_offsetI+1 to m_offsetI+m_ni 328 int m_offsetJ{}; 329 int m_offsetK{}; 330 331 int m_niGlobal{}; // The ni,nj,nk of the master block this is a subset of. 332 int m_njGlobal{}; 333 int m_nkGlobal{}; 334 335 size_t m_nodeOffset{}; 336 size_t m_cellOffset{}; 337 338 size_t m_nodeGlobalOffset{}; 339 size_t m_cellGlobalOffset{}; 340 341 Ioss::NodeBlock m_nodeBlock; 342 343 public: 344 std::vector<ZoneConnectivity> m_zoneConnectivity; 345 std::vector<BoundaryCondition> m_boundaryConditions; 346 std::vector<size_t> m_blockLocalNodeIndex; 347 std::vector<std::pair<size_t, size_t>> m_globalIdMap; 348 serialize(Archive & archive)349 template <class Archive> void serialize(Archive &archive) 350 { 351 archive(m_zoneConnectivity, m_boundaryConditions, m_blockLocalNodeIndex, m_globalIdMap); 352 } 353 }; 354 } // namespace Ioss 355 #endif 356