Newer
Older
STAging / scripts / STLibrary / TTModules.py
#!/usr/bin/env python
"""
TTModules.py: retrieve TT module or half module from an LHCb::STChannelID integer or from a uniqueSectorName.

Modules are numbered per unique layer and region, starting from 0 at the largest x (rightest).
"""

__author__  = "Elena Graverini"
__email__   = "elena.graverini@cern.ch"
__version__ = "1.0"
__date__    = "18/12/2014"


import sys, os, pickle
from STChannelID import *



class TTModulesMap():
    """
    Module-wise map of the TT detector.

    Members:
    - numberOfModules: number of modules per layer / region
    - dictOfModules: module-wise dictionary of TTModules 
    - dictOfHalfModules: half-module-wise dictionary of TTModules 
    - findModule(id): find the module containing the given STChannelID
    - findSectorModule(name): find the module containing the given sector
    - findHalfModule(id): find the half module containing the given STChannelID
    - findSectorHalfModule(name): find the half module containing the given sector    
    """
    def __init__(self):
        self.numberOfModules = {   'TTaX': { 'RegionA': 6, 'RegionB': 3, 'RegionC': 6 },
                                   'TTaU': { 'RegionA': 6, 'RegionB': 3, 'RegionC': 6 },
                                   'TTbV': { 'RegionA': 6, 'RegionB': 5, 'RegionC': 6 },
                                   'TTbX': { 'RegionA': 6, 'RegionB': 5, 'RegionC': 6 }   }
        self.dictOfModules = {}
        self.dictOfHalfModules = {}
        for uniqueLayer in STNames_instance.TTuniqueLayers:
            self.dictOfModules[uniqueLayer] = {}
            self.dictOfHalfModules[uniqueLayer] = {}
            for region in STNames_instance.TTregions:
                self.dictOfModules[uniqueLayer]['Region'+region] = []
                self.dictOfHalfModules[uniqueLayer]['Region'+region] = {}
                nModules = self.numberOfModules[uniqueLayer]['Region'+region]
                for i in range(nModules):
                    nSectors = 4 # sectors per full module
                    if 'B' in region:
                        nSectors = 6 # sectors per full module
                    if ('TTb' in uniqueLayer) and ( (i==0) or (i==nModules-1) ):
                        nSectors = 4 # sectors per full module
                    id = uniqueLayer+'Region'+region+'Module'+str(i)
                    newModule = TTModule( id, nSectors, True, uniqueLayer, 'Region'+region )
                    self.dictOfModules[uniqueLayer]['Region'+region].append( newModule )
                    self.dictOfHalfModules[uniqueLayer]['Region'+region][i] = [newModule.topHalf, newModule.bottomHalf]
    #def find(inputData):
    #    if type(inputData) == str:
    #        return self.findByUniqueSector(inputData)
    #    elif 'STChannelID' in str(inputData.__class__):
    #        return self.findBySTChannelID(inputData)
    #    elif type(inputData) == int or type(inputData) == long:
    #        return self.findByChannelID(inputData)
    #    else:
    #        print 'TTModulesMap ERROR: could not understand input!'
    #        return False
    def findModule(self, id):
        ul = STNames_instance.uniqueLayerName(id)
        reg = STNames_instance.regionName(id)
        sector = int(id.sector)
        if sector == 0:
            print 'TTModulesMap ERROR: sector numbering starts from 0!!'
            sys.exit(0)
        if (reg != 'RegionB'):
            iModule = (sector-1)/4
        elif (reg == 'RegionB') and ('TTb' in ul):
            if sector<5:
                iModule = (sector-1)/4#%4
            if sector>22:
                iModule = 4
            if 5<=sector<=22:
                iModule = (sector-1-4)/6+1
        elif (reg == 'RegionB') and ('TTa' in ul):
            iModule = (sector-1)/6#%6
        #print iModule, sector, ul, reg
        return self.dictOfModules[ul][reg][iModule]
    def findSectorModule(self, uSectorName):
        uniqueLayer, region, sector = STNames_instance.locateTTSector(uSectorName)
        reg = 'Region'+region
        if sector == 0:
            print 'TTModulesMap ERROR: sector numbering starts from 0!!'
            sys.exit(0)
        if (reg != 'RegionB'):
            iModule = (sector-1)/4
        elif (reg == 'RegionB') and ('TTb' in uniqueLayer):
            if sector<5:
                iModule = (sector-1)/4#%4
            if sector>22:
                iModule = 4
            if 5<=sector<=22:
                iModule = (sector-1-4)/6+1
        elif (reg == 'RegionB') and ('TTa' in uniqueLayer):
            iModule = (sector-1)/6#%6
        #print iModule, sector, ul, reg
        return self.dictOfModules[uniqueLayer][reg][iModule]
    def findHalfModule(self, id):
        module = self.findModule(id)
        sector = int(id.sector)
        if 'B'in STNames_instance.regionName(id) and 'TTb' in STNames_instance.uniqueLayerName(id):
            if 4<sector<23:
                if (sector-1-4)%6 >= 3:
                    return module.topHalf
                else:
                    return module.bottomHalf
            elif sector<=4:
                if sector in [3,4]:
                    return module.topHalf
                else:
                    return module.bottomHalf
            elif sector>=23:
                if sector in [25,26]:
                    return module.topHalf
                else:
                    return module.bottomHalf
        elif 'B' in STNames_instance.regionName(id) and 'TTa' in STNames_instance.uniqueLayerName(id):
            if (sector-1)%6 >= 3:
                return module.topHalf
            else:
                return module.bottomHalf
        if (sector-1)%4 >= 2:
            return module.topHalf
        else:
            return module.bottomHalf
    def findSectorHalfModule(self, uSectorName):
        module = self.findSectorModule(uSectorName)
        uniqueLayer, region, sector = STNames_instance.locateTTSector(uSectorName)
        if 'B'in region and 'TTb' in uniqueLayer:
            if 4<sector<23:
                if (sector-1-4)%6 >= 3:
                    return module.topHalf
                else:
                    return module.bottomHalf
            elif sector<=4:
                if sector in [3,4]:
                    return module.topHalf
                else:
                    return module.bottomHalf
            elif sector>=23:
                if sector in [25,26]:
                    return module.topHalf
                else:
                    return module.bottomHalf    
        elif 'B' in region and 'TTa' in uniqueLayer:
            if (sector-1)%6 >= 3:
                return module.topHalf
            else:
                return module.bottomHalf
        if (sector-1)%4 >= 2:
            return module.topHalf
        else:
            return module.bottomHalf        


