Skip to content
Snippets Groups Projects
Select Git revision
  • 702f09d8379b3d8fdcf4e87ab8091fa7abd6ec9c
  • master default protected
  • darwin/gear_preSN_feedback
  • zoom-missing-rebuild-time
  • reyz/gear_preSN_feedback
  • darwin/sink_tasks_refactored
  • darwin/gear_radiation
  • darwin/gear_preSN_fbk_merge
  • darwin/gear_mechanical_feedback
  • darwin/gear_chemistry_fluxes
  • zoom_merge protected
  • nickishch/MHD_canvas/SwitchesGradientProjection
  • zoom_mpi_redux
  • MHD_canvas protected
  • karapiperis/plasma_beta_rms_in_tensile_instability_correction_taper_function
  • nickishch/MHD_canvas/OWAR_rhob_div_rhob
  • nickishch/MHD_canvas/OWAR_induction_only
  • nickishch/MHD_canvas/OWAR
  • nickishch/MHD_canvas/Switches
  • zoom_truncate_bkg
  • split-space-split
  • v2025.04 protected
  • v2025.01 protected
  • v1.0.0 protected
  • v0.9.0 protected
  • v0.8.5 protected
  • v0.8.4 protected
  • v0.8.3 protected
  • v0.8.2 protected
  • v0.8.1 protected
  • v0.8.0 protected
  • v0.7.0 protected
  • v0.6.0 protected
  • v0.5.0 protected
  • v0.4.0 protected
  • v0.3.0 protected
  • v0.2.0 protected
  • v0.1.0-pre protected
  • v0.1 protected
  • v0.0 protected
40 results

cooling_struct.h

