From 52dbb3d0e43729811e53b62b418ca00066b292bd Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Mon, 10 Nov 2025 10:54:54 +0100 Subject: [PATCH 1/9] Implement mesh deformation: add new file and adjust related code --- example/CMakeLists.txt | 1 + .../t8_cmesh_mesh_deformation_example.cxx | 68 ++++++ src/CMakeLists.txt | 3 +- .../t8_cmesh_mesh_deformation.cxx | 198 ++++++++++++++++++ .../t8_cmesh_mesh_deformation.hxx | 75 +++++++ .../t8_cmesh_vertex_connectivity.hxx | 17 ++ src/t8_geometry/t8_geometry_handler.hxx | 12 ++ .../t8_geometry_cad.hxx | 6 + 8 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 example/cmesh/t8_cmesh_mesh_deformation_example.cxx create mode 100644 src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx create mode 100644 src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 272486619b..95628142b7 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -71,6 +71,7 @@ add_t8_example( NAME t8_cmesh_set_join_by_vertices SOURCES cmesh/t8_cmesh_s add_t8_example( NAME t8_cmesh_geometry_examples SOURCES cmesh/t8_cmesh_geometry_examples.cxx ) add_t8_example( NAME t8_cmesh_create_partitioned SOURCES cmesh/t8_cmesh_create_partitioned.cxx ) add_t8_example( NAME t8_cmesh_hypercube_pad SOURCES cmesh/t8_cmesh_hypercube_pad.cxx ) +add_t8_example( NAME t8_cmesh_mesh_deformation_example SOURCES cmesh/t8_cmesh_mesh_deformation_example.cxx ) add_t8_example( NAME t8_test_ghost SOURCES forest/t8_test_ghost.cxx ) add_t8_example( NAME t8_test_face_iterate SOURCES forest/t8_test_face_iterate.cxx ) diff --git a/example/cmesh/t8_cmesh_mesh_deformation_example.cxx b/example/cmesh/t8_cmesh_mesh_deformation_example.cxx new file mode 100644 index 0000000000..760dad9cf0 --- /dev/null +++ b/example/cmesh/t8_cmesh_mesh_deformation_example.cxx @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + MPI_Init (&argc, &argv); + + t8_init (0); + + if (argc < 4) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return -1; + } + + std::string msh_file = argv[1]; + std::string brep_file = argv[2]; + int dim = std::stoi (argv[3]); + + if (dim < 1 || dim > 3) { + std::cerr << "Invalid mesh dimension. Must be 1, 2, or 3." << std::endl; + return -1; + } + std::cout << "Using user-specified mesh dimension: " << dim << std::endl; + + sc_MPI_Comm comm = sc_MPI_COMM_WORLD; + + /* Create cmesh from msh. */ + t8_cmesh_t cmesh = t8_cmesh_from_msh_file (msh_file.c_str (), 0, comm, dim, 0, 1); + t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default (), 0, 0, comm); + + /* Load CAD geometry from .brep file. */ + auto cad = std::make_shared (brep_file); + + /* Calculate displacements. */ + auto displacements = calculate_displacement_surface_vertices (cmesh, cad.get ()); + + /* Write output. */ + t8_forest_vtk_write_file (forest, "input_forest", 1, 1, 1, 1, 0, 0, NULL); + + /* Apply displacements. */ + apply_vertex_displacements (cmesh, displacements, cad); + + /* Write output. */ + t8_forest_vtk_write_file (forest, "deformed_forest", 1, 1, 1, 1, 0, 0, NULL); + + /* Cleanup. */ + t8_forest_unref (&forest); + + std::cout << "Mesh deformation completed." << std::endl; + + MPI_Finalize (); + return 0; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f70145269a..44767d2e49 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -153,6 +153,7 @@ target_sources( T8 PRIVATE t8_cmesh/t8_cmesh_io/t8_cmesh_readmshfile.cxx t8_cmesh/t8_cmesh_io/t8_cmesh_save.cxx t8_cmesh/t8_cmesh_io/t8_cmesh_triangle.cxx + t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx t8_data/t8_shmem.c t8_data/t8_containers.cxx t8_eclass/t8_eclass.c @@ -162,7 +163,7 @@ target_sources( T8 PRIVATE t8_forest/t8_forest_partition.cxx t8_forest/t8_forest_partition_for_coarsening.cxx t8_forest/t8_forest_pfc_helper.cxx - t8_forest/t8_forest.cxx + t8_forest/t8_forest.cxx t8_forest/t8_forest_private.cxx t8_forest/t8_forest_ghost.cxx t8_forest/t8_forest_iterate.cxx diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx new file mode 100644 index 0000000000..60519095bc --- /dev/null +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx @@ -0,0 +1,198 @@ + +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 2025 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +/** + * \param [in] cmesh The coarse mesh structure. + * \param [in] cad A pointer to the CAD-based geometry object. + * \return A map from global vertex id to its displacement vector, so the difference between old and new coordinates of a vertex. + */ + +std::unordered_map +calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad) +{ + T8_ASSERT (t8_cmesh_is_committed (cmesh)); + + /* Get number of global vertices on this rank */ + //const t8_gloidx_t num_global_vertices = t8_cmesh_get_num_global_vertices (cmesh); + + const int mesh_dimension = t8_cmesh_get_dimension (cmesh); + + /* Map from global vertex id -> displacement vector. */ + std::unordered_map displacements; + + for (const auto &global_vertex : *(cmesh->vertex_connectivity)) { + + /* Get the list of all trees associated with the vertex. */ + const auto &tree_list = global_vertex.second; + const t8_gloidx_t global_vertex_id = global_vertex.first; + + /* Get the first tree and the local corner index of the vertex in the tree. */ + const auto &first_tree = tree_list.front (); + const t8_locidx_t first_tree_id = first_tree.first; + const int local_corner_index = first_tree.second; + + /* Get the first tree as a reference. */ + const int *first_tree_geom_attribute = static_cast ( + t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_NODE_GEOMETRY_ATTRIBUTE_KEY, first_tree_id)); + + /* Check if the geometry attribute is available for this tree. */ + if (first_tree_geom_attribute == nullptr) { + t8_errorf ("Error: Geometry attribute missing for tree %d\n.", first_tree_id); + SC_ABORTF ("Geometry attribute is missing."); + } + + const int first_tree_entity_dim = first_tree_geom_attribute[2 * tree_list[0].second]; + const int first_tree_entity_tag = first_tree_geom_attribute[2 * tree_list[0].second + 1]; + +#if T8_ENABLE_DEBUG + /* Iterate over all trees and compare to the reference tree. */ + for (const auto &[tree_id, local_corner_index] : tree_list) { + + const int *geom_attribute = static_cast ( + t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_NODE_GEOMETRY_ATTRIBUTE_KEY, tree_id)); + + const int entity_dim = geom_attribute[2 * local_corner_index]; + const int entity_tag = geom_attribute[2 * local_corner_index + 1]; + + /* Check if the attribute of the vertex is the same in all trees. */ + if (!(entity_dim == first_tree_entity_dim && entity_tag == first_tree_entity_tag)) { + t8_errorf ( + "Error: Inconsistent entity info for global vertex %li: tree %d: dim=%d tag=%d, expected dim=%d tag=%d\n", + global_vertex_id, tree_id, entity_dim, entity_tag, first_tree_entity_dim, first_tree_entity_tag); + SC_ABORTF ("Inconsistency in vertex info.\n"); + } + } +#endif /*T8_ENABLE_DEBUG */ + + /* Check if this vertex is a boundary node. */ + if (first_tree_entity_dim < mesh_dimension && first_tree_entity_dim >= 0) { + + /* Get the pointer to the array of (u,v)-parameters for the CAD geometry. */ + const double *uv_attribute = (const double *) t8_cmesh_get_attribute ( + cmesh, t8_get_package_id (), T8_CMESH_NODE_PARAMETERS_ATTRIBUTE_KEY, first_tree_id); + + /* Check if the (u,v)-paramters are available. */ + if (uv_attribute == nullptr) { + t8_errorf ("Error: (u,v)-parameters are missing for tree %d\n.", first_tree_id); + SC_ABORT ("(u,v)-parameters are missing."); + } + /* Get the (u,v)-parameter of the vertex. */ + const double *uv_parameter = &uv_attribute[2 * local_corner_index]; + + /* Get the pointer to the coordinate array as it was before the deformation. */ + const double *old_coords = (const double *) t8_cmesh_get_attribute ( + cmesh, t8_get_package_id (), T8_CMESH_VERTICES_ATTRIBUTE_KEY, first_tree_id); + + /* Check if the coordinates are available. */ + if (old_coords == nullptr) { + t8_errorf ("Error: Coordinates attribute missing for tree %d\n.", first_tree_id); + SC_ABORTF ("Vertex coordinates are missing."); + } + + gp_Pnt new_coords; + + /* Find the new coordinates of the vertex in the cad file, based on the geometry its lying on. */ + switch (first_tree_entity_dim) { + case 0: { + new_coords = cad->t8_geom_get_cad_point (first_tree_entity_tag); + break; + } + case 1: { + Handle_Geom_Curve curve = cad->t8_geom_get_cad_curve (first_tree_entity_tag); + curve->D0 (uv_parameter[0], new_coords); + break; + } + case 2: { + Handle_Geom_Surface surface = cad->t8_geom_get_cad_surface (first_tree_entity_tag); + surface->D0 (uv_parameter[0], uv_parameter[1], new_coords); + break; + } + default: + SC_ABORT_NOT_REACHED (); + } + + /* Get the old coordinates before the deformation. */ + const double old_x = old_coords[3 * local_corner_index + 0]; + const double old_y = old_coords[3 * local_corner_index + 1]; + const double old_z = old_coords[3 * local_corner_index + 2]; + + /* Calculate the displacement of the vertex which should be then done in the deformation. */ + displacements[global_vertex_id] = { new_coords.X () - old_x, new_coords.Y () - old_y, new_coords.Z () - old_z }; + } + } + return displacements; +} +/* + * \param [in] cmesh The coarse mesh structure. + * \param [in] a map from global vertex id to its displacement vector + * (difference between old and new coordinates) with length equal to the mesh dimension. + */ +void +apply_vertex_displacements (t8_cmesh_t cmesh, const std::unordered_map &displacements, + std::shared_ptr cad) +{ + T8_ASSERT (t8_cmesh_is_committed (cmesh)); + + /* Iterate over all vertices in the displacement map. */ + for (const auto &[global_vertex, displacement] : displacements) { + + /* Get the list of trees where this vertex exists. */ + const auto &tree_list = cmesh->vertex_connectivity->get_tree_list_of_vertex (global_vertex); + + /*Update the vertex coordinates in each tree. */ + for (const auto &[tree_id, local_vertex_index] : tree_list) { + + /* Get the vertex coordinates of the current tree. */ + double *tree_vertex_coords + = (double *) t8_cmesh_get_attribute (cmesh, t8_get_package_id (), T8_CMESH_VERTICES_ATTRIBUTE_KEY, tree_id); + + /* Check if the coordinates are available. */ + if (tree_vertex_coords != nullptr) { + /* Update the coordinates of the vertex. */ + for (int coord_index = 0; coord_index < 3; ++coord_index) { + tree_vertex_coords[3 * local_vertex_index + coord_index] += displacement[coord_index]; + } + } + } + } + + /* Update the cad geometry. */ + t8_geometry_handler *geometry_handler = cmesh->geometry_handler; + T8_ASSERT (geometry_handler != nullptr); + + for (auto geom = geometry_handler->begin (); geom != geometry_handler->end (); ++geom) { + if (geom->second->t8_geom_get_type () == T8_GEOMETRY_TYPE_CAD) { + t8_geometry_cad *cad_geom = static_cast (geom->second.get ()); + cad_geom->update_cad_manager (cad); + break; + } + } +} diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx new file mode 100644 index 0000000000..b054b9e798 --- /dev/null +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx @@ -0,0 +1,75 @@ + +/* + This file is part of t8code. + t8code is a C library to manage a collection (a forest) of multiple + connected adaptive space-trees of general element classes in parallel. + + Copyright (C) 2025 the developers + + t8code is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + t8code is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with t8code; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef T8_CMESH_DEFORMATION_HXX +#define T8_CMESH_DEFORMATION_HXX + +#include +#include +#include + +#include +#include +#include +#include + +/** Struct for mesh deformation. */ +struct t8_cmesh_mesh_deformation +{ + public: + /** Constructor */ + t8_cmesh_mesh_deformation (): associated_cmesh (nullptr), updated_geometry (nullptr) {}; + + /** Destructor */ + ~t8_cmesh_mesh_deformation () {}; + + private: + /** A pointer to the cmesh for attribute retrieval */ + t8_cmesh_t associated_cmesh; + /** A shared pointer to the updated geometry which comes from a new cad file */ + std::shared_ptr updated_geometry; +}; + +/** + * Computes the displacements of the surface vertices. + * + * \param [in] cmesh The committed mesh + * \param [in] cad Pointer to the CAD data + * \return Map from global vertex ID to 3D displacement vector + */ +std::unordered_map +calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad); + +/** + * Apply vertex displacements to a committed cmesh. + * + * Iterates over the provided map of global vertex IDs to 3D displacement vectors, + * updating the coordinates in each tree where the vertex appears. + * + * @param cmesh The committed coarse mesh structure. + * @param displacements Map from global vertex ID to 3D displacement vector [dx, dy, dz]. + */ +void +apply_vertex_displacements (t8_cmesh_t cmesh, const std::unordered_map &displacements, + std::shared_ptr cad); +#endif /* !T8_CMESH_DEFORMATION_HXX */ diff --git a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx index af53065c58..b1f9237b7c 100644 --- a/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx +++ b/src/t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx @@ -222,6 +222,23 @@ struct t8_cmesh_vertex_connectivity return get_tree_list_of_vertex (global_vertex_id).size (); } + /** Typedef for the iterator type. */ + using const_iterator = t8_cmesh_vertex_conn_vertex_to_tree::const_iterator; + + /** Iterator begin. */ + inline const_iterator + begin () const + { + return vertex_to_tree.begin (); + } + + /** Iterator end. */ + inline const_iterator + end () const + { + return vertex_to_tree.end (); + } + private: /** The internal state. Indicating whether this structure is new and unfilled, the ttv was filled or the vertex conn was built completely. */ state current_state; diff --git a/src/t8_geometry/t8_geometry_handler.hxx b/src/t8_geometry/t8_geometry_handler.hxx index b5af9c63fe..a6e3a456b7 100644 --- a/src/t8_geometry/t8_geometry_handler.hxx +++ b/src/t8_geometry/t8_geometry_handler.hxx @@ -273,6 +273,18 @@ struct t8_geometry_handler } } + auto + begin () + { + return registered_geometries.begin (); + } + + auto + end () + { + return registered_geometries.end (); + } + private: /** * Add a geometry to the geometry handler. diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx index d81e1a0454..33eaa4ed10 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx @@ -153,6 +153,12 @@ struct t8_geometry_cad: public t8_geometry_with_vertices return cad_manager; } + void + update_cad_manager (std::shared_ptr new_cad_manager) + { + cad_manager = new_cad_manager; + } + private: /** * Maps points in the reference space \f$ [0,1]^2 \f$ to \f$ \mathbb{R}^3 \f$. Only for triangle trees. From afee13d7d85f094539ba53ddc195307a68cecdeb Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Fri, 28 Nov 2025 15:22:26 +0100 Subject: [PATCH 2/9] implement sc_options for command line --- .../t8_cmesh_mesh_deformation_example.cxx | 108 +++++++++++++----- .../features/t8_features_curved_meshes.cxx | 6 +- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/example/cmesh/t8_cmesh_mesh_deformation_example.cxx b/example/cmesh/t8_cmesh_mesh_deformation_example.cxx index 760dad9cf0..975f871c14 100644 --- a/example/cmesh/t8_cmesh_mesh_deformation_example.cxx +++ b/example/cmesh/t8_cmesh_mesh_deformation_example.cxx @@ -14,55 +14,105 @@ #include #include #include +#include int main (int argc, char **argv) { - MPI_Init (&argc, &argv); + char usage[BUFSIZ]; + /* Brief help message. */ + int sreturnA = snprintf (usage, BUFSIZ, "Usage:\t%s \n\t%s -h\t for a brief overview of all options.", + basename (argv[0]), basename (argv[0])); - t8_init (0); + char help[BUFSIZ]; + /* Long help message. */ + int sreturnB = snprintf ( + help, BUFSIZ, + "Deform a mesh based on a msh file with the new CAD geometry.\n" + "Required arguments are the input mesh file, the deformation geometry file, and the mesh dimension.\n\n%s\n", + usage); - if (argc < 4) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; - return -1; + if (sreturnA > BUFSIZ || sreturnB > BUFSIZ) { + /* The usage string or help message was truncated */ + /* Note: gcc >= 7.1 prints a warning if we + * do not check the return value of snprintf. */ + t8_debugf ("Warning: Truncated usage string and help message to '%s' and '%s'\n", usage, help); } - std::string msh_file = argv[1]; - std::string brep_file = argv[2]; - int dim = std::stoi (argv[3]); + /* + * Initialization. + */ - if (dim < 1 || dim > 3) { - std::cerr << "Invalid mesh dimension. Must be 1, 2, or 3." << std::endl; - return -1; + /* Initialize MPI. This has to happen before we initialize sc or t8code. */ + int mpiret = sc_MPI_Init (&argc, &argv); + + /* Error check the MPI return value. */ + SC_CHECK_MPI (mpiret); + + /* Initialize the sc library, has to happen before we initialize t8code. */ + sc_init (sc_MPI_COMM_WORLD, 1, 1, NULL, SC_LP_PRODUCTION); + + /* Initialize t8code with log level SC_LP_PRODUCTION. See sc.h for more info on the log levels. */ + t8_init (SC_LP_PRODUCTION); + + int helpme = 0; + const char *msh_file = NULL; + const char *brep_file = NULL; + int dim = 0; + + /* Initialize command line argument parser. */ + sc_options_t *opt = sc_options_new (argv[0]); + sc_options_add_switch (opt, 'h', "help", &helpme, "Display a short help message."); + sc_options_add_string (opt, 'm', "mshfile", &msh_file, NULL, "File prefix of the input mesh file (without .msh)"); + sc_options_add_string (opt, 'b', "brepfile", &brep_file, NULL, + "File prefix of the deformation geometry file (.brep)"); + sc_options_add_int (opt, 'd', "dimension", &dim, 0, "Dimension of the mesh (1, 2 or 3)"); + + int parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); + + if (helpme) { + t8_global_productionf ("%s\n", help); + sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); + } + else if (msh_file == NULL || brep_file == NULL || dim == 0) { + t8_global_productionf ("\n\t ERROR: Missing required arguments: -m, -b, and -d are mandatory.\n\n"); + sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); } - std::cout << "Using user-specified mesh dimension: " << dim << std::endl; + else if (dim < 1 || dim > 3) { + t8_global_productionf ("\n\t ERROR: Invalid mesh dimension: dim=%d. Dimension must be 1, 2 or 3.\n\n", dim); + sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); + } + else if (parsed >= 0) { - sc_MPI_Comm comm = sc_MPI_COMM_WORLD; + /* We will use MPI_COMM_WORLD as a communicator. */ + sc_MPI_Comm comm = sc_MPI_COMM_WORLD; - /* Create cmesh from msh. */ - t8_cmesh_t cmesh = t8_cmesh_from_msh_file (msh_file.c_str (), 0, comm, dim, 0, 1); - t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default (), 0, 0, comm); + /* Create cmesh from msh. */ + t8_cmesh_t cmesh = t8_cmesh_from_msh_file (msh_file, 0, comm, dim, 0, 1); + t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default (), 2, 0, comm); - /* Load CAD geometry from .brep file. */ - auto cad = std::make_shared (brep_file); + /* Load CAD geometry from .brep file. */ + auto cad = std::make_shared (brep_file); - /* Calculate displacements. */ - auto displacements = calculate_displacement_surface_vertices (cmesh, cad.get ()); + /* Calculate displacements. */ + auto displacements = calculate_displacement_surface_vertices (cmesh, cad.get ()); - /* Write output. */ - t8_forest_vtk_write_file (forest, "input_forest", 1, 1, 1, 1, 0, 0, NULL); + /* Write output. */ + t8_forest_vtk_write_file (forest, "input_forest", 1, 1, 1, 1, 0, 0, NULL); - /* Apply displacements. */ - apply_vertex_displacements (cmesh, displacements, cad); + /* Apply displacements. */ + apply_vertex_displacements (cmesh, displacements, cad); - /* Write output. */ - t8_forest_vtk_write_file (forest, "deformed_forest", 1, 1, 1, 1, 0, 0, NULL); + /* Write output. */ + t8_forest_vtk_write_file (forest, "deformed_forest", 1, 1, 1, 1, 0, 0, NULL); - /* Cleanup. */ - t8_forest_unref (&forest); + /* Cleanup. */ + t8_forest_unref (&forest); - std::cout << "Mesh deformation completed." << std::endl; + std::cout << "Mesh deformation completed." << std::endl; + } MPI_Finalize (); + sc_options_destroy (opt); return 0; } diff --git a/tutorials/features/t8_features_curved_meshes.cxx b/tutorials/features/t8_features_curved_meshes.cxx index 58eb3a622c..1bae8a4a2b 100644 --- a/tutorials/features/t8_features_curved_meshes.cxx +++ b/tutorials/features/t8_features_curved_meshes.cxx @@ -45,7 +45,9 @@ #include /* default refinement scheme. */ #include /* Linear geometry calculation of trees */ #if T8_ENABLE_OCC -#include /* Curved geometry calculation of trees */ +#include /* Curved geometry calculation of trees */ +#include /* Mesh deformation struct */ +#include /* CAD data structure */ #endif #include /* msh file reader */ #include /* std::string */ @@ -300,7 +302,7 @@ t8_naca_plane_refinement (t8_forest_t forest, const std::string &fileprefix, int /* Moving plane loop */ while (adapt_data.t < steps) { - /* Adapt and balance the forest. + /* Adapt and balance the forest. * Note, that we have to hand the adapt data to the forest before the commit. */ t8_forest_init (&forest_new); t8_forest_set_adapt (forest_new, forest, t8_naca_plane_adapt_callback, 1); From 04959e283487c8aa04460f9c0144b13fb874ce4d Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Mon, 2 Mar 2026 14:42:44 +0100 Subject: [PATCH 3/9] fix doxygen warnings --- .../t8_cmesh_mesh_deformation.cxx | 9 +++++---- .../t8_cmesh_mesh_deformation.hxx | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx index 60519095bc..d3c229960c 100644 --- a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx @@ -99,7 +99,7 @@ calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad) const double *uv_attribute = (const double *) t8_cmesh_get_attribute ( cmesh, t8_get_package_id (), T8_CMESH_NODE_PARAMETERS_ATTRIBUTE_KEY, first_tree_id); - /* Check if the (u,v)-paramters are available. */ + /* Check if the (u,v)-parameters are available. */ if (uv_attribute == nullptr) { t8_errorf ("Error: (u,v)-parameters are missing for tree %d\n.", first_tree_id); SC_ABORT ("(u,v)-parameters are missing."); @@ -150,10 +150,11 @@ calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad) } return displacements; } -/* - * \param [in] cmesh The coarse mesh structure. - * \param [in] a map from global vertex id to its displacement vector +/** + * \param [in] cmesh The coarse mesh structure. + * \param [in] displacements A map from global vertex id to its displacement vector * (difference between old and new coordinates) with length equal to the mesh dimension. + * \param [in] cad The CAD geometry handler to be updated. */ void apply_vertex_displacements (t8_cmesh_t cmesh, const std::unordered_map &displacements, diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx index b054b9e798..969d0d4a61 100644 --- a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx @@ -53,8 +53,8 @@ struct t8_cmesh_mesh_deformation /** * Computes the displacements of the surface vertices. * - * \param [in] cmesh The committed mesh - * \param [in] cad Pointer to the CAD data + * \param [in] cmesh The coarse mesh structure. + * \param [in] cad A pointer to the CAD-based geometry object. * \return Map from global vertex ID to 3D displacement vector */ std::unordered_map @@ -66,8 +66,9 @@ calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad); * Iterates over the provided map of global vertex IDs to 3D displacement vectors, * updating the coordinates in each tree where the vertex appears. * - * @param cmesh The committed coarse mesh structure. - * @param displacements Map from global vertex ID to 3D displacement vector [dx, dy, dz]. + * \param [in] cmesh The committed coarse mesh structure. + * \param [in] displacements Map from global vertex ID to 3D displacement vector [dx, dy, dz]. + * \param [in] cad The shared pointer to the CAD geometry to update. */ void apply_vertex_displacements (t8_cmesh_t cmesh, const std::unordered_map &displacements, From 820f1e74e5b6e2f1fa0ab19c3d6edda84c7c26e0 Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Mon, 2 Mar 2026 15:35:22 +0100 Subject: [PATCH 4/9] fix doxygen warnings again --- .../t8_cmesh_mesh_deformation.cxx | 9 ++------- .../t8_cmesh_mesh_deformation.hxx | 4 ++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx index d3c229960c..759be9f176 100644 --- a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx @@ -30,9 +30,7 @@ #include #include /** - * \param [in] cmesh The coarse mesh structure. - * \param [in] cad A pointer to the CAD-based geometry object. - * \return A map from global vertex id to its displacement vector, so the difference between old and new coordinates of a vertex. + * Calculate the displacement of vertices for CAD-based mesh deformation. */ std::unordered_map @@ -151,10 +149,7 @@ calculate_displacement_surface_vertices (t8_cmesh_t cmesh, const t8_cad *cad) return displacements; } /** - * \param [in] cmesh The coarse mesh structure. - * \param [in] displacements A map from global vertex id to its displacement vector - * (difference between old and new coordinates) with length equal to the mesh dimension. - * \param [in] cad The CAD geometry handler to be updated. + * Apply vertex displacements to a cmesh and update the CAD geometry. */ void apply_vertex_displacements (t8_cmesh_t cmesh, const std::unordered_map &displacements, diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx index 969d0d4a61..19f2583aa7 100644 --- a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx @@ -21,6 +21,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** \file t8_cmesh_mesh_deformation.hxx + * Implementation of CAD-based mesh deformation. + */ + #ifndef T8_CMESH_DEFORMATION_HXX #define T8_CMESH_DEFORMATION_HXX From bd3f549dd8d929242b3e35544ed41ee02a355fb8 Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Mon, 2 Mar 2026 15:59:19 +0100 Subject: [PATCH 5/9] add doxygen file header for mesh deformation --- .../t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx index 759be9f176..3ffd5e2404 100644 --- a/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx +++ b/src/t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx @@ -21,6 +21,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/** \file t8_cmesh_mesh_deformation.cxx + * This file implements the routines for CAD-based mesh deformation. + */ + #include #include #include From fa8e2146506c6e9a1681e6e6a7b1306f698284a5 Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Thu, 5 Mar 2026 16:24:09 +0100 Subject: [PATCH 6/9] add missing documentation for cad manager and iterators --- src/t8_geometry/t8_geometry_handler.hxx | 8 ++++++++ .../t8_geometry_implementations/t8_geometry_cad.hxx | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/t8_geometry/t8_geometry_handler.hxx b/src/t8_geometry/t8_geometry_handler.hxx index a6e3a456b7..23b83631f4 100644 --- a/src/t8_geometry/t8_geometry_handler.hxx +++ b/src/t8_geometry/t8_geometry_handler.hxx @@ -273,12 +273,20 @@ struct t8_geometry_handler } } + /** + * Return an iterator to the beginning of the geometry handler. + * \return An iterator to the first geometry. + */ auto begin () { return registered_geometries.begin (); } + /** + * Return an iterator to the end of the geometry handler. + * \return An iterator to the element following the last geometry. + */ auto end () { diff --git a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx index 33eaa4ed10..9b3cf29b32 100644 --- a/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx +++ b/src/t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx @@ -153,6 +153,9 @@ struct t8_geometry_cad: public t8_geometry_with_vertices return cad_manager; } + /** Update the CAD manager with a new one. + * \param[in] new_cad_manager The new CAD manager to be used. + */ void update_cad_manager (std::shared_ptr new_cad_manager) { From f0b218222a3abc8a7d0e3d54e9c7b61c18c2399f Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Mon, 9 Mar 2026 20:23:49 +0100 Subject: [PATCH 7/9] add T8_ENABLE_OCC guards to t8_cad class --- src/t8_cad/t8_cad.cxx | 21 ++++++++++++++++----- src/t8_cad/t8_cad.hxx | 23 +++++++++++++++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/t8_cad/t8_cad.cxx b/src/t8_cad/t8_cad.cxx index dc319f08c9..7dfdc611bd 100644 --- a/src/t8_cad/t8_cad.cxx +++ b/src/t8_cad/t8_cad.cxx @@ -22,6 +22,8 @@ #include #include + +#if T8_ENABLE_OCC #include #include #include @@ -34,6 +36,7 @@ #include #include #include +#endif #if T8_ENABLE_DEBUG #include @@ -41,6 +44,7 @@ t8_cad::t8_cad (std::string fileprefix) { +#if T8_ENABLE_OCC BRep_Builder builder; std::ifstream is (fileprefix + ".brep"); if (is.is_open () == false) { @@ -60,8 +64,19 @@ t8_cad::t8_cad (std::string fileprefix) TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_EDGE, cad_shape_vertex2edge_map); TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_VERTEX, TopAbs_FACE, cad_shape_vertex2face_map); +#else + SC_ABORTF ("OpenCASCADE is not enabled. Cannot load CAD file: %s.brep\n", fileprefix.c_str ()); +#endif /* T8_ENABLE_OCC */ +} + +t8_cad::t8_cad () +{ +#if T8_ENABLE_OCC + cad_shape.Nullify (); +#endif /* T8_ENABLE_OCC */ } +#if T8_ENABLE_OCC t8_cad::t8_cad (const TopoDS_Shape cad_shape) { if (cad_shape.IsNull ()) { @@ -74,11 +89,6 @@ t8_cad::t8_cad (const TopoDS_Shape cad_shape) TopExp::MapShapesAndUniqueAncestors (cad_shape, TopAbs_EDGE, TopAbs_FACE, cad_shape_edge2face_map); } -t8_cad::t8_cad () -{ - cad_shape.Nullify (); -} - int t8_cad::t8_geom_is_line (const int curve_index) const { @@ -548,3 +558,4 @@ t8_cad::t8_geom_surface_is_closed (int geometry_index, int direction) const break; } } +#endif /* T8_ENABLE_OCC */ diff --git a/src/t8_cad/t8_cad.hxx b/src/t8_cad/t8_cad.hxx index 8dea025717..bd17cd784a 100644 --- a/src/t8_cad/t8_cad.hxx +++ b/src/t8_cad/t8_cad.hxx @@ -28,6 +28,11 @@ #ifndef T8_CAD_HXX #define T8_CAD_HXX +#include +#include +#include + +#if T8_ENABLE_OCC #include #include #include @@ -35,9 +40,7 @@ #include #include #include -#include -#include - +#endif /* T8_ENABLE_OCC */ /** * This class manages OpenCASCADE shapes and implements helper functions for working with the shapes. */ @@ -56,6 +59,12 @@ struct t8_cad */ t8_cad (std::string fileprefix); + /** + * Constructor of the cad shape for testing purposes. Sets an invalid cad_shape. + */ + t8_cad (); + +#if T8_ENABLE_OCC /** * Constructor of the cad shape. * The shape is initialized directly from an existing TopoDS_Shape. @@ -67,11 +76,6 @@ struct t8_cad */ t8_cad (const TopoDS_Shape cad_shape); - /** - * Constructor of the cad shape for testing purposes. Sets an invalid cad_shape. - */ - t8_cad (); - /** Check if a cad_curve is a line. * \param [in] curve_index The index of the cad_curve. * \return 1 if curve is a line, 0 if curve is not a line. @@ -319,8 +323,10 @@ struct t8_cad */ bool t8_geom_surface_is_closed (int geometry_index, int direction) const; +#endif /* T8_ENABLE_OCC */ private: +#if T8_ENABLE_OCC TopoDS_Shape cad_shape; /**< cad geometry */ TopTools_IndexedMapOfShape cad_shape_vertex_map; /**< Map of all TopoDS_Vertex. */ TopTools_IndexedMapOfShape cad_shape_edge_map; /**< Map of all TopoDS_Edge. */ @@ -331,6 +337,7 @@ struct t8_cad cad_shape_edge2face_map; /**< Maps all TopoDS_Edge to all its connected TopoDS_Face */ TopTools_IndexedDataMapOfShapeListOfShape cad_shape_vertex2face_map; /**< Maps all TopoDS_Vertex to all its connected TopoDS_Face */ +#endif /* T8_ENABLE_OCC */ }; #endif /* !T8_CAD_HXX */ From f13f6fbc2ed03d0371d8b4cb1c9f23e68b074cd2 Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Tue, 10 Mar 2026 20:54:17 +0100 Subject: [PATCH 8/9] chore: restart CI tests From 6a8cafa9e812c3074bc9423de446df3d4bbd746e Mon Sep 17 00:00:00 2001 From: Lena Radmer Date: Wed, 11 Mar 2026 17:54:19 +0100 Subject: [PATCH 9/9] compile mesh deformation only if OCC is enabled --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 44767d2e49..3fef382b72 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,6 +97,7 @@ if( T8CODE_ENABLE_OCC ) target_sources(T8 PRIVATE t8_geometry/t8_geometry_implementations/t8_geometry_cad.cxx t8_cad/t8_cad.cxx + t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.cxx ) install( FILES t8_geometry/t8_geometry_implementations/t8_geometry_cad.hxx