~vpec/maus/tof_calib_read

« back to all changes in this revision

Viewing changes to workers/Laser/Stability.py

  • Committer: tunnell
  • Date: 2010-09-20 10:52:02 UTC
  • Revision ID: tunnell@itchy-20100920105202-ce4w9jm59zvgnsxq
moving stuff from tucs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Author: Sebastien Viret <viret@in2p3.fr>
 
2
# Python Porter: Christopher Tunnell <tunnell@hep.uchicago.edu>  
 
3
#
 
4
# April 20, 2009
 
5
#
 
6
# This macro compares two LASER runs and plots a variation map
 
7
#
 
8
 
 
9
 
 
10
from src.GenericWorker import *
 
11
from src.region import *
 
12
from array import *
 
13
import ROOT
 
14
import math
 
15
 
 
16
class Stability(GenericWorker):
 
17
    "This worker computes the stability of laser constants between two runs"
 
18
 
 
19
    run_type     = None
 
20
    referenceRun = None
 
21
    mainRun      = None
 
22
 
 
23
    # make this runs eventually
 
24
    def __init__(self, run_type, referenceRun, mainRun):
 
25
        self.run_type     = run_type
 
26
        self.referenceRun = referenceRun
 
27
        self.mainRun      = mainRun
 
28
 
 
29
 
 
30
    # Get the channel position (SV: how to get that from region.py???)
 
31
    def GetNumber(self, hash):
 
32
        split = hash.split('_')[1:]
 
33
        number = []
 
34
        if len(split) >= 1:
 
35
            if   split[0] == 'LBA': number.append(1)
 
36
            elif split[0] == 'LBC': number.append(2)
 
37
            elif split[0] == 'EBA': number.append(3)
 
38
            elif split[0] == 'EBC': number.append(4)
 
39
            else:
 
40
                number.append(-1)
 
41
        if len(split) >= 2:
 
42
            number.append(int(split[1][1:]))
 
43
        if len(split) >= 3:
 
44
            number.append(int(split[2][1:]))
 
45
        if len(split) >= 4:
 
46
            if   split[3] == 'lowgain':  number.append(0)
 
47
            elif split[3] == 'highgain': number.append(1)
 
48
            else:
 
49
                number.append(-1)
 
50
 
 
51
        return number
 
52
 
 
53
 
 
54
    # Reorder the PMTs (SV: how to get that from region.py???)
 
55
    
 
56
    def get_PMT_index(self,part,j):
 
57
    
 
58
        chan2PMT_LB=[1,2,3,4,5,6,7,8,9,10,
 
59
                     11,12,13,14,15,16,17,18,19,20,
 
60
                     21,22,23,24,27,26,25,30,29,28,
 
61
                     -33,-32,31,36,35,34,39,38,37,42,41,
 
62
                     40,45,-44,43,48,47,46]
 
63
        
 
64
        chan2PMT_EB=[1,2,3,4,5,6,7,8,9,10,
 
65
                     11,12,13,14,15,16,17,18,-19,-20,
 
66
                     21,22,23,24,-25,-26,-27,-28,-31,-32,
 
67
                     33,29,30,-35,-36,34,44,38,37,43,42,
 
68
                     41,-39,-40,-45,-46,-47,-48]
 
69
    
 
70
        if part <= 1: 
 
71
            chan = chan2PMT_LB[j]-1
 
72
        else:
 
73
            chan = chan2PMT_EB[j]-1
 
74
    
 
75
        return chan
 
76
    
 
77
    # Macro necessary for the fiber re-ordering
 
78
    def get_index(self, part, module, channel):
 
79
        
 
80
        if part <= 1: 
 
81
            return  2*module+part+2*(0.5-part)*(channel%2)        
 
82
        else: 
 
83
            return  2*module+(channel%2)        
 
84
 
 
85
    # Also for fiber stuff
 
86
    def get_part(self, part):
 
87
        if part <= 1: 
 
88
            return  0
 
89
        else: 
 
90
            return  part-1
 
91
 
 
92
        
 
93
    def ProcessRegion(self, region):
 
94
 
 
95
        events = set()
 
96
 
 
97
        # This macro just works for TileCal
 
98
         
 
99
        if 'TILECAL' == region.GetHash():
 
100
 
 
101
            events = set()
 
102
 
 
103
            # First got all the LASER events
 
104
 
 
105
            for event in region.RecursiveGetEvents(): 
 
106
                if event.runType == self.run_type: # Just collect the LASER stuff 
 
107
                    events.add(event)
 
108
                 
 
109
            # Only process events we should, but we return main_events + other_events + reference
 
110
            main_events = set()
 
111
            reference_events = set()
 
