Making ntuples from Turbo data

This page shows you how to configure DaVinci to process Turbo data.

Due to the historical development cycle of the Turbo processing model, the format of Turbo data has changed from 2015 to 2016 and again from 2016 to 2017. Although a stable DaVinci configuration is always a priority for the Turbo developers, some changes are required when analysing datasets from different years.

The sections below are organised per year, and are standalone after reading the introduction.

Introduction

It is expected that any TupleTool that works on a microDST Stripping output will work with Turbo data.

In what follows, it is assumed that the DecayTreeTuple to be configured has been instantiated as dtt:

from Configurables import DecayTreeTuple
from DecayTreeTuple import Configuration

dtt = DecayTreeTuple(...)

An example HLT2 Turbo line is assumed, available as hlt2_line:

hlt2_line = 'Hlt2CharmHadD02KmPipTurbo'

2015, 2016, 2017, and 2018 data

In general, the latest DaVinci version is recommended, but anything past v44r3 should be sufficient for both collision data and MC.

You must set the following properties on the DaVinci() configurable for both Turbo and TurCal data:

DaVinci().InputType = 'MDST'
DaVinci().RootInTES = '/Event/<stream_name>/Turbo'
DaVinci().Turbo = True

The stream_name is the name of the stream, like CHARMSPEC or LEPTONS, but in lowercase with the first letter capitalised, like Charmspec or Leptons. In 2015 and 2016 the stream_name is always empty, so the RootInTES is just /Event/Turbo.

An example of a full location of Particle objects in 2017 is:

/Event/Charmspec/Turbo/Hlt2CharmHadD02KmPipTurbo/Particles

However, input locations to algorithms should be relative to the RootInTES property, e.g. for a DecayTreeTuple:

dtt.Inputs = ['{0}/Particles'.format(hlt2_line)]
# ...
DaVinci().RootInTES = '/Event/Charmspec/Turbo'

Monte Carlo truth

To get Monte Carlo truth information, add TupleToolMCTruth and TupleToolMCBackgroundInfo to the DecayTreeTuple ToolList as usual.

dtt.ToolList += [
    'TupleToolMCBackgroundInfo',
    'TupleToolMCTruth'
]

Then, add the following to your options:

from TeslaTools import TeslaTruthUtils

relations = TeslaTruthUtils.getRelLocs() + [
    TeslaTruthUtils.getRelLoc(''),
    # Location of the truth tables for PersistReco objects
    'Relations/Hlt2/Protos/Charged'
]
mc_tools = [
      'MCTupleToolKinematic',
      # ...and any other tools you'd like to use
]
TeslaTruthUtils.makeTruth(dtt, relations, mc_tools)

This is necessary because the MC relations tables for Turbo data are in a non-standard location. The configuration for 2015 data is slightly different.

LoKi functors

To use LoKi functors that require Monte Carlo truth matching, you similarly need to set the location of the relations tables. When using the mcMatch functor, this location can be passed as the second argument to the functor:

loki_tt = dtt.addTupleTool('LoKi::Hybrid::TupleTool/SomeName')
loki_tt.Preambulo = [
    'from LoKiPhysMC.decorators import *',
    'from LoKiPhysMC.functions import mcMatch'
]
# Use the (assumed existing) decay descriptor on the DecayTreeTuple to build
# a MC-matching descriptor
# The use of the DecayTreeTuple descriptor and of the '==>' arrow is
# not always valid for every analysis, this is just an example; be careful!
mc_decay_descriptor = dtt.Decay.replace('^', '').replace('->', '==>')
loki_tt.Variables = {
    'mcMatch' : 'switch(mcMatch({0!r}, {1!r}), 1, 0)'.format(mc_decay_descriptor, relations)
}

Where the relations variable is as defined above.

PersistReco

When an HLT2 line has the PersistReco flag enabled, the full HLT2 reconstruction is available in events where that line fired.

The Track objects are made available at /Event/Turbo/Rec/Track/Best, and the ProtoParticle objects are made available under /Event/Turbo/Rec/ProtoP/Charged. The rest of the reconstruction is under /Event/Turbo/Hlt2. Primary vertices are under /Event/Turbo/Primary as usual, but the associated VELO tracks also exist for PersistReco events.

The family of Std* particles, like StdAllPions, should be rebuilt using the Python Selection framework. The following example shows how one can take the output of a $D^{0} \rightarrow K^{-}\pi^{+}$ Turbo line and combine it with a PersistReco pion:

from PhysSelPython.Selections import (
    AutomaticData,
    CombineSelection,
    RebuildSelection,
    SelectionSequence
)
from StandardParticles import StdAllLooseANNPions

