pz-rail-astro-tools 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pz-rail-astro-tools might be problematic. Click here for more details.
- pz_rail_astro_tools-0.0.1.dist-info/LICENSE +21 -0
- pz_rail_astro_tools-0.0.1.dist-info/METADATA +83 -0
- pz_rail_astro_tools-0.0.1.dist-info/RECORD +17 -0
- pz_rail_astro_tools-0.0.1.dist-info/WHEEL +5 -0
- pz_rail_astro_tools-0.0.1.dist-info/top_level.txt +1 -0
- rail/astro_tools/__init__.py +7 -0
- rail/astro_tools/_version.py +4 -0
- rail/creation/degradation/grid_selection.py +212 -0
- rail/creation/degradation/observing_condition_degrader.py +405 -0
- rail/creation/degradation/spectroscopic_degraders.py +139 -0
- rail/creation/degradation/spectroscopic_selections.py +617 -0
- rail/examples_data/creation_data/data/hsc_ratios_and_specz.hdf5 +0 -0
- rail/examples_data/creation_data/data/survey_conditions/DC2-dr6-galcounts-i20-i25.3-nside-128.fits +0 -0
- rail/examples_data/creation_data/data/survey_conditions/DC2-mask-neg-nside-128.fits +0 -0
- rail/examples_data/creation_data/data/survey_conditions/minion_1016_dc2_Median_airmass_i_and_nightlt1825_HEAL.fits +0 -0
- rail/examples_data/creation_data/data/survey_conditions/minion_1016_dc2_Median_fiveSigmaDepth_i_and_nightlt1825_HEAL.fits +0 -0
- rail/tools/utilPhotometry.py +488 -0
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
""" Applying selection functions to catalog """
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from ceci.config import StageParameter as Param
|
|
7
|
+
from rail.creation.degrader import Degrader
|
|
8
|
+
from scipy.interpolate import interp1d
|
|
9
|
+
from rail.core.utils import find_rail_file
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SpecSelection(Degrader):
|
|
13
|
+
"""
|
|
14
|
+
The super class of spectroscopic selections.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
N_tot: integer
|
|
19
|
+
total number of down-sampled, spec-selected galaxies.
|
|
20
|
+
If N_tot is greater than the number of spec-sepected galaxies, then
|
|
21
|
+
it will be ignored.
|
|
22
|
+
nondetect_val: value to be removed for non detects
|
|
23
|
+
downsample: bool
|
|
24
|
+
If True, then downsample the pre-selected galaxies
|
|
25
|
+
to N_tot galaxies.
|
|
26
|
+
success_rate_dir: string, the path to the success rate files.
|
|
27
|
+
percentile_cut: If using color-based redshift cut, percentile in redshifts above which redshifts will be cut from the sample. Default is 100 (no cut)
|
|
28
|
+
colnames: a dictionary that includes necessary columns
|
|
29
|
+
(magnitudes, colors and redshift) for selection. For magnitudes, the keys are ugrizy; for colors, the keys are,
|
|
30
|
+
for example, gr standing for g-r; for redshift, the key is 'redshift'.
|
|
31
|
+
random_seed: random seed for reproducibility.
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
name = "specselection"
|
|
36
|
+
config_options = Degrader.config_options.copy()
|
|
37
|
+
config_options.update(
|
|
38
|
+
N_tot=Param(int, 10000, msg="Number of selected sources"),
|
|
39
|
+
nondetect_val=Param(float, 99.0, msg="value to be removed for non detects"),
|
|
40
|
+
downsample=Param(
|
|
41
|
+
bool,
|
|
42
|
+
True,
|
|
43
|
+
msg="If true, downsample the selected sources into a total number of N_tot",
|
|
44
|
+
),
|
|
45
|
+
success_rate_dir=Param(
|
|
46
|
+
str,
|
|
47
|
+
find_rail_file("examples_data/creation_data/data/success_rate_data"),
|
|
48
|
+
msg="The path to the directory containing success rate files.",
|
|
49
|
+
),
|
|
50
|
+
percentile_cut=Param(int, 100, msg="cut redshifts above this percentile"),
|
|
51
|
+
colnames=Param(
|
|
52
|
+
dict,
|
|
53
|
+
{
|
|
54
|
+
**{band: "mag_" + band + "_lsst" for band in "ugrizy"},
|
|
55
|
+
**{"redshift": "redshift"},
|
|
56
|
+
},
|
|
57
|
+
msg="a dictionary that includes necessary columns\
|
|
58
|
+
(magnitudes, colors and redshift) for selection. For magnitudes, the keys are ugrizy; for colors, the keys are, \
|
|
59
|
+
for example, gr standing for g-r; for redshift, the key is 'redshift'",
|
|
60
|
+
),
|
|
61
|
+
random_seed=Param(int, 42, msg="random seed for reproducibility"),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def __init__(self, args, comm=None):
|
|
65
|
+
Degrader.__init__(self, args, comm=comm)
|
|
66
|
+
# validate the settings
|
|
67
|
+
self._validate_settings()
|
|
68
|
+
self.mask = None
|
|
69
|
+
self.rng = None
|
|
70
|
+
|
|
71
|
+
def _validate_settings(self):
|
|
72
|
+
"""
|
|
73
|
+
Validate all the settings.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
if self.config.N_tot < 0:
|
|
77
|
+
raise ValueError(
|
|
78
|
+
"Total number of selected sources must be a " "positive integer."
|
|
79
|
+
)
|
|
80
|
+
if os.path.exists(self.config.success_rate_dir) is not True:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"Success rate path: "
|
|
83
|
+
+ self.config.success_rate_dir
|
|
84
|
+
+ " does not exist!"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def validate_colnames(self, data):
|
|
88
|
+
"""
|
|
89
|
+
Validate the column names of data table to make sure they have necessary information
|
|
90
|
+
for each selection.
|
|
91
|
+
colnames: a list of column names.
|
|
92
|
+
"""
|
|
93
|
+
colnames = self.config.colnames.values()
|
|
94
|
+
check = all(item in data.columns for item in colnames)
|
|
95
|
+
if check is not True:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"Columns in the data are not enough for the selection."
|
|
98
|
+
+ "The data should contain "
|
|
99
|
+
+ str(list(colnames))
|
|
100
|
+
+ ". \n"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def selection(self, data):
|
|
104
|
+
"""
|
|
105
|
+
Selection functions. This should be overwritten by the subclasses
|
|
106
|
+
corresponding to different spec selections.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def invalid_cut(self, data):
|
|
110
|
+
"""
|
|
111
|
+
This function removes entries in the data that have invalid magnitude values
|
|
112
|
+
(nondetect_val or NaN)
|
|
113
|
+
"""
|
|
114
|
+
nondetect_val = self.config.nondetect_val
|
|
115
|
+
for band in "ugrizy":
|
|
116
|
+
if band not in self.config.colnames.keys():
|
|
117
|
+
continue
|
|
118
|
+
colname = self.config.colnames[band]
|
|
119
|
+
self.mask &= (np.abs(data[colname]) < nondetect_val) & (
|
|
120
|
+
~np.isnan(data[colname])
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def downsampling_N_tot(self):
|
|
124
|
+
"""
|
|
125
|
+
Method to randomly sample down the objects to a given
|
|
126
|
+
number of data objects.
|
|
127
|
+
"""
|
|
128
|
+
N_tot = self.config.N_tot
|
|
129
|
+
N_selected = np.count_nonzero(self.mask)
|
|
130
|
+
if N_tot > N_selected:
|
|
131
|
+
print(
|
|
132
|
+
"Warning: N_tot is greater than the size of spec-selected "
|
|
133
|
+
+ "sample ("
|
|
134
|
+
+ str(N_selected)
|
|
135
|
+
+ "). The spec-selected sample "
|
|
136
|
+
+ "is returned."
|
|
137
|
+
)
|
|
138
|
+
return
|
|
139
|
+
else:
|
|
140
|
+
idx_selected = np.where(self.mask)[0]
|
|
141
|
+
idx_keep = self.rng.choice(idx_selected, replace=False, size=N_tot)
|
|
142
|
+
# create a mask with only those entries enabled that have been
|
|
143
|
+
# selected
|
|
144
|
+
mask = np.zeros_like(self.mask)
|
|
145
|
+
mask[idx_keep] = True
|
|
146
|
+
# update the internal state
|
|
147
|
+
self.mask &= mask
|
|
148
|
+
|
|
149
|
+
def run(self):
|
|
150
|
+
"""
|
|
151
|
+
Run the selection
|
|
152
|
+
"""
|
|
153
|
+
self.rng = np.random.default_rng(seed=self.config.seed)
|
|
154
|
+
# get the bands and bandNames present in the data
|
|
155
|
+
data = self.get_data("input", allow_missing=True)
|
|
156
|
+
self.validate_colnames(data)
|
|
157
|
+
self.mask = np.product(~np.isnan(data.to_numpy()), axis=1)
|
|
158
|
+
self.invalid_cut(data)
|
|
159
|
+
self.selection(data)
|
|
160
|
+
if self.config.downsample is True:
|
|
161
|
+
self.downsampling_N_tot()
|
|
162
|
+
|
|
163
|
+
data_selected = data.iloc[np.where(self.mask == 1)[0]]
|
|
164
|
+
|
|
165
|
+
self.add_data("output", data_selected)
|
|
166
|
+
|
|
167
|
+
def __repr__(self):
|
|
168
|
+
"""
|
|
169
|
+
Define how the model is represented and printed.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class SpecSelection_GAMA(SpecSelection):
|
|
174
|
+
"""
|
|
175
|
+
The class of spectroscopic selections with GAMA.
|
|
176
|
+
The GAMA survey covers an area of 286 deg^2, with ~238000 objects
|
|
177
|
+
The necessary column is r band
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
name = "specselection_gama"
|
|
181
|
+
|
|
182
|
+
def selection(self, data):
|
|
183
|
+
"""
|
|
184
|
+
GAMA selection function
|
|
185
|
+
"""
|
|
186
|
+
print("Applying the selection from GAMA survey...")
|
|
187
|
+
self.mask *= data[self.config.colnames["r"]] < 19.87
|
|
188
|
+
|
|
189
|
+
def __repr__(self):
|
|
190
|
+
"""
|
|
191
|
+
Define how the model is represented and printed.
|
|
192
|
+
"""
|
|
193
|
+
# start message
|
|
194
|
+
printMsg = "Applying the GAMA selection."
|
|
195
|
+
|
|
196
|
+
return printMsg
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class SpecSelection_BOSS(SpecSelection):
|
|
200
|
+
"""
|
|
201
|
+
The class of spectroscopic selections with BOSS.
|
|
202
|
+
BOSS selection function is based on
|
|
203
|
+
http://www.sdss3.org/dr9/algorithms/boss_galaxy_ts.php
|
|
204
|
+
The selection has changed slightly compared to Dawson+13
|
|
205
|
+
BOSS covers an area of 9100 deg^2 with 893,319 galaxies.
|
|
206
|
+
For BOSS selection, the data should at least include gri bands.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
name = "specselection_boss"
|
|
210
|
+
|
|
211
|
+
def selection(self, data):
|
|
212
|
+
"""
|
|
213
|
+
The BOSS selection function.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
print("Applying the selection from BOSS survey...")
|
|
217
|
+
# cut quantities (unchanged)
|
|
218
|
+
c_p = 0.7 * (
|
|
219
|
+
data[self.config.colnames["g"]] - data[self.config.colnames["r"]]
|
|
220
|
+
) + 1.2 * (
|
|
221
|
+
data[self.config.colnames["r"]] - data[self.config.colnames["i"]] - 0.18
|
|
222
|
+
)
|
|
223
|
+
c_r = (
|
|
224
|
+
(data[self.config.colnames["r"]] - data[self.config.colnames["i"]])
|
|
225
|
+
- (data[self.config.colnames["g"]] - data[self.config.colnames["r"]]) / 4.0
|
|
226
|
+
- 0.18
|
|
227
|
+
)
|
|
228
|
+
d_r = (data[self.config.colnames["r"]] - data[self.config.colnames["i"]]) - (
|
|
229
|
+
data[self.config.colnames["g"]] - data[self.config.colnames["r"]]
|
|
230
|
+
) / 8.0
|
|
231
|
+
# defining the LOWZ sample
|
|
232
|
+
# we cannot apply the r_psf - r_cmod cut
|
|
233
|
+
low_z = (
|
|
234
|
+
(data[self.config.colnames["r"]] > 16.0)
|
|
235
|
+
& (data[self.config.colnames["r"]] < 20.0)
|
|
236
|
+
& (np.abs(c_r) < 0.2) # 19.6
|
|
237
|
+
& (data[self.config.colnames["r"]] < 13.35 + c_p / 0.3)
|
|
238
|
+
) # 13.5, 0.3
|
|
239
|
+
# defining the CMASS sample
|
|
240
|
+
# we cannot apply the i_fib2, i_psf - i_mod and z_psf - z_mod cuts
|
|
241
|
+
cmass = (
|
|
242
|
+
(data[self.config.colnames["i"]] > 17.5)
|
|
243
|
+
& (data[self.config.colnames["i"]] < 20.1)
|
|
244
|
+
& (d_r > 0.55) # 19.9
|
|
245
|
+
& (data[self.config.colnames["i"]] < 19.98 + 1.6 * (d_r - 0.7))
|
|
246
|
+
& ( # 19.86, 1.6, 0.8
|
|
247
|
+
(data[self.config.colnames["r"]] - data[self.config.colnames["i"]])
|
|
248
|
+
< 2.0
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
# NOTE: we ignore the CMASS sparse sample
|
|
252
|
+
self.mask *= low_z | cmass
|
|
253
|
+
|
|
254
|
+
def __repr__(self):
|
|
255
|
+
"""
|
|
256
|
+
Define how the model is represented and printed.
|
|
257
|
+
"""
|
|
258
|
+
# start message
|
|
259
|
+
printMsg = "Applying the BOSS selection."
|
|
260
|
+
|
|
261
|
+
return printMsg
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class SpecSelection_DEEP2(SpecSelection):
|
|
265
|
+
"""
|
|
266
|
+
The class of spectroscopic selections with DEEP2.
|
|
267
|
+
DEEP2 has a sky coverage of 2.8 deg^2 with ~53000 spectra.
|
|
268
|
+
For DEEP2, one needs R band magnitude, B-R/R-I colors which are not available for the time being.
|
|
269
|
+
So we use LSST gri bands now. When the conversion degrader is ready, this subclass will be updated
|
|
270
|
+
accordingly.
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
name = "specselection_deep2"
|
|
274
|
+
|
|
275
|
+
def photometryCut(self, data):
|
|
276
|
+
"""
|
|
277
|
+
Applying DEEP2 photometric cut based on Newman+13.
|
|
278
|
+
This modified selection gives the best match to the data n(z) with
|
|
279
|
+
its cut at z~0.75 and the B-R/R-I distribution (Newman+13, Fig. 12)
|
|
280
|
+
|
|
281
|
+
Notes
|
|
282
|
+
-----
|
|
283
|
+
We cannot apply the surface brightness cut and do not apply the
|
|
284
|
+
Gaussian weighted sampling near the original colour cuts.
|
|
285
|
+
"""
|
|
286
|
+
mask = (
|
|
287
|
+
(data[self.config.colnames["r"]] > 18.5)
|
|
288
|
+
& (data[self.config.colnames["r"]] < 24.1)
|
|
289
|
+
& ( # 24.1
|
|
290
|
+
(
|
|
291
|
+
data[self.config.colnames["g"]] - data[self.config.colnames["r"]]
|
|
292
|
+
< 2.45
|
|
293
|
+
* (
|
|
294
|
+
data[self.config.colnames["r"]]
|
|
295
|
+
- data[self.config.colnames["i"]]
|
|
296
|
+
)
|
|
297
|
+
- 0.2976
|
|
298
|
+
)
|
|
299
|
+
|
|
|
300
|
+
# 2.45, 0.2976
|
|
301
|
+
(
|
|
302
|
+
data[self.config.colnames["r"]] - data[self.config.colnames["i"]]
|
|
303
|
+
> 1.1
|
|
304
|
+
)
|
|
305
|
+
| (
|
|
306
|
+
data[self.config.colnames["g"]] - data[self.config.colnames["r"]]
|
|
307
|
+
< 0.5
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
) # 0.5
|
|
311
|
+
# update the internal state
|
|
312
|
+
self.mask &= mask
|
|
313
|
+
|
|
314
|
+
def speczSuccess(self, data):
|
|
315
|
+
"""
|
|
316
|
+
Spec-z success rate as function of r_AB for Q>=3 read of Figure 13 in
|
|
317
|
+
Newman+13 for DEEP2 fields 2-4. Values are binned in steps of 0.2 mag
|
|
318
|
+
with the first and last bin centered on 19 and 24.
|
|
319
|
+
"""
|
|
320
|
+
success_R_bins = np.arange(18.9, 24.1 + 0.01, 0.2)
|
|
321
|
+
success_R_centers = (success_R_bins[1:] + success_R_bins[:-1]) / 2.0
|
|
322
|
+
# paper has given 1 - [sucess rate] in the histogram
|
|
323
|
+
success_rate_dir = self.config.success_rate_dir
|
|
324
|
+
success_R_rate = np.loadtxt(os.path.join(success_rate_dir, "DEEP2_success.txt"))
|
|
325
|
+
# interpolate the success rate as probability of being selected with
|
|
326
|
+
# the probability at R > 24.1 being 0
|
|
327
|
+
p_success_R = interp1d(
|
|
328
|
+
success_R_centers,
|
|
329
|
+
success_R_rate,
|
|
330
|
+
kind="quadratic",
|
|
331
|
+
bounds_error=False,
|
|
332
|
+
fill_value=(success_R_rate[0], 0.0),
|
|
333
|
+
)
|
|
334
|
+
# Randomly sample objects according to their success rate
|
|
335
|
+
random_draw = self.rng.random(len(data))
|
|
336
|
+
mask = random_draw < p_success_R(data[self.config.colnames["r"]])
|
|
337
|
+
# update the internal state
|
|
338
|
+
self.mask &= mask
|
|
339
|
+
|
|
340
|
+
def selection(self, data):
|
|
341
|
+
"""
|
|
342
|
+
DEEP2 selection function
|
|
343
|
+
"""
|
|
344
|
+
self.photometryCut(data)
|
|
345
|
+
self.speczSuccess(data)
|
|
346
|
+
|
|
347
|
+
def __repr__(self):
|
|
348
|
+
"""
|
|
349
|
+
Define how the model is represented and printed.
|
|
350
|
+
"""
|
|
351
|
+
# start message
|
|
352
|
+
printMsg = "Applying the DEEP2 selection."
|
|
353
|
+
|
|
354
|
+
return printMsg
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class SpecSelection_VVDSf02(SpecSelection):
|
|
358
|
+
"""
|
|
359
|
+
The class of spectroscopic selections with VVDSf02.
|
|
360
|
+
It covers an area of 0.5 deg^2 with ~10000 sources.
|
|
361
|
+
Necessary columns are i band magnitude and redshift.
|
|
362
|
+
"""
|
|
363
|
+
|
|
364
|
+
name = "specselection_VVDSf02"
|
|
365
|
+
|
|
366
|
+
def photometryCut(self, data):
|
|
367
|
+
"""
|
|
368
|
+
Photometric cut of VVDS 2h-field based on LeFèvre+05.
|
|
369
|
+
|
|
370
|
+
Notes
|
|
371
|
+
-----
|
|
372
|
+
The oversight of 1.0 magnitudes on the bright end misses 0.2% of galaxies.
|
|
373
|
+
"""
|
|
374
|
+
mask = (data[self.config.colnames["i"]] > 17.5) & (
|
|
375
|
+
data[self.config.colnames["i"]] < 24.0
|
|
376
|
+
)
|
|
377
|
+
# 17.5, 24.0
|
|
378
|
+
self.mask &= mask
|
|
379
|
+
|
|
380
|
+
def speczSuccess(self, data):
|
|
381
|
+
"""
|
|
382
|
+
Success rate of VVDS 2h-field
|
|
383
|
+
|
|
384
|
+
Notes
|
|
385
|
+
-----
|
|
386
|
+
We use a redshift-based and I-band based success rate
|
|
387
|
+
independently here since we do not know their correlation,
|
|
388
|
+
which makes the success rate worse than in reality.
|
|
389
|
+
|
|
390
|
+
Spec-z success rate as function of i_AB read of Figure 16 in
|
|
391
|
+
LeFevre+05 for the VVDS 2h field. Values are binned in steps of
|
|
392
|
+
0.5 mag with the first starting at 17 and the last bin ending at 24.
|
|
393
|
+
"""
|
|
394
|
+
success_I_bins = np.arange(17.0, 24.0 + 0.01, 0.5)
|
|
395
|
+
success_I_centers = (success_I_bins[1:] + success_I_bins[:-1]) / 2.0
|
|
396
|
+
success_rate_dir = self.config.success_rate_dir
|
|
397
|
+
success_I_rate = np.loadtxt(
|
|
398
|
+
os.path.join(success_rate_dir, "VVDSf02_I_success.txt")
|
|
399
|
+
)
|
|
400
|
+
# interpolate the success rate as probability of being selected with
|
|
401
|
+
# the probability at I > 24 being 0
|
|
402
|
+
p_success_I = interp1d(
|
|
403
|
+
success_I_centers,
|
|
404
|
+
success_I_rate,
|
|
405
|
+
kind="quadratic",
|
|
406
|
+
bounds_error=False,
|
|
407
|
+
fill_value=(success_I_rate[0], 0.0),
|
|
408
|
+
)
|
|
409
|
+
# Randomly sample objects according to their success rate
|
|
410
|
+
random_draw = self.rng.random(len(data))
|
|
411
|
+
mask = random_draw < p_success_I(data["mag_i_lsst"])
|
|
412
|
+
# Spec-z success rate as function of redshift read of Figure 13a/b in
|
|
413
|
+
# LeFevre+13 for VVDS deep sample. The listing is split by i_AB into
|
|
414
|
+
# ranges (17.5; 22.5] and (22.5; 24.0].
|
|
415
|
+
# NOTE: at z > 1.75 there are only lower limits (due to a lack of
|
|
416
|
+
# spec-z?), thus the success rate is extrapolated as 1.0 at z > 1.75
|
|
417
|
+
success_z_bright_centers, success_z_bright_rate = np.loadtxt(
|
|
418
|
+
os.path.join(success_rate_dir, "VVDSf02_z_bright_success.txt")
|
|
419
|
+
).T
|
|
420
|
+
success_z_deep_centers, success_z_deep_rate = np.loadtxt(
|
|
421
|
+
os.path.join(success_rate_dir, "VVDSf02_z_deep_success.txt")
|
|
422
|
+
).T
|
|
423
|
+
# interpolate the success rates as probability of being selected with
|
|
424
|
+
# the probability in the bright bin at z > 1.75 being 1.0 and the deep
|
|
425
|
+
# bin at z > 4.0 being 0.0
|
|
426
|
+
p_success_z_bright = interp1d(
|
|
427
|
+
success_z_bright_centers,
|
|
428
|
+
success_z_bright_rate,
|
|
429
|
+
kind="quadratic",
|
|
430
|
+
bounds_error=False,
|
|
431
|
+
fill_value=(success_z_bright_rate[0], 1.0),
|
|
432
|
+
)
|
|
433
|
+
p_success_z_deep = interp1d(
|
|
434
|
+
success_z_deep_centers,
|
|
435
|
+
success_z_deep_rate,
|
|
436
|
+
kind="quadratic",
|
|
437
|
+
bounds_error=False,
|
|
438
|
+
fill_value=(success_z_deep_rate[0], 0.0),
|
|
439
|
+
)
|
|
440
|
+
# Randomly sample objects according to their success rate
|
|
441
|
+
random_draw = self.rng.random(len(data))
|
|
442
|
+
iterator = zip(
|
|
443
|
+
[
|
|
444
|
+
data[self.config.colnames["i"]] <= 22.5,
|
|
445
|
+
data[self.config.colnames["i"]] > 22.5,
|
|
446
|
+
],
|
|
447
|
+
[p_success_z_bright, p_success_z_deep],
|
|
448
|
+
)
|
|
449
|
+
for m, p_success_z in iterator:
|
|
450
|
+
mask[m] &= random_draw[m] < p_success_z(
|
|
451
|
+
data[self.config.colnames["redshift"]][m]
|
|
452
|
+
)
|
|
453
|
+
# update the internal state
|
|
454
|
+
self.mask &= mask
|
|
455
|
+
|
|
456
|
+
def selection(self, data):
|
|
457
|
+
self.photometryCut(data)
|
|
458
|
+
self.speczSuccess(data)
|
|
459
|
+
|
|
460
|
+
def __repr__(self):
|
|
461
|
+
"""
|
|
462
|
+
Define how the model is represented and printed.
|
|
463
|
+
"""
|
|
464
|
+
# start message
|
|
465
|
+
printMsg = "Applying the VVDSf02 selection."
|
|
466
|
+
|
|
467
|
+
return printMsg
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
class SpecSelection_zCOSMOS(SpecSelection):
|
|
471
|
+
"""
|
|
472
|
+
The class of spectroscopic selections with zCOSMOS
|
|
473
|
+
It covers an area of 1.7 deg^2 with ~20000 galaxies.
|
|
474
|
+
For zCOSMOS, the data should at least include i band and redshift.
|
|
475
|
+
"""
|
|
476
|
+
|
|
477
|
+
name = "specselection_zCOSMOS"
|
|
478
|
+
|
|
479
|
+
def photometryCut(self, data):
|
|
480
|
+
"""
|
|
481
|
+
Photometry cut for zCOSMOS based on Lilly+09.
|
|
482
|
+
NOTE: This only includes zCOSMOS bright.
|
|
483
|
+
update the internal state
|
|
484
|
+
"""
|
|
485
|
+
mask = (data[self.config.colnames["i"]] > 15.0) & (
|
|
486
|
+
data[self.config.colnames["i"]] < 22.5
|
|
487
|
+
)
|
|
488
|
+
# 15.0, 22.5
|
|
489
|
+
self.mask &= mask
|
|
490
|
+
|
|
491
|
+
def speczSuccess(self, data):
|
|
492
|
+
"""
|
|
493
|
+
Spec-z success rate as function of redshift (x) and I_AB (y) read of
|
|
494
|
+
Figure 3 in Lilly+09 for zCOSMOS bright sample.
|
|
495
|
+
"""
|
|
496
|
+
success_rate_dir = self.config.success_rate_dir
|
|
497
|
+
x = np.arange(0, 1.4, 0.00587002, dtype=np.float64)
|
|
498
|
+
y = np.arange(18, 22.4, 0.01464226, dtype=np.float64)
|
|
499
|
+
|
|
500
|
+
pixels_y = np.searchsorted(y, data[self.config.colnames["i"]])
|
|
501
|
+
pixels_x = np.searchsorted(x, data[self.config.colnames["redshift"]])
|
|
502
|
+
|
|
503
|
+
rates = np.loadtxt(os.path.join(success_rate_dir, "zCOSMOS_success.txt"))
|
|
504
|
+
ratio_list = np.zeros(len(pixels_y))
|
|
505
|
+
for i, py in enumerate(pixels_y):
|
|
506
|
+
if (
|
|
507
|
+
(py >= rates.shape[0])
|
|
508
|
+
or (pixels_x[i] >= rates.shape[1])
|
|
509
|
+
or (py == 0)
|
|
510
|
+
or (pixels_x[i] == 0)
|
|
511
|
+
):
|
|
512
|
+
ratio_list[i] = 0
|
|
513
|
+
else:
|
|
514
|
+
ratio_list[i] = rates[pixels_y[i] - 1][pixels_x[i] - 1]
|
|
515
|
+
|
|
516
|
+
randoms = self.rng.uniform(size=data[self.config.colnames["i"]].size)
|
|
517
|
+
mask = randoms <= ratio_list
|
|
518
|
+
self.mask &= mask
|
|
519
|
+
|
|
520
|
+
def selection(self, data):
|
|
521
|
+
self.photometryCut(data)
|
|
522
|
+
self.speczSuccess(data)
|
|
523
|
+
|
|
524
|
+
def __repr__(self):
|
|
525
|
+
"""
|
|
526
|
+
Define how the model is represented and printed.
|
|
527
|
+
"""
|
|
528
|
+
# start message
|
|
529
|
+
printMsg = "Applying the zCOSMOS selection."
|
|
530
|
+
|
|
531
|
+
return printMsg
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
class SpecSelection_HSC(SpecSelection):
|
|
535
|
+
"""
|
|
536
|
+
The class of spectroscopic selections with HSC
|
|
537
|
+
or HSC, the data should at least include giz bands and redshift.
|
|
538
|
+
"""
|
|
539
|
+
|
|
540
|
+
name = "specselection_HSC"
|
|
541
|
+
|
|
542
|
+
def photometryCut(self, data):
|
|
543
|
+
"""
|
|
544
|
+
HSC galaxies were binned in color magnitude space with i-band mag from -2 to 6 and g-z color from 13 to 26.
|
|
545
|
+
"""
|
|
546
|
+
mask = (data[self.config.colnames["i"]] > 13.0) & (
|
|
547
|
+
data[self.config.colnames["i"]] < 26.0
|
|
548
|
+
)
|
|
549
|
+
self.mask &= mask
|
|
550
|
+
gz = data[self.config.colnames["g"]] - data[self.config.colnames["z"]]
|
|
551
|
+
mask = (gz > -2.0) & (gz < 6.0)
|
|
552
|
+
self.mask &= mask
|
|
553
|
+
|
|
554
|
+
def speczSuccess(self, data):
|
|
555
|
+
"""
|
|
556
|
+
HSC galaxies were binned in color magnitude space with i-band mag from -2 to 6 and g-z color from 13 to 26
|
|
557
|
+
200 bins in each direction. The ratio of of galaxies with spectroscopic redshifts (training galaxies) to
|
|
558
|
+
galaxies with only photometry in HSC wide field (application galaxies) was computed for each pixel. We divide
|
|
559
|
+
the data into the same pixels and randomly select galaxies into the training sample based on the HSC ratios
|
|
560
|
+
"""
|
|
561
|
+
success_rate_dir = self.config.success_rate_dir
|
|
562
|
+
x_edge = np.linspace(13, 26, 201, endpoint=True)
|
|
563
|
+
y_edge = np.linspace(-2, 6, 201, endpoint=True)
|
|
564
|
+
|
|
565
|
+
rates = np.loadtxt(os.path.join(success_rate_dir, "hsc_success.txt"))
|
|
566
|
+
|
|
567
|
+
pixels_y = np.searchsorted(
|
|
568
|
+
y_edge, data[self.config.colnames["g"]] - data[self.config.colnames["z"]]
|
|
569
|
+
)
|
|
570
|
+
pixels_x = np.searchsorted(x_edge, data[self.config.colnames["i"]])
|
|
571
|
+
|
|
572
|
+
# Do the color-based, percentile-based redshift cut
|
|
573
|
+
|
|
574
|
+
percentile_cut = self.config.percentile_cut
|
|
575
|
+
|
|
576
|
+
mask_keep = np.ones_like(data[self.config.colnames["i"]])
|
|
577
|
+
if percentile_cut != 100: # pragma: no cover
|
|
578
|
+
pixels_y_unique = np.unique(pixels_y)
|
|
579
|
+
pixels_x_unique = np.unique(pixels_x)
|
|
580
|
+
|
|
581
|
+
for y in pixels_y_unique:
|
|
582
|
+
for x in pixels_x_unique:
|
|
583
|
+
ind_inpix = np.where((pixels_y == y) * (pixels_x == x))[0]
|
|
584
|
+
if ind_inpix.size == 0:
|
|
585
|
+
continue
|
|
586
|
+
redshifts = data[self.config.colnames["redshift"]][ind_inpix]
|
|
587
|
+
percentile = np.percentile(redshifts, percentile_cut)
|
|
588
|
+
ind_remove = ind_inpix[redshifts > percentile]
|
|
589
|
+
mask_keep[ind_remove] = 0
|
|
590
|
+
self.mask &= mask_keep
|
|
591
|
+
|
|
592
|
+
pixels_y = pixels_y - 1
|
|
593
|
+
pixels_x = pixels_x - 1
|
|
594
|
+
|
|
595
|
+
ratio_list = np.zeros(len(pixels_y))
|
|
596
|
+
for i, py in enumerate(pixels_y):
|
|
597
|
+
if (py >= rates.shape[0]) or (pixels_x[i] >= rates.shape[1]):
|
|
598
|
+
ratio_list[i] = 0
|
|
599
|
+
else:
|
|
600
|
+
ratio_list[i] = rates[pixels_y[i]][pixels_x[i]]
|
|
601
|
+
|
|
602
|
+
randoms = self.rng.uniform(size=data[self.config.colnames["i"]].size)
|
|
603
|
+
mask = randoms <= ratio_list
|
|
604
|
+
self.mask &= mask
|
|
605
|
+
|
|
606
|
+
def selection(self, data):
|
|
607
|
+
self.photometryCut(data)
|
|
608
|
+
self.speczSuccess(data)
|
|
609
|
+
|
|
610
|
+
def __repr__(self):
|
|
611
|
+
"""
|
|
612
|
+
Define how the model is represented and printed.
|
|
613
|
+
"""
|
|
614
|
+
# start message
|
|
615
|
+
printMsg = "Applying the HSC selection."
|
|
616
|
+
|
|
617
|
+
return printMsg
|
|
Binary file
|
rail/examples_data/creation_data/data/survey_conditions/DC2-dr6-galcounts-i20-i25.3-nside-128.fits
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|