From 1ec35774aacc80cf91da247a8ac4bc34317f0dd0 Mon Sep 17 00:00:00 2001
From: Niels Van Eldik <niels.van.eldik@cern.ch>
Date: Tue, 16 Sep 2014 10:05:42 +0200
Subject: [PATCH] requirements cleanup (MuonSelectorTools-00-04-01)

---
 .../MuonSelectorTools/IMuonSelectionTool.h    |  55 ++++
 .../MuonSelectorTools/MuonSelectionTool.h     |  93 ++++++
 .../MuonSelectorTools/errorcheck.h            |  21 ++
 .../MuonID/MuonSelectorTools/Root/LinkDef.h   |  17 ++
 .../Root/MuonSelectionTool.cxx                | 280 ++++++++++++++++++
 .../MuonSelectorTools/cmt/Makefile.RootCore   |  16 +
 .../MuonID/MuonSelectorTools/cmt/requirements |  24 ++
 .../python/MuonSelectorCutDefs.py             |  77 +++++
 .../MuonSelectorTools/python/__init__.py      |   2 +
 .../exampleMuonSelectionAlg_jobOptions.py     |  10 +
 .../src/MuonSelectionAlg.cxx                  |  53 ++++
 .../MuonSelectorTools/src/MuonSelectionAlg.h  |  40 +++
 .../components/MuonSelectorTools_entries.cxx  |  20 ++
 .../src/components/MuonSelectorTools_load.cxx |   2 +
 .../util/MuonSelectorToolsTester.cxx          | 248 ++++++++++++++++
 15 files changed, 958 insertions(+)
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/IMuonSelectionTool.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/MuonSelectionTool.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/errorcheck.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/Root/LinkDef.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/Root/MuonSelectionTool.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/Makefile.RootCore
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/requirements
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/python/MuonSelectorCutDefs.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/python/__init__.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/share/exampleMuonSelectionAlg_jobOptions.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_entries.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_load.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonSelectorTools/util/MuonSelectorToolsTester.cxx

diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/IMuonSelectionTool.h b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/IMuonSelectionTool.h
new file mode 100644
index 0000000000000..0cb3ef942244b
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/IMuonSelectionTool.h
@@ -0,0 +1,55 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: IMuonSelectionTool.h 299883 2014-03-28 17:34:16Z krasznaa $
+#ifndef MUONSELECTORTOOLS_IMUONSELECTIONTOOL_H
+#define MUONSELECTORTOOLS_IMUONSELECTIONTOOL_H
+
+// Framework include(s):
+#include "AsgTools/IAsgTool.h"
+#include "PATCore/TAccept.h"
+
+// EDM include(s):
+#include "xAODMuon/Muon.h"
+
+namespace CP {
+
+   /// Interface for (a) muon selector tool(s)
+   ///
+   /// This is an example of how to define object selection in
+   /// a tool.
+   ///
+   /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>
+   ///
+   /// $Revision: 299883 $
+   /// $Date: 2014-03-28 18:34:16 +0100 (Fri, 28 Mar 2014) $
+   ///
+   class IMuonSelectionTool : public virtual asg::IAsgTool {
+
+      /// Declare the interface that the class provides
+      ASG_TOOL_INTERFACE( CP::IMuonSelectionTool )
+
+   public:
+      /// Decide whether the muon in question is a "good muon" or not
+      virtual const Root::TAccept& accept( const xAOD::Muon& mu ) const = 0;
+
+      /// set the passes ID cuts variable of the muon 
+      virtual void setPassesIDCuts( xAOD::Muon& mu ) const = 0;
+
+      /// set the passes quality variable of the muon 
+      virtual void setQuality( xAOD::Muon& mu ) const = 0;
+
+      /// Returns true if the muon passes the standard MCP ID cuts. To set the value on the muon, instead call setPassesIDCuts(xAOD::Muon&) const
+      virtual bool                passedIDCuts(const xAOD::Muon&) const =0;
+      
+      /// Returns the quality of the muon. To set the value on the muon, instead call setQuality(xAOD::Muon&) const
+      virtual xAOD::Muon::Quality getQuality(const xAOD::Muon& mu ) const =0;
+
+   }; // class IMuonSelectionTool
+
+} // namespace CP
+
+#endif // CPTOOLTESTS_IMUONSELECTIONTOOL_H
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/MuonSelectionTool.h b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/MuonSelectionTool.h
new file mode 100644
index 0000000000000..c522c5e96b721
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/MuonSelectionTool.h
@@ -0,0 +1,93 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: MuonSelectionTool.h 299883 2014-03-28 17:34:16Z krasznaa $
+#ifndef MUONSELECTORTOOLS_MUONSELECTIONTOOL_H
+#define MUONSELECTORTOOLS_MUONSELECTIONTOOL_H
+
+// Framework include(s):
+#include "AsgTools/AsgTool.h"
+#include "PATCore/IAsgSelectionTool.h"
+
+// Local include(s):
+#include "MuonSelectorTools/IMuonSelectionTool.h"
+
+namespace CP {
+
+   /// Implementation of the muon selector tool
+   ///
+   /// Example implementation of how an object selector tool should
+   /// look according to the TF3 recommendations.
+   ///
+   /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>
+   ///
+   /// $Revision: 299883 $
+   /// $Date: 2014-03-28 18:34:16 +0100 (Fri, 28 Mar 2014) $
+   ///
+   class MuonSelectionTool : public virtual IAsgSelectionTool,
+                             public virtual IMuonSelectionTool,
+                             public asg::AsgTool {
+
+      /// Create a proper constructor for Athena
+      ASG_TOOL_CLASS2( MuonSelectionTool, IAsgSelectionTool,
+                       CP::IMuonSelectionTool )
+
+   public:
+      /// Constructor for standalone usage
+      MuonSelectionTool( const std::string& name );
+
+      /// @name Function(s) implementing the asg::IAsgTool interface
+      /// @{
+
+      /// Function initialising the tool
+      virtual StatusCode initialize();
+
+      /// @}
+
+      /// @name Function(s) implementing the IAsgSelectionTool interface
+      /// @{
+
+      /// Get an object describing the "selection steps" of the tool
+      virtual const Root::TAccept& getTAccept() const;
+
+      /// Get the decision using a generic IParticle pointer
+      virtual const Root::TAccept& accept( const xAOD::IParticle* p ) const;
+
+      /// @}
+
+      /// @name Function(s) implementing the IMuonSelectorTool interface
+      /// @{
+
+      /// Get the decision for a specific Muon object
+      virtual const Root::TAccept& accept( const xAOD::Muon& mu ) const;
+
+      /// set the passes ID cuts variable of the muon 
+      void setPassesIDCuts(xAOD::Muon&) const;
+
+      /// set the passes quality variable of the muon 
+      void setQuality( xAOD::Muon& mu ) const;
+
+      /// Returns true if the muon passes the standard MCP ID cuts. To set the value on the muon, instead call setPassesIDCuts(xAOD::Muon&) const
+      bool                    passedIDCuts(const xAOD::Muon&) const;
+      
+      /// Returns the quality of the muon. To set the value on the muon, instead call setQuality(xAOD::Muon&) const
+      xAOD::Muon::Quality     getQuality(const xAOD::Muon& mu ) const;
+
+      /// @}
+
+
+   private:
+      /// Maximum pseudorapidity for the selected muons
+      double m_maxEta;
+
+      /// Object used to store the last decision
+      mutable Root::TAccept m_accept;
+
+   }; // class MuonSelectionTool
+
+} // namespace CP
+
+#endif // CPTOOLTESTS_MUONSELECTIONTOOL_H
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/errorcheck.h b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/errorcheck.h
new file mode 100644
index 0000000000000..6c22677eec197
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/MuonSelectorTools/errorcheck.h
@@ -0,0 +1,21 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: errorcheck.h 299732 2014-03-27 17:41:34Z krasznaa $
+#ifndef CPTOOLTESTS_ERRORCHECK_H
+#define CPTOOLTESTS_ERRORCHECK_H
+
+#define CHECK( ARG )                                     \
+   do {                                                  \
+      const bool result = ARG;                           \
+      if( ! result ) {                                   \
+         ::Error( APP_NAME, "Failed to execute: \"%s\"", \
+                  #ARG );                                \
+         return 1;                                       \
+      }                                                  \
+   } while( false )
+
+#endif // CPTOOLTESTS_ERRORCHECK_H
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/LinkDef.h b/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/LinkDef.h
new file mode 100644
index 0000000000000..3501b674da8fe
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/LinkDef.h
@@ -0,0 +1,17 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef __MUONSELECTORTOOLS__
+#define __MUONSELECTORTOOLS__
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+#pragma link C++ nestedclass;
+
+#endif
+
+#endif
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/MuonSelectionTool.cxx b/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/MuonSelectionTool.cxx
new file mode 100644
index 0000000000000..a301d2d6cc0de
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/Root/MuonSelectionTool.cxx
@@ -0,0 +1,280 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// $Id: MuonSelectionTool.cxx 299883 2014-03-28 17:34:16Z krasznaa $
+
+// Local include(s):
+#include "MuonSelectorTools/MuonSelectionTool.h"
+#include "xAODTracking/TrackingPrimitives.h"
+
+namespace CP {
+
+   MuonSelectionTool::MuonSelectionTool( const std::string& name )
+      : asg::AsgTool( name ),
+        m_accept( "MuonSelection" ) {
+
+      declareProperty( "MaxEta", m_maxEta = 2.5 );
+   }
+
+   StatusCode MuonSelectionTool::initialize() {
+
+      // Greet the user:
+      ATH_MSG_INFO( "Initialising..." );
+      ATH_MSG_DEBUG( "Maximum eta: " << m_maxEta );
+
+      // Set up the TAccept object:
+      m_accept.addCut( "Eta",
+                       "Selection of muons according to their pseudorapidity" );
+      m_accept.addCut( "Quality",
+                       "Selection of muons according to their tightness" );
+      m_accept.addCut( "IDHits",
+                       "Selection of muons according to whether they passed the MCP ID Hit cuts" );
+      // Return gracefully:
+      return StatusCode::SUCCESS;
+   }
+
+   const Root::TAccept& MuonSelectionTool::getTAccept() const {
+
+      return m_accept;
+   }
+
+   const Root::TAccept&
+   MuonSelectionTool::accept( const xAOD::IParticle* p ) const {
+
+      // Reset the result:
+      m_accept.clear();
+
+      // Check if this is a muon:
+      if( p->type() != xAOD::Type::Muon ) {
+         ATH_MSG_ERROR( "accept(...) Function received a non-muon" );
+         return m_accept;
+      }
+
+      // Cast it to a muon:
+      const xAOD::Muon* mu = dynamic_cast< const xAOD::Muon* >( p );
+      if( ! mu ) {
+         ATH_MSG_FATAL( "accept(...) Failed to cast particle to muon" );
+         return m_accept;
+      }
+
+      // Let the specific function do the work:
+      return accept( *mu );
+   }
+
+   const Root::TAccept& MuonSelectionTool::accept( const xAOD::Muon& mu ) const {
+
+      // Reset the result:
+      m_accept.clear();
+
+      // Do the eta cut:
+      ATH_MSG_VERBOSE( "Muon eta: " << mu.eta() );
+      if( std::abs( mu.eta() ) > m_maxEta ) {
+         return m_accept;
+      }
+      m_accept.setCutResult( "Eta", true );
+
+      // Medium quality doesn't exist yet, hack for now with getQuality method
+      // Do the quality cut(s):
+      // ATH_MSG_VERBOSE( "Muon quality: " << mu.quality() );
+      // if( mu.quality()!=xAOD::Muon::Medium ) {
+      //    return m_accept;
+      // }
+
+      ATH_MSG_VERBOSE( "Muon quality: " << getQuality(mu));
+      if(getQuality(mu) != xAOD::Muon::Medium){
+      	return m_accept;
+      }
+      
+      m_accept.setCutResult( "Muon quality", true );
+      
+      // Check not standalone 
+      ATH_MSG_VERBOSE( "Type: " << mu.muonType () );
+      if( mu.muonType ()==xAOD::Muon::MuonStandAlone ) {
+         return m_accept;
+      }
+      m_accept.setCutResult( "Type", true );
+
+      // Passes ID hit cuts
+      // ATH_MSG_VERBOSE( "Passes ID Hit cuts " << mu.passesIDCuts () );
+      // if( !mu.passesIDCuts () ) {
+      //   return m_accept;
+      // }
+
+      ATH_MSG_VERBOSE( "Passes ID Hit cuts " << passedIDCuts(mu) );
+      if( !passedIDCuts (mu) ) {
+        return m_accept;
+      }
+  
+      m_accept.setCutResult( "IDHits", true );
+      
+      // Return the result:
+      return m_accept;
+   }
+   
+   void MuonSelectionTool::setQuality( xAOD::Muon& mu ) const {
+     mu.setQuality(getQuality(mu)); 
+     return;
+   }
+
+   xAOD::Muon::Quality MuonSelectionTool::getQuality(const xAOD::Muon& mu ) const {
+     using namespace xAOD;
+
+     // ATH_MSG_VERBOSE( "Type: " << mu.muonType () );
+     // ATH_MSG_VERBOSE( "Quality: " << mu.quality () );
+
+     // Combined muons
+     if (mu.muonType()==Muon_v1::Combined){
+
+       uint8_t nprecisionLayers,nprecisionHoleLayers;
+
+       if (!mu.primaryTrackParticle()->summaryValue(nprecisionLayers, numberOfPrecisionLayers) || 
+         !mu.primaryTrackParticle()->summaryValue(nprecisionHoleLayers, numberOfPrecisionHoleLayers)){
+         ATH_MSG_VERBOSE("getQuality - #precision layers missing in combined muon! Aborting.");
+         return Muon_v1::Loose;
+       }
+
+       float momBalanceSig=0.0;
+
+       // if (!mu.parameter(momBalanceSig, Muon_v1::momentumBalanceSignificance)){
+       // 	ATH_MSG_VERBOSE("getQuality - momentumBalanceSignificance missing in combined muon! Don't abort yet since these variables are not filled!");
+       // 	//momentum balance signficance variable is missing, proceed with a check of the precision layers
+       // 	//return Muon_v1::Medium;
+       // }
+      
+       if( (momBalanceSig<4.0)
+         && (nprecisionLayers > 0 || ( nprecisionLayers == 1 && nprecisionHoleLayers < 2 ) ) ) {
+         return Muon_v1::Medium;
+       }
+      
+       //didn't pass the set of requirements for a medium combined muon
+       return Muon_v1::Loose;
+     }
+
+     if (mu.author()==Muon_v1::STACO || mu.author()==Muon_v1::MuTag){
+       // What about MuTagIMO? CHECK!
+       return Muon_v1::Medium;
+     }
+    
+     // SA muons
+     if (mu.muonType()==Muon_v1::MuonStandAlone && fabs(mu.eta())>2.5){
+       uint8_t nprecisionLayers;
+       uint8_t ninnerSmallHits;
+       if (!mu.primaryTrackParticle()->summaryValue(nprecisionLayers, numberOfPrecisionLayers)){
+         ATH_MSG_VERBOSE("getQuality - numberOfPrecisionLayers missing in SA muon! Aborting.");
+         return Muon_v1::Loose;
+       }
+       if (!mu.summaryValue(ninnerSmallHits, innerSmallHits)){
+         ATH_MSG_VERBOSE("getQuality - innerSmallHits missing in SA muon! Aborting.");
+         return Muon_v1::Loose;
+       }
+      
+       if( nprecisionLayers>2 || ninnerSmallHits>3 ) {
+         return Muon_v1::Medium; // Can't currently get tighter than medium... will need to change logic here if this is no longer true.
+       }
+     }
+
+     // CaloTagged and SegmentTagged muons
+     if (mu.muonType()==Muon_v1::SegmentTagged || mu.muonType()==Muon_v1::CaloTagged ){
+       return Muon_v1::Loose;
+     }
+    
+     //mu.setQuality(Muon_v1::Loose); // Is this really what we want to do? Having all other muons 'loose' with no selection, wasting information.
+      return Muon_v1::Loose;
+   }
+
+
+   
+  void MuonSelectionTool::setPassesIDCuts( xAOD::Muon& mu ) const {
+     // Any time a cut is failed, we just abort - the bit is set to true only at the very end
+     // This is a bit contrary to the concept of using TAccept, but we want to be able to call this in standard reco tools, without lots of output.
+     // Might add DEBUG/VERBOSE level output, later.
+   //      mu.setPassesIDCuts(false);// Explicitly set this here, in case this is being called on an updated muon (i.e. might be true)
+   //      using namespace xAOD;
+   //      uint8_t value1=0;
+   //      uint8_t value2=0;
+   //      if (mu.primaryTrackParticle()->summaryValue(value1, numberOfPixelHits) &&
+   // mu.primaryTrackParticle()->summaryValue(value2, numberOfPixelDeadSensors) ) {
+   //        if (value1+value2==0) return;
+   //      } else {
+   //        ATH_MSG_WARNING("setPassesIDCuts - pixel values are missing! Aborting.");
+   //        return;
+   //      }
+   //
+   //      if (mu.primaryTrackParticle()->summaryValue(value1, numberOfSCTHits) &&
+   // mu.primaryTrackParticle()->summaryValue(value2, numberOfSCTDeadSensors)){
+   //        if (value1+value2<=4) return;
+   //      } else {
+   //        ATH_MSG_WARNING("setPassesIDCuts - SCT values are missing! Aborting.");
+   //        return;
+   //      }
+   //
+   //      if (mu.primaryTrackParticle()->summaryValue(value1, numberOfPixelHoles) &&
+   // mu.primaryTrackParticle()->summaryValue(value2, numberOfSCTHoles)){
+   //        if (value1+value2>=3) return;
+   //      } else {
+   //        ATH_MSG_WARNING("setPassesIDCuts - Si hole values are missing! Aborting.");
+   //        return;
+   //      }
+   //
+   //      float abseta = std::abs(mu.eta());
+   //      if (mu.primaryTrackParticle()->summaryValue(value1, numberOfTRTHits) &&
+   // mu.primaryTrackParticle()->summaryValue(value2, numberOfTRTOutliers)){
+   //        // Okay, so have values available - now check if TRT cuts met...
+   //        uint8_t totTRThits=value1+value2;
+   //        if (!((0.1<abseta && abseta<=1.9 && totTRThits>5 && value2<(0.9 * totTRThits)) || (abseta <= 0.1 || abseta > 1.9)))
+   //          return;
+   //      } else {
+   //        ATH_MSG_WARNING("setPassesIDCuts - TRT values are missing! Aborting.");
+   //        return;
+   //      }
+   //      // Reached end - all ID hit cuts are passed.
+   //      
+   mu.setPassesIDCuts(passedIDCuts(mu));
+  }
+  
+  bool MuonSelectionTool::passedIDCuts( const xAOD::Muon& mu ) const {
+     using namespace xAOD;
+     uint8_t value1=0;
+     uint8_t value2=0;
+     
+     if (mu.primaryTrackParticle()->summaryValue(value1, numberOfPixelHits) && 
+         mu.primaryTrackParticle()->summaryValue(value2, numberOfPixelDeadSensors) ) {
+       if (value1+value2==0) return false;
+     } else {
+       ATH_MSG_WARNING("isPassedIDCuts - pixel values are missing! Aborting.");
+       return false;
+     }
+
+     if (mu.primaryTrackParticle()->summaryValue(value1, numberOfSCTHits) && 
+         mu.primaryTrackParticle()->summaryValue(value2, numberOfSCTDeadSensors)){
+       if (value1+value2<=4) return false;
+     } else {
+       ATH_MSG_WARNING("isPassedIDCuts - SCT values are missing! Aborting.");
+       return false;
+     }
+
+     if (mu.primaryTrackParticle()->summaryValue(value1, numberOfPixelHoles) && 
+         mu.primaryTrackParticle()->summaryValue(value2, numberOfSCTHoles)){
+       if (value1+value2>=3) return false;
+     } else {
+       ATH_MSG_WARNING("isPassedIDCuts - Si hole values are missing! Aborting.");
+       return false;
+     }
+
+     float abseta = std::abs(mu.eta());
+     if (mu.primaryTrackParticle()->summaryValue(value1, numberOfTRTHits) && 
+         mu.primaryTrackParticle()->summaryValue(value2, numberOfTRTOutliers)){
+       // Okay, so have values available - now check if the TRT cuts are met...
+       uint8_t totTRThits=value1+value2;
+       if (!((0.1<abseta && abseta<=1.9 && totTRThits>5 && value2<(0.9 * totTRThits)) || (abseta <= 0.1 || abseta > 1.9)))
+         return false;
+     } else {
+
+       ATH_MSG_WARNING("isPassedIDCuts - TRT values are missing! Aborting.");
+       return false;
+     }
+     // Reached end - all ID hit cuts are passed.
+     return true;
+  } // passedIDCuts
+} // namespace CP
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/Makefile.RootCore b/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/Makefile.RootCore
new file mode 100644
index 0000000000000..3784968a0d906
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/Makefile.RootCore
@@ -0,0 +1,16 @@
+PACKAGE          = MuonSelectorTools
+PACKAGE_PRELOAD  = 
+PACKAGE_CXXFLAGS = 
+PACKAGE_LDFLAGS  = 
+PACKAGE_BINFLAGS = 
+PACKAGE_LIBFLAGS =
+PACKAGE_DEP      = AsgTools PATCore xAODMuon xAODEventInfo xAODTracking
+PACKAGE_TRYDEP   =
+PACKAGE_CLEAN    =
+PACKAGE_NOGRID   =
+PACKAGE_PEDANTIC = 0
+PACKAGE_NOOPT    = 0
+PACKAGE_NOCC     = 0
+PACKAGE_REFLEX   = 0
+
+include $(ROOTCOREDIR)/Makefile-common
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/requirements b/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/requirements
new file mode 100644
index 0000000000000..91066ef5bf0dc
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/cmt/requirements
@@ -0,0 +1,24 @@
+package MuonSelectorTools
+
+author Karsten Koeneke <karsten.koeneke@cern.ch>
+
+public
+use  AtlasPolicy                AtlasPolicy-*                   
+use  AsgTools                   AsgTools-*                      Control/AthToolSupport
+use  GaudiInterface             GaudiInterface-*                External
+use  PATCore                    PATCore-*                       PhysicsAnalysis/AnalysisCommon
+use  xAODMuon                   xAODMuon-*                      Event/xAOD
+private
+use  AthenaBaseComps            AthenaBaseComps-*               Control
+use  AtlasROOT                  AtlasROOT-*                     External
+
+use xAODTracking              xAODTracking-*                  Event/xAOD
+use xAODEventInfo             xAODEventInfo-*                  Event/xAOD
+end_private
+
+library MuonSelectorTools *.cxx ../Root/*.cxx components/*.cxx
+apply_pattern component_library
+
+## install our job options files
+apply_pattern declare_joboptions files="*.py"
+
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/python/MuonSelectorCutDefs.py b/PhysicsAnalysis/MuonID/MuonSelectorTools/python/MuonSelectorCutDefs.py
new file mode 100644
index 0000000000000..15e47261c6c23
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/python/MuonSelectorCutDefs.py
@@ -0,0 +1,77 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+##=============================================================================
+## Name:        MuonSelectorCutDefs
+##
+## Author:      Karsten Koeneke (CERN)
+## Created:     July 2011
+##
+## Description: Define the cut values for the MuonSelectors
+##
+##=============================================================================
+
+# import the needed Reflex and ROOT stuff
+import PyCintex
+PyCintex.Cintex.Enable()
+import ROOT
+
+# Import a needed helper
+from PATCore.HelperUtils import *
+
+# Define GeV
+GeV = 1000.0
+
+
+
+def MuonSelectorConfig(theTool) :
+    """
+    This defines the cut values for the muon
+    """
+    theTool = GetTool(theTool)
+    theTool.nPixMin     = 1
+    theTool.nSCTMin     = 5
+    theTool.nIDHolesMax = 2
+    theTool.etaMax      = 1.9
+    theTool.etaMin      = 0.1
+    theTool.nTRTMin     = 6
+    pass
+
+def MuonSelectorConfig2011(theTool) :
+    """
+    This defines the cut values for the muons in 2011
+    """
+    theTool = GetTool(theTool)
+    theTool.nBLMin      = 1
+    theTool.nPixMin     = 2
+    theTool.nSCTMin     = 6
+    theTool.nIDHolesMax = 2
+    theTool.etaMax      = 1.9
+    theTool.etaMin      = 0.
+    theTool.nTRTMin     = 6
+    pass
+
+def CaloMuonSelectorConfig(theTool) :
+    """
+    This defines the cut values for the muon
+    """
+    theTool = GetTool(theTool)
+    theTool.nPixMin             = 1
+    theTool.nSCTMin             = 5
+    theTool.nIDHolesMax         = 2
+    theTool.etaMax              = 1.9
+    theTool.etaMin              = 0.1
+    theTool.caloEtaMax          = 0.1
+    theTool.caloMuonIDTagMin    = 11
+    theTool.caloLRLikelihoodMin = 0.9
+    pass
+
+def StandAloneMuonSelectorConfig(theTool) :
+    """
+    This defines the cut values for the muon
+    """
+    theTool = GetTool(theTool)
+    theTool.nCSCHitsMin   = 1
+    theTool.nMDTEMHitsMin = 1
+    theTool.nMDTEOHitsMin = 1
+    pass
+
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/python/__init__.py b/PhysicsAnalysis/MuonID/MuonSelectorTools/python/__init__.py
new file mode 100644
index 0000000000000..74583d364ec2c
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/python/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/share/exampleMuonSelectionAlg_jobOptions.py b/PhysicsAnalysis/MuonID/MuonSelectorTools/share/exampleMuonSelectionAlg_jobOptions.py
new file mode 100644
index 0000000000000..d3801a3ace2f7
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/share/exampleMuonSelectionAlg_jobOptions.py
@@ -0,0 +1,10 @@
+
+import AthenaPoolCnvSvc.ReadAthenaPool
+
+svcMgr.EventSelector.InputCollections = [ "/afs/cern.ch/atlas/project/PAT/xAODs/r5534/valid2.117050.PowhegPythia_P2011C_ttbar.digit.AOD.e2657_s1933_s1964_r5534/AOD.01482225._000107.pool.root.1" ]
+
+algseq = CfgMgr.AthSequencer("AthAlgSeq")
+algseq += CfgMgr.CP__MuonSelectionAlg(Input="Muons",Output="SelectedMuons",OutputLevel=DEBUG)
+
+
+theApp.EvtMax=10
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.cxx b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.cxx
new file mode 100644
index 0000000000000..d2cd6f8811c25
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.cxx
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "MuonSelectionAlg.h"
+
+#include "xAODMuon/MuonContainer.h"
+
+namespace CP {
+
+MuonSelectionAlg::MuonSelectionAlg(const std::string& name, ISvcLocator* svcloc) : AthAlgorithm(name,svcloc),
+   m_tool("CP::MuonSelectionTool") /*public tool*/ {
+
+   declareProperty("Input",m_inputMuons="");
+   declareProperty("Output",m_outputMuons="");
+   declareProperty("Tool",m_tool);
+
+}
+
+
+StatusCode MuonSelectionAlg::initialize() {
+   if(m_inputMuons=="") { ATH_MSG_ERROR("You must specify an INPUT muon collection"); return StatusCode::FAILURE; }
+   if(m_outputMuons=="") { ATH_MSG_ERROR("You must specify an OUTPUT muon collection"); return StatusCode::FAILURE; }
+   CHECK( m_tool.retrieve() );
+
+   return StatusCode::SUCCESS;
+}
+
+
+StatusCode MuonSelectionAlg::execute() {
+
+   //fetch input collection
+   const xAOD::MuonContainer* muons = 0;
+   CHECK( evtStore()->retrieve(muons,m_inputMuons) );
+
+   //create a view container for the selected muons 
+   //basically acts like pointers to the selected muons in the muon container
+   xAOD::MuonContainer* out = new xAOD::MuonContainer(SG::VIEW_ELEMENTS);
+
+   for(auto iMuon : *muons) {
+      if(m_tool->accept(*iMuon)) out->push_back(const_cast<xAOD::Muon*>(iMuon));
+   }
+   ATH_MSG_DEBUG("Selected " << out->size() << " muons");
+
+
+   CHECK( evtStore()->record(out,m_outputMuons) );
+   //if(evtStore()->proxy(muons)->isConst()) CHECK( evtStore()->setConst(out) ); - may allow in the future 
+   CHECK( evtStore()->setConst(out) ); //for now we just always lock everything we put into storegate
+
+   return StatusCode::SUCCESS;
+}
+
+} //CP namespace
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.h b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.h
new file mode 100644
index 0000000000000..bd03d9134b9f8
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/MuonSelectionAlg.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+//Simple alg to wrap the selectiontool
+//outputs a view container of the selected muons, if m_outputMuons different to m_inputMuons
+
+//author: will buttinger <will@cern.ch>
+
+
+#ifndef MUONSELECTORTOOLS_MUONSELECTIONALG
+#define MUONSELECTORTOOLS_MUONSELECTIONALG
+
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "MuonSelectorTools/IMuonSelectionTool.h"
+
+namespace CP {
+
+
+
+class MuonSelectionAlg : public AthAlgorithm {
+
+   public:
+      MuonSelectionAlg( const std::string& name, ISvcLocator* svcloc);
+
+      virtual StatusCode initialize();
+      virtual StatusCode execute();
+
+   private:
+      std::string m_inputMuons;
+      std::string m_outputMuons;
+      ToolHandle<CP::IMuonSelectionTool> m_tool;
+
+};
+
+}
+
+#endif
\ No newline at end of file
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_entries.cxx b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_entries.cxx
new file mode 100644
index 0000000000000..daad9ecaccb80
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_entries.cxx
@@ -0,0 +1,20 @@
+#include "GaudiKernel/DeclareFactoryEntries.h"
+
+#include "MuonSelectorTools/MuonSelectionTool.h"
+#include "../MuonSelectionAlg.h"
+
+
+using namespace CP;
+
+
+DECLARE_NAMESPACE_TOOL_FACTORY(CP, MuonSelectionTool )//DECLARE_TOOL_FACTORY( MuonSelectionTool ) is there a difference!?
+DECLARE_NAMESPACE_ALGORITHM_FACTORY(CP, MuonSelectionAlg )
+
+DECLARE_FACTORY_ENTRIES( MuonSelectorTools ) 
+{
+  DECLARE_NAMESPACE_ALGTOOL(CP,MuonSelectionTool)//DECLARE_ALGTOOL( CP::MuonSelectionTool )
+    
+  DECLARE_NAMESPACE_ALGORITHM( CP, MuonSelectionAlg )
+}
+
+
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_load.cxx b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_load.cxx
new file mode 100644
index 0000000000000..f56f4380949ca
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/src/components/MuonSelectorTools_load.cxx
@@ -0,0 +1,2 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+LOAD_FACTORY_ENTRIES(MuonSelectorTools)
diff --git a/PhysicsAnalysis/MuonID/MuonSelectorTools/util/MuonSelectorToolsTester.cxx b/PhysicsAnalysis/MuonID/MuonSelectorTools/util/MuonSelectorToolsTester.cxx
new file mode 100644
index 0000000000000..f889afc515484
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonSelectorTools/util/MuonSelectorToolsTester.cxx
@@ -0,0 +1,248 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/// a simple testing macro for the MuonSelectorTools_xAOD package
+/// shamelessly stolen from CPToolTests.cxx
+
+// System include(s):
+#include <memory>
+#include <cstdlib>
+#include <string>
+#include <map>
+
+// ROOT include(s):
+#include <TFile.h>
+#include <TError.h>
+#include <TStopwatch.h>
+#include <TString.h>
+
+// Infrastructure include(s):
+#ifdef ROOTCORE
+#   include "xAODRootAccess/Init.h"
+#   include "xAODRootAccess/TEvent.h"
+#endif // ROOTCORE
+
+// EDM include(s):
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODMuon/MuonContainer.h"
+#include "xAODTracking/TrackingPrimitives.h"
+#include "xAODTracking/TrackParticleContainer.h"
+
+// Local include(s):
+#include "MuonSelectorTools/errorcheck.h"
+#include "MuonSelectorTools/MuonSelectionTool.h"
+
+/// Example of how to run the MuonSelectorTools package to obtain information from muons
+
+int main( int argc, char* argv[] ) {
+
+
+	// The application's name:
+   const char* APP_NAME = argv[ 0 ];
+
+   // Check if we received a file name:
+   if( argc < 2 ) {
+      Error( APP_NAME, "No file name received!" );
+      Error( APP_NAME, "  Usage: %s [xAOD file name]", APP_NAME );
+      return 1;
+   }
+
+   // Initialise the application:
+   CHECK( xAOD::Init( APP_NAME ) );
+
+   // Open the input file:
+   const TString fileName = argv[ 1 ];
+   Info( APP_NAME, "Opening file: %s", fileName.Data() );
+   std::auto_ptr< TFile > ifile( TFile::Open( fileName, "READ" ) );
+   CHECK( ifile.get() );
+
+   // Create a TEvent object:
+   xAOD::TEvent event;
+   CHECK(event.readFrom( ifile.get(), xAOD::TEvent::kClassAccess ));
+   Info( APP_NAME, "Number of events in the file: %i",
+         static_cast< int >( event.getEntries() ) );
+
+   // Decide how many events to run over:
+   Long64_t entries = event.getEntries();
+   if( argc > 2 ) {
+      const Long64_t e = atoll( argv[ 2 ] );
+      if( e < entries ) {
+         entries = e;
+      }
+   }
+
+
+   CP::MuonSelectionTool m_muonSelection("MuonSelection");
+
+   m_muonSelection.msg().setLevel( MSG::VERBOSE );
+   m_muonSelection.setProperty( "MaxEta", 2.4 );
+   //m_muonSelection.setProperty( "Author", 12 );
+   //m_muonSelection.initialize();
+   CHECK (m_muonSelection.initialize().isSuccess());
+
+   int allMuons = 0;
+   int allgoodMuons = 0;
+
+   // Loop over the events:
+   for( Long64_t entry = 0; entry < entries; ++entry ) {
+
+      // Tell the object which entry to look at:
+      event.getEntry( entry );
+
+      int goodMuons = 0;
+
+      // Print some event information for fun:
+      const xAOD::EventInfo* ei = 0;
+      CHECK( event.retrieve( ei, "EventInfo" ) );
+      Info( APP_NAME,
+            "===>>>  start processing event #%i, "
+            "run #%i %i events processed so far  <<<===",
+            static_cast< int >( ei->eventNumber() ),
+            static_cast< int >( ei->runNumber() ),
+            static_cast< int >( entry ) );
+
+      // Get the Muons from the event:
+      const xAOD::MuonContainer* muons = 0;
+      CHECK( event.retrieve( muons, "Muons" ) );
+      Info( APP_NAME, "Number of muons: %i",
+            static_cast< int >( muons->size() ) );
+
+      // Print their properties, using the tools:
+      xAOD::MuonContainer::const_iterator mu_itr = muons->begin();
+      xAOD::MuonContainer::const_iterator mu_end = muons->end();
+      for( ; mu_itr != mu_end; ++mu_itr ) {
+
+	allMuons++;
+	uint8_t PixHits = 0, PixDead = 0, SCTHits = 0, SCTDead = 0, PixHoles = 0, SCTHoles = 0, TRTHits = 0, TRTOut = 0;
+
+
+	// std::cout << "ENTERING  ACCEPT FUNCTION " << std::endl;
+	// if(!m_muonSelection.accept(**mu_itr)) continue;
+	// std::cout << "PASSED ACCEPT FUNCTION " << std::endl;
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(PixHits,xAOD::numberOfPixelHits))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: PixHits %i ", PixHits);
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(PixDead,xAOD::numberOfPixelDeadSensors))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: PixDead %i ", PixDead);
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(SCTHits,xAOD::numberOfSCTHits))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: SCTHits %i ", SCTHits);
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(SCTDead,xAOD::numberOfSCTDeadSensors))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: SCTDead %i ", SCTDead);
+
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(PixHoles,xAOD::numberOfPixelHoles))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: PixHoles %i ", PixHoles);
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(SCTHoles,xAOD::numberOfSCTHoles))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: SCTHoles %i ", SCTHoles);
+
+	float abseta = std::abs((*mu_itr)->eta());
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(TRTHits,xAOD::numberOfTRTHits))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: TRTHits %i ", TRTHits);
+
+	if(!(*mu_itr)->primaryTrackParticle()->summaryValue(TRTOut,xAOD::numberOfTRTOutliers))
+	  Info( APP_NAME, "Missing info!");
+	Info( APP_NAME, "Primary track: TRTOut %i ", TRTOut);
+
+	uint8_t totTRT = TRTHits+TRTOut;
+
+	Info( APP_NAME, "Muon eta:  %g ", std::abs((*mu_itr)->eta()));
+	Info( APP_NAME, "TotTRT %i > 5; OutCond %i < %g ", totTRT, TRTOut, 0.9*totTRT);
+
+	if (!((0.1<abseta && abseta<=1.9 && totTRT>5 && TRTOut<(0.9 * totTRT)) || (abseta <= 0.1 || abseta > 1.9)))
+	  std::cout << "didn't pass the TRT cuts! v1 " << std::endl;
+
+	if ((0.1<abseta && abseta<=1.9) && !(totTRT>5 && TRTOut<(0.9 * totTRT)))
+	  std::cout << "didn't pass the TRT cuts! v2 " << std::endl;
+
+
+         // Select "good" muons:
+	//	if( ! m_muonSelection.accept( **mu_itr ) ) std::cout << "didn't pass! " << std::endl;
+	if( ! m_muonSelection.passedIDCuts( **mu_itr ) ) {
+	  Info(APP_NAME, "DIDNT PASS THE ID CUTS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+	  continue;
+	}
+
+	if( (*mu_itr)->quality() == xAOD::Muon_v1::Tight)
+	  std::cout << "tight " << std::endl;
+	else if( (*mu_itr)->quality() == xAOD::Muon_v1::Medium)
+	  std::cout << "medium " << std::endl;
+	else if( (*mu_itr)->quality() == xAOD::Muon_v1::Loose)
+	  std::cout << "loose " << std::endl;
+	else
+	  std::cout << "no quality! " << std::endl;
+
+	if( (*mu_itr)->muonType() == xAOD::Muon_v1::Combined)
+	  std::cout << "combined " << std::endl;
+	else if( (*mu_itr)->muonType() == xAOD::Muon_v1::MuonStandAlone)
+	  std::cout << "stand-alone " << std::endl;
+	else if( (*mu_itr)->muonType() == xAOD::Muon_v1::SegmentTagged)
+	  std::cout << "segment-tagged " << std::endl;
+	else if( (*mu_itr)->muonType() == xAOD::Muon_v1::CaloTagged)
+	  std::cout << "calo-tagged " << std::endl;
+	else if( (*mu_itr)->muonType() == xAOD::Muon_v1::SiliconAssociatedForwardMuon)
+	  std::cout << "forward " << std::endl;
+	else
+	  std::cout << "no type! " << std::endl;
+
+	Info(APP_NAME, "MyVerboseType %i ", (*mu_itr)->muonType());
+	Info(APP_NAME, "MyVerboseQuality %i ", (*mu_itr)->quality());
+	
+	Info(APP_NAME, "MyVerboseGetQuality %i ", m_muonSelection.getQuality( **mu_itr ));
+
+	if(m_muonSelection.getQuality( **mu_itr ) != xAOD::Muon_v1::Medium) {
+	  Info(APP_NAME, "DIDNT PASS THE QUALITY CUTS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+	  continue;
+	}
+
+	goodMuons++;
+	allgoodMuons++;
+
+         // // Print some info about the selected muon:
+         // Info( APP_NAME, "  Selected muon: eta = %g, phi = %g, pt = %g",
+         //       ( *mu_itr )->eta(), ( *mu_itr )->phi(), ( *mu_itr )->pt() );
+         // Info( APP_NAME, "    Primary track: eta = %g, phi = %g, pt = %g",
+         //       ( *mu_itr )->primaryTrackParticle()->eta(),
+         //       ( *mu_itr )->primaryTrackParticle()->phi(),
+         //       ( *mu_itr )->primaryTrackParticle()->pt() );
+
+         // const xAOD::TrackParticle* idtrack =
+         //    ( *mu_itr )->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
+         // if( idtrack ) {
+         //    Info( APP_NAME, "         ID track: eta = %g, phi = %g, pt = %g",
+         //          idtrack->eta(), idtrack->phi(), idtrack->pt() );
+         // }
+
+      }
+
+      Info( APP_NAME, "Number of good muons: %i",
+	    goodMuons );
+
+      // Close with a message:
+      Info( APP_NAME,
+            "===>>>  done processing event #%i, "
+            "run #%i %i events processed so far  <<<===",
+            static_cast< int >( ei->eventNumber() ),
+            static_cast< int >( ei->runNumber() ),
+            static_cast< int >( entry + 1 ) );
+   }
+
+   Info(APP_NAME, "All muons %i and good muons %i " , allMuons, allgoodMuons);
+
+   // Return gracefully:
+   return 0;
+
+
+}
-- 
GitLab