Blame
  • fof.c 17.27 KiB
    /*******************************************************************************
     * This file is part of SWIFT.
     * Copyright (c) 2018 James Willis (james.s.willis@durham.ac.uk)
     *
     * This program is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Lesser General Public License as published
     * by the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     *
     * This program 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 Lesser General Public License
     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     *
     ******************************************************************************/
    
    /* Config parameters. */
    #include "../config.h"
    
    /* This object's header. */
    #include "fof.h"
    
    /* Local headers. */
    //#include "active.h"
    
    __attribute__((always_inline)) INLINE static int fof_find(const int i, int *pid) {
        
      int root = i;
      while(root != pid[root])
        root = pid[root];
    
      /* Perform path compression. */
      //int index = i;
      //while(index != root) {
      //  int next = pid[index];
      //  pid[index] = root;
      //  index = next;
      //}
      
      return root;
    }
    
    /* Find the shortest distance between cells, remembering to account for boundary conditions. */
    __attribute__((always_inline)) INLINE static double cell_min_dist(const struct cell *ci, const struct cell *cj, const double cix, const double ciy, const double ciz, const double *dim) {
    
      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. */
      double 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];
    
      return r2;
    }
    
    /* Recurse on a cell and perform a FOF search between cells that are within range. */
    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];
    
        /* Find the shortest distance between cells, remembering to account for boundary conditions. */
        const double r2 = cell_min_dist(ci, cj, cix, ciy, ciz, dim);
    
        /* 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);
        }
      }
    }
    
    /* Recurse on a top-level cell and perform a search of all other top-level cells. Recurse on top-level cells that are within range and perform a FOF search between cells. */
    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];
    
        /* Perform FOF search on local particles within the cell. */
        fof_search_cell(s, ci, pid, num_in_groups, num_groups);
        
        /* Loop over all top-level cells skipping over the cells already searched. */
        for(int cjd=cid; cjd<s->nr_cells; cjd++) {      
    
          struct cell *restrict cj = &s->cells_top[cjd];
    
          /* Find the shortest distance between cells, remembering to account for boundary conditions. */
          const double r2 = cell_min_dist(ci, cj, cix, ciy, ciz, dim);
          
          /* 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;
      struct gpart *gparts = s->gparts;
      const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
      const double l_x2 = s->l_x2;
      int *pid;
      int *num_in_groups;
      int num_groups = nr_gparts;
    
      message("Searching %ld gravity particles for links with l_x2: %lf", nr_gparts, l_x2);
    
      /* Allocate and populate array of particle group IDs. */
      if (posix_memalign((void **)&pid, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of particle group IDs for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) pid[i] = i;    
    
      if (posix_memalign((void **)&num_in_groups, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of number in groups for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) num_in_groups[i] = 1;    
    
      for(size_t runs=0; runs<2; runs++) 
      /* Loop over particles and find which particles belong in the same group. */
      for(size_t i=0; i<nr_gparts; i++) {
      
        //message("Searching for particle: %ld groups.", i);
    
        struct gpart *pi = &gparts[i];
        const double pix = pi->x[0];
        const double piy = pi->x[1];
        const double piz = pi->x[2];
    
        for(size_t j=0; j<nr_gparts; j++) { 
    
          /* Skip yourself. */
          if(i == j) continue;
    
          struct gpart *pj = &gparts[j];
          const double pjx = pj->x[0];
          const double pjy = pj->x[1];
          const double pjz = pj->x[2];
    
          /* Compute pairwise distance, remembering to account for boundary conditions. */
          float dx[3], r2 = 0.0f;
          dx[0] = pix - pjx;
          dx[1] = piy - pjy;
          dx[2] = piz - pjz;
    
          for (int k = 0; k < 3; k++) {
            dx[k] = nearest(dx[k], dim[k]);
            r2 += dx[k] * dx[k];
          }
    
          /* Hit or miss? */
          if (r2 < l_x2 && pid[j] < pid[i]) {
    
            num_in_groups[pid[i]]--;
            num_in_groups[pid[j]]++;
            
            pid[i] = pid[j]; 
    
            num_groups--;
          }
        }
      }
    
      fof_dump_group_data("fof_output_naive.dat", nr_gparts, pid, num_in_groups);
      
      int num_parts_in_groups = 0;
      int max_group_size = 0, max_group_id = 0;
      for(size_t i=0; i<nr_gparts; i++) {
    
          if(num_in_groups[i] > 1) num_parts_in_groups += num_in_groups[i];
          if( num_in_groups[i] > max_group_size) {
            max_group_size = num_in_groups[i];
            max_group_id = i;
          }
      }
      
      message("No. of groups: %d. No. of particles in groups: %d. No. of particles not in groups: %ld.", num_groups, num_parts_in_groups, nr_gparts - num_parts_in_groups);
      message("Biggest group size: %d with ID: %d", max_group_size, max_group_id);
    
      free(pid);
      free(num_in_groups);
    }
    
    void fof_search_serial(struct space *s) {
    
      const size_t nr_gparts = s->nr_gparts;
      struct gpart *gparts = s->gparts;
      const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
      const double l_x2 = s->l_x2;
      int *pid;
      int *num_in_groups;
      int num_groups = nr_gparts;
    
      message("Searching %ld gravity particles for links with l_x2: %lf", nr_gparts, l_x2);
    
      /* Allocate and populate array of particle group IDs. */
      if (posix_memalign((void **)&pid, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of particle group IDs for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) pid[i] = i;    
    
      if (posix_memalign((void **)&num_in_groups, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of number in groups for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) num_in_groups[i] = 1;    
    
      /* Loop over particles and find which particles belong in the same group. */
      for(size_t i=0; i<nr_gparts; i++) {
      
        struct gpart *pi = &gparts[i];
        const double pix = pi->x[0];
        const double piy = pi->x[1];
        const double piz = pi->x[2];
    
        for(size_t j=i+1; j<nr_gparts; j++) { 
    
          /* Find the roots of pi and pj. */
          const int root_i = fof_find(i, pid);
          const int root_j = fof_find(j, pid);
          
          /* Skip particles in the same group. */
          if (root_i == root_j) continue;
    
          struct gpart *pj = &gparts[j];
          const double pjx = pj->x[0];
          const double pjy = pj->x[1];
          const double pjz = pj->x[2];
    
          /* Compute pairwise distance, remembering to account for boundary conditions. */
          float dx[3], r2 = 0.0f;
          dx[0] = pix - pjx;
          dx[1] = piy - pjy;
          dx[2] = piz - pjz;
    
          for (int k = 0; k < 3; k++) {
            dx[k] = nearest(dx[k], dim[k]);
            r2 += dx[k] * dx[k];
          }
    
          /* Hit or miss? */
          if (r2 < l_x2)  {
    
            if(root_j < root_i) {
              pid[root_i] = root_j; 
              num_in_groups[root_j] += num_in_groups[root_i];
              num_in_groups[root_i] -= num_in_groups[root_i];
            }
            else {
              pid[root_j] = root_i;
              num_in_groups[root_i] += num_in_groups[root_j];
              num_in_groups[root_j] -= num_in_groups[root_j];
            }
            
            num_groups--;
          }
        }
      }
    
      fof_dump_group_data("fof_output_serial.dat", nr_gparts, pid, num_in_groups);
    
      int num_parts_in_groups = 0;
      int max_group_size = 0, max_group_id = 0;
      for(size_t i=0; i<nr_gparts; i++) {
    
          if(num_in_groups[i] > 1) num_parts_in_groups += num_in_groups[i];
          if( num_in_groups[i] > max_group_size) {
            max_group_size = num_in_groups[i];
            max_group_id = i;
          }
      }
    
      message("No. of groups: %d. No. of particles in groups: %d. No. of particles not in groups: %ld.", num_groups, num_parts_in_groups, nr_gparts - num_parts_in_groups);
      message("Biggest group size: %d with ID: %d", max_group_size, max_group_id);
    
      free(pid);
      free(num_in_groups);
    }
    
    void fof_search_cell(struct space *s, struct cell *c, int *pid, int *num_in_groups, int *num_groups) {
    
      const size_t count = c->gcount;
      struct gpart *gparts = c->gparts;
      const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
      const double l_x2 = s->l_x2;
    
      /* Loop over particles and find which particles belong in the same group. */
      for(size_t i=0; i<count; i++) {
      
        struct gpart *pi = &gparts[i];
        const double pix = pi->x[0];
        const double piy = pi->x[1];
        const double piz = pi->x[2];
        const size_t offset_i = pi->offset;
    
        for(size_t j=i+1; j<count; j++) { 
    
          struct gpart *pj = &gparts[j];
          const double pjx = pj->x[0];
          const double pjy = pj->x[1];
          const double pjz = pj->x[2];
          const size_t offset_j = pj->offset;
    
          /* Compute pairwise distance, remembering to account for boundary conditions. */
          float dx[3], r2 = 0.0f;
          dx[0] = pix - pjx;
          dx[1] = piy - pjy;
          dx[2] = piz - pjz;
    
          for (int k = 0; k < 3; k++) {
            dx[k] = nearest(dx[k], dim[k]);
            r2 += dx[k] * dx[k];
          }
    
          /* Find the roots of pi and pj. */
          const int root_i = fof_find(offset_i, pid);
          const int root_j = fof_find(offset_j, pid);
          
          /* Skip particles in the same group. */
          if (root_i == root_j) continue;
    
          /* Hit or miss? */
          if (r2 < l_x2)  {
    
            if(root_j < root_i) {
              pid[root_i] = root_j; 
              num_in_groups[root_j] += num_in_groups[root_i];
              num_in_groups[root_i] -= num_in_groups[root_i];
            }
            else {
              pid[root_j] = root_i;
              num_in_groups[root_i] += num_in_groups[root_j];
              num_in_groups[root_j] -= num_in_groups[root_j];
            }
            
            (*num_groups)--;
          }
        }
      }
    
    }
    
    void fof_search_pair_cells(struct space *s, struct cell *ci, struct cell *cj, int *pid, int *num_in_groups, int *num_groups) {
    
      const size_t count_i = ci->gcount;
      const size_t count_j = cj->gcount;
      struct gpart *gparts_i = ci->gparts;
      struct gpart *gparts_j = cj->gparts;
      const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
      const double l_x2 = s->l_x2;
    
      /* Account for boundary conditions.*/
      double shift[3] = {0.0, 0.0, 0.0};
      
      /* Get the relative distance between the pairs, wrapping. */
      const int periodic = s->periodic;
      double diff[3];
      for (int k = 0; k < 3; k++) {
        diff[k] = cj->loc[k] - ci->loc[k];
        if (periodic && diff[k] < -dim[k] / 2)
          shift[k] = dim[k];
        else if (periodic && diff[k] > dim[k] / 2)
          shift[k] = -dim[k];
        else
          shift[k] = 0.0;
        diff[k] += shift[k];
      }
     
      /* Loop over particles and find which particles belong in the same group. */
      for(size_t i=0; i<count_i; i++) {
      
        struct gpart *pi = &gparts_i[i];
        const double pix = pi->x[0] - shift[0];
        const double piy = pi->x[1] - shift[1];
        const double piz = pi->x[2] - shift[2];
        const size_t offset_i = pi->offset;
    
        for(size_t j=0; j<count_j; j++) { 
    
          struct gpart *pj = &gparts_j[j];
          const size_t offset_j = pj->offset;
          
          /* Find the roots of pi and pj. */
          const int root_i = fof_find(offset_i, pid);
          const int root_j = fof_find(offset_j, pid);
          
          /* Skip particles in the same group. */
          if (root_i == root_j) continue;
    
          /* Compute pairwise distance, remembering to account for boundary conditions. */
          const double pjx = pj->x[0];
          const double pjy = pj->x[1];
          const double pjz = pj->x[2];
    
          float dx[3], r2 = 0.0f;
          dx[0] = pix - pjx;
          dx[1] = piy - pjy;
          dx[2] = piz - pjz;
    
          for (int k = 0; k < 3; k++) r2 += dx[k] * dx[k];
    
          /* Hit or miss? */
          if (r2 < l_x2)  {
    
            if(root_j < root_i) {
              pid[root_i] = root_j; 
              num_in_groups[root_j] += num_in_groups[root_i];
              num_in_groups[root_i] -= num_in_groups[root_i];
            }
            else {
              pid[root_j] = root_i;
              num_in_groups[root_i] += num_in_groups[root_j];
              num_in_groups[root_j] -= num_in_groups[root_j];
            }
            
            (*num_groups)--;
          }
        }
      }
    
    }
    
    void fof_search_tree_serial(struct space *s) {
    
      const size_t nr_gparts = s->nr_gparts;
      const size_t nr_cells = s->nr_cells;
      int *pid, *num_in_groups;
      int num_groups = nr_gparts;
      struct gpart *gparts = s->gparts;
      const double dim[3] = {s->dim[0], s->dim[1], s->dim[2]};
      const double search_r2 = s->l_x2;
    
      message("Searching %ld gravity particles for links with l_x2: %lf", nr_gparts, s->l_x2);
    
      /* Allocate and populate array of particle group IDs. */
      if (posix_memalign((void **)&pid, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of particle group IDs for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) {
        gparts[i].offset = i;
        pid[i] = i;
      }
    
      if (posix_memalign((void **)&num_in_groups, 32,
            nr_gparts * sizeof(int)) != 0)
        error("Failed to allocate list of number in groups for FOF search.");
    
      for(size_t i=0; i<nr_gparts; i++) num_in_groups[i] = 1;    
    
      /* 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 c = &s->cells_top[cid];
     
        message("Searching top-level cell: %d.", cid);
        fflush(stdout);
    
        /* 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);
    
      }
      
      fof_dump_group_data("fof_output_tree_serial.dat", nr_gparts, pid, num_in_groups);
    
      int num_parts_in_groups = 0;
      int max_group_size = 0, max_group_id = 0;
      for(size_t i=0; i<nr_gparts; i++) {
    
          if(num_in_groups[i] > 1) num_parts_in_groups += num_in_groups[i];
          if( num_in_groups[i] > max_group_size) {
            max_group_size = num_in_groups[i];
            max_group_id = i;
          }
      }
    
      message("No. of groups: %d. No. of particles in groups: %d. No. of particles not in groups: %ld.", num_groups, num_parts_in_groups, nr_gparts - num_parts_in_groups);
      message("Biggest group size: %d with ID: %d", max_group_size, max_group_id);
    
      free(pid);
      free(num_in_groups);
    }
    
    /* Dump FOF group data. */
    void fof_dump_group_data(char *out_file, const int nr_gparts, int *pid, int *num_in_groups) {
    
      FILE *file = fopen(out_file,"w");
      fprintf(file, "# %7s %7s %7s\n", "ID", "Root ID","Group Size"); 
      fprintf(file, "#-------------------------------\n"); 
    
      for(size_t i=0; i<nr_gparts; i++) {
    
          fprintf(file, "  %7ld %7d %7d\n", i, pid[i], num_in_groups[i]); 
    
      }
      
      fclose(file);
      
    }