112
            other_events = set()
 
113
 
 
114
            channel_s_brut    = ROOT.TH2F("channels variation map","",128,0.,128.,96,0.,96.)
 
115
            channel_s_brut1   = ROOT.TH1F("variation summary","",200,-2.,2.)
 
116
             
 
117
            # Initialization of variables
 
118
             
 
119
            n_channels_tot = 9856 # Total number of LASER channels (per gain)
 
120
            n_evts = 1000         # Minimum number of events recorded for a channel
 
121
            n_sig  = 2            # How many sigmas do we tolerate for filter correction (for outlier rejection ONLY) ?
 
122
            n_sig2 = 2            # How many sigmas do we tolerate for fiber correction (for outlier rejection ONLY) ?
 
123
            
 
124
            isBadLimit = 20       # Variation which put the channel automatically bad, after filter correction tough
 
125
            isProblem  = 2        # Maximum accpeted variation (after all corrections)
 
126
            
 
127
            # Reference values 
 
128
            
 
129
            rat_ref   = [0 for x in range(12288)]
 
130
            
 
131
            # Partition shifts 
 
132
            
 
133
            n_FIL     = [0 for x in range(4)]
 
134
            e_FIL     = [0 for x in range(4)]
 
135
            e_FIL_n   = [0 for x in range(4)]        
 
136
            sig_FIL   = [0 for x in range(4)]
 
137
            sig_FIL_n = [100000 for x in range(4)]
 
138
            
 
139
            # Patch panel fibers shifts
 
140
            
 
141
            n_FIB     = [0 for x in range(384)]
 
142
            e_FIB     = [0 for x in range(384)]
 
143
            e_FIB_n   = [0 for x in range(384)]        
 
144
            sig_FIB   = [0 for x in range(384)]
 
145
            sig_FIB_n = [100000 for x in range(384)]
 
146
            
 
147
            m_gain = 0   #  Low gain by default
 
148
            
 
149
            
 
150
            # Start by getting the variation 
 
151
            
 
152
            n_channels =  0
 
153
            
 
154
            to_remove = set()
 
155
 
 
156
            filter_main = 0
 
157
            filter_ref  = 0
 
158
            amp_ref     = 0
 
159
            amp_main    = 0            
 
160
            
 
161
            for event in events:                
 
162
                if event.runNumber == self.mainRun:
 
163
                    [p, i, j, w] = self.GetNumber(event.data['region'])
 
164
                    if self.get_PMT_index(p-1,j) >= 0: # a good channel    
 
165
                        main_events.add(event)
 
166
                        filter_main = event.data['wheelpos']
 
167
                        amp_main    = event.data['requamp']
 
168
                elif event.runNumber == self.referenceRun:
 
169
                    [p, i, j, w] = self.GetNumber(event.data['region'])
 
170
                    if self.get_PMT_index(p-1,j) >= 0: # a good channel
 
171
                        index = 3072*(p-1) + 48*(i-1) + j
 
172
                        rat_ref[index] = event.data['calib_const']
 
173
                        filter_ref = event.data['wheelpos']
 
174
                        amp_ref    = event.data['requamp']
 
175
                else:
 
176
                    other_events.add(event) # las   
 
177
 
 
178
            #print filter_ref
 
179
            #print amp_ref
 
180
 
 
181
            # Sanity check
 
182
 
 
183
            if filter_main != filter_ref or amp_main != amp_ref:
 
184
                print 'Run don\'t have the same characteristics: abort!'
 
185
                return
 
186
 
 
187
            # Then compute the variation w.r.t. the reference run
 
188
            for event in main_events:
 
189
                [p, i, j, w] = self.GetNumber(event.data['region'])
 
190
                index = 3072*(p-1) + 48*(i-1) + j       
 
191
                if rat_ref[index] == 0: # No reference data, skip the event
 
192
                    to_remove.add(event)
 
193
                    continue
 
194
 
 
195
                event.data['variation'] = 200*(event.data['calib_const']-rat_ref[index])/(event.data['calib_const']+rat_ref[index])
 
196
                n_channels = n_channels + 1
 
197
 
 
198
            main_events = main_events - to_remove
 
199
             
 
200
        #################################################
 
201
        ##
 
202
        ## LOOP 1 : run over all the channels just to
 
203
        ##          get the overall variation due to the 
 
204
        ##          filter wheel (one per partition)
 
205
        ##     
 
206
        ##          We do a certain number of iterations here
 
207
        ##
 
208
        #################################################
 
209
 
 
210
 
 
211
            for iter in range(4): # Iteration
 
212
            
 
213
                n_FIL   = [0 for x in range(4)]
 
