Repository navigation
Feature: mesh deformation with RBFs (TPS and CPC2) #2470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0eead4d
8759747
0884867
17f7cbd
cf17193
2542283
19f1799
19df7af
64df1b1
b0fcde7
f2d1315
984da6c
d52a348
d05a2e2
d9ca696
257f2e9
6458bf3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,13 +40,14 @@ foreach(INDEX RANGE ${DEPS_RANGE}) | |
|
|
||
| # If the DEP_CMAKE_OPTION field is non-empty, check the CMake option. | ||
| if(NOT DEP_CMAKE_OPTION STREQUAL "") | ||
| string(JSON DEP_CMAKE_OPTION_VALUE GET "${DEPS_JSON}" "thirdparty" ${INDEX} "cmake_option_install_value") | ||
| # If the named option variable does not exist in the CMake cache, abort. | ||
| if(NOT DEFINED ${DEP_CMAKE_OPTION}) | ||
| message(FATAL_ERROR "Loading thirdparty library ${DEP_NAME} at index ${INDEX} references unknown CMake option '${DEP_CMAKE_OPTION}'. Aborting.") | ||
| else() | ||
| # If the named option is defined but set to ON, skip this thirdparty library. | ||
| if(${${DEP_CMAKE_OPTION}}) | ||
| message(STATUS "Skipping FetchContent-step for thirdparty library ${DEP_NAME} because CMake option '${DEP_CMAKE_OPTION}' is '${${DEP_CMAKE_OPTION}}'") | ||
| if(NOT ${DEP_CMAKE_OPTION} STREQUAL ${DEP_CMAKE_OPTION_VALUE}) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This addition is string based, so the user has to type "ON" or "OFF". This is not pracical as we should also allow a "0" and "1" or "TRUE" and "FALSE". So we need to convert these inputs to "ON" and "OFF" beforhand, so this doesn't fail. |
||
| message(STATUS "Skipping FetchContent-step for thirdparty library ${DEP_NAME} because CMake option '${DEP_CMAKE_OPTION}' is set to '${${DEP_CMAKE_OPTION}}'") | ||
| continue() | ||
| endif() | ||
| endif() | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -28,22 +28,43 @@ | |||||||||||||
| #include <t8_cmesh/t8_cmesh_vertex_connectivity/t8_cmesh_vertex_connectivity.hxx> | ||||||||||||||
| #include <t8_cmesh/t8_cmesh_io/t8_cmesh_readmshfile.h> | ||||||||||||||
| #include <t8_schemes/t8_default/t8_default.hxx> | ||||||||||||||
| #if T8CODE_ENABLE_OCC | ||||||||||||||
| #if T8_ENABLE_OCC && T8_ENABLE_EIGEN | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need EIGEN for the mesh deformation itself? Isn't it just for the RBF? |
||||||||||||||
| #include <t8_cad/t8_cad_handle.hxx> | ||||||||||||||
| #include <t8_cmesh/t8_cmesh_mesh_deformation/t8_cmesh_mesh_deformation.hxx> | ||||||||||||||
| #endif /* T8CODE_ENABLE_OCC */ | ||||||||||||||
| #endif /* T8_ENABLE_OCC and T8_ENABLE_EIGEN*/ | ||||||||||||||
| #include <t8_vtk/t8_vtk_writer.h> | ||||||||||||||
| #include <sc_options.h> | ||||||||||||||
|
|
||||||||||||||
| #include <iostream> | ||||||||||||||
| #include <string> | ||||||||||||||
| #include <vector> | ||||||||||||||
| #include <array> | ||||||||||||||
| #include <filesystem> | ||||||||||||||
| #include <algorithm> | ||||||||||||||
|
|
||||||||||||||
| #if T8_ENABLE_OCC && T8_ENABLE_EIGEN | ||||||||||||||
| namespace fs = std::filesystem; | ||||||||||||||
|
|
||||||||||||||
| static std::vector<fs::path> | ||||||||||||||
| findBrepFiles (const char *folder) | ||||||||||||||
| { | ||||||||||||||
| std::vector<fs::path> files; | ||||||||||||||
|
|
||||||||||||||
| for (const auto &entry : fs::directory_iterator (folder)) { | ||||||||||||||
| if (entry.is_regular_file () && entry.path ().extension () == ".brep") { | ||||||||||||||
| files.push_back (entry.path ()); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return files; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| #endif /* T8_ENABLE_OCC && T8_ENABLE_EIGEN */ | ||||||||||||||
|
|
||||||||||||||
| int | ||||||||||||||
| main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | ||||||||||||||
| { | ||||||||||||||
| #if T8CODE_ENABLE_OCC | ||||||||||||||
| #if T8_ENABLE_OCC && T8_ENABLE_EIGEN | ||||||||||||||
|
|
||||||||||||||
| char usage[BUFSIZ]; | ||||||||||||||
| /* Brief help message. */ | ||||||||||||||
|
|
@@ -76,7 +97,7 @@ main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | |||||||||||||
| 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); | ||||||||||||||
| sc_init (sc_MPI_COMM_WORLD, 1, 1, NULL, SC_LP_ESSENTIAL); | ||||||||||||||
|
|
||||||||||||||
| /* Initialize t8code with log level SC_LP_PRODUCTION. See sc.h for more info on the log levels. */ | ||||||||||||||
| t8_init (SC_LP_PRODUCTION); | ||||||||||||||
|
|
@@ -85,15 +106,20 @@ main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | |||||||||||||
| const char *msh_file = NULL; | ||||||||||||||
| const char *brep_file = NULL; | ||||||||||||||
| int dim, level; | ||||||||||||||
| int rbf_type_int = 0; | ||||||||||||||
| double scale_factor_support_radius = 1.5; | ||||||||||||||
|
|
||||||||||||||
| /* 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, | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is now reffering to a folder. Should that then be called "brepfolder"? |
||||||||||||||
| "File prefix of the deformation geometry file (without .brep)"); | ||||||||||||||
| "Path to the folder containing the deformation geometry files (.brep)"); | ||||||||||||||
| sc_options_add_int (opt, 'd', "dimension", &dim, 0, "Dimension of the mesh (1, 2 or 3)"); | ||||||||||||||
| sc_options_add_int (opt, 'l', "level", &level, 2, "Uniform refinement level for the input mesh. Default: 2"); | ||||||||||||||
| sc_options_add_int (opt, 't', "rbftype", &rbf_type_int, 0, "RBF type (0 for CP_C2, 1 for TPS). Default: 0"); | ||||||||||||||
| sc_options_add_double (opt, 's', "scalefactor", &scale_factor_support_radius, 1.5, | ||||||||||||||
| "Scale factor for the support radius. Default: 1.5"); | ||||||||||||||
|
|
||||||||||||||
| int parsed = sc_options_parse (t8_get_package_id (), SC_LP_ERROR, opt, argc, argv); | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -106,7 +132,7 @@ main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | |||||||||||||
| sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); | ||||||||||||||
| } | ||||||||||||||
| else if (dim < 1 || dim > 3) { | ||||||||||||||
| t8_global_errorf ("ERROR: Invalid mesh dimension: dim=%d. Dimension must be 1, 2 or 3.\n\n", dim); | ||||||||||||||
| t8_global_errorf ("ERROR: Invalid mesh dimension: dim=%d. Dimension must be 1, 2 or 3.\n", dim); | ||||||||||||||
| sc_options_print_usage (t8_get_package_id (), SC_LP_ERROR, opt, NULL); | ||||||||||||||
| } | ||||||||||||||
| else { | ||||||||||||||
|
|
@@ -120,28 +146,35 @@ main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | |||||||||||||
| t8_cmesh_from_msh_file (&cmesh, msh_file, 0, comm, dim, 0, 1); | ||||||||||||||
| t8_forest_t forest = t8_forest_new_uniform (cmesh, t8_scheme_new_default (), level, 0, comm); | ||||||||||||||
|
|
||||||||||||||
| /* Load CAD geometry from .brep file. */ | ||||||||||||||
| auto cad = std::make_shared<t8_cad_handle> (brep_file); | ||||||||||||||
|
|
||||||||||||||
| /* Initialize the deformation object for the given mesh. */ | ||||||||||||||
| t8_cmesh_mesh_deformation deformation (cmesh); | ||||||||||||||
|
|
||||||||||||||
| /* Calculate displacements. */ | ||||||||||||||
| auto displacements = deformation.calculate_displacement_surface_vertices (cad.get ()); | ||||||||||||||
| /** Save the input RBF type. */ | ||||||||||||||
| t8_rbf_function_type rbf_type = static_cast<t8_rbf_function_type> (rbf_type_int); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be const? |
||||||||||||||
|
|
||||||||||||||
| /* Write output. */ | ||||||||||||||
| t8_forest_vtk_write_file (forest, "input_forest", 1, 1, 1, 1, 0, 0, NULL); | ||||||||||||||
| t8_forest_vtk_write_file (forest, "deformed_forest_step_0", 1, 1, 1, 1, 0, 0, NULL); | ||||||||||||||
|
|
||||||||||||||
| /* Apply displacements. */ | ||||||||||||||
| deformation.apply_vertex_displacements (displacements, cad); | ||||||||||||||
| auto brep_files = findBrepFiles (brep_file); | ||||||||||||||
| std::sort (brep_files.begin (), brep_files.end ()); | ||||||||||||||
|
|
||||||||||||||
| /* Write output. */ | ||||||||||||||
| t8_forest_vtk_write_file (forest, "deformed_forest", 1, 1, 1, 1, 0, 0, NULL); | ||||||||||||||
| int ifile = 0; | ||||||||||||||
| for (const auto &file : brep_files) { | ||||||||||||||
| auto file_without_ext = file.parent_path () / file.stem (); | ||||||||||||||
| auto cad_deformed = std::make_shared<t8_cad_handle> (file_without_ext.c_str ()); | ||||||||||||||
|
|
||||||||||||||
| auto displacements = deformation.calculate_displacement_surface_vertices (cad_deformed.get (), rbf_type, | ||||||||||||||
| scale_factor_support_radius); | ||||||||||||||
|
|
||||||||||||||
| deformation.apply_vertex_displacements (displacements, cad_deformed, rbf_type); | ||||||||||||||
|
Comment on lines
+166
to
+169
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if a user sets the rbf_type differntly for both functions calls? |
||||||||||||||
|
|
||||||||||||||
| std::string output_name = "deformed_forest_step_" + std::to_string (ifile++); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the first iteration this would also be "deformed_forest_step_0" as
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, i have changed it to ++file and also the input .brep is now skipped in the loop |
||||||||||||||
| t8_forest_vtk_write_file (forest, output_name.c_str (), 1, 1, 1, 1, 0, 0, NULL); | ||||||||||||||
| } | ||||||||||||||
| /* Cleanup. */ | ||||||||||||||
| t8_forest_unref (&forest); | ||||||||||||||
|
|
||||||||||||||
| t8_global_productionf ("Mesh deformation completed."); | ||||||||||||||
| t8_global_productionf ("Mesh deformation completed.\n"); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| sc_options_destroy (opt); | ||||||||||||||
|
|
@@ -150,9 +183,9 @@ main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | |||||||||||||
| mpiret = sc_MPI_Finalize (); | ||||||||||||||
| SC_CHECK_MPI (mpiret); | ||||||||||||||
|
|
||||||||||||||
| #else /* T8CODE_ENABLE_OCC */ | ||||||||||||||
| t8_global_errorf ("ERROR: This example requires OpenCASCADE support to be enabled in t8code.\n"); | ||||||||||||||
| #endif /* T8CODE_ENABLE_OCC */ | ||||||||||||||
| #else /* T8_ENABLE_OCC and T8_ENABLE_EIGEN*/ | ||||||||||||||
| t8_global_errorf ("ERROR: This example requires OpenCASCADE and Eigen support to be enabled in t8code.\n"); | ||||||||||||||
| #endif /* T8_ENABLE_OCC and T8_ENABLE_EIGEN*/ | ||||||||||||||
|
Comment on lines
+186
to
+188
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there has to be a space.
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| return 0; | ||||||||||||||
| } | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /* | ||
| 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) 2026 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. | ||
| */ | ||
|
|
||
| /** \file t8_rbf.cxx | ||
| * This file implements an example for CAD-based mesh deformation. | ||
| */ | ||
| #include <t8.h> | ||
| #if T8_ENABLE_EIGEN | ||
| #include <Eigen/Dense> | ||
| #endif | ||
|
|
||
| int | ||
| main ([[maybe_unused]] int argc, [[maybe_unused]] char **argv) | ||
| { | ||
| #if T8_ENABLE_EIGEN | ||
| t8_global_productionf ("--- STARTING EIGEN BASIC TEST --- \n"); | ||
| /* | ||
| * Initialization. | ||
| */ | ||
|
|
||
| /* 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_ESSENTIAL. See sc.h for more info on the log levels. */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is SC_LP_PRODUCTION in the code |
||
| t8_init (SC_LP_PRODUCTION); | ||
|
|
||
| /** Little Test. */ | ||
| Eigen::Matrix3d A; | ||
| A << 4.0, 1.2, 0.5, 1.2, 5.0, 2.1, 0.5, 2.1, 6.0; | ||
|
|
||
| /** vector b. */ | ||
| Eigen::Vector3d b; | ||
| b << 1.0, 2.0, 3.0; | ||
|
|
||
| /* We will test a dense matrix example. Given that the matrix is symmetric and positive semidefinite we will test out the LDLT decomposition. */ | ||
| Eigen::LDLT<Eigen::Matrix3d> solver (A); | ||
|
|
||
| if (solver.info () == Eigen::Success) { | ||
| Eigen::Vector3d x = solver.solve (b); | ||
|
|
||
| t8_global_productionf ("The solution is: x = [%f, %f, %f]\n", x (0), x (1), x (2)); | ||
|
|
||
| /* Test if A * x = b for a quick check. */ | ||
| Eigen::Vector3d check = A * x; | ||
| t8_global_productionf ("(A*x): [%f, %f, %f] (should be the same as b)\n", check (0), check (1), check (2)); | ||
| } | ||
| else { | ||
| t8_global_productionf ("ERROR: the system could not be solved.\n"); | ||
| } | ||
|
|
||
| sc_finalize (); | ||
| mpiret = sc_MPI_Finalize (); | ||
| SC_CHECK_MPI (mpiret); | ||
|
|
||
| #else | ||
| t8_global_productionf ("ERROR: This example requires Eigen support to be enabled in t8code.\n"); | ||
| #endif | ||
|
|
||
| return 0; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.