forked from amjsmith/hodpy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathluminosity_function.py
212 lines (154 loc) · 6.63 KB
/
luminosity_function.py
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
#! /usr/bin/env python
from __future__ import print_function
import numpy as np
from scipy.special import gamma, gammaincc
from scipy.interpolate import RegularGridInterpolator
from k_correction import GAMA_KCorrection
class LuminosityFunction(object):
def __init__(self):
pass
def __initialize_interpolator(self):
#Initializes a RegularGridInterpolator for converting number densities
#at a certain to redshift to the corresponding magnitude threshold
# arrays of z and log_n, and empty 2d array magnitudes
redshifts = np.arange(0, 1, 0.01)
log_number_densities = np.arange(-12, -0.5, 0.01)
magnitudes = np.zeros((len(redshifts),len(log_number_densities)))
# fill in 2d array of magnitudes
mags = np.arange(-25, -10, 0.001)
for i in range(len(redshifts)):
# find number density at each magnitude in mags
log_ns = np.log10(self.Phi_cumulative(mags, redshifts[i]))
# find this number density in the array log_number_densities
idx = np.searchsorted(log_ns, log_number_densities)
# interpolate to find magnitude at this number density
f = (log_number_densities - log_ns[idx-1]) / \
(log_ns[idx] - log_ns[idx-1])
magnitudes[i,:] = mags[idx-1] + f*(mags[idx] - mags[idx-1])
# create RegularGridInterpolator object
return RegularGridInterpolator((redshifts,log_number_densities),
magnitudes, bounds_error=False, fill_value=None)
def Phi(self, magnitude, redshift):
pass
def Phi_cumulative(self, magnitude, redshift):
pass
def mag2lum(self, magnitude):
"""
Convert magnitude to luminosity
"""
return 10**((4.76 - magnitude)/2.5)
def lum2mag(self, luminosity):
"""
Convert luminosity to magnitude
"""
return 4.76 - 2.5*np.log10(luminosity)
def magnitude(self, number_density, redshift):
"""
Convert number density to magnitude
"""
points = np.array(list(zip(redshift, np.log10(number_density))))
return self._interpolator(points)
class LuminosityFunctionSchechter(LuminosityFunction):
"""
Schecter luminosity function with evolution
"""
def __init__(self, Phi_star, M_star, alpha, P, Q):
# Evolving Shechter luminosity function parameters
self.Phi_star = Phi_star
self.M_star = M_star
self.alpha = alpha
self.P = P
self.Q = Q
def Phi(self, magnitude, redshift):
# evolve M_star and Phi_star to redshift
M_star = self.M_star - self.Q * (redshift - 0.1)
Phi_star = self.Phi_star * 10**(0.4*self.P*redshift)
# calculate luminosity function
lf = 0.4 * np.log(10) * Phi_star
lf *= (10**(0.4*(M_star-magnitude)))**(self.alpha+1)
lf *= np.exp(-10**(0.4*(M_star-magnitude)))
return lf
def Phi_cumulative(self, magnitude, redshift):
# evolve M_star and Phi_star to redshift
M_star = self.M_star - self.Q * (redshift - 0.1)
Phi_star = self.Phi_star * 10**(0.4*self.P*redshift)
# calculate cumulative luminosity function
t = 10**(0.4 * (M_star-magnitude))
lf = Phi_star*(gammaincc(self.alpha+2, t)*gamma(self.alpha+2) - \
t**(self.alpha+1)*np.exp(-t)) / (self.alpha+1)
return lf
class LuminosityFunctionTabulated(LuminosityFunction):
"""
Luminosity function from tabulated file, with evolution
"""
def __init__(self, filename, P, Q):
self.magnitude, self.log_number_density = \
np.loadtxt(filename, unpack=True)
self.P = P
self.Q = Q
self.__lf_interpolator = \
RegularGridInterpolator((self.magnitude,), self.log_number_density,
bounds_error=False, fill_value=None)
def Phi(self, magnitude, redshift):
pass
def Phi_cumulative(self, magnitude, redshift):
# shift magnitudes to redshift z=0.1
magnitude01 = magnitude + self.Q * (redshift - 0.1)
# find interpolated number density at z=0.1
log_lf01 = self.__lf_interpolator(magnitude01)
# shift back to redshift
log_lf = log_lf01 + 0.4 * self.P * (redshift - 0.1)
return 10**log_lf
class LuminosityFunctionTarget(LuminosityFunction):
def __init__(self, filename, Phi_star, M_star, alpha, P, Q):
self.lf_sdss = LuminosityFunctionTabulated(filename, P, Q)
self.lf_gama = \
LuminosityFunctionSchechter(Phi_star, M_star, alpha, P, Q)
self._interpolator = \
self._LuminosityFunction__initialize_interpolator()
def transition(self, redshift):
"""
Function which describes the transition between the SDSS LF
at low z and the GAMA LF at high z
"""
return 1. / (1. + np.exp(-100*(redshift-0.15)))
def Phi(self, magnitude, redshift):
pass
def Phi_cumulative(self, magnitude, redshift):
w = self.transition(redshift)
lf_sdss = self.lf_sdss.Phi_cumulative(magnitude, redshift)
lf_gama = self.lf_gama.Phi_cumulative(magnitude, redshift)
return w*lf_sdss + (1-w)*lf_gama
def test():
import matplotlib.pyplot as plt
import parameters as par
mags = np.arange(0,-25,-0.1)
z = np.ones(len(mags))* 0.0005
lf_targ = LuminosityFunctionTarget(par.lf_file, par.Phi_star, par.M_star,
par.alpha, par.P, par.Q)
logn = np.log10(lf_targ.Phi_cumulative(mags, z))
mag = lf_targ.magnitude(10**logn, z)
plt.plot(mags, logn)
plt.plot(mag, logn, ls="--")
plt.show()
lf_gama = LuminosityFunctionSchechter(par.Phi_star, par.M_star, par.alpha,
par.P, par.Q)
lf_sdss = LuminosityFunctionTabulated(par.lf_file, par.P, par.Q)
lf_targ = LuminosityFunctionTarget(par.lf_file, par.Phi_star, par.M_star,
par.alpha, par.P, par.Q)
for z in np.arange(0, 0.26, 0.05):
phi = lf_sdss.Phi_cumulative(mags, z)
plt.plot(mags, phi, c="b")
phi = lf_gama.Phi_cumulative(mags, z)
plt.plot(mags, phi, c="g")
phi = lf_targ.Phi_cumulative(mags, z)
plt.plot(mags, phi, c="r", ls="--")
plt.yscale("log")
plt.title("z = %.2f"%z)
plt.xlabel("mag")
plt.ylabel("cumulative LF")
plt.xlim(-18, -23)
plt.ylim(1e-6, 3e-2)
plt.show()
if __name__ == "__main__":
test()