Skip to content

Commit 0c203e2

Browse files
authored
Merge pull request #1087 from igmhub/new_tile_petal_night
add reading of exposure info from coadds
2 parents d6dcb13 + 13a32d1 commit 0c203e2

7 files changed

Lines changed: 275 additions & 95 deletions

File tree

py/picca/delta_extraction/astronomical_objects/desi_forest.py

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class DesiForest(Forest):
3737
targetid: int
3838
Targetid of the object
3939
40-
tile: list of int
40+
tileid: list of int
4141
Identifier of the tile used in the observation. None for no info
4242
"""
4343
def __init__(self, **kwargs):
@@ -68,10 +68,20 @@ def __init__(self, **kwargs):
6868
"Missing variable 'targetid'")
6969
del kwargs["targetid"]
7070

71-
self.tile = []
72-
if kwargs.get("tile") is not None:
73-
self.tile.append(kwargs.get("tile"))
74-
del kwargs["tile"]
71+
self.tileid = []
72+
if kwargs.get("tileid") is not None:
73+
self.tileid.append(kwargs.get("tileid"))
74+
del kwargs["tileid"]
75+
76+
self.fiber = []
77+
if kwargs.get("fiber") is not None:
78+
self.fiber.append(kwargs.get("fiber"))
79+
del kwargs["fiber"]
80+
81+
self.expid = []
82+
if kwargs.get("expid") is not None:
83+
self.expid.append(kwargs.get("expid"))
84+
del kwargs["expid"]
7585

7686
# call parent constructor
7787
kwargs["los_id"] = self.targetid
@@ -98,7 +108,9 @@ def coadd(self, other):
98108
f"{type(other).__name__}")
99109
self.night += other.night
100110
self.petal += other.petal
101-
self.tile += other.tile
111+
self.tileid += other.tileid
112+
self.expid += other.expid
113+
self.fiber += other.fiber
102114
super().coadd(other)
103115

104116
def get_header(self):
@@ -120,19 +132,29 @@ def get_header(self):
120132
},
121133
{
122134
'name': 'NIGHT',
123-
'value': "-".join(str(night) for night in self.night),
135+
'value': ",".join(str(night) for night in self.night),
124136
'comment': "Observation night(s)"
125137
},
126138
{
127139
'name': 'PETAL',
128-
'value': "-".join(str(petal) for petal in self.petal),
140+
'value': ",".join(str(petal) for petal in self.petal),
129141
'comment': 'Observation petal(s)'
130142
},
131143
{
132-
'name': 'TILE',
133-
'value': "-".join(str(tile) for tile in self.tile),
144+
'name': 'TILEID',
145+
'value': ",".join(str(tileid) for tileid in self.tileid),
134146
'comment': 'Observation tile(s)'
135147
},
148+
{
149+
'name': 'EXPID',
150+
'value': ",".join(str(expid) for expid in self.expid),
151+
'comment': 'Observation expid(s)'
152+
},
153+
{
154+
'name': 'FIBER',
155+
'value': ",".join(str(fiber) for fiber in self.fiber),
156+
'comment': 'Observation fiber(s)'
157+
},
136158
]
137159

138160
return header
@@ -150,9 +172,11 @@ def get_metadata(self):
150172
metadata = super().get_metadata()
151173
metadata += [
152174
self.targetid,
153-
"-".join(str(night) for night in self.night),
154-
"-".join(str(petal) for petal in self.petal),
155-
"-".join(str(tile) for tile in self.tile),
175+
",".join(str(n) for night in self.night for n in night),
176+
",".join(str(p) for petal in self.petal for p in petal),
177+
",".join(str(t) for tileid in self.tileid for t in tileid),
178+
",".join(str(e) for expid in self.expid for e in expid),
179+
",".join(str(f) for fiber in self.fiber for f in fiber),
156180
]
157181
return metadata
158182

@@ -168,7 +192,8 @@ def get_metadata_dtype(cls):
168192
data
169193
"""
170194
dtype = super().get_metadata_dtype()
171-
dtype += [('TARGETID', int), ('NIGHT', 'S12'), ('PETAL', 'S12'), ('TILE', 'S12')]
195+
dtype += [('TARGETID', int), ('NIGHT', 'S150'), ('PETAL', 'S150'),
196+
('TILEID', 'S150'), ('EXPID', 'S150'),('FIBER', 'S150')]
172197
return dtype
173198

