From 131758ec549878f4e8d1d76220077c6645d35580 Mon Sep 17 00:00:00 2001
From: Frank Winklmeier <fwinkl@cern>
Date: Sun, 27 Dec 2020 10:54:28 +0100
Subject: [PATCH] Revert "EventUtils: Delete unused ParticleSortingAlg/Tool"

This reverts commit 2904e609e744365d044903dc80438b0d46dea245.
---
 .../EventUtils/src/ParticleSortingAlg.cxx     | 158 +++++++++
 .../EventUtils/src/ParticleSortingAlg.h       | 149 ++++++++
 .../EventUtils/src/ParticleSortingTool.cxx    | 318 ++++++++++++++++++
 .../EventUtils/src/ParticleSortingTool.h      | 183 ++++++++++
 .../src/components/EventUtils_entries.cxx     |   4 +
 5 files changed, 812 insertions(+)
 create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx
 create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h
 create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx
 create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h

diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx
new file mode 100644
index 00000000000..f5ad85275d7
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx
@@ -0,0 +1,158 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// ParticleSortingAlg.cxx
+// Implementation file for class ParticleSortingAlg
+// Author: Karsten Koeneke <karsten.koeneke@cern.ch>
+///////////////////////////////////////////////////////////////////
+
+// EventUtils includes
+#include "ParticleSortingAlg.h"
+
+// FrameWork includes
+#include "Gaudi/Property.h"
+#include "GaudiKernel/IJobOptionsSvc.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+
+///////////////////////////////////////////////////////////////////
+// Public methods:
+///////////////////////////////////////////////////////////////////
+
+// Constructors
+////////////////
+ParticleSortingAlg::ParticleSortingAlg( const std::string& name,
+                                        ISvcLocator* pSvcLocator ) :
+  ::AthAlgorithm( name, pSvcLocator ),
+  m_jos("JobOptionsSvc", name),
+  m_tool("ParticleSortingTool/ParticleSortingTool", this),
+  m_inCollKey(""),
+  m_setInCollKey(false),
+  m_outCollKey(""),
+  m_setOutCollKey(false),
+  m_sortVar("pt"),
+  m_setSortVar(false),
+  m_sortDescending(true),
+  m_setSortDescending(false),
+  m_nEventsProcessed(0)
+{
+  declareProperty("JobOptionsSvc",   m_jos, "The JobOptionService instance.");
+
+  declareProperty("SortingTool",        m_tool, "The private ParticleSortingTool" );
+
+  declareProperty("InputContainer",  m_inCollKey="",   "Input container name" );
+  m_inCollKey.declareUpdateHandler( &ParticleSortingAlg::setupInputContainer, this );
+
+  declareProperty("OutputContainer", m_outCollKey="",
+                  "The name of the output container (with SG::VIEW_ELEMENTS) with the sorted copy of input objects" );
+  m_outCollKey.declareUpdateHandler( &ParticleSortingAlg::setupOutputContainer, this );
+
+  declareProperty("SortVariable",    m_sortVar="pt",
+                  "Define by what parameter to sort (default: 'pt'; allowed: 'pt', 'eta', 'phi', 'm', 'e', 'rapidity')" );
+  m_sortVar.declareUpdateHandler( &ParticleSortingAlg::setupSortVar, this );
+
+  declareProperty("SortDescending",   m_sortDescending=true,
+                  "Define if the container should be sorted in a descending order (default=true)" );
+  m_sortDescending.declareUpdateHandler( &ParticleSortingAlg::setupSortDescending, this );
+}
+
+
+
+// Destructor
+///////////////
+ParticleSortingAlg::~ParticleSortingAlg()
+{}
+
+
+
+// Athena Algorithm's Hooks
+////////////////////////////
+StatusCode ParticleSortingAlg::initialize()
+{
+  ATH_MSG_DEBUG ("Initializing " << name() << "...");
+
+  // Print out the used configuration
+  ATH_MSG_DEBUG ( " using = " << m_jos );
+  ATH_MSG_DEBUG ( " using = " << m_tool );
+  ATH_MSG_DEBUG ( " using = " << m_inCollKey );
+  ATH_MSG_DEBUG ( " using = " << m_outCollKey );
+  ATH_MSG_DEBUG ( " using = " << m_sortVar );
+  ATH_MSG_DEBUG ( " using = " << m_sortDescending );
+
+
+  // Initialize the counters to zero
+  m_nEventsProcessed = 0 ;
+
+
+  // Get the JobOptionService
+  // We will use this to set the properties of our private skimming tool
+  // from the properties of this algorithm.
+  ATH_MSG_VERBOSE( "Getting the JobOptionService");
+  ATH_CHECK( m_jos.retrieve() );
+
+  // Get the full name of the private skimTool
+  ATH_MSG_VERBOSE( "Getting the full name of the tool");
+  const std::string& fullToolName = this->name() + "." + m_tool.name();
+  ATH_MSG_DEBUG( "Got the full name of the tool: " << fullToolName );
+
+  // Now, set all properties of the private skimTool that were acutally configured
+  if (m_setInCollKey) {
+    ATH_MSG_DEBUG( "Setting property" << m_inCollKey
+                   << " of private tool with name: '" << fullToolName << "'" );
+    ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_inCollKey) );
+  }
+  if (m_setOutCollKey) {
+    ATH_MSG_DEBUG( "Setting property" << m_outCollKey
+                   << " of private tool with name: '" << fullToolName << "'" );
+    ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollKey) );
+  }
+  if (m_setSortVar) {
+    ATH_MSG_DEBUG( "Setting property" << m_sortVar
+                   << " of private tool with name: '" << fullToolName << "'" );
+    ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_sortVar) );
+  }
+  if (m_setSortDescending) {
+    ATH_MSG_DEBUG( "Setting property" << m_sortDescending
+                   << " of private tool with name: '" << fullToolName << "'" );
+    ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_sortDescending) );
+  }
+  ATH_MSG_DEBUG( "Done setting properties of the tool");
+
+  // Get the skimming tool
+  ATH_CHECK( m_tool.retrieve() );
+
+  ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." );
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+StatusCode ParticleSortingAlg::finalize()
+{
+  ATH_MSG_DEBUG ("Finalizing " << name() << "...");
+
+  // Release all tools and services
+  ATH_CHECK( m_jos.release() );
+  ATH_CHECK( m_tool.release() );
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+StatusCode ParticleSortingAlg::execute()
+{
+  // Increase the event counter
+  ++m_nEventsProcessed;
+
+  // Simple status message at the beginning of each event execute,
+  ATH_MSG_DEBUG ( "==> execute " << name() << " on " << m_nEventsProcessed << ". event..." );
+
+  // Call the tool
+  ATH_CHECK( m_tool->addBranches() );
+
+  return StatusCode::SUCCESS;
+}
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h
new file mode 100644
index 00000000000..763f04c952c
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h
@@ -0,0 +1,149 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// ParticleSortingAlg.h
+// Header file for class ParticleSortingAlg
+// Author: Karsten Koeneke <karsten.koeneke@cern.ch>
+///////////////////////////////////////////////////////////////////
+#ifndef EVENTUTILS_PARTICLESORTINGALG_H
+#define EVENTUTILS_PARTICLESORTINGALG_H 1
+
+// FrameWork includes
+#include "GaudiKernel/ToolHandle.h"
+#include "GaudiKernel/ServiceHandle.h"
+#include "AthenaBaseComps/AthAlgorithm.h"
+
+// STL includes
+#include <string>
+
+// Forward declarations
+class IJobOptionsSvc;
+namespace DerivationFramework {
+  class IAugmentationTool;
+}
+
+class ParticleSortingAlg
+  : public ::AthAlgorithm
+{
+
+  ///////////////////////////////////////////////////////////////////
+  // Public methods:
+  ///////////////////////////////////////////////////////////////////
+ public:
+
+  // Copy constructor:
+
+  /// Constructor with parameters:
+  ParticleSortingAlg( const std::string& name, ISvcLocator* pSvcLocator );
+
+  /// Destructor:
+  virtual ~ParticleSortingAlg();
+
+  /// Athena algorithm's initalize hook
+  virtual StatusCode  initialize();
+
+  /// Athena algorithm's execute hook
+  virtual StatusCode  execute();
+
+  /// Athena algorithm's finalize hook
+  virtual StatusCode  finalize();
+
+
+private:
+  // The update handlers
+
+  /// This internal method will realize if a user sets the 'InputContainer' property
+  void setupInputContainer( Gaudi::Details::PropertyBase& /*prop*/ );
+
+  /// This internal method will realize if a user sets the 'OutputContainer' property
+  void setupOutputContainer( Gaudi::Details::PropertyBase& /*prop*/ );
+
+  /// This internal method will realize if a user sets the 'SortVariable' property
+  void setupSortVar( Gaudi::Details::PropertyBase& /*prop*/ );
+
+  /// This internal method will realize if a user sets the 'SortDeceding' property
+  void setupSortDescending( Gaudi::Details::PropertyBase& /*prop*/ );
+
+
+
+  ///////////////////////////////////////////////////////////////////
+  // Private data:
+  ///////////////////////////////////////////////////////////////////
+ private:
+  /// The job options service (will be used to forward this algs properties to
+  /// the private tool)
+  ServiceHandle<IJobOptionsSvc> m_jos;
+
+  /// The ToolHandle to the private ParticleSortingTool
+  ToolHandle<DerivationFramework::IAugmentationTool> m_tool;
+
+  /// Input container name
+  StringProperty m_inCollKey;
+
+  /// This boolean is true if the user sets the 'InputContainer' property
+  bool m_setInCollKey;
+
+
+  /// The name of the output container (with SG::VIEW_ELEMENTS) with the sorted copy of input objects
+  StringProperty m_outCollKey;
+
+  /// This boolean is true if the user sets the 'OutputContainer' property
+  bool m_setOutCollKey;
+
+
+  /// Define by what parameter to sort (default: 'pt')
+  StringProperty m_sortVar;
+
+  /// This boolean is true if the user sets the 'SortVariable' property
+  bool m_setSortVar;
+
+
+  /// Define if the container should be sorted in a descending order (default=true)
+  BooleanProperty m_sortDescending;
+
+  /// This boolean is true if the user sets the 'SortDescending' property
+  bool m_setSortDescending;
+
+
+  /// Internal event counter
+  unsigned long m_nEventsProcessed;
+
+};
+
+
+
+///////////////////////////////////////////////////////////////////
+// Inline methods:
+///////////////////////////////////////////////////////////////////
+
+/// This internal method will realize if a user sets the 'InputContainer' property
+inline void ParticleSortingAlg::setupInputContainer( Gaudi::Details::PropertyBase& /*prop*/ ) {
+  m_setInCollKey = true;
+  return;
+}
+
+/// This internal method will realize if a user sets the 'OutputContainer' property
+inline void ParticleSortingAlg::setupOutputContainer( Gaudi::Details::PropertyBase& /*prop*/ ) {
+  m_setOutCollKey = true;
+  return;
+}
+
+/// This internal method will realize if a user sets the 'SortVariable' property
+inline void ParticleSortingAlg::setupSortVar( Gaudi::Details::PropertyBase& /*prop*/ )
+{
+  m_setSortVar = true;
+  return;
+}
+
+/// This internal method will realize if a user sets the 'SortDeceding' property
+inline void ParticleSortingAlg::setupSortDescending( Gaudi::Details::PropertyBase& /*prop*/ )
+{
+  m_setSortDescending = true;
+  return;
+}
+
+
+#endif //> !EVENTUTILS_PARTICLESORTINGALG_H
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx
new file mode 100644
index 00000000000..876c7e005d2
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx
@@ -0,0 +1,318 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// ParticleSortingTool.cxx
+// Implementation file for class ParticleSortingTool
+// Author: Karsten Koeneke <karsten.koeneke@cern.ch>
+///////////////////////////////////////////////////////////////////
+
+// EventUtils includes
+#include "ParticleSortingTool.h"
+
+// EDM includes
+#include "xAODBase/IParticle.h"
+#include "xAODBase/IParticleContainer.h"
+#include "xAODMuon/MuonContainer.h"
+#include "xAODJet/JetContainer.h"
+#include "xAODEgamma/ElectronContainer.h"
+#include "xAODEgamma/PhotonContainer.h"
+#include "xAODTau/TauJetContainer.h"
+#include "xAODPFlow/PFOContainer.h"
+#include "xAODTracking/NeutralParticleContainer.h"
+#include "xAODTracking/TrackParticleContainer.h"
+#include "xAODTruth/TruthParticleContainer.h"
+#include "xAODParticleEvent/CompositeParticleContainer.h"
+#include "xAODParticleEvent/ParticleContainer.h"
+#include "xAODCaloEvent/CaloClusterContainer.h"
+#include "AthContainers/ConstDataVector.h"
+
+// Constructors
+////////////////
+ParticleSortingTool::ParticleSortingTool( const std::string& type,
+                                          const std::string& name,
+                                          const IInterface* parent ) :
+  ::AthAlgTool  ( type, name, parent ),
+  m_inCollKey(""),
+  m_outCollKey(""),
+  m_sortVar("pt"),
+  m_sortDescending(true),
+  m_contID(0),
+  m_sortID(0),
+  m_nEventsProcessed(0)
+{
+  declareInterface< DerivationFramework::IAugmentationTool >(this);
+
+  declareProperty("InputContainer",  m_inCollKey="",   "Input container name" );
+
+  declareProperty("OutputContainer", m_outCollKey="",
+                  "The name of the output container (with SG::VIEW_ELEMENTS) with the sorted copy of input objects" );
+
+  declareProperty("SortVariable",    m_sortVar="pt",
+                  "Define by what parameter to sort (default: 'pt'; allowed: 'pt', 'eta', 'phi', 'm', 'e', 'rapidity')" );
+
+  declareProperty("SortDescending",   m_sortDescending=true,
+                  "Define if the container should be sorted in a descending order (default=true)" );
+}
+
+
+// Destructor
+///////////////
+ParticleSortingTool::~ParticleSortingTool()
+{}
+
+
+
+// Athena algtool's Hooks
+////////////////////////////
+StatusCode ParticleSortingTool::initialize()
+{
+  ATH_MSG_DEBUG ("Initializing " << name() << "...");
+
+  // Print out the used configuration
+  ATH_MSG_DEBUG ( " using = " << m_inCollKey );
+  ATH_MSG_DEBUG ( " using = " << m_outCollKey );
+
+  // initialize the counters
+  m_contID           = 0;
+  m_sortID           = 0;
+  m_nEventsProcessed = 0;
+
+  // Figure out how to sort
+  if ( m_sortVar.value() == "pt" )            { m_sortID = 1; }
+  else if ( m_sortVar.value() == "eta" )      { m_sortID = 2; }
+  else if ( m_sortVar.value() == "phi" )      { m_sortID = 3; }
+  else if ( m_sortVar.value() == "m" )        { m_sortID = 4; }
+  else if ( m_sortVar.value() == "e" )        { m_sortID = 5; }
+  else if ( m_sortVar.value() == "rapidity" ) { m_sortID = 6; }
+  else {
+    ATH_MSG_INFO("Didn't find a valid value for SortVariable=" << m_sortVar.value() << "."
+                 << " Assuming it's an auxdata member");
+    m_sortID = 7;
+  }
+  if ( m_sortDescending.value() ) { m_sortID *= -1; }
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+
+StatusCode ParticleSortingTool::finalize()
+{
+  ATH_MSG_DEBUG ("Finalizing " << name() << "...");
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+// Declare a short pre-processor macro to deal with the different container types
+#define COPY_AND_SORT_CONTAINER( CONTAINERTYPE )                                       \
+else if ( evtStore()->contains<CONTAINERTYPE>( m_inCollKey.value() ) ) {               \
+  ATH_MSG_DEBUG("Trying to copy, sort, and record container of type "#CONTAINERTYPE ); \
+  const CONTAINERTYPE* inCont;                                                         \
+  ATH_CHECK( evtStore()->retrieve( inCont, m_inCollKey.value() ) );                    \
+  CONTAINERTYPE* outCont = new CONTAINERTYPE( SG::VIEW_ELEMENTS );                     \
+  *outCont = *inCont;                                                                  \
+  ATH_CHECK( evtStore()->record ( outCont, m_outCollKey.value() ) );                   \
+  ATH_CHECK( this->doSort(outCont) );                                                  \
+}
+
+
+// Declare a short pre-processor macro to deal with the different container types
+#define OVERWRITE_AND_SORT_CONTAINER( CONTAINERTYPE )                                                \
+else if ( evtStore()->contains<CONTAINERTYPE>( m_inCollKey.value() ) ) {                             \
+  ATH_MSG_DEBUG("Trying to copy, sort, and overwrite container of type "#CONTAINERTYPE );            \
+  const CONTAINERTYPE* inCont;                                                                       \
+  ATH_CHECK( evtStore()->retrieve( inCont, m_inCollKey.value() ) );                                  \
+  ConstDataVector<CONTAINERTYPE>* outCont = new ConstDataVector<CONTAINERTYPE>( SG::VIEW_ELEMENTS ); \
+  for ( const CONTAINERTYPE::base_value_type* inPart : *inCont ){                                    \
+    outCont->push_back(inPart);                                                                      \
+  }                                                                                                  \
+  ATH_CHECK( evtStore()->overwrite( outCont, m_inCollKey.value() ) );                                \
+  ATH_CHECK( this->doSortConst<CONTAINERTYPE>(outCont) );                                            \
+}
+
+
+
+StatusCode ParticleSortingTool::addBranches() const
+{
+  // Increase the event counter
+  ++m_nEventsProcessed;
+
+  // Simple status message at the beginning of each event execute,
+  ATH_MSG_DEBUG ( "==> addBranches " << name() << " on " << m_nEventsProcessed << ". event..." );
+
+  if ( m_outCollKey.value().empty() ) {
+    // Try to get the input container as non-const
+    ATH_MSG_DEBUG("Got an empty 'OutputCollection' property. "
+                  << "Trying to retrieve a non-const version of the 'InputContainer'...");
+    xAOD::IParticleContainer* inCont = evtStore()->tryRetrieve<xAOD::IParticleContainer>( m_inCollKey.value() );
+    if (inCont){ ATH_CHECK( this->doSort(inCont) ); }
+    else {
+      ATH_MSG_DEBUG("We couldn't retrieve a non-const version of the input container... try const.");
+      const xAOD::IParticleContainer* inCont2 = nullptr;
+      ATH_CHECK( evtStore()->retrieve( inCont2, m_inCollKey.value()) );
+      // Now, do the copy and sorting and overwriting of all known container types
+      if (false) {
+      }
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::MuonContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::ElectronContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::PhotonContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::TauJetContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::JetContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::PFOContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::NeutralParticleContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::TrackParticleContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::TruthParticleContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::CompositeParticleContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::ParticleContainer)
+      OVERWRITE_AND_SORT_CONTAINER(xAOD::CaloClusterContainer)
+      else {
+        ATH_MSG_ERROR("Couln't find the provided intput container in store gate for later overwriting");
+        return StatusCode::FAILURE;
+      }
+    }
+  }
+  else {
+    ATH_MSG_DEBUG("Got a non-empty 'OutputCollection' property. "
+                  << "Trying to retrieve a const version of the 'InputContainer'...");
+
+    // Now, do the copy and sorting of all known container types
+    if (false) {
+    }
+    COPY_AND_SORT_CONTAINER(xAOD::MuonContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::ElectronContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::PhotonContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::TauJetContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::JetContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::PFOContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::NeutralParticleContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::TrackParticleContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::TruthParticleContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::CompositeParticleContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::ParticleContainer)
+    COPY_AND_SORT_CONTAINER(xAOD::CaloClusterContainer)
+    else {
+      ATH_MSG_ERROR("Couln't find the provided intput container in store gate");
+      return StatusCode::FAILURE;
+    }
+
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+StatusCode ParticleSortingTool::doSort( xAOD::IParticleContainer* cont ) const
+{
+  if ( !cont ) {
+    ATH_MSG_ERROR("No container to be sorted");
+    return StatusCode::FAILURE;
+  }
+  // Actually do the sorting, using a C++11 lambda function construct
+  // to be able to use the member function here
+  if ( std::abs(m_sortID) == 1 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->comparePt(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 2 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareEta(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 3 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->comparePhi(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 4 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareMass(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 5 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareEnergy(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 6 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareRapidity(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 7 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareAuxData(a,b);
+                } );
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+bool ParticleSortingTool::comparePt( const xAOD::IParticle* partA,
+                                     const xAOD::IParticle* partB ) const
+{
+  const double a = partA->pt();
+  const double b = partB->pt();
+  return this->compareDouble(a,b);
+}
+
+
+bool ParticleSortingTool::compareEta( const xAOD::IParticle* partA,
+                                      const xAOD::IParticle* partB ) const
+{
+  const double a = partA->eta();
+  const double b = partB->eta();
+  return this->compareDouble(a,b);
+}
+
+
+bool ParticleSortingTool::comparePhi( const xAOD::IParticle* partA,
+                                      const xAOD::IParticle* partB ) const
+{
+  const double a = partA->phi();
+  const double b = partB->phi();
+  return this->compareDouble(a,b);
+}
+
+
+bool ParticleSortingTool::compareMass( const xAOD::IParticle* partA,
+                                       const xAOD::IParticle* partB ) const
+{
+  const double a = partA->m();
+  const double b = partB->m();
+  return this->compareDouble(a,b);
+}
+
+
+bool ParticleSortingTool::compareEnergy( const xAOD::IParticle* partA,
+                                         const xAOD::IParticle* partB ) const
+{
+  const double a = partA->e();
+  const double b = partB->e();
+  return this->compareDouble(a,b);
+}
+
+
+bool ParticleSortingTool::compareRapidity( const xAOD::IParticle* partA,
+                                           const xAOD::IParticle* partB ) const
+{
+  const double a = partA->rapidity();
+  const double b = partB->rapidity();
+  return this->compareDouble(a,b);
+}
+
+bool ParticleSortingTool::compareAuxData( const xAOD::IParticle* partA,
+                                       const xAOD::IParticle* partB ) const
+{
+  const double a = partA->auxdata<float>( this->m_sortVar.value() );
+  const double b = partB->auxdata<float>( this->m_sortVar.value() );
+  return this->compareDouble(a,b);
+}
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h
new file mode 100644
index 00000000000..dc097711cfb
--- /dev/null
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h
@@ -0,0 +1,183 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
+// ParticleSortingTool.h
+// Header file for class ParticleSortingTool
+// Author: Karsten Koeneke <karsten.koeneke@cern.ch>
+///////////////////////////////////////////////////////////////////
+#ifndef EVENTUTILS_PARTICLESORTINGTOOL_H
+#define EVENTUTILS_PARTICLESORTINGTOOL_H 1
+
+// FrameWork includes
+#include "AthenaBaseComps/AthAlgTool.h"
+#include "DerivationFrameworkInterfaces/IAugmentationTool.h"
+#include "CxxUtils/fpcompare.h"
+
+// EDM inlcudes
+#include "xAODBase/IParticle.h"
+#include "xAODBase/IParticleContainer.h"
+#include "AthContainers/ConstDataVector.h"
+
+// STL includes
+#include <vector>
+#include <string>
+#include <cmath>
+
+class ParticleSortingTool
+  : virtual public ::DerivationFramework::IAugmentationTool,
+            public ::AthAlgTool
+{
+
+  ///////////////////////////////////////////////////////////////////
+  // Public methods:
+  ///////////////////////////////////////////////////////////////////
+public:
+
+  // Copy constructor:
+
+  /// Constructor with parameters:
+  ParticleSortingTool( const std::string& type,
+                       const std::string& name,
+                       const IInterface* parent );
+
+  /// Destructor:
+  virtual ~ParticleSortingTool();
+
+  /// Athena algtool's initialize
+  virtual StatusCode  initialize() override;
+
+  /// Athena algtool's finalize
+  virtual StatusCode  finalize() override;
+
+
+  /// Implement the method from the ISkimmingTool interface
+  virtual StatusCode addBranches() const final override;
+
+
+
+// Private methods
+private:
+
+  /// Helper method that implements the call to the right sort function
+  StatusCode doSort( xAOD::IParticleContainer* cont ) const;
+
+  /// Helper method to sort a ConstDataVector
+  template<class CONTAINERTYPE>
+  StatusCode doSortConst( ConstDataVector<CONTAINERTYPE>* cont ) const;
+
+  /// The method to compare the particle's pt
+  bool comparePt( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare the particle's eta
+  bool compareEta( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare the particle's phi
+  bool comparePhi( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare the particle's mass
+  bool compareMass( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare the particle's energy
+  bool compareEnergy( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare the particle's rapidity
+  bool compareRapidity( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// The method to compare an auxdata member of the particle
+  bool compareAuxData( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const;
+
+  /// Method to compare two doubles
+  inline bool compareDouble( double a, double b ) const;
+
+
+  ///////////////////////////////////////////////////////////////////
+  // Private data:
+  ///////////////////////////////////////////////////////////////////
+private:
+
+  /// Input container name
+  StringProperty m_inCollKey;
+
+  /// The name of the output container (with SG::VIEW_ELEMENTS) with the sorted copy of input objects
+  StringProperty m_outCollKey;
+
+  /// Define by what parameter to sort (default: 'pt')
+  StringProperty m_sortVar;
+
+  /// Define if the container should be sorted in a descending order (default=true)
+  BooleanProperty m_sortDescending;
+
+
+  /// Internal container type identifier
+  mutable unsigned int m_contID;
+
+  /// Internal identifier for the type of sorting
+  mutable int m_sortID;
+
+  /// Internal event counter
+  mutable unsigned long m_nEventsProcessed;
+
+};
+
+
+inline bool ParticleSortingTool::compareDouble( double a, double b ) const
+{
+  if ( m_sortID < 0 ) { return CxxUtils::fpcompare::greater(a,b); }
+  else { return CxxUtils::fpcompare::less(a,b); }
+}
+
+
+template<class CONTAINERTYPE>
+StatusCode ParticleSortingTool::doSortConst( ConstDataVector<CONTAINERTYPE>* cont ) const
+{
+  if ( !cont ) {
+    ATH_MSG_ERROR("No ConstDataVector to be sorted");
+    return StatusCode::FAILURE;
+  }
+  // Actually do the sorting, using a C++11 lambda function construct
+  // to be able to use the member function here
+  if ( std::abs(m_sortID) == 1 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->comparePt(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 2 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareEta(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 3 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->comparePhi(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 4 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareMass(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 5 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareEnergy(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 6 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareRapidity(a,b);
+                } );
+  }
+  else if ( std::abs(m_sortID) == 7 ) {
+    cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) {
+                  return this->compareAuxData(a,b);
+                } );
+  }
+
+  return StatusCode::SUCCESS;
+}
+
+
+
+#endif //> !EVENTUTILS_PARTICLESORTINGTOOL_H
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx
index 557082712e4..1f217ab44bc 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx
@@ -1,3 +1,5 @@
+#include "../ParticleSortingTool.h"
+#include "../ParticleSortingAlg.h"
 #include "../CutTool.h"
 #include "../CutAlg.h"
 #include "../ParticleSelectionTool.h"
@@ -7,6 +9,8 @@
 #include "../TriggerSelectionAlg.h"
 #include "../EventDecisionAlg.h"
 
+DECLARE_COMPONENT( ParticleSortingTool )
+DECLARE_COMPONENT( ParticleSortingAlg )
 DECLARE_COMPONENT( CutTool )
 DECLARE_COMPONENT( CutAlg )
 DECLARE_COMPONENT( ParticleSelectionTool )
-- 
GitLab