-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshell_collapse_emd.cpp
214 lines (161 loc) · 7.24 KB
/
shell_collapse_emd.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
206
207
208
209
210
211
212
213
214
/*
* In this example we evaluate the collapse of a constant density sphere to the turn-around point
* during EMD followed by RD
* The initial radial velocity of the shells is given by vr = H*r
* This turn-around point (radius and time) agree with those estimated based on analytics for these same initial conditions
*/
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <cstdlib>
using std::exit;
#include <vector>
using std::vector;
#include <sstream>
#include "src/shell.hpp"
#include "src/nbody_system_emd.hpp"
#include "src/integrator.hpp"
int sim_steps = 0; // Integral simulation time. Real time given by dt*sim_time
const int nshells = 100; // Number of shell sot simulate
double epsilon = 0.5; // The initial perturbation has profile delta ~ (M/M_0)^-epsilon
// Parameter that specifies angular momentum of the shells following https://arxiv.org/pdf/astro-ph/0008217.pdf
// alpha = 0.5 are circular orbits during pure MD, alpha = 0 are radial orbits
double alpha = 0.01; // if alpha < 1, then IC is such that shell is bound
double delta_avg_init = 1e-1; // Initial average overdensity of the whole shell config (out to radius rmax)
const double Mtot = 1.; // Arbitrary normalization of shell masses
const double rmax = 1.; // Arbitrary normalization of distances
// Infer start time from initial overdensity
const double dt = 0.00005; // Initial stepsize (may be modified in the integrator)
const double tau_emd_over_ti = 100.;
// These need to be updated if delta_avg_init is changed
double ti = sqrt((2./9.) * (1.+delta_avg_init) * (1. + 1./sqrt(tau_emd_over_ti)) * exp(-1./tau_emd_over_ti));
double tau_emd = tau_emd_over_ti*ti; // lifetime of the field responsible for EMD
double sim_time_max = 50.*tau_emd; // Length of the simulation
const double stable_frac = 0.0001; // fraction of DM that does NOT decay at the end of EMD
vector<double> r_avg; // Radii for which to print out 1+delta(r)
vector<size_t> r_out; // Indices of radii for which to print out 1+delta(r)
void initialize_gas(nbody_system &gas)
{
double m;
double ri;
double vri;
double l;
// Shell initialization:
// shell(mass, double position, double velocity, double angular_momentum, double initial_time);
// We normalize shell masses such that the total mass is Mtot
m = Mtot/(nshells);
// Initializing following https://arxiv.org/pdf/astro-ph/0008217.pdf
double mass_interior;
double delta;
for(size_t i = 0; i < nshells; i++){
mass_interior = (i+1)*m*(stable_frac + (1.-stable_frac)*exp(-1/tau_emd_over_ti));
delta = delta_avg_init/pow((i+1.)/nshells,epsilon);
ri = pow(mass_interior*(1. + delta_avg_init)/(1. + delta),1./3.);
vri = (2./3.)*(ri/ti)*(1 - (1./3.)*delta/(1.+delta));
// Initialize angular momentum
l = sqrt(alpha*2.*ri*mass_interior);
gas[i] = shell(m, ri, vri, l, ti);
}
// Which shells to print out to standard output via output_shell_evolution below
r_out.push_back(1);
r_out.push_back(nshells/2);
r_out.push_back(nshells-1);
}
void output_shell_evolution(nbody_system &gas, ofstream & shell_evolution_file)
{
size_t i;
shell_evolution_file << std::scientific;
double t = gas[0].t;
shell_evolution_file << t << " ";
for (size_t m = 0; m < r_out.size(); m++)
{
i = r_out[m];
shell_evolution_file << gas[i].r << " " << gas[i].vr << " " << gas.get_delta_interior(t, i) << " " << gas.get_mass_interior(i) << " ";
}
//cout << get_total_energy() << " ";
double t_dyn;
for (size_t m = 0; m < r_out.size(); m++)
{
i = r_out[m];
t_dyn = gas[i].t_dyn;
shell_evolution_file << t_dyn/dt << " ";
}
shell_evolution_file << endl;
}
void output_energy_evolution(nbody_system &gas, ofstream & energy_file)
{
energy_file << std::scientific;
energy_file << gas[0].t/tau_emd << " " << gas.get_total_kinetic_energy()
<< " " << gas.get_total_potential_energy()
<< " " << gas.get_total_energy();
energy_file << endl;
}
int main(int argc, char **argv)
{
if (argc <= 4){
cout << "Need four arguments: output directory, initial profile slope epsilon, angular momentum parameter alpha, initial average overdensity!" << endl;
exit(0);
}
std::string out_dir = argv[1];
epsilon = atof(argv[2]);
alpha = atof(argv[3]);
// Set the initial overdensity, and re-compute times
if (argc > 4){
delta_avg_init = atof(argv[4]);
ti = sqrt((2./9.) * (1.+delta_avg_init) * (1. + 1./sqrt(tau_emd_over_ti)) * exp(-1./tau_emd_over_ti));
tau_emd = tau_emd_over_ti*ti; // lifetime of the field responsible for EMD
sim_time_max = 50.*tau_emd; // Length of the simulation
}
//cout << "tau_emd = " << tau_emd << endl;
//exit(0);
std::string out_param = out_dir + "/log.param";
std::string out_shell_evolution = out_dir + "/select_shell_evolution.dat";
std::string out_energy_evolution = out_dir + "/energy_evolution.dat";
ofstream shell_evolution_file (out_shell_evolution.c_str());
ofstream energy_evolution_file (out_energy_evolution.c_str());
// Write down the parameters of the run
ofstream param_file (out_param.c_str());
param_file << "Initial profile slope epsilon = " << epsilon << endl;
param_file << "Angular momentum parameter alpha = " << alpha << endl;
param_file << "Number of shells = " << nshells << endl;
param_file << "Initial average overdensity = " << delta_avg_init << endl;
param_file << "Stable DM fraction = " << stable_frac << endl;
param_file << "Minimum time step (if adaptive) = " << dt << endl;
// Initialize the n-shell system and specify initial conditions
nbody_system_emd gas(nshells, tau_emd, stable_frac);
initialize_gas(gas);
// Some sanity checks
param_file << "Sanity checks..." << endl;
param_file << "Simulating " << gas.size() << " shells..." << endl;
param_file << "Max radius = " << gas[nshells-1].r << "; M(nshells) = " << gas.get_mass_interior(nshells-1) << endl;
param_file << "Average overdensity = " << gas.get_delta_interior(ti, nshells-1) << "; should be = " << delta_avg_init << endl;
param_file.close();
// Choose the integrator
//leapfrog stepper(gas, ti, dt);
adaptive_leapfrog stepper(gas, ti, dt);
// Run the simulation and print output
while(stepper.t < sim_time_max)
{
stepper.update();
// Output a few individual shell properties
if ((sim_steps%200 == 0)) output_shell_evolution(gas, shell_evolution_file);
// Output binned density profile of the whole system
//if ((sim_steps%100000 == 0))
if ((sim_steps%1000 == 0))
{
std::string out_name;
std::ostringstream ss;
//ss << floor(stepper.t);
ss << round(100.*gas[0].t/tau_emd)/100.;
out_name = out_dir+"/radial_profile_"+ss.str()+".dat";
gas.output_radial_profile(out_name.c_str());
out_name = out_dir+"/shell_state_"+ss.str()+".dat";
gas.output_shell_state(out_name.c_str());
output_energy_evolution(gas, energy_evolution_file);
}
sim_steps++;
}
shell_evolution_file.close();
energy_evolution_file.close();
}