From 0c13f82f8ff17bc66fa5837cdf181c98a9e23a90 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Delsart <delsart@in2p3.fr> Date: Thu, 11 Sep 2014 12:17:33 +0200 Subject: [PATCH] 'fix checkreq' (JetMomentTools-00-02-27) --- .../JetMomentTools/JetBadChanCorrTool.h | 185 +++++++ .../JetMomentTools/JetCaloEnergies.h | 27 + .../JetMomentTools/JetCaloQualityTool.h | 66 +++ .../JetMomentTools/JetIsolationTool.h | 147 ++++++ .../JetMomentTools/JetLArHVTool.h | 58 +++ .../JetMuonSegmentMomentsTool.h | 38 ++ .../JetMomentTools/JetPtAssociationTool.h | 66 +++ .../JetMomentTools/JetTrackMomentsTool.h | 74 +++ .../JetMomentTools/JetVertexFractionTool.h | 70 +++ .../JetMomentTools/JetWidthTool.h | 34 ++ .../Root/JetMuonSegmentMomentsTool.cxx | 31 ++ .../Root/JetPtAssociationTool.cxx | 123 +++++ .../Root/JetTrackMomentsTool.cxx | 161 ++++++ .../Root/JetVertexFractionTool.cxx | 115 +++++ .../Jet/JetMomentTools/Root/JetWidthTool.cxx | 53 ++ .../Jet/JetMomentTools/cmt/Makefile.RootCore | 24 + .../Jet/JetMomentTools/cmt/requirements | 31 ++ .../JetMomentTools/python/GhostAssociation.py | 148 ++++++ .../python/JetCopyMomentsAlg.py | 72 +++ .../python/JetMomentsConfigHelpers.py | 363 ++++++++++++++ .../python/SetupJetMomentTools.py | 302 ++++++++++++ .../JetMomentTools/src/JetBadChanCorrTool.cxx | 461 ++++++++++++++++++ .../JetMomentTools/src/JetCaloEnergies.cxx | 57 +++ .../JetMomentTools/src/JetCaloQualityTool.cxx | 177 +++++++ .../JetMomentTools/src/JetIsolationTool.cxx | 456 +++++++++++++++++ .../Jet/JetMomentTools/src/JetLArHVTool.cxx | 105 ++++ .../src/components/JetMomentTools_entries.cxx | 38 ++ .../src/components/JetMomentTools_load.cxx | 5 + 28 files changed, 3487 insertions(+) create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetBadChanCorrTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloEnergies.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloQualityTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetIsolationTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetLArHVTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetMuonSegmentMomentsTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetPtAssociationTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetTrackMomentsTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetVertexFractionTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/JetMomentTools/JetWidthTool.h create mode 100644 Reconstruction/Jet/JetMomentTools/Root/JetMuonSegmentMomentsTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/Root/JetPtAssociationTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/Root/JetTrackMomentsTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/Root/JetVertexFractionTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/Root/JetWidthTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/cmt/Makefile.RootCore create mode 100755 Reconstruction/Jet/JetMomentTools/cmt/requirements create mode 100644 Reconstruction/Jet/JetMomentTools/python/GhostAssociation.py create mode 100644 Reconstruction/Jet/JetMomentTools/python/JetCopyMomentsAlg.py create mode 100644 Reconstruction/Jet/JetMomentTools/python/JetMomentsConfigHelpers.py create mode 100644 Reconstruction/Jet/JetMomentTools/python/SetupJetMomentTools.py create mode 100644 Reconstruction/Jet/JetMomentTools/src/JetBadChanCorrTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/JetCaloEnergies.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/JetCaloQualityTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/JetIsolationTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/JetLArHVTool.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_entries.cxx create mode 100644 Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_load.cxx diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetBadChanCorrTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetBadChanCorrTool.h new file mode 100644 index 00000000000..e0abbe5288b --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetBadChanCorrTool.h @@ -0,0 +1,185 @@ +// this file is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef JETMOMENTTOOLS_JETBADCHANCORRTOOL_H +#define JETMOMENTTOOLS_JETBADCHANCORRTOOL_H + +/** @class JetBadChanCorrTol. + Calculates correction for dead cells + + It produces and stores three jet moment : BchCorrCell, BchCorrDotx, BchCorrJet + after computing the energy fraction of dead cells. + + IMPORTANT : this run2 implementation is less complete than before. + -> it can not make use of the older IHadronicCalibrationTool (wasn't used by default anyway) + and therefore doesn't take the cryostat correction into account. + + Also it now requires the existence of a MissingCaloCellsMap in SG. + + Lots of commented blocks are still around until we're sure they're not needed anymore. + + @author Yousuke Kataoka + @date (first implementation) December , 2009 + @author P.A. Delsart + @date (faster implementation) March , 2011 + @date (Run 2 re-implemantation) March , 2013 + +*/ + + +#include "JetRec/JetModifierBase.h" + +#include "JetRecTools/MissingCellListTool.h" + +#include "CaloIdentifier/CaloCell_ID.h" + +#include "TH1D.h" + + +class Identifier; +class CaloDetDescrManager; + +class ITileBadChanTool; +class ILArBadChanTool; +class ITHistSvc; + +class JetBadChanCorrTool: public JetModifierBase +{ + ASG_TOOL_CLASS0(JetBadChanCorrTool); +public: + JetBadChanCorrTool(const std::string& name); + + virtual ~JetBadChanCorrTool(); + + virtual StatusCode initialize(); + + virtual int modifyJet( xAOD::Jet& pJet) const ; + + virtual StatusCode setupEvent(); + + +protected: + int correctionFromCellsInJet( xAOD::Jet* j, const jet::CaloCellFastMap * badCellMap) const; + int correctionFromCellsInCone( xAOD::Jet* j, const jet::CaloCellFastMap * badCellMap) const; + + int correctionFromClustersBadCells( xAOD::Jet* j) const; + + private: + + ServiceHandle<ITHistSvc> m_thistSvc; + + // const CaloDetDescrManager* m_caloDDM; + // const CaloCell_ID* m_calo_id; + + // limit to calculate moments + int m_nBadCellLimit; + + + + + + // for jet-level correction + std::string m_streamName; + std::string m_profileName; + std::string m_profileTag; + + bool m_useCone; + // double m_coneDr; + + // for cell-level correction + bool m_useCalibScale; + //ToolHandle<IHadronicCalibrationTool> m_calibTool; + + //ToolHandle<IMissingCellListTool> m_missingCellToolHandle; + //MissingCellListTool* m_missingCellTool; + std::string m_missingCellMapName; + + bool m_forceMissingCellCheck; + + bool m_useClusters; + + // jet profiles + class ProfileData { + public: + ProfileData(TH1D* th, int sample, + double ptMin=0, double ptMax=9999, + double etaMin=0, double etaMax=5.0, + double phiMin=-M_PI, double phiMax=M_PI): + th(th), sample(sample), + ptMin(ptMin), ptMax(ptMax), + etaMin(etaMin), etaMax(etaMax), + phiMin(phiMin), phiMax(phiMax) {} + + virtual ~ProfileData(){} + + bool match(double pt, int sample, double eta, double phi) const { + return ( pt>=ptMin && pt<ptMax + && sample==this->sample + && fabs(eta)>=etaMin && fabs(eta)<etaMax + && phi>=phiMin && phi<phiMax); + } + + double frac(double dr) const { + int idr = th->FindBin(dr); + return th->GetBinContent(idr); + } + private: + TH1D* th; + int sample; + double ptMin; + double ptMax; + double etaMin; + double etaMax; + double phiMin; + double phiMax; + }; + std::vector<ProfileData> m_profileDatas[CaloCell_ID::Unknown];//24 + + double getProfile(double pt, double dr, int sample, double eta, double phi) const; + +}; +#endif +// DoxygenDocumentation +/*! @class JetBadChanCorrTool + @brief JetBadChanCorrTool + +The energy fraction of dead cells are estimated by jet-level estimator using jet profile. +Some cells are already corrected in cell-level using neighboring cells, so this fraction is calculated. +The estimation by jet-level for those cells corrected in cell-level is also stored to see the difference or combined the corrections. + +BCH_CORR_JET= jet level estimation of the energy fraction of dead cells +BCH_CORR_CELL= cell level correction, which is already corrected +BCH_CORR_JET_FORCELL= jet level estimation for the corrected cells in cell level + +The relation and usage of the moment is +jet = jet already corrected in cell level +jet x ( 1 - BCH_CORR_CELL ) = jet without cell level correction +jet x ( 1 - BCH_CORR_CELL + BCH_CORR_JET ) = jet corrected by jet level estimation +jet x ( 1 + BCH_CORR_JET - BCH_CORR_JET_FORCELL ) = jet with cell level correction and corrected in jet level for not covered cells + + +<b>Properties:</b> +<table style="text-align: left; width: 80%;" border="1"> +<tr><td> <b>Name</b> </td> <td><b>Type</b> </td> <td><b>Default</b> </td> <td><b>Description</b></td></tr> + +<tr><td>ProcessNJetMax </td> <td> </td> <td>999999 </td> <td></td></tr> +<tr><td>NBadCellLimit </td> <td> </td> <td>10000 </td> <td>limit to calculate the moments, if exceed, giving up the calculation ie) when Calorimeter off</td></tr> +<tr><td>AttachCorrCell </td> <td> </td> <td>True </td> <td>switch to attach BCH_CORR_CELL</td></tr> +<tr><td>AttachCorrDOTX </td> <td> </td> <td>True </td> <td>switch to attach BCH_CORR_DOTX</td></tr> +<tr><td>AttachCorrJet </td> <td> </td> <td>True </td> <td>switch to attach BCH_CORR_JET</td></tr> +<tr><td>AttachCorrJetForCell </td> <td> </td> <td>True </td> <td>switch to attach BCH_CORR_JET_FORCELL</td></tr> + +<tr><td>StreamName </td> <td> </td> <td>"/JetBadChanCorrTool/" </td> <td>name of stream name</td></tr> +<tr><td>ProfileName </td> <td> </td> <td>"JetBadChanCorrTool.root" </td> <td>name of profile data</td></tr> +<tr><td>ProfileTag </td> <td> </td> <td>"" </td> <td>tag to select profile,"" for all in file</td></tr> +<tr><td>UseCone </td> <td> </td> <td>True </td> <td>boundary of correction, cone or only associated cells</td></tr> +<tr><td>ConeDr </td> <td> </td> <td>0.4 </td> <td>boundary of correction in case UseCone=True</td></tr> +<tr><td>UseCalibScale </td> <td> </td> <td>False </td> <td>scale for calculation of the contribution of bad cells</td></tr> +<tr><td>CellCalibrator </td> <td> </td> <td> </td> <td>calibration tool for cell-level correction</td></tr> + +</table> +*/ + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloEnergies.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloEnergies.h new file mode 100644 index 00000000000..c7ee80fc727 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloEnergies.h @@ -0,0 +1,27 @@ +// this file is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef JETMOMENTTOOLS_JETCALOENERGIES_H +#define JETMOMENTTOOLS_JETCALOENERGIES_H + +#include "JetRec/JetModifierBase.h" + +class JetCaloEnergies : public JetModifierBase { + ASG_TOOL_CLASS0(JetCaloEnergies); +public: + + JetCaloEnergies(const std::string & t); + + + virtual int modifyJet(xAOD::Jet& ) const ; + + +}; + + +#undef ASG_DERIVED_TOOL_CLASS +#endif + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloQualityTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloQualityTool.h new file mode 100644 index 00000000000..cfeab4afea8 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetCaloQualityTool.h @@ -0,0 +1,66 @@ +// this file is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +/** + @class JetCaloQualityTool + Calculates calorimeter based variables for jet quality + @author Nikola Makovec + @author P-A Delsart + @date (first implementation) October , 2009 + @date (run 2 implementation) February , 2014 +*/ + +#ifndef JETREC_JETCALOQUALITYTOOL_H +#define JETREC_JETCALOQUALITYTOOL_H + + +#include "JetRec/JetModifierBase.h" + +#include "JetUtils/JetCaloCalculations.h" + +#include <vector> +#include <string> + + +class JetCaloQualityTool: public JetModifierBase { + ASG_TOOL_CLASS0(JetCaloQualityTool); + +public: + JetCaloQualityTool(const std::string & name); + + virtual int modifyJet(xAOD::Jet& ) const ; + + virtual StatusCode initialize(); + + private: + + int m_LArQualityCut; + int m_TileQualityCut; + + bool m_doFracSamplingMax; + + bool m_doN90; + bool m_doLArQuality; + bool m_doTileQuality; + bool m_doTiming; + bool m_doHECQuality; + bool m_doNegativeE; + bool m_doAverageLArQF; + bool m_timingOnlyPosE; + bool m_computeFromCluster; + bool m_doJetCentroid; + + + std::vector <double> m_timingCellTimeCuts; + std::vector <double> m_timingClusterTimeCuts; + + mutable jet::JetCaloCalculations m_jetCalculations; + + +}; +#endif + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetIsolationTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetIsolationTool.h new file mode 100644 index 00000000000..f1bbd89509f --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetIsolationTool.h @@ -0,0 +1,147 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetIsolationTool.h +// Header file for class JetIsolationTool +// Author: P-A. Delsart +/////////////////////////////////////////////////////////////////// +#ifndef JETMOMENTTOOLS_JETISOLATIONTOOL_H +#define JETMOMENTTOOLS_JETISOLATIONTOOL_H 1 + +#include "JetRec/JetModifierBase.h" +#include "JetUtils/TiledEtaPhiMap.h" +#include "AsgTools/CLASS_DEF.h" + +/////////////////////////////////////////////////////////////////// +/// \class JetIsolationTool +/// +/// This JetModifier calculates isolation variables for jets. +/// +/// The isolation variables are calculated from a list of input particles +/// which are close to the jet but not part of its constituents. +/// There are multiple options to find this list and then to calculate the +/// variables. +/// They are passed to the tools by giving a list of string identifiers through +/// the IsolationCalculations property as in +/// +/// IsolationCalculations = ["IsoKR:11:Perp","IsoKR:11:Par", "IsoFixedCone:10:SumPt",] +/// +/// where the strings have the form "ISOCRITERIA:NN:VAR" +/// - ISOCRITERIA : encode the method used to find isolation particles (IsoKR, IsoDelta, IsoFixedCone, IsoFixedArea, Iso6To8) +/// - NN : encode the value of the main parameter of ISOCRITERIA : the actual parameter used is NN/10. (same convetion as jet radius in JetContainer names) +/// - VAR : encode the variable to be calculated (Per, Par, SumPt, P) +/// +/// The input particles container from which constituents come from must be specified +/// in the ConstituentContainer property. This must correspond to an IParticleContainer in the event store. +/// (longer term : make it possible to pass PseudoJetContainer) +/// +/// +/// There are several technical difficulties +/// - the multiplicity of possible variables +/// - the dependency on the calibration state of the constituents +/// - the calculation time (looking up the full input container for each jet constituents can be *very* slow) +/// These are solved at the cost of increased multiplicity (internal helper classes, usage of a special fast lookup map) +/// +/// WARNING : currently works well only for LCTopoJets, TrackJets, TruthJets AND small R jets (R ~<0.8) +/// +/////////////////////////////////////////////////////////////////////// + +namespace jet { + namespace JetIsolation { + class IsolationCalculator; + } + + /// \class ParticlePosition + /// Object describing the position of a particle in (eta,phi) and usable within a + /// TiledEtaPhiMap (see below). + struct ParticlePosition { + ParticlePosition(const xAOD::IParticle* p, int sigstate=-1): m_eta(p->eta()), m_phi(p->phi()) ,m_part(p), m_sigState(sigstate){}; + ParticlePosition(double x=0, double y=0):m_eta(x),m_phi(y),m_part(NULL), m_sigState(-1){} + double x() const {return m_eta;} + double y() const {return m_phi;} + void setX(double x){m_eta=x;} + void setY(double x){m_phi=x;} + + const xAOD::IParticle* particle()const {return m_part;} + void setParticle(const xAOD::IParticle* p){m_part=p;} + + struct DR2 { + double operator()(const ParticlePosition &p1,const ParticlePosition &p2) const { + return JetTiledMap::utils::DR2(p1.x(),p1.y(), p2.x(), p2.y() ); + } + }; + + + protected: + double m_eta,m_phi; + const xAOD::IParticle* m_part ; + int m_sigState; // if any + }; + + /// This map is a geometric helper. It greatly speeds up the retrieval + /// of a set of point around a given position in (eta,phi). + /// It is saved in the event store, so it's not rebuild for every JetContainer + /// (could be factorized in a separate AlgTool if needed) + typedef JetTiledMap::TiledEtaPhiMap<ParticlePosition> ParticleFastMap; + +} + + +class JetIsolationTool + : public JetModifierBase +{ + ASG_TOOL_CLASS0(JetIsolationTool); + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + friend class jet::JetIsolation::IsolationCalculator; + + // Copy constructor: + + /// Constructor with parameters: + JetIsolationTool(const std::string &myname); + + /// Destructor: + virtual ~JetIsolationTool(); + + // Athena algtool's Hooks + virtual StatusCode initialize(); + virtual StatusCode finalize(); + + virtual int modify(xAOD::JetContainer& jets) const; + virtual int modifyJet(xAOD::Jet& ) const{return 0;}; + + + + /////////////////////////////////////////////////////////////////// + + +protected: + + + const jet::ParticleFastMap * retrieveInputMap() const ; + + private: + + + std::vector<std::string> m_isolationCodes; + float m_deltaRmax; + std::string m_inputPseudoJets; + + std::vector<jet::JetIsolation::IsolationCalculator*> m_isoCalculators; + + + bool m_rejectNegE; + + +}; + + +CLASS_DEF(jet::ParticleFastMap , 106240765 , 1) + +#endif //> !JETMOMENTTOOLS_JETISOLATIONTOOL_H diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetLArHVTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetLArHVTool.h new file mode 100644 index 00000000000..a9abdf5dd41 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetLArHVTool.h @@ -0,0 +1,58 @@ +// this file is -*- C++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +/** + @class JetLArHVTool + Calculates calorimeter based variables for jet quality + @author Nikola Makovec + @author P-A Delsart + @date (first implementation) October , 2009 + @date (run 2 implementation) February , 2014 +*/ + +#ifndef JETMOMENTTOOLS_JETLARHVTOOL_H +#define JETMOMENTTOOLS_JETLARHVTOOL_H + +#include "JetRec/JetModifierBase.h" +#include "AsgTools/ToolHandle.h" + + +#include "LArElecCalib/ILArHVCorrTool.h" + +class JetLArHVTool: public JetModifierBase { + ASG_TOOL_CLASS0(JetLArHVTool); + +public: + JetLArHVTool(const std::string & name); + + virtual int modifyJet(xAOD::Jet& ) const ; + + virtual StatusCode initialize(); + + private: + + bool m_useCells; + std::string m_channelKey; + std::string m_keyHVScaleCorr; + +#ifdef ASGTOOL_ATHENA + ToolHandle<ILArHVCorrTool> m_hvCorrTool; +#endif + +}; + +#endif +// DoxygenDocumentation +/*! @class JetLArHVMoment + @brief JetLArHVMoment + + +Calculates the proportion of cells in a bad LAr HV area, and gives an information about the energy affected. +(the second moment should change later). + +</table> +*/ diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetMuonSegmentMomentsTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetMuonSegmentMomentsTool.h new file mode 100644 index 00000000000..b8de3c3ff6a --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetMuonSegmentMomentsTool.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetMuonSegmentMomentsTool.h + +#ifndef JETMOMENTTOOLS_JETMUONSEGMENTMOMENTSTOOL_H +#define JETMOMENTTOOLS_JETMUONSEGMENTMOMENTSTOOL_H + +/// Steven Schramm \n +/// February 2014 +/// +/// Tool to calculate general muon segment based jet moments +/// Primarily intended for punch-through studies and corrections +/// +/// Moments to calculate: +/// None yet... + +#include "JetRec/JetModifierBase.h" + +class JetMuonSegmentMomentsTool : public JetModifierBase +{ + ASG_TOOL_CLASS(JetMuonSegmentMomentsTool,IJetModifier); + + public: + // Constructor from tool name + JetMuonSegmentMomentsTool(const std::string& name); + + // Inherited methods to modify a jet + virtual int modifyJet(xAOD::Jet& jet) const; + + private: + // Configurable parameters + std::string m_assocMuonSegName; +}; + +#endif + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetPtAssociationTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetPtAssociationTool.h new file mode 100644 index 00000000000..c339a3d15dd --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetPtAssociationTool.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetPtAssociationTool.h + +#ifndef JetMomentTools_JetPtAssociationTool_H +#define JetMomentTools_JetPtAssociationTool_H + +/// David Adams \n +/// April 2014 +/// +/// Tool to associate jets using the fraction of AP (associated particle) pT +/// shared with the constituents of jets in a matching container. +/// Properties: +/// AssociationName - Name of the association +/// InputContainer - Name of the matching jet container + +#include "JetRec/JetModifierBase.h" +#include "xAODJet/JetContainer.h" + +class JetPtAssociationTool : public JetModifierBase { + ASG_TOOL_CLASS(JetPtAssociationTool, IJetModifier); + +public: + + typedef std::vector<const xAOD::IParticle*> APVector; + typedef std::vector<unsigned> IndexVector; + typedef std::vector<float> FloatVector; + +public: + + /// Constructor from tool name. + JetPtAssociationTool(std::string myname); + + /// Initialization. + StatusCode initialize(); + + /// Inherited method to modify a jet. + /// Extract and record the element link and pT fraction + /// for the jet with the highest such fraction. + int modifyJet(xAOD::Jet& jet) const; + + /// Return the matched pT sum for each jet in a collection. + /// The matching is done with match(). + /// aps - input AP vector + /// jet - Jet to be matched + /// ptsums - output vector with matched pT fraction for each jet + int ptfrac(const APVector& aps, const xAOD::JetContainer& jets, FloatVector& ptsums) const; + + /// Return the vector of AP's that appear as + /// constituents of the given jet. + /// aps - input AP vector + /// jet - Jet to be matched + /// apvs - output vector of matched AP indices + int match(const APVector& aps, const xAOD::Jet& jet, APVector& apvs) const; + +private: // data + + /// Properties. + std::string m_aname; + std::string m_conname; + +}; + +#endif diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetTrackMomentsTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetTrackMomentsTool.h new file mode 100644 index 00000000000..7212e47f0cc --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetTrackMomentsTool.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetTrackMomentsTool.h + +#ifndef JETMOMENTTOOLS_JETTRACKMOMENTSTOOL_H +#define JETMOMENTTOOLS_JETTRACKMOMENTSTOOL_H + +/// Steven Schramm \n +/// February 2014 +/// +/// Tool to calculate general track-based jet moments +/// +/// Moments to calculate: +/// NumTrkPtXXX +/// SumPtTrkPtXXX +/// TrackWidthPtXXX +/// where the track pT threhsold is XXX MeV. + +#include "JetRec/JetModifierBase.h" +#include "JetEDM/TrackVertexAssociation.h" + +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/Vertex.h" +#include "xAODTracking/VertexContainer.h" + +#include <vector> +#include <string> + + +class JetTrackMomentsTool : public JetModifierBase { + ASG_TOOL_CLASS(JetTrackMomentsTool,IJetModifier); + +public: + + // Constructor from tool name + JetTrackMomentsTool(const std::string& name); + + // Inherited methods to modify a jet + // Calls getTrackMoments and puts the results in the jet + virtual int modifyJet(xAOD::Jet& jet) const; + +private: + + // Configurable parameters + std::string m_vertexContainer; + std::string m_assocTracksName; + std::string m_tva; + std::vector<float> m_minTrackPt; + + // Private struct to make it unambiguous what each value is (rather than a vector) + // Doubles for calculation for now - will be written as float in the aux store + struct TrackMomentStruct { int numTrk; double sumPtTrk; double trackWidth; }; + + // Local method to calculate NumTrk, SumPtTrk, and TrackWidth for all vertices + const std::vector<TrackMomentStruct> + getTrackMoments(const xAOD::Jet& jet, const xAOD::VertexContainer* vertices, + const float minTrackPt, const std::vector<const xAOD::TrackParticle*>& tracks, + const jet::TrackVertexAssociation* tva) const; + + // Local method to calculate NumTrk, SumPtTrk, and TrackWidth for one vertex + TrackMomentStruct + getTrackMoments(const xAOD::Jet&, const xAOD::Vertex* vertex, const float minTrackPt, + const std::vector<const xAOD::TrackParticle*>& tracks, + const jet::TrackVertexAssociation* tva) const; + + // Parse the float to get a moment base name + const std::string getMomentBaseName(const float minTrackPt) const; + +}; + +#endif + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetVertexFractionTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetVertexFractionTool.h new file mode 100644 index 00000000000..9ef955bdf85 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetVertexFractionTool.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetVertexFractionTool.h + +#ifndef JETMOMENTTOOLS_JETVERTEXFRACTIONTOOL_H +#define JETMOMENTTOOLS_JETVERTEXFRACTIONTOOL_H + +/// Steven Schramm \n +/// February 2014 +/// +/// Tool to calculate the jet vertex fraction (JVF) +/// JVF is a vector<float> with respect to all vertices +/// +/// Calculation requires three main types of information +/// 1. Vertex container for the event (from evtStore), which the JVF vector is aligned with +/// 2. Tracks associated to the input jet (in the jet aux store) +/// 3. Track vertex association object (from evtStore) +/// +/// Using this information, the procedure can be broken into three main steps: +/// 1. Retrieve necessary information +/// 2. Helper method to create the full vector given the information +/// 3. Helper method to create the JVF value for one vertex given the information + +#include "xAODTracking/Vertex.h" +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/TrackParticleContainer.h" + +#include "JetRec/JetModifierBase.h" +#include "JetEDM/TrackVertexAssociation.h" + +#include <vector> +#include <string> + +class JetVertexFractionTool : public JetModifierBase +{ + ASG_TOOL_CLASS(JetVertexFractionTool,IJetModifier); + + public: + // Constructor from tool name + JetVertexFractionTool(const std::string& name); + + // Inherited methods to modify a jet + // Calls getJetVertexFraction and puts the result in the jet + virtual int modifyJet(xAOD::Jet& jet) const; + + // Local method to calculate and return the JVF vector + const std::vector<float> getJetVertexFraction(const xAOD::VertexContainer*, const std::vector<const xAOD::TrackParticle*>&, const jet::TrackVertexAssociation*) const; + + // Local method to calculate the JVF for a given vertex + float getJetVertexFraction(const xAOD::Vertex*, const std::vector<const xAOD::TrackParticle*>&, const jet::TrackVertexAssociation*) const; + + // Local method to determine the highest JVF vertex and get an ElementLink to it + ElementLink<xAOD::VertexContainer> getMaxJetVertexFraction(const xAOD::VertexContainer*, const std::vector<float>&) const; + + private: + // Configurable parameters + std::string m_verticesName; + std::string m_assocTracksName; + std::string m_tvaName; + + std::vector<float> getEmptyJetVertexFraction(const xAOD::VertexContainer*) const; + +}; + + +#endif + diff --git a/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetWidthTool.h b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetWidthTool.h new file mode 100644 index 00000000000..9dc6f4ac9c1 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/JetMomentTools/JetWidthTool.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetWidthTool.h + +#ifndef JetMomentTools_JetWidthTool_H +#define JetMomentTools_JetWidthTool_H + +/// Steven Schramm and David Adams \n +/// February 2014 +/// +/// Tool to calculate the jet width. + +#include "JetRec/JetModifierBase.h" + +class JetWidthTool : public JetModifierBase { + ASG_TOOL_CLASS(JetWidthTool, IJetModifier); + +public: + + // Constructor from tool name. + JetWidthTool(std::string myname); + + // Inherited method to modify a jet. + // Calls width and puts the result on the jet. + virtual int modifyJet(xAOD::Jet& jet) const; + + // Local method to calculate and return the width. + double width(const xAOD::Jet& jet) const; + +}; + +#endif diff --git a/Reconstruction/Jet/JetMomentTools/Root/JetMuonSegmentMomentsTool.cxx b/Reconstruction/Jet/JetMomentTools/Root/JetMuonSegmentMomentsTool.cxx new file mode 100644 index 00000000000..b781cb906e9 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/Root/JetMuonSegmentMomentsTool.cxx @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JetMomentTools/JetMuonSegmentMomentsTool.h" + +JetMuonSegmentMomentsTool::JetMuonSegmentMomentsTool(const std::string& name) + : JetModifierBase(name) + , m_assocMuonSegName("GhostMuonSegment") +{ + declareProperty("AssociatedMuonSegments", m_assocMuonSegName); +} + +int JetMuonSegmentMomentsTool::modifyJet(xAOD::Jet& jet) const { + // Get muon segments associated to the jet + // Note that there are often no segments + std::vector<const xAOD::IParticle*> segments; + bool havesegs = jet.getAssociatedObjects(m_assocMuonSegName, segments); + + if ( ! havesegs ) { + ATH_MSG_ERROR("Muon segments not found."); + return 1; + } else { + ATH_MSG_DEBUG("Jet has " << segments.size() << " muon segments."); + } + + return 0; +} + + diff --git a/Reconstruction/Jet/JetMomentTools/Root/JetPtAssociationTool.cxx b/Reconstruction/Jet/JetMomentTools/Root/JetPtAssociationTool.cxx new file mode 100644 index 00000000000..cea7a27d6f1 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/Root/JetPtAssociationTool.cxx @@ -0,0 +1,123 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetPtAssociationTool.cxx + +#include "JetMomentTools/JetPtAssociationTool.h" + +using std::string; +using xAOD::IParticle; +using xAOD::Jet; +using xAOD::JetContainer; +using xAOD::JetConstituent; +using xAOD::JetConstituentVector; + +//********************************************************************** + +JetPtAssociationTool::JetPtAssociationTool(std::string myname) +: JetModifierBase(myname) { + declareProperty("AssociationName", m_aname); + declareProperty("InputContainer", m_conname); +} + +//********************************************************************** + +StatusCode JetPtAssociationTool::initialize() { + return StatusCode::SUCCESS; +} + +//********************************************************************** + +int JetPtAssociationTool::modifyJet(xAOD::Jet& jet) const { + ATH_MSG_DEBUG("Processing jet " << jet.index()); + APVector apins; + // Retrieve the association vector. + if ( ! jet.getAssociatedObjects(m_aname, apins) ) { + ATH_MSG_WARNING("Jet does not have association vector " << m_aname); + return 1; + } + // Retrieve the container of jets to be matched. + const JetContainer* pjets = evtStore()->retrieve<const JetContainer>(m_conname); + if ( pjets == 0 ) { + ATH_MSG_WARNING("Matching jet container not found: " << m_conname); + return 2; + } + // Match associated particle to jets. + FloatVector ptfs; + if ( ptfrac(apins, *pjets, ptfs) ) { + ATH_MSG_WARNING("Match of association vector to jets failed"); + return 3; + } + // Find the best match. + float frac = 0.0; + unsigned int ijet_matched = ptfs.size(); + for ( unsigned int ijet=0; ijet<ptfs.size(); ++ijet ) { + ATH_MSG_VERBOSE(" Pt fraction[" << ijet << "]: " << ptfs[ijet]); + if ( ptfs[ijet] > frac ) { + frac = ptfs[ijet]; + ijet_matched = ijet; + } + } + ElementLink<JetContainer> el; + if ( ijet_matched < ptfs.size() ) { + el = ElementLink<JetContainer>(*pjets, ijet_matched); + } + string sfrac = m_aname + "AssociationFraction"; + string slink = m_aname + "AssociationLink"; + ATH_MSG_DEBUG(" Setting " << sfrac << " = " << frac); + jet.setAttribute(sfrac, frac); + ATH_MSG_DEBUG(" Setting " << slink << " = " + << el.dataID() << "[" << el.index() << "]"); + jet.setAttribute(slink, el); + return 0; +} + +//********************************************************************** + +int JetPtAssociationTool:: +ptfrac(const APVector& apins, const xAOD::JetContainer& jets, FloatVector& ptfs) const { + ptfs.clear(); + ptfs.resize(jets.size(), 0.0); + double ptden = 0.0; + for ( const IParticle* ppar : apins ) { + if ( ppar == 0 ) return -1; + ptden += ppar->pt(); + } + if ( ptden < 0.0 ) return -2; + if ( ptden < 1.e-20 ) return 0; + ATH_MSG_DEBUG("Match jet count: " << jets.size()); + for ( unsigned int ijet=0; ijet<jets.size(); ++ijet ) { + const Jet* pjet = jets[ijet]; + if ( pjet == 0 ) return -3; + APVector apouts; + match(apins, *pjet, apouts); + double ptsum = 0.0; + for ( const IParticle* ppar : apouts ) { + if ( ppar == 0 ) return -4; + ptsum += ppar->pt(); + } + ptfs[ijet] = ptsum/ptden; + } + return 0; +} + +//********************************************************************** + +int JetPtAssociationTool:: +match(const APVector& aps, const xAOD::Jet& jet, APVector& apvs) const { + apvs.clear(); + const JetConstituentVector cons = jet.getConstituents(); + for ( const JetConstituent* pcon : cons ) { + const IParticle* pparcon = pcon->rawConstituent(); + for ( const IParticle* pparap : aps ) { + if ( pparap == pparcon ) { + apvs.push_back(pparcon); + break; + } + } + } + return 0; +} + +//********************************************************************** diff --git a/Reconstruction/Jet/JetMomentTools/Root/JetTrackMomentsTool.cxx b/Reconstruction/Jet/JetMomentTools/Root/JetTrackMomentsTool.cxx new file mode 100644 index 00000000000..a5d7f7840c2 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/Root/JetTrackMomentsTool.cxx @@ -0,0 +1,161 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JetMomentTools/JetTrackMomentsTool.h" +#include <sstream> +#include "JetUtils/JetDistances.h" + +JetTrackMomentsTool::JetTrackMomentsTool(const std::string& name) + : JetModifierBase(name) + , m_vertexContainer("") + , m_assocTracksName("") + , m_tva("") + , m_minTrackPt() +{ + declareProperty("VertexContainer",m_vertexContainer); + declareProperty("AssociatedTracks",m_assocTracksName); + declareProperty("TrackVertexAssociation",m_tva); + declareProperty("TrackMinPtCuts",m_minTrackPt); +} + +int JetTrackMomentsTool::modifyJet(xAOD::Jet& jet) const { + + // Get input vertex collection + const xAOD::VertexContainer* vertexContainer = nullptr; + if ( evtStore()->retrieve(vertexContainer,m_vertexContainer).isFailure() + || vertexContainer == nullptr ) { + ATH_MSG_ERROR("Could not retrieve the VertexContainer from evtStore: " + << m_vertexContainer); + return 1; + } + + // Get the track-vertex association + const jet::TrackVertexAssociation* tva = nullptr; + if ( evtStore()->retrieve(tva,m_tva).isFailure() || tva==nullptr ) { + ATH_MSG_ERROR("Could not retrieve the TrackVertexAssociation from evtStore: " + << m_tva); + return 2; + } + +#if 0 + // Get the tracks associated to the jet + // Note that there may be no tracks + const std::vector<const xAOD::IParticle*> tracksAsParticles; + bool havetracks = jet.getAssociatedObjects(m_assocTracksName, tracksAsParticles); + + if ( ! havetracks ) { + ATH_MSG_WARNING("Associted tracks not found"); + } + + // Do the dynamic_cast once for the particles instead of repeatedly + std::vector<const xAOD::TrackParticle*> tracks; + tracks.resize(tracksAsParticles.size()); + for (size_t iTrack = 0; iTrack < tracksAsParticles.size(); ++iTrack) + { + const xAOD::TrackParticle* track = dynamic_cast<const xAOD::TrackParticle*>(tracksAsParticles.at(iTrack)); + if (!track) + { + ATH_MSG_ERROR("Error converting index " << iTrack << " from IParticle to TrackParticle"); + return 3; + } + tracks[iTrack] = track; + } +#endif + + // Retrieve the associated tracks. + std::vector<const xAOD::TrackParticle*> tracks; + bool havetracks = jet.getAssociatedObjects(m_assocTracksName, tracks); + if ( ! havetracks ) ATH_MSG_WARNING("Associated tracks not found"); + ATH_MSG_DEBUG("Successfully retrieved track particles"); + + // For each track cut, get the associated moments + for (size_t iCut = 0; iCut < m_minTrackPt.size(); ++iCut) { + // Get info + const float minPt = m_minTrackPt.at(iCut); + const std::vector<TrackMomentStruct> moments = + getTrackMoments(jet,vertexContainer,minPt,tracks,tva); + const std::string baseName = getMomentBaseName(minPt); + // Collate info + std::vector<int> numTrkVec; numTrkVec.resize(moments.size()); + std::vector<float> sumPtTrkVec; sumPtTrkVec.resize(moments.size()); + std::vector<float> trackWidthVec; trackWidthVec.resize(moments.size()); + for ( size_t iVertex = 0; iVertex < moments.size(); ++iVertex ) { + numTrkVec[iVertex] = moments.at(iVertex).numTrk; + sumPtTrkVec[iVertex] = moments.at(iVertex).sumPtTrk; + trackWidthVec[iVertex] = moments.at(iVertex).trackWidth; + } + // Set info + jet.setAttribute("NumTrk"+baseName,numTrkVec); + jet.setAttribute("SumPtTrk"+baseName,sumPtTrkVec); + jet.setAttribute("TrackWidth"+baseName,trackWidthVec); + } + + return 0; +} + + +const std::vector<JetTrackMomentsTool::TrackMomentStruct> JetTrackMomentsTool::getTrackMoments(const xAOD::Jet& jet, const xAOD::VertexContainer* vertices, const float minTrackPt, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const +{ + std::vector<TrackMomentStruct> moments; + moments.resize(vertices->size()); + + for (size_t iVertex = 0; iVertex < vertices->size(); ++iVertex) + moments[iVertex] = getTrackMoments(jet,vertices->at(iVertex),minTrackPt,tracks,tva); + + return moments; +} + +JetTrackMomentsTool::TrackMomentStruct JetTrackMomentsTool::getTrackMoments(const xAOD::Jet& jet, const xAOD::Vertex* vertex, const float minTrackPt, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const +{ + // Prepare the moments + TrackMomentStruct moments; + moments.numTrk = 0; + moments.sumPtTrk = 0; + moments.trackWidth = 0; + + // Prepare const vars for jet eta/phi + const float jetEta = jet.eta(); + const float jetPhi = jet.phi(); + + // Loop over the tracks + for (size_t iTrack = 0; iTrack < tracks.size(); ++iTrack) + { + const xAOD::TrackParticle* track = tracks.at(iTrack); + const float trackPt = track->pt(); + + // Skip the track if it doesn't pass the cut + if (trackPt < minTrackPt) + continue; + + // Skip the track if it's not from the vertex in question + if( vertex == nullptr || vertex != tva->associatedVertex(track) ) continue ; + + // Calculate necessary info for the moments + const double deltaR = jet::JetDistances::deltaR(jetEta, jetPhi, track->eta(), track->phi() ); + + // Adjust values as necessary for this track + moments.numTrk += 1; + moments.sumPtTrk += trackPt; + moments.trackWidth += deltaR * trackPt; + } + + // Finish processing the moments + moments.trackWidth = moments.sumPtTrk > 0 ? moments.trackWidth / moments.sumPtTrk : -1; + + return moments; +} + +const std::string JetTrackMomentsTool::getMomentBaseName(const float minTrackPt) const +{ + int value = round(minTrackPt); + if (fabs(value - minTrackPt) > 0.1) + ATH_MSG_WARNING("Cut float and int disagree: " << minTrackPt << " float vs " << value << " int"); + + std::ostringstream sout; + sout << "Pt" << value; + return sout.str(); +} + + diff --git a/Reconstruction/Jet/JetMomentTools/Root/JetVertexFractionTool.cxx b/Reconstruction/Jet/JetMomentTools/Root/JetVertexFractionTool.cxx new file mode 100644 index 00000000000..72948bd303f --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/Root/JetVertexFractionTool.cxx @@ -0,0 +1,115 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JetMomentTools/JetVertexFractionTool.h" + +JetVertexFractionTool::JetVertexFractionTool(const std::string& name) +: JetModifierBase(name) +, m_verticesName("") +, m_assocTracksName("") +, m_tvaName("") +{ + declareProperty("VertexContainer",m_verticesName); + declareProperty("AssociatedTracks",m_assocTracksName); + declareProperty("TrackVertexAssociation",m_tvaName); +} + +int JetVertexFractionTool::modifyJet(xAOD::Jet& jet) const { + + // Get the vertices container + const xAOD::VertexContainer* vertices = NULL; + if ( evtStore()->retrieve(vertices,m_verticesName).isFailure() ) { + ATH_MSG_ERROR("Could not retrieve the VertexContainer from evtStore: " << m_verticesName); + return 1; + } + ATH_MSG_DEBUG("Successfully retrieved VertexContainer from evtStore: " << m_verticesName); + + // Get the tracks associated to the jet + // Note that there may be no tracks - this is both normal and an error case + // In this case, just fill a vector with zero and don't set the highest vtx moment + std::vector<const xAOD::TrackParticle*> tracks; + if ( ! jet.getAssociatedObjects(m_assocTracksName, tracks) ) { + ATH_MSG_WARNING("Associated tracks not found."); + } + + // Get the TVA object + const jet::TrackVertexAssociation* tva = NULL; + if (evtStore()->retrieve(tva,m_tvaName).isFailure()) { + ATH_MSG_ERROR("Could not retrieve the TrackVertexAssociation from evtStore: " << m_tvaName); + return 3; + } + ATH_MSG_DEBUG("Successfully retrieved TrackVertexAssociation from evtStore: " << m_tvaName); + + // Get and set the JVF vector + const std::vector<float> jvf = getJetVertexFraction(vertices,tracks,tva); + jet.setAttribute("JVF",jvf); + + // Get and set the highest JVF vertex + jet.setAttribute("HighestJVFVtx",getMaxJetVertexFraction(vertices,jvf)); + + // Done + return 0; +} + + + +std::vector<float> JetVertexFractionTool::getEmptyJetVertexFraction(const xAOD::VertexContainer* vertices) const +{ + std::vector<float> jvf; + jvf.resize(vertices->size()); + for (size_t iVertex = 0; iVertex < vertices->size(); ++iVertex) + jvf.at(iVertex) = 0; + + return jvf; +} + +const std::vector<float> JetVertexFractionTool::getJetVertexFraction(const xAOD::VertexContainer* vertices, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const +{ + std::vector<float> jvf = getEmptyJetVertexFraction(vertices); + + for (size_t iVertex = 0; iVertex < vertices->size(); ++iVertex) + jvf.at(iVertex) = getJetVertexFraction(vertices->at(iVertex),tracks,tva); + + return jvf; +} + + +float JetVertexFractionTool::getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const +{ + float sumTrackPV = 0; + float sumTrackAll = 0; + + for (size_t iTrack = 0; iTrack < tracks.size(); ++iTrack) { + const xAOD::TrackParticle* track = tracks.at(iTrack); + const xAOD::Vertex* ptvtx = tva->associatedVertex(track); + if ( ptvtx != nullptr ) { + if ( ptvtx->index() == vertex->index() ) sumTrackPV += track->pt(); + } + sumTrackAll += track->pt(); + } + + return sumTrackAll>0 ? sumTrackPV/sumTrackAll : -1; +} + + +ElementLink<xAOD::VertexContainer> JetVertexFractionTool::getMaxJetVertexFraction(const xAOD::VertexContainer* vertices, const std::vector<float>& jvf) const +{ + size_t maxIndex = 0; + float maxVal = -100; + + for (size_t iVertex = 0; iVertex < jvf.size(); ++iVertex) + if (jvf.at(iVertex) > maxVal) + { + maxIndex = iVertex; + maxVal = jvf.at(iVertex); + } + + ElementLink<xAOD::VertexContainer> link = ElementLink<xAOD::VertexContainer>(*vertices,vertices->at(maxIndex)->index()); + + return link; +} + + + diff --git a/Reconstruction/Jet/JetMomentTools/Root/JetWidthTool.cxx b/Reconstruction/Jet/JetMomentTools/Root/JetWidthTool.cxx new file mode 100644 index 00000000000..a006afce73e --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/Root/JetWidthTool.cxx @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetWidthTool.cxx + +#include "JetMomentTools/JetWidthTool.h" + +#include "xAODJet/JetConstituentVector.h" +#include "JetUtils/JetDistances.h" + +//********************************************************************** + +JetWidthTool::JetWidthTool(std::string myname) +: JetModifierBase(myname) { } + +//********************************************************************** + +int JetWidthTool::modifyJet(xAOD::Jet& jet) const { + jet.setAttribute("Width", width(jet)); + return 0; +} + +//********************************************************************** + +double JetWidthTool::width(const xAOD::Jet& jet) const { + + // Get the constituents of the jet + const xAOD::JetConstituentVector constituents = jet.getConstituents(); + xAOD::JetConstituentVector::iterator iter = constituents.begin(); + xAOD::JetConstituentVector::iterator iEnd = constituents.end(); + + // TODO: Switch to using helper function once JetUtils has been updated + // Set the width + // jetWidth = JetKinematics::ptWeightedWidth(iter,iEnd,&jet); + + // Calculate the pt weighted width + const double jetEta = jet.eta(); + const double jetPhi = jet.phi(); + double weightedWidth = 0; + double ptSum = 0; + + for ( ; iter != iEnd; ++iter) { + const double dR = jet::JetDistances::deltaR(jetEta, jetPhi, iter->eta(), iter->phi() ); + const double pt = iter->pt(); + weightedWidth += dR * pt; + ptSum += pt; + } + + return ptSum > 0 ? weightedWidth/ptSum : -1; +} + +//********************************************************************** diff --git a/Reconstruction/Jet/JetMomentTools/cmt/Makefile.RootCore b/Reconstruction/Jet/JetMomentTools/cmt/Makefile.RootCore new file mode 100644 index 00000000000..08a084251e3 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/cmt/Makefile.RootCore @@ -0,0 +1,24 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + +PACKAGE = JetMomentTools +PACKAGE_PRELOAD = +PACKAGE_CXXFLAGS = +PACKAGE_OBJFLAGS = +PACKAGE_LDFLAGS = +PACKAGE_BINFLAGS = +PACKAGE_LIBFLAGS = +PACKAGE_DEP = xAODJet JetEDM JetInterface JetRec +PACKAGE_TRYDEP = +PACKAGE_CLEAN = +PACKAGE_NOGRID = +PACKAGE_PEDANTIC = 0 +PACKAGE_NOOPT = 0 +PACKAGE_NOCC = 0 +PACKAGE_REFLEX = 0 + +include $(ROOTCOREDIR)/Makefile-common diff --git a/Reconstruction/Jet/JetMomentTools/cmt/requirements b/Reconstruction/Jet/JetMomentTools/cmt/requirements new file mode 100755 index 00000000000..031621bd8ed --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/cmt/requirements @@ -0,0 +1,31 @@ +package JetMomentTools + +author P-A Delsart <delsart at in2p3 fr> + +private +use xAODCaloEvent xAODCaloEvent-* Event/xAOD +use CaloDetDescr CaloDetDescr-* Calorimeter +use CaloEvent CaloEvent-* Calorimeter +use PathResolver PathResolver-* Tools +use AthenaKernel AthenaKernel-* Control + +public +use AtlasPolicy AtlasPolicy-* +use AtlasROOT AtlasROOT-* External +use GaudiInterface GaudiInterface-* External +use CaloIdentifier CaloIdentifier-* Calorimeter +use xAODJet xAODJet-* Event/xAOD +use JetEDM JetEDM-* Reconstruction/Jet +use JetRec JetRec-* Reconstruction/Jet +use JetUtils JetUtils-* Reconstruction/Jet +use JetRecTools JetRecTools-* Reconstruction/Jet +use xAODTracking xAODTracking-* Event/xAOD +use AsgTools AsgTools-* Control/AthToolSupport +use LArElecCalib LArElecCalib-* LArCalorimeter + +library JetMomentTools *.cxx ../Root/*.cxx -s=components *.cxx +apply_pattern component_library + +apply_pattern declare_runtime files="*.root *.txt" + +#macro_prepend asNeeded_linkopt "-lJetEDM " diff --git a/Reconstruction/Jet/JetMomentTools/python/GhostAssociation.py b/Reconstruction/Jet/JetMomentTools/python/GhostAssociation.py new file mode 100644 index 00000000000..645c1e94ee9 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/python/GhostAssociation.py @@ -0,0 +1,148 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +from AthenaCommon.AlgSequence import AlgSequence +def interpretJetName(jetcollName, finder = None,input=None, mainParam=None): + # first step : guess the finder, input , mainParam, if needed + if finder is None: + for a in [ 'AntiKt','CamKt','Kt', 'Cone','SISCone','CMSCone']: + if jetcollName.startswith(a): + finder = a + break + if finder is None: + print "Error could not guess jet finder type in ",jetcollName + return + + if input is None: + for i in ['LCTopo','Tower','Topo', "Truth"]: + if i in jetcollName: + input = i + if i== "Tower": + if 'Ghost' in jetcollName: + input = 'Tower' + else: + input = "TopoTower" + break + if input is None: + print "Error could not guess input type in ",jetcollName + return + + if mainParam is None: + # get the 2 chars following finder : + mp = jetcollName[len(finder):len(finder)+2] + mp = mp[0] if not mp[1] in '0123456789' else mp + try : + mainParam = float(mp)/10. + except ValueError : + print "Error could not guess main parameter in ",jetcollName + return + + return finder, input, mainParam + + + + +def setupGhostAssociator(assocName, assocType, assocKeys="", seq=AlgSequence()): + from JetMomentTools.JetMomentToolsConf import GhostAssociator_JetINav4MomAssociation_ , GhostTrackAssociator , GhostAssociator_TruthPtAssociation_ + + # make sure the associated container key is given as a list + assocKeys = [assocKeys] if not isinstance(assocKeys, list) else assocKeys + + # get the correct associator + if assocType == "TrackAssociation": + assocTool = GhostTrackAssociator(assocName, AssociationName = assocName, AssociatedContainers = assocKeys ) + assocTool.UseTrackSelector = True + from JetRec.TrackSelectionForJets import getDefaultJetVtxTrackHelper + assocTool.TrackSelector = getDefaultJetVtxTrackHelper() + elif assocType == "TruthAssociation": + from JetSimTools.JetTruthParticleFilterGetter import JetTruthParticleFilterGetter + if assocKeys == [""]: + assocKeys = [JetTruthParticleFilterGetter(seq=seq)._outputName] + assocTool = GhostAssociator_JetINav4MomAssociation_(assocName, AssociationName = assocName, AssociatedContainers = assocKeys, AssociatedPtMoment="pt_truth" ) + elif assocType == "TruthPtAssociation": + from JetSimTools.JetTruthParticleFilterGetter import JetTruthParticleFilterGetter + if assocKeys == [""]: + assocKeys = [JetTruthParticleFilterGetter(seq=seq)._outputName] + assocTool = GhostAssociator_TruthPtAssociation_(assocName, AssociationName = assocName, AssociatedContainers = assocKeys ) + else: + #print "Can't associate to ",assocType, " will use a generic association JetINav4MomAssociation" + assocTool = GhostAssociator_JetINav4MomAssociation_(assocName, AssociationName = assocName, AssociatedContainers = assocKeys ) + + return assocTool + + +def defaultGhostAssociator( assocName, seq=AlgSequence() ): + """Shorcuts for creating usual ghost associators """ + if assocName == "TrackAssoc": + from JetRec.TrackSelectionForJets import trackParticleContainer + return setupGhostAssociator( "TrackAssoc", "TrackAssociation", [trackParticleContainer] , seq=seq) + elif assocName == "TruthPt": + return setupGhostAssociator( "TruthPt", "TruthPtAssociation", seq=seq) + elif assocName == "TruthAssoc": + return setupGhostAssociator( "TruthAssoc", "TruthAssociation", seq=seq) + elif assocName == "TruthBHadron": + return setupGhostAssociator( "TruthBHadron", "", ["TruthBHadrons"], seq=seq) + + + +def setupGhostAssociationTool(jetcollName, ghostsAssoc = [], finder = None,input=None, mainParam=None, seq = AlgSequence()): + from JetMomentTools.JetMomentToolsConf import GhostAssociationTool + from JetRec.JetGetters import getStandardInputTools, getStandardFinderTools + + # first step : guess the finder, input , mainParam, if needed + finder, input, mainParam = interpretJetName( jetcollName, finder, input, mainParam) + replaceNegEnergy = 'Ghost' in input + + #print 'Will create an association by re-running with this jet alg : ', finder, mainParam, input + + # Create the tool + t= GhostAssociationTool("JetGhostAsso") + ghostAssocTools = [] + for g in ghostsAssoc: + if isinstance(g,str): + ghostAssocTools.append( defaultGhostAssociator(g,seq=seq) ) + else: ## Assume g is a GhostAssociator + ghostAssocTools.append( g) + + t.GhostAssociators = ghostAssocTools + t.JetFindingSequence = getStandardInputTools( input, replaceNegEnergy =replaceNegEnergy )+getStandardFinderTools( finder , mainParam) + t.JetFindingSequence[0].NoCleanup = True # Necessary ! + + return t + + +def addGhostAssociation(jetcollName, ghostAssoc = [], finder = None,input=None, mainParam=None, seq=AlgSequence()): + from JetRec.JetMomentGetter import make_JetMomentGetter + + t = setupGhostAssociationTool( jetcollName, ghostAssoc, finder ,input, mainParam, seq = seq) + g=make_JetMomentGetter(jetcollName,[t],seq=seq) + return g.getJetMomentCalc() + + +def setupGhostAssociationTool2(jetcollName, assocName, assocType, assocKeys="", finder = None,input=None, mainParam=None): + from JetMomentTools.JetMomentToolsConf import GhostAssociationTool + from JetRec.JetGetters import getStandardInputTools, getStandardFinderTools + + # first step : guess the finder, input , mainParam, if needed + finder, input, mainParam = interpretJetName( jetcollName, finder, input, mainParam) + + #print 'Will create an association by re-running with this jet alg : ', finder, mainParam, input + + # Create the tool + t= GhostAssociationTool("JetAsso"+assocName) + t.GhostAssociators = [ setupGhostAssociator(assocName , assocType, assocKeys) ] + # t.GhostAssociators = [ associatorClass(assocName, AssociationName = assocName, AssociatedContainers = assocKeys ) ] + t.JetFindingSequence = getStandardInputTools( input )+getStandardFinderTools( finder , mainParam) + t.JetFindingSequence[0].NoCleanup = True # Necessary ! + + return t + + + + + +def addGhostAssociation2(jetcollName, assocName, assocType, assocKeys="", finder = None,input=None, mainParam=None): + from JetRec.JetMomentGetter import make_JetMomentGetter + + t = setupGhostAssociationTool( jetcollName, assocName, assocType, assocKeys, finder ,input, mainParam) + g=make_JetMomentGetter(jetcollName,[t]) + return g.getJetMomentCalc() diff --git a/Reconstruction/Jet/JetMomentTools/python/JetCopyMomentsAlg.py b/Reconstruction/Jet/JetMomentTools/python/JetCopyMomentsAlg.py new file mode 100644 index 00000000000..34de1861786 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/python/JetCopyMomentsAlg.py @@ -0,0 +1,72 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# @file: JetMomentTools/python/JetCopyMomentsAlg.py.py +# @purpose: <Copy some moments from a collection to another > +# @author: P-A Delsart <delsart in2p3 fr> + +__doc__ = 'some documentation here' +__version__ = '$Revision: 1.5 $' +__author__ = 'Sebastien Binet <binet@cern.ch>' + +import AthenaCommon.SystemOfUnits as Units +import AthenaPython.PyAthena as PyAthena +from AthenaPython.PyAthena import StatusCode +import ROOT + +class JetCopyMomentsAlg (PyAthena.Alg): + 'put some documentation here' + def __init__(self, name='JetCopyMomentsAlg', **kw): + ## init base class + kw['name'] = name + super(JetCopyMomentsAlg, self).__init__(**kw) + + ## properties and data members + self.Moments = kw.get('Moments', []) # default value + self.JetCollectionSrc = kw.get('JetCollectionSrc', "") # default value + self.JetCollectionDest = kw.get('JetCollectionDest', "") # default value + return + + def initialize(self): + self.msg.info('==> initialize...') + self.sg = PyAthena.py_svc ('StoreGateSvc') + return StatusCode.Success + + def execute(self): + jcoll_src = list(self.sg.retrieve('JetCollection', self.JetCollectionSrc)) + jcoll_dest = list(self.sg.retrieve('JetCollection', self.JetCollectionDest)) + + # sort on constit scale to help with ordering. + jcoll_dest.sort(key= lambda x: x.pt(2) ) + jcoll_src.sort(key= lambda x: x.pt(2) ) + getMoment = ROOT.Jet.getMoment + moments = self.Moments + + dr = ROOT.JetDistances.deltaR + needUnorderedMatch = False + for i, (jS, jD) in enumerate(zip(jcoll_src, jcoll_dest)): + if dr(jS,jD)>0.05: + needUnorderedMatch = True + break + for m in moments: + jD.setMoment(m,jS.getMoment(m)) + + if needUnorderedMatch : + # this may happen because of final Pt cut and a calibration changing order w.r.t lcscale. + # fall back to a double loop with deltaR check on remaining jets + jcoll_src = jcoll_src[i:] + jcoll_dest = jcoll_dest[i:] + for jS in jcoll_src: + for jD in jcoll_dest: + if dr(jS,jD)<0.05: + for m in moments: + jD.setMoment(m,jS.getMoment(m)) + + + + return StatusCode.Success + + def finalize(self): + self.msg.info('==> finalize...') + return StatusCode.Success + + # class JetCopyMomentsAlg diff --git a/Reconstruction/Jet/JetMomentTools/python/JetMomentsConfigHelpers.py b/Reconstruction/Jet/JetMomentTools/python/JetMomentsConfigHelpers.py new file mode 100644 index 00000000000..616f98b1f95 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/python/JetMomentsConfigHelpers.py @@ -0,0 +1,363 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +""" +A set of helper function to configure calculations of additionnal jet moments. + +""" +from JetRec.JetAlgConfiguration import checkAndUpdateOptions, standardJetOption +from RecExConfig.RecFlags import rec +from AthenaCommon.SystemOfUnits import GeV +from AthenaCommon.AlgSequence import AlgSequence +from AthenaCommon.Logging import logging +from AthenaCommon.JobProperties import jobproperties + +from JetRec.JetRecFlags import jetFlags +from JetRec.JetFinderConfig import setupAreaCalculation + +from JetMomentTools.SetupJetMomentTools import * + + +## A dedicated logger +_momlog = logging.getLogger( 'JetMomentConfig' ) + + +# We try to schedule cpu intensive moment calculation only once. This requires to keep track of +# moments already scheduled for a given collection. Use this dictionnary. +_specialMomentAlgDict = {} + +# Some moments request can translate in modification of option to already scheduled moment tool. +# so we keep only one main algorithm (JetAlgorithm or JetMomentCalculator) per jet collection, in order to be able to +# retrieve & modify the relevant moment tool. +# However this can cause dependency issue : +# for example, truth ghostAssoc requires JetTruthParticleFilter to run before. If a 1st call doesn't require truth ghost assoc, then later a 2nd call does, then JetTruthParticleFilter will be scheduled *after* the moment calculator alg... +# workaround : move by jand JetTruthParticleFilter at a proper place in the topSequence or the PreD3PDSequence. +def moveAlgInSequence(alg, seq, newpos): + l = seq.getChildren() + delattr(seq, alg.getName()) + seq.insert(newpos, alg) + + +def checkRequiredAlgPosition(seq, momAlg, requiredAlg): + topSeq = AlgSequence() + + if requiredAlg in topSeq: + truthInd = topSeq.getChildren().index(requiredAlg) + if momAlg in topSeq: + index = topSeq.getChildren().index(momAlg) + else: + # then it is in seq, and seq must be in topSeq + index = topSeq.getChildren().index(seq) + # make sure requiredAlg is before index + if truthInd > index: + moveAlgInSequence(requiredAlg, topSeq, index) + else: + # will move requiredAlg in topSeq before seq and momAlg + # where is momAlg ? + seqInd = topSeq.getChildren().index(seq) + if momAlg in topSeq: + index = topSeq.getChildren().index(momAlg) + else: + index = seqInd + delattr(seq, requiredAlg.getName()) + topSeq.insert(index, requiredAlg) + + + +def checkTruthParticleFilterPosition(seq, momAlg): + from JetSimTools.JetTruthParticleFilterGetter import JetTruthParticleFilterGetter + truthAlg = JetTruthParticleFilterGetter().alg + checkRequiredAlgPosition(seq, momAlg, truthAlg) + + + +def retrieveFinderTool(toolSeq): + from JetRec.JetRecConf import JetConeFinderTool, JetFastJetFinderTool + for t in toolSeq: + if isinstance(t, JetFastJetFinderTool) or isinstance(t, JetConeFinderTool): + return t + + +import inspect +def whosdaddy(): + l = [ ll[3] for ll in inspect.stack()[2:] ] + return l + + + + + +# Helper functions to schedule jet moments. +# They are typically wrappers around functions in SetupJetMomentTools which are as generic as possible +# The wrappers below also perform tasks related to the particular jet collection or configuration sequence. +def scheduleMFTool(toolType,jetcollname, jf, alg, seq ,*l): + from JetMomentTools.SetupJetMomentTools import getMatchingFractionTool + tool, requiredAlg = getMatchingFractionTool(jetcollname, toolType, seq) + checkRequiredAlgPosition(seq, alg, requiredAlg) + return tool + +from JetMomentTools.JetMomentToolsConf import JetWidthTool, NumTowerInJetTool, JetEinSamplingTool + + +# The dictionnary below lists the known standard moments and how to compute them. +# keys in the dict are shorcuts, they might represent several moments +# values are function used to actually schedule the moment calculations +defaultMoments = { + 'ghostAssoc' : lambda *l : None, + 'area' : lambda jcoll,jetfinder,*l : setupAreaCalculation(jetfinder, "ActiveArea", addArea4Vec=True, addSecondArea=jetFlags.jetPerformanceJob() ) , + 'quality' : lambda jetcollname,*l : getCaloQualityTool(doCellBasedVars = (jetcollname=="AntiKt4TopoEMJets" or "Tower" in jetcollname ), computeFromCluster = "Tower" not in jetcollname ), + 'ktDeltaR' : lambda *l : getsubJetsMomentTool(), + 'isolation' : lambda *l : getJetIsolationTool("JetIsolation"), + 'jvf' : lambda jetcollname,*l : getJetVertexAssociationTool(toolName=jetcollname+'JVAtool') , + 'trackMoments' : lambda *l : getJetTracksMomentTool(), + 'truthMF' : lambda *l : scheduleMFTool("Truth",*l) , + 'trackMF' : lambda *l : scheduleMFTool("Track",*l) , + 'larHV' : lambda *l : getJetLArHVMomentTool(), + 'width' : lambda *l : JetWidthTool(), + 'eInSampling' : lambda *l : JetEinSamplingTool(), + 'numTowerJet' : lambda *l : NumTowerInJetTool(), + 'badChanCorr' : lambda jc,jf,alg,seq,jetAlgConfigDict : getJetBadChanCorrTool(**jetAlgConfigDict), + 'origin' : lambda jetcollname,*l : getORIGINMoments(jetcollname), + } + + +## The list of standard moments keys used in reconstruction. +standardMoments = standardJetOption("jetMoments") + +class TestWithMsg(object): + """Simply a boolean and a str message explaining why the boolean is False + Also supports & and | operation (logical and or) with concatenation of message""" + jetcollname="" + def __init__(self, test, failmsg): + self.test, self.failmsg= test, failmsg + def check(self, mName): + if self.test: + return True + _momlog.info( "No "+mName+" moments for "+self.jetcollname+". Reason : "+self.failmsg) + return False + def __and__(self, o ): + test = self.test and o.test + failmsg = [ t.failmsg for t in (self,o) if not t.test ] + return TestWithMsg( test, ' AND '.join(failmsg) ) + def __or__(self, o ): + test = self.test or o.test + failmsg = '' if test else self.failmsg+' AND '+o.failmsg + return TestWithMsg( test, failmsg ) + + +def checkMomentAvailability(jetcollname, momentList, jetAlgConfigDict={}): + """ Input : a jet collection name (jetcollname), list of moment keys (momentList), a jet alg configuration dict (as in JetRec.JetAlgConfiguration) + returns a filtered list of moment keys where moments incompatible with the jet collection or the job conditions are removed. + """ + # we'll need to know what the input file is + from JetRec.JetGetters import guessInputFileType + inputFileType = guessInputFileType() + + + + from AthenaCommon.DetFlags import DetFlags + from AthenaCommon.AppMgr import ToolSvc + from AthenaCommon.GlobalFlags import globalflags + from JetRec.TrackSelectionForJets import tracksAvailableForJets + + TestWithMsg.jetcollname = jetcollname + # short cut flags + # use TestWithMsg rather than simply bool only to be able to display a reason for the rejection of the moment. + accessCells = TestWithMsg( (inputFileType=="RDO") or (inputFileType=="ESD") , "No CaloCell available") + caloJet = TestWithMsg( ("Topo" in jetcollname) or ("Tower" in jetcollname), "Not calo jets") + topoJet = TestWithMsg( "Topo" in jetcollname, "Not TopoCluster jets") + lctopoJet = TestWithMsg( "LCTopo" in jetcollname, "Not LC TopoCluster jets") + notTruthJet = TestWithMsg( 'Truth' not in jetcollname, "Is Truth jets") + tracksAvailable = TestWithMsg( tracksAvailableForJets(), "Tracks selection for jets impossible") + + trueTest = TestWithMsg(True,"") + + # build the conditions at which moments can be built + compatibilityDict = { + 'area' : TestWithMsg('Cone' not in jetcollname, "no area for cone jets"), + 'ghostAssoc' : notTruthJet, + 'width' : trueTest, + 'numTowerJet' : topoJet & accessCells, + 'quality' : caloJet, + 'badChanCorr' : caloJet & accessCells, + 'constitCalib': lctopoJet & TestWithMsg( not jetAlgConfigDict.get('calibName','').startswith("LC:CONST") , "Calibration differ from LC:CONST") , + 'jvf' : caloJet & tracksAvailable, + 'larHV' : caloJet & TestWithMsg( (inputFileType=='RDO') and DetFlags.dcs.LAr_on() and globalflags.DataSource()=='data', "No proper LAr info available"), + 'eInSampling' : (caloJet & accessCells) | (topoJet), + 'truthMF' : TestWithMsg( rec.doTruth() , "Truth not available") & notTruthJet, + 'trackMF' : notTruthJet & tracksAvailable, + 'trackMoments': notTruthJet & tracksAvailable, + + } + + # filter moments : + availableMoments = set([ m for m in momentList if compatibilityDict.get(m, trueTest).check(m) ]) + return availableMoments + + + + +def findMainAlgForJetCollection(jetcollname, seq = AlgSequence()): + """Given a JetCollection name (jetcollname) in input, returns an algorithm computing moments for this collection. + The functions explore all know possibilities for finding such algs. + + The return value is (alg, set) where + - alg is a JetAlgorithm or a JetMomentCalculator. alg can be None if nothing found or unusable in the case a JetGetter was called with the disable option. + - set : is the set of known moments associated to the alg + """ + # try to find a moment calculator for this collection : + alg , existing_moments = _specialMomentAlgDict.get( jetcollname, (None,set()) ) + unknownAlg = alg is None + + if alg is None: + # try to find a getter : + from JetRec.JetGetters import retrieveConfiguredJetAlg + alg = retrieveConfiguredJetAlg(jetcollname, retrieveGetter=True) + if alg is not None: + # check if usable : + if not alg.usable(): + return ('unusable', set()) + + # get the real JetAlgorithm + alg = alg.jetAlgorithmHandle() + # in this case, no moment have been associated yet + existing_moments = set() + if alg is None: + # check if a collection exists in input file + from RecExConfig.ObjKeyStore import objKeyStore + if 'JetCollection#'+jetcollname in objKeyStore['inputFile'].list("JetCollection"): + # then create a new moment alg for this collection + from JetRec.JetMomentGetter import getJetMomentAlgorithm + alg = getJetMomentAlgorithm(jetcollname, seq = seq) + else: + # likely to fail... + # try to invoke a standard JetAlgorithm + from JetRec.JetRec_defaults import standardJetAlgorithm + try : + alg = standardJetAlgorithm(jetcollname, seq = seq) + except: + alg = None # + if unknownAlg and alg is not None: + # we created a new alg, remember it + _specialMomentAlgDict[jetcollname] = (alg, set() ) + return alg, existing_moments + +from JetRec.JetRecConf import JetAlgorithm +from JetMomentTools.JetMomentToolsConf import JetMomentCalculator +def addStandardMoments(jetcollname, moments=standardMoments, seq = AlgSequence(), jetAlgConfigDict={}): + """Add a list of jet moment calculation for a given jet collection + - jetcollname : string, the name of the jetcollection + - moments : list of string or function. string are expected to be some of the defaultMoment shortcuts. functions must return a configured moment tool + - seq : the AlgSequence to which the calculation is attached + (- jetAlgConfigDict : dictionnary, used to pass JetAlgorithm configuration options when this addStandardMoments is called while configuring the JetAlgorithm.) + Returns nothing. + Effect : retrieve (or invoke if needed) the moment calculation algorithm dedicated to jetcollname (this can be a JetAlgorithm or a JetMomentCalculator), + then add to this algorithm the moments requested in defaultMoment (only if they are not already scheduled). + """ + + if moments == []: + # nothing to do. Return now to avoid any inconvenience + return + + # retrieve the main algorithm for this jet collection + alg, existing_moments = findMainAlgForJetCollection(jetcollname, seq) + + + # check if the alg is usable --------- + if alg == 'unusable': + _momlog.info("No usable algorithm for "+jetcollname+". No jet moments added") + return + if alg is None : + # didn't find any alg. We can't add moments + _momlog.error("Can't create momens for "+jetcollname+" : no such collection in input or no algorithms scheduled for it") + _momlog.error(" ---> possible solution, invoke make_StandardJetGetter() before to schedule a JetAlgorithm for "+jetcollname) + return + + isJetMomentCalc = isinstance(alg, JetMomentCalculator) + + # filter moment list according to jet collection and other conditions + missing_moments = checkMomentAvailability( jetcollname, set(moments) - existing_moments , jetAlgConfigDict ) + + # enforce ghostAssoc, thus jet refinding, if area requested (could separate the 2 options with more config) when using a JetMomentCalculator + if 'area' in missing_moments and ('ghostAssoc' not in existing_moments) and isJetMomentCalc: + missing_moments.add('ghostAssoc') + + + jetfinder = None + # ghost association is very particular since it needs jet finding. + if 'ghostAssoc' in missing_moments: + gAssoc = [] + from JetRec.TrackSelectionForJets import tracksAvailableForJets + if tracksAvailableForJets() : + gAssoc += ["TrackAssoc"] + if rec.doTruth(): + gAssoc+=[ "TruthAssoc"] + if isJetMomentCalc: + from JetMomentTools.GhostAssociation import setupGhostAssociationTool + gtool = setupGhostAssociationTool(jetcollname, gAssoc, seq=seq) + tmpL = alg.CalculatorTools + alg.CalculatorTools = [gtool] + tmpL + else: # it's a JetAlgorithm + tmpL = list(alg.AlgTools) + from JetRec.JetGetters import adaptToolListToGhostAssociation + alg.AlgTools = adaptToolListToGhostAssociation(tmpL, gAssoc, seq) + if rec.doTruth(): + checkTruthParticleFilterPosition( seq, alg) + + jetfinder = alg.CalculatorTools['JetGhostAsso'].JetFindingSequence["JetFastJetFinder"] if isJetMomentCalc \ + else alg.AlgTools[0].JetFindingSequence["JetFastJetFinder"] + + # we are done with ghostAssoc + missing_moments.remove('ghostAssoc') + existing_moments.add('ghostAssoc') + else: # still need to retrieve the jetfinder + if 'ghostAssoc' in existing_moments: + jetfinder = alg.CalculatorTools['JetGhostAsso'].JetFindingSequence["JetFastJetFinder"] if isJetMomentCalc \ + else alg.AlgTools[0].JetFindingSequence["JetFastJetFinder"] + else: + jetfinder = retrieveFinderTool( alg.CalculatorTools if isJetMomentCalc else alg.AlgTools) + + momentTools = [] + # Loop over requested moment types and set-up the related tools + for momentType in missing_moments: + if callable(momentType): + # then assume a function returning a tool has been supplied + func = momentType + else: + func = defaultMoments[momentType] + # call the setup function, add the returned tool to the sequence + tool = func( jetcollname, jetfinder, alg, seq, jetAlgConfigDict) + if tool is not None: # some function just adapts existing tools + momentTools.append(tool) + + # add the moment tools list to the relevant alg : + if isJetMomentCalc: + alg.CalculatorTools += momentTools + else: + alg.AlgTools += momentTools + + _specialMomentAlgDict[jetcollname] = (alg, missing_moments.union(existing_moments) ) + return alg + + + + +def recommendedAreaAndJVFMoments(jetcollname, oldMomentNames=False,seq=AlgSequence()): + """Recompute the area, JVF and track related jet moment on jetcollname. + + jetcollname : string a JetCollection StoreGate key + oldMomentNames : bool, if True the moment naming will be the same as in 17.2.5 and previous releases. + """ + + alg = addStandardMoments(jetcollname,moments = ['ghostAssoc','area','jvf', 'trackMoments'], seq=seq) + + return alg + +def recommendedAreaAndJVF_StandardJetGetter( finder, mainParam, input, oldMomentNames=False, **options): + """Run a jet algorithm, adding the recomended area, JVF and track related jet moments calculation. + + all argument similar as in make_StandardJetGetter except : + + oldMomentNames : bool, if True the moment naming will be the same as in 17.2.5 and previous releases. + """ + return make_StandardJetAlg(finder, mainParam, input, jetMoments = ['ghostAssoc','area','jvf', 'trackMoments'], **options) + #alg = specialJet( finder, mainParam, input, oldMomentNames = oldMomentNames, moments=['ghostAssoc','area','jvf', 'trackMoments'], **options) diff --git a/Reconstruction/Jet/JetMomentTools/python/SetupJetMomentTools.py b/Reconstruction/Jet/JetMomentTools/python/SetupJetMomentTools.py new file mode 100644 index 00000000000..08115dbac9d --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/python/SetupJetMomentTools.py @@ -0,0 +1,302 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +from JetRec.JetAlgConfiguration import checkAndUpdateOptions +from AthenaCommon.SystemOfUnits import * +from JetRec.JetRecFlags import jetFlags +from AthenaCommon.AlgSequence import AlgSequence + +class memoize(object): + """memoize is intended to be used as a decorator + It will force the decorated function to be run only once, cache it's return value + and return this value on every subsequent call. + """ + def __init__(self, func): + # func is the function being decorated + self.func = func + self.cache = None + + def __call__(self): + # this gives the memoize object the ability to be called + # and thus this object behaves like a function + + if self.cache is None: + # call the function only once. + self.cache = self.func() + return self.cache + + + +def getJetVertexAssociationTool( toolName="JetVertexAssociation", *largs, **args): + + #options=checkAndUpdateOptions(finder=finder, mainParam=mainParam, input=input,) + + from JetMomentTools.JetMomentToolsConf import JetVertexAssociationTool, JetOriginCorrectionTool + + + jvaTool = JetVertexAssociationTool(toolName) + + jvaTool.AssociateToHighestJVF = True + + from JetRec.TrackSelectionForJets import getDefaultJetVtxTrackHelper + jvaTool.JetVtxTrackHelper = getDefaultJetVtxTrackHelper() + + # origin correction tool + origCorr = JetOriginCorrectionTool("JetOriginCorrection") + origCorr.CellCalibrator = None + origCorr.UseGCW = False + origCorr.UseClusters = True + + # Official Choice of Jet/MET Group : Primary Vertex + origCorr.UseJVA = False + origCorr.UsePrimaryVertex = True + origCorr.UseBeamSpot = True + jvaTool.OriginCorrectionTool = origCorr + + jvaTool.StoreTrkMoments = False + + jvaTool.sumPtTrkMomentName = "sumPtTrk_pv0_500MeV" + jvaTool.nTrkMomentName = "nTrk_pv0_500MeV" + jvaTool.TrackAssocName = "TrackAssoc" + + return jvaTool + +def getJetTracksMomentTool(**options): + + from JetMomentTools.JetMomentToolsConf import JetTracksMoments + from JetRec.TrackSelectionForJets import getDefaultJetVtxTrackHelper + + suffix = options.get("MomentSuffix", None) + if suffix is None: + minpt = options.get("MinPt", 1*GeV) + if minpt>=GeV : + suffix = '_%1.1fGeV'%(minpt/GeV,) + suffix = suffix.replace('.0','') # don't write '1.0GeV', simply '1GeV' + else: + suffix = '_%dMeV'%(int(minpt),) + options["MomentSuffix"] = suffix + defaultJVtx = getDefaultJetVtxTrackHelper() + options.setdefault('JetVtxTrackHelper',defaultJVtx) # update the JetVtxTrackHelper option if not given + trkTool = JetTracksMoments( + **options + ) + return trkTool + + +def getORIGINMoments(jetcollname): + from JetCalibTools.MakeCalibSequences import alternateCalibSequence + from JetMomentTools.JetMomentToolsConf import JetMomentsFromCalib + from JetMomentTools.GhostAssociation import interpretJetName + from JetRec.JetAlgConfiguration import checkAndUpdateOptions + recognizedJet = interpretJetName(jetcollname) + if recognizedJet is not None: + finder, input, mainParam = recognizedJet + calib = 'LC:ORIGIN' if 'LC' in input else 'EM:ORIGIN' + d = checkAndUpdateOptions(input=input) + return JetMomentsFromCalib( "OriginRecalculator" , Calibrator = alternateCalibSequence(calib, d) ) + + +def getDefaultMissingCellTool(rmax=1.0): + rmax = max(rmax, 1.0) + if getDefaultMissingCellTool.cache is None: + from JetMomentTools.JetMomentToolsConf import MissingCellListTool + from AthenaCommon.AppMgr import ToolSvc + + tool = MissingCellListTool() + tool.DeltaRmax = rmax + tool.AddBadCells = True + getDefaultMissingCellTool.cache = tool + tool.RemoveCellList = [1275120944, 1275121456, 1275137328, 1275268400, 1275268912, 1275383088, 1275383600, 1275514160, 1275514672, 1275628848, 1275661616, 1275662128, 1275792688, 1275793200, 1275940144, 1275940656, 1275956528, 1276054832, 1276055344, 1276071216, 1283493168, 1283493680, 1283640624, 1283641136, 1283820848, 1283821360, 1283935536, 1283936048, 1284017456, 1284017968, 1284164912, 1284165424, 1284312368, 1284312880, 1284427056, 1284427568, ] + #1275349024, 1283688480 # these tile cells were not ignored in the original implementation + + + ToolSvc += tool + else: + if rmax > getDefaultMissingCellTool.cache.DeltaRmax: + getDefaultMissingCellTool.cache.DeltaRmax = rmax + + return getDefaultMissingCellTool.cache +getDefaultMissingCellTool.cache = None + + +def getJetBadChanCorrTool(finder, mainParam, input, **options): + + options=checkAndUpdateOptions(finder=finder, mainParam=mainParam, input=input, **options) + + from JetMomentTools.JetMomentToolsConf import JetBadChanCorrTool + from CaloClusterCorrection.StandardCellWeightCalib import getCellWeightTool + + cellcalibtool = getCellWeightTool(options['finder'], options['mainParam'], input, onlyCellWeight=True) + coneSize = options['mainParam'] + + BadChanCorrT = JetBadChanCorrTool("JetBadChanCorrTool") + # Explicitly list flags + BadChanCorrT.ConeDr = coneSize + BadChanCorrT.CellCalibrator = cellcalibtool + BadChanCorrT.UseCalibScale = False + BadChanCorrT.AttachCorrCell = True + BadChanCorrT.AttachCorrDOTX = True + BadChanCorrT.AttachCorrJet = True + + BadChanCorrT.MissingCellTool = getDefaultMissingCellTool(coneSize) + # Optional + BadChanCorrT.AttachCorrJetForCell = False + if options['addJetQualityMoments'] == True: + BadChanCorrT.AttachCorrJetForCell = True + + # new setup for THistService + import os + dataPathList = os.environ[ 'DATAPATH' ].split(os.pathsep) + dataPathList.insert(0, os.curdir) + from AthenaCommon.Utils.unixtools import FindFile + RefFileName = FindFile( "JetBadChanCorrTool.root" ,dataPathList, os.R_OK ) + + + from AthenaCommon.AppMgr import ServiceMgr + if not hasattr(ServiceMgr, 'THistSvc'): + from GaudiSvc.GaudiSvcConf import THistSvc + ServiceMgr += THistSvc() + ServiceMgr.THistSvc.Input += ["JetBadChanCorrTool DATAFILE=\'%s\' OPT=\'READ\'" % RefFileName] + + return BadChanCorrT + +def getCaloQualityTool(computeFromCluster = False,doCellBasedVars = False,addJetQualityMoments=False): + + from JetMomentTools.JetMomentToolsConf import JetCaloQualityTool + caloQualityT = JetCaloQualityTool("JetCaloQualityTool") + caloQualityT.doCellBasedVariables = doCellBasedVars + caloQualityT.cutOnLAr = 4000 + caloQualityT.doLArQuality = True + caloQualityT.doTiming = True + caloQualityT.doHECQuality = True + caloQualityT.doNegativeE = True + caloQualityT.doTileQuality = False + caloQualityT.doAverageLArQF = True + #caloQualityT.timingMomentCells = [5,10] # produces jet moments: ootFracCells5, ootFracCells10 (names built on the fly from caloQualityT.timingMomentCellsName) + caloQualityT.timingMomentClusters = [5,10] # + caloQualityT.timingMomentCells = [] + caloQualityT.doJetCentroid = True + + caloQualityT.ComputeVariableFromCluster = computeFromCluster + + if addJetQualityMoments : + caloQualityT.doConstituentBasedVariables = True + caloQualityT.doSamplingBasedVariables = True + caloQualityT.cutOnTile = 254 + caloQualityT.doTileQuality = True + + + return caloQualityT + + +def getJetIsolationTool(toolname,**options): + from JetMomentTools.JetMomentToolsConf import JetIsolationTool + + default_options = dict(JetRParam = 0.4, + IsolationMoments = ["IsoKR","IsoDelta", "IsoFixedCone", "IsoFixedArea", "Iso6To8"], + IsolationParam = [ 2., 0.2, 0.8, 1.4, 0.8], + DoIsoSumPt = True, + ) + default_options.update(options) + + + isot = JetIsolationTool(toolname, **default_options) + return isot + +@memoize +def _getTruthJetIsoSelector(): + from JetSimTools.JetSimToolsConf import JetTruthParticleSelectorTool + from AthenaCommon.AppMgr import ToolSvc + + selector = JetTruthParticleSelectorTool("JetTruthIsoSelector") + selector.includeMuons = False + selector.useInteractingParticlesOnly = True + + ToolSvc += selector + return selector + +def getTruthJetIsolationTool(toolname, doTruthPileup=False, **options): + """We need special options for truth jets. + """ + isot = getJetIsolationTool(toolname, **options) + + from RecExConfig.RecFlags import rec + defaultCollName = "SpclMC" if rec.readAOD() else "INav4MomTruthEvent" + defaultContList = [defaultCollName] if not doTruthPileup else [defaultCollName, defaultCollName+'INTIME'] + truthCont = options.get('TruthInputContainers', defaultContList) + + isot.TruthInputContainers = truthCont + + # make sure we have a truth jet selector. + isot.TruthSelector = _getTruthJetIsoSelector() + + return isot + +def getJetTruthLabelTool(truthCont='TruthInputContainers') : + from JetMomentTools.JetMomentToolsConf import JetTruthLabel + + tool = JetTruthLabel("JetTruthLabel") + tool.TruthInputContainers = truthCont + + return tool + +def getsubJetsMomentTool(toolname="KtDeltaR"): + from JetMomentTools.JetMomentToolsConf import JetSubJetsMoments + from JetRec.JetFastJetConfig import configFastJet + + ktDrTool = JetSubJetsMoments(toolname) + fjtool = configFastJet("Kt",0.4, Inclusive=False, ExclusiveNjets=2, ExclusiveDcut=-1) + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += fjtool + ktDrTool.FastJetTool = fjtool + ktDrTool.FromJetAssociation = "TrackAssoc" + ktDrTool.MinPt = 1*GeV + return ktDrTool + + + +def getMatchingFractionTool(jetcollname, matchType, seq=AlgSequence()): + """ ATTENTION this tools returns (tool, alg) where alg is a dependency for Matching. + It *has* to be scheduled before (caller's reponsability). + It return None if it can not guess what truth alg to request. + """ + from JetMomentTools.GhostAssociation import interpretJetName + from JetMomentTools.JetMomentToolsConf import JetMatchingFractionTool + recognizedJet = interpretJetName(jetcollname) + if recognizedJet is None: + return None + + finder, input, mainParam = recognizedJet + algtype = finder+str(int(mainParam*10)) + from JetRec.JetGetters import make_StandardJetGetter + if matchType == "Truth": + from JetRec.JetRec_defaults import standardJetAlgorithm + alg = standardJetAlgorithm(algtype+"TruthJets") + if alg is None: # possible if truth collection already exist + # !!!! WARNNIG minPt cut is ambiguous !!!! + alg=make_StandardJetGetter(finder, mainParam,"Truth", minPt=4*GeV, jetMoments=[], outputCollectionName=algtype+"TruthNewJets", seq=seq).jetAlgorithmHandle() + + # Then the mftool can be scheduled + mftool = JetMatchingFractionTool("TruthMF",MFCollection = alg.JetCollectionName, AssociatedConstitKey="TruthAssoc", + MomentTag="Truth",UseHighestShareFrac=True) + elif matchType == "Track": + alg=make_StandardJetGetter(finder, mainParam,"TrackZ", addJetQualityMoments=False, seq=seq).jetAlgorithmHandle() + # Then the mftool can be scheduled + mftool = JetMatchingFractionTool("TrackMF",MFCollection = alg.JetCollectionName, AssociatedConstitKey="TrackAssoc", + MomentTag="Track",UseHighestShareFrac=True) + else: + return None + + return (mftool, alg) + +def getJetLArHVMomentTool(): + + from LArRecUtils.LArHVCorrToolDefault import LArHVCorrToolDefault + theLArHVCorrTool=LArHVCorrToolDefault() + from AthenaCommon.AppMgr import ToolSvc + ToolSvc+=theLArHVCorrTool + + #Now declare the jet moment algorithm: + from JetMomentTools.JetMomentToolsConf import JetLArHVMoment + JetLArHV = JetLArHVMoment("JetLArHVMoment") + JetLArHV.HVCorrTool = theLArHVCorrTool + return JetLArHV diff --git a/Reconstruction/Jet/JetMomentTools/src/JetBadChanCorrTool.cxx b/Reconstruction/Jet/JetMomentTools/src/JetBadChanCorrTool.cxx new file mode 100644 index 00000000000..53a8335bebe --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/JetBadChanCorrTool.cxx @@ -0,0 +1,461 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//#include "GaudiKernel/Service.h" +#include "GaudiKernel/ITHistSvc.h" + +#include "PathResolver/PathResolver.h" + +#include "CaloDetDescr/CaloDetDescrManager.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloEvent/CaloCellContainer.h" +//#include "CaloEvent/CaloCellPrefetchIterator.h" +//#include "CaloInterface/IHadronicCalibrationTool.h" + +#include "xAODCaloEvent/CaloCluster.h" +#include "AthenaKernel/errorcheck.h" + + +#include "TFile.h" +#include "TH1.h" + +#include "JetMomentTools/JetBadChanCorrTool.h" +#include "JetUtils/JetCellAccessor.h" +#include "JetUtils/JetDistances.h" +#include "GaudiKernel/SystemOfUnits.h" + + +using Gaudi::Units::GeV; + + +JetBadChanCorrTool::JetBadChanCorrTool( const std::string& name) : + JetModifierBase(name), + m_thistSvc( "THistSvc", name ), + // m_caloDDM(0), + // m_calo_id(0), + //m_calibTool(this), + // m_missingCellToolHandle("MissingCellListTool"), + m_missingCellMapName(), + m_forceMissingCellCheck(false), + m_useClusters(false) +{ + + // limit to calculate the moments, #bad ch is typically 3000 out of 187616 + declareProperty("NBadCellLimit", m_nBadCellLimit = 10000); + + + // for jet-level correction + declareProperty("StreamName", m_streamName = "/JetBadChanCorrTool/"); + declareProperty("ProfileName", m_profileName = "JetBadChanCorrTool.root"); + declareProperty("ProfileTag", m_profileTag = ""); + + declareProperty("UseCone", m_useCone = true); + //declareProperty("ConeDr", m_coneDr = 0.4); + + // for calibration + declareProperty("UseCalibScale", m_useCalibScale = false); + // declareProperty("CellCalibrator", m_calibTool); + + //declareProperty("MissingCellTool", m_missingCellToolHandle); + declareProperty("MissingCellMap", m_missingCellMapName= "MissingCaloCellsMap"); + declareProperty("ForceMissingCellCheck", m_forceMissingCellCheck=false); + declareProperty("UseClusters",m_useClusters= false); +} + +JetBadChanCorrTool::~JetBadChanCorrTool() +{ } + +StatusCode JetBadChanCorrTool::initialize() +{ + + if(!m_useClusters){ + std::string fname = PathResolver::find_file(m_profileName, "DATAPATH"); + + if(fname==""){ + ATH_MSG(ERROR) << "Could not get file " << m_profileName << endreq; + return StatusCode::FAILURE; + } + TFile tf(fname.c_str()); + if(tf.IsOpen()==false){ + ATH_MSG( ERROR ) << "Could not open file " << fname << endreq; + return StatusCode::FAILURE; + } + // already registered hists + std::vector<std::string> histsInSvc = m_thistSvc->getHists(); + + TListIter next(tf.GetListOfKeys()); + TObject *obj; + while((obj = next())) { + // assume hname=(tag)_sample(sample)_pt(ptMin)_(ptMax)_eta(etaMin)_(etaMax)_phi(phiMin)_(phiMax) + std::string hname=obj->GetName(); + if(hname.find('_')==std::string::npos) continue; + std::string tag = hname.substr(0,hname.find('_')); + std::string para = hname.substr(hname.find('_')+1); + std::string location = m_streamName+hname; + + if(m_profileTag=="" || m_profileTag==tag){ + // read in histo not registered yet + if(find(histsInSvc.begin(),histsInSvc.end(),location)==histsInSvc.end()){ + StatusCode sc = m_thistSvc->regHist(location); + if(sc.isFailure()){ + ATH_MSG( ERROR ) << "failed to read histo " << location << endreq; + return StatusCode::FAILURE; + } + } + int sample=0; + double ptMin=0; + double ptMax=9999; + double etaMin=0; + double etaMax=5.0; + double phiMin=-M_PI; + double phiMax=M_PI; + int ret = sscanf(para.c_str(),"sample%d_pt%lf_%lf_eta%lf_%lf_phi%lf_%lf", + &sample,&ptMin,&ptMax,&etaMin,&etaMax,&phiMin,&phiMax); + + if(ret<1 || sample<0 || sample>=CaloCell_ID::Unknown) { + ATH_MSG( DEBUG ) << "Could not understand the name of hist " << obj->GetName() << endreq; + continue; + } + + TH1* th=0; + StatusCode sc = m_thistSvc->getHist(location,th); + if(sc.isFailure()){ + ATH_MSG( ERROR ) << "failed to get histo " << location << endreq; + return StatusCode::FAILURE; + } + m_profileDatas[sample].push_back(ProfileData((TH1D*)th,sample,ptMin,ptMax,etaMin,etaMax,phiMin,phiMax)); + ATH_MSG( DEBUG ) << "read hist=" << th->GetName() + << " tag=" << tag << " sample=" << sample + << " ptMin=" << ptMin << " ptMax=" << ptMax + << " etaMin=" << etaMin << " etaMax=" << etaMax + << " phiMin=" << phiMin << " phiMax=" << phiMax << endreq; + } + } + + // if(m_useCalibScale){ + // CHECK( m_calibTool.retrieve() ) ; + // ATH_MSG( DEBUG ) << "use calibration " << m_calibTool << endreq; + // } + + if ( m_useCone) { + // CHECK( detStore()->retrieve(m_caloDDM) ); + // m_calo_id = m_caloDDM->getCaloCell_ID(); + // ATH_MSG( DEBUG ) << "perform bad cells in cone calculations " << endreq; + // if(m_calo_id==0){ + // ATH_MSG( ERROR ) << "Could not get CaloCell_ID" << endreq; + // return StatusCode::FAILURE; + // } + } + + + // CHECK( m_missingCellToolHandle.retrieve() ); + //m_missingCellTool = dynamic_cast<MissingCellListTool*>( &(*m_missingCellToolHandle)); + + } + + return StatusCode::SUCCESS; +} + +StatusCode JetBadChanCorrTool::setupEvent() +{ + + // CHECK(m_missingCellTool->prepareCellList()); + + return StatusCode::SUCCESS; +} + + +int JetBadChanCorrTool::modifyJet( xAOD::Jet& jet) const +{ + + int res = 0; + if(m_useClusters){ + res = correctionFromClustersBadCells( &jet); + }else{ + + const jet::CaloCellFastMap * badCellMap ; + StatusCode sc= evtStore()->retrieve(badCellMap, m_missingCellMapName) ; + if(sc.isFailure() ) {ATH_MSG_ERROR("Could not retieve bad cell map "<< m_missingCellMapName); return 1;} + + + // number of bad cells exceed the limit, set -1 and skip + if((int) badCellMap->cells().size() >m_nBadCellLimit){ + jet.setAttribute<float>("BchCorrCell",-1.0); + if(!m_useClusters){ + jet.setAttribute<float>("BchCorrDotx",-1.); + jet.setAttribute<float>("BchCorrJet",-1.); + jet.setAttribute<float>("BchCorrJetForCell",-1.); + } + return 0; + } + + + res = correctionFromCellsInJet(&jet, badCellMap); + // cone-based boundary + if(m_useCone) { + ATH_MSG_DEBUG( " Missing cells for cone search "<< badCellMap->size() << " jet="<< jet.index() << " R="<< jet.getSizeParameter() << " input="<< jet.getInputType() << " jet_eta="<<jet.eta() ) ; + + res+=correctionFromCellsInCone(&jet, badCellMap); + } + } + + + // // for cryo. + // if(useCalibTool) { + + // // without cell correction + // double emb3_raw = emb3-emb3_cell; + // double tile1_raw = tile1-tile1_cell; + // double cryoEt_raw = m_calibTool->etCryo(emb3_raw,tile1_raw); + // double emb3_rawotx = emb3-emb3_dotx; + // double tile1_rawotx = tile1-tile1_dotx; + // double cryoEt_rawotx = m_calibTool->etCryo(emb3_rawotx,tile1_rawotx); + + // double cryoEt = m_calibTool->etCryo(emb3,tile1); + // corr_cell += (cryoEt-cryoEt_raw) / rawPt; + // corr_dotx += (cryoEt-cryoEt_rawotx) / rawPt; + + // double cryoEt_jet_forcell = m_calibTool->etCryo(emb3_raw+emb3_jet_forcell,tile1_raw+tile1_jet_forcell); + // corr_jet_forcell += (cryoEt_jet_forcell-cryoEt_raw) / rawPt; + + // double cryoEt_jet_associate = m_calibTool->etCryo(emb3_raw+emb3_jet_associate,tile1_raw+tile1_jet_associate); + // corr_jet_associate += (cryoEt_jet_associate-cryoEt_raw) / rawPt; + + // double cryoEt_jet_cone = m_calibTool->etCryo(emb3_raw+emb3_jet_cone,tile1_raw+tile1_jet_cone); + // corr_jet_cone += (cryoEt_jet_cone-cryoEt_raw) / rawPt; + + // total_energy += cryoEt*cosh(jet.eta()); + + + + // double calib_scale = total_energy/rawE; + // corr_cell /= calib_scale; + // corr_dotx /= calib_scale; + // corr_jet_associate /= calib_scale; + // corr_jet_cone /= calib_scale; + // corr_jet_forcell /= calib_scale; + + // if(corr_cell <1e-7) corr_cell =0; + // if(corr_dotx <1e-7) corr_dotx =0; + // if(corr_jet_associate<1e-7) corr_jet_associate=0; + // if(corr_jet_cone <1e-7) corr_jet_cone =0; + // if(corr_jet_forcell <1e-7) corr_jet_forcell =0; + // } + + + + return res; +} + + +int JetBadChanCorrTool::correctionFromCellsInJet( xAOD::Jet* jet, const jet::CaloCellFastMap * ) const { + + //const jet::cellset_t & badcells = badCellMap.cells() ; + + xAOD::JetFourMom_t p4 = jet->jetP4(xAOD::JetEMScaleMomentum); + double rawPt = p4.Pt(); + double rawE = p4.E(); + + // jet moments, fraction + double corr_jet_associate=0; + //double corr_jet_cone=0; + double corr_jet_forcell=0; + double corr_cell=0; + double corr_dotx=0; + + // jet energy + double total_energy=0;//for calib, with h1 weight but without jet-scale corr. + + // for cryo., et at em-scale + // double emb3 = 0.; + // double tile1 = 0.; + // double emb3_cell = 0.; + // double tile1_cell = 0.; + // double emb3_dotx = 0.; + // double tile1_dotx = 0.; + // double emb3_jet_associate = 0.; + // double tile1_jet_associate = 0.; + // double emb3_jet_cone = 0.; + // double tile1_jet_cone = 0.; + // double emb3_jet_forcell = 0.; + // double tile1_jet_forcell = 0.; + + // bool topoJet = dynamic_cast<const CaloCluster*>(*jet.begin()) != 0; + + ///bool useCalibTool = m_useCalibScale && jet.signalState()==P4SignalState::CALIBRATED; + + // const IMissingCellListTool::list_t & missingCells = m_missingCellTool->extendedList(); + + jet::JetCellAccessor::const_iterator cellIt = jet::JetCellAccessor::begin(jet); + jet::JetCellAccessor::const_iterator cellItE = jet::JetCellAccessor::end(jet); + + for( ;cellIt!=cellItE; cellIt++) { + + const CaloDetDescrElement * dde = (*cellIt)->caloDDE(); + const CaloCell *cell = *cellIt; + double cellWeight = cellIt.weight(); + + double cell_energy = cell->e() * cellWeight; + // if(useCalibTool) { + // cell_energy *= m_calibTool->wtCell(cell); + // } + + total_energy += cell_energy; + + CaloCell_ID::CaloSample sampling = dde->getSampling(); + + // // for cryo. + // if (sampling == CaloCell_ID::EMB3) emb3 += cell->et(); + // if (sampling == CaloCell_ID::TileBar0) tile1 += cell->et(); + + bool considerBad = cell->badcell(); + //if(considerBad) badCellList.push_back( cell->ID() ); + // if(m_forceMissingCellCheck) considerBad = considerBad || ( missingCells.find( cell->ID() ) == missingCells.end() ); + // for bad channels in jet + if(considerBad){ + + // determine if this comes from a deadOTX + bool isOTX = false; + if(!(dde->is_tile())) + if(cell->provenance() & 0x0200) + isOTX = true; + + double dr = jet::JetDistances::deltaR(jet->eta(),jet->phi(),dde->eta(), dde->phi()); + double frac_cell = getProfile(rawPt, dr, sampling, dde->eta(), dde->phi()); + + double frac = frac_cell * cellWeight; + // if(useCalibTool) { + // frac *= m_calibTool->wtCell(cell); + // } + + // for cryo. + // if (sampling == CaloCell_ID::EMB3) emb3_jet_associate += frac_cell * rawPt; + // if (sampling == CaloCell_ID::TileBar0) tile1_jet_associate += frac_cell * rawPt; + + corr_jet_associate += frac; + + // corrected in cell-level + if(cell_energy!=0){ + // for cryo. + if(isOTX) + { + // if (sampling == CaloCell_ID::EMB3) emb3_dotx += cell->et(); + // if (sampling == CaloCell_ID::TileBar0) tile1_dotx += cell->et(); + corr_dotx += cell_energy ; + } + else + { + // if (sampling == CaloCell_ID::EMB3) emb3_cell += cell->et(); + // if (sampling == CaloCell_ID::TileBar0) tile1_cell += cell->et(); + corr_cell += cell_energy ; + } + + // if (sampling == CaloCell_ID::EMB3) emb3_jet_forcell += frac_cell * rawPt; + // if (sampling == CaloCell_ID::TileBar0) tile1_jet_forcell += frac_cell * rawPt; + + corr_jet_forcell += frac; + + } + } + } // loop over cells + + corr_cell /= rawE; + corr_dotx /= rawE; + ATH_MSG( DEBUG ) << "pt=" << jet->pt()/GeV << " eta=" << jet->eta() << " phi=" << jet->phi() + << " BCH_CORR_CELL=" << corr_cell + << " BCH_CORR_DOTX=" << corr_dotx + << " BCH_CORR_JET=" << corr_jet_associate + << " BCH_CORR_JET_FORCELL=" << corr_jet_forcell << endreq; + + jet->setAttribute<float>("BchCorrCell",corr_cell); + jet->setAttribute<float>("BchCorrDotx",corr_dotx); + if(!m_useCone) jet->setAttribute<float>("BchCorrJet", corr_jet_associate); + jet->setAttribute<float>("BchCorrJetForCell",corr_jet_forcell); + + return 0; +} + +int JetBadChanCorrTool::correctionFromCellsInCone(xAOD::Jet* jet, const jet::CaloCellFastMap * badCellMap) const { + + double corr_jet_cone=0; + + double rawPt = jet->jetP4(xAOD::JetEMScaleMomentum).Pt(); + + // badCellList.insert( badCellList.end(), m_missingCellTool->begin() , m_missingCellTool->end() ); + + + double jeteta = jet->eta(); + double jetphi = jet->phi(); + std::vector<jet::CellPosition> closeCells = badCellMap->cellsInDeltaR(jeteta,jetphi, jet->getSizeParameter() ); + std::vector<jet::CellPosition>::iterator itr = closeCells.begin(); + std::vector<jet::CellPosition>::iterator itrE = closeCells.end(); + + for(; itr!=itrE; itr++){ + + double cell_eta = itr->x(); + double cell_phi = itr->phi(); + + // const CaloDetDescrElement * dde = m_caloDDM->get_element(itr->m_id); + // CaloCell_ID::CaloSample sampling = dde->getSampling(); + CaloCell_ID::CaloSample sampling = itr->sampling(); + + double dr = jet::JetDistances::deltaR(jeteta,jetphi , cell_eta, cell_phi); + double frac_cell = getProfile(rawPt, dr, sampling, cell_eta, cell_phi); + + //double frac = frac_cell; + + // if(useCalibTool) { + + // CaloCell temp(dde,frac_cell*rawE,0,0,CaloGain::UNKNOWNGAIN);//to pick up weight + // frac *= m_calibTool->wtCell(&temp); + // } + + // if (sampling == CaloCell_ID::EMB3) emb3_jet_cone += frac_cell * rawPt; + // if (sampling == CaloCell_ID::TileBar0) tile1_jet_cone += frac_cell * rawPt; + + corr_jet_cone += frac_cell; + } + + jet->setAttribute<float>("BchCorrJet", corr_jet_cone ); + + return 0; +} + +int JetBadChanCorrTool::correctionFromClustersBadCells( xAOD::Jet* jet) const { + + double corrCell=0; + + size_t nconstit=jet->numConstituents(); + for(size_t i=0; i<nconstit; i++) { + // use the raw constituents since we're interested only in one moment : + const xAOD::IParticle* constit = jet->rawConstituent(i); + if( constit->type() != xAOD::Type::CaloCluster ) continue; + double badE; + bool v = static_cast<const xAOD::CaloCluster*>(constit)->retrieveMoment( xAOD::CaloCluster::ENG_BAD_CELLS, badE); + if(v) corrCell += badE; + } + + double rawE = jet->jetP4(xAOD::JetEMScaleMomentum).E(); + if(rawE==0)jet->setAttribute<float>("BchCorrCell", 0. ); + else jet->setAttribute<float>("BchCorrCell", corrCell / rawE ); + return 0; +} + + + + + +double JetBadChanCorrTool::getProfile(double pt, double dr, int sample, double eta, double phi) const { + std::vector<ProfileData>::const_iterator itr =m_profileDatas[sample].begin(); + std::vector<ProfileData>::const_iterator itrE =m_profileDatas[sample].end(); + for(; itr!=itrE; itr++){ + if((*itr).match(pt/GeV,sample,eta,phi)){ + return (*itr).frac(dr); + } + } + return 0; +} + + + diff --git a/Reconstruction/Jet/JetMomentTools/src/JetCaloEnergies.cxx b/Reconstruction/Jet/JetMomentTools/src/JetCaloEnergies.cxx new file mode 100644 index 00000000000..06b160c4747 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/JetCaloEnergies.cxx @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "JetMomentTools/JetCaloEnergies.h" + +#include "xAODJet/JetAccessorMap.h" + +#include "xAODCaloEvent/CaloCluster.h" +#include "JetUtils/JetCaloQualityUtils.h" + +#include <vector> +namespace { + +} + +JetCaloEnergies::JetCaloEnergies(const std::string & t) : JetModifierBase(t) { + +} + + + +int JetCaloEnergies::modifyJet( xAOD::Jet & jet)const { + + static xAOD::JetAttributeAccessor::AccessorWrapper< std::vector<float> > & ePerSamplingAcc = *xAOD::JetAttributeAccessor::accessor< std::vector<float> >(xAOD::JetAttribute::EnergyPerSampling); + + + size_t numConstit = jet.numConstituents(); + std::vector<float> & ePerSampling = ePerSamplingAcc( jet ); + ePerSampling.resize(CaloSampling::Unknown, 0.); + + for( float &e : ePerSampling) e=0.; // re-initialize + + if( numConstit == 0 ) return 1; + + // should find a more robust solution than using 1st constit type. + if( jet.rawConstituent( 0 )->type() == xAOD::Type::CaloCluster ){ + // loop over raw constituents + for(size_t i=0;i<numConstit;i++){ + for( size_t s= CaloSampling::PreSamplerB; s< CaloSampling::Unknown; s++){ + float samplE = dynamic_cast<const xAOD::CaloCluster*>(jet.rawConstituent( i ))->eSample( (xAOD::CaloCluster::CaloSample) s); + //std::cout<< " ___ sampling "<< s << " adding "<< samplE << " to "<< ePerSampling[s] << std::endl; + ePerSampling[s] += samplE; + } + } + + // for(float & cs: ePerSampling){ + // ATH_MSG_DEBUG( jet.index() << " esampling = "<< cs ); } + // ATH_MSG_DEBUG("_________________________"); + static xAOD::JetAttributeAccessor::AccessorWrapper<float>& emFracAcc = *xAOD::JetAttributeAccessor::accessor< float >(xAOD::JetAttribute::EMFrac); + static xAOD::JetAttributeAccessor::AccessorWrapper<float>& hecFracAcc = *xAOD::JetAttributeAccessor::accessor< float >(xAOD::JetAttribute::HECFrac); + emFracAcc(jet) = jet::JetCaloQualityUtils::emFraction( ePerSampling); + hecFracAcc(jet) = jet::JetCaloQualityUtils::hecF( &jet ); + } + + return 1; +} diff --git a/Reconstruction/Jet/JetMomentTools/src/JetCaloQualityTool.cxx b/Reconstruction/Jet/JetMomentTools/src/JetCaloQualityTool.cxx new file mode 100644 index 00000000000..ed7b98a679d --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/JetCaloQualityTool.cxx @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "JetUtils/JetCaloQualityUtils.h" + +#include "JetMomentTools/JetCaloQualityTool.h" +#include "xAODJet/JetAccessorMap.h" + + +//#include "CaloDetDescr/CaloDepthTool.h" +//#include "CaloIdentifier/CaloCell_ID.h" + +//#include "JetEvent/.h" + +#include <iostream> +#include <iomanip> +using namespace std; +using namespace jet; + + +JetCaloQualityTool::JetCaloQualityTool(const std::string& name) + : JetModifierBase(name) +{ + + declareProperty("DoFracSamplingMax",m_doFracSamplingMax=false); + + declareProperty("DoN90",m_doN90=true); + + declareProperty("DoLArQuality", m_doLArQuality=true); + declareProperty("DoTileQuality", m_doTileQuality=false); + declareProperty("LArQualityCut", m_LArQualityCut=4000); + declareProperty("TileQualityCut", m_TileQualityCut=254); + + declareProperty("DoTiming", m_doTiming=true); + declareProperty("TimingCellTimeCuts", m_timingCellTimeCuts); + declareProperty("TimingClusterTimeCuts", m_timingClusterTimeCuts); + declareProperty("TimingOnlyPosE", m_timingOnlyPosE=false); + + declareProperty("DoNegativeE", m_doNegativeE=true); + declareProperty("DoHECQuality", m_doHECQuality=true); + declareProperty("DoAverageLArQF", m_doAverageLArQF=true); + declareProperty("DoJetCentroid", m_doJetCentroid=true); + + declareProperty("ComputeVariableFromCluster",m_computeFromCluster=true); +} + + +int JetCaloQualityTool::modifyJet( xAOD::Jet& jet ) const +{ + //cout<<" "<<jet.getMomentKeys().size()<<endl; + //for(int i=0;i<jet.getMomentKeys().size();i++) + // cout<<jet.getMomentKeys()[i]<<endl; + + + if(msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Inside process() method" << endreq; + + //========================================================================== + //JetCaloQualityUtils + //========================================================================== + if(m_doFracSamplingMax==true) + { + int sampling=-1; + double fracSamplingMax=JetCaloQualityUtils::fracSamplingMax(&jet,sampling); + ATH_MSG_VERBOSE("Setting " << xAOD::JetAttribute::FracSamplingMax << " to " << fracSamplingMax); + jet.setAttribute<float>(xAOD::JetAttribute::FracSamplingMax,fracSamplingMax ); + jet.setAttribute<int>(xAOD::JetAttribute::FracSamplingMaxIndex,sampling ); + + // string samplingMaxName = "SamplingMax"; + // ATH_MSG_VERBOSE("Setting " << samplingMaxName << " to " << sampling); + // jet.setAttribute<float>(samplingMaxName, sampling); + + } + + m_jetCalculations.process(&jet); + std::vector<double> cellmoments = m_jetCalculations.calculations(); + std::vector<JetCaloCalculator*>& calculators = m_jetCalculations.calculators(); + for(size_t i=0;i < calculators.size();i++) { + ATH_MSG_DEBUG( calculators[i]->name() << " -> "<< cellmoments[i] ); + ATH_MSG_VERBOSE("Setting " << calculators[i]->name() << " to " << cellmoments[i]); + jet.setAttribute<float>( calculators[i]->name(), cellmoments[i] ); + } + + return StatusCode::SUCCESS; +} + + + +StatusCode JetCaloQualityTool::initialize() +{ + if(msgLvl(MSG::DEBUG)) msg(MSG::DEBUG) << "Inside initialize() method" << endreq; + + + if(m_doN90) + { + JetCalcnLeadingCells* c = new jet::JetCalcnLeadingCells(); + xAOD::JetAttribute::AttributeID id = m_computeFromCluster ? xAOD::JetAttribute::N90Constituents : + xAOD::JetAttribute::N90Cells ; + + c->setName( xAOD::JetAttributeAccessor::name( id)); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doLArQuality) + { + JetCalcQuality* c = new jet::JetCalcQuality(); + c->LArQualityCut = m_LArQualityCut; + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doTileQuality) + { + JetCalcQuality* c = new jet::JetCalcQuality(); + c->TileQualityCut = m_TileQualityCut; + c->includeTile = true; c->includeLAr = false; + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doTiming) + { + JetCalcTimeCells* c = new JetCalcTimeCells(); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doHECQuality) + { + JetCalcQualityHEC* c = new JetCalcQualityHEC(); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doNegativeE) + { + JetCalcNegativeEnergy* c = new JetCalcNegativeEnergy(); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doAverageLArQF){ + JetCalcAverageLArQualityF* c = new JetCalcAverageLArQualityF(); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + if(m_doJetCentroid){ + JetCalcCentroid* c = new jet::JetCalcCentroid(); + c->setCellLevelCalculation(! m_computeFromCluster); + m_jetCalculations.addCalculator( c ); + } + + for( double & timeCut : m_timingClusterTimeCuts){ + + // build the moment name from the base-name and the value of the timing cut + std::stringstream s; + string timingMomentClustersName = "OotFracClusters"; + s << std::setprecision(0) << std::fixed << timingMomentClustersName << timeCut; + std::string timingMomentClustersNameNow = s.str(); + + JetCalcOutOfTimeEnergyFraction* c = new jet::JetCalcOutOfTimeEnergyFraction(); + c->setName(timingMomentClustersNameNow); + c->setCellLevelCalculation(false); + c->timecut = timeCut; + m_jetCalculations.addCalculator( c ); + } + // cell timing to be done... + // for( double & timeCut : m_timingCellTimeCuts){ + + return StatusCode::SUCCESS; +} + + + diff --git a/Reconstruction/Jet/JetMomentTools/src/JetIsolationTool.cxx b/Reconstruction/Jet/JetMomentTools/src/JetIsolationTool.cxx new file mode 100644 index 00000000000..99f862eb51b --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/JetIsolationTool.cxx @@ -0,0 +1,456 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// JetIsolationTool.cxx +// Implementation file for class JetIsolationTool +/////////////////////////////////////////////////////////////////// + +// JetMomentTools includes +#include "JetMomentTools/JetIsolationTool.h" +#include "xAODCaloEvent/CaloCluster.h" +#include "JetUtils/JetDistances.h" +#include <sstream> + +/////////////////////////////////////////////////////////////////// +// Define some isolation calculators. +/////////////////////////////////////////////////////////////////// +namespace jet { + + ////////////////////////////////////////////////////// + /// \namespace JetIsolation + /// \brief Helper classes to calculate various isolation quantities + /// + /// There are many ways of calculating isolation variables. 3 aspect can be considered : + /// 1) The isolation zone (i.e which constituents not part of the jets are considered). In most of the cases this is simply a cone which radius depends on the jet. + /// 2) The kinematics computed from the contistuents in the isolation zone (sum pt, full P, ...) + /// 3) The signal sate at which constituents have to be chosen (i.e. LC scale or EM scale in the cluster case). + /// + /// To avoid to copy-paste similar code for the many possible combinations, + /// these 3 aspects are encapsulated in different classes : + /// 1) IsolationAreaBase and derived classes + /// 2) IsolationResult : which holds the 4-vector and has helpers to return the desired variables. + /// 3) KinematicGetter classes which hides the actual access to kinematics of constituents + /// + /// All these pieces are then combined in a IsolationCalculatorT<IsolationAreaBase, KinematicGetter> class (inheriting IsolationCalculator) + /// which is able to build the IsolationResult for the concrete IsolationAreaBase and KinematicGetter it receives as template paramters. + /// + /// Finally the JetIsolationTool instantiates as many IsolationCalculator as requested from its jobOption property. + /// + + namespace JetIsolation { + + typedef xAOD::IParticle::FourMom_t FourMom_t; + + /// IsolationCalculator : base class for isolation calculations + class IsolationCalculator { + public: + + /// Define the availble isolation variables + enum Kinematics { + SumPt, Par, Perp, P + }; + + /// names for isolation variables + static const std::string s_kname[4]; + + /// Holds the 4-vector of all constituents contributing to isolation. + /// accessors to corresponding isolation variables. + struct IsolationResult { + double isoSumPt(){ return m_isoSumPt;} + double isoPar(const TVector3 &unitV){ return m_isoP.Vect().Dot(unitV);} + double isoPerp(const TVector3 &unitV){ return m_isoP.Vect().Perp(unitV);} + FourMom_t & isoP(){ return m_isoP;} + + FourMom_t m_isoP ; + double m_isoSumPt; + + }; + + + virtual ~IsolationCalculator() {} + + + virtual std::string baseName() {return "";} + virtual IsolationCalculator * clone(const xAOD::Jet* ){return NULL;} + virtual void copyFrom( const IsolationCalculator* o, const xAOD::Jet*){ + m_attNames = o->m_attNames; + m_kinematics = o->m_kinematics; + } + + + /// compute the isolation momentum from jet and the constituents in nearbyConstit (these ones are supposed to be outside the jet). + virtual IsolationResult jetIsolation(const xAOD::Jet* , std::vector<jet::ParticlePosition> & ) const {return IsolationResult();} + virtual void setIsolationAttributes(xAOD::Jet* jet, std::vector<jet::ParticlePosition> & nearbyConstit) const { + + IsolationResult result = jetIsolation(jet,nearbyConstit); + for(size_t i = 0; i< m_kinematics.size(); i++){ + switch( m_kinematics[i]) { + case Perp: jet->setAttribute<float>( m_attNames[i], result.isoPerp(jet->p4().Vect()) ); break; + case SumPt: jet->setAttribute<float>( m_attNames[i], result.isoSumPt() ); break; + case Par: jet->setAttribute<float>( m_attNames[i], result.isoPar(jet->p4().Vect()) ); break; + case P: jet->setAttribute<float>( m_attNames[i], result.isoP().Vect().Mag() ); break; + } + } + + } + + + + bool scheduleKinematicCalculation(std::string kname){ + for( size_t i=0; i<4 ;i++){ + if( s_kname[i]==kname) { + m_kinematics.push_back( (Kinematics) i); + m_attNames.push_back( baseName()+kname ); + return true; + } + } + return false; + } + + + void dump(){ + std::cout << "Isolation calculator "<< baseName() <<std::endl; + for( size_t i =0 ; i<m_attNames.size(); i++){ + std::cout << " - "<< m_attNames[i] << std::endl; + } + } + + protected: + std::vector< Kinematics > m_kinematics; /// kinematics isolation vars to be computed + std::vector< std::string > m_attNames; /// kinematics isolation vars names + //std::string m_baseName; + }; + + const std::string IsolationCalculator::s_kname[4] = {"SumPt", "Par", "Perp", "P"}; + + + struct IParticleKinematicGetter { + const FourMom_t& getP(jet::ParticlePosition& p) const { return p.particle()->p4();} + double getPt(jet::ParticlePosition& p) const { return p.particle()->pt();} + }; + + struct EMClusterKinematicGetter { + const FourMom_t& getP(jet::ParticlePosition& p) const { + const xAOD::CaloCluster * cl = static_cast<const xAOD::CaloCluster*>(p.particle() ); + return cl->p4(xAOD::CaloCluster::UNCALIBRATED); + } + double getPt(jet::ParticlePosition& p) const { + const xAOD::CaloCluster * cl = static_cast<const xAOD::CaloCluster*>(p.particle() ); + return cl->p4(xAOD::CaloCluster::UNCALIBRATED).Pt(); + } + }; + + + template<typename ISOCRITERIA, typename KINEMATICGETTER = IParticleKinematicGetter> + class IsolationCalculatorT : public IsolationCalculator { + public: + + IsolationCalculatorT(double param=0.) : m_iso(param) { } + + virtual IsolationResult jetIsolation(const xAOD::Jet* jet, std::vector<jet::ParticlePosition> &nearbyConstit) const { + IsolationResult result; + result.m_isoSumPt = 0; + int contributed = 0; + for(size_t i=0 ; i<nearbyConstit.size(); i++){ + if( m_iso.inIsolationArea(jet, nearbyConstit[i]) ) { + result.m_isoP += m_kine.getP( nearbyConstit[i] ) ; + result.m_isoSumPt += m_kine.getPt(nearbyConstit[i]); + contributed++; + } + } + //std::cout << " "<< momentName()<< " contributed : "<< contributed<< " tot :"<< nearbyConstit.size() << " deltaRmax "<< m_deltaRmax << std::endl; + return result; + } + + virtual std::string baseName() {return m_iso.name();} + + + + virtual IsolationCalculator * clone(const xAOD::Jet* j){ + IsolationCalculator* iso; + m_iso.setup(j); + if( j->getInputType() == xAOD::JetInput::EMTopo) { + auto* isoT = new IsolationCalculatorT<ISOCRITERIA, EMClusterKinematicGetter >(); + isoT->m_iso = m_iso; + iso = isoT; + } else { + auto* isoT= new IsolationCalculatorT(); + isoT->m_iso = m_iso; + isoT->m_kine = m_kine; + iso = isoT; + } + iso->copyFrom(this,j); + return iso; + } + + + ISOCRITERIA m_iso; + KINEMATICGETTER m_kine; + }; + + + /// \class IsolationAreaBase + /// Defines a zone from which constituents will contribute to the isolation of a jet. + /// In most cases, the zone is simply a cone. + struct IsolationAreaBase { + IsolationAreaBase(double p, const std::string &n) : m_parameter(p), m_name(n){} + + bool inIsolationArea(const xAOD::Jet* j, jet::ParticlePosition& part) const { + + double dr2 = JetDistances::deltaR(j->eta(),j->phi(), part.x(), part.y()); + return dr2< m_deltaRmax2; + } + + std::string name(){ + std::ostringstream oss; oss << m_name << int(10*m_parameter); + return oss.str(); + } + + double m_parameter; + std::string m_name; + double m_deltaRmax2; + + }; + + + + // here we define a short cut to declare implementation of IsolationAreaBase classes. + // In most cases, only a definition of the max deltaR is enough to specify the area, hence these shortcuts. + // 1st parameter : class name + // 2nd parameter : code defining the max deltaR + // 3rd parameter (optional) : (re)-declaration of additional methods. + /// See below for example +#define ISOAREA( calcName, deltaRcode , additionalDecl ) struct calcName : public IsolationAreaBase { \ + calcName(double p) : IsolationAreaBase(p, #calcName){} \ + virtual void setup(const xAOD::Jet* j){double jetRadius=j->getSizeParameter(); double param = m_parameter; m_deltaRmax2=deltaRcode ; m_deltaRmax2*=m_deltaRmax2; param=jetRadius*param;} additionalDecl } + + + ISOAREA( IsoKR , jetRadius*param, ) ; + ISOAREA( IsoDelta, jetRadius+param, ) ; + ISOAREA( IsoFixedCone, param, ) ; + ISOAREA( IsoFixedArea, sqrt(jetRadius*jetRadius+param/M_PI) , ) ; + + // For Iso6To8 we need to redefine inIsolationArea + ISOAREA( Iso6To8, 0.8 , bool inIsolationArea(const xAOD::Jet* j, jet::ParticlePosition& constit)const ; ) ; + bool Iso6To8::inIsolationArea(const xAOD::Jet* j, jet::ParticlePosition& constit) const { + double dr2 = JetDistances::deltaR2(j->eta(), j->phi(), constit.x(), constit.y()); + return ( (dr2<0.8*0.8) && (dr2>0.6*0.6) ); + } + + + IsolationCalculator *createCalulator(std::string n, double parameter){ + + if( n == "IsoKR" ) return new IsolationCalculatorT<IsoKR>( parameter); + if( n == "IsoDelta" ) return new IsolationCalculatorT<IsoDelta>( parameter); + if( n == "IsoFixedCone" ) return new IsolationCalculatorT<IsoFixedCone>( parameter); + if( n == "IsoFixedArea" ) return new IsolationCalculatorT<IsoFixedArea>( parameter); + if( n == "Iso6To8" ) return new IsolationCalculatorT<Iso6To8>( parameter); + //if( n == "IsoCluster" ) return new IsoCluster(baseDr, parameter); + + return NULL; + } + + + } // namespace JetIsolation + +/// helper + void colonSplit(const std::string &in, std::string &s1, std::string &s2, std::string &s3){ + s2=""; s3=""; + std::stringstream str(in); + std::getline(str, s1, ':' ); + std::getline(str, s2, ':'); + std::getline(str, s3); + } + + + bool isConstituent(const xAOD::IParticle* p,const xAOD::Jet* j){ + // just need raw constituents. + for(size_t i = 0;i<j->numConstituents();i++){ + if( p == j->rawConstituent(i) ) return true; + } + return false; + } + +} // namespace jet + +using namespace jet::JetIsolation; + + + +// Constructors +//////////////// +JetIsolationTool::JetIsolationTool( const std::string& name) + : JetModifierBase(name), + m_deltaRmax(1.2), + m_rejectNegE(true) +{ + + // + // Property declaration + // + + declareProperty( "IsolationCalculations", m_isolationCodes); + + declareProperty( "ConstituentContainer", m_inputPseudoJets = "", "The Constituents from which isolation is computed (will be retrieve automatically if blank)" ); + +// declareProperty("RejectNegE", m_rejectNegE= true, "Ignore cluster with E<0"); + + + +} + +// Destructor +/////////////// +JetIsolationTool::~JetIsolationTool() +{} + +// Athena algtool's Hooks +//////////////////////////// +StatusCode JetIsolationTool::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // a temporary map of isolation calculator + std::map<std::string, IsolationCalculator*> calcMap; + + size_t nmom = m_isolationCodes.size(); + /// decode each isolation calculations as entered by properties + for(size_t i=0;i <nmom; i++){ + std::string isocriteria, param_s, kinematic; + jet::colonSplit( m_isolationCodes[i], isocriteria, param_s, kinematic); + std::string calcId = isocriteria+param_s; + IsolationCalculator* & isoC= calcMap[calcId]; + if( isoC == NULL) { + isoC = createCalulator( isocriteria, std::stod( param_s)/10. ); + } + if( isoC == NULL ) { + ATH_MSG_ERROR(" Unkown isolation criteria "<< isocriteria << " from "<< m_isolationCodes[i] ); + return StatusCode::FAILURE; + } + bool ok = isoC->scheduleKinematicCalculation( kinematic); + if(!ok) { + ATH_MSG_ERROR(" Unkown isolation kinematic "<< kinematic << " from "<< m_isolationCodes[i] ); + return StatusCode::FAILURE; + } + } + + /// Fill the iso calculator vector from the map + for( auto & pair : calcMap ){ + m_isoCalculators.push_back( pair.second ); + ATH_MSG_DEBUG("Will use iso calculation : "<< pair.second->baseName() ); + pair.second->dump(); + } + + + return StatusCode::SUCCESS; +} + + +int JetIsolationTool::modify(xAOD::JetContainer& jets) const { + + ATH_MSG_DEBUG("modify container..."); + if(jets.empty() ) return 0; + + const jet::ParticleFastMap * inputMap = retrieveInputMap(); + if(inputMap == NULL) { + ATH_MSG_ERROR("Can't retrieve constituents container. No isolation calculations"); + return 1; + } + + ATH_MSG_DEBUG("modify : retrieved map"); + + // adapt the calculators to these jets (radius, input type, etc...) + // We use the 1st jet, assuming all others in the container are similar. + std::vector<IsolationCalculator*> calculators; // the adapted calculators. + for( auto * calc : m_isoCalculators ){ + calculators.push_back( calc->clone( jets[0] ) ); + } + + + /// Loop over jets in this collection. + for( xAOD::Jet* jet: jets ){ + + jet::ParticlePosition jetPos(jet); + std::vector<jet::ParticlePosition> all_nearbyC = inputMap->pointsInDr( jetPos , m_deltaRmax); + + // restrict to nearby particles which are NOT jet constituents + // (for the expected num of constituents per jet (~30), doing a naive loop is + // faster than using set objects) + std::vector<jet::ParticlePosition> nearbyC; + nearbyC.reserve( 30 ); // educated guess. + + for( size_t i=0;i<all_nearbyC.size(); i++){ + jet::ParticlePosition &c= all_nearbyC[i]; + if( jet::isConstituent( c.particle(), jet ) ) continue; + nearbyC.push_back( c ); // the constituent does not belong to jet + } + + ATH_MSG_DEBUG( " Found nearbyC constit. All : "<< all_nearbyC.size() << " nearbyC :"<< nearbyC.size() << " in jet "<< jet->numConstituents() << " total "<< inputMap->size() ); + + // loop over calculators, calculate isolation given the close-by particles not part of the jet. + for( auto * calc : calculators ){ + calc->setIsolationAttributes( jet, nearbyC ); + } + + + } + ATH_MSG_DEBUG("done"); + return 0; +} + + +const jet::ParticleFastMap * JetIsolationTool::retrieveInputMap() const { + + ATH_MSG_DEBUG("retrieveInputMap "); + + // Check if the map is in SG + std::string mapName = m_inputPseudoJets+"FastMap"; + if( evtStore()->contains<jet::ParticleFastMap>(mapName) ){ + const jet::ParticleFastMap * inputMap = 0; + StatusCode sc = evtStore()->retrieve( inputMap, mapName) ; + if(sc.isFailure()) return NULL; // should never happen + return inputMap; + } + + ATH_MSG_DEBUG("Building the map ! "); + + // else build the map ! + jet::ParticleFastMap * inputMap = new jet::ParticleFastMap(); + inputMap->init(m_deltaRmax); + // For now very simple and limited. + const xAOD::IParticleContainer* inputConstits=0; + StatusCode sc= evtStore()->retrieve( inputConstits, m_inputPseudoJets) ; + if(sc.isFailure()) { + ATH_MSG_ERROR("No input constituents "<< m_inputPseudoJets); + return NULL; + } + + for( const xAOD::IParticle* p : *inputConstits ){ + if( m_rejectNegE && ( p->e()<0) ) continue; + jet::ParticlePosition pos( p ); + inputMap->insert( pos ); + } + + ATH_MSG_DEBUG("Built map size= "<< inputMap->size()); + + sc= evtStore()->record( inputMap, mapName) ; + if(sc.isFailure()) { ATH_MSG_WARNING( "Can't record fatmap "<< mapName); } + return inputMap; +} + + + + + +StatusCode JetIsolationTool::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + for( size_t i=0;i<m_isoCalculators.size(); i++){ + delete m_isoCalculators[i]; + } + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/Jet/JetMomentTools/src/JetLArHVTool.cxx b/Reconstruction/Jet/JetMomentTools/src/JetLArHVTool.cxx new file mode 100644 index 00000000000..2697e970b07 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/JetLArHVTool.cxx @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "JetUtils/JetDistances.h" + +#include "JetMomentTools/JetLArHVTool.h" +#ifdef ASGTOOL_ATHENA +#include "JetUtils/JetCellAccessor.h" +#endif + +JetLArHVTool::JetLArHVTool(const std::string& name) + : JetModifierBase(name), + m_useCells(true), +#ifdef ASGTOOL_ATHENA + m_hvCorrTool("LArHVCorrTool") +#endif +{ + declareProperty("UseCells", m_useCells=true); + declareProperty("HVCorrTool",m_hvCorrTool); +#ifdef ASGTOOL_ATHENA + declareProperty("keyHVScaleCorr",m_keyHVScaleCorr="LArHVScaleCorr"); +#endif +} + + +StatusCode JetLArHVTool::initialize() +{ +// Retrieve HVCorrTool + StatusCode sc = m_hvCorrTool.retrieve(); + if (sc.isFailure()) { + ATH_MSG_ERROR ( "Unable to find tool for LArHVCorrTool"); + return StatusCode::FAILURE; + } + + + return StatusCode::SUCCESS; + +} + + +int JetLArHVTool::modifyJet( xAOD::Jet& jet ) const +{ + double energy=0; + double energyHVaff=0; + int numCells=0; + int numCellsHVaff=0; + + double eFrac = 0; + double nFrac = 0; + + + + if( m_useCells){ +#ifdef ASGTOOL_ATHENA + jet::JetCellAccessor::const_iterator it = jet::JetCellAccessor::begin(&jet); + jet::JetCellAccessor::const_iterator itE = jet::JetCellAccessor::end(&jet); + for( ;it!=itE; it++) { + //e += it->e()*it.weight(); + const CaloCell* thisCell = *it; + Identifier cellID=thisCell->ID(); + numCells++; + energy+=fabs(thisCell->e()); + + //keep only the LAr cells in the jet: + if(thisCell->caloDDE()->is_tile())continue; + + //float hvdev = 0; + + //retrieve offline correction from DB: + float hvcorr = m_hvCorrTool->Scale(cellID); + + // //retrieve online correction from MetaData (available only in raw data) + // float hvonline = m_dd_HVScaleCorr->HVScaleCorr(cellID); + + //Correction should be between (0 and 2) + if (!(hvcorr>0. && hvcorr<100.)) continue; + + + //check if the difference between correction and 1 is greater than 2 per thousand, then we are in a LAr HV affected area. + if(fabs(hvcorr)-1.>0.002){ + ATH_MSG_DEBUG ( "HV affected" << hvcorr ); + energyHVaff+=fabs(thisCell->e()); + numCellsHVaff++; + }//end of non nominal HV area + +#endif + }//cells + + if(energy>0) eFrac = energyHVaff/energy; + if(numCells>0) nFrac = double(numCellsHVaff)/double(numCells); + + } // use cells + + + + // set the attributes + jet.setAttribute<float>("LArBadHVEnergyFrac", eFrac); + jet.setAttribute<float>("LArBadHVNCellFrac", nFrac); + + + return 0; +} + + diff --git a/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_entries.cxx b/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_entries.cxx new file mode 100644 index 00000000000..a5fefd200f9 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_entries.cxx @@ -0,0 +1,38 @@ +// JetRec_entries.cxx +#include "GaudiKernel/DeclareFactoryEntries.h" + +#include "JetMomentTools/JetCaloEnergies.h" +#include "JetMomentTools/JetCaloQualityTool.h" +#include "JetMomentTools/JetWidthTool.h" +#include "JetMomentTools/JetBadChanCorrTool.h" +#include "JetMomentTools/JetVertexFractionTool.h" +#include "JetMomentTools/JetTrackMomentsTool.h" +#include "JetMomentTools/JetMuonSegmentMomentsTool.h" +#include "JetMomentTools/JetPtAssociationTool.h" +#include "JetMomentTools/JetIsolationTool.h" +#include "JetMomentTools/JetLArHVTool.h" + +DECLARE_TOOL_FACTORY(JetCaloEnergies) +DECLARE_TOOL_FACTORY(JetCaloQualityTool) +DECLARE_TOOL_FACTORY(JetWidthTool) +DECLARE_TOOL_FACTORY(JetBadChanCorrTool) +DECLARE_TOOL_FACTORY(JetVertexFractionTool) +DECLARE_TOOL_FACTORY(JetTrackMomentsTool) +DECLARE_TOOL_FACTORY(JetMuonSegmentMomentsTool) +DECLARE_TOOL_FACTORY(JetPtAssociationTool) +DECLARE_TOOL_FACTORY(JetIsolationTool) +DECLARE_TOOL_FACTORY(JetLArHVTool) + +DECLARE_FACTORY_ENTRIES(JetRec) { + DECLARE_TOOL(JetCaloEnergies) + DECLARE_TOOL(JetCaloQualityTool) + DECLARE_TOOL(JetWidthTool) + DECLARE_TOOL(JetBadChanCorrTool) + DECLARE_TOOL(JetMuonSegmentMomentsTool) + DECLARE_TOOL(JetTrackMomentsTool) + DECLARE_TOOL(JetVertexFractionTool) + DECLARE_TOOL(JetPtAssociationTool) + DECLARE_TOOL(JetIsolationTool) + DECLARE_TOOL(JetLArHVTool) +} + diff --git a/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_load.cxx b/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_load.cxx new file mode 100644 index 00000000000..0e6ec8f4140 --- /dev/null +++ b/Reconstruction/Jet/JetMomentTools/src/components/JetMomentTools_load.cxx @@ -0,0 +1,5 @@ +// JetRec_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(JetMomentTools) -- GitLab