hlt2_global_reco.py 7.27 KB
Newer Older
1
###############################################################################
2
# (c) Copyright 2020-2021 CERN for the benefit of the LHCb Collaboration      #
3
4
5
6
7
8
9
10
11
12
13
14
15
#                                                                             #
# This software is distributed under the terms of the GNU General Public      #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
#                                                                             #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization  #
# or submit itself to any jurisdiction.                                       #
###############################################################################
"""Methods defining ProtoParticle makers, used as input to Particle selections.

The 'global' reconstruction is that which produces the final output of the
'full' HLT2 reconstruction: charged and neutral ProtoParticle containers.
"""
Sascha Stahl's avatar
Sascha Stahl committed
16
from .hlt1_tracking import make_reco_pvs
17
18
from .hlt2_tracking import make_hlt2_tracks
from .rich_reconstruction import make_all_rich_pids, default_rich_reco_options, make_merged_rich_pids
19
from .calorimeter_reconstruction import make_calo, make_photons_and_electrons, make_electron_and_brem_match
20
from .hlt2_muonid import make_muon_ids
21

22
23
24
25
from .protoparticles import (
    make_charged_protoparticles as make_charged_protoparticles_from,
    make_neutral_protoparticles as make_neutral_protoparticles_from,
)
26
27

from PyConf import configurable
Sascha Stahl's avatar
Sascha Stahl committed
28
29
from PyConf.Algorithms import (
    LHCb__Converters__RecVertex__v2__fromVectorLHCbRecVertices as
30
    FromVectorLHCbRecVertices, TrackContainerCopy)
31
32
33


# TODO make things configurable, if needed
34
35
def make_default_reconstruction():
    """Return reconstruction objects of the default reconstruction.
Sascha Stahl's avatar
Sascha Stahl committed
36
37

    """
38
39
40
    # Tracks
    hlt2_tracks = make_hlt2_tracks()
    best_tracks = hlt2_tracks["Best"]
Sascha Stahl's avatar
Sascha Stahl committed
41
42
43
44
45
46
47
    velo_tracks = hlt2_tracks["Velo"]

    # PVs
    pvs_v2 = make_reco_pvs(velo_tracks)
    pvs = FromVectorLHCbRecVertices(
        InputVerticesName=pvs_v2,
        InputTracksName=velo_tracks["v1"]).OutputVerticesName
48
49
50
51
52
53
54

    # RICH
    richRecConfs = make_all_rich_pids(best_tracks, default_rich_reco_options())
    # Merge them for now to be compatible with Brunel.
    rich_pids = make_merged_rich_pids(richRecConfs)

    # Calo
Sascha Stahl's avatar
Sascha Stahl committed
55
    calo_pids = make_calo(best_tracks["v1"], pvs)
56
57
58
59
60
61
62
63
64
65
66

    # Muons
    muon_pids = make_muon_ids(best_tracks)

    charged_protos = make_charged_protoparticles_from(
        best_tracks,
        rich_pids=rich_pids,
        calo_pids=calo_pids,
        muon_pids=muon_pids)
    neutral_protos = make_neutral_protoparticles_from(calo_pids=calo_pids)

Sascha Stahl's avatar
Sascha Stahl committed
67
    return {
68
        "ChargedProtos": charged_protos,
Sascha Stahl's avatar
Sascha Stahl committed
69
70
71
        "NeutralProtos": neutral_protos,
        "Tracks": best_tracks["v1"],
        "PVs": pvs,
72
73
        # The full data flow is functional, we only keep this for compatibility with reco from file.
        "UpfrontReconstruction": [],
74
75
76
77
78
79
80
        "CaloElectrons": calo_pids["electrons"],
        "CaloPhotons": calo_pids["photons"],
        "CaloMergedPi0s": calo_pids["mergedPi0s"],
        "CaloSplitPhotons": calo_pids["splitPhotons"],
        "MuonPIDs": muon_pids,
        "RichPIDs": rich_pids,
        #"MuonTracks": ,
Sascha Stahl's avatar
Sascha Stahl committed
81
    }
