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

Last change on this file since 13380 was 13380, checked in by neise, 13 years ago
new option in RawData.__init__() one can set do_calibration=False. and the amplitude calibration comes without np.roll() ... thx to TPK for the idea
  • Property svn:executable set to *
File size: 14.5 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 do_calibration = True):
87 """ initialize object
88
89 open data file and calibration data file
90 get basic information about the data in data_file_name
91 allocate buffers for data access
92
93 data_file_name : fits or fits.gz file of the data including the path
94 calib_file_name : fits or fits.gz file containing DRS calibration data
95 baseline_file_name : npy file containing the baseline values
96 """
97 self.__module__='pyfact'
98 # manual implementation of default value, but I need to find out
99 # if the user of this class is aware of the new option
100 if return_dict == None:
101 print 'Warning: Rawdata.__init__() has a new option "return_dict"'
102 print 'the default value of this option is False, so nothing changes for you at the moment.'
103 print
104 print 'you probably want, to get a dictionary out of the next() method anyway'
105 print ' so please change your scripts and set this option to True, for the moment'
106 print 'e.g. like this: run = RawData(data_filename, calib_filename, return_dict = True)'
107 print "after a while, the default value, will turn to True .. so you don't have to give the option anymore"
108 print 'and some time later, the option will not be supported anymore'
109 return_dict = False
110 self.return_dict = return_dict
111
112 self.do_calibration = do_calibration
113
114 self.data_file_name = data_file_name
115 self.calib_file_name = calib_file_name
116 self.baseline_file_name = baseline_file_name
117
118 self.user_action_calib = user_action_calib
119
120 # baseline correction: True / False
121 if len(baseline_file_name) == 0:
122 self.correct_baseline = False
123 else:
124 self.correct_baseline = True
125
126 # access data file
127 try:
128 data_file = fits(self.data_file_name)
129 except IOError:
130 print 'problem accessing data file: ', data_file_name
131 raise # stop ! no data
132 #: data file (fits object)
133 self.data_file = data_file
134
135 # get basic information about the data file
136 #: region of interest (number of DRS slices read)
137 self.nroi = data_file.GetUInt('NROI')
138 #: number of pixels (should be 1440)
139 self.npix = data_file.GetUInt('NPIX')
140 #: number of events in the data run
141 self.nevents = data_file.GetNumRows()
142
143 # allocate the data memories
144 self.event_id = c_ulong()
145 self.trigger_type = c_ushort()
146 #: 1D array with raw data
147 self.data = np.zeros( self.npix * self.nroi, np.int16 )
148 #: slice where drs readout started
149 self.start_cells = np.zeros( self.npix, np.int16 )
150 #: time when the FAD was triggered, in some strange units...
151 self.board_times = np.zeros( 40, np.int32 )
152
153 # set the pointers to the data++
154 data_file.SetPtrAddress('EventNum', self.event_id)
155 data_file.SetPtrAddress('TriggerType', self.trigger_type)
156 data_file.SetPtrAddress('StartCellData', self.start_cells)
157 data_file.SetPtrAddress('Data', self.data)
158 data_file.SetPtrAddress('BoardTime', self.board_times)
159
160 # open the calibration file
161 try:
162 calib_file = fits(self.calib_file_name)
163 except IOError:
164 print 'problem accessing calibration file: ', calib_file_name
165 raise
166 #: drs calibration file
167 self.calib_file = calib_file
168
169 baseline_mean = calib_file.GetN('BaselineMean')
170 gain_mean = calib_file.GetN('GainMean')
171 trigger_offset_mean = calib_file.GetN('TriggerOffsetMean')
172
173 self.blm = np.zeros(baseline_mean, np.float32)
174 self.gm = np.zeros(gain_mean, np.float32)
175 self.tom = np.zeros(trigger_offset_mean, np.float32)
176
177 self.Nblm = baseline_mean / self.npix
178 self.Ngm = gain_mean / self.npix
179 self.Ntom = trigger_offset_mean / self.npix
180
181 calib_file.SetPtrAddress('BaselineMean', self.blm)
182 calib_file.SetPtrAddress('GainMean', self.gm)
183 calib_file.SetPtrAddress('TriggerOffsetMean', self.tom)
184 calib_file.GetRow(0)
185
186 self.v_bsl = np.zeros(self.npix) # array of baseline values (all ZERO)
187
188 def __iter__(self):
189 """ iterator """
190 return self
191
192 def __add__(self, jump_over):
193 self.data_file.GetRow(jump_over)
194 return self
195
196 def next(self):
197 """ used by __iter__ """
198
199 if self.data_file.GetNextRow() == False:
200 raise StopIteration
201 else:
202 if self.do_calibration == True:
203 self.calibrate_drs_amplitude()
204
205 #print 'nevents = ', self.nevents, 'event_id = ', self.event_id.value
206 if self.return_dict:
207 return self.__dict__
208 else:
209 return self.acal_data, self.start_cells, self.trigger_type.value
210
211 def next_event(self):
212 """ load the next event from disk and calibrate it
213
214 """
215
216 self.data_file.GetNextRow()
217 self.calibrate_drs_amplitude()
218
219 def calibrate_drs_amplitude(self):
220 """ perform the drs amplitude calibration of the event data
221
222 """
223
224 to_mV = 2000./4096.
225 #: 2D array with amplitude calibrated dat in mV
226 acal_data = self.data * to_mV # convert ADC counts to mV
227
228 # make 2D arrays: row = pixel, col = drs_slice
229 acal_data = np.reshape(acal_data, (self.npix, self.nroi) )
230 blm = np.reshape(self.blm, (self.npix, self.Nblm) )
231 tom = np.reshape(self.tom, (self.npix, self.Ntom) )
232 gm = np.reshape(self.gm, (self.npix, self.Ngm) )
233
234 # double the calibration constants
235 blm = np.hstack((blm,blm))
236 gm = np.hstack((gm,gm))
237
238 for pixel in range( self.npix ):
239 # rotate the pixel baseline mean to the Data startCell
240 #blm_pixel = np.roll( blm[pixel,:], -self.start_cells[pixel] )
241 blm_pixel = blm[pixel, self.start_cells[pixel]:self.start_cells[pixel]+self.nroi]
242 # rotate the pixel gain mean to the Data startCell
243 #gm_pixel = np.roll( gm[pixel,:], -self.start_cells[pixel] )
244 gm_pixel = gm[pixel, self.start_cells[pixel]:self.start_cells[pixel]+self.nroi]
245 # the 'trigger offset mean' does not need to be rolled
246 # on the contrary, it seems there is an offset in the DRS data,
247 # which is related to its distance to the startCell, not to its
248 # distance to the beginning of the physical pipeline in the DRS chip
249 tom_pixel = tom[pixel,0:self.nroi ]
250
251 acal_data[pixel,:] -= blm_pixel
252 acal_data[pixel,:] -= tom_pixel
253 acal_data[pixel,:] /= gm_pixel
254
255 self.acal_data = acal_data * 1907.35
256
257 #print 'blm _pyfact', blm[0,0:20]
258 #t = np.roll( blm[0,:], -self.start_cells[0] )
259 #print 'blm _pyfact', t[0:20]
260 #print 'start_pyfact: ', self.start_cells[0]
261 #print 'acal _pyfact: ', self.acal_data[0,0:10]
262 #t = np.roll( gm[0,:], -self.start_cells[0] )
263 #print 'gm _pyfact: ', t[0:10]
264 self.user_action_calib( self.acal_data,
265 np.reshape(self.data, (self.npix, self.nroi) ), blm, tom, gm, self.start_cells, self.nroi)
266
267
268 def baseline_read_values(self, file, bsl_hist='bsl_sum/hplt_mean'):
269 """
270
271 open ROOT file with baseline histogram and read baseline values
272 file name of the root file
273 bsl_hist path to the histogram containing the basline values
274
275 """
276
277 try:
278 f = TFile(file)
279 except:
280 print 'Baseline data file could not be read: ', file
281 return
282
283 h = f.Get(bsl_hist)
284
285 for i in range(self.npix):
286 self.v_bsl[i] = h.GetBinContent(i+1)
287
288 f.Close()
289
290 def baseline_correct(self):
291 """ subtract baseline from the data
292
293 """
294
295 for pixel in range(self.npix):
296 self.acal_data[pixel,:] -= self.v_bsl[pixel]
297
298 def info(self):
299 """ print run information
300
301 """
302
303 print 'data file: ', data_file_name
304 print 'calib file: ', calib_file_name
305 print 'calibration file'
306 print 'N baseline_mean: ', self.Nblm
307 print 'N gain mean: ', self.Ngm
308 print 'N TriggeroffsetMean: ', self.Ntom
309
310# -----------------------------------------------------------------------------
311class fnames( object ):
312 """ organize file names of a FACT data run
313
314 """
315
316 def __init__(self, specifier = ['012', '023', '2011', '11', '24'],
317 rpath = '/scratch_nfs/res/bsl/',
318 zipped = True):
319 """
320 specifier : list of strings defined as:
321 [ 'DRS calibration file', 'Data file', 'YYYY', 'MM', 'DD']
322
323 rpath : directory path for the results; YYYYMMDD will be appended to rpath
324 zipped : use zipped (True) or unzipped (Data)
325
326 """
327
328 self.specifier = specifier
329 self.rpath = rpath
330 self.zipped = zipped
331
332 self.make( self.specifier, self.rpath, self.zipped )
333
334
335 def make( self, specifier, rpath, zipped ):
336 """ create (make) the filenames
337
338 names : dictionary of filenames, tags { 'data', 'drscal', 'results' }
339 data : name of the data file
340 drscal : name of the drs calibration file
341 results : radikal of file name(s) for results (to be completed by suffixes)
342 """
343
344 self.specifier = specifier
345
346 if zipped:
347 dpath = '/data00/fact-construction/raw/'
348 ext = '.fits.gz'
349 else:
350 dpath = '/data03/fact-construction/raw/'
351 ext = '.fits'
352
353 year = specifier[2]
354 month = specifier[3]
355 day = specifier[4]
356
357 yyyymmdd = year + month + day
358 dfile = specifier[1]
359 cfile = specifier[0]
360
361 rpath = rpath + yyyymmdd + '/'
362 self.rpath = rpath
363 self.names = {}
364
365 tmp = dpath + year + '/' + month + '/' + day + '/' + yyyymmdd + '_'
366 self.names['data'] = tmp + dfile + ext
367 self.names['drscal'] = tmp + cfile + '.drs' + ext
368 self.names['results'] = rpath + yyyymmdd + '_' + dfile + '_' + cfile
369
370 self.data = self.names['data']
371 self.drscal = self.names['drscal']
372 self.results = self.names['results']
373
374 def info( self ):
375 """ print complete filenames
376
377 """
378
379 print 'file names:'
380 print 'data: ', self.names['data']
381 print 'drs-cal: ', self.names['drscal']
382 print 'results: ', self.names['results']
383
384# end of class definition: fnames( object )
385
386def _test_iter( nevents ):
387 """ test for function __iter__ """
388
389 data_file_name = '/data00/fact-construction/raw/2011/11/24/20111124_117.fits.gz'
390 calib_file_name = '/data00/fact-construction/raw/2011/11/24/20111124_114.drs.fits.gz'
391# data_file_name = '/home/luster/win7/FACT/data/raw/20120114/20120114_028.fits.gz'
392# calib_file_name = '/home/luster/win7/FACT/data/raw/20120114/20120114_022.drs.fits.gz'
393 run = RawData( data_file_name, calib_file_name , return_dict=True)
394
395 for event in run:
396 print 'ev ', event['event_id'].value, 'data[0,0] = ', event['acal_data'][0,0], 'start_cell[0] = ', event['start_cells'][0], 'trigger type = ', event['trigger_type']
397 if run.event_id.value == nevents:
398 break
399
400if __name__ == '__main__':
401 """ tests """
402
403 _test_iter(10)
Note: See TracBrowser for help on using the repository browser.