Source code for gdt.missions.rxte.asm.phaii

# 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
#
# Developed by: Colleen A. Wilson-Hodge
# 			    National Aeronautics and Space Administration (NASA)
#     			Marshall Space Flight Center
#     			Astrophysics Branch (ST-12)
#
# 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.
#
#Make Phaii for RXTE ASM data
from gdt.core.data_primitives import Ebounds, Gti, TimeEnergyBins
from gdt.core.phaii import Phaii
from astropy.io import ascii
import astropy.io.fits as fits
import numpy as np
import os
from gdt.core import data_path
asm_path = data_path/'rxte-asm'

__all__ = ['RxtePhaiiNoHeaders']

[docs] class RxtePhaiiNoHeaders(Phaii): """Class for RXTE ASM PHAII data """ def __init__(self, *args): super(RxtePhaiiNoHeaders, self).__init__(*args) self._detector = None @property def detector(self): """(str): The detector (ssc1, ssc2, or ssc3) """ return self._detector
[docs] @classmethod def open_ascii(cls, dwell_filename, detector, t0): """Open the ASCII version of the PHAII data. Args: dwell_filename (str): The dwell filename detector (str): The ASM detector (ssc1, ssc2, or ssc3) t0 (float): The MET trigger time. Returns: (:class:`RxtePhaiiNoHeaders`) """ ascii_filename = os.path.join(asm_path,dwell_filename) obj = cls() #check if ascii_filename exists if os.path.isfile(ascii_filename): #if the filename exists then open it obj._filename = ascii_filename #open and read the text table of ASM dwell information data = ascii.read(ascii_filename) #rename colimns #first column is spacecraft time (MET-3.37s) data["col1"].name="sct" #second column is count rate in 1.5-3 keV band for ssc0 data["col2"].name="ssc1a" #third column is count rate in 3-5 keV band for ssc0 data["col3"].name="ssc1b" #fourth column is count rate in 5-12 keV band for ssc0 # pattern repeats with columns 5-7 corresponding to the three bands in ssc1 and 8-10 for the three bands in ssc2 data["col4"].name="ssc1c" data["col5"].name="ssc2a" data["col6"].name="ssc2b" data["col7"].name="ssc2c" data["col8"].name="ssc3a" data["col9"].name="ssc3b" data["col10"].name="ssc3c" # RXTE ASM has fixed energy bounds 1.5-3, 3-5, 5-12 keV for all three detectors. emin = np.array([1.5,3.0,5.0]) emax = np.array([3.0,5.0,12.0]) obj._ebounds = Ebounds.from_bounds(emin, emax) # arrange RXTE ASM data into TimeEnergyBins inputs if detector == "ssc1": counts = np.transpose(np.array([data["ssc1a"],data["ssc1b"],data["ssc1c"]])) elif detector == "ssc2": counts = np.transpose(np.array([data["ssc2a"],data["ssc2b"],data["ssc2c"]])) elif detector == "ssc3": counts = np.transpose(np.array([data["ssc3a"],data["ssc3b"],data["ssc3c"]])) else: #check if detector input correctly print (detector,' not found. Input ssc1, ssc2, or ssc3') return #define times in MET with 1 second long bins tstart = np.array([data["sct"]])+3.37843167-t0 tstop = np.array([data["sct"]])+4.37843167-t0 #exposure time is not given in data files. Assume 1 second duration. exposure = np.ones(np.size(tstart)) #put TimeEnergyBins into Phaii class obj._data = TimeEnergyBins(counts, tstart, tstop, exposure, emin, emax) # Set GTI as duration of data # obj._gti = Gti.from_bounds(gti_start, gti_end) obj._gti = Gti.from_bounds(np.amin(tstart),np.amax(tstop)) # set _detector to input detector value obj._detector = detector obj._trigtime = t0 return obj else: #Error handling - inform user that file is not found and return nothing. print (ascii_filename,' not found.') return
def _build_hdulist(self): #create FITS and primary header hdulist = fits.HDUList() primary_hdu = fits.PrimaryHDU() hdulist.append(primary_hdu) #create the ebounds extension ebounds_hdu = self._ebounds_table() hdulist.append(ebounds_hdu) #create the spectrum extension spectrum_hdu = self._spectrum_table() hdulist.append(spectrum_hdu) #create the GTI extension gti_hdu = self._gti_table() hdulist.append(gti_hdu) return hdulist def _ebounds_table(self): chan_col = fits.Column(name='CHANNEL', format='1I', array=np.arange(self.num_chans, dtype=int)) emin_col = fits.Column(name='E_MIN', format='1E', unit='keV', array=self.ebounds.low_edges()) emax_col = fits.Column(name='E_MAX', format='1E', unit='keV', array=self.ebounds.high_edges()) hdu = fits.BinTableHDU.from_columns([chan_col, emin_col, emax_col]) return hdu def _spectrum_table(self): tstart = np.copy(self.data.tstart) tstop = np.copy(self.data.tstop) if self.trigtime is not None: tstart += self.trigtime tstop += self.trigtime counts_col = fits.Column(name='COUNTS', format='{}I'.format(self.num_chans), bzero=32768, bscale=1, unit='count', array=self.data.counts) expos_col = fits.Column(name='EXPOSURE', format='1E', unit='s', array=self.data.exposure) time_col = fits.Column(name='TIME', format='1D', unit='s', bzero=self.trigtime, array=tstart) endtime_col = fits.Column(name='ENDTIME', format='1D', unit='s', bzero=self.trigtime, array=tstop) hdu = fits.BinTableHDU.from_columns([counts_col, expos_col, time_col, endtime_col]) return hdu def _gti_table(self): tstart = np.array(self.gti.low_edges()) tstop = np.array(self.gti.high_edges()) start_col = fits.Column(name='START', format='1D', unit='s', bzero=self.trigtime, array=tstart) stop_col = fits.Column(name='STOP', format='1D', unit='s', bzero=self.trigtime, array=tstop) hdu = fits.BinTableHDU.from_columns([start_col, stop_col]) return hdu
[docs] @classmethod def open_fits(cls, fits_filename, detector=None, t0=0.0, **kwargs): """Open the FITS version of the PHAII data created by gdt-rxte. Args: fits_filename (str): Name of the file detector (str, optional): The detector t0 (float, optional): The trigger time. Default is 0.0 """ obj = super().open(fits_filename, **kwargs) #check if filename exists if os.path.isfile(fits_filename): #if the filename exisits then open it obj._filename = fits_filename # the channel energy bounds ebounds = Ebounds.from_bounds(obj.column(1, 'E_MIN'), obj.column(1, 'E_MAX')) # the 2D time-channel counts data time = obj.column(2, 'TIME') endtime = obj.column(2, 'ENDTIME') exposure = obj._assert_exposure(obj.column(2, 'EXPOSURE')) data = TimeEnergyBins(obj.column(2, 'COUNTS'), time-t0, endtime-t0, exposure, obj.column(1, 'E_MIN'), obj.column(1, 'E_MAX')) # the good time intervals gti_start = obj.column(3, 'START') gti_stop = obj.column(3, 'STOP') gti = Gti.from_bounds(gti_start, gti_stop) cls.detector=detector class_ = cls obj.close() return class_.from_data(data, gti=gti, trigger_time=t0, filename=obj.filename) else: #Error handling - inform user that file is not found and return nothing. print (fits_filename,' not found.') return