diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt b/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt
index 73a5d549f74a19aaa99913585e8933fc1a235eaa..79357c8409121c3e9c760f959c7ab9159a2a84bb 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt
@@ -11,4 +11,4 @@ atlas_add_component( EventUtils
                      src/*.cxx
                      src/components/*.cxx
                      INCLUDE_DIRS ${Boost_INCLUDE_DIRS}
-                     LINK_LIBRARIES ${Boost_LIBRARIES} AthAnalysisBaseCompsLib AthContainers AthContainersInterfaces AthLinks AthenaBaseComps AthenaKernel EventInfo xAODBase xAODCaloEvent xAODCore xAODCutFlow xAODEgamma xAODEventInfo xAODJet xAODMuon xAODPFlow xAODParticleEvent xAODTau xAODTracking xAODTruth GaudiKernel PATCoreLib ExpressionEvaluationLib TrigDecisionToolLib DerivationFrameworkInterfaces )
+                     LINK_LIBRARIES ${Boost_LIBRARIES} AsgTools AthAnalysisBaseCompsLib AthContainers AthContainersInterfaces AthLinks AthenaBaseComps AthenaKernel EventInfo xAODBase xAODCaloEvent xAODCore xAODCutFlow xAODEgamma xAODEventInfo xAODJet xAODMuon xAODPFlow xAODParticleEvent xAODTau xAODTracking xAODTruth GaudiKernel PATCoreLib ExpressionEvaluationLib TrigDecisionToolLib DerivationFrameworkInterfaces )
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx
index 7642a29a3d29b82625be3b151c3385bf2a1890b6..4220165760fb62d45e60dd4a1152c8d5661487b6 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx
@@ -39,7 +39,7 @@ CutAlg::CutAlg( const std::string& name,
   m_cut(""),
   m_nEventsProcessed(0)
 {
-  declareProperty("Cut",              m_cut="",           "The name of the output container" );
+  declareProperty("Cut",              m_cut="",           "The cut expression" );
   declareProperty("TrigDecisionTool", m_trigDecisionTool, "If you do not use trigger decisions and want to ensure the TrigDecisionTool is not loaded, set this to a blank string");
 }
 
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx
index 86e11806ff28db10d4c370901464c7324493341a..e65d23e79b8f36019f87006e3c675444e33dbcc2 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx
@@ -1,9 +1,9 @@
 ///////////////////////// -*- C++ -*- /////////////////////////////
-
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
+
+/*
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+*/
+
 // EventQualityFilterAlg.cxx
 // Implementation file for class EventQualityFilterAlg
 // Author: Karsten Koeneke <karsten.koeneke@cern.ch>
@@ -16,6 +16,10 @@
 // EDM includes
 #include "xAODEventInfo/EventInfo.h"
 
+// FrameWork includes
+#include "AsgDataHandles/ReadHandle.h"
+#include "AsgTools/CurrentContext.h"
+
 
 ///////////////////////////////////////////////////////////////////
 // Public methods:
@@ -62,6 +66,7 @@ StatusCode EventQualityFilterAlg::initialize()
   ATH_MSG_DEBUG( "Using: " << m_useSCTError );
   ATH_MSG_DEBUG( "Using: " << m_useCoreError );
   // ATH_MSG_DEBUG( "Using: " << m_useTileTripReader );
+  ATH_CHECK(m_eventInfo.initialize());
   return StatusCode::SUCCESS;
 }
 
