MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
gravshort-tree.c
Go to the documentation of this file.
1 #include <mpi.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <sys/ipc.h>
8 #include <sys/sem.h>
9 
10 #include "utils.h"
11 
12 #include "forcetree.h"
13 #include "treewalk.h"
14 #include "timestep.h"
15 #include "gravshort.h"
16 #include "walltime.h"
17 
29 static struct gravshort_tree_params TreeParams;
30 /*Softening length*/
32 
33 /* gravitational softening length
34  * (given in terms of an `equivalent' Plummer softening length)
35  */
36 double FORCE_SOFTENING(int i, int type)
37 {
38  if (TreeParams.AdaptiveSoftening == 1 && type == 0) {
39  return P[i].Hsml;
40  }
41  /* Force is Newtonian beyond this.*/
42  return 2.8 * GravitySoftening;
43 }
44 
46 void
47 gravshort_set_softenings(double MeanSeparation)
48 {
50  /* 0: Gas is collisional */
51  message(0, "GravitySoftening = %g\n", GravitySoftening);
52 }
53 
54 /*This is a helper for the tests*/
56 {
57  TreeParams = tree_params;
58 }
59 
61 {
62  return TreeParams;
63 }
64 
65 /* Sets up the module*/
66 void
68 {
69  int ThisTask;
70  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
71  if(ThisTask == 0) {
72  TreeParams.BHOpeningAngle = param_get_double(ps, "BHOpeningAngle");
73  TreeParams.ErrTolForceAcc = param_get_double(ps, "ErrTolForceAcc");
74  TreeParams.BHOpeningAngle = param_get_double(ps, "BHOpeningAngle");
75  TreeParams.TreeUseBH= param_get_int(ps, "TreeUseBH");
76  TreeParams.Rcut = param_get_double(ps, "TreeRcut");
77  TreeParams.FractionalGravitySoftening = param_get_double(ps, "GravitySoftening");
78  TreeParams.AdaptiveSoftening = !param_get_int(ps, "GravitySofteningGas");
79 
80 
81  }
82  MPI_Bcast(&TreeParams, sizeof(struct gravshort_tree_params), MPI_BYTE, 0, MPI_COMM_WORLD);
83 }
84 
85 /* According to upstream P-GADGET3
86  * correct workcount slows it down and yields little benefits in load balancing
87  *
88  * YF: anything we shall do about this?
89  * */
90 
91 int
93  TreeWalkResultGravShort * output,
94  LocalTreeWalk * lv);
95 
96 
104 void
105 grav_short_tree(const ActiveParticles * act, PetaPM * pm, ForceTree * tree, double rho0, int NeutrinoTracer, int FastParticleType)
106 {
107  double timeall = 0;
108  double timetree, timewait, timecomm;
109 
110  TreeWalk tw[1] = {{0}};
111  struct GravShortPriv priv;
112  priv.cellsize = tree->BoxSize / pm->Nmesh;
113  priv.Rcut = TreeParams.Rcut * pm->Asmth * priv.cellsize;;
119  priv.G = pm->G;
120  priv.cbrtrho0 = pow(rho0, 1.0 / 3);
121 
122  if(!tree->moments_computed_flag)
123  endrun(2, "Gravtree called before tree moments computed!\n");
124 
125  tw->ev_label = "GRAVTREE";
127  /* gravity applies to all particles. Including Tracer particles to enhance numerical stability. */
128  tw->haswork = NULL;
131 
135  tw->tree = tree;
136  tw->priv = &priv;
137 
138  walltime_measure("/Misc");
139 
140  /* allocate buffers to arrange communication */
141  MPIU_Barrier(MPI_COMM_WORLD);
142  message(0, "Begin tree force. (presently allocated=%g MB)\n", mymalloc_usedbytes() / (1024.0 * 1024.0));
143 
144  walltime_measure("/Misc");
145 
147 
148  /* Now the force computation is finished */
149  /* gather some diagnostic information */
150 
151  timetree = tw->timecomp1 + tw->timecomp2 + tw->timecomp3;
152  timewait = tw->timewait1 + tw->timewait2;
153  timecomm= tw->timecommsumm1 + tw->timecommsumm2;
154 
155  walltime_add("/Tree/Walk1", tw->timecomp1);
156  walltime_add("/Tree/Walk2", tw->timecomp2);
157  walltime_add("/Tree/PostProcess", tw->timecomp3);
158  walltime_add("/Tree/Send", tw->timecommsumm1);
159  walltime_add("/Tree/Recv", tw->timecommsumm2);
160  walltime_add("/Tree/Wait1", tw->timewait1);
161  walltime_add("/Tree/Wait2", tw->timewait2);
162 
164 
165  walltime_add("/Tree/Misc", timeall - (timetree + timewait + timecomm));
166 
167  /* TreeUseBH > 1 means use the BH criterion on the initial timestep only,
168  * avoiding the fully open O(N^2) case.*/
169  if(TreeParams.TreeUseBH > 1)
170  TreeParams.TreeUseBH = 0;
171 }
172 
173 /* Add the acceleration from a node or particle to the output structure,
174  * computing the short-range kernel and softening.*/
175 static void
176 apply_accn_to_output(TreeWalkResultGravShort * output, const double dx[3], const double r2, const double h, const double mass, const double cellsize)
177 {
178  const double r = sqrt(r2);
179 
180  double fac = mass / (r2 * r);
181  double facpot = -mass / r;
182 
183  if(r2 < h*h)
184  {
185  double wp;
186  const double h3_inv = 1.0 / h / h / h;
187  const double u = r / h;
188  if(u < 0.5) {
189  fac = mass * h3_inv * (10.666666666667 + u * u * (32.0 * u - 38.4));
190  wp = -2.8 + u * u * (5.333333333333 + u * u * (6.4 * u - 9.6));
191  }
192  else {
193  fac =
194  mass * h3_inv * (21.333333333333 - 48.0 * u +
195  38.4 * u * u - 10.666666666667 * u * u * u - 0.066666666667 / (u * u * u));
196  wp =
197  -3.2 + 0.066666666667 / u + u * u * (10.666666666667 +
198  u * (-16.0 + u * (9.6 - 2.133333333333 * u)));
199  }
200  facpot = mass / h * wp;
201  }
202 
203  if(0 == grav_apply_short_range_window(r, &fac, &facpot, cellsize)) {
204  int i;
205  for(i = 0; i < 3; i++)
206  output->Acc[i] += dx[i] * fac;
207  output->Potential += facpot;
208  }
209 }
210 
211 /* Check whether a node should be discarded completely, its contents not contributing
212  * to the acceleration. This happens if the node is further away than the short-range force cutoff.
213  * Return 1 if the node should be discarded, 0 otherwise. */
214 static int
215 shall_we_discard_node(const double len, const double r2, const double center[3], const double inpos[3], const double BoxSize, const double rcut, const double rcut2)
216 {
217  /* This checks the distance from the node center of mass
218  * is greater than the cutoff. */
219  if(r2 > rcut2)
220  {
221  /* check whether we can stop walking along this branch */
222  const double eff_dist = rcut + 0.5 * len;
223  int i;
224  /*This checks whether we are also outside this region of the oct-tree*/
225  /* As long as one dimension is outside, we are fine*/
226  for(i=0; i < 3; i++)
227  if(fabs(NEAREST(center[i] - inpos[i], BoxSize)) > eff_dist)
228  return 1;
229  }
230  return 0;
231 }
232 
233 /* This function tests whether a node shall be opened (ie, should the next node be .
234  * If it should be discarded, 0 is returned.
235  * If it should be used, 1 is returned, otherwise zero is returned. */
236 static int
237 shall_we_open_node(const double len, const double mass, const double r2, const double center[3], const double inpos[3], const double BoxSize, const double aold, const int TreeUseBH, const double BHOpeningAngle2)
238 {
239  /* Check the relative acceleration opening condition*/
240  if((TreeUseBH == 0) && (mass * len * len > r2 * r2 * aold))
241  return 1;
242  /*Check Barnes-Hut opening angle*/
243  if((TreeUseBH > 0) && (len * len > r2 * BHOpeningAngle2))
244  return 1;
245 
246  const double inside = 0.6 * len;
247  /* Open the cell if we are inside it, even if the opening criterion is not satisfied.*/
248  if(fabs(NEAREST(center[0] - inpos[0], BoxSize)) < inside &&
249  fabs(NEAREST(center[1] - inpos[1], BoxSize)) < inside &&
250  fabs(NEAREST(center[2] - inpos[2], BoxSize)) < inside)
251  return 1;
252 
253  /* ok, node can be used */
254  return 0;
255 }
256 
268  TreeWalkResultGravShort * output,
269  LocalTreeWalk * lv)
270 {
271  const ForceTree * tree = lv->tw->tree;
272  const double BoxSize = tree->BoxSize;
273 
274  /*Tree-opening constants*/
275  const double cellsize = GRAV_GET_PRIV(lv->tw)->cellsize;
276  const double rcut = GRAV_GET_PRIV(lv->tw)->Rcut;
277  const double rcut2 = rcut * rcut;
278  const double aold = GRAV_GET_PRIV(lv->tw)->ErrTolForceAcc * input->OldAcc;
279  const int TreeUseBH = GRAV_GET_PRIV(lv->tw)->TreeUseBH;
280  const double BHOpeningAngle2 = GRAV_GET_PRIV(lv->tw)->BHOpeningAngle * GRAV_GET_PRIV(lv->tw)->BHOpeningAngle;
281  const int NeutrinoTracer = GRAV_GET_PRIV(lv->tw)->NeutrinoTracer;
282  const int FastParticleType = GRAV_GET_PRIV(lv->tw)->FastParticleType;
283 
284  /*Input particle data*/
285  const double * inpos = input->base.Pos;
286 
287  /*Start the tree walk*/
288  int listindex;
289 
290  /* Primary treewalk only ever has one nodelist entry*/
291  for(listindex = 0; listindex < NODELISTLENGTH && (lv->mode == 1 || listindex < 1); listindex++)
292  {
293  int numcand = 0;
294  /* Use the next node in the node list if we are doing a secondary walk.
295  * For a primary walk the node list only ever contains one node. */
296  int no = input->base.NodeList[listindex];
297  int startno = no;
298  if(no < 0)
299  break;
300 
301  while(no >= 0)
302  {
303  /* The tree always walks internal nodes*/
304  struct NODE *nop = &tree->Nodes[no];
305 
306  if(lv->mode == 1)
307  {
308  if(nop->f.TopLevel && no != startno) /* we reached a top-level node again, which means that we are done with the branch */
309  {
310  no = -1;
311  continue;
312  }
313  }
314 
315  int i;
316  double dx[3];
317  for(i = 0; i < 3; i++)
318  dx[i] = NEAREST(nop->mom.cofm[i] - inpos[i], BoxSize);
319  const double r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
320 
321  /* Discard this node, move to sibling*/
322  if(shall_we_discard_node(nop->len, r2, nop->center, inpos, BoxSize, rcut, rcut2))
323  {
324  no = nop->sibling;
325  /* Don't add this node*/
326  continue;
327  }
328 
329  /* This node accelerates the particle directly, and is not opened.*/
330  int open_node = shall_we_open_node(nop->len, nop->mom.mass, r2, nop->center, inpos, BoxSize, aold, TreeUseBH, BHOpeningAngle2);
331  if(TreeParams.AdaptiveSoftening == 1 && (input->Soft < nop->mom.hmax))
332  {
333  /* Always open the node if it has a larger softening than the particle,
334  * and the particle is inside its softening radius.
335  * This condition only ever applies for adaptive softenings. It may or may not make sense. */
336  if(r2 < nop->mom.hmax * nop->mom.hmax)
337  open_node = 1;
338  }
339 
340  if(!open_node)
341  {
342  double h = input->Soft;
344  h = DMAX(input->Soft, nop->mom.hmax);
345  /* ok, node can be used */
346  no = nop->sibling;
347  /* Compute the acceleration and apply it to the output structure*/
348  apply_accn_to_output(output, dx, r2, h, nop->mom.mass, cellsize);
349  continue;
350  }
351 
352  /* Now we have a cell that needs to be opened.
353  * If it contains particles we can add them directly here */
354  if(nop->f.ChildType == PARTICLE_NODE_TYPE)
355  {
356  /* Loop over child particles*/
357  for(i = 0; i < nop->s.noccupied; i++) {
358  int pp = nop->s.suns[i];
359  lv->ngblist[numcand++] = pp;
360  }
361  no = nop->sibling;
362  }
363  else if (nop->f.ChildType == PSEUDO_NODE_TYPE)
364  {
365  if(lv->mode == 0)
366  {
367  if(-1 == treewalk_export_particle(lv, nop->s.suns[0]))
368  return -1;
369  }
370 
371  /* Move to the sibling (likely also a pseudo node)*/
372  no = nop->sibling;
373  }
374  else if(nop->f.ChildType == NODE_NODE_TYPE)
375  {
376  /* This node contains other nodes and we need to open it.*/
377  no = nop->s.suns[0];
378  }
379  }
380  int i;
381  for(i = 0; i < numcand; i++)
382  {
383  int pp = lv->ngblist[i];
384  /* Fast particle neutrinos don't cause short-range acceleration before activation.*/
385  if(NeutrinoTracer && P[pp].Type == FastParticleType)
386  continue;
387 
388  double dx[3];
389  int j;
390  for(j = 0; j < 3; j++)
391  dx[j] = NEAREST(P[pp].Pos[j] - inpos[j], BoxSize);
392  const double r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
393 
394  /* This is always the Newtonian softening,
395  * match the default from FORCE_SOFTENING. */
396  double h = 2.8 * GravitySoftening;
397  if(TreeParams.AdaptiveSoftening == 1) {
398  h = DMAX(input->Soft, FORCE_SOFTENING(pp, P[pp].Type));
399  }
400  /* Compute the acceleration and apply it to the output structure*/
401  apply_accn_to_output(output, dx, r2, h, P[pp].Mass, cellsize);
402  }
403  lv->Ninteractions += numcand;
404  }
405 
406  if(lv->mode == 1) {
407  lv->Nnodesinlist += listindex;
408  lv->Nlist += 1;
409  }
410  return 1;
411 }
412 
413 
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
#define NODE_NODE_TYPE
Definition: forcetree.h:16
#define PARTICLE_NODE_TYPE
Definition: forcetree.h:15
#define PSEUDO_NODE_TYPE
Definition: forcetree.h:17
int grav_apply_short_range_window(double r, double *fac, double *pot, const double cellsize)
Definition: gravity.c:55
struct gravshort_tree_params get_gravshort_treepar(void)
void gravshort_set_softenings(double MeanSeparation)
int force_treeev_shortrange(TreeWalkQueryGravShort *input, TreeWalkResultGravShort *output, LocalTreeWalk *lv)
static struct gravshort_tree_params TreeParams
void set_gravshort_treepar(struct gravshort_tree_params tree_params)
double GravitySoftening
static int shall_we_discard_node(const double len, const double r2, const double center[3], const double inpos[3], const double BoxSize, const double rcut, const double rcut2)
double FORCE_SOFTENING(int i, int type)
static void apply_accn_to_output(TreeWalkResultGravShort *output, const double dx[3], const double r2, const double h, const double mass, const double cellsize)
void grav_short_tree(const ActiveParticles *act, PetaPM *pm, ForceTree *tree, double rho0, int NeutrinoTracer, int FastParticleType)
void set_gravshort_tree_params(ParameterSet *ps)
static int shall_we_open_node(const double len, const double mass, const double r2, const double center[3], const double inpos[3], const double BoxSize, const double aold, const int TreeUseBH, const double BHOpeningAngle2)
#define GRAV_GET_PRIV(tw)
Definition: gravshort.h:55
static void grav_short_copy(int place, TreeWalkQueryGravShort *input, TreeWalk *tw)
Definition: gravshort.h:74
static void grav_short_reduce(int place, TreeWalkResultGravShort *result, enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: gravshort.h:89
static void grav_short_postprocess(int i, TreeWalk *tw)
Definition: gravshort.h:58
#define mymalloc_usedbytes()
Definition: mymalloc.h:32
double param_get_double(ParameterSet *ps, const char *name)
Definition: paramset.c:336
int param_get_int(ParameterSet *ps, const char *name)
Definition: paramset.c:368
#define P
Definition: partmanager.h:88
#define NEAREST(x, BoxSize)
Definition: partmanager.h:99
int * ActiveParticle
Definition: timestep.h:13
int64_t NumActiveParticle
Definition: timestep.h:12
int moments_computed_flag
Definition: forcetree.h:82
double BoxSize
Definition: forcetree.h:106
struct NODE * Nodes
Definition: forcetree.h:97
double G
Definition: gravshort.h:45
double ErrTolForceAcc
Definition: gravshort.h:33
int FastParticleType
Definition: gravshort.h:41
double BHOpeningAngle
Definition: gravshort.h:38
double cbrtrho0
Definition: gravshort.h:52
int NeutrinoTracer
Definition: gravshort.h:43
double cellsize
Definition: gravshort.h:28
double Rcut
Definition: gravshort.h:31
int64_t Nlist
Definition: treewalk.h:65
int * ngblist
Definition: treewalk.h:62
int64_t Ninteractions
Definition: treewalk.h:63
int64_t Nnodesinlist
Definition: treewalk.h:64
TreeWalk * tw
Definition: treewalk.h:47
Definition: forcetree.h:39
int sibling
Definition: forcetree.h:40
struct NODE::@9 mom
MyFloat center[3]
Definition: forcetree.h:43
unsigned int ChildType
Definition: forcetree.h:49
MyFloat mass
Definition: forcetree.h:56
MyFloat hmax
Definition: forcetree.h:57
MyFloat cofm[3]
Definition: forcetree.h:55
unsigned int TopLevel
Definition: forcetree.h:47
struct NodeChild s
Definition: forcetree.h:66
struct NODE::@8 f
MyFloat len
Definition: forcetree.h:42
int noccupied
Definition: forcetree.h:35
int suns[NMAXCHILD]
Definition: forcetree.h:32
Definition: petapm.h:62
int Nmesh
Definition: petapm.h:68
double G
Definition: petapm.h:71
double Asmth
Definition: petapm.h:69
double Pos[3]
Definition: treewalk.h:23
int NodeList[NODELISTLENGTH]
Definition: treewalk.h:27
TreeWalkQueryBase base
Definition: gravshort.h:14
void * priv
Definition: treewalk.h:85
TreeWalkHasWorkFunction haswork
Definition: treewalk.h:100
double timecomp2
Definition: treewalk.h:124
double timecomp3
Definition: treewalk.h:125
double timecommsumm1
Definition: treewalk.h:126
const ForceTree * tree
Definition: treewalk.h:88
TreeWalkProcessFunction postprocess
Definition: treewalk.h:104
TreeWalkReduceResultFunction reduce
Definition: treewalk.h:102
const char * ev_label
Definition: treewalk.h:91
double timewait2
Definition: treewalk.h:122
TreeWalkVisitFunction visit
Definition: treewalk.h:99
size_t result_type_elsize
Definition: treewalk.h:96
TreeWalkFillQueryFunction fill
Definition: treewalk.h:101
double timecomp1
Definition: treewalk.h:123
double timewait1
Definition: treewalk.h:121
double timecommsumm2
Definition: treewalk.h:127
size_t query_type_elsize
Definition: treewalk.h:95
double BHOpeningAngle
Definition: gravity.h:12
double ErrTolForceAcc
Definition: gravity.h:11
double FractionalGravitySoftening
Definition: gravity.h:18
#define MPIU_Barrier(comm)
Definition: system.h:103
int ThisTask
Definition: test_exchange.c:23
#define DMAX(x, y)
Definition: test_interp.c:11
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
Definition: treewalk.c:619
int treewalk_export_particle(LocalTreeWalk *lv, int no)
Definition: treewalk.c:567
int(* TreeWalkVisitFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, LocalTreeWalk *lv)
Definition: treewalk.h:68
void(* TreeWalkReduceResultFunction)(const int j, TreeWalkResultBase *result, const enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: treewalk.h:76
#define NODELISTLENGTH
Definition: treewalk.h:8
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
Definition: treewalk.h:73
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
Definition: treewalk.h:75
#define walltime_measure(name)
Definition: walltime.h:8
#define WALLTIME_IGNORE
Definition: walltime.h:6
#define walltime_add(name, dt)
Definition: walltime.h:9