214
                e_FIL   = [0 for x in range(4)]
 
215
                sig_FIL = [0 for x in range(4)]
 
216
            
 
217
                for event in main_events:
 
218
                
 
219
                    [part_num, i, j, w] = self.GetNumber(event.data['region'])
 
220
                    part_num -= 1
 
221
 
 
222
                    var      = event.data['variation'] - e_FIL_n[part_num]  
 
223
               
 
224
                    # Outlier removal
 
225
                    if iter>0 and math.fabs(var)>isBadLimit:
 
226
                        continue
 
227
 
 
228
                    if math.fabs(var) < n_sig*sig_FIL_n[part_num]:
 
229
                        n_FIL[part_num] += 1
 
230
                        e_FIL[part_num] += var
 
231
                
 
232
 
 
233
                for i in range(4):
 
234
                    if n_FIL[i] != 0:
 
235
                        e_FIL[i] /= n_FIL[i]
 
236
                        
 
237
                for event in main_events:
 
238
                
 
239
                    [part_num, i, j, w] = self.GetNumber(event.data['region'])
 
240
                    part_num -= 1
 
241
                
 
242
                    var      = event.data['variation'] - e_FIL[part_num] - e_FIL_n[part_num]
 
243
 
 
244
                    if iter>0 and math.fabs(var)>isBadLimit:
 
245
                        continue 
 
246
 
 
247
                    if math.fabs(var) < n_sig*sig_FIL_n[part_num]:
 
248
                        sig_FIL[part_num] += var*var
 
249
 
 
250
                #print
 
251
                #print
 
252
                #print n_channels, '/', n_channels_tot, ' channels are initially considered'
 
253
                #print
 
254
                    
 
255
                for i in range(4):
 
256
                    if n_FIL[i] > 1:
 
257
                        sig_FIL_n[i] = math.sqrt(sig_FIL[i]/(n_FIL[i]-1))
 
258
                        e_FIL_n[i]  += e_FIL[i]
 
259
#                        print 'Filter wheel is introducing a global ', e_FIL_n[i], '+/-', sig_FIL_n[i], '% shift in partition ', i
 
260
 
 
261
 
 
262
        #################################################
 
263
        ##
 
264
        ##
 
265
        ## LOOP 2 : now we will start to tackle the PP fibers
 
266
        ##          discrepancies. We collect the mean calibration
 
267
        ##          value for all the fibers, corrected from the global shift
 
268
        ##          Once again we will need to do some outlier removal. So we compute the 
 
269
        ##          sigma for all the fibers, and perform some iterations
 
270
        ##
 
271
        #################################################
 
272
 
 
273
 
 
274
            for iter in range(4): # Iteration
 
275
            
 
276
                n_FIB   = [0 for x in range(384)]
 
277
                e_FIB   = [0 for x in range(384)]
 
278
                sig_FIB = [0 for x in range(384)]
 
279
            
 
280
                for event in main_events:
 
281
                
 
282
                    [part_num, i, j, w] = self.GetNumber(event.data['region'])
 
283
                    part_num -= 1
 
284
                    j = self.get_PMT_index(part_num,j)      
 
285
                    
 
286
                    index    = self.get_index(part_num,i-1,j)
 
287
                    part     = self.get_part(part_num)
 
288
                    indice   = int(128*part+index)
 
289
 
 
290
                    var      = event.data['variation'] - e_FIL_n[part_num]
 
291
                     
 
292
                    if (math.fabs(var) > isBadLimit):
 
293
                        continue
 
294
 
 
295
                    var      = var - e_FIB_n[indice]
 
296
 
 
297
                    # Outlier removal
 
298
                    if math.fabs(var) < n_sig2*sig_FIB_n[indice]:
 
299
                        n_FIB[indice] += 1
 
300
                        e_FIB[indice] += var
 
301
                
 
302
 
 
303
                for i in range(384):
 
304
                    if n_FIB[i] != 0:
 
305
                        e_FIB[i] /= n_FIB[i]
 
306
                    
 
307
                for event in main_events:
 
308
 
 
309
                    [part_num, i, j, w] = self.GetNumber(event.data['region'])
 
310
                    #[part_num, i, j, w] = event.region.GetNumber()
 
311
                    part_num -= 1
 
312
                    j = self.get_PMT_index(part_num,j)                 
 
313
                
 
314
                    index    = self.get_index(part_num,i-1,j)
 
315
                    part     = self.get_part(part_num)
 
316
                    indice   = int(128*part+index)
 
317
                     
 
318
                    var      = event.data['variation'] - e_FIL_n[part_num]
 
319
                     
 
320
                    if (math.fabs(var) > isBadLimit):
 
321
                        continue
 
