From 067c67dc993856faafffb7d2c0d799c6cd63f094 Mon Sep 17 00:00:00 2001 From: Felix Friedrich <felixf@cern.ch> Date: Thu, 14 Aug 2014 08:38:39 +0200 Subject: [PATCH] fix bug in case of cosmics (Jira ATLASRECTS-958) (tauRec-04-05-03-02) --- Reconstruction/tauRec/cmt/requirements | 69 ++ .../depreciated/TauEflowAddCaloInfo.cxx | 291 ++++++ .../tauRec/depreciated/TauEflowAddCaloInfo.h | 53 ++ .../depreciated/TauEflowTrackMatchCells.cxx | 529 +++++++++++ .../depreciated/TauEflowTrackMatchCells.h | 93 ++ .../tauRec/depreciated/TauEflowVariables.cxx | 840 +++++++++++++++++ .../tauRec/depreciated/TauEflowVariables.h | 80 ++ .../depreciated/TauOriginCorrectionTool.cxx | 215 +++++ .../depreciated/TauOriginCorrectionTool.h | 96 ++ .../TauPi0CrakowClusterCreator.cxx | 454 +++++++++ .../depreciated/TauPi0CrakowClusterCreator.h | 64 ++ .../depreciated/TauPi0CreatorChooser.cxx | 184 ++++ .../tauRec/depreciated/TauPi0CreatorChooser.h | 49 + .../depreciated/TauPi0EflowCreateROI.cxx | 514 ++++++++++ .../tauRec/depreciated/TauPi0EflowCreateROI.h | 90 ++ .../depreciated/TauSetTracksAndCharge.cxx | 85 ++ .../depreciated/TauSetTracksAndCharge.h | 45 + Reconstruction/tauRec/doc/mainpage.h | 23 + .../tauRec/python/TauAlgorithmsHolder.py | 879 ++++++++++++++++++ .../tauRec/python/TauConversionAlgorithms.py | 223 +++++ .../tauRec/python/TauRecAODBuilder.py | 119 +++ Reconstruction/tauRec/python/TauRecBuilder.py | 289 ++++++ Reconstruction/tauRec/python/tauRecFlags.py | 123 +++ .../tauRec/python/tauTrackSlimmer.py | 90 ++ .../tauRec/share/EMTES_Fits_Oct2010.root | Bin 0 -> 12844 bytes .../tauRec/share/EnergyCalibrationLC2011.root | Bin 0 -> 57427 bytes .../tauRec/share/EnergyCalibrationLC2012.root | Bin 0 -> 60589 bytes .../EnergyCalibrationLC2012_retuned.root | Bin 0 -> 64273 bytes .../tauRec/share/LCTES_Fits_May2011.root | Bin 0 -> 9042 bytes .../share/Pi0ClusterMaker_Bonn_jobOptions.py | 292 ++++++ .../Pi0ClusterMaker_Crakow_jobOptions.py | 106 +++ Reconstruction/tauRec/share/TauAODList.py | 86 ++ Reconstruction/tauRec/share/TauESDList.py | 92 ++ .../share/tauMerged_trackslim_jobOptions.py | 7 + .../tauRec/share/tauRecAOD_jobOptions.py | 10 + .../tauRec/share/tauRec_RTT_topOptions.py | 62 ++ Reconstruction/tauRec/share/tauRec_config.py | 81 ++ .../tauRec/share/tauRec_jobOptions.py | 41 + .../tauRec/src/CaloClusterVariables.cxx | 203 ++++ Reconstruction/tauRec/src/JetSeedBuilder.cxx | 209 +++++ .../tauRec/src/LockTauContainers.cxx | 55 ++ .../tauRec/src/PhotonConversionPID.cxx | 151 +++ .../tauRec/src/PhotonConversionVertex.cxx | 149 +++ Reconstruction/tauRec/src/TauAxisSetter.cxx | 161 ++++ Reconstruction/tauRec/src/TauBuilder.cxx | 373 ++++++++ Reconstruction/tauRec/src/TauCalibrateEM.cxx | 197 ++++ Reconstruction/tauRec/src/TauCalibrateLC.cxx | 265 ++++++ .../tauRec/src/TauCellVariables.cxx | 402 ++++++++ .../tauRec/src/TauCommonCalcVars.cxx | 226 +++++ .../tauRec/src/TauConversionFinder.cxx | 153 +++ .../tauRec/src/TauConversionTagger.cxx | 179 ++++ .../tauRec/src/TauElectronVetoVariables.cxx | 390 ++++++++ .../tauRec/src/TauGenericPi0Cone.cxx | 107 +++ .../tauRec/src/TauPi0BonnClusterCreator.cxx | 602 ++++++++++++ .../tauRec/src/TauPi0BonnCreateROI.cxx | 763 +++++++++++++++ .../tauRec/src/TauPi0BonnParser.cxx | 361 +++++++ .../tauRec/src/TauPi0BonnScoreCalculator.cxx | 244 +++++ .../tauRec/src/TauPi0BonnSelector.cxx | 148 +++ Reconstruction/tauRec/src/TauProcessor.cxx | 231 +++++ Reconstruction/tauRec/src/TauShotFinder.cxx | 554 +++++++++++ .../tauRec/src/TauShotVariableHelpers.cxx | 357 +++++++ .../tauRec/src/TauSubstructureVariables.cxx | 352 +++++++ Reconstruction/tauRec/src/TauTestDump.cxx | 127 +++ Reconstruction/tauRec/src/TauToolBase.cxx | 111 +++ Reconstruction/tauRec/src/TauTrackFilter.cxx | 359 +++++++ .../tauRec/src/TauTrackFilterUtils.cxx | 266 ++++++ Reconstruction/tauRec/src/TauTrackFinder.cxx | 607 ++++++++++++ Reconstruction/tauRec/src/TauTrackSlimmer.cxx | 177 ++++ Reconstruction/tauRec/src/TauVertexFinder.cxx | 216 +++++ .../tauRec/src/TauVertexVariables.cxx | 327 +++++++ .../tauRec/src/components/tauRec_entries.cxx | 116 +++ .../tauRec/src/components/tauRec_load.cxx | 6 + .../tauRec/src/tauCalibrateWeightTool.cxx | 395 ++++++++ .../tauRec/tauRec/CaloClusterVariables.h | 81 ++ Reconstruction/tauRec/tauRec/JetSeedBuilder.h | 54 ++ Reconstruction/tauRec/tauRec/KineUtils.h | 70 ++ .../tauRec/tauRec/LockTauContainers.h | 31 + .../tauRec/tauRec/PhotonConversionPID.h | 46 + .../tauRec/tauRec/PhotonConversionVertex.h | 88 ++ Reconstruction/tauRec/tauRec/TauAxisSetter.h | 48 + Reconstruction/tauRec/tauRec/TauBuilder.h | 55 ++ Reconstruction/tauRec/tauRec/TauCalibrateEM.h | 50 + Reconstruction/tauRec/tauRec/TauCalibrateLC.h | 58 ++ .../tauRec/tauRec/TauCandidateData.h | 106 +++ .../tauRec/tauRec/TauCellVariables.h | 49 + .../tauRec/tauRec/TauCommonCalcVars.h | 36 + .../tauRec/tauRec/TauConversionFinder.h | 48 + .../tauRec/tauRec/TauConversionTagger.h | 51 + .../tauRec/tauRec/TauElectronVetoVariables.h | 36 + .../tauRec/tauRec/TauGenericPi0Cone.h | 43 + .../tauRec/tauRec/TauPi0BonnClusterCreator.h | 109 +++ .../tauRec/tauRec/TauPi0BonnCreateROI.h | 127 +++ .../tauRec/tauRec/TauPi0BonnParser.h | 92 ++ .../tauRec/tauRec/TauPi0BonnScoreCalculator.h | 77 ++ .../tauRec/tauRec/TauPi0BonnSelector.h | 46 + Reconstruction/tauRec/tauRec/TauProcessor.h | 49 + Reconstruction/tauRec/tauRec/TauShotFinder.h | 158 ++++ .../tauRec/tauRec/TauShotVariableHelpers.h | 79 ++ .../tauRec/tauRec/TauSubstructureVariables.h | 50 + Reconstruction/tauRec/tauRec/TauTestDump.h | 35 + Reconstruction/tauRec/tauRec/TauToolBase.h | 73 ++ Reconstruction/tauRec/tauRec/TauTrackFilter.h | 47 + .../tauRec/tauRec/TauTrackFilterUtils.h | 46 + Reconstruction/tauRec/tauRec/TauTrackFinder.h | 142 +++ .../tauRec/tauRec/TauTrackSlimmer.h | 51 + .../tauRec/tauRec/TauVertexFinder.h | 70 ++ .../tauRec/tauRec/TauVertexVariables.h | 64 ++ Reconstruction/tauRec/tauRec/TrackSort.h | 44 + .../tauRec/tauRec/tauCalibrateWeightTool.h | 77 ++ 109 files changed, 18199 insertions(+) create mode 100755 Reconstruction/tauRec/cmt/requirements create mode 100644 Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.h create mode 100644 Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.h create mode 100644 Reconstruction/tauRec/depreciated/TauEflowVariables.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauEflowVariables.h create mode 100644 Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.h create mode 100644 Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.h create mode 100644 Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.h create mode 100644 Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.h create mode 100644 Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.cxx create mode 100644 Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.h create mode 100644 Reconstruction/tauRec/doc/mainpage.h create mode 100644 Reconstruction/tauRec/python/TauAlgorithmsHolder.py create mode 100644 Reconstruction/tauRec/python/TauConversionAlgorithms.py create mode 100644 Reconstruction/tauRec/python/TauRecAODBuilder.py create mode 100644 Reconstruction/tauRec/python/TauRecBuilder.py create mode 100644 Reconstruction/tauRec/python/tauRecFlags.py create mode 100644 Reconstruction/tauRec/python/tauTrackSlimmer.py create mode 100644 Reconstruction/tauRec/share/EMTES_Fits_Oct2010.root create mode 100644 Reconstruction/tauRec/share/EnergyCalibrationLC2011.root create mode 100644 Reconstruction/tauRec/share/EnergyCalibrationLC2012.root create mode 100644 Reconstruction/tauRec/share/EnergyCalibrationLC2012_retuned.root create mode 100644 Reconstruction/tauRec/share/LCTES_Fits_May2011.root create mode 100644 Reconstruction/tauRec/share/Pi0ClusterMaker_Bonn_jobOptions.py create mode 100644 Reconstruction/tauRec/share/Pi0ClusterMaker_Crakow_jobOptions.py create mode 100644 Reconstruction/tauRec/share/TauAODList.py create mode 100644 Reconstruction/tauRec/share/TauESDList.py create mode 100644 Reconstruction/tauRec/share/tauMerged_trackslim_jobOptions.py create mode 100644 Reconstruction/tauRec/share/tauRecAOD_jobOptions.py create mode 100644 Reconstruction/tauRec/share/tauRec_RTT_topOptions.py create mode 100644 Reconstruction/tauRec/share/tauRec_config.py create mode 100644 Reconstruction/tauRec/share/tauRec_jobOptions.py create mode 100644 Reconstruction/tauRec/src/CaloClusterVariables.cxx create mode 100644 Reconstruction/tauRec/src/JetSeedBuilder.cxx create mode 100644 Reconstruction/tauRec/src/LockTauContainers.cxx create mode 100644 Reconstruction/tauRec/src/PhotonConversionPID.cxx create mode 100644 Reconstruction/tauRec/src/PhotonConversionVertex.cxx create mode 100644 Reconstruction/tauRec/src/TauAxisSetter.cxx create mode 100644 Reconstruction/tauRec/src/TauBuilder.cxx create mode 100644 Reconstruction/tauRec/src/TauCalibrateEM.cxx create mode 100644 Reconstruction/tauRec/src/TauCalibrateLC.cxx create mode 100644 Reconstruction/tauRec/src/TauCellVariables.cxx create mode 100644 Reconstruction/tauRec/src/TauCommonCalcVars.cxx create mode 100644 Reconstruction/tauRec/src/TauConversionFinder.cxx create mode 100644 Reconstruction/tauRec/src/TauConversionTagger.cxx create mode 100644 Reconstruction/tauRec/src/TauElectronVetoVariables.cxx create mode 100644 Reconstruction/tauRec/src/TauGenericPi0Cone.cxx create mode 100644 Reconstruction/tauRec/src/TauPi0BonnClusterCreator.cxx create mode 100644 Reconstruction/tauRec/src/TauPi0BonnCreateROI.cxx create mode 100644 Reconstruction/tauRec/src/TauPi0BonnParser.cxx create mode 100644 Reconstruction/tauRec/src/TauPi0BonnScoreCalculator.cxx create mode 100644 Reconstruction/tauRec/src/TauPi0BonnSelector.cxx create mode 100644 Reconstruction/tauRec/src/TauProcessor.cxx create mode 100644 Reconstruction/tauRec/src/TauShotFinder.cxx create mode 100644 Reconstruction/tauRec/src/TauShotVariableHelpers.cxx create mode 100644 Reconstruction/tauRec/src/TauSubstructureVariables.cxx create mode 100644 Reconstruction/tauRec/src/TauTestDump.cxx create mode 100644 Reconstruction/tauRec/src/TauToolBase.cxx create mode 100644 Reconstruction/tauRec/src/TauTrackFilter.cxx create mode 100644 Reconstruction/tauRec/src/TauTrackFilterUtils.cxx create mode 100644 Reconstruction/tauRec/src/TauTrackFinder.cxx create mode 100644 Reconstruction/tauRec/src/TauTrackSlimmer.cxx create mode 100644 Reconstruction/tauRec/src/TauVertexFinder.cxx create mode 100644 Reconstruction/tauRec/src/TauVertexVariables.cxx create mode 100755 Reconstruction/tauRec/src/components/tauRec_entries.cxx create mode 100755 Reconstruction/tauRec/src/components/tauRec_load.cxx create mode 100644 Reconstruction/tauRec/src/tauCalibrateWeightTool.cxx create mode 100644 Reconstruction/tauRec/tauRec/CaloClusterVariables.h create mode 100644 Reconstruction/tauRec/tauRec/JetSeedBuilder.h create mode 100644 Reconstruction/tauRec/tauRec/KineUtils.h create mode 100644 Reconstruction/tauRec/tauRec/LockTauContainers.h create mode 100644 Reconstruction/tauRec/tauRec/PhotonConversionPID.h create mode 100644 Reconstruction/tauRec/tauRec/PhotonConversionVertex.h create mode 100644 Reconstruction/tauRec/tauRec/TauAxisSetter.h create mode 100644 Reconstruction/tauRec/tauRec/TauBuilder.h create mode 100644 Reconstruction/tauRec/tauRec/TauCalibrateEM.h create mode 100644 Reconstruction/tauRec/tauRec/TauCalibrateLC.h create mode 100644 Reconstruction/tauRec/tauRec/TauCandidateData.h create mode 100644 Reconstruction/tauRec/tauRec/TauCellVariables.h create mode 100644 Reconstruction/tauRec/tauRec/TauCommonCalcVars.h create mode 100644 Reconstruction/tauRec/tauRec/TauConversionFinder.h create mode 100644 Reconstruction/tauRec/tauRec/TauConversionTagger.h create mode 100644 Reconstruction/tauRec/tauRec/TauElectronVetoVariables.h create mode 100644 Reconstruction/tauRec/tauRec/TauGenericPi0Cone.h create mode 100644 Reconstruction/tauRec/tauRec/TauPi0BonnClusterCreator.h create mode 100644 Reconstruction/tauRec/tauRec/TauPi0BonnCreateROI.h create mode 100644 Reconstruction/tauRec/tauRec/TauPi0BonnParser.h create mode 100644 Reconstruction/tauRec/tauRec/TauPi0BonnScoreCalculator.h create mode 100644 Reconstruction/tauRec/tauRec/TauPi0BonnSelector.h create mode 100644 Reconstruction/tauRec/tauRec/TauProcessor.h create mode 100755 Reconstruction/tauRec/tauRec/TauShotFinder.h create mode 100644 Reconstruction/tauRec/tauRec/TauShotVariableHelpers.h create mode 100644 Reconstruction/tauRec/tauRec/TauSubstructureVariables.h create mode 100644 Reconstruction/tauRec/tauRec/TauTestDump.h create mode 100644 Reconstruction/tauRec/tauRec/TauToolBase.h create mode 100644 Reconstruction/tauRec/tauRec/TauTrackFilter.h create mode 100644 Reconstruction/tauRec/tauRec/TauTrackFilterUtils.h create mode 100644 Reconstruction/tauRec/tauRec/TauTrackFinder.h create mode 100644 Reconstruction/tauRec/tauRec/TauTrackSlimmer.h create mode 100644 Reconstruction/tauRec/tauRec/TauVertexFinder.h create mode 100644 Reconstruction/tauRec/tauRec/TauVertexVariables.h create mode 100644 Reconstruction/tauRec/tauRec/TrackSort.h create mode 100644 Reconstruction/tauRec/tauRec/tauCalibrateWeightTool.h diff --git a/Reconstruction/tauRec/cmt/requirements b/Reconstruction/tauRec/cmt/requirements new file mode 100755 index 00000000000..149e2b92bcc --- /dev/null +++ b/Reconstruction/tauRec/cmt/requirements @@ -0,0 +1,69 @@ +package tauRec + +author S. Rajagopalan <srinir@bnl.gov> + +public +use AtlasPolicy AtlasPolicy-* +use AthenaBaseComps AthenaBaseComps-* Control +use AthenaKernel AthenaKernel-* Control +use CxxUtils CxxUtils-* Control +use AtlasBoost AtlasBoost-* External +use AtlasROOT AtlasROOT-* External +use CaloInterface CaloInterface-* Calorimeter +use CaloUtils CaloUtils-* Calorimeter +use AthLinks AthLinks-* Control +use GaudiInterface GaudiInterface-* External +use ITrackToVertex ITrackToVertex-* Reconstruction/RecoTools +#use JetMomentTools JetMomentTools-* Reconstruction/Jet +use JetEDM JetEDM-* Reconstruction/Jet +use Particle Particle-* Reconstruction +use ParticleEvent ParticleEvent-* PhysicsAnalysis/AnalysisCommon +use tauEvent tauEvent-* Reconstruction +use xAODTau xAODTau-* Event/xAOD +use xAODJet xAODJet-* Event/xAOD +use xAODTracking xAODTracking-* Event/xAOD +use xAODCaloEvent xAODCaloEvent-* Event/xAOD +use xAODPFlow xAODPFlow-* Event/xAOD + +private +use AthContainers AthContainers-* Control +use CaloEvent CaloEvent-* Calorimeter +use EventKernel EventKernel-* Event +use CaloGeoHelpers CaloGeoHelpers-* Calorimeter +use AnalysisUtils AnalysisUtils-* PhysicsAnalysis/AnalysisCommon +use AtlasAIDA AtlasAIDA-* External +use AtlasCLHEP AtlasCLHEP-* External +use AtlasDetDescr AtlasDetDescr-* DetectorDescription +use CaloIdentifier CaloIdentifier-* Calorimeter +use EventInfo EventInfo-* Event +use FourMom FourMom-* Event +use FourMomUtils FourMomUtils-* Event +use NavFourMom NavFourMom-* Event +use InDetRecToolInterfaces InDetRecToolInterfaces-* InnerDetector/InDetRecTools +use JetEvent JetEvent-* Reconstruction/Jet +use PathResolver PathResolver-* Tools +use RecoToolInterfaces RecoToolInterfaces-* Reconstruction/RecoTools +use TrkParameters TrkParameters-* Tracking/TrkEvent +use TrkParticleBase TrkParticleBase-* Tracking/TrkEvent +use TrkTrackSummary TrkTrackSummary-* Tracking/TrkEvent +use TrkVertexFitterInterfaces TrkVertexFitterInterfaces-* Tracking/TrkVertexFitter +use TrkVertexFitters TrkVertexFitters-* Tracking/TrkVertexFitter +use TrkToolInterfaces TrkToolInterfaces-* Tracking/TrkTools +use TrkVxEdmCnv TrkVxEdmCnv-* Tracking/TrkVertexFitter +use TrkLinks TrkLinks-* Tracking/TrkEvent +use VxVertex VxVertex-* Tracking/TrkEvent +end_private + + +public + +#macro_append tauRec_shlibflags "-L$(ROOTSYS)/lib -lCore -lCint -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lm -ldl -lpthread -rdynamic" +macro_append ROOT_linkopts " -lTMVA" + +apply_pattern dual_use_library files="*.cxx *.c" + +apply_pattern declare_joboptions files="*.txt *.py" + +apply_pattern declare_runtime files="*.root *.dat *.xml" + +apply_pattern declare_python_modules files="*.py" diff --git a/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.cxx b/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.cxx new file mode 100644 index 00000000000..70934763f1a --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.cxx @@ -0,0 +1,291 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: tau1p3pAddCaloInfo.cxx +// package: Reconstruction/tauRec +// authors: Lukasz Janyst, Anna Kaczmarska +// date: 2005-07-05 +// +// Tool to calculate identification variables (calo + tracking) +// +// MODIFIED: +// 11/09/2006 - (AK) correcting statusCode +// 08/10/2006 - (AK) change of detRCoreCaloCut, detRIsolCaloCut +// input parameters names +// 03/07/2009 - (AK) changing closest*TrkVertCell accessors to the "old-EDM" ones +//----------------------------------------------------------------------------- + +//TODO: revisit StatusCode + +#include <algorithm> +#include <math.h> +#include <sstream> + +#include "GaudiKernel/Property.h" + +#include "FourMom/P4EEtaPhiM.h" + +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloGeoHelpers/CaloSampling.h" + +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauCommonExtraDetails.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TauOriginCorrectionTool.h" + +#include "tauRec/TauEflowAddCaloInfo.h" + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauEflowAddCaloInfo::TauEflowAddCaloInfo(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_detRCoreCaloCut(0.2), +m_detRIsolCaloCut(0.4), +m_ETCellMinCut(100.0), +m_ETStripMinCut(200.0), +m_detaStripCut(0.2), +m_doCellCorrection(false), //FF: don't do cell correction by default +m_tauOriginCorrTool("") { + declareInterface<TauToolBase > (this); + + declareProperty("detRCoreCaloCut", m_detRCoreCaloCut); + declareProperty("detRIsolCaloCut", m_detRIsolCaloCut); + declareProperty("ETCellMinCut", m_ETCellMinCut); + declareProperty("ETStripMinCut", m_ETStripMinCut); + declareProperty("detaStripCut", m_detaStripCut); + declareProperty("CellCorrection", m_doCellCorrection); + declareProperty("OriginCorrectionTool", m_tauOriginCorrTool); + +} + + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauEflowAddCaloInfo::~TauEflowAddCaloInfo() { } + + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- + +StatusCode TauEflowAddCaloInfo::initialize() { + + ATH_MSG_VERBOSE(name() << " RconeTauCut = " << m_detRIsolCaloCut); + ATH_MSG_VERBOSE(name() << " RconeCoreCut = " << m_detRCoreCaloCut); + ATH_MSG_VERBOSE(name() << " ETCellMinCut = " << m_ETCellMinCut); + ATH_MSG_VERBOSE(name() << " ETStripMinCut = " << m_ETStripMinCut); + ATH_MSG_VERBOSE(name() << " detaStripCut = " << m_detaStripCut); + + if (m_tauOriginCorrTool.retrieve().isFailure()) { + ATH_MSG_ERROR("Cannot find tool named <" << m_tauOriginCorrTool << ">"); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("tau Origin Correction Tool <" << m_tauOriginCorrTool << "> retrieved"); + + return StatusCode::SUCCESS; +} + +StatusCode TauEflowAddCaloInfo::eventInitialize(TauCandidateData * /*data*/) +{ + if (m_doCellCorrection) { + // Cell Origin Correction Tool initializeEvent is not called automatically + // -> call from here + return m_tauOriginCorrTool->eventInitialize(); + } + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- + +StatusCode TauEflowAddCaloInfo::execute(TauCandidateData *data) { + + Analysis::TauJet *pTau = data->tau; + Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + Analysis::TauCommonExtraDetails *pExtraDetails = dynamic_cast<Analysis::TauCommonExtraDetails *> (data->extraDetails); + + if (pTau->numTrack() == 0) { + ATH_MSG_VERBOSE("tau has no tracks -> skip EflowAddCaloInfo"); + return StatusCode::SUCCESS; + } + + if (!pDetails || !pExtraDetails) { + ATH_MSG_ERROR("TauCommon(Extra)Details object not valid"); + return StatusCode::FAILURE; + } + + StatusCode sc; + + + //----------------------------------------------------------------- + // Variable initialization + //----------------------------------------------------------------- + int nStrips = 0; + double sumETR02 = 0; + double sumETR01 = 0; + double sumET012 = 0; + double sumDetET012 = 0; + double stripEta = 0; + double stripEta2 = 0; + double stripET = 0; + double detPhi = 999.; + double detEta = 999.; + double detCell = 999.; + double sumETotherHAD = 0; + double sumETotherEM = 0; + double sumETchrgHAD = 0; + double stripWidth2 = 0; + double Rem = 0; + double fracETR12 = 0; + + //----------------------------------------------------------------- + // Loop on cells placed there by TauEflowTrackMatchCells + //----------------------------------------------------------------- + if (!pTau->cellCluster()) return StatusCode::FAILURE; + + //use tau vertex to correct cell position + if (m_doCellCorrection) { + m_tauOriginCorrTool->setOriginSource(pTau->origin()); + } + + const CaloCluster *pCluster = pTau->cellCluster(); + CaloCluster::cell_iterator cellItr = pCluster->cell_begin(); + CaloCluster::cell_iterator cellItrE = pCluster->cell_end(); + + const CaloCell *pCell; + + //loop on cells connected to object + for (; cellItr != cellItrE; ++cellItr) { + + pCell = (*cellItr); + + // correct cell for tau vertex + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + double cellPhi = pCell->phi(); + double cellEta = pCell->eta(); + double cellET = pCell->et(); + double cellEnergy = pCell->energy(); + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + + if (cellET < m_ETCellMinCut) continue; + + int sampling = pCell->caloDDE()->getSampling(); + if (sampling > 3 && sampling < 8) sampling = sampling - 4; + + int i = 2; + if (sampling < 4) i = sampling; + + const CaloCell* ccEta = pExtraDetails->closestEtaTrkVertCell(0, i); + const CaloCell* ccPhi = pExtraDetails->closestPhiTrkVertCell(0, i); + + if (ccPhi) { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, ccPhi->phi()); + } else { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, pTau->track(0)->phi()); + } + + if (ccEta) { + detEta = Tau1P3PKineUtils::deltaEta(cellEta, ccEta->eta()); + } else { + detEta = Tau1P3PKineUtils::deltaEta(cellEta, pTau->track(0)->eta()); + } + + detCell = Tau1P3PKineUtils::deltaR(detPhi, detEta); + + + //------------------------------------------------------------- + // Cuts + //------------------------------------------------------------- + if (detCell > m_detRIsolCaloCut) continue; + + if (detCell > m_detRCoreCaloCut) { + if (sampling > 3) { + sumETotherHAD += cellEnergy / cosh(cellEta); + } else { + sumETotherEM += cellET; + } + } + + if (detCell > m_detRCoreCaloCut) continue; + + if (sampling > 2) sumETchrgHAD += cellET; + + if (sampling == 1 && cellET > m_ETStripMinCut) { + const CaloCell* ccEta1 = *pExtraDetails->closestEtaTrkVertCell()[0][1]; + + detEta = Tau1P3PKineUtils::deltaEta(cellEta, ccEta1->eta()); + + if (std::fabs(detEta) < m_detaStripCut) { + ++nStrips; + } + } + + if (detCell < m_detRCoreCaloCut) sumETR02 += cellET; + + if (detCell < m_detRCoreCaloCut / 2.) sumETR01 += cellET; + + if (sampling > 2) continue; + + sumET012 += cellET; + sumDetET012 += cellET * detCell; + + if (sampling != 1) continue; + + stripEta += cellEta * cellET; + stripEta2 += cellEta * cellEta * cellET; + stripET += cellET; + } // end cell loop + + if (sumET012 > 0) Rem = sumDetET012 / sumET012; + + if (sumETR02 > 0) fracETR12 = (sumETR02 - sumETR01) / sumETR02; + + if (stripET > 0.0) stripWidth2 = (stripEta2 / stripET - stripEta * stripEta / stripET / stripET); + + + //----------------------------------------------------------------- + // Set properties + //----------------------------------------------------------------- + ATH_MSG_VERBOSE(name() << " taurec nStrips " << nStrips); + pDetails->setSeedTrk_nStrip(nStrips); + + ATH_MSG_VERBOSE(name() << " Rem " << Rem); + pDetails->setSeedTrk_EMRadius(Rem); + + ATH_MSG_VERBOSE(name() << " fracETR1 " << fracETR12); + pDetails->setSeedTrk_isolFrac(fracETR12); + + ATH_MSG_VERBOSE(name() << " stripWidth2 " << stripWidth2); + pDetails->setSeedTrk_stripWidth2(stripWidth2); + + ATH_MSG_VERBOSE(name() << " sumETotherHAD " << sumETotherHAD); + pDetails->setSeedTrk_etIsolHad(sumETotherHAD); + + ATH_MSG_VERBOSE(name() << " sumETotherEM " << sumETotherEM); + pDetails->setSeedTrk_etIsolEM(sumETotherEM); + + ATH_MSG_VERBOSE(name() << " sumETchrgHAD " << sumETchrgHAD); + pDetails->setSeedTrk_etChrgHad(sumETchrgHAD); + + return sc; + +} diff --git a/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.h b/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.h new file mode 100644 index 00000000000..ae12b5802f3 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowAddCaloInfo.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUEFLOWADDCALOINFO_H +#define TAUREC_TAUEFLOWADDCALOINFO_H + +#include "tauRec/TauToolBase.h" + +class TauOriginCorrectionTool; + +/** + * @brief Calculate calorimeter variables and their distances to the leading tau track. + * + * Use cells placed there by TauEflowTrackMatchCells. + * This tool was formerly named as tau1p3pAddCaloInfo. + * + * @authors Lukasz Janyst, Anna Kaczmarska + * + */ + +class TauEflowAddCaloInfo : public TauToolBase { +public: + + TauEflowAddCaloInfo(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauEflowAddCaloInfo(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventInitialize(TauCandidateData *data); + + +private: + double m_detRCoreCaloCut; + double m_detRIsolCaloCut; + double m_ETCellMinCut; + double m_ETStripMinCut; + double m_detaStripCut; + + /** + * enable cell origin correction + * eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doCellCorrection; + ToolHandle<TauOriginCorrectionTool> m_tauOriginCorrTool; + +}; + +#endif /* TAUREC_TAUEFLOWADDCALOINFO_H */ + diff --git a/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.cxx b/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.cxx new file mode 100644 index 00000000000..0df1ab35be2 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.cxx @@ -0,0 +1,529 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: tau1p3pTrackMatchCells.cxx +// package: Reconstruction/tauRec +// authors: Tadeusz Szymocha, Anna Kaczmarska +// date: 2005-07-01 +// +// Tool for building CaloCluster of cells associated with +// a given track. +// +// MODIFIED: +// 08/10/2006 - (AK) change of m_RconeTauCut -> m_detRIsolCaloCut +// 18/03/2008 - (AK) changing cone for cell preselection 0.8->0.45 +// 11/04/2008 - (AK) moving select cone size to tool properties +// 30/06/2008 - (AK) (for MW) fix of memory leak +// 16/03/2010 - (AK) initialization of triggerFlag variable +// 17/03/2010 - (AK) change to P4Helpers +// 16/05/2010 - (FF) pointer p_measPer never used (coverity 22628) +//----------------------------------------------------------------------------- + +//TODO: change statuscode failure --> recoverable + +#include "tauRec/TauEflowTrackMatchCells.h" + +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauCommonExtraDetails.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TauOriginCorrectionTool.h" + +#include <CaloEvent/CaloCluster.h> +#include <CaloUtils/CaloClusterStoreHelper.h> +#include "CaloInterface/ICaloNoiseTool.h" +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCell.h" +#include "CaloIdentifier/CaloCell_ID.h" + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" + +#include <GaudiKernel/ListItem.h> +#include <algorithm> + +static void delete_cluster(std::pair<Analysis::TauJet * const, CaloCluster *> &pr) { + pr.first->cellClusterLink().reset(); + delete pr.second; +} + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauEflowTrackMatchCells::TauEflowTrackMatchCells(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_cellsContainerName("AllCalo"), +m_detRIsolCaloCut(0.4), +m_useNoiseSigma(1), +m_AbsNoiseSigma_cut(2), +m_selectConeSize(0.45), +m_doCellCorrection(false), //FF: don't do cell correction by default +m_tauOriginCorrTool("") { + declareInterface<TauToolBase > (this); + + declareProperty("CellsContainerName", m_cellsContainerName); + // declare large fixed cone for creating subcollection of cells (cluster) + declareProperty("detRIsolCaloCut", m_detRIsolCaloCut); + // declare options for noise/weighting + declareProperty("useNoiseSigma", m_useNoiseSigma); + declareProperty("AbsNoiseSigma_cut", m_AbsNoiseSigma_cut); + declareProperty("CaloNoiseTool", m_noiseTool, "Tool Handle for noise tool"); + declareProperty("ClusterContainerName", m_clusterContainerName = "Tau1P3PCellCluster"); + //ak + declareProperty("ClusterEMContainerName", m_clusterEMContainerName = "Tau1P3PCellEM012ClusterContainer"); + declareProperty("selectConeSize", m_selectConeSize); + declareProperty("CellCorrection", m_doCellCorrection); + declareProperty("OriginCorrectionTool", m_tauOriginCorrTool); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauEflowTrackMatchCells::~TauEflowTrackMatchCells() { +} + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- + +StatusCode TauEflowTrackMatchCells::initialize() { + ATH_MSG_VERBOSE(name() << " CellsContainerName = " << m_cellsContainerName); + ATH_MSG_VERBOSE(name() << " RconeTauCut = " << m_detRIsolCaloCut); + ATH_MSG_VERBOSE(name() << " selectConeSize = " << m_selectConeSize); + + //Create Noise Tools: + if (m_useNoiseSigma != 0) { + // SL changes to retrieval of CaloNoiseTool + if (m_noiseTool.retrieve().isFailure()) { + ATH_MSG_FATAL("Unable to retrieve CaloNoiseTool"); + return StatusCode::FAILURE; + } + } + + if (m_tauOriginCorrTool.retrieve().isFailure()) { + ATH_MSG_ERROR("Cannot find tool named <" << m_tauOriginCorrTool << ">"); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("tau Origin Correction Tool <" << m_tauOriginCorrTool << "> retrieved"); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Event Initializer +//----------------------------------------------------------------------------- + +StatusCode TauEflowTrackMatchCells::eventInitialize(TauCandidateData *) { + m_clusterMap.clear(); + + if (m_doCellCorrection) { + // Cell Origin Correction Tool initializeEvent is not called automatically + // -> call from here + return m_tauOriginCorrTool->eventInitialize(); + } + return StatusCode::SUCCESS; +} + + +//------------------------------------------------------------------------- +// Event Finalizer +//------------------------------------------------------------------------- + +StatusCode TauEflowTrackMatchCells::eventFinalize(TauCandidateData *data) { + + MsgStream rLog(msgSvc(), name()); + + StatusCode sc; + + //---------------------------------------------------------------------- + // Check if we're running in the trigger + //---------------------------------------------------------------------- + bool triggerFlag = false; + sc = data->getObject("InTrigger?", triggerFlag); + if (sc.isSuccess() && triggerFlag) { + //------------------------------------------------------------------ + // Delete all the clusters + //------------------------------------------------------------------ + std::for_each(m_clusterMap.begin(), m_clusterMap.end(), delete_cluster); + + Analysis::TauDetailsContainer *pCont = data->detailsContainer; + Analysis::TauDetailsContainer::iterator it1; + for (it1 = pCont->begin(); it1 != pCont->end(); ++it1) { + Analysis::TauDetails *td = *it1; + Analysis::TauCommonDetails *det = dynamic_cast<Analysis::TauCommonDetails *> (td); + if (det) { + delete det->cellEM012Cluster(); + det->cellEM012ClusterLink().reset(); + } + } + return StatusCode::SUCCESS; + } + + //---------------------------------------------------------------------- + // Create cluster container + //---------------------------------------------------------------------- + CaloClusterContainer *clusterContainer = new CaloClusterContainer(); + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::recordClusters(&*evtStore(), + // clusterContainer, + // m_clusterContainerName, + // rLog); + + //---------------------------------------------------------------------- + // Put all clusters in the container + //---------------------------------------------------------------------- + std::map<Analysis::TauJet *, CaloCluster *> ::iterator it; + for (it = m_clusterMap.begin(); it != m_clusterMap.end(); ++it) + clusterContainer->push_back((*it).second); + + //ak + std::sort(clusterContainer->begin(), clusterContainer->end(), OrderClust()); + + //--------------------------------------------------------------------- + // Record cluster container + //--------------------------------------------------------------------- + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::finalizeClusters(&*evtStore(), + // clusterContainer, + // m_clusterContainerName, + // rLog); + + + //--------------------------------------------------------------------- + // Set up element links + //--------------------------------------------------------------------- + for (it = m_clusterMap.begin(); it != m_clusterMap.end(); ++it) + (*it).first->setCellCluster(clusterContainer, (*it).second); + + //---------------------------------------------------------------------- + // Create EM cluster container + //---------------------------------------------------------------------- + CaloClusterContainer *clusterEMContainer = new CaloClusterContainer(); + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::recordClusters(&*evtStore(), + // clusterEMContainer, + // m_clusterEMContainerName, + // rLog); + + //---------------------------------------------------------------------- + // Put all clusters in the container + //---------------------------------------------------------------------- + Analysis::TauDetailsContainer *pCont = data->detailsContainer; + Analysis::TauDetailsContainer::iterator it1; + for (it1 = pCont->begin(); it1 != pCont->end(); ++it1) { + Analysis::TauDetails *td = *it1; + Analysis::TauCommonDetails *det = dynamic_cast<Analysis::TauCommonDetails *> (td); + if (det) { + if (det->cellEM012Cluster()) { + clusterEMContainer->push_back(const_cast<CaloCluster *> (det->cellEM012Cluster())); + } + } + } + + //--------------------------------------------------------------------- + // Record cluster container + //--------------------------------------------------------------------- + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::finalizeClusters(&*evtStore(), + // clusterEMContainer, + // m_clusterEMContainerName, + // rLog); + + //--------------------------------------------------------------------- + // Set up element links + //--------------------------------------------------------------------- + for (it1 = pCont->begin(); it1 != pCont->end(); ++it1) { + Analysis::TauDetails *td = *it1; + Analysis::TauCommonDetails *det = dynamic_cast<Analysis::TauCommonDetails *> (td); + if (det) { + if (det->cellEM012Cluster()) { + det->setCellEM012Cluster(clusterEMContainer, det->cellEM012Cluster()); + } + } + } + + return sc; +} + +//----------------------------------------------------------------------------- +// Cleanup, in case this candidate was rejected later +//----------------------------------------------------------------------------- + +void TauEflowTrackMatchCells::cleanup(TauCandidateData *data) { + + //------------------------------------------------------------------------- + // Cleanup cluster + //------------------------------------------------------------------------- + Analysis::TauJet *pTau = data->tau; + std::map<Analysis::TauJet *, CaloCluster *> ::iterator it; + it = m_clusterMap.find(pTau); + + if (it != m_clusterMap.end()) { + delete (*it).second; + m_clusterMap.erase(it); + } + + pTau->cellClusterLink().reset(); + + //------------------------------------------------------------------------- + // Cleanup EM012Cluster + //------------------------------------------------------------------------- + Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + if (pDetails) { + delete pDetails->cellEM012Cluster(); + pDetails->cellEM012ClusterLink().reset(); + } +} + + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- + +StatusCode TauEflowTrackMatchCells::execute(TauCandidateData *data) { + + // Analysis::TauJet *pTau = data->tau; + // Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + // Analysis::TauCommonExtraDetails *pExtraDetails = dynamic_cast<Analysis::TauCommonExtraDetails *> (data->extraDetails); + + // // + // if (pTau->numTrack()==0) { + // ATH_MSG_VERBOSE("tau has no tracks -> skip TrackMatchCells"); + // return StatusCode::SUCCESS; + // } + + // if ( !pDetails || !pExtraDetails) { + // ATH_MSG_ERROR("TauCommon(Extra)Details object not valid"); + // return StatusCode::FAILURE; + // } + + // StatusCode sc; + + + // //--------------------------------------------------------------------- + // // Retrieve CaloCellCollection from StoreGate + // //--------------------------------------------------------------------- + // const CaloCellContainer *pCellContainer; + + // sc = data->getObject("CellContainer", pCellContainer); + // if (sc.isFailure() || !pCellContainer) { + // sc = evtStore()->retrieve(pCellContainer, m_cellsContainerName); + // if (sc.isFailure()) { + // ATH_MSG_INFO("TrackMatchCells: Unable to retrieve " << m_cellsContainerName << " from TES"); + // } + // } + + // xAOD::CaloCluster *pCluster = CaloClusterStoreHelper::makeCluster(); + // xAOD::CaloCluster *pClusterEM = CaloClusterStoreHelper::makeCluster(); + + // //put cluster into object + // pTau->cellClusterLink().reset(); + // pTau->cellClusterLink().setElement(pCluster); + // m_clusterMap[pTau] = pCluster; + + // pDetails->cellEM012ClusterLink().reset(); + // pDetails->cellEM012ClusterLink().setElement(pClusterEM); + + // //--------------------------------------------------------------------- + // // Loop over cells collection and find closest cell at a given layer + // // from track impact point at vertex and propagated in magnetic field + // //--------------------------------------------------------------------- + + // const int nTr = 10; + // const int nSa = 4; + + // double detEtaCellMin[nTr][nSa], detPhiCellMin[nTr][nSa]; + // double detEtaCellMinCh[nTr][nSa], detPhiCellMinCh[nTr][nSa]; + // double detEtaVertMin[nSa], detPhiVertMin[4]; + + // const CaloCell * pTmpEtaCell[nTr][nSa]; + // const CaloCell * pTmpPhiCell[nTr][nSa]; + // const CaloCell * pTmpEtaVertCell[nSa]; + // const CaloCell * pTmpPhiVertCell[nSa]; + + + // for (int i = 0; i < nSa; ++i) { + // detEtaVertMin[i] = 9999.; + // detPhiVertMin[i] = 9999.; + + // pTmpEtaVertCell[i] = 0; + // pTmpPhiVertCell[i] = 0; + + // for (int j = 0; j < nTr; ++j) { + // detEtaCellMin[j][i] = 9999.; + // detPhiCellMin[j][i] = 9999.; + + // detEtaCellMinCh[j][i] = 9999.; + // detPhiCellMinCh[j][i] = 9999.; + + // pTmpEtaCell[j][i] = 0; + // pTmpPhiCell[j][i] = 0; + // } + // } + + // const CaloCell *pCell; + // pCell = 0; + + // /* FF: + // //do cell selection + // CaloCellList *celllist = new CaloCellList(pCellContainer); + // celllist->select(pTau->track(0)->eta(), pTau->track(0)->phi(), m_selectConeSize); + + // if (celllist->ncells() == 0) { + // delete celllist; + // return StatusCode::FAILURE; + // } + + // CaloCellList::list_iterator itr = celllist->begin(); + // CaloCellList::list_iterator itrE = celllist->end(); + // */ + + + // //use tau vertex to correct cell position + // if (m_doCellCorrection) { + // m_tauOriginCorrTool->setOriginSource(pTau->origin()); + // } + + // //FF: use cells already associated to jet seed + // // this is valid until m_selectConeSize is < or about 0.4 + // typedef NavigationToken<CaloCell, NavigationDefaults::DefaultWeight, CaloCellIDFcn> token_t; + // token_t nt; + // pTau->fillToken(nt); + + // token_t::const_iterator itr = nt.begin(); + // token_t::const_iterator itrE = nt.end(); + // // + + // //loop over cells and calculate the variables + // for (; itr != itrE; itr++) { + // pCell = *itr; + + // // correct cell for tau vertex + // if (m_doCellCorrection) { + // m_tauOriginCorrTool->correctCell(pCell); + // } + + // double cellPhi = pCell->phi(); + // double cellEta = pCell->eta(); + // double cellEnergy = pCell->energy(); + + // if (m_doCellCorrection) { + // m_tauOriginCorrTool->resetCell(pCell); + // } + + // double detCell = P4Helpers::deltaR(*pTau->track(0), cellEta, cellPhi); + + // // collect all cells (remove noisy cells ) in a fixed + // // large cone around candidate (at vertex) + // if (detCell > m_detRIsolCaloCut) continue; + + // int isCellAccepted = 1; + + // if (m_useNoiseSigma == 1) { + // double noiseSigma; + // noiseSigma = m_noiseTool->getNoise(*itr, ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN); + // if (fabs(cellEnergy) < m_AbsNoiseSigma_cut * noiseSigma) isCellAccepted = 0; + + // } + + // // add cells above the noise to the associated cluster + // if (isCellAccepted == 1) pCluster->addCell(pCellContainer, pCell, 1.0); + + // // find position nominal position of the closest cell at each layer + // int samp = CaloSampling::getSampling(*pCell); + // if (samp > 3 && samp < 8) samp = samp - 4; + + // //ak + // if (samp < 3 && isCellAccepted == 1) pClusterEM->addCell(pCellContainer, pCell, 1.0); + + // // consider only sampling < 4 + // if (samp >= 4) continue; + + // double detPhiVert = Tau1P3PKineUtils::deltaPhi(cellPhi, pTau->phi()); + // double detEtaVert = Tau1P3PKineUtils::deltaEta(cellEta, pTau->eta()); + + // if (detEtaVert < detEtaVertMin[samp]) { + // detEtaVertMin[samp] = detEtaVert; + // pTmpEtaVertCell[samp] = pCell; + // } + + // if (detPhiVert < detPhiVertMin[samp]) { + // detPhiVertMin[samp] = detPhiVert; + // pTmpPhiVertCell[samp] = pCell; + // } + + // //for each track connected to tau object + // for (unsigned itr = 0; itr < pTau->numTrack(); itr++) { + // // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + // if (itr >= 9) break; + + // double detEtaCell[nTr]; + // double detPhiCell[nTr]; + // detEtaCell[itr] = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->etaTrkCaloSamp()[itr][samp]); + // detPhiCell[itr] = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->phiTrkCaloSamp()[itr][samp]); + + // //FIX ME! Should we look for different cell in eta and + // //in phi? ot the closest one? + + // if (detEtaCell[itr] < detEtaCellMin[itr][samp]) { + // detEtaCellMin[itr][samp] = detEtaCell[itr]; + // pTmpEtaCell[itr][samp] = pCell; + // } + + // if (detPhiCell[itr] < detPhiCellMin[itr][samp]) { + // detPhiCellMin[itr][samp] = detPhiCell[itr]; + // pTmpPhiCell[itr][samp] = pCell; + // } + + // // for better collection of energy around charged track... + // // correct if possible and consider only + // // cells with really deposited energy + // if (isCellAccepted == 0) continue; + + // if (detEtaCell[itr] < detEtaCellMinCh[itr][samp]) { + // detEtaCellMinCh[itr][samp] = detEtaCell[itr]; + // pTmpEtaCell[itr][samp] = pCell; + // } + + // if (detPhiCell[itr] < detPhiCellMinCh[itr][samp]) { + // detPhiCellMinCh[itr][samp] = detPhiCell[itr]; + // pTmpPhiCell[itr][samp] = pCell; + // } + // } // end track loop + + // } // end cell loop + + // // loop over sampling + // for (int i = 0; i < 4; i++) { + // if (pTmpEtaVertCell[i]) pExtraDetails->setClosestEtaTrkVertCell(pTmpEtaVertCell[i], pCellContainer, 0, i); + // if (pTmpPhiVertCell[i]) pExtraDetails->setClosestPhiTrkVertCell(pTmpPhiVertCell[i], pCellContainer, 0, i); + + // for (unsigned itr = 0; itr < pTau->numTrack(); itr++) { + // // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + // if (itr >= 9) break; + // if (pTmpEtaCell[itr][i]) pExtraDetails->setClosestEtaTrkCell(pTmpEtaCell[itr][i], pCellContainer, itr, i); + // if (pTmpPhiCell[itr][i]) pExtraDetails->setClosestPhiTrkCell(pTmpPhiCell[itr][i], pCellContainer, itr, i); + // } + // } + + // //FF: + // //delete celllist; + + // return sc; + return StatusCode::SUCCESS; +} + + + + diff --git a/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.h b/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.h new file mode 100644 index 00000000000..824d2883e5e --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowTrackMatchCells.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUEFLOWTRACKMATCHCELLS_H +#define TAUREC_TAUEFLOWTRACKMATCHCELLS_H + +#include <map> + +#include "GaudiKernel/ToolHandle.h" +#include "CaloInterface/ICalorimeterNoiseTool.h" +#include "CaloEvent/CaloClusterContainer.h" + +#include "tauRec/TauToolBase.h" + +class TauOriginCorrectionTool; + +/** + * @brief Tool for building CaloCluster of cells associated with a given tau. + * + * This tool was formerly named as tau1p3pTrackMatchCells. + * + * @authors Tadeusz Szymocha, Anna Kaczmarska + * + */ + +class TauEflowTrackMatchCells : public TauToolBase +{ + public: + + TauEflowTrackMatchCells(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauEflowTrackMatchCells(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + + virtual void cleanup(TauCandidateData *data); + + private: + std::string m_cellsContainerName; + std::string m_clusterContainerName; + + //! large fixed cone to collect cells around the track + double m_detRIsolCaloCut; + + //! use noise tool to estimate sigma + double m_useNoiseSigma; + + //! threshold to suppress noisy cells + double m_AbsNoiseSigma_cut; + + //! cone for cell pre-selection + double m_selectConeSize; + + //! tool for noise + ToolHandle <ICalorimeterNoiseTool> m_noiseTool; + + std::map<Analysis::TauJet *, CaloCluster *> m_clusterMap; + + std::string m_clusterEMContainerName; + + /** + * enable cell origin correction + * eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doCellCorrection; + ToolHandle<TauOriginCorrectionTool> m_tauOriginCorrTool; + +}; + +//TODO: same as in CaloClusterVariables! --> move both to KinUtils.h? +//------------------------------------------------------------------------- +//! Descending order by energy +//------------------------------------------------------------------------- + +struct OrderClust +{ + bool operator()(const CaloCluster *t1, const CaloCluster * t2) const { + //FF:: don't need a warning here + //if (t1->et() == t2->et()) { + // std::cout << " tauRec:tau1p3pTrackMatchCells WARNING Found two clusters with the same et ! " << t1->et() << std::endl; + // } + return t1->et() < t2->et(); + } +}; + + +#endif diff --git a/Reconstruction/tauRec/depreciated/TauEflowVariables.cxx b/Reconstruction/tauRec/depreciated/TauEflowVariables.cxx new file mode 100644 index 00000000000..d999dd57e69 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowVariables.cxx @@ -0,0 +1,840 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: tau1p3pAddEflowInfo.cxx +// package: Reconstruction/tauRec +// authors: Tadeusz Szymocha, Anna Kaczmarska +// date: 2006-02-09 +// +// This tool builds energy flow quantities. +// +// MODIFIED: +// 07/10/2005 - (LJ) Proper deletion of Pi0 clusters +// 14/09/2006 - (LJ,AK) temporaty solution for removing cells +// from object in order to avoid problems with +// casting CaloCellContainer to +// INavigable4MomentumCollection +// 07/10/2005 - (LJ) Proper deletion of Pi0 clusters +// 08/10/2006 - (AK) change of RconeCoreCut parameter name +// fixing wrong reading of extrapolation point for +// endcap in fillTopoClusterInfo +// 03/11/2006 - (AK) added filling sumEM +// 07/11/2006 - (AK) preselection with cuts on MVisEflow, MTrk3P, ETeflow / ETcalo variables +// 24/11/2006 - (AK) correcting phi barycenter calculation +// 26/11/2006 - (ERW) corrected eflow calculation +// 13/07/2007 - (AK) dynamic allocation of arrays +// 23/04/2007 - (AK) adding writing pi0 container +// 10/07/2007 - (AK) allowing ntrack>3 candidates +// 19/06/2007 - (ERW) removing writting pi0 container -> delegated to tau1p3pCreatePi0Cluster.cxx +// 07/07/2007 - (ERW) removing filling sumEM -> delegated to tau1p3pCreatePi0Cluster.cxx +// 04/01/2008 - (AK) adding low cut on etcalo/etflow +// 10/06/2008 - (AK) fixing floating point exceptions (bug 37635) +// 30/09/2008 - (AK) memory fragmentation fixes (bug 41937) +// 09/10/2009 - (AK) correcting unchecked SC (bug 56754) +// 17/05/2011 - (FF) add initializer for array (line 276) (coverity 20321) +//----------------------------------------------------------------------------- + +//TODO: change statuscode failure to recoverable +//TODO: AllCalo hardcoded + +#include <algorithm> +#include <math.h> +#include <sstream> + +#include "GaudiKernel/Property.h" +#include "GaudiKernel/ListItem.h" +#include "GaudiKernel/IToolSvc.h" + +#include "FourMom/P4EEtaPhiM.h" + +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "CaloGeoHelpers/CaloPhiRange.h" + +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauCommonExtraDetails.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TauOriginCorrectionTool.h" +#include "tauRec/TauEflowVariables.h" + + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauEflowVariables::TauEflowVariables(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_detRCoreCaloCut(0.2), +m_dphiEMCLCut(0.0375), +m_detaEMCLCut(0.0375), +m_dphiEMCLFACCut(2), +m_detaEMCLFACCut(3), +m_dphiChrgEMCut(0.0375), +m_detaChrgEMCut(0.0375), +m_CaloClusterContainerName("EMTopoCluster"), +m_recoTopoClusterETCut(200.0), +m_recoEtaCut(2.5), +m_TrackTopoClusPhi2Cut(0.0375), +m_TrackTopoClusEta1Cut(0.01), +m_MVisEflowCut(10000), +m_MTrk3PCut(10000), +m_ETeflow_ETcaloCut(10.), +m_ETeflow_ETcaloCutMin(0.1), +m_maxClusterEta(4.0), +m_useEMTopoClusters(true), +m_doCellCorrection(false), //FF: don't do cell correction by default +m_tauOriginCorrTool("") { + declareInterface<TauToolBase > (this); + + declareProperty("detRCoreCaloCut", m_detRCoreCaloCut); + declareProperty("dphiEMCLCut", m_dphiEMCLCut); + declareProperty("detaEMCLCut", m_detaEMCLCut); + declareProperty("dphiEMCLFACCut", m_dphiEMCLFACCut); + declareProperty("detaEMCLFACCut", m_detaEMCLFACCut); + declareProperty("dphiChrgEMCut", m_dphiChrgEMCut); + declareProperty("detaChrgEMCut", m_detaChrgEMCut); + declareProperty("CaloClusterContainerName", m_CaloClusterContainerName); + declareProperty("RecoTopoClusterETCut", m_recoTopoClusterETCut); + declareProperty("RecoEtaCut", m_recoEtaCut); + declareProperty("TrackTopoClusPhi2Cut", m_TrackTopoClusPhi2Cut); + declareProperty("TrackTopoClusEta1Cut", m_TrackTopoClusEta1Cut); + declareProperty("MVisEflowCut", m_MVisEflowCut); + declareProperty("MTrk3PCut", m_MTrk3PCut); + declareProperty("ETeflow_ETcaloCut", m_ETeflow_ETcaloCut); + declareProperty("ETeflow_ETcaloCutMin", m_ETeflow_ETcaloCutMin); + declareProperty("MaxClusterEta", m_maxClusterEta); + declareProperty("useEMTopoClusters", m_useEMTopoClusters); + declareProperty("CellCorrection", m_doCellCorrection); + declareProperty("OriginCorrectionTool", m_tauOriginCorrTool); +} + + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauEflowVariables::~TauEflowVariables() { +} + +StatusCode TauEflowVariables::eventFinalize(TauCandidateData *) { + + std::vector<int>().swap(m_isTopoClusQualif); + std::vector<int>().swap(m_closestTopoClusCell); + std::vector<double>().swap(m_TopoClustPhi); + std::vector<double>().swap(m_closestTopoClusCellPhi); + std::vector<double>().swap(m_closestTopoClusCellEta); + std::vector<double>().swap(m_TopoClusPhi); + std::vector<double>().swap(m_TopoClusEta); + + return StatusCode::SUCCESS; +} + + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- + +StatusCode TauEflowVariables::initialize() { + + StatusCode sc; + + ATH_MSG_VERBOSE(name() << " RconeCoreCut = " << m_detRCoreCaloCut); + ATH_MSG_VERBOSE(name() << " ETStripMinCut = " << m_ETStripMinCut); + ATH_MSG_VERBOSE(name() << " detaStripCut = " << m_detaStripCut); + + //--------------------------------------------------------------------- + // Retrieve pointer to ToolSvc + //--------------------------------------------------------------------- + IToolSvc *pToolSvc; + sc = service("ToolSvc", pToolSvc); + if (sc.isFailure()) { + ATH_MSG_FATAL("Unable to retrieve pointer to ToolSvc"); + return sc; + } + if (m_tauOriginCorrTool.retrieve().isFailure()) { + ATH_MSG_ERROR("Cannot find tool named <" << m_tauOriginCorrTool << ">"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +StatusCode TauEflowVariables::eventInitialize(TauCandidateData * /*data*/) +{ + if (m_doCellCorrection) { + // Cell Origin Correction Tool initializeEvent is not called automatically + // -> call from here + return m_tauOriginCorrTool->eventInitialize(); + } + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- + +StatusCode TauEflowVariables::execute(TauCandidateData *data) { + + Analysis::TauJet *pTau = data->tau; + Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + Analysis::TauCommonExtraDetails *pExtraDetails = dynamic_cast<Analysis::TauCommonExtraDetails *> (data->extraDetails); + + // + if (pTau->numTrack()==0) { + ATH_MSG_VERBOSE("tau has no tracks -> skip Eflow"); + return StatusCode::SUCCESS; + } + + if ( !pDetails || !pExtraDetails) { + ATH_MSG_ERROR("TauCommon(Extra)Details object not valid"); + return StatusCode::FAILURE; + } + + StatusCode sc; + + const CaloCellContainer *pCellContainer = 0; + + // for tau trigger + sc = data->getObject("CellContainer", pCellContainer); + if (sc.isFailure() || !pCellContainer) { + // retrieve at the normal way + //TODO: AllCalo hardcoded!! + sc = evtStore()->retrieve(pCellContainer, "AllCalo"); + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to find cell container"); + return StatusCode::FAILURE; + } + } + + const int nTr = 10; + double sumETCellsEM01Trk[nTr]; + double sumETCellsChrgEMTrk[nTr]; + double resChrgEMTrk[nTr]; + + for (int i = 0; i < nTr; ++i) { + sumETCellsEM01Trk[i] = 0.; + sumETCellsChrgEMTrk[i] = 0.; + resChrgEMTrk[i] = 0.; + } + + double sumETcalo = 0.0; + double sumETcaloHAD = 0.0; + double sumETcaloEM = 0.0; + double sumETCellsEMCL = 0.0; + double sumETCellsNeuEM = 0.0; + double sumETCellsChrgEM = 0.0; + double sumETCellsChrgHAD = 0.0; + double sumETeflow = 0.0; + double resChrgEM = 0.0; + double resNeuEM = 0.0; + double resChrgEMTrkTot = 0.0; + double pttot = 0.0; + + m_nTopoclust = 0; + + //fill information about EM Clusters + if (m_useEMTopoClusters) { + sc = fillTopoClusterInfo(data); + if (sc.isFailure()) return sc; + } + + //use tau vertex to correct cell position + if (m_doCellCorrection) { + m_tauOriginCorrTool->setOriginSource(pTau->origin()); + } + + //----------------------------------------------------------------- + // Loop on cells stored in object placed there by TauEflowTrackMatchCells + //----------------------------------------------------------------- + xAOD::CaloCluster* EMCLCluster = CaloClusterStoreHelper::makeCluster(pCellContainer); + xAOD::CaloCluster* NeuEMCluster = CaloClusterStoreHelper::makeCluster(pCellContainer); + + const CaloCluster *pCluster = pTau->cellCluster(); + CaloCluster::cell_iterator cellIter = pCluster->cell_begin(); + CaloCluster::cell_iterator cellIterE = pCluster->cell_end(); + + const CaloCell *pCell; + + for (; cellIter != cellIterE; ++cellIter) { + pCell = *cellIter; + + // correct cell for tau vertex + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + + double cellEta = pCell->eta(); + double cellPhi = pCell->phi(); + double cellEt = pCell->et(); + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + + int sampling = pCell->caloDDE()->getSampling(); + if (sampling > 3 && sampling < 8) sampling = sampling - 4; + + double detPhi, detEta, detPhiTrk[nTr] = {0.}, detEtaTrk[nTr] = {0.}; + + int i = 2; + if (sampling < 4) i = sampling; + + if (pExtraDetails->closestPhiTrkVertCell(0, i)) + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->closestPhiTrkVertCell(0, i)->phi()); + else + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, pTau->track(0)->phi()); + + if (pExtraDetails->closestEtaTrkVertCell(0, i)) + detEta = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->closestEtaTrkVertCell(0, i)->eta()); + else + detEta = Tau1P3PKineUtils::deltaEta(cellEta, pTau->track(0)->eta()); + + double detCell = Tau1P3PKineUtils::deltaR(detPhi, detEta); + + if (detCell > m_detRCoreCaloCut) continue; + + //for each track connected to object + for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + detPhiTrk[itr] = 0.; + detEtaTrk[itr] = 0.; + + if (pExtraDetails->closestPhiTrkCell(itr, i)) + detPhiTrk[itr] = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->closestPhiTrkCell(itr, i)->phi()); + else + detPhiTrk[itr] = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->phiTrkCaloSamp()[0][i]); + + if (pExtraDetails->closestEtaTrkCell(itr, i)) + detEtaTrk[itr] = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->closestEtaTrkCell(itr, i)->eta()); + else + detEtaTrk[itr] = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->etaTrkCaloSamp()[0][i]); + } + + sumETcalo += cellEt; + + if (sampling < 4) sumETcaloEM += cellEt; + else sumETcaloHAD += cellEt; + + int isCellBooked = 0; + + //----------------------------------------------------------------- + // sumETCellsEMCL - first iteration for + //----------------------------------------------------------------- + if (sampling <= 2) { + int kPi0 = -1; + for (int ic = 0; ic < m_nTopoclust; ++ic) { + if (m_isTopoClusQualif[ic] != 1) continue; + + double detPhi, detEta, Rcone; + + detPhi = Tau1P3PKineUtils::deltaPhi(pTau->phi(), m_TopoClusPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(pTau->eta(), m_TopoClusEta[ic]); + Rcone = Tau1P3PKineUtils::deltaR(detPhi, detEta); + if (Rcone > m_detRCoreCaloCut) continue; + + ++kPi0; + + if (m_closestTopoClusCell[ic] != 0) { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, m_closestTopoClusCellPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(cellEta, m_closestTopoClusCellEta[ic]); + } else { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, m_TopoClusPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(cellEta, m_TopoClusEta[ic]); + } + + if (detEta < m_detaEMCLCut && detPhi < m_dphiEMCLCut) { + if (!isCellBooked) { + sumETCellsEMCL += cellEt; + EMCLCluster->addCell(pCellContainer->findIndex(pCell->caloDDE()->calo_hash()), 1.0); + + isCellBooked = 1; + } + } + if (isCellBooked) break; + } // end track loop + } + + if (isCellBooked) continue; // go to next cell + + //----------------------------------------------------------------- + // sumETCellsChrgEM + //----------------------------------------------------------------- + //for each track connected to tau object + for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + if (sampling <= 3 && detEtaTrk[itr] < m_detaChrgEMCut && detPhiTrk[itr] < m_dphiChrgEMCut) { + if (!isCellBooked) { + sumETCellsChrgEM += cellEt; + sumETCellsChrgEMTrk[itr] += cellEt; + if (sampling <= 1) sumETCellsEM01Trk[itr] += cellEt; + isCellBooked = 1; + } + } + if (isCellBooked) break; + } // end track loop + + if (isCellBooked) continue; // go to next cell + + //----------------------------------------------------------------- + // sumETCellsEMCL - second iteration for + //----------------------------------------------------------------- + if (sampling <= 2) { + for (int ic = 0; ic < m_nTopoclust; ++ic) { + if (m_isTopoClusQualif[ic] != 1) continue; + + double detPhi, detEta, Rcone; + + detPhi = Tau1P3PKineUtils::deltaPhi(pTau->phi(), m_TopoClusPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(pTau->eta(), m_TopoClusEta[ic]); + Rcone = Tau1P3PKineUtils::deltaR(detPhi, detEta); + if (Rcone > m_detRCoreCaloCut) continue; + + if (m_closestTopoClusCell[ic] != 0) { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, m_closestTopoClusCellPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(cellEta, m_closestTopoClusCellEta[ic]); + } else { + detPhi = Tau1P3PKineUtils::deltaPhi(cellPhi, m_TopoClusPhi[ic]); + detEta = Tau1P3PKineUtils::deltaEta(cellEta, m_TopoClusEta[ic]); + } + + if (detEta < m_detaEMCLFACCut * m_detaEMCLCut && detPhi < m_dphiEMCLFACCut * m_dphiEMCLCut) { + if (!isCellBooked) { + sumETCellsEMCL += cellEt; + EMCLCluster->addCell(pCellContainer->findIndex(pCell->caloDDE()->calo_hash()), 1.0); + + isCellBooked = 1; + } + } + if (isCellBooked) break; + } // end track loop + } + if (isCellBooked) continue; // go to next cell + + //----------------------------------------------------------------- + // sumETCellsNeuEM - from still not booked cells + //----------------------------------------------------------------- + //erw: layer 3 removed from sumETCellsNeuEM + if (sampling < 3) { + sumETCellsNeuEM += cellEt; + NeuEMCluster->addCell(pCellContainer->findIndex(pCell->caloDDE()->calo_hash()), 1.0); + isCellBooked = 1; + } + if (isCellBooked) continue; // go to next cell + + //----------------------------------------------------------------- + // sumETCellsChrgHAD - from still not booked cells + //----------------------------------------------------------------- + //erw: layer 3 added to sumETCellsChrgHAD + if (sampling >= 3) { + sumETCellsChrgHAD += cellEt; + isCellBooked = 1; + } + + // at this point cell should be booked already, print warning if it is not + if (!isCellBooked) ATH_MSG_WARNING("Please check why cell is not booked"); + } // end cell loop + + //----------------------------------------------------------------- + // calculate energy flow variables + //----------------------------------------------------------------- + //for 1 prong + if (pTau->numTrack() == 1) { + double leadTrkPt = pTau->track(0)->pt(); + + if ((sumETCellsEM01Trk[0] / leadTrkPt) < 0.05) { + resChrgEM = sumETCellsChrgEM - 0.7 * leadTrkPt; + if (resChrgEM < 0.0) resChrgEM = 0.0; + sumETeflow = sumETCellsEMCL + sumETCellsNeuEM + leadTrkPt + resChrgEM; + } else if ((sumETCellsEM01Trk[0] / leadTrkPt) > 0.05 && (sumETCellsChrgHAD / leadTrkPt) > 0.4) { + resChrgEM = 2.5 * sumETCellsEM01Trk[0]; + + if (resChrgEM > sumETCellsChrgEM) resChrgEM = sumETCellsChrgEM; + sumETeflow = sumETCellsEMCL + sumETCellsNeuEM + leadTrkPt + resChrgEM; + } else { + resChrgEM = sumETCellsChrgEM - 0.65 * leadTrkPt; + if (resChrgEM < 0.0) resChrgEM = 0.0; + resNeuEM = -0.1 * leadTrkPt; + + if ((resNeuEM + sumETCellsNeuEM) < 0.0) resNeuEM = 0.0; + + sumETeflow = sumETCellsEMCL + sumETCellsNeuEM + leadTrkPt + resChrgEM + resNeuEM; + } + + pExtraDetails->setSumPtTrk(leadTrkPt); + + ATH_MSG_VERBOSE(name() << " sumETCellsEMCL " << sumETCellsEMCL); + pDetails->setSeedTrk_etEMCL(sumETCellsEMCL); + + ATH_MSG_VERBOSE(name() << " sumETCellsNeuEM " << sumETCellsNeuEM); + pDetails->setSeedTrk_etNeuEM(sumETCellsNeuEM); + + ATH_MSG_VERBOSE(name() << " sumETCellsChrgEM " << sumETCellsChrgEM); + pDetails->setSeedTrk_etChrgEM(sumETCellsChrgEM); + + ATH_MSG_VERBOSE(name() << " sumETCellsEM01Trk " << sumETCellsEM01Trk[0] << " " << pDetails->seedTrk_etChrgEM01Trk(0)); + pDetails->addSeedTrk_etChrgEM01Trk(sumETCellsEM01Trk[0]); + + ATH_MSG_VERBOSE(name() << " resChrgEM " << resChrgEM); + pDetails->addSeedTrk_etResChrgEMTrk(resChrgEM); + + ATH_MSG_VERBOSE(name() << " resNeuEM " << resNeuEM); + pDetails->setSeedTrk_etResNeuEM(resNeuEM); + + ATH_MSG_VERBOSE(name() << " sumETcaloEM " << sumETcaloEM); + pDetails->setSeedTrk_etEMAtEMScale(sumETcaloEM); + + ATH_MSG_VERBOSE(name() << " sumETcaloHAD " << sumETcaloHAD); + pDetails->setSeedTrk_etHadAtEMScale(sumETcaloHAD); + } else { + resChrgEMTrkTot = 0.; + double sumETCellsChrgEMTrkTot = 0.; + + for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + double trkPt = pTau->track(itr)->pt(); + + pttot += trkPt; + sumETCellsChrgEMTrkTot += sumETCellsChrgEMTrk[itr]; + + if ((sumETCellsChrgEMTrk[itr] - 0.7 * trkPt) > 0) + resChrgEMTrk[itr] = sumETCellsChrgEMTrk[itr] - 0.7 * trkPt; + + resChrgEMTrkTot += resChrgEMTrk[itr]; + + ATH_MSG_VERBOSE(name() << " 3p resChrgEM: track-> " << itr << " resChrgEMTrk(track) " << resChrgEMTrk[itr]); + pDetails->addSeedTrk_etResChrgEMTrk(resChrgEMTrk[itr]); + + ATH_MSG_VERBOSE("taurec 3p sumETCellsEM01Trk " << itr << " " << sumETCellsEM01Trk[itr] << " " << pDetails->seedTrk_etChrgEM01Trk(itr)); + pDetails->addSeedTrk_etChrgEM01Trk(sumETCellsEM01Trk[itr]); + } // end track loop + + resNeuEM = -0.1 * pttot; + if ((resNeuEM + sumETCellsNeuEM) < 0.0) resNeuEM = -sumETCellsNeuEM; + + sumETeflow = sumETCellsEMCL + sumETCellsNeuEM + pttot + resChrgEMTrkTot + resNeuEM; + + pExtraDetails->setSumPtTrk(pttot); + + ATH_MSG_VERBOSE(name() << " 3p sumETCellsEMCL " << sumETCellsEMCL); + pDetails->setSeedTrk_etEMCL(sumETCellsEMCL); + + ATH_MSG_VERBOSE(name() << " 3p sumETCellsNeuEM " << sumETCellsNeuEM); + pDetails->setSeedTrk_etNeuEM(sumETCellsNeuEM); + + ATH_MSG_VERBOSE(name() << " 3p sumETCellsChrgEM " << sumETCellsChrgEMTrkTot); + pDetails->setSeedTrk_etChrgEM(sumETCellsChrgEMTrkTot); + + ATH_MSG_VERBOSE(name() << " 3p resNeuEM " << resNeuEM); + pDetails->setSeedTrk_etResNeuEM(resNeuEM); + + ATH_MSG_VERBOSE(name() << " 3p sumETcaloEM " << sumETcaloEM); + pDetails->setSeedTrk_etEMAtEMScale(sumETcaloEM); + + ATH_MSG_VERBOSE(name() << " 3p sumETcaloHAD " << sumETcaloHAD); + pDetails->setSeedTrk_etHadAtEMScale(sumETcaloHAD); + } + + // calculate tau visible mass from Eflow + double MVisEflow = 0.; + if (EMCLCluster->et() != 0) { + xAOD::CaloCluster::cell_iterator cellIter = EMCLCluster->cell_begin(); + xAOD::CaloCluster::cell_iterator cellIterE = EMCLCluster->cell_end(); + const CaloCell *pCell; + double sumEMeta = 0; + double sumEMphi = 0; + double resphi = 0; + CaloPhiRange phiRange; + for (; cellIter != cellIterE; ++cellIter) { + pCell = *cellIter; + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + + sumEMeta += pCell->et() * pCell->eta(); + resphi = phiRange.diff(pCell->phi(), pTau->phi()); + sumEMphi += pCell->et() * resphi; + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + } + + double phiPi0 = phiRange.fix((sumEMphi / EMCLCluster->et()) + pTau->phi()); + double etaPi0 = sumEMeta / sumETCellsEMCL; + if (etaPi0 < -1. * m_maxClusterEta) etaPi0 = -1. * m_maxClusterEta; + else if (etaPi0 > m_maxClusterEta) etaPi0 = m_maxClusterEta; + + // correct for vertex position as given by seeding track + // as short-cut assumed that radius is 1600mm + + //TODO: + //should Perigee retrieved wrt tau origin? + //tracks are selected by quality cuts wrt tau origin so code below might be correct too. + + //for 1 prong only + if (pTau->numTrack() == 1) { + double zvert = (pTau->track(0)->measuredPerigee())->parameters()[Trk::z0]; + etaPi0 = asinh(sinh(etaPi0) - zvert / 1600.); + } + + double pxPi0 = (sumETeflow - pttot) * cos(phiPi0); + double pyPi0 = (sumETeflow - pttot) * sin(phiPi0); + double pzPi0 = (sumETeflow - pttot) * sinh(etaPi0); + double ePi0 = (sumETeflow - pttot) * cosh(etaPi0); + double pxPiCh = pttot * cos(pTau->phi()); + double pyPiCh = pttot * sin(pTau->phi()); + double pzPiCh = pttot * sinh(pTau->eta()); + double ePiCh = pttot * cosh(pTau->eta()); + + double mass = (ePi0 + ePiCh) * (ePi0 + ePiCh) - (pxPi0 + pxPiCh) * (pxPi0 + pxPiCh) + - (pyPi0 + pyPiCh) * (pyPi0 + pyPiCh) - (pzPi0 + pzPiCh) * (pzPi0 + pzPiCh); + + if (mass > 0.) MVisEflow = sqrt(mass); + } else if (NeuEMCluster->et() != 0) { + xAOD::CaloCluster::cell_iterator cellIter = NeuEMCluster->cell_begin(); + xAOD::CaloCluster::cell_iterator cellIterE = NeuEMCluster->cell_end(); + const CaloCell *pCell; + double sumEMeta = 0; + double sumEMphi = 0; + double resphi = 0; + CaloPhiRange phiRange; + for (; cellIter != cellIterE; ++cellIter) { + pCell = *cellIter; + + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + + sumEMeta += pCell->et() * pCell->eta(); + resphi = phiRange.diff(pCell->phi(), pTau->phi()); + sumEMphi += pCell->et() * resphi; + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + } + + double phi = phiRange.fix((sumEMphi / NeuEMCluster->et()) + pTau->phi()); + double eta = sumEMeta / sumETCellsNeuEM; + + if (eta < -1. * m_maxClusterEta) eta = -1. * m_maxClusterEta; + else if (eta > m_maxClusterEta) eta = m_maxClusterEta; + + // correct for vertex position as given by seeding track + // as short-cut assumed that radius is 1600mm + + //TODO: + //should Perigee retrieved wrt tau origin? + //tracks are selected by quality cuts wrt tau origin so code below might be correct too. + + //for 1 prong only + if (pTau->numTrack() == 1) { + double zvert = pTau->track(0)->measuredPerigee()->parameters()[Trk::z0]; + eta = asinh(sinh(eta) - zvert / 1600.); + } + + double px = (sumETeflow - pttot) * cos(phi); + double py = (sumETeflow - pttot) * sin(phi); + double pz = (sumETeflow - pttot) * sinh(eta); + double e = (sumETeflow - pttot) * cosh(eta); + double pxCh = pttot * cos(pTau->phi()); + double pyCh = pttot * sin(pTau->phi()); + double pzCh = pttot * sinh(pTau->eta()); + double eCh = pttot * cosh(pTau->eta()); + + double mass = (e + eCh) * (e + eCh) - (px + pxCh) * (px + pxCh) + - (py + pyCh) * (py + pyCh) - (pz + pzCh) * (pz + pzCh); + if (mass > 0.) MVisEflow = sqrt(mass); + } + + //add final 4-momentum of tau + //FF: uncommented pTau->setE(sumETeflow / pTau->sinTh()); + pDetails->setEtEflow(sumETeflow); + pDetails->setMEflow(MVisEflow); + ATH_MSG_VERBOSE(name() << " tau mass vis " << pDetails->etEflow() << " tau eflow " << pDetails->etEflow()); + + delete EMCLCluster; + delete NeuEMCluster; + + //Preselection + if ((pDetails->seedCalo_etEMAtEMScale() + pDetails->seedCalo_etHadAtEMScale()) == 0.) return StatusCode::FAILURE; + + /* + if (MVisEflow > m_MVisEflowCut || + sumETeflow / (pDetails->seedCalo_etEMAtEMScale() + pDetails->seedCalo_etHadAtEMScale()) > m_ETeflow_ETcaloCut || + sumETeflow / (pDetails->seedCalo_etEMAtEMScale() + pDetails->seedCalo_etHadAtEMScale()) < m_ETeflow_ETcaloCutMin + ) sc = StatusCode::FAILURE; + //TODO: Really FAILURE?? + */ + //adding some discrimination variables to the object + + if (pDetails->seedTrk_etEMAtEMScale() + pDetails->seedTrk_etHadAtEMScale() !=0 ) { + pDetails->setSeedTrk_isolFracWide((pDetails->seedTrk_etIsolEM() + pDetails->seedTrk_etIsolHad()) / (pDetails->seedTrk_etEMAtEMScale() + pDetails->seedTrk_etHadAtEMScale())); + } + + double totpt = 0; + for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + totpt += pTau->track(itr)->pt(); + } + + double etoverpttot = pDetails->seedTrk_etChrgHad() / totpt; + pDetails->setSeedTrk_etChrgHadOverSumTrkPt(etoverpttot); + + return StatusCode::SUCCESS; + +} + + +//------------------------------------------------------------------------- +// fill EM cluster info +// TODO: need clusters and cells here also correction for tau vertex? +// but what is aabout detector crack region cuts? +// they should use uncorrected coordinates, or? +//------------------------------------------------------------------------- + +StatusCode TauEflowVariables::fillTopoClusterInfo(TauCandidateData *data) { + + StatusCode sc; + + Analysis::TauJet *pTau = data->tau; + Analysis::TauCommonExtraDetails *pExtraDetails = dynamic_cast<Analysis::TauCommonExtraDetails *> (data->extraDetails); + + //--------------------------------------------------------------------- + // Retrieve calo cluster container from StoreGate + //--------------------------------------------------------------------- + const CaloClusterContainer *pTopoContainer; + sc = evtStore()->retrieve(pTopoContainer, m_CaloClusterContainerName); + + if (sc.isFailure()) { + ATH_MSG_WARNING("No " << m_CaloClusterContainerName << " found in TES"); + ATH_MSG_WARNING("will not use information about tau EM topo clusters"); + m_useEMTopoClusters = false; + return StatusCode::RECOVERABLE; + } + + ATH_MSG_VERBOSE(name() << " " << m_CaloClusterContainerName << " found " << pTopoContainer->size()); + + int ntopo = pTopoContainer->size(); + + m_isTopoClusQualif.resize(ntopo); + m_TopoClustPhi.resize(ntopo); + m_closestTopoClusCell.resize(ntopo); + m_closestTopoClusCellPhi.resize(ntopo); + m_closestTopoClusCellEta.resize(ntopo); + m_TopoClusPhi.resize(ntopo); + m_TopoClusEta.resize(ntopo); + + for (int i = 0; i < ntopo; ++i) { + m_isTopoClusQualif[i] = 0; + m_TopoClustPhi[i] = 0.; + m_closestTopoClusCell[i] = 0; + m_closestTopoClusCellPhi[i] = 0; + m_closestTopoClusCellEta[i] = 0; + m_TopoClusPhi[i] = 0.; + m_TopoClusEta[i] = 0.; + } + + //--------------------------------------------------------------------- + // Get pointer to fist and last cluster in the calo cluster container + //--------------------------------------------------------------------- + CaloClusterContainer::const_iterator topoIter = pTopoContainer->begin(); + CaloClusterContainer::const_iterator topoIterE = pTopoContainer->end(); + + const CaloCluster *pTopo; + int iclust = 0; + + for (; topoIter != topoIterE; ++topoIter) { + pTopo = *topoIter; + + //--------------------------------------------------------------------- + // Skip if cluster outside rapidity range or below pT threshold + //--------------------------------------------------------------------- + if (std::fabs(pTopo->eta()) > m_recoEtaCut) continue; + if (pTopo->et() < m_recoTopoClusterETCut) continue; + + //------------------------------------------------------------- + // Look for the closest cluster to tau track(s) + //------------------------------------------------------------- + double detEtaMin1 = 9999.0; + double detPhiMin2 = 9999.0; + double detPhi, detEta, detPhiCrude, detEtaCrude; + m_isTopoClusQualif[iclust] = 1; + + //loop ontracks in object + for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + // very crude treatement of crack region + int isampling = 1; + + detEtaCrude = Tau1P3PKineUtils::deltaEta(pExtraDetails->etaTrkCaloSamp()[itr][isampling], pTopo->eta()); + detEta = Tau1P3PKineUtils::deltaEta(pExtraDetails->etaTrkCaloSamp()[itr][isampling], pTopo->getVariable(CaloVariableType::ETA, CaloSampling::EMB1, true)); + + if (detEtaCrude < detEta) detEta = detEtaCrude; + if (detEta < detEtaMin1) detEtaMin1 = detEta; + + // very crude treatement of crack region + isampling = 2; + + detPhiCrude = Tau1P3PKineUtils::deltaPhi(pExtraDetails->phiTrkCaloSamp()[itr][isampling], pTopo->phi()); + detPhi = Tau1P3PKineUtils::deltaPhi(pExtraDetails->phiTrkCaloSamp()[itr][isampling], pTopo->getVariable(CaloVariableType::PHI, CaloSampling::EMB2, true)); + + if (detPhiCrude < detPhi) detPhi = detPhiCrude; + if (detPhi < detPhiMin2) detPhiMin2 = detPhi; + } + + if (detPhiMin2 < m_TrackTopoClusPhi2Cut) m_isTopoClusQualif[iclust] = 0; + if (detEtaMin1 < m_TrackTopoClusEta1Cut) m_isTopoClusQualif[iclust] = 0; + + m_TopoClusPhi[iclust] = pTopo->phi(); + m_TopoClusEta[iclust] = pTopo->eta(); + + double detRCellMin = 9999.0; + const CaloCell *pTmpCell = 0; + const CaloCell *pCell; + + CaloCluster::cell_iterator cellItr = pTopo->cell_begin(); + CaloCluster::cell_iterator cellItrE = pTopo->cell_end(); + for (; cellItr != cellItrE; ++cellItr) { + pCell = *cellItr; + if (pCell->caloDDE()->getSampling() == 2) { + double detPhi = Tau1P3PKineUtils::deltaPhi(pCell->phi(), pTopo->phi()); + double detEta = Tau1P3PKineUtils::deltaEta(pCell->eta(), pTopo->eta()); + double detRCell = Tau1P3PKineUtils::deltaR(detPhi, detEta); + + if (detRCell < detRCellMin) { + detRCellMin = detRCell; + pTmpCell = pCell; + } + } + } + if (pTmpCell) { + m_closestTopoClusCell[iclust] = 1; + m_closestTopoClusCellPhi[iclust] = pTmpCell->phi(); + m_closestTopoClusCellEta[iclust] = pTmpCell->eta(); + } + + ++iclust; + } + + m_nTopoclust = iclust; + + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/tauRec/depreciated/TauEflowVariables.h b/Reconstruction/tauRec/depreciated/TauEflowVariables.h new file mode 100644 index 00000000000..266a3bb2c78 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauEflowVariables.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUEFLOWVARIABLES_H +#define TAUREC_TAUEFLOWVARIABLES_H + +#include <vector> +#include "EventKernel/INavigable4Momentum.h" +#include "CaloUtils/CaloClusterStoreHelper.h" + +#include "tauRec/TauToolBase.h" + +class TauOriginCorrectionTool; + +/** + * @brief Class for building energy flow quantities. + * + * This tool was formerly named as tau1p3pAddEflowInfo. + * + * @author Tadeusz Szymocha, Anna Kaczmarska + */ + +class TauEflowVariables : public TauToolBase { +public: + TauEflowVariables(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauEflowVariables(); + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + + StatusCode fillTopoClusterInfo(TauCandidateData *data); + + +private: + + std::string m_trackContainerName; + double m_detRCoreCaloCut; + double m_ETCellMinCut; + double m_ETStripMinCut; + double m_detaStripCut; + double m_dphiEMCLCut; + double m_detaEMCLCut; + double m_dphiEMCLFACCut; + double m_detaEMCLFACCut; + double m_dphiChrgEMCut; + double m_detaChrgEMCut; + std::string m_CaloClusterContainerName; + double m_recoTopoClusterETCut; + double m_recoEtaCut; + double m_TrackTopoClusPhi2Cut; + double m_TrackTopoClusEta1Cut; + double m_TopoClusEtha1Cut; + double m_MVisEflowCut; + double m_MTrk3PCut; + double m_ETeflow_ETcaloCut; + double m_ETeflow_ETcaloCutMin; + double m_maxClusterEta; + bool m_useEMTopoClusters; + + int m_nTopoclust; + + std::vector<int> m_isTopoClusQualif; + std::vector<double> m_TopoClustPhi; + std::vector<int> m_closestTopoClusCell; + std::vector<double> m_closestTopoClusCellPhi; + std::vector<double> m_closestTopoClusCellEta; + std::vector<double> m_TopoClusPhi; + std::vector<double> m_TopoClusEta; + + bool m_doCellCorrection; //!< enable cell origin correction + ToolHandle<TauOriginCorrectionTool> m_tauOriginCorrTool; +}; + + +#endif diff --git a/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.cxx b/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.cxx new file mode 100644 index 00000000000..83a9081867e --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.cxx @@ -0,0 +1,215 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/********************************************************* +NAME: TauOriginCorrectionTool.cxx +PACKAGE: Reconstruction/tauRec +AUTHORS: Felix Friedrich <felix.friedrich@cern.ch> +DATE: May 12, 2011 + +PURPOSE: correct cells and cluster for vertex shift +inspired by Reconstruction/Jet/JetCalibTools/src/JetCaloOrigin.cxx +and +Reconstruction/Jet/JetMomentTools/src/JetOriginCorrectionTool.cxx + + *************************************************************/ + +#include "CaloEvent/CaloCell.h" +#include "CaloEvent/CaloCluster.h" +// This class was removed. If we want to revive this tool we need to switch to the xAOD::CaloVertexedCluster interface +// #include "CaloUtils/CaloClusterVertexCorrection.h" +#include "JetEvent/Jet.h" +#include "CLHEP/Geometry/Vector3D.h" +// #include "VxVertex/VxContainer.h" + +#include "xAODTracking/VertexContainer.h" + +#include "tauRec/TauOriginCorrectionTool.h" + + +TauOriginCorrectionTool::TauOriginCorrectionTool( const std::string& type, const std::string& name, const IInterface* parent ) : + AthAlgTool(type, name, parent), + m_originPosition(3,0), + m_useJVA(false), + m_usePrimaryVertex(false), + m_useBeamSpot(false), + m_evnInitCalled(false), + m_primVtxName("PrimaryVertices"), + // m_primVtxName("VxPrimaryCandidate"), + m_beamConditionsService("BeamCondSvc", name) +{ + declareInterface<TauOriginCorrectionTool>( this ); + + declareProperty("OriginPosition", m_originPosition); + declareProperty("UseJVA", m_useJVA); + declareProperty("UsePrimaryVertex", m_usePrimaryVertex); + declareProperty("UseBeamSpot", m_useBeamSpot); + declareProperty("VertexContainerKey",m_primVtxName = "VxPrimaryCandidate"); + declareProperty("BeamConditionsSvc", m_beamConditionsService); + declareProperty("OriginMomentName", m_OriginMomName = "OriginIndex"); + +} + +//************************************************************************************************* +StatusCode TauOriginCorrectionTool::initialize() +{ + if(m_useBeamSpot) { + if(m_beamConditionsService.retrieve().isFailure() ) { + ATH_MSG_ERROR( "Cannot find service named <" << m_beamConditionsService << ">"); + return StatusCode::FAILURE; + } + } + + return StatusCode::SUCCESS; +} + +//************************************************************************************************* +StatusCode TauOriginCorrectionTool::eventInitialize() +{ + // skip if already called + if (m_evnInitCalled) return StatusCode::SUCCESS; + + // get VxContainer - must be retrieved in eventInitialize + if(m_usePrimaryVertex || m_useJVA) { + StatusCode sc = evtStore()->retrieve(m_vxContainer, m_primVtxName); + if (sc.isFailure()) { + ATH_MSG_DEBUG("Could not retrieve VxContainer <" << m_primVtxName << "> during initialize() " ); + return StatusCode::SUCCESS; + } + m_evnInitCalled = true; + } + return StatusCode::SUCCESS; +} + +//************************************************************************************************* +// set the origin source +// jet is only used if useJVA is enabled +void TauOriginCorrectionTool::setOriginSource(const Jet* jet) { + m_jetOrigin = chooseOrigin(jet); +} + +//************************************************************************************************* +// set the origin source by hand +void TauOriginCorrectionTool::setOriginSource(const Trk::RecVertex* vertex) { + // set origin by hand + if (vertex) { + m_jetOrigin = Amg::Vector3D(vertex->position().x(), vertex->position().y(), vertex->position().z()); + } + else { + m_jetOrigin = Amg::Vector3D(0,0,0); + } +} + +//************************************************************************************************* +// set the origin source by hand +void TauOriginCorrectionTool::setOriginSource(const xAOD::Vertex* vertex) { + // set origin by hand + if (vertex) { + m_jetOrigin = Amg::Vector3D(vertex->position().x(), vertex->position().y(), vertex->position().z()); + } + else { + m_jetOrigin = Amg::Vector3D(0,0,0); + } +} + +//************************************************************************************************* +// set a new cell vertex +void TauOriginCorrectionTool::correctCell(const CaloCell* cell) { + cell->zVertex(&m_jetOrigin); +} + +//************************************************************************************************* +// reset cell +void TauOriginCorrectionTool::resetCell(const CaloCell* cell) { + cell->zVertex(0,true); +} + +//************************************************************************************************* +// set a new cluster vertex +void TauOriginCorrectionTool::correctCluster(const CaloCluster* cluster) { + // CaloClusterVertexCorrection::setVertex(cluster, &m_jetOrigin); +} + +//************************************************************************************************* +// reset cluster vertex +void TauOriginCorrectionTool::resetCluster(const CaloCluster* cluster) { + // CaloClusterVertexCorrection::resetVertex(cluster); +} + +// try to get the origin of the jet +// not not really needed at the moment, because using JVA is switched off by default +Amg::Vector3D TauOriginCorrectionTool::chooseOrigin(const Jet* jet) +{ + // Cascade in order of priority + // If one fails, go to the next approach + + // JetVertexAssociation + if(m_useJVA) { + ATH_MSG_VERBOSE("TauOriginCorrectionTool::chooseOrigin In useJVA"); + unsigned int originIndex(jet->getMoment(m_OriginMomName)); // No way to know if this has been filled at the moment + ATH_MSG_VERBOSE("TauOriginCorrectionTool::chooseOrigin Just got originIndex moment "<< originIndex); + if (originIndex > m_vxContainer->size()) { + ATH_MSG_WARNING("Index of jet origin (" << originIndex + << ") is larger than the size of the vertex container (" + << m_vxContainer->size() << "), we return (0,0,0)"); + return Amg::Vector3D (0, 0, 0); + } + ATH_MSG_VERBOSE("TauOriginCorrectionTool::chooseOrigin Just before getting position of vertex"); + Amg::Vector3D primaryVertex = (*(m_vxContainer->at(originIndex))).position(); + ATH_MSG_VERBOSE("Found a primary vertex at (" + << primaryVertex.x() << "," + << primaryVertex.y() << "," + << primaryVertex.z() << ")" + ); + return Amg::Vector3D (primaryVertex.x(), primaryVertex.y(), primaryVertex.z()); + } + + // PrimaryVertex + if(m_usePrimaryVertex) { + if(m_vxContainer) { + // At least 1 vertex + if(m_vxContainer->size()>0) { + // More than 1 track pointing to the vertex + if((*m_vxContainer->begin())->nTrackParticles() > 1) { + Amg::Vector3D primaryVertex = (*(m_vxContainer->begin()))->position(); + + ATH_MSG_VERBOSE("Found a primary vertex at (" + << primaryVertex.x() << "," + << primaryVertex.y() << "," + << primaryVertex.z() << ")" + ); + + return Amg::Vector3D (primaryVertex.x(), primaryVertex.y(), primaryVertex.z()); + } + ATH_MSG_DEBUG("Couldn't find a primary vertex! Try next approach" ); + } + } + } + + // BeamSpot + if(m_useBeamSpot) { + if(m_beamConditionsService) { + if(!m_beamConditionsService.empty()) { + Amg::Vector3D beamSpot = m_beamConditionsService->beamVtx().position(); + + ATH_MSG_VERBOSE("Found a beam spot at (" + << beamSpot.x() << "," + << beamSpot.y() << "," + << beamSpot.z() << ")" + ); + + return Amg::Vector3D (beamSpot.x(), beamSpot.y(), beamSpot.z()); + } + } + ATH_MSG_DEBUG("Couldn't find a beam spot! Try next approach" ); + } + + // Set Vertex Position by Hand + if(m_originPosition.size() == 3) + return Amg::Vector3D (m_originPosition[0], m_originPosition[1], m_originPosition[2]); + + // Last ditch default: (0,0,0) + return Amg::Vector3D (0,0,0); + +} diff --git a/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.h b/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.h new file mode 100644 index 00000000000..cf9ce2a30d2 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauOriginCorrectionTool.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUORIGINCORRECTIONTOOL_H +#define TAUREC_TAUORIGINCORRECTIONTOOL_H + +#include <vector> +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "InDetBeamSpotService/IBeamCondSvc.h" + +#include "xAODTracking/Vertex.h" +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/TrackParticle.h" + +class Jet; +class CaloCell; +class CaloCluster; +//class xAOD::VertexContainer; + +//namespace HepGeom { +// template<class T> class Vector3D; +//} +namespace Trk { + class RecVertex; +} + +static const InterfaceID IID_ITauOriginCorrectionTool("TauOriginCorrectionTool",1,0); + +/** + * @brief Correct cells and cluster for vertex shift. + * + * Inspired by Reconstruction/Jet/JetCalibTools/JetCalibTools/JetCaloOrigin.h + * + * @author Felix Friedrich + */ + +class TauOriginCorrectionTool : public AthAlgTool +{ + public: + TauOriginCorrectionTool( const std::string& type, const std::string& name, const IInterface* parent ) ; + virtual ~TauOriginCorrectionTool(){}; + + static const InterfaceID& interfaceID() { return IID_ITauOriginCorrectionTool; } + + virtual StatusCode initialize() ; + virtual StatusCode eventInitialize() ; + virtual StatusCode finalize() { return StatusCode::SUCCESS; } ; + + virtual void setOriginSource(const Jet* jet); + virtual void setOriginSource(const Trk::RecVertex* vertex); + virtual void setOriginSource(const xAOD::Vertex* vertex); + + virtual void correctCell(const CaloCell* cell); + virtual void resetCell(const CaloCell* cell); + + virtual void correctCluster(const CaloCluster* cluster); + virtual void resetCluster(const CaloCluster* cluster); + + // Return the vertex chosen + Amg::Vector3D chooseOrigin(const Jet* jet_in); + + + private: + + // 3-vector pointing to a default origin + std::vector<double> m_originPosition; + + // Choice of origin: + // Try the JetVertexAssociation + bool m_useJVA; + // Try retrieving primary vertex + bool m_usePrimaryVertex; + // Try retrieving beamspot + bool m_useBeamSpot; + + bool m_evnInitCalled; + + // origin + Amg::Vector3D m_jetOrigin; + + // Vertex Container Name + std::string m_primVtxName; + + //JVA Moment Name + std::string m_OriginMomName; + + // Pointer to the vertex container + const xAOD::VertexContainer* m_vxContainer; + + // Pointer to the beamspot handle + ServiceHandle<IBeamCondSvc> m_beamConditionsService; + +}; +#endif diff --git a/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.cxx b/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.cxx new file mode 100644 index 00000000000..bb898a340c5 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.cxx @@ -0,0 +1,454 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0CrakowClusterCreator.cxx +// package: Reconstruction/tauRec +// authors: Elzbieta Richter-Was +// date: 19/06/2007 +// +// This tool classifies Pi0 clusters, adapted from tau1P3PCreatePi0Clus.cxx +//----------------------------------------------------------------------------- + +#include <algorithm> +#include <math.h> +#include <sstream> + +#include "GaudiKernel/ListItem.h" +#include "GaudiKernel/IToolSvc.h" +#include "GaudiKernel/Property.h" + +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "CaloGeoHelpers/CaloPhiRange.h" +#include "AnalysisUtils/AnalysisMisc.h" +#include "CaloUtils/CaloClusterStoreHelper.h" + +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauCommonExtraDetails.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TauPi0CrakowClusterCreator.h" + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0CrakowClusterCreator::TauPi0CrakowClusterCreator(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_detRCoreCaloCut(0.2), +m_recoTopoClusterETCut(1000.0), +m_recoEtaCut(2.5), +m_detTrkClusMin(0.0375), +m_fracEM01verEM(0.1), +m_CaloClusterContainerName("EMTopoCluster"), +m_pi0ContainerName("Tau1P3PPi0ClusterContainer") { + declareInterface<TauToolBase > (this); + + declareProperty("detRCoreCaloCut", m_detRCoreCaloCut); + declareProperty("RecoTopoClusterETCut", m_recoTopoClusterETCut); + declareProperty("RecoEtaCut", m_recoEtaCut); + declareProperty("detTrkClusMin", m_detTrkClusMin); + declareProperty("fracEM01verEM", m_fracEM01verEM); + declareProperty("CaloClusterContainerName", m_CaloClusterContainerName); + declareProperty("Pi0ClusterContainer", m_pi0ContainerName); + +} + + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0CrakowClusterCreator::~TauPi0CrakowClusterCreator() { +} + + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- + +StatusCode TauPi0CrakowClusterCreator::initialize() { + + ATH_MSG_VERBOSE(name() << " detRCoreCaloCut = " << m_detRCoreCaloCut); + ATH_MSG_VERBOSE(name() << " RecoTopoClusterETCut = " << m_recoTopoClusterETCut); + ATH_MSG_VERBOSE(name() << " detTrkClusMin = " << m_detTrkClusMin); + ATH_MSG_VERBOSE(name() << " fracEM01verEM = " << m_fracEM01verEM); + + + StatusCode sc; + + //--------------------------------------------------------------------- + // Retrieve pointer to ToolSvc + //--------------------------------------------------------------------- + IToolSvc *pToolSvc; + sc = service("ToolSvc", pToolSvc); + if (sc.isFailure()) { + ATH_MSG_FATAL("Unable to retrieve pointer to ToolSvc"); + return sc; + } + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Delete Pi0 clusters +//----------------------------------------------------------------------------- + +static void do_delete(CaloCluster *cluster) { + delete cluster; +} + + +//------------------------------------------------------------------------- +// Event Initializer +//------------------------------------------------------------------------- + +StatusCode TauPi0CrakowClusterCreator::eventInitialize(TauCandidateData *) { + m_pi0Map.clear(); + return StatusCode::SUCCESS; +} + + + +//------------------------------------------------------------------------- +// Event Finalizer +//------------------------------------------------------------------------- + +StatusCode TauPi0CrakowClusterCreator::eventFinalize(TauCandidateData *) { + + MsgStream rLog(msgSvc(), name()); + + StatusCode sc; + + //--------------------------------------------------------------------- + // Create container for Pi0 + //--------------------------------------------------------------------- + CaloClusterContainer *pPi0Container = new CaloClusterContainer(); + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::recordClusters(&*evtStore(), + // pPi0Container, + // m_pi0ContainerName, + // rLog); + + + //--------------------------------------------------------------------- + // Put all clusters into the container + //--------------------------------------------------------------------- + std::map<Analysis::TauCommonDetails *, std::vector<CaloCluster *> > ::iterator it; + std::vector<CaloCluster *> ::iterator clustIt; + + for (it = m_pi0Map.begin(); it != m_pi0Map.end(); ++it) { + for (clustIt = (*it).second.begin(); clustIt != (*it).second.end(); ++clustIt) { + pPi0Container->push_back(*clustIt); + } + AnalysisUtils::Sort::pT(pPi0Container); + } + + //---------------------------------------------------------------------- + // Register cluster container in StoreGate + //---------------------------------------------------------------------- + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::finalizeClusters(&*evtStore(), + // pPi0Container, + // m_pi0ContainerName, + // rLog); + + + //--------------------------------------------------------------------- + // Set element links + //--------------------------------------------------------------------- + for (it = m_pi0Map.begin(); it != m_pi0Map.end(); ++it) { + (*it).first->pi0LinkVec().clear(); + for (clustIt = (*it).second.begin(); clustIt != (*it).second.end(); ++clustIt) { + (*it).first->addPi0(*clustIt, pPi0Container); + } + } + + return sc; +} + + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- + +StatusCode TauPi0CrakowClusterCreator::execute(TauCandidateData *data) { + + // Analysis::TauJet *pTau = data->tau; + // Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + // Analysis::TauCommonExtraDetails *pExtraDetails = dynamic_cast<Analysis::TauCommonExtraDetails *> (data->extraDetails); + + // // + // if (pTau->numTrack()==0) { + // ATH_MSG_VERBOSE("tau has no tracks -> skip CrakowClusterCreator"); + // return StatusCode::SUCCESS; + // } + + // if ( !pDetails || !pExtraDetails) { + // ATH_MSG_ERROR("TauCommon(Extra)Details object not valid"); + // return StatusCode::FAILURE; + // } + + // StatusCode sc; + + // //FIX ME! needed only for cell coping + // const CaloCellContainer *pCellContainer; + + // //for tau trigger + // sc = data->getObject("CellContainer", pCellContainer); + + // if (sc.isFailure() || !pCellContainer) { + // //TODO: AllCalo hardcoded!! + // sc = evtStore()->retrieve(pCellContainer, "AllCalo"); + // if (sc.isFailure()) { + // ATH_MSG_ERROR("Unable to find all calo container"); + // return StatusCode::FAILURE; + // } + // } + + // //--------------------------------------------------------------------- + // // Retrieve calo cluster container from StoreGate + // //--------------------------------------------------------------------- + // const CaloClusterContainer *pTopoContainer = 0; + // sc = evtStore()->retrieve(pTopoContainer, m_CaloClusterContainerName); + + // if (sc.isFailure()) { + // ATH_MSG_FATAL("No " << m_CaloClusterContainerName << " found in TES"); + // return sc; + // } + + + // double resPhiPi0 = 0; + + // CaloPhiRange phiRange; + + // std::vector<CaloCluster *> clusterPi0; + // const CaloCluster *pTopo; + + // //FF: + // //TODO: need cluster to be correct wrt tau origin? + // //Can not oversee impact, so leave everything as it is for the moment + + // //--------------------------------------------------------------------- + // // Start classifying clusters + // //--------------------------------------------------------------------- + // CaloClusterContainer::const_iterator topoIter = pTopoContainer->begin(); + // CaloClusterContainer::const_iterator topoIterE = pTopoContainer->end(); + + // for (; topoIter != topoIterE; ++topoIter) { + + // pTopo = *topoIter; + + // //--------------------------------------------------------------------- + // // Skip if cluster outside rapidity range or below pT threshold + // //--------------------------------------------------------------------- + // if (pTopo->et() < m_recoTopoClusterETCut) continue; + + + // double zvert = pTau->track(0)->measuredPerigee()->parameters()[Trk::z0]; + // double etazv = 0; + // if (fabs(pTopo->eta()) < 1.45) { + // double aeta = fabs(pTopo->eta()); + // double r = 1691. - 39.4884 * aeta - 23.556412 * aeta*aeta; // FIXME approximate shower depth in barrel + // double z = r * sinh(pTopo->eta()); + // double x = (z - zvert) / r; + // etazv = logf(x + sqrt(1. + x * x)); + // } else { + // double z = 3920; // FIXME approximate shower depth in emec + // if (pTopo->eta() < 0) z = -3920; + // double r = z / sinh(pTopo->eta()); + // double x = (z - zvert) / r; + // etazv = logf(x + sqrt(1. + x * x)); + // } + + // //--------------------------------------------------------------------- + // // Skip if cluster outside tauCore region + // //--------------------------------------------------------------------- + // double detPhi = phiRange.diff(pTopo->phi(), pTau->phi()); + // double detEta = etazv - pTau->eta(); + + // if (sqrt(detPhi * detPhi + detEta * detEta) > m_detRCoreCaloCut) continue; + + + // //------------------------------------------------------------- + // // Check if cluster separated from track, skip otherwise + // //------------------------------------------------------------- + // int isTopoClusQualif = 1; + + // //loop on tracks in the object + // for (unsigned itr = 0; itr < pTau->numTrack(); ++itr) { + // // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + // if (itr >= 9) break; + + // int isampling = 2; + + // double detEta = fabs(pExtraDetails->etaTrkCaloSamp()[itr][isampling] - etazv); + // double detPhi = fabs(phiRange.diff(pExtraDetails->phiTrkCaloSamp()[itr][isampling], pTopo->phi())); + + // if (sqrt(detPhi * detPhi + detEta * detEta) < m_detTrkClusMin) isTopoClusQualif = 0; + // } + + + // if (isTopoClusQualif == 0) continue; + + + // //------------------------------------------------------------- + // // Check if cluster has energy deposition in EM01, skip otherwise + // //------------------------------------------------------------- + // double e_emb0 = (double) pTopo->getVariable(CaloVariableType::ENERGY, CaloSampling::PreSamplerB, 1); + // double e_emb1 = (double) pTopo->getVariable(CaloVariableType::ENERGY, CaloSampling::EMB1, 1); + // //ak_unused double e_emb2 = (float)pTopo->getVariable(CaloVariableType::ENERGY,CaloSampling::EMB2,1); + // double e_eme0 = (double) pTopo->getVariable(CaloVariableType::ENERGY, CaloSampling::PreSamplerE, 1); + // double e_eme1 = (double) pTopo->getVariable(CaloVariableType::ENERGY, CaloSampling::EME1, 1); + // //ak_unused double e_eme2 = (float)pTopo->getVariable(CaloVariableType::ENERGY,CaloSampling::EME2,1); + + + // if ((e_emb0 + e_eme0 + e_emb1 + e_eme1) < m_fracEM01verEM * pTopo->e()) continue; + + // //------------------------------------------------------------- + // // Cluster accepted, include in bary-center calculation + // //------------------------------------------------------------- + + // // calculate energy weighted (eta,phi) + // double resPhi = phiRange.diff(pTopo->phi(), pTau->phi()); + // resPhiPi0 += resPhi * pTopo->e(); + + // ATH_MSG_VERBOSE(name() << " accepted topoForTaus clusters " + // << " energy " << pTopo->et() + // << " phi " << pTopo->phi() + // << " eta " << pTopo->eta() + // ); + + // //------------------------------------------------------------- + // // Cluster accepted, store in Pi0Cluster collection + // //------------------------------------------------------------- + + // //create temp cluster for cells storing + // xAOD::CaloCluster *pPi0cluster = CaloClusterStoreHelper::makeCluster(pCellContainer); + + // //copy cells from selected cluster into created pi0 cluster + // CaloCluster::cell_iterator cellIter = pTopo->cell_begin(); + // CaloCluster::cell_iterator cellIterE = pTopo->cell_end(); + + // for (; cellIter != cellIterE; ++cellIter) { + // //XXX still need to check this implementation + // pPi0cluster->addCell(cellIter.getElement().index(), 1.0); + // } + + // clusterPi0.push_back(pPi0cluster); + // pDetails->addPi0(pPi0cluster, 0); + // } + + // m_pi0Map[pDetails] = clusterPi0; + + + // /***** FIXME... + // // loop over pi0 clusters correction + // // correct position for zvertex + // // calculate barycentre + // // store as sumEM + // ***********/ + + // if (clusterPi0.empty()) { + // // no cluster found --> leave + // return StatusCode::SUCCESS; + // } + + // //--------------------------------------------------------------------- + // // Calculate and register energy weighted bary-center 4-momenta + // // corrected for the z-vertex position + // //--------------------------------------------------------------------- + + // float sumEMeta = 0; + // float sumEMphi = 0; + // float sumEMet = 0; + // float sumEMe = 0; + + // for (unsigned ipi0 = 0; ipi0 < clusterPi0.size(); ++ipi0) { + // const CaloCluster *pPi0Clus = clusterPi0[ipi0]; + // sumEMeta += pPi0Clus->et() * pPi0Clus->eta(); + // float resphi = phiRange.diff(pPi0Clus->phi(), pTau->phi()); + // sumEMphi += pPi0Clus->et() * resphi; + // sumEMet += pPi0Clus->et(); + // sumEMe += pPi0Clus->e(); + // } + + // float phiPi0 = phiRange.fix(sumEMphi / sumEMet + pTau->phi()); + // float etaPi0 = sumEMeta / sumEMet; + // float ePi0 = sumEMe; + + // //------------------------------------------------------------- + // // Correct for vertex position of the leading track + // //------------------------------------------------------------- + // double zvert = pTau->track(0)->measuredPerigee()->parameters()[Trk::z0]; + // float etaPi0zv; + // if (fabs(etaPi0) < 1.45) { + // double aeta = fabs(etaPi0); + // double r = 1691. - 39.4884 * aeta - 23.556412 * aeta*aeta; // FIXME approximate shower depth in barrel + // double z = r * sinh(etaPi0); + // double x = (z - zvert) / r; + // etaPi0zv = logf(x + sqrt(1. + x * x)); + // } else { + // double z = 3920; // FIXME approximate shower depth in emec + // if (etaPi0 < 0) z = -3920; + // double r = z / sinh(etaPi0); + // double x = (z - zvert) / r; + // etaPi0zv = logf(x + sqrt(1. + x * x)); + // } + + // ATH_MSG_VERBOSE(name() << " final combined Pi0 4-momenta " + // << " energy " << ePi0 + // << " phi " << phiPi0 + // << " etaZV " << etaPi0zv + // ); + + // double pxPi0 = ePi0 / cosh(etaPi0zv) * cos(phiPi0); + // double pyPi0 = ePi0 / cosh(etaPi0zv) * sin(phiPi0); + // double pzPi0 = ePi0 / cosh(etaPi0zv) * sinh(etaPi0zv); + + // // FIXME calculated with mass less hypothesis + // CLHEP::HepLorentzVector sumem(pxPi0, pyPi0, pzPi0, ePi0); + // pDetails->setSumPi0Vec(sumem); + + // ATH_MSG_VERBOSE(name() << " final Pi0 4-momenta (retrieve) " + // << " energy " << pDetails->sumPi0Vec().e() + // << " phi " << pDetails->sumPi0Vec().phi() + // << " etaZV " << pDetails->sumPi0Vec().eta() + // ); + + + return StatusCode::SUCCESS; +} + + + +//----------------------------------------------------------------------------- +// Cleanup, in case this candidate was rejected later +//----------------------------------------------------------------------------- + +void TauPi0CrakowClusterCreator::cleanup(TauCandidateData *data) { + + Analysis::TauCommonDetails *pDetails = dynamic_cast<Analysis::TauCommonDetails *> (data->details); + std::map<Analysis::TauCommonDetails *, std::vector<CaloCluster *> > ::iterator it; + it = m_pi0Map.find(pDetails); + + if (it != m_pi0Map.end()) { + std::for_each((*it).second.begin(), (*it).second.end(), do_delete); + m_pi0Map.erase(it); + } +} + + + + diff --git a/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.h b/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.h new file mode 100644 index 00000000000..9d47fd05676 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0CrakowClusterCreator.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TauPi0CrakowClusterCreator_H +#define TAUREC_TauPi0CrakowClusterCreator_H + +#include "tauRec/TauToolBase.h" +#include <map> + +namespace Analysis { + class TauCommonDetails; +} +class CaloCluster; + +/** + * @brief Class for creating Pi0 clusters from EMtopoForTaus collection. + * + * @author Elzbieta Richter-Was + * + */ + +class TauPi0CrakowClusterCreator : public TauToolBase { +public: + + TauPi0CrakowClusterCreator(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauPi0CrakowClusterCreator(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + + virtual void cleanup(TauCandidateData *data); + StatusCode fillTopoClusterInfo(TauCandidateData *data); + + +private: + + std::string m_trackContainerName; + double m_detRCoreCaloCut; + double m_recoTopoClusterETCut; + double m_recoEtaCut; + double m_detTrkClusMin; + double m_fracEM01verEM; + std::string m_CaloClusterContainerName; + + int m_nTopoClust; + + std::vector<int> m_isTopoClusQualif; + std::vector<double> m_TopoClustPhi; + std::vector<double> m_TopoClusEta; + + std::string m_pi0ContainerName; + + // CaloCluster with all cells after hypothesis of Pi0 + std::map<Analysis::TauCommonDetails *, std::vector<CaloCluster *> > m_pi0Map; +}; + +#endif /* TauPi0CrakowClusterCreator_H */ + diff --git a/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.cxx b/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.cxx new file mode 100644 index 00000000000..6508437694e --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.cxx @@ -0,0 +1,184 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0CreatorChooser.cxx +// package: Reconstruction/tauEvent +// authors: Veit Scharf +// date: 2008-10-23 +//----------------------------------------------------------------------------- + +#include <algorithm> +#include "GaudiKernel/MsgStream.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloUtils/CaloClusterStoreHelper.h" +#include "tauEvent/TauCommonDetails.h" +#include "tauRec/TauPi0CreatorChooser.h" + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0CreatorChooser::TauPi0CreatorChooser(const std::string& type, + const std::string& name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_tau1p3pCreatePi0ClusTool("tau1p3pCreatePi0Clus"), +m_tauCommonCreatePi0ClusTool("TauCommonCreatePi0Clus"), +m_pi0ClusterContainerName("Tau1P3PPi0ClusterContainer") { + declareInterface<TauToolBase > (this); + + declareProperty("Tau1p3pCreatePi0ClusTool", m_tau1p3pCreatePi0ClusTool); + declareProperty("TauCommonCreatePi0ClusTool", m_tauCommonCreatePi0ClusTool); + declareProperty("Pi0ClusterContainer", m_pi0ClusterContainerName); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0CreatorChooser::~TauPi0CreatorChooser() { +} + +StatusCode TauPi0CreatorChooser::initialize() { + + StatusCode sc; + + sc = m_tau1p3pCreatePi0ClusTool.retrieve(); + if (sc.isFailure()) { + ATH_MSG_ERROR("Could not retrieve tau1p3pCreatePi0ClusTool."); + return sc; + } + + sc = m_tauCommonCreatePi0ClusTool.retrieve(); + if (sc.isFailure()) { + ATH_MSG_ERROR("Could not retrieve tauCommonCreatePi0ClusTool."); + return sc; + } + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0CreatorChooser::eventInitialize(TauCandidateData* data) { + + StatusCode sc; + sc = m_tau1p3pCreatePi0ClusTool->eventInitialize(data); + if (sc.isFailure()) { + return sc; + } + + sc = m_tauCommonCreatePi0ClusTool->eventInitialize(data); + if (sc.isFailure()) { + return sc; + } + + m_tauDetails.clear(); + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0CreatorChooser::execute(TauCandidateData* data) { + + StatusCode sc; + + m_tauDetails.push_back(dynamic_cast<Analysis::TauCommonDetails*> (data->details)); + if (data->tau->numTrack() != 1) + sc = m_tau1p3pCreatePi0ClusTool->execute(data); + else + sc = m_tauCommonCreatePi0ClusTool->execute(data); + + return sc; +} + +void TauPi0CreatorChooser::cleanup(TauCandidateData* data) { + if (data->tau->numTrack() != 1) + m_tau1p3pCreatePi0ClusTool->cleanup(data); + else + m_tauCommonCreatePi0ClusTool->cleanup(data); + + std::vector<Analysis::TauCommonDetails*>::iterator i = std::find(m_tauDetails.begin(), + m_tauDetails.end(), + dynamic_cast<Analysis::TauCommonDetails*> (data->details)); + + if (i != m_tauDetails.end()) + m_tauDetails.erase(i); + + return; +} + +StatusCode TauPi0CreatorChooser::eventFinalize(TauCandidateData* /* data */) { + + // Do not call eventFinalize methods of the child tools. They would record + // two CaloClusterContainers with the same name. Instead do the work here. + ATH_MSG_INFO("TauPi0CreatorChooser::eventFinalize"); + + MsgStream rLog(msgSvc(), name()); + + StatusCode sc; + + + + CaloClusterContainer *pPi0ClusterContainer = new CaloClusterContainer(); + + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::recordClusters(&*evtStore(), + // pPi0ClusterContainer, + // m_pi0ClusterContainerName, + // rLog); + + std::vector<Analysis::TauCommonDetails*>::iterator dataIt(m_tauDetails.begin()), + dataItE(m_tauDetails.end()); + + + if (sc.isFailure()) { + ATH_MSG_WARNING("Could not create CaloClusterContainer: " << m_pi0ClusterContainerName << ". No pi0's will be stored."); + + // remove all pi0s if registering the container fails. + for (; dataIt != dataItE; ++dataIt) { + if (*dataIt) (*dataIt)->pi0LinkVec().clear(); + } + + return StatusCode::SUCCESS; + } + + // store clusters in the new container + for (dataIt = m_tauDetails.begin(); dataIt != dataItE; ++dataIt) { + for (unsigned i = 0; i < (*dataIt)->nPi0(); ++i) { + pPi0ClusterContainer->push_back(const_cast<CaloCluster*>((*dataIt)->pi0(i))); + } + } + + //XXX need to check if we need this tool anymore. For now just make it fail all the time + sc = StatusCode::FAILURE; + // sc = CaloClusterStoreHelper::finalizeClusters(&*evtStore(), + // pPi0ClusterContainer, + // m_pi0ClusterContainerName, + // rLog); + + if (sc.isFailure()) { + ATH_MSG_WARNING("Could not finalize CaloClusterContainer " << m_pi0ClusterContainerName << ". No pi0's will be stored."); + // remove all pi0s if registering the container fails. + for (; dataIt != dataItE; ++dataIt) { + if (*dataIt) (*dataIt)->pi0LinkVec().clear(); + } + return StatusCode::SUCCESS; + } + + // update links in Tau1P3PDetails + std::vector<const CaloCluster*> tmp; + for (dataIt = m_tauDetails.begin(); dataIt != dataItE; ++dataIt) { + tmp.clear(); + for (unsigned i = 0; i < (*dataIt)->nPi0(); ++i) { + tmp.push_back((*dataIt)->pi0(i)); + } + (*dataIt)->pi0LinkVec().clear(); + for (unsigned i = 0; i < tmp.size(); ++i) { + (*dataIt)->addPi0(tmp.at(i), pPi0ClusterContainer); + } + } + + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.h b/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.h new file mode 100644 index 00000000000..49fc73ad4ff --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0CreatorChooser.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0CREATERCHOOSER_H +#define TAUREC_TAUPI0CREATERCHOOSER_H + +#include "GaudiKernel/ToolHandle.h" +#include "tauRec/TauToolBase.h" +#include <vector> +#include <string> + +namespace Analysis { + class TauCommonDetails; +} + +/** + * @brief Tool to select the correct Pi0 Finder. + * + * Part of the "Bonn" Pi0 Finder algorithm. + * + * @author Veit Scharf + */ + +class TauPi0CreatorChooser : public TauToolBase { +public: + TauPi0CreatorChooser(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauPi0CreatorChooser(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual void cleanup(TauCandidateData *data); + +private: + + ToolHandle<TauToolBase> m_tau1p3pCreatePi0ClusTool; + ToolHandle<TauToolBase> m_tauCommonCreatePi0ClusTool; + + std::vector<Analysis::TauCommonDetails*> m_tauDetails; + std::string m_pi0ClusterContainerName; +}; + + +#endif /* TAUREC_TAUPI0CREATERCHOOSER_H */ + diff --git a/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.cxx b/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.cxx new file mode 100644 index 00000000000..ef06f1f6857 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.cxx @@ -0,0 +1,514 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: tau1p3pTrackCreateROI.cxx +// package: Reconstruction/tauRec +// authors: Elzbieta Richter-Was (addapted from tau1p3pTrackMatchCells.cxx) +// date: June2007 +// +// Tool for collecting cells for tauROI +// +// 17/03/2010: AK: change to P4Helpers +// 16/05/2010 - (FF) pointer p_measPer never used (coverity 22627) +//----------------------------------------------------------------------------- + +//TODO: statuscode failure --> recoverable +//TODO: rename! + +#include "GaudiKernel/ListItem.h" + +#include "CaloEvent/CaloCluster.h" +#include "CaloUtils/CaloClusterStoreHelper.h" +#include "CaloInterface/ICaloNoiseTool.h" +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCell.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloEvent/CaloClusterContainer.h" + +#include "tauRec/KineUtils.h" + +#include "tauRec/TauOriginCorrectionTool.h" +#include "tauRec/TauPi0EflowCreateROI.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauPi0EflowCreateROI::TauPi0EflowCreateROI(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_cellsContainerName("AllCalo"), +m_cellsOutputContainerName("TauCells"), +m_detRIsolCaloCut(0.4), +m_detRCoreCaloCut(0.2), +m_useNoiseSigma(1), +m_AbsNoiseSigma_cut(2), +m_detRChrgEMCut(0.0375), +m_removeChrgEM01(0), +m_removeChrgEM2(0), +m_fillCellContainer(false), +m_pCellOutputContainer(0) , +m_doCellCorrection(false), //FF: don't do cell correction by default +m_tauOriginCorrTool("") +{ + declareInterface<TauToolBase > (this); + + declareProperty("CellsContainerName", m_cellsContainerName); + declareProperty("CellsOutputContainerName", m_cellsOutputContainerName); + // declare options for noise/weighting + declareProperty("useNoiseSigma", m_useNoiseSigma); + declareProperty("AbsNoiseSigma_cut", m_AbsNoiseSigma_cut); + declareProperty("CaloNoiseTool", m_noiseTool, "Tool Handle for noise tool"); + // declare large fixed cone for creating subcollection of cells (cluster) + declareProperty("detRCoreCaloCut", m_detRCoreCaloCut); + declareProperty("detRChrgEMCut", m_detRChrgEMCut); + declareProperty("removeChrgEM01", m_removeChrgEM01); + declareProperty("removeChrgEM2", m_removeChrgEM2); + declareProperty("detRIsolCaloCut", m_detRIsolCaloCut); + declareProperty("fillCellContainer", m_fillCellContainer); + declareProperty("CaloCellMakerToolNames", m_caloCellMakerToolNames); + declareProperty("CellCorrection", m_doCellCorrection); + declareProperty("OriginCorrectionTool", m_tauOriginCorrTool); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauPi0EflowCreateROI::~TauPi0EflowCreateROI() { +} + +//----------------------------------------------------------------------------- +// Event Initializer +//----------------------------------------------------------------------------- + +StatusCode TauPi0EflowCreateROI::eventFinalize(TauCandidateData *) { + + + if (m_fillCellContainer) { + + StatusCode sc; + + std::vector<ICaloCellMakerTool*>::iterator itrTool = m_caloCellMakerTools.begin(); + std::vector<ICaloCellMakerTool*>::iterator endTool = m_caloCellMakerTools.end(); + + unsigned int index = 0; + + ATH_MSG_DEBUG("Order and check container " << m_cellsOutputContainerName << " with " << m_caloCellMakerTools.size() << " tools"); + for (; itrTool != endTool; ++itrTool) { + + ATH_MSG_DEBUG("Calling tool " << m_caloCellMakerToolNames[index]); + + ListItem theItem(m_caloCellMakerToolNames[index]); + + sc = (*itrTool)->process(m_pCellOutputContainer); + + if (sc.isFailure()) { + ATH_MSG_ERROR("Error executing tool " << m_caloCellMakerToolNames[index]); + //TODO: return something? + } + ++index; + } + + ATH_MSG_DEBUG("setConst container " << m_cellsOutputContainerName); + sc = evtStore()->setConst(m_pCellOutputContainer); + if (sc.isFailure()) { + ATH_MSG_ERROR("Error while setting const: " << m_cellsOutputContainerName); + } + } + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Event Initializer +//----------------------------------------------------------------------------- + +StatusCode TauPi0EflowCreateROI::eventInitialize(TauCandidateData *) { + + StatusCode sc; + + const CaloCell_ID* cellID; + sc = detStore()->retrieve(cellID); + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to retrieve caloCell_ID helper from DetectorStore"); + return sc; + } + + //Build bitmap to keep track which cells have been added to CellContainer; + IdentifierHash hashMax; + + // Get hash range + hashMax = cellID->calo_cell_hash_max(); + ATH_MSG_VERBOSE("CaloCell Hash Max: " << hashMax); + m_addedCellsMap.resize(hashMax, false); + for (unsigned i = 0; i < hashMax; i++) { + m_addedCellsMap[i] = false; + } + //ak + m_clusterMap.clear(); + + // output cell container + // record here EMtopocluster + //--------------------------------------------------------------------- + if (m_fillCellContainer) { + m_pCellOutputContainer = new CaloCellContainer(SG::VIEW_ELEMENTS); + ATH_MSG_VERBOSE("record container " << m_cellsOutputContainerName); + sc = evtStore()->record(m_pCellOutputContainer, m_cellsOutputContainerName); + + if (sc.isFailure()) { + ATH_MSG_INFO("Unable to record " << m_cellsOutputContainerName << " to TES"); + } + } + + if (m_doCellCorrection) { + // Cell Origin Correction Tool initializeEvent is not called automatically + // -> call from here + sc = m_tauOriginCorrTool->eventInitialize(); + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to retrieve TauOriginCorrectionTool"); + return sc; + } + } + + return StatusCode::SUCCESS; +} + + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- + +StatusCode TauPi0EflowCreateROI::initialize() { + + ATH_MSG_VERBOSE(name() << " CellsContainerName = " << m_cellsContainerName); + ATH_MSG_VERBOSE(name() << " RconeTauCut = " << m_detRIsolCaloCut); + + //Create Noise Tools: + if (m_useNoiseSigma != 0) { + // SL changes to retrieval of CaloNoiseTool + if (m_noiseTool.retrieve().isFailure()) { + ATH_MSG_FATAL("Unable to find tool for Calorimeter Noise "); + return StatusCode::FAILURE; + } + } + + StatusCode sc; + //--------------------------------------------------------------------- + // Get pointer to Tool Service + //--------------------------------------------------------------------- + IToolSvc *pToolSvc; + sc = service("ToolSvc", pToolSvc); + if (sc.isFailure()) { + ATH_MSG_FATAL("Tool Service not found"); + return StatusCode::FAILURE; + } + + //--------------------------------------------------------------------- + // Need some tools for cells + //--------------------------------------------------------------------- + std::vector<std::string>::const_iterator itrName = m_caloCellMakerToolNames.begin(); + std::vector<std::string>::const_iterator endName = m_caloCellMakerToolNames.end(); + + IAlgTool* algtool; + for (; itrName != endName; ++itrName) { + + ListItem theItem(*itrName); + + ATH_MSG_DEBUG("Retrieving " << *itrName); + sc = pToolSvc->retrieveTool(theItem.type(), theItem.name(), algtool); + + if (sc.isFailure()) { + ATH_MSG_INFO("Unable to find tool for " << (*itrName)); + } else { + ATH_MSG_INFO((*itrName) << " successfully retrieved"); + + m_caloCellMakerTools.push_back(dynamic_cast<ICaloCellMakerTool*> (algtool)); + } + } + + if (m_tauOriginCorrTool.retrieve().isFailure()) { + ATH_MSG_ERROR("Cannot find tool named <" << m_tauOriginCorrTool << ">"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- + +StatusCode TauPi0EflowCreateROI::execute(TauCandidateData *data) { + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau->numTrack()==0) { + ATH_MSG_VERBOSE("tau has no tracks -> skip TrackCreateROI"); + return StatusCode::SUCCESS; + } + + StatusCode sc; + + //--------------------------------------------------------------------- + // Retrieve CaloCellCollection from StoreGate + //--------------------------------------------------------------------- + const CaloCellContainer *pCellContainer; + sc = evtStore()->retrieve(pCellContainer, m_cellsContainerName); + if (sc.isFailure()) { + ATH_MSG_INFO("TrackCreateROI: Unable to retrieve " << m_cellsContainerName << " from TES"); + } else { + ATH_MSG_VERBOSE("TrackCreateROI: Successfully retrieved " << m_cellsContainerName << " from TES"); + } + + + // output cell container + /* + CaloCellContainer *pCellOutputContainer; + if (m_fillCellContainer) { + sc = evtStore()->retrieve(pCellOutputContainer, m_cellsOutputContainerName); + if (sc.isFailure()) { + ATH_MSG_INFO("TrackCreateROI: Unable to retrieve " << m_cellsOutputContainerName << " from TES"); + } else { + ATH_MSG_VERBOSE("TrackCreateROI: Successfully retrieved " << m_cellsOutputContainerName << " from TES with size = " << pCellOutputContainer->size()); + } + } + */ + + //--------------------------------------------------------------------- + // Loop over cells collection and find closest cell at a given layer + // from track impact point at vertex and propagated in magnetic field + //--------------------------------------------------------------------- + + //do cell selection + //TODO: ATTENTION: distance 0.8 is hardcoded!! + CaloCellList *celllist = new CaloCellList(pCellContainer); + celllist->select(pTau->track(0)->eta(), pTau->track(0)->phi(), 0.8); + + if (celllist->ncells() == 0) { + delete celllist; + return StatusCode::FAILURE; + } + + // scan ROI twice: first to classify the case, second time to classify cells + + float sumEM01ChrgTrk = 0; + float sumEM2Chrg = 0; + float sumHADChrg = 0; + + //use tau vertex to correct cell position + if (m_doCellCorrection && pTau->vertexLink()) { + m_tauOriginCorrTool->setOriginSource( ( *pTau->vertexLink() ) ); + } + + const CaloCell *pCell; + pCell = 0; + + CaloCellList::list_iterator itr = celllist->begin(); + CaloCellList::list_iterator itrE = celllist->end(); + for (; itr != itrE; ++itr) { + pCell = *itr; + + //correct cell + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + + double cellPhi = pCell->phi(); + double cellEta = pCell->eta(); + double cellET = pCell->et(); + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + + // XXXXstill need to migrate track extrapolation + double detCell = Tau1P3PKineUtils::deltaR(pTau->track(0)->eta(),pTau->track(0)->phi(), cellEta, cellPhi); + // double detCell = P4Helpers::deltaR(*pTau->track(0), cellEta, cellPhi); + + // collect all cells (remove noisy cells ) in a fixed + // large cone around candidate (at vertex) + if (detCell > m_detRIsolCaloCut) continue; + + // find position nominal position of the closest cell at each layer + int sampling = pCell->caloDDE()->getSampling(); + if (sampling == 4) sampling = 0; + if (sampling == 5) sampling = 1; + if (sampling == 6) sampling = 2; + if (sampling == 7) sampling = 3; + + if (sampling >= 3) sumHADChrg += cellET; + + if (sampling < 4) //ak + { + //for each track connected to tau object + for (unsigned int itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + double detEtaCell; + double detPhiCell; + // detEtaCell = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->etaTrkCaloSamp()[itr][sampling]); + // detPhiCell = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->phiTrkCaloSamp()[itr][sampling]); + // XXXXstill need to migrate track extrapolation + detEtaCell = Tau1P3PKineUtils::deltaEta(cellEta, pTau->track(itr)->eta()); + detPhiCell = Tau1P3PKineUtils::deltaPhi(cellPhi, pTau->track(itr)->phi()); + + //FIX ME! Should we look for different cell in eta and + //in phi? ot the closest one? + double detRCell = sqrt(detEtaCell * detEtaCell + detPhiCell * detPhiCell); + if (detRCell < m_detRChrgEMCut) { + if (sampling == 0 || sampling == 1) sumEM01ChrgTrk += cellET; + if (sampling == 2) sumEM2Chrg += cellET; + } + } + } //ak + } // end cell loop + + float category = 0; + float maxEM2Chrg = 0; + if (sumEM01ChrgTrk < 0.05 * pTau->track(0)->pt()) { + category = 1; + } else if (sumEM01ChrgTrk >= 0.05 * pTau->track(0)->pt() && sumHADChrg > 0.40 * pTau->track(0)->pt()) { + category = 2; + maxEM2Chrg = sumEM2Chrg - 2.5 * sumEM01ChrgTrk; + } + + float maxEMChrg = 0; + if (category == 1 || category == 2) { + maxEMChrg = 0.70 * pTau->track(0)->pt(); + } else { + maxEMChrg = 0.65 * pTau->track(0)->pt(); + } + + // if track was not interacting early, defined by finding 40% of trackPT in EM3+HAD, + // subtract cells only from EM2 + // if energy deposition in EM01, don't subtract in EM2 more then allowing up to + // 2.5*EM01 left in EM2 + + //counting subtracted cells, do not allow for more subtraction than 70% of track pt + unsigned int counter = 0; + + float sumEMChrg = 0; + sumEM2Chrg = 0.; + + itr = celllist->begin(); + for (; itr != itrE; ++itr) { + pCell = *itr; + + //correct cell + if (m_doCellCorrection) { + m_tauOriginCorrTool->correctCell(pCell); + } + + double cellPhi = pCell->phi(); + double cellEta = pCell->eta(); + double cellET = pCell->et(); + double cellEnergy = pCell->energy(); + + if (m_doCellCorrection) { + m_tauOriginCorrTool->resetCell(pCell); + } + + double detCell = Tau1P3PKineUtils::deltaR(pTau->track(0)->eta(),pTau->track(0)->phi(), cellEta, cellPhi); + // double detCell = P4Helpers::deltaR(*pTau->track(0), cellEta, cellPhi); + + // collect all cells (remove noisy cells ) in a fixed + // large cone around candidate (at vertex) + if (detCell > m_detRIsolCaloCut) continue; + + int isCellAccepted = 1; + + if (m_useNoiseSigma == 1) { + double noiseSigma; + noiseSigma = m_noiseTool->getNoise(*itr, ICalorimeterNoiseTool::ELECTRONICNOISE_HIGHESTGAIN); + if (fabs(cellEnergy) < m_AbsNoiseSigma_cut * noiseSigma) isCellAccepted = 0; + } + + // find position nominal position of the closest cell at each layer + int sampling = pCell->caloDDE()->getSampling(); + if (sampling == 4) sampling = 0; + if (sampling == 5) sampling = 1; + if (sampling == 6) sampling = 2; + if (sampling == 7) sampling = 3; + + if (sampling >= 3) isCellAccepted = 0; + + if (isCellAccepted == 0) continue; + + // remove cells in vicinity of the track + //TODO: if not necessary! + if (sampling < 4) //ak + { + //for each track connected to tau object + for (unsigned int itr = 0; itr < pTau->numTrack(); ++itr) { + // don't bother with matching for greater than 10 tracks (space only allocated for 10 tracks) + if (itr >= 9) break; + + double detEtaCell; + double detPhiCell; + // detEtaCell = Tau1P3PKineUtils::deltaEta(cellEta, pExtraDetails->etaTrkCaloSamp()[itr][sampling]); + // detPhiCell = Tau1P3PKineUtils::deltaPhi(cellPhi, pExtraDetails->phiTrkCaloSamp()[itr][sampling]); + // XXXXstill need to migrate track extrapolation + detEtaCell = Tau1P3PKineUtils::deltaEta(cellEta, pTau->track(itr)->eta()); + detPhiCell = Tau1P3PKineUtils::deltaPhi(cellPhi, pTau->track(itr)->phi()); + + //FIX ME! Should we look for different cell in eta and + //in phi? of the closest one? + + double detRCell = sqrt(detEtaCell * detEtaCell + detPhiCell * detPhiCell); + if (detRCell < m_detRChrgEMCut) { + + if (m_removeChrgEM2 == 1 && sampling == 2) { + if (sumEMChrg + cellET < maxEMChrg) { + if (category == 2 && (sumEM2Chrg + cellET < maxEM2Chrg)) { + isCellAccepted = 0; + sumEMChrg += cellET; + sumEM2Chrg += cellET; + } else { + isCellAccepted = 0; + sumEMChrg += cellET; + } + } + } + if (m_removeChrgEM01 == 1 && (sampling == 0 || sampling == 1) && category != 2) { + if (sumEMChrg + cellET < maxEMChrg) { + isCellAccepted = 0; + sumEMChrg += cellET; + } + } + + } + + } + } //ak + + + if (isCellAccepted == 0) continue; + + // add accepted cells to the container + if (m_fillCellContainer && m_pCellOutputContainer != 0) { + //Ask cell for it's hash + const IdentifierHash cellHash = pCell->caloDDE()->calo_hash(); + //Check it this cell is already part of reducedCellContainer + if (!m_addedCellsMap[cellHash]) { + ++counter; + m_pCellOutputContainer->push_back(pCell); + m_addedCellsMap[cellHash] = true; + } else + ATH_MSG_VERBOSE("Cell with hash " << cellHash << "added more than once."); + } + } //end 2nd cell loop + + delete celllist; + + ATH_MSG_DEBUG("Added " << counter << "cells to container " << m_cellsOutputContainerName); + + + return sc; +} diff --git a/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.h b/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.h new file mode 100644 index 00000000000..ba3f0057dfe --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauPi0EflowCreateROI.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAU1P3PTRACKCREATEROI_H +#define TAUREC_TAU1P3PTRACKCREATEROI_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "CaloInterface/ICalorimeterNoiseTool.h" +#include "CaloInterface/ICaloCellMakerTool.h" +#include <map> + +class ICaloNoiseTool; +class CaloCellContainer; +class TauOriginCorrectionTool; + +/** + * @brief Class for collecting cells for tau ROI. + * + * This tool was fomerly named as tau1p3pTrackCreateROI. + * + * @author Elzbieta Richter-Was + * + */ + +class TauPi0EflowCreateROI : public TauToolBase { +public: + + TauPi0EflowCreateROI(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauPi0EflowCreateROI(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + + +private: + + std::string m_cellsContainerName; + std::string m_cellsOutputContainerName; + std::string m_clusterContainerName; + + //! large fixed cone to collect cells around the track + double m_detRIsolCaloCut; + + //! large fixed cone to collect cells around the track + double m_detRCoreCaloCut; + + //! use noise tool to estimate sigma + double m_useNoiseSigma; + + //! threshold to suppress noisy cells + double m_AbsNoiseSigma_cut; + + //! threshold to suppress cell from being used for topo clustering + double m_detRChrgEMCut; + + //! threshold to suppress cell from being used for topo clustering + double m_removeChrgEM01; + + //! threshold to suppress cell from being used for topo clustering + double m_removeChrgEM2; + + // ! flag to decide wether we fill an output cell container to be later use for other clustering + bool m_fillCellContainer; + + //! tool for noise + ToolHandle<ICalorimeterNoiseTool> m_noiseTool; + + std::map<Analysis::TauJet *, CaloCluster *> m_clusterMap; + + std::vector<bool> m_addedCellsMap; + + std::vector<std::string> m_caloCellMakerToolNames ; + std::vector<ICaloCellMakerTool*> m_caloCellMakerTools ; + + CaloCellContainer * m_pCellOutputContainer; + + bool m_doCellCorrection; //<! enable cell origin correction + ToolHandle<TauOriginCorrectionTool> m_tauOriginCorrTool; + +}; + + +#endif diff --git a/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.cxx b/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.cxx new file mode 100644 index 00000000000..cf3dea0f39e --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.cxx @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "tauRec/TauCandidateData.h" +#include "tauRec/TauSetTracksAndCharge.h" +#include "tauEvent/TauJetParameters.h" + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- +TauSetTracksAndCharge::TauSetTracksAndCharge(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent), +m_trackContainerName("TrackParticleCandidate") { + declareInterface<TauToolBase > (this); + declareProperty("TrackContainer", m_trackContainerName); +} + + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- +TauSetTracksAndCharge::~TauSetTracksAndCharge() { +} + + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- +StatusCode TauSetTracksAndCharge::initialize() { + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- +StatusCode TauSetTracksAndCharge::execute(TauCandidateData *data) { + + StatusCode sc; + const Rec::TrackParticleContainer *trackContainer; + + //SX changes needed by trigger + sc = data->getObject("TrackContainer", trackContainer); + + if (sc == StatusCode::FAILURE || !trackContainer) { + + ATH_MSG_DEBUG("no TrackParticleContainer for trigger"); + + StatusCode sc = evtStore()->retrieve(trackContainer, m_trackContainerName); + if (sc.isFailure() || !trackContainer) { + ATH_MSG_WARNING("Unable to retrieve track particle container <" << m_trackContainerName << ">!"); + return StatusCode::SUCCESS; + } + } + + Analysis::TauJet *pTau = data->tau; + + double charge = 0; + + for (unsigned int i = 0; i != pTau->seedCalo_numTrack(); ++i) { + + charge += pTau->track(i)->charge(); + + // add tracks to global tau track collection + pTau->addTrack(trackContainer, pTau->track(i)); + } + + ATH_MSG_INFO("seedCalo_numTrack = " << pTau->seedCalo_numTrack()); + ATH_MSG_INFO("numTrack = " << pTau->numTrack()); + + // save charge + ATH_MSG_DEBUG("charge from tracks: " << charge << " will be saved in tau candidate as: " << (int)charge); + pTau->set_charge((int) charge); + + return StatusCode::SUCCESS; +} + + + + diff --git a/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.h b/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.h new file mode 100644 index 00000000000..deb5f695046 --- /dev/null +++ b/Reconstruction/tauRec/depreciated/TauSetTracksAndCharge.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUSETTRACKSANDCHARGE_H +#define TAUREC_TAUSETTRACKSANDCHARGE_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" + +class TauCandidateData; + +/** + * @brief Class to set number of tracks and charge of the tau (depreciated!) + * + * @author Felix Friedrich + */ + +class TauSetTracksAndCharge: public TauToolBase +{ + + public: + + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + TauSetTracksAndCharge( const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + virtual ~TauSetTracksAndCharge(); + + virtual StatusCode execute( TauCandidateData *data ); + virtual StatusCode initialize(); + + + private: + std::string m_trackContainerName; +}; + +#endif /* TAUSETTRACKSANDCHARGE_H */ + diff --git a/Reconstruction/tauRec/doc/mainpage.h b/Reconstruction/tauRec/doc/mainpage.h new file mode 100644 index 00000000000..6191183cd74 --- /dev/null +++ b/Reconstruction/tauRec/doc/mainpage.h @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + +@mainpage tauRec +@author Srini Rajagopalan, Michael Heldmann, Elzbieta Richter-Was, Lukasz Janyst, Stan Lai, Nico Meyer, Anna Kaczmarska, Felix Friedrich + +@section Introduction + +This is the tauRec package. It holds algorithms to reconstruct hadronically decaying tau candidates. The tau reconstruction is using a calorimeter seeded approach. Tracks are collected in a cone around the calorimeter seed and associated to the tau candidate. An own tau energy scale is set. + +Packages used by tauRec are listed here: + +@htmlinclude used_packages.html + +The requirements file for tauRec is shown here: + +@include requirements + + +*/ diff --git a/Reconstruction/tauRec/python/TauAlgorithmsHolder.py b/Reconstruction/tauRec/python/TauAlgorithmsHolder.py new file mode 100644 index 00000000000..97c802cf765 --- /dev/null +++ b/Reconstruction/tauRec/python/TauAlgorithmsHolder.py @@ -0,0 +1,879 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +## +#@file TauAlgorithmsHolder.py +# +#@brief All tau algorithms needed for tau reconstruction are configured here. +# +#@author Felix Friedrich <felix.friedrich@cern.ch> +################################################################################ + +from AthenaCommon.SystemOfUnits import * +from AthenaCommon.Constants import * + +cached_instances = {} + +sPrefix = 'tauRec_' +bAODmode = False + +# standard container names +_DefaultVertexContainer = "PrimaryVertices" +_DefaultTrackContainer ="InDetTrackParticles" + +######################################################################## +def setPrefix(prefix): + global sPrefix + sPrefix = prefix + +######################################################################## +def setAODmode(mode): + global bAODmode + bAODmode = mode + + +######################################################################## +# Atlas Extrapolator +def getAtlasExtrapolator(): + _name = sPrefix + 'theAtlasExtrapolator' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + #Configure the extrapolator + from TrkExTools.AtlasExtrapolator import AtlasExtrapolator + theAtlasExtrapolator=AtlasExtrapolator(name = _name) + theAtlasExtrapolator.DoCaloDynamic = False # this turns off dynamic + + ToolSvc += theAtlasExtrapolator + cached_instances[_name] = theAtlasExtrapolator + return theAtlasExtrapolator + +######################################################################## +# JetSeedBuilder +def getJetSeedBuilder(seed_collection_name): + _name = sPrefix + 'JetSeedBuilder' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import JetSeedBuilder + JetSeedBuilder = JetSeedBuilder(name = _name, + JetCollection = seed_collection_name, + maxDist = 0.2, + minPt = 10.*GeV, + SwitchJetsEmScale = False) + + cached_instances[_name] = JetSeedBuilder + return JetSeedBuilder + +######################################################################## +# Tau energy calibration and tau axis direction +def getTauAxis(): + _name = sPrefix + 'TauAxis' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauAxisSetter + TauAxisSetter = TauAxisSetter( name = _name, + ClusterCone = 0.2, + CellCorrection = True) + + cached_instances[_name] = TauAxisSetter + return TauAxisSetter + +######################################################################## +# Tau energy calibration +def getEnergyCalibrationLC(correctEnergy=True, correctAxis=False, postfix=''): + + _name = sPrefix +'EnergyCalibrationLC' + postfix + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauCalibrateLC + TauCalibrateLC = TauCalibrateLC(name = _name, + calibrationFile = "EnergyCalibrationLC2012_retuned.root", + doEnergyCorrection = correctEnergy, + doAxisCorrection = correctAxis) + + cached_instances[_name] = TauCalibrateLC + return TauCalibrateLC + +######################################################################## +# Tau cell variables calculation +def getCellVariables(cellConeSize=0.2, prefix=''): + #if prefix is not given, take global one + if not prefix: + prefix=sPrefix + + _name = prefix + 'CellVariables' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauCellVariables + TauCellVariables = TauCellVariables(name = _name, + CellEthreshold = 0.2*GeV, + StripEthreshold = 0.2*GeV, + EMSumThreshold = 0.5*GeV, + EMSumRadius = 0.2, + CellCone = cellConeSize, + CellCorrection = True) + + cached_instances[_name] = TauCellVariables + return TauCellVariables + +######################################################################## +# ExtrapolateToCaloTool +def getExtrapolateToCaloTool(): + _name = sPrefix + 'ExtrapolateToCaloTool' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + from TrackToCalo.TrackToCaloConf import ExtrapolateToCaloTool + tauExtrapolateToCaloTool=ExtrapolateToCaloTool(name = _name, Extrapolator = getAtlasExtrapolator()) + + ToolSvc += tauExtrapolateToCaloTool + cached_instances[_name] = tauExtrapolateToCaloTool + return tauExtrapolateToCaloTool + + +######################################################################## +# calibrate tau at EM scale +def getEnergyCalibrationEM(): + _name = sPrefix + 'EnergyCalibrationEM' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauCalibrateEM + TauCalibrateEM = TauCalibrateEM(name = _name, response_functions_file = "EMTES_Fits_Oct2010.root") + + cached_instances[_name] = TauCalibrateEM + return TauCalibrateEM + +######################################################################## +######################################################################## +# Tracking Tools +# TODO: rearrange +######################################################################## + + +######################################################################## +# TauFullLinearizedTrackFactory +def getTauFullLinearizedTrackFactory(): + _name = sPrefix + 'TauFullLinearizedTrackFactory' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + from TrkVertexFitterUtils.TrkVertexFitterUtilsConf import Trk__FullLinearizedTrackFactory + TauFullLinearizedTrackFactory=Trk__FullLinearizedTrackFactory(name = _name, Extrapolator = getAtlasExtrapolator()) + + ToolSvc += TauFullLinearizedTrackFactory + cached_instances[_name] = TauFullLinearizedTrackFactory + return TauFullLinearizedTrackFactory + +######################################################################## +# TauCrossDistancesSeedFinder +def getTauCrossDistancesSeedFinder(): + _name = 'TauCrossDistancesSeedFinder' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + #first the seed finder utils + from TrkVertexSeedFinderUtils.TrkVertexSeedFinderUtilsConf import Trk__SeedNewtonTrkDistanceFinder + TauNewtonTrkDistanceFinder = Trk__SeedNewtonTrkDistanceFinder( name = sPrefix+'TauSeedNewtonTrkDistanceFinder') + ToolSvc += TauNewtonTrkDistanceFinder + + #then the seed finder tools + from TrkVertexSeedFinderTools.TrkVertexSeedFinderToolsConf import Trk__CrossDistancesSeedFinder + TauCrossDistancesSeedFinder = Trk__CrossDistancesSeedFinder( name = _name, TrkDistanceFinder=TauNewtonTrkDistanceFinder) + + cached_instances[_name] = TauCrossDistancesSeedFinder + ToolSvc +=TauCrossDistancesSeedFinder + return TauCrossDistancesSeedFinder + +######################################################################## +# TauAdaptiveVertexFitter +def getTauAdaptiveVertexFitter(): + _name = sPrefix + 'TauAdaptiveVertexFitter' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + #then the fitter utils + from TrkVertexFitterUtils.TrkVertexFitterUtilsConf import Trk__ImpactPoint3dEstimator + TauInDetImpactPoint3dEstimator = Trk__ImpactPoint3dEstimator(name = sPrefix+'TauTrkImpactPoint3dEstimator', Extrapolator = getAtlasExtrapolator()) + ToolSvc += TauInDetImpactPoint3dEstimator + + from TrkVertexFitterUtils.TrkVertexFitterUtilsConf import Trk__DetAnnealingMaker + TauDetAnnealingMaker = Trk__DetAnnealingMaker(name = sPrefix+'TauDetAnnealingMaker', SetOfTemperatures = [ 64, 32, 16, 8, 4, 2, 1 ] ) + ToolSvc += TauDetAnnealingMaker + + #then the fitters (smoother + adaptive with smoothing + fast billoir) + from TrkVertexFitters.TrkVertexFittersConf import Trk__SequentialVertexSmoother + TauSequentialVertexSmoother = Trk__SequentialVertexSmoother(name = sPrefix+'TauSequentialVertexSmoother') + ToolSvc += TauSequentialVertexSmoother + + from TrkVertexFitters.TrkVertexFittersConf import Trk__AdaptiveVertexFitter + TauAdaptiveVertexFitter = Trk__AdaptiveVertexFitter(name = _name, + SeedFinder=getTauCrossDistancesSeedFinder(), + ImpactPoint3dEstimator=TauInDetImpactPoint3dEstimator, + VertexSmoother=TauSequentialVertexSmoother, + AnnealingMaker=TauDetAnnealingMaker, + LinearizedTrackFactory=getTauFullLinearizedTrackFactory(), + XAODConverter="Trk::VxCandidateXAODVertex/VertexInternalEdmFactory") + + cached_instances[_name] = TauAdaptiveVertexFitter + ToolSvc +=TauAdaptiveVertexFitter + return TauAdaptiveVertexFitter + +######################################################################## +# TauTrackToVertexIPEstimator +def getTauTrackToVertexIPEstimator(): + _name = sPrefix + 'TauTrackToVertexIPEstimator' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + from TrkVertexFitterUtils.TrkVertexFitterUtilsConf import Trk__TrackToVertexIPEstimator + TauTrackToVertexIPEstimator = Trk__TrackToVertexIPEstimator(name = _name, + Extrapolator=getAtlasExtrapolator(), + LinearizedTrackFactory=getTauFullLinearizedTrackFactory()) + cached_instances[_name] = TauTrackToVertexIPEstimator + ToolSvc += TauTrackToVertexIPEstimator + return TauTrackToVertexIPEstimator + +######################################################################## +# lock tau containers +def getContainerLock(): + _name = sPrefix + 'TauContainerLock' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import LockTauContainers + LockTauContainers = LockTauContainers(name = _name) + + cached_instances[_name] = LockTauContainers + return LockTauContainers + +######################################################################### +# Tau Variables +# TODO: rename + rearrange +def getTauCommonCalcVars(): + _name = sPrefix + 'TauCommonCalcVars' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauCommonCalcVars + TauCommonCalcVars = TauCommonCalcVars(name = _name) + + cached_instances[_name] = TauCommonCalcVars + return TauCommonCalcVars + +######################################################################### +# Tau Test +def getTauTestDump(): + _name = sPrefix + 'TauTestDump' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauTestDump + TauTestDump = TauTestDump(name = _name) + + cached_instances[_name] = TauTestDump + return TauTestDump + +######################################################################### +# Tau Vertex Variables +def getTauVertexVariables(): + _name = sPrefix + 'TauVertexVariables' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecFlags import jobproperties + useOldSeedFinderAPI = jobproperties.tauRecFlags.useOldVertexFitterAPI() + + from tauRec.tauRecConf import TauVertexVariables + TauVertexVariables = TauVertexVariables( name = _name, + PrimaryVertexKey = _DefaultVertexContainer, + TrackToVertexIPEstimator = getTauTrackToVertexIPEstimator(), + VertexFitter = getTauAdaptiveVertexFitter(), + #VertexFitter = "Trk::AdaptiveVertexFitter/InDetAdaptiveVxFitterTool", + SeedFinder = getTauCrossDistancesSeedFinder(), + XAODConverter = "Trk::VxCandidateXAODVertex/VertexInternalEdmFactory", # ATM only needed in case old API is used + TrackParticleContainer = _DefaultTrackContainer, # ATM only needed in case old API is used + useOldSeedFinderAPI = useOldSeedFinderAPI, + #OutputLevel = 2 + ) + + cached_instances[_name] = TauVertexVariables + return TauVertexVariables + +######################################################################### +# Tau Variables +# TODO: rename + rerrange +def getTauSubstructure(): + _name = sPrefix + 'TauSubstructure' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauSubstructureVariables + TauSubstructureVariables = TauSubstructureVariables( name = _name, + # parameters for CaloIsoCorrected variable + maxPileUpCorrection = 4000., #MeV + pileUpAlpha = 1.0, + VertexCorrection = True, + inAODmode = bAODmode) + + cached_instances[_name] = TauSubstructureVariables + return TauSubstructureVariables + +######################################################################### +# ele veto variables +def getElectronVetoVars(): + _name = sPrefix + 'TauElectronVetoVars' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauElectronVetoVariables + TauElectronVetoVariables = TauElectronVetoVariables(name = _name, + CellCorrection = True, + TTCExtrapolator = getExtrapolateToCaloTool()) + + cached_instances[_name] = TauElectronVetoVariables + return TauElectronVetoVariables + + +######################################################################### +# cell weight tool +def getCellWeightTool(): + _name = sPrefix + 'CellWeightTool' + + if _name in cached_instances: + return cached_instances[_name] + + #from CaloClusterCorrection.CaloClusterCorrectionConf import H1WeightToolCSC12Generic + from CaloRec.CaloTopoClusterFlags import jobproperties + # -- auto configure weight tool + finder = jobproperties.CaloTopoClusterFlags.cellWeightRefFinder.get_Value() + size = jobproperties.CaloTopoClusterFlags.cellWeightRefSize.get_Value() + signal = jobproperties.CaloTopoClusterFlags.cellWeightRefSignal.get_Value() + + from CaloClusterCorrection.StandardCellWeightCalib import getCellWeightTool + CaloWeightTool = getCellWeightTool(finder,size,signal) + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += CaloWeightTool + + cached_instances[_name] = CaloWeightTool + return CaloWeightTool + +######################################################################### +# Bonn Pi0 algo +# Cluster finder for Pi0 algo +def getBonnPi0ClusterFinder(): + _name = sPrefix + 'BonnPi0ClusterFinder' + + if _name in cached_instances: + return cached_instances[_name] + + from CaloRec.CaloRecConf import CaloCellContainerFinalizerTool + TauCellContainerFinalizer = CaloCellContainerFinalizerTool(name=sPrefix+'tauPi0CellContainerFinalizer') + + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += TauCellContainerFinalizer + + from tauRec.tauRecConf import TauPi0BonnCreateROI + TauPi0BonnCreateROI = TauPi0BonnCreateROI(name = _name, + CaloWeightTool = getCellWeightTool(), + ExtrapolateToCaloTool = getExtrapolateToCaloTool(), + CellMakerTool = TauCellContainerFinalizer, + #LonParFile = "longitudinal_para.dat", + #LatParFile = "lateral_para.dat", + LatParFile = "lateral_para.root", + #OriginCorrectionTool = getTauCellCorrection(), + ChargedPFOContainerName = 'TauPi0ChargedPFOContainer', + ) + + cached_instances[_name] = TauPi0BonnCreateROI + return TauPi0BonnCreateROI + +##################### +# create Pi0 clusters +def getBonnPi0ClusterCreator(): + _name = sPrefix + 'BonnPi0ClusterCreator' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauPi0BonnClusterCreator + TauPi0BonnClusterCreator = TauPi0BonnClusterCreator(name = _name, + ExtrapolateToCaloTool = getExtrapolateToCaloTool(), + InputPi0ClusterContainerName = 'TauPi0SubtractedClusterContainer', + OutputPi0ClusterContainerName = 'TauPi0ClusterContainer', + NeutralPFOContainerName= 'TauPi0NeutralPFOContainer', + ) + + cached_instances[_name] = TauPi0BonnClusterCreator + return TauPi0BonnClusterCreator + +##################### +# calculate MVA scores of pi0 clusters +def getPi0BonnScoreCalculator(): + _name = sPrefix + 'BonnPi0ScoreCalculator' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauPi0BonnScoreCalculator + TauPi0BonnScoreCalculator = TauPi0BonnScoreCalculator(name = _name, + ReaderOption = 'Silent:!Color', + BDTWeightFile = 'TauPi0BonnBDTWeights.xml', + ) + + cached_instances[_name] = TauPi0BonnScoreCalculator + return TauPi0BonnScoreCalculator + +##################### +# select pi0 clusters +def getPi0BonnSelector(): + _name = sPrefix + 'BonnPi0Selector' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauPi0BonnSelector + TauPi0BonnSelector = TauPi0BonnSelector(name = _name, + ClusterEtCut = (2100.*MeV,2500.*MeV,2600.*MeV,2400.*MeV,1900.*MeV), + ClusterBDTCut_1prong = (0.46,0.39,0.51,0.47,0.54), + ClusterBDTCut_mprong = (0.47,0.52,0.60,0.55,0.50), + ) + + cached_instances[_name] = TauPi0BonnSelector + return TauPi0BonnSelector + + + + +######################################################################### +# Photon Shot Finder algo +def getTauShotFinder(): + _name = sPrefix + 'TauShotFinder' + + if _name in cached_instances: + return cached_instances[_name] + + #from CaloRec.CaloRecConf import CaloCellContainerFinalizerTool + #TauCellContainerFinalizer = CaloCellContainerFinalizerTool(name=sPrefix+'tauShotCellContainerFinalizer') + #from AthenaCommon.AppMgr import ToolSvc + #ToolSvc += TauCellContainerFinalizer + + from tauRec.tauRecConf import TauShotFinder + TauShotFinder = TauShotFinder(name = _name, + CaloWeightTool = getCellWeightTool(), + ReaderOption = "Silent:!Color", + BDTWeightFile_barrel = "TauShotsBDTWeights.xml", + BDTWeightFile_endcap1 = "TauShotsBDTWeights.xml", + BDTWeightFile_endcap2 = "TauShotsBDTWeights.xml", + NCellsInEta = 5, + MinPtCut = (400.*MeV,320.*MeV,9999999.*MeV,350.*MeV,320.*MeV), + AutoDoubleShotCut = (10000.*MeV,10000.*MeV,9999999.*MeV,10000.*MeV,10000.*MeV), + MergedBDTScoreCut = (-9999999.,-9999999.,-9999999.,-9999999.,-9999999.), + ) + cached_instances[_name] = TauShotFinder + return TauShotFinder + + + + + + +######################################################################### +def getInDetTrackSelectorTool(): + _name = sPrefix + 'InDetTrackSelectorTool' + + if _name in cached_instances: + return cached_instances[_name] + + #Configures tau track selector tool (should eventually check whether an existing one is available) + from InDetTrackSelectorTool.InDetTrackSelectorToolConf import InDet__InDetDetailedTrackSelectorTool + InDetTrackSelectorTool = InDet__InDetDetailedTrackSelectorTool(name = _name, + pTMin = 1000., + IPd0Max = 1., + IPz0Max = 1.5, + useTrackSummaryInfo = True, + nHitBLayer = 0, + nHitPix = 2, # PixelHits + PixelDeadSensors + nHitSct = 0, # SCTHits + SCTDeadSensors + nHitSi = 7, # PixelHits + SCTHits + PixelDeadSensors + SCTDeadSensors + nHitTrt = 0, # nTRTHits + useSharedHitInfo = False, + nSharedBLayer = 99999, + nSharedPix = 99999, + nSharedSct = 99999, + nSharedSi = 99999, + useTrackQualityInfo = True, + fitChi2OnNdfMax = 99999, + TrackSummaryTool = None, + Extrapolator = getAtlasExtrapolator()) + + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += InDetTrackSelectorTool + + cached_instances[_name] = InDetTrackSelectorTool + return InDetTrackSelectorTool + + +############################################################################ +# setup up JVA tools +def setupTauJVFTool(): + from AthenaCommon.AppMgr import ToolSvc + + """ + #Configures tau track selector tool for TJVA + from InDetTrackSelectorTool.InDetTrackSelectorToolConf import InDet__InDetDetailedTrackSelectorTool + InDetTrackSelectorToolForTJVA = InDet__InDetDetailedTrackSelectorTool(name = sPrefix + 'InDetTrackSelectorToolForTJVA', + pTMin = 1000., + IPd0Max = 9999.*mm, + IPz0Max = 9999.*mm, + nHitPix = 2, # PixelHits + PixelDeadSensors + nHitSct = 0, # SCTHits + SCTDeadSensors + nHitSi = 7, # PixelHits + SCTHits + PixelDeadSensors + SCTDeadSensors + fitChi2OnNdfMax = 99999, + TrackSummaryTool = None, + Extrapolator = getAtlasExtrapolator()) + + ToolSvc += InDetTrackSelectorToolForTJVA + """ + from JetRec.JetRecConf import JetAlgorithm + jetTrackAlg = JetAlgorithm("JetTrackAlg_forTaus") + + """ + from JetRecTools.JetRecToolsConf import JetTrackSelectionTool + ToolSvc += JetTrackSelectionTool(InputContainer = _DefaultTrackContainer, + OutputContainer="JetSelectedTracks_forTaus", + Selector=InDetTrackSelectorToolForTJVA, + OutputLevel=2 + # what is about ptmin, eta min/max??? + ) + """ + + from JetRecTools.JetRecToolsConf import TrackVertexAssociationTool + ToolSvc += TrackVertexAssociationTool(TrackParticleContainer = _DefaultTrackContainer , + TrackVertexAssociation="JetTrackVtxAssoc_forTaus", + VertexContainer= _DefaultVertexContainer, + MaxTransverseDistance = 2.5 *mm, + MaxLongitudinalDistance = 2 *mm, + #OutputLevel=2 + ) + #jetTrackAlg.Tools = [ToolSvc.JetTrackSelectionTool , ToolSvc.TrackVertexAssociationTool ] + jetTrackAlg.Tools = [ToolSvc.TrackVertexAssociationTool ] + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + topSequence+=jetTrackAlg + +######################################################################### +def getTauVertexFinder(doUseTJVA=False): + _name = sPrefix + 'TauVertexFinder' + + if _name in cached_instances: + return cached_instances[_name] + + if doUseTJVA: + setupTauJVFTool() + + # Algorithm that overwrites numTrack() and charge() of all tauJets in the container + from tauRec.tauRecConf import TauVertexFinder + TauVertexFinder = TauVertexFinder(name = _name, + UseTJVA = doUseTJVA, + PrimaryVertexContainer = _DefaultVertexContainer, + AssociatedTracks="GhostTrack", # OK?? + TrackVertexAssociation="JetTrackVtxAssoc_forTaus" + ) + + cached_instances[_name] = TauVertexFinder + return TauVertexFinder + +######################################################################### +def getTrackToVertexTool(): + _name = sPrefix + 'TrackToVertexTool' + + if _name in cached_instances: + return cached_instances[_name] + + from TrackToVertex.TrackToVertexConf import Reco__TrackToVertex + TrackToVertexTool = Reco__TrackToVertex( name = _name, + Extrapolator = getAtlasExtrapolator()) + + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += TrackToVertexTool + + cached_instances[_name] = TrackToVertexTool + return TrackToVertexTool + +######################################################################## +# Tau-Track Association +def getTauTrackFinder(): + _name = sPrefix + 'TauTrackFinder' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauTrackFinder + TauTrackFinder = TauTrackFinder(name = _name, + MaxJetDrTau = 0.2, + MaxJetDrWide = 0.4, + TrackSelectorToolTau = getInDetTrackSelectorTool(), + TrackParticleContainer = _DefaultTrackContainer, + TrackToVertexTool = getTrackToVertexTool(), + TTCExtrapolator = getExtrapolateToCaloTool() + #maxDeltaZ0wrtLeadTrk = 2, #in mm + #removeTracksOutsideZ0wrtLeadTrk = True + ) + + cached_instances[_name] = TauTrackFinder + return TauTrackFinder + +######################################################################## +# TauTrackFilter +def getTauTrackFilter(): + _name = sPrefix + 'TauTrackFilter' + from tauRec.tauRecConf import TauTrackFilter + TauTrackFilter = TauTrackFilter(name = _name, TrackContainerName=_DefaultTrackContainer) + cached_instances[_name] = TauTrackFilter + return TauTrackFilter + +######################################################################## +# TauGenericPi0Cone +def getTauGenericPi0Cone(): + _name = sPrefix + 'TauGenericPi0Cone' + from tauRec.tauRecConf import TauGenericPi0Cone + TauGenericPi0Cone = TauGenericPi0Cone(name = _name) + cached_instances[_name] = TauGenericPi0Cone + return TauGenericPi0Cone + +#end + +""" obsolete methods + +######################################################################## +# Tau Origin Cell Correction Tool +def getTauCellCorrection(): + _name = sPrefix + 'TauCellCorrection' + + from AthenaCommon.AppMgr import ToolSvc + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauOriginCorrectionTool + TauCellCorrectionTool = TauOriginCorrectionTool(name = _name, + UseJVA = False, #not using JetVertexAssociation, b/c JetRec doesn't use it too + UsePrimaryVertex = True, + UseBeamSpot = True, + VertexContainerKey = "PrimaryVertices") + + ToolSvc += TauCellCorrectionTool + cached_instances[_name] = TauCellCorrectionTool + return TauCellCorrectionTool + +######################################################################### +# CaloNoiseTool +def getCaloNoiseTool(): + _name = 'CaloNoiseTool' + + if _name in cached_instances: + return cached_instances[_name] + + from CaloTools.CaloNoiseToolDefault import CaloNoiseToolDefault + theCaloNoiseTool = CaloNoiseToolDefault() + + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += theCaloNoiseTool + + cached_instances[_name] = theCaloNoiseTool + return theCaloNoiseTool + +######################################################################### +# tau1p3p track match cells +def getTauEflowTrackMatchCells(): + _name = sPrefix + 'EflowTrackMatchCells' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauEflowTrackMatchCells + TauEflowTrackMatchCells = TauEflowTrackMatchCells(name = _name, + detRIsolCaloCut = 0.4, + useNoiseSigma = 1, + AbsNoiseSigma_cut = 2, + CaloNoiseTool = getCaloNoiseTool(), + selectConeSize = 0.45, #not used anymore + CellCorrection = True, + OriginCorrectionTool = getTauCellCorrection()) + + cached_instances[_name] = TauEflowTrackMatchCells + return TauEflowTrackMatchCells + +######################################################################### +# tau1p3p AddCaloInfo +def getTauEflowAddCaloInfo(): + _name = sPrefix + 'EflowAddCaloInfo' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauEflowAddCaloInfo + TauEflowAddCaloInfo = TauEflowAddCaloInfo(name = _name, + detRCoreCaloCut = 0.2, + detRIsolCaloCut = 0.4, + ETCellMinCut = 0.1*GeV, + ETStripMinCut = 0.2*GeV, + detaStripCut = 0.2, + CellCorrection = True, + OriginCorrectionTool = getTauCellCorrection()) + + cached_instances[_name] = TauEflowAddCaloInfo + return TauEflowAddCaloInfo + +######################################################################### +# tau1p3p eflow info +def getTauEflowVariables(): + _name = sPrefix + 'EflowVariables' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauEflowVariables + TauEflowVariables = TauEflowVariables(name = _name, + detRCoreCaloCut = 0.2, + dphiEMCLCut = 0.0375, + detaEMCLCut = 0.0375, + dphiEMCLFACCut = 2, + detaEMCLFACCut = 3, + dphiChrgEMCut = 0.0375, + detaChrgEMCut = 0.0375, + CaloClusterContainerName = "EMTopoForTaus", #TODO: rec.scoping<3 case?? + RecoTopoClusterETCut = 0.2*GeV, + RecoEtaCut = 2.5, + TrackTopoClusPhi2Cut = 0.0375, + TrackTopoClusEta1Cut = 0.01, + MVisEflowCut = 10.*GeV, + MTrk3PCut = 10.*GeV, + ETeflow_ETcaloCut = 10., + ETeflow_ETcaloCutMin = 0.1, + useEMTopoClusters = True, + CellCorrection = True, + OriginCorrectionTool = getTauCellCorrection()) + + cached_instances[_name] = TauEflowVariables + return TauEflowVariables + +##################### +# Pi0 Creator Chooser +def getPi0CreatorChooser(): + _name = sPrefix + 'Pi0CreatorChooser' + + if _name in cached_instances: + return cached_instances[_name] + + from AthenaCommon.AppMgr import ToolSvc + ToolSvc += getBonnPi0ClusterCreator() + ToolSvc += getCrakowPi0ClusterCreator() + + from tauRec.tauRecConf import TauPi0CreatorChooser + TauPi0CreatorChooser = TauPi0CreatorChooser(name = _name, + Tau1p3pCreatePi0ClusTool = getCrakowPi0ClusterCreator(), + TauCommonCreatePi0ClusTool = getBonnPi0ClusterCreator()) + + cached_instances[_name] = TauPi0CreatorChooser + return TauPi0CreatorChooser + +######################################################################### +# Crakow Pi0/eflow algorithm +# Cluster/Cellfinder for Pi0/Eflow algos +def getPi0EflowCreateROI(): + _name = sPrefix + 'TauPi0EflowCreateROI' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauPi0EflowCreateROI + TauPi0EflowCreateROI = TauPi0EflowCreateROI( name = _name, + detRIsolCaloCut = 0.4, + detRCoreCaloCut = 0.2, + useNoiseSigma = 0, + AbsNoiseSigma_cut = 2, + removeChrgEM01 = 1, + removeChrgEM2 = 1, + detRChrgEMCut = 0.0375, + # Added by SL + fillCellContainer = TRUE, + CellsOutputContainerName = "TauCells", + CaloNoiseTool = getCaloNoiseTool(), + CaloCellMakerToolNames = ["CaloCellContainerFinalizerTool/cellfinalizerForTaus","CaloCellContainerCheckerTool/cellcheckForTaus"], + CellCorrection = True, + OriginCorrectionTool = getTauCellCorrection()) + + cached_instances[_name] = TauPi0EflowCreateROI + return TauPi0EflowCreateROI + +################ +# Pi0 Clustering +def getCrakowPi0ClusterCreator(): + _name = sPrefix + 'CrakowPi0ClusterCreator' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauPi0CrakowClusterCreator + TauPi0CrakowClusterCreator = TauPi0CrakowClusterCreator( name = _name, + detRCoreCaloCut = 0.2, + CaloClusterContainerName = "EMTopoForTaus", #TODO: rec.scoping<3 case?? + RecoTopoClusterETCut = 1.0*GeV, + RecoEtaCut = 2.5, + detTrkClusMin = 0.0375, + fracEM01verEM = 0.1) + + cached_instances[_name] = TauPi0CrakowClusterCreator + return TauPi0CrakowClusterCreator + +######################################################################## +# set track infos (charge + global track collection) +def getTauSetTracksAndCharge(): + _name = sPrefix + 'TauSetTracksAndCharge' + + if _name in cached_instances: + return cached_instances[_name] + + from tauRec.tauRecConf import TauSetTracksAndCharge + TauSetTracksAndCharge = TauSetTracksAndCharge(name = _name, TrackContainer = "TrackParticleCandidate") + + cached_instances[_name] = TauSetTracksAndCharge + return TauSetTracksAndCharge + +""" diff --git a/Reconstruction/tauRec/python/TauConversionAlgorithms.py b/Reconstruction/tauRec/python/TauConversionAlgorithms.py new file mode 100644 index 00000000000..9212a547725 --- /dev/null +++ b/Reconstruction/tauRec/python/TauConversionAlgorithms.py @@ -0,0 +1,223 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +## +#@file TauConversionsAlgorithms.py +# +#@brief Algorithms for new ConversionFinder are configured here. +# +# This file contains two functions: +# 1) getTauConversionFinderTool(): +# Returns the TauTool which assigns the conversion tracks to taujets +# 2) getPhotonConversionTool(): +# Returns the TauTool which finds conversion vertices +# Not a standalaone - meant to be used in other job options file +# +# +#@author KG Tan +#@date May 2011 +################################################################################ + + +from tauRec.tauRecFlags import jobproperties + +def getTauConversionFinderTool(): + if jobproperties.tauRecFlags.useVertexBasedConvFinder(): + inputConversionContainerName = "ConversionsVertex_Container" + minEProb = 0.04 + else: + inputConversionContainerName = "ConversionsPID_Container" + minEProb = 0.9 + from tauRec.tauRecConf import TauConversionFinder + TauConversionFinder = TauConversionFinder( + ConversionCandidatesName = inputConversionContainerName, + TrackContainerName = "InDetTrackParticles", + DoNormalTracks = True, + #DoLooseTracks = False, + MinElectronProbability = minEProb, + AdjustTauCharge = False + ) + return TauConversionFinder + +def getPhotonConversionTool(): + + if jobproperties.tauRecFlags.useVertexBasedConvFinder(): + from AthenaCommon.AppMgr import ToolSvc + + name = "_PhotonConversionVertex" + + #Configure the extrapolator + from TrkExTools.AtlasExtrapolator import AtlasExtrapolator + theAtlasExtrapolator=AtlasExtrapolator(name = 'theAtlasExtrapolator'+name) + theAtlasExtrapolator.DoCaloDynamic = False # this turns off dynamic + ToolSvc += theAtlasExtrapolator + + from TrkMagFieldTools.TrkMagFieldToolsConf import Trk__MagneticFieldTool + InDetMagField = Trk__MagneticFieldTool('InDetMagField'+name) + ToolSvc += InDetMagField + + # + # Setup track summary tool + # + from TrkTrackSummaryTool.AtlasTrackSummaryTool import AtlasTrackSummaryTool + MyInDetTrackSummaryTool = AtlasTrackSummaryTool(name = "MyInDetTrackSummaryTool"+name) + ToolSvc += MyInDetTrackSummaryTool + + from TrkVKalVrtFitter.TrkVKalVrtFitterConf import Trk__TrkVKalVrtFitter + InDetConversionVxFitterTool = Trk__TrkVKalVrtFitter(name = "InDetConversionVxFitter"+name, + Extrapolator = theAtlasExtrapolator, + IterationNumber = 30, + MakeExtendedVertex = True, + FirstMeasuredPoint = True, + MagFieldSvc = InDetMagField, + Robustness = 6, + usePhiCnst = False, + useThetaCnst = False, + FirstMeasuredPointLimit = True, + InputParticleMasses = [0.511,0.511], + VertexForConstraint = [0.,0.,0.], + CovVrtForConstraint = [0.015*0.015,0.,0.015*0.015,0.,0.,10000.*10000.]) + ToolSvc += InDetConversionVxFitterTool + print InDetConversionVxFitterTool + + # Distance of minimum approach utility + # + from TrkVertexSeedFinderUtils.TrkVertexSeedFinderUtilsConf import Trk__SeedNewtonTrkDistanceFinder + InDetConversionTrkDistanceFinder = Trk__SeedNewtonTrkDistanceFinder(name = 'InDetConversionTrkDistanceFinder'+name) + ToolSvc += InDetConversionTrkDistanceFinder + print InDetConversionTrkDistanceFinder + + # Straight line propagator needed to clean-up single track conversions + # + from TrkExSlPropagator.TrkExSlPropagatorConf import Trk__StraightLinePropagator as Propagator + InDetConversionPropagator = Propagator(name = 'InDetConversionPropagator'+name) + ToolSvc += InDetConversionPropagator + print InDetConversionPropagator + + # Helper Tool + # + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__ConversionFinderUtils + InDetConversionHelper = InDet__ConversionFinderUtils(name = "InDetConversionFinderUtils"+name) + ToolSvc += InDetConversionHelper + print InDetConversionHelper + + # Track selector tool + # + from InDetTrackSelectorTool.InDetTrackSelectorToolConf import InDet__InDetConversionTrackSelectorTool + InDetConversionTrackSelector = InDet__InDetConversionTrackSelectorTool(name = "InDetConversionTrackSelector"+name, + TrackSummaryTool = MyInDetTrackSummaryTool, + Extrapolator = theAtlasExtrapolator, + maxSiD0 = 10000., #50.0, + maxTrtD0 = 10000., #100., + maxSiZ0 = 10000., #350.0, + maxTrtZ0 = 10000., #1400., + minPt = 300, #InDetNewTrackingCuts.minSecondaryPt() + RatioCut1 = 0.0, #0.5, + RatioCut2 = 0.0, + RatioCut3 = 0.0) + + ToolSvc += InDetConversionTrackSelector + print InDetConversionTrackSelector + + + # Track pairs selector + # + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__TrackPairsSelector + InDetConversionTrackPairsSelector = InDet__TrackPairsSelector(name = "InDetConversionTrackPairsSelector"+name, + ConversionFinderHelperTool = InDetConversionHelper, + DistanceTool = InDetConversionTrkDistanceFinder, + MaxFirstHitRadius = 10000., + MaxEta = [0.12,10000.,10000.], #[0.5,1.0,0.5]) + MaxDistBetweenTracks = [6.6,10000.,10000.], #[6.,80.,30.] + MaxInitDistance = [10000.,10000.,10000.], + MinTrackAngle = 0.) + ToolSvc += InDetConversionTrackPairsSelector + print InDetConversionTrackPairsSelector + + # Vertex point estimator + # + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__VertexPointEstimator + InDetConversionVtxPointEstimator = InDet__VertexPointEstimator(name = "InDetConversionVtxPointEstimator"+name, + MaxTrkXYDiffAtVtx = [10000.,10000.,10000.], + MaxTrkZDiffAtVtx = [10000.,10000.,10000.], + MaxTrkXYValue = [10000.,10000.,10000.], + MinArcLength = [-10000., -10000., -10000.], + MaxArcLength = [10000., 10000., 10000.], + MinDeltaR = [-10000.,-10000.,-10000.], + MaxDeltaR = [10000.,10000.,10000.], + MaxHl = [10000.,10000.,10000.], + MaxPhi = [0.034, 10000., 10000.]) #[0.05, 0.1, 0.1]) + ToolSvc += InDetConversionVtxPointEstimator + print InDetConversionVtxPointEstimator + + # Conversion post selector + # + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__ConversionPostSelector + InDetConversionPostSelector = InDet__ConversionPostSelector(name = "InDetConversionPostSelector"+name, + MaxChi2Vtx = [10000.,10000.,10000.], #[40.,100.,80.], + MaxInvariantMass = [45.,25000.,25000.], #[60.,60.,30.], + MinFitMomentum = [0.,0.,0.], #[2000.,2000.,2000.], + MinRadius = [23.4,-10000.,-10000.], #[30.,35.,250.], + MinPt = 0., + MaxdR = 10000., #-250., + MaxPhiVtxTrk = 0.046) #0.2) + ToolSvc += InDetConversionPostSelector + print InDetConversionPostSelector + + # Single track conversion tool + # + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__SingleTrackConversionTool + InDetSingleTrackConversion = InDet__SingleTrackConversionTool(name = "InDetSingleTrackConversionTool"+name, + ConversionFinderHelperTool = InDetConversionHelper, + TrackSummaryTool = MyInDetTrackSummaryTool, + Extrapolator = theAtlasExtrapolator, + MinInitialHitRadius = 70., + MinRatioOfHLhits = 0.95) + ToolSvc += InDetSingleTrackConversion + print InDetSingleTrackConversion + + from InDetConversionFinderTools.InDetConversionFinderToolsConf import InDet__InDetConversionFinderTools + MyInDetConversionFinderTools = InDet__InDetConversionFinderTools(name = "InDetConversionFinderTools"+name, + VertexFitterTool = InDetConversionVxFitterTool, + TrackSelectorTool = InDetConversionTrackSelector, + TrackPairsSelector = InDetConversionTrackPairsSelector, + ConversionFinderHelperTool = InDetConversionHelper, + VertexPointEstimator = InDetConversionVtxPointEstimator, + PostSelector = InDetConversionPostSelector, + SingleTrackConversionTool = InDetSingleTrackConversion, + Extrapolator = theAtlasExtrapolator, + TrackParticleCollection = "InDetTrackParticles", + RemoveTrtTracks = False, + IsConversion = True) + ToolSvc += MyInDetConversionFinderTools + print MyInDetConversionFinderTools + + from tauRec.tauRecConf import PhotonConversionVertex + photonConv = PhotonConversionVertex(name = "PhotonConversionVertex", + TauRecContainer = "TauRecContainer", + TrackParticleContainer = "InDetTrackParticles", + OutputConversionVertexContainerName = "ConversionsVertex_Container", + MaxTauJetDr = 0.5, + ConversionFinderTool = MyInDetConversionFinderTools) + + return photonConv + + else: + from tauRec.tauRecConf import PhotonConversionPID + photonConv = PhotonConversionPID(ConversionCandidatesName = "ConversionCandidate", + ConversionOutputName = "ConversionsPID_Container", + ElectronProbability = 0.9) + return photonConv + +def getTauConversionTaggerTool(): + if jobproperties.tauRecFlags.useNewPIDBasedConvFinder(): + #Anything we need to do to run the tool + #Handled in TauRecBuilder.py + pass + else: + #Anything we need to do to avoid running the tool goes here + #Handled in TauRecBuilder.py + pass + from tauRec.tauRecConf import TauConversionTagger + TauConversionTagger = TauConversionTagger(ConversionTaggerVersion = 1) + return TauConversionTagger diff --git a/Reconstruction/tauRec/python/TauRecAODBuilder.py b/Reconstruction/tauRec/python/TauRecAODBuilder.py new file mode 100644 index 00000000000..87afc51c54f --- /dev/null +++ b/Reconstruction/tauRec/python/TauRecAODBuilder.py @@ -0,0 +1,119 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +## +#@file TauRecAODBuilder.py +# +#@brief Main steering file to rerun parts of tau reconstruction on AODs. +# +# Only algorithms which don't need cell level informations can be used. +# This is an example of how to run tauRec on AODs and should later be called by AODCalib, AODFix or TauD3PDMaker. +# Copied from TauRecBuilder.py/TauRecBuilder::TauRecVariablesProcessor. +# +# Algorithms schedule here are independent from the standard tauRec chain. +# +#@author Felix Friedrich +# +################################################################################ + + +import os, sys, string + +from AthenaCommon.Logging import logging +from AthenaCommon.SystemOfUnits import * +from AthenaCommon.Constants import * +from AthenaCommon.AlgSequence import AlgSequence +import traceback + +from RecExConfig.Configured import Configured + +################################################################################ +## @class TauRecAODProcessor +# Calculate Tau variables and properties on AODs. +################################################################################ +class TauRecAODProcessor ( Configured ) : + """Calculate remaining Tau variables and properties. Use informations available also in AODs, so no cell level is needed.""" + + _outputType = "Analysis::TauJetContainer" + _outputKey = "TauRecContainer" + _outputDetailsType = "Analysis::TauDetailsContainer" + _outputDetailsKey = "TauRecDetailsContainer" + + def __init__(self, name = "TauProcessorAODTools", inAODmode=True, doBonnPi0Clus=False, msglevel=3, ignoreExistingDataObject=True, sequence = None): + self.name = name + self.doBonnPi0Clus = doBonnPi0Clus + self.msglevel = msglevel + self.AODmode = inAODmode + self.sequence = sequence + if sequence is None: + self.sequence = AlgSequence() + Configured.__init__(self, ignoreExistingDataObject=ignoreExistingDataObject) + + + def configure(self): + mlog = logging.getLogger ('TauRecAODProcessor::configure:') + mlog.info('entering') + + import tauRec.TauAlgorithmsHolder as taualgs + + ######################################################################## + # Tau Modifier Algos + ######################################################################## + try: + from tauRec.tauRecConf import TauProcessor + #TauProcessor.OutputLevel = 2 + self._TauProcessorHandle = TauProcessor( + name = self.name, + TauContainer = self._outputKey, + TauDetailsContainer = self._outputDetailsKey, + runOnAOD = self.AODmode) + + except Exception: + mlog.error("could not get handle to TauProcessor") + print traceback.format_exc() + return False + + + tools = [] + try: + taualgs.setAODmode(True) + ## ATTENTION ################################################################################## + # running these tau tools on AODs will lead to inconsistency with standard tau reconstruction + ############################################################################################### + #tools.append(taualgs.getTauVertexFinder(doUseTJVA=True)) + tools.append(taualgs.getTauAxis()) ##needed to set correct variables for energy calibration + #tools.append(taualgs.getTauTrackFinder()) + tools.append(taualgs.getEnergyCalibrationLC(correctEnergy=True, correctAxis=False, postfix='_onlyEnergy')) + + tools.append(taualgs.getTauVertexVariables()) + tools.append(taualgs.getTauCommonCalcVars()) + tools.append(taualgs.getTauSubstructure()) + tools.append(taualgs.getEnergyCalibrationLC(correctEnergy=False, correctAxis=True, postfix='_onlyAxis')) + + # Run the conversion tagger if flagged to do so + import tauRec.TauConversionAlgorithms + from tauRec.tauRecFlags import jobproperties + if jobproperties.tauRecFlags.useNewPIDBasedConvFinder(): + tools.append(tauRec.TauConversionAlgorithms.getTauConversionTaggerTool()) + + # for testing purpose + #tools.append(taualgs.getTauTestDump()) + + self.TauProcessorHandle().Tools = tools + + except Exception: + mlog.error("could not append tools to TauProcessor") + print traceback.format_exc() + return False + + self.sequence += self.TauProcessorHandle() + + return True + + ############################################################################################# + # Helpers + ############################################################################################# + + def TauProcessorHandle(self): + return self._TauProcessorHandle + diff --git a/Reconstruction/tauRec/python/TauRecBuilder.py b/Reconstruction/tauRec/python/TauRecBuilder.py new file mode 100644 index 00000000000..558fa7ca9a7 --- /dev/null +++ b/Reconstruction/tauRec/python/TauRecBuilder.py @@ -0,0 +1,289 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +## +#@file TauRecBuilder.py +# +#@brief Main steering file to set up the different tau reconstruction steps. +# +#@author N. Meyer +#@author A. Kaczmarska +#@author Felix Friedrich +# +################################################################################ + +import os, sys, string + +from AthenaCommon.Logging import logging +from AthenaCommon.SystemOfUnits import * +from AthenaCommon.Constants import * +from AthenaCommon.BeamFlags import jobproperties +import traceback + +from RecExConfig.Configured import Configured + +# global tauRec config keys +_outputType = "xAOD::TauJetContainer_v1" +_outputKey = "TauRecContainer" +_outputAuxType = "xAOD::TauJetAuxContainer_v1" +_outputAuxKey = "TauRecContainerAux." +_track_collection = "InDetTrackParticles" +_jet_collection = "AntiKt4LCTopoJets" + +################################################################################ +## @class TauRecCoreBuilder +# Build proper tau candidates and associate tracks, vertex and cells +################################################################################ +class TauRecCoreBuilder ( Configured ) : + """Build proper tau candidates and associate tracks, vertex and cells. + Calculate properties based on cell informations. + Find clusters used for Pi0 identification and eflow variables. + PhotonConversion will be run here too. + """ + + _output = { _outputType:_outputKey , _outputAuxType:_outputAuxKey } + + def __init__(self, name = "TauCoreBuilder",doBonnPi0Clus=False, doTJVA=False, msglevel=3, ignoreExistingDataObject=True): + self.name = name + self.doBonnPi0Clus = doBonnPi0Clus + self.do_TJVA = doTJVA + self.msglevel = msglevel + Configured.__init__(self, ignoreExistingDataObject=ignoreExistingDataObject) + + + def configure(self): + mlog = logging.getLogger ('TauCoreBuilder.py::configure:') + mlog.info('entering') + + + from RecExConfig.RecFlags import rec + + # xxx ToDo: still needed? + from RecExConfig.ObjKeyStore import objKeyStore + objKeyStore.addManyTypesStreamESD(self._output) + objKeyStore.addManyTypesStreamAOD(self._output) + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + + import tauRec.TauAlgorithmsHolder as taualgs + + ######################################################################## + # TauBuilder + # create the taus + try: + from tauRec.tauRecConf import TauBuilder + self._TauBuilderHandle = TauBuilder( + name = self.name, + SeedContainer = _jet_collection, + TauContainer = _outputKey, + TauAuxContainer = _outputAuxKey, + MaxEta = 2.5, + MinPt = 10.*GeV, + doCreateTauContainers = True) + except Exception: + mlog.error("could not get handle to TauBuilder") + print traceback.format_exc() + return False + + + tools = [] + try: + tools.append(taualgs.getJetSeedBuilder(_jet_collection)) + tools.append(taualgs.getTauVertexFinder(doUseTJVA=self.do_TJVA)) + tools.append(taualgs.getTauAxis()) + tools.append(taualgs.getTauTrackFinder()) + tools.append(taualgs.getEnergyCalibrationLC(correctEnergy=True, correctAxis=False, postfix='_onlyEnergy')) + tools.append(taualgs.getCellVariables()) + tools.append(taualgs.getElectronVetoVars()) + # + tools.append(taualgs.getTauTrackFilter()) + tools.append(taualgs.getTauGenericPi0Cone()) + # + #tools.append(taualgs.getPi0EflowCreateROI()) + tools.append(taualgs.getTauShotFinder()) + if self.doBonnPi0Clus: + tools.append(taualgs.getBonnPi0ClusterFinder()) + + ##################################################################### + ## Tau Conversation Finder (found no one talking here...) + ## TODO: talk with KG about the status of the new PhotonConversionFinder + ## new PhotonConversionFinder is currently disabled (time consumption!) + ## old one is still in use + import tauRec.TauConversionAlgorithms + from tauRec.tauRecFlags import jobproperties + if jobproperties.tauRecFlags.useNewPIDBasedConvFinder(): + #Needs to run alone + tools.append(tauRec.TauConversionAlgorithms.getTauConversionTaggerTool()) + else: + #Need to run together, they will select either PID or vertex based on another flag + tools.append(tauRec.TauConversionAlgorithms.getPhotonConversionTool()) + tools.append(tauRec.TauConversionAlgorithms.getTauConversionFinderTool()) + + #tools.append(taualgs.getContainerLock()) + self.TauBuilderHandle().Tools = tools + + except Exception: + mlog.error("could not append tools to TauBuilder") + print traceback.format_exc() + return False + + # run first part of Tau Builder + topSequence += self.TauBuilderHandle() + + return True + + # Helpers + def TauBuilderHandle(self): + return self._TauBuilderHandle + + def outputKey(self): + return self._output[self._outputType] + + def outputType(self): + return self._outputType + + + +################################################################################ +## @class TauRecPi0EflowProcessor +# Calculate eflow information and run the Pi0 finder algorithms +################################################################################ +class TauRecPi0EflowProcessor ( Configured ) : + """Calculate eflow information and run the Pi0 finder algorithms. + This needs to be done in a separate step, because first special cluster and cell container have to be build. + """ + + def __init__(self, name = "TauProcessorPi0EflowTools",doBonnPi0Clus=False, msglevel=3, ignoreExistingDataObject=True): + self.name = name + self.doBonnPi0Clus = doBonnPi0Clus + self.msglevel = msglevel + Configured.__init__(self,ignoreExistingDataObject=ignoreExistingDataObject) + + def configure(self): + mlog = logging.getLogger ('TauRecPi0EflowProcessor::configure:') + mlog.info('entering') + + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + + import tauRec.TauAlgorithmsHolder as taualgs + + ######################################################################## + # Tau Modifier Algos + ######################################################################## + try: + from tauRec.tauRecConf import TauProcessor + self._TauProcessorHandle = TauProcessor( + name = self.name, + TauContainer = _outputKey, + TauAuxContainer = _outputAuxKey, + ) + except Exception: + mlog.error("could not get handle to TauProcessor") + print traceback.format_exc() + return False + + tools = [] + try: + #tools.append(taualgs.getTauEflowTrackMatchCells()) + #tools.append(taualgs.getTauEflowAddCaloInfo()) + #tools.append(taualgs.getTauEflowVariables()) + + if self.doBonnPi0Clus: tools.append(taualgs.getBonnPi0ClusterCreator()) + + self.TauProcessorHandle().Tools = tools + + except Exception: + mlog.error("could not append tools to TauProcessor") + print traceback.format_exc() + return False + + topSequence += self.TauProcessorHandle() + + return True + + # Helpers + def TauProcessorHandle(self): + return self._TauProcessorHandle + + +################################################################################ +## @class TauRecVariablesProcessor +# Calculate remaining Tau variables and properties +################################################################################ +class TauRecVariablesProcessor ( Configured ) : + """Calculate remaining Tau variables and properties. + Use informations available also in AODs, so no cell level is needed. + """ + + def __init__(self, name = "TauRecVariablesProcessor", inAODmode=False, doBonnPi0Clus=False, msglevel=3, ignoreExistingDataObject=True): + self.name = name + self.doBonnPi0Clus = doBonnPi0Clus + self.msglevel = msglevel + self.AODmode = inAODmode + Configured.__init__(self, ignoreExistingDataObject=ignoreExistingDataObject) + + + def configure(self): + mlog = logging.getLogger ('TauRecVariablesProcessor::configure:') + mlog.info('entering') + + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + + import tauRec.TauAlgorithmsHolder as taualgs + + ######################################################################## + # Tau Modifier Algos + ######################################################################## + try: + from tauRec.tauRecConf import TauProcessor + self._TauProcessorHandle = TauProcessor( + name = self.name, + TauContainer = _outputKey, + TauAuxContainer = _outputAuxKey, + runOnAOD = self.AODmode) + + except Exception: + mlog.error("could not get handle to TauProcessor") + print traceback.format_exc() + return False + + tools = [] + try: + #tools.append(taualgs.getEnergyCalibrationEM()) + # don't run 2nd vertex finder in case of cosmics + if not jobproperties.Beam.beamType()=="cosmics": + tools.append(taualgs.getTauVertexVariables()) + tools.append(taualgs.getTauCommonCalcVars()) + tools.append(taualgs.getTauSubstructure()) + if self.doBonnPi0Clus: + tools.append(taualgs.getPi0BonnScoreCalculator()) + tools.append(taualgs.getPi0BonnSelector()) + tools.append(taualgs.getEnergyCalibrationLC(correctEnergy=False, correctAxis=True, postfix='_onlyAxis')) + # + ## for testing purpose + #tools.append(taualgs.getTauTestDump()) + # + ## lock tau containers -> must be the last tau tool!! + #tools.append(taualgs.getContainerLock()) + + self.TauProcessorHandle().Tools = tools + + except Exception: + mlog.error("could not append tools to TauProcessor") + print traceback.format_exc() + return False + + topSequence += self.TauProcessorHandle() + + return True + + # Helpers + def TauProcessorHandle(self): + return self._TauProcessorHandle + +#end diff --git a/Reconstruction/tauRec/python/tauRecFlags.py b/Reconstruction/tauRec/python/tauRecFlags.py new file mode 100644 index 00000000000..055b099e236 --- /dev/null +++ b/Reconstruction/tauRec/python/tauRecFlags.py @@ -0,0 +1,123 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +################################################################################ +## +#@file tauRecFlags.py +# +#@brief define some tauRec flags +################################################################################ + +#======================================================================= +# imports +#======================================================================= +from AthenaCommon.JobProperties import JobProperty, JobPropertyContainer +from AthenaCommon.JobProperties import jobproperties + + +class Enabled(JobProperty): + """ if all tau algorithm to be enabled + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=True + +class doTauRec(JobProperty): + """ if TauRec to be enabled + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=True + def get_Value(self): + return self.statusOn and self.StoredValue and jobproperties.tauRecFlags.Enabled() + + +class doRunTauDiscriminant(JobProperty): + """ switch for TauDiscriminant running + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=True + + +class useVertexBasedConvFinder(JobProperty): + """ switch for PhotonConversionVertex.cxx/h conversion veto + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=False + +class useNewPIDBasedConvFinder(JobProperty): + """ switch for TauConversionTagger.cxx/h conversion veto + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=True + +class doPanTau(JobProperty): + """ if pantau should run after tauRec + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=True + +class doBonnPi0(JobProperty): + """ switch on new (Bonn) Pi0 Finder + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=False + +class useOldVertexFitterAPI(JobProperty): + """ use the old (AOD-style) API of the AdaptiveVertexFitter. + The AdaptiveVertexFitter is used for finding the tau decay vertex (aka. secondary vertex) and called in TauVertexVariables. + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=False + + +# Defines a sub-container for the algorithm switches +class tauRecFlags(JobPropertyContainer): + """ tau information """ + +# add the tau flags container to the top container +jobproperties.add_Container(tauRecFlags) + +# I want always the following flags in the Rec container +_list_tau=[Enabled,doTauRec,doRunTauDiscriminant,useVertexBasedConvFinder,useNewPIDBasedConvFinder,doPanTau,doBonnPi0,useOldVertexFitterAPI] +for j in _list_tau: + jobproperties.tauRecFlags.add_JobProperty(j) +del _list_tau + + + +################################################# +#### AOD flags ################################## +# # +# only for re-running tau reco on AODs # +# !not for normal reconstruction! # +################################################# + +class doUpdate(JobProperty): + """ update the tau containers (if running in AODmode) + """ + statusOn=True + allowedTypes=['bool'] + StoredValue=False + +class tauRecAODFlags(JobPropertyContainer): + """ tau information if re-running on AODs """ + +# add the tau flags container to the top container +jobproperties.add_Container(tauRecAODFlags) + +# I want always the following flags in the Rec container +_list_tau=[doUpdate] +for j in _list_tau: + jobproperties.tauRecAODFlags.add_JobProperty(j) +del _list_tau + + + +#======================================================================= + diff --git a/Reconstruction/tauRec/python/tauTrackSlimmer.py b/Reconstruction/tauRec/python/tauTrackSlimmer.py new file mode 100644 index 00000000000..2b357ff9407 --- /dev/null +++ b/Reconstruction/tauRec/python/tauTrackSlimmer.py @@ -0,0 +1,90 @@ +# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + +# +# AUTHOR: A.Kaczmarska (using egamma example) +# CREATED: July 12 2007 +# + +from AthenaCommon.Logging import logging +from AthenaCommon.SystemOfUnits import * +from AthenaCommon.Constants import * +import traceback +import EventKernel.ParticleDataType + +from RecExConfig.Configured import Configured + +from AthenaCommon.AppMgr import ServiceMgr as svcMgr +from AthenaServices.Configurables import ThinningSvc +if not hasattr(svcMgr, 'ThinningSvc'): + svcMgr += ThinningSvc(OutputLevel=INFO) +svcMgr.ThinningSvc.Streams += ['StreamAOD'] + + +class tauTrackSlimmer ( Configured ) : + #_outputType = "TrackCollection" + #_outputKey = "Tracks" + + #_output = { _outputType: _outputKey } + + def configure(self): + mlog = logging.getLogger ('tauTrackSlimmer.py::configure:') + mlog.info('entering') + + + # configure TauTrackSlimmer here: + try: + from tauRec.tauRecConf import TauTrackSlimmer + theTauTrackSlimmer = TauTrackSlimmer( + "tauTrackSlimmer", + TauContainer="TauRecContainer", + FilterTaus=True, + maxNTrack = 4, + maxCharge = 2, + maxEmRadius = 0.2, + maxIsoFrac = 0.5 + ) + except Exception: + mlog.error("could not get handle to tauTrackSlimmer") + print traceback.format_exc() + return False + self._TauBuilderHandle = theTauTrackSlimmer + + # take care of the slimming Tool + try: + from TrkTrackSlimmingTool.TrkTrackSlimmingToolConf import Trk__TrackSlimmingTool as ConfigurableTrackSlimmingTool + theTrackSlimmer=ConfigurableTrackSlimmingTool( + name = "tauTrackSlimmerTool", + KeepParameters = True, + KeepOutliers = True + ) + except Exception: + mlog.error("could not get handle to tauTrackSlimmer") + print traceback.format_exc() + return False + from AthenaCommon.AppMgr import ToolSvc + ToolSvc+=theTrackSlimmer + + #output: + from RecExConfig.ObjKeyStore import objKeyStore + # output to AOD (cluster container only!): + #DR objKeyStore.addStreamAOD(self.outputType(),self.outputKey()) + + # add to topsequence + mlog.info("now adding to topSequence") + + from AthenaCommon.AlgSequence import AlgSequence + topSequence = AlgSequence() + topSequence += theTauTrackSlimmer + + + return True + +## def tauTrackSlimmerHandle(self): +## return self._tauTrackSlimmerHandle + +## def outputType(self): +## return self._outputType + +## def outputKey(self) : +## return self._outputKey + diff --git a/Reconstruction/tauRec/share/EMTES_Fits_Oct2010.root b/Reconstruction/tauRec/share/EMTES_Fits_Oct2010.root new file mode 100644 index 0000000000000000000000000000000000000000..ffc5088be80e7cd0204774071ae094d79119e322 GIT binary patch literal 12844 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 literal 0 HcmV?d00001 diff --git a/Reconstruction/tauRec/share/EnergyCalibrationLC2011.root b/Reconstruction/tauRec/share/EnergyCalibrationLC2011.root new file mode 100644 index 0000000000000000000000000000000000000000..ce496c79bb2c8bbbd94c9ebe8a41b0e1747341c1 GIT binary patch literal 57427 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 K)n5xV4E`@RC;eIg literal 0 HcmV?d00001 diff --git a/Reconstruction/tauRec/share/EnergyCalibrationLC2012.root b/Reconstruction/tauRec/share/EnergyCalibrationLC2012.root new file mode 100644 index 0000000000000000000000000000000000000000..fd9fb8b7483d558448d5d8387a2d751b6c44ca7e GIT binary patch literal 60589 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 NZ<P%a^t*2t{{W5-AQb=r literal 0 HcmV?d00001 diff --git a/Reconstruction/tauRec/share/EnergyCalibrationLC2012_retuned.root b/Reconstruction/tauRec/share/EnergyCalibrationLC2012_retuned.root new file mode 100644 index 0000000000000000000000000000000000000000..b0413b95b96feadfad36f4ed58cec6071fdf95ff GIT binary patch literal 64273 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%0AOUfmS#!WYOr2KOGmR9!*?V zsLM9M-WhS%IZ&0K3Hhr%np*I&R_Kg%r}(P@7!DE=6QzZ7UuKk|1t>%$uig*$Xb#UW zMT*~d2)Ii+voE)xNm5oSGPJQ5B`OFPltcCR3~uUb$2^*<q@868ehl4q@(T2BJX{!8 zU+&tF!R>Nfq8kcbEtaGu?nOoGSHOGn*N7rAY~*WJkL<P#Q8E{@En*6LZwuuY-1@pC zEAsw;4A{`RMo)KGQy704#@+JJ{mAh>;?SjAH~<n6X&?|Uo<xog3F$;QY9m^T-klG7 ztE3lhlOOICYhiB2;xHR!PM+EX1?GpiRbKXGTCYY9X@7;2bbDf~to1kSj?l@GH6r;~ zr3@-2%Y=4ne=95=+szdrvIy)@9@liwsyb%ptyaTNFVW9dIu_Ld&p(9Xe<_*+1Z#rr z@3S)}#e;6b!X`T>jURiyI-@pp)qQ&VZbJW-D7}-H7mDfRd-I{e_z}cb6ixr^7jHB0 z9@ijJj3_;Hf2`%bJH{dA0=lyzqp6*jGcgAE?s!w|;9isX3NM$G!Px5(7k?&syT~(` z_g8>Evv224?9*WHw>!r!I7cVsgsWd396;BZV=g4e<1520F2`$d-sZ&G8{<{lqd<<9 z@M}NFQUS76bHj-@0kd*<Ga|Zm<8sMAY>8pIy!tWy@hDItUoD&Vd2qS2%cugX=vHzI z3c1^Qz;()rr1!reSY-hQzf@@*#WiQvucfX_r)_g;?48HghTl&5ZOw&ca3=n4LYuDm zlGxPdEtfLwZ`@WBe)ECsgZOHgdd1dq<0j{zUxADiSML#L{T<Oysz-&WA47_&gZ_n2 zF))kT<i0;CR*lGwH2D%Kdx!0tk|~P&AX8kSUGV+MEYQNU(e+*6UwCr{aO%nsVWrMD zQPRwYM?v#t*i!nvuO5DV#RjwOqS}G#lxJLqtU;eavhBOMbzo^{@5+fuk`hOH4{w5Y zyp2UvfRIJM<ywC|e^M8i;iRCudKDt`qM}vPR0!7*E{I=WDF4}PMcBS_K7atDB6Vy2 zUgDaq*^t*fexGD{iRFxz5KF?smmu;8MEqAXTvbB)C2`L>QL;2UU%7!1JzAkd<NQ{x zvO;X?V3%?<T1?pf`@Kzuk84XGOU6{D=Q>`8W%u8=^YS_Q%Nd@G6mhOU`mVn-GME^@ z4xNBqQMrcKpi<P<tC5gD-YU>qb=z#xi|9)XviuzETG|DqXE-jfezYGe?yjAm4j90R z7cn9YdJ@lABe+Vgk$rYdGY)eQu`qo>=wfz?lMvc>?iTMkaXQ+L#L!`TiAls*f&Fh} zZp=!B+quCLry95x&2OpubQv)>l*jI7H|}r!mJ}S0Ei*8CBd;V4!HTR{xjr1iOO7F@ zzU6_%^b}7m4r}P4^yo0VFWeX1I_-c!u5H+FyC1bBPxD8vy&dPy!Z{cju&o#+66_8A z#Bga;GzR|M_AeGqj7_cnsL3__j@faRY?+AO(rQ#`qQp!tO5UdpDO2?)=bVO2#SrNd zhSGZciv`e+4?)x@jzV$BaP)rns4f0B|95PyeSP)Cu*|kD2%l@rpl$L=#frbe>iY6y zP=a;0xF|xeDd>4S=~*fOVOA85jO_aMUCFo*Yh`EgF?W21W;(waJNM9=s;6U*51;<m z-}7Il`@b{YOT^J5R6cJIpsxnyS_;06yvGW7v&!%QG?)K(pb1L(zX47D|1Z$|kIE<O ze*sOQxd)&L;8-O8H2j05JlV_RjZi-E*xMpDoy3=g@`6bOg=`;7Ukr#$48LG1dY-7o zHuqbIrb|UJ>u4VsAsZCD@}TnZUG;_spc?cOq=UN=6UQs@@w*+;On)Spm|7H{U7{&T zKHWqv%aM?L{dN~r3R;F6a<8^5I&MGUOxjD|=u_0Dn=Al>$%~4Lj~aZG_}VWles)5} zNos_26mi0vcJq_|Q=e>C;WQ<dw--K+;i)5%am^<9uIjl=JntpC*FI;od*^JTK~DMo zW;aOw7_JxfouEG(8`(8#;l{`z5E7h6KT!J69Z$Ks_jD^4IwH74`;#R8z8pogbQ9g8 z!tSH*aTq_-la!oJXRX}bFPe&7pE}vhi{Ff=ndskDCbt@J((E>9z+Tu@R1q85eHdO7 zy*sZIbn{nH@F(4OcDSsz5sCJ`c#Af0y%}s%;&d(#y#DTe`z5z^K|jKqdjhWcf!o?F zJ9fZaLa(m6lOhdYKfQqmk?@$s38$f&FZbNeTFB6#UeTvRL1dq!wi#R^9qp~>Iwt|1 zPx2O~XV*AHe>QU&phbTUudhZo@aA}!j<<Dze2(qC>~bulHqf$CRHFafYX_(epm9xn z<R6HvS5jhuzYZ+;G{%66$7`9fGeJMwZ50KOLERwhluQa_T9r`BL+1@}?Nd%niL%Y9 z8?L;Fl#UgY6@2r`Q5sp9oR{Jx%ICT)!+3fCi1oZVpnG7D;|)hq#P_}6r++08i|+-- zQ-QLrrjY;!j1CK{F#kAayUER%4taA&CsXFlgnUxYrIcgX3w~vBj`h?>kmvImaE5$7 zR&r;a!(gEgTpL>G!eT>B`6+mE%!3fglNu~Ki5L~L%20$-t3wC&#;Q%YKb!U?pS-^6 zj8!$?X_teC0Dk}WmDQu<=jj9$$4`C(q!-)Onq~-#RR1zd1c);`Hr4~ATUYm<vUJ*- zn)hm_V*QEbT-YkE;e~?xNH{%EV^*f0W?gZs{Gj9s?ZS=M>_`<2g51~U1K{a&(1?;H z-H6b_peG}>uP40j&-8<9)q4tn=@EgZQetw?AY!^gVqno~>y^XEMA5Voz6W_s<^G6b zY(?9Zu*DrAvOF0o^d5)rC?38>_lpZUM|F5xe9nq=w3Swls|!145{Bqf`NCoLQ#d5h zxv{b-?&yf7xs&e{vF&!gdyPxx3zRgZlSANun#V4xDO7Mi`|?t0=<i;ebEU0U3(1Gx z?|Q({u}_}dn^whlvs^mRRfF4ul`u2{?cyBdgD=ByF9(uAGL+#~AKem}xtez};i-0P zY1rfn5ib1tjbW(YPmJ;HQFzUf@19d4g!R?&RbXJPxGz02D{`e<Vie2KnQs@;=D5aJ zDE%D17&tiS`-xqO6%g#eJ?bTro&B7Xi9QGd7Lir4VERoYsiKsn+jlo!b0Hk-MBU-j zHXp?H_QEfnmagh^iwgEI<=>a5HJn~5NABy42GD5k4T~0?#_<Sk?iS$|g|BH}lL@;} z%9gP#_qU8PvBTi!77V5~z7#SUbs)I5pVPnOx8SaAPDvh#^qv?G?L+@b3(#yR1GxR2 z2l2f8X++CJcJNnx<iJX;Ms_L|=4MB}4p1B)$xl=xGbqFmPTngRztNUOij8_%7Y^fM zd_G(-R&4dh@fgi=S}fxptGmJ1f$CNMg_CHQPwYtg-geBg<E9?5R0zCorp!R#K*y^r z?!J{1C73nxTgd+6#<spixY4oxu)rcS&)Vw<bNv}KGhBFAI0JCnc=ij6#5@CiB>0^^ zzE)RM4rxHuA&fD^T9IP&s~6SHpOray04E8<>N3O|xk30FpQ+5ngy~P`EO}2ig}S=s zogOrlw^~9%c9Qd|pt04|PC-k<fQxid_x+o5AgHh{CYj&78}0q@$pESi990=eJ#N&* z6gb-FWp=x==FoM@Hxll*jRek}!jAvykPzo6=axbbj}qNe_kO*pT$Z3l5{^XL$TpU9 z3FKhgWItJ=?4vh%%i|zlg^lPUTo9EldE<!0IF5+o$`C}9N`2Xs=sABJls?{b0=w|8 z><I!ksiIQ^)Zp1!htG)Fs*Qj&Jc0AC`Y-3B6t|RZ%u%x$=Qx&mM>nsxtco6SkECGX ztZzQuqpb@rmn@OphxzH+HHm}%c*ooo%s;1eBire23CMst+eUy8ukLO++f2ysO7trq zElK?#fCcLRUQ4Fz_0tRTYvdCpq6lm=>LL%|>`Xlf3z)BBO;gCM{2sHt`?12hc+a1T zc0T)*<mhtj?|^RExnJ!vv)7LD=>9TQ%Xhr|wKYG#CC{W{E+KruD7>)YCfZA6sxMod zR4jmNLcBrATIfv6wLF-}KuGK_4kWRzrGx0FQ`HV{nU%TgKxqVeG`xM;hi)Tx!o#Dk z#x0s$wR<6gXx=5!<>gn(AYsaiu;rJB9R7CYh~|X%yxrorrZi7E|2}zN$20tn%REB* ztG>3(*ImO*N1!M1I10LhjyPE;6&+@wp$`5k&l5v>P&go(Pxw*mt$$6Bpv2A4a@V6( z_RbB1g81=NY_l=mK9uU7Qs#>Ma^c_bAZB*2b~kmGG(s-8*c(ssyt&*4(*584&{a9Y z{rdN}bEOqZyEhZe7f%7X15GiEho_N=4V^Llg~>+8b~$z@H=oD2a+FVM9SW1OseEs( zW<~;I@6R`Lit$`0o6e>@DwFpsx(q5x<OdFo*Tn9B#>;zlA;F5_O^n-C4Bs{M+oVmN zh@N}da)tiI&X!J>pW1E_;l8|ec#ew?J9&^1`|Y@f;6SSLl=JZox=as9h+wYsx(kC~ zr<_eA3$GL7z4qMY;*G_%;c71Xn$(NqmpP1*ub(45)E!TX_>+$@7uF9c`(3x*xkNX5 z_m$9)0S9{GLcN?z=~0ufB^NNaTdiZ;1d(yxdqCuJV_?Qx=@i7o)m<~*$-?~=E#iH4 zLHkt$6J%4l_qBPa9p8k%rb3M$SA@7`wFOja3oGk`rr%SSu87XN$2;@1l`SFD+(=1m zfup~)zulT&*IxF7_3<Bfd@kB11UH=cj;y*H>HQfzaS!xW48abn0jAT74xI0-Rk;G3 zzeOwCyhJHzE(2%WWm>l*&)iPN+eBXVQ>ol7<wTqe`s*d9f4@!9A@yf^49_KFD3m6K zjV&6m6ZEuA@aH78lb+@Ya(gN;TzncYIMiSdqfWo|8iTwV4fg33v4DA9D%YP>v`qR} z{>8HcUoW*o5QW14N-ScrLDt|I=bPLUyQSZ)aI2}F$be41(FvqFjuf9=gSC_?t5a$e zD66=-5%B&=icq#M5!`>v?9+&IEHZUD0x#Ujvg5rI6nA%3(sG%=o_X)Mf%Y#|(3<&U zm<75{zXu_TP?tS|N}0Rn@@)ZMcCf6rXg!C_>GM~%kMQ7JOK!`}_`2cP$nZ>vul))l z9In|1#oT5rw*0xHR#<RG)gp;T+dV|S$Pi?g_f{6DwkC-{WoM+K7OijX#?c;Pt5`5| zi8e9}3ldYIPI7q{Te_dm`UR47<jc%dzz00kuG}HWFYCJ01#`FbFv2DbPaL{0yu?7i z3|Z$DBR=m8!xc`@#=bX~!sWHS6HB{nqtdJF(cb9{KFr2ZpyVT&dFv$#d-|)^bym~* zl|fu&PBl}vwHZswkMYwhD7ewpo7m_ey%8G5qmt3x*pa>l2hcktR!6?&3wAJHQX@P~ z`@))EiN>wg$J?o4b=l4u&x|Z^?ueAWF#9WN+oYhg(NJHaTNyd~{gI9i_RNC={gNi) zS;l+I`{K5g+?3|9c@<_4cbVTK)+$@p8w8yS!ny7#9hH($=B@o7Vcfgg!>72_ec`p! z2PRLpS>FnxrVbnUyzWXF)OSy;mtMxIemA>rGmD$#^Kfb5%*kb+AC;BenB!ozWwVqG zDq2Ua9WhO<VK3AJwmU!g+592Gy5V_SN+8p4`c#V3dzN@7{XoV-zlq*evbr$tN<-u( z$@?)#Esu8B+WWD_bW`g~!na$5PtpZ=e*5+tmV%BK&r$|SYL|{a9Y4wN<SbYtR^pC+ zp%=-zv_z}Ee&-j%?>M>CEszkLZ(d-E2W9;z>G|D~Sohiw<;0XCg!vThuYLfe(TX`w zU+@_nMdDV@m~4cAG7ZH%tGCHB#7vm}U`aVqBeNbSD9N_o;XEXirt>Tc7o-1mq`GHj z>Bmvc?pBjS&fjX3A<PoaQ`kP;H$0kP4ZN~+kjC%QZ;}1(oiXXBebC9>@%qPB@D7>4 zPh#c3uZdr5`a`WkmZY)n>SF2>u&X(HH9Wm==S@O~C@@Vo`!Rx|x&2@k`&j=X2V7P> z)zn&E(xNo<?hrrE9ZU;3&9ZQE;Zs5xc%}j&J*Bib_q<OLtd(=hM}5xNlvPn8jkp;1 zft*7zz*Vt$WIv-ep$;@~VA<QuIQE>TyHLb}kASD9oKz;FA%ADlvJ+Y{=-S>vG3>@o z^%ca(TP9gE8*$HjU4Q5A_atz6$Km*;%qV~E9fN+psWjznG^bP>8=Z8ts-*DAvw828 zffYw50M%@bhX?tY5ItqIf9$f3uQ5K7)~?-l*&ZKkew~rSV7fMYOdBMN+}?JQoQ3Qy z+R5gGAURO@mlLYz(iF!CQ903mo>)K~qfOrCpFnF1&8YS$o`L4iaG7obl=D=R%GZH% z7f5ZjO$|ZJfqDeMdf#B;TcHP|flY2dHdnI%G$>B`kMAbQg?gpuaz}1P%R<!`p4O*@ zd;3Gcsnmrz*3`~Rxc3<s%~)ZH_S)m%GA8MhO;$1e3%+{{31?NN^wWJ2pC1Y(%ZAW_ zv#m@$mv6bqcQvgLyN&&UsjnG0j@1lCwdLW-fkZLPO!ddo{EIj_PwL#PlMd1l&0&<j zL$(jXPFA;KO1b;`t1QrQ)a-UiyE`iHqr})`7YH*-?w-6XHbG=xStNmb%GmI)Zp1Lw zjbP-GY5}k59Vodj$hsuofQ>Ukg}o4;<y|X=ULLmLZZsu)b4BRErPq7&9FzSy`{g=@ zFt?$)7jD+Ao)Dth$Kh&ehKtI^w{7l~{QD6*uU75kLO7?pR<2H(5=L&Wf1jsEL^g)t z1{3jyD|*?Of7_8z1Uas=Cw~=fTCW4j%V#hawvX+>?AC)$@&XS`3UwR~rp@hXy*P+Z zxf;E?8gVfi_RhXYsf$SWCeLMNMev(l1(9lHa6#kM7nxa7G*4ZqVCB6RRDx9FVF{Z2 zl#R~K5-Ev0EQ45y@P3;jVLpBWXEyXGGQ#;DFLlh62$-@6V50Nhh=f;F8QM)9uA~G$ zz4VAWY~?+UZbp2Ys@)4&b|;$GD<6}=s+iSiwFtF6ftk49?EcJzz>#88txXEbw?u-g z^y%xqA`+SEx+eHGwwom<6UsqX(lq;`*EblO`gp!er<lGVDmK}%N$P8!hE;DIhI4PD zzWjWr)9X!baBvWiFW9`D=YE<OkNyk#qR?ro+538N*SRsZBFBYB2ySdW+KqVMc#w%L z6c})zMQ5r9+<ixCYD~NE{hYSy^z7fvE3jPSP#{T8)uOn{6Gys$yZUG2WgkbopO=nl z<FCW)Jd&z%8FR{HCWi1i^xx}QOTQmE{MX(^HmnAs`Gg<o8=0mIDNN<xLvO5eu5vSP zgv_pTUxMPU6D5b=kX|4j-j)e(ZU$tJ@D4JCEqvJiANJlds_kyy7N(_z;-wU~_Gy9Q zUYwL-E$;5_?vPNVxD<D%xE7b-gkr(n2_7IouoC3u+4tVF_j~po?}szqZ|8i-_^*sL zW|n7U&HR3IZsGGm`}w6C09s642(4*Kk3IyO-LPwiE<w(|OeAIZ0Bd>UL2qdGyO{}C zNs&MiovBf;BBN%MqT0$`X>^;hyjU1k46S-nEx*^Zir*?(oVcqjIa7-SvTJsY>Y@GE z{<i@J62$51WahoMeS8dl>oeU)Bg7Vu(!Vt!DJ{_+)kY!1+l-dRi@(pahdEk|wzVn{ zC4DPU@OKUa+1e>A2=>nLMm58YeOw=gS1Fxc167nAQz;^lbP>e4Rn2@Torn1V&Qm2Q z$-`9M{m44CHL!0t@+?L7WTZG&<klOrdMtLMlW#Bi;yGwpVZZSbxl8ONU7F?Z|E<zx zlE=&B3%LC4IeU7hJHZWgTyq3S;!l;w!}%*3RcF7@JBn@Ye4D>~h__i^sOi1{zu!DN z&)vPwYwPGPz?n4P%nJpNDe!r{Uz~c4`Y?3oZpG%We~heZJB5MxZ`E;Uou`ch=7rsu zhemCi7pmI>$A*T+dH<?gj`GY4(Ij;9Zel)o?^v-7dS?)-kRiCbW=?yO<4LYr5DJRp z!LP@+qW!l(z5nqm|8H;C-u2*sDRKV~YR<j-{rnl=mVKI0#PBg+UHCs!oAHkSH)@mX zU#ZQ%4SZ1lhuWO?R+E2tjMbcyu$~l-P3KX0)x+@Ddl}^rxj05s87Ad0F1{bNuVucx zGPin@|NbpkvP7XEis#LwlOZtlKX}cCW1k#^&YETM<?-PiIZaltm{lU6x)VKCvxjKl zA=>NnH30!3jiR27&icW(BnKP@3>E{cJ6c7jPix9|sF*|F^Uc#MP2p_xScZ{=t|$1v zz#<#hY{MR%I+3fKAHY+Z8YNdtPux#_om`i{JAFnF`g^f+xOe~h`Gcr(Pyem2{DU8< z^ZM!i5^dOnJLzX(LaJ#3L*`reYqV^qwJU9Y=>6`76Z=6<brj|%&W3;I7>pd2*-7gU zKJQe#XSf6K$ML4&W7XUl+&mO#e=dhTM`=yX9!k_T>}pLdY`s#>p_o<6x2bAvjNt_$ zBlz7#Qg|a7w7|@`rlV4KlC%(3vr$;~@z-h(<I&YJnF;2Qnw@XQu=a9SEo6tPt3Ixd zHZm>XUf(cU8yU?zC9)(id)q9r)o#IRTh*W-B1D(S+q5n1Pi_aj&KDEw`8pI;U0)=% zeW?WDYoF%!%%X-Z35IpjDD__xg~aHe!H8gOh`1MwY-YETG!f4UAM?`XZv*GkgvbGA z$;fAlw|;Yjav}oykXU`g$05TMz-8?u83Wh5<sc@<Gqc;n=yE7+wdw6`g`ow$IN5`7 zpvr2T3dG-Hx^*Eh?R4$NLC0M@>J;D&UC&@Oy)CLT%o_lbJ+xgt?=LZdAQsyP5A@Js z5+bQ7d!mr9*x0jSlw1nktX!3EGo24I9%Cw-ITalH6~LZPqPRJ0SeaE!GtEN=6JQEa zb;Pb~0w_k<AuGYO-2j5zGJSGvAlq5NU#i33JI<MH@F`-MF3NQ-ON|s1;A|i!fV@;R z$@IJ#{O;pR-o)=&77fLPu*wp$a$Jw{cdF|%t6*|CfCEXJSR$RDFof=9t&TRYgE))* z!IpZd(pr5ZsHn*KN5x_|GenYxwY6jWF_X}=6PO;0ymF*6=C+`OnMi%_w>dV_yKM>! znstd1qIi2YZjj>4@cpc)xx!3u^1vIQ05#DYS^=tSH^->uHFgOQN69wv@Umq?n`ITu zR}TirQ}%zg?`Xe-Rs90$q?eO>>NhzJK61?4jfZN!R6WhQX$GCcM`S60hs8cBY6!8% z*N2Wr>*{<F_J?2vbG_4V>tD&+$gVitYImlkAW0fc@Jh<j=7CvGOvJ6pa>6=MU12`? z6_4-5$+2aWuL1mSrSF?FyZ2Rc1=4((xxX<LBK^o>^Bx4vX+XfLwrX`Z&}N&#($hR~ zGR-NURcmrcUE}ip3SNw}dpL-=5kCrbC}e5Ne2j?f$mo@4gaCowZ=81dAi$*^4;9ek z)x<6PPoblwp6hWU<v}XDgUN6k8!ZHDsC9PHR8*%p6Cah<+uZnhA-L_YD3k+@%6^#h zH6gPmoMNashxL(7g^^zkGrEauyn%se6-I>u|Lj#jmtEB3o%I*Lt31&nSgC7MUFIU2 zt7G>#-bsmqgS{cfx03YhGte`xGmEFjt1#}4Qn@$z#tui+gU|9cq|cj<%%0ZPT9DE; zafx+)oea|W!!72&+k(EVbUG;hb8|HH)1v{2nX@PnZp|Nu8aM;dmxFSBSse4HjDr)A zD1`WPF^U*-xi@!Pb+vz}=zn|#{A8{T#WHJJIq2Z}j)eg|QPa)qe&({+Rxy@bU<mw3 zBl`Q<SxWHJt1|9@o`d!9-ZhSZ{J~K3E6aRZhEDH5xQgKImtnzdti-Iq3WQ+Zk*rF# zgVEEZ1jZ#UC&MyWmPS28ZVoB!2N~0+4b&!cHV&Ktt(VW1%4w`(e$IzU%jIt9rRh%u zbmTO59I+5tRYfF#I;rnYQ;QG!pXnHbWkE1dgXE#FH>=fF-l;~jA$9E&HlnpW!WQ|! zrM;Z#EkQo|@r#GVvwq?`ikl)AZlb+Wth+{Y9-T>(7KT8qb9=yA)+LF^5#?*0!Dm5z zy$5iE0$b^u-<SDg&@i5Bj(`An=S8RG6tNM>j(y`qU7jM9Xe?X?z7#2wY}|z1Bj*w+ zAs2dVSZlQ2&5=5bB$4HcM}k-jE}^16JqJxeeTfw{Mb?i^5H^t0#~c8l=a`76u=9MS z&t&V-{X#y+<BcexeU+2UYX7q!R>cE9-LNXKzS3HZ#XLRx`nZ$;HJ>Cs2XE%KrcD%E zBLD3PdO8P-&Y6gg0jsLx?`IZ&y;5vVAK&m?nRd!tkO?<*^v@ljz{D`78kI>Qts0dO z%E!bX5Kg1?dXc`RJjal1&pp0=9QM8f6PZ}OF$No#<|M@rDX9D`iq%YjV~%QsqVIhu z2JUL)Bcth0;p3GJAvXTwg+`@g*;d`L#Vg5H7sAL7MD^S-P~Zn5EvBZl_ofCcm7_Ti zJ<Zy!*SL)cF<`7+i~ln`-@i)vUx={GaPMIGOxTXri|=KzAY_|C!zqi;<5C@mL%1p3 zpY72OFvduyb;;<I?EVlfy9fslNwHE)@qNuT<)O*$_0pBcQwGI&H>JOO+d~_0lgzt2 zol8lxH^iH-D`=}npW8M!qMa59*)zB*{}fvuL7Nd;<OO9G3@Dn@3#%8aHuD#J6SdRs z;N?m&>MAsU9JD$kQw!nOB98TcU?yN?w6UKLPR?2t`9jWGUAr{vY0y7A|C#!HU!gL- z4QTJ~zj7t0C>viLd9H4wug`o_sPt%RI(XnrU3~f+_}V08+_RIwb1Ac%Uw0)%#kucV zdnGP0tu%Ud)jTKsv|(t$W2y}Ss=5_TXAXLlgYm2<5@}<6D@-avoa~*DCtb+fXiQa! zPqsp-7b_*YDnhQH_5GA;2sjaab*z(GP_CBa7>c728GOi9!(L%w4}Klx?yyazn-c_d z=+_#_??BZpY^P0m(n6TaNLIyWDA^>krOj{HZNY(OG*sNwvEH_PYyvMMXEPknQY6aD z>W^v+SY)H@G|wh77A+jt^UQtn3^fRS^jsA5s9UAYcFYe=hu4t;)l&J)tp@LD#4M4m znylhkE}yTAR&*9^2HHY$gQO()&+qgUxIAcQ!IFx0un1YJsk$~t4n>k`*{s?A-2S(N zy){slUmdsYo@nxk`l6Q96nEk~%$dJl2-90EN3$KI`xC+}Hu7yp9)cIcD|JCnW`=73 zf5?(lM9f-<P}{p(GxAkdN2zBN72L?lHBwST@wz6r^e#(e0v)M{6L=?XCZ(}U6WQQx z80o8Ay&bc*sH6d$-G5_~zce0&;-%$J9A2++^dF?=Ns9nAyWTuE7(09mSDFtt5Z&T_ z3bXRKw%Li>-%GAPM<-LPql2rznpCzd4cuoQf2&IxV*HTGNV-N51?N1vsb?VE&6owR z)?v+A>$o@oTi^LCwD4k}R(PuF*T;Z7T7aRasNZhg6>F7RokcOSIFFGq%YE+UAT*{* zy?1TT6dG1zzVyLyt0<V`QeszSR8+ho=s`|DG$os^DC)0({@RH4Umd&9hPM;I2H}GD zjpRu=iE9X6;alamhkoQh?n(bn?DR+Rp|=%635B|!Lr#91q3ZI)IYsF^w$oa4_O_VY zuV_jZcBVg$#D+(OgZ4z4msG|-;v%i|1n3p|vB98^evFU_{*AU#Njjdsp4``{wfUun zdgMF7S)sf#gz!q*XQYhM#)jCDmZDUS<XzzQ_~z5yTCGkgYuR^O9EwuP)Okeu6Y64& z+MvDZoA2IQhEgQ3X%b@q#o%EB?*NGV^|GdOZ!3r2Vuk;vppW{N)ceb5<IJt!c_*_R zpCsNJ@d?&3uB&s~_&zM{UzD76w_BcG3r%luE%*@Llp&E()qBxIc)rdZ-JIo-@y(#1 z^~{qY8n@#gw}HHSC4II+QA&6QQ2VI4T!2A@VdjJ<<07bOe97HsFkw7_3AF9CBBl#b z<m^R|Z-FK1`)R4EZ|x8K)Li*=fkgg%ZI`Xbkmmi)wT8VJEgnbY=zH$-LdD7PvAtxh zx<wA!o7KffD_tcN$-u{`;tojVs(RM7(5<Dd-!%Vu7P!D&$ftZpz>44J)=m61<SToh zx5EUd8-C{v_GQrOZ!kG}yb>>ZoS#<_idhpz88ZbGnK&!wO-H?VD*KSWZmbsTJh`Gq zem0JA;U@3e2Zt|;-p+>r3(9$XHX69v6|b{7xqYAAe7-}eDDnuo^n!?Z8e0Yk=c-|V zf{Ic6ENA&ioLxAsy47kMCUx`MT2i>Cu9B#!FO!b3-O&jaxZU0!Yc}@szRY+t)$xee zA_cr2-YDA~{9ra+;c}NOT~Zh)_aN7vW4+A6`w}HpUe9B&_d31meyfO!V*5(K1<)#7 zz4RI`XB&@;3Ok+T($NwCkPr`-v30lG%tjuw1P!ELfv+c;{YSY|q;i6)(}jX#<PKwR zMrM;Ct<zK~3&t*JGYP5d^?2K?yrSRlicU8a2x*ZO$|a^vcyq;Z&8#zKZzwb@w=2S+ zo;Kw@el}4Z!cOTTWu@^xq*p)hEe9g!n*A@D?D=Sf@|%*Yt}?#U_!bm}JF5|Rl$RWT zvP?0Thg_7$rk?G*nQdv6S(rSEJiV{(wI2=Gx0<0`=;^kKsYYa7?QPIbG`zJkIw!Q| zul^{D7!e|N)4GSfc&p|d@RgSU@vajGuyl=4*{%g6uvDwtW$BD^)`(76PFoGWA#I`R z^D1c#RbSA~oi&vvBh5SeOF0yH(ox^g?o*0;bC?*3HJc<e8zM!-&SP<4iqPG|sJo|x z7I2$!(_V_uo}uK?E(3<T9HkkKdr(Ws>8pMtb!SseL2By}XGxwi3G4--q94!iCFWc; zRrqqbgB#hBr9#WtlX`vBlPO!AXVu#c9rS;6dNSSE#Yzjz=Ba38PgPS|ja=0u$vo-& zGxXmL<Q``%4b|KyRUkZLb)%U|^gQQ7uU3vI<?L}MhAcq|r-Bi4k0LP3VUXfug7!cR zn?qLLNT>|ITJS{~zusMsjcA$QrEEH2b-)w%N(oQOP-LHGGHO+8$znB{M%5ys8UOn_ ziq)HZZ&~R(W-8!0if}I8Ryq2Z0Hv{s{4`fERjcKHHuLo_PJYFXH)<1&&*gQLR(=MA z2vs*Ke<F=#yn{u>&@u||QwdttE64-X+~U8_$@+Da<k*%I&~DK@i@^yMa<P^M7lh;~ zU*VGzNNV2S=0{#I^Ue5t=YdE<{Su&0D+mPk|Dr>zUAO<GbV(NVhx&T@!E{xa2d-`{ zjz__#?Ciir;Z)AE!EqpvA3f)pslTxi5n8f%?#CLHW4D{)?g+?7c<TFqzhKcdaxZkk zNk3QCr$$MB-0XX=N$EEDwAU;u=&-NbySK)`Jlbcgzn0dle@*+`C~J^sRlSPhn<%uR zzUO*aPeHfElicS+<*YWr#TZ4xL=3dO33c?;&1>|IRG=i?X;<M8un!PtsVkp2FdsIr zF8IDXDPL1vnD8fyvWD%a=PyZEZAW1WHR@#XdDb#`h8ixlXqO~@EU(r&TS1I`H}lJ> zr|$LnpE+?L%HY7K=9a%gsI&l^m{p5U<!#G$+`P035@@b}Re(=1ke{!7=LuiwQ?9MU zO1U^~seSw9tpmT#&izFLwU2l3f!0W!S=5C0!>HA_%fb7}k`(CJk5_Jq`}VqeIfb)Y zAfDOI_hYE>hCkO-H`daNzI^B14I2?e<8BUznbmvuc~>#ldGMy>_nSAEUhQsm-D`7C zJQ|TGQ2?HjqMgW6<XD}^8G3@V$SYcctxA{Ak;FnI;Ll?@;Hz7nR>#9!K(j-*JME0* z$(2Tr>4W!%$uzV!zZiYyWw`A@-!3eB0PrZb*AI^u+yYNv>c-4y<&*k}E_eG71J>_< z!=D@=xE!_k5B4dpej%=vR|80k3Kl89Z)+CxI2Vw7fVp0!_+>F@0q$rU%m&&D(ntWz zoNITmrxXc(<GGtbE6vsStAd8`xjcNKMeQ|bj7rT;tNd5Y(W>m5uEL!YD^K7BYsgO- zKeg8GT<C^e910kqwrX7|pbZBM4|HY2JRiVq2T1jdRKqmus&1Kvp-T{6%<(Q?_4NbW z$?&w>D~N7|j!h>QMDg&r8fSo$-K2E+vg3-~#8<%ls(<e$=BGA&$?mrXisvQZ+KW}m zlH+<7d?YJ9$*f(JH=+H=-3K9}%4=6E80Y!TmO>Ka-szOi!YeEOYGf$+0i2ZR6yN<` zX({H8Nze?`OL;4*{PPCcR5K=V|7@S>AfI--cnoq+=>5ZX<%R;hrF+al8a*>B956?S zRW{>ZF1>5$mn4Yc9z}MAeZ|1#HSu%?Tg@Xv+mGd5e=8Jtlisi=)K+%8y|==t8EXW@ zDVC>Xt;bsF9Ld2%1oKJx9>NM-tNi&RP_HaTWmM(|dZaAu&3j7JjFfg>(!aD}{<?q) zlYxDLf4h7l@CpA1`WD*%JpP+ZLDxegdb>Xj{#E|{&4EJHmH&AsTGtpt?U6fW{LkEJ zarys^JLUdY?(}arp}qgZoz7YFC;gr0F6la?q)eX9&4cr^Pm#y!hgzYs4BfV3e4a6b zxboXLdb)Uw&taeGBrMXbf7nP@pyqO0_WTYXRtfG2ph2!#aJ}6@Pj`KAiuuY_D`M?L z$NU55l=k$n(tDrx2hpAClCQ3Vr1|1XJONWHLVAs?4cTxL)5;54z&f5j;$Y?iS~cJ( ze19kRp6hk^dr9C4hPbvOfnxhmetVE~uC@-SQQw>(f5$67WEguacJF}dc1C@T^r7lS zDD2t8?VH%hKfCFV+Qgi%!|#_2&+p-E?<H1Fin6^#PpX@)h`)M(p~BARYXrSiot-(Q zgPY-7fa*vI8~&ZO*iO-#9NI_z)Sv%H1ASE5#pa#Z!Gj0YkVE}@dw0vq<w1$F8WP(C z!3`gOReD?1j9DeFUx^K)tEk)T5C&Ua@EG7jXHbIx``v<&36(7}rOF8oN^Q{paFX_l z$;5t;;je}ern<&k5p)8@4Co@o(@}ku_gWd(r4RgVXtT5XiN!_7{e4`?E-`60a>Bwa zU815P;SBKS_$RbIeHcZjTxEaJ8|cmOI2&USRaYSe%x@FIk1D983VAtC9R@CEvrgp> z>6o1l#3_g{q10S!W8cEZ@O9v=cF&0nFR>kS+G4_q#5L~>9ESSHizFF!`H28>Hf&lM z1AXRybk8shOgC@3q?<y?IZw+$<$75$oVD{>OH&ADBL8fQ&6RMZdwm7|edS1Swk_(M z7T)u0|A)%3VYZwS|HLRi5Q`{8o43+N*0g6{BS({r)HoljT8ldiYq3fM99zmM<~S!% zzEdm5!L^#tyxsjQVW*?g_(G0jiDP<}E&_`re3BOL1exBNw6pM5uEv@}{-V~nXO`zK z>QYqB$>~>?X68t+zQ|g&n%3a6E8t3mfxdaq{n=|tZC`q?t3%YbI4;qxnh%KB$?x0e zW}TlxM1f1H3Wc7gpXVzXpNmV%@i!HjyR#j?%iq4~xj2&xGbl$WhZxA$#m#i~1vk_7 zUu0!s@y+lQtTu9OB;Q9BD6FJ8Nw1BS?eG&Fmsy&DW6VF#B98b{2+Th_TsHq`xo(#h z0>%#I_D`;;;*)UY9iCtFt}&%4F~Y0tT|=;V9Wr9)hdA>(%raz&AiE3S*y9oEX(v5> zrf`Gh-E#j*T4K*1SdM-_d2ka`PcG--q8CwEo8mZTV?$gUD^OJrUURu?tD-zdyP@E* zURImi`qYz)ZRk>?fZVln>v@$aJ&|A(7jNvPWe<WhbTRRYlWqU7_UoTFu$4{`#$+9+ zSG9i5boPjG`xrdiHYb#G)v-I`xi^?BB}Suk_}oJ8QngUejuM7`@p@p5$xLsRb=R*P z4;EBCCzt(@ahj)oFY=R(v+7)%&0Ss))_Wt#-Y{<N7d**^S^Wkg9W6IKmSpNTa`NtN zcvV#SkfJw&E5g}*@a#<%R+Mdhrdxbw-}QAnoN}~*JjV+ZGLlOZrMPO$-m=XJOJ8hc z9CP3ny{OaPJ7$QoWnei1C>!}LLf&=b@Nrc!b2CjArk#>ES!mGMnCUt87c-DzaEL}C za95E@&Ot%jYxIW3%Ssjpnc^_A9O~rTp`I{j*xNSz%s(U7nd4on8Y$#C47|ebAYK^q zYBVkb5bvBo@@MQ(6P8^s-bt#C02cXbfO_t_ui3gYY~Uy&ioI67&DWkBW>JdQ8)LFO z(w3qy0T{ggMHiu5?F<}NRFjTs9lMSg5_?|xGfGzmhn|~@+)%(#)1%@YOoJxP<A^J& zx^?kHn<3(KCW)O$4xh7QXMl2`j0!SW>ep6p%n5^E3}jH8n=daOc&&{h$kx^ig}w~L zI#bfxn@YMu_(HN1RaZu?i@u;vU~uv#aJDayAL8$7GD%!r9Od}+V~4Xw`f26Y&~}qc zZU<5X?QwI=slDcGlupc_2EZC><u4IP6Q(|{^=~7;fq+3~KpW?Ajfk%X-7(UTBtuBm zljE3QR{m{KfO9dSOWKeYfe;<fnuNPFrTB;)9=Rtp^~leW4%YU07qfW8e7RqgbAbfb zwzTdvqM!=VH@BhF3?JW}o0b(O^Nc(aLF~SOtmq4};^>iGrMkQHeY=lB#FeBe&k~HX z#-~TS*Ufnve)ac;T#@?={yH>_LXhr9w+H=M$my`jM%h9hoD96jv2$EMt$ae-Fx;q# zD&geplAl;c2_7SIK?e{Tk%`7Pw8h?0zF97@>RmU;>?7kwhSxw}K>#4bIVX1)+3Uc0 zTn;{$R3X+u&a~m9Hh<`XgV7;ZH9gfGQ=EWM)kcMVRF-q+&v&cMCM(ws3YV)6UCo_y z<d=RJFzJxRgGIW$Q)7JgQ*Y^LHyThcKTRc9+)$68poQ+~>a%KETmQ%GqWIHqK^}Mr z7&*b=!$5Bl>E8ZC#G|?&4UbE-o5<|f@rF|YLTPe<=%2$wd`})akB1w}C`|YwTkH#o zDV(R57M!5Z)sGE4OD9}fHu>%Kd!%&n9Y(&jL!Fr+Crz2VQ61H+t5tiN#PLUnVp#*5 zD<a&W{^TOP$7_Clyxx^;t>)Xj;?xltfQ~#5X@+xf(B9wj6j*Ld{U`HusvNoW+HL$V z<lzAYWNd^5SM(z-xCmL>8h%=bUF`7(<}>C46n@*&oV|^Ms7x`s&7Ao;6YH2u0J0SB z_3j<8R{?|rDIdd)PO#^Q?(HWK6=smJ>T-EkMTxqVEyGpQ+rWc9<y}rF=`Co6z2=kd zn$2>kE@7l7P&e#?l#oy7=M$ud^3V(vEyve+DYWi78%By$JQ^n-^V%Xq75Ih}WaIBv ztZQy1$Sx{!f|RFj_y}6VG3XTdO2l<z^lt;bJI%ZV?9i)Vlco4$+teQj+IAzIW3ubu zGA2wu^dk?V5QcPFJ=DvA>+J<=*EZ7!J$x{cSqqx|v9IjSUog&AXS_q!1KOX{v3VDp z1+g{wRaVcSN{~~{<-3`gr15sC;Ya{kr{JE1k1v~zt2eYrm<RNm2#??C0@a4cz>zbz z6C<nC<I_%}=J#<PtFqb~u<;5uC(Z71boS>a=G2ctxF!3S^l>K6jjhjK$yC$;g(LZ0 zOo6n|0#G+Hx%|9F$yiw7{$Q|y-*Ne1K6r^=Q7?Eg2NO7<+52mBj2k4*+w4VM1%rHK z&nal`q^zZFx;6nWzcgr6%RfzEy$p9=IaP=Z964z@4fhU>Rg_-a1-LBy_UcLe8UB~$ zv@@*q+t0md=upTjwF)2G*TS;XUM^a!R4alk^KN)P`$0WFWzPE_HEOl4_>xGk{ULs9 zdVj8uK0OiXW+#pQB+GUN8zxgcxX`dl`fN!`LR0hk3fhu?LnB`sar0LsHuzxlL}1V~ zWvM+<Vs2C?!oT`tYdn+3{5no=n!?(#&nv=gay+bZ50`GH3K+jxqVwZBTrs?A-+?sv zqm|k<CI?8?;=FG~r^GpCnj&*I+1C(G>~yMe7@HS^nt;5V!6kyIVoo3Gg#c3p`L6mk zynY-w*f)^D87_R}TIZge@3#OD0CQpa^p%_M7b%d>t%y3Yte&cA6Y63~HkW;Gd|)Pz zt1c(3i7o=Wj3h6;*xQQ4reN<DbLZmH*>(F;Y!7%>I9pqCvN^2i4ncf?>n}x(wbVI< zul-mnY1@qVP2Ckrd8dLP&Lxg^C^8*i!*lgqwh#vPoDLz#a?aIPn24P3_B(Wr7Wvuk zc799I>1p0fO)fm$VJx_c(yO#mvvuthnMaVrQ&tT{$S&agCj%xt-fb^Ym^Uo9HZ-7| z1$eXd9Z=1+qYe8~dFSA;LcuF#|6LldFgAEX*9ND9ovWO=_)hS<$D)SrhM%W8qLn;i zoNmm7nM2f5A1NU{mq)t%eup8K0I-)%Q4k0%taA5s{80<$UiDN|Tv&LDLT1ZrY@i($ z_<~eLN83UmLj1#~oh#)oqiMoacgC$P2h^~uQ2!F|<UnWxo&vk%k*V30d9GNgWCQ=& zV<586L31|h0$INNemo`+<Zt9}7OnCtiZ%>tYRaH5ebk_vzCHd8zXhG&advd-uE_*c zSLVxB(je8DCRh22`~H(PIGOF%*T^V7KI{(JRdjViRk4J*x}jKBoy!Rxp|6ml9reE# zrM1_8Q1E4fE!>fG+6}auDN^JL^WgGEKI|ijR|Hy1`DSe|!?R$XBzc3yZg(RSWi_Kg zx8q|mcj+Nq*##VDzrja)^<MgG5^g`+3tmaDXwWROhG)B!;`d(f77D!2f``mf2oxJ- z?fO|a<!nK`ssf9>Qpn4u8k^U=rcG>m%@2F^Qj#3aokUvRmLqqK*0$;Qw;d=$k{>eF zxSj(&E&hbkLuh4~y=da384h0^g~k$)(&NGxn+T2~)MhmEL(eKBMe`>nf=p=g7CsI{ z&=;^va0L*J$Dmi=PLYkN+UdA#(3J`8Y&CV4^am=Gel4l<-e^(cu}T)BhX}D(DSADh zm0c}xo8cfnAERSBqa_<l@k&ja4Z)|huF?#K*6-(p{~2mJpHY~Q&O&dy>$=;;JO*dQ z!hd&my#E0FD}9c;=`Sq%2>jFeNRJXlp>OWzR$rWkIj+yYl$Vyid%{ckOJVAD!<+!; zFwRAmv*r4e^UZnDA+j9leM5xR_uLsif5XyGYt>{Nl&GRygsZx^klUdOgKfJ(m&w4i z(H&{UrbBXS^;6P**P!IQfP^|)D)DLs3g@RVgCDF9kX-ncV*0Mkp*TQVAlS5%WM~A? z@#;#u!~j`=IcuFap;8U~;wC>d>a4JL?7-k}mKSg{8zVHqOnHHkk*f_&c3HFn_txFd z4}7Q9yyfb>`4F#S8?_V`14?*Z5e~(UxsLW``=wO<Lgh2{re3CVr(|d%kzOmvzx&;> zP)Bv7ifd0R!6#Y&U@M>e(cTC|Pfq@t>LK{_Pk#_Ys9RY<LQ<C8iHNE&qWs`@!`=-_ zQD@z#w%m5{XPs5<Br=CAWpfzIp^kXGEj{H3m8-5Ca8_2LHQDn(52ITd30;GL*p+eP zXF9`dEZFKHt&E(dC=Mf1o4euz(kSt8+k|t9Wy`OhoCBW3u!naX7)Q8k$8YqcOXm}- z;wB#FvMP!@8nw%SeCLOfxDCq2>*mRkx`N%(%>nM}Hq)zir+E4e?QFy-@HFR*q&MEd zlCYgUJw;Wj()km4lR=!s3F%~{L#J3yH6Sy_oB7U+*u|a(W)9q?62(LeOGTY6<B|@! ziDrvLyK6Om*e=lIw5em&(Is?GU_I;d9*)t!a*+94P}ES^+w!Yk&D&d~UIOSABXYxK zbasHZHwQ?O?{7}I%6VlP3LBOdfC8C<6k_#C@H~e|cZmW0%}Gl<AFq1&6WbyjA^M+U zv0c$G3rI7#ifnS5um>8lKI52fGHu9v7i6eg)7@Clw!fQqjP>=$=QoNf(@RHoqh|@u zp@44%5v8MLbbINQM@iMn10+a_=F53Y{gdrSS=rmb?bNvezUe~R^$uFVJe(x&y9R*j zz$m!U15wvRbTqBc>|xe!(j|4#C#-g{-fhZXWnwWe`us2>f-a88fj6J>U3H&VK~=G& zVMo5S9|_7dlbOw~<xMAzya^Dp*};5vBhBO?4QCeS;kYOM{OSCL9>PqQs=$9KznyDA zB8shkRrzWuw=U5K*dwf&-d_)b+>|dDI=7>|rY}@-o-`wd-k~=&9)21_v=qOMq@OKk z(GTBIz?KyVn?0TpG7D>5)db<jG7EuN79-uY>G<-XW`u%}U%$#IvW`2p^j@@b%$ET_ zwz8FFL{T2N0keYN9{^W)iD}foOKLy#`INPKd<GKiG%!sSa27mg)pb{)M(SRuOqC6& zo!9lb5y(QyeTm7aC&Y;F?$q!Lh@xM2WaJ&1N*|NCX<z5li0)Yg-IwuqELJ+C!Bo$G zd*JQ6@!ZM=AByrAD_-u9?*&zpQjQg<<I@W^#~kn}(s=aL9v~n#*5YK<ajo^cqL-G@ zL)Dw=_j|9oqpv4QCKke^1@<DOz}%@1>6J{t4wIExuL?3h1saiqI#-ri{n0<y6GP2w z>A?fstsM+DG%pBRI|gjZTDRf%pVx5f6RCqis;hO>YXc3yP)db?)^c?Xne5J|S?}kp z-b&%o4fz^@r_-CL9d*JSm@=9v2Ih`qWLdgfOGFL}S`kltAe(X@cJe-Y6t+VId64qw za#6DO)=}QVv!+Lpcn8T7djn#sEdnt2m0wqkCfV?<CfOwsshJypoz>t2$ic6Gz0U=6 z$Fvi?Gb<L21^6FHtBeh2?k3`AE*@@LVV7-_Rrzs_G$W}o^wqN2Xqa%9;p7bKd|sd0 zqSWfvos#7?tu^<xHbcs2=L&?aDH0!*XRv?Crx+!BC&8$hq*xL#V~gcSpkhsBMLjP1 z2J`n5mv2=6^Z4&F1=pSKpU$s(IR+5bmfGF64+Rg;$I!b1AM@v>{w7L=g#RfB+CKe% zBT9Mxl_>q&80q<IG~xekjPyv9u09f_5j?q{zyF%(t4a*(VU<i%A*U>i&zm$-#i9#u zV3{?E%TJV|i?B;7ePvTzBV<!hD2JzZEcJB|*&?*7x0~so4ga%yi_|kjwYIa&w$9yU ztd`rq<(*4qu<eH3tq*RXB(h)M_s*fwC_0q%dOYOf$qH8n&iX)aVllm*UR4+`bGKB3 z{O;};XvP8u5_a$)M5*@(-IH$v%MTwDP^P6{FIp#aVl|Hhp&}o3&YjuoYqmOiOLlU& z?(Rb8oMNRzI)$Lx6-~oWx%j3A?)+|r))a|iS(9Ou46(&s;Ehh;hUO4i4?y~?y7Si2 z{|8FIgK-s2*!m@i<_~i6OxXJPYGl>F?Mur#Edf2_Cg#5Xo%t&R<W+T!<J}nMgZu++ z2Vt*+sHh+0CF$9NAOUl<yzUOrQcEa{XL$cRu5D36@mX4!@dY3@!S{V{4G~bIrKrP1 z3lCm@P9dyu$#?8AVlltr9ZNzjI9lTZ_RJm`HPK2NbO6JyxL6c@oxgi<PF;YH`L-+G z6qS44q}s3erdH8hgu1#>rB*qFw+4}d9t8ZRYs&iN=87Txb(I$zaRoVUwi`)Jj$=`M zYYbK#{fg^TB(#i<?NyAv=Ei7M1s>xbEeul^yo0lD>G)F@(SHv2*)3Xcc%p(7H(Ku! zrg5cAs8pB>w?quM4!^aZ7v3`B3RxZOj(LA<UXx))bOFdcevAGoc_r-FJWQJRlcJYN z`xp8<8#0eX_s*3bTHNwhi-yP$-rgAEKT-IrVW*m3S(v0b57`g8k(r8I6$)1Jps-Y9 z2KS16&#%T>;EQ(_JhPmK_0WL>1_SQHk(#q0Bp&&!mD{fET^z2hiwKL8G3CzOgC}Ls z3a*f1xv?-R#+Z~xm&{9u>o9-nQkGSOd=?amNU75#_XuyH0$B0)3da5>8DX~2YMP7f ztmZPEPfF6+7Bs+xdxI*LK@1@muY42JUy#pwwn-oc--N7e?bmX`aC#jYaLDq)PoJd+ z&rR=gA3_<E#l?YSm){m&X(9=orni0sa`DR@Y?LfHttYrIT9SR-mkxj?S)R!LT09Ln z(a&{vz(3UTDEjcMk%DXhcJVd3;Ko~ZBZysO?6SLzfe0iV+~gpo`0%1ShqCSssX?^= z$6MAByedN?Om1*ts6<ynq-IlM&pX#u0|Q(FxsE+iya=_}VrK*qtL{eBh0G$-ePj~u zv<r7L)NVdXE01MfJ{i9y9dVs(ZL7LJbJ`wtQ;z}+wtTtZ_M{G7lcik!1dlAmtTFgH z@`ngaJbryxP$c9e1re5fSK?a)0&-15zqHlhl;y}ali(-Sfvy^YdR@&uaB>f~f9p8t zwa1gY?r_^}&PC)+;NB`#QUw7MuUl6Qk_eV`U4L>y`{+F$rQNlz!2ZXoUjAQ-JFqL% zQpybQhl_N;zk~Wmh@}q``uvK`V>`NWKsL<uJy9aq3_?aeXKtXEaxE_>!!EugE`vHN zpJVIBPp=r6<yao`Hv3j&sG%(zQ!P(EYieCduOYs9J|?diWUHEE<vORU98Y-hOpupW zff|h(gJfh~%ocoa_)!dEUB2LJMMdBA6q&;h8_{3FQn~_xhF_K3-NnY5l;jC@wY(^6 zM)8<^etwV1;2^q%4K1__QOWY{eUzFV<ckJ2*lra6T+l7<YMKBNaVo}>&IOj?cUk60 zQ#b^~7JVdxhBS0+5Ad#o6Z{uidm}7+x9EG}2bAo~p_-a*jD@|+y`hDzMivEEXA>uh zA-<T<fcN(DXtcoi_c_qGeu3mLp`?*V+gpI7435;Zu{j!iafg`s@4)w16kIh=;Oq;B zWqIxBH<@lJ-Cpmr50idqG%qjD)1c&j$xUyCb$mU{&UWs-Pt@9HNHqe|?ZinVOjh34 z!OJsh4c~JY*{~^mYmLJctnH**jP~J-R_e{o3Uz&>OsJpp<~gwe@oL6%O!kttpct7# z#h9CyLp4}y-eMGc_C1zkis^zi<>#O9b{IC2l7|VFJwMA%AKqzQ1rJcuOG$6^_A?8z z8oPsZUP7&VXl;PndtX2A--{Rw7#q(ucR8PUUKM4UbF}4OAL*xZ7AQ$k7Zn3;gM2&H zo`2uK<KSGr+7u&09b1zf3%wm;9w%J+GOr5QpoFBow3|EXc!IHPmlNa~S2LK3_wgH? zy|hCQTNCc%HT|h+ijU11(Wy4oo=de@B+|(F9S1_6ZUlZcq5{-#46Yk!hL{@C?a>+x zxO0nX>hHw@Q**Nn^t-`1A<$|<egGCz8hKkYN^?4g()lTV$BiHwirM&Ef0FY&?dckV z=2R_cg-v=(<jqq28W`Wh&ijH`Khp7t`=AfLnbSut>loxt0n<K=yauq7=wk;bAsb&` z^!)1FX_Ws?N7>-Tw@#dGv8$8n`r8Zhh9pN|B{n1FI>FP0)~Iu!*qf2H+dD$>o=}w- z4;C9W(<K@i%gIKWfN?b=UD*E3SZD>^XFX<OHqXDiQqm*;&M7DqK{F!Vo-%Dreb{!b zPHuk;9iQnwqZTAWT$kojp+r`9_5w!|oH{Nd^*P7S?>PUwwsLcusyJ0zo6V!x6#>b_ z&V08h0eWbE^vt1f5MyA<E7P0xAuiFH2FA8k-IB~jUgbv3u8>OMG9TMI{UXQd3|q() zI{~{3MqUwnUivmjbzk<hWOtlck4tb@L^g{V4*VpzKdLltrfE-U&<g}Ib~JDrgGJi& zP<x8!ntCUY#~ZmurswH2aHNwT#Yb(9HNw&Qs{+5s->?<~rJJc!RTAh<#DE1qa?ShA zSnSNVWm`xCxsAB$5Uj!1e-*k#OB;B{gdg!?VWfvOhT3*ltn-wpy1ci+ZoEv_$=tfq zMcD1Di43PgZNV6C0frU#oCg*k^iKr)Vl9oyR7&{FGLT}$$qE^C!&nB~YuDmi*Kc|? zUF*ny^lU)B%DVP@0j6k}Aa>HCf!*FW@gZ|y4WJ)gk-X(mx?1_+zRURQN%<IWr_J?* zMw$T5ngY&37>XE7^`}Vq^~b9lTjw$V<w;ohX&B9FQgd!-e!5=)gX(&gX?2+sNW#1) z3Unx|JP1XTj#72&_cfjrO@#|@<3ipEc7B>6LedM`m!w9F5l+;89qP;n<R{h&(l*aA z;9D}qbT>a)&GR&xp4+-gbyU7?Ljevps_>Im%8iW5V|jOX7=B{Vk2i@)o8sxAl+IqG z^y+_k)D+;jwXoOE1jk%G`lIXy{@%G4kj;EIal80DXPh~1p%-c<&ENJmsTkLihn2hv z?_%+_iu*=zj89d0{wZQCVrwIH^+e8*Uk1XBq^GK?8Nb3wRON2Hd?BNlO|jio<GdDq zu2Q22Yppy-4D@)iS-3P;H!I}OnI0PXo`lf*;SY#J6DyE*hnz2K%GZ4CEXA9PE^jTK zhhsZ7E#jAb`w0$g6sYksy9h}+Ipdi*LN|_y9#b8$)hqIJmLL%(E)_-*c%4fay@Pr# z=S|*x$H^`H?tB{TJgGhUk;5m@XF;RcGp;bkm+F^x2PKN0?L*vJF?Q4Ip_QKY{y)5t z^bg+*f|4+e0R7%0!lFmGZpc&;cVaf;Wvh%QM{Gh5Ju6M>a9j5g+syBi_c-%S&aOMw zJGU5?&-D<!!u|3>+vH?V8Rovae-uCJCXb?;=4fi#hE!8r*P`!oD(w3$TAp(|e1U(a zbZ8HPfIh&EBX=_$mZ3GZ;L}S^_(pLXcvJZIkcEw@A;d$g1-=e4S-Ko{Xn&e9R6U&? zgvTXXS7}_?;PM8lX_u7SW6RgBf1!&5bv%@(8y)h~I@DQ-Mn!=Ac+9#9Q;~jwUWCGc zi!mxUw##$q`j-mv!`fe`W9UW)HM%K*#*-0v=B!F?4!?H|-*yV=Qm%xrSlX9IW<x@# z{qFT}J=?K!vN6zin3__0<TpolsP<Mq7W@CDXR23vNl_K%Nu!LBWyrI-emoU-dgx1F zuaeGPOH+#k_!LTiM)tc)Y7J<?SlU`~#y?eU-Lvq|c*+#wX1eLRDB{`3-?jrV%5XAG zMRH|!`%Mm0w0`!ZuflHo@dsUL?9ebvX?%6iyxW#YO&_p)bKoOfp*hqVDAVlV!=ye; z{Tfwd5pOGtUF^}90silbz9D)`PiVarv8kWY3Uh#kpU!G6vQpq8wgebWM80n?Dr8Y^ zG?;}7AF3J$WPT@x(2d|sEk(Mrjex3+?)kiCcN;Jv?}R7Z3Qj)AxrS$Syriknb}?g2 zWTCk6;*MfvuIvL5N@bwfy99BrNSNii1#!fqxwD$#4xNI#eIJ`gODZDUppf$9g4&qR zj<E8z+dRu!1tn@dW2j*psbC5(Eevwh{KXK8w>WJ_Al?~_qvrz85knRwvkT>gSL=1# zSe+Q`%6`lwu}BQNc&QM_jog4#XW4BwW5i6&&Xj*EK)$AEc8<-Q6Cgr;;;(2_O3Gkw zxiE&etjYRw?sY(FIDtKu+S@gjk7^3%?{|8)32EoLn><2UnKp($Zin*&I4kqw2<I6% z<qNXm#a%a<0uhrnvmf&bP>e+fl3(v0#WKt+U$l~_7SS2r6DKcEf7vqdcdyj=Bb>@0 zGMh_kkwc>tauF_IdpAO(A1*MF2COA1>UV6d!=d3)TXV*gp{S;f2y%`a-kN-CSbfam znM3HmAY|QLbJDKKyrCfC%{-zi_v!AJr0BSR=gHXMxaST+v&Ff}zSL$mr2M@*QLVq} zGRwpHaF8s3SOV|cr6t|4_(o6CFmp{dXL5v0agD#JoFnn=cO(h7(8$C*Hk8N9E1Pn+ z+R+ZfF*E^cHg*=GlMTRN|3+c6BMMS#0M)TwwG(0nb9Z(b566qNT&1YKisZ>VUu&cl zqkRqxZv<U0zdYwBsO)dW5iLu6y?znc6q|C@*Q+_Oh<;sTf5*g_>DjHiqSCE5e<D_j zx2tfH`}<U6R$YmR{4W7KX6pA0Ed#^_2|pEk;72GTL8FbIyq%kRFV1=ywr9GiLZ!$@ z+Sc14RkX?{ZYgqo&r(6}%uI=eS*(TIspx$b4|;B~Udahp=Jd{Q5EAaCy(!ag$J~{! zY2w$3ZZoio&*6kH&TjyiA0CsGe84}kZfqgiE8j)e)TIF-wv;9h>&Lz`+X}$ryA}MA z%oa*Eob%252g&vIdWIfcw)6&e1$?OHg3l8q3kS+Z{S=LYZ&0sC5C_-6f}J^d3Yvb_ z*~6GWd?TF;^++-_-|!+B+ujQ`s&N0z#OGjsH!_5-q<nO{vg8zIr;;j4bv+1Q#Qtro zz7z#VcCN55+Tpgzvc|{-BV5_1GkW+Ke*WYD+@@g4`JVh4blk2MEyK+C4792039)Cp zcU(uO)o%)_v6w-!wi*3&t?wh%;Kvn$>R*Mpe|Z6A==`0ZKKGnG1D~o}1Td$?eE-)7 zSLQkt>=@F`(H48s7d7C)uXtNe?i|98c`MG{VBp&&5oCHv#%^eK-P?zSEyqH~U{tt3 z-wSh!H9z@uh<;xs30m$Pz7~tINb_(iw{6n?xV)Fvyi0Yy%F#oE95W<p&Wd$7)jVcY z?z%bC|32m@5+F+e4C`(^I~uD`cNx=7&GE-W4m4HFkMm-t-_f~GU{iFy03P7u`A}$d z22X{SF`4+Exbs>9KJoo|G`4*4QB1z=6nnXOdRDYaK7^@FqChB5C4Wf9!64M)=#C$M zXtj(<|Jl!s&g>q6=wo=o3O6o@da4qD4N3>XIiRvU@YcIjio<2jFOR?5Kp>}q0n(a3 z2h`e!v3n3{LrYVD)ZE3OFKk(Q&IW{|^le5%-BoryOWv3qZtT6Ogw^^Q2<A8^KNf1O z**?~&P(3&QLvtjWYWra-cvZsEy91|pSJh3*PMO(<5}4lw*T<0az1R76_cDviru0V} zX!3UJhT{W1i&i>@sRF6+P%sLP&srMbiz)PTeOWp*y(7uUUmEe^WcEeq6LLw4dBur) z#nopRVx4ho-Vx)&$20pMn|=IO{d}8mTYbNBx*c2Je!C+Ao6RmSEhCN^pT~CJzp<vV zq8%5=#s8mVb@b`~_SxxZ?*Af28t|B^?)7l}>jUZSZK>L?1Hdiq(M2mQ8rl<|M-~z7 zY0^JfM2Wv`g(fKeW)YvMec_bAHg_}rZ0+D+?O;jn=wSDlkm};-VQpsa`sT6XjmiJ2 zd1Mq>pP(f@Me};%YGjoDyKAqjYiq1)r>o28ch`&HPhBHjeceeq@q3ABDJf|wY-u?u zs-;RwiH6B(@j4Y~iArArf1~j_f8%|^`*gwX&Cv*Z01F!i{f}lKI{J$mAr1}}qxEO; zDn>J(-den|sQgm#o5h0tE6ejVtVDHVBV!|@TTBg8OYpT|O68e5TSj&0jo8k&`A_6R zKcwDZpkrE?a-g})=YGb$OnGZ^$!;0g#e!nD{Ip(ir}%>QD}fwN9}7mvs~XB}rDZKF zmv^307S7?H4XhnhY~s*GJ*xy<Nd~jlyPlCdJUp>`uF(?^@RrD~nj-?N{>GR5TYMh| zwsP_l^!w);nnr}e9Gn;|*ae)4{2UxFp2D7{n~fJP82hEJ1(bDn1)$5|e6l8df%oo- zH-=#x8XEeizh@pDOX_Bk1dZ?SnV(Gjd*+|3Nm<*O6SJ|K8rxZ$aB*;QxtY7VakIHN zI=Vg9qv1bNzeoRwk#%`oG+8vBzoBUBk1sQHH7QPPMF;c$?F98N#YfEce_-VP7lwHB z-!cCJ=X}Ie|7Q%-uYbpI{j(jeM~uOL#sG}}9mD-k4EJNq@3X%#Lj3>Og#Q?iYUjUW zc>amud2Hvu<cIZ$`!C7P{#P{}{;ToKkNx~F(fj{@9O%c-sC--xw5LUnTN4va=<oft zP5t+J{Nqaj@A2%5JG!`-o4Q#$I{d%iJwg$GL(!G~v8#FihHj?+2Nc`Y&e6$SK}myC z>0gSEAe(=*r}j_Ke(t}6xc>>_R(h;9{2PS!;h*Pc<{$rm{C}UH#}3Ut?zqjgzq_^- z{x~wKze_tqXlVO6f0s~%p1g@@4-d$+n0${F6&mvAw+wVSNwnC^p20P5s-7l;PA@JP zT27}c*Gq-KBjXGyj_Ry1pP1x}Y1|%k-i$fD6i#>&mttjZ)ixzvXPcj-S1ap~>g(jy z+l9eMD>4;FG0z|O@ug}iEuC@&J)_f|?{zq3LDRW$PrHyN1SoO(7aDXEgC00<BWx(k z_=p;w-ik&POuXEd88?+vQIXJo(gwhX03{nDzDFH%WM<FdgoWxgKe@yVIDHZ?*>I4W z@neFT;-JIe6`uQ8WXQ)*ubS4`b6D^B#{8k<gw88<24&)vV$`6_=!;Osd{X5N`YN1? zFHA2mrF%%QDzC+C4Jlj#)zhkM=3~lASvvJzDwlz8d2(f*HPX^j_t)Am>gvg20~@yz zoRq(utUyJSU-j^tyd$_R+j;wW<h2Nxamk`^0gaLQ3rKIe>1p^t6OHH}@ukI$X5Hmy zEUnL>s?747T(@@k%lnJtuj>iQe>7WXUt24TkMo^|PDT{0@F&e6y_@_OD7cHZFY#j$ zv`X8g4W4Fxos0e!C+F?QU54y6!GESOaJeP7ASP>5_h#sbv4p@nfOI(HM{7Cj$f7oH zneE8*sg(*-sQ0T8YWn<~%@XZb`^tWapPQH`Zm6otyE2JW>uC8#1Of!E6ubTCl}zJa zpO{5b5J=C=n@3qgt$Ur^5!tI7d3kxFx-^%v10z;3=~)w0USw`l?V|Q|_(|(sKYgro zwtj2T6R<yf)?8RPM6<E+;YpU<x8O=o)b*>TRi^7SwEOt39HM*ECsv`(BZ27SE2G89 z;IfAhj@=jddSxjw&TV0FhFbkvZ}sT~HTrhGrW&{Q_k31dysU2*)Mlx{F&rP=Cy(u4 ze67Wa#{46`=e0bU(90y-HiD18ghF-<82{=C`8bD*Tg{+n@%%avZJ^x%t-YBQ<FIaF zfIGD4y8dbNp4-*xha76roXB@VWt+UQTK2DLBHm?7jIq4NX$veDtlo}nbxUn&Kl09; zu!<j*`XoP$c~RYjR$pb;7OmQ-n)>O5m5_*E`Sxfz#Q?bMEqjJJa)wD1IK3%H9QgdX z<=PM0ut-#iy|>520;@LbOx;Z8K6JZ*E?D>soocE*dza1anRJ$wECo5{wBO@h5L+|y zb*5$C589}w40vu6-{V9?S$uE>**!DMfF<N+!5`uyT0i{0|3Z@y&_G$dt2LBi$>CpH zOpVuk7U)gYuN*qSv45dJ><uu_NDd`uO1+PIS@WhsQ9>KRMIVtY=d_GE7J22@9X}TI zCOJU)Ui*mm2TGZjxtK(MWy9%6nQD2!Ho0(Q_(p|mK7zYcVBUk$RI+!RI>vYI`BfQQ z@l^tv6-%O*5Ix4%g32F(v<?GY)<;j)tB{0DY$Y$6v*>u=xdjBjr7Himq)qegMv0qz z`^zT$HC=~x{7Yfyf<>xi*sE61E@p-2`v4+*rgtwCE5024Kkc1WP#j;o?gts%J?I37 z-~@LaG{G6%A-Dz$Hb{cIhu}WA1qjYy!C{c#fdmVd1cC+FlYIX=yH1@t_0`$C&fUK1 zs=nyzTI=ce?dSLO>Q$!zTs#cbB$~=|{W4D-aVE_7ii3*5Y4<X9m?KeLgp2U>H<qdp zeas@=GU>2he@okAxc<djiv~LWyxemXvgBOqvuc(IPWwDvpsVLAPd5VZJ^@<f5BB60 zf|#G3k#KM@%1Bp78<j)MrEIdT1gLz5oN*;Te`)Meeb4qz>hKq511rQys_2NZhaQsf zgo~0&X_CxvKokY)%B}8NEBex=sMK~C-1b5Ibv5loKWsF?yFlLq!A0kgX>+iI+Gftk zqU58w_A5>MeK&zR6)<>>f$oi~Gf`tuK!c)I_#>evGLjmP;l2wWd~dgipV*x?_8qz| z{f~7eO<|c|vR(IB*0_Ns%Z$kT1XspP5`Bou#U`NX3f{@BI3*9#xcY7_yFf`;rGSa~ z28=;SulEK_upYWKLv%Z5KP(boDz%9bh$uaYRV$^7odO9j_vOg$3h^d|^&7%I9M_%i z<Vp-~UKDv*8;)Jhn!v&Jra43+QlBo*XkJhzRvi;o5{j(<qFJt0NuSJ87b(zD<OQyD zso~^HrfmAB`zl(9d2jd-W3}InpF9a-n=dPp{ua_|F*H#-P2Ha$G@;<JW5&Xul|stN zgF}9)RJAXVEocjLb&$}}$i|S5&D%{KB1ynx+l(YPb<Xstg=3u+Q^$!x-7IWS+xgM) z7KYgq9v`60aXJ%P(~x2@icpKH0(vnDo#-WmnT+?Ezf3oYT>t!*&Aq7U_x`y@r%9)o z5Xx{knCnGjf;YSc%2X!AM2?DbSXwIj>EocQ%i$26q{J)v_vPI=`CX=P(K8)x%SVyi zC65-XC&AWjqxbl*rXJ9%OyHQoeg*DZ#Tr;A4?{{+M;X_INi2oQo)t7)rtz+}=y>Fe z`u&5Gwt8rn11|OI!{W^S5~?y^{H6Lf{lSNAdcR0fkKlJjOl903U-gE^UPVmrpk09j z8|P$Vo8g3fKAkbnlZth{UCm0x-&lOX%_@(7qDN7)e@*v9ZSj%TCfSx4iM)y>yMpr_ zPu$&1zi6h@4~QYN^*gC#ehYrKi;K<sc(u$xGH1@2AZlCoUE)*1n4vCT5w`w-r|@9g z7$yCLjUi|m6o%%VJ5g~qc~~}~4z5P2x|6vxQ_r^J=OnTbG9>#M95UMbEwVd|UDAfK zHm^6mpQ)t8XkJ_^H};lB9zo&vE~Wj!02IP=cDfWJW=^IaEa_C`I$YH;gqg*ZBsN9c zE;&6t1{v#O6yq1Mu}_)yITy2~;1|n8Cth}!#HvzP9oTZ^B|N96C$T)@ZS=}T<NW9t zjq(yAgs;yYDW6=${(vwQ{emHoL!PtGm<AEX8K?J7{a(pKp%Dk+tei~;P@qCgEQ2dN z8|2A%NN+Rwy>D7dZUaowM8rPy2{yIL8miBX7+~>1eOm*99|Zgn1dzG=ZHj4}1XTq3 zo+@oZnf+1NPsh)uq|lM!-#k0)O_r%`8|Kf{8iN{nh`TThbfu2pk+|MIi`^eby$+X^ zrXcst`kuZ^>rK1ri8-yXnd>cwpBC2H#f#bh0~SjSX;jonV9MY9Ax8(19p3v~2<S}4 zC%JLM3SNrpVJkjw6%1z6{01e5KSo3OHvJYjH3sy&=}l2|^<;?&+1TD;`<@^hTOUn! zmr=hwperBWN-1FbGx5c8D6x35<-l5t{c1$wd~QC~YlC|9*Ysv<4-BRTvRH_sOy<19 zWh2*WT6CH7UmNQ(Z#0OTTONonh;>^ZdIZW>qH$<-?=Wqj!njMNsgKk5N5q=>_!7zD zhID;TLca2=9Mefl2JwbaYk>)pMiWl#-qPe8K63~L&yjl0Yu6*%!F9OkAKFr0t#!u3 zlc*P?m+yoKY|*8P?K#8VQ-Ll&D<yw1QXrcn(^+T6Ot!taZ1WOzyN>H`Tpvyt5nMu@ zlGM@Z>O;KtcA>%ZiF#_vRW%5s#me7urA-q_8_TB;PO;$>W^-cA4;1SQg_40Nfe#P_ zL}F{l*5-VxiNxDJCsJz^x#eM$bUa7MONv)J*8Wf0j=Toi_Syw4n1FlnMC2xJs#GI= zCv+a8F3%|uULW0zu)^H0Nv{W`cox*b4SOF5W&Due6VRFWQsUvArlfAa3#-Xf*Z$1h za8oY9W;jD^d>!m`T3QDalZb;m5}m4<#@3QV|2AWm@#<<+8S0_*1QL20o{ls+X{4uf z8?}!15GUWUa#VSB@@2YdQiD61@xt7+EnO7TL_XUJ>hY;K37B$Rj#VmJ5URW~Qu)9| zl2BW!)>llvCLw1cnR_D|o@S{2w4G8wo~^Ir<02Lna6rh=Oiq((WGtj*x7O8;>&@L! z)7$;n8G$FoF~@8PH7yw5R%boYepX8gm<V$@W$rj_45Q~eWj(u>!H?0`K8B%OQL6UO zJEPvaAm&oC;S{2ia-s(vNmrM&6O8_FTQz%9xj@uwp{Yx22`%3Ek@<$e!jlheNq)fN zgVW8yU+d_uTSZ^%Qqi%w->WA#urT8u6bQRW&{mvm@Mgbg1C~AjUlN06z!@mv;W%7G zqW;Jdl_+|!&1*B{W!5#<ss7sXWq@X|>#A{@ET7s-FWqBD?SZRukB#KC1o?)lo3gy< z7gmeU(tpEO+DAEl@Uo18f%ydTKim|W)nfNaSuFHcIhB-j?om<`>&}p-L;bJyAp7f& z{#y6#=YRalzqKBJywJZ4$3fvAoAF=rOGx0-hyu_;`xkKeWo7AOX}N1{iG(j&)|Tk< zAWM78?Jdr!F<zAmTr5F6S!+~%&oF&{0X`HYUb*-OuYgS8A-fYsczAe61bFe+czLp( zjtx$QM1n-k2FwPw6yEF=narHbcDpEL`cx1qDyj!4xuX$p&y?La@7<coC55|R_;`3A zVJ&6cQqt)DJ~{MZ`7$~xs{1?4aH1smHeSKRHVH=IC{3Ys<r`475j0%f((Yc>sGmhC zC*T0|GF1yK5KcR$i{@pK5S|bY&F5D!=!QbIDOJW5^!cHB*eEPewPb{`rS3SMzB9CD zk?2DQmu0K0s$Q!-$eX;#EvzG*yp&>BM*^rI)xfEeJcy7D?;;`l;*vOfQf1XB8{vU@ zl`H6wf=Wy4A}c|4Bon4`)c1$p(2ftx6ha|Jz$TI}PHUM$g>W7u!bzLKg&eJhzIbnF z2@pRaxviFZ%qv8@Y<|jv`hzarjQ0pVH`vk|FZoSjKdmj20?83cdG>w%MCX&x-xu<& zVhE&tYnI0wCQfyfG^P6rP|SPZodqa%$B+yKl+uM!p#zpn6O<nw9$b`stStWbPx6o= z_-{ivq>{w{Y7*x!L*e`DZg>7ulLY?@CjG;akWTk2-9HliueyDt5FJqf<^PaBWB4EP z2k-ww{tEm5A%A`SZ;|9L&q6Of*EBV!;LS(0>aPHpovkHm(<j-^YztH)Q#=jXw&=Tw zoMxoRBEuLvkW$p4t)XT|f0_erWo%?@&Q^N#0!2$L3K|84erJF{GcUHknYKwgOsxb- zA>23n`T*8wb}eC@=wVcNwAl&$fMIYsQi%fn6gVXi2zFC43VY0IlaRv{qY(xHFuDI1 zgDkV}R@izI=Kyl{uj1Lq!{jap`T^U?ck^tkA5kY8468HaZkb7YLJyl4X)RTb3&van zjkvil`ruRz@>KY<QHtV7!Y9yx8i9o+%O8#!Y1wtB+FU~#mUm|*9D*Cx((U5!juy?p zV1r*y+H(r@g8nceU<NqewsgQK!mg@r6T-*_?{PXx2xWcH+=Eb~r&8Af0V=DQxK&($ zS?FsH%N0lmjmC!`Kg0L$ezh&hKE(q7cx3#C9v<#E|4cJ#!GD&XKj`A$l^y^9d4d0- zhR8AaA8Kgv|EmK1cc|h2I{-u$A1)Mt-ao|$$MR1X+_w3@bwPrE+XZD))G(fbs_+c( z$*eJ~7h~bE6V@nS5vhv6&AGf(ji~VA-(5b10^}GJ7#PE$mP5viarNGxkO9B*&kL<y zWLAL|jh{Y?ngf7aZh=s3tmX*t@Nz82qqMo|(T%16>2TLif7%fj+8f}g|1BYiM8c!b z&4}D;oLVbLIo+<$G6>~o$K6QXYe3=Kqx$9bg?wM`e(0b&DH%Hf=O=d>=s7foUzS8J zLToe=4J`u1C)-aEVT}oFkl3e=fZnxfipUE5diAKU$TBo&whRq)&+=v&2)b!&dxMsY zVMPQ0tR$K<0RTjpf9i+OyT8;__D`GmhV!rbq2cK5gQx4`WoPAT=cVdq?@prV{?Zy5 z`nWi{IosJH58gh=LGK|1yc0scdK{aWxX>;<x|jNOlM5I1<UwD-Lm?UAze0twCO7!f zDu5{aXgpF`ZM!6Fo_9$!=j2?lL^c2sI)%lB#p&|;F<A!NMHx2(q=YGf0aYu~dirHO zEjkNxls9t*P7Euj4-US*_TA2>oltXx&E(7Jywl!y55M<hMpRcWg;^?Nw8*53&Y7zY zB0>vGS*5^BUY*_u0hfW*%St9yMBL#IIq!K*M6NiL`q9lTn2`JPDl4LsaWg-!NAys1 zg(TE3B{zb%JviN7nk5E@KbwDY;rdt*5&x6JsXxFFOIgvCqoul{n;!9W{xFU0dAXj+ z#?}Zw?UT&R#@R8ZN)+m`IFyLz^SM_0Nc8wq7d046CT_)7ASIpaWbZRBh_CAx{eo;n zm{v%g2A2e&T8yjY6bM-2(D4Y-@j$RYgQW;`*YxlJeq2GR`v9bxgcLDT+ky4S%~O{p z5&EehscTq{Rm=E|anj+Eho&rdkNI~r%Bbh6#k}xHmZs<2UzPMRI4V8luBh;!(UpUu zb~#x%H?!YeQJw$;664&YoZ7Z3jf|huwRSmlG0$qGq#KzQJO=K~hc8nqX;9ge@44j* zOOeNp+3PLMcZI`vmY=<j?({^U4WXKH-k^3dqppz@%ZeXYX-`Yo8;eVQ-zXB9WmP|8 zKWs(^KVeyp$KjHzG>cBE4t7}PI`pAl+qIH#mUw5hR^`|;L|B6+?UWgbJi%2c&d=Ii zR&!$09u)W5U37Tfe)#PLKgCsB2p$&95j>l9zeqh-z}IXPc!hbu@f7!9ex#D{0Qswq zGG4Di!a&fScj?xFBmcW~&jatbjCXEme$^Pg?=i>`*vy>K0HI3E%vqR{g)(n!d|T8+ zpS;8;`6TBl+PwMA5U*8rbl^_h{8hN?d5juIhReA%sLZjB06e<k2Xe`dUVIb+W2{KH z@8)G*Xc4$!tVX!2<^Z@4J#2b<B3TEFDGP<zIXw92w(=eWpL2ZX++F^FTE{v$9%zV- zaj8f}Y3TU~o5|Uk{#;ImD^_}6VRock%Vh@4_;SKW%J}9x?&hwr_O+{?eME4H4tb^K z+KP3`zIa`L)9@#v;#0y^=3@LR)jN{&<RQx!D~sIzocjjGOXbbm;^CKv`^#1c^VW1_ zWt0cUS%<ISfseJ1xuRiVWfmbecb;yN0ZjgfY8j7iT&@ik%FU){=kmo9&SW(mgqG|k z7Sv)Y?6sE8CyO`DHc0Z_5`U0Il`Vya{FbDCjd(jlSK6y#$XSK3u-Ez=_(M0wV4|2o z=tU{utY&#IKN&k*U)85+NItrF<@MpDaxI`YX}eNHv4iZKDlMH^+qmx}Cc@J~yH?)K z*pKSj^r0ABfoBbH8_{<K7%MjRoX{NIC%}Jc#vS{*b5}`0>M?yyo!G@FUodhlpG3=I zY;{^??8*EEq|82Yka_lJr3c*-(17`CWQ2lMT%^J8!d4leSbw#Kp^yuBK`+ySHJW`v z8fp4jP*)?82zDTi>0EUjG14aIs-nEiS8jV#?ATVcvy*7O)dA5&6}b5u$*zKPreWz6 z%rZQO7O&wuCcFi|i(HRA*0}4?DArN;s=k&}Jqig#_3IRV3OpX<WOmDC3;BpkeZzXM zmFwB^h;1%V_}dA$$xe%7NATdzD-6ABrDK{$n<XbwLjGRnep~gFkb&Qhbgy%my=)p! zRYRMgmkz4^p9)IgWUEepa)(vHvL8y5`)(`zKl9POF=O@}M4d7foyZtiW{+cAq$9rJ z@KpeJ&)M+3l`W@!tMg3*ow$-w^If!e`YWj=68I;@9I5I~)<20zK7ERCA0MPY$ezzF zDR&UUq{mo)3Y%W8QD71Es4`z+6%)uD8*D~F;o%rd1^a{4WHCuWR^RBPd*HPqI3dDe zy`VFP$Oi~u#f`Rc3*hs9Pw^A%#vRK$@o#Lw@E(`yI!ZsDe9o@eM#&{V@=>|TDEE1} z%k%N-v?$sSXTbHmoC`<|K9n4_ftEv6V>Yt!Rf(7D&wgcJ_{^F*P;q%?Hy8T(B67S1 zP(Zqsy@VS^DKZikEPNZVJ3~}p0HAz#vO)f}d412@)7DwPYnT|8FreTG-`UUUkav6K zp}*JaB9}#wHocNR@+bl0Qw=7fB}nTb5KY!F!!^ruz}Jfu3&ph}%e}QGz-Xu4Q0R+Y ziA#^^P(_k)UX^@9;noq&kDm5+!qrR%$~?N%1sy4q$!s@i8295ZDGXcLyBA!3MGB$@ zF>R$Op0bmaj`MpStt$Ni26)#!>>e;EPbXi~{2QetxxKH6x~+sl;qgRDI@)`{PYh!= zf(^nuw)tgif^pYzQadmDGAJi@*c0{r@zTss4N@+5+8hJ2i^31~BEx`I!HgdREBLh= zY{Pdpf|rW6a5IA_&>QjM=cb(spleChMvq#z4hh~k6Mo*3Hg9hE*i|FL5m76emK))k z#c#lexBj`^&&;E~^Pahp9B>guateoo99!&k&IXSmthL;LwGd(XAu)24_sylxaLqtg zSR=7VzUjl!AqbZQFXrzrQ%N>C)v)s04O|JvJ+aNYj};arQv0wmGl(PEGRu6Iicp;| zdReg?raG@%hCyAx33IIBH@Vl{20Q2@Wi%fLC1m7vF2Kbwf+K7jP6y++#M{+@_R6f` zuMY|<05~f6`2Gv2a^!+jRe5dgWy#Yv1d#B-wIIzG(MfP@a}bN_mk}^I|2Ww=%nwgc z10$l&-xbQ1Cz&a-|EshaylxI$L|3mBNjHNpp}|6;>`+T8bGFr}MnDakELFAS4hxV< zeSsY&6H__`eT>~L{V&5E)11f$=9lhQ$W2CAEv1Soi5c<xI|#zHevm}@8N(%b#A=mV zk;{Ubi#Xj<Ie{w*{Yf6bhm_f1-s)CR_(`_o2^o#&C>h~Wb=k{_wq}wOiU@6&lyv44 zCIs9*+Dv{D{SE%ciRa|JAGS2>Z-4&6!#GSt(OtwKQ^f5hY>)}_q~o#=nL8-|$sM{k zQINTVTasESer&$7O9NC8I^k?Uj}lRD;Jf;+3jEYBv-cbLEBsgSX^BW|l6jB7W4FMj z2k6oa53TMvgEoU(=hycQCMoQ1d9!$sFB#@oEde=Xk^zjp-`S6&djxj74j73%E;H8+ zub!2wE8Hzg9h#F1z7KIm7g^*Z?7#5KaFJC~t`z0fTcay0p0}JzCU1Git-^0bjm6=W zt4^W*ls+$r)WD<GXrPsZsV~lnYZtvUC;{8j4~wcgLHkf)4y}}YksdD0N~GvZ^MB+H z?mzaH_)ScO*4Ksm58MuX7tpD2=^G1&gr|t-F%r`k<I{1`E7MZH*gheA-&jTIcXqzU zzn=Tu{#COV@lKz*&>K6Vws>U-Oqe0&6XUH&&BvSYBW~Q(+L`B+!qM&3hvLDC6uZNz zeD3VVF7Ms|aqi*2M55Xl24S1`FeUC+J5nYy%l9Htzj`V7!mWa|$SzejNiW-l;Lva1 zu;@5k^)?=a^xzCZ*bIF#b3Zfgwewg)!iwf!nmV(3-F<zRKw`$*D3Pmxlf%ZY2j(b? zCoL@7nJp&T<Y$Fv>2AHK5EJ6pSQY5K#ywfp%E(fY^Bq}KYYO;c+mn1o(q!f|oW{|; zE6YxRaD4tf88YhR=RuMOR#*dPLi85)O=uz1?UKn$w$f4V20Se0D`_uPjvo$AjR&}5 zw4qe6j^gaop9=TKBS%2R&-1?hAFtFONeYPP3YDOh6}9*BAc6TUN6f7|`ZgunLr6yU zj#486T%5ULoj1z6VVEfSBTvjDAip4`F*QKRi&4h8{7>{CDG--Us~(PZw8RiuqxLs? zxV<4Dz~=jv1$i`yLSFV19wuIs`<jzX{_&_@dWaJjtruF(M2v<{iYgaPlwDGntz>l^ zaGo&}$LT3^SQKE90<!6NRFB-80)8T3uUz2iBa`I3#cH$XuiQql?}UA`jDx~DQzu-1 z$`JuR4r4jyb^Bg3ldY)fu@PI+gNUc|kY>trW;|QY-gKl@rqGyMG*MIK$mCsQ318}S zs;uZXDV^NZBnj386_Ag<DH%9<O23rHlxQPyvSqYy;yqPmMWU5;Sq6fH=xd`r$yBNK zgwI2yE9r1YuOw;7WGS2E<Tr(iPOE1wU!?a4m!Gyf9-AoB3J^8i*W~QvnG#hz(5NCP zveNeVxTOO~EO1M&QdMRxu4B0+S>TXckb>}O^y@pyA~bB)34G@^?tM{OIayd1szMUa z$pazJ6A-$SVI0Y`R(Du7r$S`WyLpKZzQ4mQn5&MTS0-gw9}{Nq>x*!DXk0KP&(^dh z-)Oby7Be_Zto4cNa8W$})Nz|J3~F`1+B!44a+IYL6J-?X%yM(FHGV1nO(Jz8`fXxh z*^ShXYS{*7nvM}oJLV8XgEIW2J_N+HPb{R1(lrF=Amj~ao~ABNew}Qf=><?V2zBR) z+R5ytqFr@04VCm}*_vQt8N=1!79DBpmo-!w97+}M`Uu^^-WcW&5X?C`n57gexArbp z-maoV`|Y5L;w5*Mq?pi3C;d!VnJ_aWn_rzdQa-aal<V9|<2$T*`5Wcn+eW)Ao3?j* zQ$bN=c@<HW%U<dOqNu*^Q4032#49p&eC-|sdJd-1E1)Izj)cF0E=!bOS;C4|RY`(n zsHisBfY05r=qQT^R4p$w{StXgm|A{(Sm;qTGZgftj+qA`m&=fuun=8;Pzka1w@HZ& z=H13Q*{kcJ9Es)EhPjMYEB$H>J6cjz&76yB^l^rHW=o6%_9=kF%1;AGp9w1fBT6v_ zGjs~#)y@~fS}3Dh;uvR_)vD3CjHkNsTZT%io->LDbf`pp05SQX=D}PN!n8rA-V1h! zNYA_@u=CnV=7`twG|z_^9&B!J#@ywQxluLeh8{XP5x)A5jLmj~#k-<)yRI5rRlWyX z5A(?o@`WDyu+R)L$!^B2=StjkF{&=mdD_Ud{M*9N>3*(outvG9FmWkzbKIRE-Zr$0 zet$`P80O*0lMexgGgIBK{F;JAWNG|gbau1L$<K3>FuUN5$=_4}R|!U{V5j4(xvr=O zp-N`xSm&O0VTFaLxab7=bvwC_pLJf1LmEvf>s#Ei9z(e6tLj}%oSzWIZ*z83wWYIL z{r;0Yr2I)97SuV2XW=z;Pi|sbJyUeAE!1W-4th;M%%}E}PgIMi$%3_A>&VDep<8~% z!$zj>)g#DhmaU}jcTv19gTHbI4Qvx`3mQ`tWWZ%2SnEr+E6z?8a*BKX7&}`iSM@jS bukd_$L4qmZaz-kGN@xbl4I57M;?jQrH*CJz literal 0 HcmV?d00001 diff --git a/Reconstruction/tauRec/share/LCTES_Fits_May2011.root b/Reconstruction/tauRec/share/LCTES_Fits_May2011.root new file mode 100644 index 0000000000000000000000000000000000000000..63a0d6805f4de9ebe5fe2e176b15256eac873edc GIT binary patch literal 9042 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 literal 0 HcmV?d00001 diff --git a/Reconstruction/tauRec/share/Pi0ClusterMaker_Bonn_jobOptions.py b/Reconstruction/tauRec/share/Pi0ClusterMaker_Bonn_jobOptions.py new file mode 100644 index 00000000000..f49fb74a0b5 --- /dev/null +++ b/Reconstruction/tauRec/share/Pi0ClusterMaker_Bonn_jobOptions.py @@ -0,0 +1,292 @@ +################################################################################ +## +#@file Pi0ClusterMaker_Bonn_jobOptions.py +# +#@brief jobOption to create clusters for the "Bonn" Pi0 Finder. +# +# Use cell container created by TauRecCoreBuilder as an input. +# Most settings copied from /Calorimeter/CaloRec/python/CaloClusterTopoGetter.py +################################################################################ + +from CaloUtils.CaloUtilsConf import CaloLCClassificationTool, CaloLCWeightTool, CaloLCOutOfClusterTool, CaloLCDeadMaterialTool + +from CaloClusterCorrection.CaloClusterCorrectionConf import CaloClusterLocalCalib +#>> new PL May 4, 2009 +from CaloClusterCorrection.CaloClusterCorrectionConf import CaloClusterCellWeightCalib +#<< + +from CaloRec.CaloRecConf import CaloTopoClusterMaker, CaloTopoClusterSplitter, CaloClusterMomentsMaker, CaloClusterMaker +from CaloRec.CaloTopoClusterFlags import jobproperties +from AthenaCommon.SystemOfUnits import deg, GeV, MeV +from AthenaCommon.GlobalFlags import globalflags + + +from CaloTools.CaloNoiseToolDefault import CaloNoiseToolDefault +theCaloNoiseTool = CaloNoiseToolDefault() + +# configure cell weight calibration +if jobproperties.CaloTopoClusterFlags.doCellWeightCalib(): + from CaloClusterCorrection.CaloClusterCorrectionConf import H1WeightToolCSC12Generic + from CaloClusterCorrection.StandardCellWeightCalib import H1Calibration, getCellWeightTool + CellWeights = CaloClusterCellWeightCalib("CellWeights") + # -- configure weight tool + finder = jobproperties.CaloTopoClusterFlags.cellWeightRefFinder.get_Value() + size = jobproperties.CaloTopoClusterFlags.cellWeightRefSize.get_Value() + signal = jobproperties.CaloTopoClusterFlags.cellWeightRefSignal.get_Value() + WeightTool = getCellWeightTool(finder,size,signal) + # -- connect weight tool + CellWeights.CellSignalWeightTool = WeightTool + CellWeights += WeightTool + #-- default properties + CellWeights.Direction = "AbsSignal" #-- use absolute cell energies for eta/phi calculation + CellWeights.BelowThresholdLikeAll = True #-- treat clusters below thresholds the same as all others + CellWeights.BelowThresholdDirection = "AbsSignal" #-- alternative direction calculation for below threshold clusters, + # ignored if BelowThresholdLikeAll = True + CellWeights.EnergyThreshold = 0.0*MeV #-- threshold for possible change of direction calculation + CellWeights.IgnoreGeoWeights = False #-- ignore geometrical cell signal weights if True + +# now configure local hadronic calibration +if jobproperties.CaloTopoClusterFlags.doTopoClusterLocalCalib(): + # tools used by tools + # EMFrac = EMFracClusterClassificationTool("EMFrac") + # EMFrac.ClassificationKey = "EMFracClassify" + # EMFrac.UseEMFractionSpread = False + # EMFrac.MaxEMFraction = 0.5 + # + # H1Weight = H1ClusterCellWeightTool("H1Weight") + # H1Weight.CorrectionKey = "H1ClusterCellWeights" + # H1Weight.SignalOverNoiseCut = 2.0 + # H1Weight.CaloNoiseTool = theCaloNoiseTool + # + # OOCC = OutOfClusterCorrectionTool("OOCC") + # OOCC.CorrectionKey = "OOCCorrection" + # + # OOCCPi0 = OutOfClusterCorrectionTool("OOCCPi0") + # OOCCPi0.CorrectionKey = "OOCPi0Correction" + + # tools used by tools + LCClassify = CaloLCClassificationTool("LCClassify") + LCClassify.ClassificationKey = "EMFracClassify" + LCClassify.UseSpread = False + LCClassify.MaxProbability = 0.5 + LCClassify.StoreClassificationProbabilityInAOD = True + + LCWeight = CaloLCWeightTool("LCWeight") + LCWeight.CorrectionKey = "H1ClusterCellWeights" + LCWeight.SignalOverNoiseCut = 2.0 + LCWeight.CaloNoiseTool = theCaloNoiseTool + LCWeight.UseHadProbability = True + + LCOut = CaloLCOutOfClusterTool("LCOut") + LCOut.CorrectionKey = "OOCCorrection" + LCOut.UseEmProbability = False + LCOut.UseHadProbability = True + + LCOutPi0 = CaloLCOutOfClusterTool("LCOutPi0") + LCOutPi0.CorrectionKey = "OOCPi0Correction" + LCOutPi0.UseEmProbability = True + LCOutPi0.UseHadProbability = False + + #DMTool = DeadMaterialCorrectionTool2("DMTool") + #DMTool.HadDMCoeffKey = "HadDMCoeff2" + #DMTool.SignalOverNoiseCut = 1.0 + #DMTool.ClusterRecoStatus = 0 + #DMTool.WeightModeDM = 2 + #DMTool.CaloNoiseTool = theCaloNoiseTool + + LCDeadMaterial = CaloLCDeadMaterialTool("LCDeadMaterial") + LCDeadMaterial.HadDMCoeffKey = "HadDMCoeff2" + LCDeadMaterial.ClusterRecoStatus = 0 + LCDeadMaterial.WeightModeDM = 2 + LCDeadMaterial.UseHadProbability = True + + # correction tools using tools + LocalCalib = CaloClusterLocalCalib ("LocalCalibForTaus") + LocalCalib.ClusterClassificationTool = [LCClassify] + #LocalCalib.ClusterRecoStatus = [2] + LocalCalib.ClusterRecoStatus = [1,2] + LocalCalib.LocalCalibTools = [LCWeight] + + LocalCalib += LCClassify + LocalCalib += LCWeight + + OOCCalib = CaloClusterLocalCalib ("OOCCalibForTaus") + #OOCCalib.ClusterRecoStatus = [2] + OOCCalib.ClusterRecoStatus = [1,2] + OOCCalib.LocalCalibTools = [LCOut] + + OOCCalib += LCOut + + OOCPi0Calib = CaloClusterLocalCalib ("OOCPi0CalibForTaus") + #OOCPi0Calib.ClusterRecoStatus = [1] + OOCPi0Calib.ClusterRecoStatus = [1,2] + OOCPi0Calib.LocalCalibTools = [LCOutPi0] + + OOCPi0Calib += LCOutPi0 + + DMCalib = CaloClusterLocalCalib ("DMCalibForTaus") + DMCalib.ClusterRecoStatus = [1,2] + #DMCalib.LocalCalibToolNames = [DMTool.getFullName()] + #DMCalib += DMTool + DMCalib.LocalCalibTools = [LCDeadMaterial] + + DMCalib += LCDeadMaterial + +TopoClusterForTaus = CaloTopoClusterMaker("TauPi0TopoClusterMaker") + +TopoClusterForTaus.CellsName = "TauCommonPi0CellContainer" +TopoClusterForTaus.CalorimeterNames=["LAREM"] +TopoClusterForTaus.SeedSamplingNames = [ + "PreSamplerB", "EMB1", "EMB2", + "PreSamplerE", "EME1", "EME2" + ] +TopoClusterForTaus.CaloNoiseTool = theCaloNoiseTool +TopoClusterForTaus.UseCaloNoiseTool = True +TopoClusterForTaus.UsePileUpNoise = True +TopoClusterForTaus.NeighborOption = "super3D" +TopoClusterForTaus.RestrictHECIWandFCalNeighbors = False +TopoClusterForTaus.CellThresholdOnEorAbsEinSigma = 0.0 +TopoClusterForTaus.NeighborThresholdOnEorAbsEinSigma = 2.0 +TopoClusterForTaus.SeedThresholdOnEorAbsEinSigma = 4.0 +TopoClusterForTaus.SeedCutsInAbsE = True +TopoClusterForTaus.ClusterEtorAbsEtCut = 0.5*GeV +TopoClusterForTaus.TwoGaussianNoise = jobproperties.CaloTopoClusterFlags.doTwoGaussianNoise() + + +TopoSplitterForTaus = CaloTopoClusterSplitter("TauPi0TopoSplitter") +# cells from the following samplings will be able to form local +# maxima. The excluded samplings are PreSamplerB, EMB1, +# PreSamplerE, EME1, all Tile samplings, all HEC samplings and the +# two rear FCal samplings. +TopoSplitterForTaus.SamplingNames = ["EMB2","EME2"] +# cells from the following samplings will also be able to form +# local maxima but only if they are not overlapping in eta and phi +# with local maxima in previous samplings from the primary list. +TopoSplitterForTaus.SecondarySamplingNames = ["EMB1","EME1"] +TopoSplitterForTaus.ShareBorderCells = True +TopoSplitterForTaus.RestrictHECIWandFCalNeighbors = False + +TopoMomentsForTaus = CaloClusterMomentsMaker ("TauPi0TopoMoments") +TopoMomentsForTaus.MaxAxisAngle = 30*deg +TopoMomentsForTaus.OutputLevel = INFO +TopoMomentsForTaus.MomentsNames = [ + "FIRST_PHI" + ,"FIRST_ETA" + ,"SECOND_R" + ,"SECOND_LAMBDA" + ,"DELTA_PHI" + ,"DELTA_THETA" + ,"DELTA_ALPHA" + ,"CENTER_X" + ,"CENTER_Y" + ,"CENTER_Z" + ,"CENTER_MAG" + ,"CENTER_LAMBDA" + ,"LATERAL" + ,"LONGITUDINAL" + ,"ENG_FRAC_EM" + ,"ENG_FRAC_MAX" + ,"ENG_FRAC_CORE" + ,"FIRST_ENG_DENS" + ,"SECOND_ENG_DENS" + ,"ISOLATION" + ] + +#TopoMomentsForTaus.AODMomentsNames = [ +# "FIRST_ETA" +# ,"SECOND_R" +# ,"SECOND_LAMBDA" +# ,"DELTA_PHI" +# ,"DELTA_THETA" +# ,"CENTER_MAG" +# ,"CENTER_LAMBDA" +# ,"LATERAL" +# ,"LONGITUDINAL" +# ,"ENG_FRAC_EM" +# ,"ENG_FRAC_MAX" +# ,"ENG_FRAC_CORE" +# ,"FIRST_ENG_DENS" +# ,"SECOND_ENG_DENS" +# ,"ISOLATION" +# ] + +#if jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingEnergies() or jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingVariables(): +# LockVariables = CaloClusterLockVars("LockVariables") +# LockVariables.FixBasicEnergy = True +# LockVariables.LockedSamplingVariables = [] +# if jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingEnergies(): +# LockVariables.LockedSamplingVariables += [ +# "Energy", "Max_Energy"] +# if jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingVariables(): +# LockVariables.LockedSamplingVariables += [ +# "Eta", "Phi", "Delta_Eta", +# "Delta_Phi", "Max_Eta", "Max_Phi" +# ] +# +#if jobproperties.CaloTopoClusterFlags.printTopoClusters(): +# PrintCaloCluster = CaloClusterPrinter("PrintCaloCluster") +# PrintCaloCluster.PrintFirstOnly = True +# PrintCaloCluster.PrintFrequency = 1 +# PrintCaloCluster.EnergyUnit = 1.0*GeV + +cluster_container = 'TauPi0SubtractedClusterContainer' +CaloTopoForTausMaker = CaloClusterMaker ("TauPi0BonnSubtractedClusterMaker") +CaloTopoForTausMaker.ClustersOutputName=cluster_container +CaloTopoForTausMaker.ClusterMakerTools=[ + TopoClusterForTaus.getFullName(), + TopoSplitterForTaus.getFullName()] +CaloTopoForTausMaker.ClusterCorrectionTools = [ + TopoMomentsForTaus.getFullName()] + +CaloTopoForTausMaker += TopoClusterForTaus +CaloTopoForTausMaker += TopoSplitterForTaus +CaloTopoForTausMaker += TopoMomentsForTaus + +#if jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingEnergies() or jobproperties.CaloTopoClusterFlags.lockTopoClusterSamplingVariables(): +# CaloTopoForTausMaker.ClusterCorrectionTools += [ +# LockVariables.getFullName()] +# CaloTopoForTausMaker += LockVariables + +if jobproperties.CaloTopoClusterFlags.doCellWeightCalib(): + CaloTopoForTausMaker.ClusterCorrectionTools += [ + CellWeights.getFullName() ] + CaloTopoForTausMaker += CellWeights + +if jobproperties.CaloTopoClusterFlags.doTopoClusterLocalCalib(): + CaloTopoForTausMaker.ClusterCorrectionTools += [ + LocalCalib.getFullName(), + OOCCalib.getFullName(), + OOCPi0Calib.getFullName(), + DMCalib.getFullName()] + CaloTopoForTausMaker.KeepCorrectionToolAndContainerNames += [ + LocalCalib.getFullName(),"CaloTopoForTausMaker"] + # CaloTopoForTausMaker.KeepEachCorrection=True + CaloTopoForTausMaker += LocalCalib + CaloTopoForTausMaker += OOCCalib + CaloTopoForTausMaker += OOCPi0Calib + CaloTopoForTausMaker += DMCalib + +#if jobproperties.CaloTopoClusterFlags.printTopoClusters(): +# CaloTopoForTausMaker.ClusterCorrectionTools += [ +# PrintCaloCluster.getFullName()] +# CaloTopoForTausMaker += PrintCaloCluster + +# +# pool/cool part +# +if jobproperties.CaloTopoClusterFlags.doTopoClusterLocalCalib(): + from CaloRec import CaloClusterTopoCoolFolder + if globalflags.DetDescrVersion().startswith("Rome"): + CaloTopoForTausMaker.LocalCalibForTaus.LCClassify.MaxProbability = 0.85 + CaloTopoForTausMaker.LocalCalibForTaus.LCClassify.UseNormalizedEnergyDensity = False + else: + CaloTopoForTausMaker.LocalCalibForTaus.LCClassify.MaxProbability = 0.50 + CaloTopoForTausMaker.LocalCalibForTaus.LCClassify.UseNormalizedEnergyDensity = True + +#CaloCell2TopoClusterForTausMapper = CaloCell2ClusterMapper("CaloCell2Pi0ClusterForTausMapper") +#CaloCell2TopoClusterForTausMapper.ClustersName = cluster_container +#CaloCell2TopoClusterForTausMapper.MapOutputName = "CaloCell2Pi0ClusterForTaus" + +topSequence += CaloTopoForTausMaker +#topSequence += CaloCell2TopoClusterForTausMapper + diff --git a/Reconstruction/tauRec/share/Pi0ClusterMaker_Crakow_jobOptions.py b/Reconstruction/tauRec/share/Pi0ClusterMaker_Crakow_jobOptions.py new file mode 100644 index 00000000000..d6ab9bd268f --- /dev/null +++ b/Reconstruction/tauRec/share/Pi0ClusterMaker_Crakow_jobOptions.py @@ -0,0 +1,106 @@ +################################################################################ +## +#@file Pi0ClusterMaker_Crakow_jobOptions.py +# +#@brief jobOption to create clusters for the "Crakow" Pi0 Finder. +# +# Use cell container created by TauRecCoreBuilder as an input. +################################################################################ +from CaloRec.CaloRecConf import CaloTopoClusterMaker, CaloTopoClusterSplitter, CaloClusterMomentsMaker, CaloClusterMaker, CaloCell2ClusterMapper +from CaloRec.CaloTopoClusterFlags import jobproperties +from AthenaCommon.SystemOfUnits import deg, GeV, MeV +from AthenaCommon.AlgSequence import AlgSequence +from AthenaCommon.GlobalFlags import globalflags + + +from CaloTools.CaloNoiseToolDefault import CaloNoiseToolDefault +theCaloNoiseTool = CaloNoiseToolDefault() +from AthenaCommon.AppMgr import ToolSvc +ToolSvc += theCaloNoiseTool + +TopoClusterForTaus = CaloTopoClusterMaker("TopoClusterForTaus") + +TopoClusterForTaus.CellsNames = ["TauCells"] +#TopoClusterForTaus.OutputLevel=2 +TopoClusterForTaus.CalorimeterNames=["LAREM"] +TopoClusterForTaus.SeedSamplingNames = [ + "PreSamplerB", "EMB1", "EMB2", + "PreSamplerE", "EME1", "EME2" + ] +TopoClusterForTaus.CaloNoiseTool=theCaloNoiseTool +TopoClusterForTaus.UseCaloNoiseTool=True +TopoClusterForTaus.UsePileUpNoise=True +TopoClusterForTaus.NeighborOption = "super3D" +TopoClusterForTaus.RestrictHECIWandFCalNeighbors = False +TopoClusterForTaus.CellThresholdOnEorAbsEinSigma = 0.0 +TopoClusterForTaus.NeighborThresholdOnEorAbsEinSigma = 2.0 +TopoClusterForTaus.SeedThresholdOnEorAbsEinSigma = 4.0 +TopoClusterForTaus.SeedCutsInAbsE = True +TopoClusterForTaus.ClusterEtorAbsEtCut = 1*GeV + + +TopoSplitterForTaus = CaloTopoClusterSplitter("TopoSplitterForTaus") +# cells from the following samplings will be able to form local +# maxima. The excluded samplings are PreSamplerB, EMB1, +# PreSamplerE, EME1, all Tile samplings, all HEC samplings and the +# two rear FCal samplings. +# +#TopoSplitterForTaus.OutputLevel=2 +TopoSplitterForTaus.SamplingNames = ["EMB2","EME2"] +# cells from the following samplings will also be able to form +# local maxima but only if they are not overlapping in eta and phi +# with local maxima in previous samplings from the primary list. +# +TopoSplitterForTaus.SecondarySamplingNames = ["EMB1","EME1"] +TopoSplitterForTaus.ShareBorderCells = True +TopoSplitterForTaus.RestrictHECIWandFCalNeighbors = False + +TopoMomentsForTaus = CaloClusterMomentsMaker ("TopoMomentsForTaus") +TopoMomentsForTaus.MaxAxisAngle = 30*deg +TopoMomentsForTaus.OutputLevel = INFO +TopoMomentsForTaus.MomentsNames = [ + "FIRST_PHI" + ,"FIRST_ETA" + ,"SECOND_R" + ,"SECOND_LAMBDA" + ,"DELTA_PHI" + ,"DELTA_THETA" + ,"DELTA_ALPHA" + ,"CENTER_X" + ,"CENTER_Y" + ,"CENTER_Z" + ,"CENTER_LAMBDA" + ,"LATERAL" + ,"LONGITUDINAL" + ,"FIRST_ENG_DENS" + ,"ENG_FRAC_EM" + ,"ENG_FRAC_MAX" + ,"ENG_FRAC_CORE" + ,"FIRST_ENG_DENS" + ,"SECOND_ENG_DENS" +] + + +CaloTopoForTausMaker = CaloClusterMaker ("CaloTopoForTausMaker") +CaloTopoForTausMaker.ClustersOutputName="EMTopoForTaus" +CaloTopoForTausMaker.ClusterMakerTools=[ + TopoClusterForTaus.getFullName(), + TopoSplitterForTaus.getFullName()] +CaloTopoForTausMaker.ClusterCorrectionTools = [ + TopoMomentsForTaus.getFullName()] + +CaloTopoForTausMaker += TopoClusterForTaus +CaloTopoForTausMaker += TopoSplitterForTaus +CaloTopoForTausMaker += TopoMomentsForTaus + +CaloCell2TopoClusterForTausMapper = CaloCell2ClusterMapper("CaloCell2TopoClusterForTausMapper") +CaloCell2TopoClusterForTausMapper.ClustersName = "EMTopoForTaus" +CaloCell2TopoClusterForTausMapper.MapOutputName = "CaloCell2TopoClusterForTaus" + + +topSequence += CaloTopoForTausMaker +topSequence += CaloCell2TopoClusterForTausMapper + + + + diff --git a/Reconstruction/tauRec/share/TauAODList.py b/Reconstruction/tauRec/share/TauAODList.py new file mode 100644 index 00000000000..b6bd7ee829c --- /dev/null +++ b/Reconstruction/tauRec/share/TauAODList.py @@ -0,0 +1,86 @@ +################################################################################ +## +#@file TauAODList.py +# +#@brief List AOD output containers. +################################################################################ + +#------------------------------------------------------------------------------ +# AOD output list +#------------------------------------------------------------------------------ +TauAODList = [] + +#------------------------------------------------------------------------------ +# Tau1P3P cell cluster +#------------------------------------------------------------------------------ +#TauAODList += [ "CaloClusterContainer#Tau1P3PCellCluster" ] + +#------------------------------------------------------------------------------ +# TauRec cell cluster +#------------------------------------------------------------------------------ +#TauAODList += [ "CaloClusterContainer#TauRecCellCluster" ] + +#------------------------------------------------------------------------------ +# Tau1P3P Pi0 cluster +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::CaloClusterContainer_v1#TauPi0ClusterContainer" ] +TauAODList += [ "xAOD::CaloClusterAuxContainer_v1#TauPi0ClusterContainerAux." ] + +#------------------------------------------------------------------------------ +# Tau1P3P cell EM012 cluster +#------------------------------------------------------------------------------ +#TauAODList += [ "CaloClusterContainer#Tau1P3PCellEM012ClusterContainer" ] + +#------------------------------------------------------------------------------ +# Tau1P3P main containers +#------------------------------------------------------------------------------ +#TauAODList += [ "Analysis::TauJetContainer#Tau1P3PContainer" ] +#TauAODList += [ "Analysis::TauDetailsContainer#Tau1P3PDetailsContainer" ] + +#------------------------------------------------------------------------------ +# TauRec main containers +#------------------------------------------------------------------------------ +#TauAODList += [ "Analysis::TauJetContainer#TauRecContainer" ] +#TauAODList += [ "Analysis::TauDetailsContainer#TauRecDetailsContainer" ] +#TauAODList += [ "Analysis::TauDetailsContainer#TauPi0CandidateDetailsContainer" ] + +#------------------------------------------------------------------------------ +# TauRec main xAOD containers +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::TauJetContainer_v1#TauRecContainer" ] +TauAODList += [ "xAOD::TauJetAuxContainer_v1#TauRecContainerAux." ] + +#------------------------------------------------------------------------------ +# Secondary Vertex for Tau Decay +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::VertexContainer_v1#TauSecondaryVertexContainer" ] +TauAODList += [ "xAOD::VertexAuxContainer_v1#TauSecondaryVertexContainerAux.-vxTrackAtVertex" ] + +#------------------------------------------------------------------------------ +# Shot PFOs +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::PFOContainer_v1#TauShotPFOContainer" ] +TauAODList += [ "xAOD::PFOAuxContainer_v1#TauShotPFOContainerAux." ] + +#------------------------------------------------------------------------------ +# Cell-based charged PFOs +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::PFOContainer_v1#TauPi0ChargedPFOContainer" ] +TauAODList += [ "xAOD::PFOAuxContainer_v1#TauPi0ChargedPFOContainerAux." ] + +#------------------------------------------------------------------------------ +# Cell-based neutral PFOs +#------------------------------------------------------------------------------ +TauAODList += [ "xAOD::PFOContainer_v1#TauPi0NeutralPFOContainer" ] +TauAODList += [ "xAOD::PFOAuxContainer_v1#TauPi0NeutralPFOContainerAux." ] + +#------------------------------------------------------------------------- +# eflowObjects for tau +#-------------------------------------------------------------------------- +#TauAODList += [ "eflowObjectContainer#eflowObjects_tauMode" ] +TauAODList += [ "xAOD::PFOContainer_v1#neutralTauPFO_eflowRec" ] +TauAODList += [ "xAOD::PFOAuxContainer_v1#neutralTauPFO_eflowRecAux." ] +TauAODList += [ "xAOD::PFOContainer_v1#chargedTauPFO_eflowRec" ] +TauAODList += [ "xAOD::PFOAuxContainer_v1#chargedTauPFO_eflowRecAux." ] + + diff --git a/Reconstruction/tauRec/share/TauESDList.py b/Reconstruction/tauRec/share/TauESDList.py new file mode 100644 index 00000000000..7dcca4c0e3c --- /dev/null +++ b/Reconstruction/tauRec/share/TauESDList.py @@ -0,0 +1,92 @@ +################################################################################ +## +#@file TauESDList.py +# +#@brief List ESD output containers. +################################################################################ + +#------------------------------------------------------------------------------ +# ESD output list +#------------------------------------------------------------------------------ +TauESDList = [] + +#------------------------------------------------------------------------------ +# Tau1P3P cell cluster +#------------------------------------------------------------------------------ +TauESDList += [ "CaloClusterContainer#Tau1P3PCellCluster" ] +TauESDList += [ "CaloCellLinkContainer#Tau1P3PCellCluster_Link" ] +TauESDList += [ "CaloShowerContainer#Tau1P3PCellCluster_Data" ] + +#------------------------------------------------------------------------------ +# TauRec cell cluster +#------------------------------------------------------------------------------ +TauESDList += [ "CaloClusterContainer#TauRecCellCluster" ] +TauESDList += [ "CaloCellLinkContainer#TauRecCellCluster_Link" ] +TauESDList += [ "CaloShowerContainer#TauRecCellCluster_Data" ] + +#------------------------------------------------------------------------------ +# Tau1P3P Pi0 cluster +#------------------------------------------------------------------------------ +TauESDList += [ "CaloClusterContainer#TauPi0ClusterContainer" ] +TauESDList += [ "CaloCellLinkContainer#TauPi0ClusterContainer_Link" ] +TauESDList += [ "CaloShowerContainer#TauPi0ClusterContainer_Data" ] +#TauESDList += [ "CaloCellContainer#TauCommonPi0CellContainer" ] # for studies of the cell-based algorithm + +#------------------------------------------------------------------------------ +# Tau shot clusters +#------------------------------------------------------------------------------ +TauESDList += [ "CaloClusterContainer#TauShotClusterContainer" ] +TauESDList += [ "CaloCellLinkContainer#TauShotClusterContainer_Link" ] +TauESDList += [ "CaloShowerContainer#TauShotClusterContainer_Data" ] + +#------------------------------------------------------------------------------ +# Shot PFOs +#------------------------------------------------------------------------------ +TauESDList += [ "xAOD::PFOContainer_v1#TauShotPFOContainer" ] +TauESDList += [ "xAOD::PFOAuxContainer_v1#TauShotPFOContainerAux." ] + +#------------------------------------------------------------------------------ +# Cell-based charged PFOs +#------------------------------------------------------------------------------ +TauESDList += [ "xAOD::PFOContainer_v1#TauPi0ChargedPFOContainer" ] +TauESDList += [ "xAOD::PFOAuxContainer_v1#TauPi0ChargedPFOContainerAux." ] + +#------------------------------------------------------------------------------ +# Cell-based neutral PFOs +#------------------------------------------------------------------------------ +TauESDList += [ "xAOD::PFOContainer_v1#TauPi0NeutralPFOContainer" ] +TauESDList += [ "xAOD::PFOAuxContainer_v1#TauPi0NeutralPFOContainerAux." ] + +#------------------------------------------------------------------------------ +# Secondary Vertex for Tau Decay +#------------------------------------------------------------------------------ +TauESDList += [ "xAOD::VertexContainer_v1#TauSecondaryVertexContainer" ] +TauESDList += [ "xAOD::VertexAuxContainer_v1#TauSecondaryVertexContainerAux.-vxTrackAtVertex" ] + +#------------------------------------------------------------------------------ +# Tau1P3P cell EM012 cluster +#------------------------------------------------------------------------------ +TauESDList += [ "CaloClusterContainer#Tau1P3PCellEM012ClusterContainer" ] +TauESDList += [ "CaloCellLinkContainer#Tau1P3PCellEM012ClusterContainer_Link" ] +TauESDList += [ "CaloShowerContainer#Tau1P3PCellEM012ClusterContainer_Data" ] + + +#------------------------------------------------------------------------------ +# Tau1P3P main containers +#------------------------------------------------------------------------------ +TauESDList += [ "Analysis::TauJetContainer#Tau1P3PContainer" ] +TauESDList += [ "Analysis::TauDetailsContainer#Tau1P3PDetailsContainer" ] +TauESDList += [ "Analysis::TauDetailsContainer#Tau1P3PExtraDetailsContainer" ] + +#------------------------------------------------------------------------------ +# TauRec main containers +#------------------------------------------------------------------------------ +TauESDList += [ "Analysis::TauJetContainer#TauRecContainer" ] +TauESDList += [ "Analysis::TauDetailsContainer#TauRecDetailsContainer" ] +TauESDList += [ "Analysis::TauDetailsContainer#TauRecExtraDetailsContainer" ] +TauESDList += [ "Analysis::TauDetailsContainer#TauPi0CandidateDetailsContainer" ] + +#------------------------------------------------------------------------- +# eflowObjects for tau +#-------------------------------------------------------------------------- +TauESDList += [ "eflowObjectContainer#eflowObjects_tauMode" ] diff --git a/Reconstruction/tauRec/share/tauMerged_trackslim_jobOptions.py b/Reconstruction/tauRec/share/tauMerged_trackslim_jobOptions.py new file mode 100644 index 00000000000..d1f8d7c42be --- /dev/null +++ b/Reconstruction/tauRec/share/tauMerged_trackslim_jobOptions.py @@ -0,0 +1,7 @@ +from RecExConfig.RecFlags import rec +if rec.ScopingLevel()<=3: + from ParticleBuilderOptions.AODFlags import AODFlags + if AODFlags.TauTrackSlimmer: + from tauRec.tauTrackSlimmer import tauTrackSlimmer + tauTrackSlimmer() + diff --git a/Reconstruction/tauRec/share/tauRecAOD_jobOptions.py b/Reconstruction/tauRec/share/tauRecAOD_jobOptions.py new file mode 100644 index 00000000000..ec6246dca06 --- /dev/null +++ b/Reconstruction/tauRec/share/tauRecAOD_jobOptions.py @@ -0,0 +1,10 @@ +################################################################################ +## +#@file tauRecAOD_jobOptions.py +# +#@brief jobOption to setup parts of the tau reconstruction chain to run on AODs. +# +#@author Felix Friedrich <felix.friedrich@cern.ch> +################################################################################ +from tauRec.TauRecAODBuilder import TauRecAODProcessor +TauRecAODProcessor(inAODmode=True) \ No newline at end of file diff --git a/Reconstruction/tauRec/share/tauRec_RTT_topOptions.py b/Reconstruction/tauRec/share/tauRec_RTT_topOptions.py new file mode 100644 index 00000000000..e0bd3f1054e --- /dev/null +++ b/Reconstruction/tauRec/share/tauRec_RTT_topOptions.py @@ -0,0 +1,62 @@ + +DetDescrVersion="ATLAS-CSC-01-02-00" + + +doESD = True # if false, all algorithms are switched off by defaults +########################### +donewTracking=True +doxKalman=True +doiPatRec=True +doEmCluster=True +doCaloCluster=True +doCaloTopoCluster=True + +doMoore=False +doMuonboy=False +doConversion=False +doBtagging=False +doEgamma=True +doJetRec=True +doTauRec=True +doMuonIDStandAlone=False +doMuonIDCombined=False +doMuidLowPt=False +doMuGirl=False +doStaco=False +doMuTag=False +doTileMuID=False +doMissingET=False +doObjMissingET=False +doEFlow=False +doEFlowJet= False +doTrigger=False +doAtlfast=False +############################ +doWriteESD = False +doWriteTAG = False +doWriteAOD = True +doTrigger = False +doHist = False +doAOD = True +doCBNT=True + +# number of event to process +#EvtMax= 5 +EvtMax=-1 + +if not 'BTaggingFlags' in dir(): + from BTagging.BTaggingFlags import BTaggingFlags + BTaggingFlags.JetFitterTag=False + #BTaggingFlags.OutputLevel=INFO + +#disable atlfast +from ParticleBuilderOptions.AODFlags import AODFlags +AODFlags.FastSimulation=False + +include ("RecExCommon/RecExCommon_flags.py") +#DetFlags.Calo_setOff() +DetFlags.Muon_setOff() + +include ("RecExCommon/RecExCommon_topOptions.py") +#CBNT_TruthParticle.NMaxTruthParticles = 3000 + diff --git a/Reconstruction/tauRec/share/tauRec_config.py b/Reconstruction/tauRec/share/tauRec_config.py new file mode 100644 index 00000000000..1bb562aecc1 --- /dev/null +++ b/Reconstruction/tauRec/share/tauRec_config.py @@ -0,0 +1,81 @@ +################################################################################ +## +#@file tauRec_config.py +# +#@brief Main RecExCommon entry point for the tau reconstruction chain including run of tau identification algorithms. +# +# This file calls the dedicated main jobOptions of tauRec and TauDiscriminant. +# Checks make sure that detector conditions are valid to run tau reconstruction. +# Tau identification will only be run if tau reconstruction was setup correctly. +# +################################################################################ +from RecExConfig.RecFlags import rec +from tauRec.tauRecFlags import jobproperties +from JetRec.JetRecFlags import jobproperties +from AthenaCommon.BeamFlags import jobproperties + + +#switch off TauDiscriminant for cosmic +if jobproperties.Beam.beamType()=="cosmics": + jobproperties.tauRecFlags.doRunTauDiscriminant=False + +#disable tau in case we run on RDO/RAW and jets are disabled as well: +if jobproperties.tauRecFlags.doTauRec() and rec.readRDO() and not rec.doJetMissingETTag(): + from AthenaCommon.Logging import logging + logTauRecConfig = logging.getLogger( 'tauRec_config' ) + logTauRecConfig.warning("Running on RDO/RAW files but doJetMissingETTag=False. Tau reco need jets --> tau reconstruction disabled!!") + jobproperties.tauRecFlags.doTauRec=False + + +if jobproperties.tauRecFlags.doTauRec() and ( rec.readESD() or ( DetFlags.haveRIO.ID_on() and DetFlags.haveRIO.Calo_on() ) ) : + _tauFail=True + + # the main tau reconstruction part + try: + include( "tauRec/tauRec_jobOptions.py" ) + _tauFail=False + except Exception: + treatException("Could not set up merged tauRec. Switched off !") + + if not _tauFail: + # call eflowRec in tau mode now + if recAlgs.doEFlow(): + try: + include("eflowRec/eflowRec_config_DC14_Tau.py") + except Exception: + treatException("could not setup eflowRec") + + #jobproperties.tauRecFlags.doPanTau=False + # call PanTau now + if jobproperties.tauRecFlags.doPanTau(): + try: + include("PanTauAnalysis/JobOptions_Main_PanTau.py") + except Exception: + treatException("Could not setup PanTau") + jobproperties.tauRecFlags.doPanTau = False + + # call TauDiscriminant + if jobproperties.tauRecFlags.doRunTauDiscriminant(): + try: + include("TauDiscriminant/TauDiscri_jobOptions.py" ) + except Exception: + treatException("Could not set up TauDiscriminant. Switched off !") + + if _tauFail and jobproperties.tauRecFlags.doTauRec(): + jobproperties.tauRecFlags.doTauRec=False + del _tauFail +else: + if jobproperties.tauRecFlags.doTauRec(): + jobproperties.tauRecFlags.doTauRec=False + +#XXX switch this off until xAOD migration is finished +#if rec.doWritexAOD(): +# from AthenaCommon.AlgSequence import AlgSequence +# sequence = AlgSequence() +# # Add the tau converter algorithm: +# outkey = "TauRecContainer" +# from xAODTauCnv.xAODTauCnvConf import xAODMaker__TauJetCnvAlg +# tauAlg = xAODMaker__TauJetCnvAlg() +# #tauAlg.OutputLevel = 1 +# sequence += tauAlg +# diff --git a/Reconstruction/tauRec/share/tauRec_jobOptions.py b/Reconstruction/tauRec/share/tauRec_jobOptions.py new file mode 100644 index 00000000000..7ab848bf341 --- /dev/null +++ b/Reconstruction/tauRec/share/tauRec_jobOptions.py @@ -0,0 +1,41 @@ +################################################################################ +## +#@file tauRec_jobOptions.py +# +#@brief Main jobOption to setup tau reconstruction chain. +# +#@author Felix Friedrich <felix.friedrich@cern.ch> +################################################################################ + +#TODO: everything needed here? +from RecExConfig.RecFlags import rec +from AthenaCommon.BeamFlags import jobproperties +from AthenaCommon.GlobalFlags import globalflags +import AthenaCommon.SystemOfUnits as Units +from tauRec.tauRecFlags import jobproperties as taujp + +# use Tau Jet Vertex Association Tool +# each Tau candidate gets its own primary vertex +# and the tracks are selected accroding to this vertex +_doTJVA = True + +# Bonn Pi0-finding algorithm +_doBonnPi0Clus = taujp.tauRecFlags.doBonnPi0() #False by default +_doBonnPi0Clus = True + +# the TauCoreBuilder +from tauRec.TauRecBuilder import TauRecCoreBuilder +TauRecCoreBuilder(doBonnPi0Clus=_doBonnPi0Clus, doTJVA=_doTJVA) + + +#include("tauRec/Pi0ClusterMaker_Crakow_jobOptions.py") +if _doBonnPi0Clus: + include("tauRec/Pi0ClusterMaker_Bonn_jobOptions.py") + +from tauRec.TauRecBuilder import TauRecPi0EflowProcessor +TauRecPi0EflowProcessor(doBonnPi0Clus=_doBonnPi0Clus) + +from tauRec.TauRecBuilder import TauRecVariablesProcessor +TauRecVariablesProcessor(doBonnPi0Clus=_doBonnPi0Clus) + + diff --git a/Reconstruction/tauRec/src/CaloClusterVariables.cxx b/Reconstruction/tauRec/src/CaloClusterVariables.cxx new file mode 100644 index 00000000000..736e9a40c0a --- /dev/null +++ b/Reconstruction/tauRec/src/CaloClusterVariables.cxx @@ -0,0 +1,203 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "tauRec/CaloClusterVariables.h" +#include "tauEvent/TauJet.h" +#include "boost/foreach.hpp" +#include "math.h" + +const double CaloClusterVariables::DEFAULT = -1111.; + +//**************************************** +// constructor +//**************************************** + +CaloClusterVariables::CaloClusterVariables() : +m_numConstit((int) DEFAULT), +m_effNumConstit_int((int) DEFAULT), +m_effNumConstit(DEFAULT), +m_aveRadius(DEFAULT), +m_aveEffRadius(DEFAULT), +m_totMass(DEFAULT), +m_effMass(DEFAULT), +m_totEnergy(DEFAULT), +m_effEnergy(DEFAULT), +m_numCells(0), +m_doVertexCorrection(false) { +} + +//******************************************* +// update/fill the cluster based variables +//******************************************* + +bool CaloClusterVariables::update(const xAOD::TauJet* pTau) { + + if (!pTau) return false; + const xAOD::Jet* pSeed = *pTau->jetLink(); + if(!pSeed) return false; + + xAOD::JetConstituentVector::const_iterator nav_it = pSeed->getConstituents().begin(); + xAOD::JetConstituentVector::const_iterator nav_itE = pSeed->getConstituents().end(); + const xAOD::CaloCluster* pCluster; + + unsigned int sumCells = 0; + + std::vector<xAOD::CaloVertexedCluster> constituents; + for (; nav_it != nav_itE; ++nav_it) { + pCluster = dynamic_cast<const xAOD::CaloCluster*> ( (*nav_it)->rawConstituent() ); + if (!pCluster) continue; + + // XXX moved the calculation of num cells up because later on we don't have access to the actual clusters anymore + sumCells += pCluster->size(); + + // correct cluster + if (pTau->vertexLink() && m_doVertexCorrection) + constituents.emplace_back (*pCluster, (*pTau->vertexLink())->position()); + else + constituents.emplace_back (*pCluster); + } + + this->m_numConstit = (int) constituents.size(); + + // Order constituents by energy + sort(constituents.begin(), constituents.end(), CaloClusterCompare()); + + //**************************************** + // Looping over all constituents + //**************************************** + + double sum_px = 0; + double sum_py = 0; + double sum_pz = 0; + double sum_e = 0; + double sum_of_E2 = 0; + double sum_radii = 0; + CLHEP::HepLorentzVector centroid = calculateTauCentroid(this->m_numConstit, constituents); + + for (const xAOD::CaloVertexedCluster& c : constituents) { + double energy = c.e(); + sum_of_E2 += energy*energy; + + double px = c.p4().Px(); + double py = c.p4().Py(); + double pz = c.p4().Pz(); + // FF: phi is wrong in case px,py AND pz is negative when using HepLorentzVector(px,py,pz,1) + // because phi = atan(py/px) + // in trigger many clusters have negative energies/momentum + // negative values of px and py are only treated correctly if pz is positive. + // Otherwise px and py must be taken as positive values + // so using cluster eta/phi directly instead of creating a HLV. + //CLHEP::HepLorentzVector constituentHLV(px, py, pz, 1); + //sum_radii += centroid.deltaR(constituentHLV); + double dr = std::sqrt( std::pow(c.eta() - centroid.eta(),2) + std::pow(c.phi() - centroid.phi(),2)); + sum_radii += dr; + sum_e += energy; + sum_px += px; + sum_py += py; + sum_pz += pz; + } + + // Sum up the energy for constituents + this->m_totEnergy = sum_e; + + // Calculate the mass of the constituents + if (this->m_numConstit < 2) this->m_totMass = DEFAULT; + else { + double mass2 = sum_e * sum_e - (sum_px * sum_px + sum_py * sum_py + sum_pz * sum_pz); + this->m_totMass = mass2 > 0 ? sqrt(mass2) : -sqrt(-mass2); + } + + // Calculate the average radius of the constituents wrt the tau centroid + this->m_aveRadius = this->m_numConstit > 0 ? sum_radii / this->m_numConstit : DEFAULT; + + // sum of cells for the tau candidate + this->m_numCells = sumCells; + + // Effective number of constituents + this->m_effNumConstit = sum_of_E2 > 0 ? (sum_e * sum_e) / (sum_of_E2) : DEFAULT; + + this->m_effNumConstit_int = int(ceil(this->m_effNumConstit)); + + // A problem! + if (this->m_effNumConstit_int > this->m_numConstit) return false; + + // Avoid segfault, happens when we try to iterate below if sum_of_E2 was 0 or negative + if (this->m_effNumConstit_int < 0) return false; + + //**************************************** + // Now: Looping over effective constituents + //**************************************** + + sum_px = 0; + sum_py = 0; + sum_pz = 0; + sum_e = 0; + sum_of_E2 = 0; + sum_radii = 0; + centroid = calculateTauCentroid(this->m_effNumConstit_int, constituents); + + int icount = this->m_effNumConstit_int; + for (const xAOD::CaloVertexedCluster& c : constituents) { + if (icount <= 0) break; + --icount; + + double energy = c.e(); + //XXXchange to use tlorentzvector + double px = c.p4().Px(); + double py = c.p4().Py(); + double pz = c.p4().Pz(); + // FF: see comment above + //CLHEP::HepLorentzVector constituentHLV(px, py, pz, 1); + //sum_radii += centroid.deltaR(constituentHLV); + double dr = std::sqrt( std::pow(c.eta() - centroid.eta(),2) + std::pow(c.phi() - centroid.phi(),2)); + sum_radii += dr; + + sum_e += energy; + sum_px += px; + sum_py += py; + sum_pz += pz; + } + + // Sum up the energy for effective constituents + this->m_effEnergy = sum_e; + + // Calculate the mass of the constituents + if (this->m_effNumConstit_int < 2) this->m_effMass = DEFAULT; + else { + double mass2 = sum_e * sum_e - (sum_px * sum_px + sum_py * sum_py + sum_pz * sum_pz); + this->m_effMass = mass2 > 0 ? sqrt(mass2) : -sqrt(-mass2); + } + + // Calculate the average radius of the constituents wrt the tau centroid + this->m_aveEffRadius = this->m_effNumConstit_int > 0 ? sum_radii / this->m_effNumConstit_int : DEFAULT; + + return true; +} + + +//***************************************** +// Calculate the geometrical center of the +// tau constituents +//***************************************** +CLHEP::HepLorentzVector CaloClusterVariables::calculateTauCentroid(int nConst, const std::vector<xAOD::CaloVertexedCluster>& constituents) { + + double px = 0; + double py = 0; + double pz = 0; + double current_px, current_py, current_pz, modulus; + + for (const xAOD::CaloVertexedCluster& c : constituents) { + if (nConst <= 0) break; + --nConst; + current_px = c.p4().Px(); + current_py = c.p4().Py(); + current_pz = c.p4().Pz(); + modulus = sqrt(current_px * current_px + current_py * current_py + current_pz * current_pz); + px += current_px / modulus; + py += current_py / modulus; + pz += current_pz / modulus; + } + CLHEP::HepLorentzVector centroid(px, py, pz, 1); + return centroid; +} diff --git a/Reconstruction/tauRec/src/JetSeedBuilder.cxx b/Reconstruction/tauRec/src/JetSeedBuilder.cxx new file mode 100644 index 00000000000..a9a23826f38 --- /dev/null +++ b/Reconstruction/tauRec/src/JetSeedBuilder.cxx @@ -0,0 +1,209 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +NAME: JetSeedBuilder.cxx +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: N. Meyer +CREATED: Nov 27 2007 + +17/03/2010: AK: change to P4Helpers +16/05/2011: FF: fix rare case if no jet_seed found at all (coverity 21744) + Dec 2011: FF: changes for tauRec4 + ********************************************************************/ + +#include "EventKernel/SignalStateHelper.h" +#include "FourMomUtils/P4Helpers.h" + +#include "xAODJet/Jet.h" +#include "xAODJet/JetContainer.h" + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODTau/TauJet.h" + +#include "tauRec/JetSeedBuilder.h" + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +JetSeedBuilder::JetSeedBuilder(const std::string& type, + const std::string& name, + const IInterface * parent) : + TauToolBase(type, name, parent), + m_jetCollectionName("AntiKt4LCTopoJets"), + m_maxJetdist(0.1), + m_minJetPt(10000.0), + m_switch_jets_em_scale(false) { + declareInterface<TauToolBase > (this); + declareProperty("JetCollection", m_jetCollectionName); + declareProperty("maxDist", m_maxJetdist); + declareProperty("minPt", m_minJetPt); + declareProperty("SwitchJetsEmScale", m_switch_jets_em_scale); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +JetSeedBuilder::~JetSeedBuilder() { +} + +//------------------------------------------------------------------------- +// initialize +//------------------------------------------------------------------------- + +StatusCode JetSeedBuilder::initialize() { + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// Event Finalize +//------------------------------------------------------------------------- + +StatusCode JetSeedBuilder::eventFinalize(TauCandidateData *) { + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// execute +//------------------------------------------------------------------------- + +StatusCode JetSeedBuilder::execute(TauCandidateData * data) { + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + StatusCode sc; + + ATH_MSG_DEBUG("Starting execute"); + + bool inTrigger = false; + if (data->hasObject("InTrigger?")) { + sc = data->getObject("InTrigger?", inTrigger); + } + + if(inTrigger) + ATH_MSG_DEBUG("inTrigger read properly"); + + const xAOD::JetContainer *pJetColl; + + if (sc.isSuccess() && inTrigger) { + // called by Trigger + // retrieve JetCollection for trigger + ATH_MSG_DEBUG("Try to retrieve object from DataContainer"); + //sc = data->getObject("JetCollection", pJetColl); + // Try a different approach: grab it directly + sc = true; + pJetColl = data->seedContainer; + if (sc.isFailure() || !pJetColl) { + ATH_MSG_DEBUG("no JetCollection for trigger available"); + ATH_MSG_DEBUG("retrieve standard JetCollection <" << m_jetCollectionName << ">"); + // retrieve standard jet collection + sc = evtStore()->retrieve(pJetColl, m_jetCollectionName); + if (sc.isFailure()) { + ATH_MSG_WARNING("no JetCollection retrieved"); + return StatusCode::FAILURE; + } + } + } else { + // called by offline tauRec + // retrieve standard jet collection + sc = evtStore()->retrieve(pJetColl, m_jetCollectionName); + if (sc.isFailure()) { + ATH_MSG_WARNING("no JetCollection retrieved"); + return StatusCode::FAILURE; + } + } + + ATH_MSG_DEBUG("Pulling out the seed"); + + const xAOD::Jet* pJetSeed = data->seed; + if (!pJetSeed) { + ATH_MSG_DEBUG("seed is not a jet -> tau will not be reconstructed"); + return StatusCode::FAILURE; + } + + ATH_MSG_DEBUG("Seed extracted"); + ATH_MSG_DEBUG("seed is Jet with" + << " pt=" << pJetSeed->pt() + << " eta=" << pJetSeed->eta() + << " phi=" << pJetSeed->phi() + ); + + xAOD::TauJetContainer::iterator itTau = data->xAODTauContainer->begin(); + xAOD::TauJetContainer::iterator itTauE = data->xAODTauContainer->end(); + + for (; itTau != itTauE; ++itTau) { + if ( (*itTau)->jetLink().isValid() ) { + if ( pJetSeed == ( * (*itTau)->jetLink() ) ) { + ATH_MSG_DEBUG("seed already used"); + return StatusCode::FAILURE; + } + } + } + + ///XXX need to decide whether to remove this, because there's no author flag in xAOD::TauJet + + //*********************************************************************** + // set author to both-seeded because we don't want to break any analysis + // most of the analyses are using author==3 or author==1 + // so setting author=3 should be safe for everybody + // calo seeded tau + // pTau->setAuthor(TauJetParameters::tauRec); + // // track seeded tau + // pTau->setAuthor(TauJetParameters::tau1P3P); + //*********************************************************************** + + // + // ATTENTION: direction will be overwritten later by TauAxis and TauEnergyCalibration + // + if (inTrigger && pJetSeed->e() < 0) { + // SL/SX trigger mode with negative jet_seed - do not set TauJet eta and phi in JetSeedBuilder + ATH_MSG_DEBUG("TauJet eta/phi will be set in Level2 Trigger for negative energy jet"); + + pTau->setDetail(xAOD::TauJetParameters::seedCalo_eta , static_cast<float>( pTau->eta() ) ); + pTau->setDetail(xAOD::TauJetParameters::seedCalo_phi , static_cast<float>( pTau->phi() ) ); + + pTau->setP4(pJetSeed->pt(),pTau->eta(),pTau->phi(),0.0); + + } else { + if (m_switch_jets_em_scale) { + ATH_MSG_INFO("trying to set seed jet signal state to EMSCALE, but this code has not been migrated to xAOD::Jet yet"); + //XXX still need to look up how signal states are handled for the xAOD jets + // SignalStateHelper sigstateH(P4SignalState::JETEMSCALE); + // sigstateH.controlObject(pJetSeed); + } + + pTau->setDetail(xAOD::TauJetParameters::seedCalo_eta , static_cast<float>( pJetSeed->eta() ) ); + pTau->setDetail(xAOD::TauJetParameters::seedCalo_phi , static_cast<float>( pJetSeed->phi() ) ); + if ( pJetSeed->pt() > 1e-7) + pTau->setP4(static_cast<float>( pJetSeed->pt() ) ,static_cast<float>( pJetSeed->eta() ) ,static_cast<float>( pJetSeed->phi() ) ,0.0 ); + else + pTau->setP4(static_cast<float>( pJetSeed->pt() ) ,static_cast<float>( pJetSeed->eta() ) ,static_cast<float>( pJetSeed->phi() ) , 0.0 ); + + //store 4-vector of seed + pTau->setP4( xAOD::TauJetParameters::JetSeed, pJetSeed->pt(), pJetSeed->eta(), pJetSeed->phi(), pJetSeed->m() ); + } + + // set now the link to the jet seed + pTau->setJet(pJetColl, pJetSeed); + + if ( pTau->jetLink().isValid() ) { + ATH_MSG_DEBUG("seed associated with tau is Jet with" + << " pt=" << (*pTau->jetLink())->pt() + << " eta=" << (*pTau->jetLink())->eta() + << " phi=" << (*pTau->jetLink())->phi() + ); + } + + return StatusCode::SUCCESS; +} + + diff --git a/Reconstruction/tauRec/src/LockTauContainers.cxx b/Reconstruction/tauRec/src/LockTauContainers.cxx new file mode 100644 index 00000000000..528ee0bcca4 --- /dev/null +++ b/Reconstruction/tauRec/src/LockTauContainers.cxx @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" + +#include "tauRec/LockTauContainers.h" + +//********************************** +// Constructor +//********************************** + +LockTauContainers::LockTauContainers( + const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); +} + + +//************************************ +// event finalize method +//************************************ + +StatusCode LockTauContainers::eventFinalize(TauCandidateData *data) { + ATH_MSG_VERBOSE("LockTauContainers::eventFinialize"); + + //------------------------------------------------------------------------- + // Lock Containers + //------------------------------------------------------------------------- + + xAOD::TauJetContainer* pContainer = data->xAODTauContainer; + xAOD::TauJetAuxContainer *pAuxContainer = data->tauAuxContainer; + + StatusCode sc; + + if (pContainer) + sc = evtStore()->setConst(pContainer); + if (sc.isFailure()) { + ATH_MSG_ERROR("Cannot set tau container to const"); + return StatusCode::FAILURE; + } + + if (pAuxContainer) + sc = evtStore()->setConst(pAuxContainer); + if (sc.isFailure()) { + ATH_MSG_ERROR("Cannot set tau aux container to const"); + return StatusCode::FAILURE; + } + + ATH_MSG_VERBOSE("all tau containers are now locked"); + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/PhotonConversionPID.cxx b/Reconstruction/tauRec/src/PhotonConversionPID.cxx new file mode 100644 index 00000000000..362c328ec64 --- /dev/null +++ b/Reconstruction/tauRec/src/PhotonConversionPID.cxx @@ -0,0 +1,151 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +NAME: PhotonConversionPID.cxx +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: Michael Boehler <michael.boehler@desy.de> +CREATED: November 2008 + ********************************************************************/ + +#include "tauRec/PhotonConversionPID.h" + +#include "xAODTracking/VertexContainer.h" +#include "TrkParticleBase/LinkToTrackParticleBase.h" +#include "TrkTrackSummary/TrackSummary.h" +#include "AthContainers/ConstDataVector.h" + +PhotonConversionPID::PhotonConversionPID(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent), +m_ownPolicy(static_cast<int> (SG::VIEW_ELEMENTS)) { + declareInterface<TauToolBase > (this); + + declareProperty("OwnPolicy", m_ownPolicy); + declareProperty("ConversionCandidatesName", m_ConversionCandidatesName = "ConversionCandidate"); + declareProperty("ConversionOutputName", m_ConversionOutputName = "ConversionsPID_Container"); + declareProperty("ElectronProbability", m_eProb_cut = 0.9); +} + +/********************************************************************/ +PhotonConversionPID::~PhotonConversionPID() { +} + +/********************************************************************/ +StatusCode PhotonConversionPID::initialize() { + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode PhotonConversionPID::finalize() { + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode PhotonConversionPID::eventFinalize(TauCandidateData* /*data*/) { + + // ------------------------------------------------------------------ + // Retrieving VxCandidates (conversions) + // ------------------------------------------------------------------ + const xAOD::VertexContainer* ConvContainer; + StatusCode sc = evtStore()->retrieve(ConvContainer, m_ConversionCandidatesName); + + if (sc.isFailure() || !ConvContainer) { + ATH_MSG_DEBUG(" No VxCandidates container found in TDS !!"); + return StatusCode::SUCCESS; + } else { + ATH_MSG_VERBOSE("Processing Conversion Container Name = " << m_ConversionCandidatesName); + } + + ATH_MSG_DEBUG("VxContainer " << m_ConversionCandidatesName << " contains " << ConvContainer->size() << " vertices. "); + + + // ------------------------------------------------------------------------------------------------- + // Create and record the empty container VxCandidates (conversions after PID) + // ------------------------------------------------------------------------------------------------- + ATH_MSG_DEBUG(" Recording identified conversion collection with key: " << m_ConversionOutputName); + + ConstDataVector<xAOD::VertexContainer>* ConversionContainerPID = new ConstDataVector<xAOD::VertexContainer>(static_cast<SG::OwnershipPolicy> (m_ownPolicy)); + + sc = evtStore()->record(ConversionContainerPID, m_ConversionOutputName); + if (sc.isFailure()) { + ATH_MSG_ERROR("execute() : cannot record CaloCellContainer " << m_ConversionOutputName); + return sc; + } + + // Loop over ConversionVertex Container: + xAOD::VertexContainer::const_iterator itr = ConvContainer->begin(); + xAOD::VertexContainer::const_iterator itrE = ConvContainer->end(); + + for (; itr != itrE; ++itr) { + + const xAOD::Vertex* vxcand = (*itr); + + ATH_MSG_VERBOSE("Tracks at vertex: " << vxcand->nTrackParticles()); + + bool isTrk1_Conv = false; + bool isTrk2_Conv = false; + + // loop over all tracks of the vertex + for (unsigned int i = 0; i < vxcand->nTrackParticles(); i++) { + /* + // these lines navigate from a VxCandidate to the track summary of each track at vertex + Trk::VxTrackAtVertex* tmpVxAtVtx = (*trklist)[i]; + Trk::ITrackLink* trkLink = tmpVxAtVtx->trackOrParticleLink(); + Trk::LinkToTrackParticleBase * linkToTrack_part = dynamic_cast<Trk::LinkToTrackParticleBase *> (trkLink); + if (!linkToTrack_part) { + ATH_MSG_WARNING("dynamic_cast of LinkToTrackParticleBase failed"); + continue; + } + + const Trk::TrackParticleBase* TP_Base = linkToTrack_part->cachedElement(); + if (!TP_Base) { + ATH_MSG_WARNING("could not get TrackParticleBase from linkToTrack_part"); + continue; + } + + const Trk::TrackSummary* summary = TP_Base->trackSummary(); + */ + const xAOD::TrackParticle *track = vxcand->trackParticle(i); + float eProbabilityComb; + if (track && track->summaryValue(eProbabilityComb, xAOD::SummaryType::eProbabilityComb)) { + //--------------------------------------------------------------- + // Checks ID of Conversion Candidates (eProb based on TRT PID) + ATH_MSG_VERBOSE("Track " << i + 1 << " PID: " << eProbabilityComb); + + if (eProbabilityComb > m_eProb_cut) { + + // both conv tracks pass PID cut (in case of double track conv) + if (i == 0) { + isTrk1_Conv = true; + } + if (i == 1 || vxcand->nTrackParticles() == 1) { + isTrk2_Conv = true; + } + } + + //------------------------------------------------------------------ + // after both tracks have been tested and passed the PID cut the + // Conversions are stored in the new Conversion Container + if (isTrk1_Conv == true && isTrk2_Conv == true) { + ATH_MSG_VERBOSE(" Conversion accepted"); + ConversionContainerPID->push_back(vxcand); + } + + + } else { + // here a new track summary can be provided (not yet implemented) + ATH_MSG_WARNING("No Track Summary has been found! NO Photon Conversion Identification has been made!!!! "); + } + + } // end track loop + } // end vertex loop + + ATH_MSG_DEBUG("After ID " << ConversionContainerPID->size() << " Conversion are stored in " << m_ConversionOutputName); + + return StatusCode::SUCCESS; +} + +/********************************************************************/ diff --git a/Reconstruction/tauRec/src/PhotonConversionVertex.cxx b/Reconstruction/tauRec/src/PhotonConversionVertex.cxx new file mode 100644 index 00000000000..df6806e74e2 --- /dev/null +++ b/Reconstruction/tauRec/src/PhotonConversionVertex.cxx @@ -0,0 +1,149 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +NAME: PhotonConversionVertex.cxx +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: KG Tan <Kong.Guan.Tan@cern.ch> +CREATED: May 2011 + +This tool identifies conversion candidates in/near (definable) a +tau decay cone by reconstructing the conversion vertices and +applying a set of cuts optimized for tau conversions on the vertex +parameters. + ********************************************************************/ + +#include "tauRec/PhotonConversionVertex.h" + +#include "tauEvent/TauJetContainer.h" +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODTracking/VertexContainer.h" +#include "InDetRecToolInterfaces/IVertexFinder.h" +#include "AthContainers/ConstDataVector.h" + +PhotonConversionVertex::PhotonConversionVertex(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent), +m_vertexFinderTool("InDet::InDetConversionFinderTools") { + declareInterface<TauToolBase > (this); + declareProperty("TauRecContainer", m_inputTauJetContainerName = "TauRecContainer"); + declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles"); + declareProperty("OutputConversionVertexContainerName", m_outputConversionVertexContainerName = "ConversionsVertex_Container"); + declareProperty("MaxTauJetDr", m_maxTauJetDr = 0.5); + declareProperty("ConversionFinderTool", m_vertexFinderTool); +} + +PhotonConversionVertex::~PhotonConversionVertex() { +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode PhotonConversionVertex::initialize() { + // Get the VertexFinderTool + if (!retrieveTool(m_vertexFinderTool)) return StatusCode::FAILURE; + + return StatusCode::SUCCESS; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode PhotonConversionVertex::finalize() { + return StatusCode::SUCCESS; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +StatusCode PhotonConversionVertex::eventFinalize(TauCandidateData *data) { + // get the jet container from TauCandidateData, or the StoreGate if it can't find it + xAOD::TauJetContainer* tauJetCont = data->xAODTauContainer; + if (!tauJetCont) { + if (!openContainer(tauJetCont, m_inputTauJetContainerName)) + return StatusCode::FAILURE; + } + + // get the track particle container from StoreGate + const xAOD::TrackParticleContainer* trackParticleCont = 0; + if (!openContainer(trackParticleCont, m_inputTrackParticleContainerName)) return StatusCode::FAILURE; + + // Define container to store + xAOD::VertexContainer* conversionCandidatesVxCont = 0; + xAOD::VertexAuxContainer* conversionCandidatesVxContAux = 0; + std::pair<xAOD::VertexContainer*, xAOD::VertexAuxContainer*> convContPair; + + // Redo conversion over the tau seed cones, or over entire region + if (m_maxTauJetDr > 0.) { + + if (tauJetCont->size() > 0) { + + // Create a temporary TrackParticle container that contains tracks within the tau seed cones + ConstDataVector<xAOD::TrackParticleContainer> tempCont (SG::VIEW_ELEMENTS); + for (xAOD::TrackParticleContainer::const_iterator tpcItr = trackParticleCont->begin(); tpcItr != trackParticleCont->end(); ++tpcItr) { + double minTauDr = getMinDrTauDecay(tauJetCont, *tpcItr); + if (minTauDr < m_maxTauJetDr) { + tempCont.push_back(*tpcItr); + } + } + ATH_MSG_VERBOSE("Number of tracks within tau seed cones for conversion finding: " << tempCont.size()); + + // Run the conversion finding algorithm over the tau seed cones + convContPair = m_vertexFinderTool->findVertex(tempCont.asDataVector()); + conversionCandidatesVxCont = convContPair.first; + conversionCandidatesVxContAux = convContPair.second; + } else + conversionCandidatesVxCont = new xAOD::VertexContainer(); // No need to run conversion finding if no tracks are found! + conversionCandidatesVxContAux = new xAOD::VertexAuxContainer(); // No need to run conversion finding if no tracks are found! + + } else { + ATH_MSG_VERBOSE("Running over entire region! Number of tracks: " << trackParticleCont->size()); + + // Run the conversion finding algorithm over the entire region! + convContPair = m_vertexFinderTool->findVertex(trackParticleCont); + conversionCandidatesVxCont = convContPair.first; + conversionCandidatesVxContAux = convContPair.second; + } + + // Perform the storing + ATH_MSG_VERBOSE("Number of conversion vertices found: " << conversionCandidatesVxCont->size()); + conversionCandidatesVxCont->setStore( conversionCandidatesVxContAux ); + if (!saveContainer(conversionCandidatesVxCont, m_outputConversionVertexContainerName)) return StatusCode::FAILURE; + if (!saveContainer(conversionCandidatesVxContAux, m_outputConversionVertexContainerName+"Aux")) return StatusCode::FAILURE; + + return StatusCode::SUCCESS; +} + +template <class T> +bool PhotonConversionVertex::openContainer(T* &container, std::string containerName) { + StatusCode sc = evtStore()->retrieve(container, containerName); + if (!container || sc.isFailure()) + ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate"); + return container; +} + +template <class T> +bool PhotonConversionVertex::saveContainer(T* &container, std::string containerName) { + StatusCode sc = evtStore()->record(container, containerName); + if (!container || sc.isFailure()) + ATH_MSG_FATAL("Container (" << containerName << ") cannot be saved in StoreGate"); + return container; +} + +template <class T> +bool PhotonConversionVertex::retrieveTool(T &tool) { + if (tool.retrieve().isFailure()) { + ATH_MSG_FATAL("Failed to retrieve tool " << tool); + return false; + } else { + ATH_MSG_VERBOSE("Retrieved tool " << tool); + } + return true; +} + +double PhotonConversionVertex::getMinDrTauDecay(const xAOD::TauJetContainer* tauJetCont, const xAOD::TrackParticle *trackParticle) { + double minDR = 99999.; + for (xAOD::TauJetContainer::const_iterator tjcItr = tauJetCont->begin(); tjcItr != tauJetCont->end(); ++tjcItr) { + const xAOD::TauJet *tauJet = *tjcItr; + double dR = trackParticle->p4().DeltaR(tauJet->p4()); + if (dR < minDR) minDR = dR; + } + return minDR; +} diff --git a/Reconstruction/tauRec/src/TauAxisSetter.cxx b/Reconstruction/tauRec/src/TauAxisSetter.cxx new file mode 100644 index 00000000000..677388c6123 --- /dev/null +++ b/Reconstruction/tauRec/src/TauAxisSetter.cxx @@ -0,0 +1,161 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "CLHEP/Vector/LorentzVector.h" +#include "CLHEP/Units/SystemOfUnits.h" +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" +#include "JetEvent/Jet.h" +#include "CaloEvent/CaloCluster.h" + +//tau +#include "tauRec/TauCandidateData.h" + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODTau/TauJet.h" + +#include "CaloUtils/CaloVertexedCluster.h" + +#include "tauRec/TauAxisSetter.h" + +/********************************************************************/ +TauAxisSetter::TauAxisSetter(const std::string& type, + const std::string& name, + const IInterface* parent): +TauToolBase(type, name, parent), +m_clusterCone(0.2), +m_doCellCorrection(false) +{ + declareInterface<TauToolBase > (this); + declareProperty("ClusterCone", m_clusterCone); + declareProperty("tauContainerKey", tauContainerKey = "TauRecContainer"); + declareProperty("CellCorrection", m_doCellCorrection); +} + +/********************************************************************/ +TauAxisSetter::~TauAxisSetter() { } + +/********************************************************************/ +StatusCode TauAxisSetter::initialize() +{ + return StatusCode::SUCCESS; +} + +StatusCode TauAxisSetter::eventInitialize(TauCandidateData * /*data*/) +{ + return StatusCode::SUCCESS; + +} + +/********************************************************************/ +StatusCode TauAxisSetter::execute(TauCandidateData *data) +{ + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + const xAOD::Jet* pJetSeed = (*pTau->jetLink()); + if (!pJetSeed) { + ATH_MSG_WARNING("tau does not have jet seed for LC calibration"); + return StatusCode::SUCCESS; + } + + xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin(); + xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end(); + + /////////////////////////////////////////////////////////////////////////// + //calculate barycenter + TLorentzVector sumAllClusterVector; + TLorentzVector tempClusterVector; + for (; cItr != cItrE; ++cItr) { + tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() ); + + sumAllClusterVector += tempClusterVector; + } + TLorentzVector BaryCenter; + BaryCenter.SetPtEtaPhiM(1., sumAllClusterVector.Eta(), sumAllClusterVector.Phi(), 0.); + + + /////////////////////////////////////////////////////////////////////////// + // calculate detector axis + TLorentzVector tauDetectorAxis; + // count number of constituents in core cone. could be zero! + int nConstituents = 0; + for (cItr = pJetSeed->getConstituents().begin(); cItr != cItrE; ++cItr) { + tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() ); + + ATH_MSG_VERBOSE("cluster in detector axis loop:" << (*cItr)->pt()<< " " << (*cItr)->eta() << " " << (*cItr)->phi() << " " << (*cItr)->e() ); + ATH_MSG_VERBOSE("delta R is " << BaryCenter.DeltaR(tempClusterVector) ); + + if (BaryCenter.DeltaR(tempClusterVector) > m_clusterCone) + continue; + + nConstituents++; + tauDetectorAxis += tempClusterVector; + } + + if (nConstituents == 0) + { + ATH_MSG_WARNING("this tau candidate does not have any constituent clusters! breaking off tau tool chain and not recording this candidate!"); + return StatusCode::FAILURE; + } + + ATH_MSG_VERBOSE("jet axis:" << (*pTau->jetLink())->pt()<< " " << (*pTau->jetLink())->eta() << " " << (*pTau->jetLink())->phi() << " " << (*pTau->jetLink())->e() ); + // save values for detector axis. + // FixMe: consider dropping these details variables as they are duplicated in the detector axis 4 vector + pTau->setDetail(xAOD::TauJetParameters::LC_TES_precalib , static_cast<float>( tauDetectorAxis.Pt() ) ); + pTau->setDetail(xAOD::TauJetParameters::seedCalo_eta, static_cast<float>( tauDetectorAxis.Eta() ) ); + pTau->setDetail(xAOD::TauJetParameters::seedCalo_phi, static_cast<float>( tauDetectorAxis.Phi() ) ); + ATH_MSG_VERBOSE("detector axis:" << tauDetectorAxis.Pt()<< " " << tauDetectorAxis.Eta() << " " << tauDetectorAxis.Phi() << " " << tauDetectorAxis.E() ); + + // detectorAxis (set default) + pTau->setP4(tauDetectorAxis.Pt(), tauDetectorAxis.Eta(), tauDetectorAxis.Phi(), pTau->m()); + // save detectorAxis + pTau->setP4(xAOD::TauJetParameters::DetectorAxis, tauDetectorAxis.Pt(), tauDetectorAxis.Eta(), tauDetectorAxis.Phi(), tauDetectorAxis.M()); + + /////////////////////////////////////////////////////////////////////////// + // calculate tau intermediate axis (corrected for tau vertex) + TLorentzVector tauInterAxis; + + for (cItr = pJetSeed->getConstituents().begin(); cItr != cItrE; ++cItr) { + tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() ); + if (BaryCenter.DeltaR(tempClusterVector) > m_clusterCone) + continue; + + const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); + if (!cluster) continue; + + if (pTau->vertexLink()) + tauInterAxis += xAOD::CaloVertexedCluster(*cluster, (*pTau->vertexLink())->position()).p4(); + else + tauInterAxis += xAOD::CaloVertexedCluster(*cluster).p4(); + } + + // save values for tau intermediate axis + // energy will be overwritten by EnergyCalibrationLC (if correctEnergy is enabled) + // direction will be overwritten by EnergyCalibrationLC (if correctAxis is enabled) + + // intermediate axis( set default) + pTau->setP4(tauInterAxis.Pt(), tauInterAxis.Eta(), tauInterAxis.Phi(), pTau->m()); + + ATH_MSG_VERBOSE("tau axis:" << tauInterAxis.Pt()<< " " << tauInterAxis.Eta() << " " << tauInterAxis.Phi() << " " << tauInterAxis.E() ); + + // save intermediateAxis + pTau->setP4(xAOD::TauJetParameters::IntermediateAxis, tauInterAxis.Pt(), tauInterAxis.Eta(), tauInterAxis.Phi(), tauInterAxis.M()); + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalize +//----------------------------------------------------------------------------- +StatusCode TauAxisSetter::finalize() +{ + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauBuilder.cxx b/Reconstruction/tauRec/src/TauBuilder.cxx new file mode 100644 index 00000000000..bab7cd3870c --- /dev/null +++ b/Reconstruction/tauRec/src/TauBuilder.cxx @@ -0,0 +1,373 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauBuilder.cxx +// package: Reconstruction/tauRec +// authors: Srini Rajagopalan, Michael Heldmann, Lukasz Janyst, +// Anna Kaczmarska +// date: 2007-02-13 +// modification: +// 15/04/2008 - (AK) fixing memory leak bug #35463 +// 19/05/2011 - (KG) added EndAthTools to transition between AlgTools and AthAlgTools +// 22/05/2011 - (FF) changed to inherit from AthAlgorithm +// 23/05/2011 - (FF) removed EndAthTools -> transition finished +// 01/12/2011 - (FF) remove track seeded containers +//----------------------------------------------------------------------------- + +#include "tauRec/TauBuilder.h" + +#include "xAODJet/Jet.h" +#include "xAODJet/JetContainer.h" + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODTau/TauDefs.h" + +#include "GaudiKernel/ListItem.h" +#include "tauRec/TauCandidateData.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauBuilder::TauBuilder(const std::string &name, + ISvcLocator * pSvcLocator) : +AthAlgorithm(name, pSvcLocator), +m_tauContainerName("TauRecContainer"), +m_tauAuxContainerName("TauRecContainerAux."), +m_seedContainerName(""), +m_maxEta(2.5), +m_minPt(10000), +m_doCreateTauContainers(false), +m_tools(this) //make tools private +{ + declareProperty("TauContainer", m_tauContainerName); + declareProperty("TauAuxContainer", m_tauAuxContainerName); + declareProperty("SeedContainer", m_seedContainerName); + declareProperty("MaxEta", m_maxEta); + declareProperty("MinPt", m_minPt); + declareProperty("doCreateTauContainers", m_doCreateTauContainers); + declareProperty("Tools", m_tools, "List of TauToolBase tools"); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauBuilder::~TauBuilder() { +} + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauBuilder::initialize() { + StatusCode sc; + + //ATH_MSG_INFO("FF::TauBuilder :: initialize()"); + + //------------------------------------------------------------------------- + // No tools allocated! + //------------------------------------------------------------------------- + if (m_tools.size() == 0) { + ATH_MSG_ERROR("no tools given!"); + return StatusCode::FAILURE; + } + + //------------------------------------------------------------------------- + // Allocate tools + //------------------------------------------------------------------------- + ToolHandleArray<TauToolBase> ::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase> ::iterator itTE = m_tools.end(); + ATH_MSG_INFO("List of tools in execution sequence:"); + ATH_MSG_INFO("------------------------------------"); + + unsigned int tool_count = 0; + + for (; itT != itTE; ++itT) { + sc = itT->retrieve(); + if (sc.isFailure()) { + ATH_MSG_WARNING("Cannot find tool named <" << *itT << ">"); + } else { + ++tool_count; + ATH_MSG_INFO((*itT)->type() << " - " << (*itT)->name()); + } + } + ATH_MSG_INFO(" "); + ATH_MSG_INFO("------------------------------------"); + + if (tool_count == 0) { + ATH_MSG_ERROR("could not allocate any tool!"); + return StatusCode::FAILURE; + } + + /////////////////////////////////////////////////////////////////////////// + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauBuilder::finalize() { + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- + +StatusCode TauBuilder::execute() { + //ATH_MSG_INFO("FF::TauBuilder :: execute()"); + StatusCode sc; + + TauCandidateData rTauData; + + xAOD::TauJetContainer * pContainer = 0; + xAOD::TauJetAuxContainer* pAuxContainer = 0; + + + + if (m_doCreateTauContainers) { + //------------------------------------------------------------------------- + // Create and Record containers + //------------------------------------------------------------------------- + + pContainer = new xAOD::TauJetContainer(); + sc = evtStore()->record( pContainer, m_tauContainerName ) ; + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to record TauContainer in TDS"); + delete pContainer; + return StatusCode::FAILURE; + } + + pAuxContainer = new xAOD::TauJetAuxContainer(); + sc = evtStore()->record( pAuxContainer, m_tauAuxContainerName ) ; + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to record TauContainer in TDS"); + delete pContainer; + return StatusCode::FAILURE; + } + + pContainer->setStore( pAuxContainer ); + ATH_MSG_DEBUG( "Recorded xAOD tau jets with key: " + << m_tauAuxContainerName ); + + // pExtraDetailsContainer = new Analysis::TauDetailsContainer(); + // sc = evtStore()->record(pExtraDetailsContainer, m_tauExtraDetailsContainerName); + // if (sc.isFailure()) { + // ATH_MSG_ERROR("Unable to record TauDetailsContainer in TDS"); + // delete pExtraDetailsContainer; + // return StatusCode::FAILURE; + // } + + // pPi0CandidateDetailsContainer = new Analysis::TauDetailsContainer(); + // sc = evtStore()->record(pPi0CandidateDetailsContainer, "TauPi0CandidateDetailsContainer"); + // if (sc.isFailure()) { + // ATH_MSG_ERROR("Unable to record TauPi0CandidateDetailsContainer in TDS"); + // delete pPi0CandidateDetailsContainer; + // return StatusCode::FAILURE; + // } + + + } else { + //------------------------------------------------------------------------- + // retrieve Tau Containers from StoreGate + //------------------------------------------------------------------------- + sc = evtStore()->retrieve(pContainer, m_tauContainerName); + if (sc.isFailure()) { + ATH_MSG_FATAL("Failed to retrieve " << m_tauContainerName); + return StatusCode::FAILURE; + } + + sc = evtStore()->retrieve(pAuxContainer, m_tauAuxContainerName); + if (sc.isFailure()) { + ATH_MSG_FATAL("Failed to retrieve " << m_tauAuxContainerName); + return StatusCode::FAILURE; + } + + // sc = evtStore()->retrieve(pExtraDetailsContainer, m_tauExtraDetailsContainerName); + // if (sc.isFailure()) { + // ATH_MSG_FATAL("Failed to retrieve " << m_tauExtraDetailsContainerName); + // return StatusCode::FAILURE; + // } + + // sc = evtStore()->retrieve(pPi0CandidateDetailsContainer, "TauPi0CandidateDetailsContainer"); + // if (sc.isFailure()) { + // ATH_MSG_FATAL("Failed to retrieve " << "TauPi0CandidateDetailsContainer"); + // return StatusCode::FAILURE; + // } + } + + // set TauCandidate properties + rTauData.xAODTau = 0; + rTauData.xAODTauContainer = pContainer; + rTauData.tauAuxContainer = pAuxContainer; + + + //XXX leave this here for now until xAOD migration is completed + /* + rTauData.tauContainer = 0; + rTauData.detailsContainer = 0; + rTauData.extraDetailsContainer = 0; + rTauData.pi0DetailsContainer = 0; + rTauData.tau = 0; + rTauData.details = 0; + rTauData.extraDetails = 0; + rTauData.pi0Details = 0; + */ + rTauData.seed = 0; + rTauData.seedContainer = 0; + + //------------------------------------------------------------------------- + // Initialize tools for this event + //------------------------------------------------------------------------- + ToolHandleArray<TauToolBase> ::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase> ::iterator itTE = m_tools.end(); + for (; itT != itTE; ++itT) { + sc = (*itT)->eventInitialize(&rTauData); + if (sc != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + + //////////////////////////////////////////////////////// + + + //--------------------------------------------------------------------- + // Retrieve seed Container from TDS, return `failure' if not + // existing + //--------------------------------------------------------------------- + const xAOD::JetContainer * pSeedContainer; + sc = evtStore()->retrieve(pSeedContainer, m_seedContainerName); + // XXX still need to fix this. Currently only handle jets + // const DataHandle<INavigable4MomentumCollection> pSeedContainer; + // sc = evtStore()->retrieve(pSeedContainer, m_seedContainerName); + if (sc.isFailure() || !pSeedContainer) { + ATH_MSG_FATAL("No seed container with key:" << m_seedContainerName); + return StatusCode::FAILURE; + } + + //--------------------------------------------------------------------- + // Loop over seeds + //--------------------------------------------------------------------- + xAOD::JetContainer::const_iterator itS = pSeedContainer->begin(); + xAOD::JetContainer::const_iterator itSE = pSeedContainer->end(); + // XXX still need to fix this. Currently only handle jets + // INavigable4MomentumCollection::const_iterator itS = pSeedContainer->begin(); + // INavigable4MomentumCollection::const_iterator itSE = pSeedContainer->end(); + + ATH_MSG_VERBOSE("Number of seeds in the container: " << pSeedContainer->size()); + + rTauData.seedContainer = pSeedContainer; + + for (; itS != itSE; ++itS) { + const xAOD::Jet *pSeed = (*itS); + ATH_MSG_VERBOSE("Seeds eta:" << pSeed->eta() << ", pt:" << pSeed->pt()); + + if (fabs(pSeed->eta()) > m_maxEta) { + ATH_MSG_VERBOSE("--> Seed rejected, eta out of range!"); + continue; + } + + if (fabs(pSeed->pt()) < m_minPt) { + ATH_MSG_VERBOSE("--> Seed rejected, pt out of range!"); + continue; + } + + rTauData.seed = pSeed; + + //----------------------------------------------------------------- + // Seed passed cuts --> create tau candidate + //----------------------------------------------------------------- + rTauData.xAODTau = new xAOD::TauJet(); + rTauData.xAODTauContainer->push_back( rTauData.xAODTau ); + + //----------------------------------------------------------------- + // Process the candidate + //----------------------------------------------------------------- + ToolHandleArray<TauToolBase>::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase>::iterator itTE = m_tools.end(); + + //----------------------------------------------------------------- + // Loop stops when Failure indicated by one of the tools + //----------------------------------------------------------------- + for (; itT != itTE; ++itT) { + ATH_MSG_VERBOSE("Invoking tool " << (*itT)->name()); + + sc = (*itT)->execute(&rTauData); + + if (sc.isFailure()) + break; + } + + if (sc.isSuccess()) { + + + ATH_MSG_VERBOSE("The tau candidate has been registered"); + + //----------------------------------------------------------------- + // Process the candidate using endTools + //----------------------------------------------------------------- + //keep this here for future use (in case more than one seeding algo exist) + /* + ToolHandleArray<TauToolBase> ::iterator p_itET = m_endTools.begin(); + ToolHandleArray<TauToolBase> ::iterator p_itETE = m_endTools.end(); + for (; p_itET != p_itETE; ++p_itET) { + ATH_MSG_VERBOSE("Invoking endTool " << (*p_itET)->name()); + p_sc = (*p_itET)->execute(&rTauData); + if (p_sc.isFailure()) + break; + } + */ + ////////////////////////////////////////////////////// + + } else if (!sc.isSuccess()) { + //TODO:cleanup of EndTools not necessary?? + //keep this here for future use (in case more than one seeding algo exist) + /* + ToolHandleArray<TauToolBase> ::iterator p_itT1 = m_tools.begin(); + for (; p_itT1 != p_itT; ++p_itT1) + (*p_itT1)->cleanup(&rTauData); + (*p_itT1)->cleanup(&rTauData); + */ + rTauData.xAODTauContainer->pop_back(); + } else + rTauData.xAODTauContainer->pop_back(); + } + + + + //------------------------------------------------------------------------- + // Finalize tools for this event + //------------------------------------------------------------------------- + //TODO: line below necessary? + rTauData.xAODTau = 0; + + itT = m_tools.begin(); + itTE = m_tools.end(); + for (; itT != itTE; ++itT) { + sc = (*itT)->eventFinalize(&rTauData); + if (sc != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + + //keep this here for future use (in case more than one seeding algo exist) + /* + p_itET = m_endTools.begin(); + p_itETE = m_endTools.end(); + for (; p_itET != p_itETE; ++p_itET) { + p_sc = (*p_itET)->eventFinalize(&rTauData); + if (p_sc != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + */ + + /////////////////////////////////////////////////////// + + // locking of containers is moved to separate tau tool + + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauCalibrateEM.cxx b/Reconstruction/tauRec/src/TauCalibrateEM.cxx new file mode 100644 index 00000000000..dd81f02987c --- /dev/null +++ b/Reconstruction/tauRec/src/TauCalibrateEM.cxx @@ -0,0 +1,197 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "TFile.h" +#include "TF1.h" +#include "GaudiKernel/Property.h" +#include <PathResolver/PathResolver.h> +#include "CLHEP/Units/SystemOfUnits.h" +#include "EventKernel/SignalStateHelper.h" +#include "JetEvent/Jet.h" + +#include "xAODTau/TauJet.h" +#include "tauRec/TauCandidateData.h" +#include "tauRec/TauToolBase.h" +#include "tauRec/TauCalibrateEM.h" + +using CLHEP::GeV; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------ + +TauCalibrateEM::TauCalibrateEM(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); + declareProperty("response_functions_file", m_response_functions_file = "EMTES_Fits_Oct2010.root"); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauCalibrateEM::~TauCalibrateEM() { +} + +//------------------------------------------------------------------------- +// initialize +//------------------------------------------------------------------------- + +StatusCode TauCalibrateEM::initialize() { + + std::string response_functions_path = PathResolver::find_file(m_response_functions_file, "DATAPATH"); + TFile* f = TFile::Open(response_functions_path.c_str(), "READ"); + + m_f1_1p_lem = new TF1(*((TF1*) f->Get("OneP_LowEMF_Eta_All"))); + m_f1_1p_hem_barrel = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_0"))); + m_f1_1p_hem_crack = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_1"))); + m_f1_1p_hem_endcap = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_2"))); + m_f1_mp_barrel = new TF1(*((TF1*) f->Get("MultiP_Eta_0"))); + m_f1_mp_crack = new TF1(*((TF1*) f->Get("MultiP_Eta_1"))); + m_f1_mp_endcap = new TF1(*((TF1*) f->Get("MultiP_Eta_2"))); + + m_min_1p_lem.first = m_f1_1p_lem->GetMinimumX(1.5, 3.0); + m_min_1p_lem.second = m_f1_1p_lem->Eval(m_min_1p_lem.first); + m_min_1p_hem_barrel.first = m_f1_1p_hem_barrel->GetMinimumX(1.5, 3.0); + m_min_1p_hem_barrel.second = m_f1_1p_hem_barrel->Eval(m_min_1p_hem_barrel.first); + m_min_1p_hem_crack.first = m_f1_1p_hem_crack->GetMinimumX(1.5, 3.0); + m_min_1p_hem_crack.second = m_f1_1p_hem_crack->Eval(m_min_1p_hem_crack.first); + m_min_1p_hem_endcap.first = m_f1_1p_hem_endcap->GetMinimumX(1.5, 3.0); + m_min_1p_hem_endcap.second = m_f1_1p_hem_endcap->Eval(m_min_1p_hem_endcap.first); + m_min_mp_barrel.first = m_f1_mp_barrel->GetMinimumX(2.0, 3.0); + m_min_mp_barrel.second = m_f1_mp_barrel->Eval(m_min_mp_barrel.first); + m_min_mp_crack.first = m_f1_mp_crack->GetMinimumX(2.0, 3.0); + m_min_mp_crack.second = m_f1_mp_crack->Eval(m_min_mp_crack.first); + m_min_mp_endcap.first = m_f1_mp_endcap->GetMinimumX(2.5, 3.5); + m_min_mp_endcap.second = m_f1_mp_endcap->Eval(m_min_mp_endcap.first); + + f->Close(); + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// execute +//------------------------------------------------------------------------- + +StatusCode TauCalibrateEM::execute(TauCandidateData *data) { + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + const xAOD::Jet* pJetSeed = (*pTau->jetLink()); + + // XXX still need to migrate to signalstate handling of xAOD::Jet + // SignalStateHelper sigstateH(P4SignalState::JETEMSCALE); + // sigstateH.controlObject(pJetSeed); + + float emscale_ptEM = 0; + float emscale_ptHad = 0; + + if ( !pTau->detail( xAOD::TauJetParameters::etEMAtEMScale, emscale_ptEM ) ) + { + ATH_MSG_DEBUG("retrieval of tau detail failed. not calculating new em scale pt"); + return StatusCode::SUCCESS; + } + + if ( !pTau->detail( xAOD::TauJetParameters::etHadAtEMScale, emscale_ptHad ) ) + { + ATH_MSG_DEBUG("retrieval of tau detail failed. not calculating new em scale pt"); + return StatusCode::SUCCESS; + } + + double emscale_pt = emscale_ptEM + emscale_ptHad; + double emscale_eta = pJetSeed->eta(); + double emfrac = (emscale_pt != 0) ? emscale_ptEM / emscale_pt : 0.; + + + ATH_MSG_DEBUG("input variables: em_pt " << emscale_pt << " eta " << emscale_eta << " ntrack " << pTau->nTracks() << " emfrac " << emfrac); + + double new_pt = evaluate_new_pt(emscale_pt / GeV, fabs(emscale_eta), pTau->nTracks(), emfrac); + + + // do NOT set TauJet energy, as this will be done in tauCalibrateLC + //tau->setE( new_pt * GeV * cosh( tau->eta() ) ); + + // instead fill place holder in TauCommonDetails + //pDetails->setSeedCalo_etEMCalib(new_pt * GeV); + + pTau->setDetail( xAOD::TauJetParameters::EM_TES_scale, static_cast<float>( new_pt * GeV ) ); + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalize +//----------------------------------------------------------------------------- + +StatusCode TauCalibrateEM::finalize() { + delete m_f1_1p_lem; + delete m_f1_1p_hem_barrel; + delete m_f1_1p_hem_crack; + delete m_f1_1p_hem_endcap; + delete m_f1_mp_barrel; + delete m_f1_mp_crack; + delete m_f1_mp_endcap; + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// calculate new tau pt at EM scale +//----------------------------------------------------------------------------- + +double TauCalibrateEM::evaluate_new_pt(double pt, double eta, int ntrack, double emfrac) { + + if (pt <= 0)return 0; + double ln_pt = log(pt); + if (ln_pt > 8.5) return pt; + + if (ntrack <= 1) { + // corrections for single prong taus + + if (emfrac < 0.15) { + // corrections for low EMF + if (ln_pt < m_min_1p_lem.first) return pt / m_min_1p_lem.second; + else return pt / m_f1_1p_lem->Eval(ln_pt); + } else { + // corrections for high EMF + + if (eta < 1.3) { + if (ln_pt < m_min_1p_hem_barrel.first) return pt / m_min_1p_hem_barrel.second; + else return pt / m_f1_1p_hem_barrel->Eval(ln_pt); + } else if (eta < 1.6) { + if (ln_pt < m_min_1p_hem_crack.first) return pt / m_min_1p_hem_crack.second; + else return pt / m_f1_1p_hem_crack->Eval(ln_pt); + } else { + if (ln_pt < m_min_1p_hem_endcap.first) return pt / m_min_1p_hem_endcap.second; + else return pt / m_f1_1p_hem_endcap->Eval(ln_pt); + } + } + + } else { + // corrections for multi-prong taus + + if (eta < 1.3) { + if (ln_pt < m_min_mp_barrel.first) return pt / m_min_mp_barrel.second; + else return pt / m_f1_mp_barrel->Eval(ln_pt); + } else if (eta < 1.6) { + if (ln_pt < m_min_mp_crack.first) return pt / m_min_mp_crack.second; + else return pt / m_f1_mp_crack->Eval(ln_pt); + } else { + if (ln_pt < m_min_mp_endcap.first) return pt / m_min_mp_endcap.second; + else return pt / m_f1_mp_endcap->Eval(ln_pt); + } + } + + return pt; +} + +// EOF + + diff --git a/Reconstruction/tauRec/src/TauCalibrateLC.cxx b/Reconstruction/tauRec/src/TauCalibrateLC.cxx new file mode 100644 index 00000000000..dc4cc3f1db3 --- /dev/null +++ b/Reconstruction/tauRec/src/TauCalibrateLC.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "PathResolver/PathResolver.h" +#include "CLHEP/Vector/LorentzVector.h" +#include "CLHEP/Units/SystemOfUnits.h" + +// root +#include "TFile.h" +#include "TF1.h" +#include "TH1D.h" + +//tau +#include "xAODTau/TauJet.h" +#include "tauRec/TauCandidateData.h" +#include "tauRec/TauCalibrateLC.h" + +using CLHEP::GeV; + +/********************************************************************/ +TauCalibrateLC::TauCalibrateLC(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent), +m_doEnergyCorr(false), +m_doAxisCorr(false), +m_printMissingContainerINFO(true), +m_clusterCone(0.2) //not used +{ + declareInterface<TauToolBase > (this); + declareProperty("tauContainerKey", tauContainerKey = "TauRecContainer"); + declareProperty("calibrationFile", calibrationFile = "EnergyCalibrationLC2012.root"); + declareProperty("vertexContainerKey", vertexContainerKey = "PrimaryVertices"); + declareProperty("doEnergyCorrection", m_doEnergyCorr); + declareProperty("doAxisCorrection", m_doAxisCorr); + declareProperty("ClusterCone", m_clusterCone); //not used +} + +/********************************************************************/ +TauCalibrateLC::~TauCalibrateLC() { +} + +/********************************************************************/ +StatusCode TauCalibrateLC::initialize() { + std::string fullPath = PathResolver::find_file(calibrationFile, "DATAPATH"); + TFile * file = TFile::Open(fullPath.c_str(), "READ"); + + if (!file) { + ATH_MSG_FATAL("Failed to open " << fullPath); + return StatusCode::FAILURE; + } + + // get the histogram defining eta binning + std::string key = "etaBinning"; + TObject * obj = file->Get(key.c_str()); + if (obj) { + etaBinHist = dynamic_cast<TH1 *> (obj); + TH1 * tmp = const_cast<TH1*> (etaBinHist); + tmp->SetDirectory(0); + } else { + ATH_MSG_FATAL("Failed to get an object with key " << key); + return StatusCode::FAILURE; + } + + //retrieve number of eta bins from file + m_nEtaBins = etaBinHist->GetNbinsX(); //member var + if (m_nEtaBins==6) + ATH_MSG_INFO("using 2011 tau energy calibration"); + else if (m_nEtaBins==5) + ATH_MSG_INFO("using 2012 tau energy calibration"); + else { + ATH_MSG_FATAL("Wrong or broken tau energy calibration file"); + return StatusCode::FAILURE; + } + + // get the histogram with eta corrections + key = "etaCorrection"; + obj = file->Get(key.c_str()); + if (obj) { + etaCorrectionHist = dynamic_cast<TH1 *> (obj); + TH1 * tmp = const_cast<TH1*> (etaCorrectionHist); + tmp->SetDirectory(0); + } else { + ATH_MSG_FATAL("Failed to get an object with key " << key); + return StatusCode::FAILURE; + } + + TString tmpSlopKey[nProngBins] = {"slopeNPV1P", "slopeNPV3P"}; + TString tmpFuncBase[nProngBins] = {"OneP_Eta_", "MultiP_Eta_"}; + + for (int i = 0; i < nProngBins; i++) { + obj = file->Get(tmpSlopKey[i]); // get pile-up slope histograms + if (obj) { + slopeNPVHist[i] = dynamic_cast<TH1 *> (obj); + TH1 * tmp = const_cast<TH1*> (slopeNPVHist[i]); + tmp->SetDirectory(0); + } else { + ATH_MSG_FATAL("Failed to get an object with key " << tmpSlopKey[i]); + return StatusCode::FAILURE; + } + + for (int j = 0; j < m_nEtaBins; j++) { + TString key = tmpFuncBase[i]; + key += j; + TObject * obj = file->Get(key); + if (obj) { + calibFunc[i][j] = dynamic_cast<TF1*> (obj); + } else { + ATH_MSG_FATAL("Failed to get an object with key " << key); + return StatusCode::FAILURE; + } + } + } + m_averageNPV = slopeNPVHist[0]->GetBinContent(0); // underflow is the average number of reconstructed primary vertices + m_minNTrackAtVertex = static_cast<unsigned int> (slopeNPVHist[0]->GetBinContent(slopeNPVHist[0]->GetNbinsX() + 1)); //overflow is the minimum number of tracks at vertex + + ATH_MSG_DEBUG("averageNPV = " << m_averageNPV); + ATH_MSG_DEBUG("minimum number of tracks at primary vertex = " << m_minNTrackAtVertex); + + file->Close(); + + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode TauCalibrateLC::execute(TauCandidateData *data) +{ + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + // energy calibration depends on number of tracks - 1p or Mp + int prongBin = 1; //Mp + if (pTau->nTracks() <= 1) prongBin = 0; //1p + + // set tau energy scale + if (m_doEnergyCorr) { + + // get detector axis values + double eta = pTau->etaDetectorAxis(); + double absEta = std::abs(eta); + int etaBin = etaBinHist->GetXaxis()->FindBin(absEta) - 1; + + if (etaBin>=m_nEtaBins) etaBin = m_nEtaBins-1; // correction from last bin should be applied on all taus outside stored eta range + + // get primary vertex container + StatusCode sc; + const xAOD::VertexContainer * vxContainer = 0; + + // for tau trigger + bool inTrigger = false; + if (data->hasObject("InTrigger?")) sc = data->getObject("InTrigger?", inTrigger); + // FF: March, 2014 + // this is for later purpose. At the moment no offset correction is used in case of tau trigger (see below) + if (sc.isSuccess() && inTrigger) sc = data->getObject("VxPrimaryCandidate", vxContainer); + + if (!inTrigger || !vxContainer || sc.isFailure() ) { + // try standard + if (evtStore()->retrieve(vxContainer, vertexContainerKey).isFailure() || !vxContainer) { + if (m_printMissingContainerINFO) { + ATH_MSG_WARNING(vertexContainerKey << " container not found --> skip TauEnergyCalibrationLC (no further info) "); + m_printMissingContainerINFO=false; + } + return StatusCode::SUCCESS; + } + } + + xAOD::VertexContainer::const_iterator vx_iter = vxContainer->begin(); + xAOD::VertexContainer::const_iterator vx_end = vxContainer->end(); + int nVertex = 0; + for (; vx_iter != vx_end; ++vx_iter) { + if ((*vx_iter)->nTrackParticles() >= m_minNTrackAtVertex) + ++nVertex; + } + + ATH_MSG_DEBUG("calculated nVertex " << nVertex ); + + + // get detector axis energy + // was saved by TauAxisSetter + double energyLC = pTau->p4(xAOD::TauJetParameters::DetectorAxis).E() / GeV; //was sumClusterVector.e() / GeV; + + if (energyLC <= 0) { + ATH_MSG_DEBUG("tau energy at LC scale is " << energyLC << "--> set energy=0.001"); + //TODO: we can not set tau energy to 0 due to bug in P4Helpers during deltaR calculation + //will set it to 0.001 MeV + pTau->setP4(0.001, pTau->eta(), pTau->phi(), pTau->m()); + return StatusCode::SUCCESS; + } + + double slopeNPV = slopeNPVHist[prongBin]->GetBinContent(etaBin + 1); + double offset = slopeNPV * (nVertex - m_averageNPV); + + // FF: March,2014 + // no offset correction for trigger + if (inTrigger) offset = 0.; + + if (energyLC - offset <= 0) { + ATH_MSG_DEBUG("after pile-up correction energy would be = " << energyLC - offset << " --> setting offset=0 now!"); + offset = 0; + } + + // apply offset correction + double energyPileupCorr = energyLC - offset; + + double calibConst = 1.0; + if (energyPileupCorr > 0 and energyPileupCorr < 10000) // from 0 to 10 TeV + { + calibConst = calibFunc[prongBin][etaBin]->Eval(energyPileupCorr); + + if (calibConst <= 0) { + ATH_MSG_DEBUG("calibration constant = " << calibConst); + ATH_MSG_DEBUG("prongBin = " << prongBin); + ATH_MSG_DEBUG("etaBin = " << etaBin); + ATH_MSG_DEBUG("energyPileupCorr = " << energyPileupCorr); + ATH_MSG_DEBUG("energyLC = " << energyLC); + calibConst = 1.0; + } + } + + double energyFinal = energyPileupCorr / calibConst; + + pTau->setP4(energyFinal * GeV / cosh( pTau->eta() ), pTau->eta(), pTau->phi(), pTau->m()); + + pTau->setP4(xAOD::TauJetParameters::TauEnergyScale, pTau->pt(), pTau->eta(), pTau->phi(), pTau->m()); + + pTau->setDetail(xAOD::TauJetParameters::TESCalibConstant, static_cast<float>( calibConst ) ); + pTau->setDetail(xAOD::TauJetParameters::TESOffset, static_cast<float>( offset * GeV ) ); + + ATH_MSG_DEBUG("Energy at LC scale = " << energyLC << " pile-up offset " << offset << " calib. const. = " << calibConst << " final energy = " << energyFinal); + } + + // final tau axis + if (m_doAxisCorr) { + + // get tau intermediate axis values + double eta = pTau->eta(); + double absEta = std::abs(eta); + double etaCorr = eta; + + if (absEta) + etaCorr = (eta / absEta)*(absEta - etaCorrectionHist->GetBinContent(etaCorrectionHist->GetXaxis()->FindBin(absEta))); + + ATH_MSG_DEBUG("eta " << eta << "; corrected eta = " << etaCorr); + + pTau->setP4( pTau->e() / cosh( etaCorr ), etaCorr, pTau->phi(), pTau->m()); + + pTau->setP4(xAOD::TauJetParameters::TauEtaCalib, pTau->pt(), pTau->eta(), pTau->phi(), pTau->m()); + + } + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalize +//----------------------------------------------------------------------------- + +StatusCode TauCalibrateLC::finalize() { + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauCellVariables.cxx b/Reconstruction/tauRec/src/TauCellVariables.cxx new file mode 100644 index 00000000000..d30423c9d14 --- /dev/null +++ b/Reconstruction/tauRec/src/TauCellVariables.cxx @@ -0,0 +1,402 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +NAME: TauCellVariables.cxx +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: S. Rajagopalan +CREATED: March 15, 2001 + +Aug 2001: Add (e,px,py,pz) for sum of EM cells (FEP) +Veto cell if track is within 0.8*size. Hence 1 cell if track +is in center, more otherwise. + +Sep 2001: Take account of larger cells in third layer + +Nov 2001: Omit third layer of EM calorimeter from EM sums. This layer +can become quite thick in the barrel, so it is more likely to +be hadronic, while photons are mainly contained in the first +two layers. (D. Lissauer suggested this.) + +Dec 2002: Add tau likelihood calculation. +Feb 2003: Fix phi wrapping for et-weighted phi calculation. +Jan 2004: Use CLHEP units. Use phi = (-pi,pi]. +Feb 2004: Fix identifiers, add taucmsdrdR +March 2004: Fix CaloCluster -> CaloEnergyCluster +Jul 2004: force -PI < phi < PI +Jul 2004: move to I4Momentum +Aug 2004: admit arbitrary seeds +23/10/2006 - (AK) fixing some compilation warnings (unused parameter) +18/04/2007 - (AK) fixing some compilation warnings (unused parameter) +18/01/2008 - (NM) use etaCalo/phiCalo for merged algo, set tauJet eta/phi if not set by tau1p3p +16/03/2010 - (AK) use the cell id instead of the pointer +17/03/2010 - (AK) change to P4Helpers +16/05/2011 - (FF) introduce possibility to correct cell origin wrt to primary vertex and beamspot +Jan 2012 - (FF) add cellEnergyRing variables + ********************************************************************/ + +#include <algorithm> +#include <math.h> +#include <vector> +#include <sstream> + +#include "GaudiKernel/Property.h" +#include "CLHEP/Units/SystemOfUnits.h" + +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "CaloEvent/CaloSamplingHelper.h" +#include "CaloUtils/CaloVertexedCell.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "Particle/TrackParticle.h" +#include "FourMom/P4EEtaPhiM.h" + +#include "xAODTau/TauJet.h" +#include "xAODJet/Jet.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TauCellVariables.h" + +using CLHEP::GeV; + +TauCellVariables::TauCellVariables(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent), +m_cellEthr(0.2 * GeV), +m_stripEthr(0.2 * GeV), +m_EMSumThr(0.5 * GeV), +m_EMSumR(0.2), +m_cellCone(0.2), +m_doCellCorrection(false) //FF: don't do cell correction by default +{ + declareInterface<TauToolBase > (this); + + declareProperty("CellEthreshold", m_cellEthr); + declareProperty("StripEthreshold", m_stripEthr); + declareProperty("EMSumThreshold", m_EMSumThr); + declareProperty("EMSumRadius", m_EMSumR); + declareProperty("CellCone", m_cellCone); + declareProperty("CellCorrection", m_doCellCorrection); +} + +TauCellVariables::~TauCellVariables() { +} + +StatusCode TauCellVariables::initialize() { + + ATH_MSG_VERBOSE("TauCellVariables::initialize"); // DEBUG + + StatusCode sc; + + // retrieve all helpers from det store + sc = detStore()->retrieve(m_emid); + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to retrieve LArEM_ID helper from DetectorStore"); + return sc; + } + ATH_MSG_VERBOSE("Storegate retrieved"); // DEBUG + + sc = detStore()->retrieve(m_tileid); + if (sc.isFailure()) { + ATH_MSG_ERROR("Unable to retrieve TileID helper from DetectorStore"); + return sc; + } + ATH_MSG_VERBOSE("TileID from DetectorStore"); // DEBUG + + return StatusCode::SUCCESS; +} + +StatusCode TauCellVariables::eventInitialize(TauCandidateData * /*data*/) { + return StatusCode::SUCCESS; +} + +StatusCode TauCellVariables::execute(TauCandidateData *data) { + + ATH_MSG_VERBOSE("execute"); // DEBUG + + AtlasDetectorID AtlasID; + + int numStripCell = 0; + int numEMCell = 0; + + double sumCellE = 0.; + double sumEMCellE = 0.; + + double eta = 0.; + double phi = 0.; + double stripEta = 0.; + double stripEta2 = 0.; + + double EMRadius = 0.; + + double sumStripET = 0.; + double sumCellET = 0.; + double sumEMCellET = 0.; + double sumCellET12 = 0.; + + double ET1Sum = 0; + + double EMET1Sum = 0; + double EMET4Sum = 0; + + double HadRadius = 0.; + double sumHadCellET = 0.; + + double cellEta, cellPhi, cellET, cellEnergy; + + std::vector<double> vCellRingEnergy(8,0.); //size=8, init with 0. + + /////////////////////////////////////////// + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + /////////////////////////////////////////// + + ATH_MSG_VERBOSE("get cluster position, use for cell loop"); + + ATH_MSG_VERBOSE("position is eta=" << pTau->eta() << " phi=" << pTau->phi() ); + + //use tau vertex to correct cell position + bool applyCellCorrection = false; + if (m_doCellCorrection && pTau->vertexLink()) { + applyCellCorrection = true; + } + + /////////////////////////////////////////////////////////////////////// + // loop over all cells of the tau (placed there by the TauSeedBuilder) + + const xAOD::Jet* pJetSeed = (*pTau->jetLink()); + if (!pJetSeed) { + ATH_MSG_WARNING("tau does not have jet seed for cell variable calculation"); + return StatusCode::SUCCESS; + } + + xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin(); + xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end(); + + unsigned int num_cells = 0; + + std::bitset<200000> cellSeen; + + for (; cItr != cItrE; ++cItr) { + + const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); + + CaloClusterCellLink::const_iterator firstcell = cluster->getCellLinks()->begin(); + CaloClusterCellLink::const_iterator lastcell = cluster->getCellLinks()->end(); + + + // ATH_MSG_VERBOSE( "in loop over clusters and cells : cluster phi= " << cluster->phi() << ", eta= " << cluster->eta()<< ", energy= " << cluster->e() << ", et= " <<cluster->pt() ); + + const CaloCell *cell; + double dR; + + //loop over cells and calculate the variables + for (; firstcell != lastcell; ++firstcell) { + cell = *firstcell; + + + if (cellSeen.test(cell->caloDDE()->calo_hash())) { + //already encountered this cell + continue; + } + else { + //New cell + cellSeen.set(cell->caloDDE()->calo_hash()); + } + ++num_cells; + + // ATH_MSG_VERBOSE( "in loop over clusters and cells : phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() ); + + // correct cell for tau vertex + if (applyCellCorrection) { + //ATH_MSG_INFO( "before cell correction: phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() ); + CaloVertexedCell vxCell (*cell, (*pTau->vertexLink())->position()); + cellPhi = vxCell.phi(); + cellEta = vxCell.eta(); + cellET = vxCell.et(); + cellEnergy = vxCell.energy(); + } + else { + cellPhi = cell->phi(); + cellEta = cell->eta(); + cellET = cell->et(); + cellEnergy = cell->energy(); + } + + CaloSampling::CaloSample calo = cell->caloDDE()->getSampling(); + + // Use cells those are in DR < m_cellCone of eta,phi of tau intermediate axis: + dR = Tau1P3PKineUtils::deltaR(pTau->eta(),pTau->phi(),cellEta,cellPhi); + + if (dR < m_cellCone) { + // Global sums + sumCellE += cellEnergy; + + eta += cellEnergy * cellEta; + + // Must handle phi wrapping! Compute relative to cluster phi: + double dphicc = cellPhi - pTau->phi(); + if (dphicc > M_PI) dphicc = dphicc - 2 * M_PI; + if (dphicc < -M_PI) dphicc = dphicc + 2 * M_PI; + + phi += cellEnergy*dphicc; + + // If cell is an EM cell, include in sum for EM radius and for + // total EM (e,px,py,pz) + // Nov 2000: Only include first 2 layers in EM + + if (dR < 0.1) ET1Sum += cellET; + + if ((calo == CaloSampling::PreSamplerB) || + (calo == CaloSampling::PreSamplerE) || + + (calo == CaloSampling::EMB1) || + (calo == CaloSampling::EME1) || + + (calo == CaloSampling::EMB2) || + (calo == CaloSampling::EME2) || + + (calo == CaloSampling::EMB3) || + (calo == CaloSampling::EME3)) { + if (dR < 0.1) EMET1Sum += cellET; + if (dR < m_cellCone) EMET4Sum += cellET; + } + + if ((calo == CaloSampling::PreSamplerB) || + (calo == CaloSampling::PreSamplerE) || + + (calo == CaloSampling::EMB1) || + (calo == CaloSampling::EME1) || + + (calo == CaloSampling::EMB2) || + (calo == CaloSampling::EME2)) { + + sumEMCellE += cellEnergy; + + // If cell is a strip cell, sum for stripET calculation: + if (((calo == CaloSampling::EMB1) || + (calo == CaloSampling::EME1)) // to be investigated + && (fabs(cellEta) < 2.5)) { + sumStripET += cellET; + stripEta += cellEta * cellET; + stripEta2 += pow(cellEta, 2) * cellET; + if (cellEnergy > m_stripEthr) numStripCell += 1; + } // end of strip cells + + EMRadius += dR*cellET; + sumEMCellET += cellET; + if (cellEnergy > m_cellEthr) numEMCell += 1; + + }// end of EM cells + else { // HAD cells + HadRadius += dR*cellET; + sumHadCellET += cellET; + } + + // Sum cells in 0.1 < DR < 0.2 for Econe calculation + sumCellET += cellET; + if (dR > 0.1 && dR < 0.2) sumCellET12 += cellET; + + }// end of dR < m_cellCone + else { + // nothing + } + + // vCellRingEnergy[0] is a dummy value + if (dR < 0.05) vCellRingEnergy[1] += cellET; + if (dR >= 0.05 && dR < 0.075) vCellRingEnergy[2] += cellET; + if (dR >= 0.075 && dR < 0.1) vCellRingEnergy[3] += cellET; + if (dR >= 0.1 && dR < 0.125) vCellRingEnergy[4] += cellET; + if (dR >= 0.125 && dR < 0.15) vCellRingEnergy[5] += cellET; + if (dR >= 0.15 && dR < 0.2) vCellRingEnergy[6] += cellET; + if (dR >= 0.2 && dR < 0.4) vCellRingEnergy[7] += cellET; + + } // end of loop over CaloCells + + }// end of loop over seed jet constituents + + ATH_MSG_DEBUG(num_cells << " cells in seed"); + + ////////////////////////////////////////////////////////////////////////// + // save variables + // keep this here until we know nobody complains that these were removed together with all extra details variables + // pExtraDetails->setSeedCalo_sumCellEnergy(sumCellE); + // pExtraDetails->setSeedCalo_sumEMCellEnergy(sumEMCellE); + // pExtraDetails->setSeedCalo_nEMCell(numEMCell); + // pExtraDetails->setSeedCalo_stripEt(sumStripET); + // + + pTau->setDetail(xAOD::TauJetParameters::nStrip , numStripCell ); + + // if (fabs(EMET4Sum) > 0.000001) + // pExtraDetails->setSeedCalo_EMCentFrac(EMET1Sum / EMET4Sum); + // else + // pExtraDetails->setSeedCalo_EMCentFrac(0); + + if (fabs(sumStripET) > 0.000001) { + stripEta = stripEta / sumStripET; + stripEta2 = stripEta2 / sumStripET; + } else { + stripEta = 0; + stripEta2 = -1.0; + } + + pTau->setDetail(xAOD::TauJetParameters::stripWidth2 , static_cast<float>(stripEta2 - stripEta * stripEta) ); + + if (fabs(sumEMCellET) > 0.000001) { + EMRadius = EMRadius / sumEMCellET; + } else { + EMRadius = -1.0; + } + if (fabs(sumHadCellET) > 0.000001) { + HadRadius = HadRadius / sumHadCellET; + } else { + HadRadius = -1.0; + } + + pTau->setDetail(xAOD::TauJetParameters::EMRadius , static_cast<float>( EMRadius ) ); + pTau->setDetail(xAOD::TauJetParameters::etEMAtEMScale , static_cast<float>( sumEMCellET ) ); + pTau->setDetail(xAOD::TauJetParameters::hadRadius , static_cast<float>( HadRadius ) ); + pTau->setDetail(xAOD::TauJetParameters::etHadAtEMScale , static_cast<float>( sumHadCellET ) ); + + if (fabs(sumCellET) > 0.000001) { + pTau->setDetail(xAOD::TauJetParameters::centFrac , static_cast<float>( ET1Sum / sumCellET ) ); + pTau->setDetail(xAOD::TauJetParameters::isolFrac , static_cast<float>( sumCellET12 / sumCellET ) ); + } else { + pTau->setDetail(xAOD::TauJetParameters::centFrac , static_cast<float>( 0.0 ) ); + pTau->setDetail(xAOD::TauJetParameters::isolFrac , static_cast<float>( -1.0 ) ); + } + + //save cell ring energies + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing1 , static_cast<float>( vCellRingEnergy[1] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing2 , static_cast<float>( vCellRingEnergy[2] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing3 , static_cast<float>( vCellRingEnergy[3] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing4 , static_cast<float>( vCellRingEnergy[4] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing5 , static_cast<float>( vCellRingEnergy[5] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing6 , static_cast<float>( vCellRingEnergy[6] ) ); + + pTau->setDetail(xAOD::TauJetParameters::cellBasedEnergyRing7 , static_cast<float>( vCellRingEnergy[7] ) ); + + return StatusCode::SUCCESS; +} + + + + diff --git a/Reconstruction/tauRec/src/TauCommonCalcVars.cxx b/Reconstruction/tauRec/src/TauCommonCalcVars.cxx new file mode 100644 index 00000000000..ff2ad3048e0 --- /dev/null +++ b/Reconstruction/tauRec/src/TauCommonCalcVars.cxx @@ -0,0 +1,226 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauCommonCalcVars.cxx +// package: Reconstruction/tauRec +// authors: Stan Lai +// date: 2008-05-18 +// +// This class calculates tau variables after core seed reconstruction +// +// 17/03/2010: (AK) change to P4Helpers +// 16/05/2011: (FF) fix if primaryVertexContainer==NULL (coverity 21734) +// Dez 2011: (FF) switch to full LC calibrated tau 4-vector for some variables +//----------------------------------------------------------------------------- +//TODO: rename + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +#include "tauRec/TauCandidateData.h" + +#include "tauRec/TauCommonCalcVars.h" +#include "tauRec/KineUtils.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauCommonCalcVars::TauCommonCalcVars(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauCommonCalcVars::~TauCommonCalcVars() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauCommonCalcVars::initialize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauCommonCalcVars::finalize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauCommonCalcVars::execute(TauCandidateData *data) { + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + ///////////////////////////////////////////////// + // Calculate variables that are always valid + //////////////////////////////////////////////// + + // Leading track pT and et/pt(lead track) + if (pTau->nTracks() > 0) { + pTau->setDetail( xAOD::TauJetParameters::leadTrkPt, static_cast<float>( pTau->track(0)->pt() ) ); + + float emscale_ptEM = 0; + float emscale_ptHad = 0; + + if ( !pTau->detail( xAOD::TauJetParameters::etEMAtEMScale, emscale_ptEM ) ) + { + ATH_MSG_DEBUG("retrieval of tau detail failed. stopping calculation of further variables"); + return StatusCode::SUCCESS; + } + + if ( !pTau->detail( xAOD::TauJetParameters::etHadAtEMScale, emscale_ptHad ) ) + { + ATH_MSG_DEBUG("retrieval of tau detail failed. stopping calculation of further variables"); + return StatusCode::SUCCESS; + } + + //EM scale + + pTau->setDetail( xAOD::TauJetParameters::etOverPtLeadTrk, static_cast<float>( (emscale_ptEM + emscale_ptHad) / pTau->track(0)->pt() ) ); + + //switch to LC energy scale + //pDetails->setEtOverPtLeadTrk(pDetails->LC_TES_precalib() / fabs(pTau->track(0)->pt())); + } + + // XXX still need to decide whether we want to fill loose track variables anymore + // // Leading loose track pT and et/pt(lead loose track) + // if (pDetails->nLooseTrk() > 0) { + // pDetails->setLeadLooseTrkPt(pDetails->looseTrk(0)->pt()); + // //EM scale + // pDetails->setEtOverPtLeadLooseTrk((pDetails->seedCalo_etHadCalib() + pDetails->seedCalo_etEMCalib()) / fabs(pDetails->looseTrk(0)->pt())); + // //LC scale + // //pDetails->setEtOverPtLeadLooseTrk(pDetails->LC_TES_precalib() / fabs(pDetails->looseTrk(0)->pt())); + // } + + // invariant mass of track system + if ((pTau->nTracks() + pTau->nWideTracks()) > 0) { + + TLorentzVector sumOfTrackVector; + TLorentzVector tempTrackVector; + + for (unsigned int i = 0; i != pTau->nTracks(); ++i) + { + tempTrackVector.SetPtEtaPhiM( pTau->track(i)->pt(), pTau->track(i)->eta(), pTau->track(i)->phi(), pTau->track(i)->m()); + sumOfTrackVector += tempTrackVector; + } + for (unsigned int i = 0; i != pTau->nWideTracks(); ++i) + { + tempTrackVector.SetPtEtaPhiM( pTau->wideTrack(i)->pt(), pTau->wideTrack(i)->eta(), pTau->wideTrack(i)->phi(), pTau->wideTrack(i)->m()); + sumOfTrackVector += tempTrackVector; + } + + pTau->setDetail( xAOD::TauJetParameters::massTrkSys, static_cast<float>( sumOfTrackVector.M() ) ); + float tempfloat = 0; + if ( pTau->detail( xAOD::TauJetParameters::massTrkSys, tempfloat ) ) + ATH_MSG_VERBOSE("set massTrkSys " << tempfloat); + } + + // width of track system squared (trkWidth2) + if (pTau->nTracks() > 1) { + + double leadTrkPhi = pTau->track(0)->phi(); + double leadTrkEta = pTau->track(0)->eta(); + + double ptSum = 0; + double sumWeightedDR = 0; + double sumWeightedDR2 = 0; + + for (unsigned int i = 0; i != pTau->nTracks(); ++i) { + + double deltaR = Tau1P3PKineUtils::deltaR(leadTrkEta, leadTrkPhi, pTau->track(i)->eta(), pTau->track(i)->phi() ); + + ptSum += pTau->track(i)->pt(); + sumWeightedDR += deltaR * (pTau->track(i)->pt()); + sumWeightedDR2 += deltaR * deltaR * (pTau->track(i)->pt()); + } + + for (unsigned int i = 0; i != pTau->nWideTracks(); ++i) { + + double deltaR = Tau1P3PKineUtils::deltaR(leadTrkEta, leadTrkPhi, pTau->wideTrack(i)->eta(), pTau->wideTrack(i)->phi() ); + + ptSum += pTau->wideTrack(i)->pt(); + sumWeightedDR += deltaR * (pTau->wideTrack(i)->pt()); + sumWeightedDR2 += deltaR * deltaR * (pTau->wideTrack(i)->pt()); + } + + double trkWidth2 = sumWeightedDR2 / ptSum - sumWeightedDR * sumWeightedDR / ptSum / ptSum; + + if (trkWidth2 > 0.) pTau->setDetail( xAOD::TauJetParameters::trkWidth2, static_cast<float>( trkWidth2 ) ); + else pTau->setDetail( xAOD::TauJetParameters::trkWidth2, static_cast<float>( 0. ) ); + } + + // Calculation for seedCalo_trkAvgDist and seedCalo_trkRmsDist + + //FF: use now the 4-vector of the tau intermediate axis + //P4EEtaPhiM P4CaloSeed(1., pDetails->seedCalo_eta(), pDetails->seedCalo_phi(), 0.); + + if ((pTau->nWideTracks() + pTau->nTracks()) > 0) { + + double ptSum = 0; + double sumWeightedDR = 0; + double sumWeightedDR2 = 0; + + for (unsigned int i = 0; i != pTau->nTracks(); ++i) { + + double deltaR = Tau1P3PKineUtils::deltaR(pTau->eta(), pTau->phi(), pTau->track(i)->eta(), pTau->track(i)->phi() ); + + ptSum += pTau->track(i)->pt(); + sumWeightedDR += deltaR * (pTau->track(i)->pt()); + sumWeightedDR2 += deltaR * deltaR * (pTau->track(i)->pt()); + } + + for (unsigned int i = 0; i != pTau->nWideTracks(); ++i) { + + double deltaR = Tau1P3PKineUtils::deltaR(pTau->eta(), pTau->phi(), pTau->wideTrack(i)->eta(), pTau->wideTrack(i)->phi() ); + + ptSum += pTau->wideTrack(i)->pt(); + sumWeightedDR += deltaR * (pTau->wideTrack(i)->pt()); + sumWeightedDR2 += deltaR * deltaR * (pTau->wideTrack(i)->pt()); + } + + if (ptSum > 0.0001) { + // seedCalo_trkAvgDist + pTau->setDetail( xAOD::TauJetParameters::trkAvgDist, static_cast<float>( sumWeightedDR / ptSum ) ); + + float tempfloat; + if ( pTau->detail( xAOD::TauJetParameters::trkAvgDist, tempfloat ) ) + ATH_MSG_VERBOSE("set seedCalo_trkAvgDist " << tempfloat ); + + // seedCalo_trkRmsDist + double trkRmsDist2 = sumWeightedDR2 / ptSum - sumWeightedDR * sumWeightedDR / ptSum / ptSum; + if (trkRmsDist2 > 0) { + pTau->setDetail( xAOD::TauJetParameters::trkRmsDist, static_cast<float>( sqrt(trkRmsDist2) ) ); + } else { + pTau->setDetail( xAOD::TauJetParameters::trkRmsDist, static_cast<float>( 0. ) ); + } + if ( pTau->detail( xAOD::TauJetParameters::trkRmsDist, tempfloat ) ) + ATH_MSG_VERBOSE("set seedCalo_trkRmsDist " << tempfloat ); + } + } + + return StatusCode::SUCCESS; +} + + diff --git a/Reconstruction/tauRec/src/TauConversionFinder.cxx b/Reconstruction/tauRec/src/TauConversionFinder.cxx new file mode 100644 index 00000000000..f5636b97b40 --- /dev/null +++ b/Reconstruction/tauRec/src/TauConversionFinder.cxx @@ -0,0 +1,153 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +NAME: TauConversionFinder.cxx +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: Michael Boehler <michael.boehler@desy.de> +CREATED: November 2008 + +This tool identifies if a tau track is reconstructed as photon +conversion track too. + ********************************************************************/ + +#include "tauRec/TauConversionFinder.h" + +#include "xAODTracking/VertexContainer.h" +#include "GaudiKernel/IToolSvc.h" +#include "TrkParticleBase/LinkToTrackParticleBase.h" + +/********************************************************************/ +TauConversionFinder::TauConversionFinder(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); + + declareProperty("ConversionCandidatesName", m_ConversionCandidatesName = "ConversionsPID_Container"); //ConversionCandidate + declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles"); + declareProperty("DoNormalTracks", m_do_normal = true); + declareProperty("MinElectronProbability", m_eProb_cut = 0.9); + declareProperty("AdjustTauCharge", m_adjust_tau_charge = false); + +} + +/********************************************************************/ +TauConversionFinder::~TauConversionFinder() { +} + +/********************************************************************/ +StatusCode TauConversionFinder::initialize() { + ATH_MSG_VERBOSE("TauConversionFinder Initialising"); + + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode TauConversionFinder::finalize() { + ATH_MSG_VERBOSE("TauConversionFinder Finalizing"); + + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode TauConversionFinder::eventFinalize(TauCandidateData *data) { + + StatusCode sc; + + const Rec::TrackParticleContainer *trackContainer; + + //TODO: trigger uses getObject + sc = evtStore()->retrieve(trackContainer, m_trackContainerName); + if (sc.isFailure() || !trackContainer) { + ATH_MSG_DEBUG(" No track container found in TDS !!"); + return StatusCode::SUCCESS; + } + + // ------------------------------------------------------------------ + // Retrieving VxCandidates (conversions) + // ------------------------------------------------------------------ + const xAOD::VertexContainer* ConvContainer; + + sc = evtStore()->retrieve(ConvContainer, m_ConversionCandidatesName); + if (sc.isFailure() || !ConvContainer) { + ATH_MSG_DEBUG(" No VxCandidates container found in TDS !!"); + return StatusCode::SUCCESS; + } else { + ATH_MSG_VERBOSE("Processing Conversion Container Name = " << m_ConversionCandidatesName); + } + ATH_MSG_VERBOSE("VxContainer " << m_ConversionCandidatesName << " contains " << ConvContainer->size() << " vertices. "); + + // ------------------------------------------------------------------ + // Check number of Tau Tracks + // ------------------------------------------------------------------ + if (!m_do_normal) { + return StatusCode::SUCCESS; + } + + // running in eventFinalize + // therefore need to loop over all tau candidates + xAOD::TauJetContainer *pTauJetCont = data->xAODTauContainer; + for (xAOD::TauJetContainer::iterator tjcItr = pTauJetCont->begin(); tjcItr != pTauJetCont->end(); ++tjcItr) { + + xAOD::TauJet *pTau = *tjcItr; + if (pTau == NULL) { + ATH_MSG_DEBUG("no candidate given"); + continue; + } + + unsigned int numTracks = pTau->nTracks(); + + m_numProng = numTracks; + + if (m_do_normal) + ATH_MSG_VERBOSE("Number of tau tracks before ConversionFinder (TauJet): " << m_numProng); + + // Loop over Conversion Container placed by TauPhotonConversionFinder + xAOD::VertexContainer::const_iterator itr = ConvContainer->begin(); + xAOD::VertexContainer::const_iterator itrE = ConvContainer->end(); + for (; itr != itrE; ++itr) { + + const xAOD::Vertex* vxcand = (*itr); + + for (unsigned int i = 0; i < vxcand->nTrackParticles(); ++i) { + + const Trk::Track* conv_trk = vxcand->trackParticle(i)->track(); + // just check if the track is reconstructed only by TRT + //-------------------------------------------- + // Find conversion in normal tau tracks + if (m_do_normal) { + for (unsigned int j = 0; j < numTracks; ++j) { + const xAOD::TrackParticle *pTauTrack = pTau->track(j); + const Trk::Track* tau_trk_def = pTauTrack->track(); + + if (conv_trk == tau_trk_def) { + if (conv_trk->trackSummary()->getPID(Trk::eProbabilityComb) > m_eProb_cut) { + bool isConversionTrack = false; + for (unsigned int k = 0; k < pTau->nConversionTracks(); k++) { + if (pTau->conversionTrack(k)->track() == pTau->track(j)->track()) + isConversionTrack = true; + } + if (isConversionTrack) { + pTau->addConversionTrackLink(pTau->conversionTrackLinks().at(j)); + if (m_adjust_tau_charge) + pTau->setCharge(pTau->charge() - pTau->track(j)->charge()); + + m_numProng--; + } + } + } + } + } + }//end of loop over Tracks at vertex + }// end of loop over VxContainer + + if (m_do_normal) + ATH_MSG_VERBOSE("Number of tau tracks after ConversionFinder (TauJet): " << m_numProng); + }// end of loop over TauJetContainer + + return StatusCode::SUCCESS; +} + +/********************************************************************/ diff --git a/Reconstruction/tauRec/src/TauConversionTagger.cxx b/Reconstruction/tauRec/src/TauConversionTagger.cxx new file mode 100644 index 00000000000..75b705bdfd5 --- /dev/null +++ b/Reconstruction/tauRec/src/TauConversionTagger.cxx @@ -0,0 +1,179 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauConversionTagger.cxx +// package: Reconstruction/tauRec +// authors: Dimitris Varouchas +// date: 2013-11-08 +// +// +//----------------------------------------------------------------------------- +//TODO: + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" +#include "CLHEP/Vector/LorentzVector.h" +#include "Particle/TrackParticle.h" + +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventID.h" +#include "TrkParameters/TrackParameters.h" + +#include "tauRec/TauCandidateData.h" +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauJetParameters.h" + +#include "tauRec/TauConversionTagger.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauConversionTagger::TauConversionTagger(const std::string &type, + const std::string &name, + const IInterface *parent) : + TauToolBase(type, name, parent), + m_trackToVertexTool("Reco::TrackToVertex") +{ + declareInterface<TauToolBase > (this); + + declareProperty("ConversionTaggerVersion", m_ConvTaggerVer = 1); + declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles"); + declareProperty("TrackToVertexTool", m_trackToVertexTool); + declareProperty ("TRTRatio", m_doTRTRatio = true); + declareProperty ("FullInfo", m_storeFullSummary = false); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauConversionTagger::~TauConversionTagger() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauConversionTagger::initialize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauConversionTagger::finalize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauConversionTagger::execute(TauCandidateData *data) { + xAOD::TauJet *pTau = data->xAODTau; + + StatusCode sc; + + sc = m_trackToVertexTool.retrieve(); + if(sc.isFailure()) { + ATH_MSG_ERROR("Could not retrieve TrackToVertexTool"); + return StatusCode::FAILURE; + } + + for(unsigned int j=0; j<pTau->nTracks(); j++ ) { + + const xAOD::TrackParticle *TauJetTrack = pTau->track(j); + const Trk::Perigee* perigee = m_trackToVertexTool->perigeeAtVertex(*TauJetTrack, (*pTau->vertexLink())->position()); + + // Declare TrackSummary info + // Note: all must be of type uint8_t for summaryValue filling to work in xAOD + // TODO: check if these default values are sane + uint8_t nBLHits = 0; + uint8_t expectBLayerHit = 0; + uint8_t nTRTHighTHits = 0; + uint8_t nTRTHighTOutliers = 0; + float nTRTHighT_outl = 0.; + uint8_t nTRTXenon = 0; + uint8_t nTRTHits = 0; + uint8_t nTRTOutliers = 0; + + // Fill TrackSummary info + TauJetTrack->summaryValue(nBLHits,xAOD::numberOfBLayerHits); + TauJetTrack->summaryValue(expectBLayerHit,xAOD::expectBLayerHit); + TauJetTrack->summaryValue(nTRTHighTHits,xAOD::numberOfTRTHighThresholdHits); + TauJetTrack->summaryValue(nTRTHighTOutliers,xAOD::numberOfTRTHighThresholdOutliers); + nTRTHighT_outl = nTRTHighTHits + nTRTHighTOutliers; + TauJetTrack->summaryValue(nTRTXenon,xAOD::numberOfTRTXenonHits); + TauJetTrack->summaryValue(nTRTHits,xAOD::numberOfTRTHits); + TauJetTrack->summaryValue(nTRTOutliers,xAOD::numberOfTRTOutliers); + + // TODO: check if default value is sane + m_TRTHighTOutliersRatio = 0.; + if (m_doTRTRatio || m_storeFullSummary) { + if (nTRTXenon > 0) + m_TRTHighTOutliersRatio = nTRTHighT_outl / nTRTXenon; + else if (nTRTHits + nTRTOutliers > 0) + m_TRTHighTOutliersRatio = nTRTHighT_outl / (nTRTHits+nTRTOutliers); + } + + double pt = TauJetTrack->pt(); + double d0 = perigee->parameters()[Trk::d0]; + + + m_TrkIsConv = false; + + float Rconv = sqrt (fabs(d0)*pt/(0.15*2.)); + + if ( m_ConvTaggerVer==0 ) { + + m_a_cut[0][0]=0.0003; m_b_cut[0][0]=0.1725; + m_a_cut[0][1]=0.0003; m_b_cut[0][1]=0.2025; + + if ( nBLHits==0 && expectBLayerHit ){ + if( m_TRTHighTOutliersRatio > -m_a_cut[0][0]*Rconv + m_b_cut[0][0] ) m_TrkIsConv=true; + } + else { + if( m_TRTHighTOutliersRatio > -m_a_cut[0][1]*Rconv + m_b_cut[0][1] ) m_TrkIsConv=true; + } + } + + else if ( m_ConvTaggerVer==1 ) { + + m_a_cut[1][0]=0.0003; m_b_cut[1][0]=0.1725; + m_a_cut[1][1]=0.0003; m_b_cut[1][1]=0.2025; + + + if(nBLHits==0 ){ + if( m_TRTHighTOutliersRatio > -m_a_cut[1][0]*Rconv + m_b_cut[1][0] ) m_TrkIsConv=true; + } + else { + if( m_TRTHighTOutliersRatio > -m_a_cut[1][1]*Rconv + m_b_cut[1][1] ) m_TrkIsConv=true; + } + } + + else { + + ATH_MSG_WARNING("No tau conversion tagger compatible with version "<<m_ConvTaggerVer); + return false; + } + + ATH_MSG_VERBOSE("Is tau track a conversion? : " << m_TrkIsConv); + if (m_TrkIsConv) + pTau->addConversionTrackLink((&pTau->trackLinks())->at(j)); + + delete perigee; //cleanup necessary to prevent mem leak + + } + + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/tauRec/src/TauElectronVetoVariables.cxx b/Reconstruction/tauRec/src/TauElectronVetoVariables.cxx new file mode 100644 index 00000000000..f788db96a04 --- /dev/null +++ b/Reconstruction/tauRec/src/TauElectronVetoVariables.cxx @@ -0,0 +1,390 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: tau1p3pEleVeto.cxx +// package: Reconstruction/tauRec +// authors: Zofia Czyczula +// date: 2006-09-27 +// +// +// This tool veto electrons. +// +// MODIFIED: +// 02-04-2007 - (AK) protection against missing egamma Collection +// 25-03-2008 - (AK for ZC) upgade of the code +// 28-03-1008 - (AK) fix for protection against missing egamma Collection +// ERROR->WARNING +// 15/04/2008 - (AK) fixing compilation warning bug #35463 +// 03-10-2008 - (ZC) upgarade of the code +// 16/03/2010 - (AK) use the cell id instead of the pointer +//----------------------------------------------------------------------------- + +//// +//TODO: this is cell based and use tracking variables -> can not run on AOD +//TODO: rename +// + +#include <algorithm> +#include <math.h> +#include <sstream> + +#include "GaudiKernel/ListItem.h" +#include "GaudiKernel/IToolSvc.h" +#include "GaudiKernel/Property.h" + +#include "CaloUtils/CaloCellList.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "CaloUtils/CaloVertexedCell.h" +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloGeoHelpers/CaloSampling.h" + +#include "xAODTau/TauJet.h" +#include "xAODJet/Jet.h" +#include "tauRec/KineUtils.h" + +#include "RecoToolInterfaces/IExtrapolateToCaloTool.h" +#include "tauRec/TauElectronVetoVariables.h" + +using CLHEP::GeV; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- +TauElectronVetoVariables::TauElectronVetoVariables(const std::string &type, + const std::string &name, + const IInterface *parent): +TauToolBase(type, name, parent), +m_doCellCorrection(false), //FF: don't do cell correction by default +m_trackToCalo("") +{ + declareInterface<TauToolBase > (this); + + declareProperty("CellCorrection", m_doCellCorrection); + declareProperty("TTCExtrapolator", m_trackToCalo, "public track extrapolator tool to match track with caloseed"); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- +TauElectronVetoVariables::~TauElectronVetoVariables() { } + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- +StatusCode TauElectronVetoVariables::initialize() +{ + if (m_trackToCalo.retrieve().isFailure()) { + ATH_MSG_ERROR("Cannot find tool named <" << m_trackToCalo << ">"); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; +} +StatusCode TauElectronVetoVariables::eventInitialize(TauCandidateData * /*data*/) +{ + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// Execution +//------------------------------------------------------------------------- +StatusCode TauElectronVetoVariables::execute(TauCandidateData *data) +{ + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + + if (pTau->nTracks() < 1) { + return StatusCode::SUCCESS; + } + + ATH_MSG_VERBOSE(name() << " in execute() ..."); + + float detPhiTrk = 0.; + float detEtaTrk = 0.; + float clEtaTrk = 0.; + float distEtaTrk = 0.; + + float energy_3phi[101] = {0.0}; + float eta[101] = {0.0}; + int max1 = 0; + int max2 = 0; + int max = 0; + int n = 0; + float Emax1 = 0.; + float Emax2 = 0.; + float etamaxcut = 0.158; + float phimaxcut = 0.1; + float signum_eta = 0.; + + signum_eta = pTau->track(0)->eta() / fabs(pTau->track(0)->eta()); + + float sumETCellsLAr = 0.; + float eta0cut = 0.075; + float eta1cut = 0.0475; + float eta2cut = 0.075; + float eta3cut = 1.5; + float phi0cut = 0.3; + float phi1cut = 0.3; + float phi2cut = 0.075; + float phi3cut = 0.075; + float etareg = 0.; + float etacase1 = 1.8; + float etagran1 = 0.00315; + float etagran2 = 0.00415; + float sumETCellsHad1 = 0.; + float etahadcut = 0.2; + float phihadcut = 0.2; + + const CaloCell *pCell; + + //use tau vertex to correct cell position + bool applyCellCorrection = false; + if (m_doCellCorrection && pTau->vertexLink()) { + applyCellCorrection = true; + } + + //--------------------------------------------------------------------- + // Calculate eta, phi impact point of leading track at calorimeter layers EM 0,1,2,3 + //--------------------------------------------------------------------- + const DataVector< const Trk::TrackParameters >* pTrk = m_trackToCalo->getParametersInCalo( ( *pTau->track(0) ) , Trk::pion, Trk::alongMomentum); //FIXME + + const int numOfsampEM = 4; + double eta_extrapol[4]; + double phi_extrapol[4]; + + for (int i = 0; i < numOfsampEM; ++i) { + eta_extrapol[i] = -11111.; + phi_extrapol[i] = -11111.; + } + + + if (pTrk && (*pTrk)[IExtrapolateToCaloTool::PreSampler]) { + eta_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().eta(); + phi_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().phi(); + } + + if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Strips]) { + eta_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().eta(); + phi_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().phi(); + } + + if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Middle]) { + eta_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().eta(); + phi_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().phi(); + } + + if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Back]) { + eta_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().eta(); + phi_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().phi(); + } + + + + + for (int i = 0; i < numOfsampEM; ++i) { + if ( eta_extrapol[i] < -11110. || phi_extrapol[i] < -11110. ) + { + ATH_MSG_WARNING("extrapolation of leading track to calo surfaces failed for sampling : " << i ); + return StatusCode::SUCCESS; + } + } + + const xAOD::Jet* pJetSeed = (*pTau->jetLink()); + if (!pJetSeed) { + ATH_MSG_WARNING("tau does not have jet seed for electron veto cell variable calculation"); + return StatusCode::SUCCESS; + } + + xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin(); + xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end(); + + std::bitset<200000> cellSeen; + + for (; cItr != cItrE; ++cItr) { + + const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); + + CaloClusterCellLink::const_iterator pCellIter = cluster->getCellLinks()->begin(); + CaloClusterCellLink::const_iterator pCellIterE = cluster->getCellLinks()->end(); + + + double cellPhi; + double cellEta; + double cellET; + for (; pCellIter != pCellIterE; pCellIter++) { + + pCell = *pCellIter; + + if (cellSeen.test(pCell->caloDDE()->calo_hash())) { + //already encountered this cell + continue; + } + else { + //New cell + cellSeen.set(pCell->caloDDE()->calo_hash()); + } + + + if (applyCellCorrection) { + //ATH_MSG_INFO( "before cell correction: phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() ); + CaloVertexedCell vxCell (*pCell, (*pTau->vertexLink())->position()); + cellPhi = vxCell.phi(); + cellEta = vxCell.eta(); + cellET = vxCell.et(); + } + else { + cellPhi = pCell->phi(); + cellEta = pCell->eta(); + cellET = pCell->et(); + } + + int sampling = pCell->caloDDE()->getSampling(); + if (sampling == 4) sampling = 0; + if (sampling == 5) sampling = 1; + if (sampling == 6) sampling = 2; + if (sampling == 7) sampling = 3; + if (sampling == 18) sampling = 12; + if (sampling == 8) sampling = 12; + if (sampling == 15) sampling = 12; + if (sampling == 19) sampling = 13; + if (sampling == 16) sampling = 13; + if (sampling == 20) sampling = 14; + if (sampling == 17) sampling = 14; + + int i = 2; + if (sampling < 4) i = sampling; + if (sampling == 12 || sampling == 13 || sampling == 14) i = 3; + + detPhiTrk = Tau1P3PKineUtils::deltaPhi( cellPhi, phi_extrapol[i] ); + detEtaTrk = std::fabs( cellEta - eta_extrapol[i] ); + clEtaTrk = eta_extrapol[i]; + distEtaTrk = cellEta - eta_extrapol[i]; + + if ((sampling == 0 && detEtaTrk < eta0cut && detPhiTrk < phi0cut) || + (sampling == 1 && detEtaTrk < eta1cut && detPhiTrk < phi1cut) || + (sampling == 2 && detEtaTrk < eta2cut && detPhiTrk < phi2cut) || + (sampling == 3 && detEtaTrk < eta3cut && detPhiTrk < phi3cut)) { + + sumETCellsLAr += cellET; + } + + if (sampling == 12 && detEtaTrk < etahadcut && detPhiTrk < phihadcut) sumETCellsHad1 += cellET; + + if (fabs(cellEta) > 0.8 && fabs(cellEta) <= 1.2 && (sampling == 13 || sampling == 14) && detEtaTrk < etahadcut && detPhiTrk < phihadcut) { + sumETCellsHad1 += cellET; + } + + if (fabs(pTau->track(0)->eta()) <= 1.7) { + if (sampling == 1 && detEtaTrk < etamaxcut && detPhiTrk <= phimaxcut) { + if ((fabs(cellEta) < 1.37 || fabs(cellEta) > 1.52) && fabs(cellEta) < 1.85) { + if (fabs(clEtaTrk) <= etacase1 && fabs(cellEta) <= etacase1) { + n = 50 + int(distEtaTrk / etagran1); + } + if (fabs(clEtaTrk) <= etacase1 && fabs(cellEta) > etacase1) { + n = 50 + int(signum_eta * ((etacase1 - fabs(clEtaTrk)) / etagran1 + (-etacase1 + fabs(cellEta)) / etagran2)); + } + energy_3phi[n] = energy_3phi[n] + cellET / GeV; + eta[n] = signum_eta * (clEtaTrk - cellEta); + } else { + energy_3phi[n] = 0; + eta[n] = 0; + } + } + } else { + energy_3phi[n] = 0; + eta[n] = 0; + } + + if (fabs(cellEta) <= etacase1) { + etareg = 0.00315; + } else { + etareg = 0.00415; + } + + } //end cell loop + + }// end jet constituent loop + + for (int m1 = 0; m1 < 101; m1++) { + if ((energy_3phi[m1] > Emax1)) { + Emax1 = energy_3phi[m1]; + max1 = m1; + } + } + + for (int m2 = 1; m2 < 100; m2++) { + if (m2 == max1) continue; + + if ((energy_3phi[m2] > Emax2) && (energy_3phi[m2] > energy_3phi[m2 - 1]) && (energy_3phi[m2] > energy_3phi[m2 + 1])) { + Emax2 = energy_3phi[m2]; + max2 = m2; + } + } + + if (fabs(eta[max1]) >= etareg) { + max = max1; + } else { + max = max2; + } + + + float TRTratio = -9999.0; + uint8_t TRTHTHits; + uint8_t TRTHTOutliers; + uint8_t TRTHits; + uint8_t TRTOutliers; + + if ( !pTau->track(0)->summaryValue( TRTHits, xAOD::SummaryType::numberOfTRTHits ) ) + { + ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate"); + return StatusCode::SUCCESS; + } + if ( !pTau->track(0)->summaryValue( TRTHTHits, xAOD::SummaryType::numberOfTRTHighThresholdHits ) ) + { + ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate"); + return StatusCode::SUCCESS; + } + if ( !pTau->track(0)->summaryValue( TRTOutliers, xAOD::SummaryType::numberOfTRTOutliers ) ) + { + ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate"); + return StatusCode::SUCCESS; + } + if ( !pTau->track(0)->summaryValue( TRTHTOutliers, xAOD::SummaryType::numberOfTRTHighThresholdOutliers ) ) + { + ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate"); + return StatusCode::SUCCESS; + } + + + if (TRTHits + TRTOutliers != 0) { + TRTratio = float( TRTHTHits + TRTHTOutliers) / float( TRTHits + TRTOutliers ); + } else { + TRTratio = 0.0; + } + // } + + pTau->setDetail(xAOD::TauJetParameters::TRT_NHT_OVER_NLT , TRTratio ); + pTau->setDetail(xAOD::TauJetParameters::secMaxStripEt , energy_3phi[max] ); + pTau->setDetail(xAOD::TauJetParameters::hadLeakEt , static_cast<float>( sumETCellsHad1 / ( pTau->track(0)->pt() ) ) ); + pTau->setDetail(xAOD::TauJetParameters::sumEMCellEtOverLeadTrkPt , static_cast<float>( ( sumETCellsLAr / ( pTau->track(0)->pt() ) ) ) ); + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //delete the trackparemeters returned by tracktocalo + if (pTrk) delete pTrk; + + return StatusCode::SUCCESS; +} + + + + diff --git a/Reconstruction/tauRec/src/TauGenericPi0Cone.cxx b/Reconstruction/tauRec/src/TauGenericPi0Cone.cxx new file mode 100644 index 00000000000..6dd3de18e22 --- /dev/null +++ b/Reconstruction/tauRec/src/TauGenericPi0Cone.cxx @@ -0,0 +1,107 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauGenericPi0Cone.cxx +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-04 +// +// +//----------------------------------------------------------------------------- + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" +#include "Particle/TrackParticle.h" + +#include "tauRec/TauCandidateData.h" +#include "tauEvent/TauCommonDetails.h" +#include "tauEvent/TauJetParameters.h" + +#include "tauRec/TauGenericPi0Cone.h" +#include "tauRec/TauTrackFilterUtils.h" + +#include "TLorentzVector.h" + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauGenericPi0Cone::TauGenericPi0Cone(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); +} + + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauGenericPi0Cone::~TauGenericPi0Cone() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauGenericPi0Cone::initialize() { + ATH_MSG_VERBOSE("TauGenericPi0Cone Initialising"); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauGenericPi0Cone::finalize() { + ATH_MSG_VERBOSE("TauGenericPi0Cone Finalizing"); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauGenericPi0Cone::execute(TauCandidateData *data) { + ATH_MSG_VERBOSE("TauGenericPi0Cone Executing"); + + xAOD::TauJet *pTau = data->xAODTau; + + TLorentzVector tau; + tau.SetPtEtaPhiE(pTau->pt(), + pTau->eta(), + pTau->phi(), + pTau->e()); + + int nProng = pTau->trackFilterProngs(); + int flag = pTau->trackFilterQuality(); + float pi0angle = 0.; //TODO sane default value + + // Get pi0 cone + if(flag != 0){ + int recProng = 0; + if((nProng == 3)||(nProng == 2)) recProng = 3; + if(nProng == 1) recProng = 1; + pi0angle = TauTrackFilterUtils::ComputePi0Cone(recProng,tau); + } + + // Convert to dR. + m_pi0conedr = std::min(pi0angle*cosh(tau.Eta()), 0.2); + + // Store result + pTau->setPi0ConeDR(m_pi0conedr); + + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/tauRec/src/TauPi0BonnClusterCreator.cxx b/Reconstruction/tauRec/src/TauPi0BonnClusterCreator.cxx new file mode 100644 index 00000000000..8843a927e60 --- /dev/null +++ b/Reconstruction/tauRec/src/TauPi0BonnClusterCreator.cxx @@ -0,0 +1,602 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0BonnClusterCreator.cxx +// package: Reconstruction/tauEvent +// authors: Benedict Winter, Will Davey +// date: 2012-10-09 +// +//----------------------------------------------------------------------------- + +#include <vector> + +#include "CaloUtils/CaloClusterStoreHelper.h" +#include "CaloGeoHelpers/CaloSampling.h" +#include "AnalysisUtils/AnalysisMisc.h" +#include "FourMomUtils/P4Helpers.h" + +#include "tauRec/TauPi0BonnClusterCreator.h" + +#include "RecoToolInterfaces/IExtrapolateToCaloTool.h" + +using std::vector; +using std::string; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0BonnClusterCreator::TauPi0BonnClusterCreator( + const string& type, + const string& name, + const IInterface *parent) + + : TauToolBase(type, name, parent) + , m_trackToCaloTool("") + , m_cellContainerName("TauCommonPi0CellContainer") + , m_inputPi0ClusterContainerName("TauPi0BonnSubtractedClusterContainer") + , m_outputPi0ClusterContainerName("TauPi0BonnClusterContainer") + , m_neutralPFOContainerName("TauPi0BonnNeutralPFOContainer") + , m_clusterEtCut(500.) +{ + declareInterface<TauToolBase > (this); + + declareProperty("ExtrapolateToCaloTool", m_trackToCaloTool); + declareProperty("CellContainerName", m_cellContainerName); + declareProperty("InputPi0ClusterContainerName", m_inputPi0ClusterContainerName); + declareProperty("OutputPi0ClusterContainerName", m_outputPi0ClusterContainerName); + declareProperty("NeutralPFOContainerName", m_neutralPFOContainerName); + declareProperty("ClusterEtCut", m_clusterEtCut); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0BonnClusterCreator::~TauPi0BonnClusterCreator() +{ +} + + +StatusCode TauPi0BonnClusterCreator::initialize() +{ + CHECK( m_trackToCaloTool.retrieve() ); + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnClusterCreator::eventInitialize(TauCandidateData * /*data*/) +{ + // create new CaloClusterContainer + // this container will later persistified + // so it will get ownership of the objects + m_pOutputPi0CaloClusterContainer = new xAOD::CaloClusterContainer(SG::OWN_ELEMENTS); + ATH_MSG_VERBOSE("record container " << m_outputPi0ClusterContainerName); + //--------------------------------------------------------------------- + // Create container for Pi0 + //--------------------------------------------------------------------- + m_pOutputPi0CaloClusterContainer = CaloClusterStoreHelper::makeContainer(&*evtStore(), + m_outputPi0ClusterContainerName, + msg() + ); + + //--------------------------------------------------------------------- + // Create neutral PFO container + //--------------------------------------------------------------------- + m_neutralPFOContainer = new xAOD::PFOContainer(); + CHECK( evtStore()->record(m_neutralPFOContainer, m_neutralPFOContainerName ) ); + m_neutralPFOAuxStore = new xAOD::PFOAuxContainer(); + CHECK( evtStore()->record( m_neutralPFOAuxStore, m_neutralPFOContainerName + "Aux." ) ); + m_neutralPFOContainer->setStore(m_neutralPFOAuxStore); + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnClusterCreator::execute(TauCandidateData *data) +{ + xAOD::TauJet *pTau = data->xAODTau; + + //--------------------------------------------------------------------- + // only run shower subtraction on 1-5 prong taus + //--------------------------------------------------------------------- + if (pTau->nTracks() == 0 || pTau->nTracks() >5 ) { + return StatusCode::SUCCESS; + } + ATH_MSG_DEBUG("ClusterCreator: new tau. \tpt = " << pTau->pt() << "\teta = " << pTau->eta() << "\tphi = " << pTau->phi() << "\tnprongs = " << pTau->nTracks()); + + //--------------------------------------------------------------------- + // get tau tracks + //--------------------------------------------------------------------- + vector<const xAOD::TrackParticle*> tracks; + for(unsigned iTrack = 0; iTrack<pTau->nTracks();++iTrack){ + const xAOD::TrackParticle* track = pTau->track(iTrack); + tracks.push_back(track); + } + + //--------------------------------------------------------------------- + // retrieve the CaloClusterContainer created by the CaloClusterMaker + //--------------------------------------------------------------------- + const xAOD::CaloClusterContainer *pPi0ClusterContainer; + CHECK( evtStore()->retrieve(pPi0ClusterContainer, m_inputPi0ClusterContainerName) ); + + //--------------------------------------------------------------------- + // extrapolate track to calo layers + //--------------------------------------------------------------------- + vector<vector<float> > tracksEtaAtSampling; + vector<vector<float> > tracksPhiAtSampling; + for(unsigned iTrack = 0; iTrack<pTau->nTracks();++iTrack){ + const xAOD::TrackParticle* track = pTau->track(iTrack); + vector<float> trackEtaAtSampling; + vector<float> trackPhiAtSampling; + this->getExtrapolatedPositions(track,trackEtaAtSampling,trackPhiAtSampling); + tracksEtaAtSampling.push_back(trackEtaAtSampling); + tracksPhiAtSampling.push_back(trackPhiAtSampling); + } + + //--------------------------------------------------------------------- + // TODO: May want to use tau vertex in the future to calculate some cluster moments (DELTA_THETA, etc.). + // Doesn't help now, since all moments are calculated wrt 0.0.0 atm. + //--------------------------------------------------------------------- + + + // Retrieve Ecal1 shots and match them to clusters + //--------------------------------------------------------------------- + std::vector<const xAOD::PFO*> shotVector; + unsigned nShots = pTau->nShot_PFOs(); + for(unsigned iShot=0;iShot<nShots;++iShot){ + const xAOD::PFO* thisShot = pTau->shot_PFO(iShot); + shotVector.push_back( thisShot ); + } + std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap = getClusterToShotMap(shotVector, pPi0ClusterContainer, pTau); + + xAOD::CaloClusterContainer::const_iterator clusterItr (pPi0ClusterContainer->begin()), + clusterItrEnd(pPi0ClusterContainer->end()); + for (; clusterItr != clusterItrEnd; ++clusterItr){ + + // selection + if ((*clusterItr)->pt() < m_clusterEtCut) continue; + // Cluster container has clusters for all taus. + // Only run on clusters that belong to this tau + if ((*clusterItr)->p4().DeltaR(pTau->p4()) > .4) continue; + + // Get shots in this cluster. Need to use (CaloCluster*) (*clusterItr) + // (not a copy!) since the pointer will otherwise be different than in clusterToShotMap + std::vector<unsigned> shotsInCluster = getShotsMatchedToCluster( shotVector, clusterToShotMap, (xAOD::CaloCluster*) (*clusterItr)); + + // Make a copy of the cluster to store in output container. + xAOD::CaloCluster* pPi0Cluster = new xAOD::CaloCluster( *(*clusterItr) ); + + // store pi0 calo cluster in the output container + m_pOutputPi0CaloClusterContainer->push_back(pPi0Cluster); + + // Calculate input variables for fake supression. + // Do this before applying the vertex correction, + // since the position of the cluster in the + // calorimeter is required. + float EM1CoreFrac = getEM1CoreFrac(pPi0Cluster); + float asymmetryInEM1WRTTrk = getAsymmetryInEM1WRTTrk(pPi0Cluster, tracksEtaAtSampling, tracksPhiAtSampling); + int NHitsInEM1 = getNPhotons(shotVector, shotsInCluster); + vector<int> NPosECellsInLayer = getNPosECells(pPi0Cluster); + vector<float> firstEtaWRTClusterPositionInLayer = get1stEtaMomWRTCluster(pPi0Cluster); + vector<float> secondEtaWRTClusterPositionInLayer = get2ndEtaMomWRTCluster(pPi0Cluster); + + // Retrieve cluster moments that are used for fake supression and that are not stored in AOD + // for every cluster. Do this after applying the vertex correction, since the moments + // (especcially DELTA_PHI and DELTA_THETA) must be calculated WRT the tau vertex + double CENTER_MAG = 0.0; + double FIRST_ETA = 0.0; + double SECOND_R = 0.0; + double SECOND_LAMBDA = 0.0; + double DELTA_PHI = 0.0; + double DELTA_THETA = 0.0; + double CENTER_LAMBDA = 0.0; + double LATERAL = 0.0; + double LONGITUDINAL = 0.0; + double ENG_FRAC_EM = 0.0; + double ENG_FRAC_MAX = 0.0; + double ENG_FRAC_CORE = 0.0; + double SECOND_ENG_DENS = 0.0; + + // TODO: Replace numbers by human readable enums + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 404, CENTER_MAG) ) ATH_MSG_WARNING("Couldn't retrieve CENTER_MAG moment. Set it to 0."); + + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 102, FIRST_ETA) ) ATH_MSG_WARNING("Couldn't retrieve FIRST_ETA moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 201, SECOND_R) ) ATH_MSG_WARNING("Couldn't retrieve SECOND_R moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 202, SECOND_LAMBDA) ) ATH_MSG_WARNING("Couldn't retrieve SECOND_LAMBDA moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 301, DELTA_PHI) ) ATH_MSG_WARNING("Couldn't retrieve DELTA_PHI moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 302, DELTA_THETA) ) ATH_MSG_WARNING("Couldn't retrieve DELTA_THETA moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 501, CENTER_LAMBDA) ) ATH_MSG_WARNING("Couldn't retrieve CENTER_LAMBDA moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 601, LATERAL) ) ATH_MSG_WARNING("Couldn't retrieve LATERAL moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 602, LONGITUDINAL) ) ATH_MSG_WARNING("Couldn't retrieve LONGITUDINAL moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 701, ENG_FRAC_EM) ) ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_EM moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 702, ENG_FRAC_MAX) ) ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_MAX moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 703, ENG_FRAC_CORE) ) ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_CORE moment. Set it to 0."); + if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 805, SECOND_ENG_DENS) ) ATH_MSG_WARNING("Couldn't retrieve SECOND_ENG_DENS moment. Set it to 0."); + + float E_EM1 = pPi0Cluster->eSample(CaloSampling::EMB1) + pPi0Cluster->eSample(CaloSampling::EME1); + float E_EM2 = pPi0Cluster->eSample(CaloSampling::EMB2) + pPi0Cluster->eSample(CaloSampling::EME2); + + // create neutral PFO. Set BDTScore to dummy value <-1. The BDT score is calculated within TauPi0BonnSelector.cxx. + xAOD::PFO* neutralPFO = new xAOD::PFO(); + m_neutralPFOContainer->push_back( neutralPFO ); + + // Create element link from tau to neutral PFO + ElementLink<xAOD::PFOContainer> PFOElementLink; + PFOElementLink.toContainedElement( *m_neutralPFOContainer, neutralPFO ); + pTau->addCellBased_Neutral_PFOLink( PFOElementLink ); + + // Set PFO variables + ElementLink<xAOD::CaloClusterContainer> clusElementLink; + clusElementLink.toContainedElement( *m_pOutputPi0CaloClusterContainer, pPi0Cluster ); + neutralPFO->setClusterLink( clusElementLink ); + + neutralPFO->setP4( (float) pPi0Cluster->pt(), (float) pPi0Cluster->eta(), (float) pPi0Cluster->phi(), (float) pPi0Cluster->m()); + neutralPFO->setBDTPi0Score( (float) -9999. ); + neutralPFO->setCharge( 0. ); + + neutralPFO->setCenterMag( (float) CENTER_MAG); + + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0, -1); + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, -1); + + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_FIRST_ETA, (float) FIRST_ETA); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_R, (float) SECOND_R); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_LAMBDA, (float) SECOND_LAMBDA); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_PHI, (float) DELTA_PHI); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_THETA, (float) DELTA_THETA); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_CENTER_LAMBDA, (float) CENTER_LAMBDA); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_LATERAL, (float) LATERAL); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_LONGITUDINAL, (float) LONGITUDINAL); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_EM, (float) ENG_FRAC_EM); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_MAX, (float) ENG_FRAC_MAX); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_CORE, (float) ENG_FRAC_CORE); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_ENG_DENS, (float) SECOND_ENG_DENS); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM1, (float) E_EM1); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM2, (float) E_EM2); + + + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_EM1CoreFrac, EM1CoreFrac); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_asymmetryInEM1WRTTrk, asymmetryInEM1WRTTrk); + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NHitsInEM1, NHitsInEM1); + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_PS, NPosECellsInLayer.at(0)); + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM1, NPosECellsInLayer.at(1)); + neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM2, NPosECellsInLayer.at(2)); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM1, firstEtaWRTClusterPositionInLayer.at(1)); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM2, firstEtaWRTClusterPositionInLayer.at(2)); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM1, secondEtaWRTClusterPositionInLayer.at(1)); + neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM2, secondEtaWRTClusterPositionInLayer.at(2)); + + // Store shot element links in neutral PFO + std::vector<ElementLink<xAOD::IParticleContainer> > shotlinks; + for(unsigned iShot = 0;iShot<shotsInCluster.size();++iShot){ + ElementLink<xAOD::PFOContainer> shotPFOElementLink = pTau->shot_PFOLinks().at(shotsInCluster.at(iShot)); + ElementLink<xAOD::IParticleContainer> shotElementLink; + shotPFOElementLink.toPersistent(); + shotElementLink.resetWithKeyAndIndex( shotPFOElementLink.persKey(), shotPFOElementLink.persIndex() ); + if (!shotElementLink.isValid()) ATH_MSG_WARNING("Created an invalid element link to xAOD track particle"); + shotlinks.push_back(shotElementLink); + } + if(!neutralPFO->setAssociatedParticleLinks( xAOD::PFODetails::TauShot,shotlinks)) + ATH_MSG_WARNING("Couldn't add shot links to neutral PFO!"); + } + return StatusCode::SUCCESS; +} + + +StatusCode TauPi0BonnClusterCreator::eventFinalize(TauCandidateData *) +{ + // pt sort container at the end of the event + // if(m_pOutputPi0CaloClusterContainer->size()) AnalysisUtils::Sort::pT(m_pOutputPi0CaloClusterContainer); + + //---------------------------------------------------------------------- + // Register cluster container in StoreGate + //---------------------------------------------------------------------- + CHECK( CaloClusterStoreHelper::finalizeClusters(&(*evtStore()), + m_pOutputPi0CaloClusterContainer, + m_outputPi0ClusterContainerName, + msg())); + + return StatusCode::SUCCESS; +} + +// Functions used to calculate BDT variables other than those provided by the CaloClusterMomentsMaker +float TauPi0BonnClusterCreator::getEM1CoreFrac( + const xAOD::CaloCluster* pi0Candidate) +{ + float coreEnergy=0.; + float sumEPosCellsEM1=0.; + + const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks(); + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + if(sampling!=1 && sampling!=5) continue; + float cellE = cellInCluster->e() * cellInClusterItr.weight(); + if(cellE<=0) continue; + sumEPosCellsEM1 += cellE; + float cellEtaWRTCluster = cellInCluster->eta()-pi0Candidate->eta(); + float cellPhiWRTCluster = P4Helpers::deltaPhi(cellInCluster->phi(), pi0Candidate->phi()); + if(fabs(cellPhiWRTCluster) > 0.05 || fabs(cellEtaWRTCluster) > 2 * 0.025/8.) continue; + coreEnergy+=cellE; + } + if(sumEPosCellsEM1<=0.) return 0.; + return coreEnergy/sumEPosCellsEM1; +} + +// Function to determine asymmetry with respect to track. For > 1 track give smallest asymmetry. +float TauPi0BonnClusterCreator::getAsymmetryInEM1WRTTrk( + const xAOD::CaloCluster* pi0Candidate, + const vector<vector<float> > tracksEtaAtSampling, + const vector<vector<float> > tracksPhiAtSampling) +{ + float minAsymmetryInEM1WRTTrk=2.; // minimum asymmetryWRT tracks + vector<vector<float> > asymmetriesInEM1WRTTrks; + vector<float> asymmetryInEM1WRTTrk; + asymmetryInEM1WRTTrk.push_back(0.); // here the energy in negative eta direction WRT the track will be stored + asymmetryInEM1WRTTrk.push_back(0.); // here the energy in positive eta direction WRT the track will be stored + asymmetryInEM1WRTTrk.push_back(0.); // here the energy in negative phi direction WRT the track will be stored + asymmetryInEM1WRTTrk.push_back(0.); // here the energy in positive phi direction WRT the track will be stored + for(unsigned iTrack = 0; iTrack<tracksEtaAtSampling.size();++iTrack){ + asymmetriesInEM1WRTTrks.push_back(asymmetryInEM1WRTTrk); + } + + float sumEPosCellsEM1=0.; + const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks(); + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + if(sampling!=1 && sampling!=5) continue; + float cellE = cellInCluster->e() * cellInClusterItr.weight(); + if(cellE<=0) continue; + sumEPosCellsEM1 += cellE; + for(unsigned iTrack = 0; iTrack<tracksEtaAtSampling.size();++iTrack){ + float cellEtaWRTTrack = cellInCluster->eta() - tracksEtaAtSampling.at(iTrack).at(sampling); + float cellPhiWRTTrack = P4Helpers::deltaPhi(cellInCluster->phi(), tracksPhiAtSampling.at(iTrack).at(sampling)); + + if(cellEtaWRTTrack<0) asymmetriesInEM1WRTTrks.at(iTrack).at(0)+=cellE; + else asymmetriesInEM1WRTTrks.at(iTrack).at(1)+=cellE; + if(cellPhiWRTTrack<0) asymmetriesInEM1WRTTrks.at(iTrack).at(2)+=cellE; + else asymmetriesInEM1WRTTrks.at(iTrack).at(3)+=cellE; + } + } + if(sumEPosCellsEM1<=0.) return 0.; // default value for clusters with no energy in EM1 + // calculate asymmetry WRT the tracks and determine minimum asymmetry + for(unsigned iTrack = 0; iTrack<tracksEtaAtSampling.size();++iTrack){ + for(unsigned int iEntry=0;iEntry<asymmetriesInEM1WRTTrks.at(iTrack).size();++iEntry){ + asymmetriesInEM1WRTTrks.at(iTrack).at(iEntry)/=sumEPosCellsEM1; + if(asymmetriesInEM1WRTTrks.at(iTrack).at(iEntry)>=1.) asymmetriesInEM1WRTTrks.at(iTrack).at(iEntry)=0.999; + } + float asymmetryToThisTrack = fabs((asymmetriesInEM1WRTTrks.at(iTrack).at(1)-asymmetriesInEM1WRTTrks.at(iTrack).at(0))* + (asymmetriesInEM1WRTTrks.at(iTrack).at(3)-asymmetriesInEM1WRTTrks.at(iTrack).at(2))); + if(asymmetryToThisTrack<minAsymmetryInEM1WRTTrk) minAsymmetryInEM1WRTTrk = asymmetryToThisTrack; + } + return minAsymmetryInEM1WRTTrk; +} + + +// Do cluster to shot matching. +// A cluster is matched to a shot if the seed cell of the shot is in the cluster +std::map<unsigned, xAOD::CaloCluster*> TauPi0BonnClusterCreator::getClusterToShotMap( + const std::vector<const xAOD::PFO*> shotVector, + const xAOD::CaloClusterContainer* pPi0ClusterContainer, + xAOD::TauJet *pTau) +{ + std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap; + for(unsigned iShot = 0;iShot<shotVector.size();++iShot){ + int seedHash_int = -1; + if( shotVector.at(iShot)->attribute(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash_int) == false) { + std::cout << "WARNING: Couldn't find seed hash. Set it to -1, no cluster will be associated to shot." << std::endl; + } + const IdentifierHash seedHash = (const IdentifierHash) seedHash_int; + xAOD::CaloClusterContainer::const_iterator clusterItr (pPi0ClusterContainer->begin()), + clusterItrEnd(pPi0ClusterContainer->end()); + float weightInCluster=-1.; + float weightInPreviousCluster=-1; + for (; clusterItr != clusterItrEnd; ++clusterItr){ + xAOD::CaloCluster* cluster = (xAOD::CaloCluster*) (*clusterItr); + weightInCluster=-1.; + if (cluster->p4().Et() < m_clusterEtCut) continue; // Not interested in clusters that fail the Et cut + // Cluster container has clusters for all taus. + // Only run on clusters that belong to this tau + if (cluster->p4().DeltaR(pTau->p4()) > .4) continue; + const CaloClusterCellLink* theCellLink = cluster->getCellLinks(); + CaloClusterCellLink::const_iterator cellItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellItrE = theCellLink->end(); + for(;cellItr!=cellItrE; ++cellItr){ + CaloCell* cellInCluster = (CaloCell*) *cellItr; + // Check if seed cell is in cluster. + if(cellInCluster->caloDDE()->calo_hash()!=seedHash) continue; + weightInCluster = cellItr.weight(); + // found cell, no need to loop over other cells + break; + } + if(weightInCluster<0) continue; + // Check if cell was already found in a previous cluster + if(weightInPreviousCluster<0){ + // Cell not found in a previous cluster. + // Have to check whether cell is shared with other cluster + clusterToShotMap[iShot] = cluster; + weightInPreviousCluster = weightInCluster; + } + else{ + // Cell has been found in a previous cluster + // assign shot to this cluster if it has larger weight for the cell + // otherwise the shots keeps assigned to the previous cluster + if(weightInCluster>weightInPreviousCluster){ + clusterToShotMap[iShot] = cluster; + } + // No need to loop over other clusters as cells can not be shared by more than two clusters + break; + } + } + } + return clusterToShotMap; +} + +std::vector<unsigned> TauPi0BonnClusterCreator::getShotsMatchedToCluster( + const std::vector<const xAOD::PFO*> shotVector, + std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap, + xAOD::CaloCluster* pPi0Cluster) +{ + std::vector<unsigned> shotsMatchedToCluster; + for(unsigned iShot = 0;iShot<shotVector.size();++iShot){ + std::map<unsigned, xAOD::CaloCluster*>::iterator itr = clusterToShotMap.find(iShot); + if(itr==clusterToShotMap.end()) continue; + if(itr->second!=pPi0Cluster) continue; + shotsMatchedToCluster.push_back(iShot); + } + return shotsMatchedToCluster; +} + +int TauPi0BonnClusterCreator::getNPhotons( + const std::vector<const xAOD::PFO*> shotVector, + std::vector<unsigned> shotsInCluster + ) +{ + int nPhotons = 0; + for(unsigned iShot = 0;iShot<shotsInCluster.size();++iShot){ + int curNPhotons=0; + if(shotVector.at(shotsInCluster.at(iShot))->attribute(xAOD::PFODetails::PFOAttributes::tauShots_nPhotons,curNPhotons) == false) + ATH_MSG_WARNING("Can't find NHitsInEM1. Set it to 0."); + nPhotons+=curNPhotons; + } + return nPhotons; +} + +vector<int> TauPi0BonnClusterCreator::getNPosECells( + const xAOD::CaloCluster* pi0Candidate) +{ + vector<int> nPosECellsInLayer(3,0); // 3 layers initialised with 0 +ve cells + + const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks(); + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + + for(;cellInClusterItr!=cellInClusterItrE; ++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + // Get cell layer: PSB and PSE belong to layer 0, + // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. + // Cells in EMB3 and EME3 have already been removed + // during subtraction. + int cellLayer = sampling%4; + if(cellInCluster->e() > 0) nPosECellsInLayer[cellLayer]++; + } + return nPosECellsInLayer; +} + + +vector<float> TauPi0BonnClusterCreator::get1stEtaMomWRTCluster( + const xAOD::CaloCluster* pi0Candidate) +{ + vector<float> firstEtaWRTClusterPositionInLayer (4, 0.); //init with 0. for 0-3 layers + vector<float> sumEInLayer (4, 0.); //init with 0. for 0-3 layers + + const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks(); + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + + for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + // Get cell layer: PSB and PSE belong to layer 0, + // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. + // Cells in EMB3 and EME3 (layer 3) have already been removed + // during subtraction. + int cellLayer = sampling%4; + + float cellEtaWRTClusterPos=cellInCluster->eta()-pi0Candidate->eta(); + float cellE=cellInCluster->e(); + if(cellE<=0) continue; + firstEtaWRTClusterPositionInLayer[cellLayer]+=cellEtaWRTClusterPos*cellE; + sumEInLayer[cellLayer]+=cellE; + } + + for(int iLayer=0;iLayer<4;++iLayer){ + if(sumEInLayer[iLayer]!=0) + firstEtaWRTClusterPositionInLayer[iLayer]/=fabs(sumEInLayer[iLayer]); + else firstEtaWRTClusterPositionInLayer[iLayer]=0.; + } + return firstEtaWRTClusterPositionInLayer; +} + +vector<float> TauPi0BonnClusterCreator::get2ndEtaMomWRTCluster( + const xAOD::CaloCluster* pi0Candidate) +{ + vector<float> secondEtaWRTClusterPositionInLayer (4, 0.); //init with 0. for 0-3 layers + vector<float> sumEInLayer (4, 0.); //init with 0. for 0-3 layers + + const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks(); + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + + for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + // Get cell layer: PSB and PSE belong to layer 0, + // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. + // Cells in EMB3 and EME3 (layer 3) have already been removed + // during subtraction. + int cellLayer = sampling%4; + + float cellEtaWRTClusterPos=cellInCluster->eta()-pi0Candidate->eta(); + float cellE=cellInCluster->e(); + if(cellE<=0) continue; + secondEtaWRTClusterPositionInLayer[cellLayer]+=cellEtaWRTClusterPos*cellEtaWRTClusterPos*cellE; + sumEInLayer[cellLayer]+=cellE; + } + + for(int iLayer=0;iLayer<4;++iLayer){ + if(sumEInLayer[iLayer]!=0) + secondEtaWRTClusterPositionInLayer[iLayer]/=fabs(sumEInLayer[iLayer]); + else secondEtaWRTClusterPositionInLayer[iLayer]=0.; + } + return secondEtaWRTClusterPositionInLayer; +} + +void TauPi0BonnClusterCreator::getExtrapolatedPositions( + const xAOD::TrackParticle * track, + vector<float> &trackToCaloEta, + vector<float> &trackToCaloPhi) +{ + for (int layer = 0 ; layer != CaloCell_ID::MINIFCAL0; ++layer) { + // Only need to extrapolate to Ecal1 (samplings 1 and 5) + if(layer!=1 && layer!=5){ + trackToCaloEta.push_back(-99999.); + trackToCaloPhi.push_back(-99999.); + continue; + } + ATH_MSG_DEBUG( "Try extrapolation of track with pt = " << track->pt() << ", eta " << track->eta() << ", phi" << track->phi() << " to layer " << layer); + // extrapolate track to layer + const Trk::TrackParameters* param_at_calo = 0; + param_at_calo = m_trackToCaloTool->extrapolate( + *track, + (CaloCell_ID::CaloSample) layer, + 0.0, Trk::alongMomentum, Trk::pion); + + // store if track extrapolation successful, else use dummy values + if(param_at_calo){ + ATH_MSG_DEBUG( "Extrapolated track with eta=" << track->eta() + << " phi="<<track->phi() + << " to eta=" << param_at_calo->position().eta() + << " phi="<<param_at_calo->position().phi() + ); + trackToCaloEta.push_back(param_at_calo->position().eta()); + trackToCaloPhi.push_back(param_at_calo->position().phi()); + delete param_at_calo; + } + else { + ATH_MSG_DEBUG( "Could not extrapolate track with eta = " << track->eta() + << " phi=" << track->phi() + ); + trackToCaloEta.push_back(-99999.); //Use something huge to flag the + trackToCaloPhi.push_back(-99999.); //track as useless + } + } +} + diff --git a/Reconstruction/tauRec/src/TauPi0BonnCreateROI.cxx b/Reconstruction/tauRec/src/TauPi0BonnCreateROI.cxx new file mode 100644 index 00000000000..4c824dc37bc --- /dev/null +++ b/Reconstruction/tauRec/src/TauPi0BonnCreateROI.cxx @@ -0,0 +1,763 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0BonnCreateROI.cxx +// package: Reconstruction/tauEvent +// authors: Will Davey +// date: 2012-10-09 +// +//----------------------------------------------------------------------------- + +#include <TString.h> +#include <TH1.h> + +#include "GaudiKernel/IToolSvc.h" + +#include "PathResolver/PathResolver.h" +#include "CaloEvent/CaloCellContainer.h" +#include "CaloEvent/CaloClusterContainer.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloUtils/CaloCellList.h" +#include "AthContainers/OwnershipPolicy.h" +#include "NavFourMom/INavigable4MomentumCollection.h" + +#include "xAODCaloEvent/CaloCluster.h" + +#include "tauRec/TauPi0BonnCreateROI.h" +#include "tauRec/TauPi0BonnParser.h" + +#include "tauEvent/TauPi0Details.h" +#include "tauEvent/TauShot.h" + +#include "CaloInterface/IHadronicCalibrationTool.h" +#include "RecoToolInterfaces/IExtrapolateToCaloTool.h" +#include "CaloInterface/ICaloCellMakerTool.h" +#include "CaloIdentifier/CaloCell_ID.h" + +using std::max; +using std::min; +using std::vector; +using std::string; +//using xAOD::PFO; // required for subtration in EM1 + + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0BonnCreateROI::TauPi0BonnCreateROI( const string& type, + const string& name, + const IInterface *parent) + : TauToolBase(type, name, parent) + , m_caloWeightTool("H1WeightToolCSC12Generic") + , m_trackToCaloTool("") + , m_cellMakerTool("") + , m_calo_dd_man(NULL) + , m_calo_id(NULL) + , m_latParser(new TauPi0BonnParser()) + , m_caloCellContainerName("AllCalo") + , m_clusterContainerName("CaloCalTopoCluster") + , m_pPi0CellContainer(NULL) + , m_pi0CellContainerName("TauCommonPi0CellContainer") + , m_chargedPFOContainerName("TauPi0BonnChargedPFOContainer") +{ + declareInterface<TauToolBase > (this); + + declareProperty("CaloWeightTool", m_caloWeightTool); + declareProperty("ExtrapolateToCaloTool", m_trackToCaloTool); + declareProperty("CellMakerTool", m_cellMakerTool); + + declareProperty("CaloCellContainerName", m_caloCellContainerName); // TODO: May be replaced using tau clusters + declareProperty("ClusterContainerName", m_clusterContainerName); // TODO: May be replaced using tau clusters + declareProperty("Pi0CellContainerName", m_pi0CellContainerName); + declareProperty("ChargedPFOContainerName", m_chargedPFOContainerName); + + declareProperty("LatParFile", m_latParFile ); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0BonnCreateROI::~TauPi0BonnCreateROI() { +} + +StatusCode TauPi0BonnCreateROI::initialize() { + + // retrieve tools + ATH_MSG_DEBUG( "Retrieving tools" ); + CHECK( m_caloWeightTool.retrieve() ); + CHECK( m_trackToCaloTool.retrieve() ); + CHECK( m_cellMakerTool.retrieve() ); + + // initialize calo cell geo + m_calo_dd_man = CaloDetDescrManager::instance(); + m_calo_id = m_calo_dd_man->getCaloCell_ID(); + + + //////////////////////////////////////////////////////////// + // Load lateral parameterisation + //////////////////////////////////////////////////////////// + // check file given for lateral shower parameteristaion + if( m_latParFile == "" ){ + ATH_MSG_ERROR( "No lateral shower parameterisation given" ); + return StatusCode::FAILURE; + } + // parse lateral config file + m_latParser->parseROOTFile( PathResolver::find_file(m_latParFile, "DATAPATH") ); + + // set addresses of all varaibles that can be used in the para. + m_latParser->setVar( "PT", m_pt ); + m_latParser->setVar( "ABSETA", m_abseta); + m_latParser->setVar( "HADF", m_hadf); + m_latParser->setVar( "SAMP", m_sampling); + + // hadf bot used atm. TODO: REMOVE? + m_hadf = 0.; + + // check that parser loaded correctly, and that the required + // variables are configured + if( !m_latParser->checkInitialisationStatus() ){ + ATH_MSG_ERROR( "Failure loading lateral shower parameterisation" ); + ATH_MSG_ERROR( "Parser stream: " << m_latParser->getStream() ); + return StatusCode::FAILURE; + } + + // Create vector with default values + for (int layer = 0 ; layer != CaloCell_ID::FCAL0; ++layer) { + m_defaultValues.push_back(-10.); + m_defaultValuesZero.push_back(0.); + } + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnCreateROI::eventInitialize(TauCandidateData * /*data*/) { + + + const CaloCell_ID* cellID; + if((detStore()->retrieve(cellID)).isFailure()){ + ATH_MSG_ERROR("Unable to retrieve caloCell_ID helper from DetectorStore"); + return StatusCode::FAILURE; + } + + // Get hash range + IdentifierHash hashMax; + hashMax = cellID->calo_cell_hash_max(); + ATH_MSG_VERBOSE("CaloCell Hash Max: " << hashMax); + + // Reset addedCellsMap + m_addedCellsMap.clear(); + for (unsigned i = 0; i < hashMax; i++) { + m_addedCellsMap.push_back(NULL); + } + + // Reset hist maps + m_trackHistMapBarrel.clear(); + m_trackHistMapEndcap.clear(); + + //--------------------------------------------------------------------- + // Create CustomCellContainer and register in StoreGate + //--------------------------------------------------------------------- + m_pPi0CellContainer = new CaloCellContainer(SG::OWN_ELEMENTS); + CHECK( evtStore()->record(m_pPi0CellContainer, m_pi0CellContainerName) ); + + // symlink as INavigable4MomentumCollection (as in CaloRec/CaloCellMaker) + CHECK(evtStore()->symLink(m_pPi0CellContainer, static_cast<INavigable4MomentumCollection*> (0))); + + //--------------------------------------------------------------------- + // Create charged PFO container + //--------------------------------------------------------------------- + m_chargedPFOContainer = new xAOD::PFOContainer(); + CHECK( evtStore()->record(m_chargedPFOContainer, m_chargedPFOContainerName ) ); + m_chargedPFOAuxStore = new xAOD::PFOAuxContainer(); + CHECK( evtStore()->record( m_chargedPFOAuxStore, m_chargedPFOContainerName + "Aux." ) ); + m_chargedPFOContainer->setStore(m_chargedPFOAuxStore); + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnCreateROI::execute(TauCandidateData *data) { + + xAOD::TauJet *pTau = data->xAODTau; + + // Any tau needs to have PFO vectors. Set empty vectors before nTrack cut + vector<ElementLink<xAOD::PFOContainer> > empty; + pTau->setCellBased_Charged_PFOLinks(empty); + pTau->setCellBased_Neutral_PFOLinks(empty); + pTau->setCellBased_Pi0_PFOLinks(empty); + + // Any tau needs to have PanTauCellBasedProto 4mom. Set it to 0 before nTrack cut + pTau->setP4(xAOD::TauJetParameters::PanTauCellBasedProto, 0.0, 0.0, 0.0, 0.0); + + //--------------------------------------------------------------------- + // only run shower subtraction on 1-5 prong taus + //--------------------------------------------------------------------- + if (pTau->nTracks() == 0 || pTau->nTracks() >5 ) { + return StatusCode::SUCCESS; + } + ATH_MSG_DEBUG("new tau. \tpt = " << pTau->pt() << "\teta = " << pTau->eta() << "\tphi = " << pTau->phi() << "\tnprongs = " << pTau->nTracks()); + + //--------------------------------------------------------------------- + // get tau tracks + //--------------------------------------------------------------------- + vector<const xAOD::TrackParticle*> tracks; + for(unsigned iTrack = 0; iTrack<pTau->nTracks();++iTrack){ + const xAOD::TrackParticle* track = pTau->track(iTrack); + tracks.push_back(track); + } + + //--------------------------------------------------------------------- + // retrieve cells around tau + //--------------------------------------------------------------------- + + // get all calo cell container + const CaloCellContainer *pCellContainer = NULL; + CHECK( evtStore()->retrieve(pCellContainer, m_caloCellContainerName) ); + + // get only EM cells within dR<0.2 + vector<CaloCell_ID::SUBCALO> emSubCaloBlocks; + emSubCaloBlocks.push_back(CaloCell_ID::LAREM); + boost::scoped_ptr<CaloCellList> pCells(new CaloCellList(pCellContainer,emSubCaloBlocks)); + + // TODO: change hardcoded 0.2 to tau cone variable, (or func. from TauJet?) + pCells->select(pTau->eta(), pTau->phi(), 0.4); + + //--------------------------------------------------------------------- + // prepare extrapolation of tracks to calo layers + //--------------------------------------------------------------------- + // clear vectors related to track extrapolation + // have to do that for each tau so it cannot be done in eventInitialize, + // which is called once per event (and not once per tau) + m_tracksEtaAtSampling.clear(); + m_tracksPhiAtSampling.clear(); + m_extrapolatedSamplings.clear(); + // Fill with default values + for(int layer = 0 ; layer != CaloCell_ID::FCAL0; ++layer) { + m_extrapolatedSamplings.push_back(false); + } + //vector<float> E_sub_track; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + m_tracksEtaAtSampling.push_back( m_defaultValues ); + m_tracksPhiAtSampling.push_back( m_defaultValues ); + //E_sub_track.push_back( 0. ); + } + + //--------------------------------------------------------------------- + // get energy in HCal associated to the different tracks + //--------------------------------------------------------------------- + const xAOD::CaloClusterContainer* clusterContainer = NULL; + CHECK( evtStore()->retrieve( clusterContainer, m_clusterContainerName ) ); + + vector<double> EestInEcal = this->getEstEcalEnergy(tracks,clusterContainer,pTau); + + //Create charged PFOs + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + const xAOD::TrackParticle* track = tracks.at(iTrack); + xAOD::PFO* chargedPFO = new xAOD::PFO(); + m_chargedPFOContainer->push_back(chargedPFO); + ElementLink<xAOD::TrackParticleContainer> myTrackLink = pTau->trackLinks().at(iTrack); + if(!chargedPFO->setTrackLink(myTrackLink)) ATH_MSG_WARNING("Could not add Track to PFO"); + chargedPFO->setCharge(track->charge()); + chargedPFO->setP4(track->pt(),track->eta(),track->phi(),track->m()); + // Create element link from tau to charged PFO + ElementLink<xAOD::PFOContainer> PFOElementLink; + PFOElementLink.toContainedElement( *m_chargedPFOContainer, chargedPFO ); + pTau->addCellBased_Charged_PFOLink( PFOElementLink ); + // Store energy to subtract/subtracted for the track in CenterMag variable. This variables is otherwise never used for charged PFOs + chargedPFO->setCenterMag( (float) EestInEcal.at(iTrack)); + } + + // Optional: Subtraction in EM1 (part 1 of 3) + // FIXME: xAOD migration of subtration in EM1 + /* + //--------------------------------------------------------------------- + // get cells in EM1 associated to the different tracks + //--------------------------------------------------------------------- + std::vector<IdentifierHash> pipmCellHash; + const std::vector<TauShot*> shotVector = pPi0Details->shotVector(); + + for(unsigned iShot = 0;iShot<shotVector.size();++iShot){ + TauShot* currentShot = shotVector.at(iShot); + const CaloCell* seedCell = currentShot->seedCell(); + + int samp = seedCell->caloDDE()->getSampling(); + double seedEta = seedCell->eta(); + + // Don't match shots in crack region. Cells are so large that pi0s are likely to be in the same cell. + if( (samp == 1 && fabs(seedEta)>1.4) || (samp == 5 && fabs(seedEta) < 1.5) ) continue; + + // Subtract 3 cells + double shotPt = currentShot->pt3(); + + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + // Do not match shots to tracks, which have E_est < shotPt + if(EestInEcal.at(iTrack)<shotPt) continue; + + // Do not match shots to tracks that have shotPt > 20% of the track pt. + // The shot is unlikely to come from the charged pion in this case + double maxFrac = 0.20; + if(tracks.at(iTrack)->pt() * maxFrac < shotPt) continue; + + // check if tracks have been extrapolated to this sampling. Do so if this is not the case + if(m_extrapolatedSamplings.at(samp)==false){ + this->getExtrapolatedPositions(tracks,samp); + ATH_MSG_DEBUG("Extr to layer " << samp << "\teta = " << m_tracksEtaAtSampling.at(iTrack).at(samp) << "\tphi = " << m_tracksPhiAtSampling.at(iTrack).at(samp)); + m_extrapolatedSamplings.at(samp)=true; + } + // Check if shot is close to the extrapolated track + double AbsDEta = fabs( seedEta - m_tracksEtaAtSampling.at(iTrack).at(samp)); + double AbsDPhi = fabs( seedCell->phi() - m_tracksPhiAtSampling.at(iTrack).at(samp)); + double cellWidthEta = seedCell->caloDDE()->deta(); + double cellWidthPhi = seedCell->caloDDE()->dphi(); + double allowedDev = 0.001; + if( (AbsDEta > cellWidthEta/2.+allowedDev) || (AbsDPhi > cellWidthPhi/2.+allowedDev) ) continue; + + // Assign shot to track + + // Store shot cells in pipmCellHash + double shotE = 0.; + std::vector<std::vector<const CaloCell*> > shotCells = currentShot->getCellVector(m_calo_id); + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + int windowSize = 3; // must be 1, 3 or 5 + if( windowSize%2!=1 && windowSize > nCells_eta) ATH_MSG_WARNING("Set window size for subtractionin EM1 properly! No energy will be subtracted in EM1"); + for(int iCell = 0; iCell != nCells_eta; ++iCell ){ + if(fabs(iCell-seedIndex)>windowSize/2) continue; + double wtCell0=0.; + double wtCell1=0.; + if(shotCells.at(0).at(iCell) != NULL){ + wtCell0 = m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + shotE+=shotCells.at(0).at(iCell)->e()*wtCell0; + pipmCellHash.push_back(shotCells.at(0).at(iCell)->caloDDE()->calo_hash()); + } + if(shotCells.at(1).at(iCell) != NULL){ + wtCell1 = m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + shotE+=shotCells.at(1).at(iCell)->e()*wtCell1; + pipmCellHash.push_back(shotCells.at(1).at(iCell)->caloDDE()->calo_hash()); + } + } + // Reduce EestInEcal by shot energy. ShotE is slightly more preciese than shotPt*cosh(currentShot->cluster()->eta()) (difference<1MeV) + EestInEcal.at(iTrack) -= shotE; + // Set number of photons in shot to 0. + currentShot->setNPhotons(0); + ATH_MSG_DEBUG("Assigned shot " << iShot << " to track " << iTrack << ". \tshotE = "<< shotE << "\tshotEta = " << seedEta << "\tshotPhi = " << seedCell->phi()); + } + } + */ + + //--------------------------------------------------------------------- + // Start creating output container: + // PS: Don't do subtraction, just put cells in output container + // EM1: Set energies of cells to 0 that have been matched to a track. Put cells in output container. + // EM2: Sum up subtraction weights for each track. Have to normalize and subtract after this loop. + //--------------------------------------------------------------------- + + // Create vectors that will be used in a second loop over EM2 cells, only + // vector of cells + std::vector<const CaloCell*> EM2Cells; + // vector of lateral weights for each cell and each track. Cells are in same order as in EM2Cells vector + std::vector<std::vector<double> > cellSubWeights; + // vector of sum of lateral weights for each track. Will be used for the normalization + std::vector<double> sumCellSubWeights; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + sumCellSubWeights.push_back(0.); + } + + CaloCellList::list_iterator cellItr(pCells->begin()), cellItrE(pCells->end()); + for(; cellItr != cellItrE; ++cellItr) { + const CaloCell* cell = (*cellItr); + + // get cell sampling + int samp = cell->caloDDE()->getSampling(); + + // only keep cells that are in PS, EM1 and EM2. + if(samp>=7 || samp == 3 ) continue; + + if( samp!=2 && samp != 6 ){ // PS and EM1 + // Optional: Subtraction in EM1 (part 2 of 3) + /* + // Check if cell is in EM1 and if it is matched to a track + bool isPipmCell = false; + if(samp == 1 || samp == 5){ + //Ask cell for it's hash + const IdentifierHash cellHash = cell->caloDDE()->calo_hash(); + + for(unsigned iPipmCellHash=0;iPipmCellHash<pipmCellHash.size();++iPipmCellHash){ + if(pipmCellHash.at(iPipmCellHash)==cellHash){ + ATH_MSG_DEBUG("Set cell energy to 0. " << "eta = " << cell->eta() << "\tphi = " << cell->phi() << "\tE = " << cell->e()); + isPipmCell = true; + break; + } + } + } + */ + double subtractedEnergy = 0.; + + // Optional: Subtraction in EM1 (part 3 of 3) + // if(isPipmCell == true) subtractedEnergy = cell->e(); + + // Store cell in output container + storeCell(cell, subtractedEnergy); + } + else{ // EM2 + + // Current procedure in crack region: Linear Interpolation from 1.375 to 1.475 + double interpolationFactorForCrack = 1.; + double crackMax = 1.475; + double crackMin = 1.375; + double crackW = crackMax - crackMin; + if(samp!=0 && samp<4 && fabs(cell->eta())>crackMin) + interpolationFactorForCrack=1.-(fabs(cell->eta())-crackMin)/crackW; + if(samp>3 && fabs(cell->eta())<crackMax) + interpolationFactorForCrack=1.-(crackMax-fabs(cell->eta()))/crackW; + + // Store weights of this cell for each track + vector<double> thisCellSubWeights; + double sumThisCellSubWeights = 0.; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + // Don't need to determine weights if no energy is to be subtracted for this track + if( EestInEcal.at(iTrack)==0. ){ + thisCellSubWeights.push_back(0.); + continue; + } + + // Get info on track + const xAOD::TrackParticle* track = tracks.at(iTrack); + + // check if tracks have been extrapolated to this sampling. Do so if this is not the case + if(m_extrapolatedSamplings.at(samp)==false){ + this->getExtrapolatedPositions(tracks,samp); + ATH_MSG_DEBUG("Extr to layer " << samp << "\teta = " << m_tracksEtaAtSampling.at(iTrack).at(samp) << "\tphi = " << m_tracksPhiAtSampling.at(iTrack).at(samp)); + m_extrapolatedSamplings.at(samp)=true; + } + + // set extrapolated track direction + TLorentzVector extTrack; + + extTrack.SetPtEtaPhiE(track->pt(), m_tracksEtaAtSampling.at(iTrack).at(samp), m_tracksPhiAtSampling.at(iTrack).at(samp), track->e()); + + // get eta/phi distance of cell to track + double deltaEta = extTrack.Eta()-cell->eta(); + double deltaPhi = TVector2::Phi_mpi_pi( extTrack.Phi() - cell->phi()); + + // TODO: + // - Determine lateral weight using TH1 + double cellWidthEta = cell->caloDDE()->deta(); + double cellWidthPhi = cell->caloDDE()->dphi(); + double cellSubWeight = getLatWeight(samp, deltaEta, deltaPhi, cellWidthEta, cellWidthPhi, iTrack, track); + + + // Get final weight by multiplying with interpolationFactorForCrack + cellSubWeight*=interpolationFactorForCrack; + sumCellSubWeights.at(iTrack)+=cellSubWeight; + thisCellSubWeights.push_back(cellSubWeight); + sumThisCellSubWeights+=cellSubWeight; + } + if(sumThisCellSubWeights == 0.){ + // No need to run subtraction in the second loop + storeCell(cell, 0.); + } + else{ + EM2Cells.push_back(cell); + cellSubWeights.push_back(thisCellSubWeights); + } + } + } + // Loop over EM2 cells. Subtract energy assigned to the cell and store it in the output cell container. + for(unsigned iCell=0; iCell!= EM2Cells.size();++iCell){ + const CaloCell* cell = EM2Cells.at(iCell); + + // Get cell weight + double wtCell = m_caloWeightTool->wtCell(cell); + // wtCell=0 (happens very rarely) would cause a FPE later + if( wtCell == 0. ) continue; + + // Determine how much energy to subtract + double subtractedEnergy = 0.; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + if(EestInEcal.at(iTrack)==0. || sumCellSubWeights.at(iTrack)==0.) continue; + subtractedEnergy+=EestInEcal.at(iTrack)*cellSubWeights.at(iCell).at(iTrack)/sumCellSubWeights.at(iTrack); + // E_sub_track.at(iTrack)+=EestInEcal.at(iTrack)*cellSubWeights.at(iCell).at(iTrack)/sumCellSubWeights.at(iTrack); + } + // Store cell in output container + storeCell(cell, subtractedEnergy); + } + // Check if total amount of subtracted energy is correct + /* + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + ATH_MSG_INFO("EestInEcal.at(iTrack) = "<<EestInEcal.at(iTrack)<<"\tE_sub_track.at(iTrack) = "<<E_sub_track.at(iTrack)<<"\tsumCellSubWeights.at(iTrack) = "<<sumCellSubWeights.at(iTrack)); + } + */ + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnCreateROI::eventFinalize(TauCandidateData* /* data */) { + + //--------------------------------------------------------------------- + // use the m_cellMakerTool to finalize the + // custom CaloCellContainer + //--------------------------------------------------------------------- + CHECK( m_cellMakerTool->process(static_cast<CaloCellContainer*> (m_pPi0CellContainer)) ); + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnCreateROI::finalize() { + // delete TH1 from parser + return StatusCode::SUCCESS; +} + +void TauPi0BonnCreateROI::getExtrapolatedPositions( + vector<const xAOD::TrackParticle*> tracks, + int sampling) +{ + for (unsigned iTrack = 0 ; iTrack < tracks.size(); ++iTrack ) { + // extrapolate track to sampling + // FIXME: xAOD migration as soon as tool is available + ATH_MSG_DEBUG( "Try extrapolation of track with pt = " << tracks.at(iTrack)->pt() << ", eta " << tracks.at(iTrack)->eta() << ", phi" << tracks.at(iTrack)->phi() + << " to layer " << sampling); + const Trk::TrackParameters* param_at_calo = 0; + param_at_calo = m_trackToCaloTool->extrapolate( + *tracks.at(iTrack), + (CaloCell_ID::CaloSample) sampling, + 0.0, Trk::alongMomentum, Trk::pion); + + // store if track extrapolation successful, else use dummy values + if(param_at_calo){ + ATH_MSG_DEBUG( "Extrapolated track with eta=" << tracks.at(iTrack)->eta() + << " phi="<<tracks.at(iTrack)->phi() + << " to eta=" << param_at_calo->position().eta() + << " phi="<<param_at_calo->position().phi() + ); + m_tracksEtaAtSampling.at(iTrack).at(sampling)=param_at_calo->position().eta(); + m_tracksPhiAtSampling.at(iTrack).at(sampling)=param_at_calo->position().phi(); + delete param_at_calo; + } + else ATH_MSG_DEBUG("Could not extrapolate track with pt = " << tracks.at(iTrack)->pt() << ", eta " << tracks.at(iTrack)->eta() << ", phi" << tracks.at(iTrack)->phi() + << " to layer " << sampling); + //just keep default values in case extrapolation failed + } +} + +vector<double> TauPi0BonnCreateROI::getEstEcalEnergy( + vector<const xAOD::TrackParticle*> tracks, + const xAOD::CaloClusterContainer* clusterContainer, + const xAOD::TauJet* rtau) +{ + // Vector that stores hadronic energy associated to one track + vector<double> EHcal; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + EHcal.push_back(0.); + } + + ATH_MSG_DEBUG("new tau. eta = " << rtau->eta() << "\t phi = " << rtau->phi() ); + + xAOD::CaloClusterContainer::const_iterator clusterItr = clusterContainer->begin(); + xAOD::CaloClusterContainer::const_iterator clusterItrE = clusterContainer->end(); + + int clusterNumber = -1; + + for(;clusterItr!=clusterItrE;++clusterItr){ + const xAOD::CaloCluster* cluster = (xAOD::CaloCluster*) *clusterItr; + + double deltaEtaToTau = rtau->eta()-cluster->eta(); + double deltaPhiToTau = TVector2::Phi_mpi_pi( rtau->phi() - cluster->phi()); + + // Check deltaR^2<0.2^2 instead of deltaR<0.2, because it is computationally less expensive. + double deltaRToTau_squared = deltaEtaToTau*deltaEtaToTau+deltaPhiToTau*deltaPhiToTau; + if(deltaRToTau_squared>0.04) continue; + + + clusterNumber++; + + ATH_MSG_DEBUG("Cluster number << " << clusterNumber << "\t energy = " << cluster->e() << "\t eta = " << cluster->eta() << "\t phi = " << cluster->phi() << + "\t deltaEtaToTau = " << deltaEtaToTau << "\t deltaPhiToTau = " << deltaPhiToTau << "\t deltaRToTau_squared = " << deltaRToTau_squared ); + + + // Get sample with maximum energy and cluster energy in Hcal + vector<double> energyInSamples=m_defaultValuesZero; + // Get energy in Hcal samplings: Loop over cells + const CaloClusterCellLink* theCellLink = cluster->getCellLinks(); + + CaloClusterCellLink::const_iterator cellInClusterItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end(); + + for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){ + CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr; + int sampling = cellInCluster->caloDDE()->getSampling(); + if(sampling <= 2 || (sampling >=4 && sampling <=6 ) || sampling >= CaloCell_ID::FCAL0) continue; + energyInSamples.at(sampling) += cellInCluster->e()*cellInClusterItr.weight(); + } + + + double cluster_EHcal = 0.; + int maxSample = -1; + double maxESample = 0.; + for(unsigned iSample = 0; iSample < energyInSamples.size(); ++iSample){ + if(iSample == 3 || iSample >= 7 ) cluster_EHcal+=energyInSamples.at(iSample); + if(energyInSamples.at(iSample)<maxESample) continue; + maxSample = iSample; + maxESample = energyInSamples.at(iSample); + } + // Apply cryostat correction + if(energyInSamples.at(3) > 0. && energyInSamples.at(12) > 0.){ + cluster_EHcal += m_caloWeightTool->wtCryo() * sqrt(energyInSamples.at(3)*energyInSamples.at(12)); + } + + + if(cluster_EHcal <= 0.){ + ATH_MSG_DEBUG("cluster_EHcal = " << cluster_EHcal/1000. << "<=0. Skip this cluster for Hcal estimate."); + continue; + } + + // check if tracks have been extrapolated to this sampling. Do so if this is not the case + if(m_extrapolatedSamplings.at(maxSample)==false){ + this->getExtrapolatedPositions(tracks,maxSample); + ATH_MSG_DEBUG("Extrapolate to layer " << maxSample << "\teta = " + << m_tracksEtaAtSampling.at(0).at(maxSample) << "\t phi = " << m_tracksPhiAtSampling.at(0).at(maxSample) ); + m_extrapolatedSamplings.at(maxSample)=true; + } + + // Assign cluster to track + int closestTrack = -1; + //double dEtaClosestTrack = 10; + //double dPhiClosestTrack = 10; + double dRToClosestTrack_squared = 0.16; // XXX can be tuned later + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + const xAOD::TrackParticle* track = tracks.at(iTrack); + + + // set extrapolated track direction + TLorentzVector extTrack; + ATH_MSG_DEBUG("filling extrapolated Track number " << iTrack << ", pt = " << track->pt() << ", eta = " << m_tracksEtaAtSampling.at(iTrack).at(maxSample) << ", phi " << m_tracksPhiAtSampling.at(iTrack).at(maxSample) << ", e = " << track->e() ); + + extTrack.SetPtEtaPhiE(track->pt(), m_tracksEtaAtSampling.at(iTrack).at(maxSample), m_tracksPhiAtSampling.at(iTrack).at(maxSample), track->e()); + + // get eta/phi distance of cell to track + double deltaEta = extTrack.Eta()-cluster->eta(); + double deltaPhi = TVector2::Phi_mpi_pi( extTrack.Phi() - cluster->phi());; + + double deltaRToTrack_squared = deltaEta*deltaEta+deltaPhi*deltaPhi; + ATH_MSG_DEBUG("Track number " << iTrack << ", extTrack.Eta() = " << extTrack.Eta() << ", extTrack.Phi() = " << extTrack.Phi()); + + if(deltaRToTrack_squared>=dRToClosestTrack_squared) continue; + closestTrack = iTrack; + //dEtaClosestTrack = deltaEta; + //dPhiClosestTrack = deltaPhi; + dRToClosestTrack_squared = deltaRToTrack_squared; + } + if(closestTrack == -1 && dRToClosestTrack_squared > 0.04){ + //ATH_MSG_DEBUG("dRToClosestTrack_squared = " << dRToClosestTrack_squared << ", dEta = " << dEtaClosestTrack << ", dPhi = " << dPhiClosestTrack + // << ". Skip cluster for Hcal estimate. \tcluster_EHcal = " << cluster_EHcal/1000.); + continue; // Didn't find a track + } + EHcal.at(closestTrack) += cluster_EHcal; + ATH_MSG_DEBUG("Cluster associated to track " << closestTrack << "\tcluster_EHcal = " << cluster_EHcal/1000.); + } + // Get energy estimate in ECAL + vector<double> E_ests; + for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){ + double E_est = tracks.at(iTrack)->e()-EHcal.at(iTrack); + // energy cant be less than 0 + if(E_est < 0) E_est = 0.; + // energy cant be more than track momentum + if(E_est > tracks.at(iTrack)->e()) E_est = tracks.at(iTrack)->e(); + E_ests.push_back(E_est); + } + return E_ests; +} + +double TauPi0BonnCreateROI::getLatWeight(int samp, + double deltaEta, + double deltaPhi, + double cellWidthEta, + double cellWidthPhi, + unsigned trackNumber, + const xAOD::TrackParticle* track + ) +{ + // No need to subtract very far away from the track + if(fabs(deltaEta)>0.15 || fabs(deltaPhi)>0.15) return 0.; + + TH1* histo; + + // Store histograms in order to speed up the algorithm + // The + + // Check if TH1 is already in one of the maps + std::map<int, TH1*>::iterator itr; + if( samp==2 ) itr = m_trackHistMapBarrel.find(trackNumber); + else itr = m_trackHistMapEndcap.find(trackNumber); + + if( (samp==2 && itr != m_trackHistMapBarrel.end()) || (samp==6 && itr != m_trackHistMapEndcap.end()) ){ + histo = itr->second; + } + else{ + //--------------------------------------------------------------------- + // Need to get bin key and histogram from parser + // set variables that can be used for parameterisation + // Note: if value outside bin range, parser will choose first or last + // bin + //--------------------------------------------------------------------- + m_pt = track->pt(); + m_abseta = fabs(track->eta()); + // FIXME: Preliminary fix for crack: + if(m_abseta>1.34 && samp==2 ) m_abseta = 1.34; + if(m_abseta<1.56 && samp==6 ) m_abseta = 1.56; + m_sampling = (double) samp; + string key = m_latParser->getBinKey(); + + ATH_MSG_DEBUG("m_pt = " << m_pt << "\tm_abseta = " << m_abseta << "\tm_hadf = " << m_hadf << "\tm_sampling = " << m_sampling << "\tkey = " << key); + + histo = m_latParser->getTH1(); + + if(samp==2) m_trackHistMapBarrel[trackNumber] = histo; + else m_trackHistMapEndcap[trackNumber] = histo; + } + + // Get cell weight from histogram + int bin = histo->FindBin(fabs(deltaEta), deltaPhi*track->charge()); + double cellWeight = histo->GetBinContent(bin); + + // multiply by cell area in order to account for varying cell sizes in the endcap + cellWeight*=cellWidthEta*cellWidthPhi; + + return cellWeight; +} + +void TauPi0BonnCreateROI::storeCell(const CaloCell* cell, + double subtractedEnergy){ + // Store cell in output container if it is a new cell + // Produce a copy of the cell, in order to prevent + // the energy of the original cell to be changed. + // Store unweighted cells, since the cell weights are applied during reclustering + + //Ask cell for it's hash + const IdentifierHash cellHash = cell->caloDDE()->calo_hash(); + //Check if this cell is already part of reducedCellContainer + bool isNewCell = (m_addedCellsMap.at(cellHash)==NULL); + + if(isNewCell){ + CaloCell* copyCell = cell->clone(); + if(subtractedEnergy>0.){ + // Get cell weight + double wtCell = m_caloWeightTool->wtCell(cell); + // wtCell=0 (happens very rarely) would cause a FPE + if( wtCell != 0. ) copyCell->setEnergy( cell->e() - subtractedEnergy/wtCell ); + } + m_pPi0CellContainer->push_back(const_cast<CaloCell*> (copyCell)); + m_addedCellsMap[cellHash] = copyCell; + } + // If the cell has been already stored the energy is subtracted for the already existing copy + else if(subtractedEnergy>0.){ + CaloCell* copyCell = m_addedCellsMap.at(cellHash); + // Get cell weight + double wtCell = m_caloWeightTool->wtCell(cell); + // wtCell=0 (happens very rarely) would cause a FPE + if( wtCell != 0. ) copyCell->setEnergy( cell->e() - subtractedEnergy/wtCell ); + } +} + diff --git a/Reconstruction/tauRec/src/TauPi0BonnParser.cxx b/Reconstruction/tauRec/src/TauPi0BonnParser.cxx new file mode 100644 index 00000000000..efea376fd40 --- /dev/null +++ b/Reconstruction/tauRec/src/TauPi0BonnParser.cxx @@ -0,0 +1,361 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0BonnParser +// package: Reconstruction/tauEvent +// authors: Will Davey <will.davey@cern.ch> +// date: 2012-09-13 +// +//----------------------------------------------------------------------------- + +#include "tauRec/TauPi0BonnParser.h" + +#include "TFile.h" +#include "TParameter.h" +#include "TVectorF.h" +#include "TObjString.h" +#include "TObjArray.h" + +#include <iostream> +#include <assert.h> +#include <string> +#include <sstream> +#include <fstream> +#include <stdlib.h> + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TauPi0BonnParser::TauPi0BonnParser() + : m_max_traceback(1000) +{ +} + +TauPi0BonnParser::~TauPi0BonnParser() +{ + // because we own the pointer of the histograms, we need to delete them here + std::map<std::string,TH1*>::iterator it=m_hist_map.begin(); + for (;it!=m_hist_map.end(); ++it) delete it->second; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void TauPi0BonnParser::setMaxTraceback(int i){ + m_max_traceback = i; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool TauPi0BonnParser::setVar( const string& key, double& val ){ + if(m_curr_val_map.find(key)==m_curr_val_map.end()){ + this->msg( "ERROR: var: "+key+" not in map" ); + return false; + } + m_curr_val_map[key] = &val; + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TH1* TauPi0BonnParser::getTH1(){ + string key = this->getBinKey(); + return m_hist_map[key]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +string TauPi0BonnParser::getStream(){ + return m_stream; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void TauPi0BonnParser::msg( const string& str ){ + m_stream += str+"\n"; + int length = m_stream.size(); + if( length>m_max_traceback ) m_stream = m_stream.substr(m_stream.size()-m_max_traceback,m_max_traceback); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// get bin key from a list of bin indices +string TauPi0BonnParser::getBinKey( const vector<int>& bin_indices ){ + string key = ""; + for( unsigned int j=0; j<bin_indices.size();j++) { + if( j!=0 ) key += "_"; + key += m_bin_order.at(j); + key += Form("%d",bin_indices.at(j)); + } + return key; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// get bin key from a list of var values +string TauPi0BonnParser::getBinKey(){ + // get current stored values of input variables + vector<double> vals = this->getCurrentVals(); + // create vector to store bins corresponding to vals of input vars + vector<int> bin_indices; + + for( unsigned int i=0; i<vals.size();i++ ){ + // get variable name and current value + string key = m_bin_order.at(i); + double val = vals.at(i); + + // retrieve binning + vector<double> bin_edges = m_bin_map[key]; + + // determine bin index + int index = 0; + for( unsigned int j=0; j<bin_edges.size()-1; j++ ){ + // return index 0 if before first bin + if( val < bin_edges.front() ) break; + // return last bin (n-2) if after last bin + if( val > bin_edges.back() ){ + index = bin_edges.size()-2; + break; + } + if( val >= bin_edges.at(j) && val < bin_edges.at(j+1) ){ + index = j; + break; + } + } + bin_indices.push_back(index); + } + return this->getBinKey(bin_indices); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +vector<double> TauPi0BonnParser::getCurrentVals(){ + vector<double> current_vals; + vector<string>::iterator itr = m_bin_order.begin(); + for( ; itr!=m_bin_order.end(); itr++ ){ + // dont try to access null pointer if user hasn't configured properly + if ( m_curr_val_map[*itr] == NULL ) { + current_vals.push_back(-9999.); + } + else{ + current_vals.push_back( (*m_curr_val_map[*itr]) ); + } + } + return current_vals; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool TauPi0BonnParser::parseTDirectory( + TDirectory* dir, + vector<int> current_bin_store, + int current_index) +{ + // make sure current_bin_store can accommodate map entries + while( current_bin_store.size()<m_bin_map.size() ) current_bin_store.push_back(0); + + // initialise iterator + if( current_index == -1 ) current_index = 0; + // increment iterator if this is a recursion + else current_index++; + + // get binning for current variable + string key = m_bin_order.at(current_index); + vector<double> bin_edges = m_bin_map[key]; + + // looping over bins for current variable (dont count last bin top edge!) + for( unsigned int i=0; i<bin_edges.size()-1; i++ ){ + // store the iterator for the current variable (is passed in recursion) + current_bin_store.at(current_index) = i; + + // once final variable reached, retrieve info from config file + if( current_index == (int)(m_bin_order.size()-1) ){ + string bin_key = getBinKey( current_bin_store ); + + /* + // attempt to retrieve from file + TVectorF* pvec = (TVectorF*) dir->Get(bin_key.c_str()); + if( !pvec ){ + msg( string("Failed to find ")+bin_key+" in dir."); + dir->ls(); + return false; + } + + // store as std::vector + vector<double> new_vec; + for( int j=0;j<pvec->GetNoElements();j++) new_vec.push_back((*pvec)(j)); + m_hist_map[bin_key]=new_vec; + */ + + TH1* hist = (TH1*) dir->Get(bin_key.c_str()); + if( !hist ){ + msg( string("Failed to find ")+bin_key+" in dir."); + dir->ls(); + return false; + } + + // store as TH1 + hist->SetDirectory(0); + m_hist_map[bin_key]=(TH1*)hist; //no clone in case SetDirectory(0) is used ->Clone(); + + } + else{ + // recursively call to loop through all binning combinations + if( !this->parseTDirectory( + dir, + current_bin_store, + current_index) + ) + { + msg( "ERROR parsing TDirectory" ); + return false; + } + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool TauPi0BonnParser::parseROOTFile( string filename, string directory ){ + + // open input file + TFile* file = TFile::Open( filename.c_str() ); + if( !file ){ + msg( string("cant load file ")+filename ); + return false; + } + + // get directory + TDirectory* dir = file->GetDirectory(directory.c_str()); + if( !dir ){ + msg( string("dir: ")+directory+" not in file: "+filename); + return false; + } + + // number of binning variables + TParameter<int>* NDIM = (TParameter<int>*)dir->Get("NDIM"); + if( !NDIM ){ + msg( "config file invalid format!"); + return false; + } + + // ';' seperated list of binning variable identifiers + TObjString* BIN_VARS = (TObjString*) dir->Get("BIN_VARS"); + if( !BIN_VARS ){ + msg( "config file invalid format!"); + return false; + } + + TString BIN_VARS_ts = BIN_VARS->GetString(); + TIterator* BIN_VARS_itr = BIN_VARS_ts.Tokenize(';')->MakeIterator(); + while( TObject* obj = BIN_VARS_itr->Next() ){ + string key = obj->GetName(); + m_bin_map[key] = vector<double>(); + m_curr_val_map[key] = NULL; + m_bin_order.push_back(key); + //cout << "key: " << key << endl; + } + + // load binning for variables + map<string,vector<double> >::iterator itrMap = m_bin_map.begin(); + for(; itrMap!=m_bin_map.end(); itrMap++ ){ + itrMap->second.clear(); + TVectorF* vec = (TVectorF*) dir->Get(Form("%s_BINS",itrMap->first.c_str())); + //assert(vec); + if (!vec) continue; + // cout << "itrMap->first = " << itrMap->first << endl; + for( int i=0; i<vec->GetNoElements(); i++ ){ + itrMap->second.push_back( (*vec)(i+1) ); + // cout << "bin" << i << ": " << (*vec)(i+1) << endl; + } + } + + // parse all bin combinations in TDirectory + if( !this->parseTDirectory(dir) ){ + msg( "failed parsing bins in TDirectory - invalid format!"); + return false; + } + + file->Close(); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool TauPi0BonnParser::checkConfig( + vector<int> current_bin_store, + int current_index) +{ + // make sure current_bin_store can accommodate map entries + while( current_bin_store.size()<m_bin_map.size() ) current_bin_store.push_back(0); + + // initialise iterator + if( current_index == -1 ) current_index = 0; + // increment iterator if this is a recursion + else current_index++; + + // get binning for current variable + string key = m_bin_order.at(current_index); + vector<double> bin_edges = m_bin_map[key]; + + // looping over bins for current variable (dont count last bin top edge!) + for( unsigned int i=0; i<bin_edges.size()-1; i++ ){ + // store the iterator for the current variable (is passed in recursion) + current_bin_store.at(current_index) = i; + + // once final variable reached, retrieve info from config file + if( current_index == (int)(m_bin_order.size()-1) ){ + string bin_key = getBinKey( current_bin_store ); + + if( m_hist_map.find(bin_key) == m_hist_map.end() ){ + msg( bin_key + " not loaded!" ); + return false; + } + } + else{ + // recursively call to loop through all binning combinations + if( !this->checkConfig( + current_bin_store, + current_index) + ) + { + msg( string("failed checkConfig") ); + return false; + } + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool TauPi0BonnParser::checkInitialisationStatus(){ + + // check at least something loaded + if( m_bin_order.size() <= 0 ){ + msg( "nothing loaded" ); + return false; + } + + + // check addresses set for all corresponding varaibles + map<string,double*>::iterator itr = m_curr_val_map.begin(); + for( ; itr!=m_curr_val_map.end(); itr++ ){ + if( itr->second == NULL ){ + msg( string("Address of ") + itr->first + " not set!" ); + return false; + } + } + + + if( !this->checkConfig() ){ + msg( "Failed loading variables" ); + return false; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void TauPi0BonnParser::summary(){ + // FIXME: Write new summary function? + /* + map<std::string,TH1*>::iterator itrMap = m_hist_map.begin(); + for( ; itrMap!=m_hist_map.end(); itrMap++ ){ + cout << itrMap->first << ": "; + for( unsigned int k=0; k<itrMap->second.size(); k++) cout << " " << Form( "%.2f",itrMap->second.at(k)); + cout << endl; + } + */ +} + diff --git a/Reconstruction/tauRec/src/TauPi0BonnScoreCalculator.cxx b/Reconstruction/tauRec/src/TauPi0BonnScoreCalculator.cxx new file mode 100644 index 00000000000..c4dbb38b2c7 --- /dev/null +++ b/Reconstruction/tauRec/src/TauPi0BonnScoreCalculator.cxx @@ -0,0 +1,244 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0BonnScoreCalculator.cxx +// package: Reconstruction/tauRec +// authors: Benedict Winter, Will Davey +// date: 2012-10-09 +// +//----------------------------------------------------------------------------- + +#include <vector> + +#include "tauRec/TauPi0BonnScoreCalculator.h" +#include "xAODPFlow/PFO.h" + +#include "TMVA/Reader.h" + +#include "PathResolver/PathResolver.h" + +using std::vector; +using std::string; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0BonnScoreCalculator::TauPi0BonnScoreCalculator( + const string& type, + const string& name, + const IInterface *parent) + + : TauToolBase(type, name, parent) + , m_readerOption("Silent:!Color") +{ + declareInterface<TauToolBase > (this); + + declareProperty("ReaderOption", m_readerOption); + declareProperty("BDTWeightFile", m_weightfile); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0BonnScoreCalculator::~TauPi0BonnScoreCalculator() +{ +} + + +StatusCode TauPi0BonnScoreCalculator::initialize() +{ + //--------------------------------------------------------------------- + // Create TMVA reader + //--------------------------------------------------------------------- + m_tmvaReader = new TMVA::Reader(TString(m_readerOption)); + + if (msgLvl(MSG::DEBUG)) m_tmvaReader->SetVerbose(true); + + int spectator = 1.; + m_tmvaReader->AddSpectator( "nTau" ,&spectator); + m_tmvaReader->AddSpectator( "nTau_test : = nTau%5" ,&spectator); + m_tmvaReader->AddSpectator( "Sample" ,&spectator); + m_tmvaReader->AddSpectator( "Pi0Cluster_type" ,&spectator); + m_tmvaReader->AddSpectator( "Pi0Cluster_BDTScore_old" ,&spectator); + m_tmvaReader->AddVariable( "Pi0Cluster_Abs_FIRST_ETA" ,&m_FIRST_ETA); + m_tmvaReader->AddVariable( "Pi0Cluster_SECOND_R" ,&m_SECOND_R); +// m_tmvaReader->AddVariable( "Pi0Cluster_SECOND_LAMBDA" ,&m_SECOND_LAMBDA); +// m_tmvaReader->AddVariable( "Pi0Cluster_Abs_DELTA_PHI" ,&m_Abs_DELTA_PHI); +// m_tmvaReader->AddVariable( "Pi0Cluster_Abs_DELTA_THETA" ,&m_Abs_DELTA_THETA); + m_tmvaReader->AddVariable( "Pi0Cluster_CENTER_LAMBDA_helped" ,&m_CENTER_LAMBDA_helped); +// m_tmvaReader->AddVariable( "Pi0Cluster_LATERAL" ,&m_LATERAL); +// m_tmvaReader->AddVariable( "Pi0Cluster_LONGITUDINAL" ,&m_LONGITUDINAL); + m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_EM" ,&m_ENG_FRAC_EM); +// m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_MAX" ,&m_ENG_FRAC_MAX); + m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_CORE" ,&m_ENG_FRAC_CORE); + m_tmvaReader->AddVariable( "Pi0Cluster_log_SECOND_ENG_DENS" ,&m_log_SECOND_ENG_DENS); + m_tmvaReader->AddVariable( "Pi0Cluster_EcoreOverEEM1" ,&m_EcoreOverEEM1); + m_tmvaReader->AddVariable( "Pi0Cluster_AsymmetryWRTTrack" ,&m_AsymmetryWRTTrack); +// m_tmvaReader->AddVariable( "Pi0Cluster_NHitsInEM1" ,&m_NHitsInEM1); +// m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_PS" ,&m_NPosCells_PS); + m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_EM1" ,&m_NPosCells_EM1); + m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_EM2" ,&m_NPosCells_EM2); +// m_tmvaReader->AddVariable( "Pi0Cluster_AbsFirstEtaWRTClusterPosition_EM1" ,&m_firstEtaWRTCluster_EM1); +// m_tmvaReader->AddVariable( "Pi0Cluster_AbsFirstEtaWRTClusterPosition_EM2" ,&m_firstEtaWRTCluster_EM2); + m_tmvaReader->AddVariable( "Pi0Cluster_secondEtaWRTClusterPosition_EM1" ,&m_secondEtaWRTCluster_EM1); + m_tmvaReader->AddVariable( "Pi0Cluster_secondEtaWRTClusterPosition_EM2" ,&m_secondEtaWRTCluster_EM2); +// m_tmvaReader->AddVariable( "Pi0Cluster_energy_EM1" ,&m_energy_EM1); +// m_tmvaReader->AddVariable( "Pi0Cluster_energy_EM2" ,&m_energy_EM2); + + if (bookMethod(m_tmvaReader, "BDT method").isFailure()) return StatusCode::FAILURE; + + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnScoreCalculator::finalize() +{ + StatusCode sc = AlgTool::finalize(); + delete m_tmvaReader; + return sc; +} + + +StatusCode TauPi0BonnScoreCalculator::execute(TauCandidateData *data) +{ + xAOD::TauJet *tauJet = data->xAODTau; + //--------------------------------------------------------------------- + // only run on 1-5 prong taus + //--------------------------------------------------------------------- + if (tauJet->nTracks() == 0 || tauJet->nTracks() >5 ) { + return StatusCode::SUCCESS; + } + ATH_MSG_DEBUG("ScoreCalculator: new tau. \tpt = " << tauJet->pt() << "\teta = " << tauJet->eta() << "\tphi = " << tauJet->phi() << "\tnprongs = " << tauJet->nTracks()); + + //--------------------------------------------------------------------- + // retrieve neutral PFOs from tau, calculate BDT scores and store them in PFO + //--------------------------------------------------------------------- + unsigned nNeutPFO = tauJet->nCellBased_Neutral_PFOs(); + for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++) { + const xAOD::PFO* curNeutPFO_const = tauJet->cellBased_Neutral_PFO( iNeutPFO ); + float BDTScore = calculateScore(curNeutPFO_const); + xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const); + curNeutPFO->setBDTPi0Score((float) BDTScore); + } + + ATH_MSG_DEBUG("End of TauPi0BonnScoreCalculator::execute"); + + return StatusCode::SUCCESS; +} + + +float TauPi0BonnScoreCalculator::calculateScore(const xAOD::PFO* neutralPFO) +{ + m_FIRST_ETA=0.; + m_SECOND_R=0.; + m_SECOND_LAMBDA=0.; + m_Abs_DELTA_PHI=0.; + m_Abs_DELTA_THETA=0.; + m_CENTER_LAMBDA_helped=0.; + m_LATERAL=0.; + m_LONGITUDINAL=0.; + m_ENG_FRAC_EM=0.; + m_ENG_FRAC_MAX=0.; + m_ENG_FRAC_CORE=0.; + m_log_SECOND_ENG_DENS=0.; + m_EcoreOverEEM1=0.; + m_AsymmetryWRTTrack=0.; + // Need to convert int variables to floats after retrieving them + int NHitsInEM1=0; + int NPosCells_PS=0; + int NPosCells_EM1=0; + int NPosCells_EM2=0; + m_firstEtaWRTCluster_EM1=0.; + m_firstEtaWRTCluster_EM2=0.; + m_secondEtaWRTCluster_EM1=0.; + m_secondEtaWRTCluster_EM2=0.; + m_energy_EM1=0.; + m_energy_EM2=0.; + + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_FIRST_ETA,m_FIRST_ETA) == false) + ATH_MSG_WARNING("Can't find FIRST_ETA. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_R,m_SECOND_R) == false) + ATH_MSG_WARNING("Can't find SECOND_R. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_LAMBDA,m_SECOND_LAMBDA) == false) + ATH_MSG_WARNING("Can't find SECOND_LAMBDA. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_PHI,m_Abs_DELTA_PHI) == false) + ATH_MSG_WARNING("Can't find DELTA_PHI. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_THETA,m_Abs_DELTA_THETA) == false) + ATH_MSG_WARNING("Can't find DELTA_THETA. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_CENTER_LAMBDA,m_CENTER_LAMBDA_helped) == false) + ATH_MSG_WARNING("Can't find CENTER_LAMBDA. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_LATERAL,m_LATERAL) == false) + ATH_MSG_WARNING("Can't find LATERAL. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_LONGITUDINAL,m_LONGITUDINAL) == false) + ATH_MSG_WARNING("Can't find LONGITUDINAL. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_EM,m_ENG_FRAC_EM) == false) + ATH_MSG_WARNING("Can't find ENG_FRAC_EM. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_MAX,m_ENG_FRAC_MAX) == false) + ATH_MSG_WARNING("Can't find ENG_FRAC_MAX. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_CORE,m_ENG_FRAC_CORE) == false) + ATH_MSG_WARNING("Can't find ENG_FRAC_CORE. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_ENG_DENS,m_log_SECOND_ENG_DENS) == false) + ATH_MSG_WARNING("Can't find SECOND_ENG_DENS. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_EM1CoreFrac,m_EcoreOverEEM1) == false) + ATH_MSG_WARNING("Can't find EM1CoreFrac. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_asymmetryInEM1WRTTrk,m_AsymmetryWRTTrack) == false) + ATH_MSG_WARNING("Can't find asymmetryInEM1WRTTrk. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NHitsInEM1,NHitsInEM1) == false) + ATH_MSG_WARNING("Can't find NHitsInEM1. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_PS,NPosCells_PS) == false) + ATH_MSG_WARNING("Can't find NPosECells_PS. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM1,NPosCells_EM1) == false) + ATH_MSG_WARNING("Can't find NPosECells_EM1. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM2,NPosCells_EM2) == false) + ATH_MSG_WARNING("Can't find NPosECells_EM2. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM1,m_firstEtaWRTCluster_EM1) == false) + ATH_MSG_WARNING("Can't find firstEtaWRTClusterPosition_EM1. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM2,m_firstEtaWRTCluster_EM2) == false) + ATH_MSG_WARNING("Can't find firstEtaWRTClusterPosition_EM2. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM1,m_secondEtaWRTCluster_EM1) == false) + ATH_MSG_WARNING("Can't find secondEtaWRTClusterPosition_EM1. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM2,m_secondEtaWRTCluster_EM2) == false) + ATH_MSG_WARNING("Can't find secondEtaWRTClusterPosition_EM2. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM1,m_energy_EM1) == false) + ATH_MSG_WARNING("Can't find energy_EM1. Set it to 0."); + if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM2,m_energy_EM2) == false) + ATH_MSG_WARNING("Can't find energy_EM2. Set it to 0."); + // Apply variable transformations + m_Abs_DELTA_PHI = fabs(m_Abs_DELTA_PHI); + m_Abs_DELTA_THETA = fabs(m_Abs_DELTA_THETA); + m_CENTER_LAMBDA_helped = fmin(m_CENTER_LAMBDA_helped, 1000.); + if(m_log_SECOND_ENG_DENS==0.) m_log_SECOND_ENG_DENS=-50.; + else m_log_SECOND_ENG_DENS = log(m_log_SECOND_ENG_DENS); + // Convert ints to floats so they can be read by the TMVA reader + m_NHitsInEM1 = (float) NHitsInEM1; + m_NPosCells_PS = (float) NPosCells_PS; + m_NPosCells_EM1 = (float) NPosCells_EM1; + m_NPosCells_EM2 = (float) NPosCells_EM2; + + // Calculate BDT score + float BDTScore = m_tmvaReader->EvaluateMVA( "BDT method" ); + + return BDTScore; +} + +StatusCode TauPi0BonnScoreCalculator::bookMethod(TMVA::Reader *reader, const std::string &methodName) const +{ + if (m_weightfile == ""){ + ATH_MSG_ERROR("No weight file given"); + return StatusCode::FAILURE; + } + std::string resolvedFileName = PathResolver::find_file(m_weightfile, "DATAPATH"); + if (resolvedFileName != "") { + ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName ); + } + else { + ATH_MSG_ERROR( "Parameterisation file " << m_weightfile << " not found" ); + return StatusCode::FAILURE; + } + reader->BookMVA( methodName, resolvedFileName); + return StatusCode::SUCCESS; +} + diff --git a/Reconstruction/tauRec/src/TauPi0BonnSelector.cxx b/Reconstruction/tauRec/src/TauPi0BonnSelector.cxx new file mode 100644 index 00000000000..8202b9a183b --- /dev/null +++ b/Reconstruction/tauRec/src/TauPi0BonnSelector.cxx @@ -0,0 +1,148 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauPi0BonnSelector.cxx +// package: Reconstruction/tauRec +// authors: Benedict Winter, Will Davey +// date: 2012-10-09 +// +//----------------------------------------------------------------------------- + +#include <vector> + +#include "tauRec/TauPi0BonnSelector.h" +#include "FourMomUtils/P4Helpers.h" + +#include "CaloUtils/CaloVertexedCluster.h" + + +using std::vector; +using std::string; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauPi0BonnSelector::TauPi0BonnSelector( + const string& type, + const string& name, + const IInterface *parent) + + : TauToolBase(type, name, parent) +{ + declareInterface<TauToolBase > (this); + + declareProperty("ClusterEtCut", m_clusterEtCut); + declareProperty("ClusterBDTCut_1prong", m_clusterBDTCut_1prong); + declareProperty("ClusterBDTCut_mprong", m_clusterBDTCut_mprong); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauPi0BonnSelector::~TauPi0BonnSelector() +{ +} + +StatusCode TauPi0BonnSelector::initialize() +{ + return StatusCode::SUCCESS; +} + +StatusCode TauPi0BonnSelector::execute(TauCandidateData *data) +{ + xAOD::TauJet *tauJet = data->xAODTau; + //--------------------------------------------------------------------- + // only run on 1-5 prong taus + //--------------------------------------------------------------------- + if (tauJet->nTracks() == 0 || tauJet->nTracks() >5 ) { + return StatusCode::SUCCESS; + } + + + //--------------------------------------------------------------------- + // retrieve neutral PFOs from tau. Apply selection and create links to + // Pi0NeutralPFOs + //--------------------------------------------------------------------- + unsigned nNeutPFO = tauJet->nCellBased_Neutral_PFOs(); + for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++) { + const xAOD::PFO* curNeutPFO_const = tauJet->cellBased_Neutral_PFO( iNeutPFO ); + + // Get eta bin + int etaBin = getPi0Cluster_etaBin( curNeutPFO_const->p4().Eta() ); + + // Preselection + if(curNeutPFO_const->p4().Et() < m_clusterEtCut.at(etaBin)) continue; + if(tauJet->p4().DeltaR(curNeutPFO_const->p4()) > 0.2) continue; // FIXME replace by shrinking cone + + // BDT Selection + float BDTScore = curNeutPFO_const->bdtPi0Score(); + if( (tauJet->nTracks()==1 && BDTScore < m_clusterBDTCut_1prong.at(etaBin)) || (tauJet->nTracks()>1 && BDTScore < m_clusterBDTCut_mprong.at(etaBin)) ) continue; + + // Set number of pi0s + int nHitsInEM1 = 0; + if(!curNeutPFO_const->attribute(xAOD::PFODetails::cellBased_NHitsInEM1, nHitsInEM1)) ATH_MSG_WARNING("Couldn't retrieve nHitsInEM1. Will set it to 0."); + xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const); + if(nHitsInEM1<3){ + curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0, 1); + curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, 1); + } + else{ + curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0, 2); + curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, 2); + } + + // Set element link to Pi0tagged PFO + ElementLink<xAOD::PFOContainer> pfoLink = tauJet->cellBased_Neutral_PFOLinks().at(iNeutPFO); + tauJet->addCellBased_Pi0_PFOLink(pfoLink); + } + // Calculate visTau hlv and store it in pPi0Details. + TLorentzVector p4 = getP4(tauJet); + tauJet->setP4(xAOD::TauJetParameters::PanTauCellBasedProto, p4.Pt(),p4.Eta(),p4.Phi(),p4.M()); + // tauJet->setPtPanTauCellBasedProto( p4.Pt()); + // tauJet->setEtaPanTauCellBasedProto(p4.Eta()); + // tauJet->setPhiPanTauCellBasedProto(p4.Phi()); + // tauJet->setEPanTauCellBasedProto( p4.E()); + // tauJet->setMPanTauCellBasedProto( p4.M()); + + return StatusCode::SUCCESS; +} + +int TauPi0BonnSelector::getPi0Cluster_etaBin(double Pi0Cluster_eta){ + int Pi0Cluster_etaBin = -1; + double Pi0Cluster_noCorr_ABSeta = fabs(Pi0Cluster_eta); + + if( Pi0Cluster_noCorr_ABSeta < 0.80 ) Pi0Cluster_etaBin = 0; + else if( Pi0Cluster_noCorr_ABSeta < 1.40 ) Pi0Cluster_etaBin = 1; + else if( Pi0Cluster_noCorr_ABSeta < 1.50 ) Pi0Cluster_etaBin = 2; + else if( Pi0Cluster_noCorr_ABSeta < 1.90 ) Pi0Cluster_etaBin = 3; + else Pi0Cluster_etaBin = 4; + return Pi0Cluster_etaBin; +} + +TLorentzVector TauPi0BonnSelector::getP4(xAOD::TauJet* tauJet) +{ + // Get 4mom of first charged PFO, which is available for all taus that are treated in this algorithm + const xAOD::PFO* firstChargedPFO = tauJet->cellBased_Charged_PFO( 0 ); + TLorentzVector p4 = firstChargedPFO->p4(); + // Add other PFO momenta + unsigned nChargedPFO = tauJet->nCellBased_Charged_PFOs(); + for(unsigned int iChargedPFO=1; iChargedPFO<nChargedPFO; iChargedPFO++){ + const xAOD::PFO* curChargedPFO = tauJet->cellBased_Charged_PFO( iChargedPFO ); + p4+=curChargedPFO->p4(); + } + unsigned nPi0NeutPFO = tauJet->nCellBased_Pi0_PFOs(); + for(unsigned int iPi0NeutPFO=0; iPi0NeutPFO<nPi0NeutPFO; iPi0NeutPFO++){ + const xAOD::PFO* curPi0NeutPFO = tauJet->cellBased_Pi0_PFO( iPi0NeutPFO ); + if (tauJet->vertexLink()) + p4+= xAOD::CaloVertexedCluster(*curPi0NeutPFO->cluster(0) , (*tauJet->vertexLink())->position()).p4(); + else + p4+= xAOD::CaloVertexedCluster(*curPi0NeutPFO->cluster(0)).p4(); + + } + return p4; +} + diff --git a/Reconstruction/tauRec/src/TauProcessor.cxx b/Reconstruction/tauRec/src/TauProcessor.cxx new file mode 100644 index 00000000000..1d47aa9c2b0 --- /dev/null +++ b/Reconstruction/tauRec/src/TauProcessor.cxx @@ -0,0 +1,231 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "GaudiKernel/ListItem.h" + +#include "xAODTau/TauJetContainer.h" + +#include "tauRec/TauProcessor.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +TauProcessor::TauProcessor(const std::string &name, + ISvcLocator * pSvcLocator) : +AthAlgorithm(name, pSvcLocator), +m_tauContainerName("TauRecContainer"), +m_tauAuxContainerName("TauRecContainerAux."), +m_AODmode(false), +m_tools(this) //make tools private +{ + declareProperty("TauContainer", m_tauContainerName); + declareProperty("TauAuxContainer", m_tauAuxContainerName); + declareProperty("Tools", m_tools, "List of TauToolBase tools"); + declareProperty("runOnAOD", m_AODmode); //AODS are input file + +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +TauProcessor::~TauProcessor() { +} + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- +StatusCode TauProcessor::initialize() { + + + //ATH_MSG_INFO("FF::TauProcessor :: initialize()"); + + //------------------------------------------------------------------------- + // No tools allocated! + //------------------------------------------------------------------------- + if (m_tools.size() == 0) { + ATH_MSG_ERROR("no tools given!"); + return StatusCode::FAILURE; + } + + StatusCode sc; + + //------------------------------------------------------------------------- + // Allocate tools + //------------------------------------------------------------------------- + ToolHandleArray<TauToolBase> ::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase> ::iterator itTE = m_tools.end(); + ATH_MSG_INFO("List of tools in execution sequence:"); + ATH_MSG_INFO("------------------------------------"); + + unsigned int tool_count = 0; + + for (; itT != itTE; ++itT) { + sc = itT->retrieve(); + if (sc.isFailure()) { + ATH_MSG_WARNING("Cannot find tool named <" << *itT << ">"); + } else { + ++tool_count; + ATH_MSG_INFO((*itT)->type() << " - " << (*itT)->name()); + } + } + ATH_MSG_INFO(" "); + ATH_MSG_INFO("------------------------------------"); + + if (tool_count == 0) { + ATH_MSG_ERROR("could not allocate any tool!"); + return StatusCode::FAILURE; + } + + /////////////////////////////////////////////////////////////////////////// + + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauProcessor::finalize() { + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauProcessor::execute() { + + StatusCode sc; + + TauCandidateData rTauData; + + const xAOD::TauJetContainer* pContainer = 0; + const xAOD::TauJetAuxContainer* pAuxContainer = 0; + + //------------------------------------------------------------------------- + // retrieve Tau Containers from StoreGate + //------------------------------------------------------------------------- + sc = evtStore()->retrieve(pContainer, m_tauContainerName); + if (sc.isFailure()) { + if (m_AODmode) { + // don't exit Athena if there is no Tau Container in (D)AODs when running in AOD mode + // just exit TauProcessor + // reason: somebody might use slimmed (D)AODs, where not needed containers are not present + ATH_MSG_WARNING("Failed to retrieve " << m_tauContainerName << "! Will exit TauProcessor now!!"); + return StatusCode::SUCCESS; + } + else { + ATH_MSG_FATAL("Failed to retrieve " << m_tauContainerName); + return StatusCode::FAILURE; + } + } + rTauData.xAODTauContainer = const_cast<xAOD::TauJetContainer*>(pContainer); + + sc = evtStore()->retrieve(pAuxContainer, m_tauAuxContainerName); + if (sc.isFailure()) { + if (m_AODmode) { + // don't exit Athena if there is no Tau AuxContainer in (D)AODs when running in AOD mode + // just exit TauProcessor + // reason: somebody might use slimmed (D)AODs, where not needed containers are not present + ATH_MSG_WARNING("Failed to retrieve " << m_tauAuxContainerName << "! Will exit TauProcessor now!!"); + return StatusCode::SUCCESS; + } + else { + ATH_MSG_FATAL("Failed to retrieve " << m_tauAuxContainerName); + return StatusCode::FAILURE; + } + } + rTauData.tauAuxContainer = const_cast<xAOD::TauJetAuxContainer*>(pAuxContainer); + + // set TauCandidate properties + rTauData.xAODTau = 0; + /* + rTauData.tau = 0; + rTauData.details = 0; + rTauData.extraDetails = 0; + rTauData.pi0Details = 0; + */ + rTauData.seed = 0; + rTauData.seedContainer = 0; + + //------------------------------------------------------------------------- + // Initialize tools for this event + //------------------------------------------------------------------------- + ToolHandleArray<TauToolBase> ::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase> ::iterator itTE = m_tools.end(); + for (; itT != itTE; ++itT) { + sc = (*itT)->eventInitialize(&rTauData); + if (sc != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + + //////////////////////////////////////////////////////// + + //loop over taus + xAOD::TauJetContainer::const_iterator tau_it = pContainer->begin(); + xAOD::TauJetContainer::const_iterator tau_end = pContainer->end(); + + for(; tau_it != tau_end; ++tau_it) { + + //----------------------------------------------------------------- + // set tau candidate data for easy handling + //----------------------------------------------------------------- + rTauData.xAODTau = const_cast<xAOD::TauJet * >( *tau_it); + rTauData.seed = ( *rTauData.xAODTau->jetLink() ); + + //----------------------------------------------------------------- + // Process the candidate + //----------------------------------------------------------------- + ToolHandleArray<TauToolBase>::iterator itT = m_tools.begin(); + ToolHandleArray<TauToolBase>::iterator itTE = m_tools.end(); + + //----------------------------------------------------------------- + // Loop stops when Failure indicated by one of the tools + //----------------------------------------------------------------- + for (; itT != itTE; ++itT) { + ATH_MSG_VERBOSE("Invoking tool " << (*itT)->name()); + + sc = (*itT)->execute(&rTauData); + + if (sc.isFailure()) + break; + } + + if (sc.isSuccess()) { + + ATH_MSG_VERBOSE("The tau candidate has been modified"); + + } else if (!sc.isSuccess()) { + //TODO:cleanup of EndTools not necessary?? + //keep this here for future use (in case more than one seeding algo exist) + /* + ToolHandleArray<TauToolBase> ::iterator p_itT1 = m_tools.begin(); + for (; p_itT1 != p_itT; ++p_itT1) + (*p_itT1)->cleanup(&rTauData); + (*p_itT1)->cleanup(&rTauData); + */ + //delete rTauData.tau; + } else { + //delete rTauData.tau; + } + } + + + + //------------------------------------------------------------------------- + // Finalize tools for this event + //------------------------------------------------------------------------- + + itT = m_tools.begin(); + itTE = m_tools.end(); + for (; itT != itTE; ++itT) { + sc = (*itT)->eventFinalize(&rTauData); + if (sc != StatusCode::SUCCESS) + return StatusCode::FAILURE; + } + + + /////////////////////////////////////////////////////// + // locking of containers is moved to separate tau tool + + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauShotFinder.cxx b/Reconstruction/tauRec/src/TauShotFinder.cxx new file mode 100644 index 00000000000..0075f5b51d0 --- /dev/null +++ b/Reconstruction/tauRec/src/TauShotFinder.cxx @@ -0,0 +1,554 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauShotFinder.cxx +// package: Reconstruction/tauRec +// authors: Will Davey, Benedict Winter, Stephanie Yuen +// date: 2013-05-22 +// +//----------------------------------------------------------------------------- + +#include <boost/scoped_ptr.hpp> + +#include "GaudiKernel/IToolSvc.h" + +#include "CaloEvent/CaloCellContainer.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODCaloEvent/CaloClusterKineHelper.h" +#include "CaloIdentifier/CaloCell_ID.h" +#include "CaloIdentifier/LArNeighbours.h" +#include "CaloUtils/CaloClusterStoreHelper.h" +#include "CaloUtils/CaloCellList.h" +#include "CaloUtils/CaloCellESort.h" +#include "CaloInterface/IHadronicCalibrationTool.h" +#include "FourMomUtils/P4Helpers.h" +#include "tauRec/TauShotFinder.h" +#include "tauRec/TauShotVariableHelpers.h" +#include "TMVA/Reader.h" +#include "PathResolver/PathResolver.h" +#include "xAODPFlow/PFOContainer.h" +#include "xAODPFlow/PFOAuxContainer.h" +#include "xAODPFlow/PFO.h" + +using std::vector; +using std::string; + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- + +TauShotFinder::TauShotFinder( const string& type, + const string& name, + const IInterface *parent) + : TauToolBase(type, name, parent) + , m_caloWeightTool("H1WeightToolCSC12Generic") + , m_caloCellContainerName("AllCalo") + , m_shotClusterContainer(NULL) + , m_shotClusterContainerName("TauShotClusterContainer") + , m_shotPFOContainerName("TauShotPFOContainer") + , m_calo_dd_man(NULL) + , m_calo_id(NULL) +{ + declareInterface<TauToolBase > (this); + declareProperty("CaloWeightTool", m_caloWeightTool); + declareProperty("CaloCellContainerName", m_caloCellContainerName); + declareProperty("ShotClusterContainerName", m_shotClusterContainerName); + declareProperty("ShotPFOContainerName", m_shotPFOContainerName); + declareProperty("ReaderOption", m_readerOption); + declareProperty("BDTWeightFile_barrel", m_weightfile_barrel); + declareProperty("BDTWeightFile_endcap1", m_weightfile_endcap1); + declareProperty("BDTWeightFile_endcap2", m_weightfile_endcap2); + declareProperty("NCellsInEta", m_nCellsInEta); + declareProperty("MinPtCut", m_minPtCut); + declareProperty("AutoDoubleShotCut", m_autoDoubleShotCut); + declareProperty("MergedBDTScoreCut", m_mergedBDTScoreCut); +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- + +TauShotFinder::~TauShotFinder() { +} + +StatusCode TauShotFinder::initialize() { + + // retrieve tools + ATH_MSG_DEBUG( "Retrieving tools" ); + CHECK( m_caloWeightTool.retrieve() ); + + // initialize calo cell geo + m_calo_dd_man = CaloDetDescrManager::instance(); + m_calo_id = m_calo_dd_man->getCaloCell_ID(); + + //--------------------------------------------------------------------- + // Create TMVA readers + //--------------------------------------------------------------------- + m_tmvaReader_barrel = new TMVA::Reader(TString(m_readerOption)); + if (msgLvl(MSG::DEBUG)) m_tmvaReader_barrel->SetVerbose(true); + m_tmvaReader_barrel->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC); + m_tmvaReader_barrel->AddVariable("shot_stdpt_5" ,&G_STDPT_5 ); + m_tmvaReader_barrel->AddVariable("shot_stdeta_5" ,&G_STDETA_5 ); + m_tmvaReader_barrel->AddVariable("shot_deltapt_min" ,&G_DELTAPT_MIN ); + + m_tmvaReader_endcap1 = new TMVA::Reader(TString(m_readerOption)); + if (msgLvl(MSG::DEBUG)) m_tmvaReader_endcap1->SetVerbose(true); + m_tmvaReader_endcap1->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC); + m_tmvaReader_endcap1->AddVariable("shot_stdpt_5" ,&G_STDPT_5 ); + m_tmvaReader_endcap1->AddVariable("shot_stdeta_5" ,&G_STDETA_5 ); + m_tmvaReader_endcap1->AddVariable("shot_deltapt_min" ,&G_DELTAPT_MIN ); + + m_tmvaReader_endcap2 = new TMVA::Reader(TString(m_readerOption)); + if (msgLvl(MSG::DEBUG)) m_tmvaReader_endcap2->SetVerbose(true); + m_tmvaReader_endcap2->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC); + m_tmvaReader_endcap2->AddVariable("shot_stdpt_5" ,&G_STDPT_5 ); + m_tmvaReader_endcap2->AddVariable("shot_stdeta_5" ,&G_STDETA_5 ); + m_tmvaReader_endcap2->AddVariable("shot_deltapt_min" ,&G_DELTAPT_MIN ); + + if (bookMethod(m_tmvaReader_barrel, m_tmvaReader_endcap1, m_tmvaReader_endcap2, "BDT method").isFailure()) return StatusCode::FAILURE; + + // setupCuts(); + + return StatusCode::SUCCESS; +} + +StatusCode TauShotFinder::finalize() +{ + StatusCode sc = AlgTool::finalize(); + delete m_tmvaReader_barrel; + delete m_tmvaReader_endcap1; + delete m_tmvaReader_endcap2; + return sc; +} + +StatusCode TauShotFinder::eventInitialize(TauCandidateData * /*data*/) { + + //--------------------------------------------------------------------- + // Create Shot ClusterContainer and register in StoreGate + //--------------------------------------------------------------------- + m_shotClusterContainer = CaloClusterStoreHelper::makeContainer(&*evtStore(), + m_shotClusterContainerName, + msg() + ); + + //--------------------------------------------------------------------- + // Create Shot PFO container + //--------------------------------------------------------------------- + m_PFOShotContainer = new xAOD::PFOContainer(); + CHECK( evtStore()->record(m_PFOShotContainer, m_shotPFOContainerName ) ); + m_PFOShotAuxStore = new xAOD::PFOAuxContainer(); + CHECK( evtStore()->record( m_PFOShotAuxStore, m_shotPFOContainerName + "Aux." ) ); + m_PFOShotContainer->setStore(m_PFOShotAuxStore); + + return StatusCode::SUCCESS; +} + +StatusCode TauShotFinder::execute(TauCandidateData *data) { + + xAOD::TauJet *pTau = data->xAODTau; + + //--------------------------------------------------------------------- + // only run shower subtraction on 1-5 prong taus + //--------------------------------------------------------------------- + if (pTau->nTracks() == 0 || pTau->nTracks() >5 ) { + return StatusCode::SUCCESS; + } + ATH_MSG_DEBUG(""); + ATH_MSG_DEBUG("New tau"); + + //--------------------------------------------------------------------- + // retrieve cells around tau + //--------------------------------------------------------------------- + // get all calo cell container + const CaloCellContainer *pCellContainer = NULL; + CHECK( evtStore()->retrieve(pCellContainer, m_caloCellContainerName) ); + + // get only EM cells within dR<0.2 + // TODO: might be possible to select only EM1 cells, but probbaly wont + // speed things up much anyway + vector<CaloCell_ID::SUBCALO> emSubCaloBlocks; + emSubCaloBlocks.push_back(CaloCell_ID::LAREM); + boost::scoped_ptr<CaloCellList> pCells(new CaloCellList(pCellContainer,emSubCaloBlocks)); + + // TODO: change hardcoded 0.2 to tau cone variable, (or func. from TauJet?) + pCells->select(pTau->eta(), pTau->phi(), 0.4); + + // Dump cells into a std::vector since CaloCellList wont allow sorting + // (maybe this can be done faster at some point). + // Also apply very basic preselection + std::vector<const CaloCell*> cells; + CaloCellList::list_iterator cellItr = pCells->begin(); + for(; cellItr!=pCells->end();++cellItr){ + // require cells above 100 MeV + if( (*cellItr)->pt()*m_caloWeightTool->wtCell(*cellItr) < 100. ) continue; + // require cells in EM1 + int samp = (*cellItr)->caloDDE()->getSampling(); + if( !( samp == CaloCell_ID::EMB1 || samp == CaloCell_ID::EME1 ) ) continue; + cells.push_back(*cellItr); + } + // sort cells in descending pt + std::sort(cells.begin(),cells.end(),ptSort(*this)); + + //--------------------------------------------------------------------- + // shot seeding + //--------------------------------------------------------------------- + // get seed cells + std::vector<const CaloCell*> seedCells; + std::set<IdentifierHash> seedCellHashes; + cellItr = cells.begin(); + for(; cellItr != cells.end(); ++cellItr) { + const CaloCell* cell = (*cellItr); + const IdentifierHash cellHash = cell->caloDDE()->calo_hash(); + + // apply seed selection on nearest neighbours + std::vector<IdentifierHash> nextEta, prevEta; + m_calo_id->get_neighbours(cellHash,LArNeighbours::nextInEta,nextEta); + m_calo_id->get_neighbours(cellHash,LArNeighbours::prevInEta,prevEta); + std::vector<IdentifierHash> neighbours = nextEta; + neighbours.insert(neighbours.end(),prevEta.begin(),prevEta.end()); + bool status = true; + std::vector<IdentifierHash>::iterator hashItr = neighbours.begin(); + for(;hashItr!=neighbours.end();++hashItr){ + // must not be next to seed cell (TODO: maybe this requirement can be removed) + if( seedCellHashes.find(*hashItr) != seedCellHashes.end() ){ + status = false; + break; + } + // must be maximum + const CaloCell* neigCell = pCellContainer->findCell(*hashItr); + if( !neigCell ) continue; + if( neigCell->pt()*m_caloWeightTool->wtCell(neigCell) >= cell->pt()*m_caloWeightTool->wtCell(cell) ){ + status = false; + break; + } + } + if( !status ) continue; + seedCells.push_back(cell); + seedCellHashes.insert(cellHash); + } // preselected cells + ATH_MSG_DEBUG("seedCells.size() = " << seedCells.size()); + + // merge across phi and construct shots + while( seedCells.size() ){ + + const CaloCell* cell = seedCells.front(); + const IdentifierHash seedHash = cell->caloDDE()->calo_hash(); + + // look for match across phi in current seeds + const CaloCell* nextPhi = NULL; + const CaloCell* prevPhi = NULL; + for( cellItr = seedCells.begin(); cellItr!=seedCells.end(); ++cellItr){ + if( (*cellItr) == cell ) continue; + IdentifierHash shotCellHash = (*cellItr)->caloDDE()->calo_hash(); + if( this->isPhiNeighbour(seedHash,shotCellHash,true) ) nextPhi = (*cellItr); + else if( this->isPhiNeighbour(seedHash,shotCellHash,false) ) prevPhi = (*cellItr); + } + + const CaloCell* mergePhi = NULL; + if( nextPhi && prevPhi ){ + // take higest-pt if merged up and down + if( nextPhi->pt()*m_caloWeightTool->wtCell(nextPhi) > prevPhi->pt()*m_caloWeightTool->wtCell(prevPhi) ) mergePhi = nextPhi; + else mergePhi = prevPhi; + } + else if (nextPhi) mergePhi = nextPhi; + else if (prevPhi) mergePhi = prevPhi; + + // get neighbours in 5x1 window + std::vector<const CaloCell*> windowNeighbours = this->getNeighbours(pCellContainer,cell,2); + if( mergePhi ){ + std::vector<const CaloCell*> mergeCells = this->getNeighbours(pCellContainer,mergePhi,2); + windowNeighbours.push_back(mergePhi); + windowNeighbours.insert(windowNeighbours.end(),mergeCells.begin(),mergeCells.end()); + } + + + // create seed cluster + xAOD::CaloCluster* shotCluster = CaloClusterStoreHelper::makeCluster(pCellContainer); + shotCluster->getCellLinks()->reserve(windowNeighbours.size()+1); + shotCluster->addCell(pCellContainer->findIndex(seedHash), 1.); + cellItr = windowNeighbours.begin(); + for( ; cellItr!=windowNeighbours.end(); ++cellItr) + shotCluster->addCell(pCellContainer->findIndex((*cellItr)->caloDDE()->calo_hash()),1.0); + CaloClusterKineHelper::calculateKine(shotCluster,true,true); + m_shotClusterContainer->push_back(shotCluster); + + // create shot PFO and store it in output container + xAOD::PFO* shot = new xAOD::PFO(); + m_PFOShotContainer->push_back( shot ); + + // Create element link from tau to shot + ElementLink<xAOD::PFOContainer> PFOElementLink; + PFOElementLink.toContainedElement( *m_PFOShotContainer, shot ); + pTau->addShot_PFOLink( PFOElementLink ); + + if( mergePhi ){ + // interpolate position + double dPhi = TVector2::Phi_mpi_pi( mergePhi->phi() - cell->phi()); + double ratio = mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi)/(cell->pt()*m_caloWeightTool->wtCell(cell) + mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi)); + float phi = cell->phi()+dPhi*ratio; + float pt = cell->pt()*m_caloWeightTool->wtCell(cell)+mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi); + + shot->setP4( (float) pt, (float) cell->eta(), (float) phi, (float) cell->m()); + } + else shot->setP4( (float) cell->pt()*m_caloWeightTool->wtCell(cell), (float) cell->eta(), (float) cell->phi(), (float) cell->m()); + + shot->setBDTPi0Score( (float) -9999. ); + shot->setCharge( 0. ); + double center_mag = 0.0; + // No need to calculate cluster moments atm. + //if( !shotCluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 404, center_mag) ) ATH_MSG_WARNING("Couldn't retrieve CENTER_MAG moment. Set it to 0."); + shot->setCenterMag( (float) center_mag); + + ElementLink<xAOD::CaloClusterContainer> clusElementLink; + clusElementLink.toContainedElement( *m_shotClusterContainer, shotCluster ); + shot->setClusterLink( clusElementLink ); + shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_nCellsInEta, m_nCellsInEta); + shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash); + + // Get cell block for variable calculations + std::vector<std::vector<const CaloCell*> > cellBlock = TauShotVariableHelpers::getCellBlock(shot, m_calo_id); + + // Some DEBUG statements + if (msgLvl(MSG::DEBUG)) { + if(cell->pt()*m_caloWeightTool->wtCell(cell)>300){ + ATH_MSG_DEBUG(""); + ATH_MSG_DEBUG("New shot. \t block size phi = " << cellBlock.size() << " \t block size eta = " << cellBlock.at(0).size() << "\t shot->pt() = " << shot->pt()); + for(unsigned iCellPhi = 0; iCellPhi<cellBlock.size();++iCellPhi){ + for(unsigned iCellEta = 0; iCellEta<cellBlock.at(iCellPhi).size();++iCellEta){ + const CaloCell* cell = cellBlock.at(iCellPhi).at(iCellEta); + if( cell==NULL ) ATH_MSG_DEBUG("Cell" << iCellPhi << iCellEta << ": \t NULL" ); + else ATH_MSG_DEBUG("Cell"<<iCellPhi<<iCellEta<<":\tPt = "<< cell->pt()*m_caloWeightTool->wtCell(cell)<<"\teta = "<<cell->eta()<<"\tphi = "<<cell->phi()); + } + } + } + } + + // set variables used for photon counting + m_pt1=TauShotVariableHelpers::ptWindow(cellBlock,1,m_caloWeightTool); + m_pt3=TauShotVariableHelpers::ptWindow(cellBlock,3,m_caloWeightTool); + m_pt5=TauShotVariableHelpers::ptWindow(cellBlock,5,m_caloWeightTool); + m_ws5=TauShotVariableHelpers::ws5(cellBlock,m_caloWeightTool); + m_sdevEta5_WRTmean=TauShotVariableHelpers::sdevEta_WRTmean(cellBlock,m_caloWeightTool); + m_sdevEta5_WRTmode=TauShotVariableHelpers::sdevEta_WRTmode(cellBlock,m_caloWeightTool); + m_sdevPt5=TauShotVariableHelpers::sdevPt(cellBlock,m_caloWeightTool); + m_deltaPt12_min=TauShotVariableHelpers::deltaPt12_min(cellBlock,m_caloWeightTool); + m_Fside_3not1=TauShotVariableHelpers::Fside(cellBlock,3,1,m_caloWeightTool); + m_Fside_5not1=TauShotVariableHelpers::Fside(cellBlock,5,1,m_caloWeightTool); + m_Fside_5not3=TauShotVariableHelpers::Fside(cellBlock,5,3,m_caloWeightTool); + m_fracSide_3not1=TauShotVariableHelpers::fracSide(cellBlock,3,1,m_caloWeightTool); + m_fracSide_5not1=TauShotVariableHelpers::fracSide(cellBlock,5,1,m_caloWeightTool); + m_fracSide_5not3=TauShotVariableHelpers::fracSide(cellBlock,5,3,m_caloWeightTool); + m_pt1OverPt3=TauShotVariableHelpers::ptWindowFrac(cellBlock,3,1,m_caloWeightTool); + m_pt3OverPt5=TauShotVariableHelpers::ptWindowFrac(cellBlock,5,3,m_caloWeightTool); + + // Same variable names as in Stephanie's private code + G_PTFRAC=m_fracSide_3not1; + G_STDPT_5=m_sdevPt5; + G_STDETA_5=fmin(m_sdevEta5_WRTmean,0.0036); + G_DELTAPT_MIN=fmax(-1000.,fmin(m_deltaPt12_min,2000)); + + // Calculate BDT scores + int etaBin = getEtaBin(cell->eta()); + float mergedBDTScore=getMergedBDTScore(etaBin); + + //////////////////////////////////////////////////////////////////////////////////////////// + // Calculate number of photons in shot + //////////////////////////////////////////////////////////////////////////////////////////// + int nPhotons = getNPhotons(etaBin, mergedBDTScore, m_pt1); + + //////////////////////////////////////////////////////////////////////////////////////////// + // Set variables in shot PFO + //////////////////////////////////////////////////////////////////////////////////////////// + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt1, m_pt1); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt3, m_pt3); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt5, m_pt5); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_ws5, m_ws5); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevEta5_WRTmean, m_sdevEta5_WRTmean); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevEta5_WRTmode, m_sdevEta5_WRTmode); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevPt5, m_sdevPt5); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_deltaPt12_min, m_deltaPt12_min); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_3not1, m_Fside_3not1); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_5not1, m_Fside_5not1); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_5not3, m_Fside_5not3); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_3not1, m_fracSide_3not1); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_5not1, m_fracSide_5not1); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_5not3, m_fracSide_5not3); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt1OverPt3, m_pt1OverPt3); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt3OverPt5, m_pt3OverPt5); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_mergedScore, mergedBDTScore); + shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_signalScore, -1.); + shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_nPhotons, nPhotons); + + // remove shot(s) from list + vector<const CaloCell*>::iterator cellItrNonConst; + cellItrNonConst = std::find(seedCells.begin(),seedCells.end(),cell); + seedCells.erase(cellItrNonConst); + if( mergePhi ){ + cellItrNonConst = std::find(seedCells.begin(),seedCells.end(),mergePhi); + seedCells.erase(cellItrNonConst); + } + + /* + ATH_MSG_DEBUG("Storing shot. pt: " << shot->pt() + << ", eta: " << shot->eta() + << ", phi: " << shot->phi() + ); + */ + + } // seed cells + + + return StatusCode::SUCCESS; +} + +void TauShotFinder::cleanup(TauCandidateData* /* data */) { + return; +} + +StatusCode TauShotFinder::eventFinalize(TauCandidateData* /* data */) { + CHECK( CaloClusterStoreHelper::finalizeClusters(&*evtStore(), + m_shotClusterContainer, + m_shotClusterContainerName, + msg()) ); + + return StatusCode::SUCCESS; +} + +std::vector<const CaloCell*> TauShotFinder::getNeighbours(const CaloCellContainer* pCellContainer, + const CaloCell* cell, + int maxDepth) +{ + std::vector<const CaloCell*> cells; + this->addNeighbours(pCellContainer,cell,cells,0,maxDepth,true); //next + this->addNeighbours(pCellContainer,cell,cells,0,maxDepth,false); //prev + return cells; +} + +void TauShotFinder::addNeighbours(const CaloCellContainer* pCellContainer, + const CaloCell* cell, + std::vector<const CaloCell*>& cells, + int depth, + int maxDepth, + bool next) +{ + depth++; + if( depth > maxDepth ) return; + + const IdentifierHash cellHash = cell->caloDDE()->calo_hash(); + std::vector<IdentifierHash> neigHashes; + if( next ) + m_calo_id->get_neighbours(cellHash,LArNeighbours::nextInEta,neigHashes); + else + m_calo_id->get_neighbours(cellHash,LArNeighbours::prevInEta,neigHashes); + + std::vector<IdentifierHash>::iterator hashItr = neigHashes.begin(); + for( ; hashItr!=neigHashes.end(); ++hashItr ){ + const CaloCell* newCell = pCellContainer->findCell(*hashItr); + if(!newCell)continue; + cells.push_back(newCell); + this->addNeighbours(pCellContainer,newCell,cells,depth,maxDepth,next); + // no EM1 cell should have more than one neighbor. Just add this neigbor for now + // FIXME: Check whether it happens that a cell has > 1 neighbors + break; + } +} + +bool TauShotFinder::isPhiNeighbour(IdentifierHash cell1Hash, IdentifierHash cell2Hash, bool next){ + std::vector<IdentifierHash> neigHashes; + if( next ) m_calo_id->get_neighbours(cell1Hash,LArNeighbours::nextInPhi,neigHashes); + else m_calo_id->get_neighbours(cell1Hash,LArNeighbours::prevInPhi,neigHashes); + std::vector<IdentifierHash>::iterator itr = neigHashes.begin(); + for( ; itr!=neigHashes.end(); ++itr ){ + if(cell2Hash == (*itr)) return true; + } + return false; +} + +float TauShotFinder::getEtaBin(float seedEta){ + float absSeedEta=fabs(seedEta); + if(fabs(absSeedEta)<0.80) return 0; // Central Barrel + else if(fabs(absSeedEta)<1.39) return 1; // Outer Barrel + else if(fabs(absSeedEta)<1.51) return 2; // crack + else if(fabs(absSeedEta)<1.80) return 3; // endcap, fine granularity + else return 4; // endcap, coarse granularity +} + +float TauShotFinder::getMergedBDTScore(int etaBin){ + float BDTScore = -1; + if(etaBin==0) BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" ); // barrel1 + else if(etaBin==1) BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" ); // barrel2 + else if(etaBin==2) BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" ); // just use barrel BDT for now to check how it looks in data + else if(etaBin==3) BDTScore = m_tmvaReader_endcap1->EvaluateMVA( "BDT method" ); // endcap1 + else if(etaBin==4) BDTScore = m_tmvaReader_endcap2->EvaluateMVA( "BDT method" ); // endcap2 + return BDTScore; +} + +float TauShotFinder::getNPhotons(int etaBin, float mergedBDTScore, float seedEnergy){ + if(etaBin==2) return 0; // no photon counting in crack atm + ATH_MSG_DEBUG("etaBin = " << etaBin << ", seedEnergy = " << seedEnergy << ", m_minPtCut.at(etaBin) = " << m_minPtCut.at(etaBin) << "m_autoDoubleShotCut.at(etaBin) = " + << m_autoDoubleShotCut.at(etaBin) << ", mergedBDTScore = " << mergedBDTScore << ", m_mergedBDTScoreCut.at(etaBin) = " << m_mergedBDTScoreCut.at(etaBin) ); + if( seedEnergy < m_minPtCut.at(etaBin) ) return 0; + if( seedEnergy > m_autoDoubleShotCut.at(etaBin) ) return 2; + if( mergedBDTScore < m_mergedBDTScoreCut.at(etaBin) ) return 2; + return 1; +} + +// some really slick c++ way of doing sort (since we need to use the member m_caloWeightTool) +// how about learing a thing or two from python... +TauShotFinder::ptSort::ptSort( const TauShotFinder& info ) : m_info(info) { } +bool TauShotFinder::ptSort::operator()( const CaloCell* c1, const CaloCell* c2 ){ + return c1->pt()*m_info.m_caloWeightTool->wtCell(c1) > c2->pt()*m_info.m_caloWeightTool->wtCell(c2); +} + +StatusCode TauShotFinder::bookMethod(TMVA::Reader *reader_barrel, + TMVA::Reader *reader_endcap1, + TMVA::Reader *reader_endcap2, + const std::string &methodName) const +{ + if (m_weightfile_barrel == ""){ + ATH_MSG_ERROR("No weight m_weightfile_barrel given"); + return StatusCode::FAILURE; + } + if (m_weightfile_endcap1 == ""){ + ATH_MSG_ERROR("No weight m_weightfile_endcap1 given"); + return StatusCode::FAILURE; + } + if (m_weightfile_endcap2 == ""){ + ATH_MSG_ERROR("No weight m_weightfile_endcap2 given"); + return StatusCode::FAILURE; + } + std::string resolvedFileName = PathResolver::find_file(m_weightfile_barrel, "DATAPATH"); + if (resolvedFileName != ""){ + ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName ); + } + else { + ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_barrel << " not found" ); + return StatusCode::FAILURE; + } + reader_barrel->BookMVA( methodName, resolvedFileName); + + resolvedFileName = PathResolver::find_file(m_weightfile_endcap1, "DATAPATH"); + if (resolvedFileName != ""){ + ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName ); + } + else { + ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_endcap1 << " not found" ); + return StatusCode::FAILURE; + } + reader_endcap1->BookMVA( methodName, resolvedFileName); + + resolvedFileName = PathResolver::find_file(m_weightfile_endcap2, "DATAPATH"); + if (resolvedFileName != ""){ + ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName ); + } + else { + ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_endcap2 << " not found" ); + return StatusCode::FAILURE; + } + reader_endcap2->BookMVA( methodName, resolvedFileName); + return StatusCode::SUCCESS; +} + +// EOF diff --git a/Reconstruction/tauRec/src/TauShotVariableHelpers.cxx b/Reconstruction/tauRec/src/TauShotVariableHelpers.cxx new file mode 100644 index 00000000000..203437ef846 --- /dev/null +++ b/Reconstruction/tauRec/src/TauShotVariableHelpers.cxx @@ -0,0 +1,357 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @brief implementation of photon shot variable calculation + * + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + * @author Stephanie Yuen <stephanie.yuen@cern.ch> + */ + +#include "tauRec/TauShotVariableHelpers.h" + +using xAOD::PFO; +using std::vector; + +namespace TauShotVariableHelpers { + std::vector<std::vector<const CaloCell*> > getCellBlock(xAOD::PFO* shot, const CaloCell_ID* calo_id){ + std::vector<std::vector<const CaloCell*> > cellVector; + std::vector<const CaloCell*> oneEtaLayer; + int nCellsInEta = 0; + if( shot->attribute(xAOD::PFODetails::PFOAttributes::tauShots_nCellsInEta, nCellsInEta) == false) { + std::cout << "WARNING: Couldn't find nCellsInEta. Return empty cell block." << std::endl; + return cellVector; + } + int seedHash = 0; + if( shot->attribute(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash) == false) { + std::cout << "WARNING: Couldn't find seed hash. Return empty cell block." << std::endl; + return cellVector; + } + for(int iCell=0;iCell<nCellsInEta;++iCell) oneEtaLayer.push_back(NULL); + // have two layers in phi + cellVector.push_back(oneEtaLayer); + cellVector.push_back(oneEtaLayer); + // get cluster from shot + const xAOD::CaloCluster* cluster = shot->cluster(0); + const CaloClusterCellLink* theCellLink = cluster->getCellLinks(); + CaloClusterCellLink::const_iterator cellItr = theCellLink->begin(); + CaloClusterCellLink::const_iterator cellItrE = theCellLink->end(); + + // get seed cell from shot cluster + const CaloCell* seedCell=NULL; + for(;cellItr!=cellItrE;++cellItr){ + if((*cellItr)->caloDDE()->calo_hash()!=(unsigned) seedHash) continue; + seedCell = *cellItr; + break; + } + if(seedCell==NULL){ + std::cout << "WARNING: Couldn't find seed cell in shot cluster. Return empty cell block." << std::endl; + } + + // get merged cell in phi. Keep NULL if shot is not merged across phi + const CaloCell* mergedCell = NULL; + std::vector<IdentifierHash> nextInPhi; + std::vector<IdentifierHash> prevInPhi; + calo_id->get_neighbours(seedCell->caloDDE()->calo_hash(),LArNeighbours::nextInPhi,nextInPhi); + calo_id->get_neighbours(seedCell->caloDDE()->calo_hash(),LArNeighbours::prevInPhi,prevInPhi); + for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){ + std::vector<IdentifierHash>::iterator itr = nextInPhi.begin(); + for( ; itr!=nextInPhi.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + mergedCell = (*cellItr); + break; + } + if(mergedCell!=NULL) break; + itr = prevInPhi.begin(); + for( ; itr!=prevInPhi.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + mergedCell = (*cellItr); + break; + } + if(mergedCell!=NULL) break; + } + // store cells in the eta layer, which contains the seed cell + int nCellsFromSeed = 1; + const CaloCell* lastCell = seedCell; + cellVector.at(0).at(nCellsInEta/2) = seedCell; // store seed cell + std::vector<IdentifierHash> next; + while(lastCell!=NULL && nCellsFromSeed<nCellsInEta/2+1){ + calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::nextInEta,next); + lastCell = NULL; + for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){ + std::vector<IdentifierHash>::iterator itr = next.begin(); + for( ; itr!=next.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + cellVector.at(0).at(nCellsInEta/2+nCellsFromSeed) = (*cellItr); + lastCell = (*cellItr); + } + } + nCellsFromSeed++; + } + nCellsFromSeed = 1; + lastCell = seedCell; + while(lastCell!=NULL && nCellsFromSeed<nCellsInEta/2+1){ + calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::prevInEta,next); + lastCell = NULL; + for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){ + std::vector<IdentifierHash>::iterator itr = next.begin(); + for( ; itr!=next.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + cellVector.at(0).at(nCellsInEta/2-nCellsFromSeed) = (*cellItr); + lastCell = (*cellItr); + } + } + nCellsFromSeed++; + } + // store cells in the eta layer, which contains the merged cell + int nCellsFromMerged = 1; + lastCell = mergedCell; // is NULL if shot is not merged + cellVector.at(1).at(nCellsInEta/2) = mergedCell; // store merged cell + while(lastCell!=NULL && nCellsFromMerged<nCellsInEta/2+1){ + calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::nextInEta,next); + lastCell = NULL; + for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){ + std::vector<IdentifierHash>::iterator itr = next.begin(); + for( ; itr!=next.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + cellVector.at(1).at(nCellsInEta/2+nCellsFromMerged) = (*cellItr); + lastCell = (*cellItr); + } + } + nCellsFromMerged++; + } + nCellsFromMerged = 1; + lastCell = mergedCell; + while(lastCell!=NULL && nCellsFromMerged<nCellsInEta/2+1){ + calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::prevInEta,next); + lastCell = NULL; + for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){ + std::vector<IdentifierHash>::iterator itr = next.begin(); + for( ; itr!=next.end(); ++itr ){ + if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue; + cellVector.at(1).at(nCellsInEta/2-nCellsFromMerged) = (*cellItr); + lastCell = (*cellItr); + } + } + nCellsFromMerged++; + } + return cellVector; + + } + + + float mean_eta(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + float sumEta=0.; + float sumWeight=0.; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + vector<const CaloCell*>::iterator itrEta = itrPhi->begin(); + for( ; itrEta!=itrPhi->end(); ++itrEta ){ + if((*itrEta) == NULL) continue; + sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta); + sumEta += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * (*itrEta)->eta(); + } + } + if(sumWeight<=0.) return -99999.; + return sumEta/sumWeight; + } + + float mean_pt(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + float sumPt=0.; + int nCells = 0; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + vector<const CaloCell*>::iterator itrEta = itrPhi->begin(); + for( ; itrEta!=itrPhi->end(); ++itrEta ){ + if((*itrEta) == NULL) continue; + sumPt += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta); + nCells ++; + } + } + if(nCells==0) return -99999.; + return sumPt/nCells; + } + + float ptWindow(vector<vector<const CaloCell*> > shotCells, int windowSize, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + // window size should be odd and noti be larger than eta window of shotCells + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + if( windowSize%2!=1 ) return 0.; + if( windowSize > nCells_eta) return 0.; + float ptWindow = 0.; + for(int iCell = 0; iCell != nCells_eta; ++iCell ){ + if(fabs(iCell-seedIndex)>windowSize/2) continue; + if(shotCells.at(0).at(iCell) != NULL) ptWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell) != NULL) ptWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + } + return ptWindow; + } + + float ws5(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + float sumWeight=0.; + float sumDev2=0.; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + for(unsigned iCell = 0; iCell != itrPhi->size(); ++iCell ){ + if(itrPhi->at(iCell) == NULL) continue; + sumWeight += itrPhi->at(iCell)->pt()*m_caloWeightTool->wtCell(itrPhi->at(iCell)); + sumDev2 += itrPhi->at(iCell)->pt()*m_caloWeightTool->wtCell(itrPhi->at(iCell)) * pow(iCell-seedIndex,2); + } + } + if(sumWeight<=0. || sumDev2 <0.) return -99999.; + return sqrt( sumDev2 / sumWeight ); + } + + float sdevEta_WRTmean(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + float mean = mean_eta(shotCells, m_caloWeightTool); + float sumWeight=0.; + float sumDev2=0.; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + vector<const CaloCell*>::iterator itrEta = itrPhi->begin(); + for( ; itrEta!=itrPhi->end(); ++itrEta ){ + if((*itrEta) == NULL) continue; + sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta); + sumDev2 += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * pow((*itrEta)->eta() - mean,2); + } + } + if(sumWeight<=0. || sumDev2 <0.) return -99999.; + return sqrt( sumDev2 / sumWeight ); + } + + float sdevEta_WRTmode(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + float mode = shotCells.at(0).at(seedIndex)->eta(); + float sumWeight=0.; + float sumDev2=0.; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + vector<const CaloCell*>::iterator itrEta = itrPhi->begin(); + for( ; itrEta!=itrPhi->end(); ++itrEta ){ + if((*itrEta) == NULL) continue; + sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta); + sumDev2 += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * pow((*itrEta)->eta() - mode,2); + } + } + if(sumWeight<=0. || sumDev2 <0.) return -99999.; + return sqrt( sumDev2 / sumWeight ); + } + + float sdevPt(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + float mean = mean_pt(shotCells, m_caloWeightTool); + float sumWeight=0.; + float sumDev2=0.; + vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin(); + for( ; itrPhi!=shotCells.end(); ++itrPhi ){ + vector<const CaloCell*>::iterator itrEta = itrPhi->begin(); + for( ; itrEta!=itrPhi->end(); ++itrEta ){ + if((*itrEta) == NULL) continue; + sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta); + sumDev2 += pow((*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) - mean,2); + } + } + if(sumWeight<=0. || sumDev2 <0.) return -99999.; + return sqrt(sumDev2)/sumWeight; + } + + float deltaPt12_min(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + bool haveLeft = false; + bool haveRight = false; + float deltaPt_left = 0.; + float deltaPt_right = 0.; + if(shotCells.at(0).at(seedIndex-1)!=NULL && shotCells.at(0).at(seedIndex-2)!=NULL){ + haveLeft = true; + deltaPt_left = shotCells.at(0).at(seedIndex-1)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex-1)) + -shotCells.at(0).at(seedIndex-2)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex-2)); + if(shotCells.at(1).at(seedIndex-1)!=NULL && shotCells.at(1).at(seedIndex-2)!=NULL){ + deltaPt_left += shotCells.at(1).at(seedIndex-1)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex-1)) + -shotCells.at(1).at(seedIndex-2)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex-2)); + } + } + if(shotCells.at(0).at(seedIndex+1)!=NULL && shotCells.at(0).at(seedIndex+2)!=NULL){ + haveRight = true; + deltaPt_right = shotCells.at(0).at(seedIndex+1)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex+1)) + -shotCells.at(0).at(seedIndex+2)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex+2)); + if(shotCells.at(1).at(seedIndex+1)!=NULL && shotCells.at(1).at(seedIndex+2)!=NULL){ + deltaPt_right += shotCells.at(1).at(seedIndex+1)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex+1)) + -shotCells.at(1).at(seedIndex+2)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex+1)); + } + } + if(haveLeft && haveRight) return fmin(deltaPt_left,deltaPt_right); + if(haveLeft) return deltaPt_left; + if(haveRight) return deltaPt_right; + else return -1.; + } + + + float Fside(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + // window sizes should be odd and windows should be not larger than eta window of shotCells + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.; + if( largerWindow <= smallerWindow) return 0.; + if( largerWindow > nCells_eta) return 0.; + float pt_largerWindow = 0.; + float pt_smallerWindow = 0.; + for(int iCell = 0; iCell != nCells_eta; ++iCell ){ + if(fabs(iCell-seedIndex)>largerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + if(fabs(iCell-seedIndex)>smallerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + } + if(pt_smallerWindow==0.) return -99999.; + return (pt_largerWindow-pt_smallerWindow)/pt_smallerWindow; + } + + float fracSide(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + // window sizes should be odd and windows should be not larger than eta window of shotCells + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.; + if( largerWindow <= smallerWindow) return 0.; + if( largerWindow > nCells_eta) return 0.; + float pt_largerWindow = 0.; + float pt_smallerWindow = 0.; + for(int iCell = 0; iCell != nCells_eta; ++iCell ){ + if(fabs(iCell-seedIndex)>largerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + if(fabs(iCell-seedIndex)>smallerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + } + if(pt_largerWindow==0.) return -99999.; + return (pt_largerWindow-pt_smallerWindow)/pt_largerWindow; + } + + float ptWindowFrac(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){ + // window sizes should be odd and windows should be not larger than eta window of shotCells + int nCells_eta = shotCells.at(0).size(); + int seedIndex = nCells_eta/2; + if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.; + if( largerWindow <= smallerWindow) return 0.; + if( largerWindow > nCells_eta) return 0.; + float pt_largerWindow = 0.; + float pt_smallerWindow = 0.; + for(int iCell = 0; iCell != nCells_eta; ++iCell ){ + if(fabs(iCell-seedIndex)>largerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + if(fabs(iCell-seedIndex)>smallerWindow/2) continue; + if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell)); + if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell)); + } + if(pt_largerWindow==0.) return -99999.; + return pt_smallerWindow/pt_largerWindow; + } +} + diff --git a/Reconstruction/tauRec/src/TauSubstructureVariables.cxx b/Reconstruction/tauRec/src/TauSubstructureVariables.cxx new file mode 100644 index 00000000000..30dd7035112 --- /dev/null +++ b/Reconstruction/tauRec/src/TauSubstructureVariables.cxx @@ -0,0 +1,352 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//********************************************************************// +// NAME: TauSubstructureVariables.cxx // +// PACKAGE: offline/Reconstruction/tauRec // +// AUTHORS: M. Trottier-McDonald // +// CREATED: January 11 2010 // +//********************************************************************// + +#include <algorithm> +#include <math.h> +#include <sstream> + +#include "GaudiKernel/Property.h" +#include "FourMomUtils/P4Helpers.h" + +#include "AnalysisUtils/AnalysisMisc.h" + +#include "xAODJet/Jet.h" +#include "xAODTau/TauJet.h" + +#include "tauRec/CaloClusterVariables.h" +#include "tauRec/TauSubstructureVariables.h" + +#include "tauRec/KineUtils.h" +#include "CaloUtils/CaloVertexedCluster.h" +//#include "CaloEvent/CaloVertexedCluster.h" + +using CLHEP::GeV; + +const double TauSubstructureVariables::DEFAULT = -1111.; + +//********************************** +// Constructor +//********************************** + +TauSubstructureVariables::TauSubstructureVariables( + const std::string& type, + const std::string& name, + const IInterface* parent) : + TauToolBase(type, name, parent), + m_maxPileUpCorrection(4 * GeV), + m_pileUpAlpha(1.0), + m_doVertexCorrection(false), //FF: don't do cell correction by default + m_inAODmode(false) { + declareInterface<TauToolBase > (this); + declareProperty("maxPileUpCorrection", m_maxPileUpCorrection); + declareProperty("pileUpAlpha", m_pileUpAlpha); + declareProperty("VertexCorrection", m_doVertexCorrection); + declareProperty("inAODmode", m_inAODmode); +} + + +//********************************** +// Destructor +//********************************** + +TauSubstructureVariables::~TauSubstructureVariables() { +} + + +//*********************************** +// Initialize method +//*********************************** + +StatusCode TauSubstructureVariables::initialize() { + return StatusCode::SUCCESS; +} + +StatusCode TauSubstructureVariables::eventInitialize(TauCandidateData * /*data*/) { + return StatusCode::SUCCESS; +} + + +//************************************ +// Execute method +//************************************ + +StatusCode TauSubstructureVariables::execute(TauCandidateData *data) { + // Getting our hands on the TauJet object + //---------------------------------------- + xAOD::TauJet* pTau = data->xAODTau; + + // Getting the jet seed + // By asking taujet instead of TauCandidateData->seed, we take advantage of the machinery already + // in place to retrieve a jet seed for track only candidates. + //------------------------------------------------------------------------------------------------ + const xAOD::Jet* taujetseed = (*pTau->jetLink()); + + //***************************************************** + // calculate some tau substructure variables + //***************************************************** + + CaloClusterVariables CaloClusterVariablesTool; + CaloClusterVariablesTool.setVertexCorrection(m_doVertexCorrection); + + bool isFilled = CaloClusterVariablesTool.update(pTau); + + if (!isFilled) { + if (!taujetseed) ATH_MSG_DEBUG("Taujet->jet() pointer is NULL: calo cluster variables will be set to -1111"); + else ATH_MSG_DEBUG("problem in calculating calo cluster variables -> will be set to -1111"); + + pTau->setDetail(xAOD::TauJetParameters::numCells , static_cast<int>(0) ); + pTau->setDetail(xAOD::TauJetParameters::numTopoClusters , static_cast<int>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::numEffTopoClusters , static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::topoInvMass, static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::effTopoInvMass, static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::topoMeanDeltaR, static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::effTopoMeanDeltaR, static_cast<float>(DEFAULT) ); + + } else { + // Getting the variables + //----------------------- + double TopoInvMass = CaloClusterVariablesTool.totalMass(); + double EffTopoInvMass = CaloClusterVariablesTool.effectiveMass(); + unsigned int NumTopoClusters = CaloClusterVariablesTool.numConstituents(); + double NumEffTopoClusters = CaloClusterVariablesTool.effectiveNumConstituents(); + double TopoMeanDeltaR = CaloClusterVariablesTool.averageRadius(); + double EffTopoMeanDeltaR = CaloClusterVariablesTool.averageEffectiveRadius(); + unsigned int Ncells = CaloClusterVariablesTool.numCells(); + + ATH_MSG_VERBOSE(" Substructure variables: "); + ATH_MSG_VERBOSE("-------------------------"); + ATH_MSG_VERBOSE(" TopoInvMass: " << TopoInvMass); + ATH_MSG_VERBOSE(" EffTopoInvMass: " << EffTopoInvMass); + ATH_MSG_VERBOSE(" NumTopoClusters: " << NumTopoClusters); + ATH_MSG_VERBOSE("NumEffTopoClusters: " << NumEffTopoClusters); + ATH_MSG_VERBOSE(" TopoMeanDeltaR: " << TopoMeanDeltaR); + ATH_MSG_VERBOSE(" EffTopoMeanDeltaR: " << EffTopoMeanDeltaR); + ATH_MSG_VERBOSE(" NumCells: " << Ncells); + + //Record the variables + //--------------------- + + if (!m_inAODmode) pTau->setDetail(xAOD::TauJetParameters::numCells , static_cast<int> (Ncells) ); + pTau->setDetail(xAOD::TauJetParameters::numTopoClusters , static_cast<int> (NumTopoClusters) ); + pTau->setDetail(xAOD::TauJetParameters::numEffTopoClusters , static_cast<float>(NumEffTopoClusters) ); + pTau->setDetail(xAOD::TauJetParameters::topoInvMass , static_cast<float>(TopoInvMass) ); + pTau->setDetail(xAOD::TauJetParameters::effTopoInvMass , static_cast<float>(EffTopoInvMass) ); + pTau->setDetail(xAOD::TauJetParameters::topoMeanDeltaR , static_cast<float>(TopoMeanDeltaR) ); + pTau->setDetail(xAOD::TauJetParameters::effTopoMeanDeltaR , static_cast<float>(EffTopoMeanDeltaR) ); + + } + + //***************************************************** + // calculate some new cluster based ID variables + //***************************************************** + + if (taujetseed == NULL) { + + // No jet seed? Warning! Fill variables with dummy values + //-------------------------------------------------------- + + ATH_MSG_DEBUG("Taujet->jet() pointer is NULL: substructure variables will be set to -1111"); + + pTau->setDetail(xAOD::TauJetParameters::lead2ClusterEOverAllClusterE, static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::lead3ClusterEOverAllClusterE, static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::caloIso , static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::caloIsoCorrected , static_cast<float>(DEFAULT) ); + pTau->setDetail(xAOD::TauJetParameters::dRmax , static_cast<float>(DEFAULT) ); + + return StatusCode::SUCCESS; + } + + // New cluster-based variables + float totalEnergy(0.); + float calo_iso(0.); + float dr(0.); + + unsigned int num_clusters(0); + const xAOD::CaloCluster* incluster; + std::vector<const xAOD::CaloCluster*> vClusters; + + // loop over all clusters of the jet seed + xAOD::JetConstituentVector jcv = taujetseed->getConstituents(); + xAOD::JetConstituentVector::const_iterator nav_it = jcv.begin(); + xAOD::JetConstituentVector::const_iterator nav_itE = jcv.end(); + for (; nav_it != nav_itE; ++nav_it) { + ++num_clusters; + + incluster = dynamic_cast<const xAOD::CaloCluster*>( (*nav_it)->rawConstituent() ); + if (!incluster) continue; + + // save all clusters of jet seed + vClusters.push_back(incluster); + + // calc total energy + totalEnergy += incluster->e(); + + //apply Vertex correction on a temporary + TLorentzVector tempclusvec; + if (m_doVertexCorrection && pTau->vertexLink()) + tempclusvec = xAOD::CaloVertexedCluster(*incluster, (*pTau->vertexLink())->position()).p4(); + else + tempclusvec = xAOD::CaloVertexedCluster(*incluster).p4(); + + dr = Tau1P3PKineUtils::deltaR(pTau->eta(),pTau->phi(), tempclusvec.Eta(), tempclusvec.Phi()); + if (0.2 <= dr && dr < 0.4) { + calo_iso += tempclusvec.Et(); + } + } + + // now sort cluster by energy + AnalysisUtils::Sort::e(&vClusters); + + // determine energy sum of leading 2 and leading 3 clusters + float sum2LeadClusterE(0.); + float sum3LeadClusterE(0.); + std::vector<const xAOD::CaloCluster*>::const_iterator icluster(vClusters.begin()); + std::vector<const xAOD::CaloCluster*>::const_iterator icluster_end(vClusters.end()); + + for (; icluster != icluster_end && icluster != vClusters.begin() + 3; ++icluster) { + if (icluster < vClusters.begin() + 2) { + sum2LeadClusterE += (*icluster)->e(); + } + sum3LeadClusterE += (*icluster)->e(); + } + + //record variables + if (totalEnergy != 0) { + ATH_MSG_VERBOSE(" lead2ClusterEOverAllClusterE: " << sum2LeadClusterE / totalEnergy); + ATH_MSG_VERBOSE(" lead3ClusterEOverAllClusterE: " << sum3LeadClusterE / totalEnergy); + + pTau->setDetail(xAOD::TauJetParameters::lead2ClusterEOverAllClusterE, static_cast<float>(sum2LeadClusterE / totalEnergy) ); + pTau->setDetail(xAOD::TauJetParameters::lead3ClusterEOverAllClusterE, static_cast<float>(sum3LeadClusterE / totalEnergy) ); + } + + ATH_MSG_VERBOSE(" caloIso: " << calo_iso); + pTau->setDetail(xAOD::TauJetParameters::caloIso, static_cast<float>(calo_iso) ); + + + // calculate calorimeter energies in different layers + float PSSEnergy(0.); + float EMEnergy(0.); + float HADEnergy(0.); + icluster = vClusters.begin(); + for (; icluster != icluster_end; ++icluster) { + float clEnergy = (*icluster)->e(); + + //Calculate the fractions of energy in different calorimeter layers + const xAOD::CaloCluster *cl = *icluster; + float PreSampler = cl->eSample(CaloSampling::PreSamplerB) + cl->eSample(CaloSampling::PreSamplerE); + float EMLayer1 = cl->eSample(CaloSampling::EMB1) + cl->eSample(CaloSampling::EME1); + float EMLayer2 = cl->eSample(CaloSampling::EMB2) + cl->eSample(CaloSampling::EME2); + + float Energy = cl->rawE(); + float PSSF = Energy != 0 ? (PreSampler + EMLayer1) / Energy : 0; + float EM2F = Energy != 0 ? EMLayer2 / Energy : 0; + float EMF = PSSF + EM2F; + + PSSEnergy += PSSF * clEnergy; + EMEnergy += EMF * clEnergy; + HADEnergy += (Energy != 0) ? (1 - EMF) * clEnergy : 0; + } + + // calculate trk momentum + float trkSysMomentum(0.); + for (unsigned int i(0); i < pTau->nTracks(); ++i) { + trkSysMomentum += pTau->track(i)->pt() * cosh(pTau->track(i)->eta()); + } + + float fPSSFraction = (totalEnergy != 0) ? PSSEnergy / totalEnergy : DEFAULT; + float fChPIEMEOverCaloEME = (EMEnergy != 0) ? (trkSysMomentum - HADEnergy) / EMEnergy : DEFAULT; + float fEMPOverTrkSysP = DEFAULT; + if (pTau->nTracks() > 0) fEMPOverTrkSysP = (trkSysMomentum != 0) ? EMEnergy / trkSysMomentum : DEFAULT; + + pTau->setDetail(xAOD::TauJetParameters::PSSFraction, static_cast<float>(fPSSFraction)); + pTau->setDetail(xAOD::TauJetParameters::ChPiEMEOverCaloEME, static_cast<float>(fChPIEMEOverCaloEME)); + pTau->setDetail(xAOD::TauJetParameters::EMPOverTrkSysP, static_cast<float>(fEMPOverTrkSysP)); + + + // get primary vertex container + // CALO_ISO_CORRECTED + // JVF and PT_PILEUP + // jvf and sumPtTrk are now a vector and the old run1-type jvf value is stored in the 0-th element + // sumPtTrk is calculated wrt Vertices + + float jvf(0.0); + float sumPtTrk(0.0); + + // for tau trigger: JVF and sumPtTrack are not available + bool inTrigger = false; + StatusCode sc; + if (data->hasObject("InTrigger?")) sc = data->getObject("InTrigger?", inTrigger); + + if (!sc.isSuccess() || !inTrigger) + { + std::vector<float> sumPtTrkvec; + std::vector<float> jvfvec; + + // ToDo still need to check if the 500MeV threshold is correct + taujetseed->getAttribute(xAOD::JetAttribute::SumPtTrkPt500, sumPtTrkvec); + taujetseed->getAttribute(xAOD::JetAttribute::JVF, jvfvec); + + if (!jvfvec.empty() && !sumPtTrkvec.empty()) { + // ToDo need to check if first vertex is the vertex we want to use here! + jvf = jvfvec[0]; + sumPtTrk = sumPtTrkvec[0]; + } + else { + ATH_MSG_WARNING("jvf value vector and/or sumPtTrk vector returned from seed jet is empty!"); + } + } + + float pt_pileup = (1.0 - jvf) * sumPtTrk; + + const float max_pileup_correction = m_maxPileUpCorrection; + const float alpha = m_pileUpAlpha; + float pileup_correction = alpha * pt_pileup; + + ATH_MSG_VERBOSE(" --------------------------------------"); + ATH_MSG_VERBOSE(" Pile-up correction parameter"); + ATH_MSG_VERBOSE(" -> sumPtTrk: " << sumPtTrk); + ATH_MSG_VERBOSE(" -> jvf: " << jvf); + ATH_MSG_VERBOSE(" -> pt_pileup: " << pt_pileup); + ATH_MSG_VERBOSE(" -> alpha: " << alpha); + ATH_MSG_VERBOSE(" -> max pileup corr: " << max_pileup_correction); + + if (pileup_correction > max_pileup_correction) { + pileup_correction = max_pileup_correction; + } + const float calo_iso_corrected = calo_iso - pileup_correction; + + ATH_MSG_VERBOSE(" -> pileup corr: " << pileup_correction); + ATH_MSG_VERBOSE(" --------------------------------------"); + + //record variable + ATH_MSG_VERBOSE(" caloIsoCorrected: " << calo_iso_corrected); + pTau->setDetail(xAOD::TauJetParameters::caloIsoCorrected, static_cast<float>(calo_iso_corrected) ); + + // calculate dRMax + unsigned int numTrack(pTau->nTracks()); + if (numTrack > 0) { + float dRmin = -1 * -1111; + float dRmax = -1111; + float dR; + + for (unsigned int i(0); i < numTrack; ++i) { + if (pTau->track(i) == 0) continue; + dR = Tau1P3PKineUtils::deltaR( pTau->track(i)->eta(), pTau->track(i)->phi(), pTau->eta(), pTau->phi() ); + if (dRmin > dR) dRmin = dR; + if (dRmax < dR) dRmax = dR; + } + //record variable + ATH_MSG_VERBOSE(" dRmax: " << dRmax); + pTau->setDetail(xAOD::TauJetParameters::dRmax, static_cast<float>(dRmax) ); + } + + return StatusCode::SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauTestDump.cxx b/Reconstruction/tauRec/src/TauTestDump.cxx new file mode 100644 index 00000000000..fd1748b3ec2 --- /dev/null +++ b/Reconstruction/tauRec/src/TauTestDump.cxx @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTestDump.cxx +// package: Reconstruction/tauRec +// authors: Felix Friedrich +// date: 2012-11-05 +// +//----------------------------------------------------------------------------- + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" +#include "CLHEP/Vector/LorentzVector.h" +#include "Particle/TrackParticle.h" + + +#include "tauRec/TauCandidateData.h" +//#include "tauEvent/TauCommonDetails.h" +//#include "tauEvent/TauPi0Details.h" +//#include "tauEvent/TauPi0Cluster.h" +#include "xAODTau/TauJet.h" + +//#include "tauEvent/TauJetParameters.h" + +#include "tauRec/TauTestDump.h" + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauTestDump::TauTestDump(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauTestDump::~TauTestDump() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauTestDump::initialize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauTestDump::finalize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauTestDump::execute(TauCandidateData *data) { + + ATH_MSG_INFO("=== TAU TEST DUMP BEGIN ==================== "); + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + ATH_MSG_INFO("Tau recorded with: pt="<< pTau->pt() <<", eta=" <<pTau->eta()<<", phi="<<pTau->phi()); + float tfFlightPathSig; + float ipSigLeadTrk; + pTau->detail(xAOD::TauJetParameters::ipSigLeadTrk, ipSigLeadTrk); + pTau->detail(xAOD::TauJetParameters::trFlightPathSig,tfFlightPathSig ); + ATH_MSG_INFO(" numTrack="<<pTau->nTracks() << ", tfFlightPathSig=" << tfFlightPathSig <<", ipSigLeadTrk=" << ipSigLeadTrk ); + + //stop here + return StatusCode::SUCCESS; + + if (pTau->nTracks() != 1) { + // Bonn Pi0 calculated only for 1p taus --> leave test case + ATH_MSG_INFO("Bonn Pi0 calculated only for 1p taus --> leave test case"); + return StatusCode::SUCCESS; + } + + // Default PFO pi0 + ATH_MSG_INFO("dumping pi0 standard"); + if (pTau->nPi0_PFOs()>0) { + for (unsigned int i=0; i<pTau->nPi0_PFOs();++i) ATH_MSG_INFO(pTau->pi0_PFO(i)->e()<< " "); + } + else ATH_MSG_INFO("no pi0 cand"); + + // Cell-based PFO pi0 + ATH_MSG_INFO("dumping pi0 cell-based"); + if (pTau->nCellBased_Pi0_PFOs()>0) { + for (unsigned int i=0; i<pTau->nCellBased_Pi0_PFOs();++i) ATH_MSG_INFO(pTau->cellBased_Pi0_PFO(i)->e()<< " "); + } + else ATH_MSG_INFO("no pi0 cand"); + + // EFlow PF0 pi0 + ATH_MSG_INFO("dumping pi0 eflow"); + if (pTau->nEflowRec_Pi0_PFOs()>0) { + for (unsigned int i=0; i<pTau->nEflowRec_Pi0_PFOs();++i) ATH_MSG_INFO(pTau->eflowRec_Pi0_PFO(i)->e()<< " "); + } + else ATH_MSG_INFO("no pi0 cand"); + + ATH_MSG_INFO("end dumping pi0"); + + ATH_MSG_INFO("=== TAU TEST DUMP END ==================== "); + + return StatusCode::SUCCESS; +} + + diff --git a/Reconstruction/tauRec/src/TauToolBase.cxx b/Reconstruction/tauRec/src/TauToolBase.cxx new file mode 100644 index 00000000000..8ce8a56656b --- /dev/null +++ b/Reconstruction/tauRec/src/TauToolBase.cxx @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauBuilderHelper.cxx +// package: Reconstruction/tauEvent +// authors: Lukasz Janyst +// date: 2007-02-13 +// +// MODIFICATIONS +// 2008-04-22: (nicom) moved setObject()/getObject() to TauCandidateData +//----------------------------------------------------------------------------- + +#include "tauRec/TauToolBase.h" + +static const InterfaceID TauToolBaseID( "TauToolBase", 1, 0 ); + +const InterfaceID& TauToolBase::interfaceID() { + return TauToolBaseID; +} + + +//------------------------------------------------------------------------- +// Constructor +//------------------------------------------------------------------------- +TauToolBase :: TauToolBase( const std::string &type, + const std::string &name, + const IInterface *parent ): + AthAlgTool(type, name, parent) +{ +} + +//------------------------------------------------------------------------- +// Destructor +//------------------------------------------------------------------------- +TauToolBase :: ~TauToolBase() +{ +} + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- +StatusCode TauToolBase :: initialize() +{ + return StatusCode :: SUCCESS; +} + +//------------------------------------------------------------------------- +// Initializer +//------------------------------------------------------------------------- +StatusCode TauToolBase :: eventInitialize( TauCandidateData *) +{ + return StatusCode :: SUCCESS; +} + +//------------------------------------------------------------------------- +// Execute +//------------------------------------------------------------------------- +StatusCode TauToolBase :: execute( TauCandidateData * ) +{ + return StatusCode :: SUCCESS; +} + +//------------------------------------------------------------------------- +// Cleanup +//------------------------------------------------------------------------- +void TauToolBase :: cleanup( TauCandidateData * ) +{ +} + +//------------------------------------------------------------------------- +// Finalizer +//------------------------------------------------------------------------- +StatusCode TauToolBase :: eventFinalize( TauCandidateData * ) +{ + return StatusCode :: SUCCESS; +} + +//------------------------------------------------------------------------- +// Finalizer +//------------------------------------------------------------------------- +StatusCode TauToolBase :: finalize() +{ + return StatusCode :: SUCCESS; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Helpers +template <class T> +bool TauToolBase::openContainer(T* &container, std::string containerName, bool printFATAL) { + StatusCode sc = evtStore()->retrieve(container, containerName); + if (sc.isFailure() || !container) { + if (printFATAL) ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate"); + return 0; + } + return container; +} + +template <class T> +bool TauToolBase::retrieveTool(T & tool) { + if (tool.retrieve().isFailure()) { + ATH_MSG_FATAL("Failed to retrieve tool " << tool); + return false; + } else { + ATH_MSG_VERBOSE("Retrieved tool " << tool); + } + return true; +} + diff --git a/Reconstruction/tauRec/src/TauTrackFilter.cxx b/Reconstruction/tauRec/src/TauTrackFilter.cxx new file mode 100644 index 00000000000..acf573be1b8 --- /dev/null +++ b/Reconstruction/tauRec/src/TauTrackFilter.cxx @@ -0,0 +1,359 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTrackFilter.cxx +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-04 +// +// +//----------------------------------------------------------------------------- + +#include <GaudiKernel/IToolSvc.h> +#include <GaudiKernel/ListItem.h> + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" + +#include "tauRec/TauCandidateData.h" + +#include "tauRec/TauTrackFilter.h" +#include "tauRec/TauTrackFilterUtils.h" + +#include "xAODTracking/TrackParticleContainer.h" + +#include "TLorentzVector.h" + +void TrackFilterAlg(TLorentzVector tau, + std::vector<TLorentzVector>* inputtracks20, + std::vector<int>* inputtracks20charge, + std::vector<TLorentzVector>* inputtracks40, + std::vector<int>* inputtracks40charge, + std::vector<TLorentzVector>* outputtracksgood, + std::vector<int>* outputtracksgoodcharge, + std::vector<TLorentzVector>* outputtracksbad, + std::vector<int>* outputtracksbadcharge, + int& nProng, + int& flag); + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauTrackFilter::TauTrackFilter(const std::string &type, + const std::string &name, + const IInterface *parent) : +TauToolBase(type, name, parent) { + declareInterface<TauToolBase > (this); + + declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles"); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauTrackFilter::~TauTrackFilter() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauTrackFilter::initialize() { + ATH_MSG_VERBOSE("TauTrackFilter Initialising"); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- + +StatusCode TauTrackFilter::finalize() { + ATH_MSG_VERBOSE("TauTrackFilter Finalizing"); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauTrackFilter::execute(TauCandidateData *data) { + ATH_MSG_VERBOSE("TauTrackFilter Executing"); + + xAOD::TauJet *pTau = data->xAODTau; + + StatusCode sc; + + const xAOD::TrackParticleContainer *trackContainer; + + //TODO: trigger uses getObject + sc = evtStore()->retrieve(trackContainer, m_trackContainerName); + if (sc.isFailure() || !trackContainer) { + ATH_MSG_DEBUG(" No track container found in TDS !!"); + return StatusCode::SUCCESS; + } + + TLorentzVector tau; + tau.SetPtEtaPhiE(pTau->pt(), + pTau->eta(), + pTau->phi(), + pTau->e()); + + std::vector<TLorentzVector>* inputtracks20 = new std::vector<TLorentzVector>; + std::vector<TLorentzVector>* inputtracks40 = new std::vector<TLorentzVector>; + std::vector<int>* inputtracks20charge = new std::vector<int>; + std::vector<int>* inputtracks40charge = new std::vector<int>; + std::vector<TLorentzVector>* outputtracksgood = new std::vector<TLorentzVector>; + std::vector<TLorentzVector>* outputtracksbad = new std::vector<TLorentzVector>; + std::vector<int>* outputtracksgoodcharge = new std::vector<int>; + std::vector<int>* outputtracksbadcharge = new std::vector<int>; + int nProng = 0; + int flag = 0; + + std::vector<unsigned int> inputtracks20index; + std::vector<unsigned int> inputtracks40index; + + m_TrkPass.clear(); + + for(unsigned int j=0; j<pTau->nTracks(); j++ ) { + const xAOD::TrackParticle *TauJetTrack = pTau->track(j); + TLorentzVector inputTrack; + inputTrack.SetPtEtaPhiE(TauJetTrack->pt(), + TauJetTrack->eta(), + TauJetTrack->phi(), + TauJetTrack->e()); // TODO Assume track has charged pion mass? + //TODO dR cut to put only correct tracks in inputtracks20 and inputtracks40 + float dR = tau.DeltaR(inputTrack); + if (dR < 0.2) { + inputtracks20->push_back(inputTrack); + inputtracks20charge->push_back(TauJetTrack->charge()); + inputtracks20index.push_back(j); + } + else if (dR < 0.4) { + inputtracks40->push_back(inputTrack); + inputtracks40charge->push_back(TauJetTrack->charge()); + inputtracks40index.push_back(j); + } + + // Add default status to track pass/fail member. + m_TrkPass.push_back(false); + } + + // Run the main algorithm + TrackFilterAlg(tau, + inputtracks20, + inputtracks20charge, + inputtracks40, + inputtracks40charge, + outputtracksgood, + outputtracksgoodcharge, + outputtracksbad, + outputtracksbadcharge, + nProng, + flag); + + // Store results + for (unsigned int j=0; j<outputtracksgood->size(); j++ ) { + for (unsigned int k=0; k<inputtracks20->size(); k++ ) { + if (outputtracksgood->at(j) == inputtracks20->at(k)) { + m_TrkPass.at(inputtracks20index.at(k)) = true; + } + } + for (unsigned int k=0; k<inputtracks40->size(); k++ ) { + if (outputtracksgood->at(j) == inputtracks40->at(k)) { + m_TrkPass.at(inputtracks40index.at(k)) = true; + } + } + } + m_nProng = nProng; + m_flag = flag; + + // Cleanup + delete inputtracks20; + delete inputtracks20charge; + delete inputtracks40; + delete inputtracks40charge; + delete outputtracksgood; + delete outputtracksbad; + delete outputtracksgoodcharge; + delete outputtracksbadcharge; + + // Set values in EDM + for (unsigned int numTrack=0; numTrack<m_TrkPass.size(); numTrack++) { + pTau->setTrackFilterPass(numTrack, m_TrkPass.at(numTrack)); + } + pTau->setTrackFilterProngs(m_nProng); + pTau->setTrackFilterQuality(m_flag); + + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Main algorithm +//----------------------------------------------------------------------------- +void TrackFilterAlg(TLorentzVector tau, + std::vector<TLorentzVector>* inputtracks20, + std::vector<int>* inputtracks20charge, + std::vector<TLorentzVector>* inputtracks40, + std::vector<int>* inputtracks40charge, + std::vector<TLorentzVector>* outputtracksgood, + std::vector<int>* outputtracksgoodcharge, + std::vector<TLorentzVector>* outputtracksbad, + std::vector<int>* outputtracksbadcharge, + int& nProng, + int& flag) { + + std::vector<TauTrackFilterUtils::TrackInfo> unsorted,tracks,SScombination; + TauTrackFilterUtils::TrackInfo track; + unsigned int tracknum = inputtracks20->size(); + unsigned int widetracknum = inputtracks40->size(); + for(unsigned int i=0;i<tracknum;i++){ + track.p4 = (*inputtracks20)[i]; + track.charge = (*inputtracks20charge)[i]; + unsorted.push_back(track); + } + while (unsorted.size() > 0){ + float trackP = unsorted[0].p4.P(); + int index = 0; + for(unsigned int i=1;i<unsorted.size();i++){ + if(unsorted[i].p4.P() > trackP){ + index = i; + trackP = unsorted[i].p4.P(); + } + } + tracks.push_back(unsorted[index]); + tracks[tracks.size()-1].index = tracks.size()-1; + unsorted.erase(unsorted.begin()+index); + } +//Step 2: Test 3 Prong Hypothesis +//Step 2a: Arrange combinations of tracks for testing + + bool test3prong = true, test2prong = true, test1prong = true; + for(unsigned int i=0;i<widetracknum;i++){ + outputtracksbad->push_back((*inputtracks40)[i]); + outputtracksbadcharge->push_back((*inputtracks40charge)[i]); + } + if(tracknum > 4){ //Anything with more than 4 tracks is a fake. + flag = 0; + test3prong = false; + test2prong = false; + test1prong = false; + } + if(tracknum < 3) test3prong = false; //Don't test 3 prong if fewer than 3 tracks + if(tracknum < 2) test2prong = false; //Don't test 2 prong if fewer than 2 tracks + if(tracknum < 1){ + flag = 0; + test1prong = false; //Don't test 1 prong if no tracks within dR < 0.2 of tau + } + if(test3prong){ + //Test 3 Highest pT Tracks + bool isSS = false; + std::vector<TauTrackFilterUtils::TrackInfo> combination; + int charge = 0; TLorentzVector threetrack; + for(unsigned int i=0;i<3;i++){ + combination.push_back(tracks[i]); //Only Care about 3 Highest pT Tracks + charge+=tracks[i].charge; + threetrack+=tracks[i].p4; + } + if((tracknum == 3) && (abs(charge)!=1)) isSS = true; //Reject all same-sign combinations +//Step 2b: Check kinematics of track combinations against shrinking cones and mass boundaries +// for(unsigned int i=0;i<combinations.size();i++){ + bool goodcombo = false; + if(tracknum == 4){ + char eqn[] = "pol2"; + float a[] = {1.51673, -0.000150534, 2.64226e-06}; + float mass99 = TauTrackFilterUtils::Compute1dim(tau.P(),a,3,eqn); + if((threetrack.M() < mass99)&&(TauTrackFilterUtils::pass3prong(combination,tau))){ + goodcombo=true; + flag = 2; + } + else flag = 0; + test1prong=false; + test2prong=false; + } + else if(TauTrackFilterUtils::pass3prong(combination, tau)){ + goodcombo=true; + flag = 1; + } + if(goodcombo){ //A Combination is found which passes 3prong hypothesis + for(unsigned int i=0;i<combination.size();i++){ + if (isSS) SScombination.push_back(combination[i]); + outputtracksgood->push_back(combination[i].p4); + outputtracksgoodcharge->push_back(combination[i].charge); + } + if(isSS) flag = 0; + else flag = 1; + nProng = 3; + test1prong = false; + test2prong = false; + if(!test1prong){ //Fill Bad Track in the Case of 4 trk taus + if(tracknum == 4){ + outputtracksbad->push_back(tracks[3].p4); + outputtracksbadcharge->push_back(tracks[3].charge); + } + } + } + }//End 3 Prong Test Conditional + if (test2prong){ + std::vector<TauTrackFilterUtils::TrackInfo> pair; + for(unsigned int i=0;i<2;i++) pair.push_back(tracks[i]); + if(TauTrackFilterUtils::pass2prong(pair,tau)){ + nProng = 2; + for(unsigned int i=0;i<pair.size();i++){ //Fill Good Tracks + outputtracksgood->push_back(pair[i].p4); + outputtracksgoodcharge->push_back(pair[i].charge); + } + test1prong = false; + if(tracknum == 3){ + flag = 2; + outputtracksbad->push_back(tracks[2].p4); //Fill Bad Track in Case of 3 trk Taus + outputtracksbadcharge->push_back(tracks[2].charge); + } + else flag = 1; //Good 2 Prong if only 2 trks + } + }//End 2 Prong Test Conditional +//Step 4: Check tracks that don't pass 2 prong hypothesis against 1 prong hypothesis + if (test1prong){ + char eqn[] = "([0]*exp([1]*x))*pol6(2)+[9]"; + float a[10]; + a[0] = 0.079586; + a[1] = -0.0289929; + a[2] = 7.06684; + a[3] = -0.158835; + a[4] = 0.000607181; + a[5] = 6.8445e-05; + a[6] = -6.79205e-07; + a[7] = 2.13158e-09; + a[8] = -5.11643e-13; + a[9] = 0.030376; + float ratio10 = TauTrackFilterUtils::Compute1dim(tau.P(),a,10,eqn); + bool goodcase = false; + if(tracknum == 1) goodcase = true; + if(tracknum == 2){ + if(tracks[1].p4.Pt()/tracks[0].p4.Pt() < ratio10) goodcase = true; //Test 2trk taus most likely to actually be 1pngs + } + if((TauTrackFilterUtils::pass1prong(tracks[0].p4,tau))&&(goodcase)){ //A track is found which passes 1prong hypothesis + outputtracksgood->push_back(tracks[0].p4); + outputtracksgoodcharge->push_back(tracks[0].charge); + nProng = 1; + if (tracknum == 2){ + flag = 2; + outputtracksbad->push_back(tracks[1].p4); //Fill Bad Track in Case of 3 trk Taus + outputtracksbadcharge->push_back(tracks[1].charge); + } + else flag = 1; + } + else flag = 0; //Fake Tau + }//End 1 Prong Test Conditional + + return; +} + diff --git a/Reconstruction/tauRec/src/TauTrackFilterUtils.cxx b/Reconstruction/tauRec/src/TauTrackFilterUtils.cxx new file mode 100644 index 00000000000..24a9d1ccac9 --- /dev/null +++ b/Reconstruction/tauRec/src/TauTrackFilterUtils.cxx @@ -0,0 +1,266 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTrackFilterUtils.cxx +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-13 +// +// +//----------------------------------------------------------------------------- + +#include "TF1.h" +#include "TLorentzVector.h" +#include "tauRec/TauTrackFilterUtils.h" +#include <vector> +#include <iostream> +#include <string> + +using namespace TauTrackFilterUtils; + +bool TauTrackFilterUtils::pass3prong(std::vector<TauTrackFilterUtils::TrackInfo> combination,TLorentzVector tau){ + + //Step 1: calculate angles + TauTrackFilterUtils::TrackPair lp, lm, sp, ls, ms, mp; + + lm.angle = fabs(combination[0].p4.Angle(combination[1].p4.Vect())); + lm.mass = (combination[0].p4+combination[1].p4).M(); + lm.charge = combination[0].charge*combination[1].charge; + ls.angle = fabs(combination[0].p4.Angle(combination[2].p4.Vect())); + ls.mass = (combination[0].p4+combination[2].p4).M(); + ls.charge = combination[0].charge*combination[2].charge; + ms.angle = fabs(combination[1].p4.Angle(combination[2].p4.Vect())); + ms.mass = (combination[1].p4+combination[2].p4).M(); + ms.charge = combination[1].charge*combination[2].charge; + + lp = lm; + if(ls.angle > lp.angle){ + mp = lp; + lp = ls; + } + else mp = ls; + if(ms.angle > lp.angle){ + sp = mp; + mp = lp; + lp = ms; + } + else if(ms.angle > mp.angle){ + sp = mp; + mp = ms; + } + else sp = ms; + + //if (lp.angle < mp.angle) ATH_MSG_WARNING("Largest angle is smaller than medium angle!"); + //if (lp.angle < sp.angle) ATH_MSG_WARNING("Largest angle is smaller than smallest angle!"); + //if (mp.angle < sp.angle) ATH_MSG_WARNING("Medium angle is smaller than smallest angle!"); + + //Step 3: calculate 99% angles + float lp99 = 0, sp99 = 0, lm99 = 0, ls99 = 0; + float p = tau.P(), eta = fabs(tau.Eta()); + + float a[9][4]; + int npar = 4, npol = 3; + +a[0][0] = 0.179041; a[1][0] = -0.0531058; a[2][0] = 0; +a[0][1] = -0.0146875; a[1][1] = 0.00414247; a[2][1] = -0.000612045; +a[0][2] = 0.0188939; a[1][2] = -0.00452375; a[2][2] = 0.00120015; +a[0][3] = 58.3066; a[1][3] = -48.2594; a[2][3] = 26.8864; + lp99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.0741985; a[1][0] = -0.0181941; a[2][0] = 0; +a[0][1] = -0.0149252; a[1][1] = 0.00512965; a[2][1] = -0.00125462; +a[0][2] = 0.00802004; a[1][2] = -0.00252272; a[2][2] = 0.000761022; +a[0][3] = 25.0145; a[1][3] = 0; a[2][3] = 0; + sp99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.102084; a[1][0] = -0.0256446; a[2][0] = 0; +a[0][1] = -0.014259; a[1][1] = 0.00465467; a[2][1] = -0.00122856; +a[0][2] = 0.010552; a[1][2] = -0.00176856; a[2][2] = 0.000446776; +a[0][3] = 36.0848; a[1][3] = -16.1489; a[2][3] = 10.2994; + lm99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.152783; a[1][0] = -0.0390978; a[2][0] = 0; +a[0][1] = -0.0139914; a[1][1] = 0.00352551; a[2][1] = -0.000624039; +a[0][2] = 0.0159925; a[1][2] = -0.00332104; a[2][2] = 0.00100568; +a[0][3] = 43.5804; a[1][3] = -18.681; a[2][3] = 6.29988; + ls99 = ComputeAngle(p,eta,a,npar,npol); + + //Step 4: compare angles and track masses, pass if all pass, fail otherwise + if((lp.angle > lp99)||(sp.angle > sp99)||(lm.angle > lm99)||(ls.angle > ls99)) return false; //One or more of the angles has failed - not a three prong tau + return true; //Track combination is a 3prong candidate! +} //End pass3prong (efficiency studies) + +bool TauTrackFilterUtils::pass2prong(std::vector<TauTrackFilterUtils::TrackInfo> pair,TLorentzVector tau){ + float angle = fabs(pair[0].p4.Angle(pair[1].p4.Vect())); + int charge = pair[0].charge*pair[1].charge; + + // Used to have more vars, but some were unused. + //float lt99 = 0, mt99 = 0, st99 = 0, ct99 = 0, lp99 = 0, mp99 = 0, sp99 = 0, los99 = 0, sos99 = 0, ss99 = 0, lm99 = 0, ls99 = 0, ms99 = 0; + float lp99 = 0, mp99 = 0, sp99 = 0, los99 = 0, sos99 = 0, ss99 = 0, lm99 = 0; + float p = tau.P(), eta = fabs(tau.Eta()); + + float a[9][4]; + int npar = 4, npol = 9; + + a[0][0] = 0.0584232; a[1][0] = -0.0177642; a[2][0] = 0; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; + a[0][1] = 0.0447435; a[1][1] = -0.659295; a[2][1] = 2.99202; a[3][1] = -6.10742; a[4][1] = 6.34017; a[5][1] = -3.49095; a[6][1] = 0.972228; a[7][1] = -0.107807; a[8][1] = 0; + a[0][2] = -0.249078; a[1][2] = 3.75779; a[2][2] = -18.9563; a[3][2] = 45.4474; a[4][2] = -59.333; a[5][2] = 44.722; a[6][2] = -19.4586; a[7][2] = 4.54039; a[8][2] = -0.4399; + a[0][3] = 124.481; a[1][3] = -1129.76; a[2][3] = 5198.92; a[3][3] = -10538.1; a[4][3] = 10741.4; a[5][3] = -5757; a[6][3] = 1548.86; a[7][3] = -164.644; a[8][3] = 0; + //lt99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.057286; a[1][0] = -0.0168061; a[2][0] = 0; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; +a[0][1] = 0.0640448; a[1][1] = -0.922493; a[2][1] = 4.10239; a[3][1] = -8.19704; a[4][1] = 8.35619; a[5][1] = -4.52961; a[6][1] = 1.24415; a[7][1] = -0.136244; a[8][1] = 0; +a[0][2] = -0.222389; a[1][2] = 3.34829; a[2][2] = -16.8256; a[3][2] = 40.1156; a[4][2] = -52.0129; a[5][2] = 38.9152; a[6][2] = -16.8076; a[7][2] = 3.89426; a[8][2] = -0.374831; +a[0][3] = 97.8443; a[1][3] = -804.025; a[2][3] = 3412.76; a[3][3] = -6058.05; a[4][3] = 5028.88; a[5][3] = -1940.87; a[6][3] = 281.19; a[7][3] = 0; a[8][3] = 0; + //ct99 = ComputeAngle(p,eta,a,npar,npol); + npol = 3; +a[0][0] = 0.0665222; a[1][0] = 0; a[2][0] = 0; +a[0][1] = -0.018755; a[1][1] = 0.00258183; a[2][1] = 0; +a[0][2] = 0.045607; a[1][2] = -0.0234824; a[2][2] = 0.00375319; +a[0][3] = 43.8011; a[1][3] = -10.0462; a[2][3] = 0; + //mt99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.156972; a[1][0] = -0.0333305; a[2][0] = 0; +a[0][1] = -0.0231364; a[1][1] = 0.0120482; a[2][1] = -0.00289192; +a[0][2] = 0.0490898; a[1][2] = -0.0273084; a[2][2] = 0.00547379; +a[0][3] = 33.1651; a[1][3] = 0; a[2][3] = 0; + //st99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.179041; a[1][0] = -0.0531058; a[2][0] = 0; +a[0][1] = -0.0146875; a[1][1] = 0.00414247; a[2][1] = -0.000612045; +a[0][2] = 0.0188939; a[1][2] = -0.00452375; a[2][2] = 0.00120015; +a[0][3] = 58.3066; a[1][3] = -48.2594; a[2][3] = 26.8864; + lp99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.142962; a[1][0] = -0.0397119; a[2][0] = 0; +a[0][1] = -0.014084; a[1][1] = 0.00437622; a[2][1] = -0.000992845; +a[0][2] = 0.0145659; a[1][2] = -0.00270987; a[2][2] = 0.00079432; +a[0][3] = 42.4831; a[1][3] = -25.893; a[2][3] = 13.6075; + mp99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.0741985; a[1][0] = -0.0181941; a[2][0] = 0; +a[0][1] = -0.0149252; a[1][1] = 0.00512965; a[2][1] = -0.00125462; +a[0][2] = 0.00802004; a[1][2] = -0.00252272; a[2][2] = 0.000761022; +a[0][3] = 25.0145; a[1][3] = 0; a[2][3] = 0; + sp99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.177021; a[1][0] = -0.0800858; a[2][0] = 0.017266; +a[0][1] = -0.0145132; a[1][1] = 0.00508756; a[2][1] = -0.00133994; +a[0][2] = 0.0174059; a[1][2] = -0.00407948; a[2][2] = 0.00130897; +a[0][3] = 59.5959; a[1][3] = -51.819; a[2][3] = 28.742; + los99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.126153; a[1][0] = -0.0504026; a[2][0] = 0.0100601; +a[0][1] = -0.01373; a[1][1] = 0.0040825; a[2][1] = -0.00103933; +a[0][2] = 0.0121626; a[1][2] = -0.00239224; a[2][2] = 0.000832398; +a[0][3] = 43.6455; a[1][3] = -34.4061; a[2][3] = 17.558; + sos99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.159394; a[1][0] = -0.0461081; a[2][0] = 0; +a[0][1] = -0.0148102; a[1][1] = 0.00429109; a[2][1] = -0.000670516; +a[0][2] = 0.0167114; a[1][2] = -0.00539364; a[2][2] = 0.00175181; +a[0][3] = 48.371; a[1][3] = -35.9336; a[2][3] = 19.3991; + ss99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.102084; a[1][0] = -0.0256446; a[2][0] = 0; +a[0][1] = -0.014259; a[1][1] = 0.00465467; a[2][1] = -0.00122856; +a[0][2] = 0.010552; a[1][2] = -0.00176856; a[2][2] = 0.000446776; +a[0][3] = 36.0848; a[1][3] = -16.1489; a[2][3] = 10.2994; + lm99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.152783; a[1][0] = -0.0390978; a[2][0] = 0; +a[0][1] = -0.0139914; a[1][1] = 0.00352551; a[2][1] = -0.000624039; +a[0][2] = 0.0159925; a[1][2] = -0.00332104; a[2][2] = 0.00100568; +a[0][3] = 43.5804; a[1][3] = -18.681; a[2][3] = 6.29988; + //ls99 = ComputeAngle(p,eta,a,npar,npol); +a[0][0] = 0.160615; a[1][0] = -0.0284831; a[2][0] = -0.00879631; +a[0][1] = -0.0140811; a[1][1] = 0.00344844; a[2][1] = -0.000421752; +a[0][2] = 0.0173056; a[1][2] = -0.00371573; a[2][2] = 0.00112158; +a[0][3] = 59.28; a[1][3] = -48.2821; a[2][3] = 26.3103; + //ms99 = ComputeAngle(p,eta,a,npar,npol); + + if ((angle < lm99)&&((angle < lp99)||(angle < mp99)||(angle < sp99))){ + if((charge == -1)&&((angle < los99)||(angle < sos99))) return true; + else if((charge == 1)&&(angle < ss99)) return true; + else return false; + } + else return false; +} //End pass2prong + +bool TauTrackFilterUtils::pass1prong(TLorentzVector track,TLorentzVector tau){ + //Step 1: Compute Angle Between Track and Tau + float angle = fabs(track.Angle(tau.Vect())); + //Step 2: Compute 99% angle + float p = tau.P(), eta = fabs(tau.Eta()); + + int npar = 4, npol = 3; + float a[3][4]; + + a[0][0] = 0.120777; a[1][0] = -0.0261681; a[2][0] = 0; + a[0][1] = -0.0307174; a[1][1] = 0.0170112; a[2][1] = -0.00381298; + a[0][2] = 0.0662689; a[1][2] = -0.0402811; a[2][2] = 0.00760013; + a[0][3] = 24.512; a[1][3] = 0; a[2][3] = 0; + float angle99 = ComputeAngle(p,eta,a,npar,npol); + + //Step 3: compare angles and return decision + if(angle > angle99) return false; //Track angle exceeds kinematic boundary + else return true; +} //End pass1prong + +float TauTrackFilterUtils::ComputePi0Cone(int recProngs,TLorentzVector tau){ + float angle = -1; + float atrue = 0, arec = 0; + float p = tau.P(), eta = fabs(tau.Eta()); + int npar = 4, npol = 9; + float a[9][4]; + switch(recProngs){ + case 3: //3 Prong Case + npol = 7; + a[0][0] = 0.0457602; a[1][0] = 1.80062; a[2][0] = -6.82921; a[3][0] = 10.8605; a[4][0] = -8.52901; a[5][0] = 3.24106; a[6][0] = -0.473647; + a[0][1] = -0.017874; a[1][1] = -0.0502181; a[2][1] = 0.162668; a[3][1] = -0.172266; a[4][1] = 0.0783324; a[5][1] = -0.013098; a[6][1] = 0; + a[0][2] = 0.0266511; a[1][2] = -0.013319; a[2][2] = 0.00289217; a[3][2] = 0; a[4][2] = 0; a[5][2] = 0; a[6][2] = 0; + a[0][3] = 237.828; a[1][3] = -2836.67; a[2][3] = 11074.1; a[3][3] = -18578.5; a[4][3] = 15086.9; a[5][3] = -5828.12; a[6][3] = 856.684; + atrue = ComputeAngle(p,eta,a,npar,npol); + npar = 3; + npol = 5; + a[0][0] = 0.178252; a[1][0] = 0.057474; a[2][0] = -0.256742; a[3][0] = 0.156772; a[4][0] = -0.0283407; + a[0][1] = -0.00950538; a[1][1] = 0.00363589; a[2][1] = -0.00157984; a[3][1] = 0; a[4][1] = 0; + a[0][2] = 0.0227538; a[1][2] = -0.0642722; a[2][2] = 0.121818; a[3][2] = -0.0679845; a[4][2] = 0.0115837; + arec = ComputeAngle(p,eta,a,npar,npol,(char*)"[0]*exp([1]*x)+[2]"); + break; + case 1: //1 Prong Case + npol = 6; + a[0][0] = 0.203158; a[1][0] = 0.269746; a[2][0] = -1.22961; a[3][0] = 1.41234; a[4][0] = -0.670384; a[5][0] = 0.114524; + a[0][1] = -0.0300622; a[1][1] = -0.0115786; a[2][1] = 0.07541; a[3][1] = -0.0782728; a[4][1] = 0.0334031; a[5][1] = -0.0052381; + a[0][2] = 0.0423083; a[1][2] = -0.0284378; a[2][2] = 0.0237394; a[3][2] = -0.0168315; a[4][2] = 0.0040657; a[5][2] = 0; + a[0][3] = 45.0612; a[1][3] = -458.353; a[2][3] = 1521.8; a[3][3] = -1895.88; a[4][3] = 1000.72; a[5][3] = -187.091; + atrue = ComputeAngle(p,eta,a,npar,npol); + a[0][0] = 0.168639; a[1][0] = -0.325194; a[2][0] = 1.4594; a[3][0] = -3.20592; a[4][0] = 3.50676; a[5][0] = -2.0571; a[6][0] = 0.621729; a[7][0] = -0.0758951; a[8][0] = 0; + a[0][1] = -0.0103477; a[1][1] = 0; a[2][1] = 0; a[3][1] = 0; a[4][1] = 0; a[5][1] = 0; a[6][1] = 0; a[7][1] = 0; a[8][1] = 0; + a[0][2] = 0.0325721; a[1][2] = -0.0496515; a[2][2] = 0.0773747; a[3][2] = -0.0396844; a[4][2] = 0.00615314; a[5][2] = 0; a[6][2] = 0; a[7][2] = 0; a[8][2] = 0; + arec = ComputeAngle(p,eta,a,npar,npol,(char*)"[0]*exp([1]*x)+[2]"); + break; + default: + //ATH_MSG_WARNING("Incorrect number of prongs!"); + return angle; + } + if (atrue > arec) angle = atrue; + else angle = arec; + return angle; +} //End ComputePi0Cone + +float TauTrackFilterUtils::ComputeAngle(float p, float eta, float a[9][4], int npar, int npol, char eqn[]){ + char name[10]; + char poleqn[10]; + + //TF1* etacoeff[npar]; //FIXME variable length array, use something like: = new TF1[npar]; + std::vector<TF1> etacoeff; + TF1* pcone = new TF1("pcone",eqn); + for(int i=0;i<npar;i++){ + sprintf(name,"p%i",i); + sprintf(poleqn,"pol%i",npol); + etacoeff.push_back(TF1(name,poleqn)); + for(int j=0;j<npol;j++) etacoeff.at(i).SetParameter(j,a[j][i]); + pcone->SetParameter(i,etacoeff.at(i).Eval(eta)); + } + float angle = pcone->Eval(p); + delete pcone; + return angle; +} + +float TauTrackFilterUtils::Compute1dim(float p, float a[10], int npar, char eqn[]){ + TF1* pcone = new TF1("pcone",eqn); + for(int i=0;i<npar;i++) pcone->SetParameter(i,a[i]); + float angle = pcone->Eval(p); + delete pcone; + return angle; +} diff --git a/Reconstruction/tauRec/src/TauTrackFinder.cxx b/Reconstruction/tauRec/src/TauTrackFinder.cxx new file mode 100644 index 00000000000..c022555997e --- /dev/null +++ b/Reconstruction/tauRec/src/TauTrackFinder.cxx @@ -0,0 +1,607 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "RecoToolInterfaces/IExtrapolateToCaloTool.h" +#include "TrkToolInterfaces/ITrackSelectorTool.h" + +#include "xAODTau/TauJet.h" +#include "xAODTau/TauJetContainer.h" + +#include "tauRec/TauTrackFinder.h" +#include "tauRec/KineUtils.h" +#include "tauRec/TrackSort.h" + + +TauTrackFinder::TauTrackFinder(const std::string& type, + const std::string& name, + const IInterface* parent) : + TauToolBase(type, name, parent), + m_trackToCalo(""), + m_trackSelectorTool_tau(""), + m_trackToVertexTool("Reco::TrackToVertex"), + m_z0maxDelta(1000), + m_applyZ0cut(false), + m_storeInOtherTrks(true) +{ + declareInterface<TauToolBase > (this); + declareProperty("MaxJetDrTau", m_maxJetDr_tau = 0.2); + declareProperty("MaxJetDrWide", m_maxJetDr_wide = 0.4); + declareProperty("TrackSelectorToolTau", m_trackSelectorTool_tau); + declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles"); + declareProperty("TTCExtrapolator", m_trackToCalo, "public track extrapolator tool to match track with caloseed"); + declareProperty("TrackToVertexTool",m_trackToVertexTool); + declareProperty("maxDeltaZ0wrtLeadTrk", m_z0maxDelta); + declareProperty("removeTracksOutsideZ0wrtLeadTrk", m_applyZ0cut); + declareProperty("StoreRemovedCoreWideTracksInOtherTracks", m_storeInOtherTrks = true); +} + +TauTrackFinder::~TauTrackFinder() { +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::initialize() { + + // Get the TrackSelectorTool + if (!retrieveTool(m_trackSelectorTool_tau)) return StatusCode::FAILURE; + + // Get the TJVA + if (!retrieveTool(m_trackToVertexTool)) return StatusCode::FAILURE; + if (!retrieveTool(m_trackToCalo)) return StatusCode::FAILURE; + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::finalize() { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::eventInitialize(TauCandidateData*) { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::eventFinalize(TauCandidateData*) { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::execute(TauCandidateData * data) { + + ATH_MSG_VERBOSE("TauTrackFinder Executing"); + + xAOD::TauJet *pTau = data->xAODTau; + + StatusCode sc; + // get the track particle container from StoreGate + const xAOD::TrackParticleContainer* trackParticleCont = 0; + + //for tau trigger + bool inTrigger = false; + if (data->hasObject("InTrigger?")) sc = data->getObject("InTrigger?", inTrigger); + if (sc.isSuccess() && inTrigger) sc = data->getObject( "TrackContainer", trackParticleCont ); + + if( !inTrigger || !trackParticleCont || sc.isFailure() ) { + // try standard + if (!openContainer(trackParticleCont, m_inputTrackParticleContainerName)) { + if (!inTrigger) return StatusCode::FAILURE; // in offline we don't reconstruct tau candidates without having a track container + else return StatusCode::SUCCESS; // we don't want stop trigger if there is no track container + } + } + + std::vector<const xAOD::TrackParticle*> tauTracks; + std::vector<const xAOD::TrackParticle*> wideTracks; + std::vector<const xAOD::TrackParticle*> otherTracks; + + const xAOD::Vertex* pVertex = pTau->vertexLink()!=0 ? (*pTau->vertexLink()) : NULL; + // retrieve tracks wrt a vertex + // as a vertex is used: tau origin / PV / beamspot / 0,0,0 (in this order, depending on availability) + getTauTracksFromPV(pTau, trackParticleCont, pVertex, tauTracks, wideTracks, otherTracks); + + + this->resetDeltaZ0Cache(); + // remove core and wide tracks outside a maximal delta z0 wrt lead core track + if (m_applyZ0cut) { + this->removeOffsideTracksWrtLeadTrk(tauTracks, wideTracks, otherTracks, pVertex, m_z0maxDelta); + } + + //clear tracks first (needed for "rerun mode" if called on AODs again) + pTau->clearTrackLinks(); + pTau->clearWideTrackLinks(); + pTau->clearOtherTrackLinks(); + + bool alreadyUsed = false; + //check for tracks used in multiple taus + for (std::vector<const xAOD::TrackParticle*>::iterator track_it = tauTracks.begin(); track_it != tauTracks.end() ;) + { + alreadyUsed = false; + + //loop over all up-to-now reconstructed tau candidates + xAOD::TauJetContainer::const_iterator tau_it = data->xAODTauContainer->begin(); + xAOD::TauJetContainer::const_iterator tau_end = data->xAODTauContainer->end(); + for( ; tau_it != tau_end; tau_it++ ) + { + //loop over core tracks + for (unsigned int j = 0; j < (*tau_it)->nTracks(); ++j) + { + if ((*track_it) == (*tau_it)->track(j)) + { + ATH_MSG_WARNING("Found a track that is identical with a track already associated to another tau. Will not add this track to more than one tau candidate"); + alreadyUsed = true; + } + } + } + + //if this track has already been used by another tau, don't associate it to this new one + if (alreadyUsed) track_it = tauTracks.erase(track_it); + else ++track_it; + } + + + // associated track to tau candidate and calculate charge + float charge = 0; + for (unsigned int i = 0; i < tauTracks.size(); ++i) { + const xAOD::TrackParticle* trackParticle = tauTracks.at(i); + + ATH_MSG_VERBOSE(name() << " adding core track nr: " << i + << " eta " << trackParticle->eta() + << " phi " << trackParticle->phi() + ); + charge += trackParticle->charge(); + ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle; + linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle); + pTau->addTrackLink(linkToTrackParticle); + ATH_MSG_VERBOSE(name() << " added core track nr: " << i + << " eta " << pTau->track(i)->eta() + << " phi " << pTau->track(i)->phi() + ); + } + // set the charge, which is defined by the core tau tracks only + pTau->setCharge(charge); + + /// FIXME hide the logic to create element links inside xAODTau + /// was + // for (unsigned int i = 0; i < wideTracks.size(); ++i) + // details->addSeedCalo_wideTrk(trackParticleCont, wideTracks.at(i)); + for (unsigned int i = 0; i < wideTracks.size(); ++i) { + const xAOD::TrackParticle* trackParticle = wideTracks.at(i); + + ATH_MSG_VERBOSE(name() << " adding wide track nr: " << i + << " eta " << trackParticle->eta() + << " phi " << trackParticle->phi() + ); + ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle; + linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle); + pTau->addWideTrackLink(linkToTrackParticle); + ATH_MSG_VERBOSE(name() << " added wide track nr: " << i + << " eta " << pTau->wideTrack(i)->eta() + << " phi " << pTau->wideTrack(i)->phi() + ); + } + + /// was + // for (unsigned int i = 0; i < otherTracks.size(); ++i) + // details->addOtherTrk(trackParticleCont, otherTracks.at(i)); + for (unsigned int i = 0; i < otherTracks.size(); ++i) { + const xAOD::TrackParticle* trackParticle = otherTracks.at(i); + + ATH_MSG_VERBOSE(name() << " adding other track nr: " << i + << " eta " << trackParticle->eta() + << " phi " << trackParticle->phi() + ); + ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle; + linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle); + pTau->addOtherTrackLink(linkToTrackParticle); + ATH_MSG_VERBOSE(name() << " added other track nr: " << i + << " eta " << pTau->otherTrack(i)->eta() + << " phi " << pTau->otherTrack(i)->phi() + ); + } + + + ATH_MSG_DEBUG("numTrack: " << "/" << pTau->nTracks()); + ATH_MSG_DEBUG("charge: " << "/" << pTau->charge()); + + // extrapolate core tracks to calorimeter surface + // store information only in ExtraDetailsContainer + sc = extrapolateToCaloSurface(data); + if (sc.isFailure() && !sc.isRecoverable()) { + ATH_MSG_ERROR("couldn't extrapolate tracks to calo surface"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +TauTrackFinder::TauTrackType TauTrackFinder::tauTrackType( const xAOD::TauJet* pTau, + const xAOD::TrackParticle* trackParticle, + const xAOD::Vertex* primaryVertex) +{ + //ATH_MSG_VERBOSE("tau axis:" << pTau->hlv().perp()<< " " << pTau->hlv().eta() << " " << pTau->hlv().phi() << " " << pTau->hlv().e() ); + double dR = Tau1P3PKineUtils::deltaR(pTau->eta(),pTau->phi(),trackParticle->eta(),trackParticle->phi()); + + if (dR > m_maxJetDr_wide) return NotTauTrack; + + if (m_trackSelectorTool_tau->decision(*trackParticle, primaryVertex)) { + if (dR > m_maxJetDr_tau) + return TauTrackWide; + else + return TauTrackCore; + } else + return TauTrackOther; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +void TauTrackFinder::getTauTracksFromPV( const xAOD::TauJet* pTau, + const xAOD::TrackParticleContainer* trackParticleCont, + const xAOD::Vertex* primaryVertex, + std::vector<const xAOD::TrackParticle*> &tauTracks, + std::vector<const xAOD::TrackParticle*> &wideTracks, + std::vector<const xAOD::TrackParticle*> &otherTracks) +{ + for (xAOD::TrackParticleContainer::const_iterator tpcItr = trackParticleCont->begin(); tpcItr != trackParticleCont->end(); ++tpcItr) { + const xAOD::TrackParticle *trackParticle = *tpcItr; + + TauTrackType type = tauTrackType(pTau, trackParticle, primaryVertex); + + if (type == TauTrackCore) + tauTracks.push_back(trackParticle); + else if (type == TauTrackWide) + wideTracks.push_back(trackParticle); + else if (type == TauTrackOther) + otherTracks.push_back(trackParticle); + + } + std::sort(tauTracks.begin(), tauTracks.end(), TrackSort()); + std::sort(wideTracks.begin(), wideTracks.end(), TrackSort()); + std::sort(otherTracks.begin(), otherTracks.end(), TrackSort()); +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauTrackFinder::extrapolateToCaloSurface(TauCandidateData *data) { + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + const int numOfsampEM = 4; + + for (unsigned int itr = 0; itr < 10 && itr < pTau->nTracks(); ++itr) { + + const xAOD::TrackParticle *orgTrack = pTau->track(itr); + + //--------------------------------------------------------------------- + // Extrapolate to all layers + //--------------------------------------------------------------------- + const DataVector< const Trk::TrackParameters >* pTrk = m_trackToCalo->getParametersInCalo(*orgTrack, Trk::pion, Trk::alongMomentum); //FIXME + + //--------------------------------------------------------------------- + // Calculate eta, phi impact point at calorimeter layers EM 0,1,2,3 + //--------------------------------------------------------------------- + double eta_extrapol[4]; + double phi_extrapol[4]; + + for (int i = 0; i < numOfsampEM; ++i) { + eta_extrapol[i] = -11111.; + phi_extrapol[i] = -11111.; + } + + // XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet + // if (pTrk && (*pTrk)[IExtrapolateToCaloTool::PreSampler]) { + // eta_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().eta(); + // phi_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().phi(); + // } + + if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Strips]) { + eta_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().eta(); + phi_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().phi(); + + if (msgLvl(MSG::VERBOSE)) + { //only if desired msg level is requested + ATH_MSG_VERBOSE(name() << " extrapolation in strip layer : " + << " track nr " << itr + << " impact point eta " << eta_extrapol[1] + << " impact point phi " << phi_extrapol[1] + ); + } + + pTau->setTrackEtaStrip( itr, (*pTrk)[IExtrapolateToCaloTool::Strips]->position().eta() ); + pTau->setTrackPhiStrip( itr, (*pTrk)[IExtrapolateToCaloTool::Strips]->position().phi() ); + + if (msgLvl(MSG::VERBOSE)) + { //only if desired msg level is requested + ATH_MSG_VERBOSE(name() << " extrapolation in strip layer stored in tau : " + << " track nr " << itr + << " impact point eta " << pTau->trackEtaStrip(itr) + << " impact point phi " << pTau->trackPhiStrip(itr) + ); + } + + } + + // XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet + // if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Middle]) { + // eta_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().eta(); + // phi_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().phi(); + // } + + // if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Back]) { + // eta_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().eta(); + // phi_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().phi(); + // } + + + // for (int i = 0; i < numOfsampEM; ++i) { + // pExtraDetails->etaLooseTrkCaloSamp()[itr][i] = eta_extrapol[i]; + // pExtraDetails->phiLooseTrkCaloSamp()[itr][i] = phi_extrapol[i]; + // } + + // // in the past this was filled by tau1P3PTrackMatchCalo + // for (int i = 0; i < numOfsampEM; ++i) { + // pExtraDetails->etaTrkCaloSamp()[itr][i] = eta_extrapol[i]; + // pExtraDetails->phiTrkCaloSamp()[itr][i] = phi_extrapol[i]; + // } + + if (pTrk) delete pTrk; + + // XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet + // if (msgLvl(MSG::VERBOSE)) { //only if desired msg level is requested + // for (int i = 0; i < numOfsampEM; ++i) { + // ATH_MSG_VERBOSE(name() << " extrapolation for loose trk in samp : " << i + // << " track nr " << itr + // << " impact point eta " << pExtraDetails->etaLooseTrkCaloSamp()[itr][i] + // << " impact point phi " << pExtraDetails->phiLooseTrkCaloSamp()[itr][i] + // ); + // ATH_MSG_VERBOSE(name() << " extrapolation in samp : " << i + // << " track nr " << itr + // << " impact point eta " << pExtraDetails->etaTrkCaloSamp()[itr][i] + // << " impact point phi " << pExtraDetails->phiTrkCaloSamp()[itr][i] + // ); + // } + // } + + } + + return StatusCode::SUCCESS; + +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +void TauTrackFinder::removeOffsideTracksWrtLeadTrk(std::vector<const Rec::TrackParticle*> &tauTracks, + std::vector<const Rec::TrackParticle*> &wideTracks, + std::vector<const Rec::TrackParticle*> &otherTracks, + const Trk::RecVertex* tauOrigin, + double maxDeltaZ0) +{ + float MAX=1e5; + this->resetDeltaZ0Cache(); + + // need at least one core track to have a leading trk to compare with + if (tauTracks.size()<1) return; + + //check if position is available for origin + /** FIXME: This causes compilation error after eigen migration + if (tauOrigin) + if (!tauOrigin->position()) + tauOrigin = 0; + */ + + // get lead trk parameters + const Rec::TrackParticle *leadTrack = tauTracks.at(0); + float z0_leadTrk = getZ0(leadTrack, tauOrigin); + + if (z0_leadTrk > MAX-1) return; // bad lead trk -> do nothing + + ATH_MSG_VERBOSE("before z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size()); + + std::vector<const Rec::TrackParticle*>::iterator itr; + + // check core tracks + // skip leading track, because it is the reference + itr = tauTracks.begin()+1; + while (itr!=tauTracks.end()) { + float z0 = getZ0(*itr, tauOrigin); + float deltaZ0=z0 - z0_leadTrk; + + ATH_MSG_VERBOSE("core Trks: deltaZ0= " << deltaZ0); + m_vDeltaZ0coreTrks.push_back(deltaZ0); + + if ( fabs(deltaZ0) < maxDeltaZ0 ) {++itr;} + else { + if (m_storeInOtherTrks) otherTracks.push_back(*itr); + itr = tauTracks.erase(itr); //remove from core track collection + } + } + + // check wide tracks + itr = wideTracks.begin(); + while (itr!=wideTracks.end()) { + float z0 = getZ0(*itr, tauOrigin); + float deltaZ0=z0 - z0_leadTrk; + + ATH_MSG_VERBOSE("wide Trks: deltaZ0= " << deltaZ0); + m_vDeltaZ0wideTrks.push_back(deltaZ0); + + if ( fabs(deltaZ0) < maxDeltaZ0 ) { ++itr; } + else { + if (m_storeInOtherTrks) otherTracks.push_back(*itr); + itr = wideTracks.erase(itr); //remove from wide track collection + } + } + + ATH_MSG_VERBOSE("after z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size()); + + // sort again + std::sort(tauTracks.begin(), tauTracks.end(), TrackSort()); + std::sort(wideTracks.begin(), wideTracks.end(), TrackSort()); + std::sort(otherTracks.begin(), otherTracks.end(), TrackSort()); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +void TauTrackFinder::removeOffsideTracksWrtLeadTrk(std::vector<const xAOD::TrackParticle*> &tauTracks, + std::vector<const xAOD::TrackParticle*> &wideTracks, + std::vector<const xAOD::TrackParticle*> &otherTracks, + const xAOD::Vertex* tauOrigin, + double maxDeltaZ0) +{ + float MAX=1e5; + this->resetDeltaZ0Cache(); + + // need at least one core track to have a leading trk to compare with + if (tauTracks.size()<1) return; + + //check if position is available for origin + /** FIXME: This causes compilation error after eigen migration + if (tauOrigin) + if (!tauOrigin->position()) + tauOrigin = 0; + */ + + // get lead trk parameters + const xAOD::TrackParticle *leadTrack = tauTracks.at(0); + float z0_leadTrk = getZ0(leadTrack, tauOrigin); + + if (z0_leadTrk > MAX-1) return; // bad lead trk -> do nothing + + ATH_MSG_VERBOSE("before z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size()); + + std::vector<const xAOD::TrackParticle*>::iterator itr; + + // check core tracks + // skip leading track, because it is the reference + itr = tauTracks.begin()+1; + while (itr!=tauTracks.end()) { + float z0 = getZ0(*itr, tauOrigin); + float deltaZ0=z0 - z0_leadTrk; + + ATH_MSG_VERBOSE("core Trks: deltaZ0= " << deltaZ0); + m_vDeltaZ0coreTrks.push_back(deltaZ0); + + if ( fabs(deltaZ0) < maxDeltaZ0 ) {++itr;} + else { + if (m_storeInOtherTrks) otherTracks.push_back(*itr); + itr = tauTracks.erase(itr); //remove from core track collection + } + } + + // check wide tracks + itr = wideTracks.begin(); + while (itr!=wideTracks.end()) { + float z0 = getZ0(*itr, tauOrigin); + float deltaZ0=z0 - z0_leadTrk; + + ATH_MSG_VERBOSE("wide Trks: deltaZ0= " << deltaZ0); + m_vDeltaZ0wideTrks.push_back(deltaZ0); + + if ( fabs(deltaZ0) < maxDeltaZ0 ) { ++itr; } + else { + if (m_storeInOtherTrks) otherTracks.push_back(*itr); + itr = wideTracks.erase(itr); //remove from wide track collection + } + } + + ATH_MSG_VERBOSE("after z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size()); + + // sort again + std::sort(tauTracks.begin(), tauTracks.end(), TrackSort()); + std::sort(wideTracks.begin(), wideTracks.end(), TrackSort()); + std::sort(otherTracks.begin(), otherTracks.end(), TrackSort()); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +float TauTrackFinder::getZ0(const Rec::TrackParticle* track, const Trk::RecVertex* vertex) +{ + float MAX=1e5; + + if (!track) return MAX; + if (!track->measuredPerigee()->covariance()) { + ATH_MSG_WARNING("Bad track; can't find perigee at vertex."); + return MAX; + } + + const Trk::Perigee* perigee = 0; + if (vertex) perigee = m_trackToVertexTool->perigeeAtVertex(*track, vertex->position()); + else perigee = m_trackToVertexTool->perigeeAtVertex(*track); //will use beamspot or 0,0,0 instead + + if (!perigee) { + ATH_MSG_WARNING("Bad track; can't find perigee at vertex."); + return MAX; + } + + float z0 = perigee->parameters()[Trk::z0]; + + delete perigee; //cleanup necessary to prevent mem leak + + return z0; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +float TauTrackFinder::getZ0(const xAOD::TrackParticle* track, const xAOD::Vertex* vertex) +{ + float MAX=1e5; + + if (!track) return MAX; + + const Trk::Perigee* perigee = 0; + if (vertex) perigee = m_trackToVertexTool->perigeeAtVertex(*track, vertex->position()); + else perigee = m_trackToVertexTool->perigeeAtVertex(*track); //will use beamspot or 0,0,0 instead + + if (!perigee) { + ATH_MSG_WARNING("Bad track; can't find perigee at vertex."); + return MAX; + } + + float z0 = perigee->parameters()[Trk::z0]; + + delete perigee; //cleanup necessary to prevent mem leak + + return z0; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +void TauTrackFinder::getDeltaZ0Values(std::vector<float>& vDeltaZ0coreTrks, std::vector<float>& vDeltaZ0wideTrks) +{ + vDeltaZ0coreTrks.clear(); + vDeltaZ0coreTrks = m_vDeltaZ0coreTrks; + + vDeltaZ0wideTrks.clear(); + vDeltaZ0wideTrks = m_vDeltaZ0wideTrks; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +void TauTrackFinder::resetDeltaZ0Cache() +{ + m_vDeltaZ0coreTrks.clear(); + m_vDeltaZ0wideTrks.clear(); +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Helpers +template <class T> +bool TauTrackFinder::openContainer(T* &container, std::string containerName, bool printFATAL) { + StatusCode sc = evtStore()->retrieve(container, containerName); + if (sc.isFailure() || !container) { + if (printFATAL) ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate"); + return 0; + } + return container; +} + +template <class T> +bool TauTrackFinder::retrieveTool(T & tool) { + if (tool.retrieve().isFailure()) { + ATH_MSG_FATAL("Failed to retrieve tool " << tool); + return false; + } else { + ATH_MSG_VERBOSE("Retrieved tool " << tool); + } + return true; +} diff --git a/Reconstruction/tauRec/src/TauTrackSlimmer.cxx b/Reconstruction/tauRec/src/TauTrackSlimmer.cxx new file mode 100644 index 00000000000..5ae7b168557 --- /dev/null +++ b/Reconstruction/tauRec/src/TauTrackSlimmer.cxx @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTrackSlimmer.cxx +// package: Reconstruction/tauRec +// authors: Anna Kaczmarska, Lukasz Janyst +// +// This class builds Slim Track objects for taus in the AOD +// +// date: 2008-01-17 +// 15/04/2008 - (AK) fixing compilation warning bug #35463 +// 25/02/2009 - (AK) adding declareProperty thinSvc +// 22/01/2010 - (AK) adding protection against size 0 track collection +//----------------------------------------------------------------------------- + +#include "tauRec/TauTrackSlimmer.h" + +#include "tauEvent/TauJetContainer.h" +#include "tauEvent/TauJet.h" +#include "tauEvent/TauCommonDetails.h" + +#include "GaudiKernel/ListItem.h" +#include <cmath> + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +TauTrackSlimmer::TauTrackSlimmer( const std::string &name, + ISvcLocator * pSvcLocator ) : + AthAlgorithm( name, pSvcLocator ), + m_thinningSvc( "ThinningSvc", name ), + m_filterTaus(false), + m_maxNTrack(4), + m_maxCharge(2), + m_maxEmRadius(0.2), + m_maxIsoFrac(0.5) +{ + // Name of the thinningSvc + declareProperty( "thinSvc", m_thinningSvc, "Name of the thinningSvc" ); + declareProperty( "TauContainer", m_tauContainerName ); + declareProperty( "FilterTaus", m_filterTaus ); + declareProperty( "maxNTrack", m_maxNTrack ); + declareProperty( "maxCharge", m_maxCharge ); + declareProperty( "maxEmRadius", m_maxEmRadius ); + declareProperty( "maxIsoFrac", m_maxIsoFrac ); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +TauTrackSlimmer::~TauTrackSlimmer() +{ +} + +//----------------------------------------------------------------------------- +// Initialiezer +//----------------------------------------------------------------------------- +StatusCode TauTrackSlimmer::initialize() +{ + + ATH_MSG_VERBOSE( "TauTrackSlimmer :: initialize()" ); + + /* + sc = service( "StoreGateSvc", evtStore() ); + if( sc.isFailure() ) + { + log << MSG :: ERROR; + log << "Unable to retrieve pointer to StoreGateSvc"; + log ); + return StatusCode :: FAILURE; + } + */ + if ( m_thinningSvc.retrieve().isFailure() ) + { + ATH_MSG_ERROR( "Unable to retrieve pointer to IThinningSvc" ); + return StatusCode :: FAILURE; + } + return StatusCode :: SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauTrackSlimmer :: finalize() +{ + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauTrackSlimmer::execute() +{ + using namespace Analysis; + + StatusCode sc; + + //--------------------------------------------------------------------------- + // Retrieve tau jet container + //--------------------------------------------------------------------------- + const Analysis::TauJetContainer *tauContainer; + sc = evtStore()->retrieve( tauContainer, m_tauContainerName ); + + if( sc.isFailure() || ! tauContainer ) + { + ATH_MSG_DEBUG( "No tau container found!" ); + return StatusCode :: SUCCESS; + } + + //--------------------------------------------------------------------------- + // Retrieve track container + //--------------------------------------------------------------------------- + const TrackCollection* tracks = 0; + sc = evtStore()->retrieve( tracks, "Tracks" ); + + if( sc.isFailure() || !tracks ){ + ATH_MSG_WARNING( "No track container found in TDS" ); + return StatusCode :: SUCCESS; + } + + if(tracks->size() == 0){ + ATH_MSG_DEBUG( "empty track container found in TDS" ); + return StatusCode :: SUCCESS; + } + + //--------------------------------------------------------------------------- + // Initialize vector of bools + //--------------------------------------------------------------------------- + std::vector<bool> selected; + selected.resize( tracks->size(), false ); + + //--------------------------------------------------------------------------- + // Initialize iterators + //--------------------------------------------------------------------------- + Analysis::TauJetContainer :: const_iterator ftau = tauContainer->begin(); + Analysis::TauJetContainer :: const_iterator etau = tauContainer->end(); + + //--------------------------------------------------------------------------- + // Loop over taus + //--------------------------------------------------------------------------- + + for(; ftau != etau; ++ftau ) + { + + const Analysis::TauCommonDetails* p_taudetails = (*ftau)->details<const Analysis::TauCommonDetails>(); + + if (m_filterTaus) { + + if ((*ftau)->numTrack() > m_maxNTrack) continue; + if (std::abs((*ftau)->charge()) > m_maxCharge) continue; + if ( p_taudetails) { + if (p_taudetails->seedCalo_EMRadius() > m_maxEmRadius) continue; + if (p_taudetails->seedCalo_isolFrac() > m_maxIsoFrac) continue; + } + + } + + for( unsigned itr = 0; itr < (*ftau)->numTrack(); ++itr ) + selected[(*ftau)->track(itr)->trackElementLink()->index()] = true; + } + + + + //--------------------------------------------------------------------------- + // Invoke the thinning service + //--------------------------------------------------------------------------- + sc = m_thinningSvc->filter( *tracks, selected, IThinningSvc :: Operator :: Or ); + if( sc.isFailure() ) + { + ATH_MSG_ERROR( "Failed to thin Tracks associated to taus" ); + return StatusCode :: SUCCESS; + } + + return StatusCode :: SUCCESS; +} diff --git a/Reconstruction/tauRec/src/TauVertexFinder.cxx b/Reconstruction/tauRec/src/TauVertexFinder.cxx new file mode 100644 index 00000000000..ae95c3f0367 --- /dev/null +++ b/Reconstruction/tauRec/src/TauVertexFinder.cxx @@ -0,0 +1,216 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "tauRec/TauVertexFinder.h" + +#include "VxVertex/RecVertex.h" +#include "VxVertex/VxCandidate.h" + +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/Vertex.h" + +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODTau/TauJet.h" + +TauVertexFinder::TauVertexFinder(const std::string& type, + const std::string& name, + const IInterface* parent) : +TauToolBase(type, name, parent), +m_printMissingContainerINFO(true), +m_maxJVF(-100.), +m_assocTracksName(""), +m_trackVertexAssocName("") +{ + declareInterface<TauToolBase > (this); + declareProperty("UseTJVA", m_useTJVA=true); + declareProperty("PrimaryVertexContainer", m_inputPrimaryVertexContainerName = "PrimaryVertices"); + declareProperty("AssociatedTracks",m_assocTracksName); + declareProperty("TrackVertexAssociation",m_trackVertexAssocName); +} + +TauVertexFinder::~TauVertexFinder() { +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauVertexFinder::initialize() { + if (m_useTJVA) ATH_MSG_INFO("using TJVA to determine tau vertex"); + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauVertexFinder::finalize() { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauVertexFinder::eventInitialize(TauCandidateData*) { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauVertexFinder::eventFinalize(TauCandidateData*) { + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +StatusCode TauVertexFinder::execute(TauCandidateData * data) { + + xAOD::TauJet *tauJet = data->xAODTau; + + // get the primary vertex container from StoreGate + //do it here because of tau trigger + const xAOD::VertexContainer* vxContainer = 0; + const xAOD::Vertex* primaryVertex = 0; + + StatusCode sc; + //for tau trigger + sc = data->getObject("VxPrimaryCandidate", vxContainer); + + if (sc.isFailure() || !vxContainer) { //not in trigger mode or no vxContainer was set by trigger + ATH_MSG_DEBUG("no VxPrimaryCandidateContainer for trigger -> try standard way"); + if (!openContainer(vxContainer, m_inputPrimaryVertexContainerName)) { + if (m_printMissingContainerINFO) { + ATH_MSG_INFO(m_inputPrimaryVertexContainerName << " container not found --> skip TauVertexFinder (no further info)"); + m_printMissingContainerINFO=false; + } + return StatusCode::SUCCESS; + } + + // find default PrimaryVertex (needed if TJVA is switched off or fails) + // see: https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/VertexReselectionOnAOD + // code adapted from + // https://svnweb.cern.ch/trac/atlasoff/browser/Tracking/TrkEvent/VxVertex/trunk/VxVertex/PrimaryVertexSelector.h + if (vxContainer->size()>0) { + // simple loop through and get the primary vertex + xAOD::VertexContainer::const_iterator vxIter = vxContainer->begin(); + xAOD::VertexContainer::const_iterator vxIterEnd = vxContainer->end(); + for ( size_t ivtx = 0; vxIter != vxIterEnd; ++vxIter, ++ivtx ){ + // the first and only primary vertex candidate is picked + if ( (*vxIter)->vertexType() == xAOD::VxType::PriVtx){ + primaryVertex = (*vxIter); + break; + } + } + } + } + else { // trigger mode + // find default PrimaryVertex (highest sum pt^2) + if (vxContainer->size()>0) primaryVertex = (*vxContainer)[0]; + } + + ATH_MSG_VERBOSE("size of VxPrimaryContainer is: " << vxContainer->size() ); + + // associate vertex to tau + if (primaryVertex) tauJet->setVertex(vxContainer, primaryVertex); + + //stop here if TJVA is disabled or vertex container is empty + if (!m_useTJVA || vxContainer->size()==0) return StatusCode::SUCCESS; + + // try to find new PV with TJVA + ATH_MSG_DEBUG("TJVA enabled -> try to find new PV for the tau candidate"); + + ElementLink<xAOD::VertexContainer> newPrimaryVertexLink = getPV_TJVA(tauJet, vxContainer ); + if (newPrimaryVertexLink.isValid()) { + // set new primary vertex + // will overwrite default one which was set above + tauJet->setVertexLink(newPrimaryVertexLink); + // save highest JVF value + tauJet->setDetail(xAOD::TauJetParameters::TauJetVtxFraction,static_cast<float>(m_maxJVF)); + ATH_MSG_DEBUG("TJVA vertex found and set"); + } + else { + ATH_MSG_DEBUG("couldn't find new PV for TJVA"); + } + + return StatusCode::SUCCESS; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +ElementLink<xAOD::VertexContainer> TauVertexFinder::getPV_TJVA(const xAOD::TauJet* pTau, const xAOD::VertexContainer* vertices) +{ + const xAOD::Jet* pJetSeed = (*pTau->jetLink()); + + // the implementation follows closely the example given in modifyJet(...) in https://svnweb.cern.ch/trac/atlasoff/browser/Reconstruction/Jet/JetMomentTools/trunk/Root/JetVertexFractionTool.cxx#15 + + // Get the tracks associated to the jet + std::vector<const xAOD::TrackParticle*> assocTracks; + if (! pJetSeed->getAssociatedObjects(m_assocTracksName, assocTracks)) { + ATH_MSG_ERROR("Could not retrieve the AssociatedObjects named \""<< m_assocTracksName <<"\" from jet"); + return ElementLink<xAOD::VertexContainer>(); + } + + // Get the TVA object + const jet::TrackVertexAssociation* tva = NULL; + if (evtStore()->retrieve(tva,m_trackVertexAssocName).isFailure()) { + ATH_MSG_ERROR("Could not retrieve the TrackVertexAssociation from evtStore: " << m_trackVertexAssocName); + return ElementLink<xAOD::VertexContainer>(); + } + + // Calculate Jet Vertex Fraction + std::vector<float> jvf; + jvf.resize(vertices->size()); + for (size_t iVertex = 0; iVertex < vertices->size(); ++iVertex) { + jvf.at(iVertex) = getJetVertexFraction(vertices->at(iVertex),assocTracks,tva); + } + + // Get the highest JVF vertex and store maxJVF for later use + // Note: the official JetMomentTools/JetVertexFractionTool doesn't provide any possibility to access the JVF value, but just the vertex. + m_maxJVF=-100.; + size_t maxIndex = 0; + for (size_t iVertex = 0; iVertex < jvf.size(); ++iVertex) { + if (jvf.at(iVertex) > m_maxJVF) { + m_maxJVF = jvf.at(iVertex); + maxIndex = iVertex; + } + } + + // Set the highest JVF vertex + ElementLink<xAOD::VertexContainer> vtxlink = ElementLink<xAOD::VertexContainer>(*vertices,vertices->at(maxIndex)->index()); + + return vtxlink; +} + +// reimplementation of JetVertexFractionTool::getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const +// avoid to call this specific tool only for this easy purpose +// see https://svnweb.cern.ch/trac/atlasoff/browser/Reconstruction/Jet/JetMomentTools/trunk/Root/JetVertexFractionTool.cxx +float TauVertexFinder::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) { // C++11 feature + if (ptvtx->index() == vertex->index()) sumTrackPV += track->pt(); + } + sumTrackAll += track->pt(); + + } + return sumTrackAll!=0 ? sumTrackPV/sumTrackAll : 0; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// Helpers +template <class T> +bool TauVertexFinder::openContainer(T* &container, std::string containerName, bool printFATAL) { + StatusCode sc = evtStore()->retrieve(container, containerName); + if (sc.isFailure() || !container) { + if (printFATAL) ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate"); + return 0; + } + return container; +} + +template <class T> +bool TauVertexFinder::retrieveTool(T & tool) { + if (tool.retrieve().isFailure()) { + ATH_MSG_FATAL("Failed to retrieve tool " << tool); + return false; + } else { + ATH_MSG_VERBOSE("Retrieved tool " << tool); + } + return true; +} diff --git a/Reconstruction/tauRec/src/TauVertexVariables.cxx b/Reconstruction/tauRec/src/TauVertexVariables.cxx new file mode 100644 index 00000000000..c0235b1b7b9 --- /dev/null +++ b/Reconstruction/tauRec/src/TauVertexVariables.cxx @@ -0,0 +1,327 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "Particle/TrackParticle.h" +#include "Particle/TrackParticleContainer.h" +#include "TrkParameters/TrackParameters.h" + +#include "xAODTracking/TrackParticleContainer.h" + +#include "TrkVertexFitterInterfaces/ITrackToVertexIPEstimator.h" +#include "TrkVertexFitterInterfaces/IVertexFitter.h" +#include "TrkVertexFitterInterfaces/IVertexSeedFinder.h" +#include "TrkVertexFitters/AdaptiveVertexFitter.h" +#include "TrkVxEdmCnv/IVxCandidateXAODVertex.h" +#include "TrkLinks/LinkToXAODTrackParticle.h" + +#include "tauRec/TauCandidateData.h" +#include "tauRec/TauVertexVariables.h" + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- + +TauVertexVariables::TauVertexVariables(const std::string &type, + const std::string &name, + const IInterface *parent) : + TauToolBase(type, name, parent), + m_primaryVertexKey("PrimaryVertices"), + m_useOldSeedFinderAPI(false), + m_fitTool("Trk::AdaptiveVertexFitter"), + m_SeedFinder("Trk::CrossDistancesSeedFinder"), + m_xaodConverter("Trk::VxCandidateXAODVertex"), + m_pSecVtxContainer(0), + m_pSecVtxAuxContainer(0){ + declareInterface<TauToolBase > (this); + declareProperty("PrimaryVertexKey", m_primaryVertexKey); + declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles"); + declareProperty("TrackToVertexIPEstimator", m_trackToVertexIPEstimator); + declareProperty("VertexFitter", m_fitTool); + declareProperty("SeedFinder", m_SeedFinder); + declareProperty("XAODConverter",m_xaodConverter); + declareProperty("useOldSeedFinderAPI",m_useOldSeedFinderAPI); +} + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- + +TauVertexVariables::~TauVertexVariables() { +} + + +//----------------------------------------------------------------------------- +// Initializer +//----------------------------------------------------------------------------- + +StatusCode TauVertexVariables::initialize() { + CHECK( m_trackToVertexIPEstimator.retrieve() ); + CHECK( m_fitTool.retrieve() ); + CHECK( m_SeedFinder.retrieve() ); + if (m_useOldSeedFinderAPI) CHECK( m_xaodConverter.retrieve() ); + + if (m_useOldSeedFinderAPI) { + ATH_MSG_INFO("using AOD-style API of the AdaptiveVertexFitter"); + } + else { + ATH_MSG_INFO("using new xAOD-style API of the AdaptiveVertexFitter"); + } + + return StatusCode::SUCCESS; +} + +StatusCode TauVertexVariables::eventInitialize(TauCandidateData * data) { + + StatusCode sc; + bool inTrigger = false; + if (data->hasObject("InTrigger?")) + sc = data->getObject("InTrigger?", inTrigger); + + // Only store the vertex containers if we are offline? + if(!sc.isSuccess() || !inTrigger) + { + // Secondary Vertex Container for tau decay vertex + m_pSecVtxContainer = new xAOD::VertexContainer(); + m_pSecVtxAuxContainer = new xAOD::VertexAuxContainer(); + m_pSecVtxContainer->setStore( m_pSecVtxAuxContainer ); + + CHECK( evtStore()->record( m_pSecVtxContainer, "TauSecondaryVertexContainer" ) ); + CHECK( evtStore()->record( m_pSecVtxAuxContainer, "TauSecondaryVertexContainerAux." ) ); + } + + return StatusCode::SUCCESS; +} + + + +//----------------------------------------------------------------------------- +// Finalizer +//----------------------------------------------------------------------------- +StatusCode TauVertexVariables::finalize() { + return StatusCode::SUCCESS; +} + + +//----------------------------------------------------------------------------- +// Execution +//----------------------------------------------------------------------------- +StatusCode TauVertexVariables::execute(TauCandidateData *data) { + + ATH_MSG_DEBUG("executing TauVertexVariables"); + + xAOD::TauJet *pTau = data->xAODTau; + + if (pTau == NULL) { + ATH_MSG_ERROR("no candidate given"); + return StatusCode::FAILURE; + } + + // impact parameter variables for standard tracks + if (pTau->nTracks() > 0) { + const Trk::ImpactParametersAndSigma * myIPandSigma(0); + + if (pTau->vertexLink()) { + const xAOD::Vertex* vxcand = *(pTau->vertexLink()) ; + //check if vertex has a valid type (skip if vertex has type NoVtx) + if (vxcand->vertexType() > 0) { + myIPandSigma = m_trackToVertexIPEstimator->estimate(pTau->track(0), *pTau->vertexLink()); + } + } + + if (myIPandSigma != 0) { + pTau->setDetail(xAOD::TauJetParameters::ipSigLeadTrk, (float)( myIPandSigma->IPd0 / myIPandSigma->sigmad0 )); + pTau->setDetail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, (float)( myIPandSigma->IPz0SinTheta / myIPandSigma->sigmaz0SinTheta )); + } else { + ATH_MSG_DEBUG("trackToVertexIPestimator failed for a standard track!"); + pTau->setDetail(xAOD::TauJetParameters::ipSigLeadTrk, (float)(-999.)); + pTau->setDetail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, (float)(-999.)); + } + delete myIPandSigma; + } + + float ipSigLeadTrk; + float ipZ0SinThetaSigLeadTrk; + + if (pTau->detail(xAOD::TauJetParameters::ipSigLeadTrk, ipSigLeadTrk)) + ATH_MSG_VERBOSE("IP significance lead track " << ipSigLeadTrk); + if (pTau->detail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, ipZ0SinThetaSigLeadTrk)) + ATH_MSG_VERBOSE("IP Z0 significance lead track " << ipZ0SinThetaSigLeadTrk); + + //try to find secondary vertex + //look for secondary vertex if more than 1 track + pTau->setDetail(xAOD::TauJetParameters::trFlightPathSig, (float)(-1111.)); + if (pTau->nTracks() < 2) { + return StatusCode::SUCCESS; + } + + // for tau trigger + bool inTrigger = false; + StatusCode sc; + if (data->hasObject("InTrigger?")) sc = data->getObject("InTrigger?", inTrigger); + + const xAOD::VertexContainer* vxContainer = 0; + if (sc.isSuccess() && inTrigger) sc = data->getObject("VxPrimaryCandidate", vxContainer); + // retrieve vertex container, exit if not found + else sc = evtStore()->retrieve(vxContainer, m_primaryVertexKey); + + if (sc.isFailure() || !vxContainer) { + ATH_MSG_WARNING("No vertex container found. Skipping secondary vertex fitting."); + return StatusCode::SUCCESS; + } + + const xAOD::TrackParticleContainer* trackParticleCont = 0; + if (inTrigger) sc = data->getObject( "TrackContainer", trackParticleCont ); + // retrieve track particle container, exit if not found + else sc = evtStore()->retrieve(trackParticleCont, m_inputTrackParticleContainerName); + if (sc.isFailure() || !trackParticleCont) { + ATH_MSG_WARNING("No track particle container found. Skipping secondary vertex fitting."); + return StatusCode::SUCCESS; + } + + // get xAOD TrackParticles and Trk::Tracks + std::vector<const xAOD::TrackParticle*> xaodTracks; + std::vector<const Trk::Track*> origTracks; + for (unsigned i = 0; i < pTau->nTracks(); ++i) { + xaodTracks.push_back(pTau->track(i)); + ATH_MSG_VERBOSE("xAOD::TrackParticle " <<i<<": "<< pTau->track(i)->pt() << " " << pTau->track(i)->eta() << " " << pTau->track(i)->phi()); + if (pTau->track(i)->track()) { + origTracks.push_back(pTau->track(i)->track()); + + // for debugging + /* + ATH_MSG_DEBUG("Trk::Track " <<i<<": "<< (*pTau->track(i)->track())->pt() << " " << (*pTau->track(i)->track())->eta() << " " << (*pTau->track(i)->track())->phi()); + const Trk::TrackParameters * tmpMeasPer = (*pTau->track(i)->track())->perigeeParameters(); + const AmgSymMatrix(5)* cov = tmpMeasPer->covariance(); + ATH_MSG_DEBUG(" TrackParameters: pT="<< tmpMeasPer->pT() << ", eta=" << tmpMeasPer->eta() << ", x=" << tmpMeasPer->position().x() << ", y="<< tmpMeasPer->position().y() <<", z="<< tmpMeasPer->position().z()); + ATH_MSG_DEBUG(" covariance ="<< *cov); + */ + // for debugging + } + else { + ATH_MSG_WARNING("no Trk::Track for xAOD::TrackParticle"); + } + } + + // get the starting point for the fit using Trk::Tracks + Trk::Vertex* seedPoint = new Trk::Vertex(m_SeedFinder->findSeed(origTracks)); + ATH_MSG_VERBOSE("seedPoint x/y/perp=" << seedPoint->position().x() << " "<< seedPoint->position().y() << " "<< seedPoint->position().perp()); + if (!seedPoint) { + ATH_MSG_WARNING("no seedPoint: Can not calculate secondary vertex!"); + return StatusCode::SUCCESS; + } + + // fitting the vertex itself + xAOD::Vertex* xAODvertex(0); + if (!m_useOldSeedFinderAPI) { // use new xAOD API of VertexFitter + xAODvertex = m_fitTool->fit(xaodTracks, *seedPoint); + if (xAODvertex && !inTrigger) { + ATH_MSG_VERBOSE("using new xAOD API: Secondary Vertex found and recorded! x="<<xAODvertex->position().x()<< ", y="<<xAODvertex->position().y()<<", perp="<<xAODvertex->position().perp()); + m_pSecVtxContainer->push_back(xAODvertex); + } + } + else { // use standard AOD-style API of VertexFitter + Trk::VxCandidate* tmpVxCandidate = m_fitTool->fit(origTracks, *seedPoint); + if (tmpVxCandidate) { + ATH_MSG_VERBOSE("using old AOD API:Secondary Vertex found and recorded! x="<<tmpVxCandidate->recVertex().position().x()<< ", y="<<tmpVxCandidate->recVertex().position().y()<<", perp="<<tmpVxCandidate->recVertex().position().perp()); + + //****************************************************************** + // convert VxCandidate to xAOD::Vertex + //****************************************************************** + + // assigning the input xAOD tracks to the fitted vertex + // this means: after that procedure the Trk::VxCandidate knows already the links to the xAOD tracks (which have to be identical with the Trk:Tracks used in the VertexFitter!) + // this is needed for the converting, otherwise the new xAODVertex don't have the track links + if(tmpVxCandidate->vxTrackAtVertex() != 0 && tmpVxCandidate->vxTrackAtVertex()->size() !=0) { + for(unsigned int i = 0; i <xaodTracks.size(); ++i) { + Trk::LinkToXAODTrackParticle * linkTT = new Trk::LinkToXAODTrackParticle; + linkTT->setElement(xaodTracks[i]); + linkTT->setStorableObject(*trackParticleCont); + // vxtrackatvertex takes ownership! + (*(tmpVxCandidate->vxTrackAtVertex()))[i]->setOrigTrack(linkTT); + } + } + + xAODvertex = new xAOD::Vertex(); + if (!inTrigger) m_pSecVtxContainer->push_back(xAODvertex); + // perform the final converting now + if( m_xaodConverter->createXAODVertex(*tmpVxCandidate,xAODvertex).isFailure() ) { + ATH_MSG_ERROR("Failed to create xAODVertex for VxCandidate. Don't set any secondary vertex for tau!"); + return StatusCode::SUCCESS; + } + delete tmpVxCandidate; + } + } + delete seedPoint; + + if (!xAODvertex) { + ATH_MSG_WARNING("no secondary vertex found!"); + return StatusCode::SUCCESS; + } + + // get the transverse flight path significance + float trFlightPS = trFlightPathSig(data, xAODvertex); + pTau->setDetail(xAOD::TauJetParameters::trFlightPathSig, (float)(trFlightPS)); + ATH_MSG_VERBOSE("transverse flight path significance="<<trFlightPS); + + // Note, we only attach the 2nd vertex if at offline, otherwise, break the trigger persistency + if (!inTrigger) { + pTau->setSecondaryVertex(m_pSecVtxContainer, xAODvertex); // set the link to the vertex + } + else { + delete xAODvertex; // delete the vertex when in trigger mode, because we can not save it + } + + return StatusCode::SUCCESS; +} + +//------------------------------------------------------------------------- +// calculate the transverse flight path significance +//------------------------------------------------------------------------- +double TauVertexVariables::trFlightPathSig(TauCandidateData *data, const xAOD::Vertex *secVertex) { + + const xAOD::TauJet *pTau = data->xAODTau; + + if (!secVertex) { + ATH_MSG_WARNING("No secondary vertex information for calculation of transverse flight path significance"); + return -11111.; + } + + const xAOD::Vertex* pVertex = 0; + if (pTau->vertexLink()) pVertex = *pTau->vertexLink(); + if (!pVertex) { + ATH_MSG_WARNING("No primary vertex information for calculation of transverse flight path significance"); + return -11111.; + } + + double fpx = secVertex->position().x() - pVertex->position().x(); + double fpy = secVertex->position().y() - pVertex->position().y(); + double fpt = (secVertex->position() - pVertex->position()).perp(); + + if (fpt == 0) { + ATH_MSG_WARNING("delta pt of (secVtx - priVtx) is 0!"); + return -11111.; + } + + double sigma_fpt2 = (fpx * fpx * secVertex->covariancePosition()(Trk::x, Trk::x) + + fpx * fpy * secVertex->covariancePosition()(Trk::x, Trk::y) + + fpy * fpx * secVertex->covariancePosition()(Trk::y, Trk::x) + + fpy * fpy * secVertex->covariancePosition()(Trk::y, Trk::y)) / (fpt * fpt); + + if (sigma_fpt2 <= 0) { + ATH_MSG_WARNING("sigma delta pt of (secVtx - priVtx) is 0!"); + return -11111.; + } + + double sigma_fpt = sqrt(sigma_fpt2); + double sign = 0; + + if (fpx * pTau->p4().Px() + fpy * pTau->p4().Py() > 0.) sign = 1.; + else sign = -1.; + + //ATH_MSG_INFO(sign << " " <<fpt << " " << sigma_fpt << " " << sign * fpt / sigma_fpt); + return sign * fpt / sigma_fpt; +} + diff --git a/Reconstruction/tauRec/src/components/tauRec_entries.cxx b/Reconstruction/tauRec/src/components/tauRec_entries.cxx new file mode 100755 index 00000000000..e4171128090 --- /dev/null +++ b/Reconstruction/tauRec/src/components/tauRec_entries.cxx @@ -0,0 +1,116 @@ +#include "tauRec/TauBuilder.h" +#include "tauRec/JetSeedBuilder.h" +#include "tauRec/LockTauContainers.h" +#include "tauRec/TauAxisSetter.h" +#include "tauRec/TauCalibrateEM.h" +#include "tauRec/TauCalibrateLC.h" +#include "tauRec/TauCellVariables.h" +//#include "tauRec/TauOriginCorrectionTool.h" +#include "tauRec/TauProcessor.h" +#include "tauRec/TauTrackFinder.h" +#include "tauRec/TauVertexFinder.h" +#include "tauRec/TauElectronVetoVariables.h" +//#include "tauRec/TauPi0EflowCreateROI.h" +#include "tauRec/TauCommonCalcVars.h" +//#include "tauRec/TauEflowAddCaloInfo.h" +//#include "tauRec/TauEflowTrackMatchCells.h" +//#include "tauRec/TauEflowVariables.h" +#include "tauRec/TauShotFinder.h" +#include "tauRec/TauPi0BonnClusterCreator.h" +#include "tauRec/TauPi0BonnCreateROI.h" +#include "tauRec/TauPi0BonnScoreCalculator.h" +#include "tauRec/TauPi0BonnSelector.h" +//#include "tauRec/TauPi0CrakowClusterCreator.h" +//#include "tauRec/TauPi0CreatorChooser.h" +#include "tauRec/TauSubstructureVariables.h" +#include "tauRec/TauConversionFinder.h" +#include "tauRec/PhotonConversionPID.h" +#include "tauRec/PhotonConversionVertex.h" +#include "tauRec/TauConversionTagger.h" +#include "tauRec/TauVertexVariables.h" +#include "tauRec/tauCalibrateWeightTool.h" //for trigger +#include "tauRec/TauTrackSlimmer.h" +#include "tauRec/TauTrackFilter.h" +#include "tauRec/TauGenericPi0Cone.h" +#include "tauRec/TauTestDump.h" + + + +#include "GaudiKernel/DeclareFactoryEntries.h" + +DECLARE_ALGORITHM_FACTORY( TauBuilder ) +DECLARE_ALGORITHM_FACTORY( TauProcessor ) +DECLARE_TOOL_FACTORY( JetSeedBuilder ) +DECLARE_TOOL_FACTORY( LockTauContainers ) +DECLARE_TOOL_FACTORY( TauAxisSetter ) +DECLARE_TOOL_FACTORY( TauCalibrateEM ) +DECLARE_TOOL_FACTORY( TauCalibrateLC ) +DECLARE_TOOL_FACTORY( TauCellVariables ) +//DECLARE_TOOL_FACTORY( TauOriginCorrectionTool ) +DECLARE_TOOL_FACTORY( TauTrackFinder ) +DECLARE_TOOL_FACTORY( TauVertexFinder ) +DECLARE_TOOL_FACTORY( TauElectronVetoVariables ) +//DECLARE_TOOL_FACTORY( TauPi0EflowCreateROI ) +DECLARE_TOOL_FACTORY( TauCommonCalcVars ) +//DECLARE_TOOL_FACTORY( TauEflowAddCaloInfo ) +//DECLARE_TOOL_FACTORY( TauEflowTrackMatchCells ) +//DECLARE_TOOL_FACTORY( TauEflowVariables ) +DECLARE_TOOL_FACTORY( TauShotFinder ) +DECLARE_TOOL_FACTORY( TauPi0BonnClusterCreator ) +DECLARE_TOOL_FACTORY( TauPi0BonnCreateROI ) +DECLARE_TOOL_FACTORY( TauPi0BonnScoreCalculator ) +DECLARE_TOOL_FACTORY( TauPi0BonnSelector ) +//DECLARE_TOOL_FACTORY( TauPi0CrakowClusterCreator ) +//DECLARE_TOOL_FACTORY( TauPi0CreatorChooser ) +DECLARE_TOOL_FACTORY( TauSubstructureVariables ) +DECLARE_TOOL_FACTORY( PhotonConversionPID ) +DECLARE_TOOL_FACTORY( PhotonConversionVertex ) +DECLARE_TOOL_FACTORY( TauConversionFinder ) +DECLARE_TOOL_FACTORY( TauConversionTagger ) +DECLARE_TOOL_FACTORY( TauVertexVariables ) +DECLARE_TOOL_FACTORY( tauCalibrateWeightTool ) +DECLARE_TOOL_FACTORY( TauTrackFilter ) +DECLARE_TOOL_FACTORY( TauGenericPi0Cone ) +DECLARE_TOOL_FACTORY( TauTestDump ) +DECLARE_ALGORITHM_FACTORY( TauTrackSlimmer ) + + +DECLARE_FACTORY_ENTRIES(tauRec) { + DECLARE_ALGORITHM(TauBuilder) + DECLARE_ALGORITHM(TauProcessor) + DECLARE_TOOL(JetSeedBuilder) + DECLARE_TOOL(LockTauContainers) + DECLARE_TOOL(TauAxisSetter) + DECLARE_TOOL(TauCalibrateEM) + DECLARE_TOOL(TauCalibrateLC) + DECLARE_TOOL(TauCellVariables) + //DECLARE_TOOL(TauOriginCorrectionTool) + DECLARE_TOOL(TauTrackFinder) + DECLARE_TOOL(TauVertexFinder) + DECLARE_TOOL( TauElectronVetoVariables ) + //DECLARE_TOOL( TauPi0EflowCreateROI ) + DECLARE_TOOL( TauCommonCalcVars ) + //DECLARE_TOOL( TauEflowAddCaloInfo ) + //DECLARE_TOOL( TauEflowTrackMatchCells ) + //DECLARE_TOOL( TauEflowVariables ) + DECLARE_TOOL( TauShotFinder ) + DECLARE_TOOL( TauPi0BonnClusterCreator ) + DECLARE_TOOL( TauPi0BonnCreateROI ) + DECLARE_TOOL( TauPi0BonnScoreCalculator ) + DECLARE_TOOL( TauPi0BonnSelector ) + //DECLARE_TOOL( TauPi0CrakowClusterCreator ) + //DECLARE_TOOL( TauPi0CreatorChooser ) + DECLARE_TOOL( TauSubstructureVariables ) + DECLARE_TOOL( PhotonConversionPID ) + DECLARE_TOOL( PhotonConversionVertex ) + DECLARE_TOOL( TauConversionFinder ) + DECLARE_TOOL( TauConversionTagger ) + DECLARE_TOOL( TauVertexVariables ) + DECLARE_TOOL( tauCalibrateWeightTool ) + DECLARE_TOOL( TauTestDump ) + DECLARE_ALGORITHM( TauTrackSlimmer ) +/* + DECLARE_ALGORITHM( TauTrackSlimmer ) + DECLARE_ALGORITHM( TauAODDetailsCleaner ) + */ +} diff --git a/Reconstruction/tauRec/src/components/tauRec_load.cxx b/Reconstruction/tauRec/src/components/tauRec_load.cxx new file mode 100755 index 00000000000..84f141f2296 --- /dev/null +++ b/Reconstruction/tauRec/src/components/tauRec_load.cxx @@ -0,0 +1,6 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(tauRec) + + + diff --git a/Reconstruction/tauRec/src/tauCalibrateWeightTool.cxx b/Reconstruction/tauRec/src/tauCalibrateWeightTool.cxx new file mode 100644 index 00000000000..c3dff174ba0 --- /dev/null +++ b/Reconstruction/tauRec/src/tauCalibrateWeightTool.cxx @@ -0,0 +1,395 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/******************************************************************** +(depreciated!) + +NAME: tauCalibrateWeightTool.cxx +PACKAGE: offline/Reconstruction/tauRec + +AUTHORS: M.Heldmann +CREATED: March 22, 2005 +MODIFIED: July 15, 2005 ( Include pT dependent correction ) +23/10/2006 - (AK) fixing some compilation warnings (unused parameter) +18/04/2007 - (AK) fixing some compilation warnings (unused parameter) +29/06/2007 - (SL) fixing some compilation warnings +13/12/2008 - (AK) change to extrapolation of TP instead of Track+code cleaning +16/03/2010 - (AK) use the cell id instead of the pointer +17/03/2010 - (AK) change to P4Helpers +14/12/2011 - (FF) change to use tau axis and numTrack (not seedCalo_) + ********************************************************************/ +#include "tauRec/TauCandidateData.h" +#include "tauEvent/TauCommonDetails.h" +#include "CaloEvent/CaloCluster.h" +#include "CaloEvent/CaloCell.h" +#include "AtlasDetDescr/AtlasDetectorID.h" +#include "CaloIdentifier/CaloID.h" +#include "CaloGeoHelpers/CaloSampling.h" + +#include "CLHEP/Units/SystemOfUnits.h" + +// INCLUDE GAUDI HEADER FILES: +#include "GaudiKernel/Property.h" +#include "AIDA/IHistogram1D.h" + +#include <algorithm> +#include <math.h> + +#include "FourMomUtils/P4Helpers.h" +#include "FourMom/P4EEtaPhiM.h" + +#include "CaloInterface/IHadronicCalibrationTool.h" +#include "TF1.h" + +#include "tauRec/tauCalibrateWeightTool.h" +/********************************************************************/ + +tauCalibrateWeightTool::tauCalibrateWeightTool(const std::string& type, + const std::string& name, + const IInterface* parent): + TauToolBase( type, name, parent ), + m_calibrateType( tauCalibrateWeightTool::calCells ), + m_caloWeightTool(this), + m_cellWeightTool("CellWeightTool2004"), + m_applyCellWeightEM(true), + m_applyCellWeightHad(true), + m_applyPtEtaCorrFactors(true), + m_validCaloWeightTool(true), + m_doEtaInterpolation(false), + m_cellCone(0.4) +{ + declareInterface<TauToolBase>( this ); + + declareProperty( "calibrateType", m_calibrateType ); + // Calibration Tool + declareProperty("CellWeightTool",m_cellWeightTool); + declareProperty("ApplyCellWeightEM", m_applyCellWeightEM); + declareProperty("ApplyCellWeightHad", m_applyCellWeightHad); + declareProperty("ApplyPtEtaCorrFactors", m_applyPtEtaCorrFactors); + declareProperty("pTNumberOfBins", m_nptbins ); + declareProperty("etaNumberOfBins", m_netabins ); + + declareProperty("pTPoints",m_ptpoints=std::vector<float>(10,0)); + declareProperty("etaPoints",m_etapoints=std::vector<float>(10,0)); + declareProperty("pTetaCorrectionsNtr1",m_ptetacorrectionsntr1=std::vector<float>(100,0)); + declareProperty("pTetaCorrectionsNtr23",m_ptetacorrectionsntr23=std::vector<float>(100,0)); + + declareProperty("FudgeFactor",m_fudge=1); + declareProperty("DoEtaInterpolation", m_doEtaInterpolation); + declareProperty("CellCone",m_cellCone); + declareProperty("CaloWeightTool",m_caloWeightTool); +} + +tauCalibrateWeightTool::~tauCalibrateWeightTool() +{ +} + +StatusCode tauCalibrateWeightTool::initialize() +{ + StatusCode sc; + ATH_MSG_INFO( "Calibrating using fitted weights. " ); + + // retrieve all helpers from det store + sc = detStore()->retrieve(m_emid); + if (sc.isFailure()) { + ATH_MSG_ERROR( "Unable to retrieve LArEM_ID helper from DetectorStore" ); + return sc; + } + + sc = detStore()->retrieve(m_tileid); + if (sc.isFailure()) { + ATH_MSG_ERROR( "Unable to retrieve TileID helper from DetectorStore" ); + return sc; + } + + // Tool service + IToolSvc* myToolSvc; + sc = service("ToolSvc",myToolSvc); + if ( sc.isFailure() ) { + ATH_MSG_FATAL( "Tool Service not found" ); + return StatusCode::FAILURE; + } + + // Fetch cell weight tool + sc = m_caloWeightTool.retrieve(); + if ( sc.isFailure() ) { + ATH_MSG_ERROR( "Cannot find tool named <" << m_cellWeightTool << ">" ); + m_validCaloWeightTool = false; + + return StatusCode::FAILURE; + } + else { + if( m_caloWeightTool != 0 ) { + ATH_MSG_INFO( "Will use the CaloWeightTool named: " << m_cellWeightTool ); + m_validCaloWeightTool = true; + } + } + + if ( (int)m_ptpoints.size() != m_nptbins || (int)m_etapoints.size() != m_netabins ) { + ATH_MSG_FATAL( "wrong number of points for interpolation" ); + return StatusCode::FAILURE; + } + + for ( int i = 0; i < m_nptbins - 1; ++i ) { + if ( m_ptpoints[i] >= m_ptpoints[i+1]) { + ATH_MSG_FATAL( "Correction factor coordinates must be ordered in Pt and unique" ); + return StatusCode::FAILURE; + } + } + m_ptpoints.push_back(0); //makes the boundary conditions easyer to handle + + for ( int i = 0; i < m_netabins - 1; ++i ) { + if ( m_etapoints[i] >= m_etapoints[i+1]) { + ATH_MSG_FATAL( "Correction factor coordinates must be ordered in eta and unique" ); + return StatusCode::FAILURE; + } + } + m_etapoints.push_back(0); + + if ( (int)m_ptetacorrectionsntr1.size() != (m_nptbins * m_netabins) ) { + ATH_MSG_FATAL( "Wrong number of correction factors for 1 Track" ); + return StatusCode::FAILURE; + } + + if ( (int)m_ptetacorrectionsntr23.size() != (m_nptbins * m_netabins) ) { + ATH_MSG_FATAL( "Wrong number of correction factors for 2 and 3 Tracks" ); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + +/********************************************************************/ +StatusCode tauCalibrateWeightTool::execute( TauCandidateData */*data*/ ) +{ + /* + * FF: March 2014 + * This Tool is not migrated yet to xAOD. Unclear if still needed. Only client was TauTrigger. + * FF will investigate. + * + * + Analysis :: TauJet *tau = data->tau; + Analysis :: TauCommonDetails *details = dynamic_cast<Analysis :: TauCommonDetails *>(data->details); + + // Detector identifiers + AtlasDetectorID AtlasID; + + // Variables for sums + double sumEM = 0; + double sumE = 0; + double sumAccb3 = 0; + double sumHad = 0; + double sumTile1 = 0; + + double sumScint = 0; + double sumGap = 0; + + double dR; + + // loop over all cells of the tau (placed there by the tauSeedBuilder) + typedef NavigationToken<CaloCell,NavigationDefaults::DefaultWeight,CaloCellIDFcn> token_t; + token_t nt; + + tau->fillToken( nt ); + + token_t::const_iterator nt_iter = nt.begin(); + token_t::const_iterator nt_end = nt.end(); + + const CaloCell *cell; + + double etaSeed = tau->eta(); //FF details->seedCalo_eta(); + double phiSeed = tau->phi(); //FF details->seedCalo_phi(); + + P4EEtaPhiM P4Seed( 1., etaSeed, phiSeed, 0. ); + + for ( ; nt_iter != nt_end; nt_iter++ ) { + cell = (*nt_iter); + + // Cell ET and index for ET range + // This is made symmetric around zero so that noise (not yet included) + // does not produce a shift. + double cellET = cell->et(); + + CaloSampling::CaloSample calo = cell->caloDDE()->getSampling(); + + // Use cells that are in DR < m_cellCone of eta,phi of jet: + dR = P4Helpers::deltaR( P4Seed, cell->eta(), cell->phi() ); + + if ( dR < m_cellCone ) { + double calWeight = 1.; + + // Check which kind of calib tools have been selected + // and Get calibration weight + + if (m_validCaloWeightTool) calWeight = m_caloWeightTool->wtCell( cell ); + + sumE += cell->e(); + + switch ( calo ) { + case CaloSampling::PreSamplerB: + case CaloSampling::PreSamplerE: + case CaloSampling::EMB1: + case CaloSampling::EME1: + case CaloSampling::EMB2: + case CaloSampling::EME2: + sumEM += (m_applyCellWeightEM ? calWeight*cellET : cellET); + break; + case CaloSampling::EMB3: + sumAccb3 += cellET; + + case CaloSampling::EME3: + // Only include first two EM layers in EM sum; add third to HAD + // Keep track of ACCB3 for cryostat correction below + sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET); + break; + + case CaloSampling::TileBar0: + sumTile1 += cellET; + + case CaloSampling::TileBar1: + case CaloSampling::TileBar2: + sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET); + break; + case CaloSampling::TileExt0: + case CaloSampling::TileExt1: + case CaloSampling::TileExt2: + sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET); + break; + case CaloSampling::TileGap1: + // scintillator ? + // Gap Scintillator is included in Gap + // Hence do NOT add it separately + // MH I don't know what's it like now .... but I guess its seperated + sumScint += cellET; + case CaloSampling::TileGap2: + case CaloSampling::TileGap3: + sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET); + sumGap += cellET; + break; + case CaloSampling::HEC0: + case CaloSampling::HEC1: + case CaloSampling::HEC2: + case CaloSampling::HEC3: + sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET); + break; + case CaloSampling::FCAL0: + case CaloSampling::FCAL1: + case CaloSampling::FCAL2: + case CaloSampling::MINIFCAL0: + case CaloSampling::MINIFCAL1: + case CaloSampling::MINIFCAL2: + case CaloSampling::MINIFCAL3: + case CaloSampling::Unknown: + break; + } + } // end dR cut + else + { + ATH_MSG_VERBOSE( "cell with energy " << cell->e() << " outside of cell cone" ); + } + + } // end cell loop + + // Cryostat correction uses geometric mean of last layer of EM and + // first layer of tile: + + if(sumAccb3<0.) sumAccb3=0.; + if(sumTile1<0.) sumTile1=0.; + + double wtCryo = 1.; + + if (m_validCaloWeightTool) wtCryo = m_caloWeightTool->wtCryo(); + double sumCryo = (m_applyCellWeightHad ? wtCryo*sqrt(sumAccb3*sumTile1) : sqrt(sumAccb3*sumTile1)); + + // Weight fudge factor. The H1 weights are taken to be independent of + // eta. This factor is applied to the hadronic energy to produce a + // more uniform response. + + details->setSeedCalo_etEMCalib(sumEM); + details->setSeedCalo_etHadCalib((sumHad+sumCryo)); + + double et = details->seedCalo_etEMCalib()+details->seedCalo_etHadCalib(); + double eta = fabs( etaSeed ); + double corr = 1; + + if (m_applyPtEtaCorrFactors) { + + ATH_MSG_VERBOSE( "energy: " << details->seedCalo_etEMCalib() << " " <<details->seedCalo_etHadCalib() << " " << sumEM <<" "<<sumHad<<" "<<sumCryo ); + + int lowpt_idx = 0; + int loweta_idx = 0; + + double lowpt_frac = 0; + double loweta_frac = 0; + + while ( lowpt_idx < m_nptbins-1 && et > m_ptpoints[lowpt_idx+1] ) + lowpt_idx++; + + lowpt_frac = ( m_ptpoints[lowpt_idx+1] - et ) / ( m_ptpoints[lowpt_idx+1] - m_ptpoints[lowpt_idx] ); // will be >1 if et is out of bounds + + if ( lowpt_frac > 1 ) + lowpt_frac = 1; + if( lowpt_frac < 0 ) { //should never happen, only if ptNumberOfBins is set wrong (which is checked now) + ATH_MSG_ERROR( "FIXME: lowpt_frac < 0 !!" ); + } + + while ( loweta_idx < m_netabins-1 && eta > m_etapoints[loweta_idx+1] ) + loweta_idx++; + + if(m_doEtaInterpolation) + loweta_frac = ( m_etapoints[loweta_idx+1] - eta ) / ( m_etapoints[loweta_idx+1] - m_etapoints[loweta_idx] ); // will be >1 if eta is out of bounds, + else + loweta_frac = 1; + + if ( loweta_frac > 1) + loweta_frac = 1; + if( loweta_frac < 0 ) { //should never happen, only if etaNumberOfBins is set wrong + ATH_MSG_ERROR( "FIXME: loweta_frac < 0 !!" ); + } + + double coeff_matrix[2][2] = { {0, 0}, {0, 0} }; + + //FF changed from seeddCalo_numTrack to numTrack + if ( tau->numTrack() <= 1 ) { + coeff_matrix[0][0] = m_ptetacorrectionsntr1[lowpt_idx*m_netabins+loweta_idx]; + if( lowpt_idx < m_nptbins-1 ) + coeff_matrix[1][0] = m_ptetacorrectionsntr1[(lowpt_idx+1)*m_netabins+loweta_idx]; + if( loweta_idx < m_netabins-1 ) + coeff_matrix[0][1] = m_ptetacorrectionsntr1[lowpt_idx*m_netabins+(loweta_idx+1)]; + if( lowpt_idx < m_nptbins-1 && loweta_idx < m_netabins-1 ) + coeff_matrix[1][1] = m_ptetacorrectionsntr1[(lowpt_idx+1)*m_netabins+(loweta_idx+1)]; + } else { + coeff_matrix[0][0] = m_ptetacorrectionsntr23[lowpt_idx*m_netabins+loweta_idx]; + if( lowpt_idx < m_nptbins-1 ) + coeff_matrix[1][0] = m_ptetacorrectionsntr23[(lowpt_idx+1)*m_netabins+loweta_idx]; + if( loweta_idx < m_netabins-1 ) + coeff_matrix[0][1] = m_ptetacorrectionsntr23[lowpt_idx*m_netabins+(loweta_idx+1)]; + if( lowpt_idx < m_nptbins-1 && loweta_idx < m_netabins-1 ) + coeff_matrix[1][1] = m_ptetacorrectionsntr23[(lowpt_idx+1)*m_netabins+(loweta_idx+1)]; + } + + corr = ( coeff_matrix[0][0] * lowpt_frac * loweta_frac ) + ( coeff_matrix[1][0] * (1-lowpt_frac) * loweta_frac ); + corr += ( coeff_matrix[0][1] * lowpt_frac * (1-loweta_frac) ) + ( coeff_matrix[1][1] * (1-lowpt_frac) * (1-loweta_frac) ); + + } // end if (m_applyPtEtaCorrFactors) + + ATH_MSG_VERBOSE( "corrected energy: " << et << "*" << corr << "=" << et*corr ); + + + //tau->setE( et*cosh( details->seedCalo_eta() )*corr*m_fudge ); + */ + + //return StatusCode::SUCCESS; + // print error so that everybody knows this tool isn't working in case it is called. + ATH_MSG_ERROR( "This Tool is not yet migrated to xAOD!" ); + return StatusCode::SUCCESS; +} + +//----------------------------------------------------------------------------- +// Finalize +//----------------------------------------------------------------------------- +StatusCode tauCalibrateWeightTool :: finalize() +{ + return StatusCode :: SUCCESS; +} diff --git a/Reconstruction/tauRec/tauRec/CaloClusterVariables.h b/Reconstruction/tauRec/tauRec/CaloClusterVariables.h new file mode 100644 index 00000000000..9b34c1b6d99 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/CaloClusterVariables.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef CALOCLUSTERVARIABLES_H +#define CALOCLUSTERVARIABLES_H + +#include <vector> +#include "CaloUtils/CaloVertexedCluster.h" +//#include "CaloEvent/CaloVertexedCluster.h" +#include "CxxUtils/fpcompare.h" +#include "xAODTau/TauJet.h" + +/** Provide calculations of cluster based variables using the clusters associated to the jet seed of the tau candidate. */ +class CaloClusterVariables { +public: + + static const double DEFAULT; + + CaloClusterVariables(); + + ~CaloClusterVariables() { + } + + bool update(const xAOD::TauJet* tau); //!< update the internal variables for the given tau + + void setVertexCorrection(bool flag) {m_doVertexCorrection=flag;} + + // ID Variables + unsigned int numConstituents() { return (unsigned int) m_numConstit; } + + double totalMass() { return m_totMass; } + double effectiveMass() { return m_effMass; } + + double effectiveNumConstituents() { return m_effNumConstit; } + int effectiveNumConstituents_int() { return m_effNumConstit_int; } + + double averageEffectiveRadius() { return m_aveEffRadius; } + double averageRadius() { return m_aveRadius; } + + // Energy Variables + double totalEnergy() { return m_totEnergy; } + double effectiveEnergy() { return m_effEnergy; } + + //cells + unsigned int numCells() { return m_numCells; } + +private: + int m_numConstit; + int m_effNumConstit_int; + double m_effNumConstit; + double m_aveRadius; + double m_aveEffRadius; + double m_totMass; + double m_effMass; + double m_totEnergy; + double m_effEnergy; + unsigned int m_numCells; + + /** Calculate the geometrical center of the tau constituents */ + CLHEP::HepLorentzVector calculateTauCentroid(int nConst, const std::vector<xAOD::CaloVertexedCluster>& constituents); + + /** + * Enable cell origin correction. + * Eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doVertexCorrection; +}; + +//------------------------------------------------------------------------- +//! Descending order by energy +//------------------------------------------------------------------------- +struct CaloClusterCompare { + bool operator()(const xAOD::CaloVertexedCluster& left, const xAOD::CaloVertexedCluster& right) { + //volatile double leftE = left.e(); + //volatile double rightE = right.e(); + return CxxUtils::fpcompare::greater (left.e(),right.e()); + } +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/JetSeedBuilder.h b/Reconstruction/tauRec/tauRec/JetSeedBuilder.h new file mode 100644 index 00000000000..1f9cec13fcb --- /dev/null +++ b/Reconstruction/tauRec/tauRec/JetSeedBuilder.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_JETSEEDBUILDER_H +#define TAUREC_JETSEEDBUILDER_H + +#include "tauRec/TauToolBase.h" + + +/** + * @brief Class to build tauRec seeds from topojets. + * + * Sets the jet ElementLink and basic kinematic variables in TauJet by searching a matching jet to the tau direction. + * Also the mass of the tau is set to 0. + * With tauRec4 the JetSeedBuilder method is the only one to search for a tau candidates. + * The author of the tau candidate is set 1 (former calo-only seeded) and 3 (former calo+track-seeded) to keep backwards compatibility. + * + * @author N.Meyer <nicom@cern.ch> + * @author Felix Friedrich +*/ + +class JetSeedBuilder : public TauToolBase { +public: + + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + JetSeedBuilder(const std::string& type, + const std::string& name, + const IInterface * parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + virtual ~JetSeedBuilder(); + + virtual StatusCode initialize(); + + virtual StatusCode execute(TauCandidateData * data); + + virtual StatusCode eventFinalize(TauCandidateData *data); + + virtual void cleanup(TauCandidateData *) { } + +private: + std::string m_jetCollectionName; + float m_maxJetdist; + float m_minJetPt; + bool m_switch_jets_em_scale; +}; + +#endif /* JETSEEDBUILDER_H */ + diff --git a/Reconstruction/tauRec/tauRec/KineUtils.h b/Reconstruction/tauRec/tauRec/KineUtils.h new file mode 100644 index 00000000000..28d5e0bf257 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/KineUtils.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_KINEUTILS_H +#define TAUREC_KINEUTILS_H + + +#include <string> +#include "TVector2.h" + +//static const double kPI = 3.1415927; +//static const double k2PI = 2*3.1415927; + +//! +//! @class Tau1P3PKineUtils +//! @brief Provides methods for simple kinematical calculations +//! +//! Provides methods for simple kinematical calculations: absolute value +//! of difference in pseudorapidity, in phi position, half-opening angle +//! in ( eta, phi ) space +//! + +class Tau1P3PKineUtils +{ + public: + //! + //! Calculates absolute value for difference in eta position + //! + //! @param x eta position of object 1 + //! @param y eta position of object 2 + //! + static double deltaEta(double eta1, double eta2) { return std::fabs( eta1 - eta2);} + + //! + //! Calculates absolute value for difference in phi position, + //! corrected for 2pi symmetry + //! + //! @param x phi position of object 1 + //! @param y phi position of object 2 + //! + + /* + static double deltaPhi(double phi1, double phi2) + { + + double dphi = std :: fabs( phi1 - phi2 ); + if( dphi > kPI ) dphi -= k2PI; + return std :: fabs( dphi ); + } + */ + static double deltaPhi(double phi1, double phi2) + { + return TVector2::Phi_mpi_pi(phi1-phi2); + } + + //! + //! Calculates half-opening angle in (eta,phi) space + //! + //! @param x detphi of two objects + //! @param y deteta of two objects + //! + static double deltaR(double de,double dp) { return std::sqrt(de*de+dp*dp); } + static double deltaR(double eta1, double phi1, double eta2, double phi2) { + return std::sqrt(deltaEta(eta1,eta2)*deltaEta(eta1,eta2)+deltaPhi(phi1,phi2)*deltaPhi(phi1,phi2)); + } + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/LockTauContainers.h b/Reconstruction/tauRec/tauRec/LockTauContainers.h new file mode 100644 index 00000000000..917b2f37911 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/LockTauContainers.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_LOCKTAUCONTAINERS_H +#define TAUREC_LOCKTAUCONTAINERS_H + +#include "tauRec/TauToolBase.h" + +/** + * @brief Set tau containers to const to prevent downstream modification. + * + * @author Felix Friedrich + */ + +class LockTauContainers : public TauToolBase +{ + public: + LockTauContainers(const std::string& type, + const std::string& name, + const IInterface* parent); + + ~LockTauContainers() { } + + virtual StatusCode initialize() { return StatusCode::SUCCESS; } + virtual StatusCode execute( TauCandidateData* ) { return StatusCode::SUCCESS; } + virtual StatusCode eventFinalize( TauCandidateData *data ); +}; + +#endif /* TAUREC_LOCKTAUCONTAINERS_H */ + diff --git a/Reconstruction/tauRec/tauRec/PhotonConversionPID.h b/Reconstruction/tauRec/tauRec/PhotonConversionPID.h new file mode 100644 index 00000000000..961274b1dff --- /dev/null +++ b/Reconstruction/tauRec/tauRec/PhotonConversionPID.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_PHOTONCONVERSIONPID_H +#define TAUREC_PHOTONCONVERSIONPID_H + +#include "tauRec/TauToolBase.h" + +/** + * @brief This tool identifies Conversion Candidates via a cut on the electron probability provided by the TRT PID Tool. + * + * Such Photon Conversions are needed e.g. to find Photon Conversions within the tau decay cone. + * + * @author M. Boehler + */ + +class PhotonConversionPID : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + + PhotonConversionPID(const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + ~PhotonConversionPID(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode eventFinalize(TauCandidateData *data); + +private: + int m_ownPolicy; + + std::string m_ConversionCandidatesName; + std::string m_ConversionOutputName; + + double m_eProb_cut; +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/PhotonConversionVertex.h b/Reconstruction/tauRec/tauRec/PhotonConversionVertex.h new file mode 100644 index 00000000000..b07abfa376c --- /dev/null +++ b/Reconstruction/tauRec/tauRec/PhotonConversionVertex.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_PHOTONCONVERSIONVERTEX_H +#define TAUREC_PHOTONCONVERSIONVERTEX_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" + +namespace Analysis { + class TauJetContainer; +} + +namespace Rec { + class TrackParticle; +} + +namespace InDet { + class IVertexFinder; +} + +/** + * @brief Class that runs the tau conversion finding algorithm + * + * This tool identifies conversion candidates + * in/near (definable) a tau decay cone by reconstructing the conversion vertices + * and applying a set of cuts optimized for tau conversions on the vertex parameters. + * + * @author KG Tan <Kong.Guan.Tan@cern.ch> + * + */ + +class PhotonConversionVertex : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor and Destructor + //------------------------------------------------------------- + PhotonConversionVertex(const std::string& type, + const std::string& name, + const IInterface* parent); + ~PhotonConversionVertex(); + + //------------------------------------------------------------- + //! Algorithm functions + //------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode eventFinalize(TauCandidateData *data); + +private: + //------------------------------------------------------------- + //! Convenience functions to handle storegate objects + //------------------------------------------------------------- + template <class T> + bool openContainer(T* &container, std::string containerName); + + template <class T> + bool saveContainer(T* &container, std::string containerName); + + template <class T> + bool retrieveTool(T &tool); + + //------------------------------------------------------------- + //! Gets the minimum dR between a particle and a set of taus + //------------------------------------------------------------- + double getMinDrTauDecay(const xAOD::TauJetContainer* tauJetCont, const xAOD::TrackParticle *trackParticle); + +private: + //------------------------------------------------------------- + //! Storegate names of input containers and output containers + //------------------------------------------------------------- + std::string m_inputTauJetContainerName; + std::string m_inputTrackParticleContainerName; + std::string m_outputConversionVertexContainerName; + + //------------------------------------------------------------- + //! Input parameters for conversion finding + //------------------------------------------------------------- + double m_maxTauJetDr; + + //------------------------------------------------------------- + //! Tool used by conversion finding, initialised in job options + //------------------------------------------------------------- + ToolHandle<InDet::IVertexFinder> m_vertexFinderTool; +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauAxisSetter.h b/Reconstruction/tauRec/tauRec/TauAxisSetter.h new file mode 100644 index 00000000000..0608e5a0dca --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauAxisSetter.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUAXISSETTER_H +#define TAUREC_TAUAXISSETTER_H + +#include "tauRec/TauToolBase.h" + + +/** + * @brief Set Tau "Detector Axis" and "Intermediate Axis". + * + * Note that both axes starts from the barycenter of the cluster associated to the jet seed. + * Then only the 4-vectors of clusters in a cone of dR around these barycenter are summed up, forming the new axis. + * For the "Intermediate Axis" the clusters are correct wrt tau vertex in this step (barycenter remains the same). + * Using this procedure, the axes are different from the original jet seed axis. + * + * @author Margar Simonyan + * @author Felix Friedrich + * + */ + +class TauAxisSetter : public TauToolBase { +public: + + TauAxisSetter(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauAxisSetter(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData * data); + virtual StatusCode finalize(); + virtual StatusCode execute(TauCandidateData *data); + +private: + std::string tauContainerKey; + + double m_clusterCone; + /** + * enable cell origin correction + * eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doCellCorrection; +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauBuilder.h b/Reconstruction/tauRec/tauRec/TauBuilder.h new file mode 100644 index 00000000000..8b46391c97c --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauBuilder.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUBUILDER_H +#define TAUREC_TAUBUILDER_H + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +#include "tauRec/TauToolBase.h" + +/** + * @brief Main class for tau candidate building and processing. + * + * This class loop over seeds from the seed container, + * creates a new tau candidate if seed is passing the given cuts, + * and run the given tau tools on the created tau candidate. + * If a tool fails the tau candidate will be removed. + * + * @authors Srini Rajagopalan, Michael Heldmann, Lukasz Janyst, Anna Kaczmarska, Felix Friedrich + */ + +class TauBuilder : public AthAlgorithm +{ + public: + //----------------------------------------------------------------- + // Constructor and destructor + //----------------------------------------------------------------- + TauBuilder(const std::string &name, ISvcLocator *pSvcLocator); + ~TauBuilder(); + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + std::string m_tauContainerName; //!< tau output container + std::string m_tauAuxContainerName; //!< tau output aux store container + std::string m_seedContainerName; //!< seed input container + double m_maxEta; //!< only build taus with eta_seed < m_maxeta + double m_minPt; //!< only build taus with pt_seed > m_minpt + + /** switch to create tau containers, + * if false tau containers will be updated only + */ + bool m_doCreateTauContainers; + + ToolHandleArray<TauToolBase> m_tools; //!< tools to process tau candidates +} ; + +#endif // TAUREC_TAUBUILDER_H diff --git a/Reconstruction/tauRec/tauRec/TauCalibrateEM.h b/Reconstruction/tauRec/tauRec/TauCalibrateEM.h new file mode 100644 index 00000000000..a3921820407 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauCalibrateEM.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCALIBRATEEM_H +#define TAUREC_TAUCALIBRATEEM_H + +#include <string> +#include <tauRec/TauToolBase.h> + +class TF1; + +/** implementation of tau EM energy scale (depreciated) */ +class TauCalibrateEM : public TauToolBase { +public: + TauCalibrateEM(const std::string& type, const std::string& name, const IInterface* parent); + ~TauCalibrateEM(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + // private methods + double evaluate_new_pt(double pt, double eta, int ntrack, double emfrac); + + // configurables + std::string m_response_functions_file; + + // private data + TF1* m_f1_1p_lem; + TF1* m_f1_1p_hem_barrel; + TF1* m_f1_1p_hem_crack; + TF1* m_f1_1p_hem_endcap; + TF1* m_f1_mp_barrel; + TF1* m_f1_mp_crack; + TF1* m_f1_mp_endcap; + + std::pair<double, double> m_min_1p_lem; + std::pair<double, double> m_min_1p_hem_barrel; + std::pair<double, double> m_min_1p_hem_crack; + std::pair<double, double> m_min_1p_hem_endcap; + std::pair<double, double> m_min_mp_barrel; + std::pair<double, double> m_min_mp_crack; + std::pair<double, double> m_min_mp_endcap; + +}; + +#endif /* TAUCALIBRATEEM_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauCalibrateLC.h b/Reconstruction/tauRec/tauRec/TauCalibrateLC.h new file mode 100644 index 00000000000..4b3f11c3462 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauCalibrateLC.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCALIBRATELC_H +#define TAUREC_TAUCALIBRATELC_H + +#include "tauRec/TauToolBase.h" + +class TH1; +class TF1; + +/** + * @brief Implementation of tau energy scale (TES) with eta and pile-up correction. + * + * The energy and eta (direction) correction are done separatly and steered by flags. + * + * @author Margar Simonyan + * @author Felix Friedrich + * + */ + +class TauCalibrateLC : public TauToolBase { +public: + + TauCalibrateLC(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauCalibrateLC(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode execute(TauCandidateData *data); + +private: + std::string tauContainerKey; + std::string vertexContainerKey; + std::string calibrationFile; //!< energy calibration file + + static const int nProngBins = 2; + + const TF1 * calibFunc[nProngBins][10]; //maximum 10 eta bins; might not be used on the whole + const TH1 * slopeNPVHist[nProngBins]; + const TH1 * etaBinHist; + const TH1 * etaCorrectionHist; + + unsigned int m_minNTrackAtVertex; + int m_nEtaBins; + double m_averageNPV; + + bool m_doEnergyCorr; //!< switch for energy correction + bool m_doAxisCorr; //!< switch for eta correction + bool m_printMissingContainerINFO; + + double m_clusterCone; //obsolete +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauCandidateData.h b/Reconstruction/tauRec/tauRec/TauCandidateData.h new file mode 100644 index 00000000000..7498f6a32d7 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauCandidateData.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_CANDIDATE_DATA_H +#define TAUREC_CANDIDATE_DATA_H +//----------------------------------------------------------------------------- +// file: TauCandidateData.h +// package: Reconstruction/tauEvent +// authors: Lukasz Janyst +// date: 2007-02-13 +// +// MODIFICATIONS +// 2008-04-22 nicom: moved setObject()/getObject() to TauCandidateData +// +//----------------------------------------------------------------------------- + +#include <string> +#include <map> +#include <boost/any.hpp> + +#include "tauEvent/TauJet.h" +#include "tauEvent/TauJetContainer.h" +#include "tauEvent/TauDetails.h" +#include "tauEvent/TauDetailsContainer.h" + + +#include "xAODTau/TauJet.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODJet/Jet.h" + + +/** + * @brief The tau candidate object. + * + * Holds all containers and information needed for the tau reconstruction process. + * + * @authors Lukasz Janyst + */ + +struct TauCandidateData +{ + //----------------------------------------------------------------- + //! Associate some object to a key - this is meant to be used by + //! TrigTauRec to pass container pointers to tauRec tools + //----------------------------------------------------------------- + template <typename P> + void setObject( std :: string key, P ptr ); + + //----------------------------------------------------------------- + //! Check if something has been associated with given key + //----------------------------------------------------------------- + bool hasObject( std :: string key ) const; + + //----------------------------------------------------------------- + //! Get the pointer associated with given key, if types don't + //! match boost :: bad_any_cast exception is thrown + //----------------------------------------------------------------- + template <typename P> + StatusCode getObject( std :: string key, P &ptr ); + + xAOD::TauJet *xAODTau; + xAOD::TauJetContainer* xAODTauContainer; + xAOD::TauJetAuxContainer *tauAuxContainer; + //think about changing this to IParticle + const xAOD::Jet *seed; + const xAOD::JetContainer *seedContainer; + unsigned int detailsNum; + + std :: map<std :: string, boost :: any> m_ptrMap; +}; + +//------------------------------------------------------------------------- +// Set pointer +//------------------------------------------------------------------------- + template <typename P> +inline void TauCandidateData :: setObject( std :: string key, P ptr ) +{ + m_ptrMap[key] = ptr; +} + +//------------------------------------------------------------------------- +// Get pointer +//------------------------------------------------------------------------- + template <typename P> +inline StatusCode TauCandidateData :: getObject( std :: string key, P &ptr ) +{ + std :: map< std :: string, boost :: any> :: iterator p_it; + p_it = m_ptrMap.find( key ); + if( p_it == m_ptrMap.end() ) + return StatusCode :: FAILURE; + + ptr = boost :: any_cast<P>( (*p_it).second ); + return StatusCode :: SUCCESS; +} + +//------------------------------------------------------------------------- +// Test if any pointer has been associated with given key +//------------------------------------------------------------------------- +inline bool TauCandidateData :: hasObject( std :: string key ) const +{ + return m_ptrMap.find( key ) != m_ptrMap.end(); +} + +#endif // TAU_CANDIDATE_DATA diff --git a/Reconstruction/tauRec/tauRec/TauCellVariables.h b/Reconstruction/tauRec/tauRec/TauCellVariables.h new file mode 100644 index 00000000000..dae7f12d5b4 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauCellVariables.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCELLVARIABLES_H +#define TAUREC_TAUCELLVARIABLES_H + +#include "tauRec/TauToolBase.h" + +class LArEM_ID; +class TileID; + +/** + * @brief Calculate tau calorimeter variables from cell information. + * + * @authors Srini Rajagopalan, Anna Kaczmarska, Felix Friedrich + */ + +class TauCellVariables : public TauToolBase { + +public: + TauCellVariables(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauCellVariables(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + +private: + double m_cellEthr; //!< EM cell E threshold + double m_stripEthr; //!< cell E threshold for strips + double m_EMSumThr; //!< threshold for 4-vector EM sum + double m_EMSumR; //!< radius for 4-vector EM sum + double m_cellCone; //!< outer cone for cells used in calculations + + const LArEM_ID* m_emid; + const TileID* m_tileid; + + /** + * enable cell origin correction + * eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doCellCorrection; +}; + +#endif /* TAUREC_TAUCELLVARIABLES_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauCommonCalcVars.h b/Reconstruction/tauRec/tauRec/TauCommonCalcVars.h new file mode 100644 index 00000000000..71e548d15c1 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauCommonCalcVars.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCOMMONCALCVARS_H +#define TAUREC_TAUCOMMONCALCVARS_H + +#include "tauRec/TauToolBase.h" + + +/** + * @brief Calculate variables which rely on tracks and precalculated cell/cluster information. + * + * All variables here can be recalculated using AODs. + * + * @author Stan Lai + * @author Felix Friedrich + */ + +class TauCommonCalcVars : public TauToolBase { +public: + //----------------------------------------------------------------- + // Constructor and destructor + //----------------------------------------------------------------- + TauCommonCalcVars(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauCommonCalcVars(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +}; + +#endif // TAUREC_TAUCOMMONCALCVARS_H diff --git a/Reconstruction/tauRec/tauRec/TauConversionFinder.h b/Reconstruction/tauRec/tauRec/TauConversionFinder.h new file mode 100644 index 00000000000..5166e7cf9e1 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauConversionFinder.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCONVERSIONFINDER_H +#define TAUREC_TAUCONVERSIONFINDER_H + +#include <tauRec/TauToolBase.h> + +/** + * @brief This tool identifies if a tau track is reconstructed as photon conversion track too. + * + * @author M. Boehler + */ + +class TauConversionFinder : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + TauConversionFinder(const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + ~TauConversionFinder(); + + virtual StatusCode initialize(); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + std::string m_vxCandidatesName; + std::string m_trackContainerName; + std::string m_ConversionCandidatesName; + + bool m_do_normal; + double m_eProb_cut; + bool m_adjust_tau_charge; + + int m_numLooseProng; + int m_numProng; + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauConversionTagger.h b/Reconstruction/tauRec/tauRec/TauConversionTagger.h new file mode 100644 index 00000000000..4cfc2806603 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauConversionTagger.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCONVERSIONTAGGER_H +#define TAUREC_TAUCONVERSIONTAGGER_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "ITrackToVertex/ITrackToVertex.h" + +/** + * @brief This tool identifies if a tau track originates from a photon conversion track. + * + * @author D. Varouchas + */ + + +class TauConversionTagger : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + TauConversionTagger(const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + ~TauConversionTagger(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + + std::string m_trackContainerName; + + int m_ConvTaggerVer; + bool m_TrkIsConv; + bool m_storeFullSummary; + bool m_doTRTRatio; + float m_a_cut[2][2], m_b_cut[2][2]; + float m_TRTHighTOutliersRatio; + ToolHandle<Reco::ITrackToVertex> m_trackToVertexTool; + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauElectronVetoVariables.h b/Reconstruction/tauRec/tauRec/TauElectronVetoVariables.h new file mode 100644 index 00000000000..f3f41c8fbae --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauElectronVetoVariables.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAU1P3PELEVETO_H +#define TAUREC_TAU1P3PELEVETO_H + +#include "tauRec/TauToolBase.h" + +class IExtrapolateToCaloTool; + +/** + * @brief Calculate variables sensitive on electrons. + * + * The variables are mainly used by the electron veto in the TauDiscriminant package. + * + * @author Zofia Czyczula + */ + +class TauElectronVetoVariables : public TauToolBase { +public: + + TauElectronVetoVariables(const std::string& type, + const std::string& name, + const IInterface* parent); + + virtual ~TauElectronVetoVariables(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + + bool m_doCellCorrection; //!< enable cell origin correction + ToolHandle<IExtrapolateToCaloTool> m_trackToCalo; +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauGenericPi0Cone.h b/Reconstruction/tauRec/tauRec/TauGenericPi0Cone.h new file mode 100644 index 00000000000..47afcbe3282 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauGenericPi0Cone.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauGenericPi0Cone.h +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-04 +// +// +//----------------------------------------------------------------------------- + +#ifndef TAUREC_TAUGENERICPI0CONE_H +#define TAUREC_TAUGENERICPI0CONE_H + +#include "tauRec/TauToolBase.h" + +class TauGenericPi0Cone : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + TauGenericPi0Cone(const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + ~TauGenericPi0Cone(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + + float m_pi0conedr; + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauPi0BonnClusterCreator.h b/Reconstruction/tauRec/tauRec/TauPi0BonnClusterCreator.h new file mode 100644 index 00000000000..d22cb783839 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauPi0BonnClusterCreator.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0BONNCLUSTERCREATOR_H +#define TAUREC_TAUPI0BONNCLUSTERCREATOR_H + +#include <string> +#include <vector> +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "tauRec/TauToolBase.h" +#include "xAODPFlow/PFOAuxContainer.h" + +using std::vector; + +class IExtrapolateToCaloTool; + +/** + * @brief Creates Pi0 clusters ("Bonn" Pi0 Finder). + * + * @author Veit Scharf + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + */ + +class TauPi0BonnClusterCreator : public TauToolBase { +public: + TauPi0BonnClusterCreator(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauPi0BonnClusterCreator(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + +private: + + + /** @brief fraction of cluster enegry in central EM1 cells */ + float getEM1CoreFrac( const xAOD::CaloCluster* /*pi0Candidate*/); + + /** @brief asymmetry of cluster energy distribution in EM1 w.r.t. the tracks */ + float getAsymmetryInEM1WRTTrk( const xAOD::CaloCluster* /*pi0Candidate*/, + const vector<vector<float> > /*tracksEtaAtSampling*/, + const vector<vector<float> > /*tracksPhiAtSampling*/); + + + /** @brief number of cells from cluster with positive energy in PS, EM1 and EM2 */ + vector<int> getNPosECells( const xAOD::CaloCluster* /*pi0Candidate*/); + + std::map<unsigned, xAOD::CaloCluster*> getClusterToShotMap( + const std::vector<const xAOD::PFO*> shotVector, + const xAOD::CaloClusterContainer* pPi0ClusterContainer, + xAOD::TauJet *pTau); + + std::vector<unsigned> getShotsMatchedToCluster( + const std::vector<const xAOD::PFO*> shotVector, + std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap, + xAOD::CaloCluster* pPi0Cluster); + + int getNPhotons( const std::vector<const xAOD::PFO*> /*shotVector*/, + std::vector<unsigned> /*shotsInCluster*/); + + /** @brief first eta moment in PS, EM1 and EM2 w.r.t cluster eta: (eta_i - eta_cluster) */ + vector<float> get1stEtaMomWRTCluster( const xAOD::CaloCluster* /*pi0Candidate*/); + + /** @brief second eta moment in PS, EM1 and EM2 w.r.t cluster eta: (eta_i - eta_cluster)^2 */ + vector<float> get2ndEtaMomWRTCluster(const xAOD::CaloCluster* /*pi0Candidate*/); + + /** @brief get extrapolated track position at each layer */ + void getExtrapolatedPositions( const xAOD::TrackParticle* /*track*/, + vector<float>& /*trackToCaloEta*/, + vector<float>& /*trackToCaloPhi*/); + + + + /** @brief tool handles */ + ToolHandle<IExtrapolateToCaloTool> m_trackToCaloTool; + + /** @brief all calo cell container name */ + std::string m_cellContainerName; + + /** @brief input cluster container of pi0 candidates */ + // TODO: input cluster container name + std::string m_inputPi0ClusterContainerName; + + /** @brief output cluster container of pi0 candidates */ + // TODO: output cluster container name + std::string m_outputPi0ClusterContainerName; + + /** @brief new neutral PFO container and name */ + xAOD::PFOContainer* m_neutralPFOContainer; + std::string m_neutralPFOContainerName; + xAOD::PFOAuxContainer* m_neutralPFOAuxStore; + + + /** @brief pt threshold for pi0 candidate clusters */ + double m_clusterEtCut; + + /** @brief output cluster container */ + xAOD::CaloClusterContainer* m_pOutputPi0CaloClusterContainer; + +}; + +#endif /* TAUPI0BONNCLUSTERCREATOR_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauPi0BonnCreateROI.h b/Reconstruction/tauRec/tauRec/TauPi0BonnCreateROI.h new file mode 100644 index 00000000000..0e168202660 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauPi0BonnCreateROI.h @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0BONNCREATEROI_H +#define TAUREC_TAUPI0BONNCREATEROI_H + +#include <string> +#include <vector> +#include <boost/scoped_ptr.hpp> +#include <map> + +#include "GaudiKernel/ToolHandle.h" +#include "tauRec/TauToolBase.h" + +#include "xAODPFlow/PFOAuxContainer.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODTau/TauJet.h" + + + +class IHadronicCalibrationTool; +class IExtrapolateToCaloTool; +class ICaloCellMakerTool; +class TauOriginCorrectionTool; +class TauPi0BonnParser; +/** + * @brief Create ROIs for the "Bonn" Pi0 Finder. + * + * @author Veit Scharf + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + */ + +class TauPi0BonnCreateROI : public TauToolBase { +public: + TauPi0BonnCreateROI(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauPi0BonnCreateROI(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + + /** @brief get extrapolated track position at each layer */ + void getExtrapolatedPositions( std::vector<const xAOD::TrackParticle*>, + int sampling); + + + /** @brief get hadronic energy associated to the tracks */ + std::vector<double> getEstEcalEnergy( std::vector<const xAOD::TrackParticle*>, + const xAOD::CaloClusterContainer*, + const xAOD::TauJet*); + + /** @brief get cell weight from lateral shape */ + double getLatWeight( int /* samp */, + double /* deltaEta */, + double /* deltaPhi */, + double /* cellWidthEta */, + double /* cellWidthPhi */, + unsigned /* trackNumber */, + const xAOD::TrackParticle* /* track */ + ); + + /** @brief store cell in output container */ + void storeCell(const CaloCell* /* cell*/, + double /* subtractedEnergy */); + + + /** @brief tool handles */ + ToolHandle<IHadronicCalibrationTool> m_caloWeightTool; + ToolHandle<IExtrapolateToCaloTool> m_trackToCaloTool; + ToolHandle<ICaloCellMakerTool> m_cellMakerTool; + + /** @brief calo cell navigation */ + const CaloDetDescrManager* m_calo_dd_man; + const CaloCell_ID* m_calo_id; + + /** @brief lateral shower parameteristaion parser */ + boost::scoped_ptr<TauPi0BonnParser> m_latParser; + std::string m_latParFile; + + + /** @brief all calo cell container name */ + std::string m_caloCellContainerName; // TODO: replace with tau clusters? + + /** @brief all cluster container name */ + std::string m_clusterContainerName; // TODO: replace with tau clusters? + + /** @brief output cell container and name*/ + CaloCellContainer *m_pPi0CellContainer; + std::string m_pi0CellContainerName; + + /** @brief new charged PFO container and name */ + xAOD::PFOContainer* m_chargedPFOContainer; + std::string m_chargedPFOContainerName; + xAOD::PFOAuxContainer* m_chargedPFOAuxStore; + + /** @brief map of tracks to normalization factors*/ + std::map<int, TH1*> m_trackHistMapBarrel; + std::map<int, TH1*> m_trackHistMapEndcap; + + /** @brief variables used for shower parameteristaion */ + double m_pt; + double m_abseta; + double m_hadf; + double m_sampling; // its really an int but just use double + // should function correctly in parser + + /** @brief hash map in order to keep track, which cells have been added to output cell container*/ + std::vector<CaloCell*> m_addedCellsMap; + + /** @brief extrapolated position of tracks and vector of bools to keep track for which sampleings this has already been done */ + std::vector<std::vector<double> > m_tracksEtaAtSampling; + std::vector<std::vector<double> > m_tracksPhiAtSampling; + std::vector<bool> m_extrapolatedSamplings; + std::vector<double> m_defaultValues; + std::vector<double> m_defaultValuesZero; +}; + +#endif /* TAUPI0BONNCREATEROI_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauPi0BonnParser.h b/Reconstruction/tauRec/tauRec/TauPi0BonnParser.h new file mode 100644 index 00000000000..dce779fc024 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauPi0BonnParser.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0BONNPARSER_H +#define TAUREC_TAUPI0BONNPARSER_H + +#include <string> +#include <map> +#include <vector> +#include <fstream> +#include "TH1.h" +class TDirectory; + +/** + * @brief Parser to read in shower parameterisations for BonnPi0CreateROI + * + * @author Will Davey <will.davey@cern.ch> + */ + + +class TauPi0BonnParser { + + public: + /** constructor */ + TauPi0BonnParser(); + /** destructor */ + ~TauPi0BonnParser(); + + /** parse input ROOT file */ + bool parseROOTFile(std::string config_file, std::string directory = ""); + + /** set the address of an input variable */ + bool setVar( const std::string& key, double& val); + + /** get vector of input parameters */ + TH1* getTH1(); + + /** get multi-dimensional bin key using stored vals */ + std::string getBinKey(); + + /** summary of config */ + void summary(); + + /** get status of initialisation */ + bool checkInitialisationStatus(); + + /** get string stream (filled incase of errors) */ + std::string getStream(); + + /** set maximum length of the stream buffer */ + void setMaxTraceback(int); + + private: + + /** get multi-dimensional bin key from list of bin indices */ + std::string getBinKey( const std::vector<int>& bin_indices ); + + /** get vector of current values of input parameters */ + std::vector<double> getCurrentVals(); + + /** parse TDirectory */ + bool parseTDirectory( TDirectory*, + std::vector<int> current_bin_store = std::vector<int>(), + int current_index = -1 + ); + + /** check m_par_map is filled with correct keys, given input var binning */ + bool checkConfig( std::vector<int> current_bin_store = std::vector<int>(), + int current_index = -1 + ); + + /** set the stream */ + void msg( const std::string& theMessage ); + + private: + /** maintain parsed bin order */ + std::vector<std::string> m_bin_order; + /** map var names to bin edges */ + std::map<std::string,std::vector<double> > m_bin_map; + /** map multi-dimensional bin key to input vectors */ + std::map<std::string,TH1*> m_hist_map; + /** map var names to current values */ + std::map<std::string,double*> m_curr_val_map; + /** error stream */ + std::string m_stream; + /** maximum length of the error stream buffer */ + int m_max_traceback; +}; + + +#endif /* TAUPI0BONNPARSER_H */ diff --git a/Reconstruction/tauRec/tauRec/TauPi0BonnScoreCalculator.h b/Reconstruction/tauRec/tauRec/TauPi0BonnScoreCalculator.h new file mode 100644 index 00000000000..cd99b1a7e0c --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauPi0BonnScoreCalculator.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0BONNSCORECALCULATOR_H +#define TAUREC_TAUPI0BONNSCORECALCULATOR_H + +#include <string> +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "xAODPFlow/PFO.h" + +namespace TMVA{ + class Reader; +} + +/** + * @brief Selectes pi0Candidates ("Bonn" Pi0 Finder). + * + * @author Veit Scharf + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + */ + +class TauPi0BonnScoreCalculator : public TauToolBase { +public: + TauPi0BonnScoreCalculator(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauPi0BonnScoreCalculator(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode execute(TauCandidateData *data); + +private: + + std::string m_readerOption; + TMVA::Reader *m_tmvaReader; + + std::string m_weightfile; + + float m_FIRST_ETA; + float m_SECOND_R; + float m_SECOND_LAMBDA; + float m_Abs_DELTA_PHI; + float m_Abs_DELTA_THETA; + float m_CENTER_LAMBDA_helped; + float m_LATERAL; + float m_LONGITUDINAL; + float m_ENG_FRAC_EM; + float m_ENG_FRAC_MAX; + float m_ENG_FRAC_CORE; + float m_log_SECOND_ENG_DENS; + float m_EcoreOverEEM1; + float m_AsymmetryWRTTrack; + float m_NHitsInEM1; + float m_NPosCells_PS; + float m_NPosCells_EM1; + float m_NPosCells_EM2; + float m_firstEtaWRTCluster_EM1; + float m_firstEtaWRTCluster_EM2; + float m_secondEtaWRTCluster_EM1; + float m_secondEtaWRTCluster_EM2; + float m_energy_EM1; + float m_energy_EM2; + + /** @brief function used to calculate BDT score */ + float calculateScore(const xAOD::PFO* neutralPFO); + + /** @brief Book TMVA methods. */ + StatusCode bookMethod(TMVA::Reader *reader, const std::string &methodName) const; + +}; + +#endif /* TAUPI0BONNSCORECALCULATOR_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauPi0BonnSelector.h b/Reconstruction/tauRec/tauRec/TauPi0BonnSelector.h new file mode 100644 index 00000000000..67a4766f3e0 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauPi0BonnSelector.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPI0BONNSELECTOR_H +#define TAUREC_TAUPI0BONNSELECTOR_H + +#include <string> +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" + +class CaloCluster; +namespace Analysis { + class TauCommonDetails; + class TauPi0Details; +} + +/** + * @brief Selectes pi0Candidates ("Bonn" Pi0 Finder). + * + * @author Veit Scharf + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + */ + +class TauPi0BonnSelector : public TauToolBase { +public: + TauPi0BonnSelector(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauPi0BonnSelector(); + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + +private: + + std::vector<float> m_clusterEtCut; + std::vector<float> m_clusterBDTCut_1prong; + std::vector<float> m_clusterBDTCut_mprong; + /** @brief function used to get eta bin of Pi0Cluster */ + int getPi0Cluster_etaBin(double Pi0Cluster_eta); + /** @brief function used to calculate the visible tau 4 momentum */ + TLorentzVector getP4(xAOD::TauJet* tauJet); +}; + +#endif /* TAUPI0BONNSELECTOR_H */ diff --git a/Reconstruction/tauRec/tauRec/TauProcessor.h b/Reconstruction/tauRec/tauRec/TauProcessor.h new file mode 100644 index 00000000000..be77ee5ae86 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauProcessor.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUPROCESSOR_H +#define TAUREC_TAUPROCESSOR_H + +#include "GaudiKernel/ToolHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + +#include "tauRec/TauToolBase.h" + +/** + * @brief Main class for tau candidate building and processing. + * + * This class loop over tau candidates in the tau container placed there by the TauBuilder + * and runs the given tau tools on the tau candidates. The tau objects are !!modified!!. + * If a tool fails, the tau reconstruction will be aborted. + * This algorithm has an AOD mode to skip TauExtraDetailsContainer, that is not available in AODs. + * + * (This algorithm was inspired by TauBuilder.) + * + * @authors Felix Friedrich + */ + +class TauProcessor: public AthAlgorithm +{ + public: + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauProcessor( const std::string &name, ISvcLocator *pSvcLocator ); + ~TauProcessor(); + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + std :: string m_tauContainerName; + std :: string m_tauAuxContainerName; + bool m_AODmode; + ToolHandleArray<TauToolBase> m_tools; +}; + +#endif // TAUREC_TAUPROCESSOR_H diff --git a/Reconstruction/tauRec/tauRec/TauShotFinder.h b/Reconstruction/tauRec/tauRec/TauShotFinder.h new file mode 100755 index 00000000000..95511c0b0a5 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauShotFinder.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUSHOTFINDER_H +#define TAUREC_TAUSHOTFINDER_H + +//#include <string> +//#include <vector> +//#include <map> + +#include "GaudiKernel/ToolHandle.h" +#include "tauRec/TauToolBase.h" +#include "xAODPFlow/PFOAuxContainer.h" +#include "xAODCaloEvent/CaloClusterAuxContainer.h" + +//#include "CaloIdentifier/CaloCell_ID.h" + +class CaloDetDescrManager; +class CaloCell_ID; +class IHadronicCalibrationTool; + +namespace TMVA{ + class Reader; +} + +/** + * @brief Find photon shots in the EM1 strip layer. + * + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + * @author Stephanie Yuen <stephanie.yuen@cern.ch> + */ + +class TauShotFinder : public TauToolBase { +public: + TauShotFinder(const std::string& type, + const std::string& name, + const IInterface *parent); + virtual ~TauShotFinder(); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual StatusCode finalize(); + + virtual void cleanup(TauCandidateData *data); + + + +private: + + /** @brief tool handles */ + ToolHandle<IHadronicCalibrationTool> m_caloWeightTool; + + /** @brief all calo cell container name */ + std::string m_caloCellContainerName; + /** @brief new shot cluster container and name */ + xAOD::CaloClusterContainer* m_shotClusterContainer; + std::string m_shotClusterContainerName; + xAOD::CaloClusterAuxContainer* m_shotClusterAuxStore; + + /** @brief new shot PFO container and name */ + xAOD::PFOContainer* m_PFOShotContainer; + std::string m_shotPFOContainerName; + xAOD::PFOAuxContainer* m_PFOShotAuxStore; + + + /** @brief calo cell navigation */ + const CaloDetDescrManager* m_calo_dd_man; + const CaloCell_ID* m_calo_id; + + /** @brief readers */ + std::string m_readerOption; + + TMVA::Reader *m_tmvaReader_barrel; + std::string m_weightfile_barrel; + + TMVA::Reader *m_tmvaReader_endcap1; + std::string m_weightfile_endcap1; + + TMVA::Reader *m_tmvaReader_endcap2; + std::string m_weightfile_endcap2; + + /** @brief Thanks C++ for ruining my day */ + struct ptSort + { + ptSort( const TauShotFinder& info ); + const TauShotFinder& m_info; + bool operator()( const CaloCell* c1, const CaloCell* c2 ); + }; + + /** @brief get neighbour cells */ + std::vector<const CaloCell*> getNeighbours(const CaloCellContainer*,const CaloCell*,int /*maxDepth*/); + + void addNeighbours(const CaloCellContainer*, + const CaloCell* cell, + std::vector<const CaloCell*>& cells, + int depth, + int maxDepth, + bool next); + + bool isPhiNeighbour(IdentifierHash cell1Hash, IdentifierHash cell2Hash, bool next); + + /** @brief get eta bin */ + float getEtaBin(float /*seedEta*/); + + /** @brief get merged BDTscore */ + float getMergedBDTScore(int /*etaBin*/); + + /** @brief get NPhotons in shot */ + float getNPhotons(int /*etaBin*/, + float /*mergedBDTScore*/, + float /*seedEnergy*/); + + /** @brief Book TMVA methods. */ + StatusCode bookMethod(TMVA::Reader *reader_barrel, + TMVA::Reader *reader_endcap1, + TMVA::Reader *reader_endcap2, + const std::string &methodName) const; + + // number of cells in eta + int m_nCellsInEta; + + // cut values + std::vector<float> m_minPtCut; + std::vector<float> m_autoDoubleShotCut; + std::vector<float> m_mergedBDTScoreCut; + + // BDT input variables + float m_pt1; + float m_pt3; + float m_pt5; + float m_ws5; + float m_sdevEta5_WRTmean; + float m_sdevEta5_WRTmode; + float m_sdevPt5; + float m_deltaPt12_min; + float m_Fside_3not1; + float m_Fside_5not1; + float m_Fside_5not3; + float m_fracSide_3not1; + float m_fracSide_5not1; + float m_fracSide_5not3; + float m_pt1OverPt3; + float m_pt3OverPt5; + + // FIXME: same variable names as in Stephanie's private code atm + float G_PTFRAC; + float G_STDPT_5; + float G_STDETA_5; + float G_DELTAPT_MIN; + +}; + +#endif /* TAUSHOTFINDER_H */ + diff --git a/Reconstruction/tauRec/tauRec/TauShotVariableHelpers.h b/Reconstruction/tauRec/tauRec/TauShotVariableHelpers.h new file mode 100644 index 00000000000..e2e9b76f8d4 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauShotVariableHelpers.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @brief implementation of photon shot variable calculation + * + * @author Will Davey <will.davey@cern.ch> + * @author Benedict Winter <benedict.tobias.winter@cern.ch> + * @author Stephanie Yuen <stephanie.yuen@cern.ch> + */ + +#ifndef TAUSHOTVARIABLEHELPERS_H +#define TAUSHOTVARIABLEHELPERS_H + +#include "xAODPFlow/PFO.h" +#include "GaudiKernel/ToolHandle.h" +#include "CaloInterface/IHadronicCalibrationTool.h" + +namespace TauShotVariableHelpers { + + /** @brief get cell block with (currently) 5x2 cells in correct order for variable calculations */ + std::vector<std::vector<const CaloCell*> > getCellBlock(xAOD::PFO* shot, + const CaloCell_ID* calo_id); + + /** @brief mean eta, used by other functions */ + float mean_eta(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief mean pt, used by other functions */ + float mean_pt(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief pt in windows */ + float ptWindow(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + int /*windowSize*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief ws5 variable (egamma) */ + float ws5(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief standard deviation in eta WRT mean */ + float sdevEta_WRTmean(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief standard deviation in eta WRT mode */ + float sdevEta_WRTmode(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief normalized standard deviation in pt */ + float sdevPt(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief pT diff b/w lead and sub-lead cell */ + float deltaPt12_min(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief Fside variable (egamma) */ + float Fside(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + int /*largerWindow*/, + int /*smallerWindow*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief similar than Fside but in unit of eta instead of number of cells */ + float fracSide(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + int /*largerWindow*/, + int /*smallerWindow*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); + + /** @brief pt window fraction */ + float ptWindowFrac(std::vector<std::vector<const CaloCell*> > /*shotCells*/, + int /*largerWindow*/, + int /*smallerWindow*/, + ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/); +} + +#endif // TAUSHOTVARIABLEHELPERS_H + diff --git a/Reconstruction/tauRec/tauRec/TauSubstructureVariables.h b/Reconstruction/tauRec/tauRec/TauSubstructureVariables.h new file mode 100644 index 00000000000..f6482faaa45 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauSubstructureVariables.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUSUBSTRUCTUREBUILDER_H +#define TAUREC_TAUSUBSTRUCTUREBUILDER_H + +#include "tauRec/TauToolBase.h" + +/** + * @brief Calculate variables from the tau substructure. + * + * @author M. Trottier-McDonald + * @author Felix Friedrich + * + */ + +class TauSubstructureVariables : public TauToolBase +{ + public: + + static const double DEFAULT; + + TauSubstructureVariables(const std::string& type, + const std::string& name, + const IInterface* parent); + + ~TauSubstructureVariables(); + + virtual StatusCode execute( TauCandidateData *data ); + + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + + private: + /** Maximal pile up correction in GeV for a tau candidate. + * Used for the caloIso corrected variable. + */ + double m_maxPileUpCorrection; + double m_pileUpAlpha; //!< slope of the pileup correction + + /** + * enable cell origin correction + * eta and phi of the cells are corrected wrt to the origin of the tau vertex + */ + bool m_doVertexCorrection; + bool m_inAODmode; //!< don't update everything if running on AODs +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauTestDump.h b/Reconstruction/tauRec/tauRec/TauTestDump.h new file mode 100644 index 00000000000..d42af44f555 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauTestDump.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUTESTDUMP_H +#define TAUREC_TAUTESTDUMP_H + +#include "tauRec/TauToolBase.h" + + +/** + * @brief Tau Tool for developing, testing and debugging + * + * + * + * @author Felix Friedrich + */ + +class TauTestDump : public TauToolBase { +public: + //----------------------------------------------------------------- + // Constructor and destructor + //----------------------------------------------------------------- + TauTestDump(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauTestDump(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +}; + +#endif // TAUREC_TAUTESTDUMP_H diff --git a/Reconstruction/tauRec/tauRec/TauToolBase.h b/Reconstruction/tauRec/tauRec/TauToolBase.h new file mode 100644 index 00000000000..8be96fe86e7 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauToolBase.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TOOLBASE_TAU_H +#define TOOLBASE_TAU_H + +#include <string> + +#include "AthenaBaseComps/AthAlgTool.h" +#include "tauRec/TauCandidateData.h" + +/** + * @brief The base class for all tau tools. + * + * @author Lukasz Janyst + */ + +class TauToolBase: public AthAlgTool +{ + public: + TauToolBase( const std::string &type, + const std::string &name, + const IInterface *parent ); + virtual ~TauToolBase(); + + //----------------------------------------------------------------- + //! InterfaceID implementation needed for ToolHandle + //----------------------------------------------------------------- + static const InterfaceID& interfaceID(); + + //----------------------------------------------------------------- + //! Tool initializer + //----------------------------------------------------------------- + virtual StatusCode initialize(); + + //----------------------------------------------------------------- + //! Event initializer - called at the beginning of each event + //----------------------------------------------------------------- + virtual StatusCode eventInitialize( TauCandidateData *data ); + + //----------------------------------------------------------------- + //! Execute - called for each tau candidate + //----------------------------------------------------------------- + virtual StatusCode execute( TauCandidateData *data ); + + //----------------------------------------------------------------- + //! Cleanup - called for each tau rejected candidate + //----------------------------------------------------------------- + virtual void cleanup( TauCandidateData *data ); + + //----------------------------------------------------------------- + //! Event finalizer - called at the end of each event + //----------------------------------------------------------------- + virtual StatusCode eventFinalize( TauCandidateData *data ); + + //----------------------------------------------------------------- + //! Finalizer + //----------------------------------------------------------------- + virtual StatusCode finalize(); + + //------------------------------------------------------------- + //! Convenience functions to handle storegate objects + //------------------------------------------------------------- + template <class T> + bool openContainer(T* &container, std::string containerName, bool printFATAL=false); + + template <class T> + bool retrieveTool(T &tool); + +}; + +#endif // TOOLBASE_TAU_H diff --git a/Reconstruction/tauRec/tauRec/TauTrackFilter.h b/Reconstruction/tauRec/tauRec/TauTrackFilter.h new file mode 100644 index 00000000000..4a20fe3f3b4 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauTrackFilter.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTrackFilter.h +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-04 +// +// +//----------------------------------------------------------------------------- + +#ifndef TAUREC_TAUTRACKFILTER_H +#define TAUREC_TAUTRACKFILTER_H + +#include "tauRec/TauToolBase.h" + +class TauTrackFilter : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor + //------------------------------------------------------------- + TauTrackFilter(const std::string& type, + const std::string& name, + const IInterface* parent); + + //------------------------------------------------------------- + //! Destructor + //------------------------------------------------------------- + ~TauTrackFilter(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode finalize(); + +private: + + std::string m_trackContainerName; + std::vector<bool> m_TrkPass; + int m_nProng; + int m_flag; + //TODO some of this probably need to be public to be useful... + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauTrackFilterUtils.h b/Reconstruction/tauRec/tauRec/TauTrackFilterUtils.h new file mode 100644 index 00000000000..443f965f46c --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauTrackFilterUtils.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------------------------- +// file: TauTrackFilterUtils.h +// package: Reconstruction/tauRec +// authors: Robert Clarke, Blake Burghgrave +// date: 2014-01-13 +// +// +//----------------------------------------------------------------------------- + +#ifndef TAUREC_TAUTRACKFILTERUTILS_H +#define TAUREC_TAUTRACKFILTERUTILS_H + +#include "TF1.h" +#include "TLorentzVector.h" +#include <vector> +#include <iostream> +#include <string> + +namespace TauTrackFilterUtils { + + struct TrackInfo{ + TLorentzVector p4; + int charge; + int index; + }; + + struct TrackPair{ + float angle; + float mass; + int charge; + }; + + bool pass3prong(std::vector<TauTrackFilterUtils::TrackInfo> combination,TLorentzVector tau); + bool pass2prong(std::vector<TauTrackFilterUtils::TrackInfo> pair,TLorentzVector tau); + bool pass1prong(TLorentzVector track,TLorentzVector tau); + float ComputePi0Cone(int recProngs,TLorentzVector tau); + float ComputeAngle(float p, float eta, float a[9][4], int npar, int npol, char eqn[] = (char*)"[0]*exp([1]*x)+[2]+[3]/(x*x)"); + float Compute1dim(float p, float a[10], int npar, char eqn[]); + +} + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauTrackFinder.h b/Reconstruction/tauRec/tauRec/TauTrackFinder.h new file mode 100644 index 00000000000..3281f4b0937 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauTrackFinder.h @@ -0,0 +1,142 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUTRACKFINDER_H +#define TAUREC_TAUTRACKFINDER_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "ITrackToVertex/ITrackToVertex.h" + +#include "xAODTracking/Vertex.h" +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/TrackParticleContainer.h" + +class IExtrapolateToCaloTool; +namespace Trk { + class ITrackSelectorTool; +} + +///////////////////////////////////////////////////////////////////////////// + +/** + * @brief Associate tracks to the tau candidate. + * + * The tracks have to pass dedicated quality criteria and have to + * match to a primary vertex consistent with the tau origin. + * + * @author KG Tan <Kong.Guan.Tan@cern.ch> + * @author Felix Friedrich + */ + +class TauTrackFinder : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor and Destructor + //------------------------------------------------------------- + TauTrackFinder(const std::string& type, const std::string& name, const IInterface* parent); + ~TauTrackFinder(); + + //------------------------------------------------------------- + //! Enumerator defining type of tau track + //------------------------------------------------------------- + enum TauTrackType + { + TauTrackCore = 0, + TauTrackWide = 1, + TauTrackOther = 2, + NotTauTrack = 3 + }; + + //------------------------------------------------------------- + //! Algorithm functions + //------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual StatusCode finalize(); + + //------------------------------------------------------------- + //! Extrapolate track eta and phi to the calorimeter middle surface + //------------------------------------------------------------- + StatusCode extrapolateToCaloSurface(TauCandidateData *data); + + TauTrackType tauTrackType( const xAOD::TauJet* tauJet, + const xAOD::TrackParticle* trackParticle, + const xAOD::Vertex* primaryVertex); + + void getTauTracksFromPV( const xAOD::TauJet* tauJet, + const xAOD::TrackParticleContainer* trackParticleCont, + const xAOD::Vertex* primaryVertex, + std::vector<const xAOD::TrackParticle*> &tauTracks, + std::vector<const xAOD::TrackParticle*> &wideTracks, + std::vector<const xAOD::TrackParticle*> &otherTracks); + + // old style AOD version + void removeOffsideTracksWrtLeadTrk(std::vector<const Rec::TrackParticle*> &tauTracks, + std::vector<const Rec::TrackParticle*> &wideTracks, + std::vector<const Rec::TrackParticle*> &otherTracks, + const Trk::RecVertex* tauOrigin, + double maxDeltaZ0); + + // new xAOD version + void removeOffsideTracksWrtLeadTrk(std::vector<const xAOD::TrackParticle*> &tauTracks, + std::vector<const xAOD::TrackParticle*> &wideTracks, + std::vector<const xAOD::TrackParticle*> &otherTracks, + const xAOD::Vertex* tauOrigin, + double maxDeltaZ0); + + void getDeltaZ0Values(std::vector<float>& vDeltaZ0coreTrks, std::vector<float>& vDeltaZ0wideTrks); + void resetDeltaZ0Cache(); + +private: + //------------------------------------------------------------- + //! Some internally used functions + //------------------------------------------------------------- + float getZ0(const Rec::TrackParticle* track, const Trk::RecVertex* vertex); //AOD version + float getZ0(const xAOD::TrackParticle* track, const xAOD::Vertex* vertex); //xAOD version + +private: + //------------------------------------------------------------- + //! Storegate names of input containers and output containers + //------------------------------------------------------------- + std::string m_inputTauJetContainerName; + std::string m_inputTrackParticleContainerName; + std::string m_inputPrimaryVertexContainerName; + + //------------------------------------------------------------- + //! tools + //------------------------------------------------------------- + ToolHandle<IExtrapolateToCaloTool> m_trackToCalo; + ToolHandle<Trk::ITrackSelectorTool> m_trackSelectorTool_tau; + ToolHandle<Reco::ITrackToVertex> m_trackToVertexTool; + + //------------------------------------------------------------- + //! Input parameters for algorithm + //------------------------------------------------------------- + double m_maxJetDr_tau; + double m_maxJetDr_wide; + + //------------------------------------------------------------- + // z0 cuts + //------------------------------------------------------------- + float m_z0maxDelta; + bool m_applyZ0cut; + bool m_storeInOtherTrks; + std::vector<float> m_vDeltaZ0coreTrks; + std::vector<float> m_vDeltaZ0wideTrks; + + //------------------------------------------------------------- + //! Convenience functions to handle storegate objects + //------------------------------------------------------------- + template <class T> + bool openContainer(T* &container, std::string containerName, bool printFATAL=false); + + template <class T> + bool retrieveTool(T &tool); + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauTrackSlimmer.h b/Reconstruction/tauRec/tauRec/TauTrackSlimmer.h new file mode 100644 index 00000000000..26ab2eb6194 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauTrackSlimmer.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TRACKSLIMMER_TAU_H +#define TAUREC_TRACKSLIMMER_TAU_H + +#include "AthenaBaseComps/AthAlgorithm.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaKernel/IThinningSvc.h" +#include "ParticleEvent/ParticleBase.h" +#include <string> + +class StoreGateSvc; + +/** + * @brief Class for tau tracks slimming. + * + * @author Anna Kaczmarska, Lukasz Janyst + */ + +class TauTrackSlimmer: public AthAlgorithm +{ + public: + + //----------------------------------------------------------------- + // Contructor and destructor + //----------------------------------------------------------------- + TauTrackSlimmer( const std::string &name, ISvcLocator *pSvcLocator ); + ~TauTrackSlimmer(); + + //----------------------------------------------------------------- + // Gaudi algorithm hooks + //----------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + private: + std :: string m_tauContainerName; + ServiceHandle<IThinningSvc> m_thinningSvc; + bool m_filterTaus; + unsigned m_maxNTrack; + ChargeType m_maxCharge; + double m_maxEmRadius; + double m_maxIsoFrac; + + +}; + +#endif // TAUREC_TRACKSLIMMER_TAU_H diff --git a/Reconstruction/tauRec/tauRec/TauVertexFinder.h b/Reconstruction/tauRec/tauRec/TauVertexFinder.h new file mode 100644 index 00000000000..3a8ea5dccf5 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauVertexFinder.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUVERTEXFINDER_H +#define TAUREC_TAUVERTEXFNIDER_H + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" +#include "xAODTracking/VertexContainer.h" +#include "JetEDM/TrackVertexAssociation.h" + +///////////////////////////////////////////////////////////////////////////// + +/** + * @brief Associate a vertex (origin) to the tau candidate. + * + * The vertex has to be consistent with the origin of tau jet seed. + * The vertex is determined in the following order: TJVA -> first PV in vertex container -> 0 + * Attention: all downstream tau variables will be calculated to the vertex set here! + * + * @author KG Tan <Kong.Guan.Tan@cern.ch> + * @author Felix Friedrich <Felix.Friedrich@cern.ch> + */ + +class TauVertexFinder : public TauToolBase { +public: + //------------------------------------------------------------- + //! Constructor and Destructor + //------------------------------------------------------------- + TauVertexFinder(const std::string& type, const std::string& name, const IInterface* parent); + ~TauVertexFinder(); + + //------------------------------------------------------------- + //! Algorithm functions + //------------------------------------------------------------- + virtual StatusCode initialize(); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventFinalize(TauCandidateData *data); + virtual StatusCode finalize(); + + ElementLink<xAOD::VertexContainer> getPV_TJVA(const xAOD::TauJet* tauJet, const xAOD::VertexContainer* vertices); + +private: + float getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const; + + //------------------------------------------------------------- + //! Convenience functions to handle storegate objects + //------------------------------------------------------------- + template <class T> + bool openContainer(T* &container, std::string containerName, bool printFATAL=false); + + template <class T> + bool retrieveTool(T &tool); + +private: + bool m_printMissingContainerINFO; + float m_maxJVF; + + //------------------------------------------------------------- + //! Configureables + //------------------------------------------------------------- + bool m_useTJVA; + std::string m_inputPrimaryVertexContainerName; + std::string m_assocTracksName; + std::string m_trackVertexAssocName; +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/TauVertexVariables.h b/Reconstruction/tauRec/tauRec/TauVertexVariables.h new file mode 100644 index 00000000000..eb830c5ea95 --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TauVertexVariables.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUVERTEXVARIABLES_H +#define TAUREC_TAUVERTEXVARIABLES_H + +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/VertexAuxContainer.h" +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" + +// forwards +class TauCandidateData; +namespace Trk { + class ITrackToVertexIPEstimator; + class IVertexFitter; + class IVertexSeedFinder; + class IVxCandidateXAODVertex; +} + +/** + * + * @brief Class for calculating vertex variables. + * + * @authors Stan Lai, Felix Friedrich + */ + +class TauVertexVariables : public TauToolBase { +public: + //----------------------------------------------------------------- + // Constructor and destructor + //----------------------------------------------------------------- + TauVertexVariables(const std::string& type, + const std::string& name, + const IInterface* parent); + ~TauVertexVariables(); + + virtual StatusCode initialize(); + virtual StatusCode execute(TauCandidateData *data); + virtual StatusCode eventInitialize(TauCandidateData *data); + virtual StatusCode finalize(); + + //------------------------------------------------------------- + //! determines the transverse flight path significance from + //! the primary vertex and the secondary vertex of tau candidate + //------------------------------------------------------------- + double trFlightPathSig(TauCandidateData *data, const xAOD::Vertex *secVertex); + +private: + std::string m_primaryVertexKey; + std::string m_inputTrackParticleContainerName; + bool m_useOldSeedFinderAPI; + ToolHandle< Trk::ITrackToVertexIPEstimator > m_trackToVertexIPEstimator; + ToolHandle< Trk::IVertexFitter > m_fitTool; //!< Pointer to the base class of the fit algtools + ToolHandle< Trk::IVertexSeedFinder > m_SeedFinder; + ToolHandle< Trk::IVxCandidateXAODVertex > m_xaodConverter; // necessary to convert VxCandidate to xAOD::Vertex in case old API is used + + xAOD::VertexContainer* m_pSecVtxContainer; + xAOD::VertexAuxContainer* m_pSecVtxAuxContainer; +}; + +#endif /* TAUREC_TAUVERTEXVARIABLES_H */ + diff --git a/Reconstruction/tauRec/tauRec/TrackSort.h b/Reconstruction/tauRec/tauRec/TrackSort.h new file mode 100644 index 00000000000..0952a84161d --- /dev/null +++ b/Reconstruction/tauRec/tauRec/TrackSort.h @@ -0,0 +1,44 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TRACKSORT_H +#define TAUREC_TRACKSORT_H + +#include "Particle/TrackParticle.h" +#include "Particle/TrackParticleContainer.h" +#include "xAODTracking/TrackParticle.h" +#include "AthLinks/ElementLink.h" + +/** + * @brief Helper method to sort tracks + * + * Usage: + * sort(track_begin, track_end, tauTrackSort); + * We want pt0 > pt1 > ..., so the test on ptInvVert is < . + * + */ + +class TrackSort { + + public: + TrackSort(){ }; + + bool operator() (const ElementLink<Rec::TrackParticleContainer>& t1, const ElementLink<Rec::TrackParticleContainer> &t2) const + { + return fabs( (*t1)->pt() ) > fabs( (*t2)->pt() ); + }; + + bool operator() ( const Rec::TrackParticle *t1, const Rec::TrackParticle *t2 ) const + { + return fabs( t1->pt() ) > fabs( t2->pt() ); + }; + + bool operator() ( const xAOD::TrackParticle *t1, const xAOD::TrackParticle *t2 ) const + { + return fabs( t1->pt() ) > fabs( t2->pt() ); + }; + +}; + +#endif diff --git a/Reconstruction/tauRec/tauRec/tauCalibrateWeightTool.h b/Reconstruction/tauRec/tauRec/tauCalibrateWeightTool.h new file mode 100644 index 00000000000..c73088aad2a --- /dev/null +++ b/Reconstruction/tauRec/tauRec/tauCalibrateWeightTool.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef TAUREC_TAUCALIBRATEWEIGHTTOOL_H +#define TAUREC_TAUCALIBRATEWEIGHTTOOL_H +/******************************************************************** +(depreciated!) + +NAME: tauCalibrateWeightTool.h +PACKAGE: offline/Reconstruction/tauRec +AUTHORS: M.Heldmann +CREATED: March 15, 2005 + +See comments in tauCalibrateWeightTool.cxx. + +13/12/2008 - (AK) change to extrapolation of TP instead of Track+code cleaning + ********************************************************************/ + +#include "tauRec/TauToolBase.h" +#include "GaudiKernel/ToolHandle.h" + + +class TauCandidateData; +class LArEM_ID; +class TileID; +class IHistogram1D; +class IHadronicCalibrationTool; + +//------------------------------------------------------------- +//! Class for applying H1-weighting on calorimeter cells and fudge factor for tau energy +//------------------------------------------------------------- +class tauCalibrateWeightTool : public TauToolBase +{ + public: + enum calibrateType { calCells = 0, calJets, calTracks, calCluster, calTopocluster }; + + tauCalibrateWeightTool(const std::string& type, + const std::string& name, + const IInterface* parent); + ~tauCalibrateWeightTool(); + + virtual StatusCode initialize(); + virtual StatusCode finalize(); + virtual StatusCode execute( TauCandidateData *data ); + + // Accessor methods: + + private: + int m_calibrateType; + ToolHandle<IHadronicCalibrationTool> m_caloWeightTool; + + const LArEM_ID* m_emid; + const TileID* m_tileid; + + std::string m_cellWeightTool; + std::vector<float> m_poly; + + bool m_applyCellWeightEM; + bool m_applyCellWeightHad; + bool m_applyPtEtaCorrFactors; + bool m_validCaloWeightTool; + bool m_doEtaInterpolation; + + float m_fudge; + double m_cellCone; + + int m_nptbins; + int m_netabins; + + std::vector<float> m_ptpoints; + std::vector<float> m_etapoints; + std::vector<float> m_ptetacorrectionsntr1; + std::vector<float> m_ptetacorrectionsntr23; +}; + +#endif -- GitLab