GADGET-4
fof_nearest.cc
Go to the documentation of this file.
1 /*******************************************************************************
2  * \copyright This file is part of the GADGET4 N-body/SPH code developed
3  * \copyright by Volker Springel. Copyright (C) 2014-2020 by Volker Springel
4  * \copyright (vspringel@mpa-garching.mpg.de) and all contributing authors.
5  *******************************************************************************/
6 
12 #include "gadgetconfig.h"
13 
14 #ifdef FOF
15 
16 #include <math.h>
17 #include <mpi.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
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 "../logs/timer.h"
29 #include "../main/simulation.h"
30 #include "../mpi_utils/generic_comm.h"
31 #include "../ngbtree/ngbtree.h"
32 #include "../system/system.h"
33 
34 /* local data structure for collecting particle/cell data that is sent to other processors if needed */
35 
36 struct fofdata_in : data_in_generic
37 {
38  MyIntPosType IntPos[3];
39  MyFloat Hsml;
40 };
41 
42 /* local data structure that holds results acquired on remote processors */
43 struct fofdata_out
44 {
45  MyFloat Distance;
46  MyIDStorage MinID;
47  int MinIDTask;
48 #if defined(SUBFIND)
49  MyFloat DM_Hsml;
50 #endif
51 };
52 
53 template <typename T_tree, typename T_domain, typename T_partset>
54 class fofdata_comm : public generic_comm<fofdata_in, fofdata_out, T_tree, T_domain, T_partset>
55 {
56  public:
58  using gcomm::D;
59  using gcomm::Thread;
60  using gcomm::Tp; // This makes sure that we can access Tp from the base class without having to use "this->Tp"
61  using gcomm::Tree;
62 
63  /* need to call the base class constructor explicitly */
64  fofdata_comm(T_domain *dptr, T_tree *tptr, T_partset *pptr)
65  : generic_comm<fofdata_in, fofdata_out, T_tree, T_domain, T_partset>(dptr, tptr, pptr)
66  {
67  }
68 
69  /* routine that fills the relevant particle/cell data into the input structure defined above */
70  void particle2in(fofdata_in *in, int i)
71  {
72  for(int k = 0; k < 3; k++)
73  in->IntPos[k] = Tp->P[i].IntPos[k];
74 
75  in->Hsml = Tp->fof_nearest_hsml[i];
76  }
77 
78  /* routine to store or combine result data */
79  void out2particle(fofdata_out *out, int i, int mode)
80  {
81  if(out->Distance < Tp->fof_nearest_distance[i])
82  {
83  Tp->fof_nearest_distance[i] = out->Distance;
84  Tp->MinID[i] = out->MinID;
85  Tp->MinIDTask[i] = out->MinIDTask;
86 #if defined(SUBFIND)
87  Tp->PS[i].v.DM_Hsml = out->DM_Hsml;
88 #endif
89  }
90  }
91 
92  int evaluate(int target, int mode, int thread_id, int action, fofdata_in *in, int numnodes, node_info *firstnode, fofdata_out &out)
93  {
94  MyIntPosType *intpos = in->IntPos;
95  double h = in->Hsml;
96  int index = -1;
97  double r2max = MAX_REAL_NUMBER;
98 
99  /* Now start the actual tree-walk computation for this particle */
100 
101  for(int k = 0; k < numnodes; k++)
102  {
103  int no;
104 
105  if(mode == MODE_LOCAL_PARTICLES)
106  {
107  no = Tree->MaxPart; /* root node */
108  }
109  else
110  {
111  no = firstnode[k].Node;
112  no = Tree->get_nodep(no)->nextnode; /* open it */
113  }
114 
115  int shmrank = Tree->TreeSharedMem_ThisTask;
116 
117  while(no >= 0)
118  {
119  if(no < Tree->MaxPart) /* single particle */
120  {
121  int p = no;
122  auto P = Tree->get_Pp(no, shmrank);
123 
124  no = Tree->get_nextnodep(shmrank)[no]; /* note: here shmrank cannot change */
125 
126  if(shmrank != Tree->TreeSharedMem_ThisTask)
127  Terminate("this routine may not consider shared memory particles");
128 
129  double dxyz[3];
130  Tp->nearest_image_intpos_to_pos(P->IntPos, intpos, dxyz); /* converts the integer distance to floating point */
131 
132  double dist = h;
133 
134  if(fabs(dxyz[0]) > dist)
135  continue;
136  if(fabs(dxyz[1]) > dist)
137  continue;
138  if(fabs(dxyz[2]) > dist)
139  continue;
140 
141  double r2 = dxyz[0] * dxyz[0] + dxyz[1] * dxyz[1] + dxyz[2] * dxyz[2];
142 
143  if(r2 < r2max && r2 < h * h)
144  {
145  index = p;
146  r2max = r2;
147  }
148  }
149  else if(no < Tree->MaxPart + Tree->MaxNodes) /* internal node */
150  {
151  if(mode == MODE_IMPORTED_PARTICLES)
152  {
153  if(no < Tree->FirstNonTopLevelNode) /* we reached a top-level node again, which means that we are done with the
154  branch */
155  break;
156  }
157 
158  fofnode *current = Tree->get_nodep(no, shmrank);
159 
160  if(current->level == 0)
161  {
162  /* we always open the root node (its full node length can't be stored in the integer type */
163  no = current->nextnode; /* no change in shmrank expected here */
164  shmrank = current->nextnode_shmrank;
165  continue;
166  }
167 
168  int nosaved = no;
169 
170  no = current->sibling; /* in case the node can be discarded */
171  shmrank = current->sibling_shmrank;
172 
173  double dxyz[3];
174  Tp->nearest_image_intpos_to_pos(current->center.da, intpos,
175  dxyz); /* converts the integer distance to floating point */
176 
177  double len = (((MyIntPosType)1) << (BITS_FOR_POSITIONS - current->level)) * Tp->FacIntToCoord;
178 
179  double dist = h + 0.5 * len;
180 
181  if(fabs(dxyz[0]) > dist)
182  continue;
183  if(fabs(dxyz[1]) > dist)
184  continue;
185  if(fabs(dxyz[2]) > dist)
186  continue;
187 
188  /* now test against the minimal sphere enclosing everything */
189  dist += FACT1 * len;
190  if(dxyz[0] * dxyz[0] + dxyz[1] * dxyz[1] + dxyz[2] * dxyz[2] > dist * dist)
191  continue;
192 
193  int p = current->nextnode;
194 
195  /* in case the next node after opening is not a top-level node, we have either reached a leaf node or are in a local
196  * branch we need to do nothing if we would end up on different shared memory thread */
197  if(p < Tree->MaxPart || (p >= Tree->FirstNonTopLevelNode && p < Tree->MaxPart + Tree->MaxNodes))
198  {
199  if(current->nextnode_shmrank != Tree->TreeSharedMem_ThisTask)
200  {
201  int task = D->ThisTask + current->nextnode_shmrank - Tree->TreeSharedMem_ThisTask;
202 
203  if(target >= 0) /* export */
204  Tree->tree_export_node_threads_by_task_and_node(task, nosaved, target, &Thread);
205 
206  no = current->sibling; /* in case the node can be discarded */
207  shmrank = current->sibling_shmrank;
208  continue;
209  }
210  }
211 
212  no = current->nextnode; /* ok, we need to open the node */
213  shmrank = current->nextnode_shmrank;
214  }
215  else if(no >= Tree->ImportedNodeOffset) /* point from imported nodelist */
216  {
217  Terminate("do not expect imported points here");
218  }
219  else /* pseudo particle */
220  {
221  if(mode == MODE_LOCAL_PARTICLES)
222  if(target >= 0)
223  Tree->tree_export_node_threads(no, target, &Thread);
224 
225  no = Tree->get_nextnodep(shmrank)[no - Tree->MaxNodes];
226  /* note: here shmrank does not need to change */
227  }
228  }
229  }
230 
231  if(index >= 0)
232  {
233  out.Distance = sqrt(r2max);
234  out.MinID = Tp->MinID[Tp->Head[index]];
235  out.MinIDTask = Tp->MinIDTask[Tp->Head[index]];
236 #if defined(SUBFIND)
237  out.DM_Hsml = Tp->PS[index].v.DM_Hsml;
238 #endif
239  }
240  else
241  {
242  out.Distance = MAX_REAL_NUMBER;
243  out.MinID.set(0);
244  out.MinIDTask = 0;
245 #if defined(SUBFIND)
246  out.DM_Hsml = 0;
247 #endif
248  }
249 
250  return 0;
251  }
252 };
253 
254 template <typename partset>
255 double fof<partset>::fof_find_nearest_dmparticle(void)
256 {
257 #ifdef LEAN
258  return 0;
259 #endif
260 
261  double tstart = Logs.second();
262 
263  mpi_printf("FOF: Start finding nearest dm-particle (presently allocated=%g MB)\n", Mem.getAllocatedBytesInMB());
264 
265  Tp->fof_nearest_distance = (MyFloat *)Mem.mymalloc("fof_nearest_distance", sizeof(MyFloat) * Tp->NumPart);
266  Tp->fof_nearest_hsml = (MyFloat *)Mem.mymalloc("fof_nearest_hsml", sizeof(MyFloat) * Tp->NumPart);
267 
268  int *TargetList = (int *)Mem.mymalloc("TargetList", Tp->NumPart * sizeof(int));
269 
270  int Nsearch = 0;
271 
272  for(int n = 0; n < Tp->NumPart; n++)
273  {
274  if(is_type_secondary_link_type(Tp->P[n].getType()))
275  {
276  Tp->fof_nearest_distance[n] = MAX_REAL_NUMBER;
277  if(Tp->P[n].getType() == 0 && Tp->SphP[n].Hsml > 0)
278  Tp->fof_nearest_hsml[n] = Tp->SphP[n].Hsml;
279  else
280  Tp->fof_nearest_hsml[n] = 0.1 * Tp->LinkL;
281 
282  TargetList[Nsearch++] = n;
283  }
284  }
285 
286  fofdata_comm<foftree<partset>, domain<partset>, partset> commpattern{FoFDomain, &FoFNgbTree, Tp};
287 
288  int iter = 0;
289  long long ntot;
290  /* we will repeat the whole thing for those particles where we didn't find enough neighbours */
291  do
292  {
293  double t0 = Logs.second();
294 
295  commpattern.execute(Nsearch, TargetList, MODE_DEFAULT);
296 
297  /* do final operations on results */
298  int npleft = 0;
299  for(int n = 0; n < Nsearch; n++)
300  {
301  int i = TargetList[n];
302 
303  if(Tp->fof_nearest_distance[i] > 1.0e29)
304  {
305  if(Tp->fof_nearest_hsml[i] < 4 * Tp->LinkL) /* we only search out to a maximum distance */
306  {
307  /* need to redo this particle */
308  TargetList[npleft++] = i;
309  Tp->fof_nearest_hsml[i] *= 2.0;
310  if(iter >= MAXITER - 10)
311  {
312  double pos[3];
313  Tp->intpos_to_pos(Tp->P[i].IntPos, pos);
314 
315  printf("FOF: i=%d task=%d ID=%d P[i].Type=%d Hsml=%g LinkL=%g nearest=%g pos=(%g|%g|%g)\n", i, ThisTask,
316  (int)Tp->P[i].ID.get(), Tp->P[i].getType(), Tp->fof_nearest_hsml[i], Tp->LinkL,
317  Tp->fof_nearest_distance[i], pos[0], pos[1], pos[2]);
318  myflush(stdout);
319  }
320  }
321  else
322  {
323  Tp->fof_nearest_distance[i] = 0; /* we do not continue to search for this particle */
324  }
325  }
326  }
327 
328  sumup_large_ints(1, &npleft, &ntot, Communicator);
329 
330  Nsearch = npleft;
331 
332  double t1 = Logs.second();
333  if(ntot > 0)
334  {
335  iter++;
336  if(iter > 0)
337  mpi_printf("FOF: fof-nearest iteration %d: need to repeat for %lld particles. (took = %g sec)\n", iter, ntot,
338  Logs.timediff(t0, t1));
339 
340  if(iter > MAXITER)
341  Terminate("FOF: failed to converge in fof-nearest\n");
342  }
343  }
344  while(ntot > 0);
345 
346  Mem.myfree(TargetList);
347  Mem.myfree(Tp->fof_nearest_hsml);
348  Mem.myfree(Tp->fof_nearest_distance);
349 
350  mpi_printf("FOF: done finding nearest dm-particle\n");
351 
352  double tend = Logs.second();
353  return Logs.timediff(tstart, tend);
354 }
355 
356 /* now make sure that the following classes are really instantiated, otherwise we may get a linking problem */
357 #include "../data/simparticles.h"
358 template class fof<simparticles>;
359 
360 #if defined(LIGHTCONE) && defined(LIGHTCONE_PARTICLES_GROUPS)
361 #include "../data/lcparticles.h"
362 template class fof<lcparticles>;
363 #endif
364 
365 #endif /* of FOF */
Definition: domain.h:31
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)
Definition: logs.cc:488
double second(void)
Definition: logs.cc:471
double getAllocatedBytesInMB(void)
Definition: mymalloc.h:68
T da[3]
Definition: symtensors.h:106
#define MAXITER
Definition: constants.h:305
#define MODE_DEFAULT
Definition: constants.h:23
#define MODE_IMPORTED_PARTICLES
Definition: constants.h:22
#define FACT1
Definition: constants.h:435
#define MODE_LOCAL_PARTICLES
Definition: constants.h:21
#define MAX_REAL_NUMBER
Definition: constants.h:94
float MyFloat
Definition: dtypes.h:86
uint32_t MyIntPosType
Definition: dtypes.h:35
#define BITS_FOR_POSITIONS
Definition: dtypes.h:37
logs Logs
Definition: main.cc:43
#define Terminate(...)
Definition: macros.h:19
void sumup_large_ints(int n, int *src, long long *res, MPI_Comm comm)
memory Mem
Definition: main.cc:44
half fabs(half arg)
Definition: half.hpp:2627
expr sqrt(half arg)
Definition: half.hpp:2777
unsigned char level
Definition: tree.h:64
unsigned char nextnode_shmrank
Definition: tree.h:66
int nextnode
Definition: tree.h:57
vector< MyIntPosType > center
Definition: tree.h:51
unsigned char sibling_shmrank
Definition: tree.h:65
int sibling
Definition: tree.h:53
Definition: tree.h:77
int Node
Definition: tree.h:78
void myflush(FILE *fstream)
Definition: system.cc:125