MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
Classes | Macros | Functions | Variables
fof.c File Reference

parallel FoF group finder More...

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <gsl/gsl_math.h>
#include <inttypes.h>
#include <omp.h>
#include "utils.h"
#include "utils/mpsort.h"
#include "walltime.h"
#include "sfr_eff.h"
#include "blackhole.h"
#include "domain.h"
#include "winds.h"
#include "forcetree.h"
#include "treewalk.h"
#include "slotsmanager.h"
#include "partmanager.h"
#include "densitykernel.h"
#include "fof.h"
Include dependency graph for fof.c:

Go to the source code of this file.

Classes

struct  FOFParams
 
struct  fof_particle_list
 
struct  TreeWalkQueryFOF
 
struct  TreeWalkResultFOF
 
struct  TreeWalkNgbIterFOF
 
struct  FOFPrimaryPriv
 
struct  FOFSecondaryPriv
 

Macros

#define LARGE   1e29
 
#define MAXITER   400
 
#define FOF_PRIMARY_GET_PRIV(tw)   ((struct FOFPrimaryPriv *) (tw->priv))
 
#define FOF_SECONDARY_GET_PRIV(tw)   ((struct FOFSecondaryPriv *) (tw->priv))
 

Functions

void set_fof_params (ParameterSet *ps)
 
void fof_init (double DMMeanSeparation)
 
static double fof_periodic (double x, double BoxSize)
 
static double fof_periodic_wrap (double x, double BoxSize)
 
static void fof_label_secondary (struct fof_particle_list *HaloLabel, ForceTree *tree)
 
static int fof_compare_HaloLabel_MinID (const void *a, const void *b)
 
static int fof_compare_Group_MinIDTask (const void *a, const void *b)
 
static int fof_compare_Group_OriginalIndex (const void *a, const void *b)
 
static int fof_compare_Group_MinID (const void *a, const void *b)
 
static void fof_reduce_groups (void *groups, int nmemb, size_t elsize, void(*reduce_group)(void *gdst, void *gsrc), MPI_Comm Comm)
 
static void fof_finish_group_properties (FOFGroups *fof, double BoxSize)
 
