Source code for gdt.missions.cgro.batse.response

# CONTAINS TECHNICAL DATA/COMPUTER SOFTWARE DELIVERED TO THE U.S. GOVERNMENT 
# WITH UNLIMITED RIGHTS
#
# Grant No.: 80NSSC21K0651
# Grantee Name: Universities Space Research Association
# Grantee Address: 425 3rd Street SW, Suite 950, Washington DC 20024
#
# Copyright 2024 by Universities Space Research Association (USRA). All rights 
# reserved.
#
# Developed by: Adam Goldstein
#               Universities Space Research Association
#               Science and Technology Institute
#               https://sti.usra.edu
#
# This work is a derivative of the Gamma-ray Data Tools (GDT), including the 
# Core and Fermi packages, originally developed by the following:
#
#     William Cleveland and Adam Goldstein
#     Universities Space Research Association
#     Science and Technology Institute
#     https://sti.usra.edu
#     
#     Daniel Kocevski
#     National Aeronautics and Space Administration (NASA)
#     Marshall Space Flight Center
#     Astrophysics Branch (ST-12)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not 
# use this file except in compliance with the License. You may obtain a copy of 
# the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software 
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
# License for the specific language governing permissions and limitations under 
# the License.

import os
import astropy.io.fits as fits
import numpy as np

from gdt.core.response import Rsp
from gdt.core.data_primitives import Ebounds, ResponseMatrix
from gdt.core.file import FitsFileContextManager
from .detectors import BatseDetectors
from .headers import RspHeaders, RspHeadersAlt
from ..time import *

__all__ = ['BatseRsp', 'BatseRspMulti']

[docs]class BatseRsp(Rsp): """Class for BATSE single-DRM response files """
[docs] @classmethod def open(cls, file_path, **kwargs): """Read a single-DRM response file from disk. Args: file_path (str): The file path Returns: (:class:`BatseRsp`) """ obj = super().open(file_path, **kwargs) hdrs = [hdu.header for hdu in obj.hdulist] try: headers = RspHeaders.from_headers(hdrs) except: headers = RspHeadersAlt.from_headers(hdrs) # check the detector number and make sure this is a single-detector file det_num = obj.column(1, 'DET_NUM') if det_num.size == 1: det_num = det_num[0] else: raise RuntimeError('This is a multi-detector response file. ' \ 'Use BatseRspMulti to open this file, and then ' \ 'select the detector you wish to use.') det = BatseDetectors.from_full_name(headers[0]['DET_MODE']+str(det_num)) tstart = from_day_time(hdrs[0]['STRT-DAY'], hdrs[0]['STRT-TIM']).cgro tstop = from_day_time(hdrs[0]['END-DAY'], hdrs[0]['END-TIM']).cgro try: trigtime = from_day_time(hdrs[0]['TRIG-DAY'], hdrs[0]['TRIG-TIM']).cgro except: trigtime = None # ebounds eedges = obj.column(1, 'E_EDGES')[0] ebounds = Ebounds.from_bounds(eedges[:-1], eedges[1:]) drm = obj._decompress(obj.hdulist[1].data, 0) obj.close() obj = cls.from_data(drm, filename=obj.filename, start_time=tstart, stop_time=tstop, trigger_time=trigtime, headers=headers, detector=det.name) return obj
@staticmethod def _decompress(drm_data, index): """Decompresses a BATSE DRM. """ mat_type = drm_data['MAT_TYPE'] mat_type = mat_type[index] if mat_type == 1: matrix = drm_data['DRM_DIR'][index] elif mat_type == 2: matrix = drm_data['DRM_SCT'][index] elif mat_type == 3: matrix = drm_data['DRM_SUM'][index] n_zeros = drm_data['N_ZEROS'][index] num_ebins = int(drm_data['NUMEBINS'][index]) num_chans = int(drm_data['NUMCHAN'][index]) num_zeros = int(drm_data['NUMZERO'][index]) sidx = 0 drm = np.zeros((num_ebins-1, num_zeros)) for ichan in range(num_zeros): eidx = int(sidx) + (num_ebins - int(n_zeros[ichan])) drm[n_zeros[ichan]-1:,ichan] = matrix[sidx:eidx] sidx = int(eidx) chan_edges = drm_data['E_EDGES'][index] phot_edges = drm_data['PHT_EDGE'][index] matrix = ResponseMatrix(drm, phot_edges[:-1], phot_edges[1:], chan_edges[:-1], chan_edges[1:]) return matrix
[docs]class BatseRspMulti(FitsFileContextManager): """BATSE response file for multiple detectors. This is typically DISCSC, MER, STTE or TTE data. """ def __init__(self): self._data = None self._headers = None self._dets = None self._tstart = None self._tstop = None self._trigtime = None @property def detectors(self): """(list): The detectors in the file""" return self._dets @property def num_dets(self): """(int): Number of detectors in the file""" return len(self._dets)
[docs] def get_detector(self, det_var): """Retrieve the response object for the given detector. Args: det_var (str, int, or :class:`BatseDetectors`) Returns: (:class:`BatseRsp``) """ if isinstance(det_var, BatseDetectors): name = det_var.name elif isinstance(det_var, str): name = det_var elif isinstance(det_var, int): name = BatseDetectors.from_num(det_var).name else: raise TypeError('det_var must be a str, int, or BatseDetectors ' \ 'object') # index number of the detector into the DRM arrays try: idx = self.detectors.index(name) except ValueError: raise ValueError(f'The DRM for {det_var} is not contained in this file.') # ebounds eedges = self._data['E_EDGES'][idx] ebounds = Ebounds.from_bounds(eedges[:-1], eedges[1:]) drm = BatseRsp._decompress(self._data, idx) # update the filename for the extracted response det_num = BatseDetectors.from_str(name).number fname = self.filename.split('_') fname = '_'.join(fname[:-1]) + f'_{det_num}_' + fname[-1] obj = BatseRsp.from_data(drm, start_time=self._tstart, filename=fname, stop_time=self._tstop, trigger_time=self._trigtime, headers=self._headers, detector=name) return obj
[docs] @classmethod def open(cls, file_path, **kwargs): """Open a response file containing DRMs from multiple detectors. Args: file_path (str): The file path Returns: (:class:`BatseDrmMulti`) """ obj = super().open(file_path, **kwargs) hdrs = [hdu.header for hdu in obj.hdulist] try: headers = RspHeaders.from_headers(hdrs) except: headers = RspHeadersAlt.from_headers(hdrs) det_mode = headers[0]['DET_MODE'] obj._dets = [det_mode + str(num) for num in obj.column(1, 'DET_NUM')] obj._headers = headers obj._tstart = from_day_time(hdrs[0]['STRT-DAY'], hdrs[0]['STRT-TIM']).cgro obj._tstop = from_day_time(hdrs[0]['END-DAY'], hdrs[0]['END-TIM']).cgro try: obj._trigtime = from_day_time(hdrs[0]['TRIG-DAY'], hdrs[0]['TRIG-TIM']).cgro except: pass obj._data = obj.hdulist[1].data obj.close() return obj
def __repr__(self): return f'<{self.__class__.__name__}: {self.num_dets} detectors>'