@@ -79,10 +84,15 @@ StatusCode EventQualityFilterAlg::execute()
 {
   ATH_MSG_DEBUG ("Executing " << name() << "...");
 
+  const EventContext& ctx = Gaudi::Hive::currentContext();
 
   // Get the EventInfo object
-  const xAOD::EventInfo* eventInfo = nullptr;
-  ATH_CHECK( evtStore()->retrieve(eventInfo) );
+  SG::ReadHandle<xAOD::EventInfo> eventInfo(m_eventInfo, ctx);
+  if (!eventInfo.isValid()) {
+    ATH_MSG_ERROR("Could not retrieve EventInfo!");
+    return StatusCode::FAILURE;
+  }
+
 
 
   // Only do the event vetoing on data
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h
index b62e0516700163d82933c99fd9a18eb40a611e31..b19bc46bee0cf48de4b25c3ee06dbab7adfb2a0c 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h
@@ -1,7 +1,7 @@
 ///////////////////////// -*- C++ -*- /////////////////////////////
 
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // EventQualityFilterAlg.h
@@ -17,6 +17,7 @@
 
 // FrameWork includes
 #include "AthenaBaseComps/AthFilterAlgorithm.h"
+#include "AsgDataHandles/ReadHandleKey.h"
 
 
 
@@ -69,6 +70,9 @@ class EventQualityFilterAlg
   // /// Flag to turn on/off checking of tile trip information
   // BooleanProperty m_useTileTripReader;
 
+  /// EventInfo read handle
+  SG::ReadHandleKey<xAOD::EventInfo> m_eventInfo {this, "EventInfo", "EventInfo", "EventInfo key"};
+
 
 };
 
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx
index 50558acd75fca99d9d94e3097b4f8dcc784cbf8a..8656e485190678f4dddc9d5e53000924b8dc700e 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx
@@ -1,7 +1,7 @@
 ///////////////////////// -*- C++ -*- /////////////////////////////
 
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // ParticleSelectionAlg.cxx
@@ -12,8 +12,6 @@
 // EventUtils includes
 #include "ParticleSelectionAlg.h"
 
-// STL includes
-
 // FrameWork includes
 #include "Gaudi/Property.h"
 #include "DerivationFrameworkInterfaces/IAugmentationTool.h"
@@ -57,7 +55,6 @@
 #include "xAODCutFlow/CutBookkeeperContainer.h"
 #include "xAODCutFlow/CutBookkeeperAuxContainer.h"
 
-
 ///////////////////////////////////////////////////////////////////
 // Public methods:
 ///////////////////////////////////////////////////////////////////
@@ -67,8 +64,8 @@
 ParticleSelectionAlg::ParticleSelectionAlg( const std::string& name,
                                             ISvcLocator* pSvcLocator ) :
   ::AthAnalysisAlgorithm( name, pSvcLocator ),
+  m_selTools(),     // makes these tools public
   m_evtInfoName("EventInfo"),
-  m_inPrimVtxCont("PrimaryVertices"),
   m_inCollKey(""),
   m_outCollKey(""),
   m_writeSplitAux(true),
