From 5e2ea76ff664a736b1c57e4072f81cac37057b40 Mon Sep 17 00:00:00 2001
From: James Willis <james.s.willis@durham.ac.uk>
Date: Sun, 19 Aug 2018 16:09:25 +0100
Subject: [PATCH] Group sizes are now updated from groups over MPI domains.

---
 src/fof.c | 120 +++++++++++++++++++++++++-----------------------------
 src/fof.h |   3 ++
 2 files changed, 58 insertions(+), 65 deletions(-)

diff --git a/src/fof.c b/src/fof.c
index 27337ce59c..e70b87e0e9 100644
--- a/src/fof.c
+++ b/src/fof.c
@@ -1029,7 +1029,7 @@ 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, *global_group_size_roots = NULL;
+  struct fof_mpi *global_group_links = NULL;
   int *displ = NULL, *group_link_counts = NULL;
   int global_group_link_count = 0;
 
@@ -1043,14 +1043,6 @@ void fof_search_foreign_cells(struct space *s) {
                        global_group_link_count * 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)
-    error("Error while allocating memory for the global list of group links");
- 
-  if (posix_memalign((void**)&global_group_size_roots, SWIFT_STRUCT_ALIGNMENT,
-                       global_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,
                        e->nr_nodes * sizeof(int)) != 0)
     error("Error while allocating memory for the number of group links on each MPI rank");
@@ -1084,37 +1076,9 @@ void fof_search_foreign_cells(struct space *s) {
   
   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);
 
