MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
winds.c
Go to the documentation of this file.
1 /*Prototypes and structures for the wind model*/
2 
3 #include <math.h>
4 #include <string.h>
5 #include <omp.h>
6 #include "winds.h"
7 #include "physconst.h"
8 #include "treewalk.h"
9 #include "slotsmanager.h"
10 #include "timebinmgr.h"
11 #include "walltime.h"
12 #include "density.h"
13 #include "hydra.h"
14 
15 /*Parameters of the wind model*/
16 static struct WindParams
17 {
18  enum WindModel WindModel;
21  /*Density threshold at which to recouple wind particles.*/
23  /* Maximum time in internal time units to allow the wind to be free-streaming.*/
25  /* used in VS08 and SH03*/
27  double WindSpeed;
29  /* used in OFJT10*/
30  double WindSigma0;
32  /* Minimum wind velocity for kicked particles, in internal velocity units*/
34  /* Fraction of wind energy in thermal energy*/
37 
38 #define NWINDHSML 5 /* Number of densities to evaluate for wind weight ngbiter*/
39 #define NUMDMNGB 40 /*Number of DM ngb to evaluate vel dispersion */
40 #define MAXDMDEVIATION 2
41 
42 typedef struct {
45  double Dt;
46  double Mass;
47  double Hsml;
48  double TotalWeight;
49  double DMRadius[NWINDHSML];
50  double Vdisp;
51  double Vel[3];
53 
54 typedef struct {
56  double TotalWeight;
57  double V1sum[NWINDHSML][3];
58  double V2sum[NWINDHSML];
59  double Ngb[NWINDHSML];
60  int alignment; /* Ensure alignment*/
61  int maxcmpte;
63 
64 typedef struct {
67 
68 /*Set the parameters of the wind module.
69  ofjt10 is Okamoto, Frenk, Jenkins and Theuns 2010 https://arxiv.org/abs/0909.0265
70  VS08 is Dalla Vecchia & Schaye 2008 https://arxiv.org/abs/0801.2770
71  SH03 is Springel & Hernquist 2003 https://arxiv.org/abs/astro-ph/0206395*/
73 {
74  int ThisTask;
75  MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
76  if(ThisTask == 0) {
77  /*Wind model parameters*/
78  wind_params.WindModel = (enum WindModel) param_get_enum(ps, "WindModel");
79  /* The following two are for VS08 and SH03*/
80  wind_params.WindEfficiency = param_get_double(ps, "WindEfficiency");
81  wind_params.WindEnergyFraction = param_get_double(ps, "WindEnergyFraction");
82 
83  /* The following two are for OFJT10*/
84  wind_params.WindSigma0 = param_get_double(ps, "WindSigma0");
85  wind_params.WindSpeedFactor = param_get_double(ps, "WindSpeedFactor");
86 
87  wind_params.WindThermalFactor = param_get_double(ps, "WindThermalFactor");
88  wind_params.MinWindVelocity = param_get_double(ps, "MinWindVelocity");
89  wind_params.MaxWindFreeTravelTime = param_get_double(ps, "MaxWindFreeTravelTime");
90  wind_params.WindFreeTravelLength = param_get_double(ps, "WindFreeTravelLength");
91  wind_params.WindFreeTravelDensFac = param_get_double(ps, "WindFreeTravelDensFac");
92  }
93  MPI_Bcast(&wind_params, sizeof(struct WindParams), MPI_BYTE, 0, MPI_COMM_WORLD);
94 }
95 
96 void
97 init_winds(double FactorSN, double EgySpecSN, double PhysDensThresh, double UnitTime_in_s)
98 {
99  wind_params.WindSpeed = sqrt(2 * wind_params.WindEnergyFraction * FactorSN * EgySpecSN / (1 - FactorSN));
100  /* Convert wind free travel time from Myr to internal units*/
105  message(0, "Windspeed: %g MaxDelay %g\n", wind_params.WindSpeed, wind_params.MaxWindFreeTravelTime);
106  } else if(HAS(wind_params.WindModel, WIND_USE_HALO)) {
107  message(0, "Reference Windspeed: %g, MaxDelay %g\n", wind_params.WindSigma0 * wind_params.WindSpeedFactor, wind_params.MaxWindFreeTravelTime);
108  } else {
109  /* Check for undefined wind models*/
110  endrun(1, "WindModel = 0x%X is strange. This shall not happen.\n", wind_params.WindModel);
111  }
112 }
113 
114 int
116 {
118  return 1;
119  else
120  return 0;
121 }
122 
123 int
125 {
127  && P[i].Type == 0 && SPHP(i).DelayTime > 0)
128  return 1;
129  return 0;
130 }
131 
132 void
133 winds_decoupled_hydro(int i, double atime)
134 {
135  int k;
136  for(k = 0; k < 3; k++)
137  SPHP(i).HydroAccel[k] = 0;
138 
139  SPHP(i).DtEntropy = 0;
140 
141  double windspeed = wind_params.WindSpeed * atime;
142  const double fac_mu = pow(atime, 3 * (GAMMA - 1) / 2) / atime;
143  windspeed *= fac_mu;
144  double hsml_c = cbrt(wind_params.WindFreeTravelDensThresh /SPHP(i).Density) * atime;
145  SPHP(i).MaxSignalVel = hsml_c * DMAX((2 * windspeed), SPHP(i).MaxSignalVel);
146 }
147 
148 static void
149 wind_do_kick(int other, double vel, double therm, double atime);
150 
151 static int
152 get_wind_dir(int i, double dir[3]);
153 
154 static void
155 get_wind_params(double * vel, double * windeff, double * utherm, const double vdisp, const double time);
156 
157 static void
158 sfr_wind_reduce_weight(int place, TreeWalkResultWind * remote, enum TreeWalkReduceMode mode, TreeWalk * tw);
159 
160 static void
161 sfr_wind_copy(int place, TreeWalkQueryWind * input, TreeWalk * tw);
162 
163 static void
164 sfr_wind_weight_postprocess(const int i, TreeWalk * tw);
165 
166 static void
168  TreeWalkResultWind * O,
169  TreeWalkNgbIterWind * iter,
170  LocalTreeWalk * lv);
171 
172 static void
174  TreeWalkResultWind * O,
175  TreeWalkNgbIterWind * iter,
176  LocalTreeWalk * lv);
177 
178 struct winddata {
179  double DMRadius;
180  double Left;
181  double Right;
182  double TotalWeight;
183 
184  double Vdisp;
185  double V2sum[NWINDHSML];
186  double V1sum[NWINDHSML][3];
187  double Ngb[NWINDHSML];
188  int maxcmpte;
189 };
190 
191 /* Returns 1 if the winds ever decouple, 0 otherwise*/
193 {
195  return 1;
196  else
197  return 0;
198 }
199 
200 /* Structure to store a potential kick
201  * to a gas particle from a newly formed star.
202  * We add a queue of these and resolve them
203  * after the treewalk. Note this star may
204  * be on another processor.*/
205 struct StarKick
206 {
207  /* Index of the kicked particle*/
209  /* Distance to the star. The closest star does the kick.*/
210  double StarDistance;
211  /* Star ID, for resolving ties.*/
213  /* Kick velocity if this kick is the one used*/
215  /* Thermal energy included in the kick*/
216  double StarTherm;
217 };
218 
219 struct WindPriv {
220  double Time;
221  double hubble;
222  struct winddata * Winddata;
223  struct StarKick * kicks;
224  int64_t nkicks;
225  int64_t maxkicks;
226  int * nvisited;
227 };
228 
229 /* Comparison function to sort the StarKicks by particle id, distance and star ID.
230  * The closest star is used. */
231 int cmp_by_part_id(const void * a, const void * b)
232 {
233  const struct StarKick * stara = (const struct StarKick * ) a;
234  const struct StarKick * starb = (const struct StarKick *) b;
235  if(stara->part_index > starb->part_index)
236  return 1;
237  if(stara->part_index < starb->part_index)
238  return -1;
239  if(stara->StarDistance > starb->StarDistance)
240  return 1;
241  if(stara->StarDistance < starb->StarDistance)
242  return -1;
243  if(stara->StarID > starb->StarID)
244  return 1;
245  if(stara->StarID < starb->StarID)
246  return -1;
247  return 0;
248 }
249 
250 #define WIND_GET_PRIV(tw) ((struct WindPriv *) (tw->priv))
251 #define WINDP(i, wind) wind[P[i].PI]
252 
253 /* Find the 1D DM velocity dispersion of the winds by running a density loop.*/
254 static void
255 winds_find_weights(TreeWalk * tw, struct WindPriv * priv, int * NewStars, int NumNewStars, const double Time, const double hubble, ForceTree * tree)
256 {
257  tw->ev_label = "WIND_WEIGHT";
260  tw->query_type_elsize = sizeof(TreeWalkQueryWind);
262  tw->tree = tree;
263 
264  /* sum the total weight of surrounding gas */
267 
268  tw->haswork = NULL;
271 
272  priv[0].Time = Time;
273  priv[0].hubble = hubble;
274  tw->priv = priv;
275 
276  int64_t totalleft = 0;
277  sumup_large_ints(1, &NumNewStars, &totalleft);
278  /* Subgrid winds come from gas, regular wind from stars: size array accordingly.*/
279  int64_t winddata_sz = SlotsManager->info[4].size;
281  winddata_sz = SlotsManager->info[0].size;
282  priv->Winddata = (struct winddata * ) mymalloc("WindExtraData", winddata_sz * sizeof(struct winddata));
283 
284  /* Note that this will be an over-count because each loop will add more.*/
285  priv->nvisited = ta_malloc("nvisited", int, omp_get_max_threads());
286  memset(WIND_GET_PRIV(tw)->nvisited, 0, omp_get_max_threads()* sizeof(int));
287 
288  int i;
289  /*Initialise the WINDP array*/
290  #pragma omp parallel for
291  for (i = 0; i < NumNewStars; i++) {
292  int n = NewStars ? NewStars[i] : i;
293  WINDP(n, priv->Winddata).DMRadius = 2 * P[n].Hsml;
294  WINDP(n, priv->Winddata).Left = 0;
295  WINDP(n, priv->Winddata).Right = tree->BoxSize;
296  WINDP(n, priv->Winddata).maxcmpte = NUMDMNGB;
297  }
298 
299  /* Find densities*/
300  treewalk_do_hsml_loop(tw, NewStars, NumNewStars, 1);
301 }
302 
303 /* This function spawns winds for the subgrid model, which comes from the star-forming gas.
304  * Does a little more calculation than is really necessary, due to shared code, but that shouldn't matter. */
305 void
306 winds_subgrid(int * MaybeWind, int NumMaybeWind, const double Time, const double hubble, ForceTree * tree, MyFloat * StellarMasses)
307 {
308  /*The non-subgrid model does nothing here*/
310  return;
311 
312  if(!MPIU_Any(NumMaybeWind > 0, MPI_COMM_WORLD))
313  return;
314 
315  TreeWalk tw[1] = {{0}};
316  struct WindPriv priv[1];
317  int n;
318  winds_find_weights(tw, priv, MaybeWind, NumMaybeWind, Time, hubble, tree);
319  myfree(priv->nvisited);
320  for(n = 0; n < NumMaybeWind; n++)
321  {
322  int i = MaybeWind ? MaybeWind[n] : n;
323  /* Notice that StellarMasses is indexed like PI, not i!*/
324  MyFloat sm = StellarMasses[P[i].PI];
325  winds_make_after_sf(i, sm, WINDP(i, priv->Winddata).Vdisp, Time);
326  }
327  myfree(priv->Winddata);
328  walltime_measure("/Cooling/Wind");
329 }
330 
331 /*Do a treewalk for the wind model. This only changes newly created star particles.*/
332 void
333 winds_and_feedback(int * NewStars, int NumNewStars, const double Time, const double hubble, ForceTree * tree)
334 {
335  /*The subgrid model does nothing here*/
337  return;
338 
339  if(!MPIU_Any(NumNewStars > 0, MPI_COMM_WORLD))
340  return;
341 
342  TreeWalk tw[1] = {{0}};
343  struct WindPriv priv[1];
344  int i;
345  winds_find_weights(tw, priv, NewStars, NumNewStars, Time, hubble, tree);
346 
347  for (i = 1; i < omp_get_max_threads(); i++)
348  priv->nvisited[0] += priv->nvisited[i];
349  priv->maxkicks = priv->nvisited[0]+2;
350 
351  /* Some particles may be kicked by multiple stars on the same timestep.
352  * To ensure this happens only once and does not depend on the order in
353  * which the loops are executed, particles are kicked by the nearest new star.
354  * This struct stores all such possible kicks, and we sort it out after the treewalk.*/
355  priv->kicks = (struct StarKick * ) mymalloc("StarKicks", priv->maxkicks * sizeof(struct StarKick));
356  priv->nkicks = 0;
357  ta_free(priv->nvisited);
358 
359  /* Then run feedback */
360  tw->haswork = NULL;
362  tw->postprocess = NULL;
363  tw->reduce = NULL;
364  tw->ev_label = "WIND_KICK";
365  tw->Niteration = 0;
366 
367  treewalk_run(tw, NewStars, NumNewStars);
368 
369  /* Sort the possible kicks*/
370  qsort_openmp(priv->kicks, priv->nkicks, sizeof(struct StarKick), cmp_by_part_id);
371  /* Not parallel as the number of kicked particles should be pretty small*/
372  int64_t last_part = -1;
373  int64_t nkicked = 0;
374  for(i = 0; i < priv->nkicks; i++) {
375  /* Only do the kick for the first particle, which is the closest*/
376  if(priv->kicks[i].part_index == last_part)
377  continue;
378  int other = priv->kicks[i].part_index;
379  last_part = other;
380  nkicked++;
381  wind_do_kick(other, priv->kicks[i].StarKickVelocity, priv->kicks[i].StarTherm, Time);
382  if(priv->kicks[i].StarKickVelocity <= 0 || !isfinite(priv->kicks[i].StarKickVelocity) || !isfinite(SPHP(other).DelayTime))
383  {
384  endrun(5, "Odd v: other = %d, DT = %g v = %g i = %d, nkicks %d maxkicks %d dist %g id %ld\n",
385  other, SPHP(other).DelayTime, priv->kicks[i].StarKickVelocity, i, priv->nkicks, priv->maxkicks,
386  priv->kicks[i].StarDistance, priv->kicks[i].StarID);
387  }
388  }
389  /* Get total number of potential new stars to allocate memory.*/
390  int64_t tot_newstars, tot_kicks, tot_applied;
391  sumup_large_ints(1, &NumNewStars, &tot_newstars);
392  MPI_Allreduce(&priv->nkicks, &tot_kicks, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
393  MPI_Allreduce(&nkicked, &tot_applied, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
394  message(0, "Made %ld gas wind, discarded %ld kicks from %d stars\n", tot_applied, tot_kicks - tot_applied, tot_newstars);
395 
396  myfree(priv->kicks);
397  myfree(priv->Winddata);
398  walltime_measure("/Cooling/Wind");
399 }
400 
401 /*Evolve a wind particle, reducing its DelayTime*/
402 void
403 winds_evolve(int i, double a3inv, double hubble)
404 {
405  /*Remove a wind particle from the delay mode if the (physical) density has dropped sufficiently.*/
406  if(SPHP(i).DelayTime > 0 && SPHP(i).Density * a3inv < wind_params.WindFreeTravelDensThresh) {
407  SPHP(i).DelayTime = 0;
408  }
409  /*Reduce the time until the particle can form stars again by the current timestep*/
410  if(SPHP(i).DelayTime > 0) {
411  /* Enforce the maximum in case of restarts*/
412  if(SPHP(i).DelayTime > wind_params.MaxWindFreeTravelTime)
413  SPHP(i).DelayTime = wind_params.MaxWindFreeTravelTime;
414  const double dloga = get_dloga_for_bin(P[i].TimeBin, P[i].Ti_drift);
415  /* the proper time duration of the step */
416  const double dtime = dloga / hubble;
417  SPHP(i).DelayTime = DMAX(SPHP(i).DelayTime - dtime, 0);
418  }
419 }
420 
421 static inline double
422 effdmradius(int place, int i, TreeWalk * tw)
423 {
424  struct winddata * Windd = WIND_GET_PRIV(tw)->Winddata;
425  double left = WINDP(place, Windd).Left;
426  double right = WINDP(place, Windd).Right;
427  /*The asymmetry is because it is free to compute extra densities for h < Hsml, but not for h > Hsml*/
428  if (right > 0.99*tw->tree->BoxSize){
429  right = WINDP(place, Windd).DMRadius;
430  }
431  if(left == 0)
432  left = 0.1 * WINDP(place, Windd).DMRadius;
433  /*Evenly split in volume*/
434  double rvol = pow(right, 3);
435  double lvol = pow(left, 3);
436  return pow((1.0*i+1)/(1.0*NWINDHSML+1) * (rvol - lvol) + lvol, 1./3);
437 }
438 
439 
440 static void
442 {
443  struct winddata * Windd = WIND_GET_PRIV(tw)->Winddata;
444 
445  const int maxcmpt = WINDP(i, Windd).maxcmpte;
446  int j;
447  double evaldmradius[NWINDHSML];
448  for(j = 0; j < maxcmpt; j++){
449  evaldmradius[j] = effdmradius(i,j,tw);
450  }
451  int close = 0;
452  WINDP(i, Windd).DMRadius = ngb_narrow_down(&WINDP(i, Windd).Right, &WINDP(i, Windd).Left, evaldmradius, WINDP(i, Windd).Ngb, maxcmpt, NUMDMNGB, &close, tw->tree->BoxSize);
453  double numngb = WINDP(i, Windd).Ngb[close];
454 
455  int tid = omp_get_thread_num();
456  /* If we have 40 neighbours, or if DMRadius is narrow, set vdisp. Otherwise add to redo queue */
457  if((numngb < (NUMDMNGB - MAXDMDEVIATION) || numngb > (NUMDMNGB + MAXDMDEVIATION)) &&
458  (WINDP(i, Windd).Right - WINDP(i, Windd).Left > 1e-2)) {
459  /* More work needed: add this particle to the redo queue*/
460  tw->NPRedo[tid][tw->NPLeft[tid]] = i;
461  tw->NPLeft[tid] ++;
462  }
463  else{
464  double vdisp = WINDP(i, Windd).V2sum[close] / numngb;
465  int d;
466  for(d = 0; d<3; d++){
467  vdisp -= pow(WINDP(i, Windd).V1sum[close][d] / numngb,2);
468  }
469  if(vdisp > 0)
470  WINDP(i, Windd).Vdisp = sqrt(vdisp / 3);
471  }
472 
473  if(tw->maxnumngb[tid] < numngb)
474  tw->maxnumngb[tid] = numngb;
475  if(tw->minnumngb[tid] > numngb)
476  tw->minnumngb[tid] = numngb;
477 }
478 
479 static void
481 {
482  struct winddata * Windd = WIND_GET_PRIV(tw)->Winddata;
483  TREEWALK_REDUCE(WINDP(place, Windd).TotalWeight, O->TotalWeight);
484 
485  int i;
486  if(mode == 0 || WINDP(place, Windd).maxcmpte > O->maxcmpte)
487  WINDP(place, Windd).maxcmpte = O->maxcmpte;
488  int k;
489  for (i = 0; i < O->maxcmpte; i++){
490  TREEWALK_REDUCE(WINDP(place, Windd).Ngb[i], O->Ngb[i]);
491  TREEWALK_REDUCE(WINDP(place, Windd).V2sum[i], O->V2sum[i]);
492  for(k = 0; k < 3; k ++) {
493  TREEWALK_REDUCE(WINDP(place, Windd).V1sum[i][k], O->V1sum[i][k]);
494  }
495  }
496 // message(1, "Reduce ID=%ld, NGB_first=%d NGB_last=%d maxcmpte = %d, left = %g, right = %g\n",
497 // P[place].ID, O->Ngb[0],O->Ngb[O->maxcmpte-1],WINDP(place, Windd).maxcmpte,WINDP(place, Windd).Left,WINDP(place, Windd).Right);
498 }
499 
500 static void
501 sfr_wind_copy(int place, TreeWalkQueryWind * input, TreeWalk * tw)
502 {
503  double dtime = get_dloga_for_bin(P[place].TimeBin, P[place].Ti_drift) / WIND_GET_PRIV(tw)->hubble;
504  struct winddata * Windd = WIND_GET_PRIV(tw)->Winddata;
505 
506  input->ID = P[place].ID;
507  input->Dt = dtime;
508  input->Mass = P[place].Mass;
509  input->Hsml = P[place].Hsml;
510  input->TotalWeight = WINDP(place, Windd).TotalWeight;
511  input->Vdisp = WINDP(place, Windd).Vdisp;
512  int i;
513  for(i=0; i<3; i++)
514  input->Vel[i] = P[place].Vel[i];
515  for(i = 0; i<NWINDHSML; i++){
516  input->DMRadius[i]=effdmradius(place,i,tw);
517  }
518 }
519 
520 static void
522  TreeWalkResultWind * O,
523  TreeWalkNgbIterWind * iter,
524  LocalTreeWalk * lv)
525 {
526  /* this evaluator walks the tree and sums the total mass of surrounding gas
527  * particles as described in VS08. */
528  /* it also calculates the DM dispersion of the nearest 40 DM particles */
529  if(iter->base.other == -1) {
530  double hsearch = DMAX(I->Hsml, I->DMRadius[NWINDHSML-1]);
531  iter->base.Hsml = hsearch;
532  iter->base.mask = 1 + 2; /* gas and dm */
534  O->maxcmpte = NWINDHSML;
535  return;
536  }
537 
538  int other = iter->base.other;
539  double r = iter->base.r;
540  double * dist = iter->base.dist;
541 
542  if(P[other].Type == 0) {
543  if(r > I->Hsml) return;
544  /* skip earlier wind particles, which receive
545  * no feedback energy */
546  if(SPHP(other).DelayTime > 0) return;
547 
548  /* NOTE: think twice if we want a symmetric tree walk when wk is used. */
549  //double wk = density_kernel_wk(&kernel, r);
550  double wk = 1.0;
551  O->TotalWeight += wk * P[other].Mass;
552  /* Sum up all particles visited on this processor*/
553  WIND_GET_PRIV(lv->tw)->nvisited[omp_get_thread_num()]++;
554  }
555 
556  int i;
557  if(P[other].Type == 1) {
558  const double atime = WIND_GET_PRIV(lv->tw)->Time;
559  for(i = 0; i < O->maxcmpte; i++){
560  if(r < I->DMRadius[i]){
561  O->Ngb[i] += 1;
562  int d;
563  for(d = 0; d < 3; d ++) {
564  /* Add hubble flow to relative velocity. */
565  double vel = P[other].Vel[d] - I->Vel[d] + WIND_GET_PRIV(lv->tw)->hubble * atime * atime * dist[d];
566  O->V1sum[i][d] += vel;
567  O->V2sum[i] += vel * vel;
568  }
569  }
570  }
571  }
572 
573  for(i = 0; i<NWINDHSML; i++){
574  if(O->Ngb[i] > NUMDMNGB){
575  O->maxcmpte = i+1;
576  iter->base.Hsml = I->DMRadius[i];
577  break;
578  }
579  }
580 
581  /*
582  message(1, "ThisTask = %d %ld ngb=%d NGB=%d TotalWeight=%g V2sum=%g V1sum=%g %g %g\n",
583  ThisTask, I->ID, numngb, O->Ngb, O->TotalWeight, O->V2sum,
584  O->V1sum[0], O->V1sum[1], O->V1sum[2]);
585  */
586 }
587 
588 /* Do the actual kick of the gas particle*/
589 static void
590 wind_do_kick(int other, double vel, double therm, double atime)
591 {
592  /* Kick the gas particle*/
593  double dir[3];
594  get_wind_dir(other, dir);
595  int j;
596  if(vel > 0 && atime > 0) {
597  for(j = 0; j < 3; j++)
598  {
599  P[other].Vel[j] += vel * dir[j];
600  }
601  /* StarTherm is internal energy per unit mass. Need to convert to entropy*/
602  const double enttou = pow(SPHP(other).Density / pow(atime, 3), GAMMA_MINUS1) / GAMMA_MINUS1;
603  SPHP(other).Entropy += therm/enttou;
604  if(winds_ever_decouple()) {
605  double delay = wind_params.WindFreeTravelLength / (vel / atime);
608  SPHP(other).DelayTime = delay;
609  }
610  }
611 }
612 
613 static int
614 get_wind_dir(int i, double dir[3]) {
615  /* v and vmean are in internal units (km/s *a ), not km/s !*/
616  /* returns 0 if particle i is converted to wind. */
617  // message(1, "%ld Making ID=%ld (%g %g %g) to wind with v= %g\n", ID, P[i].ID, P[i].Pos[0], P[i].Pos[1], P[i].Pos[2], v);
618  /* ok, make the particle go into the wind */
619  double theta = acos(2 * get_random_number(P[i].ID + 3) - 1);
620  double phi = 2 * M_PI * get_random_number(P[i].ID + 4);
621 
622  dir[0] = sin(theta) * cos(phi);
623  dir[1] = sin(theta) * sin(phi);
624  dir[2] = cos(theta);
625  return 0;
626 }
627 
628 /* Get the parameters of the wind kick*/
629 static void
630 get_wind_params(double * vel, double * windeff, double * utherm, const double vdisp, const double time)
631 {
632  /* Physical velocity*/
633  double vphys = vdisp / time;
634  *utherm = wind_params.WindThermalFactor * 1.5 * vphys * vphys;
636  *windeff = wind_params.WindEfficiency;
637  *vel = wind_params.WindSpeed * time;
638  } else if(HAS(wind_params.WindModel, WIND_USE_HALO)) {
639  *windeff = pow(wind_params.WindSigma0, 2) / (vphys * vphys + 2 * (*utherm));
640  *vel = wind_params.WindSpeedFactor * vdisp;
641  } else {
642  endrun(1, "WindModel = 0x%X is strange. This shall not happen.\n", wind_params.WindModel);
643  }
644  /* Minimum wind velocity. This ensures particles do not remain in the wind forever*/
645  if(*vel < wind_params.MinWindVelocity * time)
646  *vel = wind_params.MinWindVelocity * time;
647 }
648 
649 static void
651  TreeWalkResultWind * O,
652  TreeWalkNgbIterWind * iter,
653  LocalTreeWalk * lv)
654 {
655 
656  /* this evaluator walks the tree and blows wind. */
657 
658  if(iter->base.other == -1) {
659  iter->base.mask = 1;
661  iter->base.Hsml = I->Hsml;
662  return;
663  }
664  int other = iter->base.other;
665  double r = iter->base.r;
666 
667  /* this is radius cut is redundant because the tree walk is asymmetric
668  * we may want to use fancier weighting that requires symmetric in the future. */
669  if(r > I->Hsml) return;
670 
671  /* skip earlier wind particles */
672  if(SPHP(other).DelayTime > 0) return;
673 
674  /* No eligible gas particles not in wind*/
675  if(I->TotalWeight == 0 || I->Vdisp <= 0) return;
676 
677  /* Paranoia*/
678  if(P[other].Type != 0 || P[other].IsGarbage || P[other].Swallowed)
679  return;
680 
681  /* Get the velocity, thermal energy and efficiency of the kick*/
682  double utherm = 0, v=0, windeff = 0;
683  get_wind_params(&v, &windeff, &utherm, I->Vdisp, WIND_GET_PRIV(lv->tw)->Time);
684 
685  double p = windeff * I->Mass / I->TotalWeight;
686  double random = get_random_number(I->ID + P[other].ID);
687 
688  if (random < p && v > 0) {
689  /* Store a potential kick. This might not be the kick actually used,
690  * because another star particle may be closer, but we can resolve
691  * that after the treewalk*/
692  int64_t * nkicks = &WIND_GET_PRIV(lv->tw)->nkicks;
693  /* Use a single global kick list.*/
694  int64_t ikick = atomic_fetch_and_add_64(nkicks, 1);
695  if(ikick >= WIND_GET_PRIV(lv->tw)->maxkicks)
696  endrun(5, "Not enough room in kick queue: %ld > %ld for particle %d starid %ld distance %g\n",
697  ikick, WIND_GET_PRIV(lv->tw)->maxkicks, other, I->ID, r);
698  struct StarKick * kick = &WIND_GET_PRIV(lv->tw)->kicks[ikick];
699  kick->StarDistance = r;
700  kick->StarID = I->ID;
701  kick->StarKickVelocity = v;
702  kick->StarTherm = utherm;
703  kick->part_index = other;
704  }
705 }
706 
707 int
708 winds_make_after_sf(int i, double sm, double vdisp, double atime)
709 {
711  return 0;
712 
713  /* Get the velocity, thermal energy and efficiency of the kick*/
714  double utherm = 0, vel=0, windeff = 0;
715  get_wind_params(&vel, &windeff, &utherm, vdisp, atime);
716 
717  /* Here comes the Springel Hernquist 03 wind model */
718  /* Notice that this is the mass of the gas particle after forking a star, Mass - Mass/GENERATIONS.*/
719  double pw = windeff * sm / P[i].Mass;
720  double prob = 1 - exp(-pw);
721  if(get_random_number(P[i].ID + 2) < prob) {
722  wind_do_kick(i, vel, utherm, atime);
723  }
724  return 0;
725 }
double(* wk)(DensityKernel *kernel, double q)
Definition: densitykernel.c:94
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
static double dloga
Definition: lightcone.c:21
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define ta_malloc(name, type, nele)
Definition: mymalloc.h:25
#define ta_free(p)
Definition: mymalloc.h:28
#define myfree(x)
Definition: mymalloc.h:19
double param_get_double(ParameterSet *ps, const char *name)
Definition: paramset.c:336
int param_get_enum(ParameterSet *ps, const char *name)
Definition: paramset.c:378
#define P
Definition: partmanager.h:88
#define GAMMA_MINUS1
Definition: physconst.h:35
#define GAMMA
Definition: physconst.h:34
#define SEC_PER_MEGAYEAR
Definition: physconst.h:31
struct slots_manager_type SlotsManager[1]
Definition: slotsmanager.c:7
#define SPHP(i)
Definition: slotsmanager.h:124
double BoxSize
Definition: forcetree.h:106
TreeWalk * tw
Definition: treewalk.h:47
int part_index
Definition: winds.c:208
MyIDType StarID
Definition: winds.c:212
double StarKickVelocity
Definition: winds.c:214
double StarTherm
Definition: winds.c:216
double StarDistance
Definition: winds.c:210
double dist[3]
Definition: treewalk.h:40
enum NgbTreeFindSymmetric symmetric
Definition: treewalk.h:37
TreeWalkNgbIterBase base
Definition: winds.c:65
double Mass
Definition: winds.c:46
MyIDType ID
Definition: winds.c:44
double Vdisp
Definition: winds.c:50
double Dt
Definition: winds.c:45
double DMRadius[NWINDHSML]
Definition: winds.c:49
double Hsml
Definition: winds.c:47
double Vel[3]
Definition: winds.c:51
TreeWalkQueryBase base
Definition: winds.c:43
double TotalWeight
Definition: winds.c:48
double TotalWeight
Definition: winds.c:56
double Ngb[NWINDHSML]
Definition: winds.c:59
double V2sum[NWINDHSML]
Definition: winds.c:58
double V1sum[NWINDHSML][3]
Definition: winds.c:57
TreeWalkResultBase base
Definition: winds.c:55
int64_t Niteration
Definition: treewalk.h:142
double * minnumngb
Definition: treewalk.h:172
void * priv
Definition: treewalk.h:85
TreeWalkHasWorkFunction haswork
Definition: treewalk.h:100
size_t ngbiter_type_elsize
Definition: treewalk.h:97
double * maxnumngb
Definition: treewalk.h:171
int ** NPRedo
Definition: treewalk.h:168
const ForceTree * tree
Definition: treewalk.h:88
TreeWalkProcessFunction postprocess
Definition: treewalk.h:104
TreeWalkNgbIterFunction ngbiter
Definition: treewalk.h:103
TreeWalkReduceResultFunction reduce
Definition: treewalk.h:102
const char * ev_label
Definition: treewalk.h:91
TreeWalkVisitFunction visit
Definition: treewalk.h:99
size_t result_type_elsize
Definition: treewalk.h:96
TreeWalkFillQueryFunction fill
Definition: treewalk.h:101
size_t * NPLeft
Definition: treewalk.h:167
size_t query_type_elsize
Definition: treewalk.h:95
double WindFreeTravelDensThresh
Definition: winds.c:22
double WindEnergyFraction
Definition: winds.c:28
double WindEfficiency
Definition: winds.c:26
double WindSpeedFactor
Definition: winds.c:31
double WindThermalFactor
Definition: winds.c:35
enum WindModel WindModel
Definition: winds.c:18
double WindFreeTravelLength
Definition: winds.c:19
double WindSpeed
Definition: winds.c:27
double WindSigma0
Definition: winds.c:30
double MinWindVelocity
Definition: winds.c:33
double WindFreeTravelDensFac
Definition: winds.c:20
double MaxWindFreeTravelTime
Definition: winds.c:24
struct StarKick * kicks
Definition: winds.c:223
double hubble
Definition: winds.c:221
int64_t nkicks
Definition: winds.c:224
int64_t maxkicks
Definition: winds.c:225
int * nvisited
Definition: winds.c:226
double Time
Definition: winds.c:220
struct winddata * Winddata
Definition: winds.c:222
int64_t size
Definition: slotsmanager.h:12
struct slot_info info[6]
Definition: slotsmanager.h:112
double TotalWeight
Definition: winds.c:182
double DMRadius
Definition: winds.c:179
double Right
Definition: winds.c:181
double Left
Definition: winds.c:180
int maxcmpte
Definition: winds.c:188
double V2sum[NWINDHSML]
Definition: winds.c:185
double Vdisp
Definition: winds.c:184
double Ngb[NWINDHSML]
Definition: winds.c:187
double V1sum[NWINDHSML][3]
Definition: winds.c:186
double get_random_number(uint64_t id)
Definition: system.c:60
void sumup_large_ints(int n, int *src, int64_t *res)
Definition: system.c:192
int MPIU_Any(int condition, MPI_Comm comm)
Definition: system.c:545
static int64_t atomic_fetch_and_add_64(int64_t *ptr, int64_t value)
Definition: system.h:68
#define MPI_INT64
Definition: system.h:12
int ThisTask
Definition: test_exchange.c:23
#define qsort_openmp
Definition: test_exchange.c:14
#define DMAX(x, y)
Definition: test_interp.c:11
double get_dloga_for_bin(int timebin, const inttime_t Ti_Current)
Definition: timebinmgr.c:279
int treewalk_visit_nolist_ngbiter(TreeWalkQueryBase *I, TreeWalkResultBase *O, LocalTreeWalk *lv)
Definition: treewalk.c:1143
void treewalk_run(TreeWalk *tw, int *active_set, size_t size)
Definition: treewalk.c:619
double ngb_narrow_down(double *right, double *left, const double *radius, const double *numNgb, int maxcmpt, int desnumngb, int *closeidx, double BoxSize)
Definition: treewalk.c:1366
void treewalk_do_hsml_loop(TreeWalk *tw, int *queue, int64_t queuesize, int update_hsml)
Definition: treewalk.c:1254
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
TreeWalkReduceMode
Definition: treewalk.h:15
void(* TreeWalkProcessFunction)(const int i, TreeWalk *tw)
Definition: treewalk.h:73
void(* TreeWalkNgbIterFunction)(TreeWalkQueryBase *input, TreeWalkResultBase *output, TreeWalkNgbIterBase *iter, LocalTreeWalk *lv)
Definition: treewalk.h:70
void(* TreeWalkFillQueryFunction)(const int j, TreeWalkQueryBase *query, TreeWalk *tw)
Definition: treewalk.h:75
#define TREEWALK_REDUCE(A, B)
Definition: treewalk.h:189
@ NGB_TREEFIND_ASYMMETRIC
Definition: treewalk.h:12
#define HAS(val, flag)
Definition: types.h:22
uint64_t MyIDType
Definition: types.h:10
LOW_PRECISION MyFloat
Definition: types.h:19
#define walltime_measure(name)
Definition: walltime.h:8
static void sfr_wind_reduce_weight(int place, TreeWalkResultWind *remote, enum TreeWalkReduceMode mode, TreeWalk *tw)
Definition: winds.c:480
static double effdmradius(int place, int i, TreeWalk *tw)
Definition: winds.c:422
#define NUMDMNGB
Definition: winds.c:39
void winds_evolve(int i, double a3inv, double hubble)
Definition: winds.c:403
void winds_subgrid(int *MaybeWind, int NumMaybeWind, const double Time, const double hubble, ForceTree *tree, MyFloat *StellarMasses)
Definition: winds.c:306
#define NWINDHSML
Definition: winds.c:38
#define WIND_GET_PRIV(tw)
Definition: winds.c:250
static void wind_do_kick(int other, double vel, double therm, double atime)
Definition: winds.c:590
static void sfr_wind_weight_ngbiter(TreeWalkQueryWind *I, TreeWalkResultWind *O, TreeWalkNgbIterWind *iter, LocalTreeWalk *lv)
Definition: winds.c:521
static void sfr_wind_weight_postprocess(const int i, TreeWalk *tw)
Definition: winds.c:441
static void sfr_wind_feedback_ngbiter(TreeWalkQueryWind *I, TreeWalkResultWind *O, TreeWalkNgbIterWind *iter, LocalTreeWalk *lv)
Definition: winds.c:650
int winds_ever_decouple(void)
Definition: winds.c:192
int cmp_by_part_id(const void *a, const void *b)
Definition: winds.c:231
int winds_is_particle_decoupled(int i)
Definition: winds.c:124
int winds_are_subgrid(void)
Definition: winds.c:115
static void get_wind_params(double *vel, double *windeff, double *utherm, const double vdisp, const double time)
Definition: winds.c:630
void set_winds_params(ParameterSet *ps)
Definition: winds.c:72
#define MAXDMDEVIATION
Definition: winds.c:40
static int get_wind_dir(int i, double dir[3])
Definition: winds.c:614
static struct WindParams wind_params
void winds_decoupled_hydro(int i, double atime)
Definition: winds.c:133
int winds_make_after_sf(int i, double sm, double vdisp, double atime)
Definition: winds.c:708
#define WINDP(i, wind)
Definition: winds.c:251
static void winds_find_weights(TreeWalk *tw, struct WindPriv *priv, int *NewStars, int NumNewStars, const double Time, const double hubble, ForceTree *tree)
Definition: winds.c:255
static void sfr_wind_copy(int place, TreeWalkQueryWind *input, TreeWalk *tw)
Definition: winds.c:501
void winds_and_feedback(int *NewStars, int NumNewStars, const double Time, const double hubble, ForceTree *tree)
Definition: winds.c:333
void init_winds(double FactorSN, double EgySpecSN, double PhysDensThresh, double UnitTime_in_s)
Definition: winds.c:97
WindModel
Definition: winds.h:12
@ WIND_FIXED_EFFICIENCY
Definition: winds.h:17
@ WIND_USE_HALO
Definition: winds.h:16
@ WIND_DECOUPLE_SPH
Definition: winds.h:15
@ WIND_SUBGRID
Definition: winds.h:13