/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #!/usr/bin/env python 00002 ''' 00003 AmC Tagger 00004 Usage: 00005 nuwa.py --no-history -A "0.1*s" -n -1 -m"Quickstart.EH1Tables" -m"Quickstart.Calibrate" -m"Quickstart.CalculateCalibStats" -m"Quickstart.Reconstruct" -m"MuonTagging.MuonTagLoose" -m"CalibrationTagging.AmCTag" -o output.root input.root 00006 Help: 00007 nuwa.py -m"CalibrationTagging.AmCTag -h" 00008 00009 tsang@caltech.edu, 2011/08/22 00010 ''' 00011 00012 from UserTagging.UserTaggingAlg import UserTaggingAlg 00013 from GaudiPython import SUCCESS, FAILURE 00014 from GaudiPython import gbl 00015 import GaudiKernel.SystemOfUnits as units 00016 import math 00017 00018 # =========================================== 00019 class AmCTag(UserTaggingAlg): 00020 'Coincidence Tagger for AD events' 00021 00022 def __init__(self, name): 00023 UserTaggingAlg.__init__(self, name) 00024 00025 self.dTCut = 200*units.microsecond 00026 self.vertexCut = 1*units.meter 00027 self.ratioQCut = 0.25 00028 self.location = "/Event/Rec/AdSimple" 00029 self.muonVetoTime = 1000*units.microsecond 00030 self.adMuonEnergyCut = 20*units.MeV 00031 self.promptLowCut = 0.5*units.MeV 00032 self.promptHighCut = 2.0*units.MeV 00033 self.delayedLowCut = 6.5*units.MeV 00034 self.delayedHighCut = 9.5*units.MeV 00035 self.timeWindowLow = -1640 #ns 00036 self.timeWindowHigh = -1450 #ns 00037 self.tRmsCut = 30 00038 00039 # ------------------------------------------- 00040 def initTagList(self): 00041 self.detId = [ 00042 gbl.DetectorId.kAD1, 00043 gbl.DetectorId.kAD2, 00044 gbl.DetectorId.kAD3, 00045 gbl.DetectorId.kAD4] 00046 self.inputHeaders = {} 00047 self.lastTriggerTime = {} # dict 00048 self.lastPromptTime = {} # dict 00049 self.lastDelayedTime = {} # dict 00050 self.lastMuonTime = {} 00051 self.lastWasPrompt = {} 00052 self.stage = {} # 0: looking for prompt 00053 # 1: prompt found, looking for delayed 00054 # 2: delayed found, ensuring clearance 00055 # 3: pair found! 00056 self.freshStart = {} 00057 for id in self.detId: 00058 self.inputHeaders[id] = [] 00059 self.freshStart[id] = True 00060 self.lastWasPrompt[id] = False 00061 self.stage[id] = 0 00062 00063 self.addTag('AmC' , '/Event/Tag/Calib/AmC') 00064 return 00065 00066 # ------------------------------------------- 00067 def check(self, evt): 00068 print '='*80 00069 recHeader = evt['/Event/Rec/AdSimple'] 00070 if not recHeader: 00071 self.warning('Failed to get current recon header') 00072 return FAILURE 00073 00074 # Access the Calib Readout Header. 00075 # This is a container for calibrated data 00076 calibHdr = evt["/Event/CalibReadout/CalibReadoutHeader"] 00077 if calibHdr == None: 00078 self.error("Failed to get current calib readout header") 00079 return FAILURE 00080 00081 # Access the Readout. This is the calibrated data from one trigger. 00082 calibReadout = calibHdr.calibReadout() 00083 if calibReadout == None: 00084 self.error("Failed to get calibrated readout from header") 00085 return FAILURE 00086 00087 recResult = recHeader.recTrigger() 00088 triggerTime = recResult.triggerTime() 00089 detectorId = recHeader.context().GetDetId() 00090 00091 # Fresh start: assume first event is muon 00092 if not detectorId in self.lastMuonTime.keys(): #self.detId and self.freshStart[detectorId]: 00093 self.lastMuonTime[detectorId] = triggerTime 00094 self.lastTriggerTime[detectorId] = triggerTime 00095 self.freshStart[detectorId] = False 00096 print 'Fresh Start!',detectorId 00097 return SUCCESS 00098 00099 # Treat all non-AD triggers as muons 00100 if not detectorId in self.detId: 00101 # for id in self.detId: 00102 # self.lastMuonTime[id] = triggerTime 00103 # print 'Treat all non-AD triggers as muons.' 00104 print 'Ignore all non-AD triggers.' 00105 return SUCCESS 00106 00107 print triggerTime.AsString(), detectorId 00108 print 'Last trigger time:',self.lastTriggerTime[detectorId].AsString() 00109 print 'Last muon time:',self.lastMuonTime[detectorId].AsString() 00110 timeSinceMu = gbl.TimeStamp( recResult.triggerTime() ) 00111 timeSinceMu.Subtract(self.lastMuonTime[detectorId]) 00112 timeSinceTrig = gbl.TimeStamp( recResult.triggerTime() ) 00113 timeSinceTrig.Subtract(self.lastTriggerTime[detectorId]) 00114 00115 reject = False 00116 # Get Recon info 00117 recES = recResult.energyStatus() 00118 recE = recResult.energy() 00119 recPS = recResult.positionStatus() 00120 recX = recResult.position().x() 00121 recY = recResult.position().y() 00122 recZ = recResult.position().z() 00123 00124 # Fix for wrong energy scale 00125 recE *= 184./160. 00126 00127 # Ignore triggers with failed recon 00128 if not reject and recPS != 1: 00129 print 'Position recon failed. Trigger ignored' 00130 reject = True 00131 if not reject and recES != 1: 00132 print 'Energy recon failed. Trigger ignored' 00133 reject = True 00134 00135 # Calculate charge sum and other quantities 00136 maxQ = None 00137 sumQ = 0 00138 nChan = 0 00139 meanT = 0 00140 meanT2 = 0 00141 for channel in calibReadout.channelReadout(): 00142 q = 0 00143 for hitIdx in range( channel.size() ): 00144 hitTime = channel.time( hitIdx ) 00145 hitCharge = channel.charge( hitIdx ) 00146 if hitTime > self.timeWindowLow and hitTime < self.timeWindowHigh: 00147 nChan += 1 00148 q = hitCharge 00149 meanT += hitTime 00150 meanT2 += hitTime * hitTime 00151 break 00152 if not maxQ or maxQ < q: maxQ = q 00153 sumQ += q 00154 if sumQ != 0 and nChan > 0: 00155 ratioQ = maxQ/sumQ 00156 meanT /= nChan 00157 meanT2 /= nChan 00158 Trms = math.sqrt(meanT2-meanT*meanT) 00159 else: 00160 ratioQ = meanT = meanT2 = Trms = -1 00161 00162 # # Get ratio Max(Q)/Sum(Q) 00163 # #ratioMaxQ < 0.25 00164 # maxQ = None 00165 # sumQ = 0 00166 # for channel in calibReadout.channelReadout(): 00167 # q = 0 00168 # for hitIdx in range( channel.size() ): 00169 # hitTime = channel.time( hitIdx ) 00170 # hitCharge = channel.charge( hitIdx ) 00171 # if hitTime > -1640 and hitTime < -1450: 00172 # q = hitCharge 00173 # break 00174 # if not maxQ or maxQ < q: maxQ = q 00175 # sumQ += q 00176 # if sumQ != 0: 00177 # ratioQ = maxQ/sumQ 00178 # else: 00179 # ratioQ = 0 00180 00181 # # Max/Sum cut 00182 # if not reject and (ratioQ > self.ratioQCut or sumQ == 0): 00183 # print 'Max(Q)/Sum(Q)','=', ratioQ,'>', self.ratioQCut, '. Trigger ignored.' 00184 # reject = True 00185 00186 # Muon trigger? If so, start veto 00187 isMuon = False 00188 #isMuon = evt['/Event/Tag/Physics/MuonLoose'] 00189 if recE > self.adMuonEnergyCut: 00190 isMuon = True 00191 00192 if isMuon: 00193 print 'Loose Muon in',detectorId, '. Start veto:', self.muonVetoTime 00194 reject = True 00195 00196 # Muon veto 00197 if not reject: 00198 if timeSinceMu.GetSeconds() * units.second < self.muonVetoTime: 00199 print 'Muon veto on. Trigger ignored', detectorId 00200 reject = True 00201 00202 # Discard non-physics events 00203 if not reject and nChan == 0: 00204 print 'No hits selected in hit time window. Ignored.' 00205 reject = True 00206 if not reject and ratioQ > self.ratioQCut: 00207 print 'Max(Q)/Sum(Q)','=', ratioQ,'>', self.ratioQCut, '. Ignored.' 00208 reject = True 00209 if not reject and Trms > self.tRmsCut: 00210 print 'tRms =', Trms,'>',self.tRmsCut, '. Ignored.' 00211 reject = True 00212 00213 00214 # Energy cut for identifying prompt or delayed signal 00215 isPrompt = False 00216 isDelayed = False 00217 if not reject: 00218 if recE > self.promptLowCut and recE < self.promptHighCut: 00219 isPrompt = True 00220 print 'Prompt candidate' 00221 if recE > self.delayedLowCut and recE < self.delayedHighCut: 00222 if self.stage[detectorId] == 1: 00223 promptRecResult = self.inputHeaders[detectorId][0].recTrigger() 00224 pRecX = promptRecResult.position().x() 00225 pRecY = promptRecResult.position().y() 00226 pRecZ = promptRecResult.position().z() 00227 deltaX = (pRecX - recX) 00228 deltaY = (pRecY - recY) 00229 deltaZ = (pRecZ - recZ) 00230 deltaVertex2 = deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ 00231 if deltaVertex2 < self.vertexCut*self.vertexCut: 00232 isDelayed = True 00233 else: 00234 print 'rejected by vertex cut' 00235 else: 00236 isDelayed = True 00237 if isDelayed: print 'Delayed candidate' 00238 00239 # Timing coincidence 00240 print 'Stage', self.stage 00241 if reject: 00242 if self.stage[detectorId] == 1: 00243 self.stage[detectorId] = 0 00244 self.inputHeaders[detectorId] = [] 00245 print '1->0' 00246 else: 00247 # print 'Current trigger time:',triggerTime.AsString() 00248 # print 'Last trigger time:',self.lastTriggerTime[detectorId].AsString() 00249 # print 'Last muon time:',self.lastMuonTime[detectorId].AsString() 00250 print 'dT =', timeSinceTrig.GetSeconds(), 'second' 00251 # Stage 1->2/0 00252 if self.stage[detectorId] == 1: 00253 if isDelayed and timeSinceTrig.GetSeconds() * units.second < self.dTCut: 00254 self.inputHeaders[detectorId].append(recHeader) 00255 self.stage[detectorId] = 2 00256 print '1->2' 00257 else: 00258 self.stage[detectorId] = 0 00259 self.inputHeaders[detectorId] = [] 00260 print '1->0' 00261 # Stage 2->3/0 00262 elif self.stage[detectorId] == 2: 00263 if timeSinceTrig.GetSeconds() * units.second > self.dTCut: 00264 self.stage[detectorId] = 3 00265 print '2->3' 00266 # save tag 00267 myTag = self.getTag('AmC') 00268 print 'Length of self.inputheaders', len(self.inputHeaders[detectorId]) 00269 myTag.setInputHeaders(self.inputHeaders[detectorId]) 00270 myTag.tagIt() 00271 self.inputHeaders[detectorId] = [] 00272 self.stage[detectorId] = 0 00273 print 'Tag saved!' 00274 print '3->0' 00275 else: 00276 self.stage[detectorId] = 0 00277 self.inputHeaders[detectorId] = [] 00278 print '2->0' 00279 # Stage 0->1 00280 if isPrompt and self.stage[detectorId] == 0 and timeSinceTrig.GetSeconds() * units.second > self.dTCut: 00281 self.inputHeaders[detectorId].append(recHeader) 00282 self.stage[detectorId] = 1 00283 print '0->1' 00284 00285 00286 if isMuon: 00287 self.lastMuonTime[detectorId] = triggerTime 00288 self.lastTriggerTime[detectorId] = recResult.triggerTime() 00289 return SUCCESS 00290 00291 ##### Job Configuration for nuwa.py ######################################## 00292 options = None 00293 00294 def configure(argv=[]): 00295 """Configuration with command line arguments""" 00296 global options 00297 from optparse import OptionParser 00298 00299 parser = OptionParser() 00300 parser.add_option("-c", "--coincidence-dt", type="string", 00301 default="300*microsecond", 00302 help="AD coincidence time window") 00303 parser.add_option("-l", "--location", type="string", 00304 default="/Event/Rec/AdSimple", 00305 help="Target for AD coincidence tagging") 00306 (options, args) = parser.parse_args(args=argv) 00307 00308 def run(app): 00309 from DybPython.Tools import unitify 00310 00311 myAlg = AmCTag("AmCTag") 00312 myAlg.dTCut = unitify(options.coincidence_dt) 00313 myAlg.location = options.location 00314 app.addAlgorithm(myAlg)