From 8bf64a6a10251f9f7412cfeea298125a7c250dda Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Mon, 15 Apr 2024 15:39:48 -0600 Subject: [PATCH] Io modify handle cgns (#453) * IOSS: io_modify - try to get cgns structured mesh coordinate mods working * IOSS: io_modify - fix coordinate modification routines * IOSS: io_modify - try to handle block geometry modify in cgns * IOSS: io_info -- bbox works for structured mesh * IOSS: io_modify - redo geometry transformation code --------- Co-authored-by: Greg Sjaardema --- .../seacas/libraries/ioss/src/main/io_info.C | 2 +- .../libraries/ioss/src/main/io_modify.C | 302 ++++++++++++------ 2 files changed, 213 insertions(+), 91 deletions(-) diff --git a/packages/seacas/libraries/ioss/src/main/io_info.C b/packages/seacas/libraries/ioss/src/main/io_info.C index b44c492595..e3dabc7cbd 100644 --- a/packages/seacas/libraries/ioss/src/main/io_info.C +++ b/packages/seacas/libraries/ioss/src/main/io_info.C @@ -267,7 +267,7 @@ namespace { Ioss::Utils::info_fields(&nb, Ioss::Field::TRANSIENT, prefix + "\tTransient: ", "\n\t\t" + prefix); - if (interFace.compute_bbox()) { + if (interFace.compute_bbox() && region.mesh_type() != Ioss::MeshType::STRUCTURED) { print_bbox(nb); } } diff --git a/packages/seacas/libraries/ioss/src/main/io_modify.C b/packages/seacas/libraries/ioss/src/main/io_modify.C index f0273c018a..698302263f 100644 --- a/packages/seacas/libraries/ioss/src/main/io_modify.C +++ b/packages/seacas/libraries/ioss/src/main/io_modify.C @@ -71,7 +71,7 @@ using real = double; namespace { std::string codename; - std::string version = "2.06 (2024-04-01)"; + std::string version = "2.07 (2024-04-15)"; std::vector attributes_modified; @@ -133,11 +133,11 @@ namespace { void modify_time(Ioss::Region ®ion, double scale, double offset); void offset_filtered_coordinates(Ioss::Region ®ion, real offset[3], - const std::vector &filter); + const std::vector &blocks); void scale_filtered_coordinates(Ioss::Region ®ion, real scale[3], - const std::vector &filter); + const std::vector &blocks); void rotate_filtered_coordinates(Ioss::Region ®ion, real rotation_matrix[3][3], - const std::vector &filter); + const std::vector &blocks); bool update_rotation_matrix(real rotation_matrix[3][3], const std::string &axis, double angle); void set_db_properties(const Modify::Interface &interFace, Ioss::DatabaseIO *dbi); @@ -660,11 +660,12 @@ namespace { fmt::print(fmt::emphasis::bold, "\tGEOMETRY OFFSET "); fmt::print("{{X|Y|Z}} {{offset}} ...\n"); fmt::print(fmt::emphasis::bold, "\tGEOMETRY ROTATE "); - fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} {{angle}} ...\n"); + fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} {{angle}}\n"); fmt::print(fmt::emphasis::bold, "\tGEOMETRY MIRROR "); fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} ...\n"); fmt::print(fmt::emphasis::bold, "\tGEOMETRY SCALE "); - fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} {{scale_factor}} ...\n"); + fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} {{scale_factor}} ... " + "\n"); fmt::print(fmt::emphasis::bold, "\tGEOMETRY OFFSET "); fmt::print("{{ELEMENTBLOCKS|BLOCKS|ASSEMBLY}} {{names}} {{X|Y|Z}} {{offset}} ...\n"); } @@ -705,8 +706,7 @@ namespace { else if (Ioss::Utils::substr_equal(tokens[1], "region")) { info_entity(region, show_attribute); } - else if (Ioss::Utils::substr_equal(tokens[1], "elementblock") || - Ioss::Utils::substr_equal(tokens[1], "block")) { + else if (Ioss::Utils::substr_equal(tokens[1], "elementblock")) { const auto &entities = region.get_element_blocks(); info_entities(entities, tokens, region, "Element Blocks", show_attribute); } @@ -728,6 +728,17 @@ namespace { const auto &entities = region.get_structured_blocks(); info_entities(entities, tokens, region, "Structured Blocks", show_attribute); } + else if (Ioss::Utils::substr_equal(tokens[1], "blocks")) { + const auto type = region.mesh_type(); + if (type == Ioss::MeshType::UNSTRUCTURED) { + const auto &entities = region.get_element_blocks(); + info_entities(entities, tokens, region, "Element Blocks", show_attribute); + } + else if (type == Ioss::MeshType::STRUCTURED) { + const auto &entities = region.get_structured_blocks(); + info_entities(entities, tokens, region, "Structured Blocks", show_attribute); + } + } else if (Ioss::Utils::substr_equal(tokens[1], "sideset") || Ioss::Utils::substr_equal(tokens[1], "sset")) { const auto &entities = region.get_sidesets(); @@ -1144,7 +1155,7 @@ namespace { } void build_block_list(Ioss::Region ®ion, const Ioss::GroupingEntity *ge, - std::vector &blocks) + std::vector &blocks) { if (ge) { if (ge->type() == Ioss::ELEMENTBLOCK) { @@ -1154,6 +1165,13 @@ namespace { } return; } + else if (ge->type() == Ioss::STRUCTUREDBLOCK) { + auto *sb = dynamic_cast(ge); + if (sb != nullptr) { + blocks.push_back(sb); + } + return; + } else if (ge->type() == Ioss::ASSEMBLY) { auto *as = dynamic_cast(ge); const auto &members = as->get_members(); @@ -1165,9 +1183,13 @@ namespace { } } - std::vector get_filtered_node_list(Ioss::Region ®ion, - std::vector &blocks) + std::vector get_filtered_node_list(Ioss::Region ®ion, + const std::vector &blocks) { + const auto type = region.get_database()->get_format(); + if (type != "Exodus") { + return std::vector(); + } auto node_count = region.get_property("node_count").get_int(); if (blocks.empty() || blocks.size() == (size_t)region.get_property("element_block_count").get_int()) { @@ -1255,10 +1277,13 @@ namespace { return false; } + const auto type = region.mesh_type(); + // See if applying just selected (and connected) blocks. - size_t idx = 2; - std::vector blocks; + size_t idx = 2; + std::vector blocks; if (Ioss::Utils::substr_equal(tokens[idx], "elementblocks") || + Ioss::Utils::substr_equal(tokens[idx], "structuredblocks") || Ioss::Utils::substr_equal(tokens[idx], "blocks") || Ioss::Utils::substr_equal(tokens[idx], "assembly")) { // Parse list of block|assembly names... @@ -1267,7 +1292,9 @@ namespace { Ioss::Utils::str_equal(tokens[idx], "y") || Ioss::Utils::str_equal(tokens[idx], "z"))) { const auto &name = tokens[idx++]; - auto *ge = region.get_entity(name, Ioss::ELEMENTBLOCK); + auto *ge = + region.get_entity(name, type == Ioss::MeshType::UNSTRUCTURED ? Ioss::ELEMENTBLOCK + : Ioss::STRUCTUREDBLOCK); if (ge == nullptr) { ge = region.get_entity(name, Ioss::ASSEMBLY); } @@ -1281,50 +1308,58 @@ namespace { // If blocks is non-empty, then we are applying geometry modification to a subset of the model. // In that case, we need to get all blocks that are connected to the user-specified blocks... if (!blocks.empty()) { - std::vector tmp(blocks); - for (const auto *block : blocks) { - const auto &connected = block->get_block_adjacencies(); - for (const auto &connect : connected) { - auto *eb = region.get_element_block(connect); - tmp.push_back(eb); + if (type == Ioss::MeshType::UNSTRUCTURED) { + auto tmp(blocks); + for (const auto *block : blocks) { + auto *eb = dynamic_cast(block); + if (eb != nullptr) { + const auto &connected = eb->get_block_adjacencies(); + for (const auto &connect : connected) { + auto *elb = region.get_element_block(connect); + tmp.push_back(elb); + } + } } + Ioss::Utils::uniquify(tmp); + blocks = tmp; } - Ioss::Utils::uniquify(tmp); - blocks = tmp; } - if (blocks.empty() || - blocks.size() == (size_t)region.get_property("element_block_count").get_int()) { - fmt::print(fg(fmt::color::cyan), - "\n\t*** {} transformation will be applied to ALL element blocks.\n", tokens[1]); + if (blocks.empty()) { + fmt::print(fg(fmt::color::cyan), "\n\t*** {} transformation will be applied to ALL blocks.\n", + tokens[1]); } else { - fmt::print(fg(fmt::color::cyan), - "\n\t*** {} transformation will be applied to element blocks:\n\t", tokens[1]); + fmt::print(fg(fmt::color::cyan), "\n\t*** {} transformation will be applied to blocks:\n\t", + tokens[1]); for (const auto *block : blocks) { fmt::print(fg(fmt::color::cyan), "{}, ", block->name()); } fmt::print("\n"); } - // Now, filter the nodes to determine which nodes are connected to elements in the block list. - auto node_filter = get_filtered_node_list(region, blocks); - if (Ioss::Utils::substr_equal(tokens[1], "rotate")) { real rotation_matrix[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; // Get rotation axis... do { - const std::string &axis = tokens[idx++]; - double angle = std::stod(tokens[idx++]); - auto ok = update_rotation_matrix(rotation_matrix, axis, angle); + const std::string &axis = tokens[idx++]; + if (axis != "x" && axis != "y" && axis != "z" && axis != "X" && axis != "Y" && + axis != "Z") { + fmt::print(stderr, fg(fmt::color::red), + "ERROR: Unrecognized axis {}. Expected one of xyzXYZ.\n", axis); + handle_help("geometry"); + return false; + } + double angle = std::stod(tokens[idx++]); + auto ok = update_rotation_matrix(rotation_matrix, axis, angle); if (!ok) { return false; } } while (idx < tokens.size()); // Do the rotation... - rotate_filtered_coordinates(region, rotation_matrix, node_filter); + rotate_filtered_coordinates(region, rotation_matrix, blocks); fmt::print(fg(fmt::color::cyan), "\t*** Database coordinates rotated.\n"); return false; } @@ -1334,8 +1369,15 @@ namespace { // Get scale axis and scale factor... do { - const std::string &axis = tokens[idx++]; - double factor = std::stod(tokens[idx++]); + const std::string &axis = tokens[idx++]; + if (axis != "x" && axis != "y" && axis != "z" && axis != "X" && axis != "Y" && + axis != "Z") { + fmt::print(stderr, fg(fmt::color::red), + "ERROR: Unrecognized axis {}. Expected one of xyzXYZ.\n", axis); + handle_help("geometry"); + return false; + } + double factor = std::stod(tokens[idx++]); if (Ioss::Utils::substr_equal(axis, "x")) { scale[0] = factor; } @@ -1348,7 +1390,7 @@ namespace { } while (idx < tokens.size()); // Do the transformation... - scale_filtered_coordinates(region, scale, node_filter); + scale_filtered_coordinates(region, scale, blocks); fmt::print(fg(fmt::color::cyan), "\t*** Database coordinate(s) scaled.\n"); return false; } @@ -1359,6 +1401,13 @@ namespace { // Get mirror axis ... do { const std::string &axis = tokens[idx++]; + if (axis != "x" && axis != "y" && axis != "z" && axis != "X" && axis != "Y" && + axis != "Z") { + fmt::print(stderr, fg(fmt::color::red), + "ERROR: Unrecognized axis {}. Expected one of xyzXYZ.\n", axis); + handle_help("geometry"); + return false; + } if (Ioss::Utils::substr_equal(axis, "x")) { scale[0] = -1.0; } @@ -1371,7 +1420,7 @@ namespace { } while (idx < tokens.size()); // Do the transformation... - scale_filtered_coordinates(region, scale, node_filter); + scale_filtered_coordinates(region, scale, blocks); fmt::print(fg(fmt::color::cyan), "\t*** Database coordinate(s) mirrored.\n"); return false; } @@ -1381,8 +1430,15 @@ namespace { // Get offset axis and offset factor... do { - const std::string &axis = tokens[idx++]; - double factor = std::stod(tokens[idx++]); + const std::string &axis = tokens[idx++]; + if (axis != "x" && axis != "y" && axis != "z" && axis != "X" && axis != "Y" && + axis != "Z") { + fmt::print(stderr, fg(fmt::color::red), + "ERROR: Unrecognized axis {}. Expected one of xyzXYZ.\n", axis); + handle_help("geometry"); + return false; + } + double factor = std::stod(tokens[idx++]); if (Ioss::Utils::substr_equal(axis, "x")) { offset[0] = factor; } @@ -1395,7 +1451,7 @@ namespace { } while (idx < tokens.size()); // Do the transformation... - offset_filtered_coordinates(region, offset, node_filter); + offset_filtered_coordinates(region, offset, blocks); fmt::print(fg(fmt::color::cyan), "\t*** Database coordinate(s) offset.\n"); return false; } @@ -1736,96 +1792,162 @@ namespace { } } - void rotate_filtered_coordinates(Ioss::Region ®ion, real rotation_matrix[3][3], + void rotate_filtered_coordinates(const Ioss::GroupingEntity *nb, real rotation_matrix[3][3], const std::vector &filter) { - // `filter` is of size number of nodes. Value = 1 the rotate; value = 0 leave as is. - Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); - std::vector coord; + // `filter` is of size number of nodes. Value = 1 then rotate; value = 0 leave as is. // Get original coordinates... + std::vector coord; nb->get_field_data("mesh_model_coordinates", coord); - size_t node_count = nb->entity_count(); + size_t node_count = coord.size() / 3; // Do the rotation... for (size_t i = 0; i < node_count; i++) { - real x = coord[3 * i + 0]; - real y = coord[3 * i + 1]; - real z = coord[3 * i + 2]; - - real xn = x * rotation_matrix[0][0] + y * rotation_matrix[1][0] + z * rotation_matrix[2][0]; - real yn = x * rotation_matrix[0][1] + y * rotation_matrix[1][1] + z * rotation_matrix[2][1]; - real zn = x * rotation_matrix[0][2] + y * rotation_matrix[1][2] + z * rotation_matrix[2][2]; - - coord[3 * i + 0] = filter[i] * xn + (1 - filter[i]) * coord[3 * i + 0]; - coord[3 * i + 1] = filter[i] * yn + (1 - filter[i]) * coord[3 * i + 1]; - coord[3 * i + 2] = filter[i] * zn + (1 - filter[i]) * coord[3 * i + 2]; + if (filter.empty() || filter[i] == 1) { + real x = coord[3 * i + 0]; + real y = coord[3 * i + 1]; + real z = coord[3 * i + 2]; + + real xn = x * rotation_matrix[0][0] + y * rotation_matrix[1][0] + z * rotation_matrix[2][0]; + real yn = x * rotation_matrix[0][1] + y * rotation_matrix[1][1] + z * rotation_matrix[2][1]; + real zn = x * rotation_matrix[0][2] + y * rotation_matrix[1][2] + z * rotation_matrix[2][2]; + + coord[3 * i + 0] = xn; + coord[3 * i + 1] = yn; + coord[3 * i + 2] = zn; + } } // Output updated coordinates... nb->put_field_data("mesh_model_coordinates", coord); } - void offset_filtered_coordinates(Ioss::Region ®ion, real offset[3], + void rotate_filtered_coordinates(Ioss::Region ®ion, real rotation_matrix[3][3], + const std::vector &blocks) + { + const auto type = region.mesh_type(); + if (type == Ioss::MeshType::UNSTRUCTURED) { + auto filter = get_filtered_node_list(region, blocks); + Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); + rotate_filtered_coordinates(nb, rotation_matrix, filter); + } + else if (type == Ioss::MeshType::STRUCTURED) { + if (blocks.empty()) { + auto sblocks = region.get_structured_blocks(); + for (const auto &sb : sblocks) { + rotate_filtered_coordinates(sb, rotation_matrix, std::vector()); + } + } + else { + for (const auto &blk : blocks) { + auto *sb = dynamic_cast(blk); + if (sb != nullptr) { + rotate_filtered_coordinates(sb, rotation_matrix, std::vector()); + } + } + } + } + } + + void offset_filtered_coordinates(const Ioss::GroupingEntity *nb, real offset[3], const std::vector &filter) { // `filter` is of size number of nodes. Value = 1 transform; value = 0 leave as is. - Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); - std::vector coord; // Get original coordinates... + std::vector coord; nb->get_field_data("mesh_model_coordinates", coord); - size_t node_count = nb->entity_count(); + size_t node_count = coord.size() / 3; // Do the transformation... for (size_t i = 0; i < node_count; i++) { - real x = coord[3 * i + 0]; - real y = coord[3 * i + 1]; - real z = coord[3 * i + 2]; - - real xn = x + offset[0]; - real yn = y + offset[1]; - real zn = z + offset[2]; - - coord[3 * i + 0] = filter[i] * xn + (1 - filter[i]) * coord[3 * i + 0]; - coord[3 * i + 1] = filter[i] * yn + (1 - filter[i]) * coord[3 * i + 1]; - coord[3 * i + 2] = filter[i] * zn + (1 - filter[i]) * coord[3 * i + 2]; + if (filter.empty() || filter[i] == 1) { + coord[3 * i + 0] += offset[0]; + coord[3 * i + 1] += offset[1]; + coord[3 * i + 2] += offset[2]; + } } // Output updated coordinates... nb->put_field_data("mesh_model_coordinates", coord); } - void scale_filtered_coordinates(Ioss::Region ®ion, real scale[3], - const std::vector &filter) + void offset_filtered_coordinates(Ioss::Region ®ion, real offset[3], + const std::vector &blocks) { - // `filter` is of size number of nodes. Value = 1 transform; value = 0 leave as is. - Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); - std::vector coord; + const auto type = region.mesh_type(); + if (type == Ioss::MeshType::UNSTRUCTURED) { + auto filter = get_filtered_node_list(region, blocks); + Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); + offset_filtered_coordinates(nb, offset, filter); + } + else if (type == Ioss::MeshType::STRUCTURED) { + if (blocks.empty()) { + auto sblocks = region.get_structured_blocks(); + for (const auto &sb : sblocks) { + offset_filtered_coordinates(sb, offset, std::vector()); + } + } + else { + for (const auto &blk : blocks) { + auto *sb = dynamic_cast(blk); + if (sb != nullptr) { + offset_filtered_coordinates(sb, offset, std::vector()); + } + } + } + } + } + void scale_filtered_coordinates(const Ioss::GroupingEntity *nb, real scale[3], + const std::vector &filter) + { // Get original coordinates... + std::vector coord; nb->get_field_data("mesh_model_coordinates", coord); - size_t node_count = nb->entity_count(); + size_t node_count = coord.size() / 3; // Do the transformation... for (size_t i = 0; i < node_count; i++) { - real x = coord[3 * i + 0]; - real y = coord[3 * i + 1]; - real z = coord[3 * i + 2]; - - real xn = x * scale[0]; - real yn = y * scale[1]; - real zn = z * scale[2]; - - coord[3 * i + 0] = filter[i] * xn + (1 - filter[i]) * coord[3 * i + 0]; - coord[3 * i + 1] = filter[i] * yn + (1 - filter[i]) * coord[3 * i + 1]; - coord[3 * i + 2] = filter[i] * zn + (1 - filter[i]) * coord[3 * i + 2]; + if (filter.empty() || filter[i] == 1) { + coord[3 * i + 0] *= scale[0]; + coord[3 * i + 1] *= scale[1]; + coord[3 * i + 2] *= scale[2]; + } } // Output updated coordinates... nb->put_field_data("mesh_model_coordinates", coord); } + void scale_filtered_coordinates(Ioss::Region ®ion, real scale[3], + const std::vector &blocks) + { + const auto type = region.mesh_type(); + if (type == Ioss::MeshType::UNSTRUCTURED) { + auto filter = get_filtered_node_list(region, blocks); + Ioss::NodeBlock *nb = region.get_node_block("nodeblock_1"); + scale_filtered_coordinates(nb, scale, filter); + } + else if (type == Ioss::MeshType::STRUCTURED) { + if (blocks.empty()) { + auto sblocks = region.get_structured_blocks(); + for (const auto &sb : sblocks) { + scale_filtered_coordinates(sb, scale, std::vector()); + } + } + else { + for (const auto &blk : blocks) { + auto *sb = dynamic_cast(blk); + if (sb != nullptr) { + scale_filtered_coordinates(sb, scale, std::vector()); + } + } + } + } + } + bool update_rotation_matrix(real rotation_matrix[3][3], const std::string &axis, double angle) { int n1 = 0;