6.1.2. DecayString

The DecayString is an elegant way of telling the analysis modules about the structure and the particles of a decay tree. The syntax is borrowed mainly from the LHCb software. Here comes the first example of a DecayString (you probably can already guess the meaning):

'B+ -> [anti-D0 -> K- pi+] pi+'

The structure of the decay tree is internally represented by the DecayDescriptor class, but as analysis user you do not have to care about this.

Particles and Decays

The atomic components of the DecayString and also the simplest valid DecayStrings are particles:

'B+', 'anti-D0', 'K-', 'pi+'

The framework automatically translates the particle names to the corresponding PDG codes (e.g. ‘B+’ = 521).

A particle decay is represented by an arrow:

'B+ -> anti-D0 pi+'

'anti-D0 -> K- pi+'

On the right side, particles can be replaced by decaying particles which have to be put in brackets '[...]' to build more complex decay trees.

'B+ -> [anti-D0 -> K- pi+] pi+'

Selection

Particles can be selected with a preceding upper caret symbol, '^'. This line selects B+, anti-D0 and pi+ from the anti-D0 decay:

'^B+ -> [^anti-D0 -> K- ^pi+] pi^+'

Grammar for custom MCMatching

One can use a specific grammar for the decay string to configure how isSignal and mcErrors are behaving, which are variables of MC matching. The grammar is composed of Markers (Marker of unspecified particle and Markers for Final State Particles), Keywords, and Arrows. By default, isSignal requires that all final state particle daughters are correctly reconstructed except for radiated photons and intermediate states. One can configure isSignal to accept missing particles or not to accept missing radiated photons or intermediate resonances.

Tip

If a specific grammar is used, Error flags are removed from mcErrors. So one cannot know if a event ordinally has the flags which are accepted by the grammar. To obtain the information, one can use usual decay string and specific variables, such as isSignalAcceptMissingNeutrino, to identify signal events.

Marker of unspecified particle

Particle can be marked as unspecified particle with an at-sign, '@', in the DecayString. If the particle is marked as unspecified it will not checked for its identity when doing MC matching. Any particle which decays into the correct daughters will be flagged as correct. For example the DecayString '@Xsd -> K+ pi-' would match all particles which decay into a Kaon and a pion, for example K*, B0, D0, … Still the daughters need to be stated correctly so this can be used for “sum of exclusive” decays. Here is an example of use:

from modularAnalysis import reconstructDecay, copyLists
reconstructDecay('@Xsd:0 -> K_S0:all',                   '', path=mypath)
reconstructDecay('@Xsd:1 -> K+:loose pi-:loose',         '', path=mypath)
reconstructDecay('@Xsd:2 -> K+:loose pi-:loose pi0:all', '', path=mypath)

copyLists('Xsd:comb', ['Xsd:0', 'Xsd:1', 'Xsd:2'], path=mypath)
# copyLists('@Xsd:comb', ['Xsd:0', 'Xsd:1', 'Xsd:2'], path=mypath) # this can't work

reconstructDecay('B0:Xsdee -> Xsd:comb e+:loose e-:loose', '', path=mypath)

Markers for Final State Particles

Final State Particle (FSP) such as 'K+' or 'pi+' sometimes decays in the detector and the particle is reconstructed from the secondary decay particle, for example 'pi+ -> mu+ nu_mu'. Although such particle is identified usually as background, in some analysis works, one may wants to accept it. One can add '(decay)' to the begging of the particle name in this case. Similarly, one can add '(misID)' to accept a mis-identified FSP. Here is an example of use:

from modularAnalysis import reconstructDecay

# isSignal of D0:decayInFlight accepts DecayInFlight for pi+:loose
reconstructDecay('D0:decayInFlight -> K-:loose (decay)pi+:loose', '', path=mypath)

# isSignal of D0:misID accepts mis-identification of K-:loose and pi+:loose
reconstructDecay('D0:misID         -> (misID)K-:loose (misID)pi+:loose', '', path=mypath)

