12#include "gadgetconfig.h"
17#include <gsl/gsl_math.h>
25#include "../data/allvars.h"
26#include "../data/dtypes.h"
27#include "../data/intposconvert.h"
28#include "../data/mymalloc.h"
29#include "../domain/domain.h"
30#include "../fof/fof.h"
31#include "../gravtree/gravtree.h"
32#include "../logs/timer.h"
33#include "../main/simulation.h"
34#include "../mpi_utils/generic_comm.h"
35#include "../mpi_utils/mpi_utils.h"
36#include "../sort/cxxsort.h"
37#include "../subfind/subfind.h"
38#include "../system/system.h"
46static bool subfind_ngb_compare_dist(
const r2type &a,
const r2type &b) {
return a.r2 < b.r2; }
49static double *Dist2list;
64template <
typename T_tree,
typename T_domain,
typename T_partset>
65class nearest_comm :
public generic_comm<nearest_in, nearest_out, T_tree, T_domain, T_partset>
75 nearest_comm(T_domain *dptr, T_tree *tptr, T_partset *pptr) : gcomm(dptr, tptr, pptr) {}
80 in->IntPos[0] = Tp->P[i].IntPos[0];
81 in->IntPos[1] = Tp->P[i].IntPos[1];
82 in->IntPos[2] = Tp->P[i].IntPos[2];
83 in->DM_Hsml = Tp->PS[i].v.DM_Hsml;
90 DM_NumNgb[i] = out->Ngb;
92 DM_NumNgb[i] += out->Ngb;
99 int evaluate(
int target,
int mode,
int thread_id,
int action, nearest_in *in,
int numnodes,
node_info *firstnode, nearest_out &out)
102 double hsml = in->DM_Hsml;
106 for(
int k = 0; k < numnodes; k++)
115 no = firstnode[k].
Node;
116 no = Tree->get_nodep(no)->nextnode;
119 unsigned int shmrank = Tree->TreeSharedMem_ThisTask;
123 if(no < Tree->MaxPart)
125 auto *P = Tree->get_Pp(no, shmrank);
127 no = Tree->get_nextnodep(shmrank)[no];
130 Tp->nearest_image_intpos_to_pos(P->IntPos, intpos, dxyz);
132 double h2 = hsml * hsml;
134 double r2 = dxyz[0] * dxyz[0];
138 r2 += dxyz[1] * dxyz[1];
142 r2 += dxyz[2] * dxyz[2];
146 if(numngb >= Tp->NumPart)
149 Dist2list[numngb++] = r2;
151 else if(no < Tree->MaxPart + Tree->MaxNodes)
155 if(no < Tree->FirstNonTopLevelNode)
160 gravnode *current = Tree->get_nodep(no, shmrank);
166 Tp->nearest_image_intpos_to_pos(current->
center.da, intpos,
171 double dist = hsml + lenhalf;
173 if(
fabs(dxyz[0]) > dist)
175 if(
fabs(dxyz[1]) > dist)
177 if(
fabs(dxyz[2]) > dist)
181 dist +=
FACT1 * 2.0 * lenhalf;
182 if(dxyz[0] * dxyz[0] + dxyz[1] * dxyz[1] + dxyz[2] * dxyz[2] > dist * dist)
198 Tree->tree_export_node_threads(no, target, &Thread);
201 no = Tree->Nextnode[no - Tree->MaxNodes];
208 if(numngb >=
All.DesLinkNgb)
210 r2type *R2list = (r2type *)
Mem.mymalloc(
"R2list",
sizeof(r2type) * numngb);
211 for(
int i = 0; i < numngb; i++)
213 R2list[i].r2 = Dist2list[i];
216 mycxxsort(R2list, R2list + numngb, subfind_ngb_compare_dist);
218 Tp->PS[target].v.DM_Hsml =
sqrt(R2list[
All.DesLinkNgb - 1].r2);
219 numngb =
All.DesLinkNgb;
221 for(
int i = 0; i < numngb; i++)
223 Dist2list[i] = R2list[i].r2;
235template <
typename partset>
236void fof<partset>::subfind_find_linkngb(
domain<partset> *SubDomain,
int num,
int *list)
238 subfind_collective_printf(
"SUBFIND: root-task=%d: Start find_linkngb. (%d particles on root-task)\n", ThisTask, num);
240 Dist2list = (
double *)
Mem.mymalloc(
"Dist2list", Tp->NumPart *
sizeof(
double));
243 DM_NumNgb = (
int *)
Mem.mymalloc_movable(&DM_NumNgb,
"DM_NumNgb",
sizeof(
int) * Tp->NumPart);
245 int *targetlist = (
int *)
Mem.mymalloc(
"targetlist", num *
sizeof(
int));
247 for(
int idx = 0; idx < num; idx++)
249 targetlist[idx] = list[idx];
252 Left[i] = Right[i] = 0;
255 nearest_comm<gravtree<partset>,
domain<partset>, partset> commpattern{SubDomain, &FoFGravTree, Tp};
269 for(
int idx = 0; idx < num; idx++)
271 int i = targetlist[idx];
275 if(DM_NumNgb[i] !=
All.DesLinkNgb && ((Right[i] - Left[i]) > 1.0e-6 * Left[i] || Left[i] == 0 || Right[i] == 0))
278 targetlist[npleft++] = i;
280 if(DM_NumNgb[i] <
All.DesLinkNgb)
281 Left[i] = std::max<double>(Tp->PS[i].v.DM_Hsml, Left[i]);
286 if(Tp->PS[i].v.DM_Hsml < Right[i])
287 Right[i] = Tp->PS[i].v.DM_Hsml;
290 Right[i] = Tp->PS[i].v.DM_Hsml;
296 Tp->intpos_to_pos(Tp->P[i].IntPos, pos);
298 printf(
"i=%d task=%d ID=%d DM_Hsml=%g Left=%g Right=%g Right-Left=%g\n pos=(%g|%g|%g)\n", i, ThisTask,
299 (
int)Tp->P[i].ID.get(), Tp->PS[i].v.DM_Hsml, Left[i], Right[i], (
double)(Right[i] - Left[i]), pos[0], pos[1],
304 if(Right[i] > 0 && Left[i] > 0)
305 Tp->PS[i].v.DM_Hsml =
pow(0.5 * (
pow(Left[i], 3) +
pow(Right[i], 3)), 1.0 / 3);
308 if(Right[i] == 0 && Left[i] == 0)
311 if(Right[i] == 0 && Left[i] > 0)
312 Tp->PS[i].v.DM_Hsml *= 1.26;
314 if(Right[i] > 0 && Left[i] == 0)
315 Tp->PS[i].v.DM_Hsml /= 1.26;
331 subfind_collective_printf(
332 "SUBFIND: root-task=%d: find linkngb iteration %d, need to repeat for %lld particles. (took %g sec)\n", ThisTask, iter,
336 Terminate(
"failed to converge in neighbour iteration in density_findlinkngb()\n");
341 Mem.myfree(targetlist);
342 Mem.myfree(DM_NumNgb);
346 Mem.myfree(Dist2list);
348 subfind_collective_printf(
"SUBFIND: root-task=%d: Done with find_linkngb\n", ThisTask);
352#include "../data/simparticles.h"
353template class fof<simparticles>;
355#if defined(LIGHTCONE) && defined(LIGHTCONE_PARTICLES_GROUPS)
356#include "../data/lcparticles.h"
357template 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_LOCAL_PARTICLES
double mycxxsort(T *begin, T *end, Tcomp comp)
#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)