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

Last change on this file since 13374 was 13374, checked in by neise, 12 years ago
adjusted _test_iter for dict return value of RawData.next()
  • Property svn:executable set to *
File size: 14.1 KB
Line 
1#!/usr/bin/python -tt
2#
3# Werner Lustermann, Dominik Neise
4# ETH Zurich, TU Dortmund
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# pyfits_h.so is made from pyfits.h and is used to access the data
13# make sure the location of pyfits_h.so is in LD_LIBRARY_PATH.
14# having it in PYTHONPATH is *not* sufficient
15gSystem.Load('pyfits_h.so')
16from ROOT import *
17
18class RawDataFeeder( object ):
19 """ Wrapper class for RawData class
20 capable of iterating over multiple RawData Files
21 """
22
23 def __init__(self, filelist):
24 """ *filelist* list of files to iterate over
25 the list should contain tuples, or sublists of two filenames
26 the first should be a data file (\*.fits.gz)
27 the second should be an amplitude calibration file(\*.drs.fits.gz)
28 """
29 # sanity check for input
30 if type(filelist) != type(list()):
31 raise TypeError('filelist should be a list')
32 for entry in filelist:
33 if len(entry) != 2:
34 raise TypeError('the entries of filelist should have length == 2')
35 for path in entry:
36 if type(path) != type(str()):
37 raise TypeError('the entries of filelist should be path, i.e. of type str()')
38 #todo check if 'path' is a valid path
39 # else: throw an Exception, or Warning?
40
41 self.filelist = filelist
42 self._current_RawData = RawData(filelist[0][0], filelist[0][1], return_dict=True)
43 del filelist[0]
44
45 def __iter__(self):
46 return self
47
48 def next():
49 """ Method being called by the iterator.
50 Since the RawData Objects are simply looped over, the event_id from the
51 RawData object will not be unique.
52 Each RawData obejct will start with event_id = 1 as usual.
53 """
54 try:
55 return self._current_RawData.next()
56 except StopIteration:
57 # current_RawData was completely processed
58 # delete it (I hope this calls the destructor of the fits file and/or closes it)
59 del self._current_RawData
60 # and remake it, if possible
61 if len(self.filelist) > 0:
62 self._current_RawData = RawData(filelist[0][0], filelist[0][1], return_dict=True)
63 del filelist[0]
64 else:
65 raise
66
67
68
69class RawData( object ):
70 """ raw data access and calibration
71
72 - open raw data file and drs calibration file
73 - performs amplitude calibration
74 - performs baseline substraction if wanted
75 - provides all data in an array:
76 row = number of pixel
77 col = length of region of interest
78
79 """
80
81
82 def __init__(self, data_file_name, calib_file_name,
83 user_action_calib=lambda acal_data, data, blm, tom, gm, scells, nroi: None,
84 baseline_file_name='',
85 return_dict = None):
86 """ initialize object
87
88 open data file and calibration data file
89 get basic information about the data in data_file_name
90 allocate buffers for data access
91
92 data_file_name : fits or fits.gz file of the data including the path
93 calib_file_name : fits or fits.gz file containing DRS calibration data
94 baseline_file_name : npy file containing the baseline values
95 """
96 self.__module__='pyfact'
97 # manual implementation of default value, but I need to find out
98 # if the user of this class is aware of the new option
99 if return_dict == None:
100 print 'Warning: Rawdata.__init__() has a new option "return_dict"'
101 print 'the default value of this option is False, so nothing changes for you at the moment.'
102 print
103 print 'you probably want, to get a dictionary out of the next() method anyway'
104 print ' so please change your scripts and set this option to True, for the moment'
105 print 'e.g. like this: run = RawData(data_filename, calib_filename, return_dict = True)'
106 print "after a while, the default value, will turn to True .. so you don't have to give the option anymore"
107 print 'and some time later, the option will not be supported anymore'
108 return_dict = False
109
110 self.return_dict = return_dict
111
112 self.data_file_name = data_file_name
113 self.calib_file_name = calib_file_name
114 self.baseline_file_name = baseline_file_name
115
116 self.user_action_calib = user_action_calib
117
118 # baseline correction: True / False
119 if len(baseline_file_name) == 0:
120 self.correct_baseline = False
121 else:
122 self.correct_baseline = True
123
124 # access data file
125 try:
126 data_file = fits(self.data_file_name)
127 except IOError:
128 print 'problem accessing data file: ', data_file_name
129 raise # stop ! no data
130 #: data file (fits object)
131 self.data_file = data_file
132
133 # get basic information about the data file
134 #: region of interest (number of DRS slices read)
135 self.nroi = data_file.GetUInt('NROI')
136 #: number of pixels (should be 1440)
137 self.npix = data_file.GetUInt('NPIX')
138 #: number of events in the data run
139 self.nevents = data_file.GetNumRows()
140
141 # allocate the data memories
142 self.event_id = c_ulong()
143 self.trigger_type = c_ushort()
144 #: 1D array with raw data
145 self.data = np.zeros( self.npix * self.nroi, np.int16 )
146 #: slice where drs readout started
147 self.start_cells = np.zeros( self.npix, np.int16 )
148 #: time when the FAD was triggered, in some strange units...
149 self.board_times = np.zeros( 40, np.int32 )
150
151 # set the pointers to the data++
152 data_file.SetPtrAddress('EventNum', self.event_id)
153 data_file.SetPtrAddress('TriggerType', self.trigger_type)
154 data_file.SetPtrAddress('StartCellData', self.start_cells)
155 data_file.SetPtrAddress('Data', self.data)
156 data_file.SetPtrAddress('BoardTime', self.board_times)
157
158 # open the calibration file
159 try:
160 calib_file = fits(self.calib_file_name)
161 except IOError:
162 print 'problem accessing calibration file: ', calib_file_name
163 raise
164 #: drs calibration file
165 self.calib_file = calib_file
166
167 baseline_mean = calib_file.GetN('BaselineMean')
168 gain_mean = calib_file.GetN('GainMean')
169 trigger_offset_mean = calib_file.GetN('TriggerOffsetMean')
170
171 self.blm = np.zeros(baseline_mean, np.float32)
172 self.gm = np.zeros(gain_mean, np.float32)
173 self.tom = np.zeros(trigger_offset_mean, np.float32)
174
175 self.Nblm = baseline_mean / self.npix
176 self.Ngm = gain_mean / self.npix
177 self.Ntom = trigger_offset_mean / self.npix
178
179 calib_file.SetPtrAddress('BaselineMean', self.blm)
180 calib_file.SetPtrAddress('GainMean', self.gm)
181 calib_file.SetPtrAddress('TriggerOffsetMean', self.tom)
182 calib_file.GetRow(0)
183
184 self.v_bsl = np.zeros(self.npix) # array of baseline values (all ZERO)
185
186 def __iter__(self):
187 """ iterator """
188 return self
189
190 def __add__(self, jump_over):
191 self.data_file.GetRow(jump_over)
192 return self
193
194 def next(self):
195 """ used by __iter__ """
196
197 if self.data_file.GetNextRow() == False:
198 raise StopIteration
199 else:
200 self.calibrate_drs_amplitude()
201
202 #print 'nevents = ', self.nevents, 'event_id = ', self.event_id.value
203 if self.return_dict:
204 return self.__dict__
205 else:
206 return self.acal_data, self.start_cells, self.trigger_type.value
207
208 def next_event(self):
209 """ load the next event from disk and calibrate it
210
211 """
212
213 self.data_file.GetNextRow()
214 self.calibrate_drs_amplitude()
215
216 def calibrate_drs_amplitude(self):
217 """ perform the drs amplitude calibration of the event data
218
219 """
220
221 to_mV = 2000./4096.
222 #: 2D array with amplitude calibrated dat in mV
223 acal_data = self.data * to_mV # convert ADC counts to mV
224
225 # make 2D arrays: row = pixel, col = drs_slice
226 acal_data = np.reshape(acal_data, (self.npix, self.nroi) )
227 blm = np.reshape(self.blm, (self.npix, self.Nblm) )
228 tom = np.reshape(self.tom, (self.npix, self.Ntom) )
229 gm = np.reshape(self.gm, (self.npix, self.Ngm) )
230
231 for pixel in range( self.npix ):
232 # rotate the pixel baseline mean to the Data startCell
233 blm_pixel = np.roll( blm[pixel,:], -self.start_cells[pixel] )
234 # rotate the pixel gain mean to the Data startCell
235 gm_pixel = np.roll( gm[pixel,:], -self.start_cells[pixel] )
236 # the 'trigger offset mean' does not need to be rolled
237 # on the contrary, it seems there is an offset in the DRS data,
238 # which is related to its distance to the startCell, not to its
239 # distance to the beginning of the physical pipeline in the DRS chip
240 tom_pixel = tom[pixel,:]
241
242 acal_data[pixel,:] -= blm_pixel[0:self.nroi]
243 acal_data[pixel,:] -= tom_pixel[0:self.nroi]
244 acal_data[pixel,:] /= gm_pixel[0:self.nroi]
245
246 self.acal_data = acal_data * 1907.35
247
248 #print 'blm _pyfact', blm[0,0:20]
249 #t = np.roll( blm[0,:], -self.start_cells[0] )
250 #print 'blm _pyfact', t[0:20]
251 #print 'start_pyfact: ', self.start_cells[0]
252 #print 'acal _pyfact: ', self.acal_data[0,0:10]
253 #t = np.roll( gm[0,:], -self.start_cells[0] )
254 #print 'gm _pyfact: ', t[0:10]
255 self.user_action_calib( self.acal_data,
256 np.reshape(self.data, (self.npix, self.nroi) ), blm, tom, gm, self.start_cells, self.nroi)
257
258
259 def baseline_read_values(self, file, bsl_hist='bsl_sum/hplt_mean'):
260 """
261
262 open ROOT file with baseline histogram and read baseline values
263 file name of the root file
264 bsl_hist path to the histogram containing the basline values
265
266 """
267
268 try:
269 f = TFile(file)
270 except:
271 print 'Baseline data file could not be read: ', file
272 return
273
274 h = f.Get(bsl_hist)
275
276 for i in range(self.npix):
277 self.v_bsl[i] = h.GetBinContent(i+1)
278
279 f.Close()
280
281 def baseline_correct(self):
282 """ subtract baseline from the data
283
284 """
285
286 for pixel in range(self.npix):
287 self.acal_data[pixel,:] -= self.v_bsl[pixel]
288
289 def info(self):
290 """ print run information
291
292 """
293
294 print 'data file: ', data_file_name
295 print 'calib file: ', calib_file_name
296 print 'calibration file'
297 print 'N baseline_mean: ', self.Nblm
298 print 'N gain mean: ', self.Ngm
299 print 'N TriggeroffsetMean: ', self.Ntom
300
301# -----------------------------------------------------------------------------
302class fnames( object ):
303 """ organize file names of a FACT data run
304
305 """
306
307 def __init__(self, specifier = ['012', '023', '2011', '11', '24'],
308 rpath = '/scratch_nfs/res/bsl/',
309 zipped = True):
310 """
311 specifier : list of strings defined as:
312 [ 'DRS calibration file', 'Data file', 'YYYY', 'MM', 'DD']
313
314 rpath : directory path for the results; YYYYMMDD will be appended to rpath
315 zipped : use zipped (True) or unzipped (Data)
316
317 """
318
319 self.specifier = specifier
320 self.rpath = rpath
321 self.zipped = zipped
322
323 self.make( self.specifier, self.rpath, self.zipped )
324
325
326 def make( self, specifier, rpath, zipped ):
327 """ create (make) the filenames
328
329 names : dictionary of filenames, tags { 'data', 'drscal', 'results' }
330 data : name of the data file
331 drscal : name of the drs calibration file
332 results : radikal of file name(s) for results (to be completed by suffixes)
333 """
334
335 self.specifier = specifier
336
337 if zipped:
338 dpath = '/data00/fact-construction/raw/'
339 ext = '.fits.gz'
340 else:
341 dpath = '/data03/fact-construction/raw/'
342 ext = '.fits'
343
344 year = specifier[2]
345 month = specifier[3]
346 day = specifier[4]
347
348 yyyymmdd = year + month + day
349 dfile = specifier[1]
350 cfile = specifier[0]
351
352 rpath = rpath + yyyymmdd + '/'
353 self.rpath = rpath
354 self.names = {}
355
356 tmp = dpath + year + '/' + month + '/' + day + '/' + yyyymmdd + '_'
357 self.names['data'] = tmp + dfile + ext
358 self.names['drscal'] = tmp + cfile + '.drs' + ext
359 self.names['results'] = rpath + yyyymmdd + '_' + dfile + '_' + cfile
360
361 self.data = self.names['data']
362 self.drscal = self.names['drscal']
363 self.results = self.names['results']
364
365 def info( self ):
366 """ print complete filenames
367
368 """
369
370 print 'file names:'
371 print 'data: ', self.names['data']
372 print 'drs-cal: ', self.names['drscal']
373 print 'results: ', self.names['results']
374
375# end of class definition: fnames( object )
376
377def _test_iter( nevents ):
378 """ test for function __iter__ """
379
380 data_file_name = '/data00/fact-construction/raw/2011/11/24/20111124_117.fits.gz'
381 calib_file_name = '/data00/fact-construction/raw/2011/11/24/20111124_114.drs.fits.gz'
382# data_file_name = '/home/luster/win7/FACT/data/raw/20120114/20120114_028.fits.gz'
383# calib_file_name = '/home/luster/win7/FACT/data/raw/20120114/20120114_022.drs.fits.gz'
384 run = RawData( data_file_name, calib_file_name , return_dict=True)
385
386 for event in run:
387 print 'ev ', event['event_id'], 'data[0,0] = ', event['acal_data'][0,0], 'start_cell[0] = ', event['start_cell'][0], 'trigger type = ', event['trigger_type']
388 if run.event_id.value == nevents:
389 break
390
391if __name__ == '__main__':
392 """ tests """
393
394 _test_iter(10)
Note: See TracBrowser for help on using the repository browser.