static int fof_compile_base (struct BaseGroup *base, int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
 
static void fof_compile_catalogue (FOFGroups *fof, const int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
 
static struct Groupfof_alloc_group (const struct BaseGroup *base, const int NgroupsExt)
 
static void fof_assign_grnr (struct BaseGroup *base, const int NgroupsExt, MPI_Comm Comm)
 
void fof_label_primary (struct fof_particle_list *HaloLabel, ForceTree *tree, MPI_Comm Comm)
 
FOFGroups fof_fof (DomainDecomp *ddecomp, const int StoreGrNr, MPI_Comm Comm)
 
void fof_finish (FOFGroups *fof)
 
static int HEADl (int stop, int i, const int *const Head)
 
static void update_root (int i, const int r, int *Head)
 
static int HEAD (int i, const int *const Head)
 
static void fof_primary_copy (int place, TreeWalkQueryFOF *I, TreeWalk *tw)
 
static int fof_primary_haswork (int n, TreeWalk *tw)
 
static void fof_primary_ngbiter (TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
 
static void fofp_merge (int target, int other, TreeWalk *tw)
 
static void fof_reduce_base_group (void *pdst, void *psrc)
 
static void fof_reduce_group (void *pdst, void *psrc)
 
static void add_particle_to_group (struct Group *gdst, int i, int ThisTask)
 
static void fof_radix_Group_TotalCountTaskDiffMinID (const void *a, void *radix, void *arg)
 
static void fof_radix_Group_OriginalTaskMinID (const void *a, void *radix, void *arg)
 
void fof_save_groups (FOFGroups *fof, const char *OutputDir, const char *FOFFileBase, int num, Cosmology *CP, double atime, const double *MassTable, int MetalReturnOn, int BlackholeOn, MPI_Comm Comm)
 
static void fof_secondary_copy (int place, TreeWalkQueryFOF *I, TreeWalk *tw)
 
static int fof_secondary_haswork (int n, TreeWalk *tw)
 
static void fof_secondary_reduce (int place, TreeWalkResultFOF *O, enum TreeWalkReduceMode mode, TreeWalk *tw)
 
static void fof_secondary_ngbiter (TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
 
static void fof_secondary_postprocess (int p, TreeWalk *tw)
 
static int cmp_seed_task (const void *c1, const void *c2)
 
static void fof_seed_make_one (struct Group *g, int ThisTask, const double atime)
 
void fof_seed (FOFGroups *fof, ActiveParticles *act, double atime, MPI_Comm Comm)
 

Variables

struct FOFParams fof_params
 
static int _fof_compare_Group_MinIDTask_ThisTask
 
static MPI_Datatype MPI_TYPE_GROUP
 

Detailed Description

parallel FoF group finder

Definition in file fof.c.

Macro Definition Documentation

◆ FOF_PRIMARY_GET_PRIV

#define FOF_PRIMARY_GET_PRIV (   tw)    ((struct FOFPrimaryPriv *) (tw->priv))

Definition at line 276 of file fof.c.

◆ FOF_SECONDARY_GET_PRIV

#define FOF_SECONDARY_GET_PRIV (   tw)    ((struct FOFSecondaryPriv *) (tw->priv))

Definition at line 1126 of file fof.c.

◆ LARGE

#define LARGE   1e29

Definition at line 34 of file fof.c.

◆ MAXITER

#define MAXITER   400

Definition at line 35 of file fof.c.

Function Documentation

◆ add_particle_to_group()

static void add_particle_to_group ( struct Group gdst,
int  i,
int  ThisTask 
)
static

Definition at line 634 of file fof.c.

634  {
635 
636  /* My local number of particles contributing to the full catalogue. */
637  const int index = i;
638  if(gdst->Length == 0) {
639  struct BaseGroup base = gdst->base;
640  memset(gdst, 0, sizeof(gdst[0]));
641  gdst->base = base;
642  gdst->seed_index = gdst->seed_task = -1;
643  }
644 
645  gdst->Length ++;
646  gdst->Mass += P[index].Mass;
647  gdst->LenType[P[index].Type]++;
648  gdst->MassType[P[index].Type] += P[index].Mass;
649 
650  if(P[index].Type == 0) {
651  gdst->MassHeIonized += P[index].Mass * P[index].HeIIIionized;
652  gdst->Sfr += SPHP(index).Sfr;
653  gdst->GasMetalMass += SPHP(index).Metallicity * P[index].Mass;
654  int j;
655  for(j = 0; j < NMETALS; j++)
656  gdst->GasMetalElemMass[j] += SPHP(index).Metals[j] * P[index].Mass;
657  }
658  if(P[index].Type == 4) {
659  int j;
660  gdst->StellarMetalMass += STARP(index).Metallicity * P[index].Mass;
661  for(j = 0; j < NMETALS; j++)
662  gdst->StellarMetalElemMass[j] += STARP(index).Metals[j] * P[index].Mass;
663  }
664 
665  if(P[index].Type == 5)
666  {
667  gdst->BH_Mdot += BHP(index).Mdot;
668  gdst->BH_Mass += BHP(index).Mass;
669  }
670  /*This used to depend on black holes being enabled, but I do not see why.
671  * I think because it is only useful for seeding*/
672  /* Don't make bh in wind.*/
673  if(P[index].Type == 0 && !winds_is_particle_decoupled(index))
674  if(SPHP(index).Density > gdst->MaxDens)
675  {
676  gdst->MaxDens = SPHP(index).Density;
677  gdst->seed_index = index;
678  gdst->seed_task = ThisTask;
679  }
680 
681  int d1, d2;
682  double xyz[3];
683  double rel[3];
684  double vel[3];
685  double jmom[3];
686 
687  for(d1 = 0; d1 < 3; d1++)
688  {
689  double first = gdst->base.FirstPos[d1];
690  rel[d1] = fof_periodic(P[index].Pos[d1] - first, PartManager->BoxSize) ;
691  xyz[d1] = rel[d1] + first;
692  vel[d1] = P[index].Vel[d1];
693  }
694 
695  crossproduct(rel, vel, jmom);
696 
697  for(d1 = 0; d1 < 3; d1++) {
698  gdst->CM[d1] += P[index].Mass * xyz[d1];
699  gdst->Vel[d1] += P[index].Mass * vel[d1];
700  gdst->Jmom[d1] += P[index].Mass * jmom[d1];
701 
702  for(d2 = 0; d2 < 3; d2++) {
703  gdst->Imom[d1][d2] += P[index].Mass * rel[d1] * rel[d2];
704  }
705  }
706 }
static void crossproduct(const double v1[3], const double v2[3], double out[3])
Definition: densitykernel.h:63
static double fof_periodic(double x, double BoxSize)
Definition: fof.c:71
struct part_manager_type PartManager[1]
Definition: partmanager.c:11
#define P
Definition: partmanager.h:88
#define BHP(i)
Definition: slotsmanager.h:125
#define SPHP(i)
Definition: slotsmanager.h:124
#define STARP(i)
Definition: slotsmanager.h:126
#define NMETALS
Definition: slotsmanager.h:60
Definition: fof.h:13
float FirstPos[3]
Definition: fof.h:22
double Sfr
Definition: fof.h:40
struct BaseGroup base
Definition: fof.h:27
double MaxDens
Definition: fof.h:54
double GasMetalMass
Definition: fof.h:44
float GasMetalElemMass[NMETALS]
Definition: fof.h:47
double StellarMetalMass
Definition: fof.h:45
double Imom[3][3]
Definition: fof.h:37
double BH_Mdot
Definition: fof.h:53
int seed_index
Definition: fof.h:56
double CM[3]
Definition: fof.h:34
int Length
Definition: fof.h:28
double Jmom[3]
Definition: fof.h:38
double MassType[6]
Definition: fof.h:30
float MassHeIonized
Definition: fof.h:50
double BH_Mass
Definition: fof.h:52
float StellarMetalElemMass[NMETALS]
Definition: fof.h:46
int seed_task
Definition: fof.h:57
int LenType[6]
Definition: fof.h:29
double Vel[3]
Definition: fof.h:35
double Mass
Definition: fof.h:31
int ThisTask
Definition: test_exchange.c:23
int winds_is_particle_decoupled(int i)
Definition: winds.c:124

References Group::base, Group::BH_Mass, Group::BH_Mdot, BHP, part_manager_type::BoxSize, Group::CM, crossproduct(), BaseGroup::FirstPos, fof_periodic(), Group::GasMetalElemMass, Group::GasMetalMass, Group::Imom, Group::Jmom, Group::Length, Group::LenType, Group::Mass, Group::MassHeIonized, Group::MassType, Group::MaxDens, NMETALS, P, PartManager, Group::seed_index, Group::seed_task, Group::Sfr, SPHP, STARP, Group::StellarMetalElemMass, Group::StellarMetalMass, ThisTask, Group::Vel, and winds_is_particle_decoupled().

Referenced by fof_compile_catalogue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cmp_seed_task()

static int cmp_seed_task ( const void *  c1,
const void *  c2 
)
static

Definition at line 1282 of file fof.c.

1282  {
1283  const struct Group * g1 = (const struct Group *) c1;
1284  const struct Group * g2 = (const struct Group *) c2;
1285 
1286  return g1->seed_task - g2->seed_task;
1287 }
Definition: fof.h:26

References Group::seed_task.

Referenced by fof_seed().

Here is the caller graph for this function:

◆ fof_alloc_group()

static struct Group * fof_alloc_group ( const struct BaseGroup base,
const int  NgroupsExt 
)
static

Definition at line 819 of file fof.c.

820 {
821  int i;
822  struct Group * Group = (struct Group *) mymalloc2("Group", sizeof(struct Group) * NgroupsExt);
823  memset(Group, 0, sizeof(Group[0]) * NgroupsExt);
824 
825  /* copy in the base properties */
826  /* at this point base group shall be sorted by MinID */
827  #pragma omp parallel for
828  for(i = 0; i < NgroupsExt; i ++) {
829  Group[i].base = base[i];
830  }
831  return Group;
832 }
#define mymalloc2(name, size)
Definition: mymalloc.h:16

References Group::base, and mymalloc2.

Referenced by fof_fof().

Here is the caller graph for this function:

◆ fof_assign_grnr()

static void fof_assign_grnr ( struct BaseGroup base,
const int  NgroupsExt,
MPI_Comm  Comm 
)
static

Definition at line 1062 of file fof.c.

1063 {
1064  int i, j, NTask, ThisTask;
1065  int64_t ngr;
1066  MPI_Comm_size(Comm, &NTask);
1067  MPI_Comm_rank(Comm, &ThisTask);
1068 
1069  #pragma omp parallel for
1070  for(i = 0; i < NgroupsExt; i++)
1071  {
1072  base[i].OriginalTask = ThisTask; /* original task */
1073  }
1074 
1075  mpsort_mpi(base, NgroupsExt, sizeof(base[0]),
1076  fof_radix_Group_TotalCountTaskDiffMinID, 24, NULL, Comm);
1077 
1078  /* assign group numbers
1079  * at this point, both Group are is sorted by length,
1080  * and the every time OriginalTask == MinIDTask, a list of ghost base is stored.
1081  * they shall get the same GrNr.
1082  * */
1083  ngr = 0;
1084  for(i = 0; i < NgroupsExt; i++)
1085  {
1086  if(base[i].OriginalTask == base[i].MinIDTask) {
1087  ngr++;
1088  }
1089  base[i].GrNr = ngr;
1090  }
1091 
1092  int64_t * ngra = ta_malloc("NGRA", int64_t, NTask);
1093 
1094  MPI_Allgather(&ngr, 1, MPI_INT64, ngra, 1, MPI_INT64, Comm);
1095 
1096  /* shift to the global grnr. */
1097  int64_t groffset = 0;
1098  #pragma omp parallel for reduction(+: groffset)
1099  for(j = 0; j < ThisTask; j++)
1100  groffset += ngra[j];
1101  #pragma omp parallel for
1102  for(i = 0; i < NgroupsExt; i++)
1103  base[i].GrNr += groffset;
1104 
1105  ta_free(ngra);
1106 
1107  /* bring the group list back into the original task, sorted by MinID */
1108  mpsort_mpi(base, NgroupsExt, sizeof(base[0]),
1109  fof_radix_Group_OriginalTaskMinID, 16, NULL, Comm);
1110 }
static void fof_radix_Group_OriginalTaskMinID(const void *a, void *radix, void *arg)
Definition: fof.c:1456
static void fof_radix_Group_TotalCountTaskDiffMinID(const void *a, void *radix, void *arg)
Definition: fof.c:1448
#define mpsort_mpi(base, nmemb, elsize, radix, rsize, arg, comm)
Definition: mpsort.h:26
#define ta_malloc(name, type, nele)
Definition: mymalloc.h:25
#define ta_free(p)
Definition: mymalloc.h:28
int OriginalTask
Definition: fof.h:14
int GrNr
Definition: fof.h:17
#define MPI_INT64
Definition: system.h:12
int NTask
Definition: test_exchange.c:23

References fof_radix_Group_OriginalTaskMinID(), fof_radix_Group_TotalCountTaskDiffMinID(), BaseGroup::GrNr, BaseGroup::MinIDTask, MPI_INT64, mpsort_mpi, NTask, BaseGroup::OriginalTask, ta_free, ta_malloc, and ThisTask.

Referenced by fof_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_compare_Group_MinID()

static int fof_compare_Group_MinID ( const void *  a,
const void *  b 
)
static

Definition at line 1415 of file fof.c.

1417 {
1418  if(((struct BaseGroup *) a)->MinID < ((struct BaseGroup *) b)->MinID)
1419  return -1;
1420 
1421  if(((struct BaseGroup *) a)->MinID > ((struct BaseGroup *) b)->MinID)
1422  return +1;
1423 
1424  return 0;
1425 }

Referenced by fof_reduce_groups().

Here is the caller graph for this function:

◆ fof_compare_Group_MinIDTask()

static int fof_compare_Group_MinIDTask ( const void *  a,
const void *  b 
)
static

Definition at line 1427 of file fof.c.

1428 {
1429  const struct BaseGroup * p1 = (const struct BaseGroup *) a;
1430  const struct BaseGroup * p2 = (const struct BaseGroup *) b;
1431  int t1 = p1->MinIDTask;
1432  int t2 = p2->MinIDTask;
1433  if(t1 == _fof_compare_Group_MinIDTask_ThisTask) t1 = -1;
1434  if(t2 == _fof_compare_Group_MinIDTask_ThisTask) t2 = -1;
1435 
1436  if(t1 < t2) return -1;
1437  if(t1 > t2) return +1;
1438  return 0;
1439 
1440 }
static int _fof_compare_Group_MinIDTask_ThisTask
Definition: fof.c:99
int MinIDTask
Definition: fof.h:19

References _fof_compare_Group_MinIDTask_ThisTask, and BaseGroup::MinIDTask.

Referenced by fof_reduce_groups().

Here is the caller graph for this function:

◆ fof_compare_Group_OriginalIndex()

static int fof_compare_Group_OriginalIndex ( const void *  a,
const void *  b 
)
static

Definition at line 1442 of file fof.c.

1444 {
1445  return ((struct BaseGroup *) a)->OriginalIndex - ((struct BaseGroup *) b)->OriginalIndex;
1446 }

Referenced by fof_reduce_groups().

Here is the caller graph for this function:

◆ fof_compare_HaloLabel_MinID()

static int fof_compare_HaloLabel_MinID ( const void *  a,
const void *  b 
)
static

Definition at line 1404 of file fof.c.

1405 {
1406  if(((struct fof_particle_list *) a)->MinID < ((struct fof_particle_list *) b)->MinID)
1407  return -1;
1408 
1409  if(((struct fof_particle_list *) a)->MinID > ((struct fof_particle_list *) b)->MinID)
1410  return +1;
1411 
1412  return 0;
1413 }

Referenced by fof_fof().

Here is the caller graph for this function:

◆ fof_compile_base()

static int fof_compile_base ( struct BaseGroup base,
int  NgroupsExt,
struct fof_particle_list HaloLabel,
MPI_Comm  Comm 
)
static

Definition at line 761 of file fof.c.

762 {
763  memset(base, 0, sizeof(base[0]) * NgroupsExt);
764 
765  int i;
766  int start;
767 
768  start = 0;
769  for(i = 0; i < PartManager->NumPart; i++)
770  {
771  if(i == 0 || HaloLabel[i].MinID != HaloLabel[i - 1].MinID) {
772  base[start].MinID = HaloLabel[i].MinID;
773  base[start].MinIDTask = HaloLabel[i].MinIDTask;
774  int d;
775  for(d = 0; d < 3; d ++) {
776  base[start].FirstPos[d] = P[HaloLabel[i].Pindex].Pos[d];
777  }
778  start ++;
779  }
780  }
781 
782  /* count local lengths */
783  /* This works because base is sorted by MinID by construction. */
784  start = 0;
785  for(i = 0; i < NgroupsExt; i++)
786  {
787  /* find the first particle */
788  for(;start < PartManager->NumPart; start++) {
789  if(HaloLabel[start].MinID >= base[i].MinID) break;
790  }
791  /* count particles */
792  for(;start < PartManager->NumPart; start++) {
793  if(HaloLabel[start].MinID != base[i].MinID) {
794  break;
795  }
796  base[i].Length ++;
797  }
798  }
799 
800  /* update global attributes */
801  fof_reduce_groups(base, NgroupsExt, sizeof(base[0]), fof_reduce_base_group, Comm);
802 
803  /* eliminate all groups that are too small */
804  for(i = 0; i < NgroupsExt; i++)
805  {
806  if(base[i].Length < fof_params.FOFHaloMinLength)
807  {
808  base[i] = base[NgroupsExt - 1];
809  NgroupsExt--;
810  i--;
811  }
812  }
813  return NgroupsExt;
814 }
static void fof_reduce_base_group(void *pdst, void *psrc)
Definition: fof.c:584
static void fof_reduce_groups(void *groups, int nmemb, size_t elsize, void(*reduce_group)(void *gdst, void *gsrc), MPI_Comm Comm)
Definition: fof.c:907
struct FOFParams fof_params
MyIDType MinID
Definition: fof.h:18
int Length
Definition: fof.h:16
int FOFHaloMinLength
Definition: fof.c:44
int Pindex
Definition: fof.c:94
int MinIDTask
Definition: fof.c:93
MyIDType MinID
Definition: fof.c:92

References Group::base, BaseGroup::FirstPos, fof_params, fof_reduce_base_group(), fof_reduce_groups(), FOFParams::FOFHaloMinLength, BaseGroup::Length, Group::Length, fof_particle_list::MinID, BaseGroup::MinID, fof_particle_list::MinIDTask, BaseGroup::MinIDTask, part_manager_type::NumPart, P, PartManager, and fof_particle_list::Pindex.

Referenced by fof_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_compile_catalogue()

static void fof_compile_catalogue ( FOFGroups fof,
const int  NgroupsExt,
struct fof_particle_list HaloLabel,
MPI_Comm  Comm 
)
static

Definition at line 835 of file fof.c.

836 {
837  int i, start, ThisTask;
838 
839  MPI_Comm_rank(Comm, &ThisTask);
840 
841  start = 0;
842  for(i = 0; i < NgroupsExt; i++)
843  {
844  /* find the first particle */
845  for(;start < PartManager->NumPart; start++) {
846  if(HaloLabel[start].MinID >= fof->Group[i].base.MinID) break;
847  }
848  /* add particles */
849  for(;start < PartManager->NumPart; start++) {
850  if(HaloLabel[start].MinID != fof->Group[i].base.MinID) {
851  break;
852  }
853  add_particle_to_group(&fof->Group[i], HaloLabel[start].Pindex, ThisTask);
854  }
855  }
856 
857  /* collect global properties */
858  fof_reduce_groups(fof->Group, NgroupsExt, sizeof(fof->Group[0]), fof_reduce_group, Comm);
859 
860  /* count Groups and number of particles hosted by me */
861  fof->Ngroups = 0;
862  int64_t Nids = 0;
863  for(i = 0; i < NgroupsExt; i ++) {
864  if(fof->Group[i].base.MinIDTask != ThisTask) continue;
865 
866  fof->Ngroups++;
867  Nids += fof->Group[i].base.Length;
868 
869  if(fof->Group[i].base.Length != fof->Group[i].Length) {
870  /* These two shall be consistent */
871  endrun(3333, "i=%d Group base Length %d != Group Length %d\n", i, fof->Group[i].base.Length, fof->Group[i].Length);
872  }
873  }
874 
876 
877  int64_t TotNids;
878  sumup_large_ints(1, &fof->Ngroups, &fof->TotNgroups);
879  MPI_Allreduce(&Nids, &TotNids, 1, MPI_INT64, MPI_SUM, Comm);
880 
881  /* report some statistics */
882  int largestloc_tot = 0;
883  double largestmass_tot= 0;
884  if(fof->TotNgroups > 0)
885  {
886  double largestmass = 0;
887  int largestlength = 0;
888 
889  for(i = 0; i < NgroupsExt; i++)
890  if(fof->Group[i].Length > largestlength) {
891  largestlength = fof->Group[i].Length;
892  largestmass = fof->Group[i].Mass;
893  }
894  MPI_Allreduce(&largestlength, &largestloc_tot, 1, MPI_INT, MPI_MAX, Comm);
895  MPI_Allreduce(&largestmass, &largestmass_tot, 1, MPI_DOUBLE, MPI_MAX, Comm);
896  }
897 
898  message(0, "Total number of groups with at least %d particles: %ld\n", fof_params.FOFHaloMinLength, fof->TotNgroups);
899  if(fof->TotNgroups > 0)
900  {
901  message(0, "Largest group has %d particles, mass %g.\n", largestloc_tot, largestmass_tot);
902  message(0, "Total number of particles in groups: %012ld\n", TotNids);
903  }
904 }
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
static void add_particle_to_group(struct Group *gdst, int i, int ThisTask)
Definition: fof.c:634
static void fof_finish_group_properties(FOFGroups *fof, double BoxSize)
Definition: fof.c:709
static void fof_reduce_group(void *pdst, void *psrc)
Definition: fof.c:591
struct Group * Group
Definition: fof.h:63
int Ngroups
Definition: fof.h:66
int64_t TotNgroups
Definition: fof.h:67
void sumup_large_ints(int n, int *src, int64_t *res)
Definition: system.c:192

References add_particle_to_group(), Group::base, part_manager_type::BoxSize, endrun(), fof_finish_group_properties(), fof_params, fof_reduce_group(), fof_reduce_groups(), FOFParams::FOFHaloMinLength, FOFGroups::Group, BaseGroup::Length, Group::Length, Group::Mass, message(), BaseGroup::MinID, BaseGroup::MinIDTask, MPI_INT64, FOFGroups::Ngroups, part_manager_type::NumPart, PartManager, fof_particle_list::Pindex, sumup_large_ints(), ThisTask, and FOFGroups::TotNgroups.

Referenced by fof_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_finish()

void fof_finish ( FOFGroups fof)

Definition at line 257 of file fof.c.

258 {
259  myfree(fof->Group);
260 
261  message(0, "Finished computing FoF groups. (presently allocated=%g MB)\n",
262  mymalloc_usedbytes() / (1024.0 * 1024.0));
263 
264  walltime_measure("/FOF/MISC");
265 
266  MPI_Type_free(&MPI_TYPE_GROUP);
267 }
static MPI_Datatype MPI_TYPE_GROUP
Definition: fof.c:142
#define mymalloc_usedbytes()
Definition: mymalloc.h:32
#define myfree(x)
Definition: mymalloc.h:19
#define walltime_measure(name)
Definition: walltime.h:8

References FOFGroups::Group, message(), MPI_TYPE_GROUP, myfree, mymalloc_usedbytes, and walltime_measure.

Referenced by run(), runfof(), and test_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_finish_group_properties()

static void fof_finish_group_properties ( FOFGroups fof,
double  BoxSize 
)
static

Definition at line 709 of file fof.c.

710 {
711  int i;
712 
713  for(i = 0; i < fof->Ngroups; i++)
714  {
715  int d1, d2;
716  double cm[3];
717  double rel[3];
718  double jcm[3];
719  double vcm[3];
720 
721  struct Group * gdst = &fof->Group[i];
722  for(d1 = 0; d1 < 3; d1++)
723  {
724  gdst->Vel[d1] /= gdst->Mass;
725  vcm[d1] = gdst->Vel[d1];
726  cm[d1] = gdst->CM[d1] / gdst->Mass;
727 
728  rel[d1] = fof_periodic(cm[d1] - gdst->base.FirstPos[d1], BoxSize);
729 
730  cm[d1] = fof_periodic_wrap(cm[d1], BoxSize);
731  gdst->CM[d1] = cm[d1];
732 
733  }
734  crossproduct(rel, vcm, jcm);
735 
736  for(d1 = 0; d1 < 3; d1 ++) {
737  gdst->Jmom[d1] -= jcm[d1] * gdst->Mass;
738  }
739 
740  for(d1 = 0; d1 < 3; d1 ++) {
741  for(d2 = 0; d2 < 3; d2++) {
742  /* Parallel Axis theorem:
743  * https://en.wikipedia.org/wiki/Parallel_axis_theorem ;
744  * J was relative to FirstPos, I is relative to CM.
745  *
746  * Note that our definition of Imom follows the astronomy one,
747  *
748  * I_ij = sum x_i x_j (where x_i x_j is relative displacement)
749  * */
750 
751  double diff = rel[d1] * rel[d2];
752 
753  gdst->Imom[d1][d2] -= gdst->Mass * diff;
754  }
755  }
756  }
757 
758 }
static double fof_periodic_wrap(double x, double BoxSize)
Definition: fof.c:81

References Group::base, Group::CM, crossproduct(), BaseGroup::FirstPos, fof_periodic(), fof_periodic_wrap(), FOFGroups::Group, Group::Imom, Group::Jmom, Group::Mass, FOFGroups::Ngroups, and Group::Vel.

Referenced by fof_compile_catalogue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_fof()

FOFGroups fof_fof ( DomainDecomp ddecomp,
const int  StoreGrNr,
MPI_Comm  Comm 
)

Definition at line 151 of file fof.c.

152 {
153  int i;
154 
155  message(0, "Begin to compute FoF group catalogues. (allocated: %g MB)\n",
156  mymalloc_usedbytes() / (1024.0 * 1024.0));
157 
158  walltime_measure("/Misc");
159 
160  message(0, "Comoving linking length: %g\n", fof_params.FOFHaloComovingLinkingLength);
161 
162  struct fof_particle_list * HaloLabel = (struct fof_particle_list *) mymalloc("HaloLabel", PartManager->NumPart * sizeof(struct fof_particle_list));
163 
164  /* HaloLabel stores the MinID and MinIDTask of particles, this pair serves as a halo label. */
165  #pragma omp parallel for
166  for(i = 0; i < PartManager->NumPart; i++) {
167  HaloLabel[i].Pindex = i;
168  }
169 
170  /* We only need a tree containing primary linking particles only. No moments*/
171  ForceTree dmtree = {0};
172  force_tree_rebuild_mask(&dmtree, ddecomp, fof_params.FOFPrimaryLinkTypes, 0, NULL);
173 
174  /* Fill FOFP_List of primary */
175  fof_label_primary(HaloLabel, &dmtree, Comm);
176 
177  MPIU_Barrier(Comm);
178  message(0, "Group finding done.\n");
179  walltime_measure("/FOF/Primary");
180 
181  /* Fill FOFP_List of secondary */
182  fof_label_secondary(HaloLabel, &dmtree);
183  force_tree_free(&dmtree);
184 
185  MPIU_Barrier(Comm);
186  message(0, "Attached gas and star particles to nearest dm particles.\n");
187 
188  walltime_measure("/FOF/Secondary");
189 
190  /* sort HaloLabel according to MinID, because we need that for compiling catalogues */
192 
193  int NgroupsExt = 0;
194 
195  for(i = 0; i < PartManager->NumPart; i ++) {
196  if(i == 0 || HaloLabel[i].MinID != HaloLabel[i - 1].MinID) NgroupsExt ++;
197  }
198 
199  /* The first round is to eliminate groups that are too short. */
200  /* We create the smaller 'BaseGroup' data set for this. */
201  struct BaseGroup * base = (struct BaseGroup *) mymalloc("BaseGroup", sizeof(struct BaseGroup) * NgroupsExt);
202 
203  NgroupsExt = fof_compile_base(base, NgroupsExt, HaloLabel, Comm);
204 
205  MPIU_Barrier(Comm);
206  message(0, "Compiled local group data and catalogue.\n");
207 
208  walltime_measure("/FOF/Compile");
209 
210  fof_assign_grnr(base, NgroupsExt, Comm);
211 
212  /*Store the group number in the particle struct*/
213  if(StoreGrNr) {
214  #pragma omp parallel for
215  for(i = 0; i < PartManager->NumPart; i++)
216  P[i].GrNr = -1; /* will mark particles that are not in any group */
217 
218  int64_t start = 0;
219  for(i = 0; i < NgroupsExt; i++)
220  {
221  for(;start < PartManager->NumPart; start++) {
222  if (HaloLabel[start].MinID >= base[i].MinID)
223  break;
224  }
225 
226  for(;start < PartManager->NumPart; start++) {
227  if (HaloLabel[start].MinID != base[i].MinID)
228  break;
229  P[HaloLabel[start].Pindex].GrNr = base[i].GrNr;
230  }
231  }
232  }
233 
234  /*Initialise the Group object from the BaseGroup*/
235  FOFGroups fof;
236  MPI_Type_contiguous(sizeof(fof.Group[0]), MPI_BYTE, &MPI_TYPE_GROUP);
237  MPI_Type_commit(&MPI_TYPE_GROUP);
238 
239  fof.Group = fof_alloc_group(base, NgroupsExt);
240 
241  myfree(base);
242 
243  fof_compile_catalogue(&fof, NgroupsExt, HaloLabel, Comm);
244 
245  MPIU_Barrier(Comm);
246  message(0, "Finished FoF. Group properties are now allocated.. (presently allocated=%g MB)\n",
247  mymalloc_usedbytes() / (1024.0 * 1024.0));
248 
249  walltime_measure("/FOF/Prop");
250 
251  myfree(HaloLabel);
252 
253  return fof;
254 }
static void fof_compile_catalogue(FOFGroups *fof, const int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
Definition: fof.c:835
static struct Group * fof_alloc_group(const struct BaseGroup *base, const int NgroupsExt)
Definition: fof.c:819
static int fof_compare_HaloLabel_MinID(const void *a, const void *b)
Definition: fof.c:1404
static int fof_compile_base(struct BaseGroup *base, int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
Definition: fof.c:761
static void fof_label_secondary(struct fof_particle_list *HaloLabel, ForceTree *tree)
Definition: fof.c:1207
void fof_label_primary(struct fof_particle_list *HaloLabel, ForceTree *tree, MPI_Comm Comm)
Definition: fof.c:369
static void fof_assign_grnr(struct BaseGroup *base, const int NgroupsExt, MPI_Comm Comm)
Definition: fof.c:1062
void force_tree_rebuild_mask(ForceTree *tree, DomainDecomp *ddecomp, int mask, const int HybridNuGrav, const char *EmergencyOutputDir)
Definition: forcetree.c:161
void force_tree_free(ForceTree *tree)
Definition: forcetree.c:1409
#define mymalloc(name, size)
Definition: mymalloc.h:15
Definition: fof.h:62
double FOFHaloComovingLinkingLength
Definition: fof.c:43
int FOFPrimaryLinkTypes
Definition: fof.c:45
#define MPIU_Barrier(comm)
Definition: system.h:103
#define qsort_openmp
Definition: test_exchange.c:14

References fof_alloc_group(), fof_assign_grnr(), fof_compare_HaloLabel_MinID(), fof_compile_base(), fof_compile_catalogue(), fof_label_primary(), fof_label_secondary(), fof_params, FOFParams::FOFHaloComovingLinkingLength, FOFParams::FOFPrimaryLinkTypes, force_tree_free(), force_tree_rebuild_mask(), BaseGroup::GrNr, FOFGroups::Group, message(), fof_particle_list::MinID, BaseGroup::MinID, MPI_TYPE_GROUP, MPIU_Barrier, myfree, mymalloc, mymalloc_usedbytes, part_manager_type::NumPart, P, PartManager, fof_particle_list::Pindex, qsort_openmp, and walltime_measure.

Referenced by run(), runfof(), and test_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_init()

void fof_init ( double  DMMeanSeparation)

Definition at line 66 of file fof.c.

67 {
69 }
double FOFHaloLinkingLength
Definition: fof.c:42

References fof_params, FOFParams::FOFHaloComovingLinkingLength, and FOFParams::FOFHaloLinkingLength.

Referenced by init().

Here is the caller graph for this function:

◆ fof_label_primary()

void fof_label_primary ( struct fof_particle_list HaloLabel,
ForceTree tree,
MPI_Comm  Comm 
)

Definition at line 369 of file fof.c.

370 {
371  int i;
372  int64_t link_across;
373  int64_t link_across_tot;
374  double t0, t1;
375  int ThisTask;
376  MPI_Comm_rank(Comm, &ThisTask);
377 
378  message(0, "Start linking particles (presently allocated=%g MB)\n", mymalloc_usedbytes() / (1024.0 * 1024.0));
379 
380  TreeWalk tw[1] = {{0}};
381  tw->ev_label = "FOF_FIND_GROUPS";
385 
388  tw->reduce = NULL;
389  tw->type = TREEWALK_ALL;
390  tw->query_type_elsize = sizeof(TreeWalkQueryFOF);
392  tw->tree = tree;
393  struct FOFPrimaryPriv priv[1];
394  tw->priv = priv;
395 
396  FOF_PRIMARY_GET_PRIV(tw)->Head = (int*) mymalloc("FOF_Links", PartManager->NumPart * sizeof(int));
397  FOF_PRIMARY_GET_PRIV(tw)->PrimaryActive = (char*) mymalloc("FOFActive", PartManager->NumPart * sizeof(char));
398  FOF_PRIMARY_GET_PRIV(tw)->OldMinID = (MyIDType *) mymalloc("FOFActive", PartManager->NumPart * sizeof(MyIDType));
399  FOF_PRIMARY_GET_PRIV(tw)->HaloLabel = HaloLabel;
400  /* allocate buffers to arrange communication */
401 
402  #pragma omp parallel for
403  for(i = 0; i < PartManager->NumPart; i++)
404  {
405  FOF_PRIMARY_GET_PRIV(tw)->Head[i] = i;
406  FOF_PRIMARY_GET_PRIV(tw)->OldMinID[i]= P[i].ID;
407  FOF_PRIMARY_GET_PRIV(tw)->PrimaryActive[i] = 1;
408 
409  HaloLabel[i].MinID = P[i].ID;
411  }
412 
413  /* The lock is used to protect MinID*/
414  priv[0].spin = init_spinlocks(PartManager->NumPart);
415  do
416  {
417  t0 = second();
418 
419  treewalk_run(tw, NULL, PartManager->NumPart);
420 
421  t1 = second();
422  /* This sets the MinID of the head particle to the minimum ID
423  * of the child particles. We set this inside the treewalk,
424  * but the locking allows a race, where the particle with MinID set
425  * is no longer the one which is the true Head of the group.
426  * So we must check it again here.*/
427  #pragma omp parallel for
428  for(i = 0; i < PartManager->NumPart; i++) {
429  int head = HEAD(i, FOF_PRIMARY_GET_PRIV(tw)->Head);
430  /* Don't check against ourself*/
431  if(head == i)
432  continue;
433  MyIDType headminid;
434  #pragma omp atomic read
435  headminid = HaloLabel[head].MinID;
436  /* No atomic needed for i as this is not a head*/
437  if(headminid > HaloLabel[i].MinID) {
438  lock_spinlock(head, priv->spin);
439  if(HaloLabel[head].MinID > HaloLabel[i].MinID) {
440  #pragma omp atomic write
441  HaloLabel[head].MinID = HaloLabel[i].MinID;
443  }
444  unlock_spinlock(head, priv->spin);
445  }
446  }
447  /* let's check out which particles have changed their MinID,
448  * mark them for next round. */
449  link_across = 0;
450 #pragma omp parallel for reduction(+: link_across)
451  for(i = 0; i < PartManager->NumPart; i++) {
452  int head = HEAD(i, FOF_PRIMARY_GET_PRIV(tw)->Head);
453  /* This loop sets the MinID of the children to the minID of the head.
454  * The minID of the head is set above and is stable at this point.*/
455  if(i != head) {
456  HaloLabel[i].MinID = HaloLabel[head].MinID;
458  }
459  MyIDType newMinID = HaloLabel[head].MinID;
460  if(newMinID != FOF_PRIMARY_GET_PRIV(tw)->OldMinID[i]) {
461  FOF_PRIMARY_GET_PRIV(tw)->PrimaryActive[i] = 1;
462  FOF_PRIMARY_GET_PRIV(tw)->OldMinID[i] = newMinID;
463  link_across ++;
464  } else {
465  FOF_PRIMARY_GET_PRIV(tw)->PrimaryActive[i] = 0;
466  }
467  }
468  MPI_Allreduce(&link_across, &link_across_tot, 1, MPI_INT64, MPI_SUM, Comm);
469  message(0, "Linked %ld particles %g seconds\n", link_across_tot, t1 - t0);
470  }
471  while(link_across_tot > 0);
472 
473  free_spinlocks(priv[0].spin);
474 
475  message(0, "Local groups found.\n");
476 
480 }
static int fof_primary_haswork(int n, TreeWalk *tw)
Definition: fof.c:357
static void fof_primary_ngbiter(TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
Definition: fof.c:546
static int HEAD(int i, const int *const Head)
Definition: fof.c:333
static void fof_primary_copy(int place, TreeWalkQueryFOF *I, TreeWalk *tw)
Definition: fof.c:342
#define FOF_PRIMARY_GET_PRIV(tw)
Definition: fof.c:276
void free_spinlocks(struct SpinLocks *spin)
Definition: spinlocks.c:70
void lock_spinlock(int i, struct SpinLocks *spin)
Definition: spinlocks.c:23
struct SpinLocks * init_spinlocks(int NumLock)
Definition: spinlocks.c:49
static struct SpinLocks spin
Definition: spinlocks.c:21
void unlock_spinlock(int i, struct SpinLocks *spin)
Definition: spinlocks.c:30
int * Head
Definition: fof.c:270
char * PrimaryActive
Definition: fof.c:272
MyIDType * OldMinID
Definition: fof.c:273
struct fof_particle_list * HaloLabel
Definition: fof.c:274
enum TreeWalkType type
Definition: treewalk.h:93
void * priv
Definition: treewalk.h:85
TreeWalkHasWorkFunction haswork
Definition: treewalk.h:100
size_t ngbiter_type_elsize
Definition: treewalk.h:97
const ForceTree * tree
Definition: treewalk.h:88
TreeWalkNgbIterFunction ngbiter
Definition: treewalk.h:103
TreeWalkReduceResultFunction reduce
Definition: treewalk.h:102
const char * ev_label
Definition: treewalk.h:91
TreeWalkVisitFunction visit
Definition: treewalk.h:99
size_t result_type_elsize
Definition: treewalk.h:96
TreeWalkFillQueryFunction fill
Definition: treewalk.h:101
size_t query_type_elsize
Definition: treewalk.h:95
double second(void)
Definition: system.c:83
int treewalk_visit_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
Definition: treewalk.c:924
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
Definition: treewalk.c:619
int(* TreeWalkVisitFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, LocalTreeWalk *lv)
Definition: treewalk.h:68
@ TREEWALK_ALL
Definition: treewalk.h:80
void(* TreeWalkNgbIterFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, TreeWalkNgbIterBase *iter, LocalTreeWalk *lv)
Definition: treewalk.h:70
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
Definition: treewalk.h:75
uint64_t MyIDType
Definition: types.h:10

References TreeWalk::ev_label, TreeWalk::fill, fof_primary_copy(), FOF_PRIMARY_GET_PRIV, fof_primary_haswork(), fof_primary_ngbiter(), free_spinlocks(), FOFPrimaryPriv::HaloLabel, TreeWalk::haswork, FOFPrimaryPriv::Head, HEAD(), init_spinlocks(), lock_spinlock(), message(), fof_particle_list::MinID, fof_particle_list::MinIDTask, MPI_INT64, myfree, mymalloc, mymalloc_usedbytes, TreeWalk::ngbiter, TreeWalk::ngbiter_type_elsize, part_manager_type::NumPart, FOFPrimaryPriv::OldMinID, P, PartManager, FOFPrimaryPriv::PrimaryActive, TreeWalk::priv, TreeWalk::query_type_elsize, TreeWalk::reduce, TreeWalk::result_type_elsize, second(), FOFPrimaryPriv::spin, spin, ThisTask, TreeWalk::tree, TREEWALK_ALL, treewalk_run(), treewalk_visit_ngbiter(), TreeWalk::type, unlock_spinlock(), and TreeWalk::visit.

Referenced by fof_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_label_secondary()

static void fof_label_secondary ( struct fof_particle_list HaloLabel,
ForceTree tree 
)
static

Definition at line 1207 of file fof.c.

1208 {
1209  int n;
1210 
1211  TreeWalk tw[1] = {{0}};
1212  tw->ev_label = "FOF_FIND_NEAREST";
1220  tw->type = TREEWALK_ALL;
1221  tw->query_type_elsize = sizeof(TreeWalkQueryFOF);
1222  tw->result_type_elsize = sizeof(TreeWalkResultFOF);
1223  tw->tree = tree;
1224  struct FOFSecondaryPriv priv[1];
1225 
1226  tw->priv = priv;
1227 
1228  message(0, "Start finding nearest dm-particle (presently allocated=%g MB)\n",
1229  mymalloc_usedbytes() / (1024.0 * 1024.0));
1230 
1231  FOF_SECONDARY_GET_PRIV(tw)->distance = (float *) mymalloc("FOF_SECONDARY->distance", sizeof(float) * PartManager->NumPart);
1232  FOF_SECONDARY_GET_PRIV(tw)->hsml = (float *) mymalloc("FOF_SECONDARY->hsml", sizeof(float) * PartManager->NumPart);
1233  FOF_SECONDARY_GET_PRIV(tw)->HaloLabel = HaloLabel;
1234 
1235  #pragma omp parallel for
1236  for(n = 0; n < PartManager->NumPart; n++)
1237  {
1238  FOF_SECONDARY_GET_PRIV(tw)->distance[n] = LARGE;
1240 
1241  if((P[n].Type == 0 || P[n].Type == 4 || P[n].Type == 5) && FOF_SECONDARY_GET_PRIV(tw)->hsml[n] < 0.5 * P[n].Hsml) {
1242  /* use gas sml as a hint (faster convergence than 0.1 fof_params.FOFHaloComovingLinkingLength at high-z */
1243  FOF_SECONDARY_GET_PRIV(tw)->hsml[n] = 0.5 * P[n].Hsml;
1244  }
1245  }
1246 
1247  int64_t ntot;
1248 
1249  /* we will repeat the whole thing for those particles where we didn't find enough neighbours */
1250 
1251  message(0, "fof-nearest iteration started\n");
1252  int NumThreads = omp_get_max_threads();
1253  FOF_SECONDARY_GET_PRIV(tw)->npleft = ta_malloc("NPLeft", int, NumThreads);
1254 
1255  do
1256  {
1257  memset(FOF_SECONDARY_GET_PRIV(tw)->npleft, 0, sizeof(int) * NumThreads);
1258 
1259  treewalk_run(tw, NULL, PartManager->NumPart);
1260 
1261  for(n = 1; n < NumThreads; n++) {
1262  FOF_SECONDARY_GET_PRIV(tw)->npleft[0] += FOF_SECONDARY_GET_PRIV(tw)->npleft[n];
1263  }
1264  sumup_large_ints(1, &FOF_SECONDARY_GET_PRIV(tw)->npleft[0], &ntot);
1265 
1266  if(ntot < 0 || (ntot > 0 && tw->Niteration > MAXITER))
1267  endrun(1159, "Failed to converge in fof-nearest: ntot %ld", ntot);
1268  }
1269  while(ntot > 0);
1270 
1274 }
#define FOF_SECONDARY_GET_PRIV(tw)
Definition: fof.c:1126
static int fof_secondary_haswork(int n, TreeWalk *tw)
Definition: fof.c:1135
static void fof_secondary_postprocess(int p, TreeWalk *tw)
Definition: fof.c:1181
static void fof_secondary_copy(int place, TreeWalkQueryFOF *I, TreeWalk *tw)
Definition: fof.c:1128
static void fof_secondary_reduce(int place, TreeWalkResultFOF *O, enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: fof.c:1143
#define MAXITER
Definition: fof.c:35
static void fof_secondary_ngbiter(TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
Definition: fof.c:1153
#define LARGE
Definition: fof.c:34
float * hsml
Definition: fof.c:1121
struct fof_particle_list * HaloLabel
Definition: fof.c:1123
float * distance
Definition: fof.c:1120
int * npleft
Definition: fof.c:1122
int64_t Niteration
Definition: treewalk.h:142
TreeWalkProcessFunction postprocess
Definition: treewalk.h:104
int treewalk_visit_nolist_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
Definition: treewalk.c:1143
void(* TreeWalkReduceResultFunction)(const int j, TreeWalkResultBase *result, const enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: treewalk.h:76
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
Definition: treewalk.h:73

References FOFSecondaryPriv::distance, endrun(), TreeWalk::ev_label, TreeWalk::fill, fof_params, fof_secondary_copy(), FOF_SECONDARY_GET_PRIV, fof_secondary_haswork(), fof_secondary_ngbiter(), fof_secondary_postprocess(), fof_secondary_reduce(), FOFParams::FOFHaloComovingLinkingLength, FOFSecondaryPriv::HaloLabel, TreeWalk::haswork, FOFSecondaryPriv::hsml, LARGE, MAXITER, message(), myfree, mymalloc, mymalloc_usedbytes, TreeWalk::ngbiter, TreeWalk::ngbiter_type_elsize, TreeWalk::Niteration, FOFSecondaryPriv::npleft, part_manager_type::NumPart, P, PartManager, TreeWalk::postprocess, TreeWalk::priv, TreeWalk::query_type_elsize, TreeWalk::reduce, TreeWalk::result_type_elsize, sumup_large_ints(), ta_free, ta_malloc, TreeWalk::tree, TREEWALK_ALL, treewalk_run(), treewalk_visit_nolist_ngbiter(), TreeWalk::type, and TreeWalk::visit.

Referenced by fof_fof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_periodic()

static double fof_periodic ( double  x,
double  BoxSize 
)
static

Definition at line 71 of file fof.c.

72 {
73  if(x >= 0.5 * BoxSize)
74  x -= BoxSize;
75  if(x < -0.5 * BoxSize)
76  x += BoxSize;
77  return x;
78 }

Referenced by add_particle_to_group(), and fof_finish_group_properties().

Here is the caller graph for this function:

◆ fof_periodic_wrap()

static double fof_periodic_wrap ( double  x,
double  BoxSize 
)
static

Definition at line 81 of file fof.c.

82 {
83  while(x >= BoxSize)
84  x -= BoxSize;
85  while(x < 0)
86  x += BoxSize;
87  return x;
88 }

Referenced by fof_finish_group_properties().

Here is the caller graph for this function:

◆ fof_primary_copy()

static void fof_primary_copy ( int  place,
TreeWalkQueryFOF I,
TreeWalk tw 
)
static

Definition at line 342 of file fof.c.

342  {
343  /* The copied data is *only* used for the
344  * secondary treewalk, so fill up garbage for the primary treewalk.
345  * The copy is a technical race otherwise. */
346  if(I->base.NodeList[0] == tw->tree->firstnode) {
347  I->MinID = -1;
348  I->MinIDTask = -1;
349  return;
350  }
351  /* Secondary treewalk, no need for locking here*/
352  int head = HEAD(place, FOF_PRIMARY_GET_PRIV(tw)->Head);
353  I->MinID = FOF_PRIMARY_GET_PRIV(tw)->HaloLabel[head].MinID;
354  I->MinIDTask = FOF_PRIMARY_GET_PRIV(tw)->HaloLabel[head].MinIDTask;
355 }
int firstnode
Definition: forcetree.h:84
int NodeList[NODELISTLENGTH]
Definition: treewalk.h:27
MyIDType MinID
Definition: fof.c:124
TreeWalkQueryBase base
Definition: fof.c:122
int MinIDTask
Definition: fof.c:125

References TreeWalkQueryFOF::base, ForceTree::firstnode, FOF_PRIMARY_GET_PRIV, HEAD(), TreeWalkQueryFOF::MinID, TreeWalkQueryFOF::MinIDTask, TreeWalkQueryBase::NodeList, and TreeWalk::tree.

Referenced by fof_label_primary().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_primary_haswork()

static int fof_primary_haswork ( int  n,
TreeWalk tw 
)
static

Definition at line 357 of file fof.c.

357  {
358  if(P[n].IsGarbage || P[n].Swallowed)
359  return 0;
360  return (((1 << P[n].Type) & (fof_params.FOFPrimaryLinkTypes))) && FOF_PRIMARY_GET_PRIV(tw)->PrimaryActive[n];
361 }

References fof_params, FOF_PRIMARY_GET_PRIV, FOFParams::FOFPrimaryLinkTypes, and P.

Referenced by fof_label_primary().

Here is the caller graph for this function:

◆ fof_primary_ngbiter()

static void fof_primary_ngbiter ( TreeWalkQueryFOF I,
TreeWalkResultFOF O,
TreeWalkNgbIterFOF iter,
LocalTreeWalk lv 
)
static

Definition at line 546 of file fof.c.

550 {
551  TreeWalk * tw = lv->tw;
552  if(iter->base.other == -1) {
556  return;
557  }
558  int other = iter->base.other;
559 
560  if(lv->mode == 0) {
561  /* Local FOF */
562  if(lv->target <= other) {
563  // printf("locked merge %d %d by %d\n", lv->target, other, omp_get_thread_num());
564  fofp_merge(lv->target, other, tw);
565  }
566  }
567  else /* mode is 1, target is a ghost */
568  {
569  int head = HEAD(other, FOF_PRIMARY_GET_PRIV(tw)->Head);
570  struct fof_particle_list * HaloLabel = FOF_PRIMARY_GET_PRIV(tw)->HaloLabel;
571  struct SpinLocks * spin = FOF_PRIMARY_GET_PRIV(tw)->spin;
572 // printf("locking %d by %d in ngbiter\n", other, omp_get_thread_num());
573  lock_spinlock(head, spin);
574  if(HaloLabel[head].MinID > I->MinID)
575  {
576  HaloLabel[head].MinID = I->MinID;
577  HaloLabel[head].MinIDTask = I->MinIDTask;
578  }
579 // printf("unlocking %d by %d in ngbiter\n", other, omp_get_thread_num());
580  unlock_spinlock(head, spin);
581  }
582 }
static void fofp_merge(int target, int other, TreeWalk *tw)
Definition: fof.c:483
TreeWalk * tw
Definition: treewalk.h:47
enum NgbTreeFindSymmetric symmetric
Definition: treewalk.h:37
TreeWalkNgbIterBase base
Definition: fof.c:138
@ NGB_TREEFIND_ASYMMETRIC
Definition: treewalk.h:12

References TreeWalkNgbIterFOF::base, fof_params, FOF_PRIMARY_GET_PRIV, FOFParams::FOFHaloComovingLinkingLength, fofp_merge(), FOFParams::FOFPrimaryLinkTypes, HEAD(), TreeWalkNgbIterBase::Hsml, lock_spinlock(), TreeWalkNgbIterBase::mask, fof_particle_list::MinID, TreeWalkQueryFOF::MinID, fof_particle_list::MinIDTask, TreeWalkQueryFOF::MinIDTask, LocalTreeWalk::mode, NGB_TREEFIND_ASYMMETRIC, TreeWalkNgbIterBase::other, spin, TreeWalkNgbIterBase::symmetric, LocalTreeWalk::target, LocalTreeWalk::tw, and unlock_spinlock().

Referenced by fof_label_primary().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_radix_Group_OriginalTaskMinID()

static void fof_radix_Group_OriginalTaskMinID ( const void *  a,
void *  radix,
void *  arg 
)
static

Definition at line 1456 of file fof.c.

1456  {
1457  uint64_t * u = (uint64_t *) radix;
1458  struct BaseGroup * f = (struct BaseGroup *) a;
1459  u[0] = f->MinID;
1460  u[1] = f->OriginalTask;
1461 }

References BaseGroup::MinID, and BaseGroup::OriginalTask.

Referenced by fof_assign_grnr().

Here is the caller graph for this function:

◆ fof_radix_Group_TotalCountTaskDiffMinID()

static void fof_radix_Group_TotalCountTaskDiffMinID ( const void *  a,
void *  radix,
void *  arg 
)
static

Definition at line 1448 of file fof.c.

1448  {
1449  uint64_t * u = (uint64_t *) radix;
1450  struct BaseGroup * f = (struct BaseGroup *) a;
1451  u[0] = labs(f->OriginalTask - f->MinIDTask);
1452  u[1] = f->MinID;
1453  u[2] = UINT64_MAX - (f->Length);
1454 }

References BaseGroup::Length, BaseGroup::MinID, BaseGroup::MinIDTask, and BaseGroup::OriginalTask.

Referenced by fof_assign_grnr().

Here is the caller graph for this function:

◆ fof_reduce_base_group()

static void fof_reduce_base_group ( void *  pdst,
void *  psrc 
)
static

Definition at line 584 of file fof.c.

584  {
585  struct BaseGroup * gdst = (struct BaseGroup *) pdst;
586  struct BaseGroup * gsrc = (struct BaseGroup *) psrc;
587  gdst->Length += gsrc->Length;
588  /* preserve the dst FirstPos so all other base group gets the same FirstPos */
589 }

References BaseGroup::Length.

Referenced by fof_compile_base().

Here is the caller graph for this function:

◆ fof_reduce_group()

static void fof_reduce_group ( void *  pdst,
void *  psrc 
)
static

Definition at line 591 of file fof.c.

591  {
592  struct Group * gdst = (struct Group *) pdst;
593  struct Group * gsrc = (struct Group *) psrc;
594  int j;
595  gdst->Length += gsrc->Length;
596  gdst->Mass += gsrc->Mass;
597 
598  for(j = 0; j < 6; j++)
599  {
600  gdst->LenType[j] += gsrc->LenType[j];
601  gdst->MassType[j] += gsrc->MassType[j];
602  }
603 
604  gdst->Sfr += gsrc->Sfr;
605  gdst->GasMetalMass += gsrc->GasMetalMass;
606  gdst->StellarMetalMass += gsrc->StellarMetalMass;
607  gdst->MassHeIonized += gsrc->MassHeIonized;
608  for(j = 0; j < NMETALS; j++) {
609  gdst->GasMetalElemMass[j] += gsrc->GasMetalElemMass[j];
610  gdst->StellarMetalElemMass[j] += gsrc->StellarMetalElemMass[j];
611  }
612  gdst->BH_Mdot += gsrc->BH_Mdot;
613  gdst->BH_Mass += gsrc->BH_Mass;
614  if(gsrc->MaxDens > gdst->MaxDens)
615  {
616  gdst->MaxDens = gsrc->MaxDens;
617  gdst->seed_index = gsrc->seed_index;
618  gdst->seed_task = gsrc->seed_task;
619  }
620 
621  int d1, d2;
622  for(d1 = 0; d1 < 3; d1++)
623  {
624  gdst->CM[d1] += gsrc->CM[d1];
625  gdst->Vel[d1] += gsrc->Vel[d1];
626  gdst->Jmom[d1] += gsrc->Jmom[d1];
627  for(d2 = 0; d2 < 3; d2 ++) {
628  gdst->Imom[d1][d2] += gsrc->Imom[d1][d2];
629  }
630  }
631 
632 }

References Group::BH_Mass, Group::BH_Mdot, Group::CM, Group::GasMetalElemMass, Group::GasMetalMass, Group::Imom, Group::Jmom, Group::Length, Group::LenType, Group::Mass, Group::MassHeIonized, Group::MassType, Group::MaxDens, NMETALS, Group::seed_index, Group::seed_task, Group::Sfr, Group::StellarMetalElemMass, Group::StellarMetalMass, and Group::Vel.

Referenced by fof_compile_catalogue().

Here is the caller graph for this function:

◆ fof_reduce_groups()

static void fof_reduce_groups ( void *  groups,
int  nmemb,
size_t  elsize,
void(*)(void *gdst, void *gsrc)  reduce_group,
MPI_Comm  Comm 
)
static

Definition at line 907 of file fof.c.

912 {
913 
914  int NTask, ThisTask;
915  MPI_Comm_size(Comm, &NTask);
916  MPI_Comm_rank(Comm, &ThisTask);
917  /* slangs:
918  * prime: groups hosted by ThisTask
919  * ghosts: groups that spans into ThisTask but not hosted by ThisTask;
920  * part of the local catalogue
921  * images: ghosts that are sent from another rank.
922  * images are reduced to prime, then the prime attributes
923  * are copied to images, and sent back to the ghosts.
924  *
925  * in the begining, prime and ghosts contains local group attributes.
926  * in the end, prime and ghosts all contain full group attributes.
927  **/
928  int * Send_count = ta_malloc("Send_count", int, NTask);
929  int * Recv_count = ta_malloc("Recv_count", int, NTask);
930 
931  void * images = NULL;
932  void * ghosts = NULL;
933  int i;
934  int start;
935 
936  MPI_Datatype dtype;
937 
938  MPI_Type_contiguous(elsize, MPI_BYTE, &dtype);
939  MPI_Type_commit(&dtype);
940 
941  /*Set global data for the comparison*/
943  /* local groups will be moved to the beginning, we skip them with offset */
944  qsort_openmp(groups, nmemb, elsize, fof_compare_Group_MinIDTask);
945  /* count how many we have of each task */
946  memset(Send_count, 0, sizeof(int) * NTask);
947 
948  for(i = 0; i < nmemb; i++) {
949  struct BaseGroup * gi = (struct BaseGroup *) (((char*) groups) + i * elsize);
950  Send_count[gi->MinIDTask]++;
951  }
952 
953  /* Skip local groups */
954  int Nmine = Send_count[ThisTask];
955  Send_count[ThisTask] = 0;
956 
957  MPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Comm);
958 
959  int nimport = 0;
960  for(i = 0; i < NTask; i ++) {
961  nimport += Recv_count[i];
962  }
963 
964  images = mymalloc("images", nimport * elsize);
965  ghosts = ((char*) groups) + elsize * Nmine;
966 
967  MPI_Alltoallv_smart(ghosts, Send_count, NULL, dtype,
968  images, Recv_count, NULL, dtype, Comm);
969 
970  for(i = 0; i < nimport; i++) {
971  struct BaseGroup * gi = (struct BaseGroup*) ((char*) images + i * elsize);
972  gi->OriginalIndex = i;
973  }
974 
975  /* sort the groups according to MinID */
976  qsort_openmp(groups, Nmine, elsize, fof_compare_Group_MinID);
977  qsort_openmp(images, nimport, elsize, fof_compare_Group_MinID);
978 
979  /* merge the imported ones with the local ones */
980  start = 0;
981  for(i = 0; i < Nmine; i++) {
982  for(;start < nimport; start++) {
983  struct BaseGroup * prime = (struct BaseGroup*) ((char*) groups + i * elsize);
984  struct BaseGroup * image = (struct BaseGroup*) ((char*) images + start * elsize);
985  if(image->MinID >= prime->MinID) {
986  break;
987  }
988  }
989  for(;start < nimport; start++) {
990  struct BaseGroup * prime = (struct BaseGroup*) ((char*) groups + i * elsize);
991  struct BaseGroup * image = (struct BaseGroup*) ((char*) images + start * elsize);
992  if(image->MinID != prime->MinID) {
993  break;
994  }
995  reduce_group(prime, image);
996  }
997  }
998 
999  /* update the images, such that they can be send back to the ghosts */
1000  start = 0;
1001  for(i = 0; i < Nmine; i++)
1002  {
1003  for(;start < nimport; start++) {
1004  struct BaseGroup * prime = (struct BaseGroup*) ((char*) groups + i * elsize);
1005  struct BaseGroup * image = (struct BaseGroup*) ((char*) images + start * elsize);
1006  if(image->MinID >= prime->MinID) {
1007  break;
1008  }
1009  }
1010  for(;start < nimport; start++) {
1011  struct BaseGroup * prime = (struct BaseGroup*) ((char*) groups + i * elsize);
1012  struct BaseGroup * image = (struct BaseGroup*) ((char*) images + start * elsize);
1013  if(image->MinID != prime->MinID) {
1014  break;
1015  }
1016  int save = image->OriginalIndex;
1017  memcpy(image, prime, elsize);
1018  image->OriginalIndex = save;
1019  }
1020  }
1021 
1022  /* reset the ordering of imported list, such that it can be properly returned */
1023  qsort_openmp(images, nimport, elsize, fof_compare_Group_OriginalIndex);
1024 
1025  for(i = 0; i < nimport; i++) {
1026  struct BaseGroup * gi = (struct BaseGroup*) ((char*) images + i * elsize);
1027  if(gi->MinIDTask != ThisTask) {
1028  abort();
1029  }
1030  }
1031  void * ghosts2 = mymalloc("TMP", nmemb * elsize);
1032 
1033  MPI_Alltoallv_smart(images, Recv_count, NULL, dtype,
1034  ghosts2, Send_count, NULL, dtype,
1035  Comm);
1036  for(i = 0; i < nmemb - Nmine; i ++) {
1037  struct BaseGroup * g1 = (struct BaseGroup*) ((char*) ghosts + i * elsize);
1038  struct BaseGroup * g2 = (struct BaseGroup*) ((char*) ghosts2 + i* elsize);
1039  if(g1->MinID != g2->MinID) {
1040  endrun(2, "g1 minID %lu, g2 minID %lu\n", g1->MinID, g2->MinID);
1041  }
1042  if(g1->MinIDTask != g2->MinIDTask) {
1043  endrun(2, "g1 minIDTask %d, g2 minIDTask %d\n", g1->MinIDTask, g2->MinIDTask);
1044  }
1045  }
1046  memcpy(ghosts, ghosts2, elsize * (nmemb - Nmine));
1047  myfree(ghosts2);
1048 
1049  myfree(images);
1050 
1051  MPI_Type_free(&dtype);
1052 
1053  /* At this point, each Group entry has the reduced attribute of the full group */
1054  /* And the local groups (MinIDTask == ThisTask) are placed at the begining of the list*/
1055  ta_free(Recv_count);
1056  ta_free(Send_count);
1057 }
static int fof_compare_Group_MinID(const void *a, const void *b)
Definition: fof.c:1415
static int fof_compare_Group_OriginalIndex(const void *a, const void *b)
Definition: fof.c:1442
static int fof_compare_Group_MinIDTask(const void *a, const void *b)
Definition: fof.c:1427
int OriginalIndex
Definition: fof.h:15
int MPI_Alltoallv_smart(void *sendbuf, int *sendcnts, int *sdispls, MPI_Datatype sendtype, void *recvbuf, int *recvcnts, int *rdispls, MPI_Datatype recvtype, MPI_Comm comm)
Definition: system.c:278

References _fof_compare_Group_MinIDTask_ThisTask, endrun(), fof_compare_Group_MinID(), fof_compare_Group_MinIDTask(), fof_compare_Group_OriginalIndex(), BaseGroup::MinID, BaseGroup::MinIDTask, MPI_Alltoallv_smart(), myfree, mymalloc, NTask, BaseGroup::OriginalIndex, qsort_openmp, ta_free, ta_malloc, and ThisTask.

Referenced by fof_compile_base(), and fof_compile_catalogue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_save_groups()

void fof_save_groups ( FOFGroups fof,
const char *  OutputDir,
const char *  FOFFileBase,
int  num,
Cosmology CP,
double  atime,
const double *  MassTable,
int  MetalReturnOn,
int  BlackholeOn,
MPI_Comm  Comm 
)

Definition at line 1113 of file fof.c.

1114 {
1115  fof_save_particles(fof, OutputDir, FOFFileBase, num, fof_params.FOFSaveParticles, CP, atime, MassTable, MetalReturnOn, BlackholeOn, Comm);
1116 }
void fof_save_particles(FOFGroups *fof, const char *OutputDir, const char *FOFFileBase, int num, int SaveParticles, Cosmology *CP, double atime, const double *MassTable, int MetalReturnOn, int BlackholeOn, MPI_Comm Comm)
Definition: fofpetaio.c:32
static Cosmology * CP
Definition: power.c:27
int FOFSaveParticles
Definition: fof.c:39

References CP, fof_params, fof_save_particles(), and FOFParams::FOFSaveParticles.

Referenced by run(), and runfof().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_secondary_copy()

static void fof_secondary_copy ( int  place,
TreeWalkQueryFOF I,
TreeWalk tw 
)
static

Definition at line 1128 of file fof.c.

1128  {
1129 
1130  I->Hsml = FOF_SECONDARY_GET_PRIV(tw)->hsml[place];
1131  I->MinID = FOF_SECONDARY_GET_PRIV(tw)->HaloLabel[place].MinID;
1132  I->MinIDTask = FOF_SECONDARY_GET_PRIV(tw)->HaloLabel[place].MinIDTask;
1133 }
MyFloat Hsml
Definition: fof.c:123

References FOF_SECONDARY_GET_PRIV, TreeWalkQueryFOF::Hsml, TreeWalkQueryFOF::MinID, and TreeWalkQueryFOF::MinIDTask.

Referenced by fof_label_secondary().

Here is the caller graph for this function:

◆ fof_secondary_haswork()

static int fof_secondary_haswork ( int  n,
TreeWalk tw 
)
static

Definition at line 1135 of file fof.c.

1135  {
1136  if(P[n].IsGarbage || P[n].Swallowed)
1137  return 0;
1138  /* Exclude particles where we already found a neighbour*/
1139  if(FOF_SECONDARY_GET_PRIV(tw)->distance[n] < 0.5 * LARGE)
1140  return 0;
1141  return ((1 << P[n].Type) & fof_params.FOFSecondaryLinkTypes);
1142 }
int FOFSecondaryLinkTypes
Definition: fof.c:46

References fof_params, FOF_SECONDARY_GET_PRIV, FOFParams::FOFSecondaryLinkTypes, LARGE, and P.

Referenced by fof_label_secondary().

Here is the caller graph for this function:

◆ fof_secondary_ngbiter()

static void fof_secondary_ngbiter ( TreeWalkQueryFOF I,
TreeWalkResultFOF O,
TreeWalkNgbIterFOF iter,
LocalTreeWalk lv 
)
static

Definition at line 1153 of file fof.c.

1157 {
1158  if(iter->base.other == -1) {
1159  O->Distance = LARGE;
1160  O->MinID = I->MinID;
1161  O->MinIDTask = I->MinIDTask;
1162  iter->base.Hsml = I->Hsml;
1165  return;
1166  }
1167  int other = iter->base.other;
1168  double r = iter->base.r;
1169  if(r < O->Distance)
1170  {
1171  O->Distance = r;
1172  O->MinID = FOF_SECONDARY_GET_PRIV(lv->tw)->HaloLabel[other].MinID;
1173  O->MinIDTask = FOF_SECONDARY_GET_PRIV(lv->tw)->HaloLabel[other].MinIDTask;
1174  }
1175  /* No need to search nodes at a greater distance
1176  * now that we have a neighbour.*/
1177  iter->base.Hsml = iter->base.r;
1178 }
MyFloat Distance
Definition: fof.c:131
MyIDType MinID
Definition: fof.c:132
int MinIDTask
Definition: fof.c:133

References TreeWalkNgbIterFOF::base, TreeWalkResultFOF::Distance, fof_params, FOF_SECONDARY_GET_PRIV, FOFParams::FOFPrimaryLinkTypes, TreeWalkQueryFOF::Hsml, TreeWalkNgbIterBase::Hsml, LARGE, TreeWalkNgbIterBase::mask, TreeWalkQueryFOF::MinID, TreeWalkResultFOF::MinID, TreeWalkQueryFOF::MinIDTask, TreeWalkResultFOF::MinIDTask, NGB_TREEFIND_ASYMMETRIC, TreeWalkNgbIterBase::other, TreeWalkNgbIterBase::r, TreeWalkNgbIterBase::symmetric, and LocalTreeWalk::tw.

Referenced by fof_label_secondary().

Here is the caller graph for this function:

◆ fof_secondary_postprocess()

static void fof_secondary_postprocess ( int  p,
TreeWalk tw 
)
static

Definition at line 1181 of file fof.c.

1182 {
1183  /* More work needed: add this particle to the redo queue*/
1184  int tid = omp_get_thread_num();
1185 
1186  if(FOF_SECONDARY_GET_PRIV(tw)->distance[p] > 0.5 * LARGE)
1187  {
1188  if(FOF_SECONDARY_GET_PRIV(tw)->hsml[p] < 4 * fof_params.FOFHaloComovingLinkingLength) /* we only search out to a maximum distance */
1189  {
1190  /* need to redo this particle */
1191  FOF_SECONDARY_GET_PRIV(tw)->npleft[tid]++;
1192  FOF_SECONDARY_GET_PRIV(tw)->hsml[p] *= 2.0;
1193 /*
1194  if(iter >= MAXITER - 10)
1195  {
1196  endrun(1, "i=%d task=%d ID=%llu Hsml=%g pos=(%g|%g|%g)\n",
1197  p, ThisTask, P[p].ID, FOF_SECONDARY_GET_PRIV(tw)->hsml[p],
1198  P[p].Pos[0], P[p].Pos[1], P[p].Pos[2]);
1199  }
1200 */
1201  } else {
1202  FOF_SECONDARY_GET_PRIV(tw)->distance[p] = -1; /* we not continue to search for this particle */
1203  }
1204  }
1205 }

References fof_params, FOF_SECONDARY_GET_PRIV, FOFParams::FOFHaloComovingLinkingLength, and LARGE.

Referenced by fof_label_secondary().

Here is the caller graph for this function:

◆ fof_secondary_reduce()

static void fof_secondary_reduce ( int  place,
TreeWalkResultFOF O,
enum TreeWalkReduceMode  mode,
TreeWalk tw 
)
static

Definition at line 1143 of file fof.c.

1143  {
1144  if(O->Distance < FOF_SECONDARY_GET_PRIV(tw)->distance[place] && O->Distance >= 0 && O->Distance < 0.5 * LARGE)
1145  {
1146  FOF_SECONDARY_GET_PRIV(tw)->distance[place] = O->Distance;
1147  FOF_SECONDARY_GET_PRIV(tw)->HaloLabel[place].MinID = O->MinID;
1148  FOF_SECONDARY_GET_PRIV(tw)->HaloLabel[place].MinIDTask = O->MinIDTask;
1149  }
1150 }

References TreeWalkResultFOF::Distance, FOF_SECONDARY_GET_PRIV, LARGE, TreeWalkResultFOF::MinID, and TreeWalkResultFOF::MinIDTask.

Referenced by fof_label_secondary().

Here is the caller graph for this function:

◆ fof_seed()

void fof_seed ( FOFGroups fof,
ActiveParticles act,
double  atime,
MPI_Comm  Comm 
)

Definition at line 1290 of file fof.c.

1291 {
1292  int i, j, n, ntot;
1293 
1294  int NTask;
1295  MPI_Comm_size(Comm, &NTask);
1296 
1297  char * Marked = (char *) mymalloc2("SeedMark", fof->Ngroups);
1298 
1299  int Nexport = 0;
1300  #pragma omp parallel for reduction(+:Nexport)
1301  for(i = 0; i < fof->Ngroups; i++)
1302  {
1303  Marked[i] =
1305  && (fof->Group[i].MassType[4] >= fof_params.MinMStarForNewSeed)
1306  && (fof->Group[i].LenType[5] == 0)
1307  && (fof->Group[i].seed_index >= 0);
1308 
1309  if(Marked[i]) Nexport ++;
1310  }
1311  struct Group * ExportGroups = (struct Group *) mymalloc("Export", sizeof(fof->Group[0]) * Nexport);
1312  j = 0;
1313  for(i = 0; i < fof->Ngroups; i ++) {
1314  if(Marked[i]) {
1315  ExportGroups[j] = fof->Group[i];
1316  j++;
1317  }
1318  }
1319  myfree(Marked);
1320 
1321  qsort_openmp(ExportGroups, Nexport, sizeof(ExportGroups[0]), cmp_seed_task);
1322 
1323  int * Send_count = ta_malloc("Send_count", int, NTask);
1324  int * Recv_count = ta_malloc("Recv_count", int, NTask);
1325 
1326  memset(Send_count, 0, NTask * sizeof(int));
1327  for(i = 0; i < Nexport; i++) {
1328  Send_count[ExportGroups[i].seed_task]++;
1329  }
1330 
1331  MPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Comm);
1332 
1333  int Nimport = 0;
1334 
1335  for(j = 0; j < NTask; j++)
1336  {
1337  Nimport += Recv_count[j];
1338  }
1339 
1340  struct Group * ImportGroups = (struct Group *)
1341  mymalloc2("ImportGroups", Nimport * sizeof(struct Group));
1342 
1343  MPI_Alltoallv_smart(ExportGroups, Send_count, NULL, MPI_TYPE_GROUP,
1344  ImportGroups, Recv_count, NULL, MPI_TYPE_GROUP,
1345  Comm);
1346 
1347  myfree(ExportGroups);
1348  ta_free(Recv_count);
1349  ta_free(Send_count);
1350 
1351  MPI_Allreduce(&Nimport, &ntot, 1, MPI_INT, MPI_SUM, Comm);
1352 
1353  message(0, "Making %d new black hole particles.\n", ntot);
1354 
1355  /* Do we have enough black hole slots to create this many black holes?
1356  * If not, allocate more slots. */
1357  if(Nimport + SlotsManager->info[5].size > SlotsManager->info[5].maxsize)
1358  {
1359  int *ActiveParticle_tmp=NULL;
1360  /* This is only called on a PM step, so the condition should never be true*/
1361  if(act->ActiveParticle) {
1362  ActiveParticle_tmp = (int *) mymalloc2("ActiveParticle_tmp", act->NumActiveParticle * sizeof(int));
1363  memmove(ActiveParticle_tmp, act->ActiveParticle, act->NumActiveParticle * sizeof(int));
1364  myfree(act->ActiveParticle);
1365  }
1366 
1367  /*Now we can extend the slots! */
1368  int64_t atleast[6];
1369  int64_t i;
1370  for(i = 0; i < 6; i++)
1371  atleast[i] = SlotsManager->info[i].maxsize;
1372  atleast[5] += ntot*1.1;
1373  slots_reserve(1, atleast, SlotsManager);
1374 
1375  /*And now we need our memory back in the right place*/
1376  if(ActiveParticle_tmp) {
1377  act->ActiveParticle = (int *) mymalloc("ActiveParticle", sizeof(int)*(act->NumActiveParticle + PartManager->MaxPart - PartManager->NumPart));
1378  memmove(act->ActiveParticle, ActiveParticle_tmp, act->NumActiveParticle * sizeof(int));
1379  myfree(ActiveParticle_tmp);
1380  }
1381  }
1382 
1383  int ThisTask;
1384  MPI_Comm_rank(Comm, &ThisTask);
1385 
1386  for(n = 0; n < Nimport; n++)
1387  {
1388  fof_seed_make_one(&ImportGroups[n], ThisTask, atime);
1389  }
1390 
1391  myfree(ImportGroups);
1392 
1393  walltime_measure("/FOF/Seeding");
1394 }
static void fof_seed_make_one(struct Group *g, int ThisTask, const double atime)
Definition: fof.c:1396
static int cmp_seed_task(const void *c1, const void *c2)
Definition: fof.c:1282
size_t slots_reserve(int where, int64_t atleast[6], struct slots_manager_type *sman)
Definition: slotsmanager.c:475
struct slots_manager_type SlotsManager[1]
Definition: slotsmanager.c:7
int * ActiveParticle
Definition: timestep.h:13
int64_t NumActiveParticle
Definition: timestep.h:12
double MinFoFMassForNewSeed
Definition: fof.c:40
double MinMStarForNewSeed
Definition: fof.c:41
int64_t maxsize
Definition: slotsmanager.h:11
int64_t size
Definition: slotsmanager.h:12
struct slot_info info[6]
Definition: slotsmanager.h:112

References ActiveParticles::ActiveParticle, cmp_seed_task(), fof_params, fof_seed_make_one(), FOFGroups::Group, slots_manager_type::info, Group::LenType, Group::Mass, Group::MassType, part_manager_type::MaxPart, slot_info::maxsize, message(), FOFParams::MinFoFMassForNewSeed, FOFParams::MinMStarForNewSeed, MPI_Alltoallv_smart(), MPI_TYPE_GROUP, myfree, mymalloc, mymalloc2, FOFGroups::Ngroups, NTask, ActiveParticles::NumActiveParticle, part_manager_type::NumPart, PartManager, qsort_openmp, Group::seed_index, Group::seed_task, slot_info::size, slots_reserve(), SlotsManager, ta_free, ta_malloc, ThisTask, and walltime_measure.

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fof_seed_make_one()

static void fof_seed_make_one ( struct Group g,
int  ThisTask,
const double  atime 
)
static

Definition at line 1396 of file fof.c.

1396  {
1397  if(g->seed_task != ThisTask) {
1398  endrun(7771, "Seed does not belong to the right task");
1399  }
1400  int index = g->seed_index;
1401  blackhole_make_one(index, atime);
1402 }
void blackhole_make_one(int index, const double atime)
Definition: blackhole.c:1576

References blackhole_make_one(), endrun(), Group::seed_index, Group::seed_task, and ThisTask.

Referenced by fof_seed().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fofp_merge()

static void fofp_merge ( int  target,
int  other,
TreeWalk tw 
)
static

Definition at line 483 of file fof.c.

484 {
485  /* this will lock h1 */
486  int * Head = FOF_PRIMARY_GET_PRIV(tw)->Head;
487  int h1, h2;
488  do {
489  h1 = HEADl(-1, target, Head);
490  /* Done if we find h1 along the path
491  * (because other is already in the same halo) */
492  h2 = HEADl(h1, other, Head);
493  if(h2 < 0)
494  return;
495  /* Ensure that we always merge to the lower entry.
496  * This avoids circular loops in the Head entries:
497  * a -> b -> a */
498  if(h1 > h2) {
499  int tmp = h2;
500  h2 = h1;
501  h1 = tmp;
502  }
503  /* Atomic compare exchange to make h2 a subtree of h1.
504  * Set Head[h2] = h1 iff Head[h2] is still h2. Otherwise loop.*/
505  } while(!__atomic_compare_exchange(&Head[h2], &h2, &h1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED));
506 
507  struct SpinLocks * spin = FOF_PRIMARY_GET_PRIV(tw)->spin;
508 
509  /* update MinID of h1: h2 is now just another child of h1
510  * so we don't need to check that h2 changes its head.
511  * It might happen that h1 is added to another halo at this point
512  * and the addition gets the wrong MinID.
513  * For this reason we recompute the MinIDs after the main treewalk.
514  * We also lock h2 for a copy in case it is the h1 in another thread,
515  * and may have inconsistent MinID and MinIDTask.*/
516 
517  /* Get a copy of h2 under the lock, which ensures
518  * that MinID and MinIDTask do not change independently. */
519  struct fof_particle_list * HaloLabel = FOF_PRIMARY_GET_PRIV(tw)->HaloLabel;
520  struct fof_particle_list h2label;
521  lock_spinlock(h2, spin);
522  h2label.MinID = HaloLabel[h2].MinID;
523  h2label.MinIDTask = HaloLabel[h2].MinIDTask;
524  unlock_spinlock(h2, spin);
525 
526  /* Now lock h1 so we don't change MinID but not MinIDTask.*/
527  lock_spinlock(h1, spin);
528  if(HaloLabel[h1].MinID > h2label.MinID)
529  {
530  HaloLabel[h1].MinID = h2label.MinID;
531  HaloLabel[h1].MinIDTask = h2label.MinIDTask;
532  }
533  unlock_spinlock(h1, spin);
534 
535  /* h1 must be the root of other and target both:
536  * do the splay to speed up future accesses.
537  * We do not need to have h2 locked, because h2 is
538  * now just another child of h1: these do not change the root,
539  * they make the tree shallow.*/
540  update_root(target, h1, Head);
541  update_root(other, h1, Head);
542 
543 }
static void update_root(int i, const int r, int *Head)
Definition: fof.c:314
static int HEADl(int stop, int i, const int *const Head)
Definition: fof.c:291

References FOF_PRIMARY_GET_PRIV, FOFPrimaryPriv::Head, HEADl(), lock_spinlock(), fof_particle_list::MinID, fof_particle_list::MinIDTask, spin, unlock_spinlock(), and update_root().

Referenced by fof_primary_ngbiter().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ HEAD()

static int HEAD ( int  i,
const int *const  Head 
)
static

Definition at line 333 of file fof.c.

334 {
335  int r = i;
336  while(Head[r] != r) {
337  r = Head[r];
338  }
339  return r;
340 }

Referenced by fof_label_primary(), fof_primary_copy(), and fof_primary_ngbiter().

Here is the caller graph for this function:

◆ HEADl()

static int HEADl ( int  stop,
int  i,
const int *const  Head 
)
static

Definition at line 291 of file fof.c.

292 {
293  int next = i;
294 
295  do {
296  i = next;
297  /* Reached stop, return*/
298  if(i == stop)
299  return -1;
300  /* atomic read because we may change
301  * this in update_root: not necessary on x86_64, but avoids tears elsewhere*/
302  #pragma omp atomic read
303  next = Head[i];
304  } while(next != i);
305 
306  /* return unmerged particle*/
307  return i;
308 }

Referenced by fofp_merge().

Here is the caller graph for this function:

◆ set_fof_params()

void set_fof_params ( ParameterSet ps)

Definition at line 50 of file fof.c.

51 {
52  int ThisTask;
53  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
54  if(ThisTask == 0) {
55  fof_params.FOFSaveParticles = param_get_int(ps, "FOFSaveParticles");
56  fof_params.FOFHaloLinkingLength = param_get_double(ps, "FOFHaloLinkingLength");
57  fof_params.FOFHaloMinLength = param_get_int(ps, "FOFHaloMinLength");
58  fof_params.MinFoFMassForNewSeed = param_get_double(ps, "MinFoFMassForNewSeed");
59  fof_params.MinMStarForNewSeed = param_get_double(ps, "MinMStarForNewSeed");
60  fof_params.FOFPrimaryLinkTypes = param_get_int(ps, "FOFPrimaryLinkTypes");
61  fof_params.FOFSecondaryLinkTypes = param_get_int(ps, "FOFSecondaryLinkTypes");
62  }
63  MPI_Bcast(&fof_params, sizeof(struct FOFParams), MPI_BYTE, 0, MPI_COMM_WORLD);
64 }
double param_get_double(ParameterSet *ps, const char *name)
Definition: paramset.c:336
int param_get_int(ParameterSet *ps, const char *name)
Definition: paramset.c:368
Definition: fof.c:38

References fof_params, FOFParams::FOFHaloLinkingLength, FOFParams::FOFHaloMinLength, FOFParams::FOFPrimaryLinkTypes, FOFParams::FOFSaveParticles, FOFParams::FOFSecondaryLinkTypes, FOFParams::MinFoFMassForNewSeed, FOFParams::MinMStarForNewSeed, param_get_double(), param_get_int(), and ThisTask.

Referenced by read_parameter_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_root()

static void update_root ( int  i,
const int  r,
int *  Head 
)
static

Definition at line 314 of file fof.c.

315 {
316  int t = i;
317  do {
318  i = t;
319  #pragma omp atomic capture
320  {
321  t = Head[i];
322  Head[i]= r;
323  }
324  /* Stop if we reached the top (new head is the same as the old)
325  * or if the new head is less than or equal to the desired head, indicating
326  * another thread changed us*/
327  } while(t != i && (t > r));
328 }

Referenced by fofp_merge().

Here is the caller graph for this function:

Variable Documentation

◆ _fof_compare_Group_MinIDTask_ThisTask

int _fof_compare_Group_MinIDTask_ThisTask
static

Definition at line 99 of file fof.c.

Referenced by fof_compare_Group_MinIDTask(), and fof_reduce_groups().

◆ fof_params

struct FOFParams fof_params

◆ MPI_TYPE_GROUP

MPI_Datatype MPI_TYPE_GROUP
static

Definition at line 142 of file fof.c.

Referenced by fof_finish(), fof_fof(), and fof_seed().