diff --git a/src/fof.c b/src/fof.c index 47c718375bd7a2147d6d42dfdad58e794d7ea0a4..aa31e792a4ef3e95750562a73f7fa39edcc5b0c3 100644 --- a/src/fof.c +++ b/src/fof.c @@ -26,7 +26,7 @@ /* Local headers. */ //#include "active.h" -__attribute__((always_inline)) INLINE int fof_find(const int i, const int *pid) { +__attribute__((always_inline)) INLINE static int fof_find(const int i, const int *pid) { int root = i; while(root != pid[root]) @@ -43,6 +43,91 @@ __attribute__((always_inline)) INLINE int fof_find(const int i, const int *pid) return root; } +static void rec_fof_search_sub(struct cell *ci, struct cell *cj, struct space *s, int *pid, int *num_in_groups, int *num_groups, const double *dim, const double search_r2) { + + /* Recurse on cj. */ + if (cj->split) + for (int k = 0; k < 8; k++) + if (cj->progeny[k] != NULL) + rec_fof_search_sub(ci, cj->progeny[k], s, pid, num_in_groups, num_groups, dim, search_r2); + + /* No progeny? */ + if (!cj->split) { + const double cix = ci->loc[0]; + const double ciy = ci->loc[1]; + const double ciz = ci->loc[2]; + + const double cjx = cj->loc[0]; + const double cjy = cj->loc[1]; + const double cjz = cj->loc[2]; + + /* Find the shortest distance between cells, remembering to account for boundary conditions. */ + float dx[3], r2 = 0.0f; + dx[0] = min3(abs(nearest(cix - cjx, dim[0])), abs(nearest(cix - (cjx + cj->width[0]), dim[0])), abs(nearest((cix + ci->width[0]) - cjx, dim[0]))); + dx[0] = min(dx[0], abs(nearest((cix + ci->width[0]) - (cjx + cj->width[0]), dim[0]))); + + dx[1] = min3(abs(nearest(ciy - cjy, dim[1])), abs(nearest(ciy - (cjy + cj->width[1]), dim[1])), abs(nearest((ciy + ci->width[1]) - cjy, dim[1]))); + dx[1] = min(dx[1], abs(nearest((ciy + ci->width[1]) - (cjy + cj->width[1]), dim[1]))); + + dx[2] = min3(abs(nearest(ciz - cjz, dim[2])), abs(nearest(ciz - (cjz + cj->width[2]), dim[2])), abs(nearest((ciz + ci->width[2]) - cjz, dim[2]))); + dx[2] = min(dx[2], abs(nearest((ciz + ci->width[2]) - (cjz + cj->width[2]), dim[2]))); + + for (int k = 0; k < 3; k++) { + r2 += dx[k] * dx[k]; + } + + /* Perform FOF search between pairs of cells that are within the linking length and not the same cell. */ + if (r2 < search_r2 && ci != cj) { + fof_search_pair_cells(s, ci, cj, pid, num_in_groups, num_groups); + } + } +} + +static void rec_fof_search(struct cell *ci, const int cid, struct space *s, int *pid, int *num_in_groups, int *num_groups, const double *dim, const double search_r2) { + + /* Recurse on ci. */ + if (ci->split) + for (int k = 0; k < 8; k++) + if (ci->progeny[k] != NULL) + rec_fof_search(ci->progeny[k], cid, s, pid, num_in_groups, num_groups, dim, search_r2); + + /* No progeny? */ + if (!ci->split) { + const double cix = ci->loc[0]; + const double ciy = ci->loc[1]; + const double ciz = ci->loc[2]; + + /* Loop over all other top-level cells. */ + for(int cjd=cid + 1; cjd<s->nr_cells; cjd++) { + + struct cell *restrict cj = &s->cells_top[cjd]; + const double cjx = cj->loc[0]; + const double cjy = cj->loc[1]; + const double cjz = cj->loc[2]; + + /* Find the shortest distance between cells, remembering to account for boundary conditions. */ + float dx[3], r2 = 0.0f; + dx[0] = min3(abs(nearest(cix - cjx, dim[0])), abs(nearest(cix - (cjx + cj->width[0]), dim[0])), abs(nearest((cix + ci->width[0]) - cjx, dim[0]))); + dx[0] = min(dx[0], abs(nearest((cix + ci->width[0]) - (cjx + cj->width[0]), dim[0]))); + + dx[1] = min3(abs(nearest(ciy - cjy, dim[1])), abs(nearest(ciy - (cjy + cj->width[1]), dim[1])), abs(nearest((ciy + ci->width[1]) - cjy, dim[1]))); + dx[1] = min(dx[1], abs(nearest((ciy + ci->width[1]) - (cjy + cj->width[1]), dim[1]))); + + dx[2] = min3(abs(nearest(ciz - cjz, dim[2])), abs(nearest(ciz - (cjz + cj->width[2]), dim[2])), abs(nearest((ciz + ci->width[2]) - cjz, dim[2]))); + dx[2] = min(dx[2], abs(nearest((ciz + ci->width[2]) - (cjz + cj->width[2]), dim[2]))); + + for (int k = 0; k < 3; k++) r2 += dx[k] * dx[k]; + + /* If the leaf cell of ci is within the linking length of the top-level cell cj recurse on cj. Otherwise skip over cj as all of its leaf cells will also be out of range. */ + if (r2 > search_r2) continue; + else if(cj->split) rec_fof_search_sub(ci, cj, s, pid, num_in_groups, num_groups, dim, search_r2); + /* Perform FOF search between pairs of cells that are within the linking length and not the same cell. */ + else if(ci != cj) fof_search_pair_cells(s, ci, cj, pid, num_in_groups, num_groups); + + } + } +} + void fof_search_naive(struct space *s) { const size_t nr_gparts = s->nr_gparts; @@ -404,41 +489,17 @@ void fof_search_tree_serial(struct space *s) { /* Loop over cells and find which cells are in range of each other to perform the FOF search. */ for(int cid=0; cid<nr_cells; cid++) { - struct cell *restrict ci = &s->cells_top[cid]; - const double cix = ci->loc[0]; - const double ciy = ci->loc[1]; - const double ciz = ci->loc[2]; + struct cell *restrict c = &s->cells_top[cid]; - /* Perform FOF search on local particles within the cell. */ - fof_search_cell(s, ci, pid, num_in_groups, &num_groups); - - for(int cjd=cid + 1; cjd<nr_cells; cjd++) { - - struct cell *restrict cj = &s->cells_top[cjd]; - const double cjx = cj->loc[0]; - const double cjy = cj->loc[1]; - const double cjz = cj->loc[2]; + message("Searching top-level cell: %d.", cid); + fflush(stdout); - /* Find the shortest distance between cells, remembering to account for boundary conditions. */ - float dx[3], r2 = 0.0f; - dx[0] = min3(abs(nearest(cix - cjx, dim[0])), abs(nearest(cix - (cjx + cj->width[0]), dim[0])), abs(nearest((cix + ci->width[0]) - cjx, dim[0]))); - dx[0] = min(dx[0], abs(nearest((cix + ci->width[0]) - (cjx + cj->width[0]), dim[0]))); - - dx[1] = min3(abs(nearest(ciy - cjy, dim[1])), abs(nearest(ciy - (cjy + cj->width[1]), dim[1])), abs(nearest((ciy + ci->width[1]) - cjy, dim[1]))); - dx[1] = min(dx[1], abs(nearest((ciy + ci->width[1]) - (cjy + cj->width[1]), dim[1]))); - - dx[2] = min3(abs(nearest(ciz - cjz, dim[2])), abs(nearest(ciz - (cjz + cj->width[2]), dim[2])), abs(nearest((ciz + ci->width[2]) - cjz, dim[2]))); - dx[2] = min(dx[2], abs(nearest((ciz + ci->width[2]) - (cjz + cj->width[2]), dim[2]))); + /* Perform FOF search on local particles within the cell. */ + fof_search_cell(s, c, pid, num_in_groups, &num_groups); - for (int k = 0; k < 3; k++) { - r2 += dx[k] * dx[k]; - } + /* Recursively perform FOF search on all other cells in top-level grid. */ + rec_fof_search(c, cid, s, pid, num_in_groups, &num_groups, dim, search_r2); - /* Perform FOF search between pairs of cells that are within the linking length. */ - if (r2 < search_r2) { - fof_search_pair_cells(s, ci, cj, pid, num_in_groups, &num_groups); - } - } } fof_dump_group_data("fof_output_tree_serial.dat", nr_gparts, pid, num_in_groups);