FML
SphericalCollapse.cpp
Go to the documentation of this file.
1#include "SphericalCollapse.h"
2
3namespace FML {
4
5 namespace COSMOLOGY {
6
7 namespace SPHERICALCOLLAPSE {
8
9 //================================================
10 // Computes the growth factor (not normalized) and growth rate
11 //================================================
14 Spline & growthfactor_of_x_spline,
15 Spline & growthrate_of_x_spline,
16 const double xini,
17 const double xend,
18 const int npts){
19
20 auto x_array = FML::MATH::linspace(xini, xend, npts);
21 ODEFunction deriv = [&model](double x, const double * y, double * dydx) {
22 return model.ode_system_linear_growth(x, y, dydx);
23 };
24
25 // EdS D ~ a so D'=D
26 DVector y_initial{std::exp(xini), std::exp(xini)};
27 ODESolver ode;
28 ode.solve(deriv, x_array, y_initial);
29 const auto growthfactor_array = ode.get_data_by_component(0);
30 const auto delta_prime_lin_array = ode.get_data_by_component(1);
31 auto growthrate_array = delta_prime_lin_array;
32 for(size_t i = 0; i < growthfactor_array.size(); i++){
33 growthrate_array[i] /= growthfactor_array[i];
34 }
35 growthfactor_of_x_spline = Spline(x_array, growthfactor_array, "Growthfactor D(loga)");
36 growthrate_of_x_spline = Spline(x_array, growthrate_array, "Growthrate f(loga)");
37 }
38
39 //================================================
40 // This is the dimensionless quantity r(x)/R
41 // for spherical collapse evolution
42 //================================================
44 double delta,
45 double x,
46 double RH0,
47 double delta_ini) {
48 return (RH0) * std::pow((1.0+delta_ini)/(1.0+delta),1.0/3.0)*std::exp(x);
49 };
50
51 //===========================================================
52 // Evolve the spherical collapse equation + linear
53 // for a given set of IC delta_ini over a given range
54 // [xini,xcollapse] and return the arrays + the x-value
55 // where delta(x) > delta_infinity (i.e. it has collapsed
56 // completely). If it haven't collapsed return xcollapse
57 // This value can be used to more easily figure out delta_ini
58 // that corresponds to collapse at exactly xcollapse via
59 // root finding
60 //===========================================================
63 const double delta_ini,
64 DVector & x_array,
65 DVector & delta_array,
66 DVector & delta_prime_array,
67 DVector & delta_lin_array,
68 DVector & delta_lin_prime_array,
69 const bool get_arrays,
70 const double xini,
71 const double xcollapse,
72 const int npts,
73 const double delta_infinity) {
74
75 // ODE solver parameters
76 const double hstart = 1e-3;
77 const double epsilon_abs = 1e-6;
78 const double epsilon_rel = 1e-6;
79
80 // The first x for which delta > delta_infinity
81 double xminover = xcollapse;
82
83 // Set x array (linear in 'a' seems to work well)
84 x_array = FML::MATH::linspace(std::exp(xini),std::exp(xcollapse),npts);
85 for(auto & x : x_array) x = std::log(x);
86
87 ODEFunction deriv = [&model,&xminover,&delta_infinity](double x, const double * y, double * dydx) -> int {
88 // Check if we have collapsed
89 if(y[0] > delta_infinity){
90 if(x < xminover) xminover = x;
91 dydx[0] = dydx[1] = 0.0;
92 return GSL_SUCCESS;
93 }
94 return model.ode_system_non_linear_growth(x, y, dydx);
95 };
96
97 // The growing mode has D ~ a = exp(x) so D' = D
98 DVector y_initial{delta_ini, delta_ini, delta_ini, delta_ini};
99 ODESolver ode;
100 ode.set_accuracy(hstart, epsilon_abs, epsilon_rel);
101 ode.solve(deriv, x_array, y_initial, gsl_odeiv2_step_rkck);
102
103 // Fetch solution arrays
104 if(get_arrays){
105 delta_array = ode.get_data_by_component(0);
106 delta_prime_array = ode.get_data_by_component(1);
107 delta_lin_array = ode.get_data_by_component(2);
108 delta_lin_prime_array = ode.get_data_by_component(3);
109 }
110 return xminover;
111 }
112
113 //===========================================================
114 // Do root finding to figure out the delta_ini that gives
115 // collapse at x=xcollapse
116 //===========================================================
119 const double xini,
120 const double xcollapse,
121 const int npts,
122 const double epsilon_delta){
123
124 auto condition = [&](double delta_ini){
125 DVector x_array, delta_array, delta_prime_array, delta_lin_array, delta_lin_prime_array;
126 const double xminover = evolve_spherical_collapse_equations(
127 model,
128 delta_ini,
129 x_array,
130 delta_array,
131 delta_prime_array,
132 delta_lin_array,
133 delta_lin_prime_array,
134 false,
135 xini,
136 xcollapse,
137 npts);
138 return xminover - xcollapse;
139 };
140 return FML::MATH::find_root_bisection(condition, {0.0, 1.0}, epsilon_delta);
141 }
142
143 //================================================
144 // Extract useful times from spherical collapse evolution
145 // like turnaround, virialization and non-linear onset
146 //================================================
148 const double xini,
149 const double xcollapse,
151 const Spline & delta_spline,
152 const Spline & delta_prime_spline) -> std::tuple<double, double, double, double> {
153
154 // Accuracy in x for finding times
155 const double epsilon_x = 1e-8;
156
157 // Compute turnaround time
158 auto turnaround_condition = [&delta_spline, &delta_prime_spline](double x){
159 const double delta = delta_spline(x), delta_prime = delta_prime_spline(x);
160 return 1.0 - delta_prime/3.0/(1.0+delta);
161 };
162 const double xturnaround = FML::MATH::find_root_bisection(turnaround_condition, {xini, xcollapse}, epsilon_x);
163
164 // Compute virialization time
165 auto virial_condition = [&model, &delta_spline, &delta_prime_spline](double x) {
166 const double delta = delta_spline(x), delta_prime = delta_prime_spline(x);
167 const double roverR = roverR_of_delta_and_x(delta, x);
168 return model.virial_condition(delta, delta_prime, roverR, x);
169 };
170 // If we have several times where 2T+W=0 pick the one with largest redshift
171 double x_search = xturnaround;
172 const double deltax = 0.01;
173 const int sign = virial_condition(x_search) > 0 ? 1 : -1;
174 while(true){
175 const int sign1 = virial_condition(x_search) > 0 ? 1 : -1;
176 if(sign * sign1 == -1) break;
177 x_search += deltax;
178 }
179 const double xvir = FML::MATH::find_root_bisection(virial_condition, {xturnaround, x_search}, epsilon_x);
180
181 // Compute non-linear time
182 auto nonlinear_condition = [&model, &delta_spline, &delta_prime_spline](double x){
183 const double delta = delta_spline(x), delta_prime = delta_prime_spline(x);
184 const double roverR = roverR_of_delta_and_x(delta, x);
185 return model.nonlinear_condition(delta, delta_prime, roverR, x);;
186 };
187 const double xnl = FML::MATH::find_root_bisection(nonlinear_condition, {xini, xcollapse}, epsilon_x);
188
189 // Compute time for which r=rturnaround/2
190 const double roverR_turnaround = roverR_of_delta_and_x(delta_spline(xturnaround), xturnaround);
191 auto halfturnaround_condition = [&roverR_turnaround, &delta_spline](double x) {
192 const double delta = delta_spline(x);
193 const double roverR = roverR_of_delta_and_x(delta, x);
194 return roverR - roverR_turnaround/2.0;
195 };
196 const double xhalfturnaround = FML::MATH::find_root_bisection(halfturnaround_condition, {xturnaround, xcollapse}, epsilon_x);
197
198 return std::tuple(xturnaround, xvir, xnl, xhalfturnaround);
199 }
200
201 //================================================
202 // Runs spherical collapse for all redshifts
203 // and makes splines of deltac(z), ...
204 // and other stuff
205 //================================================
208 Spline & deltac_of_x_spline,
209 Spline & DeltaVir_of_x_spline,
210 Spline & xnl_of_x_spline,
211 Spline & xta_of_x_spline,
212 Spline & xvir_of_x_spline,
213 Spline & delta_ini_of_x_spline,
214 const double xini,
215 const int npts,
216 bool verbose){
217
218 // Run spherical collapse and extract splines
219 auto run_and_generate_delta_splines = [](
220 const double xini,
221 const double xcollapse,
222 const int npts,
224 Spline & delta_spline,
225 Spline & delta_prime_spline,
226 Spline & delta_lin_spline,
227 double delta_ini = -1.0){
228 if(delta_ini < 0.0)
229 delta_ini = find_delta_ini(model, xini, xcollapse, npts);
230 DVector x_array, delta_array, delta_prime_array, delta_lin_array, delta_lin_prime_array;
232 model,
233 delta_ini,
234 x_array,
235 delta_array,
236 delta_prime_array,
237 delta_lin_array,
238 delta_lin_prime_array,
239 true,
240 xini,
241 xcollapse,
242 npts);
243 delta_spline = Spline(x_array, delta_array, "delta(loga)");
244 delta_prime_spline = Spline(x_array, delta_prime_array, "ddelta/dloga(loga)");
245 delta_lin_spline = Spline(x_array, delta_lin_array, "deltaLin(loga)");
246 return delta_ini;
247 };
248
249 // Range we want deltac(z) etc on
250 const double zini = 10.0;
251 const double zend = 0.0;
252 const int npts_z = 100;
253 const auto xcollapse_array = FML::MATH::linspace(std::log(1.0/(1.0+zini)),std::log(1.0/(1.0+zend)),npts_z);
254
255 DVector deltac_array(xcollapse_array.size());
256 DVector DeltaVir_array(xcollapse_array.size());
257 DVector xta_array(xcollapse_array.size());
258 DVector xvir_array(xcollapse_array.size());
259 DVector xnl_array(xcollapse_array.size());
260 DVector delta_ini_array(xcollapse_array.size());
261
262#ifdef USE_OMP
263#pragma omp parallel for schedule(dynamic,1)
264#endif
265 for(size_t i = 0; i < xcollapse_array.size(); i++){
266 auto xcollapse = xcollapse_array[i];
267
268 // Generate solution
269 Spline delta_spline;
270 Spline delta_prime_spline;
271 Spline delta_lin_spline;
272 const double delta_ini = run_and_generate_delta_splines(
273 xini,
274 xcollapse,
275 npts,
276 model,
277 delta_spline,
278 delta_prime_spline,
279 delta_lin_spline);
280
281 // Compute quantities
282 const auto times = compute_times(xini, xcollapse, model, delta_spline, delta_prime_spline);
283 const double xta = std::get<0>(times);
284 const double xvir = std::get<1>(times);
285 const double xnl = std::get<2>(times);
286 const double xta2 = std::get<3>(times);
287 const double DeltaVir = (1.0+delta_spline(xvir))*std::exp(3.0*xcollapse-3.0*xvir);
288 const double deltac = delta_lin_spline(xcollapse);
289
290 if(xcollapse == 0.0 and verbose){
291 std::cout << "\n#=====================================================\n";
292 std::cout << "# For collapse at z=0 we get:\n";
293 std::cout << "#=====================================================\n";
294 std::cout << " deltac = " << deltac << "\n";
295 std::cout << " DeltaVir = " << DeltaVir << "\n";
296 std::cout << " Turnaround r = " << roverR_of_delta_and_x(delta_spline(xta),xta,1.0,0.0) << "\n";
297 std::cout << " Virial r = " << roverR_of_delta_and_x(delta_spline(xvir),xvir,1.0,0.0) << "\n";
298 std::cout << " rta/2 = " << roverR_of_delta_and_x(delta_spline(xta2),xta2,1.0,0.0) << "\n";
299 std::cout << "#=====================================================\n";
300 }
301
302 xta_array[i] = xta;
303 xnl_array[i] = xnl;
304 xvir_array[i] = xvir;
305 deltac_array[i] = deltac;
306 DeltaVir_array[i] = DeltaVir;
307 delta_ini_array[i] = delta_ini;
308
309 // In this case the problem is not well posed so return nan
310 if(model.muofx(xcollapse) <= 0.0){
311 throw std::runtime_error("Spherical collapse. Negative Geff/G encountere. Problem not well posed!");
312 }
313 }
314 xta_of_x_spline = Spline(xcollapse_array, xta_array, "loga_turnaround(loga_collapse)");
315 xnl_of_x_spline = Spline(xcollapse_array, xnl_array, "loga_nonlinear(loga_collapse)");
316 xvir_of_x_spline = Spline(xcollapse_array, xvir_array, "loga_virialization(loga_collapse)");
317 deltac_of_x_spline = Spline(xcollapse_array, deltac_array, "deltac(loga_collapse)");
318 DeltaVir_of_x_spline = Spline(xcollapse_array, DeltaVir_array, "DeltaVir(loga_collapse)");
319 delta_ini_of_x_spline = Spline(xcollapse_array, delta_ini_array, "delta_ini(loga_collapse)");
320 }
321
322 }
323 }
324}
const double zini
Definition: Main.cpp:40
The class contains all the info about the model needed to run the spherical collapse and halomodel Co...
This is a wrapper class for easy use of GSL splines It is (OpenMP) thread safe as long as splines are...
Definition: Spline.h:80
This is a wrapper around the GSL library to easily solve ODEs and return the data in whatever format ...
Definition: ODESolver.h:87
DVector get_data_by_component(int icomponent) const
Get the data for a particular component y_i(xarr)
Definition: ODESolver.cpp:178
void solve(ODEFunctionPointer ode_equation, void *parameters, DVector &xarr, DVector &yinitial, const gsl_odeiv2_step_type *stepper=ODESOLVER_FIDUCIAL_STEPPER, ODEFunctionPointerJacobian jacobian=nullptr)
Definition: ODESolver.cpp:71
void set_accuracy(const double hstart, const double abserr, const double relerr)
Set the accuracy parameters (first guess for the step-size, the absolute and relative error)
Definition: ODESolver.cpp:204
double evolve_spherical_collapse_equations(const SphericalCollapseModel &model, const double delta_ini, DVector &x_array, DVector &delta_array, DVector &delta_prime_array, DVector &delta_lin_array, DVector &delta_lin_prime_array, const bool get_arrays, const double xini, const double xcollapse, const int npts, const double delta_infinity)
Evolve the spherical collapse equation + linear for a given set of IC delta_ini over a given range [x...
void compute_growthfactor(const SphericalCollapseModel &model, Spline &growthfactor_of_x_spline, Spline &growthrate_of_x_spline, const double xini, const double xend, const int npts)
Computes the growth factor (not normalized) and growth rate for a given model and returns splines wit...
auto compute_times(const double xini, const double xcollapse, const SphericalCollapseModel &model, const Spline &delta_spline, const Spline &delta_prime_spline) -> std::tuple< double, double, double, double >
Extract useful times from spherical collapse evolution like turnaround, virialization and non-linear ...
double find_delta_ini(const SphericalCollapseModel &model, const double xini, const double xcollapse, const int npts, const double epsilon_delta)
Do root finding to figure out the delta_ini that gives collapse at x=xcollapse.
FML::INTERPOLATION::SPLINE::Spline Spline
double roverR_of_delta_and_x(double delta, double x, double RH0, double delta_ini)
This is the dimensionless quantity (the radius of the tophat) for spherical collapse evolution,...
void compute_sphericalcollapse_splines(const SphericalCollapseModel &model, Spline &deltac_of_x_spline, Spline &DeltaVir_of_x_spline, Spline &xnl_of_x_spline, Spline &xta_of_x_spline, Spline &xvir_of_x_spline, Spline &delta_ini_of_x_spline, const double xini, const int npts, bool verbose)
Do spherical collapse for all times.
FML::SOLVERS::ODESOLVER::DVector DVector
FML::SOLVERS::ODESOLVER::ODEFunction ODEFunction
DVector linspace(double xmin, double xmax, int num)
Python linspace. Generate a lineary spaced array.
Definition: Math.cpp:269
double find_root_bisection(const std::function< double(double)> &function, std::pair< double, double > xrange, double epsilon)
Find roots using bisection.
Definition: Math.cpp:51
Definition: CAMBReader.h:10
return y
Definition: Global.h:265
const double exp
Definition: Global.h:259
deltac
Definition: example.py:67
bool verbose
Definition: example.py:19
x
Definition: test.py:18