class TTModule():
    """
    Description of a TT module / half module.

    Members:
    - id (unique identifier)
    - moduleNumber (numbering restarts for every detector region)
    - nSectors (number of readout sectors)
    - parent (True if this is a full module, False if this is a half module)
    - uniqueLayer (unique layer identifier)
    - region (region identifier)
    - position (Top or Bottom for half modules, None for full modules)
    - topHalf, bottomHalf (half modules if this is a full module)
    - sectors (list of unique identifiers for sectors contained in this full or half module)
    """
    def __init__(self, id, nSectors=4, parent=True, uniqueLayer='TTaX', region='RegionB', position='Top'):
        self.id           = str(id)
        self.moduleNumber = int( self.id.split('Module')[-1].replace('b','').replace('t','') )
        self.nSectors     = nSectors
        self.parent       = parent
        self.uniqueLayer  = uniqueLayer
        self.region       = region
        self.position     = position
        # Assigning half modules
        if parent:
            self.topHalf    = TTModule(id=self.id+'t', nSectors=self.nSectors/2, parent=False, uniqueLayer=self.uniqueLayer, region=self.region, position='Top')
            self.bottomHalf = TTModule(id=self.id+'b', nSectors=self.nSectors/2, parent=False, uniqueLayer=self.uniqueLayer, region=self.region, position='Bottom')
            self.position   = None
        # Assigning sectors
        if not parent: nSectors = self.nSectors*2
        if 'B'in self.region and 'TTb' in self.uniqueLayer:
            if self.moduleNumber == 0:
                secNums = range(1,5)
            elif self.moduleNumber == 4:
                secNums = range(23,27)
            else: 
                secNums = [((self.moduleNumber-1)*nSectors + (i + 1 + 4)) for i in xrange(nSectors)]
        else:
            secNums = [((self.moduleNumber)*nSectors + (i + 1)) for i in xrange(nSectors)]
        if self.position == 'Top':
            self.sectors = [(self.uniqueLayer + self.region + 'Sector' + str(i)) for i in secNums[len(secNums)/2:]]
        elif self.position == 'Bottom':
            self.sectors = [(self.uniqueLayer + self.region + 'Sector' + str(i)) for i in secNums[:len(secNums)/2]]
        elif self.position == None:
            self.sectors = [(self.uniqueLayer + self.region + 'Sector' + str(i)) for i in secNums]


