diff --git a/Reconstruction/Jet/JetInterface/JetInterface/IJetProvider.h b/Reconstruction/Jet/JetInterface/JetInterface/IJetProvider.h index ac0d0eab46c424b99b374e2cef128e80ebf371ea..abf24cf50ab6ed1acbcb835760231497f5d37cb3 100644 --- a/Reconstruction/Jet/JetInterface/JetInterface/IJetProvider.h +++ b/Reconstruction/Jet/JetInterface/JetInterface/IJetProvider.h @@ -53,6 +53,17 @@ public: /// from the templated JetProvider class provided below. virtual StatusCode getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetHandle) const = 0; + /// Method to allow the client to pass in a WriteHandle during + /// initialisation, in case this is needed for anything... + /// + /// The main (only?) use case is for copying jets, and propagating + /// any decorations already on the original to the copy in StoreGate + /// + /// Quietly return success in the general case -- the JetRecAlg + /// will always call this, so as to remain agnostic as to the + /// concrete type. + virtual StatusCode initWithOutput(const SG::WriteHandleKey<xAOD::JetContainer>&) {return StatusCode::SUCCESS;}; + }; @@ -65,8 +76,8 @@ template <typename CONCRETEAUX> class JetProvider : virtual public IJetProvider { -public: - + public: + StatusCode getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetHandle) const { std::unique_ptr<xAOD::JetContainer> jets(nullptr); std::unique_ptr<SG::IAuxStore> auxCont(nullptr); diff --git a/Reconstruction/Jet/JetRec/CMakeLists.txt b/Reconstruction/Jet/JetRec/CMakeLists.txt index f67252d4a75554d2d39649967657a4f4e4cff236..767c7545bc1890ba5453b871b06cc801277ea2b2 100644 --- a/Reconstruction/Jet/JetRec/CMakeLists.txt +++ b/Reconstruction/Jet/JetRec/CMakeLists.txt @@ -8,7 +8,7 @@ set( extra_libs ) if( NOT GENERATIONBASE ) list( APPEND extra_libs xAODPFlow ) if( NOT XAOD_STANDALONE ) - list( APPEND extra_libs AthenaMonitoringKernelLib ) + list( APPEND extra_libs AthenaMonitoringKernelLib StoreGateLib ) endif() endif() diff --git a/Reconstruction/Jet/JetRec/JetRec/JetCopier.h b/Reconstruction/Jet/JetRec/JetRec/JetCopier.h index bc7534bca579c46d1bc190ae24a13f26fd7a4909..5d6f7f9855c4ce7ab7dad90e8cf15b36bfc16916 100644 --- a/Reconstruction/Jet/JetRec/JetRec/JetCopier.h +++ b/Reconstruction/Jet/JetRec/JetRec/JetCopier.h @@ -19,10 +19,17 @@ #include "AsgTools/PropertyWrapper.h" #include "AsgTools/AsgTool.h" #include "AsgDataHandles/ReadHandleKey.h" +#include "AsgDataHandles/WriteHandleKey.h" #include "JetInterface/IJetProvider.h" #include "xAODJet/JetContainer.h" #include "xAODCore/ShallowAuxContainer.h" +// This class doesn't (yet) exist for AnalysisBase, so in that release +// we will simply have to rerun modifiers if we need them. +#ifndef XAOD_ANALYSIS +#include "StoreGate/ShallowCopyDecorDeps.h" +#endif + class JetCopier : public asg::AsgTool, virtual public IJetProvider @@ -32,20 +39,35 @@ class JetCopier public: using asg::AsgTool::AsgTool; + // Called in parent initialize() virtual StatusCode initialize() override; - virtual StatusCode getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetHandle) const override; +#ifndef XAOD_ANALYSIS + // Needed to initialise the ShallowCopyDecorDeps object, which propagates + // decorations on the original into the copy in StoreGate. + // Override interface implementation in Athena only + virtual StatusCode initWithOutput(const SG::WriteHandleKey<xAOD::JetContainer>& outputJets) override; +#endif + // Called during execution + virtual StatusCode getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetHandle) const override; virtual std::pair<std::unique_ptr<xAOD::JetContainer>, std::unique_ptr<SG::IAuxStore> > getJets() const override; + + private: + virtual std::pair<std::unique_ptr<xAOD::JetContainer>, std::unique_ptr<SG::IAuxStore> > ShallowCopyJets() const; virtual std::pair<std::unique_ptr<xAOD::JetContainer>, std::unique_ptr<SG::IAuxStore> > DeepCopyJets() const; - private: // Handle Input JetContainer SG::ReadHandleKey<xAOD::JetContainer> m_inputJets {this, "InputJets", "", "Jet collection to be copied"}; Gaudi::Property<bool> m_shallowCopy {this, "ShallowCopy", true, "True for shallow copy, false for deep copy"}; Gaudi::Property<bool> m_shallowIO {this, "ShallowIO", false, "True for storing only modified data"}; + +#ifndef XAOD_ANALYSIS + SG::ShallowCopyDecorDeps<xAOD::JetContainer> m_decorDeps { this, "DecorDeps", {}, + "List of decorations to propagate through the shallow copy." }; +#endif }; #endif diff --git a/Reconstruction/Jet/JetRec/Root/JetCopier.cxx b/Reconstruction/Jet/JetRec/Root/JetCopier.cxx index f27f31e349387dbebb9d0b139b9773718037c126..07297e9e3787ebbdc43af43af0827671695a6e59 100644 --- a/Reconstruction/Jet/JetRec/Root/JetCopier.cxx +++ b/Reconstruction/Jet/JetRec/Root/JetCopier.cxx @@ -35,6 +35,15 @@ StatusCode JetCopier::initialize() { return StatusCode::SUCCESS; } + +#ifndef XAOD_ANALYSIS +// Setup helper to propagate decorations from original to copy +StatusCode JetCopier::initWithOutput(const SG::WriteHandleKey<xAOD::JetContainer>& outputJets) { + return m_decorDeps.initialize(m_inputJets, outputJets) ; +} +#endif + + StatusCode JetCopier::getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetHandle) const { std::unique_ptr<xAOD::JetContainer> jets(nullptr); std::unique_ptr<SG::IAuxStore> auxCont(nullptr); @@ -44,12 +53,19 @@ StatusCode JetCopier::getAndRecordJets(SG::WriteHandle<xAOD::JetContainer>& jetH if(m_shallowCopy){ std::unique_ptr<xAOD::ShallowAuxContainer> auxCont_derived(static_cast<xAOD::ShallowAuxContainer*>(auxCont.release())); - return jetHandle.record(std::move(jets), std::move(auxCont_derived)); + ATH_CHECK( jetHandle.record(std::move(jets), std::move(auxCont_derived)) ); +#ifndef XAOD_ANALYSIS + ATH_CHECK( m_decorDeps.linkDecors (m_inputJets) ); +#endif } else{ std::unique_ptr<xAOD::JetAuxContainer> auxCont_derived(static_cast<xAOD::JetAuxContainer*>(auxCont.release())); - return jetHandle.record(std::move(jets), std::move(auxCont_derived)); + ATH_CHECK( jetHandle.record(std::move(jets), std::move(auxCont_derived)) ); +#ifndef XAOD_ANALYSIS + ATH_CHECK( m_decorDeps.linkDecors (m_inputJets) ); +#endif } + return StatusCode::SUCCESS; } std::pair<std::unique_ptr<xAOD::JetContainer>,std::unique_ptr<SG::IAuxStore> > JetCopier::getJets() const { diff --git a/Reconstruction/Jet/JetRec/src/JetRecAlg.cxx b/Reconstruction/Jet/JetRec/src/JetRecAlg.cxx index a15742dbb8e79f6a8efc67c30a7994e2365d8c99..5368dde708bc6f9a7bf1b9fb5219a3ddca67fb23 100644 --- a/Reconstruction/Jet/JetRec/src/JetRecAlg.cxx +++ b/Reconstruction/Jet/JetRec/src/JetRecAlg.cxx @@ -17,7 +17,13 @@ using std::string; StatusCode JetRecAlg::initialize() { + ATH_CHECK(m_output.initialize()); + ATH_CHECK(m_jetprovider.retrieve()); + // Some providers (e.g. copy) need the output WriteHandle + // to be provided during initialisation + ATH_CHECK(m_jetprovider->initWithOutput(m_output)); + ATH_MSG_INFO(" Initialized IJetProvider : "<< m_jetprovider->name()); ATH_MSG_INFO(" Initialize .... List of modifiers: "); @@ -26,7 +32,6 @@ StatusCode JetRecAlg::initialize() { ATH_MSG_INFO(" --> : "<< t->name()); } - ATH_CHECK(m_output.initialize()); return StatusCode::SUCCESS; } diff --git a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py index 4e1950ae4a471c49ab38b9f3226829eae8220240..beeaf5bfbcbfdbdd42620d4f734887b199eeb358 100644 --- a/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py +++ b/Reconstruction/Jet/JetRecConfig/python/JetRecConfig.py @@ -325,11 +325,15 @@ def getJetRecAlg( jetdef): # these may be set up already in the original jet collection # In future we may wish to add a toggle. # -def getJetCopyAlg(jetsin, jetsoutdef, shallowcopy=True, shallowIO=True): +# The decoration list can be set in order for the decorations +# (jet moments) on the original jets to be propagated to the +# copy collection. Beware of circular dependencies! +def getJetCopyAlg(jetsin, jetsoutdef, decorations=[], shallowcopy=True, shallowIO=True): jcopy = CompFactory.JetCopier( "copier", InputJets = jetsin, + DecorDeps=decorations, ShallowCopy=shallowcopy, ShallowIO=shallowIO) diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py index 1f91b6668fff7de7ab9e72a799b63f4bcdc2b40d..6a11c5ec9050038a4c228efb0a0def56d2956407 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoConfiguration.py @@ -263,3 +263,19 @@ def defineCalibMods(jetRecoDict,dataSource,rhoKey="auto"): "Calib:"+calibSpec] return calibMods + +def getDecorList(doTracks,isPFlow): + # Basic jet info provided by the jet builder + decorlist = [ 'AlgorithmType', 'InputType' + 'ActiveArea', 'ActiveArea4vec_eta', 'ActiveArea4vec_m', + 'ActiveArea4vec_phi', 'ActiveArea4vec_pt'] + + if doTracks: + decorlist += ["GhostTrack", + "NumTrkPt500","NumTrkPt1000", + "SumPtTrkPt500","SumPtTrkPt1000", + "TrackWidthPt1000", + "JVFCorr"] + if isPFlow: + decorlist += ["SumPtChargedPFOPt500"] + return decorlist diff --git a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoSequences.py b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoSequences.py index 97d40f5a0de1e22e94b2605009fb046dde463195..c9bb7f3ee3b315613984e1a341f2554afe2a215e 100644 --- a/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoSequences.py +++ b/Trigger/TriggerCommon/TriggerMenuMT/python/HLTMenuConfig/Jet/JetRecoSequences.py @@ -77,11 +77,16 @@ def jetRecoSequence( configFlags, clustersKey, **jetRecoDict ): def standardJetBuildSequence( configFlags, dataSource, clustersKey, **jetRecoDict ): jetDefString = jetRecoDictToString(jetRecoDict) buildSeq = parOR( "JetBuildSeq_"+jetDefString, []) - trkcolls = getTrkColls(jetRecoDict) if jetRecoDict["trkopt"]!="notrk" else {} + doesTracking = jetRecoDict["trkopt"]!="notrk" + trkcolls = getTrkColls(jetRecoDict) if doesTracking else {} + if doesTracking and not trkcolls: + raise RuntimeError("Failed to retrieve track collections for trkopt '{}'".format(jetRecoDict["trkopt"])) + + isPFlow = "pf" in jetRecoDict["dataType"] # Add particle flow reconstruction if needed - if "pf" in jetRecoDict["dataType"]: - if not trkcolls: + if isPFlow: + if not doesTracking: raise RuntimeError("PFlow jet chain requested with no tracking option!") from eflowRec.PFHLTSequence import PFHLTSequence (pfseq, pfoPrefix) = RecoFragmentsPool.retrieve( @@ -114,11 +119,10 @@ def standardJetBuildSequence( configFlags, dataSource, clustersKey, **jetRecoDic # Basic list of PseudoJets is just the constituents # Append ghosts (tracks) if desired pjs = [constitPJKey] - if trkcolls: - pjs.append(trkcolls["GhostTracks"]) - + # Also compile modifier list jetModList = [] - if trkcolls: + if doesTracking: + pjs.append(trkcolls["GhostTracks"]) trkMods = JetRecoConfiguration.defineTrackMods(jetRecoDict["trkopt"]) jetModList += trkMods @@ -177,8 +181,13 @@ def standardJetRecoSequence( configFlags, dataSource, clustersKey, **jetRecoDict rhoKey = str(eventShapeAlg.EventDensityTool.OutputContainer) jetDef.modifiers = JetRecoConfiguration.defineCalibMods(jetRecoDict,dataSource,rhoKey) - jetDef.modifiers += jetDefNoCalib.modifiers[:-2] # Leave off sort + filter - copyCalibAlg = JetRecConfig.getJetCopyAlg(jetsin=jetsNoCalib,jetsoutdef=jetDef) + # If we need JVT, just rerun the JVT modifier + doesTracking = jetRecoDict["trkopt"] != "notrk" + isPFlow = "pf" in jetRecoDict["dataType"] + if doesTracking: + jetDef.modifiers.append("JVT:"+jetRecoDict["trkopt"]) + decorList = JetRecoConfiguration.getDecorList(doesTracking,isPFlow) + copyCalibAlg = JetRecConfig.getJetCopyAlg(jetsin=jetsNoCalib,jetsoutdef=jetDef,decorations=decorList) recoSeq += copyCalibAlg