diff --git a/src/libs/blueprint/conduit_blueprint_mesh_examples.cpp b/src/libs/blueprint/conduit_blueprint_mesh_examples.cpp index 4daf48567..c280b5163 100644 --- a/src/libs/blueprint/conduit_blueprint_mesh_examples.cpp +++ b/src/libs/blueprint/conduit_blueprint_mesh_examples.cpp @@ -3421,6 +3421,165 @@ adjset_uniform(Node &res) } } +//----------------------------------------------------------------------------- +void +polyhedral_chain(index_t howmany, // how long the chain ought to be + Node &chain) +{ + Node &chain_coords = chain["coordsets/coords"]; + Node &chain_topo = chain["topologies/topo"]; + Node &chain_fields = chain["fields"]; + + chain_coords["type"] = "explicit"; + + // Each cube requires 8 vertices, and each triangular prism requires 6 + // There are two prisms for every cube, so 8+6+6 = 20 vertices + chain_coords["values/x"].set(conduit::DataType::int64(howmany * 20)); + chain_coords["values/y"].set(conduit::DataType::int64(howmany * 20)); + chain_coords["values/z"].set(conduit::DataType::int64(howmany * 20)); + + int64* values_x = chain_coords["values/x"].value(); + int64* values_y = chain_coords["values/y"].value(); + int64* values_z = chain_coords["values/z"].value(); + + for (int i = 0; i < howmany; i ++) + { + // points for the cubes + values_x[i * 20] = 1 + i * 2; values_y[i * 20] = 1; values_z[i * 20] = 1 + i * 2; + values_x[i * 20 + 1] = 1 + i * 2; values_y[i * 20 + 1] = 1; values_z[i * 20 + 1] = -1 + i * 2; + values_x[i * 20 + 2] = -1 + i * 2; values_y[i * 20 + 2] = 1; values_z[i * 20 + 2] = -1 + i * 2; + values_x[i * 20 + 3] = -1 + i * 2; values_y[i * 20 + 3] = 1; values_z[i * 20 + 3] = 1 + i * 2; + values_x[i * 20 + 4] = 1 + i * 2; values_y[i * 20 + 4] = -1; values_z[i * 20 + 4] = 1 + i * 2; + values_x[i * 20 + 5] = 1 + i * 2; values_y[i * 20 + 5] = -1; values_z[i * 20 + 5] = -1 + i * 2; + values_x[i * 20 + 6] = -1 + i * 2; values_y[i * 20 + 6] = -1; values_z[i * 20 + 6] = -1 + i * 2; + values_x[i * 20 + 7] = -1 + i * 2; values_y[i * 20 + 7] = -1; values_z[i * 20 + 7] = 1 + i * 2; + + // points for half the triangular prisms + values_x[i * 20 + 8] = 1 + i * 2; values_y[i * 20 + 8] = 1; values_z[i * 20 + 8] = -1 + i * 2 + 2; + values_x[i * 20 + 9] = -1 + i * 2; values_y[i * 20 + 9] = 1; values_z[i * 20 + 9] = -1 + i * 2 + 2; + values_x[i * 20 + 10] = -1 + i * 2 + 2; values_y[i * 20 + 10] = 1; values_z[i * 20 + 10] = 1 + i * 2 + 2; + values_x[i * 20 + 11] = 1 + i * 2; values_y[i * 20 + 11] = -1; values_z[i * 20 + 11] = -1 + i * 2 + 2; + values_x[i * 20 + 12] = -1 + i * 2; values_y[i * 20 + 12] = -1; values_z[i * 20 + 12] = -1 + i * 2 + 2; + values_x[i * 20 + 13] = -1 + i * 2 + 2; values_y[i * 20 + 13] = -1; values_z[i * 20 + 13] = 1 + i * 2 + 2; + + // points for the other half + values_x[i * 20 + 14] = 1 + i * 2; values_y[i * 20 + 14] = 1; values_z[i * 20 + 14] = -1 + i * 2 + 2; + values_x[i * 20 + 15] = -1 + i * 2 + 2; values_y[i * 20 + 15] = 1; values_z[i * 20 + 15] = -1 + i * 2; + values_x[i * 20 + 16] = -1 + i * 2 + 4; values_y[i * 20 + 16] = 1; values_z[i * 20 + 16] = 1 + i * 2; + values_x[i * 20 + 17] = 1 + i * 2; values_y[i * 20 + 17] = -1; values_z[i * 20 + 17] = -1 + i * 2 + 2; + values_x[i * 20 + 18] = -1 + i * 2 + 2; values_y[i * 20 + 18] = -1; values_z[i * 20 + 18] = -1 + i * 2; + values_x[i * 20 + 19] = -1 + i * 2 + 4; values_y[i * 20 + 19] = -1; values_z[i * 20 + 19] = 1 + i * 2; + } + + chain_topo["type"] = "unstructured"; + chain_topo["coordset"] = "coords"; + chain_topo["elements/shape"] = "polyhedral"; + + // 6 cube faces + 5 prism faces * 2 prisms makes 16 + chain_topo["elements/connectivity"].set(conduit::DataType::int64(howmany * 16)); + int64* connec = chain_topo["elements/connectivity"].value(); + for (int i = 0; i < howmany * 16; i ++) + { + // our faces are specified in order and no faces are reused + connec[i] = i; + } + + // this is 3 because every time howmany is increased by 1, 3 more polyhedra are added, + // the cube and two prisms + chain_topo["elements/sizes"].set(conduit::DataType::int64(howmany * 3)); + int64* sizes = chain_topo["elements/sizes"].value(); + for (int i = 0; i < howmany * 3; i ++) + { + // this ensures that sizes will be of the form {6,5,5, 6,5,5, 6,5,5, ..., 6,5,5} + sizes[i] = ((i % 3) > 0) ? 5 : 6; + } + + chain_topo["elements/offsets"].set(conduit::DataType::int64(howmany * 3)); + int64* offsets = chain_topo["elements/offsets"].value(); + offsets[0] = 0; + for (int i = 1; i < howmany * 3; i ++) + { + offsets[i] = offsets[i - 1] + sizes[i - 1]; + } + + chain_topo["subelements/shape"] = "polygonal"; + // 24 points -> 6 sides -> a cube + // 18 points -> 5 sides -> triangular prism + // so 24 + 18 * 2 = 60 + chain_topo["subelements/connectivity"].set(conduit::DataType::int64(howmany * 60)); + int64* sub_connec = chain_topo["subelements/connectivity"].value(); + for (int i = 0; i < howmany; i ++) + { + // CUBE + // top // bottom + sub_connec[i * 60] = 0 + i * 20; sub_connec[i * 60 + 4] = 4 + i * 20; + sub_connec[i * 60 + 1] = 1 + i * 20; sub_connec[i * 60 + 5] = 5 + i * 20; + sub_connec[i * 60 + 2] = 2 + i * 20; sub_connec[i * 60 + 6] = 6 + i * 20; + sub_connec[i * 60 + 3] = 3 + i * 20; sub_connec[i * 60 + 7] = 7 + i * 20; + + // side where x = 1 // side where x = -1 + sub_connec[i * 60 + 8] = 0 + i * 20; sub_connec[i * 60 + 12] = 2 + i * 20; + sub_connec[i * 60 + 9] = 1 + i * 20; sub_connec[i * 60 + 13] = 3 + i * 20; + sub_connec[i * 60 + 10] = 5 + i * 20; sub_connec[i * 60 + 14] = 7 + i * 20; + sub_connec[i * 60 + 11] = 4 + i * 20; sub_connec[i * 60 + 15] = 6 + i * 20; + + // side where z = 1 // side where z = -1 + sub_connec[i * 60 + 16] = 0 + i * 20; sub_connec[i * 60 + 20] = 1 + i * 20; + sub_connec[i * 60 + 17] = 3 + i * 20; sub_connec[i * 60 + 21] = 2 + i * 20; + sub_connec[i * 60 + 18] = 7 + i * 20; sub_connec[i * 60 + 22] = 6 + i * 20; + sub_connec[i * 60 + 19] = 4 + i * 20; sub_connec[i * 60 + 23] = 5 + i * 20; + + // PRISM 1 + sub_connec[i * 60 + 24] = 9 + i * 20; sub_connec[i * 60 + 28] = 8 + i * 20; sub_connec[i * 60 + 32] = 8 + i * 20; + sub_connec[i * 60 + 25] = 10 + i * 20; sub_connec[i * 60 + 29] = 9 + i * 20; sub_connec[i * 60 + 33] = 10 + i * 20; + sub_connec[i * 60 + 26] = 13 + i * 20; sub_connec[i * 60 + 30] = 12 + i * 20; sub_connec[i * 60 + 34] = 13 + i * 20; + sub_connec[i * 60 + 27] = 12 + i * 20; sub_connec[i * 60 + 31] = 11 + i * 20; sub_connec[i * 60 + 35] = 11 + i * 20; + + sub_connec[i * 60 + 36] = 8 + i * 20; sub_connec[i * 60 + 39] = 11 + i * 20; + sub_connec[i * 60 + 37] = 9 + i * 20; sub_connec[i * 60 + 40] = 12 + i * 20; + sub_connec[i * 60 + 38] = 10 + i * 20; sub_connec[i * 60 + 41] = 13 + i * 20; + + // PRISM 2 + sub_connec[i * 60 + 42] = 15 + i * 20; sub_connec[i * 60 + 46] = 14 + i * 20; sub_connec[i * 60 + 50] = 14 + i * 20; + sub_connec[i * 60 + 43] = 16 + i * 20; sub_connec[i * 60 + 47] = 15 + i * 20; sub_connec[i * 60 + 51] = 16 + i * 20; + sub_connec[i * 60 + 44] = 19 + i * 20; sub_connec[i * 60 + 48] = 18 + i * 20; sub_connec[i * 60 + 52] = 19 + i * 20; + sub_connec[i * 60 + 45] = 18 + i * 20; sub_connec[i * 60 + 49] = 17 + i * 20; sub_connec[i * 60 + 53] = 17 + i * 20; + + sub_connec[i * 60 + 54] = 14 + i * 20; sub_connec[i * 60 + 57] = 17 + i * 20; + sub_connec[i * 60 + 55] = 15 + i * 20; sub_connec[i * 60 + 58] = 18 + i * 20; + sub_connec[i * 60 + 56] = 16 + i * 20; sub_connec[i * 60 + 59] = 19 + i * 20; + } + + chain_topo["subelements/sizes"].set(conduit::DataType::int64(howmany * 16)); + int64* sub_sizes = chain_topo["subelements/sizes"].value(); + for (int i = 0; i < howmany * 16; i ++) + { + // this ensures sizes will be of the form {4,4,4,4,4,4,4,4,4,3,3,4,4,4,3,3, 4,4,4,4,4,4,4,4,4,3,3,4,4,4,3,3, ...} + int imod16 = i % 16; + sub_sizes[i] = ((imod16 < 9) || ((imod16 > 10) && (imod16 < 14))) ? 4 : 3; + } + + chain_topo["subelements/offsets"].set(conduit::DataType::int64(howmany * 16)); + int64* sub_offsets = chain_topo["subelements/offsets"].value(); + sub_offsets[0] = 0; + for (int i = 1; i < howmany * 16; i ++) + { + sub_offsets[i] = sub_offsets[i - 1] + sub_sizes[i - 1]; + } + + chain_fields["chain/topology"] = "topo"; + chain_fields["chain/association"] = "element"; + chain_fields["chain/volume_dependent"] = "false"; + chain_fields["chain/values"].set(conduit::DataType::int64(howmany * 3)); + int64* field_values = chain_fields["chain/values"].value(); + + for (int i = 0; i < howmany * 3; i ++) + { + // ensures that the field is of the form {0,1,1, 0,1,1, ..., 0,1,1} + field_values[i] = (i % 3) == 0 ? 0 : 1; + } +} + } //----------------------------------------------------------------------------- // -- end conduit::blueprint::mesh::examples -- diff --git a/src/libs/blueprint/conduit_blueprint_mesh_examples.hpp b/src/libs/blueprint/conduit_blueprint_mesh_examples.hpp index ddbec5e1b..e06be51a8 100644 --- a/src/libs/blueprint/conduit_blueprint_mesh_examples.hpp +++ b/src/libs/blueprint/conduit_blueprint_mesh_examples.hpp @@ -80,6 +80,10 @@ namespace examples /// Generates a mesh that uses uniform adjsets void CONDUIT_BLUEPRINT_API adjset_uniform(conduit::Node &res); + + // Generates a chain of cubes and triangular prisms + void CONDUIT_BLUEPRINT_API polyhedral_chain(conduit::index_t howmany, + conduit::Node &chain); } //----------------------------------------------------------------------------- // -- end conduit::blueprint::mesh::examples -- diff --git a/src/tests/blueprint/t_blueprint_mesh_examples.cpp b/src/tests/blueprint/t_blueprint_mesh_examples.cpp index 76700acec..d838e140e 100644 --- a/src/tests/blueprint/t_blueprint_mesh_examples.cpp +++ b/src/tests/blueprint/t_blueprint_mesh_examples.cpp @@ -966,6 +966,21 @@ TEST(conduit_blueprint_mesh_examples, number_of_domains) } +//----------------------------------------------------------------------------- +TEST(conduit_blueprint_mesh_examples, polyhedral_chain) +{ + Node res; + blueprint::mesh::examples::polyhedral_chain(7, // number of cubes + res); + + Node info; + EXPECT_TRUE(blueprint::mesh::verify(res,info)); + CONDUIT_INFO(info.to_yaml()); + + test_save_mesh_helper(res,"polyhedral_chain_example"); +} + + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) {