From f0bcc41c2b73d88d82c45cbd5d828070eaceccb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9lestin=20Marot?= <celestin.marot@uclouvain.be> Date: Tue, 21 Apr 2020 10:20:34 +0200 Subject: [PATCH] update hxt: The *hxt* standalone repos that we are maintaining on a private Gitlab is becoming a total mess IMO. Therefore, as I'm at the end of my thesis and I want to distribute the *hxt* library in a "clean" manner, I thought I could maybe clean the *hxt* directory in *contrib*, and make it so that we can compile things independently. Therefore, I created this huge commit. - Keep a directory structure, even if it is in contrib. Each part of *hxt* has its own CMakeList.txt, and is compiled by gmsh as an OBJECT library target. Each target can be separately compiled. For example, you can go in *contrib/hxt/tetMesh* and do `mkdir build && cd build && cmake .. && make -j4` - Files that were not used by gmsh were deleted. Metis was actually not used. - tetMesh was updated to the newest version - hxt_octree.cpp was almost entirely surrounded by `#ifdef HAVE_P4EST` and it was throwing an error if it wasn't the case Therefore, I change that so that HAVE_P4EST was a prerequisite for the compilation. - You might notice cmake_minimum_required in *hxt* is version 3.9 to enable target_compile_features(... c_std_99) I doubt that people who wants to have HXT_ENABLED AND have a compiler with OpenMP 4+ and C99 AND have the latest version of Gmsh will have problem installing a newer version of CMake. --- CMakeLists.txt | 49 +- Geo/GModelParametrize.cpp | 5 +- Geo/discreteFace.cpp | 5 +- Mesh/automaticMeshSizeField.cpp | 5 +- Mesh/automaticMeshSizeField.h | 2 +- Mesh/meshGRegionHxt.cpp | 7 +- contrib/hxt/CMakeLists.txt | 65 - contrib/hxt/CREDITS.txt | 10 +- contrib/hxt/core/CMakeLists.txt | 50 + contrib/hxt/{ => core/include}/hxt_bbox.h | 16 +- contrib/hxt/{ => core/include}/hxt_mesh.h | 51 +- contrib/hxt/{ => core/include}/hxt_message.h | 90 +- contrib/hxt/{ => core/include}/hxt_omp.h | 0 contrib/hxt/{ => core/include}/hxt_sort.h | 55 +- contrib/hxt/{ => core/include}/hxt_tools.h | 54 +- contrib/hxt/{ => core/src}/hxt_bbox.c | 8 + contrib/hxt/{ => core/src}/hxt_mesh.c | 177 +- contrib/hxt/{ => core/src}/hxt_message.c | 9 + contrib/hxt/{ => core/src}/hxt_sort.c | 8 + contrib/hxt/hxt_api.h | 118 -- contrib/hxt/hxt_bissection.c | 458 ---- contrib/hxt/hxt_bissection.h | 11 - contrib/hxt/hxt_boundary_recovery.h | 4 - contrib/hxt/hxt_context.c | 19 - contrib/hxt/hxt_context.h | 9 - contrib/hxt/hxt_edgeRemoval.h | 43 - contrib/hxt/hxt_laplace.c | 159 -- contrib/hxt/hxt_laplace.h | 8 - contrib/hxt/hxt_mesh3d.c | 424 ---- contrib/hxt/hxt_mesh3d.h | 28 - contrib/hxt/hxt_mesh3d_main.c | 166 -- contrib/hxt/hxt_mesh3d_main.h | 20 - contrib/hxt/hxt_mesh_size.c | 145 -- contrib/hxt/hxt_mesh_size.h | 18 - contrib/hxt/hxt_octree_api.h | 53 - contrib/hxt/hxt_opt.c | 812 ------- contrib/hxt/hxt_opt.h | 170 -- contrib/hxt/hxt_option.c | 504 ----- contrib/hxt/hxt_option.h | 182 -- contrib/hxt/hxt_parametrization.c | 754 ------- contrib/hxt/hxt_parametrization.h | 17 - contrib/hxt/hxt_tetOpti.c | 819 ------- contrib/hxt/hxt_tetOptiDate.h | 19 - contrib/hxt/hxt_tetPartition.h | 35 - contrib/hxt/hxt_tetPostpro.c | 182 -- contrib/hxt/hxt_tetPostpro.h | 32 - contrib/hxt/hxt_tetQuality.c | 254 --- contrib/hxt/hxt_tet_aspect_ratio.c | 192 -- contrib/hxt/hxt_tet_aspect_ratio.h | 9 - contrib/hxt/hxt_tetrahedra.c | 1882 ----------------- contrib/hxt/hxt_tetrahedra.h | 113 - contrib/hxt/hxt_tools.c | 138 -- contrib/hxt/laplace_main.c | 16 - contrib/hxt/predicates.h | 72 - contrib/hxt/predicates/CMakeLists.txt | 32 + contrib/hxt/predicates/include/predicates.h | 98 + contrib/hxt/{ => predicates/src}/predicates.c | 477 ++--- contrib/hxt/reparam/CMakeLists.txt | 46 + contrib/hxt/reparam/cmake/FindPETSc.cmake | 119 ++ .../hxt/{ => reparam/include}/hxt_curvature.h | 0 contrib/hxt/{ => reparam/include}/hxt_edge.h | 2 - .../{ => reparam/include}/hxt_linear_system.h | 3 +- .../{ => reparam/include}/hxt_mean_values.h | 3 + .../hxt/{ => reparam/src}/hxt_class_macro.h | 0 contrib/hxt/{ => reparam/src}/hxt_curvature.c | 53 +- contrib/hxt/{ => reparam/src}/hxt_edge.c | 9 +- .../hxt/{ => reparam/src}/hxt_linear_system.c | 5 + .../{ => reparam/src}/hxt_linear_system_lu.c | 144 +- .../{ => reparam/src}/hxt_linear_system_lu.h | 3 +- .../src}/hxt_linear_system_petsc.c | 65 +- .../src}/hxt_linear_system_petsc.h | 3 +- .../hxt/{ => reparam/src}/hxt_mean_values.c | 11 +- .../{ => reparam/src}/hxt_non_linear_solver.c | 3 +- .../{ => reparam/src}/hxt_non_linear_solver.h | 1 - contrib/hxt/sizeField/CMakeLists.txt | 15 + contrib/hxt/{ => sizeField}/hxt_octree.cpp | 26 +- contrib/hxt/{ => sizeField}/hxt_octree.h | 4 - contrib/hxt/tetBR/CMakeLists.txt | 28 + .../hxt/tetBR/include/hxt_boundary_recovery.h | 16 + .../{ => tetBR/src}/hxt_boundary_recovery.cxx | 113 +- contrib/hxt/{ => tetBR/src}/tetgenBR.cxx | 0 contrib/hxt/{ => tetBR/src}/tetgenBR.h | 2 +- contrib/hxt/tetMesh/CMakeLists.txt | 59 + .../hxt/{ => tetMesh/include}/hxt_tetMesh.h | 14 +- contrib/hxt/{ => tetMesh/src}/HXTSPR.c | 198 +- contrib/hxt/{ => tetMesh/src}/HXTSPR.h | 65 +- .../hxt/{ => tetMesh/src}/hxt_edgeRemoval.c | 185 +- contrib/hxt/tetMesh/src/hxt_edgeRemoval.h | 26 + contrib/hxt/{ => tetMesh/src}/hxt_smoothing.c | 52 +- contrib/hxt/{ => tetMesh/src}/hxt_smoothing.h | 31 +- contrib/hxt/{ => tetMesh/src}/hxt_tetColor.c | 8 + contrib/hxt/{ => tetMesh/src}/hxt_tetColor.h | 12 +- .../hxt/{ => tetMesh/src}/hxt_tetDelaunay.c | 594 ++++-- .../hxt/{ => tetMesh/src}/hxt_tetDelaunay.h | 14 +- contrib/hxt/{ => tetMesh/src}/hxt_tetFlag.c | 10 +- contrib/hxt/{ => tetMesh/src}/hxt_tetFlag.h | 19 +- contrib/hxt/{ => tetMesh/src}/hxt_tetMesh.c | 36 +- .../hxt/{ => tetMesh/src}/hxt_tetNodalSize.c | 9 + .../hxt/{ => tetMesh/src}/hxt_tetNodalSize.h | 12 +- contrib/hxt/tetMesh/src/hxt_tetOpti.c | 724 +++++++ contrib/hxt/{ => tetMesh/src}/hxt_tetOpti.h | 22 +- contrib/hxt/tetMesh/src/hxt_tetOptiUtils.h | 68 + contrib/hxt/tetMesh/src/hxt_tetPartition.h | 66 + contrib/hxt/tetMesh/src/hxt_tetQuality.c | 70 + .../hxt/{ => tetMesh/src}/hxt_tetQuality.h | 26 +- contrib/hxt/{ => tetMesh/src}/hxt_tetRefine.c | 390 ++-- contrib/hxt/{ => tetMesh/src}/hxt_tetRefine.h | 15 +- contrib/hxt/{ => tetMesh/src}/hxt_tetRepair.c | 176 +- contrib/hxt/{ => tetMesh/src}/hxt_tetRepair.h | 12 +- contrib/hxt/{ => tetMesh/src}/hxt_tetSync.c | 12 +- contrib/hxt/{ => tetMesh/src}/hxt_tetSync.h | 13 +- contrib/hxt/{ => tetMesh/src}/hxt_tetUtils.c | 13 +- contrib/hxt/{ => tetMesh/src}/hxt_tetUtils.h | 13 +- contrib/hxt/{ => tetMesh/src}/hxt_vertices.c | 8 + contrib/hxt/{ => tetMesh/src}/hxt_vertices.h | 12 +- 115 files changed, 3317 insertions(+), 9499 deletions(-) delete mode 100644 contrib/hxt/CMakeLists.txt create mode 100644 contrib/hxt/core/CMakeLists.txt rename contrib/hxt/{ => core/include}/hxt_bbox.h (90%) rename contrib/hxt/{ => core/include}/hxt_mesh.h (79%) rename contrib/hxt/{ => core/include}/hxt_message.h (53%) rename contrib/hxt/{ => core/include}/hxt_omp.h (100%) rename contrib/hxt/{ => core/include}/hxt_sort.h (97%) rename contrib/hxt/{ => core/include}/hxt_tools.h (81%) rename contrib/hxt/{ => core/src}/hxt_bbox.c (92%) rename contrib/hxt/{ => core/src}/hxt_mesh.c (82%) rename contrib/hxt/{ => core/src}/hxt_message.c (96%) rename contrib/hxt/{ => core/src}/hxt_sort.c (93%) delete mode 100644 contrib/hxt/hxt_api.h delete mode 100644 contrib/hxt/hxt_bissection.c delete mode 100644 contrib/hxt/hxt_bissection.h delete mode 100644 contrib/hxt/hxt_boundary_recovery.h delete mode 100644 contrib/hxt/hxt_context.c delete mode 100644 contrib/hxt/hxt_context.h delete mode 100644 contrib/hxt/hxt_edgeRemoval.h delete mode 100644 contrib/hxt/hxt_laplace.c delete mode 100644 contrib/hxt/hxt_laplace.h delete mode 100644 contrib/hxt/hxt_mesh3d.c delete mode 100644 contrib/hxt/hxt_mesh3d.h delete mode 100644 contrib/hxt/hxt_mesh3d_main.c delete mode 100644 contrib/hxt/hxt_mesh3d_main.h delete mode 100644 contrib/hxt/hxt_mesh_size.c delete mode 100644 contrib/hxt/hxt_mesh_size.h delete mode 100644 contrib/hxt/hxt_octree_api.h delete mode 100644 contrib/hxt/hxt_opt.c delete mode 100644 contrib/hxt/hxt_opt.h delete mode 100644 contrib/hxt/hxt_option.c delete mode 100644 contrib/hxt/hxt_option.h delete mode 100644 contrib/hxt/hxt_parametrization.c delete mode 100644 contrib/hxt/hxt_parametrization.h delete mode 100644 contrib/hxt/hxt_tetOpti.c delete mode 100644 contrib/hxt/hxt_tetOptiDate.h delete mode 100644 contrib/hxt/hxt_tetPartition.h delete mode 100644 contrib/hxt/hxt_tetPostpro.c delete mode 100644 contrib/hxt/hxt_tetPostpro.h delete mode 100644 contrib/hxt/hxt_tetQuality.c delete mode 100644 contrib/hxt/hxt_tet_aspect_ratio.c delete mode 100644 contrib/hxt/hxt_tet_aspect_ratio.h delete mode 100644 contrib/hxt/hxt_tetrahedra.c delete mode 100644 contrib/hxt/hxt_tetrahedra.h delete mode 100644 contrib/hxt/hxt_tools.c delete mode 100644 contrib/hxt/laplace_main.c delete mode 100644 contrib/hxt/predicates.h create mode 100644 contrib/hxt/predicates/CMakeLists.txt create mode 100644 contrib/hxt/predicates/include/predicates.h rename contrib/hxt/{ => predicates/src}/predicates.c (89%) create mode 100644 contrib/hxt/reparam/CMakeLists.txt create mode 100644 contrib/hxt/reparam/cmake/FindPETSc.cmake rename contrib/hxt/{ => reparam/include}/hxt_curvature.h (100%) rename contrib/hxt/{ => reparam/include}/hxt_edge.h (97%) rename contrib/hxt/{ => reparam/include}/hxt_linear_system.h (98%) rename contrib/hxt/{ => reparam/include}/hxt_mean_values.h (95%) rename contrib/hxt/{ => reparam/src}/hxt_class_macro.h (100%) rename contrib/hxt/{ => reparam/src}/hxt_curvature.c (81%) rename contrib/hxt/{ => reparam/src}/hxt_edge.c (98%) rename contrib/hxt/{ => reparam/src}/hxt_linear_system.c (96%) rename contrib/hxt/{ => reparam/src}/hxt_linear_system_lu.c (77%) rename contrib/hxt/{ => reparam/src}/hxt_linear_system_lu.h (98%) rename contrib/hxt/{ => reparam/src}/hxt_linear_system_petsc.c (88%) rename contrib/hxt/{ => reparam/src}/hxt_linear_system_petsc.h (98%) rename contrib/hxt/{ => reparam/src}/hxt_mean_values.c (99%) rename contrib/hxt/{ => reparam/src}/hxt_non_linear_solver.c (99%) rename contrib/hxt/{ => reparam/src}/hxt_non_linear_solver.h (98%) create mode 100644 contrib/hxt/sizeField/CMakeLists.txt rename contrib/hxt/{ => sizeField}/hxt_octree.cpp (99%) rename contrib/hxt/{ => sizeField}/hxt_octree.h (98%) create mode 100644 contrib/hxt/tetBR/CMakeLists.txt create mode 100644 contrib/hxt/tetBR/include/hxt_boundary_recovery.h rename contrib/hxt/{ => tetBR/src}/hxt_boundary_recovery.cxx (91%) rename contrib/hxt/{ => tetBR/src}/tetgenBR.cxx (100%) rename contrib/hxt/{ => tetBR/src}/tetgenBR.h (99%) create mode 100644 contrib/hxt/tetMesh/CMakeLists.txt rename contrib/hxt/{ => tetMesh/include}/hxt_tetMesh.h (93%) rename contrib/hxt/{ => tetMesh/src}/HXTSPR.c (91%) rename contrib/hxt/{ => tetMesh/src}/HXTSPR.h (79%) rename contrib/hxt/{ => tetMesh/src}/hxt_edgeRemoval.c (77%) create mode 100644 contrib/hxt/tetMesh/src/hxt_edgeRemoval.h rename contrib/hxt/{ => tetMesh/src}/hxt_smoothing.c (84%) rename contrib/hxt/{ => tetMesh/src}/hxt_smoothing.h (50%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetColor.c (99%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetColor.h (82%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetDelaunay.c (82%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetDelaunay.h (94%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetFlag.c (98%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetFlag.h (97%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetMesh.c (86%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetNodalSize.c (96%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetNodalSize.h (76%) create mode 100644 contrib/hxt/tetMesh/src/hxt_tetOpti.c rename contrib/hxt/{ => tetMesh/src}/hxt_tetOpti.h (85%) create mode 100644 contrib/hxt/tetMesh/src/hxt_tetOptiUtils.h create mode 100644 contrib/hxt/tetMesh/src/hxt_tetPartition.h create mode 100644 contrib/hxt/tetMesh/src/hxt_tetQuality.c rename contrib/hxt/{ => tetMesh/src}/hxt_tetQuality.h (73%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetRefine.c (55%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetRefine.h (73%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetRepair.c (75%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetRepair.h (83%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetSync.c (92%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetSync.h (87%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetUtils.c (88%) rename contrib/hxt/{ => tetMesh/src}/hxt_tetUtils.h (86%) rename contrib/hxt/{ => tetMesh/src}/hxt_vertices.c (99%) rename contrib/hxt/{ => tetMesh/src}/hxt_vertices.h (93%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9320475e6..cfeb4c73ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1200,28 +1200,35 @@ if(HAVE_SOLVER) endif() endif() -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/hxt AND - ENABLE_HXT AND HAVE_METIS) - set_config_option(HAVE_HXT "Hxt") - add_subdirectory(contrib/hxt) - include_directories(BEFORE contrib/hxt) - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/hxt/hxt_tetDelaunay.c) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/hxt AND ENABLE_HXT) + if("${CMAKE_VERSION}" VERSION_LESS "3.9.0") + message(WARNING "Your CMake version is not sufficient to compile hxt") + else() + set_config_option(HAVE_HXT "Hxt") set_config_option(HAVE_HXT3D "Hxt3D") - endif() - if(MSVC) - # Visual C++ does not support C99 - force compilation as C++ code - file(GLOB_RECURSE HXT_SRC contrib/hxt/*.c) - set_compile_flags(HXT_SRC "/TP") - endif() - check_include_file("immintrin.h" HAVE_IMMINTRIN_H) - if(NOT HAVE_IMMINTRIN_H) - add_definitions(-DHAVE_NO_IMMINTRIN_H) - endif() - if(HAVE_PETSC) - add_definitions(-DHXT_HAVE_PETSC) - endif() - if(CMAKE_C_COMPILER MATCHES "pgi") - add_definitions(-DHAVE_NO_OPENMP_SIMD) + + set(HXT_REPARAM_OBJECT_ONLY ON CACHE BOOL "use object library" FORCE) + set(HXT_TETMESH_OBJECT_ONLY ON CACHE BOOL "use object library" FORCE) + set(HXT_TETBR_OBJECT_ONLY ON CACHE BOOL "use object library" FORCE) + + add_subdirectory(contrib/hxt/core) # need to be included before reparam tetMesh & tetBR + add_subdirectory(contrib/hxt/predicates) # need to be included before tetMesh & tetBR + add_subdirectory(contrib/hxt/reparam) + add_subdirectory(contrib/hxt/tetMesh) + add_subdirectory(contrib/hxt/tetBR) + + list(APPEND EXTERNAL_LIBRARIES hxt_core hxt_predicates hxt_reparam hxt_tetMesh hxt_tetBR) + list(APPEND EXTERNAL_INCLUDES $<TARGET_PROPERTY:hxt_core,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:hxt_predicates,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:hxt_reparam,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:hxt_tetMesh,INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:hxt_tetBR,INCLUDE_DIRECTORIES>) + + if(HAVE_P4EST) + # this will compile together with GMSH + add_subdirectory(contrib/hxt/sizeField) + include_directories(BEFORE contrib/hxt/sizeField) + endif() endif() endif() diff --git a/Geo/GModelParametrize.cpp b/Geo/GModelParametrize.cpp index 5b6ffe0907..3eecfed250 100644 --- a/Geo/GModelParametrize.cpp +++ b/Geo/GModelParametrize.cpp @@ -33,6 +33,7 @@ #if defined(HAVE_HXT) extern "C" { #include "hxt_mesh.h" +#include "hxt_tools.h" #include "hxt_edge.h" #include "hxt_curvature.h" #include "hxt_linear_system.h" @@ -482,10 +483,8 @@ static HXTStatus gmsh2hxt(int tag, const std::vector<MTriangle *> &t, HXTMesh **pm, std::map<MVertex *, int> &v2c, std::vector<MVertex *> &c2v) { - HXTContext *context; - hxtContextCreate(&context); HXTMesh *m; - HXT_CHECK(hxtMeshCreate(context, &m)); + HXT_CHECK(hxtMeshCreate(&m)); std::set<MVertex *> all; for(std::size_t i = 0; i < t.size(); i++) { all.insert(t[i]->getVertex(0)); diff --git a/Geo/discreteFace.cpp b/Geo/discreteFace.cpp index 8233cf8374..8e20c4d632 100644 --- a/Geo/discreteFace.cpp +++ b/Geo/discreteFace.cpp @@ -20,6 +20,7 @@ #if defined(HAVE_HXT) extern "C" { #include "hxt_mesh.h" +#include "hxt_tools.h" #include "hxt_edge.h" #include "hxt_mean_values.h" #include "hxt_linear_system.h" @@ -446,10 +447,8 @@ static HXTStatus gmsh2hxt(GFace *gf, HXTMesh **pm, int tag = gf->tag(); const std::vector<MTriangle *> &t = gf->triangles; - HXTContext *context; - hxtContextCreate(&context); HXTMesh *m; - HXT_CHECK(hxtMeshCreate(context, &m)); + HXT_CHECK(hxtMeshCreate(&m)); std::set<MVertex *> all; for(size_t i = 0; i < t.size(); i++) { all.insert(t[i]->getVertex(0)); diff --git a/Mesh/automaticMeshSizeField.cpp b/Mesh/automaticMeshSizeField.cpp index 8e6962fcf2..b2d2f5e847 100644 --- a/Mesh/automaticMeshSizeField.cpp +++ b/Mesh/automaticMeshSizeField.cpp @@ -5,6 +5,7 @@ #ifdef HAVE_HXT extern "C" { +#include "hxt_tools.h" #include "hxt_edge.h" #include "hxt_curvature.h" #include "hxt_bbox.h" @@ -66,9 +67,7 @@ HXTStatus automaticMeshSizeField:: updateHXT(){ // create HXT mesh structure HXTMesh *mesh; - HXTContext *context; - HXT_CHECK(hxtContextCreate(&context)); - HXT_CHECK(hxtMeshCreate(context, &mesh)); + HXT_CHECK(hxtMeshCreate(&mesh)); std::map<MVertex *, int> v2c; std::vector<MVertex *> c2v; Gmsh2Hxt(regions, mesh, v2c, c2v); diff --git a/Mesh/automaticMeshSizeField.h b/Mesh/automaticMeshSizeField.h index 915d2f6b1b..aa910f45aa 100644 --- a/Mesh/automaticMeshSizeField.h +++ b/Mesh/automaticMeshSizeField.h @@ -3,7 +3,7 @@ #include "GmshConfig.h" -#ifdef HAVE_HXT +#if defined(HAVE_HXT) && defined(HAVE_P4EST) #include "hxt_octree.h" #endif diff --git a/Mesh/meshGRegionHxt.cpp b/Mesh/meshGRegionHxt.cpp index 1634649cb9..47aff61de8 100644 --- a/Mesh/meshGRegionHxt.cpp +++ b/Mesh/meshGRegionHxt.cpp @@ -26,7 +26,7 @@ #if defined(HAVE_HXT3D) extern "C" { -#include "hxt_api.h" +#include "hxt_tools.h" #include "hxt_boundary_recovery.h" #include "hxt_tetMesh.h" } @@ -365,9 +365,7 @@ static HXTStatus _meshGRegionHxt(std::vector<GRegion *> ®ions) /******************* ^ all argument were processed *********************/ HXTMesh *mesh; - HXTContext *context; - HXT_CHECK(hxtContextCreate(&context)); - HXT_CHECK(hxtMeshCreate(context, &mesh)); + HXT_CHECK(hxtMeshCreate(&mesh)); std::map<MVertex *, int> v2c; std::vector<MVertex *> c2v; @@ -399,7 +397,6 @@ static HXTStatus _meshGRegionHxt(std::vector<GRegion *> ®ions) HXT_CHECK(Hxt2Gmsh(regions, mesh, v2c, c2v)); HXT_CHECK(hxtMeshDelete(&mesh)); - HXT_CHECK(hxtContextDelete(&context)); return HXT_STATUS_OK; } diff --git a/contrib/hxt/CMakeLists.txt b/contrib/hxt/CMakeLists.txt deleted file mode 100644 index ee142416e6..0000000000 --- a/contrib/hxt/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -# Gmsh - Copyright (C) 1997-2020 C. Geuzaine, J.-F. Remacle -# -# See the LICENSE.txt file for license information. Please report all -# issues on https://gitlab.onelab.info/gmsh/gmsh/issues. - -# HXT (reparametrization) -set(SRC - hxt_context.c - hxt_curvature.c - hxt_edge.c - hxt_laplace.c - hxt_linear_system.c - hxt_linear_system_lu.c - hxt_linear_system_petsc.c - hxt_mean_values.c - hxt_mesh.c - hxt_message.c - hxt_parametrization.c - hxt_tools.c - ) - -# HXT3D (3D meshing) -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/hxt_tetDelaunay.c) -set(SRC ${SRC} - hxt_bbox.c - hxt_boundary_recovery.cxx - hxt_edgeRemoval.c - hxt_mesh.c - hxt_smoothing.c - hxt_sort.c - hxt_tetColor.c - hxt_tetDelaunay.c - hxt_tetFlag.c - hxt_tetMesh.c - hxt_tetNodalSize.c - hxt_tetOpti.c - hxt_tetPostpro.c - hxt_tetQuality.c - hxt_tetRefine.c - hxt_tetRepair.c - hxt_tetSync.c - hxt_tetUtils.c - hxt_vertices.c - hxt_octree.cpp - HXTSPR.c - predicates.c -) -endif() - -# do not use arithmetic contraction in predicates.c -if("x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" ) - set_source_files_properties(predicates.c PROPERTIES COMPILE_FLAGS - "/fp:strict") -endif() -if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") - set_source_files_properties(predicates.c PROPERTIES COMPILE_FLAGS - "-fno-unsafe-math-optimizations -ffp-contract=off") -endif() -if(CMAKE_C_COMPILER_ID STREQUAL "Intel") - set_source_files_properties(predicates.c PROPERTIES COMPILE_FLAGS - "-fp-model strict") -endif() - -file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) -append_gmsh_src(contrib/hxt "${SRC};${HDR}") diff --git a/contrib/hxt/CREDITS.txt b/contrib/hxt/CREDITS.txt index 5a7b1896f2..b837763c3a 100644 --- a/contrib/hxt/CREDITS.txt +++ b/contrib/hxt/CREDITS.txt @@ -2,8 +2,8 @@ Universite catholique de Louvain -The TetGen/BR code (tetgenBR.{cxx,h}) is copyright (c) 2016 Hang Si, -Weierstrass Institute for Applied Analysis and Stochatics. It is relicensed -under the terms of gmsh/LICENSE.txt for use in Gmsh thanks to a Software License -Agreement between Weierstrass Institute for Applied Analysis and Stochastics and -GMESH SPRL. +The TetGen/BR code (hxt_boundaryRecovery/src/tetgenBR.{cxx,h}) is copyright (c) +2016 Hang Si, Weierstrass Institute for Applied Analysis and Stochatics. It is +relicensed under the terms of gmsh/LICENSE.txt for use in Gmsh thanks to a +Software License Agreement between Weierstrass Institute for Applied Analysis +and Stochastics and GMESH SPRL. diff --git a/contrib/hxt/core/CMakeLists.txt b/contrib/hxt/core/CMakeLists.txt new file mode 100644 index 0000000000..d88337ed53 --- /dev/null +++ b/contrib/hxt/core/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.9) +project(hxt_core C) + +if(TARGET hxt_core) + # header guard for CMake. You need to include this directory first + return() +endif() + +option(HXT_ENABLE_OPENMP "Enable OpenMP" ON) +option(HXT_ALIGN_ALLOCATIONS "Align allocation" OFF) +option(HXT_CORE_FILEIO "Compile HXT core with file I/O" OFF) +option(HXT_CORE_OBJECT_ONLY "Do not create hxt_core library" ON) + +set(HXT_CORE_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_bbox.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_mesh.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_message.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_sort.c" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_bbox.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_mesh.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_message.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_omp.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_sort.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tools.h" + ) + +if(HXT_CORE_OBJECT_ONLY) + # make an object library (no archive) + add_library(hxt_core OBJECT ${HXT_CORE_SRC}) +else() + add_library(hxt_core ${HXT_CORE_SRC}) +endif() + +target_include_directories(hxt_core PUBLIC include) +target_compile_features(hxt_core PRIVATE c_std_99) + +if(HXT_ENABLE_OPENMP) + find_package(OpenMP 4) + if(OpenMP_C_FOUND) + target_link_libraries(hxt_core PUBLIC OpenMP::OpenMP_C) + endif() +endif() + +if(HXT_ALIGN_ALLOCATIONS) + target_compile_definitions(hxt_core PUBLIC HXT_ALIGN_ALLOCATIONS) +endif() + +if(HXT_ENABLE_FILEIO) + target_compile_definitions(hxt_core PUBLIC HXT_CORE_FILEIO) +endif() diff --git a/contrib/hxt/hxt_bbox.h b/contrib/hxt/core/include/hxt_bbox.h similarity index 90% rename from contrib/hxt/hxt_bbox.h rename to contrib/hxt/core/include/hxt_bbox.h index f96f5d82f8..ca37248a3f 100644 --- a/contrib/hxt/hxt_bbox.h +++ b/contrib/hxt/core/include/hxt_bbox.h @@ -1,13 +1,21 @@ -#ifndef _HXT_BBOX_H_ -#define _HXT_BBOX_H_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot -#include <hxt_tools.h> // for stdint.h and hxtDeclareAligned32 only -#include <float.h> +#ifndef HXT_BBOX_H +#define HXT_BBOX_H #ifdef __cplusplus extern "C" { #endif +#include <hxt_tools.h> // for stdint.h and hxtDeclareAligned32 only +#include <float.h> + // the fourth member is unused... typedef struct hxtBboxStruct{ double hxtDeclareAligned32 min[3]; diff --git a/contrib/hxt/hxt_mesh.h b/contrib/hxt/core/include/hxt_mesh.h similarity index 79% rename from contrib/hxt/hxt_mesh.h rename to contrib/hxt/core/include/hxt_mesh.h index cc1d5ba0cb..46134e3274 100644 --- a/contrib/hxt/hxt_mesh.h +++ b/contrib/hxt/core/include/hxt_mesh.h @@ -1,12 +1,13 @@ -#ifndef _HEXTREME_MESH_ -#define _HEXTREME_MESH_ +#ifndef HXT_MESH_H +#define HXT_MESH_H -#include "hxt_tools.h" // to have SIMD_ALIGN and stdint.h - -#if defined(WIN32) && !defined(INT32_MAX) // FIXME: Gmsh -#define INT32_MAX 2147483647i32 +#ifdef __cplusplus +extern "C" { #endif +#include "hxt_message.h" +#include <stdint.h> + #define HXT_GHOST_VERTEX UINT32_MAX #define HXT_NO_ADJACENT UINT64_MAX @@ -23,9 +24,7 @@ typedef enum { HXT_PYR = 7 } HXT_ELT_TYPE; -struct hxtMeshStruct { - HXTContext* ctx; - +typedef struct { // vertices struct { uint32_t num; @@ -43,7 +42,7 @@ struct hxtMeshStruct { uint64_t num; // number of tetrahedra uint64_t size; // reserved number of tetrahedra (size of the vector) } tetrahedra; - + // hexahedra struct { uint32_t* node; // aligned (size = hexahedra.size*8*sizeof(uint32_t)) @@ -65,7 +64,7 @@ struct hxtMeshStruct { uint64_t num; // number of tetrahedra uint64_t size; // reserved number of prisms (size of the vector) } prisms; - + // pyramids struct { uint32_t* node; // aligned (size = pyramids.size*5*sizeof(uint32_t)) @@ -80,12 +79,20 @@ struct hxtMeshStruct { // triangles // TODO: consider writing a array of structure... struct { uint32_t* node; - uint64_t* neigh; + uint64_t* neigh; uint16_t* colors; uint64_t num; uint64_t size; } triangles; + struct { + uint32_t* node; + uint64_t* neigh; + uint16_t* colors; + uint64_t num; + uint64_t size; + } triangles2; + // quads struct { uint32_t* node; @@ -102,6 +109,13 @@ struct hxtMeshStruct { uint64_t size; } lines; + struct { + uint32_t* node; + uint16_t* colors; + uint32_t num; + uint32_t size; + } points; + // boundary representation struct { uint16_t numVolumes; @@ -115,7 +129,18 @@ struct hxtMeshStruct { uint16_t numPoints; uint16_t *points; } brep; -}; +} HXTMesh; + +HXTStatus hxtMeshCreate ( HXTMesh** mesh); +HXTStatus hxtMeshDelete ( HXTMesh** meshPtr); +#ifdef HXT_CORE_FILEIO +HXTStatus hxtMeshReadGmsh ( HXTMesh* mesh, const char* filename); +HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh, const char* filename); +#endif + +#ifdef __cplusplus +} +#endif #endif diff --git a/contrib/hxt/hxt_message.h b/contrib/hxt/core/include/hxt_message.h similarity index 53% rename from contrib/hxt/hxt_message.h rename to contrib/hxt/core/include/hxt_message.h index e1b4ff2bb3..0ca3f52240 100644 --- a/contrib/hxt/hxt_message.h +++ b/contrib/hxt/core/include/hxt_message.h @@ -1,8 +1,60 @@ -#ifndef _MESSAGE_H_ -#define _MESSAGE_H_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_MESSAGE_H +#define HXT_MESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdlib.h> +#include <stdarg.h> + + +/* HEXTREME FUNCTIONS ONLY RETURN A STATUS (except hxtGetMessageString)*/ +typedef enum +{ + // positive values mean a success => HXT_CHECK does nothing for positive values + HXT_STATUS_OK = 0, + HXT_STATUS_TRUE = 0, + HXT_STATUS_FALSE = 1, + + + // ====== ERRORS + // negatives values means errors + + // Fatal Errors => HXT_CHECK give trace message and return + HXT_STATUS_ERROR = -1, + HXT_STATUS_FAILED = -2, + HXT_STATUS_ASSERTION_FAILED = -3, + HXT_STATUS_OUT_OF_MEMORY = -4, + HXT_STATUS_FILE_CANNOT_BE_OPENED = -5, + HXT_STATUS_POINTER_ERROR = -6, + HXT_STATUS_READ_ERROR = -7, + HXT_STATUS_WRITE_ERROR = -8, + HXT_STATUS_RANGE_ERROR = -9, + HXT_STATUS_FORMAT_ERROR = -10, + + + // INTERNAL Errors (<= HXT_STATUS_INTERNAL) => HXT_CHECK does not give trace message but returns... should be catched internally ! + HXT_STATUS_INTERNAL = -1024, + HXT_STATUS_SKIP = -1025, + HXT_STATUS_TRYAGAIN = -1026, + // a smoothing or topological operation can silently fail because of these + HXT_STATUS_CONFLICT = -1027, + HXT_STATUS_CONSTRAINT = -1028, + HXT_STATUS_NOTBETTER = -1029, + HXT_STATUS_DOUBLE_PT = -1030 + + +}HXTStatus; -#include "hxt_api.h" -#include "hxt_omp.h" #define STR(x) #x #define STRINGIFY(x) STR(x) @@ -50,9 +102,33 @@ #endif -#ifdef __cplusplus -extern "C" { -#endif +const char* hxtGetStatusString(HXTStatus status); + + +/* MESSAGE */ +typedef struct { + /* the message content */ + const char* string; // lifetime = time of callback function + + /* information about the location of the code which sent the message */ + const char* func; // lifetime = forever + const char* file; // lifetime = forever + const char* line; // lifetime = forever + int threadId; // the thread which sent the message + int numThreads; // the number of threads + + enum{ + HXT_MSGLEVEL_INFO = 0, + HXT_MSGLEVEL_DEBUG = 1, + HXT_MSGLEVEL_WARNING = 2, + HXT_MSGLEVEL_ERROR = 3, + HXT_MSGLEVEL_TRACE = 4 + } level; +} HXTMessage; + + +/* MESSAGE AND ERROR HANDLING */ +HXTStatus hxtSetMessageCallback (HXTStatus (*hxtMsgCallback)(HXTMessage* msg)); HXTStatus hxtMessageInfo ( const char* func, const char* file, const char* line, const char *fmt, ...); HXTStatus hxtMessageWarning ( const char* func, const char* file, const char* line, const char *fmt, ...); diff --git a/contrib/hxt/hxt_omp.h b/contrib/hxt/core/include/hxt_omp.h similarity index 100% rename from contrib/hxt/hxt_omp.h rename to contrib/hxt/core/include/hxt_omp.h diff --git a/contrib/hxt/hxt_sort.h b/contrib/hxt/core/include/hxt_sort.h similarity index 97% rename from contrib/hxt/hxt_sort.h rename to contrib/hxt/core/include/hxt_sort.h index c42be6961f..e6525d0554 100644 --- a/contrib/hxt/hxt_sort.h +++ b/contrib/hxt/core/include/hxt_sort.h @@ -1,31 +1,21 @@ -/* This file is part of HXTSort. * - * - HXTSort 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 3 of the License, or * - (at your option) any later version. * - * - HXTSort 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 HXTSort. If not, see <http://www.gnu.org/licenses/>. * - * - See the COPYING file for the GNU General Public License . * - * -Author: Célestin Marot (celestin.marot@uclouvain.be) */ - -#ifndef __HXT_SORT_H__ -#define __HXT_SORT_H__ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot -#include "hxt_tools.h" +#ifndef HXT_SORT_H +#define HXT_SORT_H #ifdef __cplusplus extern "C" { #endif +#include "hxt_tools.h" +#include "hxt_omp.h" + // sorting function already defined typedef struct{ uint64_t v[2]; @@ -169,6 +159,27 @@ do { \ } \ } while(0) +/* simply sort 4 values */ +#define HXTSORT_4_VALUES_INPLACE(HXTSORT_TYPE, a) \ +do { \ + HXTSORT_TYPE* _copya = (a); \ + if(_copya[0]>_copya[1]){ \ + HXTSORT_TYPE _tmp = _copya[0]; _copya[0] = _copya[1]; _copya[1] = _tmp; \ + } \ + if(_copya[2]>_copya[3]){ \ + HXTSORT_TYPE _tmp = _copya[2]; _copya[2] = _copya[3]; _copya[3] = _tmp; \ + } \ + if(_copya[0]>_copya[2]){ \ + HXTSORT_TYPE _tmp = _copya[0]; _copya[0] = _copya[2]; _copya[2] = _tmp; \ + } \ + if(_copya[1]>_copya[3]){ \ + HXTSORT_TYPE _tmp = _copya[1]; _copya[1] = _copya[3]; _copya[3] = _tmp; \ + } \ + if(_copya[1]>_copya[2]){ \ + HXTSORT_TYPE _tmp = _copya[1]; _copya[1] = _copya[2]; _copya[2] = _tmp; \ + } \ +} while(0) + /************************************************************************************** * To use pragma in a macro * diff --git a/contrib/hxt/hxt_tools.h b/contrib/hxt/core/include/hxt_tools.h similarity index 81% rename from contrib/hxt/hxt_tools.h rename to contrib/hxt/core/include/hxt_tools.h index 1e6a76e4a3..cefd41eda8 100644 --- a/contrib/hxt/hxt_tools.h +++ b/contrib/hxt/core/include/hxt_tools.h @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #ifndef HXT_TOOLS_H #define HXT_TOOLS_H @@ -5,6 +13,10 @@ extern "C" { #endif +#include "hxt_message.h" +#include <string.h> +#include <stdint.h> + /* define SIMD ALIGNMENT */ #ifndef SIMD_ALIGN #ifdef HXT_ALIGN_ALLOCATIONS @@ -23,8 +35,8 @@ extern "C" { #ifndef __restrict__ #define __restrict__ __restrict #endif -#define HXTu64 "%I64u" -#define HXTd64 "%I64d" +#define HXTu64 "I64u" +#define HXTd64 "I64d" #define HXT_LIKELY(exp) exp #define HXT_UNLIKELY(exp) exp #define HXT_ASSUME(exp) __assume(exp) @@ -34,8 +46,8 @@ extern "C" { #define hxtDeclareAligned __attribute__((aligned(SIMD_ALIGN))) #define hxtDeclareAligned32 __attribute__((aligned(32))) #define hxtDeclareAligned64 __attribute__((aligned(64))) -#define HXTu64 "%" PRIu64 -#define HXTi64 "%" PRId64 +#define HXTu64 PRIu64 +#define HXTi64 PRId64 #define HXT_LIKELY(exp) __builtin_expect(!!(exp), 1) #define HXT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) #ifdef __GNUC__ @@ -52,12 +64,6 @@ extern "C" { #define HXT_UNUSED(x) (void)(x) // portable way to avoid warning about unused variable -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <math.h> -#include "hxt_message.h" // already include hxt_api (for HXT_status_t and stdint.h) - /********************************************************* * Hextreme malloc implementation *********************************************************/ @@ -246,34 +252,6 @@ static inline uint32_t hxtReproducibleLCG(uint32_t *seed) return *seed; } -/********************************************************* - * Operations on 3D vectors - *********************************************************/ -HXTStatus hxtNorm2V3(double v[3], double* norm2); -HXTStatus hxtNorm2V(double v[3], int size, double* norm2); -HXTStatus hxtNormalizeV3(double v[3]); -HXTStatus hxtNormalizeV(double *v, int size); -HXTStatus hxtCrossProductV3(double a[3], double b[3], double res[3]); - -/********************************************************* - * Matrix operations - *********************************************************/ -HXTStatus hxtDet2x2(double mat[2][2], double* det); -HXTStatus hxtInv2x2(double mat[2][2], double inv[2][2], double *det); -HXTStatus hxtDet3x3(double mat[3][3], double *det); -HXTStatus hxtInv3x3(double mat[3][3], double inv[3][3], double *det); - -HXTStatus hxtInv4x4ColumnMajor(double mat[16], double inv[16], double *det); - -/********************************************************* - * Operations on linear Tet - *********************************************************/ -HXTStatus hxtJacobianLinTet(double *x , double *y, double *z , double mat[3][3]); - -#ifndef M_PI - #define M_PI 3.14159265358979323846264338327950 -#endif // !M_PI - #ifdef __cplusplus } #endif diff --git a/contrib/hxt/hxt_bbox.c b/contrib/hxt/core/src/hxt_bbox.c similarity index 92% rename from contrib/hxt/hxt_bbox.c rename to contrib/hxt/core/src/hxt_bbox.c index 9bd247b5af..694f23dfa2 100644 --- a/contrib/hxt/hxt_bbox.c +++ b/contrib/hxt/core/src/hxt_bbox.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_bbox.h" /* update the bounding box with an array of n vertices at once (far quicker) */ diff --git a/contrib/hxt/hxt_mesh.c b/contrib/hxt/core/src/hxt_mesh.c similarity index 82% rename from contrib/hxt/hxt_mesh.c rename to contrib/hxt/core/src/hxt_mesh.c index 7ea65b5bf5..acc2980767 100644 --- a/contrib/hxt/hxt_mesh.c +++ b/contrib/hxt/core/src/hxt_mesh.c @@ -1,4 +1,6 @@ #include "hxt_mesh.h" +#include "hxt_tools.h" +#include <stdio.h> #include <float.h> /* Compatible with HXT_ELT_TYPE enum exposed in header */ @@ -10,84 +12,15 @@ #define HEXID 5 #define PRIID 6 #define PYRID 7 +#define TRIID2 9 -HXTStatus hxtMeshCreate ( HXTContext* ctx, HXTMesh** mesh) { +HXTStatus hxtMeshCreate ( HXTMesh** mesh) { HXT_CHECK( hxtMalloc (mesh, sizeof(HXTMesh)) ); if (*mesh == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); - (*mesh)->ctx = ctx; - // vertices - (*mesh)->vertices.coord = NULL; - (*mesh)->vertices.num = 0; - (*mesh)->vertices.size = 0; - - // tetrahedra - (*mesh)->tetrahedra.node = NULL; - (*mesh)->tetrahedra.colors = NULL; - (*mesh)->tetrahedra.flag = NULL; - (*mesh)->tetrahedra.neigh = NULL; - (*mesh)->tetrahedra.neighType = NULL; - // (*mesh)->tetrahedra.subdet = NULL; - (*mesh)->tetrahedra.num = 0; - (*mesh)->tetrahedra.size = 0; - - // hexahedra - (*mesh)->hexahedra.node = NULL; - (*mesh)->hexahedra.colors = NULL; - (*mesh)->hexahedra.flag = NULL; - (*mesh)->hexahedra.neigh = NULL; - (*mesh)->hexahedra.neighType = NULL; - (*mesh)->hexahedra.num = 0; - (*mesh)->hexahedra.size = 0; - - // prisms - (*mesh)->prisms.node = NULL; - (*mesh)->prisms.colors = NULL; - (*mesh)->prisms.flag = NULL; - (*mesh)->prisms.neigh = NULL; - (*mesh)->prisms.neighType = NULL; - (*mesh)->prisms.num = 0; - (*mesh)->prisms.size = 0; - - // pyramids - (*mesh)->pyramids.node = NULL; - (*mesh)->pyramids.colors = NULL; - (*mesh)->pyramids.flag = NULL; - (*mesh)->pyramids.neigh = NULL; - (*mesh)->pyramids.neighType = NULL; - (*mesh)->pyramids.num = 0; - (*mesh)->pyramids.size = 0; - - // triangles - (*mesh)->triangles.node = NULL; - (*mesh)->triangles.neigh = NULL; - (*mesh)->triangles.colors = NULL; - (*mesh)->triangles.num = 0; - (*mesh)->triangles.size = 0; - - // quads - (*mesh)->quads.node = NULL; - (*mesh)->quads.colors = NULL; - (*mesh)->quads.num = 0; - (*mesh)->quads.size = 0; - - // lines - (*mesh)->lines.node = NULL; - (*mesh)->lines.colors = NULL; - (*mesh)->lines.num = 0; - (*mesh)->lines.size = 0; - - // boundary representation - (*mesh)->brep.numVolumes = 0; - (*mesh)->brep.numSurfacesPerVolume = NULL; - (*mesh)->brep.surfacesPerVolume = NULL; - (*mesh)->brep.numSurfaces = 0; - (*mesh)->brep.numCurvesPerSurface = NULL; - (*mesh)->brep.curvesPerSurface = NULL; - (*mesh)->brep.numCurves = 0; - (*mesh)->brep.endPointsOfCurves = NULL; - (*mesh)->brep.numPoints = 0; - (*mesh)->brep.points = NULL; + // This line, using a compound literal, will initialize everything + // to zero (and pointers to NULL) + **mesh = (HXTMesh) {0}; return HXT_STATUS_OK; } @@ -131,6 +64,10 @@ HXTStatus hxtMeshDelete ( HXTMesh** mesh) { HXT_CHECK( hxtAlignedFree(&(*mesh)->triangles.node) ); HXT_CHECK( hxtAlignedFree(&(*mesh)->triangles.colors) ); + // triangles2 + HXT_CHECK( hxtAlignedFree(&(*mesh)->triangles2.node) ); + HXT_CHECK( hxtAlignedFree(&(*mesh)->triangles2.colors) ); + // quads HXT_CHECK( hxtAlignedFree(&(*mesh)->quads.node) ); HXT_CHECK( hxtAlignedFree(&(*mesh)->quads.colors) ); @@ -139,6 +76,10 @@ HXTStatus hxtMeshDelete ( HXTMesh** mesh) { HXT_CHECK( hxtAlignedFree(&(*mesh)->lines.node) ); HXT_CHECK( hxtAlignedFree(&(*mesh)->lines.colors) ); + // points + HXT_CHECK( hxtAlignedFree(&(*mesh)->points.node) ); + + // boundary representation HXT_CHECK( hxtAlignedFree(&(*mesh)->brep.numSurfacesPerVolume) ); HXT_CHECK( hxtAlignedFree(&(*mesh)->brep.surfacesPerVolume) ); @@ -147,11 +88,21 @@ HXTStatus hxtMeshDelete ( HXTMesh** mesh) { HXT_CHECK( hxtAlignedFree(&(*mesh)->brep.endPointsOfCurves) ); HXT_CHECK( hxtAlignedFree(&(*mesh)->brep.points) ); + // reset every fields to zero + **mesh = (HXTMesh) {0}; HXT_CHECK( hxtFree(mesh) ); return HXT_STATUS_OK; } + + + + + + +#ifdef HXT_CORE_FILEIO + // TODO: more checking of fgets HXTStatus ReadNodesFromGmsh(FILE *fp, HXTMesh* m){ rewind (fp); @@ -184,7 +135,7 @@ HXTStatus ReadNodesFromGmsh(FILE *fp, HXTMesh* m){ // TODO: add possibility to read the elements from an array // TODO: more checking of fgets -// TODO: compute other stuffs, like the subdets... +// TODO: why set to zero AND use malloc ? => either set to zero and use realloc, either trust it is zero and malloc HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ int k; char buf[BUFSIZ]={""}; @@ -192,7 +143,9 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ rewind (fp); m->lines.num = 0; + m->points.num = 0; m->triangles.num = 0; + m->triangles2.num = 0; m->quads.num = 0; m->tetrahedra.num = 0; m->hexahedra.num = 0; @@ -224,6 +177,9 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ else if(etype==TRIID){ // triangles ++(m->triangles.num); } + else if(etype==TRIID2){ // triangles p2 + ++(m->triangles2.num); + } else if(etype==QUADID){ // quads ++(m->quads.num); } @@ -232,6 +188,7 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ } else if(etype==POINTID){ // points // ++(m->lines.num); + ++(m->points.num); } } break; @@ -277,6 +234,13 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ if (m->triangles.colors == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); m->triangles.size = m->triangles.num; } + if (m->triangles2.num){ + HXT_CHECK( hxtAlignedMalloc(&m->triangles2.node, (m->triangles2.num)*6*sizeof(uint32_t)) ); + if (m->triangles2.node == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); + HXT_CHECK( hxtAlignedMalloc(&m->triangles2.colors, (m->triangles2.num)*sizeof(uint16_t)) ); + if (m->triangles2.colors == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); + m->triangles2.size = m->triangles2.num; + } if (m->quads.num){ HXT_CHECK( hxtAlignedMalloc(&m->quads.node, (m->quads.num)*4*sizeof(uint32_t)) ); if (m->quads.node == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); @@ -291,6 +255,11 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ if (m->lines.colors == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); m->lines.size = m->lines.num; } + if (m->points.num){ + HXT_CHECK( hxtAlignedMalloc(&m->points.node, (m->points.num)*sizeof(uint32_t)) ); + if (m->points.node == NULL)return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY); + m->points.size = m->points.num; + } while( fgets(buf, BUFSIZ, fp )){ @@ -304,8 +273,10 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ m->prisms.num=0; m->pyramids.num=0; m->triangles.num=0; + m->triangles2.num=0; m->quads.num=0; m->lines.num=0; + m->points.num=0; for(k=0;k<tmpK;++k){ int etype = 0, ntags; @@ -383,6 +354,21 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ } ++m->triangles.num; } + else if(etype==TRIID2){ // triangles + if(ntags==2){ // + int a, b, c, d, e, f, color; + sscanf(buf, "%*d %*d %*d %*d %d %d %d %d %d %d %d", + &color,&a, &b, &c, &d, &e, &f); + m->triangles2.node[6*m->triangles.num+0] = a-1; + m->triangles2.node[6*m->triangles.num+1] = b-1; + m->triangles2.node[6*m->triangles.num+2] = c-1; + m->triangles2.node[6*m->triangles.num+3] = d-1; + m->triangles2.node[6*m->triangles.num+4] = e-1; + m->triangles2.node[6*m->triangles.num+5] = f-1; + m->triangles2.colors[m->triangles.num] = color; + } + ++m->triangles2.num; + } else if(etype==QUADID){ // quads if(ntags==2){ // int a, b, c, d, color; @@ -400,9 +386,11 @@ HXTStatus ReadElementsFromGmsh(FILE *fp, HXTMesh* m){ if(ntags==2){ // int a; sscanf(buf, "%*d %*d %*d %*d %*d %d",&a); + m->points.node[m->points.num] = a-1; // m->lines.node[2*m->lines.num+0] = a-1; // m->lines.node[2*m->lines.num+1] = b-1; } + ++m->points.num; } if(etype==LINEID){ // lines if(ntags==2){ // @@ -470,17 +458,19 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { if(mesh->tetrahedra.node[i*4 + 3]!=UINT32_MAX){ uint16_t myColor = mesh->tetrahedra.colors ? mesh->tetrahedra.colors[i] : 0; // color = UINT16_MAX --> outside the domain - // if (myColor != UINT16_MAX) + if (myColor != UINT16_MAX) ++index; } } fprintf(file,"$EndNodes\n" "$Elements\n" - "%lu\n", + "%" HXTu64 "\n", index + + mesh->points.num + mesh->lines.num + mesh->triangles.num + + mesh->triangles2.num + mesh->quads.num + mesh->hexahedra.num + mesh->prisms.num @@ -490,24 +480,40 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { { /* print the elements */ index = 0; + for (i=0; i<mesh->points.num; i++){ + fprintf(file,"%lu %u 2 0 %u %u\n", ++index,POINTID, + mesh->points.node[i]+1, + mesh->points.node[i]+1); + } for (i=0; i<mesh->lines.num; i++){ uint16_t myColor = mesh->lines.colors ? mesh->lines.colors[i] : 0; - fprintf(file,"%lu %u 2 0 %u %u %u\n", ++index,LINEID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u\n", ++index,LINEID, myColor, mesh->lines.node[i*2]+1, mesh->lines.node[i*2 + 1]+1); } for (i=0; i<mesh->triangles.num; i++){ uint16_t myColor = mesh->triangles.colors ? mesh->triangles.colors[i] : 0; - fprintf(file,"%lu %u 2 0 %u %u %u %u\n", ++index,TRIID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u\n", ++index,TRIID, myColor, mesh->triangles.node[i*3]+1, mesh->triangles.node[i*3 + 1]+1, mesh->triangles.node[i*3 + 2]+1); } + for (i=0; i<mesh->triangles2.num; i++){ + uint16_t myColor = mesh->triangles2.colors ? mesh->triangles2.colors[i] : 0; + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u %u %u\n", ++index,TRIID2, + myColor, + mesh->triangles2.node[i*6 + 0]+1, + mesh->triangles2.node[i*6 + 1]+1, + mesh->triangles2.node[i*6 + 2]+1, + mesh->triangles2.node[i*6 + 3]+1, + mesh->triangles2.node[i*6 + 4]+1, + mesh->triangles2.node[i*6 + 5]+1); + } for (i=0; i<mesh->quads.num; i++){ uint16_t myColor = mesh->quads.colors ? mesh->quads.colors[i] : 0; - fprintf(file,"%lu %u 2 0 %u %u %u %u %u\n", ++index,QUADID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u\n", ++index,QUADID, myColor, mesh->quads.node[i*4]+1, mesh->quads.node[i*4 + 1]+1, @@ -518,8 +524,8 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { for (i=0; i<mesh->tetrahedra.num; i++){ if(mesh->tetrahedra.node[i*4 + 3]!=UINT32_MAX){ uint16_t myColor = mesh->tetrahedra.colors ? mesh->tetrahedra.colors[i] : 0; - // if (myColor != UINT16_MAX) - fprintf(file,"%lu %u 2 0 %u %u %u %u %u\n", ++index,TETID, + if (myColor != UINT16_MAX) + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u\n", ++index,TETID, myColor, mesh->tetrahedra.node[i*4]+1, mesh->tetrahedra.node[i*4 + 1]+1, @@ -531,7 +537,7 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { if(mesh->hexahedra.node[i*8 + 7]!=UINT32_MAX){ uint16_t myColor = mesh->hexahedra.colors ? mesh->hexahedra.colors[i] : 0; if (myColor != UINT16_MAX) - fprintf(file,"%lu %u 2 0 %u %u %u %u %u %u %u %u %u\n", ++index,HEXID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u %u %u %u %u\n", ++index,HEXID, myColor, mesh->hexahedra.node[i*8]+1, mesh->hexahedra.node[i*8 + 1]+1, @@ -547,7 +553,7 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { if(mesh->prisms.node[i*6 + 5]!=UINT32_MAX){ uint16_t myColor = mesh->prisms.colors ? mesh->prisms.colors[i] : 0; if (myColor != UINT16_MAX) - fprintf(file,"%lu %u 2 0 %u %u %u %u %u %u %u\n", ++index,PRIID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u %u %u\n", ++index,PRIID, myColor, mesh->prisms.node[i*6]+1, mesh->prisms.node[i*6 + 1]+1, @@ -561,7 +567,7 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { if(mesh->pyramids.node[i*5 + 4]!=UINT32_MAX){ uint16_t myColor = mesh->pyramids.colors ? mesh->pyramids.colors[i] : 0; if (myColor != UINT16_MAX) - fprintf(file,"%lu %u 2 0 %u %u %u %u %u %u\n", ++index,PYRID, + fprintf(file, "%" HXTu64 " %u 2 0 %u %u %u %u %u %u\n", ++index,PYRID, myColor, mesh->pyramids.node[i*5]+1, mesh->pyramids.node[i*5 + 1]+1, @@ -577,4 +583,5 @@ HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh , const char *filename) { return HXT_STATUS_OK; } +#endif diff --git a/contrib/hxt/hxt_message.c b/contrib/hxt/core/src/hxt_message.c similarity index 96% rename from contrib/hxt/hxt_message.c rename to contrib/hxt/core/src/hxt_message.c index bedd547d23..46692e04e8 100644 --- a/contrib/hxt/hxt_message.c +++ b/contrib/hxt/core/src/hxt_message.c @@ -1,5 +1,14 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include <stdlib.h> #include <stdio.h> +#include "hxt_omp.h" #include "hxt_message.h" diff --git a/contrib/hxt/hxt_sort.c b/contrib/hxt/core/src/hxt_sort.c similarity index 93% rename from contrib/hxt/hxt_sort.c rename to contrib/hxt/core/src/hxt_sort.c index 4bece40a22..a45cdac0fe 100644 --- a/contrib/hxt/hxt_sort.c +++ b/contrib/hxt/core/src/hxt_sort.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_sort.h" diff --git a/contrib/hxt/hxt_api.h b/contrib/hxt/hxt_api.h deleted file mode 100644 index d2b876b000..0000000000 --- a/contrib/hxt/hxt_api.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _HEXTREME_API_H_ -#define _HEXTREME_API_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdlib.h> -#include <stdarg.h> -#include <stdint.h> - -/* HEXTREME FUNCTIONS ONLY RETURN A STATUS (except hxtGetMessageString)*/ -typedef enum -{ - // positive values mean a success => HXT_CHECK does nothing for positive values - HXT_STATUS_OK = 0, - HXT_STATUS_TRUE = 0, - HXT_STATUS_FALSE = 1, - - - // ====== ERRORS - // negatives values means errors - - // Fatal Errors => HXT_CHECK give trace message and return - HXT_STATUS_ERROR = -1, - HXT_STATUS_FAILED = -2, - HXT_STATUS_ASSERTION_FAILED = -3, - HXT_STATUS_OUT_OF_MEMORY = -4, - HXT_STATUS_FILE_CANNOT_BE_OPENED = -5, - HXT_STATUS_POINTER_ERROR = -6, - HXT_STATUS_READ_ERROR = -7, - HXT_STATUS_WRITE_ERROR = -8, - HXT_STATUS_RANGE_ERROR = -9, - HXT_STATUS_FORMAT_ERROR = -10, - - - // INTERNAL Errors (<= HXT_STATUS_INTERNAL) => HXT_CHECK does not give trace message but returns... should be catched internally ! - HXT_STATUS_INTERNAL = -1024, - HXT_STATUS_SKIP = -1025, - HXT_STATUS_TRYAGAIN = -1026, - // a smoothing or topological operation can silently fail because of these - HXT_STATUS_CONFLICT = -1027, - HXT_STATUS_CONSTRAINT = -1028, - HXT_STATUS_NOTBETTER = -1029, - HXT_STATUS_DOUBLE_PT = -1030 - - -}HXTStatus; - -typedef uint32_t HXTIndex; - -const char* hxtGetStatusString(HXTStatus status); - - -/* MESSAGE */ -typedef struct { - /* the message content */ - const char* string; // lifetime = time of callback function - - /* information about the location of the code which sent the message */ - const char* func; // lifetime = forever - const char* file; // lifetime = forever - const char* line; // lifetime = forever - int threadId; // the thread which sent the message - int numThreads; // the number of threads - - enum{ - HXT_MSGLEVEL_INFO = 0, - HXT_MSGLEVEL_DEBUG = 1, - HXT_MSGLEVEL_WARNING = 2, - HXT_MSGLEVEL_ERROR = 3, - HXT_MSGLEVEL_TRACE = 4 - } level; -} HXTMessage; - - -/* INITIALIZE STUFF, SETS GLOBAL PARAMETERS THROUGH COMMAND LINE*/ -HXTStatus hxtInit(int argc, char **argv); -HXTStatus hxtFinalize(void); - - -/* A CONTEXT SIMILAR TO THE CONTEXT OF GMSH (OPTIONS & CO + MESSAGES) */ -typedef struct hxtContextStruct HXTContext; -HXTStatus hxtContextCreate ( HXTContext** ctxtPtr); -HXTStatus hxtContextDelete ( HXTContext** ctxtPtr); - - -/* MESSAGE AND ERROR HANDLING */ -HXTStatus hxtSetMessageCallback (HXTStatus (*hxtMsgCallback)(HXTMessage* msg)); - - - -/* THE MESH OBJECT */ -typedef struct hxtMeshStruct HXTMesh ; -HXTStatus hxtMeshCreate ( HXTContext* ctxt, HXTMesh** mesh); -HXTStatus hxtMeshDelete ( HXTMesh** meshPtr); -HXTStatus hxtMeshReadGmsh ( HXTMesh* mesh, const char* filename); -HXTStatus hxtMeshWriteGmsh ( HXTMesh* mesh, const char* filename); - -/* THE MESH SIZE OBJECT */ -typedef struct hxtMeshSizeStruct HXTMeshSize; -typedef HXTStatus (*HXTMeshSizeCallback)(double x[3], void* data, double* s); -HXTStatus hxtMeshSizeCreate ( HXTContext* ctxt, HXTMeshSize** ); -HXTStatus hxtMeshSizeDelete ( HXTMeshSize** ); -HXTStatus hxtMeshSizeCompute ( HXTMeshSize* meshSize , double min[3], double max[3], HXTMeshSizeCallback cb, void *data); -HXTStatus hxtMeshSizeEvaluate ( HXTMeshSize* meshSize, double x[3], double* v); - - -/* SOME MESHING ROUTINES */ -HXTStatus hxtMeshTetrahedralize ( HXTMesh* mesh , HXTMeshSize* meshSize); -HXTStatus hxtMeshOptimize ( HXTMesh* mesh , HXTMeshSize* meshSize); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/hxt_bissection.c b/contrib/hxt/hxt_bissection.c deleted file mode 100644 index f6b9c7babf..0000000000 --- a/contrib/hxt/hxt_bissection.c +++ /dev/null @@ -1,458 +0,0 @@ -#include "hxt_edge.h" -#include "hxt_sort.h" - - - -static HXTStatus hxtDoubleLongestEdge(HXTEdges *e, int tri, double *l) -{ - uint32_t *ed = &e->tri2edg[3*tri]; - *l=0; - - for(int i=0; i<3; i++){ - uint64_t *tr= &e->edg2tri[2*ed[i]]; - - if(tr[1]==(uint64_t)-1) - continue; - - if(*l<hxtEdgesLength(e,ed[i])) - *l=hxtEdgesLength(e,ed[i]); - } - return HXT_STATUS_OK; - -} - - -static HXTStatus hxtLongestEdge(HXTEdges *edges, int tri,int *ie,int comp) -{ - - uint32_t *ed = &edges->tri2edg[3*tri]; - double longest = hxtEdgesLength(edges,comp); - *ie=comp; - for(int i=0; i<3; i++){ - uint64_t *tr= &edges->edg2tri[2*ed[i]]; - - if(tr[1]==(uint64_t)-1) - continue; - - if(longest<hxtEdgesLength(edges,ed[i])){ - longest=hxtEdgesLength(edges,ed[i]); - *ie = ed[i]; - } - } - return HXT_STATUS_OK; -} - -HXTStatus hxtLongestEdgeBisection(HXTEdges *edges,int nrefinements) -{ - - double threshold = 0, counter=0; - for(uint32_t ie=0; ie<edges->numEdges; ie++) - if(edges->edg2tri[2*ie+1]==(uint64_t)-1){ - threshold+= hxtEdgesLength(edges,ie); - counter++; - } - if (counter>0) - threshold/=counter; - - // longest-edge bisection: boundary edges are not splitted - for(int ir=0; ir<nrefinements; ir++){ - HXTEdges *e = edges; - HXTMesh *m = edges->edg2mesh; - - - - uint64_t *flag=NULL; - HXT_CHECK(hxtMalloc(&flag,m->triangles.num*sizeof(uint64_t))); - for(uint64_t it=0; it<m->triangles.num; it++){ - double l; - HXT_CHECK(hxtDoubleLongestEdge(e,it,&l)); - if(l>2*threshold) - flag[it] = 0; - else - flag[it] = 1; - } - - int maxVert = m->vertices.num; - int maxTri = m->triangles.num; - int maxEdg = e->numEdges; - uint64_t initialNumberOfTriangles = m->triangles.num; - for(uint64_t it=0; it<initialNumberOfTriangles; it++){ - if(flag[it] > 0) - continue; - - while(flag[it]==0){ - int ti = (int) it, tj; - int ei,ej; - for(int ib=0; ib<3; ib++){ - if (e->edg2tri[2*e->tri2edg[3*it+ib]+1] == (uint64_t) -1) - continue; - else{ - hxtLongestEdge(e,it,&ej,e->tri2edg[3*it+ib]); - break; - } - } - do{ - HXT_CHECK(hxtLongestEdge(e,ti,&ei,ej)); - tj = e->edg2tri[2*ei+0]==ti ? e->edg2tri[2*ei+1] : e->edg2tri[2*ei+0]; - HXT_CHECK(hxtLongestEdge(e,tj,&ej,ei)); - ti = e->edg2tri[2*ej+0]==tj ? e->edg2tri[2*ej+1] : e->edg2tri[2*ej+0]; - }while(ei!=ej); - - m->vertices.num += 1; - if(m->vertices.num > maxVert){ - maxVert *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->vertices.coord,4*maxVert*sizeof(double))); - } - int ni = e->node[2*ei+0], nj = e->node[2*ei+1]; - - for(int xj=0; xj<3; xj++) - m->vertices.coord[4*(m->vertices.num-1)+xj] = ( m->vertices.coord[4*ni+xj] + m->vertices.coord[4*nj+xj] )/2.; - - m->triangles.num +=2; - if(m->triangles.num > maxTri){ - maxTri *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->triangles.node,3*maxTri*sizeof(uint32_t))); - HXT_CHECK(hxtAlignedRealloc(&m->triangles.colors,maxTri*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->tri2edg,3*maxTri*sizeof(uint32_t))); - } - int tti = m->triangles.num-2, ttj = tti+1; - int e0 = e->numEdges, e1=e0+1, e2=e1+1; - for(int ic=0; ic<3; ic++){ - if(m->triangles.node[3*ti+ic]==ni && m->triangles.node[3*ti+(ic+1)%3]==nj){ - m->triangles.node[3*ti+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = m->vertices.num-1; - m->triangles.node[3*tti+1] = nj; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e->tri2edg[3*ti+(ic+1)%3]; - e->tri2edg[3*tti+2] = e1; - - e->tri2edg[3*ti+(ic+1)%3] = e1; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+1]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - else if (m->triangles.node[3*ti+ic]==nj && m->triangles.node[3*ti+(ic+1)%3]==ni) { - m->triangles.node[3*ti+ic] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = nj; - m->triangles.node[3*tti+1] = m->vertices.num-1; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e1; - e->tri2edg[3*tti+2] = e->tri2edg[3*ti+(ic+2)%3]; - - e->tri2edg[3*ti+(ic+2)%3] = e1; - - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+2]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - if(m->triangles.node[3*tj+ic]==nj && m->triangles.node[3*tj+(ic+1)%3]==ni){ - m->triangles.node[3*tj+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = m->vertices.num-1; - m->triangles.node[3*ttj+1] = ni; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ei; - e->tri2edg[3*ttj+1] = e->tri2edg[3*tj+(ic+1)%3]; - e->tri2edg[3*ttj+2] = e2; - - e->tri2edg[3*tj+(ic+1)%3] = e2; - e->tri2edg[3*tj+ic] = e0; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+1]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - - } - else if (m->triangles.node[3*tj+ic]==ni && m->triangles.node[3*tj+(ic+1)%3]==nj){ - - m->triangles.node[3*tj+ic] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = ni; - m->triangles.node[3*ttj+1] = m->vertices.num-1; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ei; - e->tri2edg[3*ttj+1] = e2; - e->tri2edg[3*ttj+2] = e->tri2edg[3*tj+(ic+2)%3]; - - e->tri2edg[3*tj+ic] = e0; - e->tri2edg[3*tj+(ic+2)%3] = e2; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+2]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - } - }//end for - e->numEdges +=3; - if(e->numEdges > maxEdg){ - maxEdg *= 2; - HXT_CHECK(hxtRealloc(&e->node,2*maxEdg*sizeof(uint32_t))); - HXT_CHECK(hxtRealloc(&e->color,maxEdg*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->edg2tri,2*maxEdg*sizeof(uint64_t))); - } - e->node[2*ei+1] = m->vertices.num-1; - e->edg2tri[2*ei+0] = ti; - e->edg2tri[2*ei+1] = ttj; - e->node[2*e0+0] = m->vertices.num-1; - e->node[2*e0+1] = nj; - e->edg2tri[2*e0+0] = tti; - e->edg2tri[2*e0+1] = tj; - e->node[2*e1+0] = m->vertices.num-1; - e->node[2*e1+1] = m->triangles.node[3*tti+2]; - e->edg2tri[2*e1+0] = ti; - e->edg2tri[2*e1+1] = tti; - e->node[2*e2+0] = m->vertices.num-1; - e->node[2*e2+1] = m->triangles.node[3*ttj+2]; - e->edg2tri[2*e2+0] = tj; - e->edg2tri[2*e2+1] = ttj; - - - if (ti < initialNumberOfTriangles) - flag[ti] = 1; - if (tj < initialNumberOfTriangles) - flag[tj] = 1; - - }// end while flag[it]==0 - }//end for it - - - /* - if(threshold>0) - for(uint64_t it=0; it<m->triangles.num; it++){ - double l; - HXT_CHECK(hxtDoubleLongestEdge(e,it,&l)); - if(l>2*threshold && nrefinements<10){ - nrefinements++; - break; - } - } - */ - - }//end refinement - - - - - return HXT_STATUS_OK; -} - - - -static uint64_t hxtLengthKey(uint32_t* edgeID, HXTEdges* edges){ - double l = hxtEdgesLength(edges,*edgeID); - return double_to_u64(l); -} - - -HXTStatus hxtEdgeRefinement(HXTEdges *edges,int nrefinements) -{ - - double threshold = 0, counter=0; - for(uint32_t ie=0; ie<edges->numEdges; ie++) - if(edges->edg2tri[2*ie+1]==(uint64_t)-1){ - threshold+= hxtEdgesLength(edges,ie); - counter++; - } - if (counter>0) - threshold/=counter; - else{ - for(uint32_t ie=0; ie<edges->numEdges; ie++) - threshold+= hxtEdgesLength(edges,ie); - threshold /= edges->numEdges; - } - threshold *= 2; - - - //bisection of longest edges first; boundary edges are not splitted - for(int ir=0; ir<nrefinements; ir++){ - HXTEdges *e = edges; - HXTMesh *m = edges->edg2mesh; - - - - uint32_t* edgIdx = NULL; - HXT_CHECK(hxtMalloc(&edgIdx,edges->numEdges*sizeof(uint32_t))); - - for(uint32_t edg=0; edg<edges->numEdges; edg++) - edgIdx[edg] = edg; - - HXTSORT64_UNIFORM(uint32_t, edgIdx, edges->numEdges, UINT64_MAX, hxtLengthKey, edges); - - - int maxVert = m->vertices.num; - int maxTri = m->triangles.num; - uint32_t initialNumberOfEdges = e->numEdges; - int maxEdg = initialNumberOfEdges; - //splitting from longest edge to smallest one - //splitted edges were larger than thredshold - //boundary edges are never splitted - for(uint32_t edg=initialNumberOfEdges-1; edg>=0; edg--){ - uint32_t ie = edgIdx[edg]; - if(hxtEdgesLength(e,ie)<threshold) - break; - if(e->edg2tri[2*ie+1]==(uint64_t)-1) - continue; - m->vertices.num += 1; - if(m->vertices.num > maxVert){ - maxVert *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->vertices.coord,4*maxVert*sizeof(double))); - } - int ni = e->node[2*ie+0], nj = e->node[2*ie+1]; - int ti = (int) e->edg2tri[2*ie+0], tj = (int) e->edg2tri[2*ie+1]; - for(int xj=0; xj<3; xj++) - m->vertices.coord[4*(m->vertices.num-1)+xj] = ( m->vertices.coord[4*ni+xj] + m->vertices.coord[4*nj+xj] )/2.; - - m->triangles.num +=2; - if(m->triangles.num > maxTri){ - maxTri *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->triangles.node,3*maxTri*sizeof(uint32_t))); - HXT_CHECK(hxtAlignedRealloc(&m->triangles.colors,maxTri*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->tri2edg,3*maxTri*sizeof(uint32_t))); - } - int tti = m->triangles.num-2, ttj = tti+1; - int e0 = e->numEdges, e1=e0+1, e2=e1+1; - for(int ic=0; ic<3; ic++){ - if(m->triangles.node[3*ti+ic]==ni && m->triangles.node[3*ti+(ic+1)%3]==nj){ - m->triangles.node[3*ti+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = m->vertices.num-1; - m->triangles.node[3*tti+1] = nj; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e->tri2edg[3*ti+(ic+1)%3]; - e->tri2edg[3*tti+2] = e1; - - e->tri2edg[3*ti+(ic+1)%3] = e1; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+1]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - else if (m->triangles.node[3*ti+ic]==nj && m->triangles.node[3*ti+(ic+1)%3]==ni) { - m->triangles.node[3*ti+ic] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = nj; - m->triangles.node[3*tti+1] = m->vertices.num-1; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e1; - e->tri2edg[3*tti+2] = e->tri2edg[3*ti+(ic+2)%3]; - - e->tri2edg[3*ti+(ic+2)%3] = e1; - - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+2]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - if(m->triangles.node[3*tj+ic]==nj && m->triangles.node[3*tj+(ic+1)%3]==ni){ - m->triangles.node[3*tj+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = m->vertices.num-1; - m->triangles.node[3*ttj+1] = ni; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ie; - e->tri2edg[3*ttj+1] = e->tri2edg[3*tj+(ic+1)%3]; - e->tri2edg[3*ttj+2] = e2; - - e->tri2edg[3*tj+(ic+1)%3] = e2; - e->tri2edg[3*tj+ic] = e0; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+1]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - - } - else if (m->triangles.node[3*tj+ic]==ni && m->triangles.node[3*tj+(ic+1)%3]==nj){ - - m->triangles.node[3*tj+ic] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = ni; - m->triangles.node[3*ttj+1] = m->vertices.num-1; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ie; - e->tri2edg[3*ttj+1] = e2; - e->tri2edg[3*ttj+2] = e->tri2edg[3*tj+(ic+2)%3]; - - e->tri2edg[3*tj+ic] = e0; - e->tri2edg[3*tj+(ic+2)%3] = e2; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+2]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - } - }//end for - e->numEdges +=3; - if(e->numEdges > maxEdg){ - maxEdg *= 2; - HXT_CHECK(hxtRealloc(&e->node,2*maxEdg*sizeof(uint32_t))); - HXT_CHECK(hxtRealloc(&e->color,maxEdg*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->edg2tri,2*maxEdg*sizeof(uint64_t))); - } - e->node[2*ie+1] = m->vertices.num-1; - e->edg2tri[2*ie+0] = ti; - e->edg2tri[2*ie+1] = ttj; - e->node[2*e0+0] = m->vertices.num-1; - e->node[2*e0+1] = nj; - e->edg2tri[2*e0+0] = tti; - e->edg2tri[2*e0+1] = tj; - e->node[2*e1+0] = m->vertices.num-1; - e->node[2*e1+1] = m->triangles.node[3*tti+2]; - e->edg2tri[2*e1+0] = ti; - e->edg2tri[2*e1+1] = tti; - e->node[2*e2+0] = m->vertices.num-1; - e->node[2*e2+1] = m->triangles.node[3*ttj+2]; - e->edg2tri[2*e2+0] = tj; - e->edg2tri[2*e2+1] = ttj; - - - - - - - - }//end for ie - - - - for(uint32_t ie=0; ie<e->numEdges; ie++) - if(hxtEdgesLength(e,ie)>threshold){ - nrefinements++; - break; - } - - }//end for ir - printf("nrefinements:\t %d\n",nrefinements); - return HXT_STATUS_OK; -} - - diff --git a/contrib/hxt/hxt_bissection.h b/contrib/hxt/hxt_bissection.h deleted file mode 100644 index f38fe702f3..0000000000 --- a/contrib/hxt/hxt_bissection.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef HEXTREME_BISSECTION_H -#define HEXTREME_BISSECTION_H - -#include "hxt_tools.h" -#include "hxt_mesh.h" -#include "hxt_edge.h" - - -HXTStatus hxtLongestEdgeBisection(HXTEdges *edges,int nrefinements); -HXTStatus hxtEdgeRefinement(HXTEdges *edges,int nrefinements); -#endif diff --git a/contrib/hxt/hxt_boundary_recovery.h b/contrib/hxt/hxt_boundary_recovery.h deleted file mode 100644 index b046b4a7a7..0000000000 --- a/contrib/hxt/hxt_boundary_recovery.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _HXT_BOUNDARY_RECOVERY_ -#define _HXT_BOUNDARY_RECOVERY_ -HXTStatus hxt_boundary_recovery(HXTMesh *mesh); -#endif diff --git a/contrib/hxt/hxt_context.c b/contrib/hxt/hxt_context.c deleted file mode 100644 index abf2bdbfaf..0000000000 --- a/contrib/hxt/hxt_context.c +++ /dev/null @@ -1,19 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include "hxt_tools.h" -#include "hxt_context.h" - -HXTStatus hxtInit(int argc, char **argv) { - return HXT_STATUS_OK; -} - -HXTStatus hxtContextCreate ( HXTContext** ctxtPtr){ - HXT_CHECK( hxtMalloc (ctxtPtr, sizeof(HXTContext)) ); - return HXT_STATUS_OK; -} - - -HXTStatus hxtContextDelete ( HXTContext** ctxtPtr){ - HXT_CHECK( hxtFree(ctxtPtr) ); - return HXT_STATUS_OK; -} \ No newline at end of file diff --git a/contrib/hxt/hxt_context.h b/contrib/hxt/hxt_context.h deleted file mode 100644 index 212813efbf..0000000000 --- a/contrib/hxt/hxt_context.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _HXT_CONTEXT_T_ -#define _HXT_CONTEXT_T_ -#include "hxt_api.h" - -struct hxtContextStruct{ - int emptyStructIsUndefinedBehaviorInC; -}; - -#endif diff --git a/contrib/hxt/hxt_edgeRemoval.h b/contrib/hxt/hxt_edgeRemoval.h deleted file mode 100644 index 7b672d2cb7..0000000000 --- a/contrib/hxt/hxt_edgeRemoval.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _HXT_EDGEREMOVAL_ -#define _HXT_EDGEREMOVAL_ - -#include "hxt_tetSync.h" -#include "hxt_tetPartition.h" -#include "hxt_tetQuality.h" -#include "hxt_tetOptiDate.h" - -#define HXT_EDGE_REMOVAL_MAX 7 // you cannot increase it above 7 ATM - -typedef struct { // bipyramidal cavity for the edge-removal - uint64_t neigh_up [HXT_EDGE_REMOVAL_MAX]; - uint64_t neigh_down[HXT_EDGE_REMOVAL_MAX]; - uint16_t flag [HXT_EDGE_REMOVAL_MAX]; - uint32_t annulus [HXT_EDGE_REMOVAL_MAX]; - uint32_t v_up; - uint32_t v_down; - uint32_t num; -} HXTBipyramid; - - -typedef struct { - HXTBipyramid cavity; // bipyramid cavity is specific to edge removal, that's why it is not a ptr - HXTDeleted* deleted; - HXTPartition* partition; - HXTTetQualities* quality; - HXTTetDates* date; - HXT2Sync* toSync; -} HXTEdgeRemovalData; - - -/* return internal error (that you must catch) if: - * - the cavity overlap different partitions => HXT_STATUS_CONFLICT - * - there is a contraint inside the cavity => HXT_STATUS_CONSTRAINT - * - does'nt result in a better triangulation => HXT_STATUS_NOTBETTER - * - there is more than 7 pts around the edge => HXT_STATUS_INTERNAL - * a facet without neighbor (set to HXT_NO_ADJACENT) is also a constraint. - */ -HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, - uint64_t badTet, - unsigned edgeID); - -#endif \ No newline at end of file diff --git a/contrib/hxt/hxt_laplace.c b/contrib/hxt/hxt_laplace.c deleted file mode 100644 index ce4d16dd60..0000000000 --- a/contrib/hxt/hxt_laplace.c +++ /dev/null @@ -1,159 +0,0 @@ -#include <math.h> -#include "hxt_laplace.h" -#include "hxt_mesh.h" - -#include "hxt_laplace.h" -#include "hxt_api.h" -#include "hxt_linear_system.h" - -/* - compute the element matrix for one P1 triangle - local matrix is \intE \nabla NI \cdot \nabla NJ ds - v - ^ - | F (u,v) = N_0 (u,v) F_0 + N_1 (u,v) F_1 + N_2 (u,v) F_2 - + 2 FJ is the value of F at node j - |\ NJ ( uI, vI) = \delta_{ij} - | \ N_0 = 1-u-v ; N_1 = u ; N_2 = v - | \ grad N = { { -1 , -1} , { 1 , 0} , { 0 , 1} }; - | \ - | \ - | \ - |0 (0,0) \ 1 (1,0) - +------------+--------> u - - X_0, X_1, X_2 the three vertices of a triangle in XYZ coordinate system - X (u,v) = X_0 N_0 + X_1 N_1 + X_2 N_2 -*/ - -static inline double normalize (double *n){ - double d = sqrt (n[0]*n[0]+n[1]*n[1]+n[2]*n[2]); - if (d != 0.0){ - n[0] /= d; - n[1] /= d; - n[2] /= d; - } - return fabs(d); -} - -static inline void crossprod (double *a, double *b, double *n){ - n[0] = a[1]*b[2] - a[2]*b[1]; - n[1] = - (a[0]*b[2] - a[2]*b[0]); - n[2] = a[0]*b[1] - a[1]*b[0]; -} - - -static inline HXTStatus inverseJacobian ( double *X0, double *X1, double *X2, double invjac[3][3], double *det) -{ - double v1[3] = {X1[0]-X0[0],X1[1]-X0[1],X1[2]-X0[2]}; - double v2[3] = {X2[0]-X0[0],X2[1]-X0[1],X2[2]-X0[2]}; - double n[3] ; crossprod (v1,v2,n); - normalize (n); - double jac[3][3] = {{v1[0], v1[1], v1[2]}, - {v2[0], v2[1], v2[2]}, - {n[0] , n[1] , n[2]}}; - HXT_CHECK(hxtInv3x3(jac, invjac,det)); - return HXT_STATUS_OK; -} - -static inline double dotprod (double *a, double *b){ - return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; -} - -static inline void elementMatrix ( double *X0, double *X1, double *X2, double mat[9]) -{ - double invjac[3][3], det; - inverseJacobian ( X0, X1, X2, invjac, &det); - - double GradN0[3] = {-invjac[0][0]-invjac[0][1],-invjac[1][0]-invjac[1][1],-invjac[2][0]-invjac[2][1]}; - double GradN1[3] = {invjac[0][0],invjac[1][0],invjac[2][0]}; - double GradN2[3] = {invjac[0][1],invjac[1][1],invjac[2][1]}; - - mat[3*0+0] = dotprod(GradN0,GradN0) * det * .5; - mat[3*1+1] = dotprod(GradN1,GradN1) * det * .5; - mat[3*2+2] = dotprod(GradN2,GradN2) * det * .5; - - mat[3*0+1] = mat[3*1+0] = dotprod(GradN0,GradN1) * det * .5; - mat[3*0+2] = mat[3*2+0] = dotprod(GradN0,GradN2) * det * .5; - mat[3*1+2] = mat[3*2+1] = dotprod(GradN1,GradN2) * det * .5; -} - - -HXTStatus hxtLaplace(HXTMesh *mesh) -{ - uint64_t nTriangles = mesh->triangles.num; - uint64_t nEdgesBdry = mesh->lines.num; - uint64_t nVertices = mesh->vertices.num; - HXTLinearSystem *nrSys; - - HXT_CHECK(hxtLinearSystemCreateLU(&nrSys,nTriangles,3,1,mesh->triangles.node)); - - double *sol, *rhs; - HXT_CHECK(hxtMalloc(&sol,nVertices*sizeof(double))); - HXT_CHECK(hxtMalloc(&rhs,nVertices*sizeof(double))); - - for(uint64_t i=0;i<nVertices;i++){ - rhs[i] = 0.0; - } - - double mat[9]; - - for(uint64_t i=0;i<nTriangles;i++){ - uint32_t n0 = mesh->triangles.node[3*i+0]; - uint32_t n1 = mesh->triangles.node[3*i+1]; - uint32_t n2 = mesh->triangles.node[3*i+2]; - elementMatrix ( mesh->vertices.coord + 4*n0, - mesh->vertices.coord + 4*n1, - mesh->vertices.coord + 4*n2, mat); - // printf("xxx %d %d %d %d %d\n",i,n0,n1,n2, nVertices); - HXT_CHECK(hxtLinearSystemAddToMatrix(nrSys,i,i,mat)); - } - - - for(uint64_t i=0;i<nEdgesBdry;i++){ - uint32_t n0 = mesh->lines.node[2*i+0]; - uint32_t n1 = mesh->lines.node[2*i+1]; - double *X0 = mesh->vertices.coord + 4*n0; - double *X1 = mesh->vertices.coord + 4*n1; - double V0 = X0[1]; - double V1 = X1[1]; - HXT_CHECK(hxtLinearSystemSetMatrixRowIdentity(nrSys,n0,0)); - HXT_CHECK(hxtLinearSystemSetMatrixRowIdentity(nrSys,n1,0)); - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n0,0,V0)); - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n1,0,V1)); - - // according to your elementary entities, you can set your Dirichlet conditions - // here 1 and 3 is your elementary entities numbers - /*if(mesh->lines.colors[i] == 1){ - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n0,0,0.)); - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n1,0,0.)); - } - if(mesh->lines.colors[i] == 3){ - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n0,0,1.)); - HXT_CHECK(hxtLinearSystemSetRhsEntry(nrSys,rhs,n1,0,1.)); - }*/ - } - - HXT_CHECK(hxtLinearSystemSolve(nrSys,rhs,sol)); - - FILE *f = fopen("a.pos","w"); - fprintf(f,"View \"\"{\n"); - for(uint64_t i=0;i<nTriangles;i++){ - int n0 = mesh->triangles.node[3*i+0]; - int n1 = mesh->triangles.node[3*i+1]; - int n2 = mesh->triangles.node[3*i+2]; - double *X0 = mesh->vertices.coord +4*n0; - double *X1 = mesh->vertices.coord +4*n1; - double *X2 = mesh->vertices.coord +4*n2; - fprintf(f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",X0[0],X0[1],X0[2],X1[0],X1[1],X1[2],X2[0],X2[1],X2[2],sol[n0],sol[n1],sol[n2]); - } - fprintf(f,"};\n"); - fclose(f); - - HXT_CHECK(hxtFree(&rhs)); - HXT_CHECK(hxtFree(&sol)); - HXT_CHECK(hxtLinearSystemDelete(&nrSys)); - - - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/hxt_laplace.h b/contrib/hxt/hxt_laplace.h deleted file mode 100644 index b6f8a24c69..0000000000 --- a/contrib/hxt/hxt_laplace.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef HEXTREME_LAPLACE_H -#define HEXTREME_LAPLACE_H - -#include "hxt_mesh.h" - -HXTStatus hxtLaplace(HXTMesh *mesh); - -#endif diff --git a/contrib/hxt/hxt_mesh3d.c b/contrib/hxt/hxt_mesh3d.c deleted file mode 100644 index 5fc35e353d..0000000000 --- a/contrib/hxt/hxt_mesh3d.c +++ /dev/null @@ -1,424 +0,0 @@ -// #include "hxt_mesh_size.h" -#include "hxt_tetDelaunay.h" -// #include "hxt_vertices.h" -#include "hxt_mesh3d.h" -#include "predicates.h" -#include "hxt_tetFlag.h" - -// #if defined(_MSC_VER) -// #define _CRT_RAND_S -// #include <stdlib.h> -// double drand48() { -// double a; -// rand_s(&a); -// return a; -// } -// #endif - -HXTStatus hxtCreateNodalSizeFromFunction(HXTMesh* mesh, HXTDelaunayOptions* delOptions, - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData) -{ - HXT_CHECK(hxtAlignedMalloc(&delOptions->nodalSizes,mesh->vertices.num*sizeof(double))); - - #pragma omp parallel for - for (uint32_t i=0; i<mesh->vertices.num; i++) { - double* coord = &mesh->vertices.coord[4*i]; - delOptions->nodalSizes[i] = mesh_size(coord[0], coord[1], coord[2], userData); - } - - return HXT_STATUS_OK; -} - - -HXTStatus hxtCreateNodalsizeFromTrianglesAndLines(HXTMesh* mesh, HXTDelaunayOptions* delOptions) -{ - - HXT_CHECK(hxtAlignedMalloc(&delOptions->nodalSizes,mesh->vertices.num*sizeof(double))); - - #pragma omp parallel for - for (uint32_t i = 0; i<mesh->vertices.num; i++){ - delOptions->nodalSizes[i] = DBL_MAX; - } - - // only do for triangles - // we do not take into account hereafter delOptions->nodalSizes = to DBL_MAX - // could be changed in another fashion - for (uint32_t i = 0; i<mesh->triangles.num; i++){ - for (uint32_t j = 0; j<3; j++){ - for (uint32_t k = j+1; k<3; k++){ - uint32_t n1 = mesh->triangles.node[3*i+j]; - uint32_t n2 = mesh->triangles.node[3*i+k]; - if (n1 != HXT_GHOST_VERTEX && n2 != HXT_GHOST_VERTEX){ - double *X1 = mesh->vertices.coord + (size_t) 4*n1; - double *X2 = mesh->vertices.coord + (size_t) 4*n2; - double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+ - (X1[1]-X2[1])*(X1[1]-X2[1])+ - (X1[2]-X2[2])*(X1[2]-X2[2])); - if(l<delOptions->nodalSizes[n1]) delOptions->nodalSizes[n1] = l; - if(l<delOptions->nodalSizes[n2]) delOptions->nodalSizes[n2] = l; - } - } - } - } - - for (uint32_t i = 0; i<mesh->lines.num; i++){ - uint32_t n1 = mesh->lines.node[2*i+0]; - uint32_t n2 = mesh->lines.node[2*i+1]; - if (n1 != HXT_GHOST_VERTEX && n2 != HXT_GHOST_VERTEX){ - double *X1 = mesh->vertices.coord + (size_t) 4*n1; - double *X2 = mesh->vertices.coord + (size_t) 4*n2; - double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+ - (X1[1]-X2[1])*(X1[1]-X2[1])+ - (X1[2]-X2[2])*(X1[2]-X2[2])); - if(l<delOptions->nodalSizes[n1]) delOptions->nodalSizes[n1] = l; - if(l<delOptions->nodalSizes[n2]) delOptions->nodalSizes[n2] = l; - } - } - return HXT_STATUS_OK; -} - -HXTStatus hxtCreateNodalsizeFromMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) -{ - - HXT_CHECK(hxtAlignedMalloc(&delOptions->nodalSizes,mesh->vertices.num*sizeof(double))); - - #pragma omp parallel for - for (uint32_t i = 0; i<mesh->vertices.num; i++){ - delOptions->nodalSizes[i] = DBL_MAX; - } - - // only do for triangles - // we do not take into account hereafter delOptions->nodalSizes = to DBL_MAX - // could be changed in another fashion - for (uint32_t i = 0; i<mesh->tetrahedra.num; i++){ - for (uint32_t j = 0; j<4; j++){ - for (uint32_t k = j+1; k<4; k++){ - uint32_t n1 = mesh->tetrahedra.node[4*i+j]; - uint32_t n2 = mesh->tetrahedra.node[4*i+k]; - if (n1 != HXT_GHOST_VERTEX && n2 != HXT_GHOST_VERTEX){ - double *X1 = mesh->vertices.coord + (size_t) 4*n1; - double *X2 = mesh->vertices.coord + (size_t) 4*n2; - double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+ - (X1[1]-X2[1])*(X1[1]-X2[1])+ - (X1[2]-X2[2])*(X1[2]-X2[2])); - if(l<delOptions->nodalSizes[n1]) delOptions->nodalSizes[n1] = l; - if(l<delOptions->nodalSizes[n2]) delOptions->nodalSizes[n2] = l; - } - } - } - } - return HXT_STATUS_OK; -} - -HXTStatus hxtDestroyNodalsize(HXTDelaunayOptions* delOptions) -{ - HXT_CHECK( hxtAlignedFree(&delOptions->nodalSizes) ); - return HXT_STATUS_OK; -} - - - - -HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) -{ -// we assume that the input is a surface mesh - if (mesh->tetrahedra.num) - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "The input mesh should only contain triangles"); - if (mesh->triangles.num == 0) - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "The input mesh should contain triangles"); - - double minDist2 = DBL_MAX; - #pragma omp parallel for reduction(min:minDist2) - for (uint64_t i=0; i<mesh->triangles.num; i++){ - uint32_t* node = mesh->triangles.node + 3*i; - for (int j=0; j<3; j++) { - double* n1 = mesh->vertices.coord + (size_t) 4*node[j]; - double* n2 = mesh->vertices.coord + (size_t) 4*node[(j+1)%3]; - - double dist2 = (n1[0]-n2[0])*(n1[0]-n2[0]) - + (n1[1]-n2[1])*(n1[1]-n2[1]) - + (n1[2]-n2[2])*(n1[2]-n2[2]); - - if(dist2<minDist2) - minDist2 = dist2; - } - } - - double minSize = sqrt(minDist2); - - hxtNodeInfo* nodeInfo; - HXT_CHECK( hxtAlignedMalloc(&nodeInfo, sizeof(hxtNodeInfo)*mesh->vertices.num) ); - -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) -#endif - for (uint32_t i=0; i<mesh->vertices.num; i++) { - nodeInfo[i].node = i; - nodeInfo[i].status = HXT_STATUS_TRYAGAIN; - } - - delOptions->minSizeStart = 0.0; - delOptions->minSizeEnd = minSize; - HXT_CHECK( hxtDelaunaySteadyVertices(mesh, delOptions, nodeInfo, mesh->vertices.num) ); - delOptions->minSizeStart = minSize; - delOptions->minSizeEnd = minSize; - delOptions->numVerticesInMesh = mesh->vertices.num; - -#ifdef DEBUG -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) -#endif - for (uint32_t i=0; i<mesh->vertices.num; i++) { - if(nodeInfo[i].status!=HXT_STATUS_TRUE){ - HXT_WARNING("vertex %u of the empty mesh was not inserted\n", nodeInfo[i].node); - } - } -#endif - - HXT_CHECK( hxtAlignedFree(&nodeInfo) ); - - return HXT_STATUS_OK; -} - - - -// refine - - -double hxtTetCircumcenter(double a[3], double b[3], double c[3], double d[3], - double circumcenter[3], double *xi, double *eta, double *zeta) -{ - double xba, yba, zba, xca, yca, zca, xda, yda, zda; - double balength, calength, dalength; - double xcrosscd, ycrosscd, zcrosscd; - double xcrossdb, ycrossdb, zcrossdb; - double xcrossbc, ycrossbc, zcrossbc; - double denominator; - double xcirca, ycirca, zcirca; - - /* Use coordinates relative to point `a' of the tetrahedron. */ - xba = b[0] - a[0]; - yba = b[1] - a[1]; - zba = b[2] - a[2]; - xca = c[0] - a[0]; - yca = c[1] - a[1]; - zca = c[2] - a[2]; - xda = d[0] - a[0]; - yda = d[1] - a[1]; - zda = d[2] - a[2]; - /* Squares of lengths of the edges incident to `a'. */ - balength = xba * xba + yba * yba + zba * zba; - calength = xca * xca + yca * yca + zca * zca; - dalength = xda * xda + yda * yda + zda * zda; - /* Cross products of these edges. */ - xcrosscd = yca * zda - yda * zca; - ycrosscd = zca * xda - zda * xca; - zcrosscd = xca * yda - xda * yca; - xcrossdb = yda * zba - yba * zda; - ycrossdb = zda * xba - zba * xda; - zcrossdb = xda * yba - xba * yda; - xcrossbc = yba * zca - yca * zba; - ycrossbc = zba * xca - zca * xba; - zcrossbc = xba * yca - xca * yba; - - /* Calculate the denominator of the formulae. */ - /* Use orient3d() from http://www.cs.cmu.edu/~quake/robust.html */ - /* to ensure a correctly signed (and reasonably accurate) result, */ - /* avoiding any possibility of division by zero. */ - const double xxx = orient3d(b, c, d, a); - denominator = 0.5 / xxx; - - /* Calculate offset (from `a') of circumcenter. */ - xcirca = (balength * xcrosscd + calength * xcrossdb + dalength * xcrossbc) * - denominator; - ycirca = (balength * ycrosscd + calength * ycrossdb + dalength * ycrossbc) * - denominator; - zcirca = (balength * zcrosscd + calength * zcrossdb + dalength * zcrossbc) * - denominator; - circumcenter[0] = xcirca + a[0]; - circumcenter[1] = ycirca + a[1]; - circumcenter[2] = zcirca + a[2]; - - /* - printf(" %g %g %g %g\n", - sqrt((a[0]-xcirca)*(a[0]-xcirca)+(a[1]-ycirca)*(a[1]-ycirca)+(a[2]-zcirca)*(a[2]-zcirca)), - sqrt((b[0]-xcirca)*(b[0]-xcirca)+(b[1]-ycirca)*(b[1]-ycirca)+(b[2]-zcirca)*(b[2]-zcirca)), - sqrt((c[0]-xcirca)*(c[0]-xcirca)+(c[1]-ycirca)*(c[1]-ycirca)+(c[2]-zcirca)*(c[2]-zcirca)), - sqrt((d[0]-xcirca)*(d[0]-xcirca)+(d[1]-ycirca)*(d[1]-ycirca)+(d[2]-zcirca)*(d[2]-zcirca)) ); - */ - - if (xi != (double *) NULL) { - /* To interpolate a linear function at the circumcenter, define a */ - /* coordinate system with a xi-axis directed from `a' to `b', */ - /* an eta-axis directed from `a' to `c', and a zeta-axis directed */ - /* from `a' to `d'. The values for xi, eta, and zeta are computed */ - /* by Cramer's Rule for solving systems of linear equations. */ - *xi = (xcirca * xcrosscd + ycirca * ycrosscd + zcirca * zcrosscd) * - (2.0 * denominator); - *eta = (xcirca * xcrossdb + ycirca * ycrossdb + zcirca * zcrossdb) * - (2.0 * denominator); - *zeta = (xcirca * xcrossbc + ycirca * ycrossbc + zcirca * zcrossbc) * - (2.0 * denominator); - } - return xxx; -} - - -static HXTStatus hxtRefineTetrahedraOneStep(HXTMesh* mesh, HXTDelaunayOptions* delOptions, - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData , int *nbAdd, int iter) -{ - double *newVertices; - uint32_t *numCreated; - int maxThreads = omp_get_max_threads(); - HXT_CHECK( hxtAlignedMalloc(&newVertices, sizeof(double)*4*mesh->tetrahedra.num) ); - HXT_CHECK( hxtMalloc(&numCreated, maxThreads*sizeof(uint32_t)) ); - - - // TODO: creating multiple vertices per tetrahedron - uint32_t add = 0; - HXTStatus status = HXT_STATUS_OK; - #pragma omp parallel reduction(+:add) - { - int threadID = omp_get_thread_num(); - uint32_t localAdd = 0; - - - #pragma omp for schedule(static) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { - newVertices[(size_t) 4*i+3] = -1.0; - if (mesh->tetrahedra.colors[i] != UINT16_MAX && getProcessedFlag(mesh, i)==0){ - double *a = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+0]; - double *b = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+1]; - double *c = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+2]; - double *d = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+3]; - double circumcenter [3]; - double u,v,w; - hxtTetCircumcenter(a,b,c,d, circumcenter, &u, &v, &w); - double circumradius2 = (a[0]-circumcenter[0])*(a[0]-circumcenter[0])+ - (a[1]-circumcenter[1])*(a[1]-circumcenter[1])+ - (a[2]-circumcenter[2])*(a[2]-circumcenter[2]); - - setProcessedFlag(mesh, i); // we do not need to refine that tetrahedra anymore - - // all new edges will have a length equal to circumradius2 - double meshSize; - // HXTStatus status = hxtMeshSizeEvaluate ( sizeField, circumcenter, &meshSize); - - if(u <= 0 || v <= 0 || w <= 0 || 1.-u-v-w <= 0) - continue; - - if(mesh_size!=NULL) { - meshSize = mesh_size(circumcenter[0], circumcenter[1], circumcenter[2], userData); - } - else { // we suppose delOptions->nodalSize!=NULL - double SIZES[4]; - double AVG = 0; - int NN = 0; - for (int j=0;j<4;j++){ - SIZES[j] = delOptions->nodalSizes[mesh->tetrahedra.node[4*i+j]]; - if (SIZES[j] != DBL_MAX){ - NN++; - AVG += SIZES[j]; - } - } - if (NN != 4){ - AVG /= NN; - for (int j=0;j<4;j++){ - if (SIZES[j] == DBL_MAX){ - // delOptions->nodalSizes[mesh->tetrahedra.node[4*i+j]] = AVG; - SIZES[j] = AVG; - } - } - } - - meshSize = SIZES[0] * (1-u-v-w) + SIZES[1] * u + SIZES[2] * v + SIZES[3] * w; - } - - - - if (meshSize * meshSize /* .49*/ < circumradius2) { - // printf("%llu %g\n",i,sqrt(circumradius2),meshSize); - newVertices[(size_t) 4*i ] = circumcenter[0]; - newVertices[(size_t) 4*i+1] = circumcenter[1]; - newVertices[(size_t) 4*i+2] = circumcenter[2]; - newVertices[(size_t) 4*i+3] = meshSize; - localAdd++; - } - } - } - - numCreated[threadID] = localAdd; - - #pragma omp barrier - #pragma omp single - { - int nthreads = omp_get_num_threads(); - add = 0; - for (int i=0; i<nthreads; i++) { - uint32_t tsum = add + numCreated[i]; - numCreated[i] = add; - add = tsum; - } - - if(mesh->vertices.num + add>mesh->vertices.size){ - status=hxtAlignedRealloc(&mesh->vertices.coord, sizeof(double)*4*(mesh->vertices.num + add)); - if(status==HXT_STATUS_OK){ - status=hxtAlignedRealloc(&delOptions->nodalSizes, (mesh->vertices.num + add)*sizeof(double)); - mesh->vertices.size = mesh->vertices.num + add; - } - } - } - - localAdd = numCreated[threadID] + mesh->vertices.num; - - if(status==HXT_STATUS_OK){ - #pragma omp for schedule(static) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++){ - if ( newVertices [4*i+3]!=-1.0 ) { - mesh->vertices.coord[ (size_t) 4*localAdd ] = newVertices [(size_t) 4*i ]; - mesh->vertices.coord[ (size_t) 4*localAdd+1 ] = newVertices [(size_t) 4*i+1]; - mesh->vertices.coord[ (size_t) 4*localAdd+2 ] = newVertices [(size_t) 4*i+2]; - delOptions->nodalSizes[localAdd] = newVertices [4*i+3]; - localAdd++; - } - } - } - } - - if(status!=HXT_STATUS_OK){ - HXT_TRACE(status); - return status; - } - - mesh->vertices.num += add; - - - HXT_CHECK( hxtFree(&numCreated) ); - HXT_CHECK(hxtAlignedFree(&newVertices)); - - HXT_CHECK(hxtDelaunay(mesh, delOptions)); - - *nbAdd = mesh->vertices.num - delOptions->numVerticesInMesh; - delOptions->numVerticesInMesh = mesh->vertices.num; - return HXT_STATUS_OK; -} - -HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, - HXTDelaunayOptions* delOptions, - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData) { - int iter = 0; - while(iter++ < 40){ - int nbAdd=0; - HXT_CHECK(hxtRefineTetrahedraOneStep(mesh, delOptions, mesh_size, userData, &nbAdd, iter)); - // uint32_t nb; - // HXT_CHECK(hxtColorMesh(mesh,&nb)); - if (nbAdd == 0) break; - } - return HXT_STATUS_OK; -} - - diff --git a/contrib/hxt/hxt_mesh3d.h b/contrib/hxt/hxt_mesh3d.h deleted file mode 100644 index 23afb959df..0000000000 --- a/contrib/hxt/hxt_mesh3d.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _HXT_MESH_3D_ -#define _HXT_MESH_3D_ - -#include "hxt_tetDelaunay.h" - -/// Creates a structure that allows to look over triangular faces of the 2D mesh -HXTStatus hxtCreateFaceSearchStructure(HXTMesh* mesh, uint32_t **pfaces); - -//// creates a mesh with all points of the surface mesh -HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions); - -/// Compute sizes at vertices of the mesh from a mesh_size function -HXTStatus hxtCreateNodalSizeFromFunction(HXTMesh* mesh, HXTDelaunayOptions* delOptions, - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData); - -/// Compute sizes at vertices of the mesh from existing edges -HXTStatus hxtCreateNodalsizeFromTrianglesAndLines(HXTMesh* mesh, HXTDelaunayOptions* delOptions); -HXTStatus hxtCreateNodalsizeFromMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions); -HXTStatus hxtDestroyNodalsize(HXTDelaunayOptions* delOptions); - -/// Add points at tets circumcenter in order to fullfill a mesh size constraint -HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, - HXTDelaunayOptions* delOptions, - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData); - -#endif diff --git a/contrib/hxt/hxt_mesh3d_main.c b/contrib/hxt/hxt_mesh3d_main.c deleted file mode 100644 index a5f3df74ff..0000000000 --- a/contrib/hxt/hxt_mesh3d_main.c +++ /dev/null @@ -1,166 +0,0 @@ -#include "hxt_mesh3d.h" -#include "hxt_tetDelaunay.h" -#include "hxt_tetRepair.h" -#include "hxt_tetUtils.h" -#include "hxt_tetFlag.h" -#include "hxt_tetColor.h" -#include "hxt_tetOpti.h" - - -HXTStatus hxtTetMesh3d(HXTMesh* mesh, - int defaulThreads, - int DelaunayThreads, - int optimizationThreads, - int reproducible, - int verbosity, - int displayStat, - int refine, - int optimize, - double qualityThreshold, - HXTStatus (*bnd_recovery)(HXTMesh* mesh), - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData) { - - if(defaulThreads>0) { - omp_set_num_threads(defaulThreads); - } - - double t[8]={0}; - t[0] = omp_get_wtime(); - - HXTBbox bbox; - hxtBboxInit(&bbox); - HXT_CHECK( hxtBboxAdd(&bbox, mesh->vertices.coord, mesh->vertices.num) ); - - HXTDelaunayOptions delOptions = {&bbox, NULL, 0.0, 0.0, 0, verbosity, reproducible, DelaunayThreads}; - uint32_t numVerticesConstrained = mesh->vertices.num; - - HXT_INFO_COND(verbosity>0, "Creating an empty mesh with %u vertices", numVerticesConstrained); - HXT_CHECK( hxtEmptyMesh(mesh, &delOptions) ); - - t[1] = omp_get_wtime(); - - uint64_t nbMissingTriangles, nbLinesNotInTriangles, nbMissingLines=0; - uint16_t nbColors; - uint64_t* tri2TetMap = NULL; - uint64_t* lines2TriMap = NULL; - uint64_t* lines2TetMap = NULL; - - HXT_CHECK( hxtAlignedMalloc(&tri2TetMap, mesh->triangles.num*sizeof(uint64_t)) ); - HXT_CHECK( hxtAlignedMalloc(&lines2TriMap, mesh->lines.num*sizeof(uint64_t)) ); - - HXT_CHECK( hxtGetTri2TetMap(mesh, tri2TetMap, &nbMissingTriangles) ); - HXT_CHECK( hxtGetLines2TriMap(mesh, lines2TriMap, &nbLinesNotInTriangles) ); - - if(nbLinesNotInTriangles!=0) { - HXT_CHECK( hxtAlignedMalloc(&lines2TetMap, mesh->lines.num*sizeof(uint64_t)) ); - if(nbMissingTriangles==0) { - HXT_CHECK( hxtGetLines2TetMap(mesh, lines2TetMap, &nbMissingLines) ); - } - } - - - t[2] = omp_get_wtime(); - - if (nbMissingTriangles!=0 || nbMissingLines!=0){ - if(bnd_recovery==NULL) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, - "there are missing features but no boundary recovery function is given"); - - if(nbMissingTriangles) - HXT_INFO("Recovering %lu missing facet(s)", nbMissingTriangles); - else if(nbMissingLines) - HXT_INFO("Recovering %lu missing edge(s)", nbMissingLines); - - HXT_CHECK(bnd_recovery(mesh)); - - if(delOptions.numVerticesInMesh < mesh->vertices.num) { - HXT_INFO("Steiner(s) point(s) were inserted"); - delOptions.numVerticesInMesh = mesh->vertices.num; - } - - t[3] = omp_get_wtime(); - - HXT_CHECK( hxtGetTri2TetMap(mesh, tri2TetMap, &nbMissingTriangles) ); - if(nbMissingTriangles!=0) - return HXT_ERROR_MSG( HXT_STATUS_ERROR, - "%d boundary face%s still missing (after recovery step).", - nbMissingTriangles, (nbMissingTriangles>1)?"s are":" is" ); - - if(nbLinesNotInTriangles!=0) - HXT_CHECK( hxtGetLines2TetMap(mesh, lines2TetMap, &nbMissingLines) ); - - if(nbMissingLines!=0) - return HXT_ERROR_MSG( HXT_STATUS_ERROR, - "%d constrained edge%s still missing (after recovery step).", - nbMissingLines, (nbMissingLines>1)?"s are":" is" ); - } - - HXT_CHECK( hxtConstrainTriangles(mesh, tri2TetMap) ); - - if(nbLinesNotInTriangles!=0) - HXT_CHECK( hxtConstrainLinesNotInTriangles(mesh, lines2TetMap, lines2TriMap) ); - - HXT_CHECK( hxtColorMesh(mesh, &nbColors) ); - - HXT_CHECK( hxtMapColorsToBrep(mesh, nbColors, tri2TetMap) ); - - HXT_CHECK( hxtAlignedFree(&tri2TetMap) ); - HXT_CHECK( hxtAlignedFree(&lines2TetMap) ); - HXT_CHECK( hxtAlignedFree(&lines2TriMap) ); - - t[4] = omp_get_wtime(); - - if(refine){ - // HXT_CHECK(hxtComputeMeshSizeFromMesh(mesh, &delOptions)); - if(mesh_size==NULL) - HXT_CHECK(hxtCreateNodalsizeFromTrianglesAndLines(mesh, &delOptions)); - else - HXT_CHECK(hxtCreateNodalSizeFromFunction(mesh, &delOptions, mesh_size, userData) ); - - if(nbColors!=mesh->brep.numVolumes) { - HXT_CHECK( setFlagsToProcessOnlyVolumesInBrep(mesh) ); - } - - HXT_CHECK(hxtRefineTetrahedra(mesh, &delOptions, mesh_size, userData)); - - HXT_CHECK( hxtDestroyNodalsize(&delOptions) ); - } - - t[5] = omp_get_wtime(); - - - if(optimize) - HXT_CHECK( hxtOptimizeTetrahedra(mesh, &bbox, optimizationThreads, delOptions.minSizeEnd, qualityThreshold, numVerticesConstrained) ); - - t[6] = omp_get_wtime(); - - - if(displayStat){ - HXT_INFO("\n\t\tFinal tet. mesh contains %lu tetrahedra" - "\n\t\tand %u vertices", mesh->tetrahedra.num, mesh->vertices.num); - - HXT_INFO("tEmptyMesh \t = \t %8.3f", t[1]-t[0]); - HXT_INFO("tVerifyBnd \t = \t %8.3f", t[2]-t[1]); - if(t[3]){ - HXT_INFO("tBndRecovery\t = \t %8.3f", t[3]-t[2]); - HXT_INFO("tConvertMesh\t = \t %8.3f", t[4]-t[3]); - if(refine) - HXT_INFO("tRefine \t = \t %8.3f", t[5]-t[4]); - } - else{ - HXT_INFO("tBndRecovery\t = \t 0.000 (boundary not altered)"); - HXT_INFO("tConvertMesh\t = \t 0.000 (nothing to convert)"); - if(refine) - HXT_INFO("tRefine \t = \t %8.3f", t[5]-t[2]); - } - - if(!optimize) - HXT_INFO("tOptimize \t = \t 0.000 (mesh optimization disabled)"); - else - HXT_INFO("tOptimize \t = \t %8.3f", t[6]-t[5]); - } - - return HXT_STATUS_OK; -} - diff --git a/contrib/hxt/hxt_mesh3d_main.h b/contrib/hxt/hxt_mesh3d_main.h deleted file mode 100644 index f54e9001c6..0000000000 --- a/contrib/hxt/hxt_mesh3d_main.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _HXT_MESH_3D_MAIN_ -#define _HXT_MESH_3D_MAIN_ - -#include "hxt_mesh.h" - -HXTStatus hxtTetMesh3d(HXTMesh* mesh, - int defaulThreads, - int DelaunayThreads, - int optimizationThreads, - int reproducible, - int verbosity, - int displayStat, - int refine, - int optimize, - double qualityThreshold, - HXTStatus (*bnd_recovery)(HXTMesh* mesh), - double (*mesh_size)(double x, double y, double z, void* userData), - void* userData); - -#endif \ No newline at end of file diff --git a/contrib/hxt/hxt_mesh_size.c b/contrib/hxt/hxt_mesh_size.c deleted file mode 100644 index 639dd09443..0000000000 --- a/contrib/hxt/hxt_mesh_size.c +++ /dev/null @@ -1,145 +0,0 @@ -#include "hxt_api.h" -#include "hxt_tools.h" -#include "hxt_mesh_size.h" -#include <math.h> - -//typedef struct hxtMeshSizeStruct HXTMeshSize; // already defined in hxt_api.h - -HXTStatus hxtMeshSizeCellEvaluate(HXTMeshSizeCell *cell, double x, double y, double z, double *v) { - if (cell->isleaf){ - *v = *(double*)cell->data; - return HXT_STATUS_OK; - } - HXTMeshSizeCell *sub = (HXTMeshSizeCell*)cell->data; - int i = x > 0.5 ? 1 : 0; - int j = y > 0.5 ? 1 : 0; - int k = z > 0.5 ? 1 : 0; - return hxtMeshSizeCellEvaluate(&sub[i*4+j*2+k],2*x-i, 2*y-j, 2*z-k, v); -} - -HXTStatus hxtMeshSizeCreate (HXTContext* context, HXTMeshSize **meshSizePtr) -{ - HXTMeshSize *meshSize; - HXT_CHECK( - hxtMalloc(&meshSize, sizeof(HXTMeshSize))); - - meshSize->context = context; - meshSize->root.data = NULL; - *meshSizePtr = meshSize; - return HXT_STATUS_OK; -} - -HXTStatus hxtMeshSizeCellReleaseMemory(HXTMeshSizeCell *cell) -{ - if(!cell->data) - return HXT_STATUS_OK; - if(!cell->isleaf) { - HXTMeshSizeCell *sub = (HXTMeshSizeCell*) cell->data; - for (int i = 0; i < 8; ++i) - HXT_CHECK(hxtMeshSizeCellReleaseMemory(&sub[i])); - } - HXT_CHECK(hxtFree(&cell->data)); - return HXT_STATUS_OK; -} - - - -HXTStatus hxtMeshSizeCellInit(HXTMeshSizeCell *cell, double x0, double y0, double z0, double l, HXTMeshSizeCallback cb, void *data, int level) { -#if 0 - double v[8] = { - field(x0,y0,z0),field(x0,y0,z0+l),field(x0,y0+l,z0),field(x0,y0+l,z0+l), - field(x0+l,y0,z0),field(x0+l,y0,z0+l),field(x0+l,y0+l,z0),field(x0+l,y0+l,z0+l) - }; - double dmax = 0; - double vmin = v[0]; - double vc = field(x0+l/2,y0+l/2,z0+l/2); - for (int i = 0; i < 8; ++i){ - dmax = fmax(dmax, std::abs(vc-v[i])); - vmin = fmin(vmin, v[i]); - } -#else - double dmax = 0; - double x[3] = {x0+l/2, y0+l/2, z0+l/2}; - double vc; - HXT_CHECK(cb(x, data, &vc)); - double vmin = vc; - int split = level > 0; - if (level > -4) { -#define NSAMPLE 4 - double dl = l/NSAMPLE; - for (int i = 0; i <= NSAMPLE; ++i){ - for (int j = 0; j <= NSAMPLE; ++j){ - for (int k = 0; k <= NSAMPLE; ++k){ - double xs[3] = {x0 + i*dl, y0+j*dl, z0+k*dl}; - double w; - HXT_CHECK(cb(xs, data, &w)); - dmax = fmax(dmax, fabs(vc-w)); - vmin = fmin(vmin, w); - split |= (dmax/vmin > 0.2 && vmin < l); - if(split) - break; - } - } - } -#endif - } - if (split) { - cell->isleaf = 0; - HXTMeshSizeCell *sub; - HXT_CHECK(hxtMalloc(&sub, sizeof(HXTMeshSizeCell)*8)); - double l2 = l/2; - HXT_CHECK(hxtMeshSizeCellInit(sub+0, x0, y0, z0, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+1, x0, y0, z0+l2, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+2, x0, y0+l2, z0, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+3, x0, y0+l2, z0+l2, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+4, x0+l2, y0, z0, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+5, x0+l2, y0, z0+l2, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+6, x0+l2, y0+l2, z0, l2, cb, data, level-1)); - HXT_CHECK(hxtMeshSizeCellInit(sub+7, x0+l2, y0+l2, z0+l2, l2, cb, data, level-1)); - cell->data = (void*)sub; - } - else { - cell->isleaf = 1; - HXT_CHECK(hxtMalloc(&cell->data, sizeof(double))); - *(double*)cell->data = vc; - } - return HXT_STATUS_OK; -} - -HXTStatus hxtMeshSizeDelete(HXTMeshSize **meshSizePtr) -{ - HXTMeshSize *meshSize = *meshSizePtr; - if (meshSize == NULL) - return HXT_STATUS_OK; - HXT_CHECK(hxtMeshSizeCellReleaseMemory(&meshSize->root)); - HXT_CHECK(hxtFree(&meshSize)); - *meshSizePtr = NULL; - return HXT_STATUS_OK; -} - -HXTStatus hxtMeshSizeEvaluate(HXTMeshSize *meshSize, double x[3], double *v) -{ - if(!meshSize->root.data) { - //hxtMessageError(meshSize->context, "meshSize has not been computed\n"); - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "meshSize has not been computed"); - } - double *bbmin = meshSize->bbmin; - double l = meshSize->l0; - HXT_CHECK(hxtMeshSizeCellEvaluate(&meshSize->root, (x[0]-bbmin[0])/l, (x[1]-bbmin[1])/l, (x[2]-bbmin[2])/l, v)); - return HXT_STATUS_OK; -} - -HXTStatus hxtMeshSizeCompute( HXTMeshSize *meshSize , double min[3], double max[3], HXTMeshSizeCallback cb, void *data) -{ - if (meshSize->root.data) { - HXT_CHECK(hxtMeshSizeCellReleaseMemory(&meshSize->root)); - } - for (int i = 0; i < 3; ++i) { - meshSize->bbmin[i] = min[i]; - meshSize->bbmax[i] = max[i]; - } - double l = fmax(max[0]-min[0], fmax(max[1]-min[1], max[2]-min[2])); - meshSize->l0 = l; - HXT_CHECK(hxtMeshSizeCellInit(&meshSize->root,min[0],min[1],min[2],l, cb, data, 4)); - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/hxt_mesh_size.h b/contrib/hxt/hxt_mesh_size.h deleted file mode 100644 index ef669795d9..0000000000 --- a/contrib/hxt/hxt_mesh_size.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _HXT_MESH_SIZE_H_ -#define _HXT_MESH_SIZE_H_ - -#include "hxt_api.h" - -typedef struct { - void *data; - int isleaf; -} HXTMeshSizeCell; - -struct hxtMeshSizeStruct { - HXTMeshSizeCell root; - double bbmin[3], bbmax[3]; - double l0; - HXTContext* context; -}; - -#endif diff --git a/contrib/hxt/hxt_octree_api.h b/contrib/hxt/hxt_octree_api.h deleted file mode 100644 index 70d01e0c69..0000000000 --- a/contrib/hxt/hxt_octree_api.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _HXT_OCTREE_API_H_ -#define _HXT_OCTREE_API_H_ - -#include <vector> -extern "C" { -#include "hxt_api.h" -#include "hxt_bbox.h" -} - -struct HXTForest; -struct HXTForestOptions; - -HXTStatus hxtOctreeRefineSizeVariation(HXTForest *forest, int recursive); -HXTStatus hxtOctreeCoarsenSizeVariation(HXTForest *forest, int recursive); -HXTStatus hxtOctreeRefineToLevel(HXTForest *forest, int lvl); -HXTStatus hxtOctreeInitialRefine(HXTForest *forest, int nRefine); -HXTStatus hxtOctreeComputeLaplacian(HXTForest *forest); - -// HXTStatus hxtOctreeRefineLaplacian(HXTForest *forest); -HXTStatus hxtOctreeCoarsenLaplacian(HXTForest *forest, int recursive); -HXTStatus hxtOctreeLaplacianRefine(HXTForest *forest, int nRefine); - -// HXTStatus hxtOctreeBalance(HXTForest *forest); - -HXTStatus hxtOctreeSetMaxGradient(HXTForest *forest); -HXTStatus hxtOctreeSmoothGradient(HXTForest *forest, int nMax); - -HXTStatus hxtOctreeComputeMaxGradientX(HXTForest *forest, double* dsdx_max); -HXTStatus hxtOctreeComputeMaxGradientY(HXTForest *forest, double* dsdy_max); -HXTStatus hxtOctreeComputeMaxGradientZ(HXTForest *forest, double* dsdz_max); -HXTStatus hxtOctreeComputeMinimumSize(HXTForest *forest, double* size_min); - -HXTStatus hxtForestOptionsCreate(HXTForestOptions **forestOptions); -HXTStatus hxtForestOptionsDelete(HXTForestOptions **forestOptions); - -// HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, void *user_pointer); -HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, HXTForestOptions *forestOptions); -HXTStatus hxtForestDelete(HXTForest **forest); - -HXTStatus hxtForestWriteBBoxMesh(HXTBbox *bbox, const char* filename); - -HXTStatus hxtOctreeRTreeIntersection(HXTForest *forest); - -HXTStatus hxtOctreeCurvatureRefine(HXTForest *forest, int nMax); - -HXTStatus hxtOctreeSearchOne(HXTForest *forest, double x, double y, double z, double *size); -HXTStatus hxtOctreeSearch(HXTForest *forest, std::vector<double> *x, std::vector<double> *y, std::vector<double> *z, std::vector<double> *size); - -HXTStatus hxtOctreeSurfacesProches(HXTForest *forest); - -HXTStatus hxtOctreeElementEstimation(HXTForest *forest, double *elemEstimate); - -#endif diff --git a/contrib/hxt/hxt_opt.c b/contrib/hxt/hxt_opt.c deleted file mode 100644 index 70257871d8..0000000000 --- a/contrib/hxt/hxt_opt.c +++ /dev/null @@ -1,812 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <float.h> -#include <errno.h> -#include <limits.h> -#include "hxt_opt.h" - - -const HXTOptionArgumentConstraints HXT_POSITIVE_RANGE = { - 0, DBL_MAX, - 0, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_ALPHA_LOWERCASE_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHA_LOWERCASE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_ALPHA_UPPERCASE_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHA_UPPERCASE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_ALPHA_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHA_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_NUMERIC_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_NUMERIC_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_LOWERCASE_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHANUMERIC_LOWERCASE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_UPPERCASE_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHANUMERIC_UPPERCASE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_ALPHANUMERIC_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_PRINTABLE_VISIBLE_RANGE = {// between space and ~ - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_PRINTABLE_VISIBLE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_PRINTABLE_RANGE = { - -DBL_MAX, DBL_MAX, - LLONG_MIN, LLONG_MAX, - 0, ULLONG_MAX, - NULL, NULL, HXT_PRINTABLE_CHARACTERS -}; -const HXTOptionArgumentConstraints HXT_0_1_RANGE = { - 0., 1., - 0, 1, - 0, 1, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_2_RANGE = { - 0., 2., - 0, 2, - 0, 2, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_3_RANGE = { - 0., 3., - 0, 3, - 0, 3, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_4_RANGE = { - 0., 4., - 0, 4, - 0, 4, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_5_RANGE = { - 0., 5., - 0, 5, - 0, 5, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_10_RANGE = { - 0., 10., - 0, 10, - 0, 10, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_20_RANGE = { - 0., 20., - 0, 20, - 0, 20, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_50_RANGE = { - 0., 50., - 0, 50, - 0, 50, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_100_RANGE = { - 0., 100., - 0, 100, - 0, 100, - NULL, NULL, NULL -}; -const HXTOptionArgumentConstraints HXT_0_1000_RANGE = { - 0., 1000., - 0, 1000, - 0, 1000, - NULL, NULL, NULL -}; - - -typedef struct HXTOptionStruct { - char shortName; - const char* longName; - const char* description; - const HXTOptionArgumentConstraints* constraints; - HXTOptionArgumentType valueType; - void* valuePtr; -} HXTOption; - -static HXTOption helpOption = {'h', "help", "Display this help message", NULL, HXT_FLAG, NULL}; -static HXTOption* optionList = NULL; -static int optionListLength = 0; -static int optionListSize = 0; - - -#define MAX(a,b) (((a)>(b))?(a):(b)) - - -static HXTStatus optionListReserve(int n) -{ - if(optionList==NULL) { - optionListSize = MAX(16,n); - HXT_CHECK( hxtMalloc(&optionList, optionListSize*sizeof(HXTOption)) ); - optionList[0] = helpOption; - optionListLength = 1; - } - else if(optionListLength + n > optionListSize) { - optionListSize = MAX(2*optionListSize, optionListLength + n); - HXT_CHECK( hxtRealloc(&optionList, optionListSize) ); - } - return HXT_STATUS_OK; -} - - -HXTStatus hxtAddOption(char shortName, - const char* longName, - const char* description, - HXTOptionArgumentType valueType, - const HXTOptionArgumentConstraints* constraints, - void* valuePtr) -{ - HXT_CHECK( optionListReserve(1) ); - -#ifndef NDEBUG - if(valuePtr==NULL && (shortName!='\0' || longName!=NULL || description!=NULL)) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "Adding a non-empty option with a NULL value pointer makes no sense"); - for (int i=0; i<optionListLength; i++) { - if(shortName!='\0' && shortName==optionList[i].shortName) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "-%c is already the short name of another option", shortName); - } - if(longName!=NULL) { - if(longName[0]=='\0') - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "Cannot use empty string as a long option name. Use NULL pointer if you do not want a long option name."); - if(longName[0]=='-') - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "long option \"%s\" cannot begin with a '-'", longName); - for (int i=0; longName[i]!='\0'; i++) { - if(longName[i]<=' ') - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "long option \"%s\" should only contain printable characters", longName); - } - for (int i=0; i<optionListLength; i++) { - if(optionList[i].longName!=NULL && strcmp(longName, optionList[i].longName)==0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "--%s is already the long name of another option", longName); - } - } -#endif - - if(shortName=='\0' && (longName==NULL || longName[0]=='\0') && - (valueType==HXT_FLAG || valueType==HXT_NO_FLAG) && valuePtr!=NULL) { - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "A flag must have an option name. Therefore, it can not be a trailing option"); - } - - optionList[optionListLength].shortName = shortName; - optionList[optionListLength].longName = longName; - optionList[optionListLength].description = description; - optionList[optionListLength].valueType = valueType; - optionList[optionListLength].constraints = constraints; - optionList[optionListLength].valuePtr = valuePtr; - optionListLength++; - - return HXT_STATUS_OK; -} - - -/********************************************************************* -* search a long option inside the list * -*********************************************************************/ -static int searchLongOption(const char* string) -{ - for (int i=0; i<optionListLength; i++) { - if(optionList[i].longName!=NULL && - strcmp(optionList[i].longName, string)==0) { - return i; - } - } - - return -1; -} - - -/********************************************************************* -* search a short option inside the list * -*********************************************************************/ -static int searchShortOption(char c) -{ - for (int i=0; i<optionListLength; i++) { - if(c==optionList[i].shortName) { - return i; - } - } - return -1; -} - - -int fileExists(const char *fname) -{ - FILE *file; - if ((file = fopen(fname, "r"))) - { - fclose(file); - return 1; - } - return 0; -} - - -static const char* getArgTypeName(HXTOptionArgumentType t){ - switch(t) { - case HXT_FLAG: - case HXT_NO_FLAG: - return "(none)"; - case HXT_DOUBLE: - return "a double"; - case HXT_FLOAT: - return "a float"; - case HXT_INT: - return "an integer "; - case HXT_I64: - return "a 64-bit integer"; - case HXT_I32: - return "a 32-bit integer"; - case HXT_I16: - return "a 16-bit integer"; - case HXT_UNSIGNED: - return "an unsigned integer "; - case HXT_U64: - return "a 64-bit unsigned integer"; - case HXT_U32: - return "a 32-bit unsigned integer"; - case HXT_U16: - return "a 16-bit unsigned integer"; - default: - return "a string"; - } -} - - -/********************************************************************* -* scan the argument and verify its validity * -*********************************************************************/ -static HXTStatus doOption(HXTOption* opt, - const char* arg, - const char* optName) -{ - if(opt->valueType==HXT_FLAG) { - *(int*) opt->valuePtr = 1; - return HXT_STATUS_OK; - } - if(opt->valueType==HXT_NO_FLAG) { - *(int*) opt->valuePtr = 0; - return HXT_STATUS_OK; - } - - char* endptr = NULL; - double r = 0; - unsigned long long u = 0; - long long int i = 0; - const char* s = NULL; - - int isDouble = 0, isInteger = 0, isUnsigned = 0; - - if(opt->valueType==HXT_DOUBLE || opt->valueType==HXT_FLOAT) { - isDouble = 1; - r = strtod(arg, &endptr); - } - else if(opt->valueType==HXT_INT || - opt->valueType==HXT_I64 || - opt->valueType==HXT_I32 || - opt->valueType==HXT_I16) { - isInteger = 1; - i = strtoll(arg, &endptr, 10); - } - else if(opt->valueType==HXT_UNSIGNED || - opt->valueType==HXT_U64 || - opt->valueType==HXT_U32 || - opt->valueType==HXT_U16) { - isUnsigned = 1; - u = strtoull(arg, &endptr, 10); - } - else { - s = arg; - } - - // verify the validity - if(errno == ERANGE){ -range_error: - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (range overflow)", - arg, optName, getArgTypeName(opt->valueType)); - } - else if (arg == endptr) - { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (no digit)", - arg, optName, getArgTypeName(opt->valueType)); - } - else if(endptr!=NULL && *endptr!='\0') { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (trailing unvalid characters)", - arg, optName, getArgTypeName(opt->valueType)); - } - - // verify the conversion is possible - switch(opt->valueType) { - // floating point values: - case HXT_DOUBLE: - *(double*) opt->valuePtr = r; - break; - case HXT_FLOAT: - if((float)r!=r) goto range_error; - *(float*) opt->valuePtr = r; - break; - // integer values - case HXT_INT: - if((int)i!=i) goto range_error; - *(int*) opt->valuePtr = i; - break; - case HXT_I64: - if((int64_t)i!=i) goto range_error; - *(int64_t*) opt->valuePtr = i; - break; - case HXT_I32: - if((int32_t)i!=i) goto range_error; - *(int32_t*) opt->valuePtr = i; - break; - case HXT_I16: - if((int16_t)i!=i) goto range_error; - *(int16_t*) opt->valuePtr = i; - break; - // unsigned integer values - case HXT_UNSIGNED: - if((unsigned)u!=u) goto range_error; - *(unsigned*) opt->valuePtr = u; - break; - case HXT_U64: - if((uint64_t)u!=u) goto range_error; - *(uint64_t*) opt->valuePtr = u; - break; - case HXT_U32: - if((uint32_t)u!=u) goto range_error; - *(uint32_t*) opt->valuePtr = u; - break; - case HXT_U16: - if((uint16_t)u!=u) goto range_error; - *(uint16_t*) opt->valuePtr = u; - break; - // string values - case HXT_EXISTING_FILENAME: - if(!fileExists(s)) - return HXT_ERROR_MSG(HXT_STATUS_FILE_CANNOT_BE_OPENED, - "file \"%s\" does not exist", s); - *(const char**) opt->valuePtr = s; - break; - case HXT_NEW_FILENAME: - if(fileExists(s)) - return HXT_ERROR_MSG(HXT_STATUS_FILE_CANNOT_BE_OPENED, - "file \"%s\" already exists", s); - *(const char**) opt->valuePtr = s; - break; - case HXT_ASK_TO_ERASE_FILENAME: - if(fileExists(s)) { - char memory[64]; - HXT_INFO("file \"%s\" already exists\n do you want to overwrite it ? y/N", s); - char* string = fgets(memory, 64, stdin); - if(string==NULL || (string[0]!='y' && string[0]!='Y') ) - return HXT_ERROR_MSG(HXT_STATUS_FILE_CANNOT_BE_OPENED, "aborting"); - } - /* fall through */ - - default: - *(const char**) opt->valuePtr = s; - break; - } - - if(opt->constraints==NULL) - return HXT_STATUS_OK; - - - if(isDouble){ - if(r < opt->constraints->doubleMin || r > opt->constraints->doubleMax) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" " - "to %s between %g and %g (range overflow)", - arg, optName, getArgTypeName(opt->valueType), - opt->constraints->doubleMin, opt->constraints->doubleMax); - } - else if(isInteger){ - if(i < opt->constraints->intMin || i > opt->constraints->intMax) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" " - "to %s between %lld and %lld (range overflow)", - arg, optName, getArgTypeName(opt->valueType), - opt->constraints->intMin, opt->constraints->intMax); - } - else if(isUnsigned){ - if(u < opt->constraints->unsignedMin || u > opt->constraints->unsignedMax) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" " - "to %s between %llu and %llu (range overflow)", - arg, optName, getArgTypeName(opt->valueType), - opt->constraints->unsignedMin, opt->constraints->unsignedMax); - } - else { - if(opt->constraints->stringPrefix!=NULL) { - const char* prefix = opt->constraints->stringPrefix; - size_t lenpre = strlen(prefix), lens = strlen(s); - if(lens < lenpre || strncmp(prefix, s, lenpre) != 0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "argument \"%s\" of option \"%s\" is not prefixed by \"%s\"", prefix); - } - if(opt->constraints->stringSuffix!=NULL) { - const char* suffix = opt->constraints->stringSuffix; - size_t lensuf = strlen(suffix), lens = strlen(s); - if(lens < lensuf || strcmp(suffix, s + lens - lensuf) != 0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "argument \"%s\" of option \"%s\" is not suffixed by \"%s\"", suffix); - } - if(opt->constraints->stringCharAllowed!=NULL) { - const char* allowed = opt->constraints->stringCharAllowed; - for (int j=0; s[j]!='\0'; j++) { - int found = 0; - int special = 0; - if(opt->constraints==&HXT_ALPHA_LOWERCASE_RANGE - || opt->constraints==&HXT_ALPHA_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_LOWERCASE_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_RANGE) { - special = 1; - if(s[j]>='a' && s[j]<='z') found = 1; - } - if(opt->constraints==&HXT_ALPHA_UPPERCASE_RANGE - || opt->constraints==&HXT_ALPHA_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_UPPERCASE_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_RANGE) { - special = 1; - if(s[j]>='A' && s[j]<='Z') found = 1; - } - if(opt->constraints==&HXT_NUMERIC_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_LOWERCASE_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_UPPERCASE_RANGE - || opt->constraints==&HXT_ALPHANUMERIC_RANGE) { - special = 1; - if(s[j]>='0' && s[j]<='9') found = 1; - } - if(opt->constraints==&HXT_PRINTABLE_VISIBLE_RANGE - || opt->constraints==&HXT_PRINTABLE_RANGE) { - special = 1; - if(s[j]>' ' && s[j]<='~') found = 1; - } - if(opt->constraints==&HXT_PRINTABLE_RANGE) { - special = 1; - if(s[j]==' ' || s[j]=='\t' || s[j]=='\n') found = 1; - } - if(special!=1) { - for (int k=0; allowed[k]!='\0'; k++) { - if(s[j]==allowed[k]){ - found = 1; - break; - } - } - } - - if(found==0) - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, "argument \"%s\" of option \"%s\" contain the unvalid character %c", s[j]); - } - } - } - - return HXT_STATUS_OK; -} - - -static int getNextTrailingOption(int n) { - for (int i=n+1; i<optionListLength; i++) { - if(optionList[i].shortName=='\0' && optionList[i].longName==NULL) { - return i; - } - } - return -1; -} - - -HXTStatus hxtParseOptions(const int argc, char* argv[]) -{ - int dashdash = 0; - int trailing = getNextTrailingOption(0); - for (int i=1; i<argc; i++) { - const char *arg = NULL; - HXTOption* opt = NULL; - - if(dashdash || argv[i][0]!='-' || (argv[i][0]=='-' && argv[i][1]=='\0')){ - if(trailing==-1 || optionList[trailing].valuePtr==NULL) - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "Additional argument \"%s\" does not correspond to any option", - argv[i]); - else - HXT_CHECK( doOption(&optionList[trailing], argv[i], optionList[trailing].description) ); - - trailing = getNextTrailingOption(trailing); - } - else if(argv[i][1]=='-') { /* long opt */ - if(argv[i][2]=='\0') /* -- terminate argument parsing, - everything from now on is a trailing option */ { - dashdash = 1; - continue; - } - - char* equalSign = strchr(argv[i]+2,'='); - - if(equalSign!=NULL){ - *equalSign = '\0'; - arg = equalSign + 1; - } - - int num = searchLongOption(argv[i]+2); - if(num<0){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \"%s\" not found", argv[i]); - } - opt = &optionList[num]; - - if(equalSign!=NULL){ - *equalSign = '='; - if(opt->valueType==HXT_FLAG || opt->valueType==HXT_NO_FLAG){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \"%s\" takes no argument", argv[i]); - } - } - else{ - if(num==0) { // it's the help option - return HXT_STATUS_INTERNAL; - } - if(opt->valueType!=HXT_FLAG && opt->valueType!=HXT_NO_FLAG) { - if(argc<=i+1) { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "options \"%s\" requires an argument", argv[i]); - } - else { - arg = argv[i+1]; - i++; - } - } - } - - HXT_CHECK( doOption(opt, arg, argv[i]) ); - } - else{ /* short option */ - int cond = argv[i][1]; - for(int j=1; cond; j++){ - int num = searchShortOption(argv[i][j]); - if(num<0){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \'%c\' in \"%s\" not found", argv[i][j], argv[i]); - } - - char optName[] = "- "; - optName[1] = argv[i][j]; - cond = argv[i][j+1]; - - if(num==0){ - return HXT_STATUS_INTERNAL; - } - - opt = &optionList[num]; - - if(opt->valueType!=HXT_FLAG && opt->valueType!=HXT_NO_FLAG){ - if(cond){ - arg = argv[i] + j+1; - cond = 0; // stop the loop - } - else if(argc<=i+1) { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "options \'%c\' in \"%s\" requires an argument", argv[i][j], argv[i]); - } - else { - arg = argv[i+1]; - i++; - } - } - - HXT_CHECK( doOption(opt, arg, optName) ); - } - } - } - - if(trailing!=-1) { - if(getNextTrailingOption(trailing)!=-1) - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, "No \"%s\" given", optionList[trailing].description); - } - - HXT_CHECK( hxtFree(&optionList) ); - - return HXT_STATUS_OK; -} - - -#define MY_SPRINTF(...) *offset+=snprintf(text+ *offset, 16384- *offset, ## __VA_ARGS__ ) - -static const char* getHelpValueName(HXTOption* opt) { - switch(opt->valueType) { - case HXT_DOUBLE: - case HXT_FLOAT: - return "VAL"; - case HXT_INT: - case HXT_I64: - case HXT_I32: - case HXT_I16: - case HXT_UNSIGNED: - case HXT_U64: - case HXT_U32: - case HXT_U16: - return "NUM"; - case HXT_STRING: - return "TEXT"; - case HXT_EXISTING_FILENAME: - case HXT_NEW_FILENAME: - case HXT_ASK_TO_ERASE_FILENAME: - return "FILENAME"; - default: - return "(none)"; - } -} - - -static void printOptionLine(HXTOption* opt, char text[16384], int* offset) -{ - const int char_max = 30; - int oldOffset = *offset; - MY_SPRINTF(" "); - - if(opt->shortName!='\0'){ - if(opt->longName!=NULL){ - MY_SPRINTF("-%c, ", opt->shortName); - } - else{ - MY_SPRINTF("-%c", opt->shortName); - } - } - - if(opt->longName!=NULL){ - if(opt->valueType==HXT_FLAG || opt->valueType==HXT_NO_FLAG) - MY_SPRINTF("--%s", opt->longName); - else - MY_SPRINTF("--%s=%s", opt->longName, getHelpValueName(opt)); - - - } - - int char_count = *offset - oldOffset; - if(char_count<char_max) - MY_SPRINTF("%*c", char_max - char_count, ' '); - else - MY_SPRINTF("\n%*c", char_max, ' '); - - // description - { - int i,k; - for (i=0,k=0; opt->description[i+1]!='\0'; i++, k++) { - if(opt->description[i]=='\n'){ - if(opt->description[i+1]=='\n' || opt->description[i+1]=='\0') - MY_SPRINTF("%.*s\n", k, opt->description+i-k); - else - MY_SPRINTF("%.*s\n%*c", k, opt->description+i-k, char_max+2, ' '); - k=-1; - } - } - MY_SPRINTF("%s", opt->description+i-k); - } - - // default argument - if(opt->valueType!=HXT_FLAG && opt->valueType!=HXT_NO_FLAG) - { - double r = 0; - unsigned long long u = 0; - long long int i = 0; - MY_SPRINTF("\n%*cdefault: %s=", char_max+1, ' ', getHelpValueName(opt)); - switch(opt->valueType) { - case HXT_DOUBLE: - MY_SPRINTF("%g", *(double*) opt->valuePtr); - break; - case HXT_FLOAT: - r = *(float*) opt->valuePtr; - MY_SPRINTF("%g", r); - break; - case HXT_INT: - MY_SPRINTF("%d", *(int*) opt->valuePtr); - break; - case HXT_I64: - i = *(int64_t*) opt->valuePtr; - MY_SPRINTF("%lld", i); - break; - case HXT_I32: - i = *(int32_t*) opt->valuePtr; - MY_SPRINTF("%lld", i); - break; - case HXT_I16: - i = *(int16_t*) opt->valuePtr; - MY_SPRINTF("%lld", i); - break; - case HXT_UNSIGNED: - MY_SPRINTF("%u", *(unsigned*) opt->valuePtr); - break; - case HXT_U64: - u = *(uint64_t*) opt->valuePtr; - MY_SPRINTF("%llu", u); - break; - case HXT_U32: - u = *(uint32_t*) opt->valuePtr; - MY_SPRINTF("%llu", u); - break; - case HXT_U16: - u = *(uint16_t*) opt->valuePtr; - MY_SPRINTF("%llu", u); - break; - case HXT_STRING: - case HXT_EXISTING_FILENAME: - case HXT_NEW_FILENAME: - case HXT_ASK_TO_ERASE_FILENAME: - if(opt->valuePtr!=NULL) - MY_SPRINTF("%s", *(const char**) opt->valuePtr); - break; - default: - break; - } - } - - MY_SPRINTF("\n"); -} - - -HXTStatus hxtGetOptionHelp(char text[16384], - const char* programName, - const char* programDescription, - const char* additionalInfo) -{ - int offsetval = 0; - int* offset = &offsetval; - if(programName!=NULL) { - MY_SPRINTF("Usage: %s [OPTION]...", programName); - int n = getNextTrailingOption(0); - while(n!=-1 && optionList[n].valuePtr!=NULL) { - int n2 = getNextTrailingOption(n); - if(optionList[n].shortName=='\0' && optionList[n].longName==NULL && optionList[n].description!=NULL) { - if(n2==-1) - MY_SPRINTF(" [%s]", optionList[n].description); - else - MY_SPRINTF(" %s", optionList[n].description); - } - n=n2; - } - } - - if(programDescription!=NULL) - MY_SPRINTF("\n\n%s", programDescription); - MY_SPRINTF("\n\n"); - - for (int i=0; i<optionListLength; i++) { - if(optionList[i].shortName!='\0' || optionList[i].longName!=NULL) - printOptionLine(&optionList[i], text, offset); - } - - if(additionalInfo) - MY_SPRINTF("%s\n", additionalInfo); - return HXT_STATUS_OK; -} \ No newline at end of file diff --git a/contrib/hxt/hxt_opt.h b/contrib/hxt/hxt_opt.h deleted file mode 100644 index 2fc77be450..0000000000 --- a/contrib/hxt/hxt_opt.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef __HXT_OPT_H__ -#define __HXT_OPT_H__ - -#include "hxt_tools.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/**************************************************************************************** - * argument type: the type of the argument that must be given to the option - * or HXT[_NO]_FLAG to indicate that the option doesn't have an argument - ***************************************************************************************/ -typedef enum { -// flags - // no argument must be given, the value must be an integer set to 0 (it is set to 1 when option is called) - HXT_FLAG, - // no argument must be given, the value must be an integer set to 1 (it is set to 0 when option is called) - HXT_NO_FLAG, - -// floating point values: - HXT_DOUBLE, - HXT_FLOAT, - -// integer values - HXT_INT, - HXT_I64, - HXT_I32, - HXT_I16, - -// unsigned integer values - HXT_UNSIGNED, - HXT_U64, - HXT_U32, - HXT_U16, - -// strings values - HXT_STRING, - HXT_EXISTING_FILENAME, - HXT_NEW_FILENAME, - HXT_ASK_TO_ERASE_FILENAME -} HXTOptionArgumentType; - -/************************************************************************************* - * Constraints on the accepted range of the value given in argument * - ************************************************************************************/ -typedef struct { - // acceptable range for floating-point values - double doubleMin; - double doubleMax; - - // acceptable range for integer values - long long int intMin; - long long int intMax; - - // acceptable range for unsigned integer values - unsigned long long unsignedMin; - unsigned long long unsignedMax; - - // required prefix and suffix to the string (NULL pointer are omitted) - const char* stringPrefix; - const char* stringSuffix; - - // character allowed, required or forbidden (NULL pointer are omitted) - const char* stringCharAllowed; -} HXTOptionArgumentConstraints; - -#define HXT_ALPHA_LOWERCASE_CHARACTERS "abcdefghijklmnopqrstuvwxyz" -#define HXT_ALPHA_UPPERCASE_CHARACTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define HXT_ALPHA_CHARACTERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define HXT_NUMERIC_CHARACTERS "0123456789" -#define HXT_ALPHANUMERIC_LOWERCASE_CHARACTERS "abcdefghijklmnopqrstuvwxyz0123456789" -#define HXT_ALPHANUMERIC_UPPERCASE_CHARACTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -#define HXT_ALPHANUMERIC_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -#define HXT_PRINTABLE_VISIBLE_CHARACTERS \ - "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" -#define HXT_PRINTABLE_CHARACTERS \ - "\t\n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" - -// built-in hxtOptionArg -extern const HXTOptionArgumentConstraints HXT_POSITIVE_RANGE; - -extern const HXTOptionArgumentConstraints HXT_ALPHA_LOWERCASE_RANGE; -extern const HXTOptionArgumentConstraints HXT_ALPHA_UPPERCASE_RANGE; -extern const HXTOptionArgumentConstraints HXT_ALPHA_RANGE; -extern const HXTOptionArgumentConstraints HXT_NUMERIC_RANGE; -extern const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_LOWERCASE_RANGE; -extern const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_UPPERCASE_RANGE; -extern const HXTOptionArgumentConstraints HXT_ALPHANUMERIC_RANGE; -extern const HXTOptionArgumentConstraints HXT_PRINTABLE_VISIBLE_RANGE; -extern const HXTOptionArgumentConstraints HXT_PRINTABLE_RANGE; - -extern const HXTOptionArgumentConstraints HXT_0_1_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_2_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_3_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_4_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_5_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_10_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_20_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_50_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_100_RANGE; -extern const HXTOptionArgumentConstraints HXT_0_1000_RANGE; - - -HXTStatus hxtAddOption(char short_name, - const char* longName, - const char* description, - HXTOptionArgumentType valueType, - const HXTOptionArgumentConstraints* constraints, - void* valuePtr); - -/* Trailing options are options without an option name. - * the order in which they are added is important ! - * by default, the last trailing option is optional - * you can add an empty trailing option (a trailing option with valuePtr==NULL) at the end to make the last trailing option required - * example: - * - * const char* input = NULL; - * HXT_CHECK(hxtAddTrailingOption("INPUT_MESH", HXT_EXISTING_FILENAME, NULL, &input)); - * - * // without the next line, the user would be allowed not giving an input mesh file in the command line - * - * HXT_CHECK(hxtAddTrailingOption(NULL, 0, NULL, NULL)); - * - * // this empty trailing option option ensure that an input mesh file is required -*/ -static inline HXTStatus hxtAddTrailingOption( - const char* argumentName, // name to use in the usage line ./program [Options] trailingArg1 trailingArg2 ... - HXTOptionArgumentType valueType, - const HXTOptionArgumentConstraints* constraints, - void* valuePtr) -{ - HXT_CHECK( hxtAddOption('\0', NULL, argumentName, valueType, constraints, valuePtr) ); - return HXT_STATUS_OK; -} - -// use the HXT_PARSE_COMMAND_LINE macro instead -HXTStatus hxtGetOptionHelp(char message[16384], - const char* programName, - const char* programDescription, - const char* additionalInfo); - -// use the HXT_PARSE_COMMAND_LINE macro instead -HXTStatus hxtParseOptions(const int argc, char* argv[]); - -// This macro should be placed in the main, after all options are added ! -#define HXT_PARSE_COMMAND_LINE(argc, argv, programName, programDescription, additionalInfo) \ -do{ \ - char help[16384]; \ - HXTStatus status = hxtGetOptionHelp(help, programName, programDescription, additionalInfo); \ - if(status==HXT_STATUS_OK) \ - status = hxtParseOptions(argc, argv); \ - if(status!=HXT_STATUS_OK && status!=HXT_STATUS_INTERNAL) { \ - HXT_TRACE(status); \ - puts("\n ==> Help on Error\n\n ---\n"); \ - } \ - if(status!=HXT_STATUS_OK) { \ - printf("%s", help); \ - return status!=HXT_STATUS_INTERNAL?status:0; \ - } \ -} while(0); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/hxt_option.c b/contrib/hxt/hxt_option.c deleted file mode 100644 index 090db3cee5..0000000000 --- a/contrib/hxt/hxt_option.c +++ /dev/null @@ -1,504 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include "hxt_option.h" - -static HXTOpt help_option = {"h", "help", "Display this help message"}; - -/********************************************************************* -* program structure * -*********************************************************************/ -struct HXTOptProgramStruct { - const char* usage_line; - const char* start_description; - const char* end_description; - HXTOpt** opts; - size_t opt_length; - size_t opt_capacity; -}; - - -/********************************************************************* -* Create a program * -*********************************************************************/ -HXTStatus hxtOptProgCreate(HXTOptProgram** program_ptr, - const char* usage_line, - const char* start_description, - const char* end_description) -{ - HXT_ASSERT(program_ptr!=NULL); - - HXTOptProgram* program; - HXT_CHECK( hxtMalloc(&program, sizeof(HXTOptProgram)) ); - *program_ptr = program; - - program->usage_line = usage_line; - program->start_description = start_description; - program->end_description = end_description; - program->opts = NULL; - program->opt_length = 0; - program->opt_capacity = 0; - - hxtOptProgAddOption(program, &help_option); - - return HXT_STATUS_OK; -} - - -/********************************************************************* -* add an option to a program * -*********************************************************************/ -HXTStatus hxtOptProgAddOption(HXTOptProgram* program, HXTOpt* opt) -{ - HXT_ASSERT( program!=NULL ); - HXT_ASSERT( opt!=NULL ); - - if(program->opt_length >= program->opt_capacity){ - size_t newSize = program->opt_length?program->opt_length*2:16; - HXT_CHECK( hxtRealloc(&program->opts, - sizeof(HXTOpt*) * newSize ) ); - program->opt_capacity = newSize; - } - - program->opts[program->opt_length++] = opt; - - return HXT_STATUS_OK; -} - - -/********************************************************************* -* delete a program * -*********************************************************************/ -HXTStatus hxtOptProgDelete(HXTOptProgram* program){ - HXT_ASSERT( program!=NULL ); - HXT_CHECK( hxtFree(&program->opts) ); - HXT_CHECK( hxtFree(&program) ); - - return HXT_STATUS_OK; -} - - -/********************************************************************* -* search a long option inside the lists of a program * -*********************************************************************/ -static int searchLongOption(HXTOptProgram* program, - const char* string) -{ - for (size_t i=0; i<program->opt_length; i++) { - if(program->opts[i]->longs!=NULL && - strcmp(program->opts[i]->longs, string)==0) { - return i; - } - } - - return -1; -} - - -/********************************************************************* -* search a short option inside the lists of a program * -*********************************************************************/ -static int searchShortOption(HXTOptProgram* program, - char c) -{ - for (size_t i=0; i<program->opt_length; i++) { - if(program->opts[i]->shorts!=NULL && - strchr(program->opts[i]->shorts, c)!=NULL) { - return i; - } - } - - return 0; -} - -static inline const char* getArgTypeName(ARG_TYPE t){ - switch(t) { - case ARG_INT64 : - return "a 64-bit integer"; - case ARG_INT32 : - return "a 32-bit integer"; - case ARG_UINT32 : - return "a 32-bit unsigned integer"; - case ARG_DOUBLE : - return "a float"; - case ARG_FLOAT : - return "a double"; - case ARG_POSITIVE_FLOAT : - return "a positive float"; - case ARG_POSITIVE_DOUBLE : - return "a positive double"; - case ARG_STRING : - return "a string"; - default: - if(t>0) - return "an integer"; - else - return "a string"; - } -} - - -/********************************************************************* -* scan parameter and execute callback function for user options * -*********************************************************************/ -static HXTStatus doOption(HXTOpt* opt, - const char* arg, - void* state, - char* optName) -{ - char* endptr = NULL; - - int64_t integer = INT64_MIN; - double real = NAN; - const char* string = "\a"; - - - if(opt->argRequirement&1 || - (opt->argRequirement==ARG_OPTIONAL && arg!=NULL)) { - if(opt->argType>-4) - integer = strtol(arg, &endptr, 0); - else if(opt->argType>-8) - real = strtod(arg, &endptr); - else - string = arg; - - - if(errno == ERANGE){ - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (range overflow)", - arg, optName, getArgTypeName(opt->argType)); - } - else if (arg == endptr) - { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (no digit)", - arg, optName, getArgTypeName(opt->argType)); - } - else if(endptr!=NULL && *endptr!='\0') { - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (trailing unvalid characters)", - arg, optName, getArgTypeName(opt->argType)); - } - - switch(opt->argType){ - case ARG_POSITIVE_INT64 : - if(integer<0) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (value was negative)", - arg, optName, getArgTypeName(opt->argType)); - break; - case ARG_INT32: - { - int32_t i32 = integer; - if(i32!=integer) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s ((int32_t)%ld!=%ld)", - arg, optName, getArgTypeName(opt->argType), integer, integer); - } - break; - case ARG_UINT32: - { - uint32_t u32 = integer; - if(u32!=integer) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s ((uint32_t)%ld!=%ld)", - arg, optName, getArgTypeName(opt->argType), integer, integer); - } - break; - case ARG_POSITIVE_DOUBLE: - if(real<0.0) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (value was negative)", - arg, optName, getArgTypeName(opt->argType)); - break; - case ARG_POSITIVE_FLOAT: - if(real<0.0) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s (value was negative)", - arg, optName, getArgTypeName(opt->argType)); - /* fallthrough */ - case ARG_FLOAT: - { - float f32 = real; - if(f32!=real) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to %s ((float)%f!=%f)", - arg, optName, getArgTypeName(opt->argType), real, real); - } - break; - default: - if(opt->argType>0 && ( integer > opt->argType || integer<0 ) ) - return HXT_ERROR_MSG(HXT_STATUS_RANGE_ERROR, - "cannot convert argument \"%s\" of option \"%s\" to an integer between 0 and %d", - arg, optName, opt->argType); - break; - - } - } - - if(opt->argType>-4) - opt->integer = integer; - else if(opt->argType>-8) - opt->real = real; - else - opt->string = string; - - if(opt->cb!=NULL){ - HXTStatus err = opt->cb(opt, state); - if(err<0){ - return HXT_ERROR_MSG(HXT_STATUS_ERROR, - "argument \"%s\" of option \"%s\" triggered an error in callback", - arg, optName); - } - } - - return HXT_STATUS_OK; -} - - -HXTStatus hxtOptCalledWithoutArg(HXTOpt* opt){ - if(opt->argType>-4) // integer type - return (opt->integer==INT64_MIN); - else if(opt->argType>-8) - return (opt->real==NAN); - else - return (opt->string[0]=='\a'); -} - - -/********************************************************************* -* Function parsing argv * -*********************************************************************/ -HXTStatus hxtOptProgParse(HXTOptProgram* program, - const int argc, - char* argv[], - void* state, - int* optind) -{ - HXT_ASSERT(program!=NULL); - HXT_ASSERT(optind!=NULL); - - int numarg = argc; - *optind = 1; - for (int i=1; i<numarg; i++) { - char *arg = NULL; - HXTOpt* opt = NULL; - - if(argv[i][0]!='-' || (argv[i][0]=='-' && argv[i][1]=='\0')){ - /* not opt, shift everything before this string */ - arg = argv[i]; - for (int j=i; j<argc-1; j++) { - argv[j] = argv[j+1]; - } - argv[argc-1] = arg; - numarg--; - i--; - } - else if(argv[i][1]=='-') { /* long opt */ - if(argv[i][2]=='\0') /* -- terminate argument parsing */ - return HXT_STATUS_OK; - - char* equalSign = strchr(argv[i]+2,'='); - - if(equalSign!=NULL){ - *equalSign = '\0'; - arg = equalSign + 1; - } - - int num = searchLongOption(program, argv[i]+2); - if(num<0){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \"%s\" not found", argv[i]); - } - opt = program->opts[num]; - - if(equalSign!=NULL){ - *equalSign = '='; - if(opt->argRequirement==ARG_NONE){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \"%s\" takes no argument", argv[i]); - } - } - else{ - if(num==0) { // it's the help option - *optind = -1; - return HXT_STATUS_OK; - } - if(opt->argRequirement&1 && numarg<=i+1){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "options \"%s\" requires an argument", argv[i]); - } - else if(numarg>i+1 && (opt->argRequirement&1 || argv[i+1][0]!='-')) { - arg = argv[i+1]; - i++; - } - } - - HXT_CHECK( doOption(opt, arg, state, argv[i]) ); - } - else{ /* short option */ - int cond = argv[i][1]; - for(int j=1; cond; j++){ - int num = searchShortOption(program, argv[i][j]); - if(num<0){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "option \'%c\' in \"%s\" not found", argv[i][j], argv[i]); - } - - char optName[] = "- "; - optName[1] = argv[i][j]; - cond = argv[i][j+1]; - - if(num==0){ - *optind = -1; - return HXT_STATUS_OK; - } - - opt = program->opts[num]; - - if(opt->argRequirement!=ARG_NONE){ - if(cond){ - arg = argv[i] + j+1; - cond = 0; // stop the loop - } - else if(opt->argRequirement&1 && numarg<=i+1){ - return HXT_ERROR_MSG(HXT_STATUS_FORMAT_ERROR, - "options \'%c\' in \"%s\" requires an argument", argv[i][j], argv[i]); - } - else if(numarg>i+1 && (opt->argRequirement==ARG_REQUIRED || argv[i+1][0]!='-')) { - arg = argv[i+1]; - i++; - } - } - - HXT_CHECK( doOption(opt, arg, state, optName) ); - } - } - *optind = i+1; - } - - for (size_t i=0; i<program->opt_length; i++) { - HXTOpt* opt = program->opts[i]; - if(opt->argRequirement==ARG_NON_NULL_REQUIRED && - ((opt->argType>-4 && opt->integer==0) || - (opt->argType>-8 && opt->real==0.0) || - (opt->argType<=-8 && opt->string==NULL) - ) - ) { - if(opt->longs!=NULL) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, - "mandatory option \"--%s\" must have a non-null argument", - opt->longs); - else - return HXT_ERROR_MSG(HXT_STATUS_ERROR, - "mandatory option \'-%c\' must have a non-null argument", - opt->shorts[0]); - } - } - - return HXT_STATUS_OK; -} - - -#define MY_SPRINTF(...) *offset+=snprintf(text+ *offset, 16384- *offset, ## __VA_ARGS__ ) - -static void printOptionLine(HXTOpt* opt, char text[16384], int* offset) -{ - int char_max = 30; - int oldOffset = *offset; - MY_SPRINTF(" "); - - int long_exist = opt->longs!=NULL && opt->longs[0]!='\0'; - - // short params - if(opt->shorts!=NULL && opt->shorts[0]!='\0'){ - int len = strlen(opt->shorts); - - for (int i=0; i<len-1; i++){ - MY_SPRINTF("-%c, ", opt->shorts[i]); - } - - if(long_exist){ - MY_SPRINTF("-%c, ", opt->shorts[len-1]); - } - else{ - MY_SPRINTF("-%c", opt->shorts[len-1]); - } - } - - if(long_exist){ - if(opt->argRequirement==ARG_NONE) - MY_SPRINTF("--%s", opt->longs); - else if(opt->argRequirement==ARG_OPTIONAL) - MY_SPRINTF("--%s[=%s]", opt->longs, opt->argName); - else - MY_SPRINTF("--%s=%s", opt->longs, opt->argName); - - - } - - int char_count = *offset - oldOffset; - if(char_count<char_max) - MY_SPRINTF("%*c", char_max - char_count, ' '); - else - MY_SPRINTF("\n%*c", char_max, ' '); - - // description - { - int i,k; - for (i=0,k=0; opt->description[i+1]!='\0'; i++, k++) { - if(opt->description[i]=='\n'){ - if(opt->description[i+1]=='\n' || opt->description[i+1]=='\0') - MY_SPRINTF("%.*s\n", k, opt->description+i-k); - else - MY_SPRINTF("%.*s\n%*c", k, opt->description+i-k, char_max+2, ' '); - k=-1; - } - } - MY_SPRINTF("%s", opt->description+i-k); - } - - // default argument - if(opt->argRequirement!=ARG_NONE && - (opt->argType!=ARG_STRING || opt->string!=NULL)) - { - MY_SPRINTF("\n%*cdefault: %s=", char_max+1, ' ', opt->argName); - if(opt->argType>-4) // integer type - MY_SPRINTF("%ld",opt->integer); - else if(opt->argType>-8) - MY_SPRINTF("%g",opt->real); - else - MY_SPRINTF("%s",opt->string); - } - - MY_SPRINTF("\n"); -} - - - -HXTStatus hxtOptProgGetHelp(HXTOptProgram* program, char text[16384]) -{ - int offsetval = 0; - int* offset = &offsetval; - if(program->usage_line) - MY_SPRINTF("%s\n\n", program->usage_line); - - if(program->start_description) - MY_SPRINTF("%s\n\n", program->start_description); - - int oldOffset = *offset; - MY_SPRINTF("Application Options:\n"); - int char_printed = *offset - oldOffset; - - MY_SPRINTF("%.*s\n", char_printed>64?63:char_printed-1, - "---------------------------------------------------------------"); - - for (size_t i=0; i<program->opt_length; i++) { - printOptionLine(program->opts[i], text, offset); - } - - if(program->end_description) - MY_SPRINTF("%s\n", program->end_description); - return HXT_STATUS_OK; -} \ No newline at end of file diff --git a/contrib/hxt/hxt_option.h b/contrib/hxt/hxt_option.h deleted file mode 100644 index c07e33e1cc..0000000000 --- a/contrib/hxt/hxt_option.h +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef __HXT_OPT_H__ -#define __HXT_OPT_H__ - -#include "hxt_tools.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct HXTOptListStruct HXTOptList; -typedef struct HXTOptProgramStruct HXTOptProgram; - -/************** new option parsing method ****************** - - ## the program is detailed into a HXTOptProgram. - HXTOptProgram* program; - HXT_CHECK( hxtOptProgCreate(&program, - "Usage: mon_programme [options]", ## a usage line for Help - "mon_programme is a programme that doesn't do much", ## a description of the program - "Example:\n mon_programme --coucou=David" ## Examples, contact information etc. - ) ); - - ## then, we will add each possible options to this program - ## each options is detailed into a HXTOpt: - HXTOpt myOpt = { - "cC", ## short option names (each character is a short name => '-c' and '-C' refer to this option) - "coucou", ## long option name (a unique long name => '--coucou' refers to this option) - - "Prints coucou c to the screen\n" ## a description of this option - "Not usefull at all but funny", ## can span multiple lines (no comma on the previous line) - - coucouCallBack, ## a callback function called everytime the program is called - ## the prototype of 'coucouCallBack' must be: - ## HXTStatus coucouCallBack(HXTOpt* opt, void* state); - ## the option given will be 'myOpt'. - ## the state is a pointer that we give to the parsing function - - "YOUR_NAME", ## the name of the argument to show in Help - ## here Help will show: - ## -c, -C, --coucou=YOUR_NAME Prints coucou YOUR_NAME to the screen - - ARG_REQUIRED, ## one of ARG_NONE, ARG_REQUIRED, ARG_OPTIONAL and ARG_NON_NULL_REQUIRED - ## specify if an argument is required (see ARG_REQUIREMENT section) - - ARG_STRING, ## the type of the argument as described below (ARG_TYPE section) - - {.string="Joe"} ## a default value for the argument (uneeded here as the argument is required...) - }; - - ##then we add the option to the program: - HXT_CHECK( hxtOptProgAddOption(program, myOpt) ); - - ## Once all options are added, we can parse the argument. - ## The function will automatically return the status and print Help on errors - - void* state = NULL; ## this pointer will be given to each callback functions - int optind=0; ## this integer will contain the number of string processed in argv - HXT_OPT_MAIN_PARSE(program, argc, argv, NULL, &optind ); - - ## you can now use the argument provided by the user safely - printf(" Coucou %s !!!", myOpt.string); - - ## and delete the program structure - HXT_CHECK( hxtOptProgDelete(program) ); - -*/ - - -/**************************************************************************************** - * ARG_REQUIREMENT : specify if an argument is required to follow the option - ***************************************************************************************/ -typedef enum { - ARG_NONE=0, /* no argument, the union value is incremented at each call */ - ARG_REQUIRED=1, /* argument required, the union value is the value of the argument */ - ARG_OPTIONAL=2, /* optional argument, the union value is: - - the value of the argument if there is an argument - - INT64_MIN for integers type - - NAN for floating point type if there was no argument - - "\a" for string types - */ - ARG_NON_NULL_REQUIRED=3 /* argument is required and the option should be non-null - at end of parsing */ -} ARG_REQUIREMENT; - - -/**************************************************************************************** - * ARG_TYPE: the accepted values of the possible argument - * (use whatever you want if argRequirement==ARG_NONE) - ***************************************************************************************/ -typedef enum { - // a positive value N means an integer between 0 and N included - ARG_POSITIVE_INT32=INT32_MAX, - - /* Integer value types (stored in opt.integer) */ - ARG_INT64=0, // an integer, whatever fits in a int64_t - ARG_POSITIVE_INT64=-1, - ARG_INT32=-2, // the value is checked to fit in a int32_t - ARG_UINT32=-3,// the value is checked to fit in a uint32_t - - /* Floating value types (stored in opt.real) */ - ARG_DOUBLE=-4,// a double value, whatever fits in a double - ARG_FLOAT=-5, // the value is checked to fit in a float - ARG_POSITIVE_FLOAT=-6, // the value is checked to fit in a float and be positive - ARG_POSITIVE_DOUBLE=-7,// the value is checked to fit in a double and be positive - - /* String value type (stored in opt.string) */ - ARG_STRING=-8 -} ARG_TYPE; - - - -typedef struct HXTOptStruct{ - const char* const shorts; - const char* const longs; - const char* const description; - HXTStatus (*const cb)(struct HXTOptStruct* arg, void* state); - const char* const argName; - const ARG_REQUIREMENT argRequirement; - const int argType; -// struct { - int64_t integer; - double real; - const char* string; -// } -}HXTOpt; - - - - - - -HXTStatus hxtOptProgCreate(HXTOptProgram** program_ptr, - const char* usage_line, - const char* start_description, - const char* end_description); - - -HXTStatus hxtOptProgAddOption(HXTOptProgram* program, - HXTOpt* opt); - - -HXTStatus hxtOptProgParse(HXTOptProgram* program, - const int argc, char* argv[], - void* state, - int* optind); - - -#define HXT_OPT_MAIN_PARSE(program, argc, argv, state, optind_ptr) \ - do { \ - char help[16384]; \ - hxtOptProgGetHelp(program, help); \ - HXTStatus _status = hxtOptProgParse(program, argc, argv, NULL, optind_ptr ); \ - if(_status!=HXT_STATUS_OK){ \ - HXT_TRACE(_status); \ - puts("\n ==> Help on Error\n\n ---\n\n"); \ - *optind_ptr=-1; \ - } \ - if(*optind_ptr==-1) { \ - printf("%s", help); \ - HXT_CHECK( hxtOptProgDelete(program) ); \ - return _status; \ - } \ - }while(0) - -HXTStatus hxtOptCalledWithoutArg(HXTOpt* opt); - -HXTStatus hxtOptProgGetHelp(HXTOptProgram* program, char text[16384]); - -HXTStatus hxtOptProgDelete(HXTOptProgram* program); - - -static inline HXTStatus hxtOptProgAddOptionArray(HXTOptProgram* program, - HXTOpt* opt, int n) { - for (int i=0; i<n; i++) { HXT_CHECK( hxtOptProgAddOption(program, &opt[i]) ); } - return HXT_STATUS_OK; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/hxt_parametrization.c b/contrib/hxt/hxt_parametrization.c deleted file mode 100644 index 36d4a37920..0000000000 --- a/contrib/hxt/hxt_parametrization.c +++ /dev/null @@ -1,754 +0,0 @@ -#include "hxt_parametrization.h" -#include "hxt_mean_values.h" -#include "hxt_edge.h" -#include "metis.h" - - -/* - -// # O U T P U T - -int* colors; //gives colors of elements: colors[i] = color of i-th element -int* nNodes; //gives lower index of int* nodes for a color: nNodes[i] = first node index of i-th color -int* nodes; //gives the global index of initial 'mesh': nodes[i] = if i=nNodes[c]+k, gives the global index of k-th node of c-th color -double* uv; //give the uv param coordinates of a local node: uv[2*i+p] = u/v component of the global k-node of the c-th color - - */ - - - - -struct HXTVectorStruct{ - void **ptr; - int last; - int length; -}; - - -static HXTStatus hxtVectorInit(HXTVector **vecptr){ - - - HXT_CHECK(hxtMalloc(vecptr,sizeof(HXTVector))); - - HXTVector *new = *vecptr; - - new->ptr = NULL; - new->last = -1; - new->length = 0; - - return HXT_STATUS_OK; -} - - -static HXTStatus hxtVectorFree(HXTVector **vecptr){ - - HXTVector *vector = *vecptr; - - HXT_CHECK(hxtFree(&vector->ptr)); - - HXT_CHECK(hxtFree(vecptr)); - - return HXT_STATUS_OK; - -} - -static HXTStatus hxtVectorPushBack(HXTVector *vector, void *object){ - - int i = vector->last; - int length = vector->length; - - if(i+1 >= length){ - if(length==0) - length=1; - HXT_CHECK(hxtRealloc(&vector->ptr,2*(length)*sizeof(void *))); - vector->length = 2*length; - } - vector->ptr[i+1] = object; - vector->last = i+1; - - return HXT_STATUS_OK; -} - - -/*---------------------------------------*/ - - - -struct HXTParametrizationStruct{ - HXTEdges *edges; - int n; - HXTMeanValues **maps; -}; - - - - -static HXTStatus hxtDoubleLongestEdge(HXTEdges *e, int tri, double *l) -{ - uint32_t *ed = &e->tri2edg[3*tri]; - *l=0; - - for(int i=0; i<3; i++){ - uint64_t *tr= &e->edg2tri[2*ed[i]]; - - if(tr[1]==(uint64_t)-1) - continue; - - if(*l<hxtEdgesLength(e,ed[i])) - *l=hxtEdgesLength(e,ed[i]); - } - return HXT_STATUS_OK; -} - -static HXTStatus hxtLongestEdge(HXTEdges *edges, int tri,int *ie,int comp) -{ - uint32_t *ed = &edges->tri2edg[3*tri]; - double longest = hxtEdgesLength(edges,comp); - *ie=comp; - for(int i=0; i<3; i++){ - uint64_t *tr= &edges->edg2tri[2*ed[i]]; - - if(tr[1]==(uint64_t)-1) - continue; - - if(longest<hxtEdgesLength(edges,ed[i])){ - longest=hxtEdgesLength(edges,ed[i]); - *ie = ed[i]; - } - } - return HXT_STATUS_OK; -} - -static HXTStatus hxtLongestEdgeBisection(HXTEdges *edges,int nrefinements) -{ - double threshold = 0, counter=0; - for(uint32_t ie=0; ie<edges->numEdges; ie++) - if(edges->edg2tri[2*ie+1]==(uint64_t)-1){ - threshold+= hxtEdgesLength(edges,ie); - counter++; - } - if (counter>0) - threshold/=counter; - - // longest-edge bisection: boundary edges are not splitted - for(int ir=0; ir<nrefinements; ir++){ - HXTEdges *e = edges; - HXTMesh *m = edges->edg2mesh; - - - - uint64_t *flag=NULL; - HXT_CHECK(hxtMalloc(&flag,m->triangles.num*sizeof(uint64_t))); - for(uint64_t it=0; it<m->triangles.num; it++){ - double l; - HXT_CHECK(hxtDoubleLongestEdge(e,it,&l)); - if(l>2*threshold) - flag[it] = 0; - else - flag[it] = 1; - } - - int maxVert = m->vertices.num; - int maxTri = m->triangles.num; - int maxEdg = e->numEdges; - uint64_t initialNumberOfTriangles = m->triangles.num; - for(uint64_t it=0; it<initialNumberOfTriangles; it++){ - if(flag[it] > 0) - continue; - - while(flag[it]==0){ - int ti = (int) it, tj; - int ei,ej; - for(int ib=0; ib<3; ib++){ - if (e->edg2tri[2*e->tri2edg[3*it+ib]+1] == (uint64_t) -1) - continue; - else{ - hxtLongestEdge(e,it,&ej,e->tri2edg[3*it+ib]); - break; - } - } - do{ - HXT_CHECK(hxtLongestEdge(e,ti,&ei,ej)); - tj = e->edg2tri[2*ei+0]==ti ? e->edg2tri[2*ei+1] : e->edg2tri[2*ei+0]; - HXT_CHECK(hxtLongestEdge(e,tj,&ej,ei)); - ti = e->edg2tri[2*ej+0]==tj ? e->edg2tri[2*ej+1] : e->edg2tri[2*ej+0]; - }while(ei!=ej); - - m->vertices.num += 1; - if(m->vertices.num > maxVert){ - maxVert *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->vertices.coord,4*maxVert*sizeof(double))); - } - int ni = e->node[2*ei+0], nj = e->node[2*ei+1]; - - for(int xj=0; xj<3; xj++) - m->vertices.coord[4*(m->vertices.num-1)+xj] = ( m->vertices.coord[4*ni+xj] + m->vertices.coord[4*nj+xj] )/2.; - - m->triangles.num +=2; - if(m->triangles.num > maxTri){ - maxTri *= 2; - HXT_CHECK(hxtAlignedRealloc(&m->triangles.node,3*maxTri*sizeof(uint32_t))); - HXT_CHECK(hxtAlignedRealloc(&m->triangles.colors,maxTri*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->tri2edg,3*maxTri*sizeof(uint32_t))); - } - int tti = m->triangles.num-2, ttj = tti+1; - int e0 = e->numEdges, e1=e0+1, e2=e1+1; - for(int ic=0; ic<3; ic++){ - if(m->triangles.node[3*ti+ic]==ni && m->triangles.node[3*ti+(ic+1)%3]==nj){ - m->triangles.node[3*ti+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = m->vertices.num-1; - m->triangles.node[3*tti+1] = nj; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e->tri2edg[3*ti+(ic+1)%3]; - e->tri2edg[3*tti+2] = e1; - - e->tri2edg[3*ti+(ic+1)%3] = e1; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+1]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - else if (m->triangles.node[3*ti+ic]==nj && m->triangles.node[3*ti+(ic+1)%3]==ni) { - m->triangles.node[3*ti+ic] = m->vertices.num-1; - - m->triangles.node[3*tti+0] = nj; - m->triangles.node[3*tti+1] = m->vertices.num-1; - m->triangles.node[3*tti+2] = m->triangles.node[3*ti+(ic+2)%3]; - e->tri2edg[3*tti+0] = e0; - e->tri2edg[3*tti+1] = e1; - e->tri2edg[3*tti+2] = e->tri2edg[3*ti+(ic+2)%3]; - - e->tri2edg[3*ti+(ic+2)%3] = e1; - - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*tti+2]]; - if(t_[0]==ti) - t_[0] = tti; - else - t_[1] = tti; - - } - if(m->triangles.node[3*tj+ic]==nj && m->triangles.node[3*tj+(ic+1)%3]==ni){ - m->triangles.node[3*tj+(ic+1)%3] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = m->vertices.num-1; - m->triangles.node[3*ttj+1] = ni; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ei; - e->tri2edg[3*ttj+1] = e->tri2edg[3*tj+(ic+1)%3]; - e->tri2edg[3*ttj+2] = e2; - - e->tri2edg[3*tj+(ic+1)%3] = e2; - e->tri2edg[3*tj+ic] = e0; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+1]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - - } - else if (m->triangles.node[3*tj+ic]==ni && m->triangles.node[3*tj+(ic+1)%3]==nj){ - - m->triangles.node[3*tj+ic] = m->vertices.num-1; - - m->triangles.node[3*ttj+0] = ni; - m->triangles.node[3*ttj+1] = m->vertices.num-1; - m->triangles.node[3*ttj+2] = m->triangles.node[3*tj+(ic+2)%3]; - e->tri2edg[3*ttj+0] = ei; - e->tri2edg[3*ttj+1] = e2; - e->tri2edg[3*ttj+2] = e->tri2edg[3*tj+(ic+2)%3]; - - e->tri2edg[3*tj+ic] = e0; - e->tri2edg[3*tj+(ic+2)%3] = e2; - - uint64_t *t_ = &e->edg2tri[2*e->tri2edg[3*ttj+2]]; - if(t_[0]==tj) - t_[0] = ttj; - else - t_[1] = ttj; - - } - }//end for - e->numEdges +=3; - if(e->numEdges > maxEdg){ - maxEdg *= 2; - HXT_CHECK(hxtRealloc(&e->node,2*maxEdg*sizeof(uint32_t))); - HXT_CHECK(hxtRealloc(&e->color,maxEdg*sizeof(uint16_t))); - HXT_CHECK(hxtRealloc(&e->edg2tri,2*maxEdg*sizeof(uint64_t))); - } - e->node[2*ei+1] = m->vertices.num-1; - e->edg2tri[2*ei+0] = ti; - e->edg2tri[2*ei+1] = ttj; - e->node[2*e0+0] = m->vertices.num-1; - e->node[2*e0+1] = nj; - e->edg2tri[2*e0+0] = tti; - e->edg2tri[2*e0+1] = tj; - e->node[2*e1+0] = m->vertices.num-1; - e->node[2*e1+1] = m->triangles.node[3*tti+2]; - e->edg2tri[2*e1+0] = ti; - e->edg2tri[2*e1+1] = tti; - e->node[2*e2+0] = m->vertices.num-1; - e->node[2*e2+1] = m->triangles.node[3*ttj+2]; - e->edg2tri[2*e2+0] = tj; - e->edg2tri[2*e2+1] = ttj; - - - if (ti < initialNumberOfTriangles) - flag[ti] = 1; - if (tj < initialNumberOfTriangles) - flag[tj] = 1; - - }// end while flag[it]==0 - }//end for it - - if(threshold>0) - for(uint64_t it=0; it<m->triangles.num; it++){ - double l; - HXT_CHECK(hxtDoubleLongestEdge(e,it,&l)); - if(l>2*threshold && nrefinements<10){ - nrefinements++; - break; - } - } - - - }//end refinement - - - - - return HXT_STATUS_OK; -} - -static HXTStatus hxtPartitioning(HXTEdges *edges,int *part, int nPartitions,HXTVector *partitions) -{ - - HXTMesh *mesh = edges->edg2mesh; - - uint32_t *flagVertices; - HXT_CHECK(hxtMalloc(&flagVertices,mesh->vertices.num*sizeof(uint32_t))); - for(int p = 0; p<nPartitions; p++){ - HXTMesh *msh=NULL; - HXT_CHECK(hxtMeshCreate(mesh->ctx,&msh)); - - - for(uint32_t iv=0; iv<mesh->vertices.num; iv++) - flagVertices[iv] = -1; - - uint32_t cv = 0; - uint64_t ce = 0; - for(uint64_t ie=0; ie<mesh->triangles.num; ie++){ - if(part[ie]==p){ - for(int jv=0; jv<3; jv++){ - uint32_t current = mesh->triangles.node[3*ie+jv]; - if(flagVertices[current] == (uint32_t)-1) - flagVertices[current] = cv++; - } - ce++; - } - } - /* - printf("------------stat \t part %d---------------\n",p); - printf("\t number of vertices:%u\n",cv); - printf("\t number of elements:%lu\n",ce); - */ - msh->vertices.num = cv; - HXT_CHECK(hxtAlignedMalloc(&msh->vertices.coord,4*cv*sizeof(double))); - for(uint32_t iv=0; iv<mesh->vertices.num; iv++){ - uint32_t current = flagVertices[iv]; - if(current==(uint32_t)-1); - else{ - msh->vertices.coord[4*current+0] = mesh->vertices.coord[4*iv+0]; - msh->vertices.coord[4*current+1] = mesh->vertices.coord[4*iv+1]; - msh->vertices.coord[4*current+2] = mesh->vertices.coord[4*iv+2]; - msh->vertices.coord[4*current+3] = mesh->vertices.coord[4*iv+3]; - } - } - - msh->triangles.num = ce; - //< - uint64_t *global; - HXT_CHECK(hxtMalloc(&global,ce*sizeof(uint64_t))); - //> - HXT_CHECK( hxtAlignedMalloc(&msh->triangles.node,ce*3*sizeof(uint32_t)) ); - HXT_CHECK( hxtAlignedMalloc(&msh->triangles.colors,ce*sizeof(uint16_t)) ); - ce = 0; - for(uint64_t ie=0; ie<mesh->triangles.num; ie++){ - if(part[ie]==p){ - global[ce] = edges->global[ie]; - msh->triangles.colors[ce] = mesh->triangles.colors[ie]; - for(int jv=0; jv<3; jv++){ - uint32_t current = flagVertices[mesh->triangles.node[3*ie+jv]]; - msh->triangles.node[3*ce+jv] = current; - } - ce++; - } - } - HXTEdges* edg = NULL; - HXT_CHECK(hxtEdgesCreate(msh,&edg)); - edg->global = global; - HXT_CHECK(hxtVectorPushBack(partitions,edg)); - } - - return HXT_STATUS_OK; - -} - -static HXTStatus hxtCheckConnectivity(HXTEdges *e,HXTVector *partitions) -{ - - HXTMesh *m = e->edg2mesh; - - int *flag = NULL; - HXT_CHECK(hxtMalloc(&flag,m->triangles.num*sizeof(int))); - for(uint64_t i=0; i<m->triangles.num; i++) - flag[i] = -1; - - uint64_t *queue = NULL; - HXT_CHECK(hxtMalloc(&queue,m->triangles.num*sizeof(uint64_t))); - int last = 1; - - - uint64_t *idx = NULL; - HXT_CHECK(hxtMalloc(&idx,(m->triangles.num+1)*sizeof(uint64_t))); - - - int count = 0; - flag[0] = count; - queue[0] = 0; - int goOn = 1; - int iq=0; - idx[0] = 1; - while(goOn){ - for(; iq<last; iq++){ - idx[iq+1] = idx[iq]; - uint64_t current = queue[iq]; - uint32_t *ed = &e->tri2edg[3*current]; - for(int j=0; j<3; j++){ - if (e->edg2tri[2*ed[j]+1] == (uint64_t) -1) - continue; - uint64_t next = e->edg2tri[2*ed[j]] == current ? e->edg2tri[2*ed[j]+1] : e->edg2tri[2*ed[j]]; - if (flag[next] == -1){ - queue[last]= next; - last++; - idx[iq+1]++; - flag[next] = (int) count; - } - } - } - count++; - goOn = 0; - for(uint64_t i=0; i<m->triangles.num; i++) - if (flag[i]== -1){ - goOn=1; - iq=last; - queue[last] = i; - last++; - flag[i] = count; - break; - } - } - - // printf("HXT_INFO \t There is/are %d connected part(s).\n",count); - - for(uint64_t i=0; i<m->triangles.num; i++){ - uint32_t *refVert = &m->triangles.node[3*queue[i]]; - for(uint64_t j=idx[i]+flag[queue[i]]; j<idx[i+1]+flag[queue[i]]; j++){ - - int cond = 0; - uint32_t *checkVert = &m->triangles.node[3*queue[j]]; - for(int ii=0; ii<3; ii++){ - for(int jj=0; jj<3; jj++){ - if(refVert[ii]==checkVert[(jj+1)%3] && refVert[(ii+1)%3]==checkVert[jj]){ - cond = 1; - break; - } - } - if(cond==1) - break; - }//end for ii - if(cond==0){ - printf("Unconsistent orientation \t %lu (%u %u %u) ; (%u %u)-(%u %u)-(%u %u) [%d] ~ %lu (%u %u %u) ; (%u %u)-(%u %u)-(%u %u) [%d].\n",queue[i],refVert[0],refVert[1],refVert[2],e->node[2*e->tri2edg[3*queue[i]+0]+0],e->node[2*e->tri2edg[3*queue[i]+0]+1],e->node[2*e->tri2edg[3*queue[i]+1]+0],e->node[2*e->tri2edg[3*queue[i]+1]+1],e->node[2*e->tri2edg[3*queue[i]+2]+0],e->node[2*e->tri2edg[3*queue[i]+2]+1],flag[queue[i]],queue[j],checkVert[0],checkVert[1],checkVert[2],e->node[2*e->tri2edg[3*queue[j]+0]+0],e->node[2*e->tri2edg[3*queue[j]+0]+1],e->node[2*e->tri2edg[3*queue[j]+1]+0],e->node[2*e->tri2edg[3*queue[j]+1]+1],e->node[2*e->tri2edg[3*queue[j]+2]+0],e->node[2*e->tri2edg[3*queue[j]+2]+1],flag[queue[j]]); - uint64_t temp = m->triangles.node[3*queue[j]+0]; - m->triangles.node[3*queue[j]+0] = m->triangles.node[3*queue[j]+1]; - m->triangles.node[3*queue[j]+1] = temp; - uint32_t te = e->tri2edg[3*queue[j]+1]; - e->tri2edg[3*queue[j]+1] = e->tri2edg[3*queue[j]+2]; - e->tri2edg[3*queue[j]+2] = te; - - printf("Consistent (?) orientation \t %lu (%u %u %u) ; (%u %u)-(%u %u)-(%u %u) [%d] ~ %lu (%u %u %u) ; (%u %u)-(%u %u)-(%u %u) [%d].\n",queue[i],refVert[0],refVert[1],refVert[2],e->node[2*e->tri2edg[3*queue[i]+0]+0],e->node[2*e->tri2edg[3*queue[i]+0]+1],e->node[2*e->tri2edg[3*queue[i]+1]+0],e->node[2*e->tri2edg[3*queue[i]+1]+1],e->node[2*e->tri2edg[3*queue[i]+2]+0],e->node[2*e->tri2edg[3*queue[i]+2]+1],flag[queue[i]],queue[j],checkVert[0],checkVert[1],checkVert[2],e->node[2*e->tri2edg[3*queue[j]+0]+0],e->node[2*e->tri2edg[3*queue[j]+0]+1],e->node[2*e->tri2edg[3*queue[j]+1]+0],e->node[2*e->tri2edg[3*queue[j]+1]+1],e->node[2*e->tri2edg[3*queue[j]+2]+0],e->node[2*e->tri2edg[3*queue[j]+2]+1],flag[queue[j]]); - - }//end if cond==0 - }//end for j - }//end for i - - if (partitions!=NULL) - HXT_CHECK(hxtPartitioning(e,(int*)flag,count,partitions)); - - return HXT_STATUS_OK; -} - - -static HXTStatus hxtSplitEdges(HXTEdges *edges,int nPartitions,HXTVector *partitions) -{ - - HXTMesh *mesh = edges->edg2mesh; - - uint32_t *tri2edg = edges->tri2edg; - uint64_t *edg2tri = edges->edg2tri; - - HXTBoundaries *boundaries; - HXT_CHECK(hxtEdgesSetBoundaries(edges, &boundaries)); - int nbedg; - HXT_CHECK(hxtBoundariesGetNumberOfBorderEdges(boundaries,&nbedg)); - - int nVertex = (int) mesh->triangles.num; - int nEdge = (int) (edges->numEdges) - nbedg; - - int *idx=NULL; - HXT_CHECK(hxtMalloc(&idx,(nVertex+1)*sizeof(int))); - int *nbh=NULL; - HXT_CHECK(hxtMalloc(&nbh, 2*nEdge*sizeof(int))); - int *weights=NULL; - HXT_CHECK(hxtMalloc(&weights,2*nEdge*sizeof(int))); - - idx[0] = 0; - for(int i=0; i<nVertex; i++){// triangle by triangle - uint32_t *current = &tri2edg[3*i]; - int temp = 0; - for(int j=0; j<3; j++){ - uint64_t *local = &edg2tri[2*current[j]]; - if(local[1]==(uint64_t)-1) - continue; - else{ - nbh[idx[i]+temp] = i == (int) local[0] ? (int) local[1] : (int) local[0]; - weights[idx[i]+temp] = (int) (hxtEdgesLength(edges,current[j])+1); - temp++; - } - } - - idx[i+1] = idx[i] + temp; - } - - - // only for k-way - idx_t options[METIS_NOPTIONS]; - METIS_SetDefaultOptions(options); - options[METIS_OPTION_NCUTS] = nPartitions; - //options[METIS_OPTION_MINCONN] = 1; - //options[METIS_OPTION_CCORDER] = 1; - options[METIS_OPTION_CONTIG] = 1; - //options[METIS_OPTION_DBGLVL] = 1; - - int edgeCut; - int *part; - HXT_CHECK(hxtMalloc(&part,nVertex*sizeof(int))); - //int zero = 0; - int one=1; - //METIS_PartGraphRecursive(&nVertex,&one,idx,nbh,NULL,NULL,NULL,&nPartitions,NULL,NULL,NULL,&edgeCut,part); - METIS_PartGraphKway(&nVertex,&one,idx,nbh,NULL,NULL,weights,&nPartitions,NULL,NULL,options,&edgeCut,part); - - HXT_CHECK(hxtFree(&nbh)); - HXT_CHECK(hxtFree(&idx)); - - HXT_CHECK(hxtPartitioning(edges,part,nPartitions,partitions)); - - return HXT_STATUS_OK; -} - -static HXTStatus hxtCuttingProcess(HXTEdges *edges, int ar, int bool, HXTVector *toparam) -{ - HXTBoundaries *boundaries; - HXT_CHECK(hxtEdgesSetBoundaries(edges, &boundaries)); - int nll, seamPoint; - HXT_CHECK(hxtBoundariesGetNumberOfLineLoops(boundaries,&nll)); - int g = (edges->numEdges - edges->edg2mesh->vertices.num - edges->edg2mesh->triangles.num + 2 - nll)/2; - HXT_CHECK(hxtBoundariesGetSeamPoint(boundaries,&seamPoint)); - - HXTVector *toSplit; - HXT_CHECK(hxtVectorInit(&toSplit)); - if(seamPoint!=0 || ar==0 || g!=0 || nll == 0) - HXT_CHECK(hxtVectorPushBack(toSplit,edges)); - else - HXT_CHECK(hxtVectorPushBack(toparam,edges)); - for(int i=0; i<toSplit->last+1; i++){ - HXTVector *split=NULL; - HXT_CHECK(hxtVectorInit(&split)); - HXTEdges *beingSplitted = (HXTEdges*) toSplit->ptr[i]; - HXT_CHECK(hxtSplitEdges(beingSplitted,2,split)); - if(bool>0){ - HXT_CHECK(hxtMeshDelete(&beingSplitted->edg2mesh)); - HXT_CHECK(hxtEdgesDelete(&beingSplitted)); - } - else - bool=1; - for(int j=0; j<split->last+1; j++){ - HXTEdges* piece = (HXTEdges*) split->ptr[j]; - HXT_CHECK(hxtEdgesSetBoundaries(piece, &boundaries)); - HXT_CHECK(hxtBoundariesGetNumberOfLineLoops(boundaries,&nll)); - g = (piece->numEdges - piece->edg2mesh->vertices.num - piece->edg2mesh->triangles.num + 2 - nll)/2; - HXT_CHECK(hxtBoundariesGetSeamPoint(boundaries,&seamPoint)); - if(seamPoint !=0 || g != 0 || nll == 0){ - //printf("nl=%d\t g=%d\n",nll,g); - HXT_CHECK(hxtVectorPushBack(toSplit,piece)); - } - else - HXT_CHECK(hxtVectorPushBack(toparam,piece)); - } - HXT_CHECK(hxtVectorFree(&split)); - } - HXT_CHECK(hxtVectorFree(&toSplit)); - // free boundaries - - return HXT_STATUS_OK; -} - -HXTStatus hxtParametrizationCreate(HXTMesh *mesh, int nrefinements, HXTParametrization **parametrization) -{ - HXTParametrization* param0; - HXT_CHECK(hxtMalloc(¶m0,sizeof(HXTParametrization))); - *parametrization = param0; - - HXTMesh *initialMesh=NULL; - HXT_CHECK(hxtMeshCreate(mesh->ctx,&initialMesh)); - *initialMesh = *mesh; - HXT_CHECK(hxtEdgesCreate(initialMesh, ¶m0->edges)); - - // printf("checking connectivity ...\n"); - HXT_CHECK(hxtCheckConnectivity(param0->edges,NULL)); - // HXT_CHECK(hxtLongestEdgeBisection(param0->edges,nrefinements)); - - HXTEdges *edges=NULL; - HXT_CHECK(hxtEdgesCreate(initialMesh, &edges)); - uint64_t *global; - HXT_CHECK(hxtMalloc(&global,edges->edg2mesh->triangles.num*sizeof(uint64_t))); - for(uint64_t i=0; i<edges->edg2mesh->triangles.num; i++) - global[i]= i; - edges->global = global; - param0->edges->global = global; - - HXTVector *connect; - HXT_CHECK(hxtVectorInit(&connect)); - HXT_CHECK(hxtCheckConnectivity(edges,connect)); - - // printf("connectivity is done\n"); - - HXTVector *toparam; - HXT_CHECK(hxtVectorInit(&toparam)); - for(int i=0; i<connect->last+1; i++){ - HXT_CHECK(hxtCuttingProcess(connect->ptr[i],1,0,toparam)); - } - //printf("initial cutting process is done, %d\n", param0->n); - // return HXT_STATUS_OK; - - - HXTVector *atlas; - HXT_CHECK(hxtVectorInit(&atlas)); - for(int i=0; i<toparam->last+1; i++){ - HXTMeanValues *param; - HXTEdges *current = (HXTEdges *)(toparam->ptr[i]); - HXT_CHECK(hxtMeanValuesCreate(current,¶m)); - HXT_CHECK(hxtMeanValuesCompute(param)); - int ar = 0; - HXT_CHECK(hxtMeanValueAspectRatio(param,&ar)); - - if (0 && ar==0) - HXT_CHECK(hxtCuttingProcess(current,ar,toparam->last,toparam)); - else - HXT_CHECK(hxtVectorPushBack(atlas,param)); - } - hxtVectorFree(&toparam); - - param0->n = atlas->last+1; - HXT_CHECK(hxtMalloc(¶m0->maps,param0->n*sizeof(HXTMeanValues*))); - for(int i=0; i<param0->n; i++) - param0->maps[i] = (HXTMeanValues *) atlas->ptr[i]; - - HXT_CHECK(hxtVectorFree(&atlas)); - return HXT_STATUS_OK; -} - - - -HXTStatus hxtParametrizationDelete(HXTParametrization **parametrization) -{ - - return HXT_STATUS_OK; -} - -HXTStatus hxtParametrizationCompute(HXTParametrization *parametrization, int **_colors_, int **_nNodes_, int **_nodes_, double **_uv_, int *nc, HXTMesh **m) -{ - - int *colors=NULL, *nNodes=NULL, *nodes=NULL; - double *uv=NULL; - - *m = parametrization->edges->edg2mesh; - int Ncolors = parametrization->n; - *nc=Ncolors; - int totalNtriangles = (int) parametrization->edges->edg2mesh->triangles.num; - HXT_CHECK(hxtMalloc(&colors,totalNtriangles*sizeof(int))); - HXT_CHECK(hxtMalloc(&nNodes,(Ncolors+1)*sizeof(int))); - nNodes[0] = 0; - for(int c=0; c<Ncolors; c++){ - - uint64_t *global=NULL; - int nv, ne; - HXT_CHECK(hxtMeanValuesGetData(parametrization->maps[c],&global, NULL, NULL, &nv,&ne,0)); - nNodes[c+1] = nNodes[c]+nv; - - for(int ie=0; ie<ne; ie++) - colors[global[ie]] = c; - - HXT_CHECK(hxtFree(&global)); - - } - - - HXT_CHECK(hxtMalloc(&uv,2*nNodes[Ncolors]*sizeof(double)));// - HXT_CHECK(hxtMalloc(&nodes,nNodes[Ncolors]*sizeof(int))); - for(int it=0; it<nNodes[Ncolors]; it++) - nodes[it] = -1; - - for(int c=0; c<Ncolors; c++){ - - uint64_t *global=NULL; - uint32_t *gn=NULL; - double *uvc=NULL; - int nv, ne; - HXT_CHECK(hxtMeanValuesGetData(parametrization->maps[c],&global, &gn, &uvc, &nv,&ne,0)); - for(int iv=0; iv<2*nv; iv++) - uv[2*nNodes[c]+iv] = uvc[iv]; - - for(int ie=0; ie<ne; ie++){ - for(int kk=0; kk<3; kk++){ - int gvn = (int) parametrization->edges->edg2mesh->triangles.node[3*global[ie]+kk]; - nodes[nNodes[c]+gn[3*ie+kk]] = gvn; - } - } - - HXT_CHECK(hxtFree(&global)); - HXT_CHECK(hxtFree(&gn)); - HXT_CHECK(hxtFree(&uvc)); - } - - - *_colors_=colors; - *_nNodes_=nNodes; - *_nodes_=nodes; - *_uv_=uv; - - return HXT_STATUS_OK; -} - -HXTStatus hxtParametrizationWrite(HXTParametrization *parametrization, const char *filename) -{ - - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/hxt_parametrization.h b/contrib/hxt/hxt_parametrization.h deleted file mode 100644 index 3943041aad..0000000000 --- a/contrib/hxt/hxt_parametrization.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HEXTREME_PARAMETRIZATION_H -#define HEXTREME_PARAMETRIZATION_H - -#include "hxt_tools.h" -#include "hxt_mesh.h" -#include "hxt_edge.h" - -typedef struct HXTVectorStruct HXTVector; -typedef struct HXTParametrizationStruct HXTParametrization; - -HXTStatus hxtParametrizationCreate(HXTMesh *mesh, int nrefinements, HXTParametrization **parametrization); -HXTStatus hxtParametrizationDelete(HXTParametrization **parametrization); -HXTStatus hxtParametrizationCompute(HXTParametrization *parametrization, int **colors, int **nNodes, int **nodes, double **uv, int*nc, HXTMesh **m); -HXTStatus hxtParametrizationWrite(HXTParametrization *parametrization, const char *filename); - - -#endif diff --git a/contrib/hxt/hxt_tetOpti.c b/contrib/hxt/hxt_tetOpti.c deleted file mode 100644 index 95bd189515..0000000000 --- a/contrib/hxt/hxt_tetOpti.c +++ /dev/null @@ -1,819 +0,0 @@ -#include "hxt_tetOpti.h" -#include "hxt_tetFlag.h" -#include "hxt_edgeRemoval.h" -#include "hxt_smoothing.h" -#include "hxt_sort.h" -#include "HXTSPR.h" -#include "hxt_tetRepair.h" -#include "hxt_tetOptiDate.h" - -#define SMALLEST_ROUND 1024 - -/************************************************************************** - Thread-shared structure - **************************************************************************/ -typedef struct { - struct { - HXTGroup2* array; - uint64_t num; - uint64_t size; - } badTets; - - HXTTetDates date; - HXTTetQualities quality; - HXT2Sync toSync; - - int numThreads; - uint32_t seed; -} ThreadShared; - - -/* Statistics about the mesh improvement. - * Attempts and conflicts are per operation, so for smoothing and - * edge-removal, there can be up to 6 E-R attempts and 4 Smoothing attempts - * = 10 attempts (and maybe also conflict) per bad tetrahedra. - * Success and failure are per bad tet. - * Note that the number of `bad tet != failure + success` - * because some bad tet gets eliminated by operations on other bad tets. - * Also, some tets might cross partition boundary, in which case conflict - * is guaranteed, therefore no operation are attempted and the tet does not - * count in either success or failure */ -typedef struct { - uint64_t attempt; - uint64_t conflict; - uint64_t success; // cavity was modified, but there may still be a bad tet. - uint64_t failure; -} Statistic; - - -typedef struct -{ - // cavity for edge removal is a bipyramid - HXTEdgeRemovalData* edgeRemoval; - HXTSmoothingData* smoothing; - HXTSPRData* SPR; - - // list of deleted tet. Added when the cavity is created, removed when the cavity is filled - HXTDeleted deleted; - HXTPartition partition; - Statistic stat; -} ThreadLocal; - - -static void qualitySetDeleted(void** qualityArray_ptr, uint64_t a, uint64_t b) -{ - double* qualityArray = *qualityArray_ptr; - - for (uint64_t i=a; i<b; i++) { - qualityArray[i] = DBL_MAX; - } -} - - - -/************************************************************************** - create/update/delete shared structure, containing list of bad tetrahedra - **************************************************************************/ - -// suppose that the right capacity for quality values is already allocated -static HXTStatus threadShared_update(HXTMesh* mesh, ThreadShared* shared) { - int maxThreads = omp_get_max_threads(); - HXTStatus status = HXT_STATUS_OK; - - uint64_t* badTetsCount; - HXT_CHECK( hxtMalloc(&badTetsCount, maxThreads*sizeof(uint64_t)) ); - -#ifndef __SANITIZE_ADDRESS__ // this portion does not seem to work with the address sanitizer of GCC 8 with OpenMP - #pragma omp parallel -#endif - { - int threadID = omp_get_thread_num(); - badTetsCount[threadID] = 0; - - #pragma omp for schedule(static) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(!getProcessedFlag(mesh, i) && !getDeletedFlag(mesh, i) && shared->quality.values[i]<shared->quality.threshold) - badTetsCount[threadID]++; - } - - #pragma omp barrier - #pragma omp single - { - int nthreads = omp_get_num_threads(); - shared->badTets.num = 0; - for (int i=0; i<nthreads; i++) { - uint64_t tsum = badTetsCount[i] + shared->badTets.num; - badTetsCount[i] = shared->badTets.num; - shared->badTets.num = tsum; - } - - if(shared->badTets.num > shared->badTets.size) { - hxtAlignedFree(&shared->badTets.array); - hxtAlignedMalloc(&shared->badTets.array, sizeof(HXTGroup2)*shared->badTets.num); - shared->badTets.size = shared->badTets.num; - } - } - - if(status==HXT_STATUS_OK){ - #pragma omp for schedule(static) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(!getProcessedFlag(mesh, i) && !getDeletedFlag(mesh, i) && shared->quality.values[i]<shared->quality.threshold){ - uint64_t badTetsID = badTetsCount[threadID]++; - shared->badTets.array[badTetsID].v[1] = i; - } - } - } - } - HXT_CHECK( hxtFree(&badTetsCount) ); - - shared->toSync.threadFinished = 0; - - return status; -} - -static HXTStatus threadShared_create(HXTMesh *mesh, - HXTOptimizeOptions* options, - ThreadShared** shared) { - ThreadShared* newShared; - HXT_CHECK( hxtMalloc(&newShared, sizeof(ThreadShared))); - newShared->numThreads = options->numThreads; - - if(options->qualityMin<0.0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "quality threshold must be positive"); - - newShared->badTets.array = NULL; - newShared->badTets.size = 0; - newShared->badTets.num = 0; - newShared->quality.function = options->qualityFun ? options->qualityFun : hxtTetAspectRatio; - newShared->quality.threshold = options->qualityMin; - newShared->quality.userData = options->qualityData; - HXT_CHECK( hxtAlignedMalloc(&newShared->quality.values, sizeof(double)*mesh->tetrahedra.size) ); - - newShared->date.current = 0; - HXT_CHECK( hxtAlignedMalloc(&newShared->date.values, sizeof(HXTTetDate)*mesh->tetrahedra.size) ); - - newShared->toSync = (HXT2Sync) {.mesh = mesh, - .allocMore = 0, - .otherArrays = {(void*) &newShared->quality.values, - (void*) &newShared->date.values, NULL, NULL}, - .otherArraysElementSize = {sizeof(double), sizeof(HXTTetDate), 0, 0}, - .otherArraysSetDeleted = {qualitySetDeleted, NULL, NULL, NULL}, - .threadFinished = 0}; - - #pragma omp parallel for - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - newShared->date.values[i] = (HXTTetDate) {0}; - - if(getProcessedFlag(mesh, i)) - newShared->quality.values[i] = DBL_MAX; // exterior tetrahedra have maximum quality - else { - uint32_t* nodes = mesh->tetrahedra.node + 4*i; -// #ifndef NDEBUG - if(nodes[3]==HXT_GHOST_VERTEX){ - exit( HXT_ERROR_MSG(HXT_STATUS_ERROR, "ghost tetrahedra should have been set to processed") ); - } -// #endif - newShared->quality.values[i] = tetQuality(mesh, &newShared->quality, nodes[0], nodes[1], nodes[2], nodes[3]); - } - } - - *shared = newShared; - return HXT_STATUS_OK; -} - -static HXTStatus threadShared_destroy(ThreadShared** shared) { - HXT_CHECK( hxtAlignedFree(&(*shared)->quality.values) ); - HXT_CHECK( hxtAlignedFree(&(*shared)->date.values) ); - HXT_CHECK( hxtAlignedFree(&(*shared)->badTets.array)); - HXT_CHECK( hxtFree(shared) ); - return HXT_STATUS_OK; -} - - - -/************************************************************************** - create/update/delete local structure, containing partitions definition - **************************************************************************/ - -static HXTStatus threadLocals_create(ThreadLocal** locals_ptr, HXTOptimizeOptions* options) { - int nthreads = options->numThreads; - ThreadLocal* newLocal; - HXT_CHECK( hxtMalloc(&newLocal, nthreads*sizeof(ThreadLocal))); - - for (int threadID=0; threadID<nthreads; threadID++) { - HXT_CHECK( hxtAlignedMalloc(&newLocal[threadID].deleted.array, sizeof(uint64_t)*DELETED_BUFFER_SIZE) ); - newLocal[threadID].deleted.size = DELETED_BUFFER_SIZE; - newLocal[threadID].deleted.num = 0; - } - - *locals_ptr = newLocal; - return HXT_STATUS_OK; -} - - -static inline HXTStatus EdgeRemovalStructs_create(ThreadLocal* locals, ThreadShared* shared, int nThreads) { - for (int threadID=0; threadID<nThreads; threadID++) { - HXT_CHECK( hxtMalloc(&locals[threadID].edgeRemoval, sizeof(HXTEdgeRemovalData)) ); - locals[threadID].edgeRemoval->deleted = &locals[threadID].deleted; - locals[threadID].edgeRemoval->partition = &locals[threadID].partition; - locals[threadID].edgeRemoval->quality = &shared->quality; - locals[threadID].edgeRemoval->date = &shared->date; - locals[threadID].edgeRemoval->toSync = &shared->toSync; - } - return HXT_STATUS_OK; -} - - -static inline HXTStatus EdgeRemovalStructs_destroy(ThreadLocal* locals, int nThreads) { - for (int threadID=0; threadID<nThreads; threadID++) { - HXT_CHECK( hxtFree(&locals[threadID].edgeRemoval) ); - } - return HXT_STATUS_OK; -} - - -static inline HXTStatus SmoothingStructs_create(ThreadLocal* locals, ThreadShared* shared, - int nThreads, uint32_t numVerticesConstrained) { - for (int threadID=0; threadID<nThreads; threadID++) { - HXT_CHECK( hxtMalloc(&locals[threadID].smoothing, sizeof(HXTSmoothingData)) ); - locals[threadID].smoothing->mesh = shared->toSync.mesh; - locals[threadID].smoothing->deleted = &locals[threadID].deleted; - locals[threadID].smoothing->partition = &locals[threadID].partition; - locals[threadID].smoothing->quality = &shared->quality; - locals[threadID].smoothing->date = &shared->date; - locals[threadID].smoothing->numVerticesConstrained = numVerticesConstrained; - } - return HXT_STATUS_OK; -} - - -static inline HXTStatus SmoothingStructs_destroy(ThreadLocal* locals, int nThreads) { - for (int threadID=0; threadID<nThreads; threadID++) { - HXT_CHECK( hxtFree(&locals[threadID].smoothing) ); - } - return HXT_STATUS_OK; -} - -// TODO: use a HHXTTetQualities in SPR... -static inline HXTStatus SPRStructs_create(ThreadLocal* locals, ThreadShared* shared, - int nThreads) { - for (int threadID=0; threadID<nThreads; threadID++) { - HXT_CHECK( hxtMalloc(&locals[threadID].SPR, sizeof(HXTSPRData)) ); - locals[threadID].SPR->quality = &shared->quality; - locals[threadID].SPR->date = &shared->date; - locals[threadID].SPR->dateOfLastCheck = 0; - locals[threadID].SPR->dateOfLastCreation = 0; - locals[threadID].SPR->maxSearchNodes = 500; - locals[threadID].SPR->deleted = &locals[threadID].deleted; - locals[threadID].SPR->toSync = &shared->toSync; - locals[threadID].SPR->partition = &locals[threadID].partition; - } - return HXT_STATUS_OK; -} - - -static inline HXTStatus SPRStructs_destroy(ThreadLocal* locals, HXTOptimizeOptions* options) { - int nthreads = options->numThreads; - for (int threadID=0; threadID<nthreads; threadID++) { - HXT_CHECK( hxtFree(&locals[threadID].SPR) ); - } - return HXT_STATUS_OK; -} - -static Statistic threadLocals_collectStats(ThreadLocal* locals, int nThreads) { - // check the stat to see if we keep the same number of threads and if we move partitions - Statistic stat = {0,0,0,0}; - - for (int threadID=0; threadID<nThreads; threadID++) - { - stat.attempt += locals[threadID].stat.attempt; - stat.conflict += locals[threadID].stat.conflict; - stat.success += locals[threadID].stat.success; - stat.failure += locals[threadID].stat.failure; - } - return stat; -} - -// this -static HXTStatus threadLocals_update(HXTMesh* mesh, HXTBbox* bbox, - ThreadShared* shared, ThreadLocal* locals, - uint32_t* seed, int changePartitions) { - - // initialize statistics - for (int threadID=0; threadID<shared->numThreads; threadID++) { - locals[threadID].stat = (Statistic) {0}; - } - - if(shared->numThreads>1) { - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - HXTGroup2* badTets = shared->badTets.array; - - double indexShift = (double) hxtReproducibleLCG(seed)/RAND_MAX; - - if(changePartitions) { - double hxtDeclareAligned bboxShift[3]; - - bboxShift[0] = (double) hxtReproducibleLCG(seed)/RAND_MAX; - bboxShift[1] = (double) hxtReproducibleLCG(seed)/RAND_MAX; - bboxShift[2] = (double) hxtReproducibleLCG(seed)/RAND_MAX; - - HXT_CHECK( hxtMoore(bbox, vertices, mesh->vertices.num, bboxShift) ); - } - - #pragma omp parallel for simd aligned(badTets:SIMD_ALIGN) - for (uint64_t i=0; i<shared->badTets.num; i++) { - uint32_t firstNode = mesh->tetrahedra.node[4*badTets[i].v[1]]; - badTets[i].v[0] = vertices[firstNode].padding.hilbertDist; - } - - // sort the bad tetrahedrons following their first node hilbert dist - HXT_CHECK( group2_sort_v0(badTets, shared->badTets.num, (UINT64_C(1)<<63) - 1) ); - - if(badTets[0].v[0]==badTets[shared->badTets.num-1].v[0]) { - // only one partition possible, everything is in the same cell ! - shared->numThreads = 1; - locals[0].partition.startDist = 0; - locals[0].partition.lengthDist = UINT64_MAX; - locals[0].partition.firstElem = 0; - locals[0].partition.numElem = shared->badTets.num; - return HXT_STATUS_OK; - } - - const double step = shared->badTets.num/shared->numThreads; - - #pragma omp parallel num_threads(shared->numThreads) - { - const int threadID = omp_get_thread_num(); - - uint64_t first = MIN((uint64_t) step*(threadID+1)-1, (uint64_t) (step*(threadID + indexShift))); - uint64_t startDist = badTets[first].v[0]; - - uint64_t up = 1; - while(first+up<shared->badTets.num && startDist==badTets[first + up].v[0]) - up++; - - first = first+up==shared->badTets.num?0:first+up; - if(first > 0) - startDist = (badTets[first].v[0] + badTets[first - 1].v[0] + 1)/2; - else - startDist = badTets[shared->badTets.num-1].v[0] + - (badTets[first].v[0] - badTets[shared->badTets.num - 1].v[0])/2; - - locals[threadID].partition.firstElem = first; - locals[threadID].partition.startDist = startDist; - - #pragma omp barrier - - uint64_t firstNext = locals[(threadID+1)%shared->numThreads].partition.firstElem; - uint64_t endDist = locals[(threadID+1)%shared->numThreads].partition.startDist; - locals[threadID].partition.numElem = (firstNext + shared->badTets.num - first)%shared->badTets.num; - locals[threadID].partition.lengthDist = endDist - startDist; - - uint64_t rel = endDist - startDist; - - // dismiss tetrahedron that are in our list but not in our partition - for (uint64_t i=0; i<locals[threadID].partition.numElem; i++) { - uint64_t index = (locals[threadID].partition.firstElem + i)%shared->badTets.num; - uint64_t curTet = shared->badTets.array[index].v[1]; - - uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; - - if(vertexOutOfPartition(vertices, nodes[0], rel, startDist) + - vertexOutOfPartition(vertices, nodes[1], rel, startDist) + - vertexOutOfPartition(vertices, nodes[2], rel, startDist) + - vertexOutOfPartition(vertices, nodes[3], rel, startDist) > 1) { - shared->badTets.array[index].v[1] = HXT_NO_ADJACENT; - locals[threadID].stat.attempt++; - locals[threadID].stat.conflict++; - } - } - } - } - else { - // TODO: when there is only one thread, we could sort bad tetrahedra from worst to best... - locals[0].partition.startDist = 0; - locals[0].partition.lengthDist = UINT64_MAX; - locals[0].partition.firstElem = 0; - locals[0].partition.numElem = shared->badTets.num; - } - - return HXT_STATUS_OK; -} - - -static HXTStatus threadLocals_destroy(ThreadLocal** local, int nthreads) { - for (int threadID=0; threadID<nthreads; threadID++) { - HXT_CHECK( hxtAlignedFree(&(*local)[threadID].deleted.array) ); - } - - HXT_CHECK( hxtFree(local) ); - return HXT_STATUS_OK; -} - - -/* once the SPR is done, the current date should be changed to the date of the lastCheck */ -static void SPRDates_update(ThreadShared* shared, ThreadLocal* locals) -{ - uint16_t lastCheck = 0; - for(int threadID=0; threadID<shared->numThreads; threadID++) { - if(locals[threadID].SPR->dateOfLastCheck > lastCheck) - lastCheck = locals[threadID].SPR->dateOfLastCheck; - } - - shared->date.current = lastCheck; - - for(int threadID=0; threadID<shared->numThreads; threadID++) { - locals[threadID].SPR->dateOfLastCheck = lastCheck; - locals[threadID].SPR->dateOfLastCreation = lastCheck; - } -} - - -static double meanQuality(HXTMesh* mesh, double* quality) { - double mean = 0; - uint64_t ntet = 0; - #pragma omp parallel for reduction(+:mean,ntet) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(quality[i]!=DBL_MAX){ - ntet++; - mean += quality[i]; - } - } - mean/=ntet; - return mean; -} - - -static double minQuality(HXTMesh* mesh, double* quality) { - double min = DBL_MAX; - - #pragma omp parallel for reduction(min:min) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(quality[i]!=DBL_MAX) - min = fmin(quality[i], min); - } - - return min; -} - - -static uint64_t badTetrahedra(HXTMesh* mesh, double* quality, double threshold) { - uint64_t count = 0; - - #pragma omp parallel for reduction(+:count) - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { - if(quality[i]<threshold) - count++; - } - return count; -} - - -// TODO: some thing are seriously wrongly done -static inline void stage0_heuristic(Statistic stage0, Statistic stage1, uint64_t numBad, - int* numThreads, int* changePartitions) { - if(numBad < (uint64_t) *numThreads*16) { - *numThreads = MAX(1, numBad/16); - // *changePartitions = 1; - } - - if(stage0.attempt==0) // first time, we just return - return; - - // too much conflict - if(stage0.conflict>=stage0.attempt){ - // puts("too much conflict"); - *numThreads = 1; - return; - } - - // not enough success - if(stage0.conflict > 10*stage0.success) { - // int n = stage0.conflict / (10*stage0.success+1); - // puts("not enough success"); - *numThreads = (*numThreads+1)/2; - // *changePartitions = 1; - } - - if(*numThreads>1) - *changePartitions = 1; - - HXT_UNUSED(stage1); -} - - -static inline int continue_stage0(Statistic stage0, Statistic stage1) { - HXT_UNUSED(stage1); - - return stage0.success>16 || stage0.conflict; -} - - -static inline void stage1_heuristic(Statistic stage0, Statistic stage1, uint64_t numBad, - int* numThreads) { - if(numBad < (uint64_t) *numThreads*2) { - *numThreads = MAX(1, numBad/2); - } - - if(stage1.attempt==0) // first time, we just return - return; - - if(stage1.attempt > 32*stage1.success) { - *numThreads = (*numThreads+1)/2; - } - - HXT_UNUSED(stage0); -} - - -static inline int continue_stage1(Statistic stage1) { - return stage1.success || stage1.conflict; -} - - -/************************************************************************** -*************************************************************************** - - main function, optimizes a mesh - - ************************************************************************** - **************************************************************************/ - -HXTStatus hxtOptimizeTetrahedra(HXTMesh *mesh, - HXTOptimizeOptions* options){ - ThreadLocal* locals = NULL; - ThreadShared* shared = NULL; - volatile HXTStatus globalStatus = HXT_STATUS_OK; - uint32_t seed = 1; - - if(options->numThreads<0) - options->numThreads = omp_get_num_procs(); - else if(options->numThreads==0) - options->numThreads = omp_get_max_threads(); - - HXTBbox bbox; - if(options->bbox==NULL) { - hxtBboxAdd(&bbox, mesh->vertices.coord, mesh->vertices.num); - } - else { - bbox = *options->bbox; - } - - HXT_CHECK( threadShared_create(mesh, options, &shared) ); - HXT_CHECK( threadLocals_create(&locals, options) ); - HXT_CHECK( EdgeRemovalStructs_create(locals, shared, options->numThreads)); - HXT_CHECK( SmoothingStructs_create(locals, shared, options->numThreads, options->numVerticesConstrained)); - HXT_CHECK( SPRStructs_create(locals, shared, options->numThreads) ); - - int iter = 0; - int SPRnumThreads = options->numThreads; - Statistic stage0; - Statistic stage1 = {0}; - - do { - HXT_INFO_COND(options->verbosity>0, - "Optimization stage %u.0: smoothing and edge removal", iter); - - int changePartitions = 1; - shared->numThreads = options->numThreads; - stage0 = (Statistic) {0}; - - do { - // double time00 = omp_get_wtime(); - // create a list of bad tets - HXT_CHECK( threadShared_update(mesh, shared) ); - if(shared->badTets.num==0) - break; - - stage0_heuristic(stage0, stage1, shared->badTets.num, &shared->numThreads, &changePartitions); - - // create partitions - HXT_CHECK( threadLocals_update(mesh, &bbox, shared, locals, &seed, changePartitions) ); - - HXT_INFO_COND(options->verbosity>0, " " - HXTu64 " bad tetrahedra being optimized on %d threads", - shared->badTets.num, shared->numThreads); - - #pragma omp parallel num_threads(shared->numThreads) - { - const int threadID = omp_get_thread_num(); - ThreadLocal* local = locals + threadID; - - for (uint64_t i=0; i<local->partition.numElem && globalStatus==HXT_STATUS_OK; i++) { - uint64_t index = (local->partition.firstElem + i)%shared->badTets.num; - uint64_t curTet = shared->badTets.array[index].v[1]; - - if(curTet==HXT_NO_ADJACENT || shared->quality.values[curTet]>= shared->quality.threshold) - continue; - - HXTStatus status=HXT_STATUS_OK; - for (int edge=0; edge<6; edge++) { - unsigned facet0, facet1; - getFacetsFromEdge(edge, &facet0, &facet1); - - local->stat.attempt++; - status = hxtEdgeRemoval_opti(local->edgeRemoval, curTet, edge); - if(status==HXT_STATUS_CONFLICT) - local->stat.conflict++; - else if(status==HXT_STATUS_OK){ - local->stat.success++; - break; - } - else if(status>HXT_STATUS_INTERNAL) { - // fatal error - break; - } - } - - /*** make a swap whenever it is possible and it is an improvement ***/ - if(status<=HXT_STATUS_INTERNAL) { - for (int vertex=0; vertex<4; vertex++) { - local->stat.attempt++; - status = hxtSmoothing(local->smoothing, 4*curTet+vertex); - if(status==HXT_STATUS_CONFLICT) - local->stat.conflict++; - else if(status==HXT_STATUS_OK) { - local->stat.success++; - break; - } - else if(status>HXT_STATUS_INTERNAL) { - // fatal error - break; - } - } - } - - if(status<=HXT_STATUS_INTERNAL) { // the cavity could not be modified - local->stat.failure++; - continue; - } - else if(status!=HXT_STATUS_OK) { - #pragma omp atomic write - globalStatus = status; - break; - } - } - - HXTStatus status = waitForPossibleReallocation(&shared->toSync, shared->numThreads); - if(status!=HXT_STATUS_OK) { - #pragma omp atomic write - globalStatus = status; - } - } - - if(globalStatus!=HXT_STATUS_OK){ - HXT_TRACE(globalStatus); - return globalStatus; - } - - stage0 = threadLocals_collectStats(locals, shared->numThreads); - HXT_INFO_COND(options->verbosity>1, " " - HXTu64 " attempts, " HXTu64 " modifications, " HXTu64 " conflict, " HXTu64 " failures", - stage0.attempt, stage0.success, stage0.conflict, stage0.failure); - // double time01 = omp_get_wtime(); - // printf("Smoothing & ER took %f s/tet, %f modif/tet, %f conflict/attempt\n", - // (time01 - time00)/(stage0.success + stage0.failure), - // (double) stage0.success/(stage0.success + stage0.failure), - // (double) stage0.conflict/stage0.attempt); - } while(continue_stage0(stage0, stage1)); - - // if we exited previous loop, we need to exit this one again - if(shared->badTets.num==0) - break; - - // Now, one pass of SPR - HXT_INFO_COND(options->verbosity>0, - "Optimization stage %u.1: small polyhedron reconnection", iter); - - // double time1 = omp_get_wtime(); - - // create a list of bad tets - HXT_CHECK( threadShared_update(mesh, shared) ); - if(shared->badTets.num==0) - break; - - stage1_heuristic(stage0, stage1, shared->badTets.num, &SPRnumThreads); - shared->numThreads = SPRnumThreads; - changePartitions = 1; - - // create partitions - HXT_CHECK( threadLocals_update(mesh, &bbox, shared, locals, &seed, changePartitions) ); - - HXT_INFO_COND(options->verbosity>0, " " - HXTu64 " bad tetrahedra being optimized on %d threads", - shared->badTets.num, shared->numThreads); - - #pragma omp parallel num_threads(shared->numThreads) - { - const int threadID = omp_get_thread_num(); - ThreadLocal* local = locals + threadID; - - for (uint64_t i=0; i<local->partition.numElem && globalStatus==HXT_STATUS_OK; i++) { - uint64_t index = (local->partition.firstElem + i)%shared->badTets.num; - uint64_t curTet = shared->badTets.array[index].v[1]; - - if(curTet==HXT_NO_ADJACENT || shared->quality.values[curTet]>= shared->quality.threshold) - continue; - - local->stat.attempt++; - - HXTStatus status = hxtSPR_opti(local->SPR, curTet); - - if(status==HXT_STATUS_CONFLICT){ - local->stat.conflict++; - local->stat.failure++; - } - else if(status==HXT_STATUS_OK) - local->stat.success++; - else if(status==HXT_STATUS_INTERNAL) - local->stat.failure++; - else { - // fatal error - #pragma omp atomic write - globalStatus = status; - break; - } - - // // complete verification - // for (int threadID=0; threadID<options->numThreads; threadID++) { - // for (uint64_t i=0; i<locals[threadID].deleted.num; i++) { - // uint64_t delTet = locals[threadID].deleted.array[i]; - // #ifdef DEBUG - // if(!getDeletedFlag(mesh, delTet)) - // return HXT_ERROR_MSG(HXT_STATUS_ERROR, "deleted flag not set on deleted tet"); - // if(shared->quality.values[delTet]!=DBL_MAX) - // return HXT_ERROR_MSG(HXT_STATUS_ERROR, "quality of deleted tet %lu should have been set to DBL_MAX", delTet); - // #endif - // for (int j=0; j<4; j++) - // mesh->tetrahedra.neigh[4*delTet+j] = HXT_NO_ADJACENT; - // } - // } - - // HXT_CHECK( hxtRemoveDeleted(mesh) ); - // local->deleted.num = 0; - } - - HXTStatus status = waitForPossibleReallocation(&shared->toSync, shared->numThreads); - if(status!=HXT_STATUS_OK) { - #pragma omp atomic write - globalStatus = status; - } - } - - if(globalStatus!=HXT_STATUS_OK){ - HXT_TRACE(globalStatus); - return globalStatus; - } - - SPRDates_update(shared, locals); - - stage1 = threadLocals_collectStats(locals, shared->numThreads); - HXT_INFO_COND(options->verbosity>1, " " - HXTu64 " attempts, " HXTu64 " modifications, " HXTu64 " conflict", - stage1.attempt, stage1.success, stage1.conflict); - // double time2 = omp_get_wtime(); - // printf("SPR took %f s/tet, %f modif/tet, %f conflict/attempt\n", - // (time2 - time1)/(stage1.success + stage1.failure), - // (double) stage1.success/(stage1.success + stage1.failure), - // (double) stage1.conflict/stage1.attempt); - - iter++; - } while(continue_stage1(stage1)); - - HXT_CHECK( SPRStructs_destroy(locals, options) ); - HXT_CHECK( EdgeRemovalStructs_destroy(locals, options->numThreads) ); - HXT_CHECK( SmoothingStructs_destroy(locals, options->numThreads) ); - - HXT_INFO_COND(options->verbosity>0, " " - "\n\t" HXTu64" bad tet. | mean quality: %f | min quality: %f\n", - badTetrahedra(mesh, shared->quality.values, shared->quality.threshold), - meanQuality(mesh, shared->quality.values), - minQuality(mesh, shared->quality.values)); - - for (int threadID=0; threadID<options->numThreads; threadID++) { - for (uint64_t i=0; i<locals[threadID].deleted.num; i++) { - uint64_t delTet = locals[threadID].deleted.array[i]; -#ifdef DEBUG - if(!getDeletedFlag(mesh, delTet)) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "deleted flag not set on deleted tet"); - if(shared->quality.values[delTet]!=DBL_MAX) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "quality of deleted tet should have been set to DBL_MAX"); -#endif - for (int j=0; j<4; j++) - mesh->tetrahedra.neigh[4*delTet+j] = HXT_NO_ADJACENT; - } - } - -#ifdef DEBUG - HXT_CHECK( hxtTetVerify(mesh) ); -#endif - - HXT_CHECK( hxtRemoveDeleted(mesh) ); - - HXT_CHECK( threadLocals_destroy(&locals, options->numThreads) ); - HXT_CHECK( threadShared_destroy(&shared) ); - - return HXT_STATUS_OK; -} - diff --git a/contrib/hxt/hxt_tetOptiDate.h b/contrib/hxt/hxt_tetOptiDate.h deleted file mode 100644 index 22b993f46b..0000000000 --- a/contrib/hxt/hxt_tetOptiDate.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _HXT_TETOPTIDATE_ -#define _HXT_TETOPTIDATE_ - -#include "stdint.h" - -typedef struct { - uint16_t creation; - uint16_t check; -} HXTTetDate; - -typedef struct { - HXTTetDate* values; - uint16_t current; -} HXTTetDates; - - - - -#endif \ No newline at end of file diff --git a/contrib/hxt/hxt_tetPartition.h b/contrib/hxt/hxt_tetPartition.h deleted file mode 100644 index 0b011c9a9c..0000000000 --- a/contrib/hxt/hxt_tetPartition.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _HXT_TETPARTITION_ -#define _HXT_TETPARTITION_ - -#ifdef __cplusplus -extern "C" { -#endif - - -#include "hxt_vertices.h" - -typedef struct { - uint64_t startDist; - uint64_t lengthDist; - uint64_t firstElem; - uint64_t numElem; -} HXTPartition; - - -/* simple utility function to tell if a vertex is inside a partition, - * given the partition start and it's length 'rel' - * !!! Does not work with ghost vertex !!! */ -static inline int vertexOutOfPartition(HXTVertex* vertices, uint32_t v, uint64_t lengthDist, uint64_t startDist) { - // unsigned wrap around is defined by the standard - return vertices[v].padding.hilbertDist - startDist >= lengthDist; -} - - -// HXTStatus hxtComputePartitions(HXTPartition* partitions[], int nThreads, uint64_t* hilbertDist, uint64_t n); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/hxt_tetPostpro.c b/contrib/hxt/hxt_tetPostpro.c deleted file mode 100644 index 3aa691fb46..0000000000 --- a/contrib/hxt/hxt_tetPostpro.c +++ /dev/null @@ -1,182 +0,0 @@ -#include "predicates.h" -#include "hxt_tetPostpro.h" -#include "hxt_tetFlag.h" -#include "hxt_tetUtils.h" -#include "hxt_vertices.h" - - -static void verticesPlaneOrient(HXTMesh* mesh, double* __restrict__ p0, double* __restrict__ p1, double* __restrict__ p2){ - #pragma omp parallel for - for (uint32_t i=0; i<mesh->vertices.num; i++) { - mesh->vertices.coord[4*i+3] = orient3d(p0, p1, p2, mesh->vertices.coord + 4*i); - } -} - -/** keep only tetrahedra whose intersection with a plane is not empty. -The plane is defined by 3 points. */ -HXTStatus hxtTetPlaneIntersection(HXTMesh* mesh, double* p0, double* p1, double* p2){ - verticesPlaneOrient(mesh, p0, p1, p2); - - #pragma omp parallel for - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(mesh->tetrahedra.node[4*i+3] == HXT_GHOST_VERTEX) { - setDeletedFlag(mesh, i); - } - else { - double firstOrient = mesh->vertices.coord[4*mesh->tetrahedra.node[4*i]+3]; - for (int j=1; j<4; j++) { - double secondOrient = mesh->vertices.coord[4*mesh->tetrahedra.node[4*i+j]+3]; - if(firstOrient*secondOrient<=0.0){ - firstOrient = 0.0; - break; - } - } - - if(firstOrient!=0.0) - setDeletedFlag(mesh, i); - } - } - - HXT_CHECK( hxtRemoveDeleted(mesh) ); - - return HXT_STATUS_OK; -} - -/** keep only tetrahedra with at least two vertices on the positive side of the plane {p0,p1,p2}. -(p is on the positive side <=> orient3d(p0,p1,p2, p) > 0) -When seen from the negative side, p0,p1,p2 is counter-clockwise */ -HXTStatus hxtTetPlaneOrient(HXTMesh* mesh, double* p0, double* p1, double* p2){ - verticesPlaneOrient(mesh, p0, p1, p2); - - #pragma omp parallel for - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - if(mesh->tetrahedra.node[4*i+3] == HXT_GHOST_VERTEX) { - setDeletedFlag(mesh, i); - } - else { - for (int j=0; j<4; j++) { - if(mesh->vertices.coord[4*mesh->tetrahedra.node[4*i+j]+3]<0.0){ - setDeletedFlag(mesh, i); - break; - } - } - } - } - - HXT_CHECK( hxtRemoveDeleted(mesh) ); - - return HXT_STATUS_OK; -} - - -/** keep only vertices that are either in the surface mesh or in the tetrahedra mesh */ -HXTStatus hxtFilterVertices(HXTMesh* mesh, double* nodalSizes){ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - #pragma omp parallel for - for (uint32_t i=0; i<mesh->vertices.num; i++) { - vertices[i].padding.status = HXT_STATUS_FALSE; - } - - if(mesh->tetrahedra.node!=NULL){ - #pragma omp parallel for - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - vertices[mesh->tetrahedra.node[4*i+0]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->tetrahedra.node[4*i+1]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->tetrahedra.node[4*i+2]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->tetrahedra.node[4*i+3]].padding.status = HXT_STATUS_TRUE; - } - } - - if(mesh->triangles.node!=NULL){ - #pragma omp parallel for - for (uint64_t i=0; i<mesh->triangles.num; i++) { - vertices[mesh->triangles.node[3*i+0]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->triangles.node[3*i+1]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->triangles.node[3*i+2]].padding.status = HXT_STATUS_TRUE; - } - } - - if(mesh->lines.node!=NULL){ - #pragma omp parallel for - for (uint64_t i=0; i<mesh->lines.num; i++) { - vertices[mesh->lines.node[2*i+0]].padding.status = HXT_STATUS_TRUE; - vertices[mesh->lines.node[2*i+1]].padding.status = HXT_STATUS_TRUE; - } - } - - /* remove deleted vertices and change tetrahedra.node triangles.node and lines.nodes accordingly */ - uint32_t* numInserted; - HXT_CHECK( hxtAlignedMalloc(&numInserted, omp_get_max_threads()*sizeof(uint32_t)) ); - const uint32_t n = mesh->vertices.num; - - // when a vertex was skipped, nodeInfo[i].status = HXT_STATUS_FALSE - #pragma omp parallel - { - uint32_t start = 0; - int threadID = omp_get_thread_num(); - numInserted[threadID] = 0; - - #pragma omp for schedule(static) - for (uint32_t i=0; i<n; i++) { - if(vertices[i].padding.status==HXT_STATUS_TRUE) - numInserted[threadID]++; - }// implicit barrier here - - for (int i=0; i<threadID; i++) { - start+=numInserted[i]; - } - - // 3rd: compute where each vertices will be - #pragma omp for schedule(static) - for (uint32_t i=0; i<n; i++) { - uint32_t oldStart = start; - - if(vertices[i].padding.status==HXT_STATUS_TRUE) - start++; - - // index and status are at the same location (it's a union) we cannot put this above the "if" ! - vertices[i].padding.index = oldStart; - } - - // 4th: update tetrahedra.node accordingly - if(mesh->tetrahedra.node!=NULL){ - #pragma omp for - for (uint64_t i=0; i<4*mesh->tetrahedra.num; i++) { - uint32_t index = mesh->tetrahedra.node[i]; - if(index!=HXT_GHOST_VERTEX) - mesh->tetrahedra.node[i] = vertices[index].padding.index; - } - } - - if(mesh->triangles.node!=NULL){ - #pragma omp for - for (uint64_t i=0; i<3*mesh->triangles.num; i++) { - uint32_t index = mesh->triangles.node[i]; - mesh->triangles.node[i] = vertices[index].padding.index; - } - } - - if(mesh->lines.node!=NULL){ - #pragma omp for - for (uint64_t i=0; i<2*mesh->lines.num; i++) { - uint32_t index = mesh->lines.node[i]; - mesh->lines.node[i] = vertices[index].padding.index; - } - } - } - - HXT_CHECK( hxtAlignedFree(&numInserted) ); - - // 5th: put vertices at the right indices - for (uint32_t i=0; i<mesh->vertices.num; i++) { - if(nodalSizes!=NULL){ - nodalSizes[vertices[i].padding.index] = nodalSizes[i]; - } - vertices[vertices[i].padding.index] = vertices[i]; - } - - mesh->vertices.num = vertices[mesh->vertices.num-1].padding.index + 1; - - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/hxt_tetPostpro.h b/contrib/hxt/hxt_tetPostpro.h deleted file mode 100644 index 62ebd5cc35..0000000000 --- a/contrib/hxt/hxt_tetPostpro.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _HXT_TETPOSTPRO_ -#define _HXT_TETPOSTPRO_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "hxt_mesh.h" - -/** -* \file hxt_tetPospro.h postprocessing to keep only some part of a tetrahedra mesh -* \author Célestin Marot -*/ - -/** keep only tetrahedra whose intersection with a plane is not empty. -The plane is defined by 3 points. */ -HXTStatus hxtTetPlaneIntersection(HXTMesh* mesh, double* p0, double* p1, double* p2); - -/** keep only tetrahedra with at least two vertices on the positive side of the plane {p0,p1,p2}. -(p is on the positive side <=> orient3d(p0,p1,p2, p) > 0) -When seen from the negative side, p0,p1,p2 is counter-clockwise */ -HXTStatus hxtTetPlaneOrient(HXTMesh* mesh, double* p0, double* p1, double* p2); - -/** keep only vertices that are either in the surface mesh or in the tetrahedra mesh */ -HXTStatus hxtFilterVertices(HXTMesh* mesh, double* nodalSizes); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/hxt_tetQuality.c b/contrib/hxt/hxt_tetQuality.c deleted file mode 100644 index 6543af70d0..0000000000 --- a/contrib/hxt/hxt_tetQuality.c +++ /dev/null @@ -1,254 +0,0 @@ -#include <math.h> -#include <float.h> -#include "predicates.h" - -static inline void hxt_cross_prod(double a[3], double b[3], double c[3]) -{ - c[0] = a[1] * b[2] - a[2] * b[1]; - c[1] = a[2] * b[0] - a[0] * b[2]; - c[2] = a[0] * b[1] - a[1] * b[0]; -} - -static inline double hxt_distance2(double p0[3], double p1[3]){ - double a = p0[0]-p1[0]; - double b = p0[1]-p1[1]; - double c = p0[2]-p1[2]; - return a*a+b*b+c*c; -} - -double hxt_triangle_area(double p0[3], double p1[3], double p2[3]) -{ - double a[3], b[3], c[3]; - - a[0] = p2[0] - p1[0]; - a[1] = p2[1] - p1[1]; - a[2] = p2[2] - p1[2]; - - b[0] = p0[0] - p1[0]; - b[1] = p0[1] - p1[1]; - b[2] = p0[2] - p1[2]; - - hxt_cross_prod(a, b, c); - return 0.5 * sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]); -} - -double hxtTetDeterminantInexact(double a[3], double b[3], double c[3], double d[3], void* userData) { -HXT_UNUSED(userData); - - double ab[3], ac[3], ad[3]; - for (int i=0; i<3; i++) { - ab[i] = b[i] - a[i]; // AB - ac[i] = c[i] - a[i]; // AC - ad[i] = d[i] - a[i]; // AD - } - - double acxad0 = ac[1]*ad[2] - ac[2]*ad[1]; - double adxab0 = ad[1]*ab[2] - ad[2]*ab[1]; - double abxac0 = ab[1]*ac[2] - ab[2]*ac[1]; - double volume6 = ab[0]*acxad0 + ac[0]*adxab0 + ad[0]*abxac0; - - return volume6; -} - - -double hxtTetAspectRatio (double p0[3], double p1[3], double p2[3], double p3[3], void* userData) { - HXT_UNUSED(userData); - - double volume = -orient3d (p0,p1,p2,p3) / 6.0; - - double s1 = fabs(hxt_triangle_area(p0, p1, p2)); - double s2 = fabs(hxt_triangle_area(p0, p2, p3)); - double s3 = fabs(hxt_triangle_area(p0, p1, p3)); - double s4 = fabs(hxt_triangle_area(p1, p2, p3)); - - double rhoin = 3. * volume / (s1 + s2 + s3 + s4); - double l = hxt_distance2 (p0,p1); - double l2 = hxt_distance2 (p0,p2); - double l3 = hxt_distance2 (p0,p3); - double l4 = hxt_distance2 (p1,p2); - double l5 = hxt_distance2 (p1,p3); - double l6 = hxt_distance2 (p2,p3); - - l = l2 > l ? l2:l; - l = l3 > l ? l3:l; - l = l4 > l ? l4:l; - l = l5 > l ? l5:l; - l = l6 > l ? l6:l; - - return sqrt(24./l) * rhoin ; -} - - - -//!\ this function does not return the aspect ratio 'r'. It returns 'r^2/24' -double hxtTetAspectFastRatio (double a[3], double b[3], double c[3], double d[3], void* userData) { - HXT_UNUSED(userData); - - double ab[3], ac[3], ad[3], bc[3], cd[3], db[3]; - for (int i=0; i<3; i++) { - ab[i] = b[i] - a[i]; // AB - ac[i] = c[i] - a[i]; // AC - ad[i] = d[i] - a[i]; // AD - } - - double acxad0 = ac[1]*ad[2] - ac[2]*ad[1]; - double adxab0 = ad[1]*ab[2] - ad[2]*ab[1]; - double abxac0 = ab[1]*ac[2] - ab[2]*ac[1]; - double volume6 = ab[0]*acxad0 + ac[0]*adxab0 + ad[0]*abxac0; - - // abort as early as possible - if(volume6<=0.0) - return 0.0; - - double acxad1 = ac[2]*ad[0] - ac[0]*ad[2]; - double acxad2 = ac[0]*ad[1] - ac[1]*ad[0]; - - double adxab1 = ad[2]*ab[0] - ad[0]*ab[2]; - double adxab2 = ad[0]*ab[1] - ad[1]*ab[0]; - - double abxac1 = ab[2]*ac[0] - ab[0]*ac[2]; - double abxac2 = ab[0]*ac[1] - ab[1]*ac[0]; - - for (int i=0; i<3; i++) { - db[i] = b[i] - d[i]; // DB = B-D = AB-AD - bc[i] = c[i] - b[i]; // BC = C-B = AC-AB - cd[i] = d[i] - c[i]; // CD = D-c = AD-AC - } - - double bcxcd0 = bc[1]*cd[2] - bc[2]*cd[1]; // = acxad0+abxac0+adxab0; - double bcxcd1 = bc[2]*cd[0] - bc[0]*cd[2]; // = acxad1+abxac1+adxab1; - double bcxcd2 = bc[0]*cd[1] - bc[1]*cd[0]; // = acxad2+abxac2+adxab2; - - double areaSum = sqrt(acxad0*acxad0 + acxad1*acxad1 + acxad2*acxad2) - + sqrt(adxab0*adxab0 + adxab1*adxab1 + adxab2*adxab2) - + sqrt(abxac0*abxac0 + abxac1*abxac1 + abxac2*abxac2) - + sqrt(bcxcd0*bcxcd0 + bcxcd1*bcxcd1 + bcxcd2*bcxcd2); - - double l = ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2]; // |AB|² - double l2 = ac[0]*ac[0] + ac[1]*ac[1] + ac[2]*ac[2]; // |AC|² - double l3 = ad[0]*ad[0] + ad[1]*ad[1] + ad[2]*ad[2]; // |AD|² - double l4 = bc[0]*bc[0] + bc[1]*bc[1] + bc[2]*bc[2]; // |BC|² - double l5 = cd[0]*cd[0] + cd[1]*cd[1] + cd[2]*cd[2]; // |CD|² - double l6 = db[0]*db[0] + db[1]*db[1] + db[2]*db[2]; // |DB|² - - if(l2>l) l=l2; - if(l3>l) l=l3; - if(l4>l) l=l4; - if(l5>l) l=l5; - if(l6>l) l=l6; - - return volume6*volume6/(l*areaSum*areaSum); -} - - - - -// static inline double vec_dot(double a[3], double b[3]) { -// return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; -// } - -// static inline double vec_norm(double v[3]) { -// return vec_dot(v,v); -// } - -// double myOwnAspectRatio(double a[3], double b[3], double c[3], double d[3]) { -// double edges[6][4]; -// for (int i=0; i<3; i++) { -// edges[0][i] = b[i] - a[i]; -// edges[1][i] = c[i] - b[i]; -// edges[2][i] = d[i] - c[i]; -// edges[3][i] = a[i] - d[i]; -// edges[4][i] = c[i] - a[i]; -// edges[5][i] = d[i] - b[i]; -// } - -// double normal[4][4]; -// const unsigned ci[4] = {1,2,0,1}; - -// for (unsigned j=0; j<3; j++) { -// for (unsigned i=0; i<4; i++) { -// normal[i][j] = edges[(i+1)&3][ci[j]]*edges[(i+2)&3][ci[j+1]] - edges[(i+2)&3][ci[j]]*edges[(i+1)&3][ci[j+1]]; -// } -// } - -// // abort as early as possible -// if(edges[0][0]*normal[1][0] < edges[4][0]*normal[2][0] + edges[3][0]*normal[3][0]) -// return -1.0; - -// double maxEdge = 0.0; -// for (int i=0; i<6; i++) { -// double l = vec_norm(edges[i]); -// if(l>maxEdge) -// maxEdge = l; -// } - -// double minHeight = DBL_MAX; -// for (int i=0; i<4; i++) { -// double h = vec_dot(edges[i], normal[i]); -// h = h*h/vec_norm(normal[i]); -// if(h<minHeight) -// minHeight = h; -// } - -// return minHeight/maxEdge*1.5; -// } - - -// double myOwnAspectRatio(double a[3], double b[3], double c[3], double d[3]) { -// double x[8], y[8], z[8]; - -// x[0] = b[0] - a[0]; -// x[1] = c[0] - b[0]; -// x[2] = d[0] - c[0]; -// x[3] = a[0] - d[0]; -// x[4] = c[0] - a[0]; -// x[5] = d[0] - b[0]; - -// y[0] = b[1] - a[1]; -// y[1] = c[1] - b[1]; -// y[2] = d[1] - c[1]; -// y[3] = a[1] - d[1]; -// y[4] = c[1] - a[1]; -// y[5] = d[1] - b[1]; - -// z[0] = b[2] - a[2]; -// z[1] = c[2] - b[2]; -// z[2] = d[2] - c[2]; -// z[3] = a[2] - d[2]; -// z[4] = c[2] - a[2]; -// z[5] = d[2] - b[2]; - -// double normal_x[4], normal_y[4], normal_z[4]; -// for (unsigned k=0; k<4; k++) { -// unsigned i = (k+1)&3; -// unsigned j = (k+2)&3; - -// normal_x[k] = y[i]*z[j] - y[j]*z[i]; -// normal_y[k] = z[i]*x[j] - z[j]*x[i]; -// normal_z[k] = x[i]*y[j] - x[j]*y[i]; -// } - -// if(x[0]*normal_x[1] < x[4]*normal_x[2] + x[3]*normal_x[3]) -// return -1.0; - -// double maxEdge = 0.0; -// for (int i=0; i<6; i++) { -// double l = x[i]*x[i]+y[i]*y[i]+z[i]*z[i]; -// if(l>maxEdge) -// maxEdge = l; -// } - -// double minHeight = DBL_MAX; -// for (int i=0; i<4; i++) { -// double h = x[i]*normal_x[i] + y[i]*normal_y[i] + z[i]*normal_z[i]; -// double n = normal_x[i]*normal_x[i] + normal_y[i]*normal_y[i] + normal_z[i]*normal_z[i]; -// h = h*h/n; -// if(h<minHeight) -// minHeight = h; -// } - -// double r = minHeight/maxEdge; - -// return r < (1./9.) ? r*4.5 : r*0.9 + 0.4; -// } -// #endif \ No newline at end of file diff --git a/contrib/hxt/hxt_tet_aspect_ratio.c b/contrib/hxt/hxt_tet_aspect_ratio.c deleted file mode 100644 index 3320d5915d..0000000000 --- a/contrib/hxt/hxt_tet_aspect_ratio.c +++ /dev/null @@ -1,192 +0,0 @@ -#include <math.h> -#include "predicates.h" - -void hxt_cross_prod(double a[3], double b[3], double c[3]) -{ - c[2] = a[0] * b[1] - a[1] * b[0]; - c[1] = -a[0] * b[2] + a[2] * b[0]; - c[0] = a[1] * b[2] - a[2] * b[1]; -} - -double hxt_distance2(double p0[3], double p1[3]){ - double a = p0[0]-p1[0]; - double b = p0[1]-p1[1]; - double c = p0[2]-p1[2]; - return a*a+b*b+c*c; -} - -double hxt_triangle_area(double p0[3], double p1[3], double p2[3]) -{ - double a[3], b[3], c[3]; - - a[0] = p2[0] - p1[0]; - a[1] = p2[1] - p1[1]; - a[2] = p2[2] - p1[2]; - - b[0] = p0[0] - p1[0]; - b[1] = p0[1] - p1[1]; - b[2] = p0[2] - p1[2]; - - hxt_cross_prod(a, b, c); - return 0.5 * sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]); -} - -double hxtTetAspectRatio (double p0[3], double p1[3], double p2[3], double p3[3]) { - double volume = orient3d (p0,p1,p2,p3) / 6.0; - - double s1 = fabs(hxt_triangle_area(p0, p1, p2)); - double s2 = fabs(hxt_triangle_area(p0, p2, p3)); - double s3 = fabs(hxt_triangle_area(p0, p1, p3)); - double s4 = fabs(hxt_triangle_area(p1, p2, p3)); - - double rhoin = 3. * volume / (s1 + s2 + s3 + s4); - double l = hxt_distance2 (p0,p1); - double l2 = hxt_distance2 (p0,p2); - double l3 = hxt_distance2 (p0,p3); - double l4 = hxt_distance2 (p1,p2); - double l5 = hxt_distance2 (p1,p3); - double l6 = hxt_distance2 (p2,p3); - - l = l2 > l ? l2:l; - l = l3 > l ? l3:l; - l = l4 > l ? l4:l; - l = l5 > l ? l5:l; - l = l6 > l ? l6:l; - - return sqrt(24./l) * rhoin ; -} - - - -//!\ this function does not return the aspect ratio 'r'. It returns 'r^2/24' -double hxtTetAspectFastRatio (double a[3], double b[3], double c[3], double d[3]) { - double ab[3], ac[3], ad[3], bc[3], cd[3], db[3]; - for (int i=0; i<3; i++) { - ab[i] = b[i] - a[i]; // AB - ac[i] = c[i] - a[i]; // AC - ad[i] = d[i] - a[i]; // AD - } - - double acxad0 = ac[1]*ad[2] - ac[2]*ad[1]; - double adxab0 = ad[1]*ab[2] - ad[2]*ab[1]; - double abxac0 = ab[1]*ac[2] - ab[2]*ac[1]; - double volume6 = ab[0]*acxad0 + ac[0]*adxab0 + ad[0]*abxac0; - - // abort as early as possible - if(volume6<=0.0) - return 0.0; - - double acxad1 = ac[2]*ad[0] - ac[0]*ad[2]; - double acxad2 = ac[0]*ad[1] - ac[1]*ad[0]; - - double adxab1 = ad[2]*ab[0] - ad[0]*ab[2]; - double adxab2 = ad[0]*ab[1] - ad[1]*ab[0]; - - double abxac1 = ab[2]*ac[0] - ab[0]*ac[2]; - double abxac2 = ab[0]*ac[1] - ab[1]*ac[0]; - - for (int i=0; i<3; i++) { - db[i] = b[i] - d[i]; // DB = B-D = AB-AD - bc[i] = c[i] - b[i]; // BC = C-B = AC-AB - cd[i] = d[i] - c[i]; // CD = D-c = AD-AC - } - - double bcxcd0 = bc[1]*cd[2] - bc[2]*cd[1]; // = acxad0+abxac0+adxab0; - double bcxcd1 = bc[2]*cd[0] - bc[0]*cd[2]; // = acxad1+abxac1+adxab1; - double bcxcd2 = bc[0]*cd[1] - bc[1]*cd[0]; // = acxad2+abxac2+adxab2; - - double areaSum = sqrt(acxad0*acxad0 + acxad1*acxad1 + acxad2*acxad2) - + sqrt(adxab0*adxab0 + adxab1*adxab1 + adxab2*adxab2) - + sqrt(abxac0*abxac0 + abxac1*abxac1 + abxac2*abxac2) - + sqrt(bcxcd0*bcxcd0 + bcxcd1*bcxcd1 + bcxcd2*bcxcd2); - - double l = ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2]; // |AB|² - double l2 = ac[0]*ac[0] + ac[1]*ac[1] + ac[2]*ac[2]; // |AC|² - double l3 = ad[0]*ad[0] + ad[1]*ad[1] + ad[2]*ad[2]; // |AD|² - double l4 = bc[0]*bc[0] + bc[1]*bc[1] + bc[2]*bc[2]; // |BC|² - double l5 = cd[0]*cd[0] + cd[1]*cd[1] + cd[2]*cd[2]; // |CD|² - double l6 = db[0]*db[0] + db[1]*db[1] + db[2]*db[2]; // |DB|² - - if(l2>l) l=l2; - if(l3>l) l=l3; - if(l4>l) l=l4; - if(l5>l) l=l5; - if(l6>l) l=l6; - - return volume6*volume6/(l*areaSum*areaSum); -} - - -// for a pair of tetrahedra: (abcd) and (abec) -// void hxtTetAspectFastRatioPair (double a[3], double b[3], double c[3], double d[3], double e[3], double* quality1, double quality2) { -// double ab[3], ac[3], ad[3], bc[3], cd[3], db[3]; -// for (int i=0; i<3; i++) { -// ab[i] = b[i] - a[i]; // AB -// ac[i] = c[i] - a[i]; // AC -// ad[i] = d[i] - a[i]; // AD -// ae[i] = e[i] - a[i]; // AE -// } - -// double adxac0 = ad[1]*ac[2] - ad[2]*ac[1]; -// double abxad0 = ab[1]*ad[2] - ab[2]*ad[1]; -// double acxab0 = ac[1]*ab[2] - ac[2]*ab[1]; -// double acxae0 = ac[1]*ae[2] - ac[2]*ae[1]; -// double aexab0 = ae[1]*ab[2] - ae[2]*ab[1]; -// double volume1 = ab[0]*adxac0 + ac[0]*abxad0 + ad[0]*acxab0; -// double volume2 = ab[0]*acxae0 - ae[0]*acxab0 + ac[0]*aexab0; - -// // abort as early as possible -// if(volume1<=0.0 || volume2<=0.0){ -// *quality1 = 0.0; -// *quality2 = 0.0; -// return; -// } - -// double adxac1 = ad[2]*ac[0] - ad[0]*ac[2]; -// double adxac2 = ad[0]*ac[1] - ad[1]*ac[0]; - -// double abxad1 = ab[2]*ad[0] - ab[0]*ad[2]; -// double abxad2 = ab[0]*ad[1] - ab[1]*ad[0]; - -// double acxab1 = ac[2]*ab[0] - ac[0]*ab[2]; -// double acxab2 = ac[0]*ab[1] - ac[1]*ab[0]; - -// double acxae1 = ac[2]*ae[0] - ac[0]*ae[2]; -// double acxae2 = ac[0]*ae[1] - ac[1]*ae[0]; - -// double aexab1 = ae[2]*ab[0] - ae[0]*ab[2]; -// double aexab2 = ae[0]*ab[1] - ae[1]*ab[0]; - -// for (int i=0; i<3; i++) { -// db[i] = b[i] - d[i]; // DB = B-D = AB-AD -// bc[i] = c[i] - b[i]; // BC = C-B = AC-AB -// cd[i] = d[i] - c[i]; // CD = D-c = AD-AC - -// } - -// double cdxbc0 = cd[1]*bc[2] - cd[2]*bc[1]; // = adxac0+acxab0+abxad0; -// double cdxbc1 = cd[2]*bc[0] - cd[0]*bc[2]; // = adxac1+acxab1+abxad1; -// double cdxbc2 = cd[0]*bc[1] - cd[1]*bc[0]; // = adxac2+acxab2+abxad2; - -// double commonArea = sqrt(acxab0*acxab0 + acxab1*acxab1 + acxab2*acxab2); - -// double areaSum1 = commonArea -// + sqrt(adxac0*adxac0 + adxac1*adxac1 + adxac2*adxac2) -// + sqrt(abxad0*abxad0 + abxad1*abxad1 + abxad2*abxad2) -// + sqrt(cdxbc0*cdxbc0 + cdxbc1*cdxbc1 + cdxbc2*cdxbc2); - -// double l = ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2]; // |AB|² -// double l2 = ac[0]*ac[0] + ac[1]*ac[1] + ac[2]*ac[2]; // |AC|² -// double l3 = ad[0]*ad[0] + ad[1]*ad[1] + ad[2]*ad[2]; // |AD|² -// double l4 = bc[0]*bc[0] + bc[1]*bc[1] + bc[2]*bc[2]; // |BC|² -// double l5 = cd[0]*cd[0] + cd[1]*cd[1] + cd[2]*cd[2]; // |CD|² -// double l6 = db[0]*db[0] + db[1]*db[1] + db[2]*db[2]; // |DB|² - -// if(l2>l) l=l2; -// if(l3>l) l=l3; -// if(l4>l) l=l4; -// if(l5>l) l=l5; -// if(l6>l) l=l6; - -// *quality1 = volume1*volume1/(l*areaSum1*areaSum1); -// } \ No newline at end of file diff --git a/contrib/hxt/hxt_tet_aspect_ratio.h b/contrib/hxt/hxt_tet_aspect_ratio.h deleted file mode 100644 index 0ecc2bd5f7..0000000000 --- a/contrib/hxt/hxt_tet_aspect_ratio.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _HXT_TET_ASPECT_RATIO_ -#define _HXT_TET_ASPECT_RATIO_ - -double hxtTetAspectRatio (double p0[3], double p1[3], double p2[3], double p3[3]); - -//!\ this function does not return the aspect ratio 'r'. It returns 'r^2/24' -double hxtTetAspectFastRatio (double p0[3], double p1[3], double p2[3], double p3[3]); - -#endif diff --git a/contrib/hxt/hxt_tetrahedra.c b/contrib/hxt/hxt_tetrahedra.c deleted file mode 100644 index b04c63369a..0000000000 --- a/contrib/hxt/hxt_tetrahedra.c +++ /dev/null @@ -1,1882 +0,0 @@ -#include "hxt_tetrahedra.h" -#include "predicates.h" -#include "hxt_tetRepair.h" -#include "hxt_tetUtils.h" -#include "hxt_tetFlag.h" -#include "hxt_sort.h" - -/** -* \file hxt_tetrahedra.c see header hxt_tetrahedra.h. -* \author Célestin Marot -*/ - -/* compile-time parameters */ -#define SMALLEST_ROUND 2048 -#define DELETED_BUFFER_SIZE 8182 -// #define HXT_DELAUNAY_LOW_MEMORY /* doesn't use any buffer (a lot slower, except if you are at the limit of filling the RAM) */ - -/* usefull macros */ -#define ABS(x) ((x) >= 0 ? (x) : -(x)) -#define MAX(x,y) ((x)>(y) ? (x) : (y)) -#define MIN(x,y) ((x)<(y) ? (x) : (y)) - -#define HXT_OMP_CHECK(status) do{ HXTStatus _tmp_ = (status); \ - if(_tmp_<0){ \ - if(_tmp_>HXT_STATUS_INTERNAL) \ - HXT_TRACE_MSG(_tmp_, "cannot break OpenMP region -> exiting"); \ - fflush(stdout); fflush(stderr); \ - exit(_tmp_); \ - } \ - }while(0) - - -typedef struct{ - uint32_t hxtDeclareAligned node[3]; - uint16_t flag; - uint64_t neigh; // the tet on the other side of the boundar -} cavityBnd_t; - -typedef struct { -#ifndef HXT_DELAUNAY_LOW_MEMORY - uint64_t hxtDeclareAligned Map[1024]; -#endif - - struct { - cavityBnd_t* bnd; - uint64_t num; - uint64_t size; - } ball; - - struct { - uint64_t* tetID; - uint64_t num; - uint64_t size; - } deleted; - - struct { - uint64_t startDist; - uint64_t endDist; - uint32_t first; - } partition; -} TetLocal; - - -/*********************************** - * create the initial tetrahedron - * surrounded by 4 ghost tetrahedra - ***********************************/ -static inline HXTStatus hxtTetrahedraInit(HXTMesh* mesh, hxtNodeInfo* nodeInfo, uint32_t nToInsert, int verbosity){ - if(nToInsert < 4){ - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "cannot mesh less than four vertices"); - } - if(mesh->tetrahedra.size < 5){ - uint32_t maxSizeEstim = MAX(omp_get_max_threads()*DELETED_BUFFER_SIZE+8UL*nToInsert, 10UL*nToInsert); - HXT_CHECK( hxtTetrahedraReserve(mesh, maxSizeEstim) ); - HXT_INFO_COND(verbosity>1, "Initialization reserved %lu Tet.", mesh->tetrahedra.size); - } - - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - // find non-coplanar vertices - double orientation = 0.0; - - uint32_t i=0, j=1, k=2, l=3; - for (i=0; orientation==0.0 && i<nToInsert-3; i++) - { - for (j=i+1; orientation==0.0 && j<nToInsert-2; j++) - { - for (k=j+1; orientation==0.0 && k<nToInsert-1; k++) - { - for (l=k+1; orientation==0.0 && l<nToInsert; l++) - { - orientation = orient3d(vertices[nodeInfo[i].node].coord, - vertices[nodeInfo[j].node].coord, - vertices[nodeInfo[k].node].coord, - vertices[nodeInfo[l].node].coord); - } - } - } - } - l--; k--; j--; i--; - - - if(orientation==0.0){ - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "all vertices are coplanar"); - } - - // swap 0<->i 1<->j 2<->k 3<->l - { - hxtNodeInfo tmp = nodeInfo[i]; - nodeInfo[i] = nodeInfo[0]; - nodeInfo[0] = tmp; - nodeInfo[0].status = HXT_STATUS_TRUE; - i = 0; - - tmp = nodeInfo[j]; - nodeInfo[j] = nodeInfo[1]; - nodeInfo[1] = tmp; - nodeInfo[1].status = HXT_STATUS_TRUE; - j = 1; - - tmp = nodeInfo[k]; - nodeInfo[k] = nodeInfo[2]; - nodeInfo[2] = tmp; - nodeInfo[2].status = HXT_STATUS_TRUE; - k = 2; - - tmp = nodeInfo[l]; - nodeInfo[l] = nodeInfo[3]; - nodeInfo[3] = tmp; - nodeInfo[3].status = HXT_STATUS_TRUE; - l = 3; - } - - - if(orientation < 0.0){ - uint32_t tmp = i; - i = j; - j = tmp; - } - - mesh->tetrahedra.neigh[ 0] = 19; mesh->tetrahedra.node[ 0] = nodeInfo[l].node; - mesh->tetrahedra.neigh[ 1] = 15; mesh->tetrahedra.node[ 1] = nodeInfo[k].node; - mesh->tetrahedra.neigh[ 2] = 11; mesh->tetrahedra.node[ 2] = nodeInfo[j].node; - mesh->tetrahedra.neigh[ 3] = 7; mesh->tetrahedra.node[ 3] = nodeInfo[i].node; - - mesh->tetrahedra.neigh[ 4] = 18; mesh->tetrahedra.node[ 4] = nodeInfo[l].node; - mesh->tetrahedra.neigh[ 5] = 10; mesh->tetrahedra.node[ 5] = nodeInfo[j].node; - mesh->tetrahedra.neigh[ 6] = 13; mesh->tetrahedra.node[ 6] = nodeInfo[k].node; - mesh->tetrahedra.neigh[ 7] = 3; mesh->tetrahedra.node[ 7] = HXT_GHOST_VERTEX; - - mesh->tetrahedra.neigh[8 ] = 17; mesh->tetrahedra.node[ 8] = nodeInfo[l].node; - mesh->tetrahedra.neigh[9 ] = 14; mesh->tetrahedra.node[ 9] = nodeInfo[k].node; - mesh->tetrahedra.neigh[10] = 5; mesh->tetrahedra.node[10] = nodeInfo[i].node; - mesh->tetrahedra.neigh[11] = 2; mesh->tetrahedra.node[11] = HXT_GHOST_VERTEX; - - mesh->tetrahedra.neigh[12] = 16; mesh->tetrahedra.node[12] = nodeInfo[l].node; - mesh->tetrahedra.neigh[13] = 6; mesh->tetrahedra.node[13] = nodeInfo[i].node; - mesh->tetrahedra.neigh[14] = 9; mesh->tetrahedra.node[14] = nodeInfo[j].node; - mesh->tetrahedra.neigh[15] = 1; mesh->tetrahedra.node[15] = HXT_GHOST_VERTEX; - - mesh->tetrahedra.neigh[16] = 12; mesh->tetrahedra.node[16] = nodeInfo[k].node; - mesh->tetrahedra.neigh[17] = 8; mesh->tetrahedra.node[17] = nodeInfo[j].node; - mesh->tetrahedra.neigh[18] = 4; mesh->tetrahedra.node[18] = nodeInfo[i].node; - mesh->tetrahedra.neigh[19] = 0; mesh->tetrahedra.node[19] = HXT_GHOST_VERTEX; - - mesh->tetrahedra.num = 5; - - for (uint64_t i=0; i<5 ;i++){ - mesh->tetrahedra.colors[i] = UINT16_MAX; - mesh->tetrahedra.flag[i] = 0; - } - - return HXT_STATUS_OK; -} - -/*********************************** - * fill the passes array which tells - * the size of each BRIO round. - * return the number of BRIO passes - ***********************************/ -static unsigned computePasses(uint32_t passes[12], uint32_t nInserted, uint32_t nToInsert) -{ - unsigned npasses=0; - passes[0] = nToInsert; - - for (unsigned i=0; i<10; i++) { - if(passes[i] < SMALLEST_ROUND || passes[i]/8 < nInserted){ - passes[i+1] = 0; - npasses = i+1; - break; - } - passes[i+1] = passes[i]/7.5; - } - - for(unsigned i=0; i<=npasses/2; i++){ - uint32_t tmp = passes[i]; - passes[i] = passes[npasses-i]; - passes[npasses-i] = tmp; - } - - return npasses; -} - -/****************************************** - * initialisation of the TetLocal structure - ******************************************/ -static inline HXTStatus localInit(TetLocal* local){ - local->ball.size = 1020; // accounting for the offset in aligned malloc, to avoid additional memory page - local->ball.num = 0; - local->ball.bnd = NULL; - local->deleted.size = DELETED_BUFFER_SIZE; - local->deleted.num = 0; - local->deleted.tetID = NULL; - - HXT_CHECK( hxtAlignedMalloc(&local->ball.bnd, local->ball.size*sizeof(cavityBnd_t)) ); - HXT_CHECK( hxtAlignedMalloc(&local->deleted.tetID, local->deleted.size*sizeof(uint64_t)) ); - - return HXT_STATUS_OK; -} - -/*********************************************** - re-allocation functions - ***********************************************/ -static HXTStatus synchronizeReallocation(HXTMesh* mesh, volatile int* toCopy, volatile int* copy){ - // threads cant be doing something while the realloc portion happen - #pragma omp barrier - - // this unable us to have the same value of toCopy for everyone, as we are sure nothing happens to those variables here - if(toCopy!=copy){ - *copy = *toCopy; - } - - HXTStatus status = HXT_STATUS_OK; - // make reallocations in a critical section - #pragma omp single - { - if(mesh->tetrahedra.num > mesh->tetrahedra.size){ - status = hxtTetrahedraDoubleSize(mesh); - } - } // implicit barrier here - - if(status!=HXT_STATUS_OK) - HXT_TRACE(status); - - return status; -} - - -// pragma atomic capture to get tetrahedra.num and update it at the same time before caling this function ! -static inline HXTStatus reserveNewTet(HXTMesh* mesh){ - if(mesh->tetrahedra.num > mesh->tetrahedra.size){ - HXT_CHECK( synchronizeReallocation(mesh, NULL, NULL) ); - } - - return HXT_STATUS_OK; -} - -static inline HXTStatus reserveNewDeleted(TetLocal* local, uint64_t num){ - num += local->deleted.num; - if(num > local->deleted.size){ - HXT_CHECK( hxtAlignedRealloc(&local->deleted.tetID, 2*num*sizeof(uint64_t)) ); - local->deleted.size = 2*num; - } - - return HXT_STATUS_OK; -} - -static inline HXTStatus reserveNewBnd(TetLocal* local, uint64_t num){ - num += local->ball.num; - if(num > local->ball.size){ - HXT_CHECK( hxtAlignedRealloc(&local->ball.bnd, 2*num*sizeof(cavityBnd_t)) ); - local->ball.size = 2*num; - } - - return HXT_STATUS_OK; -} -/***********************************************/ - -/************************************ - * check if a tetrahedra is entirely - * in the calling thread's partition - ***********************************/ -static inline HXTStatus checkTetrahedron(HXTVertex* vertices, TetLocal* local, const uint32_t* nodes){ - /* Actually, one vertex (not more) could be in another partition without creating a conflict. - However, all threads would have to have a verticesID array => a lot of memory space wasted. - Instead, we only allow the ghost vertex to be in another partition, it is handle differently in - computeAdjacenciesFast function */ - uint64_t rel = local->partition.endDist - local->partition.startDist; - - if(local->partition.endDist==UINT64_MAX) // if we are working with one thread only - return HXT_STATUS_OK; - - // unsigned wrap around is defined by the standard - uint64_t d0 = vertices[nodes[0]].padding.hilbertDist - local->partition.startDist; - uint64_t d1 = vertices[nodes[1]].padding.hilbertDist - local->partition.startDist; - uint64_t d2 = vertices[nodes[2]].padding.hilbertDist - local->partition.startDist; - uint64_t d3 = nodes[3]==HXT_GHOST_VERTEX ? d2: (vertices[nodes[3]].padding.hilbertDist - local->partition.startDist); - - if((d0>=rel) || (d1>=rel) || (d2>=rel) || (d3>=rel)) - return HXT_STATUS_INTERNAL; - - return HXT_STATUS_OK; - -} - - -static inline HXTStatus pointIsTooClose(const double* __restrict__ p1, const double* __restrict__ p2, double nodalSize){ - double d2 = (p1[0]-p2[0])*(p1[0]-p2[0]) - + (p1[1]-p2[1])*(p1[1]-p2[1]) - + (p1[2]-p2[2])*(p1[2]-p2[2]); - if (d2 < 0.8*0.8*nodalSize*nodalSize){ - return HXT_STATUS_INTERNAL; - } - - return HXT_STATUS_OK; -} - -/* if one edge of the cavity is shorter than the nodalSize, return HXT_STATUS_INTERNAL */ -static inline HXTStatus filterCavity (TetLocal* local, HXTMesh *mesh, const double *nodalSizes, const uint32_t vta) -{ - double *vtaCoord = mesh->vertices.coord + 4*vta; - double vtaNodalSize = nodalSizes[vta]; - - for (uint64_t i = 0 ; i< local->ball.num ; i++) { - for (unsigned j=0;j<3;j++) { - uint32_t nodej = local->ball.bnd[i].node[j]; - - if (j!=3 || nodej != HXT_GHOST_VERTEX){ - double *Xj = mesh->vertices.coord + 4*nodej; - HXT_CHECK( pointIsTooClose(vtaCoord, Xj, 0.5*( vtaNodalSize + nodalSizes[nodej])) ); - } - } - } - return HXT_STATUS_OK; -} - -static inline HXTStatus filterTet(HXTMesh* mesh, const double *nodalSizes, const uint64_t curTet, const uint32_t vta){ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - double *vtaCoord = vertices[vta].coord; - double vtaNodalSize = nodalSizes[vta]; - - for (unsigned j=0; j<4; j++) { - uint32_t nodej = mesh->tetrahedra.node[4*curTet+j]; - - if (j!=3 || nodej != HXT_GHOST_VERTEX){ - double* Xj = vertices[nodej].coord; - double otherNodalSize = nodalSizes[nodej]; - if(otherNodalSize==DBL_MAX){ - otherNodalSize = vtaNodalSize; - } - HXT_CHECK( pointIsTooClose(vtaCoord, Xj, 0.5*( vtaNodalSize + otherNodalSize)) ); - } - } - return HXT_STATUS_OK; -} - - -/* restore the structure as it was before the failed insertion attempt */ -static inline void restoreDeleted(HXTMesh* mesh, TetLocal* local, const uint64_t prevDeleted, const uint16_t color){ - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) - unmarkTetAsDeleted(mesh, local->deleted.tetID[i]); - - local->deleted.num = prevDeleted; -} - - -/*********************************** - * insphere predicate & perturbation - ***********************************/ -// see Perturbations and Vertex Removal in a 3D Delaunay Triangulation, O. Devillers & M. Teillaud -static double symbolicPerturbation (uint32_t indices[5] , const double* __restrict__ i, - const double* __restrict__ j, - const double* __restrict__ k, - const double* __restrict__ l, - const double* __restrict__ m){ - double const* pt[5] = {i,j,k,l,m}; - - // Sort the five points such that their indices are in the increasing - // order. An optimized bubble sort algorithm is used, i.e., it has - // the worst case O(n^2) runtime, but it is usually much faster. - int swaps = 0; // Record the total number of swaps. - int n = 5; - int count; - do { - count = 0; - n = n - 1; - for (int iter = 0; iter < n; iter++) { - if (indices[iter] > indices[iter+1]) { - - const double *swappt = pt[iter]; - pt[iter] = pt[iter+1]; - pt[iter+1] = swappt; - - uint32_t sw = indices [iter]; - indices[iter] = indices[iter+1]; - indices[iter+1] = sw; - count++; - } - } - swaps += count; - } while (count > 0); // Continue if some points are swapped. - - double oriA = orient3d(pt[1], pt[2], pt[3], pt[4]); - if (oriA != 0.0) { - // Flip the sign if there are odd number of swaps. - if ((swaps % 2) != 0) oriA = -oriA; - return oriA; - } - - double oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]); - if (oriB == 0.0) HXT_WARNING("Symbolic perturbation failed (2 superposed vertices ?)"); - - // Flip the sign if there are odd number of swaps. - if ((swaps % 2) != 0) oriB = -oriB; - return oriB; -} - - -/* wrapper around the insphere predicate that handles - the ghost vertex and symbolic perturbation if needed */ -double tetInsphere(HXTMesh* mesh, const uint64_t curTet, const uint32_t vta){ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - uint32_t* Node = mesh->tetrahedra.node + curTet; - - const double* __restrict__ a = vertices[Node[0]].coord; - const double* __restrict__ b = vertices[Node[1]].coord; - const double* __restrict__ c = vertices[Node[2]].coord; - const double* __restrict__ e = vertices[vta].coord; - - if(Node[3]==HXT_GHOST_VERTEX){ - double det = orient3d(a,b,c,e); - - if(det!=0.0){ - return det; - } - - // we never go here, except when point are aligned on boundary - // HXT_INFO("insphere using opposite vertex"); - uint32_t oppositeNode = mesh->tetrahedra.node[mesh->tetrahedra.neigh[curTet+3]]; - double* const __restrict__ oppositeVertex = vertices[oppositeNode].coord; - det = insphere(a,b,c,oppositeVertex,e); - - if (det == 0.0) { - uint32_t nn[5] = {Node[0],Node[1],Node[2],oppositeNode,vta}; - // HXT_INFO("symbolic perturbation on boundary"); - det = symbolicPerturbation (nn, a,b,c,oppositeVertex,e); - - } - return -det; - } - - double* const __restrict__ d = vertices[Node[3]].coord; - - double det = insphere(a,b,c,d,e); - if (det == 0.0) { - uint32_t nn[5] = {Node[0],Node[1],Node[2],Node[3],vta}; - // HXT_INFO("symbolic perturbation"); - det = symbolicPerturbation (nn, a,b,c,d,e); - } - return det; -} - - -/*********************************** - * walk to cavity - ***********************************/ -static HXTStatus walking2Cavity(HXTMesh* mesh, TetLocal* local, uint64_t* __restrict__ curTet, const uint32_t vta){ - uint64_t nextTet = *curTet; - uint32_t seed = 1; - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - /* if nextTet is a ghost triangle, go to the neighbor that is not a ghost triangle */ - if(mesh->tetrahedra.node[4*nextTet+3]==HXT_GHOST_VERTEX) - nextTet = mesh->tetrahedra.neigh[4*nextTet+3]/4; - - double* const vtaCoord = vertices[vta].coord; - unsigned enteringFace = 4; - -#ifndef NDEBUG - uint64_t TotalCount = 0; -#endif - - - while(1){ - const uint32_t* __restrict__ curNode = mesh->tetrahedra.node + 4*nextTet; - const uint64_t* __restrict__ curNeigh = mesh->tetrahedra.neigh + 4*nextTet; - - #ifndef NDEBUG - if(curNode[3]==HXT_GHOST_VERTEX){ - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "walked outside of the domain"); - } - #endif - - unsigned neigh = 4; - unsigned outside = 0; - uint32_t randomU = hxtReproducibleLCG(&seed); - for (unsigned i=0; i<4; i++) - { - uint32_t index = (i+randomU)%4; - if (index!=enteringFace) { - // we walk where the volume is minimum - const double* __restrict__ a = vertices[curNode[(index+1)&3]].coord; - const double* __restrict__ b = vertices[curNode[(index&2)^3]].coord; - const double* __restrict__ c = vertices[curNode[(index+3)&2]].coord; - - if (orient3d(a,b,c, vtaCoord) < 0.0){ - if(curNeigh[index]==HXT_NO_ADJACENT) { // the point is outside the triangulation - return HXT_ERROR_MSG(HXT_STATUS_ERROR, - "vertex {%f %f %f} outside the triangulation and no ghost tetrahedra", - vtaCoord[0], vtaCoord[1], vtaCoord[2]); - } - - uint64_t tet = curNeigh[index]/4; - const uint32_t* __restrict__ neighNodes = mesh->tetrahedra.node + tet*4; - if(checkTetrahedron(vertices, local, neighNodes)==HXT_STATUS_OK){ - if(neighNodes[3]==HXT_GHOST_VERTEX){ - *curTet = tet; - return HXT_STATUS_OK; - } - neigh=index; - break; - } - outside = 1; - } - } - } - - if(neigh==4){ - const double* __restrict__ a = vertices[curNode[0]].coord; - const double* __restrict__ b = vertices[curNode[1]].coord; - const double* __restrict__ c = vertices[curNode[2]].coord; - const double* __restrict__ d = vertices[curNode[3]].coord; - if(outside || - (orient3d(a,b,c,vtaCoord)<=0.0) + - (orient3d(a,b,vtaCoord,d)<=0.0) + - (orient3d(a,vtaCoord,c,d)<=0.0) + - (orient3d(vtaCoord,b,c,d)<=0.0)>2){ - return HXT_STATUS_TRYAGAIN; - } - *curTet = nextTet; - return HXT_STATUS_OK; - } - - // printf("nextTet %u %g %u %u\n",nextTet,Min, count, neigh); - nextTet = curNeigh[neigh]/4; - enteringFace = curNeigh[neigh]&3; - - #ifndef NDEBUG - if(TotalCount>mesh->tetrahedra.num){ - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "infinite walk to find the cavity"); - } - // printf("%lu\n",TotalCount); - TotalCount++; - #endif - } -} - - -/*********************************** - * digging cavity - ***********************************/ - -/* pushing cavity boundary information to local->ball */ -static inline void bndPush( TetLocal* local, uint16_t flag, - const uint32_t node1, const uint32_t node2, - const uint32_t node3, const uint64_t neigh){ - uint64_t n = local->ball.num; - local->ball.bnd[n].node[0] = node1; - local->ball.bnd[n].node[1] = node2; - local->ball.bnd[n].node[2] = node3; - local->ball.bnd[n].flag = flag; - local->ball.bnd[n].neigh = neigh; - local->ball.num++; -} - -/* delete a tetrahedra being part of the cavity */ -static inline HXTStatus deletedPush(HXTMesh* mesh, TetLocal* local, const uint64_t neigh){ - // check if 3 points of the new tetrahedra are owned by this thread - HXT_CHECK( checkTetrahedron((HXTVertex*) mesh->vertices.coord, local, mesh->tetrahedra.node + neigh*4) ); - local->deleted.tetID[local->deleted.num++] = neigh; - markTetAsDeleted(mesh, neigh); - - return HXT_STATUS_OK; -} - -/* check if the cavity is star shaped - This isn't usefull for pure Delaunay but when we constrain cavity with colors, - it is usefull */ -static HXTStatus isStarShaped(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t* blindFaceIndex) -{ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - double *vtaCoord = vertices[vta].coord; - - for (uint64_t i=0; i<local->ball.num; i++) { - if(local->ball.bnd[i].node[2]==HXT_GHOST_VERTEX){ - - } - else{ - double* b = vertices[local->ball.bnd[i].node[0]].coord; - double* c = vertices[local->ball.bnd[i].node[1]].coord; - double* d = vertices[local->ball.bnd[i].node[2]].coord; - if(orient3d(vtaCoord, b, c, d)<=0.0){ - *blindFaceIndex = i; - return HXT_STATUS_INTERNAL; - } - } - } - return HXT_STATUS_OK; -} - - -static HXTStatus undeleteTetrahedron(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t tetToUndelete) { - // the tetrahedra should not be deleted anymore - for (uint64_t i=local->deleted.num; ; i--) { - if(local->deleted.tetID[i-1]==tetToUndelete) { - local->deleted.num--; - local->deleted.tetID[i-1] = local->deleted.tetID[local->deleted.num]; - break; - } -#ifdef DEBUG - if(i==1) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "could not find the tetrahedra in the deleted array"); -#endif - } - unmarkTetAsDeleted(mesh, tetToUndelete); - - uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; - int nbndFace = 0; - - // we should update the boundary (that's the difficult part...) - // first remove all the boundary faces that come from the tetrahedron we just remove from the cavity - for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { - if(mesh->tetrahedra.neigh[local->ball.bnd[i-1].neigh]/4==tetToUndelete) { - bndFaces[nbndFace++] = local->ball.bnd[i-1].neigh; - local->ball.num--; - local->ball.bnd[i-1] = local->ball.bnd[local->ball.num]; - } - } - - // we must replace them by all the other faces of the tetrahedron we just removed - const uint64_t* __restrict__ curNeigh = mesh->tetrahedra.neigh + tetToUndelete*4; - const uint32_t* __restrict__ curNode = mesh->tetrahedra.node + tetToUndelete*4; - -#ifdef DEBUG - int nbndFace2 = (isTetDeleted(mesh, curNeigh[0]/4)==0) + (isTetDeleted(mesh, curNeigh[1]/4)==0) + (isTetDeleted(mesh, curNeigh[2]/4)==0) + (isTetDeleted(mesh, curNeigh[3]/4)==0); - if(nbndFace!=nbndFace2) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "found %d non-deleted tet adjacent to the tet we unremove but there should be %d %lu %lu %lu %lu", nbndFace, nbndFace2, bndFaces[0], bndFaces[1], bndFaces[2], bndFaces[3]); -#endif - - HXT_CHECK( reserveNewBnd(local, 3) ); - - if(curNeigh[0]!=bndFaces[0] && curNeigh[0]!=bndFaces[1] && curNeigh[0]!=bndFaces[2] && curNeigh[0]!=bndFaces[3]) - bndPush(local, (mesh->tetrahedra.flag[tetToUndelete] & 0x9) | - (isEdgeConstrained(mesh, tetToUndelete, 0 , 2)>>1) | - (isEdgeConstrained(mesh, tetToUndelete, 0 , 1)<<1), curNode[2], curNode[1], curNode[3], 4*tetToUndelete+0); - - if(curNeigh[1]!=bndFaces[0] && curNeigh[1]!=bndFaces[1] && curNeigh[1]!=bndFaces[2] && curNeigh[1]!=bndFaces[3]) - bndPush(local, ((mesh->tetrahedra.flag[tetToUndelete] & 0xD0)>>4) | - isEdgeConstrained(mesh, tetToUndelete, 0 , 1), curNode[0], curNode[2], curNode[3], 4*tetToUndelete+1); - - if(curNeigh[2]!=bndFaces[0] && curNeigh[2]!=bndFaces[1] && curNeigh[2]!=bndFaces[2] && curNeigh[2]!=bndFaces[3]) - bndPush(local, ((mesh->tetrahedra.flag[tetToUndelete] & 0x900)>>8) | - (isEdgeConstrained(mesh, tetToUndelete, 1 , 2)>>5) | - isEdgeConstrained(mesh, tetToUndelete, 0 , 2), curNode[1], curNode[0], curNode[3], 4*tetToUndelete+2); - - if(curNeigh[3]!=bndFaces[0] && curNeigh[3]!=bndFaces[1] && curNeigh[3]!=bndFaces[2] && curNeigh[3]!=bndFaces[3]) - bndPush(local, (isFacetConstrained(mesh, 4*tetToUndelete+3)>>12) | - (isEdgeConstrained(mesh, tetToUndelete, 0 , 3)>>2) | - (isEdgeConstrained(mesh, tetToUndelete, 1 , 3)>>5) | - (isEdgeConstrained(mesh, tetToUndelete, 2 , 3)>>8), curNode[0], curNode[1], curNode[2], 4*tetToUndelete+3); - - return HXT_STATUS_OK; -} - - -static HXTStatus reshapeCavityIfNeeded(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t prevDeleted) { - // we will remove the tetrahedra adjacent to the face that does not see the point, progressively, until the cavity is star shaped... - uint64_t blindFace = 0; - while(isStarShaped(local, mesh, vta, &blindFace)==HXT_STATUS_INTERNAL) - { - // printf("deleting %lu cavity:%lu ball:%lu\n",mesh->tetrahedra.neigh[local->ball.bnd[blindFace].neigh]/4, local->deleted.num-prevDeleted, local->ball.num ); - HXT_CHECK( undeleteTetrahedron(local, mesh, vta, mesh->tetrahedra.neigh[local->ball.bnd[blindFace].neigh]/4) ); - } - return HXT_STATUS_OK; -} - - -static HXTStatus respectEdgeConstraint(TetLocal* local, HXTMesh* mesh, const uint32_t vta, const uint16_t color, const uint64_t prevDeleted) { - // HXT_WARNING("a constrained edge was inside the cavity, recovering it"); - - // all the tetrahedron have the same color 'color', we will use that color to flag them - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.tetID[i]; - mesh->tetrahedra.colors[delTet] = 0; - } - - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.tetID[i]; - int exist = 1; - for (int j=0; exist && j<4; j++) { - for (int k=j+1; exist && k<4; k++) { - if(isEdgeConstrained(mesh, delTet, j, k) && (mesh->tetrahedra.colors[delTet] & (1U<<(j*4+k)))==0) { - // const int _UP_FACET[4][4] = {{-1, 2, 3, 1}, - // { 3,-1, 0, 2}, - // { 1, 3,-1, 0}, - // { 2, 0, 1,-1}}; - - // HXT_WARNING("found constrained edge %u-%u in tetrahedron %lu (%d %d) inside the cavity\n",mesh->tetrahedra.node[4*delTet+ _UP_FACET[j][k]], mesh->tetrahedra.node[4*delTet+ _UP_FACET[k][j]], delTet, j, k); - // turn around the edge to check if a facet is on the boundary of the cavity. If yes, the edge is processed... if not, we delete one tet. - int in_facet = j; - int out_facet = k; - - int edgeIsSafe = 0; - uint64_t curTet = delTet; - // first turn - do - { - uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; - - // go into the neighbor through out_facet - uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; - curTet = neigh/4; - in_facet = neigh%4; - - uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; - for (out_facet=0; out_facet<3; out_facet++) - if(nodes[out_facet]==newV) - break; - - if(isTetDeleted(mesh, curTet)!=0) { - // mark that the edge as been treate - #ifdef DEBUG - if((mesh->tetrahedra.colors[curTet] & (1U<<(in_facet<out_facet?in_facet*4+out_facet:out_facet*4+in_facet)))!=0) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "the flag says that the tet has already been processed for this edge..."); - #endif - mesh->tetrahedra.colors[curTet] |= (1U<<(in_facet*4+out_facet)) | (1U<<(out_facet*4+in_facet)); - } - else { - edgeIsSafe=1; - } - - // printf("edge %u-%u, tet %lu (%d %d) deleted:%u\n", mesh->tetrahedra.node[4*curTet+ _UP_FACET[in_facet][out_facet]], mesh->tetrahedra.node[4*curTet+ _UP_FACET[out_facet][in_facet]], curTet, in_facet, out_facet, isTetDeleted(mesh, curTet)!=0); - - } while (curTet!=delTet); - - if(!edgeIsSafe) { // we must find a tetrahedron on the opposite side of vta and delete it. - in_facet = j; - out_facet = k; - curTet = delTet; - - uint64_t tetContainingVta = local->deleted.tetID[prevDeleted]; - uint64_t tetToUndelete = HXT_NO_ADJACENT; - double distMax = 0.0; - double* vtaCoord = mesh->vertices.coord + 4*vta; - - #ifdef DEBUG - double* a = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta]; - double* b = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+1]; - double* c = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+2]; - double* d = mesh->vertices.coord + 4*mesh->tetrahedra.node[4*tetContainingVta+3]; - - if(orient3d(vtaCoord,b,c,d)<0.0 || orient3d(a,vtaCoord,c,d)<0.0 || orient3d(a,b,vtaCoord,d)<0.0 || orient3d(a,b,c,vtaCoord)<0.0) { - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "an edge part of a ghost tetrahedron is constrained"); - } - #endif - - do - { - uint32_t newV = mesh->tetrahedra.node[4*curTet + in_facet]; - - // go into the neighbor through out_facet - uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; - curTet = neigh/4; - in_facet = neigh%4; - - uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; - for (out_facet=0; out_facet<3; out_facet++) - if(nodes[out_facet]==newV) - break; - - double* coord1 = mesh->vertices.coord + newV; - double* coord2 = mesh->vertices.coord + nodes[in_facet]; - - if(curTet!=tetContainingVta) { - double dist = 0.0; - for (int l=0; l<3; l++) { - double meanCoord = (coord1[l]+coord2[l])*0.5; - double diff = meanCoord-vtaCoord[l]; - dist += diff*diff; - } - - if(dist>distMax) { - dist = distMax; - tetToUndelete = curTet; - } - } - } while (curTet!=delTet); - - if(tetToUndelete==delTet) - exist = 0; - - // printf("undeleting tetrahedron %lu\n", tetToUndelete); - mesh->tetrahedra.colors[tetToUndelete] = color; - HXT_CHECK( undeleteTetrahedron(local, mesh, vta, tetToUndelete) ); - } - } - } - } - } - - for (uint64_t i=prevDeleted; i<local->deleted.num; i++) { - uint64_t delTet = local->deleted.tetID[i]; - mesh->tetrahedra.colors[delTet] = color; - } - - return HXT_STATUS_OK; -} - - -/* this function does a Breadth-first search of the tetrahedra in the cavity - * it add those to local->deleted - * it also maintain a local->bnd array with all the information concerning the boundary of the cavity - */ -static inline HXTStatus diggingACavity(HXTMesh* mesh, TetLocal* local, uint64_t curTet, const uint32_t vta, int* edgeConstraint){ - // add tetrahedra to cavity - local->deleted.tetID[local->deleted.num++] = curTet; - markTetAsDeleted(mesh, curTet); - local->ball.num = 0; - - - - for(uint64_t start=local->deleted.num-1; start < local->deleted.num; start++){ - uint64_t curTet = local->deleted.tetID[start]; - const uint64_t* __restrict__ curNeigh = mesh->tetrahedra.neigh + 4*curTet; - const uint32_t* __restrict__ curNode = mesh->tetrahedra.node + 4*curTet; - - *edgeConstraint += isAnyEdgeConstrained(mesh, curTet)!=0; - - /* here we allocate enough space for the boundary (local->bnd), the cavity (local->deleted) and the vertices (local->vertices) */ - HXT_CHECK( reserveNewDeleted(local, 4) ); - HXT_CHECK( reserveNewBnd(local, 4) ); - - // we unrolled the loop for speed (also because indices are not trivial, we would need a 4X4 array) - - /* and here we push stuff to local->bnd or local->deleted, always keeping ghost tet at last place */ - uint64_t neigh = curNeigh[0]/4; - if(curNeigh[0]!=HXT_NO_ADJACENT && isTetDeleted(mesh, neigh)==0){ - if(isFacetConstrained(mesh, 4*curTet+0) || - tetInsphere(mesh, neigh*4, vta)<=0.0){ - bndPush(local, mesh->tetrahedra.flag[curTet] & 0xF, - curNode[1], curNode[2], curNode[3], curNeigh[0]); - } - else{ - HXT_CHECK( deletedPush(mesh, local, neigh) ); - } - } - - neigh = curNeigh[1]/4; - if(curNeigh[1]!=HXT_NO_ADJACENT && isTetDeleted(mesh, neigh)==0){ - if(isFacetConstrained(mesh, 4*curTet+1) || - tetInsphere(mesh, neigh*4, vta)<=0.0){ - bndPush(local, (isFacetConstrained(mesh, 4*curTet+1)>>4) | - (isEdgeConstrained(mesh, curTet, 1 , 2)>>5) | - (isEdgeConstrained(mesh, curTet, 0 , 1)<<1) | - (isEdgeConstrained(mesh, curTet, 1 , 3)>>4), - curNode[2], curNode[0], curNode[3], curNeigh[1]); - } - else{ - HXT_CHECK( deletedPush(mesh, local, neigh) ); - } - } - - neigh = curNeigh[2]/4; - if(curNeigh[2]!=HXT_NO_ADJACENT && isTetDeleted(mesh, neigh)==0){ - if(isFacetConstrained(mesh, 4*curTet+2)|| - tetInsphere(mesh, neigh*4, vta)<=0.0){ - bndPush(local, (isFacetConstrained(mesh, 4*curTet+2)>>8) | - (isEdgeConstrained(mesh, curTet, 0 , 2)>>1) | - (isEdgeConstrained(mesh, curTet, 1 , 2)>>4) | - (isEdgeConstrained(mesh, curTet, 2 , 3)>>8), - curNode[0], curNode[1], curNode[3], curNeigh[2]); - } - else{ - HXT_CHECK( deletedPush(mesh, local, neigh) ); - } - } - - neigh = curNeigh[3]/4; - if(curNeigh[3]!=HXT_NO_ADJACENT && isTetDeleted(mesh, neigh)==0){ - if(isFacetConstrained(mesh, 4*curTet+3) || - tetInsphere(mesh, neigh*4, vta)<=0.0){ - - bndPush(local, (isFacetConstrained(mesh, 4*curTet+3)>>12) | - (isEdgeConstrained(mesh, curTet, 1 , 3)>>6) | - (isEdgeConstrained(mesh, curTet, 0 , 3)>>1) | - (isEdgeConstrained(mesh, curTet, 2 , 3)>>8), - // there are 2 valid order for nodes: 1,0,2,3 and 0,2,1,3 - curNode[1], curNode[0], curNode[2], curNeigh[3]); - } - else{ - HXT_CHECK( deletedPush(mesh, local, neigh) ); - } - } - } - - return HXT_STATUS_OK; -} - - -/************************************************************** - * compute adjacencies with a matrix O(1) insertion and search - **************************************************************/ -#ifndef HXT_DELAUNAY_LOW_MEMORY -static inline HXTStatus computeAdjacenciesFast(HXTMesh* mesh, TetLocal* local, uint32_t* __restrict__ verticesID, const uint64_t blength){ - cavityBnd_t* __restrict__ bnd = local->ball.bnd; - -#ifndef NDEBUG - int ghost_is_there = 0; -#endif - -HXT_ASSERT(((size_t) bnd)%SIMD_ALIGN==0); -HXT_ASSERT(((size_t) verticesID)%SIMD_ALIGN==0); - -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp simd aligned(verticesID,bnd:SIMD_ALIGN) -#endif - for (uint32_t i=0; i<blength; i++){ - verticesID[bnd[i].node[0]] = UINT32_MAX; - verticesID[bnd[i].node[1]] = UINT32_MAX; - if(bnd[i].node[2]!=HXT_GHOST_VERTEX){ - verticesID[bnd[i].node[2]] = UINT32_MAX; - } - } - - uint32_t npts = 1; - for (uint32_t i=0; i<blength; i++) - { - if(verticesID[bnd[i].node[0]]>npts){ - verticesID[bnd[i].node[0]] = npts++; - } - bnd[i].node[0] = verticesID[bnd[i].node[0]]; - if(verticesID[bnd[i].node[1]]>npts){ - verticesID[bnd[i].node[1]] = npts++; - } - bnd[i].node[1] = verticesID[bnd[i].node[1]]; - - if(bnd[i].node[2]==HXT_GHOST_VERTEX){ - bnd[i].node[2] = 0; -#ifndef NDEBUG - ghost_is_there = 1; -#endif - } - else{ - if(verticesID[bnd[i].node[2]]>npts){ - verticesID[bnd[i].node[2]] = npts++; - } - bnd[i].node[2] = verticesID[bnd[i].node[2]]; - } - - } - - HXT_ASSERT_MSG((npts-3+ghost_is_there)*2==blength, "Failed to compute adjacencies (f) %u (%u ghost) vertices and %u cavity boundaries", npts-1+ghost_is_there, ghost_is_there, blength); // symbol undefined - -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp simd aligned(verticesID:SIMD_ALIGN) -#endif - for (uint32_t i=0; i<blength; i++) - { - local->Map[bnd[i].node[0]*32 + bnd[i].node[1]] = bnd[i].neigh + 3; - local->Map[bnd[i].node[1]*32 + bnd[i].node[2]] = bnd[i].neigh + 1; - local->Map[bnd[i].node[2]*32 + bnd[i].node[0]] = bnd[i].neigh + 2; - } - -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp simd aligned(verticesID:SIMD_ALIGN) -#endif - for (uint32_t i=0; i<blength; i++) - { - mesh->tetrahedra.neigh[bnd[i].neigh + 1] = local->Map[bnd[i].node[2]*32 + bnd[i].node[1]]; - mesh->tetrahedra.neigh[bnd[i].neigh + 2] = local->Map[bnd[i].node[0]*32 + bnd[i].node[2]]; - mesh->tetrahedra.neigh[bnd[i].neigh + 3] = local->Map[bnd[i].node[1]*32 + bnd[i].node[0]]; - } - - return HXT_STATUS_OK; -} -#endif - - -/************************************************************** - * compute adjacencies with a matrix O(n) insertion and search - **************************************************************/ -static inline HXTStatus computeAdjacenciesSlow(HXTMesh* mesh, TetLocal* local, const uint64_t start, const uint64_t blength){ - - uint64_t tlength = 0; - const uint64_t middle = blength*3/2; // 3N - - // N+2 point on the surface of the cavity - // 2N triangle on the surface of the cavity, x3 (4*0.5+1) data = 6N+9 uint64_t - // => enough place for the 3N edge x2 data = 6N uint64_t - uint64_t* Tmp = (uint64_t*) local->ball.bnd; - const unsigned index[4] = {2,3,1,2}; - - for (uint64_t i=0; i<blength; i++) - { - uint64_t curTet = local->deleted.tetID[start+ i]; - const uint32_t* __restrict__ Node = mesh->tetrahedra.node + 4*curTet; - - // pointer to the position of Node[0] in the Tmp array - for (unsigned j=0; j<3; j++) - { - // define the edge by the minimum vertex and the other - uint64_t key = ((uint64_t) Node[index[j]]<<32) + Node[index[j+1]]; - - // linear searching/pushing into Tmp - uint64_t k; - for (k=0; k<tlength; k++) // this is the only nested loop... the one that cost it all - { - __assume_aligned(Tmp, SIMD_ALIGN); - if(Tmp[k]==key) - break; - } - - uint64_t curFace = 4*curTet+j+1; - - // we did not found it - if(k==tlength){ - Tmp[tlength] = (key>>32) + (key<<32); - Tmp[middle + tlength] = curFace; - tlength++; - } - else{// we found the neighbour ! - uint64_t pairValue = Tmp[middle+k]; - mesh->tetrahedra.neigh[curFace] = pairValue; - mesh->tetrahedra.neigh[pairValue] = curFace; - tlength--; - if(k<tlength){// put the last entry in the one we just discovered - Tmp[k] = Tmp[tlength]; - Tmp[middle+k] = Tmp[middle + tlength]; - } - } - } - } - HXT_ASSERT_MSG(tlength==0, "Failed to compute adjacencies (s)"); // verify that all neighbor were found - return HXT_STATUS_OK; -} - - -/**************************************** - * filling back the cavity (DelaunayBall) - ****************************************/ -static inline HXTStatus fillingACavity(HXTMesh* mesh, TetLocal* local, uint32_t* __restrict__ verticesID, uint64_t* __restrict__ curTet, const uint32_t vta, const uint16_t color){ - uint64_t clength = local->deleted.num; - uint64_t blength = local->ball.num; - - uint64_t start = clength - blength; - - // #pragma vector aligned -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp simd -#endif - for (uint64_t i=0; i<blength; i++) - { - - __assume_aligned(local->deleted.tetID, SIMD_ALIGN); - __assume_aligned(local->ball.bnd, SIMD_ALIGN); - __assume_aligned(mesh->tetrahedra.colors, SIMD_ALIGN); - __assume_aligned(mesh->tetrahedra.flag, SIMD_ALIGN); - __assume_aligned(mesh->tetrahedra.node, SIMD_ALIGN); - __assume_aligned(mesh->tetrahedra.neigh, SIMD_ALIGN); - - const uint64_t newTet = local->deleted.tetID[i + start]; - uint32_t* __restrict__ Node = mesh->tetrahedra.node + 4*newTet; - mesh->tetrahedra.colors[newTet] = color; - mesh->tetrahedra.flag[newTet] = 0; - - /* we need to always put the ghost vertex at the fourth slot*/ - Node[0] = vta; - Node[1] = local->ball.bnd[i].node[0]; - Node[2] = local->ball.bnd[i].node[1]; - Node[3] = local->ball.bnd[i].node[2]; - - const uint64_t neigh = local->ball.bnd[i].neigh; - mesh->tetrahedra.neigh[4*newTet] = neigh; - - mesh->tetrahedra.flag[newTet] = local->ball.bnd[i].flag; - - // update neighbor's neighbor - mesh->tetrahedra.neigh[neigh] = 4*newTet; - - // we recycle neigh to contain newTet (used in computeAdjacencies) - local->ball.bnd[i].neigh = 4*newTet; - } -#ifndef HXT_DELAUNAY_LOW_MEMORY - if(blength<=58){ // N+2<=31 => N<=29 => 2N<=58 - #ifndef NDEBUG - HXT_CHECK( computeAdjacenciesFast(mesh, local, verticesID, blength) ); - #else - computeAdjacenciesFast(mesh, local, verticesID, blength); - #endif - } - else -#endif - { - #ifndef NDEBUG - HXT_CHECK(computeAdjacenciesSlow(mesh, local, start, blength) ); - #else - computeAdjacenciesSlow(mesh, local, start, blength); - #endif - } - - - - *curTet = local->deleted.tetID[start]; - local->deleted.num = start; - - return HXT_STATUS_OK; -} - - -/************************************************************* - * insert a single point - ************************************************************/ -static inline HXTStatus insertion(HXTMesh* mesh, - uint32_t* verticesID, - TetLocal* local, - const double* nodalSizes, - uint64_t* curTet, - const uint32_t vta, - int perfectlyDelaunay){ - const uint64_t prevDeleted = local->deleted.num; - - HXT_CHECK( walking2Cavity(mesh, local, curTet, vta) ); - - if(nodalSizes!=NULL && filterTet(mesh, nodalSizes, *curTet, vta)){ - return HXT_STATUS_FALSE; - } - - const uint16_t color = mesh->tetrahedra.colors[*curTet]; - int edgeConstraint = 0; - HXTStatus status = diggingACavity(mesh, local, *curTet, vta, &edgeConstraint); - - if(status==HXT_STATUS_INTERNAL){ - restoreDeleted(mesh, local, prevDeleted, color); - return HXT_STATUS_TRYAGAIN; - } - else{ - HXT_CHECK(status); - } - - if(edgeConstraint) { - HXT_CHECK( respectEdgeConstraint(local, mesh, vta, color, prevDeleted) ); - } - - // uint64_t face = 0; - // if(!perfectlyDelaunay && isStarShaped(local, mesh, vta, &face)==HXT_STATUS_INTERNAL) { - // restoreDeleted(mesh, local, prevDeleted, color); - // return HXT_STATUS_FALSE; - // } - - // reshape the cavity if it is not star shaped - if(!perfectlyDelaunay) - HXT_CHECK( reshapeCavityIfNeeded(local, mesh, vta, prevDeleted) ); - - if(nodalSizes!=NULL && filterCavity(local, mesh, nodalSizes, vta)) { - restoreDeleted(mesh, local, prevDeleted, color); - return HXT_STATUS_FALSE; - } - - - if(local->ball.num > local->deleted.num){ - uint64_t needed = MAX(DELETED_BUFFER_SIZE,local->ball.num)-local->deleted.num; - - uint64_t ntet; - - #pragma omp atomic capture - { ntet = mesh->tetrahedra.num; mesh->tetrahedra.num+=needed;} - - reserveNewTet(mesh); - reserveNewDeleted(local, needed); - -#if !defined(HAVE_NO_OPENMP_SIMD) - #pragma omp simd -#endif - for (uint64_t i=0; i<needed; i++){ - local->deleted.tetID[local->deleted.num+i] = ntet+i; - mesh->tetrahedra.flag[ntet+i] = 0; - markTetAsDeleted(mesh, ntet+i); - } - - local->deleted.num+=needed; - } - - HXT_CHECK( fillingACavity(mesh, local, verticesID, curTet, vta, color) ); - - return HXT_STATUS_TRUE; -} - - -/************************************************************* - * Delaunay triangulation of a set of points - ************************************************************/ -static HXTStatus parallelDelaunay3D(HXTMesh* mesh, - HXTDelaunayOptions* options, - hxtNodeInfo* nodeInfo, - const uint32_t nToInsert, - int noReordering) -{ - uint32_t totalNumSkipped = 0; - uint32_t seed = 1; - - // third, divide indices in different passes - const int maxThreads = options->delaunayThreads; - const int perfectlyDelaunay = mesh->tetrahedra.num<=5; - - uint32_t passes[12]; - unsigned npasses = computePasses(passes, options->numVerticesInMesh, nToInsert); - - // that ugly cast because people want an array of double into the mesh structure - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - - /****************************************************** - shuffle (and optimize cache locality) - ******************************************************/ - if(noReordering){ - // shuffle nodeInfo - HXT_CHECK( hxtNodeInfoShuffle(nodeInfo, nToInsert) ); - } - else { - HXT_INFO_COND(options->verbosity>1, "Reordering vertices from %u to %u", mesh->vertices.num - nToInsert, mesh->vertices.num); - HXTVertex* verticesToInsert = vertices + mesh->vertices.num - nToInsert; - - if(options->nodalSizes==NULL){ - // shuffle the vertices to insert, then sort each pass except the first according to the hilbert curve... - HXT_CHECK( hxtVerticesShuffle(verticesToInsert, nToInsert) ); - } - else{ - HXT_CHECK( hxtNodeInfoShuffle(nodeInfo, nToInsert) ); - } - - uint32_t nbits = hxtAdvancedHilbertBits(options->bbox, options->minSizeStart, options->minSizeEnd, - options->numVerticesInMesh, - options->numVerticesInMesh + nToInsert, - options->numVerticesInMesh + nToInsert/4, - nToInsert/2, - maxThreads); - - HXT_CHECK( hxtVerticesHilbertDist(options->bbox, verticesToInsert, nToInsert, &nbits, NULL) ); - - if(options->nodalSizes==NULL){ - for (unsigned i=options->numVerticesInMesh < SMALLEST_ROUND; i<npasses; i++) { - HXT_CHECK( hxtVerticesSort(verticesToInsert+passes[i], passes[i+1]-passes[i], nbits) ); - } - } - else{ - #pragma omp parallel for - for (int i=0; i<nToInsert; i++) { - nodeInfo[i].hilbertDist = verticesToInsert[i].padding.hilbertDist; - } - - for (unsigned i=options->numVerticesInMesh < SMALLEST_ROUND; i<npasses; i++) { - HXT_CHECK( hxtNodeInfoSort(nodeInfo+passes[i], passes[i+1]-passes[i], nbits) ); - } - - const uint32_t nodalMin = mesh->vertices.num - nToInsert; - double* sizesToInsert = options->nodalSizes + nodalMin; - - size_t vertSize = nToInsert*sizeof(HXTVertex); - size_t sizeSize = nToInsert*sizeof(double); - HXTVertex* vertCopy; - double* sizeCopy; - HXT_CHECK( hxtAlignedMalloc(&vertCopy, vertSize) ); - HXT_CHECK( hxtAlignedMalloc(&sizeCopy, sizeSize) ); - - #pragma omp parallel for - for (uint32_t i=0; i<nToInsert; i++) { - vertCopy[i] = verticesToInsert[nodeInfo[i].node-nodalMin]; - sizeCopy[i] = sizesToInsert[nodeInfo[i].node-nodalMin]; - nodeInfo[i].node = nodalMin + i; - } - - memcpy(verticesToInsert, vertCopy, vertSize); - memcpy(sizesToInsert, sizeCopy, sizeSize); - - HXT_CHECK( hxtAlignedFree(&vertCopy) ); - HXT_CHECK( hxtAlignedFree(&sizeCopy) ); - } - } - - /****************************************************** - Initializations and allocations - ******************************************************/ - if(mesh->tetrahedra.num<5){ - HXT_INFO_COND(options->verbosity>0, - "Initialization of tet. mesh"); - HXT_CHECK( hxtTetrahedraInit(mesh, nodeInfo, nToInsert, options->verbosity) ); - options->numVerticesInMesh = 4; // not counting the ghost vertex - passes[0] = 4; - } - - - uint32_t* verticesID; -#ifdef HXT_DELAUNAY_LOW_MEMORY - verticesID = NULL; // we do not need it -#else - HXT_CHECK( hxtAlignedMalloc(&verticesID, mesh->vertices.num*sizeof(uint32_t)) ); -#endif - - TetLocal* Locals; - HXT_CHECK( hxtMalloc(&Locals, maxThreads*sizeof(TetLocal)) ); - // HXT_CHECK( hxtMalloc()) - - for (int i=0; i<maxThreads; i++) - localInit(&Locals[i]); - - - HXT_INFO_COND(options->verbosity>0, - "Delaunay of %10u vertices on %3d threads\t- mesh.nvert: %-10u", - passes[npasses] - passes[0], maxThreads, options->numVerticesInMesh); - - for (uint32_t p=0; p<npasses; p++) - { - - double percent = 200; - int nthreads = 1; - uint32_t tmp = (passes[p+1]-passes[p])/SMALLEST_ROUND; - while(tmp>0 && nthreads<maxThreads){ - tmp = tmp/2; - nthreads*=2; - } - nthreads = MIN(nthreads, maxThreads); - - // const uint32_t initialPassLength = passes[p+1] - passes[p]; - - for(uint32_t n=0; passes[p+1]-passes[p]; n++) - { - const uint32_t passStart = passes[p]; - const uint32_t passEnd = passes[p+1]; - const uint32_t passLength = passEnd - passStart; - - /****************************************************** - choosing number of threads - ******************************************************/ - if(percent<140/nthreads || passLength<SMALLEST_ROUND){ - nthreads=1; - } - else if(percent<20){ - nthreads=(nthreads+1)/2; - } - else if(passLength < nthreads*SMALLEST_ROUND) - nthreads=(nthreads+1)/2; - - - /****************************************************** - Sorting vertices - ******************************************************/ - double hxtDeclareAligned bboxShift[4]={0.5,0.5,0.5,0}; - - if(percent<100 && nthreads>1) - { - bboxShift[0] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; - bboxShift[1] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; - bboxShift[2] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; - bboxShift[3] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; // this is not a bbox deformation, it's an index shift - } - - uint32_t nbits = hxtAdvancedHilbertBits(options->bbox, options->minSizeStart, options->minSizeEnd, - options->numVerticesInMesh - passStart, - options->numVerticesInMesh - passStart + nToInsert, - options->numVerticesInMesh, - passLength, - nthreads); - if(noReordering){ - HXT_CHECK( hxtVerticesHilbertDist(options->bbox, vertices, mesh->vertices.num, &nbits, bboxShift) ); - } - else{ - // TODO: do not recompute hilber dist of the whole mesh on 1 thread - HXT_CHECK( hxtVerticesHilbertDist(options->bbox, vertices, mesh->vertices.num - nToInsert + passEnd, &nbits, bboxShift) ); - } - - - #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) - for (uint32_t i=passStart; i<passEnd; i++) { - nodeInfo[i].hilbertDist = vertices[nodeInfo[i].node].padding.hilbertDist; - } - - if(p!=0 || n!=0 || nthreads>1 || options->numVerticesInMesh >= SMALLEST_ROUND){ - HXT_CHECK( hxtNodeInfoSort(nodeInfo + passStart, passLength, nbits) ); - } - - const uint32_t step = passLength/nthreads; - - uint32_t indexShift = MIN(step-1,(uint32_t) bboxShift[3]*step); - - int threadFinished = 0; - - #pragma omp parallel num_threads(nthreads) - { - #ifdef _MSC_VER - #pragma omp single - nthreads = omp_get_num_threads(); - #endif - - uint64_t curTet = 0; // we always begin with the first tet. (index 0) - const int threadID = omp_get_thread_num(); - - uint32_t localStart; - uint32_t localN; - int foundTet = 0; - - if(nthreads>1){ - // if(threadID<nthreads){ - - /****************************************************** - Making partitions - ******************************************************/ - localStart = step*threadID + indexShift; - uint64_t dist = nodeInfo[passStart + localStart].hilbertDist; - - uint32_t up = 1; - while(localStart+up<passLength && dist==nodeInfo[passStart + localStart + up].hilbertDist) - up++; - - localStart = localStart+up==passLength?0:localStart+up; - if(localStart > 0) - Locals[threadID].partition.startDist = (nodeInfo[passStart + localStart].hilbertDist - + nodeInfo[passStart + localStart - 1].hilbertDist + 1)/2; - else - Locals[threadID].partition.startDist = nodeInfo[passStart + passLength-1].hilbertDist + (nodeInfo[passStart + localStart].hilbertDist - nodeInfo[passStart + passLength - 1].hilbertDist)/2; - Locals[threadID].partition.first = localStart; - // } - - #pragma omp barrier - - // if(threadID<nthreads){ - uint32_t localEnd = Locals[(threadID+1)%nthreads].partition.first; - localN = (localEnd + passLength - localStart)%passLength; - - Locals[threadID].partition.endDist = Locals[(threadID+1)%nthreads].partition.startDist; - - // printf("%d) first dist: %lu, last dist: %lu startDist: %lu endDist: %lu\n", threadID, nodeInfo[passStart + localStart].hilbertDist, nodeInfo[(passStart + localStart + localN-1)%passLength].hilbertDist, Locals[threadID].partition.startDist, Locals[threadID].partition.endDist); - - - /****************************************************** - find starting tetrahedron - ******************************************************/ - - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { - curTet = i; - if(isTetDeleted(mesh, i)==0 && - checkTetrahedron(vertices, &Locals[threadID], mesh->tetrahedra.node + curTet*4 )==HXT_STATUS_OK) - { - foundTet = 1; - break; - } - } - - if(options->reproducible){ - Locals[threadID].partition.startDist = 0; - Locals[threadID].partition.endDist = UINT64_MAX; - - // walk in total liberty toward the first point - HXTStatus status = walking2Cavity(mesh, &Locals[threadID], &curTet, nodeInfo[passStart + (localStart+localN/2)%passLength].node); - - if(status!=HXT_STATUS_OK && status!=HXT_STATUS_TRYAGAIN){ - HXT_OMP_CHECK( status ); - } - - Locals[threadID].partition.startDist = nodeInfo[passStart + localStart].hilbertDist; - Locals[threadID].partition.endDist = nodeInfo[passStart + localEnd].hilbertDist; - - if(checkTetrahedron(vertices, &Locals[threadID], mesh->tetrahedra.node + curTet*4 )!=HXT_STATUS_OK){ - foundTet = 0; - // check the neighbors - for (unsigned i=0; i<4; i++) { - uint64_t tet = mesh->tetrahedra.neigh[4*curTet+i]/4; - if(checkTetrahedron(vertices, &Locals[threadID], mesh->tetrahedra.node + tet*4 )==HXT_STATUS_OK){ - foundTet = 1; - curTet = tet; - break; - } - } - } - } - - // } - - #pragma omp barrier - } - else - // if(threadID==0) - { - - /****************************************************** - single-thread partition and starting tetrahedron - ******************************************************/ - localStart = 0; - localN = passLength; - Locals[0].partition.startDist = 0; - Locals[0].partition.endDist = UINT64_MAX; - - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { - if(isTetDeleted(mesh, i)==0){ - curTet = i; - foundTet = 1; - break; - } - } - } - - if (foundTet == 0) { - HXT_INFO_COND(options->verbosity>1, - "thread %d did not find any tetrahedron to begin with", threadID); - } - - // filtering vertices on the Moore curve - if(options->nodalSizes!=NULL) - { - double* p1 = NULL; - double p1Size = 0; - - for (uint32_t i=0; i<localN; i++) - { - uint32_t passIndex = (localStart+i)%passLength; - uint32_t lastNode = nodeInfo[passStart + passIndex].node; - if(nodeInfo[passStart + passIndex].status==HXT_STATUS_TRYAGAIN){ - double* p2 = vertices[lastNode].coord; - double p2Size = options->nodalSizes[lastNode]; - if(p1!=NULL && pointIsTooClose(p1, p2, 0.5*(p1Size+p2Size))!=HXT_STATUS_OK){ - nodeInfo[passStart + passIndex].status=HXT_STATUS_FALSE; - } - else{ - p1 = p2; - p1Size = p2Size; - } - } - } - } - - - // if(threadID<nthreads){ - if(foundTet!=0){ - - /****************************************************** - vertices insertion - ******************************************************/ - for (uint32_t i=0; i<localN; i++) - { - uint32_t passIndex = (localStart+i)%passLength; - uint32_t vta = nodeInfo[passStart + passIndex].node; - if(nodeInfo[passStart + passIndex].status==HXT_STATUS_TRYAGAIN){ - HXTStatus status = insertion(mesh, verticesID, &Locals[threadID], options->nodalSizes, &curTet, vta, perfectlyDelaunay); - - switch(status){ - case HXT_STATUS_TRYAGAIN: - // ; - if(nthreads==1){ - double* vtaCoord = vertices[vta].coord; - HXT_WARNING("skipping supposedly duplicate vertex (%f %f %f)", vtaCoord[0], vtaCoord[1], vtaCoord[2]); - nodeInfo[passStart + passIndex].status = HXT_STATUS_FALSE; - break; - } - case HXT_STATUS_FALSE: - case HXT_STATUS_TRUE: - nodeInfo[passStart + passIndex].status = status; - break; - default: // error other than HXT_STATUS_TRYAGAIN cause the program to return - nodeInfo[passStart + passIndex].status = HXT_STATUS_TRYAGAIN; - HXT_OMP_CHECK( status ); - break; - } - } - else{ - nodeInfo[passStart + passIndex].status = HXT_STATUS_FALSE; - } - } - } - // } - - #pragma omp atomic update - threadFinished++; - - int val = 0; - do{ - // threads are waiting here for a reallocation - HXT_OMP_CHECK( synchronizeReallocation(mesh, &threadFinished, &val) ); - }while(val<nthreads); - // }while(val<maxThreads); - } - - /****************************************************** - vertices that have to be tried again are put at the end - ******************************************************/ - // everything above i+shift is HXT_STATUS_TRYAGAIN - uint32_t shift = 0; - unsigned numSkipped = 0; - for (uint32_t i=passEnd; i>passStart;) - { - i--; - if(nodeInfo[i].status!=HXT_STATUS_TRYAGAIN){ - if(nodeInfo[i].status==HXT_STATUS_FALSE) - numSkipped++; - shift++; - } - else if(shift!=0) { - hxtNodeInfo tmp = nodeInfo[i]; - nodeInfo[i] = nodeInfo[i+shift]; - nodeInfo[i+shift] = tmp; - } - } - - options->numVerticesInMesh += shift - numSkipped; - - percent = (shift-numSkipped)*100.0/MAX(1,passLength-numSkipped); - totalNumSkipped += numSkipped; - - HXT_INFO_COND(options->verbosity>1, - "%3d thrd |%10u/%-10u-> %*.1f%-*c\t- mesh.nvert: %-10u", - nthreads, shift-numSkipped, passLength-numSkipped, MIN(8,n/2)+5, percent, 8-MIN(8,n/2),'%', options->numVerticesInMesh); - - passes[p] += shift; - } - } - - /****************************************************** - Cleaning - ******************************************************/ - #pragma omp parallel num_threads(maxThreads) - { - const int threadID = omp_get_thread_num(); - for (uint64_t i=0; i<Locals[threadID].deleted.num; i++) { - for (int j=0; j<4; j++) { - mesh->tetrahedra.neigh[4*Locals[threadID].deleted.tetID[i]+j] = HXT_NO_ADJACENT; - } - } - } - HXT_CHECK( hxtRemoveDeleted(mesh) ); - - for (int i=0; i<maxThreads; i++){ - HXT_CHECK( hxtAlignedFree(&Locals[i].deleted.tetID) ); - HXT_CHECK( hxtAlignedFree(&Locals[i].ball.bnd) ); - } - - HXT_CHECK( hxtAlignedFree(&verticesID) ); - HXT_CHECK( hxtFree(&Locals) ); - - /*************************************************************** - if reordering allowed, remove vertices we could not insert - ***************************************************************/ - if(!noReordering && totalNumSkipped!=0){ - /* remove deleted vertices and change tetrahedra.node accordingly */ - - uint32_t* numInserted; - HXT_CHECK( hxtAlignedMalloc(&numInserted, omp_get_max_threads()*sizeof(uint32_t)) ); - - uint32_t firstShifted = mesh->vertices.num - nToInsert; - uint32_t n = nToInsert; - - // when a vertex was skipped, nodeInfo[i].status = HXT_STATUS_FALSE - #pragma omp parallel - { - // 1st: mark vertices with their corresponding status - #pragma omp for schedule(static) - for (uint32_t i=0; i<nToInsert; i++) { - uint32_t index = nodeInfo[i].node; - HXTStatus status = nodeInfo[i].status; - vertices[index].padding.status = status; - }// implicit barrier here - - #pragma omp single - { - uint32_t i = 0; - while (vertices[firstShifted+i].padding.status==HXT_STATUS_TRUE) i++; - - firstShifted += i+1; - n -= i+1; - }// implicit barrier here - - uint32_t start = 0; - int threadID = omp_get_thread_num(); - numInserted[threadID] = 0; - - #pragma omp for schedule(static) - for (uint32_t i=0; i<n; i++) { - if(vertices[firstShifted+i].padding.status==HXT_STATUS_TRUE) - numInserted[threadID]++; - }// implicit barrier here - - for (int i=0; i<threadID; i++) { - start+=numInserted[i]; - } - start += firstShifted-1; - - // 3rd: compute where each vertices will be - #pragma omp for schedule(static) - for (uint32_t i=0; i<n; i++) { - uint32_t oldStart = start; - - if(vertices[firstShifted+i].padding.status==HXT_STATUS_TRUE) - start++; - - // index and status are at the same location (it's a union) we cannot put this above the "if" ! - vertices[firstShifted+i].padding.index = oldStart; - } - - // 4th: update tetrahedra.node accordingly - #pragma omp for - for (uint64_t i=0; i<4*mesh->tetrahedra.num; i++) { - uint32_t index = mesh->tetrahedra.node[i]; - if(index>=firstShifted && index!=HXT_GHOST_VERTEX) - mesh->tetrahedra.node[i] = vertices[index].padding.index; - } - } - - HXT_CHECK( hxtAlignedFree(&numInserted) ); - - // 5th: put vertices at the right indices - for (uint32_t i=firstShifted; i<mesh->vertices.num; i++) { - if(options->nodalSizes!=NULL){ - options->nodalSizes[vertices[i].padding.index] = options->nodalSizes[i]; - } - vertices[vertices[i].padding.index] = vertices[i]; - } - - if(options->verbosity>1) - HXT_INFO("%u vertices removed (vertices not inserted in the mesh are removed when using hxtDelaunay)\n", totalNumSkipped); - - mesh->vertices.num = mesh->vertices.num - totalNumSkipped; - } - - HXT_INFO_COND(options->verbosity>0, "Delaunay done !%10u skipped", totalNumSkipped); - HXT_INFO_COND(options->verbosity>1, "mem. allocated:%5.2fGB - mesh.ntet: %-12lu - mesh.nvert: %-10lu", - ((50 + 2*(mesh->tetrahedra.flag!=NULL)) * mesh->tetrahedra.size + - (32 + 8*(options->nodalSizes!=NULL)) * mesh->vertices.size)/(1024.*1024.*1024.), - mesh->tetrahedra.num, mesh->vertices.num); - - if(options->reproducible && maxThreads!=1){ - HXT_INFO_COND(options->verbosity>1, "Reordering tetrahedra (reproducible==true)\n", mesh->vertices.num - nToInsert, mesh->vertices.num); - HXT_CHECK( hxtTetReorder(mesh) ); - } - - return HXT_STATUS_OK; -} - - -/***************************************** - * complete the HXTDelaunayOptions struct - * when there are missing fields. - ****************************************/ -static HXTStatus DelaunayOptionsInit(HXTMesh* mesh, - HXTDelaunayOptions* userOptions, - HXTDelaunayOptions* options, - HXTBbox* bbox){ -HXT_ASSERT(mesh!=NULL); - - if(userOptions!=NULL){ - options->bbox = userOptions->bbox; - options->nodalSizes = userOptions->nodalSizes; - options->verbosity = userOptions->verbosity; - options->minSizeStart = MAX(0.0, userOptions->minSizeStart); - options->minSizeEnd = MAX(options->minSizeStart, userOptions->minSizeEnd); - options->numVerticesInMesh = userOptions->numVerticesInMesh; - options->delaunayThreads = userOptions->delaunayThreads; - options->reproducible = userOptions->reproducible; - } - else{ - HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - - // default parameters - options->bbox = NULL; - options->nodalSizes = NULL; - options->minSizeStart = 0.0; - options->minSizeEnd = 0.0; - options->verbosity = 1; - options->delaunayThreads = 0; - options->reproducible = 0; - - // count the number of vertices in the mesh - #pragma omp parallel for - for (uint32_t i=0; i<mesh->vertices.num; i++) { - vertices[i].padding.index = 0; - } - - #pragma omp parallel for - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { - vertices[mesh->tetrahedra.node[4*i+0]].padding.index = 1; - vertices[mesh->tetrahedra.node[4*i+1]].padding.index = 1; - vertices[mesh->tetrahedra.node[4*i+2]].padding.index = 1; - if(mesh->tetrahedra.node[4*i+3]!=HXT_GHOST_VERTEX) - vertices[mesh->tetrahedra.node[4*i+3]].padding.index = 1; - } - - uint32_t numVerticesInMesh = 0; - #pragma omp parallel for reduction(+:numVerticesInMesh) - for (uint32_t i=0; i<mesh->vertices.num; i++) { - numVerticesInMesh += vertices[i].padding.index; - } - - options->numVerticesInMesh = numVerticesInMesh; - } - -HXT_ASSERT(options->numVerticesInMesh <= mesh->vertices.num); - - if(options->bbox==NULL){ - options->bbox = bbox; - hxtBboxInit(bbox); - HXT_CHECK( hxtBboxAdd(bbox, mesh->vertices.coord, mesh->vertices.num) ); - } - - if(options->delaunayThreads==0) - options->delaunayThreads = omp_get_max_threads(); - else if(options->delaunayThreads<0) - options->delaunayThreads = omp_get_num_procs(); - - if(options->delaunayThreads>omp_get_thread_limit()) - options->delaunayThreads = omp_get_thread_limit(); - - // for the predicates to work - exactinit(options->bbox->max[0]-options->bbox->min[0], - options->bbox->max[1]-options->bbox->min[1], - options->bbox->max[2]-options->bbox->min[2]); - - return HXT_STATUS_OK; -} - - -/***************************************** - * parallel Delaunay - * see header for a complete description - ****************************************/ -HXTStatus hxtDelaunay(HXTMesh* mesh, HXTDelaunayOptions* userOptions){ - HXTDelaunayOptions options; - HXTBbox bbox; - HXT_CHECK( DelaunayOptionsInit(mesh, userOptions, &options, &bbox) ); - - const uint32_t nToInsert = mesh->vertices.num - options.numVerticesInMesh; - - if(options.reproducible && nToInsert<2048) // not worth launching threads and having to reorder tets after... - options.delaunayThreads = 1; - - hxtNodeInfo* nodeInfo; - HXT_CHECK( hxtAlignedMalloc(&nodeInfo, nToInsert*sizeof(hxtNodeInfo)) ); - - // we fill nodeInfo with the indices of each vertices to insert... - #pragma omp parallel for simd - for (uint32_t i=0; i<nToInsert; i++) { - nodeInfo[i].node = options.numVerticesInMesh + i; - nodeInfo[i].status = HXT_STATUS_TRYAGAIN; // necessary for when foundTet = 0; - } - - HXT_CHECK( parallelDelaunay3D(mesh, &options, nodeInfo, nToInsert, 0) ); - - HXT_CHECK( hxtAlignedFree(&nodeInfo) ); - - return HXT_STATUS_OK; -} - - -/************************************************ - * parallel Delaunay without moving the vertices - * see header for a complete description - ***********************************************/ -HXTStatus hxtDelaunaySteadyVertices(HXTMesh* mesh, HXTDelaunayOptions* userOptions, hxtNodeInfo* nodeInfo, uint64_t nToInsert){ -HXT_ASSERT(nodeInfo!=NULL); - - HXTDelaunayOptions options; - HXTBbox bbox; - HXT_CHECK( DelaunayOptionsInit(mesh, userOptions, &options, &bbox) ); - - if(options.reproducible && nToInsert<2048) // not worth launching threads and having to reorder tets after... - options.delaunayThreads = 1; - -HXT_ASSERT(options.numVerticesInMesh+nToInsert <= mesh->vertices.num); - - HXT_CHECK( parallelDelaunay3D(mesh, &options, nodeInfo, nToInsert, 1) ); - - return HXT_STATUS_OK; -} - diff --git a/contrib/hxt/hxt_tetrahedra.h b/contrib/hxt/hxt_tetrahedra.h deleted file mode 100644 index 5511dd5b93..0000000000 --- a/contrib/hxt/hxt_tetrahedra.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _HXT_TETRAHEDRA_ -#define _HXT_TETRAHEDRA_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "hxt_mesh.h" -#include "hxt_vertices.h" - -/** -* \file tetrahedra.h Delaunay tetrahedrization -* \author Célestin Marot -*/ - -/** - * \struct HXTDelaunayOptions - * - * Options for the Delaunay functions hxtDelaunay() and hxtDelaunaySteadyVertices() - * - * - */ -typedef struct { - HXTBbox* bbox; /**< The bounding box for all vertices. - * - if bbox==NULL, the bbox is recomputed internally; - * - if bbox!=NULL, bbox must contain all vertices */ - - double* nodalSizes; /**< - * - if nodalSize==NULL, doesn't restrict nodalSize; - * - if nodalSize!=NULL, nodalSize contains the minimum - * mesh size at each vertex.\n - * If the insertion of a vertex create an edge smaller than - * the average nodalSize of its endpoints, the vertex is - * not inserted - * \warning a segmentation fault will occur if a vertex - * doesn't have a corresponding mesh size */ - - double minSizeStart; /**< estimate of the minimum mesh size at the moment of the call. - * 0 if the mesh is empty or if the distribution is uniform - * (the mesh size is then guessed with the number of point) */ - double minSizeEnd; /**< estimate of the minimum mesh size when all points are inserted in the Delaunay. - * 0 if the distribution is uniform - * (the mesh size is then guessed with the number of point) */ - - uint32_t numVerticesInMesh; /**< The number of vertices in the mesh */ - - int verbosity; /**< - * - if verbosity<=0: don't print information. - * - if verbosity==1: print basic information on each pass - * - if verbosity>=2: print everything */ - - int reproducible; /**< If reproducible!=0, the Delaunay use a reproducible tetrahedra order - * in order to be totally deterministic. - * \warning this takes time ! - * It requires a total reordering of tetrahedra at the end to get a reproducible order\n - * except if `delaunayThreads==1 || (delaunayThreads==0 && omp_get_max_threads()==1)`\n - * in which case it is reproducible anyway */ - - int delaunayThreads; /**< number of threads for the delaunay insertion - * - if delaunayThreads==0, it will use omp_get_max_threads() - * - if delaunayThreads<0, it will uses omp_get_num_procs() */ -} HXTDelaunayOptions; - - -/** - * \brief Delaunay of a set of vertices that does not modify their order - * \details This perform the insertion of the vertices whose indices are - * given in nodeInfo (in the \ref hxtNodeInfo.node wtructure member)\n - * This function does not change the order of vertices in the mesh.\n - * \ref hxtNodeInfo.status will be modified by the function to tell - * if the vertex was successfully inserted or not. - * - nodeInfo[i].status==HXT_STATUS_TRUE if the vertex was successfully inserted. - * - nodeInfo[i].status==HXT_STATUS_FALSE if the vertex was not inserted. - * - nodeInfo[i].status==HXT_STATUS_TRYAGAIN if an error occured before the vertex could be inserted - * - * \warning - * - the order of nodeInfo will change - * - hxtNodeInfo[i].hilbertDist will change - * - mesh->tetrahedra.* will change - * - mesh->vertices.coord[4*i+3] will change - * - * \param mesh: a valid Delaunay mesh - * \param options: options to give to the Delaunay algorithm \ref HXTDelaunayOptions - * \param[in, out] nodeInfo: the indices of the vertices to insert in the tetrahedral mesh. - * \param nToInset: the number of element in nodeInfo, hence the number of vertices to insert. - */ -HXTStatus hxtDelaunaySteadyVertices(HXTMesh* mesh, HXTDelaunayOptions* options, hxtNodeInfo* nodeInfo, uint64_t nToInsert); - - -/** - * \brief Delaunay of a set of vertices - * \details This perform the insertion of the vertices - * from numVerticesInMesh to mesh->vertices.num\n - * - * \warning - * - the order of mesh->vertices will change - * - hxtNodeInfo[i].hilbertDist will change - * - mesh->tetrahedra.* will change - * - mesh->vertices.coord[4*i+3] will change - * - vertices that could not be inserted are deleted from mesh->vertices ! - * - * \param mesh: a valid Delaunay mesh - * \param options: options to give to the Delaunay algorithm \ref HXTDelaunayOptions - */ -HXTStatus hxtDelaunay(HXTMesh* mesh, HXTDelaunayOptions* options); - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/contrib/hxt/hxt_tools.c b/contrib/hxt/hxt_tools.c deleted file mode 100644 index f12fbcae51..0000000000 --- a/contrib/hxt/hxt_tools.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "hxt_api.h" -#include "hxt_tools.h" - -HXTStatus hxtNorm2V(double v[3], int size, double* norm2){ - *norm2=0.0; - for(int i=0; i<size; i++) - *norm2+=v[i]*v[i]; - *norm2 = sqrt(*norm2); - return HXT_STATUS_OK; -} - -HXTStatus hxtNorm2V3(double v[3], double* norm2){ - *norm2 = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); - return HXT_STATUS_OK; -} - -HXTStatus hxtNormalizeV(double *v, int size){ - double norm=0.0; - hxtNorm2V(v,size,&norm); - for(int i=0; i<size; i++) - v[i] /= norm; - return HXT_STATUS_OK; -} - -HXTStatus hxtNormalizeV3(double v[3]){ - double norm=0.0; - hxtNorm2V3(v,&norm); - v[0] /= norm; - v[1] /= norm; - v[2] /= norm; - return HXT_STATUS_OK; -} - -HXTStatus hxtCrossProductV3(double a[3], double b[3], double res[3]){ - res[0] = a[1]*b[2] - a[2]*b[1]; - res[1] = a[2]*b[0] - a[0]*b[2]; - res[2] = a[0]*b[1] - a[1]*b[0]; - return HXT_STATUS_OK; -} - -HXTStatus hxtDet2x2(double mat[2][2], double* det){ - *det = mat[0][0]*mat[1][1]-mat[0][1]*mat[1][0]; - return HXT_STATUS_OK; -} - -HXTStatus hxtInv2x2(double mat[2][2], double inv[2][2], double *det){ - hxtDet2x2(mat,det); - if(*det) { - const double ud = 1. / *det; - inv[0][0] = mat[1][1] * ud; - inv[0][1] = -mat[0][1] * ud; - inv[1][0] = -mat[1][0] * ud; - inv[1][1] = mat[0][0] * ud; - } else { - return HXT_STATUS_ERROR; - } - return HXT_STATUS_OK; -} - -HXTStatus hxtDet3x3(double mat[3][3], double *det) -{ - *det = (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) - - mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) + - mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0])); - return HXT_STATUS_OK; -} - -HXTStatus hxtInv3x3(double mat[3][3], double inv[3][3], double *det) -{ - HXT_CHECK(hxtDet3x3(mat, det)); - if(*det){ - double ud = 1. / *det; - inv[0][0] = (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) * ud; - inv[1][0] = -(mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) * ud; - inv[2][0] = (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) * ud; - inv[0][1] = -(mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) * ud; - inv[1][1] = (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * ud; - inv[2][1] = -(mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) * ud; - inv[0][2] = (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * ud; - inv[1][2] = -(mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]) * ud; - inv[2][2] = (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]) * ud; - return HXT_STATUS_OK; - } - else{ - for(int i = 0; i < 3; i++) - for(int j = 0; j < 3; j++) - inv[i][j] = 0.; - return HXT_ERROR_MSG(HXT_STATUS_FAILED, "Singular matrix 3x3"); - } -} - -HXTStatus hxtInv4x4ColumnMajor(double m[16], double invOut[16], double *det) -{ - double inv[16]; - int i; - - inv[ 0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; - inv[ 4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; - inv[ 8] = m[4] * m[ 9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[ 9]; - inv[12] = -m[4] * m[ 9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[ 9]; - inv[ 1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; - inv[ 5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; - inv[ 9] = -m[0] * m[ 9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[ 9]; - inv[13] = m[0] * m[ 9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[ 9]; - inv[ 2] = m[1] * m[ 6] * m[15] - m[1] * m[ 7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[ 7] - m[13] * m[3] * m[ 6]; - inv[ 6] = -m[0] * m[ 6] * m[15] + m[0] * m[ 7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[ 7] + m[12] * m[3] * m[ 6]; - inv[10] = m[0] * m[ 5] * m[15] - m[0] * m[ 7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[ 7] - m[12] * m[3] * m[ 5]; - inv[14] = -m[0] * m[ 5] * m[14] + m[0] * m[ 6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[ 6] + m[12] * m[2] * m[ 5]; - inv[ 3] = -m[1] * m[ 6] * m[11] + m[1] * m[ 7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[ 9] * m[2] * m[ 7] + m[ 9] * m[3] * m[ 6]; - inv[ 7] = m[0] * m[ 6] * m[11] - m[0] * m[ 7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[ 8] * m[2] * m[ 7] - m[ 8] * m[3] * m[ 6]; - inv[11] = -m[0] * m[ 5] * m[11] + m[0] * m[ 7] * m[ 9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[ 9] - m[ 8] * m[1] * m[ 7] + m[ 8] * m[3] * m[ 5]; - inv[15] = m[0] * m[ 5] * m[10] - m[0] * m[ 6] * m[ 9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[ 9] + m[ 8] * m[1] * m[ 6] - m[ 8] * m[2] * m[ 5]; - - *det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; - - if(*det == 0) - return HXT_STATUS_ERROR; - - double invDet = 1.0 / *det; - - for(i = 0; i < 16; i++) - invOut[i] = inv[i] * invDet; - - return HXT_STATUS_OK; -} - -HXTStatus hxtJacobianLinTet(double *x , double *y, double *z , double mat[3][3]){ - mat[0][0] = x[1] - x[0]; - mat[0][1] = x[2] - x[0]; - mat[0][2] = x[3] - x[0]; - mat[1][0] = y[1] - y[0]; - mat[1][1] = y[2] - y[0]; - mat[1][2] = y[3] - y[0]; - mat[2][0] = z[1] - z[0]; - mat[2][1] = z[2] - z[0]; - mat[2][2] = z[3] - z[0]; - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/laplace_main.c b/contrib/hxt/laplace_main.c deleted file mode 100644 index ad72100f42..0000000000 --- a/contrib/hxt/laplace_main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "hxt_api.h" -#include "hxt_laplace.h" -#include "hxt_linear_system.h" -int main(int argc, char **argv) { - if (argc != 2) - return HXT_ERROR_MSG(HXT_STATUS_FAILED,"usage: laplace input.msh"); - HXT_CHECK(hxtInitializeLinearSystems(&argc, &argv)); - - HXTContext *context; - hxtContextCreate(&context); - HXTMesh *mesh; - HXT_CHECK(hxtMeshCreate(context, &mesh)); - HXT_CHECK(hxtMeshReadGmsh(mesh, argv[1])); - HXT_CHECK(hxtLaplace(mesh)); - return HXT_STATUS_OK; -} diff --git a/contrib/hxt/predicates.h b/contrib/hxt/predicates.h deleted file mode 100644 index 35d171f1a5..0000000000 --- a/contrib/hxt/predicates.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _ROBUST_PREDICATES_H_ -#define _ROBUST_PREDICATES_H_ - -#include <hxt_tools.h> - -#ifdef __cplusplus -extern "C" { -#endif - -extern double splitter; -extern double o3dstaticfilter; -extern double o3derrboundA; -extern double ispstaticfilter; -extern double isperrboundA; - -double exactinit(double maxx, double maxy, double maxz); -// double incircle(double *pa, double *pb, double *pc, double *pd); - -/** \todo Please comment the freaking variable type you are using. [JP] - */ -double insphere( - const double* const __restrict__ pa, - const double* const __restrict__ pb, - const double* const __restrict__ pc, - const double* const __restrict__ pd, - const double* const __restrict__ pe); - -double orient3d( - const double* const __restrict__ pa, - const double* const __restrict__ pb, - const double* const __restrict__ pc, - const double* const __restrict__ pd); - -double incircle( - const double* const __restrict__ pa, - const double* const __restrict__ pb, - const double* const __restrict__ pc, - const double* const __restrict__ pd); - -double orient2d( - const double* const __restrict__ pa, - const double* const __restrict__ pb, - const double* const __restrict__ pc); - -int grow_expansion( - int elen, const double *e, double b, double *h); - -int grow_expansion_zeroelim( - int elen, const double *e, double b, double *h); - -int fast_expansion_sum_zeroelim( - const int elen, const double *e, - const int flen, const double *f, double *h); - -int fast_expansion_sum( - int elen, const double *e, int flen, const double *f, double *h); - -int fast_expansion_sum_zeroelim( - const int elen, const double *e, - const int flen, const double *f, double *h); - -int scale_expansion( - const int elen, const double *e, const double b, double *h); - -int scale_expansion_zeroelim( - const int elen, const double *e, const double b, double *h); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/contrib/hxt/predicates/CMakeLists.txt b/contrib/hxt/predicates/CMakeLists.txt new file mode 100644 index 0000000000..6b12f414f1 --- /dev/null +++ b/contrib/hxt/predicates/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.9) +project(hxt_predicates C) + +if(TARGET hxt_predicates) + # header guard for CMake. You need to include this directory first + return() +endif() + +set(HXT_PREDICATES_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/src/predicates.c" + "${CMAKE_CURRENT_SOURCE_DIR}/include/predicates.h" + ) + +# make an object library (no archive) +add_library(hxt_predicates OBJECT ${HXT_PREDICATES_SRC}) + +target_include_directories(hxt_predicates INTERFACE include) + +# do not use extended double precision or arithmetic contraction in predicates.c +if(MSVC OR (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND WIN32)) + target_compile_options(hxt_predicates PRIVATE "/fp:strict") +elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel") + target_compile_options(${target} ${keyword} "-fp-model" "strict") +elseif(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(hxt_predicates PRIVATE "-fno-unsafe-math-optimizations" "-ffp-contract=off") +else() + message(WARNING + "Unsupported compiler ! + Make sure compiled functions from predicates.c + do NOT use extended double precision and follow IEEE754 standard. + It is crucial for the robustness of geometric predicates.") +endif() diff --git a/contrib/hxt/predicates/include/predicates.h b/contrib/hxt/predicates/include/predicates.h new file mode 100644 index 0000000000..b52dffb39b --- /dev/null +++ b/contrib/hxt/predicates/include/predicates.h @@ -0,0 +1,98 @@ +#ifndef ROBUST_PREDICATES_H +#define ROBUST_PREDICATES_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern double splitter; +extern double o3dstaticfilter; +extern double o3derrboundA; +extern double ispstaticfilter; +extern double isperrboundA; + +void exactinit(double maxx, double maxy, double maxz); + +double insphere( + const double* const __restrict__ pa, + const double* const __restrict__ pb, + const double* const __restrict__ pc, + const double* const __restrict__ pd, + const double* const __restrict__ pe); + +double orient3d( + const double* const __restrict__ pa, + const double* const __restrict__ pb, + const double* const __restrict__ pc, + const double* const __restrict__ pd); + +double incircle( + const double* const __restrict__ pa, + const double* const __restrict__ pb, + const double* const __restrict__ pc, + const double* const __restrict__ pd); + +double orient2d( + const double* const __restrict__ pa, + const double* const __restrict__ pb, + const double* const __restrict__ pc); + + +/* if you want a rough idea of the volume of one tet, but you don't need + * exact sign computation */ +static inline double orient3d_inexact(const double* __restrict__ pa, + const double* __restrict__ pb, + const double* __restrict__ pc, + const double* __restrict__ pd) +{ + double adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; + double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + adz = pa[2] - pd[2]; + bdz = pb[2] - pd[2]; + cdz = pc[2] - pd[2]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + + return adz * (bdxcdy - cdxbdy) + + bdz * (cdxady - adxcdy) + + cdz * (adxbdy - bdxady); +} + + +// remember to call exactinit with the right ranges beforehand !!! +static inline int orient3d_inline(const double* __restrict__ pa, + const double* __restrict__ pb, + const double* __restrict__ pc, + const double* __restrict__ pd) +{ + double det = orient3d_inexact(pa, pb, pc, pd); + + int ret = (det > o3dstaticfilter) - (det < -o3dstaticfilter); + + if (ret!=0) return ret; + + det = orient3d(pa,pb,pc,pd); + + return (det>0.0) - (det<0.0); +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/hxt/predicates.c b/contrib/hxt/predicates/src/predicates.c similarity index 89% rename from contrib/hxt/predicates.c rename to contrib/hxt/predicates/src/predicates.c index c9b7b54058..315a44211b 100644 --- a/contrib/hxt/predicates.c +++ b/contrib/hxt/predicates/src/predicates.c @@ -123,15 +123,6 @@ #include <fpu_control.h> #endif /* LINUX */ -#include "hxt_tools.h" - -#ifdef _MSC_VER -#pragma fp_contract (off) // disable floating-point contraction - // same as -ffp-contract=off in gcc - // done by -fp-model strict in icc -#endif - - /* On some machines, the exact arithmetic routines might be defeated by the */ /* use of internal extended precision floating-point registers. Sometimes */ /* this problem can be fixed by defining certain values to be volatile, */ @@ -180,10 +171,6 @@ x = (REAL) (a + b); \ Fast_Two_Sum_Tail(a, b, x, y) -#define Fast_Two_Diff_Tail(a, b, x, y) \ - bvirt = a - x; \ - y = bvirt - b - #define Two_Sum_Tail(a, b, x, y) \ bvirt = (REAL) (x - a); \ avirt = x - bvirt; \ @@ -235,16 +222,6 @@ err3 = err2 - (ahi * blo); \ y = (alo * blo) - err3 -/* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - /* Square() can be done more quickly than Two_Product(). */ #define Square_Tail(a, x, y) \ @@ -276,10 +253,6 @@ Two_One_Diff(a1, a0, b0, _j, _0, x0); \ Two_One_Diff(_j, _0, b1, x3, x2, x1) -#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b , _j, x1, x0); \ - Two_One_Sum(a3, a2, _j, x4, x3, x2) - #define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ Split(b, bhi, blo); \ Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ @@ -288,44 +261,6 @@ Fast_Two_Sum(_j, _k, x3, x2) -#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ - Split(a0, a0hi, a0lo); \ - Split(b0, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ - Split(a1, a1hi, a1lo); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, _1); \ - Fast_Two_Sum(_j, _k, _l, _2); \ - Split(b1, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ - Two_Sum(_1, _0, _k, x1); \ - Two_Sum(_2, _k, _j, _1); \ - Two_Sum(_l, _j, _m, _2); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _n, _0); \ - Two_Sum(_1, _0, _i, x2); \ - Two_Sum(_2, _i, _k, _1); \ - Two_Sum(_m, _k, _l, _2); \ - Two_Sum(_j, _n, _k, _0); \ - Two_Sum(_1, _0, _j, x3); \ - Two_Sum(_2, _j, _i, _1); \ - Two_Sum(_l, _i, _m, _2); \ - Two_Sum(_1, _k, _i, x4); \ - Two_Sum(_2, _i, _k, x5); \ - Two_Sum(_m, _k, x7, x6) - -/* An expansion of length two can be squared more quickly than finding the */ -/* product of two different expansions of length two, and the result is */ -/* guaranteed to have no more than six (rather than eight) components. */ - -#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ - Square(a0, _j, x0); \ - _0 = a0 + a0; \ - Two_Product(a1, _0, _k, _1); \ - Two_One_Sum(_k, _1, _j, _l, _2, x1); \ - Square(a1, _j, _1); \ - Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) - /* splitter = 2^ceiling(p / 2) + 1. Used to split floats in half. */ REAL splitter; static REAL epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ @@ -447,156 +382,6 @@ void exactinit(REAL maxx, REAL maxy, REAL maxz) ispstaticfilter = 1.2466136531027298e-13 * maxx * maxy * maxz * (maxz * maxz); } -/*****************************************************************************/ -/* */ -/* grow_expansion() Add a scalar to an expansion. */ -/* */ -/* Sets h = e + b. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int grow_expansion(int elen, const REAL *e, REAL b, REAL *h) -/* e and h can be the same. */ -{ - REAL Q; - INEXACT REAL Qnew; - int eindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - Q = b; - for (eindex = 0; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, h[eindex]); - Q = Qnew; - } - h[eindex] = Q; - return eindex + 1; -} - -/*****************************************************************************/ -/* */ -/* grow_expansion_zeroelim() Add a scalar to an expansion, eliminating */ -/* zero components from the output expansion. */ -/* */ -/* Sets h = e + b. See the long version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int grow_expansion_zeroelim(int elen, const REAL *e, REAL b, REAL *h) -/* e and h can be the same. */ -{ - REAL Q, hh; - INEXACT REAL Qnew; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - - hindex = 0; - Q = b; - for (eindex = 0; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, hh); - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* fast_expansion_sum() Sum two expansions. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* If round-to-even is used (as with IEEE 754), maintains the strongly */ -/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ -/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ -/* properties. */ -/* */ -/*****************************************************************************/ - -int fast_expansion_sum(int elen, const REAL *e, int flen, const REAL *f, REAL *h) -/* h cannot be e or f. */ -{ - REAL Q; - INEXACT REAL Qnew; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - Q = enow; - ++eindex; - } else { - Q = fnow; - ++findex; - } - hindex = 0; - if ((eindex < elen) && (findex < flen)) { - enow = e[eindex]; - fnow = f[findex]; - if ((fnow > enow) == (fnow > -enow)) { - Fast_Two_Sum(enow, Q, Qnew, h[0]); - ++eindex; - } else { - Fast_Two_Sum(fnow, Q, Qnew, h[0]); - ++findex; - } - Q = Qnew; - hindex = 1; - while ((eindex < elen) && (findex < flen)) { - enow = e[eindex]; - fnow = f[findex]; - if ((fnow > enow) == (fnow > -enow)) { - Two_Sum(Q, enow, Qnew, h[hindex]); - ++eindex; - } else { - Two_Sum(Q, fnow, Qnew, h[hindex]); - ++findex; - } - Q = Qnew; - hindex++; - } - } - while (eindex < elen) { - enow = e[eindex]; - Two_Sum(Q, enow, Qnew, h[hindex]); - ++eindex; - Q = Qnew; - hindex++; - } - while (findex < flen) { - fnow = f[findex]; - Two_Sum(Q, fnow, Qnew, h[hindex]); - ++findex; - Q = Qnew; - hindex++; - } - h[hindex] = Q; - return hindex + 1; -} /*****************************************************************************/ /* */ @@ -612,7 +397,11 @@ int fast_expansion_sum(int elen, const REAL *e, int flen, const REAL *f, REAL *h /* */ /*****************************************************************************/ -int fast_expansion_sum_zeroelim(const int elen, const REAL *e, const int flen, const REAL *f, REAL *h) +static int fast_expansion_sum_zeroelim(const int elen, + const REAL* const __restrict__ e, + const int flen, + const REAL* const __restrict__ f, + REAL* const __restrict__ h) /* h cannot be e or f. */ { REAL Q; @@ -697,49 +486,6 @@ int fast_expansion_sum_zeroelim(const int elen, const REAL *e, const int flen, c return hindex; } -/*****************************************************************************/ -/* */ -/* scale_expansion() Multiply an expansion by a scalar. */ -/* */ -/* Sets h = be. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int scale_expansion(int elen, REAL *e, REAL b, REAL *h) -/* e and h cannot be the same. */ -{ - INEXACT REAL Q; - INEXACT REAL sum; - INEXACT REAL product1; - REAL product0; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - - Split(b, bhi, blo); - Two_Product_Presplit(e[0], b, bhi, blo, Q, h[0]); - hindex = 1; - for (eindex = 1; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Product_Presplit(enow, b, bhi, blo, product1, product0); - Two_Sum(Q, product0, sum, h[hindex]); - hindex++; - Two_Sum(product1, sum, Q, h[hindex]); - hindex++; - } - h[hindex] = Q; - return elen + elen; -} /*****************************************************************************/ /* */ @@ -756,7 +502,10 @@ int scale_expansion(int elen, REAL *e, REAL b, REAL *h) /* */ /*****************************************************************************/ -int scale_expansion_zeroelim(const int elen, const REAL *e, const REAL b, REAL *h) +static int scale_expansion_zeroelim(const int elen, + const REAL* const __restrict__ e, + const REAL b, + REAL* const __restrict__ h) /* e and h cannot be the same. */ { INEXACT REAL Q, sum; @@ -805,7 +554,7 @@ int scale_expansion_zeroelim(const int elen, const REAL *e, const REAL b, REAL * /* */ /*****************************************************************************/ -static REAL estimate(const int elen, const REAL *e) +static REAL estimate(const int elen, const REAL* const e) { REAL Q; int eindex; @@ -843,18 +592,21 @@ static REAL estimate(const int elen, const REAL *e) /* */ /*****************************************************************************/ -REAL orient2dfast(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc) -{ - REAL acx, bcx, acy, bcy; - - acx = pa[0] - pc[0]; - bcx = pb[0] - pc[0]; - acy = pa[1] - pc[1]; - bcy = pb[1] - pc[1]; - return acx * bcy - acy * bcx; -} - -REAL orient2dadapt(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc, const REAL detsum) +// REAL orient2dfast(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc) +// { +// REAL acx, bcx, acy, bcy; + +// acx = pa[0] - pc[0]; +// bcx = pb[0] - pc[0]; +// acy = pa[1] - pc[1]; +// bcy = pb[1] - pc[1]; +// return acx * bcy - acy * bcx; +// } + +static REAL orient2dadapt(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL detsum) { INEXACT REAL acx, acy, bcx, bcy; REAL acxtail, acytail, bcxtail, bcytail; @@ -934,7 +686,7 @@ REAL orient2dadapt(const REAL* __restrict__ pa, const REAL* __restrict__ pb, con return(D[Dlength - 1]); } -REAL orient2d(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc) +REAL orient2d(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc) { REAL detleft, detright, det; REAL detsum, errbound; @@ -997,7 +749,11 @@ REAL orient2d(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const RE /*****************************************************************************/ -static REAL orient3dadapt(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc, const REAL* __restrict__ pd, const REAL permanent) +static REAL orient3dadapt(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd, + const REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; REAL det, errbound; @@ -1409,7 +1165,10 @@ static REAL orient3dadapt(const REAL* __restrict__ pa, const REAL* __restrict__ } -REAL orient3d(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd) +REAL orient3d(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd) { // return orient3dexact(pa, pb, pc, pd); @@ -1485,30 +1244,37 @@ REAL orient3d(const REAL* const __restrict__ pa, const REAL* const __restrict__ /* */ /*****************************************************************************/ -REAL incirclefast(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc, const REAL* __restrict__ pd) -{ - REAL adx, ady, bdx, bdy, cdx, cdy; - REAL abdet, bcdet, cadet; - REAL alift, blift, clift; - - adx = pa[0] - pd[0]; - ady = pa[1] - pd[1]; - bdx = pb[0] - pd[0]; - bdy = pb[1] - pd[1]; - cdx = pc[0] - pd[0]; - cdy = pc[1] - pd[1]; - - abdet = adx * bdy - bdx * ady; - bcdet = bdx * cdy - cdx * bdy; - cadet = cdx * ady - adx * cdy; - alift = adx * adx + ady * ady; - blift = bdx * bdx + bdy * bdy; - clift = cdx * cdx + cdy * cdy; - - return alift * bcdet + blift * cadet + clift * abdet; -} - -REAL incircleadapt(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc, const REAL* __restrict__ pd, const REAL permanent) +// REAL incirclefast(const REAL* const __restrict__ pa, +// const REAL* const __restrict__ pb, +// const REAL* const __restrict__ pc, +// const REAL* const __restrict__ pd) +// { +// REAL adx, ady, bdx, bdy, cdx, cdy; +// REAL abdet, bcdet, cadet; +// REAL alift, blift, clift; + +// adx = pa[0] - pd[0]; +// ady = pa[1] - pd[1]; +// bdx = pb[0] - pd[0]; +// bdy = pb[1] - pd[1]; +// cdx = pc[0] - pd[0]; +// cdy = pc[1] - pd[1]; + +// abdet = adx * bdy - bdx * ady; +// bcdet = bdx * cdy - cdx * bdy; +// cadet = cdx * ady - adx * cdy; +// alift = adx * adx + ady * ady; +// blift = bdx * bdx + bdy * bdy; +// clift = cdx * cdx + cdy * cdy; + +// return alift * bcdet + blift * cadet + clift * abdet; +// } + +static REAL incircleadapt(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd, + const REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; REAL det, errbound; @@ -2080,7 +1846,10 @@ REAL incircleadapt(const REAL* __restrict__ pa, const REAL* __restrict__ pb, con return finnow[finlength - 1]; } -REAL incircle(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const REAL* __restrict__ pc, const REAL* __restrict__ pd) +REAL incircle(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd) { REAL adx, bdx, cdx, ady, bdy, cdy; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; @@ -2149,50 +1918,54 @@ REAL incircle(const REAL* __restrict__ pa, const REAL* __restrict__ pb, const RE /* */ /*****************************************************************************/ -REAL inspherefast(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd, const REAL* const __restrict__ pe) -{ - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL alift, blift, clift, dlift; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - - ab = aex * bey - bex * aey; - bc = bex * cey - cex * bey; - cd = cex * dey - dex * cey; - da = dex * aey - aex * dey; - - ac = aex * cey - cex * aey; - bd = bex * dey - dex * bey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; - - alift = aex * aex + aey * aey + aez * aez; - blift = bex * bex + bey * bey + bez * bez; - clift = cex * cex + cey * cey + cez * cez; - dlift = dex * dex + dey * dey + dez * dez; - - return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); -} - -REAL insphereexact(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd, const REAL* const __restrict__ pe) +// REAL inspherefast(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd, const REAL* const __restrict__ pe) +// { +// REAL aex, bex, cex, dex; +// REAL aey, bey, cey, dey; +// REAL aez, bez, cez, dez; +// REAL alift, blift, clift, dlift; +// REAL ab, bc, cd, da, ac, bd; +// REAL abc, bcd, cda, dab; + +// aex = pa[0] - pe[0]; +// bex = pb[0] - pe[0]; +// cex = pc[0] - pe[0]; +// dex = pd[0] - pe[0]; +// aey = pa[1] - pe[1]; +// bey = pb[1] - pe[1]; +// cey = pc[1] - pe[1]; +// dey = pd[1] - pe[1]; +// aez = pa[2] - pe[2]; +// bez = pb[2] - pe[2]; +// cez = pc[2] - pe[2]; +// dez = pd[2] - pe[2]; + +// ab = aex * bey - bex * aey; +// bc = bex * cey - cex * bey; +// cd = cex * dey - dex * cey; +// da = dex * aey - aex * dey; + +// ac = aex * cey - cex * aey; +// bd = bex * dey - dex * bey; + +// abc = aez * bc - bez * ac + cez * ab; +// bcd = bez * cd - cez * bd + dez * bc; +// cda = cez * da + dez * ac + aez * cd; +// dab = dez * ab + aez * bd + bez * da; + +// alift = aex * aex + aey * aey + aez * aez; +// blift = bex * bex + bey * bey + bez * bez; +// clift = cex * cex + cey * cey + cez * cez; +// dlift = dex * dex + dey * dey + dez * dez; + +// return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); +// } + +static REAL insphereexact(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd, + const REAL* const __restrict__ pe) { INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; @@ -2446,8 +2219,12 @@ REAL insphereexact(const REAL* const __restrict__ pa, const REAL* const __restri } -REAL insphereadapt(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd, const REAL* const __restrict__ pe, - const REAL permanent) +static REAL insphereadapt(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd, + const REAL* const __restrict__ pe, + const REAL permanent) { INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; REAL det, errbound; @@ -2664,7 +2441,11 @@ REAL insphereadapt(const REAL* const __restrict__ pa, const REAL* const __restri } -REAL insphere(const REAL* const __restrict__ pa, const REAL* const __restrict__ pb, const REAL* const __restrict__ pc, const REAL* const __restrict__ pd, const REAL* const __restrict__ pe) +REAL insphere(const REAL* const __restrict__ pa, + const REAL* const __restrict__ pb, + const REAL* const __restrict__ pc, + const REAL* const __restrict__ pd, + const REAL* const __restrict__ pe) { REAL aex, bex, cex, dex; REAL aey, bey, cey, dey; diff --git a/contrib/hxt/reparam/CMakeLists.txt b/contrib/hxt/reparam/CMakeLists.txt new file mode 100644 index 0000000000..498faf3150 --- /dev/null +++ b/contrib/hxt/reparam/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.9) +project(hxt_reparam C) + +# most options are inherited from hxt_core (see ../core/CMakeList.txt) + +option(HXT_ENABLE_PETSC "USE PETSc as linear solver (requires petsc compile without mpi and for real numbers)" ON) +option(HXT_REPARAM_OBJECT_ONLY "Do not create hxt_reparam library" OFF) + +set(HXT_REPARAM_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edge.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_curvature.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_mean_values.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_linear_system.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_linear_system_lu.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_non_linear_solver.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_linear_system_petsc.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_class_macro.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_linear_system_lu.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_non_linear_solver.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_linear_system_petsc.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_curvature.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_edge.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_linear_system.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_mean_values.h" + ) + +if(HXT_REPARAM_OBJECT_ONLY) + add_library(hxt_reparam OBJECT ${HXT_REPARAM_SRC}) +else() + add_library(hxt_reparam ${HXT_REPARAM_SRC}) +endif() + +add_subdirectory(../core "${CMAKE_CURRENT_BINARY_DIR}/core") + +target_link_libraries(hxt_reparam PUBLIC hxt_core) +target_compile_features(hxt_reparam PRIVATE c_std_99) +target_include_directories(hxt_reparam PUBLIC include) + +if(ENABLE_PETSC) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + find_package(PETSc REQUIRED) + target_include_directories(hxt_reparam PRIVATE "${PETSC_INC}") + target_link_libraries(hxt_reparam PRIVATE "${PETSC_LIBS}") + target_compile_definitions(hxt_reparam PRIVATE HXT_HAVE_PETSC) +endif() + diff --git a/contrib/hxt/reparam/cmake/FindPETSc.cmake b/contrib/hxt/reparam/cmake/FindPETSc.cmake new file mode 100644 index 0000000000..c566e20bcb --- /dev/null +++ b/contrib/hxt/reparam/cmake/FindPETSc.cmake @@ -0,0 +1,119 @@ +# - Try to find PETSc +# Once done this will define +# +# PETSC_INC - the PETSc include directories +# PETSC_LIBS - Link these to use PETSc + +macro(find_all_libraries VARNAME LISTNAME PATH SUFFIX) + set(${VARNAME}) + list(LENGTH ${LISTNAME} NUM_LIST) + foreach(LIB ${${LISTNAME}}) + if("${PATH}" STREQUAL "") + find_library(FOUND_LIB ${LIB} PATH_SUFFIXES ${SUFFIX}) + else("${PATH}" STREQUAL "") + find_library(FOUND_LIB ${LIB} PATHS ${PATH} NO_DEFAULT_PATH) + endif("${PATH}" STREQUAL "") + if(FOUND_LIB) + list(APPEND ${VARNAME} ${FOUND_LIB}) + endif(FOUND_LIB) + unset(FOUND_LIB CACHE) + endforeach(LIB) + list(LENGTH ${VARNAME} NUM_FOUND_LIBRARIES) + if(NUM_FOUND_LIBRARIES LESS NUM_LIST) + set(${VARNAME}) + endif(NUM_FOUND_LIBRARIES LESS NUM_LIST) +endmacro(find_all_libraries) + + +if(PETSC_DIR) + set(ENV_PETSC_DIR ${PETSC_DIR}) +else(PETSC_DIR) + set(ENV_PETSC_DIR $ENV{PETSC_DIR}) +endif(PETSC_DIR) +if(PETSC_ARCH) + set(ENV_PETSC_ARCH ${PETSC_ARCH}) +else(PETSC_ARCH) + set(ENV_PETSC_ARCH $ENV{PETSC_ARCH}) +endif(PETSC_ARCH) +set(PETSC_POSSIBLE_CONF_FILES + ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/conf/petscvariables + ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/lib/petsc-conf/petscvariables + ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/lib/petsc/conf/petscvariables) +foreach(FILE ${PETSC_POSSIBLE_CONF_FILES}) + if(EXISTS ${FILE}) + # old-style PETSc installations (using PETSC_DIR and PETSC_ARCH) + message(STATUS "Using PETSc dir: ${ENV_PETSC_DIR}") + message(STATUS "Using PETSc arch: ${ENV_PETSC_ARCH}") + # find includes by parsing the petscvariables file + file(STRINGS ${FILE} PETSC_VARIABLES NEWLINE_CONSUME) + endif(EXISTS ${FILE}) +endforeach(FILE) +if(PETSC_VARIABLES) + # try to find PETSC_CC_INCLUDES for PETSc >= 3.4 + string(REGEX MATCH "PETSC_CC_INCLUDES = [^\n\r]*" PETSC_PACKAGES_INCLUDES + ${PETSC_VARIABLES}) + if(PETSC_PACKAGES_INCLUDES) + string(REPLACE "PETSC_CC_INCLUDES = " "" PETSC_PACKAGES_INCLUDES + ${PETSC_PACKAGES_INCLUDES}) + else(PETSC_PACKAGES_INCLUDES) + # try to find PETSC_PACKAGES_INCLUDES in older versions + list(APPEND PETSC_INC ${ENV_PETSC_DIR}/include) + list(APPEND PETSC_INC ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/include) + string(REGEX MATCH "PACKAGES_INCLUDES = [^\n\r]*" PETSC_PACKAGES_INCLUDES + ${PETSC_VARIABLES}) + string(REPLACE "PACKAGES_INCLUDES = " "" PETSC_PACKAGES_INCLUDES + ${PETSC_PACKAGES_INCLUDES}) + endif(PETSC_PACKAGES_INCLUDES) + if(PETSC_PACKAGES_INCLUDES) + if(PETSC_PACKAGES_INCLUDES) + string(REPLACE "-I" "" PETSC_PACKAGES_INCLUDES ${PETSC_PACKAGES_INCLUDES}) + string(REPLACE " " ";" PETSC_PACKAGES_INCLUDES ${PETSC_PACKAGES_INCLUDES}) + foreach(VAR ${PETSC_PACKAGES_INCLUDES}) + # seem to include unexisting directories (/usr/include/lib64) + # check to avoid warnings + if(EXISTS ${VAR}) + list(APPEND PETSC_INC ${VAR}) + endif(EXISTS ${VAR}) + endforeach(VAR) + endif(PETSC_PACKAGES_INCLUDES) + endif(PETSC_PACKAGES_INCLUDES) + # find libraries (<= 3.0) + set(PETSC_LIBS_REQUIRED petscksp petscdm petscmat petscvec petsc) + find_all_libraries(PETSC_LIBS PETSC_LIBS_REQUIRED + ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/lib "") + # petsc 3.1 creates only one library (libpetsc) + if(NOT PETSC_LIBS) + find_library(PETSC_LIBS petsc PATHS ${ENV_PETSC_DIR}/${ENV_PETSC_ARCH}/lib + NO_DEFAULT_PATH) + endif(NOT PETSC_LIBS) + # find additional libraries to link with + string(REGEX MATCH "PACKAGES_LIBS = [^\n\r]*" PLIBS ${PETSC_VARIABLES}) + if(PLIBS) + string(REPLACE "PACKAGES_LIBS = " "" PLIBS ${PLIBS}) + string(STRIP ${PLIBS} PLIBS) + list(APPEND PETSC_LIBS "${PLIBS}") + endif(PLIBS) + string(REGEX MATCH "PETSC_EXTERNAL_LIB_BASIC = [^\n\r]*" PLIBS_BASIC ${PETSC_VARIABLES}) + if(PLIBS_BASIC) + string(REPLACE "PETSC_EXTERNAL_LIB_BASIC = " "" PLIBS_BASIC ${PLIBS_BASIC}) + string(STRIP ${PLIBS_BASIC} PLIBS_BASIC) + separate_arguments(PLIBS_BASIC) + list(APPEND PETSC_LIBS "${PLIBS_BASIC}") + endif(PLIBS_BASIC) + string(REGEX MATCH "PCC_LINKER_LIBS = [^\n\r]*" LLIBS ${PETSC_VARIABLES}) + if(LLIBS) + string(REPLACE "PCC_LINKER_LIBS = " "" LLIBS ${LLIBS}) + string(STRIP ${LLIBS} LLIBS) + list(APPEND PETSC_LIBS "${LLIBS}") + endif(LLIBS) +else(PETSC_VARIABLES) + # new-style PETSc installations (in standard system directories) + find_library(PETSC_LIBS petsc) + find_path(PETSC_INC "petsc.h" PATH_SUFFIXES include/petsc) +endif(PETSC_VARIABLES) + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(PETSc DEFAULT_MSG PETSC_LIBS PETSC_INC) +mark_as_advanced(PETSC_LIBS PETSC_INC) + diff --git a/contrib/hxt/hxt_curvature.h b/contrib/hxt/reparam/include/hxt_curvature.h similarity index 100% rename from contrib/hxt/hxt_curvature.h rename to contrib/hxt/reparam/include/hxt_curvature.h diff --git a/contrib/hxt/hxt_edge.h b/contrib/hxt/reparam/include/hxt_edge.h similarity index 97% rename from contrib/hxt/hxt_edge.h rename to contrib/hxt/reparam/include/hxt_edge.h index 11a2cf7a14..8857d9b0c4 100644 --- a/contrib/hxt/hxt_edge.h +++ b/contrib/hxt/reparam/include/hxt_edge.h @@ -1,9 +1,7 @@ #ifndef HEXTREME_EDGE_H #define HEXTREME_EDGE_H -#include "hxt_tools.h" #include "hxt_mesh.h" -#include <math.h> typedef struct hxtLineLoopStruct HXTLineLoop; diff --git a/contrib/hxt/hxt_linear_system.h b/contrib/hxt/reparam/include/hxt_linear_system.h similarity index 98% rename from contrib/hxt/hxt_linear_system.h rename to contrib/hxt/reparam/include/hxt_linear_system.h index 133380cb2d..23faf30798 100644 --- a/contrib/hxt/hxt_linear_system.h +++ b/contrib/hxt/reparam/include/hxt_linear_system.h @@ -1,7 +1,8 @@ #ifndef HEXTREME_LINEAR_SYSTEM_H #define HEXTREME_LINEAR_SYSTEM_H + #include <stdint.h> -#include "hxt_api.h" +#include "hxt_message.h" typedef struct HXTLinearSystemStruct HXTLinearSystem; diff --git a/contrib/hxt/hxt_mean_values.h b/contrib/hxt/reparam/include/hxt_mean_values.h similarity index 95% rename from contrib/hxt/hxt_mean_values.h rename to contrib/hxt/reparam/include/hxt_mean_values.h index fcbf246ffc..05916f6e40 100644 --- a/contrib/hxt/hxt_mean_values.h +++ b/contrib/hxt/reparam/include/hxt_mean_values.h @@ -12,7 +12,10 @@ HXTStatus hxtMeanValuesDelete(HXTMeanValues **meanValues); HXTStatus hxtMeanValuesCompute(HXTMeanValues *meanValues); HXTStatus hxtMeanValueAspectRatio(HXTMeanValues *meanValues, int *aspectRatio); HXTStatus hxtMeanValuesGetData(HXTMeanValues *mv, uint64_t **global, uint32_t **gn, double **uv, int *nv, int *ne, int onlyuv); + +#ifdef HXT_CORE_FILEIO HXTStatus hxtMeanValuesWrite(HXTMeanValues *meanValues, const char* filename); HXTStatus hxtMeanValuesWriteParamMesh(HXTMeanValues *meanValues, const char* filename); +#endif #endif diff --git a/contrib/hxt/hxt_class_macro.h b/contrib/hxt/reparam/src/hxt_class_macro.h similarity index 100% rename from contrib/hxt/hxt_class_macro.h rename to contrib/hxt/reparam/src/hxt_class_macro.h diff --git a/contrib/hxt/hxt_curvature.c b/contrib/hxt/reparam/src/hxt_curvature.c similarity index 81% rename from contrib/hxt/hxt_curvature.c rename to contrib/hxt/reparam/src/hxt_curvature.c index f38bcb81ad..9ebd686f47 100644 --- a/contrib/hxt/hxt_curvature.c +++ b/contrib/hxt/reparam/src/hxt_curvature.c @@ -1,8 +1,47 @@ -#include <math.h> -#include <time.h> #include "hxt_curvature.h" +#include "hxt_tools.h" +#include <math.h> +#include <stdio.h> + +// #include <time.h> // for commented timings + #define tolerance 0.1e-20 + +static HXTStatus hxtInv4x4ColumnMajor(double m[16], double invOut[16], double *det) +{ + double inv[16]; + int i; + + inv[ 0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + inv[ 4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + inv[ 8] = m[4] * m[ 9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[ 9]; + inv[12] = -m[4] * m[ 9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[ 9]; + inv[ 1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + inv[ 5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + inv[ 9] = -m[0] * m[ 9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[ 9]; + inv[13] = m[0] * m[ 9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[ 9]; + inv[ 2] = m[1] * m[ 6] * m[15] - m[1] * m[ 7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[ 7] - m[13] * m[3] * m[ 6]; + inv[ 6] = -m[0] * m[ 6] * m[15] + m[0] * m[ 7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[ 7] + m[12] * m[3] * m[ 6]; + inv[10] = m[0] * m[ 5] * m[15] - m[0] * m[ 7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[ 7] - m[12] * m[3] * m[ 5]; + inv[14] = -m[0] * m[ 5] * m[14] + m[0] * m[ 6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[ 6] + m[12] * m[2] * m[ 5]; + inv[ 3] = -m[1] * m[ 6] * m[11] + m[1] * m[ 7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[ 9] * m[2] * m[ 7] + m[ 9] * m[3] * m[ 6]; + inv[ 7] = m[0] * m[ 6] * m[11] - m[0] * m[ 7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[ 8] * m[2] * m[ 7] - m[ 8] * m[3] * m[ 6]; + inv[11] = -m[0] * m[ 5] * m[11] + m[0] * m[ 7] * m[ 9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[ 9] - m[ 8] * m[1] * m[ 7] + m[ 8] * m[3] * m[ 5]; + inv[15] = m[0] * m[ 5] * m[10] - m[0] * m[ 6] * m[ 9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[ 9] + m[ 8] * m[1] * m[ 6] - m[ 8] * m[2] * m[ 5]; + + *det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + + if(*det == 0) + return HXT_STATUS_ERROR; + + double invDet = 1.0 / *det; + + for(i = 0; i < 16; i++) + invOut[i] = inv[i] * invDet; + + return HXT_STATUS_OK; +} static void solveEig(double A, double B, double C, double D, double* lambda1, double *v1x, double*v1y, @@ -43,8 +82,8 @@ static void solveEig(double A, double B, double C, double D, static inline int node2trianglescmp(const void *p0, const void *p1) { - uint64_t *e0 = (uint64_t*)p0; - uint64_t *e1 = (uint64_t*)p1; + const uint64_t *e0 = (const uint64_t*)p0; + const uint64_t *e1 = (const uint64_t*)p1; if (e0[0] < e1[0]) return -1; if (e0[0] > e1[0]) return 1; @@ -135,14 +174,14 @@ void saveNodalField (HXTMesh *mesh, double *v, int ncomp, const char *fn){ p0[0],p0[1],p0[2],p1[0],p1[1],p1[2],p2[0],p2[1],p2[2], v0[3],v0[4],v0[5],v1[3],v1[4],v1[5],v2[3],v2[4],v2[5]); } - fprintf(f,"};\n"); + fprintf(f,"};\n"); fclose (f); } HXTStatus hxtCurvatureRusinkiewicz (HXTMesh *mesh, double **nodalCurvatures, double **crossField, HXTEdges* edges, int debug) { - clock_t T1 = clock(); + // clock_t T1 = clock(); uint64_t nTriangles = mesh->triangles.num; // uint64_t nEdgesBdry = mesh->lines.num; @@ -370,7 +409,7 @@ HXTStatus hxtCurvatureRusinkiewicz (HXTMesh *mesh, double **nodalCurvatures, dou HXT_CHECK(hxtFree(&nodeNormals)); HXT_CHECK(hxtFree(&CURV)); - clock_t T2 = clock(); + // clock_t T2 = clock(); // HXT_INFO ("Curvature has been computed for %u vertices in %8.4f seconds",nVertices,(double)(T2-T1)/CLOCKS_PER_SEC); diff --git a/contrib/hxt/hxt_edge.c b/contrib/hxt/reparam/src/hxt_edge.c similarity index 98% rename from contrib/hxt/hxt_edge.c rename to contrib/hxt/reparam/src/hxt_edge.c index ea53381250..99538a974a 100644 --- a/contrib/hxt/hxt_edge.c +++ b/contrib/hxt/reparam/src/hxt_edge.c @@ -1,4 +1,7 @@ #include "hxt_edge.h" +#include "hxt_tools.h" +#include <string.h> +#include <math.h> struct hxtLineLoopStruct{ double length; @@ -33,9 +36,9 @@ double hxtEdgesLength(const HXTEdges *edges,uint32_t ie){ static inline int halfedgecmp(const void *p0, const void *p1) { - uint32_t *e0 = (uint32_t*)p0; + const uint32_t *e0 = (const uint32_t*)p0; uint32_t es0[2] = {e0[0] < e0[1] ? e0[0] : e0[1], e0[0] < e0[1] ? e0[1] : e0[0]}; - uint32_t *e1 = (uint32_t*)p1; + const uint32_t *e1 = (const uint32_t*)p1; uint32_t es1[2] = {e1[0] < e1[1] ? e1[0] : e1[1], e1[0] < e1[1] ? e1[1] : e1[0]}; if (es0[0] < es1[0]) return -1; @@ -183,7 +186,7 @@ HXTStatus hxtEdgesSetBoundaries(HXTEdges *edges, HXTBoundaries **boundaries) HXT_CHECK(hxtFree(&firstNode2Edge)); lineLoops->nbedg = nbBorder; if(lineLoops->seamPoint==1){ - printf("SEAM POINT!!!!\n"); + HXT_WARNING("SEAM POINT!!!!\n"); lineLoops->nll=-1; lineLoops->lineLoop = NULL; return HXT_STATUS_OK; diff --git a/contrib/hxt/hxt_linear_system.c b/contrib/hxt/reparam/src/hxt_linear_system.c similarity index 96% rename from contrib/hxt/hxt_linear_system.c rename to contrib/hxt/reparam/src/hxt_linear_system.c index 7105062d2f..61d3759f27 100644 --- a/contrib/hxt/hxt_linear_system.c +++ b/contrib/hxt/reparam/src/hxt_linear_system.c @@ -27,6 +27,11 @@ HXT_DECLARE_DERIVED_CLASS(LinearSystem, LinearSystemPETSc) #endif HXTStatus hxtInitializeLinearSystems(int *argc, char ***argv) { +#ifndef HXT_HAVE_PETSC + HXT_UNUSED(argc); + HXT_UNUSED(argv); +#endif + HXT_CHECK(hxtLinearSystemLURegister()); #ifdef HXT_HAVE_PETSC HXT_CHECK(hxtInitializePETSc(argc, argv)); diff --git a/contrib/hxt/hxt_linear_system_lu.c b/contrib/hxt/reparam/src/hxt_linear_system_lu.c similarity index 77% rename from contrib/hxt/hxt_linear_system_lu.c rename to contrib/hxt/reparam/src/hxt_linear_system_lu.c index 51a40453e8..6fcc926e33 100644 --- a/contrib/hxt/hxt_linear_system_lu.c +++ b/contrib/hxt/reparam/src/hxt_linear_system_lu.c @@ -8,16 +8,16 @@ //#define CONMAX 2000 #ifdef CONMAX -static void connectivityInsert(int *connectivity, int i, int j) +static HXTStatus connectivityInsert(int *connectivity, int i, int j) { for (int k = 0; k < CONMAX; ++k) { int *p = connectivity + CONMAX*i + k; if (*p == -1) *p = j; if (*p == j) - return; + return HXT_STATUS_OK; } - printf("ERROR : node %i has more than %i neighbours\n", i, CONMAX); + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "node %i has more than %i neighbours\n", i, CONMAX); } #endif @@ -46,57 +46,61 @@ struct HXTConnectivity { int **nodeConnectivity; }; -void mallocConnectivity (struct HXTConnectivity *c, int n, int q) +static HXTStatus allocConnectivity (struct HXTConnectivity *c, int n, int q) { - c-> nNodes = n; - c-> quantum = q; - c-> allocated = malloc (sizeof(int) * c->nNodes); - c-> degree = malloc (sizeof(int) * c->nNodes); - c-> nodeConnectivity = malloc (sizeof(int*)* c->nNodes); + c->nNodes = n; + c->quantum = q; + HXT_CHECK( hxtMalloc(&c->allocated, sizeof(int) * c->nNodes) ); + HXT_CHECK( hxtMalloc(&c->degree, sizeof(int) * c->nNodes) ); + HXT_CHECK( hxtMalloc(&c->nodeConnectivity, sizeof(int) * c->nNodes) ); for (int i=0;i<c->nNodes;i++){ - c-> allocated[i] = c->quantum; - c-> degree [i] = 0; - c-> nodeConnectivity [i] = malloc (sizeof(int) * c-> allocated[i]); + c->allocated[i] = c->quantum; + c->degree [i] = 0; + HXT_CHECK( hxtMalloc(&c->nodeConnectivity[i], sizeof(int) * c-> allocated[i]) ); } + return HXT_STATUS_OK; } -void freeConnectivity (struct HXTConnectivity *c) +static HXTStatus freeConnectivity (struct HXTConnectivity *c) { for (int i=0;i<c->nNodes;i++){ - free(c-> nodeConnectivity [i]); + HXT_CHECK( hxtFree(&c->nodeConnectivity[i]) ); } - free(c-> nodeConnectivity); - free(c-> degree); - free(c-> allocated); + HXT_CHECK( hxtFree(&c->nodeConnectivity) ); + HXT_CHECK( hxtFree(&c->degree) ); + HXT_CHECK( hxtFree(&c->allocated) ); c-> nNodes = 0; + return HXT_STATUS_OK; } -int addToConnectivity (struct HXTConnectivity *c, int myRow, int myCol){ - if (myRow >= c->nNodes) return -1; +static HXTStatus addToConnectivity (struct HXTConnectivity *c, int myRow, int myCol){ + if (myRow >= c->nNodes) return HXT_ERROR(HXT_STATUS_ERROR); if (c->allocated[myRow] == c->degree[myRow]){ c->allocated[myRow]*= 2; - c-> nodeConnectivity [myRow] = realloc (c-> nodeConnectivity [myRow],sizeof(int) * c-> allocated[myRow]); + HXT_CHECK( hxtRealloc(&c->nodeConnectivity[myRow], sizeof(int) * c->allocated[myRow]) ); } for (int i=0;i<c->degree[myRow];i++){ - if (c-> nodeConnectivity [myRow][i] == myCol)return 0; + if (c-> nodeConnectivity [myRow][i] == myCol) return HXT_STATUS_OK; } c-> nodeConnectivity [myRow][c->degree[myRow]] = myCol; c->degree[myRow]++; + return HXT_STATUS_OK; } -static void reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering) +static HXTStatus reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering) { #ifdef CONMAX - int *nodeConnectivity = malloc(sizeof(int)*system->nNodes*CONMAX); + int *nodeConnectivity; + HXT_CHECK( hxtMalloc(&nodeConnectivity, sizeof(int)*system->nNodes*CONMAX) ); for (int i = 0; i < system->nNodes*CONMAX; ++i) { nodeConnectivity[i] = -1; } #else struct HXTConnectivity myConnectivity; - mallocConnectivity (&myConnectivity,system->nNodes,9); // 7 is the average connectivity of a triangular mesh, we put a llitle more + HXT_CHECK( allocConnectivity (&myConnectivity,system->nNodes,9) ); // 7 is the average connectivity of a triangular mesh, we put a llitle more #endif for (int i = 0; i < system->nElements; ++i) { @@ -105,17 +109,19 @@ static void reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering) for (int l = 0; l < system->nNodesByElement; ++l){ if (k == l) continue; #ifdef CONMAX - connectivityInsert(nodeConnectivity, el[k], el[l]); - connectivityInsert(nodeConnectivity, el[l], el[k]); + HXT_CHECK( connectivityInsert(nodeConnectivity, el[k], el[l]) ); + HXT_CHECK( connectivityInsert(nodeConnectivity, el[l], el[k]) ); #else - addToConnectivity(&myConnectivity,el[k], el[l]); - addToConnectivity(&myConnectivity,el[l], el[k]); + HXT_CHECK( addToConnectivity(&myConnectivity,el[k], el[l]) ); + HXT_CHECK( addToConnectivity(&myConnectivity,el[l], el[k]) ); #endif } } } #ifdef CONMAX - int *nodeDegree = malloc(sizeof(int)*system->nNodes); + + int *nodeDegree; + HXT_CHECK( hxtMalloc(&nodeDegree, sizeof(int)*system->nNodes) ); for (int i = 0; i < system->nNodes; ++i) { nodeDegree[i] = 0; for (int j = 0; j < CONMAX; ++j) { @@ -128,7 +134,8 @@ static void reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering) int *nodeDegree = myConnectivity.degree; #endif - int *queue = malloc(sizeof(int)*system->nNodes); + int *queue; + HXT_CHECK( hxtMalloc(&queue, sizeof(int)*system->nNodes) ); queue[0] = 0; for (int i = 0; i < system->nNodes; ++i){ ordering[i] = -1; @@ -172,25 +179,20 @@ static void reverseCuthillMckee(HXTLinearSystemLU *system, int *ordering) for (int i = 0; i < system->nNodes; ++i) if(ordering[i] >= 0) ordering[i] = id-1-ordering[i]; - free(queue); + HXT_CHECK( hxtFree(&queue) ); #ifdef CONMAX - free(nodeDegree); - free(nodeConnectivity); + HXT_CHECK( hxtFree(&nodeDegree) ); + HXT_CHECK( hxtFree(&nodeConnectivity) ); #else - freeConnectivity (&myConnectivity); + HXT_CHECK( freeConnectivity (&myConnectivity) ); #endif + return HXT_STATUS_OK; } #define PADDING (SIMD_ALIGN/8) - -typedef hxtDeclareAligned double alignedDouble; -#ifndef HAVE_NO_IMMINTRIN_H // FIXME: Gmsh -#include <immintrin.h> -#endif - // y[from:to] += a*x[from:to] // y and x must be 256-bit aligned // memory should be allocated in consequence @@ -288,7 +290,7 @@ static HXTStatus LUPDecompose(HXTLinearSystemLU *system){ rowAxpy(-A[j][i],A[i],A[j],i+1,system->rowEnd[i]); } } - return(1); + return HXT_STATUS_OK; } static void LUPSolve(HXTLinearSystemLU *system, double *b){ @@ -303,34 +305,36 @@ static void LUPSolve(HXTLinearSystemLU *system, double *b){ x[i] -= rowReduction(A[i], x, i+1, imin(system->rowEnd[i], N)); if(fabs(A[i][i])<1e-8) - printf("pivot is close to be zero! %d\n",i); + HXT_WARNING("pivot is close to be zero! %d\n",i); x[i] = x[i]/A[i][i]; } } HXTStatus hxtLinearSystemLUCreate(HXTLinearSystemLU **pSystem, int nElements, int nNodesByElement, int nFields, uint32_t *elements) { - HXTLinearSystemLU *system = malloc(sizeof(HXTLinearSystemLU)); + HXTLinearSystemLU *system; + HXT_CHECK( hxtMalloc(&system, sizeof(HXTLinearSystemLU)) ); *pSystem = system; system->nFields = nFields; system->nNodesByElement = nNodesByElement; system->nElements = nElements; system->elements = elements; - int nNodes = 0; + uint32_t nNodes = 0; for (int i = 0; i < nElements*nNodesByElement; ++i) if(elements[i]+1 > nNodes) nNodes = elements[i]+1; system->nNodes = nNodes; system->n = nNodes *nFields; - system->nodeMap = malloc(sizeof(int)*nNodes); - reverseCuthillMckee(system, system->nodeMap); + HXT_CHECK( hxtMalloc(&system->nodeMap, sizeof(int)*nNodes) ); + HXT_CHECK( reverseCuthillMckee(system, system->nodeMap) ); int nUsedNodes = 0; - for (int i = 0; i < nNodes; ++i) + for (uint32_t i = 0; i < nNodes; ++i) if (system->nodeMap[i] >= 0) nUsedNodes ++; system->n = nUsedNodes*system->nFields; - int *nodeRowStart = malloc(sizeof(int)*nUsedNodes); - int *nodeRowEnd = malloc(sizeof(int)*nUsedNodes); + int *nodeRowStart, *nodeRowEnd; + HXT_CHECK( hxtMalloc(&nodeRowStart, sizeof(int)*nUsedNodes) ); + HXT_CHECK( hxtMalloc(&nodeRowEnd, sizeof(int)*nUsedNodes) ); for (int i = 0; i < nUsedNodes; ++i) { nodeRowEnd[i] = 0; nodeRowStart[i] = nUsedNodes; @@ -350,9 +354,9 @@ HXTStatus hxtLinearSystemLUCreate(HXTLinearSystemLU **pSystem, int nElements, in } } int totalSize = 0; - system->rowStart = malloc(sizeof(int)*system->n); - system->rowEnd = malloc(sizeof(int)*system->n); - system->rowLuEnd = malloc(sizeof(int)*system->n); + HXT_CHECK( hxtMalloc(&system->rowStart, sizeof(int)*system->n) ); + HXT_CHECK( hxtMalloc(&system->rowEnd, sizeof(int)*system->n) ); + HXT_CHECK( hxtMalloc(&system->rowLuEnd, sizeof(int)*system->n) ); for (int i = 0; i < nUsedNodes; ++i) { for (int j = 0; j < nFields; ++j) { int k = i*nFields +j; @@ -372,11 +376,12 @@ HXTStatus hxtLinearSystemLUCreate(HXTLinearSystemLU **pSystem, int nElements, in int paddedStart = (start+PADDING-1)&~(PADDING-1); totalSize += system->rowEnd[i]-system->rowStart[i]+(paddedStart-start); } - free(nodeRowStart); - free(nodeRowEnd); - //system->M = _mm_malloc(sizeof(double)*totalSize, PADDING*8); - system->M = malloc(sizeof(double)*totalSize); // FIXME Gmsh - system->rows = malloc(sizeof(double*)*system->n); + HXT_CHECK( hxtFree(&nodeRowStart) ); + HXT_CHECK( hxtFree(&nodeRowEnd) ); + + HXT_CHECK( hxtAlignedMalloc(&system->M, sizeof(double)*totalSize) ); + + HXT_CHECK( hxtMalloc(&system->rows, sizeof(double)*system->n) ); for (int i = 0; i < totalSize; ++i) system->M[i] = 0.0; @@ -388,8 +393,8 @@ HXTStatus hxtLinearSystemLUCreate(HXTLinearSystemLU **pSystem, int nElements, in totalSize += system->rowEnd[i]-system->rowStart[i]+(paddedStart-start); system->rows[i] = system->M + paddedStart; } - //system->x = _mm_malloc(sizeof(double)*system->n, PADDING*8); - system->x = malloc(sizeof(double)*system->n); // FIXME Gmsh + + HXT_CHECK( hxtAlignedMalloc(&system->x, sizeof(double)*system->n) ); return HXT_STATUS_OK; } @@ -498,7 +503,7 @@ HXTStatus hxtLinearSystemLUAddRhsEntry(HXTLinearSystemLU *system, double *rhs, i HXTStatus hxtLinearSystemLUSolve(HXTLinearSystemLU *system, double *rhs, double *solution){ if(system->flaglu==0){ - LUPDecompose(system); + HXT_CHECK( LUPDecompose(system) ); system->flaglu=1; } @@ -514,6 +519,9 @@ HXTStatus hxtLinearSystemLUSolve(HXTLinearSystemLU *system, double *rhs, double HXTStatus hxtLinearSystemLUHasConverged(HXTLinearSystemLU *lsys, int *converged) { + // Fixme: is this really implemented correctly ? XD + HXT_UNUSED(lsys); // unused argument + *converged = 1; return HXT_STATUS_OK; } @@ -523,14 +531,14 @@ HXTStatus hxtLinearSystemLUDelete(HXTLinearSystemLU **pSystem) HXTLinearSystemLU *system = *pSystem; if (system == NULL) return HXT_STATUS_OK; - free(system->x); - free(system->M); - free(system->rows); - free(system->rowStart); - free(system->rowEnd); - free(system->rowLuEnd); - free(system->nodeMap); - free(system); + HXT_CHECK( hxtAlignedFree(&system->x) ); + HXT_CHECK( hxtAlignedFree(&system->M) ); + HXT_CHECK( hxtFree(&system->rows) ); + HXT_CHECK( hxtFree(&system->rowStart) ); + HXT_CHECK( hxtFree(&system->rowEnd) ); + HXT_CHECK( hxtFree(&system->rowLuEnd) ); + HXT_CHECK( hxtFree(&system->nodeMap) ); + HXT_CHECK( hxtFree(&system) ); *pSystem = NULL; return HXT_STATUS_OK; } diff --git a/contrib/hxt/hxt_linear_system_lu.h b/contrib/hxt/reparam/src/hxt_linear_system_lu.h similarity index 98% rename from contrib/hxt/hxt_linear_system_lu.h rename to contrib/hxt/reparam/src/hxt_linear_system_lu.h index 430060363a..01f1b0f62f 100644 --- a/contrib/hxt/hxt_linear_system_lu.h +++ b/contrib/hxt/reparam/src/hxt_linear_system_lu.h @@ -1,7 +1,8 @@ #ifndef HEXTREME_LINEAR_SYSTEM_LU_H #define HEXTREME_LINEAR_SYSTEM_LU_H + +#include "hxt_message.h" #include <stdint.h> -#include "hxt_api.h" #ifndef HEXTREME_LINEAR_SYSTEM_H // to avoid illegal (in C) redefinition of typedef typedef struct HXTLinearSystemLUStruct HXTLinearSystemLU; diff --git a/contrib/hxt/hxt_linear_system_petsc.c b/contrib/hxt/reparam/src/hxt_linear_system_petsc.c similarity index 88% rename from contrib/hxt/hxt_linear_system_petsc.c rename to contrib/hxt/reparam/src/hxt_linear_system_petsc.c index d359fc642b..aa20e3d515 100644 --- a/contrib/hxt/hxt_linear_system_petsc.c +++ b/contrib/hxt/reparam/src/hxt_linear_system_petsc.c @@ -33,31 +33,32 @@ typedef struct SparsityChunkStruct { struct SparsityChunkStruct *next; }SparsityChunk; -static SparsityChunk *sparsityChunkNew(void) +static HXTStatus sparsityChunkNew(SparsityChunk** new) { - SparsityChunk *s = malloc(sizeof(SparsityChunk)); + HXT_CHECK( hxtMalloc(new, sizeof(SparsityChunk)) ); for (int i = 0; i < CSIZE; ++i) - s->n[i] = -1; - s->next = NULL; - return s; + (*new)->n[i] = -1; + (*new)->next = NULL; } -static void sparsityChunkInsert(SparsityChunk *s, int id) +static HXTStatus sparsityChunkInsert(SparsityChunk *s, int id) { for (int i=0; i<CSIZE; ++i) { if (s->n[i] == -1) s->n[i] = id; if (s->n[i] == id) return; } - if (s->next == NULL) - s->next = sparsityChunkNew(); - sparsityChunkInsert(s->next, id); + if (s->next == NULL) { + HXT_CHECK( sparsityChunkNew(&s->next) ); + } + HXT_CHECK( sparsityChunkInsert(s->next, id) ); } -static void sparsityChunkFree(SparsityChunk *s) +static HXTStatus sparsityChunkFree(SparsityChunk *s) { - if (s->next) - sparsityChunkFree(s->next); - free(s); + if (s->next) { + HXT_CHECK( hxtFree(s->next) ); + } + HXT_CHECK( hxtFree(&s) ); } static HXTStatus assembleIfNeeded(HXTLinearSystemPETSc *system) @@ -72,9 +73,11 @@ static HXTStatus assembleIfNeeded(HXTLinearSystemPETSc *system) static HXTStatus linearSystemPreAllocateMatrix(HXTLinearSystemPETSc *system) { - SparsityChunk **sparsity = malloc(sizeof(SparsityChunk*)*system->nMappedNodes); - for (int i = 0; i < system->nMappedNodes; ++i) - sparsity[i] = sparsityChunkNew(); + SparsityChunk **sparsity; + HXT_CHECK( hxtMalloc(&sparsity, sizeof(SparsityChunk*)*system->nMappedNodes) ); + for (int i = 0; i < system->nMappedNodes; ++i){ + HXT_CHECK( sparsityChunkNew(&sparsity[i]) ); + } for (int i = 0; i < system->nElements; ++i) { uint32_t *el = system->elements + system->nNodesByElement * i; for (int k = 0; k < system->nNodesByElement; ++k) { @@ -85,11 +88,12 @@ static HXTStatus linearSystemPreAllocateMatrix(HXTLinearSystemPETSc *system) uint32_t nl = system->nodeMap[el[l]]; if (nl == -1) continue; - sparsityChunkInsert(sparsity[nk], nl); + HXT_CHECK( sparsityChunkInsert(sparsity[nk], nl) ); } } } - int *nByRow = malloc(sizeof(int) * system->nMappedNodes*system->nFields); + int *nByRow; + HXT_CHECK( hxtMalloc(&nByRow, sizeof(int) * system->nMappedNodes*system->nFields) ); for (uint32_t i = 0; i < system->nMappedNodes; ++i){ int n = 0; SparsityChunk *c = sparsity[i]; @@ -100,14 +104,14 @@ static HXTStatus linearSystemPreAllocateMatrix(HXTLinearSystemPETSc *system) for (int j = 0; j < CSIZE; ++j) if(c->n[j] != -1) n++; - sparsityChunkFree(sparsity[i]); + HXT_CHECK( sparsityChunkFree(sparsity[i]) ); for (uint32_t j = 0; j < system->nFields; ++j){ nByRow[i*system->nFields+j] = n*system->nFields; } } - free(sparsity); + HXT_CHECK( hxtFree(&sparsity) ); HXT_PETSC_CHECK(MatSeqAIJSetPreallocation(system->a, 0, nByRow)); - free(nByRow); + HXT_CHECK( hxtFree(&nByRow) ); return HXT_STATUS_OK; } @@ -117,8 +121,9 @@ HXTStatus hxtLinearSystemPETScAddToMatrix(HXTLinearSystemPETSc *system, int el0, int nn = system->nNodesByElement; uint32_t *e0 = system->elements + el0*nn; uint32_t *e1 = system->elements + el1*nn; - int *map0 = malloc(sizeof(int)*nn*nf); - int *map1 = malloc(sizeof(int)*nn*nf); + int *map0, *map1; + HXT_CHECK( hxtMalloc(&map0, sizeof(int)*nn*nf) ); + HXT_CHECK( hxtMalloc(&map1, sizeof(int)*nn*nf) ); for(int i=0; i<nn; ++i){ for (int j=0; j<nf; ++j){ map0[j*nn+i] = system->nodeMap[e0[i]]*nf+j; @@ -126,8 +131,8 @@ HXTStatus hxtLinearSystemPETScAddToMatrix(HXTLinearSystemPETSc *system, int el0, } } HXT_PETSC_CHECK(MatSetValues(system->a,nn*nf,map0,nn*nf,map1,localMatrix,ADD_VALUES)); - free(map0); - free(map1); + HXT_CHECK( hxtFree(&map0) ); + HXT_CHECK( hxtFree(&map1) ); system->assemblyNeeded = 1; return HXT_STATUS_OK; } @@ -256,7 +261,8 @@ HXTStatus hxtLinearSystemPETScCreate(HXTLinearSystemPETSc **pSystem, int nElemen HXT_PETSC_CHECK(PetscOptionsInsertString(NULL, petscOptions)); HXT_PETSC_CHECK(PetscOptionsPrefixPop(NULL)); #endif - HXTLinearSystemPETSc *system = malloc(sizeof(HXTLinearSystemPETSc)); + HXTLinearSystemPETSc *system; + HXT_CHECK( hxtMalloc(&system, sizeof(HXTLinearSystemPETSc)) ); *pSystem = system; system->nElements = nElements; system->nNodesByElement = nNodesByElement; @@ -268,7 +274,8 @@ HXTStatus hxtLinearSystemPETScCreate(HXTLinearSystemPETSc **pSystem, int nElemen nNodes = elements[i]+1; } system->nNodes = nNodes; - uint32_t *nodeMap = malloc((nNodes)*sizeof(uint32_t)); + uint32_t *nodeMap; + HXT_CHECK( hxtMalloc(&nodeMap, sizeof(uint32_t) * nNodes) ); for (uint32_t i = 0; i < nNodes; ++i) { nodeMap[i] = -1; } @@ -308,8 +315,8 @@ HXTStatus hxtLinearSystemPETScDelete(HXTLinearSystemPETSc **pSystem) HXT_PETSC_CHECK(KSPDestroy(&system->ksp)); HXT_PETSC_CHECK(VecDestroy(&system->x)); HXT_PETSC_CHECK(MatDestroy(&system->a)); - free(system->nodeMap); - free(system); + HXT_CHECK( hxtFree(&system->nodeMap) ); + HXT_CHECK( hxtFree(&system) ); *pSystem = NULL; return HXT_STATUS_OK; } diff --git a/contrib/hxt/hxt_linear_system_petsc.h b/contrib/hxt/reparam/src/hxt_linear_system_petsc.h similarity index 98% rename from contrib/hxt/hxt_linear_system_petsc.h rename to contrib/hxt/reparam/src/hxt_linear_system_petsc.h index 416132b986..4b9cf41f71 100644 --- a/contrib/hxt/hxt_linear_system_petsc.h +++ b/contrib/hxt/reparam/src/hxt_linear_system_petsc.h @@ -1,7 +1,8 @@ #ifndef HEXTREME_LINEAR_SYSTEM_PETSC_H #define HEXTREME_LINEAR_SYSTEM_PETSC_H + +#include "hxt_message.h" #include <stdint.h> -#include "hxt_api.h" #include <petscmat.h> typedef struct HXTLinearSystemPETScStruct HXTLinearSystemPETSc; diff --git a/contrib/hxt/hxt_mean_values.c b/contrib/hxt/reparam/src/hxt_mean_values.c similarity index 99% rename from contrib/hxt/hxt_mean_values.c rename to contrib/hxt/reparam/src/hxt_mean_values.c index cea68540c5..bc7a24fee4 100644 --- a/contrib/hxt/hxt_mean_values.c +++ b/contrib/hxt/reparam/src/hxt_mean_values.c @@ -1,7 +1,13 @@ #include "hxt_mean_values.h" #include "hxt_edge.h" #include "hxt_linear_system.h" +#include "hxt_tools.h" + + #include <math.h> +#ifndef M_PI + #define M_PI 3.14159265358979323846264338327950 +#endif // !M_PI @@ -69,8 +75,6 @@ HXTStatus hxtMeanValuesCreate(HXTEdges *edges, HXTMeanValues **meanValues) } -HXTStatus hxtMeanValuesDelete(HXTMeanValues **meanValues); - HXTStatus hxtMeanValuesCompute(HXTMeanValues *meanValues){ HXTEdges *edges = meanValues->initialEdges; @@ -370,6 +374,7 @@ HXTStatus hxtMeanValuesGetData(HXTMeanValues *mv, uint64_t **global,uint32_t **g } +#ifdef HXT_CORE_FILEIO HXTStatus hxtMeanValuesWrite(HXTMeanValues *meanValues, const char* filename) { @@ -428,3 +433,5 @@ HXTStatus hxtMeanValuesWriteParamMesh(HXTMeanValues *meanValues,const char* file return HXT_STATUS_OK; } + +#endif diff --git a/contrib/hxt/hxt_non_linear_solver.c b/contrib/hxt/reparam/src/hxt_non_linear_solver.c similarity index 99% rename from contrib/hxt/hxt_non_linear_solver.c rename to contrib/hxt/reparam/src/hxt_non_linear_solver.c index cfaac46f28..ac15117d3f 100644 --- a/contrib/hxt/hxt_non_linear_solver.c +++ b/contrib/hxt/reparam/src/hxt_non_linear_solver.c @@ -1,5 +1,6 @@ #include "hxt_non_linear_solver.h" #include "hxt_tools.h" +#include <math.h> HXTStatus hxtNewtonRaphson(HXTLinearSystem *nrSys, double *solution, int size, int maxiter, double tol, HXTNonLinearSolverCallbackF *fcb, HXTNonLinearSolverCallbackDF *dfcb, void *data) { double *delta, *rhs; @@ -16,7 +17,7 @@ HXTStatus hxtNewtonRaphson(HXTLinearSystem *nrSys, double *solution, int size, i nrNorm += delta[ie]*delta[ie]; } nrNorm = sqrt(nrNorm); - printf("__NR iter %i norm %g\n",n,nrNorm); + HXT_INFO("__NR iter %i norm %g\n",n,nrNorm); if(nrNorm<tol) break; } diff --git a/contrib/hxt/hxt_non_linear_solver.h b/contrib/hxt/reparam/src/hxt_non_linear_solver.h similarity index 98% rename from contrib/hxt/hxt_non_linear_solver.h rename to contrib/hxt/reparam/src/hxt_non_linear_solver.h index 28054ec5e3..3be8fe11a0 100644 --- a/contrib/hxt/hxt_non_linear_solver.h +++ b/contrib/hxt/reparam/src/hxt_non_linear_solver.h @@ -2,7 +2,6 @@ #define HXT_NON_LINEAR_SOLVER_H #include "hxt_linear_system.h" -#include "hxt_api.h" typedef HXTStatus HXTNonLinearSolverCallbackF(void *data, const double *solution, HXTLinearSystem *sys, double *f); typedef HXTStatus HXTNonLinearSolverCallbackDF(void *data, const double *solution, HXTLinearSystem *sys); diff --git a/contrib/hxt/sizeField/CMakeLists.txt b/contrib/hxt/sizeField/CMakeLists.txt new file mode 100644 index 0000000000..f3b743ea50 --- /dev/null +++ b/contrib/hxt/sizeField/CMakeLists.txt @@ -0,0 +1,15 @@ +# this project is a little bit special, as it needs to be part of GMSH build tree + +if(NOT HAVE_P4EST) + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + find_library(P4EST_LIB p4est) + find_path(P4EST_INC "p4est.h" PATH_SUFFIXES src) + if((NOT P4EST_LIB) OR (NOT P4EST_INC)) + message(FATAL_ERROR "P4EST library not found") + else() + message("found P4est library (${P4EST_LIB})") + endif() +endif() + +append_gmsh_src(contrib/hxt/hxt_sizeField "hxt_octree.cpp;hxt_octree.h") diff --git a/contrib/hxt/hxt_octree.cpp b/contrib/hxt/sizeField/hxt_octree.cpp similarity index 99% rename from contrib/hxt/hxt_octree.cpp rename to contrib/hxt/sizeField/hxt_octree.cpp index 43e03c45a6..c0a8c0ccd8 100644 --- a/contrib/hxt/hxt_octree.cpp +++ b/contrib/hxt/sizeField/hxt_octree.cpp @@ -8,9 +8,11 @@ #define ALPHA 1.40123 #define BULK_SIZE 7.77; -#ifdef HAVE_P4EST - p4est_connectivity_t *p8est_connectivity_new_cube (double c); + +static inline double hxtNorm2V3(double v[3]){ + return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); +} static double hxtOctreeBulkSize(double x, double y, double z){ return BULK_SIZE; @@ -1793,9 +1795,8 @@ static void hxtOctreeRTreeCallback(p4est_iter_volume_info_t * info, void *user_d double *v1 = forestOptions->nodalCurvature + 6*node; double *v2 = forestOptions->nodalCurvature + 6*node + 3; - double k1, k2; - hxtNorm2V3(v1, &k1); - hxtNorm2V3(v2, &k2); + double k1 = hxtNorm2V3(v1); + double k2 = hxtNorm2V3(v2); kappa = fmax(kappa,fmax(k1,k2)); } @@ -2274,18 +2275,3 @@ p8est_connectivity_new_cube (double c) NULL, &num_ett, NULL, NULL, NULL, &num_ctt, NULL, NULL); } - -#else // HAVE_P4EST - -HXTStatus hxtOctreeSearchOne(HXTForest *forest, double x, double y, double z, double *size) { - - *size = 1.e22; - static int count = 0; - if (count ++ < 20) - return HXT_ERROR_MSG(HXT_STATUS_ERROR,"HXT needs P4EST to compute automatic size fields"); - return HXT_STATUS_ERROR; -} - - - -#endif // HAVE_P4EST diff --git a/contrib/hxt/hxt_octree.h b/contrib/hxt/sizeField/hxt_octree.h similarity index 98% rename from contrib/hxt/hxt_octree.h rename to contrib/hxt/sizeField/hxt_octree.h index 67ba99e4cf..a8db22e9a6 100644 --- a/contrib/hxt/hxt_octree.h +++ b/contrib/hxt/sizeField/hxt_octree.h @@ -14,7 +14,6 @@ // P4EST INCLUDES -#ifdef HAVE_P4EST #include <p4est_to_p8est.h> #include <p8est_bits.h> #include <p8est_ghost.h> @@ -23,7 +22,6 @@ #include <p8est_iterate.h> #include <p8est_extended.h> #include <p8est_search.h> -#endif // HXT INCLUDES @@ -53,9 +51,7 @@ typedef struct HXTForest{ // Donnees disponibles sur chaque quadrant typedef struct size_data{ double size; -#ifdef HAVE_P4EST double ds[P4EST_DIM]; -#endif double d2s; // Laplacien double h; diff --git a/contrib/hxt/tetBR/CMakeLists.txt b/contrib/hxt/tetBR/CMakeLists.txt new file mode 100644 index 0000000000..c7feef927c --- /dev/null +++ b/contrib/hxt/tetBR/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.9) +project(hxt_tetBR CXX) + +# options are inherited from hxt_core (see ../core/CMakeList.txt) + +option(HXT_TETBR_OBJECT_ONLY "Do not create hxt_tetBR library" OFF) + +set(HXT_TETBR_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_boundary_recovery.cxx" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_boundary_recovery.h" + ) + +if(HXT_TETBR_OBJECT_ONLY) + add_library(hxt_tetBR OBJECT ${HXT_TETBR_SRC}) +else() + add_library(hxt_tetBR ${HXT_TETBR_SRC}) +endif() + +add_subdirectory(../core "${CMAKE_CURRENT_BINARY_DIR}/hxt_boundaryRecovery_core") +add_subdirectory(../predicates "${CMAKE_CURRENT_BINARY_DIR}/predicates") + +target_include_directories(hxt_tetBR + PUBLIC include + PRIVATE src) +target_link_libraries(hxt_tetBR + PUBLIC hxt_core + PRIVATE hxt_predicates) + diff --git a/contrib/hxt/tetBR/include/hxt_boundary_recovery.h b/contrib/hxt/tetBR/include/hxt_boundary_recovery.h new file mode 100644 index 0000000000..80186326f6 --- /dev/null +++ b/contrib/hxt/tetBR/include/hxt_boundary_recovery.h @@ -0,0 +1,16 @@ +#ifndef HXT_BOUNDARY_RECOVERY_H +#define HXT_BOUNDARY_RECOVERY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hxt_mesh.h" + +HXTStatus hxt_boundary_recovery(HXTMesh *mesh); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/hxt/hxt_boundary_recovery.cxx b/contrib/hxt/tetBR/src/hxt_boundary_recovery.cxx similarity index 91% rename from contrib/hxt/hxt_boundary_recovery.cxx rename to contrib/hxt/tetBR/src/hxt_boundary_recovery.cxx index a6a59021d2..808634e06e 100644 --- a/contrib/hxt/hxt_boundary_recovery.cxx +++ b/contrib/hxt/tetBR/src/hxt_boundary_recovery.cxx @@ -1,9 +1,8 @@ -#define __STDC_LIMIT_MACROS // FIXME Gmsh (for UINT_MAX & co in C++ code) -#include <limits.h> extern "C" { #include "hxt_mesh.h" -#include "predicates.h" +#include "hxt_tools.h" #include "hxt_omp.h" +#include "predicates.h" } #include <assert.h> @@ -71,26 +70,27 @@ static double orient4d(double*, double *, double *, double *, double *, #if !defined(TETLIBRARY) #define TETLIBRARY #endif + +#include <cstdio> +#include <cstring> #include "tetgenBR.h" #include "tetgenBR.cxx" -// int _edges [12][2] = {{3,2},{3,0},{1,0},{1,2},{2,1},{0,2},{0,3},{2,0},{1,3},{2,3},{3,1},{0,1}}; -// int computeTetGenVersion (const int iface1, uint32_t *v1, -// uint32_t *v2){ -// uint32_t i1 = v1[_edges[iface1][0]]; -// uint32_t i2 = v1[_edges[iface1][1]]; -// for (int i=0;i<12;i++){ -// if (i2 == v2[_edges[i][0]] && -// i1 == v2[_edges[i][1]]) return i; -// } -// printf("oulalalala\n"); -// return -1; +/* just a function such that: + * if hashLess(a,b)==true + * then hashLess(b,a)==false + * + * BUT hashLess(a,b)==true and hashLess(b,c)==true + * doesn't imply that hashLess(a,c)==true + * and inversely if you replace true with false (no transitivity) */ +static inline uint64_t hashLess(uint64_t a, uint64_t b) { + return ((a^b)&1)^(a<b); +} -// } -static inline int computeTetGenVersion2(uint32_t v1, uint32_t* v2Choices, const int iface2){ +static inline int computeTetGenVersion(uint32_t v1, uint32_t* v2Choices, const int iface2){ int i; for (i=0; i<3; i++) { if(v1==v2Choices[i]){ @@ -119,10 +119,10 @@ int tetgenmesh::reconstructmesh(void *p){ initializepools(); // printf("we have %u vertices\n", mesh->vertices.num); - + { point pointloop; - REAL x, y, z; + REAL x, y, z; // Read the points. for (uint32_t i = 0; i < mesh->vertices.num; i++) { makepoint(&pointloop, UNUSEDVERTEX); @@ -162,12 +162,12 @@ int tetgenmesh::reconstructmesh(void *p){ } point *idx2verlist; - + // Create a map from indices to vertices. // printf("we create a map from indices to vertices\n"); makeindex2pointmap(idx2verlist); - + { hullsize = 0; @@ -208,17 +208,26 @@ int tetgenmesh::reconstructmesh(void *p){ for (tf1.ver=0; tf1.ver<4; tf1.ver++){ uint64_t neigh = mesh->tetrahedra.neigh[4*i + tf1.ver]; uint64_t n = neigh/4; - int iface2 = neigh%4; - triface tf2 = ts[n]; - - // the face of the neighbor tetrahedra that is the same - uint32_t face2[3] = {mesh->tetrahedra.node[4*n+((iface2+1)&3)], - mesh->tetrahedra.node[4*n+((iface2&2)^3)], - mesh->tetrahedra.node[4*n+((iface2+3)&2)]}; - - tf2.ver = computeTetGenVersion2(mesh->tetrahedra.node[4*i+((tf1.ver+1)&3)], face2, iface2); - bond(tf1,tf2); + /* we shouldn't compute bond on both side of a facet, so we must + * give a priority to one side. + * simply using if(i<n) would produce load imbalance + * as the first thread, which takes care of the first tet + * would have much more work to do. Therefore, we use the + * hashLess function */ + if(hashLess(i, n)) { + int iface2 = neigh%4; + + triface tf2 = ts[n]; + + // the face of the neighbor tetrahedra that is the same + uint32_t face2[3] = {mesh->tetrahedra.node[4*n+((iface2+1)&3)], + mesh->tetrahedra.node[4*n+((iface2&2)^3)], + mesh->tetrahedra.node[4*n+((iface2+3)&2)]}; + + tf2.ver = computeTetGenVersion(mesh->tetrahedra.node[4*i+((tf1.ver+1)&3)], face2, iface2); + bond(tf1,tf2); + } } } } @@ -232,8 +241,8 @@ int tetgenmesh::reconstructmesh(void *p){ tetrahedron tptr = encode(tetloop); for (tetloop.ver = 0; tetloop.ver < 4; tetloop.ver++) { // Create the point-to-tet map. - setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr); - + setpoint2tet((point) (tetloop.tet[4 + tetloop.ver]), tptr); + // Clean the temporary used space. tetloop.tet[8 + tetloop.ver] = NULL; } @@ -246,7 +255,7 @@ int tetgenmesh::reconstructmesh(void *p){ face newseg; point p[4]; int idx; - + for (uint64_t i=0;i<mesh->triangles.num;i++){ for (uint64_t j = 0; j < 3; j++) { p[j] = idx2verlist[mesh->triangles.node[3*i+j]]; @@ -254,7 +263,7 @@ int tetgenmesh::reconstructmesh(void *p){ setpointtype(p[j], FACETVERTEX); } } - + // Create an initial triangulation. makeshellface(subfaces, &newsh); setshvertices(newsh, p[0], p[1], p[2]); @@ -272,17 +281,17 @@ int tetgenmesh::reconstructmesh(void *p){ } // i unifysegments(); - - + + face* shperverlist; int* idx2shlist; face searchsh, neighsh; face segloop, checkseg; point checkpt; - + // Construct a map from points to subfaces. makepoint2submap(subfaces, idx2shlist, shperverlist); - + // Process the set of PSC edges. // Remeber that all segments have default marker '-1'. // int COUNTER = 0; @@ -298,7 +307,7 @@ int tetgenmesh::reconstructmesh(void *p){ // This is a potential problem in surface mesh. continue; // Skip this edge. } - + // Find a face contains the edge p[0], p[1]. newseg.sh = NULL; searchsh.sh = NULL; @@ -362,7 +371,7 @@ int tetgenmesh::reconstructmesh(void *p){ } setshellmark(newseg, mesh->lines.colors[i]); } // i - + delete [] shperverlist; delete [] idx2shlist; insegments = subsegs->items; @@ -371,7 +380,7 @@ int tetgenmesh::reconstructmesh(void *p){ delete [] idx2verlist; clock_t t = clock(); - recoverboundary(t); + recoverboundary(t); // printf("Carve Holes\n"); // carveholes(); if (subvertstack->objects > 0l) { @@ -391,7 +400,7 @@ int tetgenmesh::reconstructmesh(void *p){ // Write mesh into to HXT. point p[4]; std::set<int> /*l_faces, */l_edges; - + if (points->items > mesh->vertices.num) { mesh->vertices.num = points->items; if(mesh->vertices.num > mesh->vertices.size) { @@ -400,7 +409,7 @@ int tetgenmesh::reconstructmesh(void *p){ 4*mesh->vertices.num*sizeof( double )) ); mesh->vertices.size = mesh->vertices.num; } - + face parentseg, parentsh, spinsh; point pointloop; // Create newly added mesh vertices. @@ -450,10 +459,10 @@ int tetgenmesh::reconstructmesh(void *p){ if (reconstructingTriangularMeshIsRequired) { // restore 2D mesh ... HXT_CHECK( hxtAlignedFree(&(mesh->triangles.node))); - HXT_CHECK( hxtAlignedFree(&(mesh->triangles.colors))); + HXT_CHECK( hxtAlignedFree(&(mesh->triangles.colors))); HXT_INFO("deleting %u triangles",mesh->triangles.num); mesh->triangles.num = 0; // firstindex; // in->firstnumber; - { + { face subloop; subloop.shver = 0; subfaces->traversalinit(); @@ -494,10 +503,10 @@ int tetgenmesh::reconstructmesh(void *p){ } } } - + // TODO: maybe fill a vector with triface and use that to convert in parallel ? int elementnumber = 0; // firstindex; // in->firstnumber; - { + { // number tets triface tetloop; tetrahedrons->traversalinit(); @@ -511,10 +520,10 @@ int tetgenmesh::reconstructmesh(void *p){ if(elementnumber!=tetrahedrons->items) return HXT_ERROR_MSG(HXT_STATUS_ERROR, "This can not happen..."); - + { // move data to HXT - triface tetloop; + triface tetloop; tetrahedrons->traversalinit(); tetloop.tet = alltetrahedrontraverse(); @@ -537,8 +546,8 @@ int tetgenmesh::reconstructmesh(void *p){ mesh->tetrahedra.size = mesh->tetrahedra.num; } - - + + int counter = 0; while (tetloop.tet != (tetrahedron *) NULL) { tetloop.ver = 11; @@ -563,7 +572,7 @@ int tetgenmesh::reconstructmesh(void *p){ else { mesh->tetrahedra.node[4*counter+k] = pointmark(p[k]); if (mesh->tetrahedra.node[4*counter+k] >= mesh->vertices.num) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "ERROR : index %u out of range (%u)\n", + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "ERROR : index %u out of range (%u)\n", mesh->tetrahedra.node[4*counter+k], mesh->vertices.num); } diff --git a/contrib/hxt/tetgenBR.cxx b/contrib/hxt/tetBR/src/tetgenBR.cxx similarity index 100% rename from contrib/hxt/tetgenBR.cxx rename to contrib/hxt/tetBR/src/tetgenBR.cxx diff --git a/contrib/hxt/tetgenBR.h b/contrib/hxt/tetBR/src/tetgenBR.h similarity index 99% rename from contrib/hxt/tetgenBR.h rename to contrib/hxt/tetBR/src/tetgenBR.h index 13b1903719..d47ef862f8 100644 --- a/contrib/hxt/tetgenBR.h +++ b/contrib/hxt/tetBR/src/tetgenBR.h @@ -215,7 +215,7 @@ public: brio_threshold = 64; brio_ratio = 0.125; facet_separate_ang_tol = 179.9; - facet_overlap_ang_tol = 0.001; + facet_overlap_ang_tol = 0.01; facet_small_ang_tol = 15.0; maxvolume = -1.0; minratio = 2.0; diff --git a/contrib/hxt/tetMesh/CMakeLists.txt b/contrib/hxt/tetMesh/CMakeLists.txt new file mode 100644 index 0000000000..0d813fb47a --- /dev/null +++ b/contrib/hxt/tetMesh/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.9) +project(hxt_tetMesh C) + +# options are inherited from hxt_core (see ../core/CMakeList.txt) + +option(HXT_TETMESH_OBJECT_ONLY "Do not create hxt_tetMesh library" OFF) + +set(HXT_TETMESH_SRC + "${CMAKE_CURRENT_SOURCE_DIR}/src/HXTSPR.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetFlag.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetMesh.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetOpti.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetSync.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetColor.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetUtils.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_vertices.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_smoothing.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRefine.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRepair.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetQuality.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edgeRemoval.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetDelaunay.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetNodalSize.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/HXTSPR.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetFlag.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetOpti.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetSync.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetColor.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetUtils.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_vertices.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_smoothing.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRefine.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRepair.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetQuality.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edgeRemoval.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetDelaunay.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetNodalSize.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetOptiUtils.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetPartition.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetMesh.h" + ) + +if(HXT_TETMESH_OBJECT_ONLY) + add_library(hxt_tetMesh OBJECT ${HXT_TETMESH_SRC}) +else() + add_library(hxt_tetMesh ${HXT_TETMESH_SRC}) +endif() + +add_subdirectory(../core "${CMAKE_CURRENT_BINARY_DIR}/core") +add_subdirectory(../predicates "${CMAKE_CURRENT_BINARY_DIR}/predicates") + +target_include_directories(hxt_tetMesh + PUBLIC include + PRIVATE src) +target_link_libraries(hxt_tetMesh + PUBLIC hxt_core + PRIVATE hxt_predicates) +target_compile_features(hxt_tetMesh PRIVATE c_std_99) + diff --git a/contrib/hxt/hxt_tetMesh.h b/contrib/hxt/tetMesh/include/hxt_tetMesh.h similarity index 93% rename from contrib/hxt/hxt_tetMesh.h rename to contrib/hxt/tetMesh/include/hxt_tetMesh.h index 6c6311e7c1..018182e0d8 100644 --- a/contrib/hxt/hxt_tetMesh.h +++ b/contrib/hxt/tetMesh/include/hxt_tetMesh.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETMESH_ -#define _HXT_TETMESH_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETMESH_H +#define HXT_TETMESH_H #include "hxt_mesh.h" @@ -50,7 +58,7 @@ typedef struct { void* meshSizeData; /* user pointer to give to meshSizeFun */ /* function to recover missing features in a mesh */ - HXTStatus (*recoveryFun)(HXTMesh* mesh, void* userData); + HXTStatus (*recoveryFun)(HXTMesh* mesh, void* recoveryData); void* recoveryData; /* user pointer to give to recoveryFun */ } HXTTetMeshOptions; diff --git a/contrib/hxt/HXTSPR.c b/contrib/hxt/tetMesh/src/HXTSPR.c similarity index 91% rename from contrib/hxt/HXTSPR.c rename to contrib/hxt/tetMesh/src/HXTSPR.c index 37232bc956..25073f1f34 100644 --- a/contrib/hxt/HXTSPR.c +++ b/contrib/hxt/tetMesh/src/HXTSPR.c @@ -1,23 +1,13 @@ -/* This file is part of HXTSPR. * - * - HXTSPR 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 3 of the License, or * - (at your option) any later version. * - * - HXTSPR 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 HXTSPR. If not, see <http://www.gnu.org/licenses/>. * - * - See the COPYING file for the GNU General Public License . * - * -Author: Célestin Marot (celestin.marot@uclouvain.be) */ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot #include "HXTSPR.h" +#include <math.h> #include "hxt_tetFlag.h" #include "predicates.h" @@ -1141,8 +1131,8 @@ static void add_knownPositive_quality_map(SPRCavity* SPR, unsigned v3, double qual) { - int orientation = get_orient3d(SPR, v0, v1, v2, v3); #ifndef NDEBUG + int orientation = get_orient3d(SPR, v0, v1, v2, v3); if(orientation >= 0.0){ HXT_WARNING("a tetrahedron has a negative volume but a quality of %f", qual); } @@ -1174,11 +1164,11 @@ static int tetOutOfPartition(HXTVertex* vertices, * growingCav->worstQuality is the quality of that tet * growingCav->meshAdjacencies[] are the adjacencies of that tet */ static inline HXTStatus SPROpti_init(SPRGrowingCavity* growingCav, - HXTSPRData* data, + ThreadLocal* local, uint64_t badTet) { SPRCavity* SPR = &growingCav->cavity; - growingCav->worstQuality = data->quality->values[badTet]; + growingCav->worstQuality = local->quality->values[badTet]; // initialize the SPR structure maps and arrays SPR_clear_maps(SPR); @@ -1188,21 +1178,21 @@ static inline HXTStatus SPROpti_init(SPRGrowingCavity* growingCav, SPR->triangles.num = 0; // add_face() (in second for loop) already increments num SPR->tetrahedra.num = 1; SPR->tetrahedra.array[0] = (SPRTet) {{0,1,2,3}}; - SPR->tetrahedra.quality = data->quality->values[badTet]; - SPR->quality.function = data->quality->function; - SPR->quality.userData = data->quality->userData; + SPR->tetrahedra.quality = local->quality->values[badTet]; + SPR->quality.function = local->quality->function; + SPR->quality.userData = local->quality->userData; SPR->num_search_nodes = 0; - SPR->max_search_nodes = data->maxSearchNodes; + SPR->max_search_nodes = local->SPR.maxSearchNodes; - HXTMesh* mesh = data->toSync->mesh; - HXTPartition* partition = data->partition; + HXTMesh* mesh = local->toSync->mesh; + HXTPartition* partition = &local->partition; HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; // maybe this is unnecessary... better check anyway if(tetOutOfPartition(vertices, partition, &mesh->tetrahedra.node[4*badTet])) return HXT_STATUS_CONFLICT; - HXTDeleted* deleted = data->deleted; + HXTDeleted* deleted = &local->deleted; HXT_CHECK( askForDeleted(deleted, 1) ); setDeletedFlag(mesh, badTet); deleted->array[deleted->num++] = badTet; @@ -1221,7 +1211,7 @@ static inline HXTStatus SPROpti_init(SPRGrowingCavity* growingCav, }; } - add_knownPositive_quality_map(SPR, 0, 1, 2, 3, data->quality->values[badTet]); + add_knownPositive_quality_map(SPR, 0, 1, 2, 3, local->quality->values[badTet]); // adding faces and linked stuffs for(int i=0; i<4; i++) { @@ -1240,8 +1230,8 @@ static inline HXTStatus SPROpti_init(SPRGrowingCavity* growingCav, static inline HXTStatus find_best_point(SPRGrowingCavity* growingCav, - HXTSPRData* data, - int* bestPoint) { + ThreadLocal* local, + int* bestPoint) { /* A point is good if it is very connected to the cavity ! * (connection <==> a tet containing the point having a face on the cavity) * If multiple points have the same number of connections the quality of @@ -1254,7 +1244,7 @@ static inline HXTStatus find_best_point(SPRGrowingCavity* growingCav, * opposite_point[] array, If it is present, we increment numConnected. */ SPRCavity* SPR = &growingCav->cavity; - HXTMesh* mesh = data->toSync->mesh; + HXTMesh* mesh = local->toSync->mesh; uint64_t* adjacencies = growingCav->meshAdjacencies; uint32_t opposite_point[SPR_MAX_TRIANGLES]; @@ -1308,6 +1298,9 @@ static inline HXTStatus find_best_point(SPRGrowingCavity* growingCav, } } + if(mostNumConnected==0) // cavity is completely constrained + return HXT_STATUS_INTERNAL; + /* if there is equality, we must compute the sum of qualities * for each point with mostNumConnected connection */ if(equality) { @@ -1320,9 +1313,9 @@ static inline HXTStatus find_best_point(SPRGrowingCavity* growingCav, double score = 0.0; for(int t=0; t<SPR->triangles.num; t++) { - if(adjacencies[t]==HXT_NO_ADJACENT || mesh->tetrahedra.node[adjacencies[t]]!=node) + if(adjacencies[t]==HXT_NO_ADJACENT || mesh->tetrahedra.node[adjacencies[t]]!=node || getFacetConstraint(mesh, adjacencies[t]/4, adjacencies[t]%4)) continue; - score += data->quality->values[adjacencies[t]/4]; + score -= local->quality->values[adjacencies[t]/4]; } if(score > bestScore) { @@ -1382,13 +1375,13 @@ static inline int needNewSPREdge(HXTMesh* mesh, uint64_t meshTet, int in_facet, /* attach the best point (see find_best_point()) to the cavity */ static inline HXTStatus attach_best_point(SPRGrowingCavity* growingCav, - HXTSPRData* data) + ThreadLocal* local) { SPRCavity* SPR = &growingCav->cavity; - HXTMesh* mesh = data->toSync->mesh; + HXTMesh* mesh = local->toSync->mesh; int newNode; - HXT_CHECK( find_best_point(growingCav, data, &newNode) ); + HXT_CHECK( find_best_point(growingCav, local, &newNode) ); // we can now add mostConnectPoint !! :-) double* coord = &mesh->vertices.coord[4*newNode]; @@ -1404,10 +1397,10 @@ static inline HXTStatus attach_best_point(SPRGrowingCavity* growingCav, uint64_t* adjacencies = growingCav->meshAdjacencies; /* we delete tetrahedra that contain the added point. */ - HXTPartition* partition = data->partition; + HXTPartition* partition = &local->partition; HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - HXTDeleted* deleted = data->deleted; + HXTDeleted* deleted = &local->deleted; for(int i=0; i<SPR->triangles.num;) { // notice we don't increment i here uint64_t meshTet = adjacencies[i]/4; @@ -1475,12 +1468,12 @@ static inline HXTStatus attach_best_point(SPRGrowingCavity* growingCav, // add the quality of the meshTet to known cavities :-) add_knownPositive_quality_map(SPR, tetV[0], tetV[1], tetV[2], tetV[3], - data->quality->values[meshTet]); + local->quality->values[meshTet]); // update the quality to the worst one... - if(data->quality->values[meshTet] < growingCav->worstQuality) { - SPR->tetrahedra.quality = data->quality->values[meshTet]; - growingCav->worstQuality = data->quality->values[meshTet]; + if(local->quality->values[meshTet] < growingCav->worstQuality) { + SPR->tetrahedra.quality = local->quality->values[meshTet]; + growingCav->worstQuality = local->quality->values[meshTet]; } adjacencies[i] = adjacencies[SPR->triangles.num-1]; @@ -1603,26 +1596,34 @@ static HXTStatus fillConstrainedEdgeMap(HXTMesh* mesh, SPRCavity* SPR, /* replace the interior of the cavity within the mesh by the triangulation * found by hxtSPR() */ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, - HXTSPRData* data, + ThreadLocal* local, +#ifdef DEBUG uint64_t prevNumDeleted, +#endif uint64_t badTet) { - HXTDeleted* deleted = data->deleted; - HXTMesh* mesh = data->toSync->mesh; + HXTDeleted* deleted = &local->deleted; + HXTMesh* mesh = local->toSync->mesh; uint16_t color = mesh->tetrahedra.colors[badTet]; - uint16_t lastCheck = data->dateOfLastCheck; - data->dateOfLastCreation = lastCheck; + uint16_t lastCheck = local->SPR.dateOfLastCheck; + local->SPR.dateOfLastCreation = lastCheck; SPRCavity* SPR = &growingCav->cavity; +#ifdef DEBUG + int adjacencies_to_nowhere = 0; + for(uint64_t i=prevNumDeleted; i<deleted->num; i++) { + uint64_t oldTet = deleted->array[i]; + for(int j=0; j<4; j++) { + if(mesh->tetrahedra.neigh[4*oldTet + j] == HXT_NO_ADJACENT) + adjacencies_to_nowhere++; + } + } +#endif + // we integrate the SPR cavity into the mesh if((uint64_t) SPR->tetrahedra.num > deleted->num) { - HXT_CHECK( createNewDeleted(data->toSync, deleted, SPR->tetrahedra.num) ); - } - else if((uint64_t) SPR->tetrahedra.num < deleted->num - prevNumDeleted) { - for(uint64_t i=prevNumDeleted; i<deleted->num - SPR->tetrahedra.num; i++) { - data->quality->values[deleted->array[i]] = DBL_MAX; - } + HXT_CHECK( createNewDeleted(local->toSync, deleted, SPR->tetrahedra.num) ); } uint64_t* adjacencies = growingCav->meshAdjacencies; @@ -1648,9 +1649,9 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, mesh->tetrahedra.flag[meshTet] = 0; unsigned index = get_compressed_index(v[0], v[1], v[2], v[3]); - data->quality->values[meshTet] = SPR->map.qualities[index]; - data->date->values[meshTet].creation = lastCheck; - data->date->values[meshTet].check = lastCheck; + local->quality->values[meshTet] = SPR->map.qualities[index]; + local->date->values[meshTet].creation = lastCheck; + local->date->values[meshTet].check = lastCheck; for(int j=0; j<4; j++) { // try to find the face in SPRTriangles @@ -1659,13 +1660,18 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, v[getNode1FromFacet(j)], v[getNode2FromFacet(j)]); + remove_face_map(SPR, v[getNode0FromFacet(j)], + v[getNode1FromFacet(j)], + v[getNode2FromFacet(j)]); + if(index==UINT16_MAX) { mesh->tetrahedra.neigh[4*meshTet + j] = HXT_NO_ADJACENT; } else { uint64_t adj = adjacencies[index]; - if(adj==HXT_NO_ADJACENT) { // happens for constrained faces + if(adj==HXT_NO_ADJACENT) { // happens for constrained faces, or + // when there are no ghosts mesh->tetrahedra.neigh[4*meshTet + j] = HXT_NO_ADJACENT; setFacetConstraint(mesh, meshTet, j); } @@ -1698,7 +1704,8 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, return HXT_ERROR_MSG(HXT_STATUS_ERROR, "DEBUG: missing external adjacency"); #endif - /* now, all external adjacencies have been found, we just have to find internal adjacencies :p */ + /* now, all external adjacencies (except HXT_NO_ADJACENT ones obviously) + * have been found, we just have to find internal adjacencies :p */ for(int i=0; i<SPR->tetrahedra.num; i++) { uint64_t meshTet = newTet[i]; @@ -1722,8 +1729,10 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, SPR->tetrahedra.array[i].node[getNode0FromFacet(j)], SPR->tetrahedra.array[i].node[getNode2FromFacet(j)], SPR->tetrahedra.array[i].node[getNode1FromFacet(j)]); - uint64_t neighTet = newTet[adj/4]; - mesh->tetrahedra.neigh[4*meshTet+j] = 4*neighTet + adj%4; + if(adj!=UINT16_MAX) { + uint64_t neighTet = newTet[adj/4]; + mesh->tetrahedra.neigh[4*meshTet+j] = 4*neighTet + adj%4; + } } } } @@ -1734,17 +1743,20 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, for (int j=0; j<4; ++j) { - if(mesh->tetrahedra.neigh[4*meshTet+j]>=4*mesh->tetrahedra.num) { - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "one of the tetrahedron is missing a neighbor"); + if(mesh->tetrahedra.neigh[4*meshTet+j]==HXT_NO_ADJACENT) { + adjacencies_to_nowhere--; } - } - for (int j=0; j<4; ++j) - { - if(mesh->tetrahedra.neigh[mesh->tetrahedra.neigh[4*meshTet+j]]!=4*meshTet+j){ + else if(mesh->tetrahedra.neigh[4*meshTet+j]!=HXT_NO_ADJACENT && mesh->tetrahedra.neigh[4*meshTet+j]/4>=mesh->tetrahedra.num) { + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "invalid neighbor"); + } + else if(mesh->tetrahedra.neigh[mesh->tetrahedra.neigh[4*meshTet+j]]!=4*meshTet+j){ return HXT_ERROR_MSG(HXT_STATUS_ERROR, "one of the tetrahedron is not the neighbor of its neighbor"); } } } + + if(adjacencies_to_nowhere!=0) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "there are unrecovered adjacencies"); #endif deleted->num -= SPR->tetrahedra.num; @@ -1757,11 +1769,11 @@ static inline HXTStatus rebuildMesh(SPRGrowingCavity* growingCav, * if none of the date are as recent as the last check * return 0 * else, return 1 */ -int verifyDates(HXTSPRData* data, uint64_t prevNumDeleted, uint16_t lastCheck) +int verifyDates(ThreadLocal* local, uint64_t prevNumDeleted, uint16_t lastCheck) { - HXTDeleted* deleted = data->deleted; + HXTDeleted* deleted = &local->deleted; for(uint64_t i=prevNumDeleted; i<deleted->num; i++) { - uint16_t creation = data->date->values[deleted->array[i]].creation; + uint16_t creation = local->date->values[deleted->array[i]].creation; if(creation >= lastCheck) return 1; } @@ -1772,18 +1784,18 @@ int verifyDates(HXTSPRData* data, uint64_t prevNumDeleted, uint16_t lastCheck) /* we checked the growing cavity till the end but it didn't work * we mark the date of this failure... */ -HXTStatus setCheckDate(HXTSPRData* data, uint64_t badTet) +HXTStatus setCheckDate(ThreadLocal* local, uint64_t badTet) { - data->date->values[badTet].check = data->dateOfLastCreation + 1; - data->dateOfLastCheck = data->dateOfLastCreation + 1; + local->date->values[badTet].check = local->SPR.dateOfLastCreation + 1; + local->SPR.dateOfLastCheck = local->SPR.dateOfLastCreation + 1; return HXT_STATUS_OK; } -static void deleted_reset(HXTSPRData* data, uint64_t prevNumDeleted) +static void deleted_reset(ThreadLocal* local, uint64_t prevNumDeleted) { - HXTDeleted* deleted = data->deleted; - HXTMesh* mesh = data->toSync->mesh; + HXTDeleted* deleted = &local->deleted; + HXTMesh* mesh = local->toSync->mesh; for(uint64_t i=prevNumDeleted; i<deleted->num; i++) { unsetDeletedFlag(mesh, deleted->array[i]); } @@ -1795,25 +1807,24 @@ static void deleted_reset(HXTSPRData* data, uint64_t prevNumDeleted) -HXTStatus hxtSPR_opti(HXTSPRData* data, +HXTStatus hxtSPR_opti(ThreadLocal* local, uint64_t badTet) { SPRGrowingCavity growingCav; // all the structure on the stack... it should fit ^^ SPRCavity* SPR = &growingCav.cavity; - uint64_t prevNumDeleted = data->deleted->num; + uint64_t prevNumDeleted = local->deleted.num; - uint16_t lastCheck = data->date->values[badTet].check; + uint16_t lastCheck = local->date->values[badTet].check; int datesOk = 0; - HXT_CHECK( SPROpti_init(&growingCav, data, badTet) ); - - int lastNumPoints = 4; + HXT_CHECK( SPROpti_init(&growingCav, local, badTet) ); do { - HXTStatus status = attach_best_point(&growingCav, data); + // return HXT_STATUS_INTERNAL if the cavity if completely constrained + HXTStatus status = attach_best_point(&growingCav, local); - if(status==HXT_STATUS_CONFLICT) { - deleted_reset(data, prevNumDeleted); + if(status==HXT_STATUS_CONFLICT || status==HXT_STATUS_INTERNAL) { + deleted_reset(local, prevNumDeleted); return status; } else if(status!=HXT_STATUS_OK) { @@ -1822,7 +1833,7 @@ HXTStatus hxtSPR_opti(HXTSPRData* data, } if(datesOk==0) - datesOk = verifyDates(data, prevNumDeleted, lastCheck); + datesOk = verifyDates(local, prevNumDeleted, lastCheck); if(datesOk) { /* applying the SPR algorithm, only initializing the necessary minimum */ @@ -1844,8 +1855,8 @@ HXTStatus hxtSPR_opti(HXTSPRData* data, } else { // HXT_WARNING("Maximum nodes of SPR search reached"); - deleted_reset(data, prevNumDeleted); - setCheckDate(data, badTet); + deleted_reset(local, prevNumDeleted); + setCheckDate(local, badTet); return HXT_STATUS_INTERNAL; } } @@ -1871,13 +1882,18 @@ HXTStatus hxtSPR_opti(HXTSPRData* data, if(growingCav.cavity.points.num==SPR_MAX_PTS) { // HXT_WARNING("Too much points in SPR cavity"); - deleted_reset(data, prevNumDeleted); - setCheckDate(data, badTet); + deleted_reset(local, prevNumDeleted); + setCheckDate(local, badTet); return HXT_STATUS_INTERNAL; } } while(1); - HXT_CHECK( rebuildMesh(&growingCav, data, prevNumDeleted, badTet) ); + HXT_CHECK( rebuildMesh(&growingCav, + local, +#ifdef DEBUG + prevNumDeleted, +#endif + badTet) ); return HXT_STATUS_OK; } diff --git a/contrib/hxt/HXTSPR.h b/contrib/hxt/tetMesh/src/HXTSPR.h similarity index 79% rename from contrib/hxt/HXTSPR.h rename to contrib/hxt/tetMesh/src/HXTSPR.h index d0daa46ac8..83145102fc 100644 --- a/contrib/hxt/HXTSPR.h +++ b/contrib/hxt/tetMesh/src/HXTSPR.h @@ -1,36 +1,20 @@ -/* This file is part of HXTSPR. * - * - HXTSPR 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 3 of the License, or * - (at your option) any later version. * - * - HXTSPR 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 HXTSPR. If not, see <http://www.gnu.org/licenses/>. * - * - See the COPYING file for the GNU General Public License . * - * -Author: Célestin Marot (celestin.marot@uclouvain.be) */ - - -#ifndef _HXTSPR_ -#define _HXTSPR_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + + +#ifndef HXTSPR_H +#define HXTSPR_H #ifdef __cplusplus extern "C" { #endif -#include "hxt_tetSync.h" -#include "hxt_tetPartition.h" -#include "hxt_tetQuality.h" -#include "hxt_tetOptiDate.h" -#include "hxt_bbox.h" - +#include "hxt_tetOptiUtils.h" /* /!\ Warning /!\ This version is a modified version of HXTSPR * @@ -214,21 +198,6 @@ typedef struct { HXTStatus hxtSPR(SPRCavity* cavity); - -typedef struct { - HXTDeleted* deleted; - HXTPartition* partition; - HXTTetQualities* quality; - HXTTetDates* date; - uint16_t dateOfLastCheck; - uint16_t dateOfLastCreation; - HXT2Sync* toSync; - // unsigned char* verticesMap; - uint64_t maxSearchNodes; -} HXTSPRData; - - - /* hxtSPR_opti() performs an optimization of the quality of a mesh * by growing a cavity around the tetrahedron `badTet` * and applying hxtSPR repeatedly. @@ -243,10 +212,16 @@ typedef struct { * However, this function requires no knowledge of how SPR works, * and no knowledge of the SPRCavity structure. * - * * It is meant to be used for mesh optimization in hxt_tetOpti.c + * + * Possible return status: + * - HXT_STATUS_OK (on success: cavity improved) + * - HXT_STATUS_ERROR (on error) + * - HXT_STATUS_CONFLICT (on conflict with other partition) + * - HXT_STATUS_INTERNAL (on failure: cavity not improved) + * */ -HXTStatus hxtSPR_opti(HXTSPRData* data, +HXTStatus hxtSPR_opti(ThreadLocal* local, uint64_t badTet); diff --git a/contrib/hxt/hxt_edgeRemoval.c b/contrib/hxt/tetMesh/src/hxt_edgeRemoval.c similarity index 77% rename from contrib/hxt/hxt_edgeRemoval.c rename to contrib/hxt/tetMesh/src/hxt_edgeRemoval.c index 679c522fee..76be934860 100644 --- a/contrib/hxt/hxt_edgeRemoval.c +++ b/contrib/hxt/tetMesh/src/hxt_edgeRemoval.c @@ -1,8 +1,27 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_edgeRemoval.h" #include "hxt_tetFlag.h" -#define NV -128 // not a valid entry +#define NV -128 // not a valid entry +#define HXT_EDGE_REMOVAL_MAX 7 // you cannot increase it above 7 ATM + +typedef struct { // bipyramidal cavity for the edge-removal + uint64_t neigh_up [HXT_EDGE_REMOVAL_MAX]; + uint64_t neigh_down[HXT_EDGE_REMOVAL_MAX]; + uint16_t flag [HXT_EDGE_REMOVAL_MAX]; + uint32_t annulus [HXT_EDGE_REMOVAL_MAX]; + uint32_t v_up; + uint32_t v_down; + uint32_t num; +} HXTBipyramid; /* @@ -359,27 +378,28 @@ static const SwapPattern patterns[8] = { **************************************************************************/ /* create a cavity containing all tetrahedra around an edge, by turning around it */ -static inline HXTStatus buildEdgeCavity(HXTEdgeRemovalData* data, - const uint64_t badTet, - unsigned in_facet, unsigned out_facet) +static inline HXTStatus buildERCavity(ThreadLocal* local, + HXTBipyramid* cavity, + const uint64_t badTet, + unsigned in_facet, unsigned out_facet) { - const uint64_t startDist = data->partition->startDist; - const uint64_t rel = data->partition->lengthDist; + const uint64_t startDist = local->partition.startDist; + const uint64_t rel = local->partition.lengthDist; int edgeOut = 0; - HXTMesh* mesh = data->toSync->mesh; - HXTDeleted* deleted = data->deleted; + HXTMesh* mesh = local->toSync->mesh; + HXTDeleted* deleted = &local->deleted; HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; uint64_t curTet = badTet; - data->cavity.num = 0; + cavity->num = 0; if(getEdgeConstraint(mesh, badTet, getEdgeFromFacets(in_facet, out_facet))) return HXT_STATUS_CONSTRAINT; - data->cavity.v_up = mesh->tetrahedra.node[4*badTet + UP_VERTEX(in_facet, out_facet)]; - edgeOut += vertexOutOfPartition(vertices, data->cavity.v_up, rel, startDist); - data->cavity.v_down = mesh->tetrahedra.node[4*badTet + DOWN_VERTEX(in_facet, out_facet)]; - edgeOut += vertexOutOfPartition(vertices, data->cavity.v_down, rel, startDist); + cavity->v_up = mesh->tetrahedra.node[4*badTet + UP_VERTEX(in_facet, out_facet)]; + edgeOut += vertexOutOfPartition(vertices, cavity->v_up, rel, startDist); + cavity->v_down = mesh->tetrahedra.node[4*badTet + DOWN_VERTEX(in_facet, out_facet)]; + edgeOut += vertexOutOfPartition(vertices, cavity->v_down, rel, startDist); HXT_CHECK( askForDeleted(deleted, 7) ); @@ -394,15 +414,15 @@ static inline HXTStatus buildEdgeCavity(HXTEdgeRemovalData* data, } // add the current tetrahedra - deleted->array[deleted->num + data->cavity.num] = curTet; + deleted->array[deleted->num + cavity->num] = curTet; { unsigned up_facet = UP_FACET(in_facet, out_facet); unsigned down_facet = DOWN_FACET(in_facet, out_facet); // add the neighbor up and down - data->cavity.neigh_up[data->cavity.num] = mesh->tetrahedra.neigh[4*curTet + up_facet]; - data->cavity.neigh_down[data->cavity.num] = mesh->tetrahedra.neigh[4*curTet + down_facet]; + cavity->neigh_up[cavity->num] = mesh->tetrahedra.neigh[4*curTet + up_facet]; + cavity->neigh_down[cavity->num] = mesh->tetrahedra.neigh[4*curTet + down_facet]; int upDownEdge = getEdgeFromFacets(up_facet, down_facet); int upOutEdge = getEdgeFromFacets(up_facet, out_facet); @@ -412,18 +432,18 @@ static inline HXTStatus buildEdgeCavity(HXTEdgeRemovalData* data, // TODO: just store one flag for up and down. the one of the default tetrahedron - data->cavity.flag[data->cavity.num] = (getFacetConstraint(mesh, curTet, up_facet)!=0) + - ((getEdgeConstraint(mesh, curTet, upOutEdge)!=0)<<1) + - ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<2) + - ((getEdgeConstraint(mesh, curTet, upInEdge)!=0)<<3) + - ((getFacetConstraint(mesh, curTet, down_facet)!=0)<<4) + - ((getEdgeConstraint(mesh, curTet, downOutEdge)!=0)<<5) + - ((getEdgeConstraint(mesh, curTet, downInEdge)!=0)<<6) + - ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<7); + cavity->flag[cavity->num] = (getFacetConstraint(mesh, curTet, up_facet)!=0) + + ((getEdgeConstraint(mesh, curTet, upOutEdge)!=0)<<1) + + ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<2) + + ((getEdgeConstraint(mesh, curTet, upInEdge)!=0)<<3) + + ((getFacetConstraint(mesh, curTet, down_facet)!=0)<<4) + + ((getEdgeConstraint(mesh, curTet, downOutEdge)!=0)<<5) + + ((getEdgeConstraint(mesh, curTet, downInEdge)!=0)<<6) + + ((getEdgeConstraint(mesh, curTet, upDownEdge)!=0)<<7); } // add the annulus vertex - data->cavity.annulus[data->cavity.num] = oldV; - data->cavity.num++; + cavity->annulus[cavity->num] = oldV; + cavity->num++; // go into the neighbor through out_facet uint64_t neigh = mesh->tetrahedra.neigh[4*curTet + out_facet]; @@ -432,7 +452,7 @@ static inline HXTStatus buildEdgeCavity(HXTEdgeRemovalData* data, return HXT_STATUS_CONSTRAINT; } - if(data->cavity.num>=HXT_EDGE_REMOVAL_MAX) + if(cavity->num>=HXT_EDGE_REMOVAL_MAX) return HXT_STATUS_INTERNAL; curTet = neigh/4; @@ -453,43 +473,31 @@ static inline HXTStatus buildEdgeCavity(HXTEdgeRemovalData* data, /* perform the edge removal, also called edge swap */ -HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, +HXTStatus hxtEdgeRemoval_opti(ThreadLocal* local, uint64_t badTet, unsigned edgeID) { unsigned in_facet, out_facet; getFacetsFromEdge(edgeID, &in_facet, &out_facet); - HXTMesh* mesh = data->toSync->mesh; - HXTBipyramid* cavity = &data->cavity; - HXTDeleted* deleted = data->deleted; - double* qualityArray = data->quality->values; - - HXT_CHECK( buildEdgeCavity(data, badTet, in_facet, out_facet) ); - - // int modified = 0; - // for (uint32_t i=0; i<cavity->num; i++) { - // if(getEdgeRemovalFlag(mesh, deleted->array[deleted->num+i])) { - // modified = 1; - // break; - // } - // } + HXTMesh* mesh = local->toSync->mesh; + HXTDeleted* deleted = &local->deleted; + double* qualityArray = local->quality->values; - // if(!modified) { - // return HXT_STATUS_INTERNAL; - // } + HXTBipyramid cavity; + HXT_CHECK( buildERCavity(local, &cavity, badTet, in_facet, out_facet) ); // find worst quality tet of the cavity double worst = DBL_MAX; - for (uint32_t i=0; i<cavity->num; i++) { + for (uint32_t i=0; i<cavity.num; i++) { uint64_t tet = deleted->array[deleted->num+i]; double qual = qualityArray[tet]; if(qual<worst) worst = qual; } - const SwapPattern* patt = &patterns[cavity->num]; - const unsigned num_triangle_per_triangul = cavity->num-2; - uint32_t* annulus = cavity->annulus; + const SwapPattern* patt = &patterns[cavity.num]; + const unsigned num_triangle_per_triangul = cavity.num-2; + uint32_t* annulus = cavity.annulus; // calculate qualities of all possible tetrahedra double hxtDeclareAligned qual_up[35]; @@ -502,8 +510,8 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, // printf("%u %u %u\n", p0, p1, p2); - qual_up[i] = tetQuality(mesh, data->quality, p0, p1, cavity->v_up, p2); - qual_down[i] = tetQuality(mesh, data->quality, p0, p1, p2, cavity->v_down); + qual_up[i] = tetQuality(mesh, local->quality, p0, p1, cavity.v_up, p2); + qual_down[i] = tetQuality(mesh, local->quality, p0, p1, p2, cavity.v_down); if(qual_up[i]<=worst || qual_down[i]<=worst) mask |= patt->triangle_in_triangul[i]; @@ -543,15 +551,14 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, } // mark new deleted tet as deleted - for (uint32_t i=0; i<cavity->num; i++) { - qualityArray[deleted->array[deleted->num+i]] = DBL_MAX; // deleted tets have good quality + for (uint32_t i=0; i<cavity.num; i++) { setDeletedFlag(mesh, deleted->array[deleted->num+i]); } - deleted->num += cavity->num; + deleted->num += cavity.num; // reserve enough tetrahedra if(2*num_triangle_per_triangul > deleted->num){ // tetrahedra are created... - HXT_CHECK(createNewDeleted(data->toSync, deleted, 2*num_triangle_per_triangul) ); + HXT_CHECK(createNewDeleted(local->toSync, deleted, 2*num_triangle_per_triangul) ); } uint64_t start = deleted->num - 2*num_triangle_per_triangul; @@ -580,24 +587,24 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, mesh->tetrahedra.colors[newTet_up] = color; mesh->tetrahedra.flag[newTet_up] = 0; qualityArray[newTet_up] = qual_up[tri]; - data->date->values[newTet_up].creation = data->date->current; + local->date->values[newTet_up].creation = local->date->current; nodes[0] = p0; nodes[1] = p1; - nodes[2] = cavity->v_up; + nodes[2] = cavity.v_up; nodes[3] = p2; if(n0>=0){ // v we add this because if n0%4==2 then it should be 3 neigh[0] = 4*deleted->array[start + (n0/4)*2] + (n0%4) + (n0%4)/2; } else { - neigh[0] = cavity->neigh_up[-n0-1]; + neigh[0] = cavity.neigh_up[-n0-1]; // (down=2, in=3, out=1, up=0) - mesh->tetrahedra.flag[newTet_up] |= (cavity->flag[-n0-1]&UINT16_C(1))<<8 |// face (bit 0) is the up_facet => 0 (bit 8) - (cavity->flag[-n0-1]&UINT16_C(2))>>1 |// first edge (bit 1) was between up_facet and out_facet => 0-1 (bit 0) - (cavity->flag[-n0-1]&UINT16_C(4))>>1 |// second edge (bit 2) was between up_facet and down_facet => 0-2 (bit 1) - (cavity->flag[-n0-1]&UINT16_C(8))>>1; // third edge (bit 3) was between up_facet and in_facet => 0-3 (bit 2) + mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n0-1]&UINT16_C(1))<<8 |// face (bit 0) is the up_facet => 0 (bit 8) + (cavity.flag[-n0-1]&UINT16_C(2))>>1 |// first edge (bit 1) was between up_facet and out_facet => 0-1 (bit 0) + (cavity.flag[-n0-1]&UINT16_C(4))>>1 |// second edge (bit 2) was between up_facet and down_facet => 0-2 (bit 1) + (cavity.flag[-n0-1]&UINT16_C(8))>>1; // third edge (bit 3) was between up_facet and in_facet => 0-3 (bit 2) if(neigh[0]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[0]] = 4*newTet_up + 0; @@ -606,13 +613,13 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, neigh[1] = 4*deleted->array[start + (n1/4)*2] + (n1%4) + (n1%4)/2; } else { - neigh[1] = cavity->neigh_up[-n1-1]; + neigh[1] = cavity.neigh_up[-n1-1]; // (down=2, in=0, out=3, up=1) - mesh->tetrahedra.flag[newTet_up] |= (cavity->flag[-n1-1]&UINT16_C(1))<<9 |// face (bit 0) is the up_facet => 1 (bit 9) - (cavity->flag[-n1-1]&UINT16_C(2))<<3 |// first edge (bit 1) was between up_facet and out_facet => 1-3 (bit 4) - (cavity->flag[-n1-1]&UINT16_C(4))<<1 |// second edge (bit 2) was between up_facet and down_facet => 1-2 (bit 3) - (cavity->flag[-n1-1]&UINT16_C(8))>>3; // third edge (bit 3) was between up_facet and in_facet => 0-1 (bit 0) + mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n1-1]&UINT16_C(1))<<9 |// face (bit 0) is the up_facet => 1 (bit 9) + (cavity.flag[-n1-1]&UINT16_C(2))<<3 |// first edge (bit 1) was between up_facet and out_facet => 1-3 (bit 4) + (cavity.flag[-n1-1]&UINT16_C(4))<<1 |// second edge (bit 2) was between up_facet and down_facet => 1-2 (bit 3) + (cavity.flag[-n1-1]&UINT16_C(8))>>3; // third edge (bit 3) was between up_facet and in_facet => 0-1 (bit 0) if(neigh[1]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[1]] = 4*newTet_up + 1; @@ -622,13 +629,13 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, neigh[3] = 4*deleted->array[start + (n2/4)*2] + (n2%4) + (n2%4)/2; } else { - neigh[3] = cavity->neigh_up[-n2-1]; + neigh[3] = cavity.neigh_up[-n2-1]; // (down=2, in=1, out=0, up=3) - mesh->tetrahedra.flag[newTet_up] |= (cavity->flag[-n2-1]&UINT16_C(1))<<11 |// face (bit 0) is the up_facet => 3 (bit 11) - (cavity->flag[-n2-1]&UINT16_C(2))<<1 |// first edge (bit 1) was between up_facet and out_facet => 0-3 (bit 2) - (cavity->flag[-n2-1]&UINT16_C(4))<<3 |// second edge (bit 2) was between up_facet and down_facet => 2-3 (bit 5) - (cavity->flag[-n2-1]&UINT16_C(8))<<1; // third edge (bit 3) was between up_facet and in_facet => 1-3 (bit 4) + mesh->tetrahedra.flag[newTet_up] |= (cavity.flag[-n2-1]&UINT16_C(1))<<11 |// face (bit 0) is the up_facet => 3 (bit 11) + (cavity.flag[-n2-1]&UINT16_C(2))<<1 |// first edge (bit 1) was between up_facet and out_facet => 0-3 (bit 2) + (cavity.flag[-n2-1]&UINT16_C(4))<<3 |// second edge (bit 2) was between up_facet and down_facet => 2-3 (bit 5) + (cavity.flag[-n2-1]&UINT16_C(8))<<1; // third edge (bit 3) was between up_facet and in_facet => 1-3 (bit 4) if(neigh[3]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[3]] = 4*newTet_up + 3; @@ -643,24 +650,24 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, mesh->tetrahedra.colors[newTet_down] = color; mesh->tetrahedra.flag[newTet_down] = 0; qualityArray[newTet_down] = qual_down[tri]; - data->date->values[newTet_down].creation = data->date->current; + local->date->values[newTet_down].creation = local->date->current; nodes[0] = p0; nodes[1] = p1; nodes[2] = p2; - nodes[3] = cavity->v_down; + nodes[3] = cavity.v_down; if(n0>=0){ neigh[0] = 4*deleted->array[start + (n0/4)*2 +1] + (n0%4); } else { - neigh[0] = cavity->neigh_down[-n0-1]; + neigh[0] = cavity.neigh_down[-n0-1]; // (down=0, in=2, out=1, up=3) - mesh->tetrahedra.flag[newTet_down] |= (cavity->flag[-n0-1]&UINT16_C(16))<<4 |// face (bit 4) is the down_facet => 0 (bit 8) - (cavity->flag[-n0-1]&UINT16_C(32))>>5 |// first edge (bit 5) was between down_facet and out_facet => 0-1 (bit 0) - (cavity->flag[-n0-1]&UINT16_C(64))>>5 |// second edge (bit 6) was between down_facet and in_facet => 0-2 (bit 1) - (cavity->flag[-n0-1]&UINT16_C(128))>>5;// third edge (bit 7) was between down_facet and up_facet => 0-3 (bit 2) + mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n0-1]&UINT16_C(16))<<4 |// face (bit 4) is the down_facet => 0 (bit 8) + (cavity.flag[-n0-1]&UINT16_C(32))>>5 |// first edge (bit 5) was between down_facet and out_facet => 0-1 (bit 0) + (cavity.flag[-n0-1]&UINT16_C(64))>>5 |// second edge (bit 6) was between down_facet and in_facet => 0-2 (bit 1) + (cavity.flag[-n0-1]&UINT16_C(128))>>5;// third edge (bit 7) was between down_facet and up_facet => 0-3 (bit 2) if(neigh[0]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[0]] = 4*newTet_down + 0; @@ -669,13 +676,13 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, neigh[1] = 4*deleted->array[start + (n1/4)*2 +1] + (n1%4); } else { - neigh[1] = cavity->neigh_down[-n1-1]; + neigh[1] = cavity.neigh_down[-n1-1]; // (down=1, in=0, out=2, up=3) - mesh->tetrahedra.flag[newTet_down] |= (cavity->flag[-n1-1]&UINT16_C(16))<<5 |// face (bit 4) is the down_facet => 1 (bit 9) - (cavity->flag[-n1-1]&UINT16_C(32))>>2 |// first edge (bit 5) was between down_facet and out_facet => 1-2 (bit 3) - (cavity->flag[-n1-1]&UINT16_C(64))>>6 |// second edge (bit 6) was between down_facet and in_facet => 0-1 (bit 0) - (cavity->flag[-n1-1]&UINT16_C(128))>>3;// third edge (bit 7) was between down_facet and up_facet => 1-3 (bit 4) + mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n1-1]&UINT16_C(16))<<5 |// face (bit 4) is the down_facet => 1 (bit 9) + (cavity.flag[-n1-1]&UINT16_C(32))>>2 |// first edge (bit 5) was between down_facet and out_facet => 1-2 (bit 3) + (cavity.flag[-n1-1]&UINT16_C(64))>>6 |// second edge (bit 6) was between down_facet and in_facet => 0-1 (bit 0) + (cavity.flag[-n1-1]&UINT16_C(128))>>3;// third edge (bit 7) was between down_facet and up_facet => 1-3 (bit 4) if(neigh[1]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[1]] = 4*newTet_down + 1; @@ -684,13 +691,13 @@ HXTStatus hxtEdgeRemoval_opti(HXTEdgeRemovalData* data, neigh[2] = 4*deleted->array[start + (n2/4)*2 +1] + (n2%4); } else { - neigh[2] = cavity->neigh_down[-n2-1]; + neigh[2] = cavity.neigh_down[-n2-1]; // (down=2, in=1, out=0, up=3) - mesh->tetrahedra.flag[newTet_down] |= (cavity->flag[-n2-1]&UINT16_C(16))<<6 |// face (bit 4) is the down_facet => 2*4 (bit 10) - (cavity->flag[-n2-1]&UINT16_C(32))>>4 |// first edge (bit 5) was between down_facet and out_facet => 0-2 (bit 1) - (cavity->flag[-n2-1]&UINT16_C(64))>>3 |// second edge (bit 6) was between down_facet and in_facet => 1-2 (bit 3) - (cavity->flag[-n2-1]&UINT16_C(128))>>2;// third edge (bit 7) was between down_facet and up_facet => 2-3 (bit 5) + mesh->tetrahedra.flag[newTet_down] |= (cavity.flag[-n2-1]&UINT16_C(16))<<6 |// face (bit 4) is the down_facet => 2*4 (bit 10) + (cavity.flag[-n2-1]&UINT16_C(32))>>4 |// first edge (bit 5) was between down_facet and out_facet => 0-2 (bit 1) + (cavity.flag[-n2-1]&UINT16_C(64))>>3 |// second edge (bit 6) was between down_facet and in_facet => 1-2 (bit 3) + (cavity.flag[-n2-1]&UINT16_C(128))>>2;// third edge (bit 7) was between down_facet and up_facet => 2-3 (bit 5) if(neigh[2]!=HXT_NO_ADJACENT) mesh->tetrahedra.neigh[neigh[2]] = 4*newTet_down + 2; diff --git a/contrib/hxt/tetMesh/src/hxt_edgeRemoval.h b/contrib/hxt/tetMesh/src/hxt_edgeRemoval.h new file mode 100644 index 0000000000..3d1452bf0e --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_edgeRemoval.h @@ -0,0 +1,26 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_EDGEREMOVAL_H +#define HXT_EDGEREMOVAL_H + +#include "hxt_tetOptiUtils.h" + + +/* return internal error (that you must catch) if: + * - the cavity overlap different partitions => HXT_STATUS_CONFLICT + * - there is a contraint inside the cavity => HXT_STATUS_CONSTRAINT + * - does'nt result in a better triangulation => HXT_STATUS_NOTBETTER + * - there is more than 7 pts around the edge => HXT_STATUS_INTERNAL + * a facet without neighbor (set to HXT_NO_ADJACENT) is also a constraint. + */ +HXTStatus hxtEdgeRemoval_opti(ThreadLocal* local, + uint64_t badTet, + unsigned edgeID); + +#endif \ No newline at end of file diff --git a/contrib/hxt/hxt_smoothing.c b/contrib/hxt/tetMesh/src/hxt_smoothing.c similarity index 84% rename from contrib/hxt/hxt_smoothing.c rename to contrib/hxt/tetMesh/src/hxt_smoothing.c index 7be04c5d06..6edc6e727f 100644 --- a/contrib/hxt/hxt_smoothing.c +++ b/contrib/hxt/tetMesh/src/hxt_smoothing.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_smoothing.h" #include "hxt_tetFlag.h" @@ -5,17 +13,17 @@ smoothing related functions **************************************************************************/ /* create a cavity containing all tetrahedra around a vertex, with a BFS */ -static inline HXTStatus buildSmoothingCavity(HXTSmoothingData* data, +static inline HXTStatus buildSmoothingCavity(ThreadLocal* local, uint64_t startFace) { - const uint64_t startDist = data->partition->startDist; - const uint64_t rel = data->partition->lengthDist; - HXTMesh* mesh = data->mesh; + const uint64_t startDist = local->partition.startDist; + const uint64_t rel = local->partition.lengthDist; + HXTMesh* mesh = local->toSync->mesh; const uint32_t vertex = mesh->tetrahedra.node[startFace]; HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; - HXTDeleted* deleted = data->deleted; + HXTDeleted* deleted = &local->deleted; - if(vertex < data->numVerticesConstrained) + if(vertex < local->numVerticesConstrained) return HXT_STATUS_CONSTRAINT; // the vertex we are moving should be in the partition or we don't even try... @@ -23,7 +31,7 @@ static inline HXTStatus buildSmoothingCavity(HXTSmoothingData* data, return HXT_STATUS_CONFLICT; } - HXT_CHECK( askForDeleted(data->deleted, 4) ); + HXT_CHECK( askForDeleted(&local->deleted, 4) ); deleted->array[deleted->num++] = startFace; setDeletedFlag(mesh, startFace/4); @@ -70,7 +78,7 @@ static inline HXTStatus buildSmoothingCavity(HXTSmoothingData* data, // we can add the face without any fears now, but we have to find where is the vertex for (unsigned k=1; k<4; k++) { if(mesh->tetrahedra.node[4*neighTet + (neighF+k)%4]==vertex) { - deleted->array[data->deleted->num++] = 4*neighTet + (neighF+k)%4; + deleted->array[local->deleted.num++] = 4*neighTet + (neighF+k)%4; break; } } @@ -109,15 +117,15 @@ static inline void interpolate_coord(const double start[3], const double end[3], } } -static HXTStatus golden_section_search(HXTSmoothingData* data, +static HXTStatus golden_section_search(ThreadLocal* local, uint64_t prevNumDeleted, double start[3], double end[3], uint32_t vertex) { - HXTMesh* mesh = data->mesh; - HXTDeleted* deleted = data->deleted; - HXTTetQualities* quality = data->quality; + HXTMesh* mesh = local->toSync->mesh; + HXTDeleted* deleted = &local->deleted; + HXTTetQualities* quality = local->quality; double* coord = mesh->vertices.coord + 4*vertex; double tol = 0.00001; @@ -173,29 +181,31 @@ static HXTStatus golden_section_search(HXTSmoothingData* data, interpolate_coord(start, end, coord, v[0]); - // compute new qualities and set new dates - for (uint64_t i=prevNumDeleted; i<data->deleted->num; i++) { - uint64_t tet = data->deleted->array[i]/4; + // compute new qualities and set new dates and reset "unused" flags + for (uint64_t i=prevNumDeleted; i<local->deleted.num; i++) { + uint64_t tet = local->deleted.array[i]/4; quality->values[tet] = tetQuality(mesh, quality, mesh->tetrahedra.node[4*tet + 0], mesh->tetrahedra.node[4*tet + 1], mesh->tetrahedra.node[4*tet + 2], mesh->tetrahedra.node[4*tet + 3]); - data->date->values[tet].creation = data->date->current; + // unused flag should be set to zero + resetUnusedFlags(mesh, tet); + local->date->values[tet].creation = local->date->current; } return HXT_STATUS_OK; } /* curFace is the face opposite to the vertex we are going to move */ -HXTStatus hxtSmoothing(HXTSmoothingData* data, +HXTStatus hxtSmoothing(ThreadLocal* local, uint64_t curFace) { - HXTMesh* mesh = data->mesh; - HXTDeleted* deleted = data->deleted; + HXTMesh* mesh = local->toSync->mesh; + HXTDeleted* deleted = &local->deleted; uint64_t prevNumDeleted = deleted->num; - HXTStatus status = buildSmoothingCavity(data, curFace); + HXTStatus status = buildSmoothingCavity(local, curFace); for (uint64_t i=prevNumDeleted; i<deleted->num; i++) { unsetDeletedFlag(mesh, deleted->array[i]/4); @@ -231,7 +241,7 @@ HXTStatus hxtSmoothing(HXTSmoothingData* data, centerCoord[j] /= (double) numTetInCavity ; } - status = golden_section_search(data, prevNumDeleted, oldCoord, centerCoord, vertex); + status = golden_section_search(local, prevNumDeleted, oldCoord, centerCoord, vertex); deleted->num = prevNumDeleted; if(status!=HXT_STATUS_OK) diff --git a/contrib/hxt/hxt_smoothing.h b/contrib/hxt/tetMesh/src/hxt_smoothing.h similarity index 50% rename from contrib/hxt/hxt_smoothing.h rename to contrib/hxt/tetMesh/src/hxt_smoothing.h index af6b1a30f0..6e747ddc5c 100644 --- a/contrib/hxt/hxt_smoothing.h +++ b/contrib/hxt/tetMesh/src/hxt_smoothing.h @@ -1,33 +1,28 @@ -#ifndef _HXT_SMOOTHING_ -#define _HXT_SMOOTHING_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_SMOOTHING_H +#define HXT_SMOOTHING_H #ifdef __cplusplus extern "C" { #endif -#include "hxt_tetSync.h" -#include "hxt_tetPartition.h" -#include "hxt_tetQuality.h" -#include "hxt_tetOptiDate.h" - -typedef struct { - HXTMesh *mesh; - HXTDeleted* deleted; - HXTPartition* partition; - HXTTetQualities* quality; - HXTTetDates* date; - uint32_t numVerticesConstrained; -} HXTSmoothingData; - +#include "hxt_tetOptiUtils.h" /* return internal error (that you must catch) if: * - the cavity overlap different partitions => HXT_STATUS_CONFLICT * - there is a contraint inside the cavity => HXT_STATUS_CONSTRAINT - * - does'nt result in a better triangulation => HXT_STATUS_NOTBETTER + * - does'nt result in a better triangulation => HXT_STATUS_INTERNAL * a facet without neighbor (set to HXT_NO_ADJACENT) is also a constraint * a node n with n<numVerticesConstrained has its position constrained */ -HXTStatus hxtSmoothing(HXTSmoothingData* data, +HXTStatus hxtSmoothing(ThreadLocal* local, uint64_t oppositeFacet); diff --git a/contrib/hxt/hxt_tetColor.c b/contrib/hxt/tetMesh/src/hxt_tetColor.c similarity index 99% rename from contrib/hxt/hxt_tetColor.c rename to contrib/hxt/tetMesh/src/hxt_tetColor.c index cc4c9d3c3b..e8f1309240 100644 --- a/contrib/hxt/hxt_tetColor.c +++ b/contrib/hxt/tetMesh/src/hxt_tetColor.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetColor.h" #include "hxt_tetFlag.h" #include "hxt_sort.h" diff --git a/contrib/hxt/hxt_tetColor.h b/contrib/hxt/tetMesh/src/hxt_tetColor.h similarity index 82% rename from contrib/hxt/hxt_tetColor.h rename to contrib/hxt/tetMesh/src/hxt_tetColor.h index 8a841956d8..cec29d9c9a 100644 --- a/contrib/hxt/hxt_tetColor.h +++ b/contrib/hxt/tetMesh/src/hxt_tetColor.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETCOLOR_ -#define _HXT_TETCOLOR_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETCOLOR_H +#define HXT_TETCOLOR_H #ifdef __cplusplus extern "C" { diff --git a/contrib/hxt/hxt_tetDelaunay.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c similarity index 82% rename from contrib/hxt/hxt_tetDelaunay.c rename to contrib/hxt/tetMesh/src/hxt_tetDelaunay.c index 0e99b188f1..263239aca9 100644 --- a/contrib/hxt/hxt_tetDelaunay.c +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetDelaunay.h" #include "predicates.h" #include "hxt_tetSync.h" @@ -12,22 +20,23 @@ */ /* compile-time parameters */ -#define SMALLEST_ROUND 2048 // #define HXT_DELAUNAY_LOW_MEMORY /* doesn't use any buffer (a lot slower, except if you are at the limit of filling the RAM) */ // #define HXT_WALK_OPTI +#define SMALLEST_PASS 2048 + + /* usefull macros */ #define HXT_OMP_CHECK(status) do{ HXTStatus _tmp_ = (status); \ if(_tmp_<0){ \ if(_tmp_>HXT_STATUS_INTERNAL) \ HXT_TRACE_MSG(_tmp_, "cannot break OpenMP region -> exiting"); \ - fflush(stdout); fflush(stderr); \ exit(_tmp_); \ } \ }while(0) -typedef struct{ +typedef struct { uint64_t neigh; // the tet on the other side of the boundary uint32_t node[3]; uint16_t flag; @@ -50,6 +59,17 @@ typedef struct { } TetLocal; +static int compareNodeLexicographically(uint32_t* nodes0, uint32_t* nodes1) +{ + for(int i=0; i<4; i++) { + if(nodes0[i] < nodes1[i]) + return -1; + else if(nodes0[i] > nodes1[i]) + return 1; + } + return 0; +} + /*********************************** * create the initial tetrahedron @@ -57,10 +77,11 @@ typedef struct { ***********************************/ static inline HXTStatus hxtTetrahedraInit(HXTMesh* mesh, hxtNodeInfo* nodeInfo, uint32_t nToInsert, int verbosity){ if(nToInsert < 4){ - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "cannot mesh less than four vertices"); + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "cannot mesh less than four points"); } if(mesh->tetrahedra.size < 5){ - uint32_t maxSizeEstim = MAX(omp_get_max_threads()*DELETED_BUFFER_SIZE+8UL*nToInsert, 10UL*nToInsert); + uint64_t sizeEstim = omp_get_max_threads()*DELETED_BUFFER_SIZE+8UL*nToInsert; + uint64_t maxSizeEstim = MAX(sizeEstim, 10UL*nToInsert); HXT_CHECK( hxtTetrahedraReserve(mesh, maxSizeEstim) ); HXT_INFO_COND(verbosity>1, "Initialization reserved %lu Tet.", mesh->tetrahedra.size); } @@ -163,18 +184,26 @@ static inline HXTStatus hxtTetrahedraInit(HXTMesh* mesh, hxtNodeInfo* nodeInfo, return HXT_STATUS_OK; } + /*********************************** * fill the passes array which tells * the size of each BRIO round. * return the number of BRIO passes ***********************************/ -static unsigned computePasses(uint32_t passes[12], uint32_t nInserted, uint32_t nToInsert) +unsigned computePasses(uint32_t passes[12], + uint32_t nInserted, + uint32_t nToInsert, + double partitionability, + int maxThreads) { + double alpha = 1.0/(maxThreads*maxThreads); + nInserted *= ((1.0 - alpha) * partitionability + alpha); + unsigned npasses=0; passes[0] = nToInsert; for (unsigned i=0; i<10; i++) { - if(passes[i] < SMALLEST_ROUND || passes[i]/8 < nInserted){ + if(passes[i] < SMALLEST_PASS || passes[i]/8 < nInserted){ passes[i+1] = 0; npasses = i+1; break; @@ -211,6 +240,7 @@ static inline HXTStatus localInit(TetLocal* local){ local->deleted.size = DELETED_BUFFER_SIZE; local->deleted.num = 0; + local->deleted.createdNew = 0; HXT_CHECK( hxtAlignedMalloc(&local->deleted.array, sizeof(uint64_t)*local->deleted.size) ); return HXT_STATUS_OK; @@ -221,13 +251,13 @@ static inline HXTStatus localInit(TetLocal* local){ * check if a tetrahedra is entirely * in the calling thread's partition ***********************************/ -static inline HXTStatus checkTetrahedron(HXTVertex* vertices, TetLocal* local, const uint32_t* nodes){ +static inline HXTStatus checkTetrahedron(HXTVertex* vertices, HXTPartition* partition, const uint32_t* nodes){ /* Actually, one vertex (not more) could be in another partition without creating a conflict. However, all threads would have to have a verticesID array => a lot of memory space wasted. Instead, we only allow the ghost vertex to be in another partition, it is handled differently in computeAdjacenciesFast function */ - uint64_t len = local->partition.lengthDist; - uint64_t start = local->partition.startDist; + uint64_t len = partition->lengthDist; + uint64_t start = partition->startDist; // if(local->partition.lengthDist==UINT64_MAX) // if we are working with one thread only // return HXT_STATUS_OK; @@ -919,8 +949,9 @@ static inline HXTStatus diggingACavity(HXTMesh* mesh, TetLocal* local, uint64_t } else{ uint32_t node = mesh->tetrahedra.node[curNeigh[0]]; - if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) + if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) { return HXT_STATUS_CONFLICT; + } local->deleted.array[local->deleted.num++] = neigh; setDeletedFlag(mesh, neigh); } @@ -938,8 +969,9 @@ static inline HXTStatus diggingACavity(HXTMesh* mesh, TetLocal* local, uint64_t } else{ uint32_t node = mesh->tetrahedra.node[curNeigh[1]]; - if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) + if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) { return HXT_STATUS_CONFLICT; + } local->deleted.array[local->deleted.num++] = neigh; setDeletedFlag(mesh, neigh); } @@ -957,8 +989,9 @@ static inline HXTStatus diggingACavity(HXTMesh* mesh, TetLocal* local, uint64_t } else{ uint32_t node = mesh->tetrahedra.node[curNeigh[2]]; - if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) + if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) { return HXT_STATUS_CONFLICT; + } local->deleted.array[local->deleted.num++] = neigh; setDeletedFlag(mesh, neigh); } @@ -978,8 +1011,9 @@ static inline HXTStatus diggingACavity(HXTMesh* mesh, TetLocal* local, uint64_t } else{ uint32_t node = mesh->tetrahedra.node[curNeigh[3]]; - if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) + if(node!=HXT_GHOST_VERTEX && vertexOutOfPartition(vertices, node, rel, local->partition.startDist)) { return HXT_STATUS_CONFLICT; + } local->deleted.array[local->deleted.num++] = neigh; setDeletedFlag(mesh, neigh); } @@ -1248,6 +1282,43 @@ static HXTStatus insertion(HXT2Sync* shared2sync, return HXT_STATUS_TRUE; } +/* filter vertices that are too close from each other, + * returns the number of filtered vertices */ +// TODO: this should be done way before assigning partition +// it should be used to identify a possible imbalance ahead of time ! +static inline uint32_t filterOnMooreCurve(HXTVertex* vertices, + hxtNodeInfo* nodeInfo, + uint32_t n, + double* nodalSizes) +{ + uint32_t mooreSkipped = 0; + #pragma omp parallel reduction(+:mooreSkipped) + { + double* p1 = NULL; + double p1Size = 0; + + #pragma omp for + for (uint32_t i=0; i<n; i++) + { + uint32_t lastNode = nodeInfo[i].node; + if(nodeInfo[i].status==HXT_STATUS_TRYAGAIN){ + double* p2 = vertices[lastNode].coord; + double p2Size = nodalSizes[lastNode]; + if(p1!=NULL && pointIsTooClose(p1, p2, 0.5*(p1Size+p2Size))!=HXT_STATUS_OK){ + mooreSkipped++; + nodeInfo[i].status=HXT_STATUS_FALSE; + } + else{ + p1 = p2; + p1Size = p2Size; + } + } + } + } + + return mooreSkipped; +} + /************************************************************* * Delaunay triangulation of a set of points @@ -1258,7 +1329,9 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, const uint32_t nToInsert, int noReordering) { + int nonDeterministic = 0; uint32_t totalNumSkipped = 0; + uint32_t totalNumInserted = 0; uint32_t seed = 1; // third, divide indices in different passes @@ -1266,7 +1339,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, const int perfectlyDelaunay = mesh->tetrahedra.num<=5; uint32_t passes[12]; - unsigned npasses = computePasses(passes, options->numVerticesInMesh, nToInsert); + unsigned npasses = computePasses(passes, options->numVerticesInMesh, nToInsert, options->partitionability, maxThreads); // that ugly cast because people want an array of double into the mesh structure HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; @@ -1274,44 +1347,58 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, /****************************************************** shuffle (and optimize cache locality) ******************************************************/ - if(noReordering){ - // shuffle nodeInfo - if(npasses>1) - HXT_CHECK( hxtNodeInfoShuffle(nodeInfo, nToInsert) ); - } - else { - HXT_INFO_COND(options->verbosity>1, "Reordering vertices from %u to %u", mesh->vertices.num - nToInsert, mesh->vertices.num); - HXTVertex* verticesToInsert = vertices + mesh->vertices.num - nToInsert; - - if(options->nodalSizes==NULL){ - // shuffle the vertices to insert, then sort each pass except the first according to the hilbert curve... - if(npasses>1) - HXT_CHECK( hxtVerticesShuffle(verticesToInsert, nToInsert) ); + int firstPassEver = (options->numVerticesInMesh==0); + uint32_t firstToInsert = mesh->vertices.num - nToInsert; + HXT_INFO_COND(options->verbosity>1, "Reordering points from %u to %u", mesh->vertices.num - nToInsert, mesh->vertices.num); + HXTVertex* verticesToInsert = vertices + mesh->vertices.num - nToInsert; + + int defaultMooreCurve = 1; + + if(options->nodalSizes==NULL && !noReordering){ + // shuffle the vertices to insert, then sort each pass except the first according to the hilbert curve... + if(npasses>1 || firstPassEver){ + HXT_CHECK( hxtVerticesShuffle(verticesToInsert, nToInsert) ); } - else{ - if(npasses>1) - HXT_CHECK( hxtNodeInfoShuffle(nodeInfo, nToInsert) ); + + HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num, NULL) ); + + for (unsigned i=firstPassEver; i<npasses; i++) { + HXT_CHECK( hxtVerticesSort(verticesToInsert+passes[i], passes[i+1]-passes[i]) ); } - - HXT_CHECK( hxtMoore(options->bbox, verticesToInsert, nToInsert, NULL) ); - if(options->nodalSizes==NULL){ - for (unsigned i=options->numVerticesInMesh < SMALLEST_ROUND; i<npasses; i++) { - HXT_CHECK( hxtVerticesSort(verticesToInsert+passes[i], passes[i+1]-passes[i]) ); - } + #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) + for (uint32_t i=0; i<nToInsert; i++) { + nodeInfo[i].node = firstToInsert + i; + nodeInfo[i].status = HXT_STATUS_TRYAGAIN; + nodeInfo[i].hilbertDist = verticesToInsert[i].padding.hilbertDist; } - else{ - #pragma omp parallel for + } + else{ + + HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num, NULL) ); + + if(!noReordering) { + #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) for (uint32_t i=0; i<nToInsert; i++) { - nodeInfo[i].hilbertDist = verticesToInsert[i].padding.hilbertDist; + nodeInfo[i].node = firstToInsert + i; + nodeInfo[i].status = HXT_STATUS_TRYAGAIN; } + } - for (unsigned i=options->numVerticesInMesh < SMALLEST_ROUND; i<npasses; i++) { - HXT_CHECK( hxtNodeInfoSort(nodeInfo+passes[i], passes[i+1]-passes[i]) ); - } + if(npasses>1 || firstPassEver) + HXT_CHECK( hxtNodeInfoShuffle(nodeInfo, nToInsert) ); - const uint32_t nodalMin = mesh->vertices.num - nToInsert; - double* sizesToInsert = options->nodalSizes + nodalMin; + #pragma omp parallel for + for (uint32_t i=0; i<nToInsert; i++) { + nodeInfo[i].hilbertDist = vertices[nodeInfo[i].node].padding.hilbertDist; + } + + for (unsigned i=firstPassEver; i<npasses; i++) { + HXT_CHECK( hxtNodeInfoSort(nodeInfo+passes[i], passes[i+1]-passes[i]) ); + } + + if(!noReordering) { + double* sizesToInsert = options->nodalSizes + firstToInsert; size_t vertSize = nToInsert*sizeof(HXTVertex); size_t sizeSize = nToInsert*sizeof(double); @@ -1319,12 +1406,12 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, double* sizeCopy; HXT_CHECK( hxtAlignedMalloc(&vertCopy, vertSize) ); HXT_CHECK( hxtAlignedMalloc(&sizeCopy, sizeSize) ); - + #pragma omp parallel for simd aligned(vertCopy,sizeCopy,nodeInfo: SIMD_ALIGN) for (uint32_t i=0; i<nToInsert; i++) { - vertCopy[i] = verticesToInsert[nodeInfo[i].node-nodalMin]; - sizeCopy[i] = sizesToInsert[nodeInfo[i].node-nodalMin]; - nodeInfo[i].node = nodalMin + i; + vertCopy[i] = verticesToInsert[nodeInfo[i].node-firstToInsert]; + sizeCopy[i] = sizesToInsert[nodeInfo[i].node-firstToInsert]; + nodeInfo[i].node = firstToInsert + i; } memcpy(verticesToInsert, vertCopy, vertSize); @@ -1335,6 +1422,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, } } + /****************************************************** Initializations and allocations ******************************************************/ @@ -1356,90 +1444,140 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, TetLocal* Locals; HXT_CHECK( hxtMalloc(&Locals, maxThreads*sizeof(TetLocal)) ); - // HXT_CHECK( hxtMalloc()) + + uint64_t* startTetGlobal; + HXT_CHECK( hxtMalloc(&startTetGlobal, maxThreads*maxThreads*sizeof(uint64_t)) ); for (int i=0; i<maxThreads; i++) localInit(&Locals[i]); - HXT_INFO_COND(options->verbosity>0, - "Delaunay of %10u vertices on %3d threads\t- mesh.nvert: %-10u", + "Delaunay of %10u points on %3d threads - mesh.nvert: %-10u", passes[npasses] - passes[0], maxThreads, options->numVerticesInMesh); - for (uint32_t p=0; p<npasses; p++) + for (uint32_t ipass=0; ipass<npasses; ipass++) { + int nthreads = maxThreads; + double conflictRatio = 0.0; - double percent = 200; - int nthreads = 1; + for(uint32_t iround=0; passes[ipass+1]-passes[ipass]; iround++) { - uint32_t tmp = (passes[p+1]-passes[p])/SMALLEST_ROUND; - while(tmp>0 && nthreads<maxThreads){ - tmp = tmp/2; - nthreads*=2; - } - } - nthreads = MIN(nthreads, maxThreads); - - // const uint32_t initialPassLength = passes[p+1] - passes[p]; - - for(uint32_t n=0; passes[p+1]-passes[p]; n++) - { - const uint32_t passStart = passes[p]; - const uint32_t passEnd = passes[p+1]; + const uint32_t passStart = passes[ipass]; + const uint32_t passEnd = passes[ipass+1]; const uint32_t passLength = passEnd - passStart; - double step = (double) passLength/nthreads; - double indexShift = 0.0; + uint32_t startShift = 0; + + nthreads = computeNumberOfThreads(conflictRatio, nthreads, passes[ipass+1]-passes[ipass], SMALLEST_PASS); /****************************************************** - choosing number of threads + Sorting vertices ******************************************************/ - if(maxThreads>1 || noReordering) { - if(percent<140/nthreads || passLength<SMALLEST_ROUND){ - nthreads=1; + if(iround>0 && !(nthreads==1 && defaultMooreCurve)) { + double bboxShift[3]; + if(nthreads==1) { + startShift = 0; + bboxShift[0] = 0.5; + bboxShift[1] = 0.5; + bboxShift[2] = 0.5; + defaultMooreCurve = 1; } - else if(percent<20){ - nthreads=(nthreads+1)/2; - } - else if(passLength < (uint32_t) nthreads*SMALLEST_ROUND) - nthreads=(nthreads+1)/2; - - - /****************************************************** - Sorting vertices - ******************************************************/ - double hxtDeclareAligned bboxShift[4]={0.5,0.5,0.5,0}; - if(percent<100 && nthreads>1) - { + else { + startShift = (double) hxtReproducibleLCG(&seed)/RAND_MAX; bboxShift[0] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; bboxShift[1] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; bboxShift[2] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; - bboxShift[3] = (double) hxtReproducibleLCG(&seed)/RAND_MAX; // this is not a bbox deformation, it's an index shift + defaultMooreCurve = 0; } - step = (double) passLength/nthreads; - indexShift = bboxShift[3]; - if(noReordering) { HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num, bboxShift) ); } else { HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num - nToInsert + passEnd, bboxShift) ); } - + #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) for (uint32_t i=passStart; i<passEnd; i++) { nodeInfo[i].hilbertDist = vertices[nodeInfo[i].node].padding.hilbertDist; } - if(p!=0 || n!=0 || nthreads>1 || options->numVerticesInMesh >= SMALLEST_ROUND){ - HXT_CHECK( hxtNodeInfoSort(nodeInfo + passStart, passLength) ); + HXT_CHECK( hxtNodeInfoSort(nodeInfo + passStart, passLength) ); + } + else if(!defaultMooreCurve) { + if(noReordering) { + HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num, NULL) ); + } + else { + HXT_CHECK( hxtMoore(options->bbox, vertices, mesh->vertices.num - nToInsert + passEnd, NULL) ); + } + defaultMooreCurve = 1; + } - // if we can only do one partition because all points are in the same cell - if(nodeInfo[passStart].hilbertDist==nodeInfo[passStart + passLength-1].hilbertDist) - nthreads = 1; + + /****************************************************** + filtering vertices on the Moore curve + ******************************************************/ + uint32_t mooreSkipped = 0; + if(options->nodalSizes!=NULL) + mooreSkipped = filterOnMooreCurve(vertices, &nodeInfo[passStart], passLength, options->nodalSizes); + + + /****************************************************** + Making partitions + ******************************************************/ + if(nthreads > 1) { + uint32_t numToProcessPerThread = (passLength - mooreSkipped) / nthreads + 1; + uint32_t counter = numToProcessPerThread; + int threadID = 0; + + for(uint32_t i=0; i<passLength; i++) { + uint32_t index = (startShift*passLength/nthreads + i) % passLength; + uint64_t hilbertDist = nodeInfo[passStart + index].hilbertDist; + if(counter>=numToProcessPerThread) { + uint64_t prevDist = nodeInfo[passStart + (index + passLength - 1) % passLength].hilbertDist; + // uint64_t nextDist = nodeInfo[passStart + (index + 1) % passLength].hilbertDist; + // uint64_t prevGrad = hilbertDist - prevDist; + // uint64_t nextGrad = nextDist - hilbertDist; + + if(/*nextGrad <= prevGrad &&*/ hilbertDist!=prevDist) { + Locals[threadID].partition.firstElem = index; + Locals[threadID].partition.startDist = prevDist + (hilbertDist - prevDist + 1)/2; + counter = 0; + threadID++; + } + } + + if(nodeInfo[passStart + index].status==HXT_STATUS_TRYAGAIN) + counter++; + } + + if(threadID <= 1) { + nthreads = 1; + } + else { + nthreads = threadID; + + // don't forget to fill all the fields of partitions + for(threadID=0; threadID<nthreads; threadID++) { + uint32_t localStart = Locals[threadID].partition.firstElem; + uint32_t localEnd = Locals[(threadID+1)%nthreads].partition.firstElem; + Locals[threadID].partition.numElem = (localEnd + passLength - localStart)%passLength; + + Locals[threadID].partition.lengthDist = Locals[(threadID+1)%nthreads].partition.startDist + - Locals[threadID].partition.startDist; + } } } + + if(nthreads==1) { + Locals[0].partition.startDist = 0; + Locals[0].partition.lengthDist = UINT64_MAX; + Locals[0].partition.firstElem = 0; + Locals[0].partition.numElem = passLength; + } + + HXT2Sync shared2sync = {.mesh = mesh, .allocMore = 8, .otherArrays = {NULL}, @@ -1447,6 +1585,58 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, .otherArraysSetDeleted = {NULL}, .threadFinished = 0}; + if(nthreads>1){ + if(options->reproducible){ + + #pragma omp parallel num_threads(maxThreads) + { + int threadID = omp_get_thread_num(); + // we want to reorder tets only at the very end. Because the selected tet should not depend + // on the ordering of tet in reproducible mode, we have very few options... + // we will select the tet in the good partition that has the lowest nodes in lexicographic order + uint64_t* startTetLocal = startTetGlobal + threadID * nthreads; + for(int i=0; i<nthreads; i++) { + startTetLocal[i] = UINT64_MAX; + } + + #pragma omp for + for (uint64_t i=0; i<mesh->tetrahedra.num; i++) + { + if(getDeletedFlag(mesh, i)==0) + { + int partitionOfTet = -1; + for(int t=0; t<nthreads; t++) { + if(checkTetrahedron(vertices, + &Locals[t].partition, + &mesh->tetrahedra.node[i*4] + )==HXT_STATUS_OK) { + partitionOfTet = t; + break; + } + } + + if(partitionOfTet==-1) + continue; + + uint64_t oldStartTet = startTetLocal[partitionOfTet]; + + if(oldStartTet==UINT64_MAX) { + startTetLocal[partitionOfTet] = i; + } + else { + int cmp = compareNodeLexicographically(&mesh->tetrahedra.node[4*i], + &mesh->tetrahedra.node[4*oldStartTet]); + HXT_ASSERT(cmp!=0); + if(cmp==-1){ + startTetLocal[partitionOfTet] = i; + } + } + } + } // implicit barrier at the end of the omp for loop :-) + } + } + } + #pragma omp parallel num_threads(nthreads) { #ifdef _MSC_VER @@ -1454,80 +1644,30 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, nthreads = omp_get_num_threads(); #endif - uint64_t curTet = 0; // we always begin with the first tet. (index 0) + uint64_t curTet = HXT_NO_ADJACENT; const int threadID = omp_get_thread_num(); - uint32_t localStart; - uint32_t localN; - int foundTet = 0; + uint32_t localStart = Locals[threadID].partition.firstElem; + uint32_t localN = Locals[threadID].partition.numElem; if(nthreads>1){ - // if(threadID<nthreads){ - - /****************************************************** - Making partitions - ******************************************************/ - localStart = MIN((uint32_t) step*(threadID+1)-1, (uint32_t) (step*(threadID + indexShift))); - uint64_t dist = nodeInfo[passStart + localStart].hilbertDist; - - uint32_t up = 1; - while(localStart+up<passLength && dist==nodeInfo[passStart + localStart + up].hilbertDist) - up++; - - localStart = localStart+up==passLength?0:localStart+up; - if(localStart > 0) { - dist = (nodeInfo[passStart + localStart].hilbertDist - + nodeInfo[passStart + localStart - 1].hilbertDist + 1)/2; - } - else { - dist = nodeInfo[passStart + passLength-1].hilbertDist - + (nodeInfo[passStart + localStart].hilbertDist - - nodeInfo[passStart + passLength - 1].hilbertDist)/2; - } - Locals[threadID].partition.startDist = dist; - Locals[threadID].partition.firstElem = localStart; - // } - - #pragma omp barrier - - // if(threadID<nthreads){ - uint32_t localEnd = Locals[(threadID+1)%nthreads].partition.firstElem; - localN = (localEnd + passLength - localStart)%passLength; - Locals[threadID].partition.numElem = localN; - - Locals[threadID].partition.lengthDist = Locals[(threadID+1)%nthreads].partition.startDist - dist; - /****************************************************** find starting tetrahedron ******************************************************/ - // we want to reorder tets only at the very end. Because the selected tet should not depend - // on the ordering of tet in reproducible mode, we have very few options... - // we will select the tet in the good partition that has the lowest nodes in lexicographic order if(options->reproducible){ - - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { - if(getDeletedFlag(mesh, i)==0 && - checkTetrahedron(vertices, &Locals[threadID], - mesh->tetrahedra.node + i*4 )==HXT_STATUS_OK) - { - if(foundTet==0) { - curTet = i; - foundTet = 1; + for(int t=0; t<maxThreads; t++) { + uint64_t startTet = startTetGlobal[t*nthreads + threadID]; + if(startTet != UINT64_MAX) { + if(curTet==HXT_NO_ADJACENT) { + curTet = startTet; } else { - uint32_t* iNode = &mesh->tetrahedra.node[4*i]; - uint32_t* curNode = &mesh->tetrahedra.node[4*curTet]; - - // compare in lexicographic order - for(int j=0; j<4; j++) { - if(iNode[j]<curNode[j]){ - curTet = i; - break; - } - if(iNode[j]>curNode[j]) - break; + int cmp = compareNodeLexicographically(&mesh->tetrahedra.node[4*startTet], + &mesh->tetrahedra.node[4*curTet]); + HXT_ASSERT(cmp!=0); + if(cmp==-1){ + curTet = startTet; } } } @@ -1538,75 +1678,35 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { if(getDeletedFlag(mesh, i)==0 && - checkTetrahedron(vertices, &Locals[threadID], + checkTetrahedron(vertices, &Locals[threadID].partition, mesh->tetrahedra.node + i*4 )==HXT_STATUS_OK) { curTet = i; - foundTet = 1; break; } } } - - // } - - #pragma omp barrier } - else - // if(threadID==0) - { - + else { /****************************************************** - single-thread partition and starting tetrahedron + single-thread starting tetrahedron ******************************************************/ - localStart = 0; - localN = passLength; - Locals[0].partition.startDist = 0; - Locals[0].partition.lengthDist = UINT64_MAX; - for (uint64_t i=0; i<mesh->tetrahedra.num; i++) - { + { if(getDeletedFlag(mesh, i)==0){ curTet = i; - foundTet = 1; break; } } } - if (foundTet == 0) { + #pragma omp barrier + + if (curTet==HXT_NO_ADJACENT) { HXT_INFO_COND(options->verbosity>1, "thread %d did not find any tetrahedron to begin with", threadID); } - - // filtering vertices on the Moore curve - if(options->nodalSizes!=NULL) - { - double* p1 = NULL; - double p1Size = 0; - - for (uint32_t i=0; i<localN; i++) - { - uint32_t passIndex = (localStart+i)%passLength; - uint32_t lastNode = nodeInfo[passStart + passIndex].node; - if(nodeInfo[passStart + passIndex].status==HXT_STATUS_TRYAGAIN){ - double* p2 = vertices[lastNode].coord; - double p2Size = options->nodalSizes[lastNode]; - if(p1!=NULL && pointIsTooClose(p1, p2, 0.5*(p1Size+p2Size))!=HXT_STATUS_OK){ - nodeInfo[passStart + passIndex].status=HXT_STATUS_FALSE; - } - else{ - p1 = p2; - p1Size = p2Size; - } - } - } - } - - - // if(threadID<nthreads){ - if(foundTet!=0){ - + else{ /****************************************************** vertices insertion ******************************************************/ @@ -1627,7 +1727,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, case HXT_STATUS_DOUBLE_PT: nodeInfo[passStart + passIndex].status = HXT_STATUS_FALSE; double* vtaCoord = vertices[vta].coord; - HXT_WARNING("skipping supposedly duplicate vertex (%f %f %f)", vtaCoord[0], vtaCoord[1], vtaCoord[2]); + HXT_WARNING("skipping supposedly duplicate point (%f %f %f)", vtaCoord[0], vtaCoord[1], vtaCoord[2]); break; case HXT_STATUS_CONFLICT: status = HXT_STATUS_TRYAGAIN; @@ -1647,7 +1747,6 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, } } } - // } HXT_OMP_CHECK( waitForPossibleReallocation(&shared2sync, nthreads) ); } @@ -1657,7 +1756,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, ******************************************************/ // everything above i+shift is HXT_STATUS_TRYAGAIN uint32_t shift = 0; - unsigned numSkipped = 0; + uint32_t numSkipped = 0; for (uint32_t i=passEnd; i>passStart;) { i--; @@ -1673,19 +1772,51 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, } } - options->numVerticesInMesh += shift - numSkipped; + uint32_t numInserted = shift - numSkipped; + uint32_t numConflict = passLength - shift; - percent = (shift-numSkipped)*100.0/MAX(1,passLength-numSkipped); + totalNumInserted += numInserted; totalNumSkipped += numSkipped; - HXT_INFO_COND(options->verbosity>1, - "%3d thrd |%10u/%-10u-> %*.1f%-*c\t- mesh.nvert: %-10u", - nthreads, shift-numSkipped, passLength-numSkipped, MIN(8,n/2)+5, percent, 8-MIN(8,n/2),'%', options->numVerticesInMesh); + conflictRatio = (double) numConflict / (passLength - numSkipped); + + if(options->verbosity>1) { + uint32_t numPointsMinusSkipped = passLength - numSkipped; + uint32_t numInserted = numPointsMinusSkipped - numConflict; + int numSpaces = MIN(8, iround/2)+5; + HXT_INFO("%3d thrd |%10u/%-10u-> %*.1f%%", + nthreads, numInserted, numPointsMinusSkipped, + numSpaces, 100.0*MAX((double) numInserted/numPointsMinusSkipped, 0.0)); + } + + // printf("moore filtered %4.1f%%\n", mooreSkipped*100.0/passLength); + // printf("total filtered %4.1f%%\n", numSkipped*100.0/passLength); + // printf(" conflict %4.1f%%\n", numConflict*100.0/passLength); + // printf(" inserted %4.1f%%\n", numInserted*100.0/passLength); + // printf("filtered/inserted %f\n", (numSkipped - mooreSkipped)*1.0/numInserted); - passes[p] += shift; + passes[ipass] += shift; + + // compute if there was a nonDeterministic ordering of allocation + if(options->reproducible && nonDeterministic==0) { + int createdNew = 0; + for(int threadID=0; threadID<nthreads; threadID++) { + if(Locals[threadID].deleted.createdNew) + createdNew++; + } + + if(createdNew>1) + nonDeterministic = 1; + } + + for(int threadID=0; threadID<maxThreads; threadID++) { + Locals[threadID].deleted.createdNew = 0; + } } } + options->numVerticesInMesh += totalNumInserted; + /****************************************************** Cleaning ******************************************************/ @@ -1707,6 +1838,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, HXT_CHECK( hxtAlignedFree(&verticesID) ); HXT_CHECK( hxtFree(&Locals) ); + HXT_CHECK( hxtFree(&startTetGlobal) ); /*************************************************************** if reordering allowed, remove vertices we could not insert @@ -1786,23 +1918,22 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh, vertices[vertices[i].padding.index] = vertices[i]; } - if(options->verbosity>1) - HXT_INFO("%u vertices removed (vertices not inserted in the mesh are removed when using hxtDelaunay)", totalNumSkipped); - mesh->vertices.num = mesh->vertices.num - totalNumSkipped; } - HXT_INFO_COND(options->verbosity>0, "Delaunay done !%10u skipped", totalNumSkipped); - HXT_INFO_COND(options->verbosity>1, "mem. allocated:%5.2fGB - mesh.ntet: %-12lu - mesh.nvert: %-10lu", - ((50 + 2*(mesh->tetrahedra.flag!=NULL)) * mesh->tetrahedra.size + - (32 + 8*(options->nodalSizes!=NULL)) * mesh->vertices.size)/(1024.*1024.*1024.), - mesh->tetrahedra.num, mesh->vertices.num); + if(totalNumSkipped!=0 && options->verbosity>0) { + HXT_INFO(" - %10u points filtered", totalNumSkipped); + HXT_INFO(" = %10u points added", totalNumInserted); + HXT_INFO_COND(options->verbosity>1, "mem. allocated:%5.2fGB - mesh.ntet: %-9lu- mesh.nvert: %-10lu", + ((50 + 2*(mesh->tetrahedra.flag!=NULL)) * mesh->tetrahedra.size + + (32 + 8*(options->nodalSizes!=NULL)) * mesh->vertices.size)/(1024.*1024.*1024.), + mesh->tetrahedra.num, mesh->vertices.num); + } - if(options->reproducible && maxThreads!=1){ + if(nonDeterministic){ HXT_INFO_COND(options->verbosity>1, "Reordering tetrahedra (reproducible==true)", mesh->vertices.num - nToInsert, mesh->vertices.num); HXT_CHECK( hxtTetReorder(mesh) ); } - HXT_INFO_COND(options->verbosity>1,""); // just separate stuff with a blank line return HXT_STATUS_OK; } @@ -1900,13 +2031,6 @@ HXTStatus hxtDelaunay(HXTMesh* mesh, HXTDelaunayOptions* userOptions){ hxtNodeInfo* nodeInfo; HXT_CHECK( hxtAlignedMalloc(&nodeInfo, nToInsert*sizeof(hxtNodeInfo)) ); - - // we fill nodeInfo with the indices of each vertices to insert... - #pragma omp parallel for simd - for (uint32_t i=0; i<nToInsert; i++) { - nodeInfo[i].node = options.numVerticesInMesh + i; - nodeInfo[i].status = HXT_STATUS_TRYAGAIN; // necessary for when foundTet = 0; - } HXT_CHECK( parallelDelaunay3D(mesh, &options, nodeInfo, nToInsert, 0) ); diff --git a/contrib/hxt/hxt_tetDelaunay.h b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.h similarity index 94% rename from contrib/hxt/hxt_tetDelaunay.h rename to contrib/hxt/tetMesh/src/hxt_tetDelaunay.h index 7a3edab07f..885cc79d0e 100644 --- a/contrib/hxt/hxt_tetDelaunay.h +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETDELAUNAY_ -#define _HXT_TETDELAUNAY_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETDELAUNAY_H +#define HXT_TETDELAUNAY_H #ifdef __cplusplus extern "C" { @@ -35,6 +43,8 @@ typedef struct { * doesn't have a corresponding mesh size */ uint32_t numVerticesInMesh; /**< The number of vertices in the mesh (all vertices below this point are not (re-)inserted */ + double partitionability; /**< a number between 0 and 1 telling if this mesh is good for making partitions. + Generally, put 0 for an empty mesh, 1-(1/2)^n for a mesh refined n time */ int verbosity; /**< * - if verbosity<=0: don't print information. diff --git a/contrib/hxt/hxt_tetFlag.c b/contrib/hxt/tetMesh/src/hxt_tetFlag.c similarity index 98% rename from contrib/hxt/hxt_tetFlag.c rename to contrib/hxt/tetMesh/src/hxt_tetFlag.c index 6e0f47e006..5172c1c93f 100644 --- a/contrib/hxt/hxt_tetFlag.c +++ b/contrib/hxt/tetMesh/src/hxt_tetFlag.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_sort.h" #include "hxt_tetFlag.h" @@ -335,7 +343,7 @@ HXT_ASSERT( mesh!=NULL ); #ifndef NDEBUG if(edgeKey[i+1].v[1]%2==0) { HXT_ERROR_MSG(HXT_STATUS_ERROR, "Duplicated line in mesh->lines (" HXTu64 " & " HXTu64 ")\n" - "\tThis case is not handled in Release mode, FIX IT !!", + "\tThis issue will not produce a direct error if NDEBUG is defined", edgeKey[i].v[1]/2, edgeKey[i+1].v[1]/2); exit(EXIT_FAILURE); } diff --git a/contrib/hxt/hxt_tetFlag.h b/contrib/hxt/tetMesh/src/hxt_tetFlag.h similarity index 97% rename from contrib/hxt/hxt_tetFlag.h rename to contrib/hxt/tetMesh/src/hxt_tetFlag.h index 7ff7db77c3..b93bd1e94c 100644 --- a/contrib/hxt/hxt_tetFlag.h +++ b/contrib/hxt/tetMesh/src/hxt_tetFlag.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETFLAG_ -#define _HXT_TETFLAG_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETFLAG_H +#define HXT_TETFLAG_H #ifdef __cplusplus extern "C" { @@ -163,10 +171,12 @@ HXTStatus hxtConstrainLinesNotInTriangles(HXTMesh* mesh, uint64_t* lines2TetMap, #define HXT_DELETED_MASK UINT16_C(0x40) #define HXT_PROCESSED_MASK UINT16_C(0X80) + #define HXT_UNUSED0_MASK UINT16_C(0x1000) #define HXT_UNUSED1_MASK UINT16_C(0x2000) #define HXT_UNUSED2_MASK UINT16_C(0x4000) #define HXT_UNUSED3_MASK UINT16_C(0x8000) +#define HXT_ALL_UNUSED_MASK UINT16_C(0xF000) /*************************** @@ -346,6 +356,11 @@ static inline void unsetUnusedFlag(HXTMesh* mesh, uint64_t tet, unsigned id) { } +static inline void resetUnusedFlags(HXTMesh* mesh, uint64_t tet) { + mesh->tetrahedra.flag[tet] &= ~UINT16_C(HXT_ALL_UNUSED_MASK); +} + + #ifdef __cplusplus } #endif diff --git a/contrib/hxt/hxt_tetMesh.c b/contrib/hxt/tetMesh/src/hxt_tetMesh.c similarity index 86% rename from contrib/hxt/hxt_tetMesh.c rename to contrib/hxt/tetMesh/src/hxt_tetMesh.c index b63fa0aeb3..0dfd49fcde 100644 --- a/contrib/hxt/hxt_tetMesh.c +++ b/contrib/hxt/tetMesh/src/hxt_tetMesh.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetRefine.h" #include "hxt_tetNodalSize.h" #include "hxt_tetRepair.h" @@ -8,6 +16,8 @@ #include "hxt_tetMesh.h" #include "hxt_tetQuality.h" +#include "hxt_omp.h" + // void aspect_ratio_graph(HXTMesh* mesh) { // // make a count of aspect ratio... // unsigned bins[21] = {0}; @@ -60,6 +70,7 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, HXT_INFO_COND(options->verbosity>0, "Creating an empty mesh with %u vertices", numVerticesConstrained); HXT_CHECK( hxtEmptyMesh(mesh, &delOptions) ); + HXT_INFO_COND(options->verbosity>1, "Empty mesh finished\n"); t[1] = omp_get_wtime(); @@ -91,10 +102,10 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, "there are missing features but no boundary recovery function is given"); if(nbMissingTriangles) - HXT_INFO("Recovering " HXTu64 " missing facet(s)", + HXT_INFO("Recovering %" HXTu64 " missing facet(s)", nbMissingTriangles); else if(nbMissingLines) - HXT_INFO("Recovering " HXTu64 " missing edge(s)", + HXT_INFO("Recovering %" HXTu64 " missing edge(s)", nbMissingLines); HXT_CHECK(options->recoveryFun(mesh, options->recoveryData)); @@ -109,7 +120,7 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, HXT_CHECK( hxtGetTri2TetMap(mesh, tri2TetMap, &nbMissingTriangles) ); if(nbMissingTriangles!=0) return HXT_ERROR_MSG( HXT_STATUS_ERROR, - HXTu64 " boundary face%s still missing (after recovery step).", + "%" HXTu64 " boundary face%s still missing (after recovery step).", nbMissingTriangles, (nbMissingTriangles>1)?"s are":" is" ); if(nbLinesNotInTriangles!=0) @@ -117,8 +128,10 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, if(nbMissingLines!=0) return HXT_ERROR_MSG( HXT_STATUS_ERROR, - HXTu64 " constrained edge%s still missing (after recovery step).", + "%" HXTu64 " constrained edge%s still missing (after recovery step).", nbMissingLines, (nbMissingLines>1)?"s are":" is" ); + + HXT_INFO_COND(options->verbosity>1,"Constrained lines and triangles recovered\n"); } HXT_CHECK( hxtConstrainTriangles(mesh, tri2TetMap) ); @@ -148,6 +161,8 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, HXT_CHECK(hxtRefineTetrahedra(mesh, &delOptions, options->meshSizeFun, options->meshSizeData)); HXT_CHECK( hxtDestroyNodalsize(&delOptions.nodalSizes) ); + + HXT_INFO_COND(options->verbosity>1, "Mesh refinement finished\n"); } t[5] = omp_get_wtime(); @@ -165,8 +180,10 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, .qualityMin = options->qualityMin, .numThreads = options->improveThreads, .numVerticesConstrained = numVerticesConstrained, - .verbosity = options->verbosity + .verbosity = options->verbosity, + .reproducible = options->reproducible } ) ); + HXT_INFO_COND(options->verbosity>1, "Mesh improvement finished\n"); } // aspect_ratio_graph(mesh); @@ -174,11 +191,8 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, if(options->stat){ - HXT_INFO("\n\t\tFinal tet. mesh contains " HXTu64 " tetrahedra" - "\n\t\tand %u vertices", - mesh->tetrahedra.num, - mesh->vertices.num); - + HXT_INFO(" \tFinal tet. mesh contains %" HXTu64 " tetrahedra", mesh->tetrahedra.num); + HXT_INFO(" \tFinal tet. mesh contains %u vertices", mesh->vertices.num); HXT_INFO("tEmptyMesh \t = \t %8.3f", t[1]-t[0]); HXT_INFO("tVerifyBnd \t = \t %8.3f", t[2]-t[1]); if(t[3]){ @@ -200,6 +214,8 @@ HXTStatus hxtTetMesh(HXTMesh* mesh, HXT_INFO("tOptimize \t = \t 0.000 (mesh optimization disabled)"); } + HXT_INFO_COND(options->verbosity>1, "Mesh generated\n"); + return HXT_STATUS_OK; } diff --git a/contrib/hxt/hxt_tetNodalSize.c b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c similarity index 96% rename from contrib/hxt/hxt_tetNodalSize.c rename to contrib/hxt/tetMesh/src/hxt_tetNodalSize.c index fd9b51112d..7150bd0e3a 100644 --- a/contrib/hxt/hxt_tetNodalSize.c +++ b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c @@ -1,4 +1,13 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_vertices.h" +#include <math.h> HXTStatus hxtCreateNodalSizeFromFunction(HXTMesh* mesh, double** nodalSizes_ptr, diff --git a/contrib/hxt/hxt_tetNodalSize.h b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.h similarity index 76% rename from contrib/hxt/hxt_tetNodalSize.h rename to contrib/hxt/tetMesh/src/hxt_tetNodalSize.h index 5af1c668cc..c1d10d2d9f 100644 --- a/contrib/hxt/hxt_tetNodalSize.h +++ b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETNODALSIZE_ -#define _HXT_TETNODALSIZE_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETNODALSIZE_H +#define HXT_TETNODALSIZE_H #include "hxt_mesh.h" diff --git a/contrib/hxt/tetMesh/src/hxt_tetOpti.c b/contrib/hxt/tetMesh/src/hxt_tetOpti.c new file mode 100644 index 0000000000..add322fafc --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetOpti.c @@ -0,0 +1,724 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#include "hxt_tetOpti.h" +#include "hxt_tetFlag.h" +#include "hxt_edgeRemoval.h" +#include "hxt_smoothing.h" +#include "HXTSPR.h" +#include "hxt_sort.h" +#include "hxt_tetRepair.h" +#include "hxt_tetOptiUtils.h" + + +static inline uint16_t getConflictFlag(HXTMesh* mesh, uint64_t tet) { + return getUnusedFlag(mesh, tet, 0); +} + + +static inline void setConflictFlag(HXTMesh* mesh, uint64_t tet) { + setUnusedFlag(mesh, tet, 0); +} + + +static inline void unsetConflictFlag(HXTMesh* mesh, uint64_t tet) { + unsetUnusedFlag(mesh, tet, 0); +} + +static void conflictFlagsInit(HXTMesh* mesh, HXTGroup2* badTets, uint64_t num) { + #pragma omp parallel for simd + for(uint64_t i=0; i<num; i++) { + setConflictFlag(mesh, badTets[i].v[1]); + } +} + + +/************************************************************************** + Thread-shared structure + **************************************************************************/ +typedef struct { + struct { + HXTGroup2* array; + uint64_t num; + } badTets; + + HXTTetDates date; + HXTTetQualities quality; + HXT2Sync toSync; + + int numThreads; +} ThreadShared; + + +/************************************************************************** + create/update/delete shared structure, containing list of bad tetrahedra + **************************************************************************/ + +// suppose that the right capacity for quality values is already allocated +static HXTStatus badTets_update(HXTMesh* mesh, ThreadShared* shared) { + int maxThreads = omp_get_max_threads(); + HXTStatus status = HXT_STATUS_OK; + + uint64_t* badTetsCount; + HXT_CHECK( hxtMalloc(&badTetsCount, maxThreads*sizeof(uint64_t)) ); + + #pragma omp parallel + { + int threadID = omp_get_thread_num(); + badTetsCount[threadID] = 0; + + #pragma omp for schedule(static) + for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { + if(!getProcessedFlag(mesh, i) && + !getDeletedFlag(mesh, i) && + shared->quality.values[i]<shared->quality.threshold) + badTetsCount[threadID]++; + } + + #pragma omp barrier + #pragma omp single + { + int nthreads = omp_get_num_threads(); + shared->badTets.num = 0; + for (int i=0; i<nthreads; i++) { + uint64_t tsum = badTetsCount[i] + shared->badTets.num; + badTetsCount[i] = shared->badTets.num; + shared->badTets.num = tsum; + } + + status = hxtAlignedFree(&shared->badTets.array); + if(status==HXT_STATUS_OK) + status = hxtAlignedMalloc(&shared->badTets.array, sizeof(HXTGroup2)*shared->badTets.num); + } + + if(status==HXT_STATUS_OK){ + #pragma omp for schedule(static) + for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { + if(!getProcessedFlag(mesh, i) && + !getDeletedFlag(mesh, i) && + shared->quality.values[i]<shared->quality.threshold){ + uint64_t badTetsID = badTetsCount[threadID]++; + shared->badTets.array[badTetsID].v[1] = i; + } + } + } + } + HXT_CHECK( hxtFree(&badTetsCount) ); + + return status; +} + + +static HXTStatus badTets_update_among_conflicts(HXTMesh* mesh, ThreadShared* shared) { + int maxThreads = omp_get_max_threads(); + HXTStatus status = HXT_STATUS_OK; + + uint64_t* badTetsCount; + HXT_CHECK( hxtMalloc(&badTetsCount, maxThreads*sizeof(uint64_t)) ); + + uint64_t oldBadTetNum = shared->badTets.num; + HXTGroup2* oldBadTets = shared->badTets.array; + + #pragma omp parallel + { + int threadID = omp_get_thread_num(); + badTetsCount[threadID] = 0; + + #pragma omp for schedule(static) + for (uint64_t i=0; i<oldBadTetNum; i++) { + if(getConflictFlag(mesh, oldBadTets[i].v[1]) && !getDeletedFlag(mesh, oldBadTets[i].v[1])) + badTetsCount[threadID]++; + } + + #pragma omp barrier + #pragma omp single + { + int nthreads = omp_get_num_threads(); + shared->badTets.num = 0; + for (int i=0; i<nthreads; i++) { + uint64_t tsum = badTetsCount[i] + shared->badTets.num; + badTetsCount[i] = shared->badTets.num; + shared->badTets.num = tsum; + } + + status = hxtAlignedMalloc(&shared->badTets.array, sizeof(HXTGroup2)*shared->badTets.num); + } + + if(status==HXT_STATUS_OK){ + #pragma omp for schedule(static) + for (uint64_t i=0; i<oldBadTetNum; i++) { + if(getConflictFlag(mesh, oldBadTets[i].v[1]) && !getDeletedFlag(mesh, oldBadTets[i].v[1])) { + uint64_t badTetsID = badTetsCount[threadID]++; + shared->badTets.array[badTetsID] = oldBadTets[i]; + } + } + } + } + HXT_CHECK( hxtFree(&badTetsCount) ); + HXT_CHECK( hxtAlignedFree(&oldBadTets) ); + + return status; +} + + +static HXTStatus threadShared_init(HXTMesh *mesh, + HXTOptimizeOptions* options, + ThreadShared* shared) { + shared->numThreads = options->numThreads; + + if(options->qualityMin<0.0) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "quality threshold must be positive"); + + shared->badTets.array = NULL; + shared->badTets.num = mesh->tetrahedra.num; + shared->quality.function = options->qualityFun ? options->qualityFun : hxtTetAspectRatio; + shared->quality.threshold = options->qualityMin; + shared->quality.userData = options->qualityData; + HXT_CHECK( hxtAlignedMalloc(&shared->quality.values, sizeof(double)*mesh->tetrahedra.size) ); + + shared->date.current = 0; + HXT_CHECK( hxtAlignedMalloc(&shared->date.values, sizeof(HXTTetDate)*mesh->tetrahedra.size) ); + + shared->toSync = (HXT2Sync) {.mesh = mesh, + .allocMore = 0, + .otherArrays = {(void*) &shared->quality.values, + (void*) &shared->date.values, NULL, NULL}, + .otherArraysElementSize = {sizeof(double), sizeof(HXTTetDate), 0, 0}, + .otherArraysSetDeleted = {NULL, NULL, NULL, NULL}, + .threadFinished = 0}; + + #pragma omp parallel for + for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { + shared->date.values[i] = (HXTTetDate) {0}; + + if(!getProcessedFlag(mesh, i)) { + uint32_t* nodes = mesh->tetrahedra.node + 4*i; +// #ifndef NDEBUG + if(nodes[3]==HXT_GHOST_VERTEX){ + exit( HXT_ERROR_MSG(HXT_STATUS_ERROR, "ghost tetrahedra should have been set to processed") ); + } +// #endif + shared->quality.values[i] = tetQuality(mesh, &shared->quality, nodes[0], nodes[1], nodes[2], nodes[3]); + } + } + return HXT_STATUS_OK; +} + + +static HXTStatus threadShared_destroy(ThreadShared* shared) { + HXT_CHECK( hxtAlignedFree(&shared->quality.values) ); + HXT_CHECK( hxtAlignedFree(&shared->date.values) ); + HXT_CHECK( hxtAlignedFree(&shared->badTets.array)); + return HXT_STATUS_OK; +} + + +static HXTStatus reorderTetIfNeeded(HXTMesh* mesh, ThreadLocal* locals, int nThreads) +{ + int createdNew = 0; + for(int i=0; i<nThreads; i++) { + if(locals[i].deleted.createdNew) + createdNew++; + } + + if(createdNew > 1) { + HXT_INFO("reordering tetrahedra to ensure reproducibility (reproducible==true)"); + HXT_CHECK( hxtTetReorder(mesh) ); + } + + for(int i=0; i<nThreads; i++) { + locals[i].deleted.createdNew = 0; + } + + return HXT_STATUS_OK; +} + + + +/************************************************************************** + create/update/delete local structure, containing partitions definition + **************************************************************************/ + +static HXTStatus threadLocals_create(ThreadLocal** locals_ptr, ThreadShared* shared, HXTOptimizeOptions* options) { + int nthreads = options->numThreads; + ThreadLocal* newLocal; + HXT_CHECK( hxtMalloc(&newLocal, nthreads*sizeof(ThreadLocal))); + + for (int threadID=0; threadID<nthreads; threadID++) { + HXT_CHECK( hxtAlignedMalloc(&newLocal[threadID].deleted.array, sizeof(uint64_t)*DELETED_BUFFER_SIZE) ); + // init deleted + newLocal[threadID].deleted.size = DELETED_BUFFER_SIZE; + newLocal[threadID].deleted.num = 0; + newLocal[threadID].deleted.createdNew = 0; + + // partition is initialized in threadLocals_update + + // statistics are also initialize in threadLocals_update + + newLocal[threadID].quality = &shared->quality; + newLocal[threadID].date = &shared->date; + newLocal[threadID].toSync = &shared->toSync; + newLocal[threadID].numVerticesConstrained = options->numVerticesConstrained; + newLocal[threadID].SPR.dateOfLastCheck = 0; + newLocal[threadID].SPR.dateOfLastCreation = 0; + newLocal[threadID].SPR.maxSearchNodes = 500; + } + + *locals_ptr = newLocal; + return HXT_STATUS_OK; +} + + +static Statistic threadLocals_collectStats(ThreadLocal* locals, int nThreads) { + // check the stat to see if we keep the same number of threads and if we move partitions + Statistic stat = {0}; + + for (int threadID=0; threadID<nThreads; threadID++) + { + stat.attempt += locals[threadID].stat.attempt; + stat.conflict += locals[threadID].stat.conflict; + stat.success += locals[threadID].stat.success; + } + return stat; +} + + +static HXTStatus threadLocals_update(HXTMesh* mesh, HXTBbox* bbox, + ThreadShared* shared, ThreadLocal* locals, + uint32_t* seed, + int changePartitionCurve, + int badTetAlreadySorted) +{ + const uint64_t bit63 = UINT64_C(1)<<63; + #pragma omp parallel for simd + for(uint64_t i=0; i<shared->badTets.num; i++) { + shared->badTets.array[i].v[0] &= ~bit63; + } + + + HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; + HXTGroup2* badTets = shared->badTets.array; + + double indexShift = (double) hxtReproducibleLCG(seed)/RAND_MAX; + + if(changePartitionCurve) { + double hxtDeclareAligned bboxShift[3]; + bboxShift[0] = (double) hxtReproducibleLCG(seed)/RAND_MAX; + bboxShift[1] = (double) hxtReproducibleLCG(seed)/RAND_MAX; + bboxShift[2] = (double) hxtReproducibleLCG(seed)/RAND_MAX; + + HXT_CHECK( hxtMoore(bbox, vertices, mesh->vertices.num, bboxShift) ); + } + + if(changePartitionCurve || !badTetAlreadySorted) { + #pragma omp parallel for simd aligned(badTets:SIMD_ALIGN) + for (uint64_t i=0; i<shared->badTets.num; i++) { + uint64_t curTet = badTets[i].v[1]; + uint32_t* nodes = &mesh->tetrahedra.node[4*curTet]; + uint64_t hilbertDist[4]; + for(int j=0; j<4; j++) { + hilbertDist[j] = vertices[nodes[j]].padding.hilbertDist; + } + + HXTSORT_4_VALUES_INPLACE(uint64_t, hilbertDist); + + uint64_t minDist = UINT64_MAX; + uint64_t middle = 0; + for(int j=0; j<4; j++) { + if(hilbertDist[(j+1)%4] - hilbertDist[j] < minDist) { + minDist = hilbertDist[(j+1)%4] - hilbertDist[j]; + middle = hilbertDist[j] + minDist/2; + } + } + + // we are going to sort the four values + badTets[i].v[0] = middle; + } + + // sort the bad tetrahedrons following their first node hilbert dist + HXT_CHECK( group2_sort_v0(badTets, shared->badTets.num, bit63 - 1) ); + } + + if(shared->numThreads==1 || badTets[0].v[0]==badTets[shared->badTets.num-1].v[0]) { + // only one partition possible, everything is in the same cell ! + shared->numThreads = 1; + locals[0].partition.startDist = 0; + locals[0].partition.lengthDist = UINT64_MAX; + locals[0].partition.firstElem = 0; + locals[0].partition.numElem = shared->badTets.num; + locals[0].stat = (Statistic) {0}; + return HXT_STATUS_OK; + } + + if(shared->numThreads > 1) { + const double step = shared->badTets.num/shared->numThreads; + #pragma omp parallel num_threads(shared->numThreads) + { + int threadID = omp_get_thread_num(); + locals[threadID].stat = (Statistic) {0}; + + uint64_t first = MIN((uint64_t) step*(threadID+1)-1, (uint64_t) (step*(threadID + indexShift))); + uint64_t startDist = badTets[first].v[0]; + + uint64_t up = 1; + while(first+up<shared->badTets.num && startDist==badTets[first + up].v[0]) + up++; + + first = first+up==shared->badTets.num?0:first+up; + if(first > 0) + startDist = (badTets[first].v[0] + badTets[first - 1].v[0] + 1)/2; + else + startDist = badTets[shared->badTets.num-1].v[0] + + (badTets[first].v[0] - badTets[shared->badTets.num - 1].v[0])/2; + + locals[threadID].partition.firstElem = first; + locals[threadID].partition.startDist = startDist; + + #pragma omp barrier + + uint64_t firstNext = locals[(threadID+1)%shared->numThreads].partition.firstElem; + uint64_t endDist = locals[(threadID+1)%shared->numThreads].partition.startDist; + uint64_t numElem = (firstNext + shared->badTets.num - first)%shared->badTets.num; + locals[threadID].partition.numElem = numElem; + locals[threadID].partition.lengthDist = endDist - startDist; + + uint64_t rel = endDist - startDist; + + // dismiss tetrahedron that are in our list but not in our partition + for (uint64_t i=0; i<numElem; i++) { + uint64_t index = (first + i)%shared->badTets.num; + uint64_t curTet = shared->badTets.array[index].v[1]; + + uint32_t* nodes = mesh->tetrahedra.node + 4*curTet; + + if(vertexOutOfPartition(vertices, nodes[0], rel, startDist) + + vertexOutOfPartition(vertices, nodes[1], rel, startDist) + + vertexOutOfPartition(vertices, nodes[2], rel, startDist) + + vertexOutOfPartition(vertices, nodes[3], rel, startDist) > 1) { + shared->badTets.array[index].v[0] |= bit63; + locals[threadID].stat.attempt++; + locals[threadID].stat.conflict++; + } + } + } + } + + return HXT_STATUS_OK; +} + + +static HXTStatus threadLocals_destroy(ThreadLocal** local, int nthreads) { + for (int threadID=0; threadID<nthreads; threadID++) { + HXT_CHECK( hxtAlignedFree(&(*local)[threadID].deleted.array) ); + } + + HXT_CHECK( hxtFree(local) ); + return HXT_STATUS_OK; +} + + +/* once the SPR is done, the current date should be changed to the date of the lastCheck */ +static void SPRDates_update(ThreadShared* shared, ThreadLocal* locals) +{ + uint16_t lastCheck = 0; + for(int threadID=0; threadID<shared->numThreads; threadID++) { + if(locals[threadID].SPR.dateOfLastCheck > lastCheck) + lastCheck = locals[threadID].SPR.dateOfLastCheck; + } + + shared->date.current = lastCheck; + + for(int threadID=0; threadID<shared->numThreads; threadID++) { + locals[threadID].SPR.dateOfLastCheck = lastCheck; + locals[threadID].SPR.dateOfLastCreation = lastCheck; + } +} + + +static void badTetrahedraStat(HXTMesh* mesh, double* quality, double threshold, + uint64_t* badTetNum, + double* meanQuality, + double* minQuality) +{ + uint64_t good = 0; + uint64_t bad = 0; + double sum = 0.0; + double min = DBL_MAX; + + #pragma omp parallel for reduction(+: good, bad, sum) reduction(min:min) + for (uint64_t i=0; i<mesh->tetrahedra.num; i++) + { + if(getDeletedFlag(mesh, i) || getProcessedFlag(mesh, i)) + continue; + + sum += quality[i]; + + if(quality[i]<threshold) + bad++; + else + good++; + + if(quality[i]<min) + min = quality[i]; + } + + *badTetNum = bad; + *meanQuality = sum / (good + bad); + *minQuality = min; +} + + +/************************************************************************** +*************************************************************************** + + main function, optimizes a mesh + + ************************************************************************** + **************************************************************************/ + +HXTStatus hxtOptimizeTetrahedra(HXTMesh *mesh, + HXTOptimizeOptions* options) +{ + if(options->numThreads<0) + options->numThreads = omp_get_num_procs(); + else if(options->numThreads==0) + options->numThreads = omp_get_max_threads(); + + HXTBbox bbox; + if(options->bbox==NULL) { + hxtBboxAdd(&bbox, mesh->vertices.coord, mesh->vertices.num); + } + else { + bbox = *options->bbox; + } + + + ThreadShared shared; + HXT_CHECK( threadShared_init(mesh, options, &shared) ); + + ThreadLocal* locals = NULL; + HXT_CHECK( threadLocals_create(&locals, &shared, options) ); + + HXT_CHECK( hxtMoore(&bbox, (HXTVertex*) mesh->vertices.coord, mesh->vertices.num, NULL) ); + + + int doSPR = 1; + double conflictRatio = 0.0; + + uint64_t roundModifIn = UINT64_MAX; + uint64_t roundModifOut = UINT64_MAX; + // uint64_t roundBadTetOut = UINT64_MAX; + + uint64_t maxBadTetIn = 0; + uint64_t roundBadTetIn = UINT64_MAX; + double lastSPRModifRatio = 0.95; + + int changePartitionCurve = 0; + int badTetAlreadySorted = 0; + + uint32_t seed = 1; + volatile HXTStatus globalStatus = HXT_STATUS_OK; + + while(1) { + /************************************************************************** + * Choosing the number of threads and the method that we are going to use + **************************************************************************/ + if(conflictRatio==0.0 || shared.badTets.num==0) { + HXT_CHECK( badTets_update(mesh, &shared) ); + + if(shared.badTets.num > maxBadTetIn) + maxBadTetIn = shared.badTets.num; + + conflictFlagsInit(mesh, shared.badTets.array, shared.badTets.num); + if(roundModifOut==0 || shared.badTets.num==0 || + (maxBadTetIn - roundBadTetIn > 1000 * roundModifOut && roundBadTetIn > 1000 * roundModifOut)) + break; + + double lastModifRatio = (double) roundModifIn/roundBadTetIn; + if(doSPR) { + lastSPRModifRatio = lastModifRatio; + doSPR = 0; + roundModifOut = 0; + // roundBadTetOut = shared.badTets.num; + } + else if(200.0 * lastModifRatio <= lastSPRModifRatio*lastSPRModifRatio*0.75 + lastSPRModifRatio*0.1 + 0.1) { + doSPR = 1; + roundModifOut = 0; + // roundBadTetOut = shared.badTets.num; + } + roundModifIn = 0; + roundBadTetIn = shared.badTets.num; + changePartitionCurve = 0; + badTetAlreadySorted = 0; + conflictRatio = 0.0; + shared.numThreads = options->numThreads; + + HXT_INFO_COND(options->verbosity>0, + "Improving %10" HXTu64 " tet. on %3d thrd %s", + roundBadTetIn, shared.numThreads, doSPR ? "(SPR)":"(S & ER)"); + } + else { + HXT_CHECK( badTets_update_among_conflicts(mesh, &shared) ); + + badTetAlreadySorted = 1; // because badTets_update_among_conflicts is stable + if((conflictRatio>0.6 || (doSPR && conflictRatio>0.2)) && shared.numThreads!=1) + changePartitionCurve = 1; + else + changePartitionCurve = 0; + } + + shared.numThreads = computeNumberOfThreads(conflictRatio, + shared.numThreads, + shared.badTets.num, + doSPR ? 8 : 128); + + shared.toSync.threadFinished = 0; + + // create partitions + HXT_CHECK( threadLocals_update(mesh, &bbox, &shared, locals, &seed, + changePartitionCurve, badTetAlreadySorted) ); + + #pragma omp parallel num_threads(shared.numThreads) + { + int threadID = omp_get_thread_num(); + ThreadLocal* local = &locals[threadID]; + const uint64_t numElem = local->partition.numElem; + const uint64_t first = local->partition.firstElem; + + for (uint64_t i=0; i<numElem && globalStatus==HXT_STATUS_OK; i++) { + uint64_t index = (first + i)%shared.badTets.num; + uint64_t curTet = shared.badTets.array[index].v[1]; + + if(shared.badTets.array[index].v[0] & (UINT64_C(1)<<63) || !getConflictFlag(mesh, curTet) || getDeletedFlag(mesh, curTet)) + continue; + + HXTStatus status = HXT_STATUS_OK; + local->stat.attempt++; + + if(!doSPR) { + int conflict = 0; + for (int edge=0; edge<6; edge++) { + unsigned facet0, facet1; + getFacetsFromEdge(edge, &facet0, &facet1); + + status = hxtEdgeRemoval_opti(local, curTet, edge); + if(status==HXT_STATUS_CONFLICT) + conflict = 1; + else if(status==HXT_STATUS_OK){ + break; + } + else if(status>HXT_STATUS_INTERNAL) { + // fatal error + break; + } + } + + /*** make a swap whenever it is possible and it is an improvement ***/ + if(status<=HXT_STATUS_INTERNAL) { + for (int vertex=0; vertex<4; vertex++) { + status = hxtSmoothing(local, 4*curTet+vertex); + if(status==HXT_STATUS_CONFLICT) + conflict = 1; + else if(status==HXT_STATUS_OK) { + break; + } + else if(status>HXT_STATUS_INTERNAL) { + // fatal error + break; + } + } + } + + if(status==HXT_STATUS_INTERNAL && conflict) + status = HXT_STATUS_CONFLICT; + } + else { + status = hxtSPR_opti(local, curTet); + } + + if(status==HXT_STATUS_CONFLICT) + local->stat.conflict++; + else if(status==HXT_STATUS_OK) + local->stat.success++; + else if(status<=HXT_STATUS_INTERNAL)// the cavity could not be modified + unsetConflictFlag(mesh, curTet); + else { + // fatal error + #pragma omp atomic write + globalStatus = status; + break; + } + } + + HXTStatus status = waitForPossibleReallocation(&shared.toSync, shared.numThreads); + if(status!=HXT_STATUS_OK) { + #pragma omp atomic write + globalStatus = status; + } + } // end of parallel section + + if(globalStatus!=HXT_STATUS_OK){ + HXT_TRACE(globalStatus); + return globalStatus; + } + + if(doSPR) + SPRDates_update(&shared, locals); + + if(options->reproducible) { + HXT_CHECK( reorderTetIfNeeded(mesh, locals, shared.numThreads) ); + } + + Statistic stat = threadLocals_collectStats(locals, shared.numThreads); + HXT_INFO_COND(options->verbosity>1, + "%3d thrd |%10" HXTu64 "/%-10" HXTu64 " %" HXTu64 " conflicts", + shared.numThreads, stat.success, stat.attempt, stat.conflict); + + roundModifIn += stat.success; + roundModifOut += stat.success; + conflictRatio = (double) stat.conflict / stat.attempt; + } + + + if(options->verbosity>1) { + + uint64_t badTetNum; + double meanQuality; + double minQuality; + badTetrahedraStat(mesh, shared.quality.values, shared.quality.threshold, + &badTetNum, &meanQuality, &minQuality); + + HXT_INFO("%" HXTu64 " bad tet. | mean quality: %g | min quality: %g", + badTetNum, meanQuality, minQuality); + } + + + for (int threadID=0; threadID<options->numThreads; threadID++) { + for (uint64_t i=0; i<locals[threadID].deleted.num; i++) { + uint64_t delTet = locals[threadID].deleted.array[i]; +#ifdef DEBUG + if(!getDeletedFlag(mesh, delTet)) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "deleted flag not set on deleted tet"); +#endif + for (int j=0; j<4; j++) + mesh->tetrahedra.neigh[4*delTet+j] = HXT_NO_ADJACENT; + } + } + +#ifdef DEBUG + HXT_CHECK( hxtTetVerify(mesh) ); +#endif + + HXT_CHECK( hxtRemoveDeleted(mesh) ); + + HXT_CHECK( threadLocals_destroy(&locals, options->numThreads) ); + HXT_CHECK( threadShared_destroy(&shared) ); + + return HXT_STATUS_OK; +} + diff --git a/contrib/hxt/hxt_tetOpti.h b/contrib/hxt/tetMesh/src/hxt_tetOpti.h similarity index 85% rename from contrib/hxt/hxt_tetOpti.h rename to contrib/hxt/tetMesh/src/hxt_tetOpti.h index 59e61105b0..a6fab3d0ff 100644 --- a/contrib/hxt/hxt_tetOpti.h +++ b/contrib/hxt/tetMesh/src/hxt_tetOpti.h @@ -1,5 +1,17 @@ -#ifndef HXT_MESH_H_ -#define HXT_MESH_H_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_OPTI_H +#define HXT_OPTI_H + +#ifdef __cplusplus +extern "C" { +#endif #include "hxt_mesh.h" #include "hxt_bbox.h" @@ -26,6 +38,7 @@ typedef struct { uint32_t numVerticesConstrained; int verbosity; + int reproducible; } HXTOptimizeOptions; @@ -38,4 +51,9 @@ typedef struct { */ HXTStatus hxtOptimizeTetrahedra(HXTMesh *mesh, HXTOptimizeOptions* options); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/contrib/hxt/tetMesh/src/hxt_tetOptiUtils.h b/contrib/hxt/tetMesh/src/hxt_tetOptiUtils.h new file mode 100644 index 0000000000..fedf57f2e9 --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetOptiUtils.h @@ -0,0 +1,68 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETOPTIUTILS_H +#define HXT_TETOPTIUTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hxt_tetPartition.h" +#include "hxt_tetSync.h" +#include "hxt_tetQuality.h" + +typedef struct { + uint16_t creation; + uint16_t check; +} HXTTetDate; + + +typedef struct { + HXTTetDate* values; + uint16_t current; +} HXTTetDates; + + +typedef struct { + uint64_t attempt; + uint64_t conflict; + uint64_t success; +} Statistic; + + +typedef struct +{ + /*** located here ***/ + // list of deleted tet. Added when the cavity is created, removed when the cavity is filled + HXTDeleted deleted; + HXTPartition partition; + Statistic stat; + + /*** located in shared structure ***/ + HXTTetQualities* quality; + HXTTetDates* date; + HXT2Sync* toSync; + uint32_t numVerticesConstrained; + + struct { + // special dates used by SPR + uint64_t dateOfLastCheck; + uint64_t dateOfLastCreation; + + // maximum number of nodes in the SPR search tree + uint64_t maxSearchNodes; + } SPR; +} ThreadLocal; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/hxt/tetMesh/src/hxt_tetPartition.h b/contrib/hxt/tetMesh/src/hxt_tetPartition.h new file mode 100644 index 0000000000..20e5cd1509 --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetPartition.h @@ -0,0 +1,66 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETPARTITION_H +#define HXT_TETPARTITION_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "hxt_vertices.h" + +typedef struct { + uint64_t startDist; + uint64_t lengthDist; + uint64_t firstElem; + uint64_t numElem; +} HXTPartition; + + +/* simple utility function to tell if a vertex is inside a partition, + * given the partition start and it's length 'rel' + * !!! Does not work with ghost vertex !!! */ +static inline int vertexOutOfPartition(HXTVertex* vertices, uint32_t v, uint64_t lengthDist, uint64_t startDist) { + // unsigned wrap around is defined by the standard + return vertices[v].padding.hilbertDist - startDist >= lengthDist; +} + + +static inline int computeNumberOfThreads(double conflictRatio, int numThreads, uint64_t numElem, uint64_t smallestPass) +{ + const double maxBorders = 8.0; + if(conflictRatio > (numThreads - 1) * maxBorders / ( numThreads * (maxBorders + 1) - 2.) ) { + numThreads = (numThreads + 1) / 2; + } + + int maxThreadsInRound = 1; + { + uint32_t tmp = numElem/smallestPass; + while(tmp>1 && maxThreadsInRound < numThreads){ + tmp = tmp/2; + maxThreadsInRound*=2; + } + } + + if(maxThreadsInRound < numThreads) + return maxThreadsInRound; + + return numThreads; +} + + +// HXTStatus hxtComputePartitions(HXTPartition* partitions[], int nThreads, uint64_t* hilbertDist, uint64_t n); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/hxt/tetMesh/src/hxt_tetQuality.c b/contrib/hxt/tetMesh/src/hxt_tetQuality.c new file mode 100644 index 0000000000..31b876c3f0 --- /dev/null +++ b/contrib/hxt/tetMesh/src/hxt_tetQuality.c @@ -0,0 +1,70 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#include <math.h> +#include "hxt_tools.h" + +//!\ this function does not return the aspect ratio 'r'. It returns 'r^2/24' +double hxtTetAspectFastRatio (double a[3], double b[3], double c[3], double d[3], void* userData) { + HXT_UNUSED(userData); + + double ab[3], ac[3], ad[3], bc[3], cd[3], db[3]; + for (int i=0; i<3; i++) { + ab[i] = b[i] - a[i]; // AB + ac[i] = c[i] - a[i]; // AC + ad[i] = d[i] - a[i]; // AD + } + + double acxad0 = ac[1]*ad[2] - ac[2]*ad[1]; + double adxab0 = ad[1]*ab[2] - ad[2]*ab[1]; + double abxac0 = ab[1]*ac[2] - ab[2]*ac[1]; + double volume6 = ab[0]*acxad0 + ac[0]*adxab0 + ad[0]*abxac0; + + // abort as early as possible + if(volume6<=0.0) + return 0.0; + + double acxad1 = ac[2]*ad[0] - ac[0]*ad[2]; + double acxad2 = ac[0]*ad[1] - ac[1]*ad[0]; + + double adxab1 = ad[2]*ab[0] - ad[0]*ab[2]; + double adxab2 = ad[0]*ab[1] - ad[1]*ab[0]; + + double abxac1 = ab[2]*ac[0] - ab[0]*ac[2]; + double abxac2 = ab[0]*ac[1] - ab[1]*ac[0]; + + for (int i=0; i<3; i++) { + db[i] = b[i] - d[i]; // DB = B-D = AB-AD + bc[i] = c[i] - b[i]; // BC = C-B = AC-AB + cd[i] = d[i] - c[i]; // CD = D-c = AD-AC + } + + double bcxcd0 = bc[1]*cd[2] - bc[2]*cd[1]; // = acxad0+abxac0+adxab0; + double bcxcd1 = bc[2]*cd[0] - bc[0]*cd[2]; // = acxad1+abxac1+adxab1; + double bcxcd2 = bc[0]*cd[1] - bc[1]*cd[0]; // = acxad2+abxac2+adxab2; + + double areaSum = sqrt(acxad0*acxad0 + acxad1*acxad1 + acxad2*acxad2) + + sqrt(adxab0*adxab0 + adxab1*adxab1 + adxab2*adxab2) + + sqrt(abxac0*abxac0 + abxac1*abxac1 + abxac2*abxac2) + + sqrt(bcxcd0*bcxcd0 + bcxcd1*bcxcd1 + bcxcd2*bcxcd2); + + double l = ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2]; // |AB|² + double l2 = ac[0]*ac[0] + ac[1]*ac[1] + ac[2]*ac[2]; // |AC|² + double l3 = ad[0]*ad[0] + ad[1]*ad[1] + ad[2]*ad[2]; // |AD|² + double l4 = bc[0]*bc[0] + bc[1]*bc[1] + bc[2]*bc[2]; // |BC|² + double l5 = cd[0]*cd[0] + cd[1]*cd[1] + cd[2]*cd[2]; // |CD|² + double l6 = db[0]*db[0] + db[1]*db[1] + db[2]*db[2]; // |DB|² + + if(l2>l) l=l2; + if(l3>l) l=l3; + if(l4>l) l=l4; + if(l5>l) l=l5; + if(l6>l) l=l6; + + return volume6*volume6/(l*areaSum*areaSum); +} \ No newline at end of file diff --git a/contrib/hxt/hxt_tetQuality.h b/contrib/hxt/tetMesh/src/hxt_tetQuality.h similarity index 73% rename from contrib/hxt/hxt_tetQuality.h rename to contrib/hxt/tetMesh/src/hxt_tetQuality.h index 77de220484..f93db5b25a 100644 --- a/contrib/hxt/hxt_tetQuality.h +++ b/contrib/hxt/tetMesh/src/hxt_tetQuality.h @@ -1,12 +1,20 @@ -#ifndef _HXT_TETQUALITY_ -#define _HXT_TETQUALITY_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETQUALITY_H +#define HXT_TETQUALITY_H #ifdef __cplusplus extern "C" { #endif #include "hxt_mesh.h" -#include <float.h> +#include <math.h> typedef struct { double* values; // qualities for all tet. @@ -15,21 +23,15 @@ typedef struct { void* userData; } HXTTetQualities; -double hxtTetDeterminantInexact(double p0[3], double p1[3], double p2[3], double p3[3], void* userData); - -/// TODO: make an optimized version of this -double hxtTetAspectRatio(double p0[3], double p1[3], double p2[3], double p3[3], void* userData); - //!\ this function does not return the aspect ratio 'r'. It returns 'r^2/24' double hxtTetAspectFastRatio(double p0[3], double p1[3], double p2[3], double p3[3], void* userData); // double myOwnAspectRatio(double a[3], double b[3], double c[3], double d[3]); +static inline double hxtTetAspectRatio(double p0[3], double p1[3], double p2[3], double p3[3], void* userData){ + return sqrt(24.*hxtTetAspectFastRatio(p0, p1, p2, p3, userData)); +} - -/* - Compute the squared aspect ratio of a tet with vertices p0 p1 p2 p3 -*/ static inline double tetQuality(HXTMesh *mesh, HXTTetQualities* quality, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) diff --git a/contrib/hxt/hxt_tetRefine.c b/contrib/hxt/tetMesh/src/hxt_tetRefine.c similarity index 55% rename from contrib/hxt/hxt_tetRefine.c rename to contrib/hxt/tetMesh/src/hxt_tetRefine.c index 6bca8f4e28..04443028ea 100644 --- a/contrib/hxt/hxt_tetRefine.c +++ b/contrib/hxt/tetMesh/src/hxt_tetRefine.c @@ -1,6 +1,16 @@ -#include "hxt_tetRefine.h" +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#include <math.h> +#include "hxt_tetDelaunay.h" #include "predicates.h" #include "hxt_tetFlag.h" +#include "hxt_omp.h" HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) @@ -11,23 +21,6 @@ HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) if (mesh->triangles.num == 0) return HXT_ERROR_MSG(HXT_STATUS_FAILED, "The input mesh should contain triangles"); - double minDist2 = DBL_MAX; - #pragma omp parallel for reduction(min:minDist2) - for (uint64_t i=0; i<mesh->triangles.num; i++){ - uint32_t* node = mesh->triangles.node + 3*i; - for (int j=0; j<3; j++) { - double* n1 = mesh->vertices.coord + (size_t) 4*node[j]; - double* n2 = mesh->vertices.coord + (size_t) 4*node[(j+1)%3]; - - double dist2 = (n1[0]-n2[0])*(n1[0]-n2[0]) - + (n1[1]-n2[1])*(n1[1]-n2[1]) - + (n1[2]-n2[2])*(n1[2]-n2[2]); - - if(dist2<minDist2) - minDist2 = dist2; - } - } - hxtNodeInfo* nodeInfo; HXT_CHECK( hxtAlignedMalloc(&nodeInfo, sizeof(hxtNodeInfo)*mesh->vertices.num) ); @@ -44,7 +37,7 @@ HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) #pragma omp parallel for simd aligned(nodeInfo:SIMD_ALIGN) for (uint32_t i=0; i<mesh->vertices.num; i++) { if(nodeInfo[i].status!=HXT_STATUS_TRUE){ - HXT_WARNING("vertex %u of the empty mesh was not inserted\n", nodeInfo[i].node); + HXT_WARNING("point %u of the empty mesh was not inserted\n", nodeInfo[i].node); } } #endif @@ -55,10 +48,6 @@ HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions) } - -// refine - - double hxtTetCircumcenter(double a[3], double b[3], double c[3], double d[3], double circumcenter[3], double *xi, double *eta, double *zeta) { @@ -146,11 +135,10 @@ static inline double square_dist(double v0[3], double v1[3]) } -static int is_too_close(HXTMesh* mesh, double tetNodeSize, double vtaSize, - double squareDist) +static int is_too_close(double ptSize, double vtaSize, double squareDist) { - if(tetNodeSize!=DBL_MAX) { - double meanSize = 0.5*(tetNodeSize+vtaSize); + if(ptSize!=DBL_MAX) { + double meanSize = 0.5*(ptSize+vtaSize); if(squareDist < /*(0.94*0.94) * */meanSize * meanSize) { return 1; } @@ -160,6 +148,115 @@ static int is_too_close(HXTMesh* mesh, double tetNodeSize, double vtaSize, } +/* receives the 4 nodalSize of the node of a tet, as well as the barycentric + * coordinates of a point in the tet, and returns the nodalSize at that point */ +static inline double getNodalSizeFromBary(double* nodalSize, double* bary) +{ + double denom = 0.0; + double num = 0.0; + int ndef = 0; + for (int j=0;j<4;j++){ + double size = nodalSize[j]; + if (size != DBL_MAX){ + double weight = bary[j]; + denom += weight; + num += weight * size; + } + else { + ndef++; + } + } + + if(ndef!=4) { + return num/denom; + } + else { + HXT_WARNING("tetrahedron with undefined size"); + return DBL_MAX; + } +} + + +/* receives the 4 nodalSize of the node of a tet, and returns barycentric + * coordinates that are proportional to the inverse of the nodalSize. */ +static inline double getBaryFromNodalSize(double* nodalSize, double* bary) { + double denom = 0.0; + int ndef = 0; + for (int j=0; j<4; j++) + { + double size = nodalSize[j]; + if(size!=DBL_MAX && size!=0.0) { + bary[j] = 1./size; + denom += bary[j]; + } + else { + bary[j] = -1.0; + ndef++; + } + } + + if(ndef && ndef!=4) { + denom *= 4.0/(4.0-ndef); + } + + for (int j=0; j<4; j++) + { + if(bary[j]==-1.0) { + bary[j] = 0.25; + } + else { + bary[j] /= denom; + } + } + + if(ndef!=4) { + return 4.0/denom; + } + else { + HXT_WARNING("tetrahedron with undefined size"); + return DBL_MAX; + } +} + + +/* just fill tetCoord and tetNodalSize with the coordinates and nodal size of each node of + * tetrahedron tet */ +static inline void getTetCoordAndNodalSize(HXTMesh* mesh, double* nodalSizes, uint64_t tet, + double tetCoord[4][4], double tetNodalSize[4]) +{ + uint32_t* nodes = &mesh->tetrahedra.node[4*tet]; + for(int i=0; i<4; i++) { + tetCoord[i][0] = mesh->vertices.coord[4 * nodes[i] + 0]; + tetCoord[i][1] = mesh->vertices.coord[4 * nodes[i] + 1]; + tetCoord[i][2] = mesh->vertices.coord[4 * nodes[i] + 2]; + + tetNodalSize[i] = nodalSizes[nodes[i]]; + } +} + + + +// HXTStatus hxtRefineTetrahedraFirst(HXTMesh* mesh, HXTDelaunayOptions* delOptions, +// double (*meshSizeFun)(double x, double y, double z, +// void* meshSizeData), +// void* meshSizeData) +// { + +// #pragma omp parallel for +// for(uint64_t i=0; i<mesh->tetrahedra.num; i++) { + +// if(getProcessedFlag(mesh, i)) +// continue; + +// // we got to turn around each edge :p +// } + +// HXT_CHECK(hxtDelaunay(mesh, delOptions)); + +// return HXT_STATUS_OK; +// } + + HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, double (*meshSizeFun)(double x, double y, double z, void* meshSizeData), @@ -180,23 +277,15 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, uint64_t numToProcessPerThread; { // get the number of unprocessed tet to avid wasting memory ressources... - uint64_t hxtDeclareAligned64 numToProcessSIMD[4] = {0}; - for(uint64_t i=0; i<mesh->tetrahedra.num/4; i++) { - numToProcessSIMD[0] += getProcessedFlag(mesh, i*4+0)==0; - numToProcessSIMD[1] += getProcessedFlag(mesh, i*4+1)==0; - numToProcessSIMD[2] += getProcessedFlag(mesh, i*4+2)==0; - numToProcessSIMD[3] += getProcessedFlag(mesh, i*4+3)==0; - } - - for(uint64_t i=mesh->tetrahedra.num/4*4; i<mesh->tetrahedra.num; i++) { - numToProcessSIMD[0] += getProcessedFlag(mesh, i)==0; + uint64_t numToProcess = 0; + for(uint64_t i=0; i<mesh->tetrahedra.num; i++) { + numToProcess += getProcessedFlag(mesh, i)==0; } // each thread will have to process a certain number of tet - numToProcessPerThread =((numToProcessSIMD[0]+numToProcessSIMD[1]) + - (numToProcessSIMD[2]+numToProcessSIMD[3]))/maxThreads + 1; + numToProcessPerThread = numToProcess/maxThreads + 1; - uint64_t numToProcess = 0; + numToProcess = 0; uint64_t step = 0; int threadID = 0; for(uint64_t i=0; i<mesh->tetrahedra.num; i++) { @@ -216,10 +305,9 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, - uint32_t add = 0; HXTStatus status = HXT_STATUS_OK; - #pragma omp parallel reduction(+:add) + #pragma omp parallel { int threadID = omp_get_thread_num(); @@ -228,141 +316,86 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, for(uint64_t i=startIndex[threadID]; i<startIndex[threadID+1]; i++) { - if (getProcessedFlag(mesh, i)==0){ - int pointAdded = 0; - double* p[4]; - p[0] = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+0]; - p[1] = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+1]; - p[2] = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+2]; - p[3] = mesh->vertices.coord + (size_t) 4*mesh->tetrahedra.node[4*i+3]; - double newCoord [3]; - double bary[4]; - double vtaSize; - setProcessedFlag(mesh, i); // we do not need to refine that tetrahedra anymore - - double tetNodeSize[4]; - for(int j=0; j<4; j++) { - tetNodeSize[j] = delOptions->nodalSizes[mesh->tetrahedra.node[4*i+j]]; - } + if (getProcessedFlag(mesh, i)) + continue; + + setProcessedFlag(mesh, i); // we do not need to refine that tetrahedron anymore + + int pointAdded = 0; + double p[4][4]; + double s[4]; + double bary[4]; + double newCoord [3]; + double vtaSize; + getTetCoordAndNodalSize(mesh, delOptions->nodalSizes, i, p, s); - // try to add the point at the circumcenter - hxtTetCircumcenter(p[0], p[1], p[2], p[3], newCoord, &bary[1], &bary[2], &bary[3]); - bary[0] = 1.0 - bary[1] - bary[2] - bary[3]; - - // we don't insert at circumcenter if it is outside the tet. - if(bary[0] > 0 && bary[1] > 0 && bary[2] > 0 && bary[3] > 0) { - - // computing the mesh size - if(meshSizeFun!=NULL) { - vtaSize = meshSizeFun(newCoord[0], newCoord[1], newCoord[2], meshSizeData); - } - else { // we suppose delOptions->nodalSize!=NULL - double denom = 0.0; - double num = 0.0; - for (int j=0;j<4;j++){ - double size = delOptions->nodalSizes[mesh->tetrahedra.node[4*i+j]]; - if (size != DBL_MAX){ - if(bary[j]>0.999) { - num = size; - denom = 1; - break; - } - double weight = bary[j]; - denom += weight; - num += weight * size; - } - } - - vtaSize = num/denom; - } - - double circumradius2 = square_dist(p[0], newCoord); - - if(!is_too_close(mesh, tetNodeSize[0], vtaSize, circumradius2) && - !is_too_close(mesh, tetNodeSize[1], vtaSize, circumradius2) && - !is_too_close(mesh, tetNodeSize[2], vtaSize, circumradius2) && - !is_too_close(mesh, tetNodeSize[3], vtaSize, circumradius2)) { - size_t vertexIndex = vertexStart + localAdd; - newVertices[vertexIndex*4 ] = newCoord[0]; - newVertices[vertexIndex*4+1] = newCoord[1]; - newVertices[vertexIndex*4+2] = newCoord[2]; - newVertices[vertexIndex*4+3] = vtaSize; - pointAdded = 1; - localAdd++; - } + // try to add the point at the circumcenter + hxtTetCircumcenter(p[0], p[1], p[2], p[3], newCoord, &bary[1], &bary[2], &bary[3]); + bary[0] = 1.0 - bary[1] - bary[2] - bary[3]; + + // we don't insert at circumcenter if it is outside the tet. + if(bary[0] > 0 && bary[1] > 0 && bary[2] > 0 && bary[3] > 0) { + + // computing the mesh size + if(meshSizeFun!=NULL) { + vtaSize = meshSizeFun(newCoord[0], newCoord[1], newCoord[2], meshSizeData); + } + else { // we suppose delOptions->nodalSize!=NULL + vtaSize = getNodalSizeFromBary(s, bary); } + + double circumradius2 = square_dist(p[0], newCoord); - // try to add the point at barycentric coordinates - // ponderated by the inverse of the mesh size - if(!pointAdded){ - double denom = 0.0; - int ndef = 0; - for (int j=0; j<4; j++) - { - double size = tetNodeSize[j]; - if(size!=DBL_MAX && size!=0.0) { - bary[j] = 1./size; - denom += bary[j]; - } - else { - bary[j] = -1.0; - ndef++; - } - } - - if(ndef && ndef!=4) { - denom *= 4.0/(4.0-ndef); - } - - for (int j=0; j<4; j++) - { - if(bary[j]==-1.0) { - bary[j] = 0.25; - } - else { - bary[j] /= denom; - } - } - - for (int j=0; j<3; j++) - { - newCoord[j] = bary[0]*p[0][j] + - bary[1]*p[1][j] + - bary[2]*p[2][j] + - bary[3]*p[3][j]; - } - - // this does not work with ffast-math, GCC completely ignore this... - #if !defined(__FAST_MATH__) && !defined(NDEBUG) - if(!isfinite(newCoord[0]) || !isfinite(newCoord[1]) || !isfinite(newCoord[2])){ - HXT_ERROR_MSG(HXT_STATUS_ERROR, "new coordinates are not finite"); - exit(EXIT_FAILURE); - } - #endif - - if(meshSizeFun!=NULL) { - vtaSize = meshSizeFun(newCoord[0], newCoord[1], newCoord[2], meshSizeData); - } - else { - if(ndef==4) - vtaSize = DBL_MAX; - else { - vtaSize = 4.0/denom; - } - } - - if(!is_too_close(mesh, tetNodeSize[0], vtaSize, square_dist(p[0], newCoord)) && - !is_too_close(mesh, tetNodeSize[1], vtaSize, square_dist(p[1], newCoord)) && - !is_too_close(mesh, tetNodeSize[2], vtaSize, square_dist(p[2], newCoord)) && - !is_too_close(mesh, tetNodeSize[3], vtaSize, square_dist(p[3], newCoord))){ - size_t vertexIndex = vertexStart + localAdd; - newVertices[vertexIndex*4 ] = newCoord[0]; - newVertices[vertexIndex*4+1] = newCoord[1]; - newVertices[vertexIndex*4+2] = newCoord[2]; - newVertices[vertexIndex*4+3] = vtaSize; - pointAdded = 1; - localAdd++; - } + if(!is_too_close(s[0], vtaSize, circumradius2) && + !is_too_close(s[1], vtaSize, circumradius2) && + !is_too_close(s[2], vtaSize, circumradius2) && + !is_too_close(s[3], vtaSize, circumradius2)) { + size_t vertexIndex = vertexStart + localAdd; + newVertices[vertexIndex*4 ] = newCoord[0]; + newVertices[vertexIndex*4+1] = newCoord[1]; + newVertices[vertexIndex*4+2] = newCoord[2]; + newVertices[vertexIndex*4+3] = vtaSize; + pointAdded = 1; + localAdd++; + } + } + + // try to add the point at barycentric coordinates + // ponderated by the inverse of the mesh size + if(!pointAdded){ + vtaSize = getBaryFromNodalSize(s, bary); + + for (int j=0; j<3; j++) + { + newCoord[j] = bary[0]*p[0][j] + + bary[1]*p[1][j] + + bary[2]*p[2][j] + + bary[3]*p[3][j]; + } + + // this does not work with ffast-math, GCC completely ignore this... +#if !defined(__FAST_MATH__) && !defined(NDEBUG) + if(!isfinite(newCoord[0]) || !isfinite(newCoord[1]) || !isfinite(newCoord[2])){ + HXT_ERROR_MSG(HXT_STATUS_ERROR, "new coordinates are not finite"); + exit(EXIT_FAILURE); + } +#endif + + if(meshSizeFun!=NULL) { + vtaSize = meshSizeFun(newCoord[0], newCoord[1], newCoord[2], meshSizeData); + } + + if(!is_too_close(s[0], vtaSize, square_dist(p[0], newCoord)) && + !is_too_close(s[1], vtaSize, square_dist(p[1], newCoord)) && + !is_too_close(s[2], vtaSize, square_dist(p[2], newCoord)) && + !is_too_close(s[3], vtaSize, square_dist(p[3], newCoord))){ + size_t vertexIndex = vertexStart + localAdd; + newVertices[vertexIndex*4 ] = newCoord[0]; + newVertices[vertexIndex*4+1] = newCoord[1]; + newVertices[vertexIndex*4+2] = newCoord[2]; + newVertices[vertexIndex*4+3] = vtaSize; + pointAdded = 1; + localAdd++; } } } @@ -381,6 +414,8 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, add = tsum; } + HXT_INFO_COND(delOptions->verbosity>1, "Refinement adds %u points", add); + if(mesh->vertices.num + add>mesh->vertices.size){ status=hxtAlignedRealloc(&mesh->vertices.coord, sizeof(double)*4*(mesh->vertices.num + add)); if(status==HXT_STATUS_OK){ @@ -409,9 +444,14 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions, return status; } + HXT_CHECK(hxtAlignedFree(&newVertices)); + + if(add == 0) + break; + mesh->vertices.num += add; - HXT_CHECK(hxtAlignedFree(&newVertices)); + delOptions->partitionability = 1.0 - pow(0.5, iter); HXT_CHECK(hxtDelaunay(mesh, delOptions)); diff --git a/contrib/hxt/hxt_tetRefine.h b/contrib/hxt/tetMesh/src/hxt_tetRefine.h similarity index 73% rename from contrib/hxt/hxt_tetRefine.h rename to contrib/hxt/tetMesh/src/hxt_tetRefine.h index 368d5c3c7b..c0e208e553 100644 --- a/contrib/hxt/hxt_tetRefine.h +++ b/contrib/hxt/tetMesh/src/hxt_tetRefine.h @@ -1,10 +1,15 @@ -#ifndef _HXT_TETREFINE_ -#define _HXT_TETREFINE_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot -#include "hxt_tetDelaunay.h" +#ifndef HXT_TETREFINE_H +#define HXT_TETREFINE_H -/// Creates a structure that allows to look over triangular faces of the 2D mesh -HXTStatus hxtCreateFaceSearchStructure(HXTMesh* mesh, uint32_t **pfaces); +#include "hxt_tetDelaunay.h" //// creates a mesh with all points of the surface mesh HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions); diff --git a/contrib/hxt/hxt_tetRepair.c b/contrib/hxt/tetMesh/src/hxt_tetRepair.c similarity index 75% rename from contrib/hxt/hxt_tetRepair.c rename to contrib/hxt/tetMesh/src/hxt_tetRepair.c index 2df4c551fa..43096a5f46 100644 --- a/contrib/hxt/hxt_tetRepair.c +++ b/contrib/hxt/tetMesh/src/hxt_tetRepair.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetRepair.h" #include "hxt_tetUtils.h" #include "hxt_tetFlag.h" @@ -285,6 +293,13 @@ HXTStatus hxtTetVerify(HXTMesh* mesh) volatile int errorOccured = 0; HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord; + if(mesh->tetrahedra.node==NULL && mesh->tetrahedra.num!=0) { + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "list of nodes not given"); + } + + if(mesh->tetrahedra.neigh==NULL && mesh->tetrahedra.num!=0) + HXT_WARNING("adjacencies not computed"); + #pragma omp parallel for for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { @@ -293,17 +308,29 @@ HXTStatus hxtTetVerify(HXTMesh* mesh) // continue; uint32_t* Node = mesh->tetrahedra.node + i*4; - uint64_t* Neigh = mesh->tetrahedra.neigh + i*4; - if(getDeletedFlag(mesh, i)){ + if(mesh->tetrahedra.flag && getDeletedFlag(mesh, i)){ // HXT_WARNING("deleted tetrahedra remain in the mesh"); continue; } // check for good placement of ghost vertex - if(Node[0]==HXT_GHOST_VERTEX || Node[1]==HXT_GHOST_VERTEX || Node[2]==HXT_GHOST_VERTEX){ - HXT_ERROR_MSG(HXT_STATUS_ERROR, "ghost vertex at wrong place in tet. %lu", i); - errorOccured=1; + int localError = 0; + for(int j=0; j<4; j++) { + if(Node[j]==HXT_GHOST_VERTEX){ + if(j!=3) { + HXT_ERROR_MSG(HXT_STATUS_ERROR, "ghost vertex at wrong place in tet. %lu", i); + localError=1; + } + } + else if(Node[j]>=mesh->vertices.num){ + HXT_ERROR_MSG(HXT_STATUS_ERROR, "node %d of tet. %lu does not exist", j, i); + localError=2; + } + } + + if(localError) { + errorOccured = localError; continue; } @@ -318,85 +345,88 @@ HXTStatus hxtTetVerify(HXTMesh* mesh) // else if(Node[3]!=HXT_GHOST_VERTEX && orient3d(a,b,c,vertices[Node[3]].coord)>=0.0){ HXT_ERROR_MSG(HXT_STATUS_ERROR, "orientation of tet %lu is wrong",i); - errorOccured=1; + errorOccured=3; continue; } - // check the neighbors - for (unsigned j=0; j<4; j++) - { - if(Neigh[j]==HXT_NO_ADJACENT){ - continue; - } + if(mesh->tetrahedra.neigh) { + uint64_t* Neigh = mesh->tetrahedra.neigh + i*4; - uint64_t neigh = Neigh[j]/4; - unsigned face = Neigh[j]%4; + // check the neighbors + for (unsigned j=0; j<4; j++) + { + if(Neigh[j]==HXT_NO_ADJACENT){ + continue; + } - if(neigh>=mesh->tetrahedra.num) { - HXT_ERROR_MSG(HXT_STATUS_ERROR, "%uth neighbor of tet %lu does not exist", j, i); - errorOccured=1; - continue; - } + uint64_t neigh = Neigh[j]/4; + unsigned face = Neigh[j]%4; - if(getDeletedFlag(mesh, neigh)) { - HXT_ERROR_MSG(HXT_STATUS_ERROR, "%uth neighbor of tet %lu is deleted", j, i); - errorOccured=1; - continue; - } + if(neigh>=mesh->tetrahedra.num) { + HXT_ERROR_MSG(HXT_STATUS_ERROR, "%uth neighbor of tet %lu does not exist", j, i); + errorOccured=4; + continue; + } - // uint64_t* NeighNeigh = mesh->tetrahedra.neigh + neigh; - uint32_t* NeighNode = mesh->tetrahedra.node + neigh*4; - - if(mesh->tetrahedra.neigh[4*neigh+face]!=i*4+j){ - HXT_ERROR_MSG(HXT_STATUS_ERROR, "tet %lu (%lu/4) is not the neighbor of its %uth neighbor %lu (%lu/4)", i, i*4,j, neigh, 4*neigh+face); - errorOccured=1; - continue; - } + if(mesh->tetrahedra.flag && getDeletedFlag(mesh, neigh)) { + HXT_ERROR_MSG(HXT_STATUS_ERROR, "%uth neighbor of tet %lu is deleted", j, i); + errorOccured=5; + continue; + } - uint32_t V[3] = { Node[((j+1)&3)], Node[((j+3)&2)], Node[((j&2)^3)]}; - unsigned l; + // uint64_t* NeighNeigh = mesh->tetrahedra.neigh + neigh; + uint32_t* NeighNode = mesh->tetrahedra.node + neigh*4; + + if(mesh->tetrahedra.neigh[4*neigh+face]!=i*4+j){ + HXT_ERROR_MSG(HXT_STATUS_ERROR, "tet %lu (%lu/4) is not the neighbor of its %uth neighbor %lu (%lu/4)", i, i*4,j, neigh, 4*neigh+face); + errorOccured=6; + continue; + } - for (l=0; l<3; l++) - { - if(NeighNode[((face+1)&3)]==V[l] && NeighNode[((face+3)&2)]==V[(l+1)%3] && NeighNode[((face&2)^3)]==V[(l+2)%3]) - break; - } + uint32_t V[3] = { Node[getNode0FromFacet(j)], Node[getNode1FromFacet(j)], Node[getNode2FromFacet(j)]}; + unsigned l; - if(l!=3){ - HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet. %lu is intersecting it (common face has the same orientation)",j,i); - errorOccured=1; - continue; - } + for (l=0; l<3; l++) + { + if(NeighNode[getNode0FromFacet(face)]==V[l] && NeighNode[getNode1FromFacet(face)]==V[(l+1)%3] && NeighNode[getNode2FromFacet(face)]==V[(l+2)%3]) + break; + } - for (l=0; l<3; l++) - { - if(NeighNode[((face+1)&3)]==V[l] && NeighNode[((face&2)^3)]==V[(l+1)%3] && NeighNode[((face+3)&2)]==V[(l+2)%3]) - break; - } + if(l!=3){ + HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet. %lu is intersecting it (common face has the same orientation)",j,i); + errorOccured=7; + continue; + } - if(l==3){ - HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet. %lu doesn't contain 3 common vertices",j,i); - errorOccured=1; - continue; - } + for (l=0; l<3; l++) + { + if(NeighNode[getNode0FromFacet(face)]==V[l] && NeighNode[getNode2FromFacet(face)]==V[(l+1)%3] && NeighNode[getNode1FromFacet(face)]==V[(l+2)%3]) + break; + } + + if(l==3){ + HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet. %lu doesn't contain 3 common vertices",j,i); + errorOccured=8; + continue; + } + if(mesh->tetrahedra.flag && (getFacetConstraint(mesh, i,j)!=0) ^ (getFacetConstraint(mesh, neigh, face)!=0)) { + HXT_ERROR_MSG(HXT_STATUS_ERROR, "constraint is not consistent on both side of facet 4*%lu+%u",i,j); + errorOccured=9; + continue; + } - if((getFacetConstraint(mesh, i,j)!=0) ^ (getFacetConstraint(mesh, neigh, face)!=0)) { - HXT_ERROR_MSG(HXT_STATUS_ERROR, "constraint is not consistent on both side of facet 4*%lu+%u",i,j); - errorOccured=1; - continue; + // only for delaunay triangulation... + // if(Node[3]!=HXT_GHOST_VERTEX && NeighNode[face]!=HXT_GHOST_VERTEX && insphere(vertices[Node[0]].coord, + // vertices[Node[1]].coord, + // vertices[Node[2]].coord, + // vertices[Node[3]].coord, + // vertices[NeighNode[face]].coord)<0.0){ + // HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet %lu has it's non-common node in the sphere (insphere(%u %u %u %u %u)>0)",j,i*4, Node[0], Node[1], Node[2], Node[3], NeighNode[face]); + // errorOccured=1; + // continue; + // } } - - // only for delaunay triangulation... - // if(Node[3]!=HXT_GHOST_VERTEX && NeighNode[face]!=HXT_GHOST_VERTEX && insphere(vertices[Node[0]].coord, - // vertices[Node[1]].coord, - // vertices[Node[2]].coord, - // vertices[Node[3]].coord, - // vertices[NeighNode[face]].coord)<0.0){ - // HXT_ERROR_MSG(HXT_STATUS_ERROR, "neighbor %u of tet %lu has it's non-common node in the sphere (insphere(%u %u %u %u %u)>0)",j,i*4, Node[0], Node[1], Node[2], Node[3], NeighNode[face]); - // errorOccured=1; - // continue; - // } } } @@ -492,11 +522,13 @@ HXTStatus hxtAddGhosts(HXTMesh* mesh){ if(getFacetConstraint(mesh, i, j)) setFacetConstraint(mesh, newGhost, 3); + setProcessedFlag(mesh, newGhost); + uint32_t v0, v1, v2; - v0 = mesh->tetrahedra.node[4*i+((j+1)&3)]; - v1 = mesh->tetrahedra.node[4*i+((j+3)&2)]; - v2 = mesh->tetrahedra.node[4*i+((j&2)^3)]; + v0 = mesh->tetrahedra.node[4*i+getNode0FromFacet(j)]; + v1 = mesh->tetrahedra.node[4*i+getNode2FromFacet(j)]; + v2 = mesh->tetrahedra.node[4*i+getNode1FromFacet(j)]; mesh->tetrahedra.node[4*newGhost+0] = v0; mesh->tetrahedra.node[4*newGhost+1] = v1; diff --git a/contrib/hxt/hxt_tetRepair.h b/contrib/hxt/tetMesh/src/hxt_tetRepair.h similarity index 83% rename from contrib/hxt/hxt_tetRepair.h rename to contrib/hxt/tetMesh/src/hxt_tetRepair.h index 0ae279a995..f7acd56708 100644 --- a/contrib/hxt/hxt_tetRepair.h +++ b/contrib/hxt/tetMesh/src/hxt_tetRepair.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETREPAIR_ -#define _HXT_TETREPAIR_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETREPAIR_H +#define HXT_TETREPAIR_H #ifdef __cplusplus extern "C" { diff --git a/contrib/hxt/hxt_tetSync.c b/contrib/hxt/tetMesh/src/hxt_tetSync.c similarity index 92% rename from contrib/hxt/hxt_tetSync.c rename to contrib/hxt/tetMesh/src/hxt_tetSync.c index 3ed97de3b0..2458194f71 100644 --- a/contrib/hxt/hxt_tetSync.c +++ b/contrib/hxt/tetMesh/src/hxt_tetSync.c @@ -1,5 +1,14 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetSync.h" #include "hxt_tetFlag.h" +#include "hxt_tools.h" HXTStatus synchronizeReallocation(HXT2Sync* shared, int* threadFinishedLocal) { @@ -73,7 +82,7 @@ HXTStatus createNewDeleted(HXT2Sync* shared, #pragma omp atomic capture { ntet = mesh->tetrahedra.num; mesh->tetrahedra.num+=needed;} - if(mesh->tetrahedra.num > mesh->tetrahedra.size) { + if(ntet + needed > mesh->tetrahedra.size) { HXT_CHECK( synchronizeReallocation(shared, NULL) ); } HXT_CHECK( askForDeleted(deleted, needed) ); @@ -91,6 +100,7 @@ HXTStatus createNewDeleted(HXT2Sync* shared, } } + deleted->createdNew = 1; deleted->num = DELETED_BUFFER_SIZE; return HXT_STATUS_OK; } \ No newline at end of file diff --git a/contrib/hxt/hxt_tetSync.h b/contrib/hxt/tetMesh/src/hxt_tetSync.h similarity index 87% rename from contrib/hxt/hxt_tetSync.h rename to contrib/hxt/tetMesh/src/hxt_tetSync.h index 4cb90ad680..941993e0d2 100644 --- a/contrib/hxt/hxt_tetSync.h +++ b/contrib/hxt/tetMesh/src/hxt_tetSync.h @@ -1,5 +1,13 @@ -#ifndef _HXT_TETSYNC_ -#define _HXT_TETSYNC_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETSYNC_H +#define HXT_TETSYNC_H #ifdef __cplusplus extern "C" { @@ -41,6 +49,7 @@ typedef struct { uint64_t* array; uint64_t num; uint64_t size; + int createdNew; // just a flag that tells if createNewDeleted was called } HXTDeleted; diff --git a/contrib/hxt/hxt_tetUtils.c b/contrib/hxt/tetMesh/src/hxt_tetUtils.c similarity index 88% rename from contrib/hxt/hxt_tetUtils.c rename to contrib/hxt/tetMesh/src/hxt_tetUtils.c index 6e9d980124..03fa64f613 100644 --- a/contrib/hxt/hxt_tetUtils.c +++ b/contrib/hxt/tetMesh/src/hxt_tetUtils.c @@ -1,15 +1,24 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_tetUtils.h" #include "hxt_tetFlag.h" #include "hxt_sort.h" -#define MAX(x,y) ((x)>(y) ? (x) : (y)) - /*********************************** * remove deleted tetrahedra of mesh ***********************************/ // TODO: a parallel technique HXTStatus hxtRemoveDeleted(HXTMesh* mesh) { + if(mesh->tetrahedra.num==0) + return HXT_STATUS_OK; + #pragma omp parallel for for (uint64_t i=0; i<mesh->tetrahedra.num; i++) { if(getDeletedFlag(mesh, i)){ diff --git a/contrib/hxt/hxt_tetUtils.h b/contrib/hxt/tetMesh/src/hxt_tetUtils.h similarity index 86% rename from contrib/hxt/hxt_tetUtils.h rename to contrib/hxt/tetMesh/src/hxt_tetUtils.h index a7861f6c2b..8f5a37c145 100644 --- a/contrib/hxt/hxt_tetUtils.h +++ b/contrib/hxt/tetMesh/src/hxt_tetUtils.h @@ -1,11 +1,20 @@ -#ifndef _HXT_TETUTILS_ -#define _HXT_TETUTILS_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_TETUTILS_H +#define HXT_TETUTILS_H #ifdef __cplusplus extern "C" { #endif #include "hxt_mesh.h" +#include "hxt_tools.h" /** * \file tetUtils.h utility for the tetrahedral mesh diff --git a/contrib/hxt/hxt_vertices.c b/contrib/hxt/tetMesh/src/hxt_vertices.c similarity index 99% rename from contrib/hxt/hxt_vertices.c rename to contrib/hxt/tetMesh/src/hxt_vertices.c index ad5c25d386..09c34bc45a 100644 --- a/contrib/hxt/hxt_vertices.c +++ b/contrib/hxt/tetMesh/src/hxt_vertices.c @@ -1,3 +1,11 @@ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + #include "hxt_omp.h" #include <string.h> #include "hxt_vertices.h" diff --git a/contrib/hxt/hxt_vertices.h b/contrib/hxt/tetMesh/src/hxt_vertices.h similarity index 93% rename from contrib/hxt/hxt_vertices.h rename to contrib/hxt/tetMesh/src/hxt_vertices.h index e629e1b1c9..3f7176b54e 100644 --- a/contrib/hxt/hxt_vertices.h +++ b/contrib/hxt/tetMesh/src/hxt_vertices.h @@ -1,5 +1,13 @@ -#ifndef _HEXTREME_VERTICES_ -#define _HEXTREME_VERTICES_ +// Hxt - Copyright (C) +// 2016 - 2020 UCLouvain +// +// See the LICENSE.txt file for license information. +// +// Contributor(s): +// Célestin Marot + +#ifndef HXT_VERTICES_H +#define HXT_VERTICES_H #include "hxt_mesh.h" #include "hxt_bbox.h" -- GitLab