combiner_sel = CombineSelection(
    'CombineD0pi',
    inputs=[
        # The output of the HLT2 line
        AutomaticData('{0}/Particles'.format(hlt2_line)),
        # Extra pions
        RebuildSelection(StdAllLooseANNPions)
    ],
    DecayDescriptors=[
      'D*(2010)+ -> D0 pi+',
      'D*(2010)- -> D0 pi-'
    ],
    DaughtersCuts={
        'pi+': 'PROBNNpi > 0.2'
    },
    CombinationCut=(
      'in_range(0, (AM - AM1 - AM2), 170)'
    ),
    MotherCut=(
      '(VFASPF(VCHI2PDOF) < 10) &'
      'in_range(0, (M - M1 - M2), 150)'
    )
)
selseq = SelectionSequence(
    combiner_sel.name() + 'Sequence',
    TopSelection=combiner_sel
)

You can then add the full selection to some sequence with selseq.sequence(), getting the output particle location using sel.outputLocation(). For example:

dtt = DecayTreeTuple(...)
dtt.Inputs = [combiner_sel.outputLocation()]
# ...
DaVinci().UserAlgorithms = [selseq.sequence(), dtt]

Exact clones in particle combinations in 2016 data

Due to some technicalities, you will see exact clones when trying to perform particle combinatorics with 2016 Turbo+PersistReco data. This means that the same underlying Track object is used twice in the same combination, and is an issue because it can create unphysical peaking structures in mass distributions.

As an example, assume your Turbo candidate (the object that fired your HLT2 line) is $J/\psi \to \mu^{+}\mu^{-}$. The HLT2 line has PersistReco enabled, and you want to reconstruct $B^{+} \to J/\psi K^{+}$, taking the $J/\psi$ Turbo candidate and kaons from StdLooseKaons. With the default configuration of CombineParticles, you will end up saving $B^{+}$ candidates where the same track is used for the $\mu^{+}$ and the $K^{+}$, meaning that the 3-momenta of the two particles will be identical.

To avoid this issue, you can configure CombineParticles to perform a more robust overlap check:

my_combiner = CombineParticles(
   ...,
   CheckOverlapTool='LoKi::CheckOverlap'
)

2015 and 2016 data

If you see errors like this when processing data:

Hlt2PackedDataD...WARNING HltPackedDataDecoder:: No HltPackedData raw bank (the DstData bank) in raw event. Quitting.
LinkHltPersistR...WARNING Gaudi::DataLink:: No valid data is found at '/Event/Hlt2/Vertex/PV3D'
LoKiSvc.REPORT    WARNING The WARNING message is suppressed : 'LoKi::Vertices::SourceDesktop:    No input primary vertices from IDVAlgorithm [myalg]' StatusCode=FAILURE
LoKiSvc.REPORT    WARNING The WARNING message is suppressed : 'LoKi::Vertices::SourceDesktop:    No vertices are selected by 'PRIMARY' [myalg]' StatusCode=FAILURE
LoKiSvc.REPORT      ERROR The   ERROR message is suppressed : 'LoKi::Particles::MinImpParChi2DV:        Empty list of vertices is loaded! [myalg]' StatusCode=FAILURE

then one or more algorithms or tools are trying to access primary vertices directly from the Brunel location, rather than going via the Particle-to-PV relations tables created in HLT2 which point to the Turbo location.

In this case, algorithms and tools must be explicitly configured to pick up the Turbo primary vertices. The Turbo-specific DecayTreeTuple configuration will look like this:

dtt.Inputs = ['{0}/Particles'.format(hlt2_line)]
dtt.InputPrimaryVertices = '/Event/Turbo/Primary'

If your line had PV refitting enabled, and you wish to use the refitted PVs, change InputPrimaryVertices to point to the corresponding location.

Monte Carlo truth

This is similar to the procedure for 2016+ data, but the list of relations locations is specified differently:

relations = [TeslaTruthUtils.getRelLoc(hlt2_line + '/')]

Efficient processing

As for any other DaVinci job, it is recommended that you stop processing an event as soon as possible in order to reduce CPU time. A good way to acheive this with Turbo data is to filter out events that don't contain a positive decision for your trigger(s).

from PhysConf.Filters import LoKi_Filters

trigger_filter = LoKi_Filters(
    # Adjust this regular expression to match whatever set of lines you're
    # interested in studying
    HLT2_Code="HLT_PASS_RE('.*{0}.*'.format(hlt2_line))"
)

DaVinci().EventPreFilters = trigger_filter.filters('TriggerFilter')

This prevents expensive unpacking algorithms running on events where your candidates don't exist.

Edit | Attach | Watch | Print version | History: r20 < r19 < r18 < r17 < r16 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r20 - 2019-07-03 - AlexPearce
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    LHCb All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback