@@ -743,6 +743,8 @@ def __init__(
743
743
data_kind = "events" ,
744
744
):
745
745
self .fname = fname
746
+ self ._data = fits .open (self .fname )
747
+
746
748
self ._meta_attrs = []
747
749
self .gtistring = gtistring
748
750
self .output_class = output_class
@@ -759,7 +761,10 @@ def __init__(
759
761
additional_columns = [self .detector_key ]
760
762
elif self .detector_key != "NONE" :
761
763
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" ]
763
768
self .gti_file = gti_file
764
769
self ._read_gtis (self .gti_file )
765
770
@@ -793,7 +798,6 @@ def __getitem__(self, index):
793
798
"""Return an element or a slice of the object, e.g. ``ts[1]`` or ``ts[1:2]."""
794
799
795
800
data = self .data_hdu .data [index ]
796
-
797
801
return self .transform_slice (data )
798
802
799
803
def transform_slice (self , data ):
@@ -854,18 +858,34 @@ def _transform_slice_into_events(self, data):
854
858
)
855
859
except ValueError :
856
860
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
+
859
870
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
862
873
):
863
874
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 )
869
889
870
890
det_numbers = None
871
891
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):
906
926
If not None, the name of the HDU to read. If None, an extension called
907
927
EVENTS or the first extension.
908
928
"""
909
- hdulist = fits . open ( fname )
929
+ hdulist = self . _data
910
930
911
931
if not force_hduname :
912
- for hdu in hdulist :
932
+ for hdu in self . _data :
913
933
if "TELESCOP" in hdu .header or "MISSION" in hdu .header :
914
934
probe_header = hdu .header
915
935
break
916
936
else :
917
- probe_header = hdulist [force_hduname ].header
937
+ probe_header = self . _data [force_hduname ].header
918
938
919
939
# We need the minimal information to read the mission database.
920
940
# That is, the name of the mission/telescope, the instrument and,
@@ -955,12 +975,11 @@ def _initialize_header_events(self, fname, force_hduname=None):
955
975
956
976
# If the EVENT/``force_hduname`` extension is not found, try the first extension
957
977
# which is usually the one containing the data
958
- if hduname not in hdulist :
978
+ if hduname not in self . _data :
959
979
warnings .warn (f"HDU { hduname } not found. Trying first extension" )
960
980
hduname = 1
961
981
self ._add_meta_attr ("hduname" , hduname )
962
-
963
- header = hdulist [hduname ].header
982
+ header = self ._data [hduname ].header
964
983
if "OBS_ID" in header :
965
984
self ._add_meta_attr ("obsid" , header ["OBS_ID" ])
966
985
if "TIMEDEL" in header :
@@ -970,7 +989,7 @@ def _initialize_header_events(self, fname, force_hduname=None):
970
989
# No need to cope with dicts working badly with Netcdf, for example. The header
971
990
# can be saved back and forth to files and be interpreted through
972
991
# 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 ())
974
993
self ._add_meta_attr ("nphot" , header ["NAXIS2" ])
975
994
976
995
# These are the important keywords for timing.
@@ -1016,16 +1035,28 @@ def _initialize_header_events(self, fname, force_hduname=None):
1016
1035
default_pi_column = get_key_from_mission_info (db , "ecol" , "PI" , instr , self .mode )
1017
1036
if isinstance (default_pi_column , str ):
1018
1037
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
1020
1046
)
1021
1047
1022
1048
self ._add_meta_attr ("pi_column" , default_pi_column )
1023
1049
1024
1050
# If a column named "energy" is found, we read it and assume the energy conversion
1025
1051
# is already done.
1026
1052
energy_column = _case_insensitive_search_in_list (
1027
- "energy" , hdulist [self .hduname ].data .columns .names
1053
+ "energy" , self . _data [self .hduname ].data .columns .names
1028
1054
)
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
+
1029
1060
self ._add_meta_attr ("energy_column" , energy_column )
1030
1061
1031
1062
def _read_gtis (self , gti_file = None , det_numbers = None ):
0 commit comments