def test_merged_selection():
    sel00 = AutomaticData(Location='Phys/Sel00/Particles')
    sel01 = AutomaticData(Location='Phys/Sel01/Particles')
    ms = MergedSelection('Merge00And01', RequiredSelections=[sel00, sel01])
    assert ms.name() == 'Merge00And01'
    assert ms.requiredSelections() == [
    ]  # should not export its required selections. Algos contained internally.
    assert ms.outputLocation() == 'Phys/Merge00And01/Particles'
    assert [alg.name() for alg in ms._algos] == [
        'SelFilterPhys_Sel00_Particles', 'SelFilterPhys_Sel01_Particles',
        'Merge00And01'
    ]
    assert ms._algos == [
        sel00.algorithm(),
        sel01.algorithm(),
        ms._sel.algorithm()
    ]
Exemple #2
0
def makeB2nbody(name,PiSel,KSel,pSel,KsSel,LmSel,DzSel,DpSel,DsSel,LcSel,PhSel,KSSel,JpSel,DSSel,
                nbody,MinBMass,MaxBMass,MinBPt,MaxBVertChi2DOF,MinBPVVDChi2,MaxBPVIPChi2,MinBPVDIRA,MaxMass,MaxNtrk,MinNvc,
                doPi,doK,dop,doKs,doLm,doDz,doDp,doDs,doLc,doPh,doKS,doJp,doDS):

    # Define a class that contains all relevant particle properties
    class particle:
        def __init__(self,name,m,ntrk,nvc,q,b):
            self.name=name
            self.m=m            #mass
            self.ntrk=ntrk      # number of charged tracks in fian state
            self.nvc=nvc        # number of vertex-contraining (pseudo)tracks
            self.Q=q            # electrical charge
            self.B=b            # baryon number
            self.cp=self
        def CP(self,name):
            p= particle(name,self.m,self.ntrk,self.nvc,-self.Q,-self.B)
            p.cp=self
            self.cp=p
            return p
        def isCP(self):
            if self.cp.name==self.name: return True
            else: return False



    # Define the particles
    particles=[]
    if doPi: particles.append(particle(        "pi+"       , 139.6,1,1,  +1,  0))
    if doPi: particles.append(particles[-1].CP("pi-"       ))
    if doK:  particles.append(particle(        "K+"        , 493.7,1,1,  +1,  0))
    if doK:  particles.append(particles[-1].CP("K-"        ))
    if dop:  particles.append(particle(        "p+"        , 938.3,1,1,  +1, +1))
    if dop:  particles.append(particles[-1].CP("p~-"       ))
    if doKs: particles.append(particle(        "KS0"       , 497.6,2,0,   0,  0))
    if doLm: particles.append(particle(        "Lambda0"   ,1115.7,2,0,   0, +1))
    if doLm: particles.append(particles[-1].CP("Lambda~0"  ))
    if doDz: particles.append(particle(        "D0"        ,1864.8,2,1,   0,  0))
    if doDz: particles.append(particles[-1].CP("D~0"       ))
    if doDp: particles.append(particle(        "D+"        ,1869.6,3,1,  +1,  0))
    if doDp: particles.append(particles[-1].CP("D-"        ))
    if doDs: particles.append(particle(        "D_s+"      ,1968.5,3,1,  +1,  0))
    if doDs: particles.append(particles[-1].CP("D_s-"      ))
    if doLc: particles.append(particle(        "Lambda_c+" ,2286.5,3,1,  +1, +1))
    if doLc: particles.append(particles[-1].CP("Lambda_c~-"))
    if doPh: particles.append(particle(        "phi(1020)" ,1019.5,2,2,   0,  0))
    if doKS: particles.append(particle(        "K*(892)0"  , 895.9,2,2,   0,  0))
    if doKS: particles.append(particles[-1].CP("K*(892)~0" ))
    if doJp: particles.append(particle(        "J/psi(1S)" ,3096.9,2,2,   0,  0))
    if doDS: particles.append(particle(        "D*(2010)+" ,2010.2,3,2,  +1,  0))
    if doDS: particles.append(particles[-1].CP("D*(2010)-" ))

    # in itertools only since python 2.7
    def combinations_with_replacement(iterable, r):
        pool = tuple(iterable)
        n = len(pool)
        if not n and r: return
        indices = [0] * r
        yield tuple(pool[i] for i in indices)
        while True:
            for i in reversed(range(r)):
                if indices[i] != n - 1: break
            else: return
            indices[i:] = [indices[i] + 1] * (r - i)
            yield tuple(pool[i] for i in indices)

    #alphabetically ordered name of particles
    def pname(ps):
        names=[]
        for p in ps: names.append(p.name)
        names.sort()
        result=""
        for name in names:
            result=result+name+' '
        return result[:-1]

    descriptors = []
    for comb in combinations_with_replacement(particles,nbody):
        #check for the mass
        m=0
        for p in comb: m+=p.m
        if m>MaxMass: continue
        #check for the number of tracks in the final state
        ntrk=0
        for p in comb: ntrk+=p.ntrk
        if ntrk>MaxNtrk: continue
        #check for the number of vertex-constraining (pseudo)tracks
        nvc=0
        for p in comb: nvc+=p.nvc
        if nvc<MinNvc: continue
        #check for charge and baryon number
        Q=0
        for p in comb: Q+=p.Q
        if abs(Q)>1: continue
        B=0
        for p in comb: B+=p.B
        if abs(B)>1: continue

        #assign identity to mother 
        mother=""
        if Q==0  and B==0: mother="B0"
        if Q==1  and B==0: mother="B+"
        if Q==0  and B==1: mother="Lambda_b0"
        if Q==-1 and B==1: mother="Xi_b-"
        if Q==+1 and B==1: mother="Xi_bc+"
        if mother=="": continue

        #check if final state is CP eigenstate
        ps=[p for p in comb if not p.isCP()]
        while True:
            doagain=False
            for p in ps:
                if ps.count(p.cp)>0:
                    ps.remove(p)
                    ps.remove(p.cp)
                    doagain=True
                    break
            if not doagain: break
        if len(ps)==0: CP=True
        else: CP=False
        
        #for B0 non-CP combinations come twice. 
        if mother=="B0" and not CP:
            combcp=[x.cp for x in comb]
            if pname(comb)<pname(combcp):continue

        #build the decay descriptor
        descriptor=mother+" -> "+pname(comb)
        if not CP:descriptor="["+descriptor+"]cc"
        descriptors.append(descriptor)

    print "%s: %d channels"%(name,len(descriptors))
    #for descriptor in descriptors: print "DESCRIPTOR:",descriptor


    #make a merge of the input selections
    AllSel=[]
    if doPi:AllSel.append(PiSel)
    if doK: AllSel.append(KSel)
    if dop: AllSel.append(pSel)
    if doKs:AllSel.append(KsSel)
    if doLm:AllSel.append(LmSel)
    if doDz:AllSel.append(DzSel)
    if doDp:AllSel.append(DpSel)
    if doDs:AllSel.append(DsSel)
    if doLc:AllSel.append(LcSel)
    if doPh:AllSel.append(PhSel)
    if doKS:AllSel.append(KSSel)
    if doJp:AllSel.append(JpSel)
    if doDS:AllSel.append(DSSel)
    InputSel= MergedSelection("InputFor"+name, RequiredSelections = AllSel )

    _combinationCuts =    "(in_range(%(MinBMass)s*MeV, AM, %(MaxBMass)s*MeV))" % locals()
    _combinationCuts += "& (APT>%(MinBPt)s*MeV)"%locals()
    _motherCuts = "(VFASPF(VCHI2/VDOF)<%(MaxBVertChi2DOF)s)"%locals()
    _motherCuts += "& (BPVVDCHI2 > %(MinBPVVDChi2)s)"% locals()
    _motherCuts += "& (BPVIPCHI2() < %(MaxBPVIPChi2)s)"%locals()
    _motherCuts += "& (BPVDIRA > %(MinBPVDIRA)s)"% locals()

    #make a selection
    _B=CombineParticles(DecayDescriptors = descriptors, CombinationCut = _combinationCuts, MotherCut = _motherCuts)

    #make a preselection
    _presel=VoidEventSelection("preselFor"+name,
                               Code="(CONTAINS('%s')> %3.1f)"%(InputSel.outputLocation(),nbody-0.5 ),
                               RequiredSelection=InputSel
                               )

    return Selection(name, Algorithm = _B, RequiredSelections = [_presel] )