/search.css" rel="stylesheet" type="text/css"/> /search.js">
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

In This Package:

AmCTag.py
Go to the documentation of this file.
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)
| Classes | Job Modules | Data Objects | Services | Algorithms | Tools | Packages | Directories | Tracs |

Generated on Fri May 16 2014 10:10:08 for CalibrationTagging by doxygen 1.7.4