-  int *global_group_index = NULL, *global_group_id = NULL;
-
+  int *global_group_index = NULL, *global_group_id = NULL, *global_group_size = NULL;
   int group_count = 0;
 
   if (posix_memalign((void**)&global_group_index, SWIFT_STRUCT_ALIGNMENT,
@@ -1125,8 +1089,14 @@ void fof_search_foreign_cells(struct space *s) {
                       global_group_link_count  * sizeof(int)) != 0)
     error("Error while allocating memory for the displacement in memory for the global group link list");
   
+  if (posix_memalign((void**)&global_group_size, SWIFT_STRUCT_ALIGNMENT,
+                      global_group_link_count  * sizeof(int)) != 0)
+    error("Error while allocating memory for the displacement in memory for the global group link list");
+  
+  bzero(global_group_size, global_group_link_count * sizeof(int));
 
   /* Compress the list of group links across an MPI domain by removing the symmetric cases. */
+  /* Store each group ID once along with its size. */
   for(int i=0; i<global_group_link_count; i++) {
     
     int found_i = 0, found_j = 0;
@@ -1150,21 +1120,49 @@ void fof_search_foreign_cells(struct space *s) {
 
     /* If it doesn't already exist in the list add it. */
     if(!found_i) {
+      global_group_size[group_count] += global_group_links[i].group_i_size;
       global_group_id[group_count++] = group_i;
     }
     
     if(!found_j) {
+      /* Need to search for group_j sizes as the group size is only known on the local node. */
+      for(int j=0; j<global_group_link_count; j++) {
+        if(global_group_links[j].group_i == group_j) {
+          global_group_size[group_count] += global_group_links[j].group_i_size;
+          break;
+        }
+      }
+
       global_group_id[group_count++] = group_j;
     }
 
   }
 
+  /* Create a global_group_index list of groups across MPI domains so that you can perform a union-find locally on each node. */
+  /* The value of which is an offset into global_group_id, which is the actual root. */
   for(int i=0; i<group_count; i++) global_group_index[i] = i;
 
+  /* Save group links for each rank to a file. */
+  char fof_map_filename[200] = "group_map";
+  sprintf(fof_map_filename + strlen(fof_map_filename), "_%d.dat",
+      engine_rank);
+  
+  fof_file = fopen(fof_map_filename, "w");
+  fprintf(fof_file, "# %7s %7s %7s\n", "Index", "Group ID", "Group Size");
+  fprintf(fof_file, "#-------------------------------\n");
+
+  for(int i=0; i<group_count; i++) {
+    fprintf(fof_file, "  %7d %7d %7d\n", global_group_index[i], global_group_id[i], global_group_size[i]);
+  }
+  
+  fclose(fof_file);
+
+  /* Perform a union-find on the group links. */
   for(int i=0; i<global_group_link_count; i++) {
   
     int find_i = 0, find_j = 0;
 
+    /* Find group offset into global_group_id */
     for(int j=0; j<group_count; j++) {  
       if(global_group_id[j] == global_group_links[i].group_i) {
         find_i = j;
@@ -1179,48 +1177,40 @@ void fof_search_foreign_cells(struct space *s) {
       }
     }
 
+    /* Use the offset to find the group's root. */
     int root_i = fof_find(find_i, global_group_index);
     int root_j = fof_find(find_j, global_group_index);
     
     int group_i = global_group_id[root_i];
     int group_j = global_group_id[root_j];
 
+    /* Update roots accordingly. */
     if(group_j < group_i) global_group_index[root_i] = root_j;
     else global_group_index[root_j] = root_i;
 
   }
 
-
+  /* Update each group locally with new root information. */
   for(int i=0; i<group_count; i++) {
     
     int group_id = global_group_id[i];
+    int new_root = global_group_id[fof_find(global_group_index[i], global_group_index)];
     
-    if(group_id >= node_offset && group_id < node_offset + nr_gparts) {
-      
-      int old_root = group_index[group_id - node_offset];
-      int new_root = global_group_id[global_group_index[i]];
-
-      if(old_root >= new_root) group_index[group_id - node_offset] = new_root;
-      else error("Rank %d. Group_j: %d Trying to set a root: %d to a larger value: %d", engine_rank, group_id, old_root, new_root);
+    /* If the group is local update its root and size. */
+    if(group_id >= node_offset && group_id < node_offset + nr_gparts &&
+       new_root != group_id) {
+        group_index[group_id - node_offset] = new_root;
+        group_size[group_id - node_offset] -= global_group_size[i];
+    }
+     
+    /* If the group linked to a local root update its size. */
+    if(new_root >= node_offset && new_root < node_offset + nr_gparts &&
+       new_root != group_id) {
+      group_size[new_root - node_offset] += global_group_size[i];
     }
 
   }
 
-  /* Save particle links for each rank to a file. */
-  char fof_map_filename[200] = "group_map";
-  sprintf(fof_map_filename + strlen(fof_map_filename), "_%d.dat",
-      engine_rank);
-  
-  fof_file = fopen(fof_map_filename, "w");
-  fprintf(fof_file, "# %7s %7s\n", "Index", "Group ID");
-  fprintf(fof_file, "#-------------------------------\n");
-
-  for(int i=0; i<group_count; i++) {
-    fprintf(fof_file, "  %7d %7d\n", global_group_index[i], global_group_id[i]);
-  }
-  
-  fclose(fof_file);
-
   /* 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",
@@ -1241,8 +1231,10 @@ void fof_search_foreign_cells(struct space *s) {
   free(interface_cells);
   free(group_links);
   free(global_group_links);
-  free(global_group_roots);
   free(displ);
+  free(global_group_index);
+  free(global_group_size);
+  free(global_group_id);
 
   message("Rank %d finished linking local roots to foreign roots.", engine_rank);
 
@@ -1399,13 +1391,11 @@ void fof_search_tree(struct space *s) {
 
     MPI_Gatherv(group_index, nr_gparts, MPI_INT, global_group_index, global_nr_gparts, displ, MPI_INT, 0, MPI_COMM_WORLD);
     MPI_Gatherv(group_id, nr_gparts, MPI_LONG_LONG, global_group_id, global_nr_gparts, displ, MPI_LONG_LONG, 0, MPI_COMM_WORLD);
-    MPI_Gatherv(group_size, nr_gparts, MPI_INT, global_group_size, global_nr_gparts, displ, MPI_INT, 0, MPI_COMM_WORLD);
+    //MPI_Gatherv(group_size, nr_gparts, MPI_INT, global_group_size, global_nr_gparts, displ, MPI_INT, 0, MPI_COMM_WORLD);
 
     total_num_groups = 0;
 
     for (size_t i = 0; i < s->e->total_nr_gparts; i++) {
-      //const int root = fof_find(i, global_group_index);
-      //global_group_size[root]++;
       if(global_group_index[i] == i) total_num_groups++;
     }
     
diff --git a/src/fof.h b/src/fof.h
index 1442b30320..4e1c575eb8 100644
--- a/src/fof.h
+++ b/src/fof.h
@@ -33,6 +33,9 @@ struct fof_mpi {
   /* The local particle's root ID.*/
   int group_i;
 
+  /* The local group's size.*/
+  int group_i_size;
+
   /* The foreign particle's root ID.*/
   int group_j;
 
-- 
GitLab