# # files.py (c) Stuart B. Wilkins 2010 # # $Id$ # $HeadURL$ # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Part of the "pyspec" package # import numpy import time import struct __version__ = "$Revision$" __author__ = "Stuart B. Wilkins " __date__ = "$LastChangedDate$" __id__ = "$Id$" def LCLSdataformat(iname, dataFormat = "142500f"): """function to read LCLS data. no headers in this""" FH = open(iname, "rb") data = numpy.array(struct.unpack(dataFormat, FH.read())) FH.close() return data class PrincetonSPEFile(): """Class to read SPE files from Princeton CCD cameras""" TEXTCOMMENTMAX = 80 DATASTART = 4100 NCOMMENTS = 5 DATEMAX = 10 TIMEMAX = 7 def __init__(self, fname = None, fid = None): """Initialize class. Parameters: fname = Filename of SPE file fid = File ID of open stream This function initializes the class and, if either a filename or fid is provided opens the datafile and reads the contents""" self._fid = None self.fname = fname if fname is not None: self.openFile(fname) elif fid is not None: self._fid = fid if self._fid: self.readData() def __str__(self): """Provide a text representation of the file.""" s = "Filename : %s\n" % self.fname s += "Data size : %d x %d x %d\n" % (self._size[::-1]) s += "CCD Chip Size : %d x %d\n" % self._chipSize[::-1] s += "File date : %s\n" % time.asctime(self._filedate) s += "Exposure Time : %f\n" % self.Exposure s += "Num ROI : %d\n" % self.NumROI s += "Num ROI Exp : %d\n" % self.NumROIExperiment s += "Contoller Ver.: %d\n" % self.ControllerVersion s += "Logic Output : %d\n" % self.LogicOutput #self.AppHiCapLowNoise = self._readInt(4) s += "Timing Mode : %d\n" % self.TimingMode s += "Det. Temp : %d\n" % self.DetTemperature s += "Det. Type : %d\n" % self.DetectorType s += "Trigger Diode : %d\n" % self.TriggerDiode s += "Delay Time : %d\n" % self.DelayTime s += "Shutter Cont. : %d\n" % self.ShutterControl s += "Absorb Live : %d\n" % self.AbsorbLive s += "Absorb Mode : %d\n" % self.AbsorbMode s += "Virtual Chip : %d\n" % self.CanDoVirtualChip s += "Thresh. Min L : %d\n" % self.ThresholdMinLive s += "Thresh. Min : %d\n" % self.ThresholdMin s += "Thresh. Max L : %d\n" % self.ThresholdMaxLive s += "Thresh. Max : %d\n" % self.ThresholdMax s += "Geometric Op : %d\n" % self.GeometricOps s += "ADC Offset : %d\n" % self.ADCOffset s += "ADC Rate : %d\n" % self.ADCRate s += "ADC Type : %d\n" % self.ADCType s += "ADC Resol. : %d\n" % self.ADCRes s += "ADC Bit. Adj. : %d\n" % self.ADCBitAdj s += "ADC Gain : %d\n" % self.Gain i = 0 for roi in self.allROI: s += "ROI %-4d : %-5d %-5d %-5d %-5d %-5d %-5d\n" % (i,roi[0], roi[1], roi[2], roi[3], roi[4], roi[5]) i += 1 s += "\nComments :\n" i = 0 for c in self._comments: s += "%-3d : " % i i += 1 s += c s += "\n" return s def __getitem__(self, n): """Return the array with zdimension n This method can be used to quickly obtain a 2-D array of the data""" return self._array[n] def getData(self): """Return the array of data""" return self._array def getBinnedData(self): """Return the binned (sum of all frames) data""" return self._array.sum(0) def readData(self): """Read all the data into the class""" self._readHeader() self._readSize() self._readComments() self._readAllROI() self._readDate() self._readArray() def openFile(self, fname): """Open a SPE file""" self._fname = fname self._fid = open(fname, "rb") def getSize(self): """Return a tuple of the size of the data array""" return self._size def getChipSize(self): """Return a tuple of the size of the CCD chip""" return self._chipSize def getVirtualChipSize(self): """Return the virtual chip size""" return self._vChipSize def getComment(self, n = None): """Return the comments in the data file If n is not provided then all the comments are returned as a list of string values. If n is provided then the n'th comment is returned""" if n is None: return self._comments else: return self._comments[n] def _readAtNumpy(self, pos, size, ntype): if pos is not None: self._fid.seek(pos) return numpy.fromfile(self._fid, ntype, size) def _readAtString(self, pos, size): if pos is not None: self._fid.seek(pos) return self._fid.read(size).rstrip(chr(0)) def _readInt(self, pos): return self._readAtNumpy(pos, 1, numpy.int16)[0] def _readFloat(self, pos): return self._readAtNumpy(pos, 1, numpy.float32)[0] def _readHeader(self): """This routine contains all other information""" self.ControllerVersion = self._readInt(0) self.LogicOutput = self._readInt(2) self.AppHiCapLowNoise = self._readInt(4) self.TimingMode = self._readInt(8) self.Exposure = self._readFloat(10) self.DetTemperature = self._readFloat(36) self.DetectorType = self._readInt(40) self.TriggerDiode = self._readInt(44) self.DelayTime = self._readFloat(46) self.ShutterControl = self._readInt(50) self.AbsorbLive = self._readInt(52) self.AbsorbMode = self._readInt(54) self.CanDoVirtualChip = self._readInt(56) self.ThresholdMinLive = self._readInt(58) self.ThresholdMin = self._readFloat(60) self.ThresholdMaxLive = self._readInt(64) self.ThresholdMax = self._readFloat(66) self.ADCOffset = self._readInt(188) self.ADCRate = self._readInt(190) self.ADCType = self._readInt(192) self.ADCRes = self._readInt(194) self.ADCBitAdj = self._readInt(196) self.Gain = self._readInt(198) self.GeometricOps = self._readInt(600) def _readAllROI(self): self.allROI = self._readAtNumpy(1512, 60, numpy.int16).reshape(-1,6) self.NumROI = self._readAtNumpy(1510, 1, numpy.int16)[0] self.NumROIExperiment = self._readAtNumpy(1488, 1, numpy.int16)[0] if self.NumROI == 0: self.NumROI = 1 if self.NumROIExperiment == 0: self.NumROIExperiment = 1 def _readDate(self): _date = self._readAtString(20, self.DATEMAX) _time = self._readAtString(172, self.TIMEMAX) self._filedate = time.strptime(_date + _time, "%d%b%Y%H%M%S") def _readSize(self): xdim = self._readAtNumpy(42, 1, numpy.int16)[0] ydim = self._readAtNumpy(656, 1, numpy.int16)[0] zdim = self._readAtNumpy(1446, 1, numpy.uint32)[0] dxdim = self._readAtNumpy(6, 1, numpy.int16)[0] dydim = self._readAtNumpy(18, 1, numpy.int16)[0] vxdim = self._readAtNumpy(14, 1, numpy.int16)[0] vydim = self._readAtNumpy(16, 1, numpy.int16)[0] dt = numpy.int16(self._readAtNumpy(108, 1, numpy.int16)[0]) data_types = (numpy.float32, numpy.int32, numpy.int16, numpy.uint16) if (dt > 3) or (dt < 0): raise Exception("Unknown data type") self._dataType = data_types[dt] self._size = (zdim, ydim, xdim) self._chipSize = (dydim, dxdim) self._vChipSize = (vydim, vxdim) def _readComments(self): self._comments = [] for n in range(5): self._comments.append( self._readAtString(200 + (n * self.TEXTCOMMENTMAX), self.TEXTCOMMENTMAX)) def _readArray(self): self._fid.seek(self.DATASTART) self._array = numpy.fromfile(self._fid, dtype = self._dataType, count = -1) self._array = self._array.reshape(self._size)