-
Notifications
You must be signed in to change notification settings - Fork 0
/
MWDisks.cpp
206 lines (182 loc) · 4.41 KB
/
MWDisks.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
This code is free to use, copy, distribute, and modify.
If you use this code or any modification of this code, we request that you reference both this code https://zenodo.org/record/438675 and the paper https://arxiv.org/abs/1703.09721.
*/
#include <math.h>
#include <cmath>
#include <assert.h>
#include "MWDisks.h"
#include "Coordinates.h"
#include "rng.h"
// initialize the MCMC points
MCMC_point::MCMC_point(double x, double y, double z, int section)
: x(x), y(y), z(z), section(section)
{
Calc_Phi(this);
}
// the MCMC points
MCMC_point MCMC_bulge(0, 0, 0, 0);
MCMC_point MCMC_thin(0, 0, 0, 1);
MCMC_point MCMC_thick(0, 0, 0, 2);
// 5pc minimum distance cutoff
const double d_min = 5;
// from 1102.4340
// See best fit in table 2
// in pc, solar masses
const double Sigma_d_thin = 816.6;
const double R_d_thin = 2.9e3;
const double Sigma_d_thick = 209.5;
const double R_d_thick = 3.31e3;
const double rho_b = 95.6;
const double R_0 = 8.29e3; // distance from sun to GC
// from below eq 1
const double M_b = 8.9e9;
const double alpha = 1.8;
const double r_0 = 0.075e3;
const double r_cut = 2.1e3;
const double q = 0.5;
// from below eq 3
const double M_thin = 2 * M_PI * Sigma_d_thin * pow(R_d_thin, 2);
const double M_thick = 2 * M_PI * Sigma_d_thick * pow(R_d_thick, 2);
const double z_d_thin = 300;
const double z_d_thick = 900;
void Calc_Phi(MCMC_point* p, bool rsq)
{
double R, r_prime, d, Phi;
R = sqrt(pow(p->x, 2) + pow(p->y, 2));
if (rsq)
d = sqrt(pow(p->x - R_0, 2) + pow(p->y, 2) + pow(p->z, 2)); // distance from point to earth
else
d = 1 + d_min; // for testing, compare to the function uncorrected by distance
// cutoff at sources too close to the earth
if (d < d_min)
{
p->Phi = 0;
return;
}
switch (p->section)
{
case 0: // bulge
r_prime = sqrt(pow(R, 2) + pow(p->z / q, 2));
Phi = exp(-pow(r_prime / r_cut, 2)) / pow(1 + r_prime / r_0, alpha);
break;
case 1: // thin
Phi = (Sigma_d_thin / (2 * z_d_thin)) * exp(-std::abs(p->z) / z_d_thin - R / R_d_thin);
break;
case 2: // thick
Phi = (Sigma_d_thick / (2 * z_d_thick)) * exp(-std::abs(p->z) / z_d_thick - R / R_d_thick);
break;
default:
Phi = 0;
}
p->Phi = Phi / pow(d, 2);
}
MCMC_point jump(MCMC_point p0, bool rsq)
{
MCMC_point p1 = p0;
switch (p0.section)
{
case 0: // bulge
double sigma;
sigma = r_0; // scale of bulge
sigma = R_0; // earth to bulge
switch (p0.parameter)
{
case 0: // x
p1.x = rng.gaussian(p1.x, sigma);
break;
case 1: // y
p1.y = rng.gaussian(p1.y, sigma);
break;
case 2: // z
p1.z = rng.gaussian(p1.z, sigma);
}
break;
case 1: // thin
switch (p0.parameter)
{
case 0: // x
p1.x = rng.gaussian(p0.x, R_d_thin);
break;
case 1: // y
p1.y = rng.gaussian(p0.y, R_d_thin);
break;
case 2: // z
p1.z = rng.gaussian(p0.z, z_d_thin);
}
break;
case 2: // thick
switch (p0.parameter)
{
case 0: // x
p1.x = rng.gaussian(p0.x, R_d_thick);
break;
case 1: // y
p1.y = rng.gaussian(p0.y, R_d_thick);
break;
case 2: // z
p1.z = rng.gaussian(p0.z, z_d_thick);
}
break;
}
p1.section = p0.section;
Calc_Phi(&p1, rsq);
return p1;
}
// metropolis hastings
void MH(MCMC_point* p, bool rsq)
{
MCMC_point jumped;
jumped = jump(*p, rsq);
p->parameter = (p->parameter + 1) % 3;
if (jumped.Phi > p->Phi)
{
*p = jumped;
return;
} // new point is better than the first: automatically accept
double r = rng.rand();
if (r < jumped.Phi / p->Phi)
{
*p = jumped;
return;
} // new point isn't too much worse, accept anyways
// keep the old point
// do nothing
}
coord_sph spherical(MCMC_point p)
{
coord_cart coord_c;
coord_c.x = p.x;
coord_c.y = p.y;
coord_c.z = p.z;
return cart_to_sph(coord_c);
}
coord_sph MW_sph(bool rsq)
{
// determine if from bulge, thin disk, or thick disk based on the total mass in each region
double M_rand;
coord_sph coord_s;
M_rand = rng.rand(M_b + M_thin + M_thick);
if (M_rand < M_b)
{
MH(&MCMC_bulge, rsq);
coord_s = spherical(MCMC_bulge);
} // from bulge
else if (M_rand < M_b + M_thin)
{
MH(&MCMC_thin, rsq);
coord_s = spherical(MCMC_thin);
} // from thin disk
else
{
MH(&MCMC_thick, rsq);
coord_s = spherical(MCMC_thick);
} // from thick disk
coord_s = gal_to_sun(coord_s); // back to centered on the sun
return coord_s;
}
coord2D MW(bool rsq)
{
coord_sph coord_s = MW_sph(rsq);
return coord2D(coord_s.theta, coord_s.phi);
}