MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
drift.c
Go to the documentation of this file.
1 #include <mpi.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <math.h>
6 #include <gsl/gsl_math.h>
7 #include "drift.h"
8 #include "blackhole.h"
9 #include "walltime.h"
10 #include "timefac.h"
11 #include "timestep.h"
12 #include "utils.h"
13 
14 /* Drifts an individual particle to time ti1, by a drift factor ddrift.
15  * The final argument is a random shift vector applied uniformly to all particles before periodic wrapping.
16  * The box is periodic, so this does not affect real physics, but it avoids correlated errors
17  * in the tree expansion. The shift is relative to the current position. On most timesteps this is zero,
18  * signifying no change in the coordinate frame. On PM steps a random offset is generated, and the routine
19  * receives a shift vector removing the previous random shift and adding a new one.
20  * This function also updates the velocity and updates the density according to an adiabatic factor.
21  */
22 void real_drift_particle(struct particle_data * pp, struct slots_manager_type * sman, const double ddrift, const double BoxSize, const double random_shift[3])
23 {
24  int j;
25  if(pp->IsGarbage || pp->Swallowed) {
26  /* Keep the random shift updated so the
27  * physical position of swallowed particles remains unchanged.*/
28  for(j = 0; j < 3; j++) {
29  pp->Pos[j] += random_shift[j];
30  while(pp->Pos[j] > BoxSize) pp->Pos[j] -= BoxSize;
31  while(pp->Pos[j] <= 0) pp->Pos[j] += BoxSize;
32  }
33  /* Swallowed particles still need a peano key.*/
34  if(pp->Swallowed)
35  pp->Key = PEANO(pp->Pos, BoxSize);
36  return;
37  }
38 
39  /* Jumping of BH */
40  if(BHGetRepositionEnabled() && pp->Type == 5) {
41  int k;
42  int pi = pp->PI;
43  struct bh_particle_data * BH = (struct bh_particle_data *) sman->info[5].ptr;
44  if (BH[pi].JumpToMinPot) {
45  for(k = 0; k < 3; k++) {
46  double dx = NEAREST(pp->Pos[k] - BH[pi].MinPotPos[k], BoxSize);
47  if(dx > 0.1 * BoxSize) {
48  endrun(1, "Drifting blackhole very far, from %g %g %g to %g %g %g id = %ld. Likely due to the time step is too sparse.\n",
49  pp->Pos[0],
50  pp->Pos[1],
51  pp->Pos[2],
52  BH[pi].MinPotPos[0],
53  BH[pi].MinPotPos[1],
54  BH[pi].MinPotPos[2], pp->ID);
55  }
56  pp->Pos[k] = BH[pi].MinPotPos[k];
57  pp->Vel[k] = BH[pi].MinPotVel[k];
58  }
59  }
60  BH[pi].JumpToMinPot = 0;
61  }
62  else if(pp->Type == 0)
63  {
64  /* DtHsml is 1/3 DivVel * Hsml evaluated at the last active timestep for this particle.
65  * This predicts Hsml during the current timestep in the way used in Gadget-4, more accurate
66  * than the Gadget-2 prediction which could run away in deep timesteps. */
67  pp->Hsml += pp->DtHsml * ddrift;
68  if(pp->Hsml <= 0)
69  endrun(5, "Part id %ld has bad Hsml %g with DtHsml %g vel %g %g %g\n",
70  pp->ID, pp->Hsml, pp->DtHsml, pp->Vel[0], pp->Vel[1], pp->Vel[2]);
71  /* Cap the Hsml just in case: if DivVel is large for a particle with a long timestep
72  * at one point Hsml could rarely run away.*/
73  const double Maxhsml = BoxSize /2.;
74  if(pp->Hsml > Maxhsml)
75  pp->Hsml = Maxhsml;
76  }
77 
78  for(j = 0; j < 3; j++) {
79  pp->Pos[j] += pp->Vel[j] * ddrift + random_shift[j];
80  }
81 
82  for(j = 0; j < 3; j ++) {
83  while(pp->Pos[j] > BoxSize) pp->Pos[j] -= BoxSize;
84  while(pp->Pos[j] <= 0) pp->Pos[j] += BoxSize;
85  }
86  /* avoid recomputing them during layout and force tree build.*/
87  pp->Key = PEANO(pp->Pos, BoxSize);
88 }
89 
90 /* Update all particles to the current time, shifting them by a random vector.*/
91 void drift_all_particles(inttime_t ti0, inttime_t ti1, Cosmology * CP, const double random_shift[3])
92 {
93  int i;
94  walltime_measure("/Misc");
95  if(ti1 < ti0) {
96  endrun(12, "Trying to reverse time: ti0=%d ti1=%d\n", ti0, ti1);
97  }
98  const double ddrift = get_exact_drift_factor(CP, ti0, ti1);
99 
100 #pragma omp parallel for
101  for(i = 0; i < PartManager->NumPart; i++) {
102 #ifdef DEBUG
103  if(PartManager->Base[i].Ti_drift != ti0)
104  endrun(10, "Drift time mismatch: (ids = %ld %ld) %d != %d\n",PartManager->Base[0].ID, PartManager->Base[i].ID, ti0, PartManager->Base[i].Ti_drift);
105 #endif
106  real_drift_particle(&PartManager->Base[i], SlotsManager, ddrift, PartManager->BoxSize, random_shift);
107  PartManager->Base[i].Ti_drift = ti1;
108  }
109 
110  walltime_measure("/Drift/All");
111 }
int BHGetRepositionEnabled(void)
Definition: blackhole.c:60
void drift_all_particles(inttime_t ti0, inttime_t ti1, Cosmology *CP, const double random_shift[3])
Definition: drift.c:91
void real_drift_particle(struct particle_data *pp, struct slots_manager_type *sman, const double ddrift, const double BoxSize, const double random_shift[3])
Definition: drift.c:22
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
struct part_manager_type PartManager[1]
Definition: partmanager.c:11
#define NEAREST(x, BoxSize)
Definition: partmanager.h:99
static peano_t PEANO(double *Pos, double BoxSize)
Definition: peano.h:14
static Cosmology * CP
Definition: power.c:27
struct slots_manager_type SlotsManager[1]
Definition: slotsmanager.c:7
double MinPotPos[3]
Definition: slotsmanager.h:41
MyFloat MinPotVel[3]
Definition: slotsmanager.h:42
struct particle_data * Base
Definition: partmanager.h:74
MyFloat Hsml
Definition: partmanager.h:59
MyIDType ID
Definition: partmanager.h:38
unsigned int Swallowed
Definition: partmanager.h:20
MyFloat DtHsml
Definition: partmanager.h:52
MyFloat Vel[3]
Definition: partmanager.h:40
double Pos[3]
Definition: partmanager.h:12
peano_t Key
Definition: partmanager.h:66
unsigned int Type
Definition: partmanager.h:17
unsigned int IsGarbage
Definition: partmanager.h:19
inttime_t Ti_drift
Definition: partmanager.h:36
char * ptr
Definition: slotsmanager.h:10
struct slot_info info[6]
Definition: slotsmanager.h:112
double get_exact_drift_factor(Cosmology *CP, inttime_t ti0, inttime_t ti1)
Definition: timefac.c:64
int32_t inttime_t
Definition: types.h:8
#define walltime_measure(name)
Definition: walltime.h:8