82
83


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def make_fastest_reconstruction():
    """Return reconstruction objects of the fastest reconstruction.

    Currently no charged protoparticles for upstream tracks are created.

    """
    # Tracks
    hlt2_tracks = make_hlt2_tracks(
        light_reco=True, fast_reco=True, use_pr_kf=True)
    velo_tracks = hlt2_tracks["Velo"]
    merge_tracks = TrackContainerCopy(
        name="CreateBestTrackContainer",
        inputLocations=[
            hlt2_tracks["BestLong"]["v1"], hlt2_tracks["BestDownstream"]["v1"],
            hlt2_tracks["SeedDecloned"]["v1"]
        ])

    best_tracks = {"v1": merge_tracks.outputLocation}
    # PVs
    pvs_v2 = make_reco_pvs(velo_tracks)
    pvs = FromVectorLHCbRecVertices(
        InputVerticesName=pvs_v2,
        InputTracksName=velo_tracks["v1"]).OutputVerticesName

    # RICH
    richRecConfs = make_all_rich_pids(
        best_tracks,
        default_rich_reco_options(),
        track_types=["Long", "Downstream"])
    # Merge them for now to be backwards compatible.
    rich_pids = make_merged_rich_pids(richRecConfs)

    # Calo, enable fast matching of tracks to calo clusters
    with make_photons_and_electrons.bind(selective_matching=True), \
          make_electron_and_brem_match.bind(selective_matching=True):
        calo_pids = make_calo(best_tracks["v1"], pvs)

    # Muons
    muon_pids = make_muon_ids(best_tracks)

    charged_protos = make_charged_protoparticles_from(
        tracks=best_tracks,
        rich_pids=rich_pids,
        calo_pids=calo_pids,
        muon_pids=muon_pids,
        track_types=["Long", "Downstream"])

    neutral_protos = make_neutral_protoparticles_from(calo_pids=calo_pids)

    return {
        "ChargedProtos": charged_protos,
        "NeutralProtos": neutral_protos,
        "Tracks": best_tracks["v1"],
        "PVs": pvs,
        # The full data flow is functional, we only keep this for compatibility with reco from file.
        "UpfrontReconstruction": [],
        "CaloElectrons": calo_pids["electrons"],
        "CaloPhotons": calo_pids["photons"],
        "CaloMergedPi0s": calo_pids["mergedPi0s"],
        "CaloSplitPhotons": calo_pids["splitPhotons"],
        "MuonPIDs": muon_pids,
        "RichPIDs": rich_pids,
        #"MuonTracks": ,
    }


@configurable
def reconstruction(make_reconstruction=make_default_reconstruction):
    """Hook to allow switching between reconstructions.

    make_reconstruction (function): which reconstruction to run.

    Note it is advised to use this function if more than one object is needed,
    rather than the accessors below  as it makes the configuration slower.
    """
    return make_reconstruction()


162
163
164
165
166
167
168
def make_charged_protoparticles():
    """Return a DataHandle to the container of charged ProtoParticles.

    The charged ProtoParticle making is not functional, and so the sequence of algorithms
    which produces the full information at this location needs to be scheduled explicitly
    by including the `upfront_reconstruction` method in the file in the control flow.
    """
Sascha Stahl's avatar
Sascha Stahl committed
169
    return reconstruction()["ChargedProtos"]
170
171
172
173
174


def upfront_reconstruction():
    """Return sequence to create charged ProtoParticles.

175
    Be aware that the node needs to be configures with the mode `force_order=True`.
176
177
178
179
180
181

    The charged ProtoParticle making is not functional, and so the sequence of algorithms
    which produces the full information at this location needs to be scheduled explicitly
    by including the `upfront_reconstruction` method in the file in the control flow.
    """

Sascha Stahl's avatar
Sascha Stahl committed
182
    return reconstruction()["UpfrontReconstruction"]
183
184
185
186
187
188
189
190
191


def make_neutral_protoparticles():
    """Return a DataHandle to the container of neutral ProtoParticles.

    The neutral ProtoParticle making is functional, there is no need to
    schedule the upfront reconstruction explicitly.
    """

Sascha Stahl's avatar
Sascha Stahl committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
    return reconstruction()["NeutralProtos"]


def make_pvs():
    """Return a DataHandle to the container of PVs
    """

    return reconstruction()["PVs"]


def make_tracks():
    """Return a DataHandle to the container of all tracks
    """
    return reconstruction()["Tracks"]