@@ -83,11 +80,9 @@ ParticleSelectionAlg::ParticleSelectionAlg( const std::string& name,
   m_contType(UNKNOWN),
   m_cutBKStartIdx(0),
   m_selToolIdxOffset(),
-  m_selWPVToolIdxOffset(),
   m_idxSelParster(0)
 {
   declareProperty("EventInfo",                 m_evtInfoName,   "Input container name");
-  declareProperty("PrimaryVertexContainer",    m_inPrimVtxCont, "The input primary vertex container name");
   declareProperty("InputContainer",            m_inCollKey,     "Input container name");
   declareProperty("OutputContainer",           m_outCollKey,
                   "The name of the output container with the deep copy of selected xAOD::IParticles");
@@ -96,6 +91,7 @@ ParticleSelectionAlg::ParticleSelectionAlg( const std::string& name,
   declareProperty("OutputContainerOwnershipPolicy", m_outOwnPolicyName,
                   "Defines the ownership policy of the output container (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')");
 
+  declareProperty("SelectionToolList",       m_selTools,     "The list of IAsgSelectionTools");
   declareProperty("Selection",               m_selection,
                   "The selection string that defines which xAOD::IParticles to select from the container");
 
@@ -121,13 +117,15 @@ StatusCode ParticleSelectionAlg::initialize()
   ATH_MSG_DEBUG ("Initializing " << name() << "...");
 
   // Print out the used configuration
-  ATH_MSG_DEBUG ( " using = " << m_inCollKey );
-  ATH_MSG_DEBUG ( " using = " << m_outCollKey );
-  ATH_MSG_DEBUG ( " using = " << m_writeSplitAux );
-  ATH_MSG_DEBUG ( " using = " << m_outOwnPolicyName );
-  ATH_MSG_DEBUG ( " using = " << m_selection );
+  ATH_MSG_DEBUG ( " using EventInfo = " << m_evtInfoName );
+  ATH_MSG_DEBUG ( " using InputContainer = " << m_inCollKey );
+  ATH_MSG_DEBUG ( " using OutputContainer = " << m_outCollKey );
+  ATH_MSG_DEBUG ( " using WriteSplitOutputContainer = " << m_writeSplitAux );
+  ATH_MSG_DEBUG ( " using OutputContainerOwnershipPolicy = " << m_outOwnPolicyName );
+  ATH_MSG_DEBUG ( " using SelectionToolList = " << m_selTools );
+  ATH_MSG_DEBUG ( " using Selection = " << m_selection );
   ATH_MSG_DEBUG ( " using DoCutBookkeeping = " << m_doCutFlow );
-  ATH_MSG_DEBUG ( " using = " << m_cutBKCName );
+  ATH_MSG_DEBUG ( " using CutBookkeeperContainer = " << m_cutBKCName );
 
   // initialize proxy loaders for expression parsing
   if ( !(m_selection.value().empty()) ){
@@ -154,6 +152,9 @@ StatusCode ParticleSelectionAlg::initialize()
     return StatusCode::FAILURE;
   }
 
+  // Retrieve all tools
+  ATH_CHECK( m_selTools.retrieve() );
+
   ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." );
   return StatusCode::SUCCESS;
 }
@@ -164,6 +165,9 @@ StatusCode ParticleSelectionAlg::finalize()
 {
   ATH_MSG_DEBUG ("Finalizing " << name() << "...");
 
+  // Release all tools and services
+  ATH_CHECK( m_selTools.release() );
+
   // Clean up the memory
   if (m_parser) {
     delete m_parser;
@@ -218,6 +222,34 @@ StatusCode ParticleSelectionAlg::start()
     ATH_MSG_VERBOSE( "Recorded xAOD::CutBookkeeperContainer " << m_cutBKCName.value() << "Aux." );
   }
 
+  //------------- for the AsgSelectionTools --------------
+  // Now, register one CutBookkeeper per cut that will be applied.
+  // For each of the registered tools, get the TAccept and ask it for all known cuts.
+  for ( std::size_t toolIdx=0; toolIdx < m_selTools.size(); ++toolIdx ){
+    const ToolHandle<IAsgSelectionTool>& tool = m_selTools[toolIdx];
+    // Fill the index bookkeeping at what index in the CutBookkeeperContainer
+    // the CutBookkeepers for this tool start.
+    m_selToolIdxOffset.push_back( cutBKCont->size() );
+    // Get some needed quantities
+    const std::string toolName = tool->name();
+    const asg::AcceptInfo& acceptInfo = tool->getAcceptInfo();
+    const unsigned int nCuts = acceptInfo.getNCuts();
+    for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){
+      // Get the name and description of this cut
+      const std::string cutName  = acceptInfo.getCutName(iCut);
+      const std::string cutDescr = acceptInfo.getCutDescription(iCut);
+      // Create a new xAOD::CutBookkeeper and add it to the container
+      xAOD::CutBookkeeper* cutBK = new xAOD::CutBookkeeper();
+      cutBKCont->push_back(cutBK);
+      // Now, set its properties
+      cutBK->setName(toolName+"_"+cutName);
+      cutBK->setDescription(cutDescr);
+      cutBK->setCutLogic(xAOD::CutBookkeeper::CutLogic::REQUIRE); // Each cut must be passed, thus REQUIRE, i.e, logical AND
+      cutBK->setInputStream(inputStreamName);
+      cutBK->setCycle(maxInputCycle);
+    }
+  }
+
   //------------- for the ExpressionParsing in this algorithm --------------
   if ( !(m_selection.value().empty()) ){
     // Create a new xAOD::CutBookkeeper and add it to the container
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h
index 3c17dd6afa9fcf8f431882e9f03b9b35816beb4b..b5acec334ad0d0411af3f8dfa35c0d532674a2d5 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h
@@ -1,7 +1,7 @@
 ///////////////////////// -*- C++ -*- /////////////////////////////
 
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // ParticleSelectionAlg.h
@@ -11,10 +11,6 @@
 #ifndef EVENTUTILS_PARTICLESELECTIONALG_H
 #define EVENTUTILS_PARTICLESELECTIONALG_H 1
 
-// STL includes
-#include <string>
-#include <vector>
-
 // FrameWork includes
 #include "GaudiKernel/ToolHandle.h"
 // #include "GaudiKernel/ServiceHandle.h"
@@ -22,6 +18,11 @@
 #include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
 #include "xAODBase/IParticleContainer.h"
 //#include "TrigDecisionTool/TrigDecisionTool.h"
+#include "PATCore/IAsgSelectionTool.h"
+
+// STL includes
+#include <string>
+#include <vector>
 
 // // Forward declarations
 // namespace Trig{
@@ -76,12 +77,12 @@ class ParticleSelectionAlg
   // Private data:
   ///////////////////////////////////////////////////////////////////
  private:
+  /// The list of IAsgSelectionTools
+  ToolHandleArray<IAsgSelectionTool> m_selTools;
+
   /// Name of the EventInfo object
   StringProperty m_evtInfoName;
 
-  /// Name of the PrimaryVertex container
-  StringProperty m_inPrimVtxCont;
-
   /// Input container name
   StringProperty m_inCollKey;
 
@@ -153,10 +154,6 @@ class ParticleSelectionAlg
   /// starting index of the corresponding CutBookKeeper inside the CutBookkeeperContainer.
   std::vector<std::size_t> m_selToolIdxOffset;
 
-  /// The list of pairs of the tool index of the AsgSelectionWithVertexTools and the
-  /// starting index of the corresponding CutBookKeeper inside the CutBookkeeperContainer.
-  std::vector<std::size_t> m_selWPVToolIdxOffset;
-
   /// Store the index of the CutBookKeeper in the CutBookkeeperContainer for the
   /// selection using the ExpressionParser
   std::size_t m_idxSelParster;
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc
index 84370ef7b9c8c34021cd3454469d9d9b0098e633..2d4ed4e6c4b4c7aec25b595137105918c29ba444 100644
--- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc
+++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc
@@ -1,7 +1,7 @@
 // Dear emacs, this is -*- c++ -*-
 
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 
@@ -9,8 +9,6 @@
 #include "xAODCore/AuxContainerBase.h"
 #include "AthContainers/ConstDataVector.h"
 #include "xAODEventInfo/EventInfo.h"
-#include "xAODTracking/VertexContainer.h"
-#include "xAODTracking/Vertex.h"
 #include "xAODCutFlow/CutBookkeeperContainer.h"
 #include "PATCore/AcceptInfo.h"
 #include "PATCore/AcceptData.h"
@@ -82,6 +80,32 @@ StatusCode ParticleSelectionAlg::selectParticles(const xAOD::IParticleContainer*
     // the remainder of the cuts will not even be tried
     bool passEverything = true;
 
+    //------------- for the AsgSelectionTools --------------
+    // Loop over all selection tools
+    ATH_MSG_VERBOSE("Loop over all selection tools");
+    for ( std::size_t toolIdx=0; toolIdx < m_selTools.size(); ++toolIdx ){
+      if (passEverything){
+        ATH_MSG_VERBOSE("Now going to try AsgSelectionTools number " << toolIdx );
+        const asg::AcceptData acceptData = m_selTools[toolIdx]->accept(part);
+        if (!m_doCutFlow){ passEverything &= static_cast<bool>(acceptData); }
+        else {
+          const std::size_t cbkStartIdx = m_selToolIdxOffset[toolIdx];
+          const unsigned int nCuts = acceptData.getNCuts();
+          for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){
+            passEverything &= acceptData.getCutResult(iCut);
+            if (passEverything){
+              const std::size_t currentCBKIdx = cbkStartIdx + iCut;
+              xAOD::CutBookkeeper* cutBK = cutBKCont->at(currentCBKIdx);
+              cutBK->addNAcceptedEvents(1);
+              cutBK->addSumOfEventWeights(eventWeight);
+              cutBK->addSumOfEventWeightsSquared(eventWeight*eventWeight);
+            }
+          }
+        } // Done doing detailed particle cut-flow for this tool
+        ATH_MSG_VERBOSE("AsgSelectionTools number " << toolIdx << " passed/failed: " << passEverything );
+      }
+    }
+
     //------------- for the ExpressionParsing in this algorithm --------------
     ATH_MSG_VERBOSE("Looking at expression parser result: " << passEverything);
     if ( passEverything && !(resultVec.empty()) ){
diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f5ad85275d7fda499fa4e9ee13f2a4490c6a552c
--- /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 0000000000000000000000000000000000000000..763f04c952cab1305f4467bf3595943579326178
--- /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 0000000000000000000000000000000000000000..876c7e005d22ee27a6c552c9dd4a51180907afc3
--- /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 0000000000000000000000000000000000000000..dc097711cfb25798ce5dcdc24dd85b4188fc18b1
--- /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 4a60ef060d833692aeaa4e0acef5b62e3d1e69be..1f217ab44bc034c41a03ce489c916891a10c2e04 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 )
@@ -15,4 +19,3 @@ DECLARE_COMPONENT( EventQualityFilterAlg )
 DECLARE_COMPONENT( ParticleRemoverAlg )
 DECLARE_COMPONENT( TriggerSelectionAlg )
 DECLARE_COMPONENT( EventDecisionAlg )
-
diff --git a/PhysicsAnalysis/AnalysisCommon/PATCore/PATCore/IAsgSelectionTool.h b/PhysicsAnalysis/AnalysisCommon/PATCore/PATCore/IAsgSelectionTool.h
index 791dea0bd9e28e910ff64d45da45849ab38590df..6e8e2db1902e75551b246c6bc9f1b8bcdc3696f9 100644
--- a/PhysicsAnalysis/AnalysisCommon/PATCore/PATCore/IAsgSelectionTool.h
+++ b/PhysicsAnalysis/AnalysisCommon/PATCore/PATCore/IAsgSelectionTool.h
@@ -1,7 +1,7 @@
 ///////////////////////// -*- C++ -*- /////////////////////////////
 
 /*
-  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
 */
 
 // IAsgSelectionTool.h 
@@ -11,9 +11,6 @@
 #ifndef PATCORE_IASGSELECTIONTOOL_H
 #define PATCORE_IASGSELECTIONTOOL_H 1
 
-// STL includes
-
-
 // FrameWork includes
 #include "AsgTools/IAsgTool.h"
 
@@ -26,7 +23,6 @@ namespace xAOD{
   class IParticle;
 }
 
-
 class  IAsgSelectionTool
   : virtual public asg::IAsgTool
 { 
@@ -51,6 +47,6 @@ class  IAsgSelectionTool
   virtual asg::AcceptData accept( const xAOD::IParticle* /*part*/ ) const = 0;
 
 
-}; 
+};
 
 #endif //> !PATCORE_IASGSELECTIONTOOL_H