############################################################################### # (c) Copyright 2020-2021 CERN for the benefit of the LHCb Collaboration # # # # 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. """ from .hlt1_tracking import make_reco_pvs from .hlt2_tracking import make_hlt2_tracks from .rich_reconstruction import make_all_rich_pids, default_rich_reco_options, make_merged_rich_pids from .calorimeter_reconstruction import make_calo, make_photons_and_electrons, make_electron_and_brem_match from .hlt2_muonid import make_muon_ids from .protoparticles import ( make_charged_protoparticles as make_charged_protoparticles_from, make_neutral_protoparticles as make_neutral_protoparticles_from, ) from PyConf import configurable from PyConf.Algorithms import ( LHCb__Converters__RecVertex__v2__fromVectorLHCbRecVertices as FromVectorLHCbRecVertices, TrackContainerCopy) # TODO make things configurable, if needed def make_default_reconstruction(): """Return reconstruction objects of the default reconstruction. """ # Tracks hlt2_tracks = make_hlt2_tracks() best_tracks = hlt2_tracks["Best"] velo_tracks = hlt2_tracks["Velo"] # 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()) # Merge them for now to be compatible with Brunel. rich_pids = make_merged_rich_pids(richRecConfs) # Calo calo_pids = make_calo(best_tracks["v1"], pvs) # 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) 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": , } 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() 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. """ return reconstruction()["ChargedProtos"] def upfront_reconstruction(): """Return sequence to create charged ProtoParticles. Be aware that the node needs to be configures with the mode `force_order=True`. 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. """ return reconstruction()["UpfrontReconstruction"] 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. """ 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"]