12#include "gadgetconfig.h"
22#include "../data/allvars.h"
23#include "../data/dtypes.h"
24#include "../data/intposconvert.h"
25#include "../data/mymalloc.h"
26#include "../domain/domain.h"
27#include "../fof/fof.h"
28#include "../gravtree/gravtree.h"
29#include "../logs/timer.h"
30#include "../main/simulation.h"
31#include "../mpi_utils/generic_comm.h"
32#include "../subfind/subfind.h"
33#include "../system/system.h"
35static double *R200, *M200;
49template <
typename T_tree,
typename T_domain,
typename T_partset>
50class sodata_comm :
public generic_comm<sodata_in, sodata_out, T_tree, T_domain, T_partset>
59 typename fof<T_partset>::group_properties *Group;
62 sodata_comm(T_domain *dptr, T_tree *tptr, T_partset *pptr,
typename fof<T_partset>::group_properties *grpptr)
63 : gcomm(dptr, tptr, pptr)
71 in->IntPos[0] = Group[i].IntPos[0];
72 in->IntPos[1] = Group[i].IntPos[1];
73 in->IntPos[2] = Group[i].IntPos[2];
79 void out2particle(sodata_out *out,
int i,
int mode)
override
91 int evaluate(
int target,
int mode,
int thread_id,
int action, sodata_in *in,
int numnodes,
node_info *firstnode,
92 sodata_out &out)
override
95 double hsml = in->R200;
99 for(
int k = 0; k < numnodes; k++)
109 no = firstnode[k].
Node;
110 no = Tree->get_nodep(no)->nextnode;
113 unsigned int shmrank = Tree->TreeSharedMem_ThisTask;
117 if(no < Tree->MaxPart)
119 auto P = Tree->get_Pp(no, shmrank);
121 no = Tree->get_nextnodep(shmrank)[no];
124 Tp->nearest_image_intpos_to_pos(P->IntPos, intpos, dxyz);
126 double h2 = hsml * hsml;
128 double r2 = dxyz[0] * dxyz[0];
132 r2 += dxyz[1] * dxyz[1];
136 r2 += dxyz[2] * dxyz[2];
140 mass += P->getMass();
142 else if(no < Tree->MaxPart + Tree->MaxNodes)
147 if(no < Tree->FirstNonTopLevelNode)
151 gravnode *current = Tree->get_nodep(no, shmrank);
158 Tp->nearest_image_intpos_to_pos(current->
center.da, intpos, dxyz);
162 double dist = hsml + lenhalf;
164 if(
fabs(dxyz[0]) > dist)
166 if(
fabs(dxyz[1]) > dist)
168 if(
fabs(dxyz[2]) > dist)
172 dist +=
FACT1 * 2.0 * lenhalf;
174 double r2 = dxyz[0] * dxyz[0] + dxyz[1] * dxyz[1] + dxyz[2] * dxyz[2];
179 if(no >= Tree->FirstNonTopLevelNode)
188 mass += current->
mass;
196 else if(no >= Tree->ImportedNodeOffset)
198 int n = no - Tree->ImportedNodeOffset;
199 no = Tree->Nextnode[no - Tree->MaxNodes];
203 Tp->nearest_image_intpos_to_pos(Tree->Points[n].IntPos, intpos,
206 double h2 = hsml * hsml;
208 double r2 = dxyz[0] * dxyz[0];
212 r2 += dxyz[1] * dxyz[1];
216 r2 += dxyz[2] * dxyz[2];
220 mass += Tree->Points[n].Mass;
225 Tree->tree_export_node_threads(no, target, &Thread);
227 no = Tree->Nextnode[no - Tree->MaxNodes];
238template <
typename partset>
239double fof<partset>::subfind_get_overdensity_value(
int type,
double ascale)
241 double z = 1 / ascale - 1;
244 double x = omegaz - 1;
252 return (18 *
M_PI *
M_PI + 82 * x - 39 * x * x) / omegaz;
256 return 200.0 / omegaz;
260 return 500.0 / omegaz;
268template <
typename partset>
269double fof<partset>::subfind_overdensity(
void)
271 int *TargetList = (
int *)
Mem.mymalloc(
"TargetList", Ngroups *
sizeof(
int));
273 double *Left = (
double *)
Mem.mymalloc(
"Left",
sizeof(
double) * Ngroups);
274 double *Right = (
double *)
Mem.mymalloc(
"Right",
sizeof(
double) * Ngroups);
276 R200 = (
double *)
Mem.mymalloc(
"R200",
sizeof(
double) * Ngroups);
277 M200 = (
double *)
Mem.mymalloc(
"M200",
sizeof(
double) * Ngroups);
283 sodata_comm<gravtree<partset>,
domain<partset>, partset> commpattern{FoFDomain, &FoFGravTree, Tp, Group};
285 for(
int rep = 0; rep < 4; rep++)
289 for(
int i = 0; i < Ngroups; i++)
291 if(Group[i].Nsubs > 0)
295 TargetList[Nso++] = i;
297 Right[i] = 3 * rguess;
300 R200[i] = 0.5 * (Left[i] + Right[i]);
316 for(
int n = 0; n < Nso; n++)
318 int i = TargetList[n];
320 double overdensity = M200[i] / (4.0 *
M_PI / 3.0 * R200[i] * R200[i] * R200[i]) / rhoback;
322 if((Right[i] - Left[i]) > 1.0e-4 * Left[i])
325 TargetList[npleft++] = i;
327 double delta = subfind_get_overdensity_value(rep, Group[i].Ascale);
328 if(overdensity > delta)
333 R200[i] = 0.5 * (Left[i] + Right[i]);
337 printf(
"gr=%d task=%d R200=%g Left=%g Right=%g Menclosed=%g Right-Left=%g\n pos=(%g|%g|%g)\n", i, ThisTask,
338 R200[i], Left[i], Right[i], M200[i], Right[i] - Left[i], Group[i].Pos[0], Group[i].Pos[1],
356 mpi_printf(
"SUBFIND: SO iteration %2d: need to repeat for %12lld halo centers. (took %g sec)\n", iter, ntot,
360 Terminate(
"failed to converge in SO iteration");
365 for(
int i = 0; i < Ngroups; i++)
367 if(Group[i].Nsubs > 0)
369 double overdensity = M200[i] / (4.0 *
M_PI / 3.0 * R200[i] * R200[i] * R200[i]) / rhoback;
371 double delta = subfind_get_overdensity_value(rep, Group[i].Ascale);
373 if((overdensity - delta) > 0.1 * delta)
375 R200[i] = M200[i] = 0;
377 else if(M200[i] < 5 * Group[i].Mass / Group[i].Len)
379 R200[i] = M200[i] = 0;
383 R200[i] = M200[i] = 0;
388 Group[i].M_Mean200 = M200[i];
389 Group[i].R_Mean200 = R200[i];
392 Group[i].M_TopHat200 = M200[i];
393 Group[i].R_TopHat200 = R200[i];
396 Group[i].M_Crit200 = M200[i];
397 Group[i].R_Crit200 = R200[i];
400 Group[i].M_Crit500 = M200[i];
401 Group[i].R_Crit500 = R200[i];
411 Mem.myfree(TargetList);
418#include "../data/simparticles.h"
419template class fof<simparticles>;
421#if defined(LIGHTCONE) && defined(LIGHTCONE_PARTICLES_GROUPS)
422#include "../data/lcparticles.h"
423template class fof<lcparticles>;
global_data_all_processes All
virtual void out2particle(T_out *out, int i, int mode)=0
virtual void particle2in(T_in *in, int i)=0
virtual int evaluate(int target, int mode, int thread_id, int action, T_in *in, int numnodes, node_info *firstnode, T_out &out)=0
double timediff(double t0, double t1)
#define MODE_IMPORTED_PARTICLES
#define MODE_LOCAL_PARTICLES
#define BITS_FOR_POSITIONS
void sumup_large_ints(int n, int *src, long long *res, MPI_Comm comm)
expr pow(half base, half exp)
unsigned char nextnode_shmrank
vector< MyIntPosType > center
unsigned char sibling_shmrank
void myflush(FILE *fstream)