You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
8.5 KiB
248 lines
8.5 KiB
2 years ago
|
// 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 <Ioss_DatabaseIO.h>
|
||
|
#include <Ioss_ElementBlock.h>
|
||
|
#include <Ioss_ElementTopology.h>
|
||
|
#include <Ioss_EntityBlock.h>
|
||
|
#include <Ioss_Field.h>
|
||
|
#include <Ioss_Property.h>
|
||
|
#include <Ioss_SideBlock.h>
|
||
|
#include <cassert>
|
||
|
#include <cstddef>
|
||
|
#include <fmt/ostream.h>
|
||
|
#include <string>
|
||
|
#include <tokenize.h>
|
||
|
#include <vector>
|
||
|
|
||
|
#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<std::string> &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 <typename INT> int internal_consistent_side_number(std::vector<INT> &element_side)
|
||
|
{
|
||
|
size_t ecount = element_side.size();
|
||
|
int side = ecount > 0 ? static_cast<INT>(element_side[1]) : 0;
|
||
|
for (size_t i = 3; i < ecount; i += 2) {
|
||
|
int this_side = static_cast<INT>(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<int64_t> element_side;
|
||
|
get_field_data("element_side", element_side);
|
||
|
side = internal_consistent_side_number(element_side);
|
||
|
}
|
||
|
else {
|
||
|
std::vector<int> 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); }
|