2424accepted_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
3030defaults = update_default_options (defaults , {
3838defaults = update_default_options (defaults , defaults_quasar_catalogue )
3939
4040def 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
0 commit comments