Skip to content

Commit bc55428

Browse files
add support for fermi_gbm files
1 parent cc4c259 commit bc55428

File tree

1 file changed

+51
-20
lines changed

1 file changed

+51
-20
lines changed

stingray/io.py

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)