174199
@classmethod
@@ -182,5 +207,5 @@ def get_metadata_units(cls):
182207
A list with the units of the line-of-sight data
183208
"""
184209
units = super().get_metadata_units()
185-
units += ["", "", "", ""]
210+
units += ["", "", "", "", "", ""]
186211
return units

py/picca/delta_extraction/data_catalogues/desi_data.py

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
accepted_options = update_accepted_options(accepted_options,
2525
["use non-coadded spectra",
2626
"uniquify night targetid",
27-
"keep single exposures",
27+
"keep single exposures",
2828
"wave solution"])
2929

3030
defaults = update_default_options(defaults, {
@@ -38,7 +38,7 @@
3838
defaults = update_default_options(defaults, defaults_quasar_catalogue)
3939

4040
def verify_exposures_shape(forests_by_targetid):
41-
"""Verify that the exposures have the same shape.
41+
"""Verify that the exposures have the same shape.
4242
If not, it removes them from the dictionnary of forests by targetid.
4343
Only works for use_non_coadded_spectra and keep_single_exposures options.
4444
@@ -134,7 +134,7 @@ class DesiData(Data):
134134
If True, remove the quasars taken on the same night.
135135
136136
keep_single_exposures: bool
137-
If True, the date loadded from non-coadded spectra are not coadded.
137+
If True, the date loadded from non-coadded spectra are not coadded.
138138
Otherwise, coadd the spectra here.
139139
"""
140140

@@ -295,7 +295,7 @@ class DesiDataFileHandler():
295295
If True, remove the quasars taken on the same night.
296296
297297
keep_single_exposures: bool
298-
If True, the date loadded from non-coadded spectra are not coadded.
298+
If True, the date loadded from non-coadded spectra are not coadded.
299299
Otherwise, coadd the spectra here.
300300
"""
301301

@@ -314,7 +314,7 @@ def __init__(self,
314314
for details
315315
316316
keep_single_exposures: bool
317-
If True, the date loadded from non-coadded spectra are not coadded.
317+
If True, the date loadded from non-coadded spectra are not coadded.
318318
Otherwise, coadd the spectra here.
319319
320320
uniquify_night_targetid: bool
@@ -352,7 +352,8 @@ def format_data(self,
352352
catalogue,
353353
spectrographs_data,
354354
targetid_spec,
355-
reso_from_truth=False):
355+
reso_from_truth=False,
356+
metadata_dict=None):
356357
"""After data has been read, format it into DesiForest instances
357358
358359
Instances will be DesiForest or DesiPk1dForest depending on analysis_type
@@ -399,6 +400,51 @@ def format_data(self,
399400
f"for {targetid}")
400401
else:
401402
w_t = w_t[0]
403+
if metadata_dict is not None and not self.use_non_coadded_spectra:
404+
exp_w_t = np.where(metadata_dict["EXP_TARGETID"] == targetid)[0]
405+
expid = metadata_dict["EXP_EXPID"][exp_w_t]
406+
night = metadata_dict["EXP_NIGHT"][exp_w_t]
407+
petal = metadata_dict["EXP_PETAL"][exp_w_t]
408+
tileid = metadata_dict["EXP_TILEID"][exp_w_t]
409+
fiber = metadata_dict["EXP_FIBER"][exp_w_t]
410+
metadata_dict_targetid = {'expid': expid,
411+
'night': night,
412+
'petal': petal,
413+
'fiber': fiber,
414+
'tileid': tileid}
415+
elif metadata_dict is not None and self.use_non_coadded_spectra:
416+
try:
417+
len(metadata_dict["EXPID"][w_t])
418+
expid = metadata_dict["EXPID"][w_t]
419+
except TypeError:
420+
expid = [metadata_dict["EXPID"][w_t]]
421+
try:
422+
len(metadata_dict["NIGHT"][w_t])
423+
night = metadata_dict["NIGHT"][w_t]
424+
except TypeError:
425+
night = [metadata_dict["NIGHT"][w_t]]
426+
try:
427+
len(metadata_dict["PETAL"][w_t])
428+
petal = metadata_dict["PETAL"][w_t]
429+
except TypeError:
430+
petal = [metadata_dict["PETAL"][w_t]]
431+
try:
432+
len(metadata_dict["FIBER"][w_t])
433+
fiber = metadata_dict["FIBER"][w_t]
434+
except TypeError:
435+
fiber = [metadata_dict["FIBER"][w_t]]
436+
try:
437+
len(metadata_dict["TILEID"][w_t])
438+
tileid = metadata_dict["TILEID"][w_t]
439+
except TypeError:
440+
tileid = [metadata_dict["TILEID"][w_t]]
441+
metadata_dict_targetid = {'expid': expid,
442+
'night': night,
443+
'petal': petal,
444+
'fiber': fiber,
445+
'tileid': tileid}
446+
else:
447+
metadata_dict_targetid = None
402448
# Construct DesiForest instance
403449
# Fluxes from the different spectrographs will be coadded
404450
for spec in spectrographs_data.values():
@@ -431,7 +477,8 @@ def format_data(self,
431477
ivar_i,
432478
w_t,
433479
reso_from_truth,
434-
num_data)
480+
num_data,
481+
metadata_dict=metadata_dict_targetid)
435482
else:
436483
forests_by_targetid, num_data = self.update_forest_dictionary(
437484
forests_by_targetid,
@@ -443,7 +490,8 @@ def format_data(self,
443490
ivar,
444491
w_t,
445492
reso_from_truth,
446-
num_data)
493+
num_data,
494+
metadata_dict=metadata_dict_targetid)
447495
return forests_by_targetid, num_data
448496