322
                     
 
323
                    var      = var - e_FIB_n[indice]
 
324
                
 
325
                    if math.fabs(var) < n_sig2*sig_FIB_n[indice]:
 
326
                        sig_FIB[indice] += var*var
 
327
                    
 
328
                for i in range(384):
 
329
                    if n_FIB[i] > 1:
 
330
                        sig_FIB_n[i] = math.sqrt(sig_FIB[i]/(n_FIB[i]-1))
 
331
                        e_FIB_n[i]  += e_FIB[i]
 
332
 
 
333
#            print 'Filter wheel is introducing a global ', e_FIL_n[0], '+/-', sig_FIL_n[0], '% shift '
 
334
 #           print 'Fiber is introducing a global ', e_FIB_n[0], '+/-', sig_FIB_n[0], '% shift '
 
335
 
 
336
        #################################################
 
337
        ##
 
338
        ##
 
339
        ## LOOP 3 : get the final comparison, removing the 
 
340
        ##          fiber correction
 
341
        ##
 
342
        #################################################
 
343
 
 
344
            for event in main_events:
 
345
 
 
346
                [part_num, i, j, w] = self.GetNumber(event.data['region'])                
 
347
                part_num -= 1
 
348
                j = self.get_PMT_index(part_num,j)         
 
349
                 
 
350
                index    = self.get_index(part_num,i-1,j)
 
351
                part     = self.get_part(part_num)
 
352
                indice   = int(128*part+index)
 
353
                
 
354
                var      = event.data['variation'] - e_FIL_n[part_num] - e_FIB_n[indice]
 
355
                
 
356
                channel_s_brut.Fill(i-0.5+64*(part_num%2),j+0.5+48*((part_num/2)%2),var)  
 
357
                channel_s_brut1.Fill(var)    
 
358
                
 
359
 
 
360
       ## Then do the cosmetics
 
361
                
 
362
        ##### STAT ######  #TODO! DO NOT ACCESS gStyle directly!  Hurts everybody else.  fixme
 
363
            ROOT.gStyle.SetStatW(0.2)
 
364
            ROOT.gStyle.SetStatH(0.2)
 
365
            ROOT.gStyle.SetStatX(0.8)
 
366
            ROOT.gStyle.SetStatY(0.8)
 
367
            ROOT.gStyle.SetStatFont(42)
 
368
            ROOT.gStyle.SetOptStat(0)
 
369
            ROOT.gStyle.SetOptFit(0)
 
370
        ##################
 
371
             
 
372
            # Colored Gradient                                                                                                                                                                                              
 
373
            Number = 5;
 
374
            
 
375
            Red = [ 1.0, 1.0, 1.0, 1.0, 0.0 ] 
 
376
            Green = [ 1.0, 1.0, 0.6, 0.0, 0.0 ] 
 
377
            Blue  = [ 1.0, 0.0, 0.1, 0.0, 0.0 ] 
 
378
            
 
379
            # Define the length of the (color)-interval between this points                                                                                                                                                 
 
380
            Length = [ 0.00, 0.25, 0.5, 0.75, 1.00 ]
 
381
            
 
382
            ROOT.TColor.CreateGradientColorTable(Number, array('d', Length), array('d', Red),
 
383
                                                 array('d', Green), array('d', Blue), 300);
 
384
            
 
385
            c1 = ROOT.TCanvas("c1","Filter+fiber correction",200,200,1000,700)
 
386
            c1.SetFillColor(0);
 
387
            c1.SetBorderMode(0)
 
388
            c1.Divide(1,2)
 
389
            
 
390
            c1.cd(1)
 
391
            channel_s_brut.GetXaxis().SetTitle("Module number")
 
392
            channel_s_brut.GetYaxis().SetTitle("Channel number")
 
393
            channel_s_brut.Draw("colz")
 
394
            pt = ROOT.TPaveText(20.,95.,110.,105.,"br")
 
395
            pt.SetTextSize(0.05)
 
396
            
 
397
            filename = "Diff. bet. runs %d and %d : all partitions" % (self.mainRun, self.referenceRun)
 
398
            
 
399
            text = pt.AddText(filename);
 
400
            pt.Draw();
 
401
            
 
402
            c1.cd(2);
 
403
            
 
404
            filename = "Diff. bet. runs %d and %d : all partitions (in %%)" % (self.mainRun, self.referenceRun)
 
405
            
 
406
            channel_s_brut1.GetXaxis().SetTitle(filename)
 
407
            channel_s_brut1.Draw()
 
408
            
 
409
            c1.Update()
 
410
            c1.Print('plots/laser_comparison1.eps')
 
411
            
 
412
        return events
 
413