diff --git a/src/fof.c b/src/fof.c index 8a7635f424fa326eb35d174f31a522db7db26fcf..f71b9714ff0fe0fd68b4d4e67a71139ab0d1db4e 100644 --- a/src/fof.c +++ b/src/fof.c @@ -810,6 +810,8 @@ void fof_search_foreign_cells(struct space *s) { struct engine *e = s->e; struct cell *cells = s->cells_top; int *group_index = s->fof_data.group_index; + int *group_size = s->fof_data.group_size; + const int nr_gparts = s->nr_gparts; const size_t nr_cells = s->nr_cells; const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]}; const double search_r2 = s->l_x2; @@ -820,7 +822,7 @@ void fof_search_foreign_cells(struct space *s) { int count = 0; /* Make group IDs globally unique. */ - for (size_t i = 0; i < s->nr_gparts; i++) group_index[i] += node_offset; + for (size_t i = 0; i < nr_gparts; i++) group_index[i] += node_offset; /* Loop over top-level cells and find local cells that touch foreign cells. Calculate the total number of possible links between these cells. */ for (size_t cid = 0; cid < nr_cells; cid++) { @@ -952,12 +954,12 @@ void fof_search_foreign_cells(struct space *s) { if(foreign_cell->nodeID == engine_rank) error("Rank %d. Foreign cell is actually local.", engine_rank); - if(gparts[0].root >= node_offset && gparts[0].root < node_offset + s->nr_gparts) { + if(gparts[0].root >= node_offset && gparts[0].root < node_offset + nr_gparts) { //error("Rank %d received foreign particle with local root: %d", engine_rank, gparts[k].root); //message("Rank %d received foreign particle %lld from rank %d with a local root: %d. i=%d,j=%d.", engine_rank, gparts[0].id_or_neg_offset, foreign_cell->nodeID, gparts[0].root, i, j); } for(int k=0; k<foreign_cell->gcount; k++) { - if(gparts[k].root >= node_offset && gparts[k].root < node_offset + s->nr_gparts) { + if(gparts[k].root >= node_offset && gparts[k].root < node_offset + nr_gparts) { //error("Rank %d received foreign particle with local root: %d", engine_rank, gparts[k].root); //message("Rank %d received foreign particle %lld from rank %d with a local root: %d. i=%d,j=%d,k=%d.", engine_rank, gparts[k].id_or_neg_offset, foreign_cell->nodeID, gparts[k].root, i, j, k); } @@ -1019,6 +1021,7 @@ void fof_search_foreign_cells(struct space *s) { /* If it doesn't already exist in the list add it. */ if(!found) { group_links[group_link_count].group_i = local_root; + group_links[group_link_count].group_i_size = group_size[local_root - node_offset]; group_links[group_link_count++].group_j = foreign_root; } @@ -1026,21 +1029,27 @@ void fof_search_foreign_cells(struct space *s) { message("Rank %d found %d unique group links.", engine_rank, group_link_count); - struct fof_mpi *global_group_links = NULL, *global_group_roots = NULL; + struct fof_mpi *global_all_group_links = NULL, *global_group_links = NULL, *global_group_roots = NULL; int *displ = NULL, *group_link_counts = NULL; + int global_all_group_link_count = 0; int global_group_link_count = 0; /* Sum the total number of links across MPI domains over each MPI rank. */ - MPI_Allreduce(&group_link_count, &global_group_link_count, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); - - message("Global list count: %d", global_group_link_count); + MPI_Allreduce(&group_link_count, &global_all_group_link_count, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + + message("Global list count: %d", global_all_group_link_count); + + if (posix_memalign((void**)&global_all_group_links, SWIFT_STRUCT_ALIGNMENT, + global_all_group_link_count * sizeof(struct fof_mpi)) != 0) + error("Error while allocating memory for the global list of group links"); + /* Unique set of links is half of all group links as each link is found twice by opposing MPI ranks. */ if (posix_memalign((void**)&global_group_links, SWIFT_STRUCT_ALIGNMENT, - global_group_link_count * sizeof(struct fof_mpi)) != 0) + global_all_group_link_count / 2 * sizeof(struct fof_mpi)) != 0) error("Error while allocating memory for the global list of group links"); if (posix_memalign((void**)&global_group_roots, SWIFT_STRUCT_ALIGNMENT, - global_group_link_count * sizeof(struct fof_mpi)) != 0) + global_all_group_link_count * sizeof(struct fof_mpi)) != 0) error("Error while allocating memory for the global list of group links"); if (posix_memalign((void**)&group_link_counts, SWIFT_STRUCT_ALIGNMENT, @@ -1059,7 +1068,7 @@ void fof_search_foreign_cells(struct space *s) { for(int i=1; i<e->nr_nodes; i++) displ[i] = displ[i-1] + group_link_counts[i-1]; /* Gather the global link list on all ranks. */ - MPI_Allgatherv(group_links, group_link_count, fof_mpi_type, global_group_links, group_link_counts, displ, fof_mpi_type, MPI_COMM_WORLD); + MPI_Allgatherv(group_links, group_link_count, fof_mpi_type, global_all_group_links, group_link_counts, displ, fof_mpi_type, MPI_COMM_WORLD); /* Save particle links for each rank to a file. */ char fof_filename[200] = "part_links"; @@ -1070,15 +1079,45 @@ void fof_search_foreign_cells(struct space *s) { fprintf(fof_file, "# %7s %7s %7s\n", "Local PID", "Foreign PID", "Root ID"); fprintf(fof_file, "#-------------------------------\n"); - for(int i=0; i<global_group_link_count; i++) { - fprintf(fof_file, " %7d <-> %7d\n", global_group_links[i].group_i, global_group_links[i].group_j); + for(int i=0; i<global_all_group_link_count; i++) { + fprintf(fof_file, " %7d (%7d) <-> %7d\n", global_all_group_links[i].group_i, global_all_group_links[i].group_i_size, global_all_group_links[i].group_j); } fclose(fof_file); + /* Compress the list of group links across an MPI domain by removing the symmetric cases. */ + for(int i=0; i<global_all_group_link_count; i++) { + + int found = 0; + int local_root = global_all_group_links[i].group_i; + int foreign_root = global_all_group_links[i].group_j; + + if(local_root == foreign_root) error("Particles have same root. local_root: %d, foreign_root: %d", local_root, foreign_root); + + /* Loop over list and check that the link doesn't already exist. */ + for(int j=0; j<global_all_group_link_count; j++) { + if((global_group_links[j].group_i == local_root && global_group_links[j].group_j == foreign_root) || + (global_group_links[j].group_j == local_root && global_group_links[j].group_i == foreign_root)) { + found = 1; + break; + } + } + + /* If it doesn't already exist in the list add it. */ + if(!found) { + global_group_links[global_group_link_count].group_i = local_root; + global_group_links[global_group_link_count].group_i_size = group_size[local_root - node_offset]; + global_group_links[global_group_link_count++].group_j = foreign_root; + } + + } + + message("Reduced global list count: %d", global_group_link_count); + /* Copy the initial roots from the group list. */ for(int i=0; i<global_group_link_count; i++) { global_group_roots[i].group_i = global_group_links[i].group_i; + global_group_roots[i].group_i_size = global_group_links[i].group_i_size; global_group_roots[i].group_j = global_group_links[i].group_j; } @@ -1086,6 +1125,8 @@ void fof_search_foreign_cells(struct space *s) { for(int i=0; i<global_group_link_count; i++) { int group_i = global_group_links[i].group_i; int group_j = global_group_links[i].group_j; + int group_i_count = global_group_links[i].group_i_size; + //int group_j_count = 0; if(group_i == group_j) error("Particles have same root. local_root: %d, foreign_root: %d", group_i, group_j); @@ -1111,7 +1152,7 @@ void fof_search_foreign_cells(struct space *s) { message("Rank %d. Link %d <-> %d has common lowest root: %d", engine_rank, group_i, group_j, min_root); /* If group_i is local to the node, update its root. */ - if((group_i >= node_offset && group_i < node_offset + s->nr_gparts) && + if((group_i >= node_offset && group_i < node_offset + nr_gparts) && (group_i != min_root)) { int root = group_index[group_i - node_offset]; @@ -1120,9 +1161,13 @@ void fof_search_foreign_cells(struct space *s) { else error("Rank %d. Group_i: %d Trying to set a root: %d to a larger value: %d", engine_rank, group_i, root, min_root); } + + if(min_root >= node_offset && min_root < node_offset + nr_gparts) { + group_size[min_root - node_offset] += group_i_count; + } /* If group_j is local to the node, update its root. */ - if((group_j >= node_offset && group_j < node_offset + s->nr_gparts) && + if((group_j >= node_offset && group_j < node_offset + nr_gparts) && (group_j != min_root)) { int root = group_index[group_j - node_offset]; @@ -1136,12 +1181,12 @@ void fof_search_foreign_cells(struct space *s) { int old_group_j = global_group_roots[i].group_j; /* If the group had an old root that was local, make sure it is also updated. */ - if(old_group_i >= node_offset && old_group_i < node_offset + s->nr_gparts) { + if(old_group_i >= node_offset && old_group_i < node_offset + nr_gparts) { if(min_root < old_group_i) group_index[old_group_i - node_offset] = min_root; } - if(old_group_j >= node_offset && old_group_j < node_offset + s->nr_gparts) { + if(old_group_j >= node_offset && old_group_j < node_offset + nr_gparts) { if(min_root < old_group_j) group_index[old_group_j - node_offset] = min_root; } @@ -1159,6 +1204,21 @@ void fof_search_foreign_cells(struct space *s) { } } + /* Save particle links for each rank to a file. */ + char fof_size_filename[200] = "group_sizes"; + sprintf(fof_size_filename + strlen(fof_size_filename), "_%d.dat", + engine_rank); + + fof_file = fopen(fof_size_filename, "w"); + fprintf(fof_file, "# %7s %7s\n", "Root ID", "Group Size"); + fprintf(fof_file, "#-------------------------------\n"); + + for(int i=0; i<nr_gparts; i++) { + fprintf(fof_file, " %7d %7d\n", i + node_offset, group_size[i]); + } + + fclose(fof_file); + /* Clean up memory. */ free(part_links); free(interface_cells); @@ -1181,8 +1241,7 @@ void fof_search_tree(struct space *s) { const size_t nr_cells = s->nr_cells; struct gpart *gparts = s->gparts; long long *group_id; - int *group_index; - int *group_size; + int *group_index, *group_size; float *group_mass; int num_groups = 0; ticks tic = getticks(); @@ -1262,10 +1321,10 @@ void fof_search_tree(struct space *s) { #ifdef WITH_MPI /* Calculate the total number of particles in each group, group mass and the total number of groups. */ - //for (size_t i = 0; i < nr_gparts; i++) { - // int root = fof_find_global(i - node_offset, group_index); - // group_size[root - node_offset]++; - //} + for (size_t i = 0; i < nr_gparts; i++) { + int root = fof_find(i, group_index); + group_size[root]++; + } if (s->e->nr_nodes > 1) { /* Find any particle links with other nodes. */ @@ -1282,11 +1341,10 @@ void fof_search_tree(struct space *s) { /* Calculate the total number of particles in each group, group mass and the total number of groups. */ for (size_t i = 0; i < nr_gparts; i++) { int root = fof_find(i, group_index); - if(root >= node_offset) root -= node_offset; group_size[root]++; group_mass[root] += gparts[i].mass; - if(group_index[i] == (int)(i + node_offset)) num_groups++; - //group_id[i] = group_id[root - node_offset]; + if(group_index[i] == i) num_groups++; + //group_id[i] = group_id[root]; group_id[i] = gparts[i].id_or_neg_offset; } #endif @@ -1333,8 +1391,13 @@ void fof_search_tree(struct space *s) { global_group_size[root]++; if(global_group_index[i] == i) total_num_groups++; } - + if(engine_rank == 0) { + + int num_parts = 0; + + for (size_t i = 0; i < s->e->total_nr_gparts; i++) num_parts += global_group_size[i]; + fof_file = fopen("global_group_index.dat", "w"); fprintf(fof_file, "# %7s %7s\n", "Index", "Group ID"); fprintf(fof_file, "#-------------------------------\n"); @@ -1347,6 +1410,8 @@ void fof_search_tree(struct space *s) { fof_dump_group_data(output_file_name, s->e->total_nr_gparts, global_group_index, global_group_size, global_group_id); + message("Total no. of particles in groups: %d.", num_parts); + } int num_groups_mpi = 0;