12#include "gadgetconfig.h"
16#include <gsl/gsl_math.h>
24#include "../data/allvars.h"
25#include "../data/dtypes.h"
26#include "../data/intposconvert.h"
27#include "../data/mymalloc.h"
28#include "../domain/domain.h"
29#include "../fof/fof.h"
30#include "../gravtree/gravtree.h"
31#include "../logs/timer.h"
32#include "../main/simulation.h"
33#include "../mpi_utils/mpi_utils.h"
34#include "../sort/cxxsort.h"
35#include "../sort/parallel_sort.h"
36#include "../sort/peano.h"
37#include "../subfind/subfind.h"
38#include "../system/system.h"
40#define MAX_UNBOUND_FRAC_BEFORE_BULK_VELOCITY_UPDATE 0.02
41#define MAX_UNBOUND_FRAC_BEFORE_POTENTIAL_UPDATE 0.20
47template <
typename partset>
48int fof<partset>::subfind_unbind(
domain<partset> *D, MPI_Comm Communicator,
int *d,
int num)
50 double fac_vel_to_phys, fac_hubbleflow, fac_comov_to_phys;
51 subfind_get_factors(fac_vel_to_phys, fac_hubbleflow, fac_comov_to_phys);
54 int commNTask, commThisTask;
55 MPI_Comm_size(Communicator, &commNTask);
56 MPI_Comm_rank(Communicator, &commThisTask);
58 typename partset::pdata *P = Tp->P;
62 int phaseflag = RECOMPUTE_ALL;
66 long long totnum = num;
67 MPI_Allreduce(MPI_IN_PLACE, &totnum, 1, MPI_LONG_LONG, MPI_SUM, Communicator);
72 int *dremoved = (
int *)
Mem.mymalloc(
"dremoved", num *
sizeof(
int));
73 double *potold = (
double *)
Mem.mymalloc(
"potold", num *
sizeof(
double));
77 FoFGravTree.treeallocate(Tp->NumPart, Tp, D);
79 if(phaseflag == RECOMPUTE_ALL)
81 FoFGravTree.treebuild(num, d);
85 FoFGravTree.treebuild(num_removed, dremoved);
87 for(
int i = 0; i < num; i++)
88 potold[i] = PS[d[i]].u.s.u.DM_Potential;
92 subfind_potential_compute(D, num, d);
94 FoFGravTree.treefree();
96 if(phaseflag == RECOMPUTE_ALL)
99 for(
int i = 0; i < num; i++)
101 int softtype = P[d[i]].getSofteningClass();
103 PS[d[i]].
u.s.
u.DM_Potential += Tp->P[d[i]].getMass() / (
All.
ForceSoftening[softtype] / 2.8);
104 PS[d[i]].
u.s.
u.DM_Potential *=
All.
G / fac_comov_to_phys;
110 for(
int i = 0; i < num; i++)
112 PS[d[i]].
u.s.
u.DM_Potential *=
All.
G / fac_comov_to_phys;
113 PS[d[i]].
u.s.
u.DM_Potential = potold[i] - PS[d[i]].
u.s.
u.DM_Potential;
133 for(
int i = 0; i < num; i++)
134 if(PS[d[i]].u.s.u.DM_Potential < local.pot)
136 local.pot = PS[d[i]].
u.s.
u.DM_Potential;
140 MPI_Allreduce(&local, &global, 1, MPI_DOUBLE_INT, MPI_MINLOC, Communicator);
144 if(commThisTask == global.rank)
145 for(
int j = 0; j < 3; j++)
146 intpos[j] = P[minindex].IntPos[j];
148 MPI_Bcast(intpos, 3 *
sizeof(
MyIntPosType), MPI_BYTE, global.rank, Communicator);
153 long long totunbound;
157 double massloc = 0, sloc[3] = {0, 0, 0}, vloc[3] = {0, 0, 0};
159 for(
int i = 0; i < num; i++)
161 int part_index = d[i];
164 Tp->nearest_image_intpos_to_pos(P[part_index].IntPos, intpos, dxyz);
166 for(
int j = 0; j < 3; j++)
167 sloc[j] += Tp->P[part_index].getMass() * dxyz[j];
169 for(
int j = 0; j < 3; j++)
170 vloc[j] += Tp->P[part_index].getMass() * P[part_index].Vel[j];
172 massloc += Tp->P[part_index].getMass();
175 double s[3], v[3], mass;
176 MPI_Allreduce(sloc, s, 3, MPI_DOUBLE, MPI_SUM, Communicator);
177 MPI_Allreduce(vloc, v, 3, MPI_DOUBLE, MPI_SUM, Communicator);
178 MPI_Allreduce(&massloc, &mass, 1, MPI_DOUBLE, MPI_SUM, Communicator);
180 for(
int j = 0; j < 3; j++)
187 Tp->pos_to_signedintpos(s, off);
191 int_cm[0] = off[0] + intpos[0];
192 int_cm[1] = off[1] + intpos[1];
193 int_cm[2] = off[2] + intpos[2];
195 double *bnd_energy = (
double *)
Mem.mymalloc(
"bnd_energy", num *
sizeof(
double));
198 for(
int i = 0; i < num; i++)
200 int part_index = d[i];
204 Tp->nearest_image_intpos_to_pos(P[part_index].IntPos, int_cm, dx);
208 for(
int j = 0; j < 3; j++)
210 dv[j] = fac_vel_to_phys * (P[part_index].Vel[j] - v[j]);
211 dv[j] += fac_hubbleflow * fac_comov_to_phys * dx[j];
214 PS[part_index].v.DM_BindingEnergy =
215 PS[part_index].
u.s.
u.DM_Potential + 0.5 * (dv[0] * dv[0] + dv[1] * dv[1] + dv[2] * dv[2]);
217 if(P[part_index].getType() == 0)
218 PS[part_index].v.DM_BindingEnergy += PS[part_index].Utherm;
220 bnd_energy[i] = PS[part_index].v.DM_BindingEnergy;
224 mycxxsort_parallel(bnd_energy, bnd_energy + num, subfind_compare_binding_energy, Communicator);
226 int *npart = (
int *)
Mem.mymalloc(
"npart", commNTask *
sizeof(
int));
227 MPI_Allgather(&num, 1, MPI_INT, npart, 1, MPI_INT, Communicator);
231 long long j = std::max<long long>(5, (
long long)(MAX_UNBOUND_FRAC_BEFORE_BULK_VELOCITY_UPDATE * totnum));
235 while(j >= npart[task])
243 if(commThisTask == task)
244 energy_limit = bnd_energy[j];
246 MPI_Allreduce(MPI_IN_PLACE, &energy_limit, 1, MPI_DOUBLE, MPI_MIN, Communicator);
251 for(
int i = 0; i < num; i++)
255 if(PS[p].v.DM_BindingEnergy > 0 && PS[p].v.DM_BindingEnergy > energy_limit)
259 dremoved[num_removed++] = d[i];
268 Mem.myfree(bnd_energy);
270 totunbound = num_unbound;
271 totremoved = num_removed;
274 MPI_Allreduce(MPI_IN_PLACE, &totunbound, 1, MPI_LONG_LONG, MPI_SUM, Communicator);
275 MPI_Allreduce(MPI_IN_PLACE, &totremoved, 1, MPI_LONG_LONG, MPI_SUM, Communicator);
276 MPI_Allreduce(MPI_IN_PLACE, &totnum, 1, MPI_LONG_LONG, MPI_SUM, Communicator);
278 while(totunbound > 0 && totnum >=
All.DesLinkNgb && totremoved < MAX_UNBOUND_FRAC_BEFORE_POTENTIAL_UPDATE * totnum);
282 if(iter > MAX_ITER_UNBIND)
285 if(phaseflag == RECOMPUTE_ALL)
288 phaseflag = UPDATE_ALL;
294 phaseflag = RECOMPUTE_ALL;
299 while(totremoved > 0 && totnum >=
All.DesLinkNgb);
302 Mem.myfree(dremoved);
308#include "../data/simparticles.h"
309template class fof<simparticles>;
311#if defined(LIGHTCONE) && defined(LIGHTCONE_PARTICLES_GROUPS)
312#include "../data/lcparticles.h"
313template class fof<lcparticles>;
global_data_all_processes All
#define MAX_DOUBLE_NUMBER
int32_t MySignedIntPosType
double mycxxsort_parallel(T *begin, T *end, Comp comp, MPI_Comm comm)
double ForceSoftening[NSOFTCLASSES+NSOFTCLASSES_HYDRO+2]