MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
thermal.c
Go to the documentation of this file.
1 #include <gsl/gsl_integration.h>
2 #include <gsl/gsl_interp.h>
3 #include <gsl/gsl_rng.h>
4 #include <assert.h>
5 #include "thermal.h"
6 /*For speed of light*/
7 #include <libgadget/physconst.h>
8 #include <libgadget/utils.h>
9 
10 /*The Boltzmann constant in units of eV/K*/
11 #define BOLEVK 8.61734e-5
12 
13 /* This function converts the dimensionless units used in the integral to dimensionful units.
14  * Unit scaling velocity for neutrinos:
15  * This is an arbitrary rescaling of the unit system in the Fermi-Dirac kernel so we can integrate dimensionless quantities.
16  * The true thing to integrate is:
17  * q^2 /(e^(q c / kT) + 1 ) dq between 0 and q.
18  * So we choose x = (q c / kT_0) and integrate between 0 and x_0.
19  * The units are restored by multiplying the resulting x by kT/c for q
20  * To get a v we then use q = a m v/c^2
21  * to get: v/c =x kT/(m a)*/
22 /*NOTE: this m is the mass of a SINGLE neutrino species, not the sum of neutrinos!*/
23 double
24 NU_V0(const double Time, const double kBTNubyMNu, const double UnitVelocity_in_cm_per_s)
25 {
26  return kBTNubyMNu / Time * (LIGHTCGS / UnitVelocity_in_cm_per_s);
27 }
28 
29 //Amplitude of the random velocity for WDM
30 double WDM_V0(const double Time, const double WDM_therm_mass, const double Omega_CDM, const double HubbleParam, const double UnitVelocity_in_cm_per_s)
31 {
32  //Not actually sure where this equation comes from: the fiducial values are from Bode, Ostriker & Turok 2001.
33  double WDM_V0 = 0.012 / Time * pow(Omega_CDM / 0.3, 1.0 / 3) * pow(HubbleParam / 0.65, 2.0 / 3) * pow(1.0 /WDM_therm_mass,4.0 / 3);
34  WDM_V0 *= 1.0e5 / UnitVelocity_in_cm_per_s;
35  return WDM_V0;
36 }
37 
38 /*Fermi-Dirac kernel for below*/
39 static double
40 fermi_dirac_kernel(double x, void * params)
41 {
42  return x * x / (exp(x) + 1);
43 }
44 
45 /*Initialise the probability tables*/
46 double
47 init_thermalvel(struct thermalvel* thermals, const double v_amp, double max_fd,const double min_fd)
48 {
49  int i;
50  if(max_fd <= min_fd)
51  endrun(1,"Thermal vel called with negative interval: %g <= %g\n", max_fd, min_fd);
52 
53  if(max_fd > MAX_FERMI_DIRAC)
54  max_fd = MAX_FERMI_DIRAC;
55  thermals->m_vamp = v_amp;
56 
57  /*These functions are so smooth that we don't need much space*/
58  gsl_integration_workspace * w = gsl_integration_workspace_alloc (100);
59  double abserr;
60  gsl_function F;
61  F.function = &fermi_dirac_kernel;
62  F.params = NULL;
63  for(i = 0; i < LENGTH_FERMI_DIRAC_TABLE; i++) {
64  thermals->fermi_dirac_vel[i] = min_fd+(max_fd-min_fd)* i / (LENGTH_FERMI_DIRAC_TABLE - 1.0);
65  gsl_integration_qag (&F, min_fd, thermals->fermi_dirac_vel[i], 0, 1e-6,100,GSL_INTEG_GAUSS61, w,&(thermals->fermi_dirac_cumprob[i]), &abserr);
66  // printf("gsl_integration_qng in fermi_dirac_init_nu. Result %g, error: %g, intervals: %lu\n",fermi_dirac_cumprob[i], abserr,w->size);
67  }
68  /*Save the largest cum. probability, pre-normalisation,
69  * divided by the total F-D probability (which is 3 Zeta(3)/2 ~ 1.8 if MAX_FERMI_DIRAC is large enough*/
70  double total_fd;
71  gsl_integration_qag (&F, 0, MAX_FERMI_DIRAC, 0, 1e-6,100,GSL_INTEG_GAUSS61, w,&(total_fd), &abserr);
72  assert(total_fd > 1.8);
73 
74  gsl_integration_workspace_free (w);
75 
76  double total_frac = thermals->fermi_dirac_cumprob[LENGTH_FERMI_DIRAC_TABLE-1]/total_fd;
77  //Normalise total integral to unity
78  for(i = 0; i < LENGTH_FERMI_DIRAC_TABLE; i++)
80 
81  /*Initialise the GSL table*/
82  thermals->fd_intp = gsl_interp_alloc(gsl_interp_cspline,LENGTH_FERMI_DIRAC_TABLE);
83  thermals->fd_intp_acc = gsl_interp_accel_alloc();
84  gsl_interp_init(thermals->fd_intp,thermals->fermi_dirac_cumprob, thermals->fermi_dirac_vel,LENGTH_FERMI_DIRAC_TABLE);
85  return total_frac;
86 }
87 
88 /*Generate a table of random seeds, one for each pencil.*/
89 unsigned int *
90 init_rng(int Seed, int Nmesh)
91 {
92  unsigned int * seedtable = (unsigned int *) mymalloc("randseeds", Nmesh*Nmesh*sizeof(unsigned int));
93  gsl_rng * rng = gsl_rng_alloc(gsl_rng_ranlxd1);
94  gsl_rng_set(rng, Seed);
95 
96  int i, j;
97  for(i = 0; i < Nmesh; i++)
98  for(j=0; j < Nmesh; j++)
99  {
100  seedtable[i+Nmesh*j] = gsl_rng_get(rng);
101  }
102  gsl_rng_free(rng);
103  return seedtable;
104 }
105 
106 /* Add a randomly generated thermal speed in v_amp*(min_fd, max_fd) to a 3-velocity.
107  * The particle Id is used as a seed for the RNG.*/
108 void
109 add_thermal_speeds(struct thermalvel * thermals, gsl_rng *g_rng, float Vel[])
110 {
111  const double p = gsl_rng_uniform (g_rng);
112  /*m_vamp multiples by the dimensional factor to get a velocity again.*/
113  const double v = thermals->m_vamp * gsl_interp_eval(thermals->fd_intp,thermals->fermi_dirac_cumprob, thermals->fermi_dirac_vel, p, thermals->fd_intp_acc);
114 
115  /*Random phase*/
116  const double phi = 2 * M_PI * gsl_rng_uniform (g_rng);
117  const double theta = acos(2 * gsl_rng_uniform (g_rng) - 1);
118 
119  Vel[0] += v * sin(theta) * cos(phi);
120  Vel[1] += v * sin(theta) * sin(phi);
121  Vel[2] += v * cos(theta);
122 }
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define LIGHTCGS
Definition: physconst.h:18
gsl_interp * fd_intp
Definition: thermal.h:15
double fermi_dirac_cumprob[LENGTH_FERMI_DIRAC_TABLE]
Definition: thermal.h:13
double m_vamp
Definition: thermal.h:14
double fermi_dirac_vel[LENGTH_FERMI_DIRAC_TABLE]
Definition: thermal.h:12
gsl_interp_accel * fd_intp_acc
Definition: thermal.h:16
double NU_V0(const double Time, const double kBTNubyMNu, const double UnitVelocity_in_cm_per_s)
Definition: thermal.c:24
double WDM_V0(const double Time, const double WDM_therm_mass, const double Omega_CDM, const double HubbleParam, const double UnitVelocity_in_cm_per_s)
Definition: thermal.c:30
unsigned int * init_rng(int Seed, int Nmesh)
Definition: thermal.c:90
double init_thermalvel(struct thermalvel *thermals, const double v_amp, double max_fd, const double min_fd)
Definition: thermal.c:47
void add_thermal_speeds(struct thermalvel *thermals, gsl_rng *g_rng, float Vel[])
Definition: thermal.c:109
static double fermi_dirac_kernel(double x, void *params)
Definition: thermal.c:40
#define MAX_FERMI_DIRAC
Definition: thermal.h:7
#define LENGTH_FERMI_DIRAC_TABLE
Definition: thermal.h:8