// Copyright(C) 1999-2023 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Ioss_FieldManager.h" #include "Ioss_ParallelUtils.h" #include "Ioss_PropertyManager.h" /** \brief Create a side block. * * \param[in] io_database The database associated with the region containing the side block. * \param[in] my_name The side block's name. * \param[in] side_type The name of the side topology type for the side block. * \param[in] element_type The name of the element topology of the parent element type for the side * block. * \param[in] side_count The number of sides in the side block. */ Ioss::SideBlock::SideBlock(Ioss::DatabaseIO *io_database, const std::string &my_name, const std::string &side_type, const std::string &element_type, size_t side_count) : Ioss::EntityBlock(io_database, my_name, side_type, side_count) { parentTopology_ = ElementTopology::factory(element_type); assert(parentTopology_ != nullptr); properties.add(Ioss::Property(this, "parent_topology_type", Ioss::Property::STRING)); properties.add(Ioss::Property(this, "distribution_factor_count", Ioss::Property::INTEGER)); fields.add(Ioss::Field("element_side", field_int_type(), "pair", Ioss::Field::MESH, side_count)); // Same as element_side except that the element id are the local // element position (1-based) and not the global element id. fields.add( Ioss::Field("element_side_raw", field_int_type(), "pair", Ioss::Field::MESH, side_count)); // Distribution factors are optional... } Ioss::SideBlock::SideBlock(const Ioss::SideBlock &other) : EntityBlock(other), parentTopology_(other.parentTopology_), consistentSideNumber(other.consistentSideNumber) { } std::string Ioss::SideBlock::generate_sideblock_name(const std::string &sideset_name, const std::string &block_or_element, const std::string &face_topology_name) { // The naming of sideblocks is: // * If name is of form surface_{id}, // * then {surface} + _ + block-or-element-topology + _ + side_topology + _ + {id} // * Eg – surface_1 would have sideblocks surface_block_1_quad_1 // // * If name is not of that form (e.g. surface_1_foam or “gregs_liner”) then: // * Name + _ + block-or-element-topology + _ + side_topology // * Eg surface_1_foam_block_1_edge2, surface_1_foam_quad4_edge2 // * Eg gregs_liner_block_1_edge2, gregs_liner_quad4_edge2 // Check whether the `block_or_element` portion of the name names a valid element topology... std::string tmp_block_or_element = block_or_element; auto *element_topology = ElementTopology::factory(block_or_element); if (element_topology != nullptr) { tmp_block_or_element = element_topology->name(); } // Verify that `face_topology_name` is a valid topology and Get its "non-aliased" name. std::string tmp_face_topology = face_topology_name; auto *face_topology = ElementTopology::factory(face_topology_name); if (face_topology != nullptr) { tmp_face_topology = face_topology->name(); } else { std::ostringstream errmsg; fmt::print(errmsg, "ERROR: Invalid face topology '{}' in function {}.\n", face_topology_name, __func__); IOSS_ERROR(errmsg); } auto tokens = Ioss::tokenize(sideset_name, "_"); if (tokens.size() == 2) { bool all_dig = tokens[1].find_first_not_of("0123456789") == std::string::npos; if (all_dig && Ioss::Utils::str_equal(tokens[0], "surface")) { std::string sideblock_name = tokens[0] + "_" + tmp_block_or_element + "_" + tmp_face_topology + "_" + tokens[1]; return sideblock_name; } } std::string sideblock_name = sideset_name + "_" + tmp_block_or_element + "_" + tmp_face_topology; return sideblock_name; } int64_t Ioss::SideBlock::internal_get_field_data(const Ioss::Field &field, void *data, size_t data_size) const { return get_database()->get_field(this, field, data, data_size); } int64_t Ioss::SideBlock::internal_put_field_data(const Ioss::Field &field, void *data, size_t data_size) const { return get_database()->put_field(this, field, data, data_size); } int64_t Ioss::SideBlock::internal_get_zc_field_data(const Field &field, void **data, size_t *data_size) const { return get_database()->get_zc_field(this, field, data, data_size); } Ioss::Property Ioss::SideBlock::get_implicit_property(const std::string &my_name) const { if (my_name == "distribution_factor_count") { if (field_exists("distribution_factors")) { int64_t nnodes = topology()->number_nodes(); int64_t nside = entity_count(); return Ioss::Property(my_name, nnodes * nside); } return Ioss::Property(my_name, 0); } if (my_name == "parent_topology_type") { return Ioss::Property(my_name, parent_element_topology()->name()); } return Ioss::EntityBlock::get_implicit_property(my_name); } void Ioss::SideBlock::block_membership(std::vector &block_members) { // Simplest case. If the surfaces are split by element block, then this will // return non-null // and we are done. const Ioss::EntityBlock *eb = parent_block(); if (eb != nullptr) { block_members.push_back(eb->name()); return; } if (blockMembership.empty()) { get_database()->compute_block_membership(this, blockMembership); } block_members = blockMembership; } namespace { template int internal_consistent_side_number(std::vector &element_side) { size_t ecount = element_side.size(); int side = ecount > 0 ? static_cast(element_side[1]) : 0; for (size_t i = 3; i < ecount; i += 2) { int this_side = static_cast(element_side[i]); if (this_side != side) { side = 999; // Indicates the sides are not consistent ; break; } } return side; } } // namespace int Ioss::SideBlock::get_consistent_side_number() const { if (consistentSideNumber == -1) { // It wasn't calculated during the metadata reading of the surfaces. // Determine it now... if (field_exists("element_side")) { int side = 0; if (get_database()->int_byte_size_api() == 8) { std::vector element_side; get_field_data("element_side", element_side); side = internal_consistent_side_number(element_side); } else { std::vector element_side; get_field_data("element_side", element_side); side = internal_consistent_side_number(element_side); } int side_max = get_database()->util().global_minmax(side, Ioss::ParallelUtils::DO_MAX); if (side_max != 999) { consistentSideNumber = side_max; } else { consistentSideNumber = 0; } } else { consistentSideNumber = 0; } } return consistentSideNumber; } bool Ioss::SideBlock::equal_(const Ioss::SideBlock &rhs, bool quiet) const { if (this->parentTopology_ != rhs.parentTopology_) { if (!quiet) { fmt::print(Ioss::OUTPUT(), "SideBlock: parentTopology_ mismatch\n"); } return false; } if (this->blockMembership != rhs.blockMembership) { if (!quiet) { fmt::print(Ioss::OUTPUT(), "SideBlock: blockMembership mismatch\n"); } return false; } if (this->consistentSideNumber != rhs.consistentSideNumber) { if (!quiet) { fmt::print(Ioss::OUTPUT(), "SideBlock: consistentSideNumber mismatch ({} vs. {})\n", this->consistentSideNumber, rhs.consistentSideNumber); } return false; } if (!quiet) { return Ioss::EntityBlock::equal(rhs); } else { return Ioss::EntityBlock::operator==(rhs); } } bool Ioss::SideBlock::operator==(const Ioss::SideBlock &rhs) const { return equal_(rhs, true); } bool Ioss::SideBlock::operator!=(const Ioss::SideBlock &rhs) const { return !(*this == rhs); } bool Ioss::SideBlock::equal(const Ioss::SideBlock &rhs) const { return equal_(rhs, false); }