# One can use the markers at same time
reconstructDecay('D0:decayInFlightMisID -> (misID)(decay)K-:loose (decay)(misID)pi+:loose', '', path=mypath)

Keywords

If one put the following keywords at the end of the decay string, isSignal will accept missing massive particles/neutrinos/gammas(not radiated), respectively, or gammas added by bremsstrahlung tools.

  • '...' Missing massive final state particles are ignored

  • '?nu' Missing neutrinos are ignored

  • '?gamma' Missing gammas are ignored

  • '?addbrems' Gammas added by bremsstrahlung tools are ignored

These are useful to analyze inclusive processes with fully-inclusive method.

Keywords must be placed at the end of the decay string. It is not allowed to put keywords in front of particles. Here is an exapmle of use:

from modularAnalysis import reconstructDecay
# Keywords must be placed behind all particles
reconstructDecay('K_S0:missNu     -> pi+:loose e-:loose ?nu',      '', path=mypath)
# isSignal of K_S0:missNu accepts missing neutrino
reconstructDecay('Xsu:missMassive -> K+:loose pi0:all ... ?gamma', '', path=mypath)
# isSignal of Xsu:missMassive accepts missing massive FSP and gamma (such as pi0 -> gamma gamma)
reconstructDecay('B+:inclusive    -> mu-:loose ... ?nu ?gamma',    '', path=mypath)
# isSignal of B+:inclusive accepts missing massive FSP, neutrino, and gamma.
reconstructDecay('B+:brems        -> K+:loose e-:corrected e+:corrected ?addbrems', '', path=mypath)
# isSignal of B+:brems accepts photons added by bremsstrahlung tools (correctBrems or correctBremsBelle).

Arrows

In addition to the common arrow '->', one can use different types of arrows. If any of the following verbose arrows are used, isSignal will behave differently with additional (unspecified) radiated photons and/or unspecified intermediate resonances.

  • '->' decays that proceed via intermediate resonances and/or with radiated photons are counted as signal even if they weren’t exactly specified in the decay string

  • '=direct=>' decays with intermediate resonances are not counted as signal unless included in the decay string, but decays with radiated photons are counted as signal even if they are not specified in the decay string

  • '=norad=>' radiated photons are not counted as signal but decays via an intermediate resonance are

  • '=exact=>' exact match of the decay forbidding any intermediate resonances and radiated photons unless explicitly specified in the decay string

Here is an exapmle of use:

from modularAnalysis import reconstructDecay
reconstructDecay('B+:default ->        K+:loose e+:loose e-:loose', '', path=mypath)
reconstructDecay('B+:direct  =direct=> K+:loose e+:loose e-:loose', '', path=mypath)
reconstructDecay('B+:norad   =norad=>  K+:loose e+:loose e-:loose', '', path=mypath)
reconstructDecay('B+:exact   =exact=>  K+:loose e+:loose e-:loose', '', path=mypath)

# If one reconstructs B+ -> K+ e+ e- with above codes, one gets following results
# isSignal(B+:default) == 1
# isSignal(B+:direct)  == 1
# isSignal(B+:norad)   == 1
# isSignal(B+:exact)   == 1

# If one reconstructs B+ -> K+ e+ e- and FSR photon with above codes, one gets following results
# isSignal(B+:default) == 1
# isSignal(B+:direct)  == 1
# isSignal(B+:norad)   == 0 Because the radiated photon is missed.
# isSignal(B+:exact)   == 0 Because the radiated photon is missed.

# If one reconstructs B+ -> K+ Jpsi( -> e+ e- and FSR photon) with above codes, one gets following results
# isSignal(B+:default) == 1
# isSignal(B+:direct)  == 0 Because the intermediate resonance (Jpsi) is missed.
# isSignal(B+:norad)   == 0 Because the radiated photon is missed.
# isSignal(B+:exact)   == 0 Because the intermediate resonance (Jpsi) and the radiated photon are missed.