TTModulesMap_instance = TTModulesMap()


def dictOfTTChannelIDs(save=True):
    bits = STChannelID(0)
    d = {}
    for itype,typ in enumerate(('TT',)):
        for istation,station in enumerate(('a','b'), start=1):
            for ilayer,layer in enumerate( (("X", "U"), ("V", "X"))[istation-1], start=1 ):
                for iregion,region in enumerate(("C","B","A"), start=1):
                    for module in TTModulesMap_instance.dictOfModules['TT'+station+layer]['Region'+region]:
                        for halfmodule in TTModulesMap_instance.dictOfHalfModules['TT'+station+layer]['Region'+region][module.moduleNumber]:
                            secNums = [ int(it) for it in sectorsInHalfModule(halfmodule.id)[-1] ]
                            for sector in secNums:
                                for i in xrange(1,513):
                                    chanID = (  i 
                                                + (sector   << bits.sectorBits)
                                                + (iregion  << bits.detRegionBits)
                                                + (ilayer   << bits.layerBits)
                                                + (istation << bits.stationBits)
                                                + (itype    << bits.typeBits)        )
                                    d[chanID] = { 'type':typ, 'station':station, 'layer':layer, 'region':region,
                                                  'sector':sector, 'uniqueSector': 'TT%s%s'%(station,layer)+'Region%s'%region+'Sector%s'%sector,
                                                  'module':halfmodule.id.replace('t','').replace('b',''), 'hm':halfmodule.id }
    def write(d):
        pickle.dump(d, open('../Pickle/TTchIDlookupTable.pkl', 'wb'))
    #    
    if save:
        if os.path.isfile('../Pickle/TTchIDlookupTable.pkl'):
            yes = raw_input("dictOfTTChannelIDs WARNING: file ../Pickle/TTchIDlookupTable.pkl already exists! Overwrite? (yes or no)\n\t")
            if yes=='yes':
                write(d)
            else:
                print "Skipping."
        else:
            write(d)
    return d




def listOfTTHalfModules():
    """
    Flat list of unique half modules indentifiers.
    """
    hm = TTModulesMap_instance.dictOfHalfModules
    listOfHalfModules = []
    for ul in hm.keys():
        for reg in hm[ul].keys():
            for module in hm[ul][reg]:
                for halfmod in hm[ul][reg][module]:
                    listOfHalfModules.append(halfmod.id)
    return listOfHalfModules