449497
def update_forest_dictionary(self,
@@ -456,7 +504,8 @@ def update_forest_dictionary(self,
456504
ivar,
457505
w_t,
458506
reso_from_truth,
459-
num_data):
507+
num_data,
508+
metadata_dict=None):
460509
"""Add new forests to the current forest dictonary
461510
462511
Arguments
@@ -491,7 +540,7 @@ def update_forest_dictionary(self,
491540
492541
num_data: int
493542
The number of instances loaded
494-
543+
495544
Return
496545
------
497546
forests_by_targetid: dict
@@ -508,6 +557,8 @@ def update_forest_dictionary(self,
508557
"dec": row['DEC'],
509558
"z": row['Z'],
510559
}
560+
if metadata_dict is not None:
561+
args.update(metadata_dict)
511562
args["log_lambda"] = np.log10(spec['WAVELENGTH'])
512563

513564

@@ -582,3 +633,51 @@ def read_file(self, filename, catalogue):
582633
"""
583634
raise DataError(
584635
"Function 'read_data' was not overloaded by child class")
636+
637+
def get_metadata_dict(self,fibermap,exp_fibermap,index_unique) :
638+
"""
639+
Constructs a dictionary containing metadata extracted from the provided fibermap
640+
and exp_fibermap.
641+
642+
Parameters:
643+
- fibermap (numpy.ndarray): The primary fibermap data structure containing metadata.
644+
- exp_fibermap (numpy.ndarray or None): The exposure-specific fibermap data structure
645+
containing metadata. If None, the function uses the `fibermap` and `index_unique`
646+
to extract metadata.
647+
- index_unique (numpy.ndarray): An array of indices used to select unique entries from
648+
the `fibermap`.
649+
650+
Returns:
651+
- metadata_dict (dict): A dictionary where keys are metadata field names and values
652+
are numpy arrays containing the corresponding metadata values. The keys are prefixed
653+
with 'EXP_' if `use_non_coadded_spectra` is False and `exp_fibermap` is not None.
654+
655+
Notes:
656+
- The function checks if certain keys (`TARGETID`, `NIGHT`, `EXPID`, `PETAL_LOC`,
657+
`FIBER`, `TILEID`) exist in the `input_fibermap`. If a key exists, it extracts the
658+
corresponding data; otherwise, it fills the entry with zeros.
659+
- The `use_non_coadded_spectra` attribute of the class instance determines whether to
660+
use the `exp_fibermap` or the `fibermap` combined with `index_unique` for extracting
661+
metadata.
662+
"""
663+
input_fibermap = fibermap
664+
ikeys=["TARGETID","NIGHT","EXPID","PETAL_LOC","FIBER","TILEID"]
665+
if not self.use_non_coadded_spectra :
666+
if exp_fibermap is not None :
667+
input_fibermap = exp_fibermap
668+
okeys=["EXP_TARGETID","EXP_NIGHT","EXP_EXPID","EXP_PETAL","EXP_FIBER","EXP_TILEID"]
669+
else :
670+
okeys=["TARGETID","NIGHT","EXPID","PETAL","FIBER","TILEID"]
671+
672+
metadata_dict = {}
673+
674+
for ikey,okey in zip(ikeys,okeys) :
675+
if ikey in input_fibermap.dtype.names :
676+
if exp_fibermap is not None :
677+
metadata_dict[okey] = exp_fibermap[ikey]
678+
else :
679+
metadata_dict[okey] = fibermap[ikey][index_unique]
680+
else :
681+
metadata_dict[okey] = np.zeros(index_unique.size,dtype=int)
682+
683+
return metadata_dict

