source: fact/tools/pyscripts/pyfact/pyfact.py@ 12852

Last change on this file since 12852 was 12842, checked in by neise, 13 years ago
corrected import name of scipy.signal from spsi to signal
  • Property svn:executable set to *
File size: 12.2 KB
Line 
1#!/usr/bin/python
2#
3# Werner Lustermann
4# ETH Zurich
5#
6from ctypes import *
7import numpy as np
8from scipy import signal
9
10# get the ROOT stuff + my shared libs
11from ROOT import gSystem
12# fitslib.so is made from fits.h and is used to access the data
13gSystem.Load('~/py/fitslib.so')
14from ROOT import *
15
16class rawdata( object ):
17 """
18 raw data access and calibration
19 - open raw data file and drs calibration file
20 - performs amplitude calibration
21 - performs baseline substraction if wanted
22 - provides all data in an array:
23 row = number of pixel
24 col = length of region of interest
25 """
26 # constructor of the classe
27 def __init__( self, dfname, calfname, bslfname='' ):
28 """
29 open data file and calibration data file
30 get basic information about the data in dfname
31 allocate buffers for data access
32
33 dfname : fits or fits.gz file containing the data including the path
34 calfname : fits or fits.gz file containing DRS calibration data
35 bslfname : npy file containing the baseline values
36 """
37 self.dfname = dfname
38 self.calfname = calfname
39 self.bslfname = bslfname
40
41 # baseline correction: True / False
42 if len( bslfname ) == 0:
43 self.correct_baseline = False
44 else:
45 self.correct_baseline = True
46
47 # access data file
48 try:
49 df = fits( self.dfname )
50 except IOError:
51 print 'problem accessing data file: ', dfname
52 raise # stop ! no data
53 self.df = df
54
55 # get basic information about the data file
56 self.NROI = df.GetUInt( 'NROI' ) # region of interest (length of DRS pipeline read out)
57 self.NPIX = df.GetUInt( 'NPIX' ) # number of pixels (should be 1440)
58 self.NEvents = df.GetNumRows() # find number of events
59 # allocate the data memories
60 self.evNum = c_ulong()
61 self.trigType = c_ushort()
62 self.Data = np.zeros( self.NPIX * self.NROI, np.int16 )
63 self.startCells = np.zeros( self.NPIX, np.int16 )
64 # set the pointers to the data++
65 df.SetPtrAddress( 'EventNum', self.evNum )
66 df.SetPtrAddress( 'TriggerType', self.trigType )
67 df.SetPtrAddress( 'StartCellData', self.startCells ) # DRS readout start cell
68 df.SetPtrAddress( 'Data', self.Data ) # this is what you would expect
69 # df.GetNextRow() # access the first event
70
71 # access calibration file
72 try:
73 calf = fits( self.calfname )
74 except IOError:
75 print 'problem accessing calibration file: ', calfname
76 raise
77 self.calf = calf
78 #
79 BaselineMean = calf.GetN('BaselineMean')
80 GainMean = calf.GetN('GainMean')
81 TriggerOffsetMean = calf.GetN('TriggerOffsetMean')
82
83 self.blm = np.zeros( BaselineMean, np.float32 )
84 self.gm = np.zeros( GainMean, np.float32 )
85 self.tom = np.zeros( TriggerOffsetMean, np.float32 )
86
87 self.Nblm = BaselineMean / self.NPIX
88 self.Ngm = GainMean / self.NPIX
89 self.Ntom = TriggerOffsetMean / self.NPIX
90
91 calf.SetPtrAddress( 'BaselineMean', self.blm )
92 calf.SetPtrAddress( 'GainMean', self.gm )
93 calf.SetPtrAddress( 'TriggerOffsetMean', self.tom )
94 calf.GetRow(0)
95
96 self.v_bsl = np.zeros( self.NPIX ) # array with baseline values (all ZERO)
97 self.smoothData = None
98 self.maxPos = None
99 self.maxAmp = None
100
101
102 def next( self ):
103 """
104 load the next event from disk and calibrate it
105 """
106 self.df.GetNextRow()
107 self.calibrate_drsAmplitude()
108
109
110 def calibrate_drsAmplitude( self ):
111 """
112 perform amplitude calibration for the event
113 """
114 tomV = 2000./4096.
115 acalData = self.Data * tomV # convert into mV
116
117 # reshape arrays: row = pixel, col = drs_slice
118 acalData = np.reshape( acalData, (self.NPIX, self.NROI) )
119 blm = np.reshape( self.blm, (self.NPIX, 1024) )
120 tom = np.reshape( self.tom, (self.NPIX, 1024) )
121 gm = np.reshape( self.gm, (self.NPIX, 1024) )
122
123 # print 'acal Data ', acalData.shape
124 # print 'blm shape ', blm.shape
125 # print 'gm shape ', gm.shape
126
127 for pixel in range( self.NPIX ):
128 # rotate the pixel baseline mean to the Data startCell
129 blm_pixel = np.roll( blm[pixel,:], -self.startCells[pixel] )
130 acalData[pixel,:] -= blm_pixel[0:self.NROI]
131 acalData[pixel,:] -= tom[pixel, 0:self.NROI]
132 acalData[pixel,:] /= gm[pixel, 0:self.NROI]
133
134 self.acalData = acalData * 1907.35
135
136 # print 'acalData ', self.acalData[0:2,0:20]
137
138 def filterSlidingAverage( self , windowSize = 4):
139 """ sliding average filter
140 using:
141 self.acalData
142 filling array:
143 self.smoothData
144 """
145 #scipy.signal.lfilter(b, a, x, axis=-1, zi=None)
146 smoothData = self.acalData.copy()
147 b = np.ones( windowSize )
148 a = np.zeros( windowSize )
149 a[0] = len(b)
150 smoothData[:,:] = signal.lfilter(b, a, smoothData[:,:])
151
152 self.smoothData = smoothData
153
154 def filterCFD( self, length=10, ratio=0.75):
155 """ constant fraction filter
156 using:
157 self.smoothData
158 filling array:
159 self.cfdData
160 """
161 if self.smoothData == None:
162 print 'error pyfact.filterCFD was called without prior call to filterSlidingAverage'
163 print ' variable self.smoothData is needed '
164 pass
165 cfdData = self.smoothData.copy()
166 b = np.zeros( length )
167 a = np.zeros( length )
168 b[0] = -1. * ratio
169 b[length-1] = 1.
170 a[0] = 1.
171 cfdData[:,:] = signal.lfilter(b, a, cfdData[:,:])
172
173 self.cfdData = cfdData
174
175 def findPeak (self, min=30, max=250):
176 """ find maximum in search window
177 using:
178 self.smoothData
179 filling arrays:
180 self.maxPos
181 self.maxAmp
182 """
183 if self.smoothData == None:
184 print 'error pyfact.findPeakMax was called without prior call to filterSlidingAverage'
185 print ' variable self.smoothData is needed '
186 pass
187 maxPos = np.argmax( self.smoothData[:,min:max] , 1)
188 maxAmp = np.max( self.smoothData[:,min:max] , 1)
189 self.maxPos = maxPos
190 self.maxAmp = maxAmp
191
192 def sumAroundPeak (self, left=13, right=23):
193 """ integrate signal in gate around Peak
194 using:
195 self.maxPos
196 self.acalData
197 filling array:
198 self.integral
199 """
200 if self.maxPos == None:
201 print 'error pyfact.sumAroundPeak was called without prior call of findPeak'
202 print ' variable self.maxPos is needed'
203 pass
204
205 sums = np.empty( self.NPIX )
206 for pixel in range( self.NPIX ):
207 min = self.maxPos[pixel]-left
208 max = self.maxPos[pixel]+right
209 sums[pixel] = self.acalData[pixel,min:max].sum()
210
211 self.integral = sums
212
213 def ReadBaseline( self, file, bsl_hist = 'bsl_sum/hplt_mean' ):
214 """
215 open ROOT file with baseline histogram and read baseline values
216 file name of the root file
217 bsl_hist path to the histogram containing the basline values
218 """
219 try:
220 f = TFile( file )
221 except:
222 print 'Baseline data file could not be read: ', file
223 return
224
225 h = f.Get( bsl_hist )
226
227 for i in range( self.NPIX ):
228 self.v_bsl[i] = h.GetBinContent( i+1 )
229
230 f.Close()
231
232
233 def CorrectBaseline( self ):
234 """
235 apply baseline correction
236 """
237 for pixel in range( self.NPIX ):
238 self.acalData[pixel,:] -= self.v_bsl[pixel]
239
240
241 def info( self ):
242 """
243 print information
244 """
245 print 'data file: ', dfname
246 print 'calib file: ', calfname
247 print 'calibration file'
248 print 'N BaselineMean: ', self.Nblm
249 print 'N GainMean: ', self.Ngm
250 print 'N TriggeroffsetMean: ', self.Ntom
251
252# --------------------------------------------------------------------------------
253class fnames( object ):
254 """ organize file names of a FACT data run
255
256 """
257
258 def __init__( self, specifier = ['012', '023', '2011', '11', '24'],
259 rpath = '/scratch_nfs/bsl/',
260 zipped = True):
261 """
262 specifier : list of strings defined as:
263 [ 'DRS calibration file', 'Data file', 'YYYY', 'MM', 'DD']
264
265 rpath : directory path for the results; YYYYMMDD will be appended to rpath
266 zipped : use zipped (True) or unzipped (Data)
267 """
268 self.specifier = specifier
269 self.rpath = rpath
270 self.zipped = zipped
271
272 self.make( self.specifier, self.rpath, self.zipped )
273 # end of def __init__
274
275 def make( self, specifier, rpath, zipped ):
276 """ create (make) the filenames
277
278 names : dictionary of filenames, tags { 'data', 'drscal', 'results' }
279 data : name of the data file
280 drscal : name of the drs calibration file
281 results : radikal of file name(s) for results (to be completed by suffixes)
282 """
283
284 self.specifier = specifier
285
286 if zipped:
287 dpath = '/data00/fact-construction/raw/'
288 ext = '.fits.gz'
289 else:
290 dpath = '/data03/fact-construction/raw/'
291 ext = '.fits'
292
293 year = specifier[2]
294 month = specifier[3]
295 day = specifier[4]
296
297 yyyymmdd = year + month + day
298 dfile = specifier[1]
299 cfile = specifier[0]
300
301 rpath = rpath + yyyymmdd + '/'
302 self.rpath = rpath
303 self.names = {}
304
305 tmp = dpath + year + '/' + month + '/' + day + '/' + yyyymmdd + '_'
306 self.names['data'] = tmp + dfile + ext
307 self.names['drscal'] = tmp + cfile + '.drs' + ext
308 self.names['results'] = rpath + yyyymmdd + '_' + dfile + '_' + cfile
309
310 self.data = self.names['data']
311 self.drscal = self.names['drscal']
312 self.results = self.names['results']
313
314 # end of make
315
316 def info( self ):
317 """ print complete filenames
318
319 """
320
321 print 'file names:'
322 print 'data: ', self.names['data']
323 print 'drs-cal: ', self.names['drscal']
324 print 'results: ', self.names['results']
325 # end of def info
326
327# end of class definition: fnames( object )
328
329
330
331class histogramList( object ):
332
333 def __init__( self, name ):
334 """ set the name and create empty lists """
335 self.name = name # name of the list
336 self.list = [] # list of the histograms
337 self.dict = {} # dictionary of histograms
338 self.hList = TObjArray() # list a la ROOT of the histograms
339
340 def add( self, tag, h ):
341 self.list.append( h )
342 self.dict[tag] = h
343 self.hList.Add( h )
344
345
346class pixelHisto1d ( object ):
347
348 def __init__( self, name, title, Nbin, first, last, xtitle, ytitle, NPIX ):
349 """
350 book one dimensional histograms for each pixel
351 """
352 self.name = name
353
354 self.list = [ x for x in range( NPIX ) ]
355 self.hList = TObjArray()
356
357 for pixel in range( NPIX ):
358
359 hname = name + ' ' + str( pixel )
360 htitle = title + ' ' + str( pixel )
361 self.list[pixel] = TH1F( hname, htitle, Nbin, first, last )
362
363 self.list[pixel].GetXaxis().SetTitle( xtitle )
364 self.list[pixel].GetYaxis().SetTitle( ytitle )
365 self.hList.Add( self.list[pixel] )
366
367# simple test method
368if __name__ == '__main__':
369 """
370 create an instance
371 """
372 dfname = '/data03/fact-construction/raw/2011/11/24/20111124_121.fits'
373 calfname = '/data03/fact-construction/raw/2011/11/24/20111124_111.drs.fits'
374 rd = rawdata( dfname, calfname )
375 rd.info()
376 rd.next()
377
378# for i in range(10):
379# df.GetNextRow()
380
381# print 'evNum: ', evNum.value
382# print 'startCells[0:9]: ', startCells[0:9]
383# print 'evData[0:9]: ', evData[0:9]
Note: See TracBrowser for help on using the repository browser.