Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

rcFitsWriter.py

00001 #!/usr/local/bin/python
00002 #
00003 #                               Copyright 2002
00004 #                                     by
00005 #                        The Board of Trustees of the
00006 #                     Leland Stanford Junior University.
00007 #                            All rights reserved.
00008 #
00009 
00010 __facility__ = "Online"
00011 __abstract__ = "FITS writer class"
00012 __author__   = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__     = ("$Date: 2005/01/21 23:50:49 $").split(' ')[1]
00014 __version__  = "$Revision: 2.5 $"
00015 __release__  = "$Name: R04-12-00 $"
00016 __credits__  = "SLAC"
00017 
00018 import LATTE.copyright_SLAC
00019 
00020 import os.path
00021 #import pyfits
00022 #import numarray
00023 from cfitsio import *
00024 import time
00025 import struct
00026 import types
00027 import sys
00028 import rcReportGen
00029 
00030 FORMAT_WORD = 0
00031 FORMAT_BYTE = 1
00032 
00033 MODE_CREATE = 0
00034 MODE_READONLY = 2
00035 
00036 RUN_REPORT_VERSION = "1.0"
00037 
00038 class rcFitsWriter(object):
00039   #~ def __init__(self, fileName=None):
00040     #~ if fileMame is None:
00041       #~ ts   = strftime('%y%m%d%H%M%S', gmtime())
00042       #~ self.__fileName = 'ebf' + ts + '.fits'
00043     #~ else:
00044       #~ self.__fileName = fileName
00045     #~ self.__fitsobj = pyfits.HDUList()
00046     #~ hdu = pyfits.PrimaryHDU()
00047     #~ self.__fitsobj.append(hdu)
00048 
00049   #~ def write(self, eventSummary, rawEventData):
00050     #~ hdu = pyfits.ImageHDU(numarray.fromstring(rawEventData, numarray.Int32))
00051     #~ #col1 = pyfits.Column(name='event_data', format='i',
00052     #~ #                     array=numarray.fromstring(rawEventData, numarray.UInt32))
00053     #~ #hdu = pyfits.new_table([col1])
00054     #~ #hdu.data.field(0).byteswap()
00055     #~ hdu.header.update('EVT_NO', eventSummary.evNumber, "Event number")
00056     #~ hdu.header.update('EVT_TAG', eventSummary.tag, "Event tag")
00057     #~ self.__fitsobj.append(hdu)
00058 
00059   #~ def close(self):
00060     #~ self.__fitsobj.writeto(self.__fileName)
00061 
00062   def __init__(self, filePath=None, fileName=None, mode=MODE_CREATE, format=FORMAT_WORD, tableSize=1000, compress=0, flushInterval=0, reportGen=None):
00063     if fileName is None:
00064       ts   = time.strftime('%y%m%d%H%M%S', time.gmtime())
00065       self.__fileName = getFileNameFromTS(ts)
00066     else:
00067       self.__fileName = fileName
00068     if compress: self.__fileName += '.gz'
00069     if filePath is None:
00070       self.__filePath = ""
00071     else:
00072       self.__filePath = filePath
00073     self.__format = format
00074     self.__tableSize = tableSize
00075     self.__mode = mode
00076     self.__flushInterval = flushInterval
00077     self.__reportGen = reportGen
00078     if mode == MODE_READONLY:
00079       if format != FORMAT_BYTE:
00080         raise RuntimeError, "Sorry FITS file reading currently only works in BYTE mode"
00081       (self.__status, self.__fptr) = cfitsio.fits_open_file(os.path.join(self.__filePath, self.__fileName), cfitsio.READONLY)
00082       if self.__status != 0:
00083         raise IOError, "fits_open_file: %s" % cfitsio.fits_get_errstatus(self.__status)
00084       else:
00085         if reportGen is not None:
00086           self.getHeaders()
00087         self.__tablenum = 2
00088         status = self.moveToHDU(self.__tablenum)
00089         self.__rownum = 0
00090     elif mode == MODE_CREATE:
00091       (self.__status, self.__fptr) = cfitsio.fits_create_file(os.path.join(self.__filePath, self.__fileName))
00092       if self.__status != 0:
00093         raise IOError, "fits_create_file: %s" % cfitsio.fits_get_errstatus(self.__status)
00094       else:
00095         naxis = 0
00096         naxes = []
00097         self.__status = cfitsio.fits_create_img(self.__fptr, cfitsio.SHORT_IMG, naxis, naxes)
00098         if self.__status != 0:
00099           raise IOError, "fits_create_img: %s" % cfitsio.fits_get_errstatus(self.__status)
00100         else:
00101           try:
00102             from LDF import LDF
00103           except:
00104             raise RuntimeError, (__name__ + "Can't find LDF, aborting...")
00105           comment1 = "The data in this file can be parsed using %s of the Online software" % LDF.__version__
00106           comment2 = "package LDF or a similar package designed according to LAT-TD-00606-D1,"
00107           comment3 = " V/I 2.1/1; LAT-TD-00605-D1, V/I 3.1/1; LAT-TD-00639-D1, V/I 2.9/1 and"
00108           comment4 = " LAT-TD-01545, V/I 2.0/2 ."
00109           status = cfitsio.fits_write_comment(self.__fptr, " ")
00110           status = cfitsio.fits_write_comment(self.__fptr, comment1)
00111           status = cfitsio.fits_write_comment(self.__fptr, comment2)
00112           status = cfitsio.fits_write_comment(self.__fptr, comment3)
00113           status = cfitsio.fits_write_comment(self.__fptr, comment4)
00114           self.__tablenum = 0
00115     else:
00116       raise RuntimeError, "Invalid FITS file mode"
00117 
00118 
00119   def createNewTable(self, datagram_id=None, version_info=None):
00120     if datagram_id is not None:
00121       tmp = self.bcLong2Int(datagram_id)
00122       self.__status = cfitsio.fits_write_key_lng(self.__fptr, "DGRAMID",
00123                                                  tmp, "Datagram Identity")
00124     if version_info is not None:
00125       tmp = self.bcLong2Int(version_info)
00126       self.__status = cfitsio.fits_write_key_lng(self.__fptr, "EVTVERSN",
00127                                                  tmp, "Event Version")
00128     ttype = ['event_data']
00129     if self.__format == FORMAT_BYTE:
00130       tform = ['1PB(4096)']
00131     else:
00132       tform = ['1PV(1024)']
00133     tunit=[' ']
00134     extname='Event Data'
00135     tfields=1
00136     self.__status = cfitsio.fits_create_tbl(self.__fptr, cfitsio.BINARY_TBL,
00137                         self.__tableSize, tfields, ttype, tform, tunit, extname)
00138     if self.__status != 0:
00139       raise IOError, "fits_create_tbl: %s" % cfitsio.fits_get_errstatus(self.__status)
00140     self.__status = cfitsio.fits_write_key_lng(self.__fptr, "EVTCOUNT",
00141                                                 0, "Event Count")
00142     if self.__status != 0:
00143       raise IOError, "fits_write_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00144     self.__rownum = 1
00145     self.__tablenum += 1
00146 
00147   def bcLong2Int(self, datum):
00148     # cfitsio has a problem with putting any long integer with bit 32 set into
00149     # a key.  (fits_write_key_ulng does not exist in nasa space)
00150     # do some bizarre ass bit conversions with integer arithmetic to make sure that the type
00151     # stays "int"
00152     if datum & 0x80000000L:
00153       shiftword = -2147483648                 # - 2^31, really 0x8000000 expressed as an int
00154       truncated = int(datum & 0x7fffffff)     # Slice off bit 31
00155       datum = truncated+shiftword             # add on bit 31
00156     return datum
00157 
00158 
00159   def write(self, rawEventData):
00160     if self.__tablenum == 0:
00161       (datagram_id, datagram_length, version_info) = struct.unpack('!III', rawEventData[:12])
00162       self.createNewTable(datagram_id, version_info)
00163     elif self.__rownum > self.__tableSize:
00164       self.__status = cfitsio.fits_update_key_lng(self.__fptr, "EVTCOUNT",
00165                                                  self.__rownum - 1, "Event Count")
00166       if self.__status != 0:
00167         raise IOError, "fits_update_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00168       if self.__flushInterval > 0:
00169           self.__status = cfitsio.fits_flush_file(self.__fptr)
00170           if self.__status != 0:
00171             raise IOError, "fits_flush_file: %s" % cfitsio.fits_get_errstatus(self.__status)
00172       self.createNewTable()
00173     l = len(rawEventData)
00174     if self.__format == FORMAT_BYTE:
00175       self.__status = cfitsio.fits_write_col_byt(self.__fptr, 1, self.__rownum,
00176                                                  1, l, rawEventData)
00177       if self.__status != 0:
00178         raise IOError, "fits_write_col_byt: %s" % cfitsio.fits_get_errstatus(self.__status)
00179     else:
00180       extra = l % 4
00181       nelem = (l - extra) / 4
00182       if extra != 0:
00183         data = list(struct.unpack('!'+'i'*nelem, rawEventData[:-extra]))
00184       else:
00185         data = list(struct.unpack('!'+'i'*nelem, rawEventData))
00186       self.__status = cfitsio.fits_write_col_uint(self.__fptr, 1, self.__rownum,
00187                                                   1, nelem, data)
00188       if self.__status != 0:
00189         raise IOError, "fits_write_col_uint: %s" % cfitsio.fits_get_errstatus(self.__status)
00190     if (self.__flushInterval > 0) and (self.__rownum % self.__flushInterval == 0):
00191       self.__status = cfitsio.fits_update_key_lng(self.__fptr, "EVTCOUNT",
00192                                                 self.__rownum, "Event Count")
00193       if self.__status != 0:
00194         raise IOError, "fits_update_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00195       self.__status = cfitsio.fits_flush_buffer(self.__fptr, 0)
00196       if self.__status != 0:
00197         raise IOError, "fits_flush_buffer: %s" % cfitsio.fits_get_errstatus(self.__status)
00198     self.__rownum +=1
00199 
00200 
00201   def moveToHDU(self, tablenum):
00202     (self.__status, hdutype) = cfitsio.fits_movabs_hdu(self.__fptr, tablenum)
00203     if self.__status != 0:
00204       return self.__status
00205     (self.__status, self.__eventCount, comment) = cfitsio.fits_read_key_lng(self.__fptr, 'EVTCOUNT')
00206     # Skip the exception if there are tables after the event data (202 is keyword not found)
00207     if self.__status != 0 and self.__status != 202:
00208       raise IOError, "fits_read_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00209     return self.__status
00210 
00211 
00212   def read(self):
00213     self.__rownum += 1
00214     if self.__rownum > self.__eventCount:
00215       self.__tablenum += 1
00216       status = self.moveToHDU(self.__tablenum)
00217       if status != 0:
00218         return None
00219       self.__rownum = 1
00220     (self.__status, event_size, heap_addr) = cfitsio.fits_read_descript(self.__fptr, 1, self.__rownum)
00221     if self.__status != 0:
00222       raise IOError, "fits_read_descript: %s" % cfitsio.fits_get_errstatus(self.__status)
00223     (self.__status, dat) = cfitsio.fits_read_col_byt(self.__fptr, 1, self.__rownum, 1, event_size, None)
00224     if self.__status != 0:
00225       raise IOError, "fits_read_col_byt: %s" % cfitsio.fits_get_errstatus(self.__status)
00226     return dat
00227 
00228 
00229   def close(self, inShutdown=0):
00230     if self.__mode != MODE_READONLY:
00231       if self.__tablenum > 0:
00232         self.__status = cfitsio.fits_update_key_lng(self.__fptr, "EVTCOUNT",
00233                                                    self.__rownum - 1, "Event Count")
00234         if self.__status != 0:
00235           raise IOError, "fits_update_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00236       if self.__reportGen is not None and not inShutdown:
00237         self.updateRunReportFields()
00238 
00239     self.__status = cfitsio.fits_close_file(self.__fptr)
00240     if self.__status != 0:
00241       raise IOError, "fits_close_file: %s" % cfitsio.fits_get_errstatus(self.__status)
00242     self.__fptr = None
00243 
00244   def updateRunReportFields(self):
00245     (self.__status, hdutype) = cfitsio.fits_movabs_hdu(self.__fptr, 1)
00246 
00247     # Write the version for the run report keyword/value dump in case
00248     # we need to modify it in the future
00249     self.__status = cfitsio.fits_write_key_str(self.__fptr, "RPTVERSN",
00250                                                RUN_REPORT_VERSION,
00251                                                "Run Report Fields Version")
00252     if self.__status != 0:
00253       raise IOError, "fits_write_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00254 
00255     reportFields      = self.__reportGen.getReportFields()
00256     reportData        = self.__reportGen.getReportData()
00257     reportUnits       = self.__reportGen.getReportUnits()
00258 
00259     self.__status = cfitsio.fits_write_key_lng(self.__fptr, "NUM_KVS",
00260                                                len(reportFields),
00261                                                "Number of Key/Value pairs")
00262     if self.__status != 0:
00263       raise IOError, "fits_write_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00264 
00265     for i in range(len(reportFields)):
00266       listType = 0
00267       dictType = 0
00268       x = None
00269     #  self.__status = cfitsio.fits_write_key_str(self.__fptr,
00270     #                                             reportShortNames[i],
00271     #                                             reportData[i],
00272     #                                             reportFields[i])
00273       try:
00274         exec("x=" + reportData[i])
00275         if type(x) == types.ListType:
00276           listType = 1
00277         elif type(x) == types.DictType:
00278           dictType = 1
00279       except:
00280         #print sys.exc_info()
00281         pass
00282       if listType and len(x) > 0:
00283         ttype = ['list_value']
00284         tform = ['80A']
00285         tunit=[' ']
00286         extname= reportFields[i]
00287         tfields=1
00288         self.__status = cfitsio.fits_create_tbl(self.__fptr, cfitsio.BINARY_TBL,
00289                             len(x), tfields, ttype, tform, tunit, extname)
00290         if self.__status != 0:
00291           raise IOError, "fits_create_tbl: %s" % cfitsio.fits_get_errstatus(self.__status)
00292 
00293         self.__status = cfitsio.fits_write_col_str(self.__fptr, 1, 1, 1, map(str, x))
00294         if self.__status != 0:
00295           raise IOError, "fits_write_col_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00296         (self.__status, hdutype) = cfitsio.fits_movabs_hdu(self.__fptr, 1)
00297         if self.__status != 0:
00298           raise IOError, "fits_movabs_hdu %s" % cfitsio.fits_get_errstatus(self.__status)
00299       elif dictType and len(x) > 0:
00300         ttype = ['dict_key', 'dict_value']
00301         tform = ['80A','80A']
00302         tunit=[' ',' ']
00303         extname= reportFields[i]
00304         tfields=2
00305         self.__status = cfitsio.fits_create_tbl(self.__fptr, cfitsio.BINARY_TBL,
00306                             len(x), tfields, ttype, tform, tunit, extname)
00307         if self.__status != 0:
00308           raise IOError, "fits_create_tbl: %s" % cfitsio.fits_get_errstatus(self.__status)
00309 
00310         self.__status = cfitsio.fits_write_col_str(self.__fptr, 1, 1, 1, map(str, x.keys()))
00311         if self.__status != 0:
00312           raise IOError, "fits_write_col_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00313         self.__status = cfitsio.fits_write_col_str(self.__fptr, 2, 1, 1, map(str, x.values()))
00314         if self.__status != 0:
00315           raise IOError, "fits_write_col_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00316 
00317         (self.__status, hdutype) = cfitsio.fits_movabs_hdu(self.__fptr, 1)
00318         if self.__status != 0:
00319           raise IOError, "fits_movabs_hdu: %s" % cfitsio.fits_get_errstatus(self.__status)
00320       self.__status = cfitsio.fits_write_key_str(self.__fptr,
00321                                                   "KEY_%04d" % i,
00322                                                   reportFields[i],
00323                                                   "")
00324       if self.__status != 0:
00325         raise IOError, "fits_write_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00326 
00327       if (listType or dictType):
00328         if len(x) > 0:
00329           self.__status = cfitsio.fits_write_key_str(self.__fptr,
00330                                                     "VAL_%04d" % i,
00331                                                     "",
00332                                                     "See table '" + reportFields[i] + "'")
00333         else:
00334           self.__status = cfitsio.fits_write_key_str(self.__fptr,
00335                                                     "VAL_%04d" % i,
00336                                                     "",
00337                                                     "")
00338         if self.__status != 0:
00339           raise IOError, "fits_write_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00340       else:
00341         if reportUnits[i] == rcReportGen.UNITS_STRING:
00342           self.__status = cfitsio.fits_write_key_str(self.__fptr,
00343                                                     "VAL_%04d" % i,
00344                                                     reportData[i],
00345                                                     "")
00346           if self.__status != 0:
00347             raise IOError, "fits_write_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00348 
00349         elif reportUnits[i] in (rcReportGen.UNITS_INT, rcReportGen.UNITS_LONG):
00350           self.__status = cfitsio.fits_write_key_lng(self.__fptr,
00351                                                     "VAL_%04d" % i,
00352                                                     long(reportData[i]),
00353                                                     "")
00354           if self.__status != 0:
00355             raise IOError, "fits_write_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00356         elif reportUnits[i] == rcReportGen.UNITS_FLOAT:
00357           self.__status = cfitsio.fits_write_key_fixflt(self.__fptr,
00358                                                     "VAL_%04d" % i,
00359                                                     float(reportData[i]),
00360                                                     4,
00361                                                     "")
00362           if self.__status != 0:
00363             raise IOError, "fits_write_key_flt: %s" % cfitsio.fits_get_errstatus(self.__status)
00364         else:
00365           self.__status = cfitsio.fits_write_key_str(self.__fptr,
00366                                                     "VAL_%04d" % i,
00367                                                     reportData[i],
00368                                                     "")
00369           if self.__status != 0:
00370             raise IOError, "fits_write_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00371 
00372 
00373   def setFlushInterval(self, flushInterval):
00374     self.__flushInterval = flushInterval
00375 
00376   def getStatus(self):
00377     return self.__status
00378 
00379   def getFileName(self):
00380       return self.__fileName
00381 
00382   def getFilePath(self):
00383     return self.__filePath
00384 
00385   def getHeaders(self):
00386     """If we are in read only mode and reportGen is provided then read the headers of off the FITS file
00387 
00388     """
00389     (self.__status, nkv, comment) = cfitsio.fits_read_key_lng(self.__fptr, "NUM_KVS")
00390     if self.__status != 0:
00391       raise IOError, "fits_read_key_lng: %s" % cfitsio.fits_get_errstatus(self.__status)
00392     #print "NUMBER OF KEYWORDS=", nkv
00393     for i in range(nkv):
00394       (self.__status, keyValue, comment) = cfitsio.fits_read_key_str(self.__fptr, "KEY_%04d" % i)
00395       if self.__status != 0:
00396         raise IOError, "fits_read_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00397       #print "KEY_%04d=%s %s" % (i,keyValue,comment)
00398       (self.__status, valValue, comment) = cfitsio.fits_read_key_str(self.__fptr, "VAL_%04d" % i)
00399       if self.__status != 0:
00400         raise IOError, "fits_read_key_str: %s" % cfitsio.fits_get_errstatus(self.__status)
00401       #print "VAL_%04d=%s %s" % (i,valValue,comment)
00402       if valValue == '':
00403         #print "Moving to HDU", keyValue
00404         self.__status = cfitsio.fits_movnam_hdu(self.__fptr, cfitsio.ANY_HDU, keyValue, 0)
00405         if self.__status != 0:
00406           #print "fits_movnam_hdu %s" % cfitsio.fits_get_errstatus(self.__status)
00407           self.__reportGen.addField(keyValue, "[]")
00408         else:
00409           repData = self.processTable()
00410           self.__reportGen.addField(keyValue, str(repData))
00411         (self.__status, hdutype) = cfitsio.fits_movabs_hdu(self.__fptr, 1)
00412       else:
00413         self.__reportGen.addField(keyValue, str(valValue))
00414 
00415   def processTable(self):
00416     (self.__status, nCols) = cfitsio.fits_get_num_cols(self.__fptr)
00417     if self.__status != 0:
00418       raise IOError, "fits_get_num_cols %s" % cfitsio.fits_get_errstatus(self.__status)
00419     #print "Number of columns=", nCols
00420     (self.__status, nRows) = cfitsio.fits_get_num_rows(self.__fptr)
00421     if self.__status != 0:
00422       raise IOError, "fits_get_num_rows %s" % cfitsio.fits_get_errstatus(self.__status)
00423     #print "Number of rows=", nRows
00424     if nCols == 1:
00425       (self.__status, repList) = cfitsio.fits_read_col_str(self.__fptr, 1, 1, 1, nRows)
00426       if self.__status != 0:
00427         raise IOError, "fits_read_col_str %s" % cfitsio.fits_get_errstatus(self.__status)
00428       return repList
00429     elif nCols == 2:
00430       (self.__status, keyList) = cfitsio.fits_read_col_str(self.__fptr, 1, 1, 1, nRows)
00431       if self.__status != 0:
00432         raise IOError, "fits_read_col_str %s" % cfitsio.fits_get_errstatus(self.__status)
00433       (self.__status, valList) = cfitsio.fits_read_col_str(self.__fptr, 2, 1, 1, nRows)
00434       if self.__status != 0:
00435         raise IOError, "fits_read_col_str %s" % cfitsio.fits_get_errstatus(self.__status)
00436       repDict={}
00437       for key,value in map(None,keyList,valList):
00438           repDict[key]=value
00439       return repDict
00440 
00441 # ----- End rcFitsWriter ------
00442 
00443 def getFileNameFromTS(ts):
00444     return "ebf" + ts + ".fits"
00445 

Generated on Fri Jul 21 13:26:31 2006 for LATTE R04-12-00 by doxygen 1.4.3