py/picca/delta_extraction/data_catalogues/desi_healpix.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ def read_file(self, filename, catalogue):
208208
return {}, 0
209209
# Read targetid from fibermap to match to catalogue later
210210
fibermap = hdul['FIBERMAP'].read()
211+
exp_fibermap = None
212+
if not self.use_non_coadded_spectra :
213+
if 'EXP_FIBERMAP' in hdul :
214+
exp_fibermap = hdul['EXP_FIBERMAP'].read()
211215

212216
index_unique = np.full(fibermap.shape,True)
213217
if self.uniquify_night_targetid:
@@ -275,10 +279,13 @@ def _read_resolution(color, indices):
275279
if hdul_truth is not None:
276280
hdul_truth.close()
277281

282+
metadata_dict=self.get_metadata_dict(fibermap,exp_fibermap,index_unique)
283+
278284
forests_by_targetid, num_data = self.format_data(
279285
catalogue,
280286
spectrographs_data,
281287
fibermap["TARGETID"][index_unique],
282-
reso_from_truth=reso_from_truth)
288+
reso_from_truth=reso_from_truth,
289+
metadata_dict=metadata_dict)
283290

284291
return forests_by_targetid, num_data

py/picca/delta_extraction/data_catalogues/desi_healpix_fast.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ def read_data(self, is_mock=False):
122122
self.forests = combine_results(imap_it)
123123
t1 = time.time()
124124
self.logger.progress(f"Time spent meerging threads: {t1-t0}")
125+
else:
126+
raise NotImplementedError('fast healpix reading is not implemented'
127+
'for analyses with "num processors=1"')
125128

126129
if len(self.forests) == 0:
127130
raise DataError("No quasars found, stopping here")
@@ -198,7 +201,10 @@ def read_file(self, filename, catalogue):
198201
return {}, 0
199202
# Read targetid from fibermap to match to catalogue later
200203
fibermap = hdul['FIBERMAP'].read()
201-
204+
if 'EXP_FIBERMAP' in hdul :
205+
exp_fibermap = hdul['EXP_FIBERMAP'].read()
206+
else :
207+
exp_fibermap = fibermap
202208
colors = ["B", "R"]
203209
if "Z_FLUX" in hdul:
204210
colors.append("Z")
@@ -222,6 +228,7 @@ def read_file(self, filename, catalogue):
222228
# It should be there by construction
223229
targetid = row["TARGETID"]
224230
w_t = np.where(fibermap["TARGETID"] == targetid)[0]
231+
w_t_exp = np.where(exp_fibermap["TARGETID"] == targetid)[0]
225232
if len(w_t) == 0:
226233
self.logger.warning(
227234
f"Error reading {targetid}. Ignoring object")
@@ -240,8 +247,16 @@ def read_file(self, filename, catalogue):
240247
"ra": row['RA'],
241248
"dec": row['DEC'],
242249
"z": row['Z'],
243-
"log_lambda": log_lambda,
250+
"log_lambda": log_lambda
244251
}
252+
ikeys=["NIGHT","PETAL_LOC","FIBER","TILEID","EXPID"]
253+
okeys=["night","petal","fiber","tileid","expid"]
254+
for ikey,okey in zip(ikeys,okeys) :
255+
if ikey in exp_fibermap.dtype.names :
256+
args[okey] = exp_fibermap[ikey][w_t_exp]
257+
else :
258+
args[okey] = np.zeros(w_t_exp.size,dtype=int)
259+
245260
forest = DesiForest(**args)
246261
forest.rebin()
247262
forests.append(forest)

0 commit comments

Comments
 (0)