def listOfOverlappingTTPairs():
    """
    Flat list of neighbouring TT half modules.
    """
    listOfHalfModules = listOfTTHalfModules()
    ttmap = TTModulesMap_instance
    pairs = []
    regions = {'A':1, 'B':2, 'C':3}
    print "Overlapping TT half modules:"
    for hm1 in listOfHalfModules:
        for hm2 in listOfHalfModules:
            # they must be different
            if hm1 == hm2: continue
            # they must be both on top or both on bottom
            if locateTTHalfModule(hm1)[3] != locateTTHalfModule(hm2)[3]: continue
            # they must be on the same layer
            if locateTTHalfModule(hm1)[0] != locateTTHalfModule(hm2)[0]: continue
            # avoid duplicates
            if (hm1, hm2) in pairs: continue
            if (hm2, hm1) in pairs: continue
            # they must be contiguous:
            if (locateTTHalfModule(hm1)[1] == locateTTHalfModule(hm2)[1]):
                if (abs(locateTTHalfModule(hm1)[2] - locateTTHalfModule(hm2)[2]) == 1):
                    pairs.append( (hm1, hm2) )
            else:
                num1 = locateTTHalfModule(hm1)[2]
                num2 = locateTTHalfModule(hm2)[2]
                max1 = ttmap.numberOfModules[locateTTHalfModule(hm1)[0]]['Region'+locateTTHalfModule(hm1)[1]] - 1
                max2 = ttmap.numberOfModules[locateTTHalfModule(hm2)[0]]['Region'+locateTTHalfModule(hm2)[1]] - 1
                nreg1 = regions[locateTTHalfModule(hm1)[1]]
                nreg2 = regions[locateTTHalfModule(hm2)[1]]
                if ( (num1==max1 and num2==0 and nreg2-nreg1==1) or (num2==max2 and num1==0 and nreg1-nreg2==1) ):
                    pairs.append( (hm1, hm2) )
                    print '\t', hm1, hm2
            ## - same region
            #if ((abs(locateTTHalfModule(hm1)[2] - locateTTHalfModule(hm2)[2]) != 1)
            #    and (locateTTHalfModule(hm1)[0] != locateTTHalfModule(hm2)[0])): continue
            ## - or neighbouring region
            #elif not ((locateTTHalfModule(hm1)[0] != locateTTHalfModule(hm2)[0])
            #    and ( ( (ttmap.numberOfModules[locateTTHalfModule(hm1)[0]] == locateTTHalfModule(hm1)[2]+1 )
            #            and (locateTTHalfModule(hm2)[2] == 0) )
            #        or ( (ttmap.numberOfModules[locateTTHalfModule(hm2)[0]] == locateTTHalfModule(hm2)[2]+1 )
            #             and (locateTTHalfModule(hm1)[2] == 0) ) ) ): continue
            ## append to list of pairs
            #pairs.append( (hm1, hm2) )
    print
    return pairs


def locateTTModule(moduleId):
    """
    Extract layer, region, module number and position from
    a unique half module identifier.
    """
    uLayer = moduleId.split('Region')[0]
    region, moduleNum = moduleId.split('Region')[1].split('Module')
    return uLayer, region, int(moduleNum)


def locateTTHalfModule(halfModuleId):
    """
    Extract layer, region, module number and position from
    a unique half module identifier.
    """
    position = halfModuleId[-1:]
    uLayer = halfModuleId.split('Region')[0]
    region, moduleNum = halfModuleId.split('Region')[1].split('Module')
    return uLayer, region, int(moduleNum[:-1]), position


def sectorsInModule(moduleId):
    """
    List of sectors and list of sector numbers belonging to a TT module.
    """
    uLayer, region, moduleNum = locateTTModule(moduleId)
    sectors = TTModulesMap_instance.dictOfModules[uLayer]['Region'+region][moduleNum].sectors
    sectorNumbers = [secName.split('Sector')[-1] for secName in sectors]
    return sectors, sectorNumbers


def sectorsInHalfModule(halfModuleId):
    """
    List of sectors and list of sector numbers belonging to a TT module.
    """
    uLayer, region, moduleNum, position = locateTTHalfModule(halfModuleId)
    index = 0
    if 'b' in position:
        index = 1
    sectors = TTModulesMap_instance.dictOfHalfModules[uLayer]['Region'+region][moduleNum][index].sectors
    sectorNumbers = [secName.split('Sector')[-1] for secName in sectors]
    return sectors, sectorNumbers


def elenaNamesToOlafNames(name):
    """
    Converts the name of a TT half module from Elena's alphabet to Olaf's alphabet

    * RegionA, RegionB, RegionC -> R3, R2, R1
    * Module#i -> Module#(i+1)

    """
    layer, region, num, position = locateTTHalfModule(name)
    reg = {'A': 'R3', 'B': 'R2', 'C':'R1'}
    return layer+'Layer'+reg[region]+'Module'+str(num+1)+position.capitalize()


if __name__ == '__main__':
    import ROOT as r
    f = r.TFile('../../RootFiles/EveryHit/runs131973-133785-end2012.root','read')
    t = f.Get('TTHitEfficiencyTuple/TrackMonTuple')
    for (i, track) in enumerate(t):
        ids = track.clusterSTchanID
        chids = [long(id) for id in ids]
        if len(chids)>=4:
            id = STChannelID(chids[3])
            if not id.isTT():
                print 'Not TT.'
                sys.exit(0)
            if 'TTb' in STNames().uniqueLayerName(id) and 'B' in STNames().regionName(id):
                print id.sector(), STNames().uniqueSectorName(id), '\t', TTModulesMap_instance.findHalfModule(id).id