9 #include <gsl/gsl_math.h>
53 MPI_Comm_rank(MPI_COMM_WORLD, &
ThisTask);
73 if(x >= 0.5 * BoxSize)
75 if(x < -0.5 * BoxSize)
107 void (*reduce_group)(
void * gdst,
void * gsrc), MPI_Comm Comm);
114 static struct Group *
155 message(0,
"Begin to compute FoF group catalogues. (allocated: %g MB)\n",
165 #pragma omp parallel for
178 message(0,
"Group finding done.\n");
186 message(0,
"Attached gas and star particles to nearest dm particles.\n");
196 if(i == 0 || HaloLabel[i].
MinID != HaloLabel[i - 1].
MinID) NgroupsExt ++;
206 message(0,
"Compiled local group data and catalogue.\n");
214 #pragma omp parallel for
219 for(i = 0; i < NgroupsExt; i++)
246 message(0,
"Finished FoF. Group properties are now allocated.. (presently allocated=%g MB)\n",
261 message(0,
"Finished computing FoF groups. (presently allocated=%g MB)\n",
276 #define FOF_PRIMARY_GET_PRIV(tw) ((struct FOFPrimaryPriv *) (tw->priv))
291 HEADl(
int stop,
int i,
const int *
const Head)
302 #pragma omp atomic read
319 #pragma omp atomic capture
327 }
while(t != i && (t > r));
333 HEAD(
int i,
const int *
const Head)
336 while(Head[r] != r) {
358 if(
P[n].IsGarbage ||
P[n].Swallowed)
373 int64_t link_across_tot;
402 #pragma omp parallel for
427 #pragma omp parallel for
434 #pragma omp atomic read
440 #pragma omp atomic write
450 #pragma omp parallel for reduction(+: link_across)
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);
471 while(link_across_tot > 0);
475 message(0,
"Local groups found.\n");
505 }
while(!__atomic_compare_exchange(&
Head[h2], &h2, &h1, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED));
574 if(HaloLabel[head].MinID > I->
MinID)
598 for(j = 0; j < 6; j++)
622 for(d1 = 0; d1 < 3; d1++)
624 gdst->
CM[d1] += gsrc->
CM[d1];
625 gdst->
Vel[d1] += gsrc->
Vel[d1];
627 for(d2 = 0; d2 < 3; d2 ++) {
628 gdst->
Imom[d1][d2] += gsrc->
Imom[d1][d2];
640 memset(gdst, 0,
sizeof(gdst[0]));
646 gdst->
Mass +=
P[index].Mass;
648 gdst->
MassType[
P[index].Type] +=
P[index].Mass;
650 if(
P[index].Type == 0) {
658 if(
P[index].Type == 4) {
665 if(
P[index].Type == 5)
687 for(d1 = 0; d1 < 3; d1++)
691 xyz[d1] = rel[d1] + first;
692 vel[d1] =
P[index].Vel[d1];
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];
702 for(d2 = 0; d2 < 3; d2++) {
703 gdst->
Imom[d1][d2] +=
P[index].Mass * rel[d1] * rel[d2];
713 for(i = 0; i < fof->
Ngroups; i++)
722 for(d1 = 0; d1 < 3; d1++)
725 vcm[d1] = gdst->
Vel[d1];
726 cm[d1] = gdst->
CM[d1] / gdst->
Mass;
731 gdst->
CM[d1] = cm[d1];
736 for(d1 = 0; d1 < 3; d1 ++) {
737 gdst->
Jmom[d1] -= jcm[d1] * gdst->
Mass;
740 for(d1 = 0; d1 < 3; d1 ++) {
741 for(d2 = 0; d2 < 3; d2++) {
751 double diff = rel[d1] * rel[d2];
753 gdst->
Imom[d1][d2] -= gdst->
Mass * diff;
763 memset(
base, 0,
sizeof(
base[0]) * NgroupsExt);
771 if(i == 0 || HaloLabel[i].MinID != HaloLabel[i - 1].MinID) {
775 for(d = 0; d < 3; d ++) {
785 for(i = 0; i < NgroupsExt; i++)
789 if(HaloLabel[start].MinID >=
base[i].MinID)
break;
793 if(HaloLabel[start].MinID !=
base[i].MinID) {
804 for(i = 0; i < NgroupsExt; i++)
818 static struct Group *
823 memset(
Group, 0,
sizeof(
Group[0]) * NgroupsExt);
827 #pragma omp parallel for
828 for(i = 0; i < NgroupsExt; i ++) {
842 for(i = 0; i < NgroupsExt; i++)
863 for(i = 0; i < NgroupsExt; i ++) {
879 MPI_Allreduce(&Nids, &TotNids, 1,
MPI_INT64, MPI_SUM, Comm);
882 int largestloc_tot = 0;
883 double largestmass_tot= 0;
886 double largestmass = 0;
887 int largestlength = 0;
889 for(i = 0; i < NgroupsExt; i++)
894 MPI_Allreduce(&largestlength, &largestloc_tot, 1, MPI_INT, MPI_MAX, Comm);
895 MPI_Allreduce(&largestmass, &largestmass_tot, 1, MPI_DOUBLE, MPI_MAX, Comm);
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);
911 void (*reduce_group)(
void * gdst,
void * gsrc), MPI_Comm Comm)
915 MPI_Comm_size(Comm, &
NTask);
931 void * images = NULL;
932 void * ghosts = NULL;
938 MPI_Type_contiguous(elsize, MPI_BYTE, &dtype);
939 MPI_Type_commit(&dtype);
946 memset(Send_count, 0,
sizeof(
int) *
NTask);
948 for(i = 0; i < nmemb; i++) {
957 MPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Comm);
960 for(i = 0; i <
NTask; i ++) {
961 nimport += Recv_count[i];
964 images =
mymalloc(
"images", nimport * elsize);
965 ghosts = ((
char*) groups) + elsize * Nmine;
968 images, Recv_count, NULL, dtype, Comm);
970 for(i = 0; i < nimport; i++) {
981 for(i = 0; i < Nmine; i++) {
982 for(;start < nimport; start++) {
989 for(;start < nimport; start++) {
995 reduce_group(prime, image);
1001 for(i = 0; i < Nmine; i++)
1003 for(;start < nimport; start++) {
1010 for(;start < nimport; start++) {
1017 memcpy(image, prime, elsize);
1025 for(i = 0; i < nimport; i++) {
1031 void * ghosts2 =
mymalloc(
"TMP", nmemb * elsize);
1034 ghosts2, Send_count, NULL, dtype,
1036 for(i = 0; i < nmemb - Nmine; i ++) {
1046 memcpy(ghosts, ghosts2, elsize * (nmemb - Nmine));
1051 MPI_Type_free(&dtype);
1066 MPI_Comm_size(Comm, &
NTask);
1069 #pragma omp parallel for
1070 for(i = 0; i < NgroupsExt; i++)
1075 mpsort_mpi(base, NgroupsExt,
sizeof(base[0]),
1084 for(i = 0; i < NgroupsExt; i++)
1097 int64_t groffset = 0;
1098 #pragma omp parallel for reduction(+: groffset)
1100 groffset += ngra[j];
1101 #pragma omp parallel for
1102 for(i = 0; i < NgroupsExt; i++)
1103 base[i].
GrNr += groffset;
1108 mpsort_mpi(base, NgroupsExt,
sizeof(base[0]),
1113 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)
1115 fof_save_particles(fof, OutputDir, FOFFileBase, num,
fof_params.
FOFSaveParticles,
CP, atime, MassTable, MetalReturnOn, BlackholeOn, Comm);
1126 #define FOF_SECONDARY_GET_PRIV(tw) ((struct FOFSecondaryPriv *) (tw->priv))
1136 if(
P[n].IsGarbage ||
P[n].Swallowed)
1168 double r = iter->
base.
r;
1184 int tid = omp_get_thread_num();
1228 message(0,
"Start finding nearest dm-particle (presently allocated=%g MB)\n",
1235 #pragma omp parallel for
1251 message(0,
"fof-nearest iteration started\n");
1252 int NumThreads = omp_get_max_threads();
1261 for(n = 1; n < NumThreads; n++) {
1267 endrun(1159,
"Failed to converge in fof-nearest: ntot %ld", ntot);
1283 const struct Group * g1 = (
const struct Group *) c1;
1284 const struct Group * g2 = (
const struct Group *) c2;
1295 MPI_Comm_size(Comm, &
NTask);
1300 #pragma omp parallel for reduction(+:Nexport)
1301 for(i = 0; i < fof->
Ngroups; i++)
1309 if(Marked[i]) Nexport ++;
1313 for(i = 0; i < fof->
Ngroups; i ++) {
1315 ExportGroups[j] = fof->
Group[i];
1326 memset(Send_count, 0,
NTask *
sizeof(
int));
1327 for(i = 0; i < Nexport; i++) {
1328 Send_count[ExportGroups[i].
seed_task]++;
1331 MPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Comm);
1335 for(j = 0; j <
NTask; j++)
1337 Nimport += Recv_count[j];
1340 struct Group * ImportGroups = (
struct Group *)
1351 MPI_Allreduce(&Nimport, &ntot, 1, MPI_INT, MPI_SUM, Comm);
1353 message(0,
"Making %d new black hole particles.\n", ntot);
1359 int *ActiveParticle_tmp=NULL;
1370 for(i = 0; i < 6; i++)
1372 atleast[5] += ntot*1.1;
1376 if(ActiveParticle_tmp) {
1379 myfree(ActiveParticle_tmp);
1386 for(n = 0; n < Nimport; n++)
1398 endrun(7771,
"Seed does not belong to the right task");
1436 if(t1 < t2)
return -1;
1437 if(t1 > t2)
return +1;
1445 return ((
struct BaseGroup *) a)->OriginalIndex - ((
struct BaseGroup *) b)->OriginalIndex;
1449 uint64_t * u = (uint64_t *) radix;
1453 u[2] = UINT64_MAX - (f->
Length);
1457 uint64_t * u = (uint64_t *) radix;
void blackhole_make_one(int index, const double atime)
static void crossproduct(const double v1[3], const double v2[3], double out[3])
void message(int where, const char *fmt,...)
void endrun(int where, const char *fmt,...)
static int fof_compare_Group_MinID(const void *a, const void *b)
static void update_root(int i, const int r, int *Head)
static void fof_compile_catalogue(FOFGroups *fof, const int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
static struct Group * fof_alloc_group(const struct BaseGroup *base, const int NgroupsExt)
static int fof_primary_haswork(int n, TreeWalk *tw)
#define FOF_SECONDARY_GET_PRIV(tw)
static int fof_compare_Group_OriginalIndex(const void *a, const void *b)
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 int fof_secondary_haswork(int n, TreeWalk *tw)
static int fof_compare_HaloLabel_MinID(const void *a, const void *b)
static double fof_periodic(double x, double BoxSize)
static void fof_radix_Group_OriginalTaskMinID(const void *a, void *radix, void *arg)
static int fof_compile_base(struct BaseGroup *base, int NgroupsExt, struct fof_particle_list *HaloLabel, MPI_Comm Comm)
static void fof_secondary_postprocess(int p, TreeWalk *tw)
static void fof_secondary_copy(int place, TreeWalkQueryFOF *I, TreeWalk *tw)
static void fof_radix_Group_TotalCountTaskDiffMinID(const void *a, void *radix, void *arg)
void set_fof_params(ParameterSet *ps)
static void fof_seed_make_one(struct Group *g, int ThisTask, const double atime)
static void add_particle_to_group(struct Group *gdst, int i, int ThisTask)
static void fof_finish_group_properties(FOFGroups *fof, double BoxSize)
static void fof_primary_ngbiter(TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
static void fof_secondary_reduce(int place, TreeWalkResultFOF *O, enum TreeWalkReduceMode mode, TreeWalk *tw)
void fof_init(double DMMeanSeparation)
static int HEADl(int stop, int i, const int *const Head)
static int HEAD(int i, const int *const Head)
static int cmp_seed_task(const void *c1, const void *c2)
static int _fof_compare_Group_MinIDTask_ThisTask
static int fof_compare_Group_MinIDTask(const void *a, const void *b)
void fof_finish(FOFGroups *fof)
static void fof_reduce_group(void *pdst, void *psrc)
static void fof_secondary_ngbiter(TreeWalkQueryFOF *I, TreeWalkResultFOF *O, TreeWalkNgbIterFOF *iter, LocalTreeWalk *lv)
static void fof_primary_copy(int place, TreeWalkQueryFOF *I, TreeWalk *tw)
static double fof_periodic_wrap(double x, double BoxSize)
void fof_seed(FOFGroups *fof, ActiveParticles *act, double atime, MPI_Comm Comm)
static MPI_Datatype MPI_TYPE_GROUP
static void fof_label_secondary(struct fof_particle_list *HaloLabel, ForceTree *tree)
void fof_label_primary(struct fof_particle_list *HaloLabel, ForceTree *tree, MPI_Comm Comm)
static void fofp_merge(int target, int other, TreeWalk *tw)
static void fof_reduce_base_group(void *pdst, void *psrc)
#define FOF_PRIMARY_GET_PRIV(tw)
static void fof_assign_grnr(struct BaseGroup *base, const int NgroupsExt, MPI_Comm Comm)
static void fof_reduce_groups(void *groups, int nmemb, size_t elsize, void(*reduce_group)(void *gdst, void *gsrc), MPI_Comm Comm)
FOFGroups fof_fof(DomainDecomp *ddecomp, const int StoreGrNr, MPI_Comm Comm)
struct FOFParams fof_params
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)
void force_tree_rebuild_mask(ForceTree *tree, DomainDecomp *ddecomp, int mask, const int HybridNuGrav, const char *EmergencyOutputDir)
void force_tree_free(ForceTree *tree)
#define mpsort_mpi(base, nmemb, elsize, radix, rsize, arg, comm)
#define mymalloc(name, size)
#define ta_malloc(name, type, nele)
#define mymalloc2(name, size)
#define mymalloc_usedbytes()
double param_get_double(ParameterSet *ps, const char *name)
int param_get_int(ParameterSet *ps, const char *name)
struct part_manager_type PartManager[1]
size_t slots_reserve(int where, int64_t atleast[6], struct slots_manager_type *sman)
struct slots_manager_type SlotsManager[1]
void free_spinlocks(struct SpinLocks *spin)
void lock_spinlock(int i, struct SpinLocks *spin)
struct SpinLocks * init_spinlocks(int NumLock)
static struct SpinLocks spin
void unlock_spinlock(int i, struct SpinLocks *spin)
int64_t NumActiveParticle
double FOFHaloComovingLinkingLength
double MinFoFMassForNewSeed
int FOFSecondaryLinkTypes
double MinMStarForNewSeed
double FOFHaloLinkingLength
struct fof_particle_list * HaloLabel
struct fof_particle_list * HaloLabel
float GasMetalElemMass[NMETALS]
float StellarMetalElemMass[NMETALS]
enum NgbTreeFindSymmetric symmetric
int NodeList[NODELISTLENGTH]
TreeWalkHasWorkFunction haswork
size_t ngbiter_type_elsize
TreeWalkProcessFunction postprocess
TreeWalkNgbIterFunction ngbiter
TreeWalkReduceResultFunction reduce
TreeWalkVisitFunction visit
size_t result_type_elsize
TreeWalkFillQueryFunction fill
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)
void sumup_large_ints(int n, int *src, int64_t *res)
#define MPIU_Barrier(comm)
int treewalk_visit_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
int treewalk_visit_nolist_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
int(* TreeWalkVisitFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, LocalTreeWalk *lv)
void(* TreeWalkReduceResultFunction)(const int j, TreeWalkResultBase *result, const enum TreeWalkReduceMode mode, TreeWalk *tw)
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
void(* TreeWalkNgbIterFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, TreeWalkNgbIterBase *iter, LocalTreeWalk *lv)
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
@ NGB_TREEFIND_ASYMMETRIC
#define walltime_measure(name)
int winds_is_particle_decoupled(int i)