diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c index c31e3eee3f8013efc3eeb0e626b083183874f77c..30067c1902599722d710cd512290359bcb14241d 100644 --- a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c @@ -206,7 +206,7 @@ unsigned computePasses(uint32_t passes[12], * initialisation of the TetLocal structure ******************************************/ static inline HXTStatus localInit(TetLocal* local){ - local->ball.size = 1020; + local->ball.size = 1024; local->ball.num = 0; HXT_CHECK( hxtAlignedMalloc(&local->ball.array, sizeof(cavityBnd_t)*local->ball.size)); @@ -770,56 +770,132 @@ HXT_ASSERT(((size_t) verticesID)%SIMD_ALIGN==0); /************************************************************** * compute adjacencies by sorting => O(n log n) **************************************************************/ + +static inline uint64_t hash64(uint64_t x) { + x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); + return x ^ (x >> 31); +} + +// key must be unique, and it cannot be 0 +static inline uint64_t hashTableSearch(HXTGroup2* pairs, uint64_t mask, uint64_t key, uint64_t neigh) { + uint64_t hash = hash64(key) & mask; + while(pairs[hash].v[0] != key && pairs[hash].v[0] != 0) { + hash = (hash + 1) & mask; + } + if(pairs[hash].v[0] == key) { + return pairs[hash].v[1]; + } + + pairs[hash].v[0] = key; + pairs[hash].v[1] = neigh; + return HXT_NO_ADJACENT; +} + + static inline HXTStatus computeAdjacenciesSlow(HXTMesh* mesh, TetLocal* local, const uint64_t start, const uint64_t blength) { - HXTGroup2* edges; - - HXT_CHECK( askForBall(local, 2 * blength) ); - edges = (HXTGroup2*) local->ball.array; // recycle array + uint64_t size = UINT64_C(1) << u64_log2(5*blength);// 3*blength/2 entries => we want a hash table of at least 3*blength for a good load factor + uint64_t mask = size - 1; + + // recycle memory + if(sizeof(cavityBnd_t) * local->ball.size < sizeof(HXTGroup2) * size) { + uint64_t capacity = (sizeof(HXTGroup2) * size + sizeof(cavityBnd_t) - 1) / sizeof(cavityBnd_t); + capacity = MAX(2 * local->ball.size, capacity); + HXT_CHECK( hxtAlignedFree(&local->ball.array) ); + HXT_CHECK( hxtAlignedMalloc(&local->ball.array, sizeof(cavityBnd_t) * capacity) ); + local->ball.size = capacity; + } + HXTGroup2* pairs = (HXTGroup2*) local->ball.array; + memset(pairs, 0, size * sizeof(HXTGroup2)); const uint8_t index[4] = {2,3,1,2}; - const uint32_t n = mesh->vertices.num + 1; - uint64_t maxKey = 0; +#ifdef DEBUG + int found = 0; +#endif for (uint64_t i=0; i<blength; i++) { - uint64_t curTet = local->deleted.array[start+ i]; + uint64_t curTet = local->deleted.array[start + i]; const uint32_t* __restrict__ Node = mesh->tetrahedra.node + 4*curTet; for (unsigned j=0; j<3; j++) { - uint32_t n0 = Node[index[j]] + 1; - uint32_t n1 = Node[index[j+1]] + 1; - - if(n0 < n1) - edges[3*i + j].v[0] = ((uint64_t) n0 * n) + n1; - else - edges[3*i + j].v[0] = ((uint64_t) n1 * n) + n0; - - if(edges[3*i + j].v[0] > maxKey) - maxKey = edges[3*i + j].v[0]; - - edges[3*i + j].v[1] = 4*curTet+j+1; + uint32_t n0 = Node[index[j]]; + uint32_t n1 = Node[index[j+1]]; + uint64_t key = (uint64_t) (n0 ^ n1) << 32 | MAX(n0, n1); + + uint64_t neigh = hashTableSearch(pairs, mask, key, 4 * curTet + j + 1); + if(neigh != HXT_NO_ADJACENT) { +#ifdef DEBUG + found++; +#endif + mesh->tetrahedra.neigh[4 * curTet + j + 1] = neigh; + mesh->tetrahedra.neigh[neigh] = 4 * curTet + j + 1; + } } } - HXT_CHECK( group2_sort_v0(edges, 3*blength, maxKey) ); - - for(int i=0; i<3*blength; i+=2) { -#ifndef NDEBUG - if(edges[i].v[0] != edges[i+1].v[0]) - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "Failed to compute adjacencies (b)"); +#ifdef DEBUG + if(2 * found != 3 * blength) + return HXT_ERROR_MSG(HXT_STATUS_ERROR, "Failed to compute adjacencies (b)"); #endif - uint64_t f0 = edges[i].v[1]; - uint64_t f1 = edges[i+1].v[1]; - mesh->tetrahedra.neigh[f0] = f1; - mesh->tetrahedra.neigh[f1] = f0; - } return HXT_STATUS_OK; } + +// static inline HXTStatus computeAdjacenciesSlow(HXTMesh* mesh, TetLocal* local, const uint64_t start, const uint64_t blength) +// { +// HXTGroup2* edges; + +// HXT_CHECK( askForBall(local, 2 * blength) ); +// edges = (HXTGroup2*) local->ball.array; // recycle array + +// const uint8_t index[4] = {2,3,1,2}; + +// const uint32_t n = mesh->vertices.num + 1; +// uint64_t maxKey = 0; + +// for (uint64_t i=0; i<blength; i++) +// { +// uint64_t curTet = local->deleted.array[start+ i]; +// const uint32_t* __restrict__ Node = mesh->tetrahedra.node + 4*curTet; +// for (unsigned j=0; j<3; j++) +// { +// uint32_t n0 = Node[index[j]] + 1; +// uint32_t n1 = Node[index[j+1]] + 1; + +// if(n0 < n1) +// edges[3*i + j].v[0] = ((uint64_t) n0 * n) + n1; +// else +// edges[3*i + j].v[0] = ((uint64_t) n1 * n) + n0; + +// if(edges[3*i + j].v[0] > maxKey) +// maxKey = edges[3*i + j].v[0]; + +// edges[3*i + j].v[1] = 4*curTet+j+1; +// } +// } + +// HXT_CHECK( group2_sort_v0(edges, 3*blength, maxKey) ); + +// for(int i=0; i<3*blength; i+=2) { +// #ifndef NDEBUG +// if(edges[i].v[0] != edges[i+1].v[0]) +// return HXT_ERROR_MSG(HXT_STATUS_ERROR, "Failed to compute adjacencies (b)"); +// #endif +// uint64_t f0 = edges[i].v[1]; +// uint64_t f1 = edges[i+1].v[1]; + +// mesh->tetrahedra.neigh[f0] = f1; +// mesh->tetrahedra.neigh[f1] = f0; +// } +// return HXT_STATUS_OK; +// } + + /**************************************** * filling back the cavity (DelaunayBall) ****************************************/ diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c index bd43205e44bd1d75ba51299877b4d11950e6d4f6..87d13c029d0dbbed2d61a938bcfb8f5ec3b30a0a 100644 --- a/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c +++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunayReshape.c @@ -287,118 +287,118 @@ HXTStatus hashTableDestroy(HXTHashTable* map) { // remove the tetrahedra adjacent to the face that does not see the point, progressively, until the cavity is star shaped... HXTStatus reshapeCavityIfNeeded(TetLocal* local, HXTMesh* mesh, const uint32_t vta, uint64_t prevNumDeleted) { - uint64_t count = 0; +// uint64_t count = 0; - // STEP 1: for each ball faces, we need the index of the tet in the deleted array, instead of the index of the tet in the mesh - // for each deleted tet, we need the index of the 4 faces in the ball, or the index of the neighbor in the deleted array - // if the facet is not a facet of the cavity. To differentiate both, BND_FACE_FLAG is set for indices of the ball. - uint64_t numTet = local->deleted.num - prevNumDeleted; - uint64_t* tets = &local->deleted.array[prevNumDeleted]; +// // STEP 1: for each ball faces, we need the index of the tet in the deleted array, instead of the index of the tet in the mesh +// // for each deleted tet, we need the index of the 4 faces in the ball, or the index of the neighbor in the deleted array +// // if the facet is not a facet of the cavity. To differentiate both, BND_FACE_FLAG is set for indices of the ball. +// uint64_t numTet = local->deleted.num - prevNumDeleted; +// uint64_t* tets = &local->deleted.array[prevNumDeleted]; - HXTHashTable map; - HXT_CHECK( hashTableInit(&map, numTet) ); +// HXTHashTable map; +// HXT_CHECK( hashTableInit(&map, numTet) ); - for(uint64_t i=0; i<numTet; i++) { - hashTablePut(&map, tets[i], i); - } +// for(uint64_t i=0; i<numTet; i++) { +// hashTablePut(&map, tets[i], i); +// } - uint64_t* faces; - HXT_CHECK( hxtMalloc(&faces, sizeof(uint64_t) * 4 * numTet) ); +// uint64_t* faces; +// HXT_CHECK( hxtMalloc(&faces, sizeof(uint64_t) * 4 * numTet) ); - // just copy the adjacency into faces - uint64_t curFace = 0; - for(uint64_t i=0; i<numTet; i++) { - uint64_t curTet = tets[i]; - for(uint64_t j=0; j<4; j++) { +// // just copy the adjacency into faces +// uint64_t curFace = 0; +// for(uint64_t i=0; i<numTet; i++) { +// uint64_t curTet = tets[i]; +// for(uint64_t j=0; j<4; j++) { - uint64_t neigh = mesh->tetrahedra.neigh[4 * curTet + j]; - if(neigh != HXT_NO_ADJACENT && getDeletedFlag(mesh, neigh / 4)) { - faces[4 * i + j] = 4 * hashTableGet(&map, neigh / 4) + neigh % 4; - } - else { // it should be the next one in the ball, (we didn't change the order since @diggingACavity) - HXT_ASSERT(local->ball.array[curFace].neigh==neigh); - faces[4 * i + j] = curFace; - curFace++; - } - } - } +// uint64_t neigh = mesh->tetrahedra.neigh[4 * curTet + j]; +// if(neigh != HXT_NO_ADJACENT && getDeletedFlag(mesh, neigh / 4)) { +// faces[4 * i + j] = 4 * hashTableGet(&map, neigh / 4) + neigh % 4; +// } +// else { // it should be the next one in the ball, (we didn't change the order since @diggingACavity) +// HXT_ASSERT(local->ball.array[curFace].neigh==neigh); +// faces[4 * i + j] = curFace; +// curFace++; +// } +// } +// } - HXT_CHECK( hashTableDestroy(&map) ); +// HXT_CHECK( hashTableDestroy(&map) ); -#ifndef NDEBUG - if(curFace != local->ball.num) { - return HXT_ERROR_MSG(HXT_STATUS_ERROR, "DEBUG: Faces did not appear in the same order as deleted tet"); - } -#endif +// #ifndef NDEBUG +// if(curFace != local->ball.num) { +// return HXT_ERROR_MSG(HXT_STATUS_ERROR, "DEBUG: Faces did not appear in the same order as deleted tet"); +// } +// #endif - // double *vtaCoord = &mesh->vertices.coord[4 * vta]; +// // double *vtaCoord = &mesh->vertices.coord[4 * vta]; - // // STEP 2: for each face that does not see vta, delete the associated tet, and update the boundary of the cavity - // for (uint64_t curFace=0; curFace<local->ball.num; curFace++) { - // if(local->ball.array[curFace].node[2]==HXT_GHOST_VERTEX){ - // continue; - // } +// // // STEP 2: for each face that does not see vta, delete the associated tet, and update the boundary of the cavity +// // for (uint64_t curFace=0; curFace<local->ball.num; curFace++) { +// // if(local->ball.array[curFace].node[2]==HXT_GHOST_VERTEX){ +// // continue; +// // } - // double* b = &mesh->vertices.coord[4 * local->ball.array[curFace].node[0]]; - // double* c = &mesh->vertices.coord[4 * local->ball.array[curFace].node[1]]; - // double* d = &mesh->vertices.coord[4 * local->ball.array[curFace].node[2]]; - // if(orient3d(vtaCoord, b, c, d)<0.0){ - // continue; - // } +// // double* b = &mesh->vertices.coord[4 * local->ball.array[curFace].node[0]]; +// // double* c = &mesh->vertices.coord[4 * local->ball.array[curFace].node[1]]; +// // double* d = &mesh->vertices.coord[4 * local->ball.array[curFace].node[2]]; +// // if(orient3d(vtaCoord, b, c, d)<0.0){ +// // continue; +// // } - // // 2.1 update the facets so that no facet points to the current tet... does not work with our structure. SHITTT !! - // // => we are forced to use an O(n^2) algo if we do not want to use a super large table +// // // 2.1 update the facets so that no facet points to the current tet... does not work with our structure. SHITTT !! +// // // => we are forced to use an O(n^2) algo if we do not want to use a super large table - // // 2.2: undelete the tetrahedron - // uint64_t index = local->ball.array[curFace].neigh; - // uint64_t tetToUndelete = local->deleted.array[index / 4]; - // unsigned facet = index % 4; - // unsetDeletedFlag(mesh, tetToUndelete); +// // // 2.2: undelete the tetrahedron +// // uint64_t index = local->ball.array[curFace].neigh; +// // uint64_t tetToUndelete = local->deleted.array[index / 4]; +// // unsigned facet = index % 4; +// // unsetDeletedFlag(mesh, tetToUndelete); - // // second part: remove the faces of the tet that were on the boundary - // // do not forget to update curFace to point just before the next face to process - // uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; - // int nbndFace = 0; +// // // second part: remove the faces of the tet that were on the boundary +// // // do not forget to update curFace to point just before the next face to process +// // uint64_t bndFaces[4] = {HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT, HXT_NO_ADJACENT}; +// // int nbndFace = 0; - // // the way that the boundary faces are contructed, - // // TODO: use a bidirectional structure to be able to find the faces of deleted tet. +// // // the way that the boundary faces are contructed, +// // // TODO: use a bidirectional structure to be able to find the faces of deleted tet. - // // face to delete: curface +// // // face to delete: curface - // for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { - // if(mesh->tetrahedra.neigh[local->ball.array[i-1].neigh]/4==tetToUndelete) { - // bndFaces[nbndFace++] = local->ball.array[i-1].neigh; - // local->ball.num--; - // local->ball.array[i-1] = local->ball.array[local->ball.num]; - // } - // } +// // for (uint64_t i=local->ball.num; nbndFace<4 && i>0; i--) { +// // if(mesh->tetrahedra.neigh[local->ball.array[i-1].neigh]/4==tetToUndelete) { +// // bndFaces[nbndFace++] = local->ball.array[i-1].neigh; +// // local->ball.num--; +// // local->ball.array[i-1] = local->ball.array[local->ball.num]; +// // } +// // } - // // third part: add new facets to the boundary +// // // third part: add new facets to the boundary - // count++; - // } +// // count++; +// // } - // // if(count) - // // printf("nbr of tet to undelete = %lu, nbr of deleted tet = %lu\n", count, local->deleted.num); +// // // if(count) +// // // printf("nbr of tet to undelete = %lu, nbr of deleted tet = %lu\n", count, local->deleted.num); - // // // STEP 3: compute all the flags at once ! ?? +// // // // STEP 3: compute all the flags at once ! ?? - // STEP 4: put back the right neighbor value inside the ball struct - for(uint64_t i=0; i<local->ball.num; i++) { - uint64_t index = local->ball.array[i].neigh; - uint64_t interiorTet = tets[index / 4]; - unsigned facet = index % 4; - local->ball.array[i].neigh = mesh->tetrahedra.neigh[4 * interiorTet + facet]; - } +// // STEP 4: put back the right neighbor value inside the ball struct +// for(uint64_t i=0; i<local->ball.num; i++) { +// uint64_t index = local->ball.array[i].neigh; +// uint64_t interiorTet = tets[index / 4]; +// unsigned facet = index % 4; +// local->ball.array[i].neigh = mesh->tetrahedra.neigh[4 * interiorTet + facet]; +// } - HXT_CHECK( hxtFree(&faces) ); +// HXT_CHECK( hxtFree(&faces) ); uint64_t blindFace = 0;