@@ -743,6 +743,8 @@ def __init__(
743743 data_kind = "events" ,
744744 ):
745745 self .fname = fname
746+ self ._data = fits .open (self .fname )
747+
746748 self ._meta_attrs = []
747749 self .gtistring = gtistring
748750 self .output_class = output_class
@@ -759,7 +761,10 @@ def __init__(
759761 additional_columns = [self .detector_key ]
760762 elif self .detector_key != "NONE" :
761763 additional_columns .append (self .detector_key )
762- self .data_hdu = fits .open (self .fname )[self .hduname ]
764+ self .data_hdu = self ._data [self .hduname ]
765+
766+ if self .energy_column == "EBOUNDS" :
767+ self .edata_hdu = self ._data ["EBOUNDS" ]
763768 self .gti_file = gti_file
764769 self ._read_gtis (self .gti_file )
765770
@@ -793,7 +798,6 @@ def __getitem__(self, index):
793798 """Return an element or a slice of the object, e.g. ``ts[1]`` or ``ts[1:2]."""
794799
795800 data = self .data_hdu .data [index ]
796-
797801 return self .transform_slice (data )
798802
799803 def transform_slice (self , data ):
@@ -854,18 +858,34 @@ def _transform_slice_into_events(self, data):
854858 )
855859 except ValueError :
856860 pi_energy_func = None
857- if self .energy_column in data .dtype .names :
858- conversion = 1
861+
862+ if self .energy_column is not None and self .energy_column .lower () == "ebounds" :
863+ channels = self .data_hdu .data ["PHA" ]
864+ elower = self .edata_hdu .data ["E_MIN" ]
865+ ehigher = self .edata_hdu .data ["E_MAX" ]
866+ emid = elower + (ehigher - elower ) / 2.0
867+
868+ energy = np .array ([emid [c ] for c in channels ])
869+
859870 if (
860- hasattr (data . columns [self . energy_column ], "unit" )
861- and (unit := data . columns [self . energy_column ].unit ) is not None
871+ hasattr (self . edata_hdu . columns ["E_MIN" ], "unit" )
872+ and (unit := self . edata_hdu . columns ["E_MIN" ].unit ) is not None
862873 ):
863874 conversion = (1 * u .Unit (unit )).to (u .keV ).value
864- new_ts .energy = data [self .energy_column ] * conversion
865- elif self .pi_column .lower () in [col .lower () for col in data .dtype .names ]:
866- new_ts .pi = data [self .pi_column ]
867- if pi_energy_func is not None :
868- new_ts .energy = pi_energy_func (new_ts .pi )
875+ new_ts .energy = energy * conversion
876+ else :
877+ if self .energy_column in data .dtype .names :
878+ conversion = 1
879+ if (
880+ hasattr (data .columns [self .energy_column ], "unit" )
881+ and (unit := data .columns [self .energy_column ].unit ) is not None
882+ ):
883+ conversion = (1 * u .Unit (unit )).to (u .keV ).value
884+ new_ts .energy = data [self .energy_column ] * conversion
885+ elif self .pi_column .lower () in [col .lower () for col in data .dtype .names ]:
886+ new_ts .pi = data [self .pi_column ]
887+ if pi_energy_func is not None :
888+ new_ts .energy = pi_energy_func (new_ts .pi )
869889
870890 det_numbers = None
871891 if self .detector_key is not None and self .detector_key in data .dtype .names :
@@ -906,15 +926,15 @@ def _initialize_header_events(self, fname, force_hduname=None):
906926 If not None, the name of the HDU to read. If None, an extension called
907927 EVENTS or the first extension.
908928 """
909- hdulist = fits . open ( fname )
929+ hdulist = self . _data
910930
911931 if not force_hduname :
912- for hdu in hdulist :
932+ for hdu in self . _data :
913933 if "TELESCOP" in hdu .header or "MISSION" in hdu .header :
914934 probe_header = hdu .header
915935 break
916936 else :
917- probe_header = hdulist [force_hduname ].header
937+ probe_header = self . _data [force_hduname ].header
918938
919939 # We need the minimal information to read the mission database.
920940 # That is, the name of the mission/telescope, the instrument and,
@@ -955,12 +975,11 @@ def _initialize_header_events(self, fname, force_hduname=None):
955975
956976 # If the EVENT/``force_hduname`` extension is not found, try the first extension
957977 # which is usually the one containing the data
958- if hduname not in hdulist :
978+ if hduname not in self . _data :
959979 warnings .warn (f"HDU { hduname } not found. Trying first extension" )
960980 hduname = 1
961981 self ._add_meta_attr ("hduname" , hduname )
962-
963- header = hdulist [hduname ].header
982+ header = self ._data [hduname ].header
964983 if "OBS_ID" in header :
965984 self ._add_meta_attr ("obsid" , header ["OBS_ID" ])
966985 if "TIMEDEL" in header :
@@ -970,7 +989,7 @@ def _initialize_header_events(self, fname, force_hduname=None):
970989 # No need to cope with dicts working badly with Netcdf, for example. The header
971990 # can be saved back and forth to files and be interpreted through
972991 # fits.Header.fromstring(self.header) when needed.
973- self ._add_meta_attr ("header" , hdulist [self .hduname ].header .tostring ())
992+ self ._add_meta_attr ("header" , self . _data [self .hduname ].header .tostring ())
974993 self ._add_meta_attr ("nphot" , header ["NAXIS2" ])
975994
976995 # These are the important keywords for timing.
@@ -1016,16 +1035,28 @@ def _initialize_header_events(self, fname, force_hduname=None):
10161035 default_pi_column = get_key_from_mission_info (db , "ecol" , "PI" , instr , self .mode )
10171036 if isinstance (default_pi_column , str ):
10181037 default_pi_column = _case_insensitive_search_in_list (
1019- default_pi_column , hdulist [self .hduname ].data .columns .names
1038+ default_pi_column , self ._data [self .hduname ].data .columns .names
1039+ )
1040+ if default_pi_column is None :
1041+ default_pi_column = get_key_from_mission_info (db , "ecol" , "PHA" , instr , self .mode )
1042+
1043+ if isinstance (default_pi_column , str ):
1044+ default_pi_column = _case_insensitive_search_in_list (
1045+ default_pi_column , self ._data [self .hduname ].data .columns .names
10201046 )
10211047
10221048 self ._add_meta_attr ("pi_column" , default_pi_column )
10231049
10241050 # If a column named "energy" is found, we read it and assume the energy conversion
10251051 # is already done.
10261052 energy_column = _case_insensitive_search_in_list (
1027- "energy" , hdulist [self .hduname ].data .columns .names
1053+ "energy" , self . _data [self .hduname ].data .columns .names
10281054 )
1055+ if energy_column is None :
1056+ energy_column = _case_insensitive_search_in_list (
1057+ "ebounds" , [hdu .name for hdu in self ._data ]
1058+ )
1059+
10291060 self ._add_meta_attr ("energy_column" , energy_column )
10301061
10311062 def _read_gtis (self , gti_file = None , det_numbers = None ):
0 commit comments