|
2 | 2 | import scipy |
3 | 3 | from scipy.interpolate import interp1d, BSpline, splrep |
4 | 4 |
|
5 | | -def empirical_density_profile(rbins, pos, mass): |
6 | | - """ |
7 | | - Computes the number density radial profile assuming all particles have the same mass. |
8 | | -
|
9 | | - Args: |
10 | | - pos (ndarray): array of particle positions in cartesian coordinates with shape (n,3). |
11 | | - mass (ndarray): array of particle masses with shape (n,). |
12 | | - nbins (int, optional): number of bins in the radial profile. Default is 500. |
13 | | - rmin (float, optional): minimum radius of the radial profile. Default is 0. |
14 | | - rmax (float, optional): maximum radius of the radial profile. Default is 600. |
15 | | - log_space (bool, optional): whether to use logarithmic binning. Default is False. |
16 | | -
|
17 | | - Returns: |
18 | | - tuple: a tuple containing the arrays of radius and density with shapes (nbins,) and (nbins,), respectively. |
19 | | -
|
20 | | - Raises: |
21 | | - ValueError: if pos and mass arrays have different lengths or if nbins is not a positive integer. |
22 | | - """ |
23 | | - if len(pos) != len(mass): |
24 | | - raise ValueError("pos and mass arrays must have the same length") |
25 | | - if not isinstance(len(rbins), int) or len(rbins) <= 0: |
26 | | - raise ValueError("rbins must be a positive integer") |
27 | | - |
28 | | - # Compute radial distances |
29 | | - r_p = np.sqrt(np.sum(pos**2, axis=1)) |
30 | | - |
31 | | - V_shells = 4/3 * np.pi * (rbins[1:]**3 - rbins[:-1]**3) |
32 | | - |
33 | | - # Compute density profile |
34 | | - density, _ = np.histogram(r_p, bins=rbins, weights=mass) |
35 | | - density /= V_shells |
36 | | - |
37 | | - #compute bin centers and return profile |
38 | | - radius = 0.5 * (rbins[1:] + rbins[:-1]) |
39 | | - |
40 | | - tck_s = splrep(radius, np.log10(density), s=0.15) |
41 | | - dens2 = BSpline(*tck_s)(radius) |
42 | | - |
43 | | - return radius, 10**dens2 |
44 | | - |
45 | | - |
46 | | - |
47 | | -def powerhalo(r, rs=1.,rc=0.,alpha=1.,beta=1.e-7): |
48 | | - """return generic twopower law distribution |
49 | | - |
50 | | - inputs |
51 | | - ---------- |
52 | | - r : (float) radius values |
53 | | - rs : (float, default=1.) scale radius |
54 | | - rc : (float, default=0. i.e. no core) core radius |
55 | | - alpha : (float, default=1.) inner halo slope |
56 | | - beta : (float, default=1.e-7) outer halo slope |
57 | | - |
58 | | - returns |
59 | | - ---------- |
60 | | - densities evaluated at r |
61 | | - |
62 | | - notes |
63 | | - ---------- |
64 | | - different combinations are known distributions. |
65 | | - alpha=1,beta=2 is NFW |
66 | | - alpha=1,beta=3 is Hernquist |
67 | | - alpha=2.5,beta=0 is a typical single power law halo |
68 | | - |
69 | | - |
70 | | - """ |
71 | | - ra = r/rs |
72 | | - return 1./(((ra+rc/rs)**alpha)*((1+ra)**beta)) |
73 | | - |
74 | | - |
75 | | -def powerhalorolloff(r, rs=1., rc=0., alpha=1., beta=1.e-7): |
76 | | - """return generic twopower law distribution with an erf rolloff |
77 | | - |
78 | | - inputs |
79 | | - ---------- |
80 | | - r : (float) radius values |
81 | | - rs : (float, default=1.) scale radius |
82 | | - rc : (float, default=0. i.e. no core) core radius |
83 | | - alpha : (float, default=1.) inner halo slope |
84 | | - beta : (float, default=1.e-7) outer halo slope |
85 | | - |
86 | | - returns |
87 | | - ---------- |
88 | | - densities evaluated at r |
89 | | - |
90 | | - notes |
91 | | - ---------- |
92 | | - different combinations are known distributions. |
93 | | - alpha=1,beta=2 is NFW |
94 | | - alpha=1,beta=3 is Hernquist |
95 | | - alpha=2.5,beta=0 is a typical single power law halo |
96 | | - |
97 | | - |
98 | | - """ |
99 | | - ra = r/rs |
100 | | - dens = 1./(((ra+rc/rs)**alpha)*((1+ra)**beta)) |
101 | | - rtrunc = 25*rs |
102 | | - wtrunc = rtrunc*0.2 |
103 | | - rolloff = 0.5 - 0.5*scipy.special.erf((r-rtrunc)/wtrunc) |
104 | | - return dens*rolloff |
105 | | - |
106 | | - |
107 | | -def plummer_density(radius, scale_radius=1.0, mass=1.0, astronomicalG=1.0): |
108 | | - """basic plummer density profile""" |
109 | | - return ((3.0*mass)/(4*np.pi))*(scale_radius**2.)*((scale_radius**2 + radius**2)**(-2.5)) |
110 | | - |
111 | | -def twopower_density_withrolloff(r, a, alpha, beta, rcen, wcen): |
112 | | - """a twopower density profile""" |
113 | | - ra = r/a |
114 | | - prefac = 0.5*(1.-scipy.special.erf((ra-rcen)/wcen)) |
115 | | - return prefac*(ra**-alpha)*(1+ra)**(-beta+alpha) |
116 | | - |
117 | | -def hernquist_halo(r, a): |
118 | | - return 1 / ( 2*np.pi * (r/a) * (1 + r/a)**3) |
119 | | - |
120 | | - |
121 | | - |
122 | | -## Teporary Makemodel function that will be integrated into pyEXP |
123 | | - |
124 | 5 | def makemodel(func, M, funcargs, rvals = 10.**np.linspace(-2.,4.,2000), pfile='', plabel = '',verbose=True): |
125 | 6 | """make an EXP-compatible spherical basis function table |
126 | 7 | |
|
0 commit comments