From bc4eb98da856ac712f1e9fdc25b791694aa7fd38 Mon Sep 17 00:00:00 2001
From: Atlas-Software Librarian <Atlas-Software.Librarian@cern.ch>
Date: Fri, 8 Apr 2016 15:54:16 +0200
Subject: [PATCH] 'CMakeLists.txt' (MuonTPTools-00-00-15)

    * Tagging MuonTPTools-00-00-15

2015-06-23  Massimiliano Bellomo  <massimiliano.bellomo@cern.ch>
    * Added Event trigger branches to MuonTPTreeTool and needed changes to MuonTPEfficiencyTool interfance to read trigger for probes
    * Improved consistency of some tree branches
    * Added support for High Pt working point

2015-06-23 Max Goblirsch <goblirsc@CERN.CH>
    * Added flag to the Tree tool to write SF info only when needed
    * Writing match dR only for nominal matching scenarios

2015-06-22 Max Goblirsch <goblirsc@CERN.CH>
    * MuonTPTreeTool: added tag trigger matching information
    * MuonTPSelectionTool: added method to retrieve trigger list
    * Actually implemented the match dR systematic in MuonTrigTPEfficiencyTool....

2015-06-22  Massimiliano Bellomo  <massimiliano.bellomo@cern.ch>
    * DiMuonTPSelectionTool, MuonTPSelectionTool added option to select truth matched reco probes
    * MuonTPPlotTool removed useDirDefault option, not neeeded anymore
    * DiMuonTPTreeTool renamed tag and probes branches
...
(Long ChangeLog diff - truncated)
---
 .../MuonTPTools/CMakeLists.txt                |  40 +
 ...umuMuonTPPlotTool.h => DiMuonTPPlotTool.h} |  13 +-
 ...electionTool.h => DiMuonTPSelectionTool.h} |  29 +-
 .../MuonTPTools/DiMuonTPTreeTool.h            | 121 +++
 .../MuonTPTools/IMuonTPEfficiencyTool.h       |   6 +
 .../MuonTPTools/MuonTPTools/IMuonTPPlotTool.h |   2 +-
 .../MuonTPTools/IMuonTPSelectionTool.h        |   8 +
 .../MuonTPTools/MuonTPTools/IMuonTPTreeTool.h |  20 +-
 .../MuonTPTools/JPsiMuonTPEfficiencyTool.h    |  34 -
 .../MuonTPTools/JPsiMuonTPPlotTool.h          |  34 -
 .../MuonTPTools/JPsiMuonTPSelectionTool.h     |  62 --
 .../MuonTPTools/MuonIsolTPEfficiencyTool.h    |  32 +
 .../MuonTPTools/MuonRecoTPEfficiencyTool.h    |  54 +-
 .../MuonTPTools/MuonTPEfficiencyTool.h        |  17 +-
 .../MuonTPTools/MuonTPTools/MuonTPPlotTool.h  |  36 +-
 .../MuonTPTools/MuonTPSelectionTool.h         |  36 +-
 .../MuonTPTools/MuonTPTools/MuonTPTool.h      |   4 +-
 .../MuonTPTools/MuonTPTools/MuonTPTreeTool.h  |  68 +-
 .../MuonTPTools/MuonTrigTPEfficiencyTool.h    |   5 +-
 .../MuonTPTools/MuonTrigTPPlotTool.h          |  38 -
 .../MuonTPTools/MuonTrigTPTreeTool.h          |  50 --
 .../ZmumuMuonTPIsolationTreeTool.h            |  91 --
 .../MuonTPTools/ZmumuMuonTPTreeTool.h         |  64 --
 .../MuonTPTools/Root/DiMuonTPPlotTool.cxx     |  56 ++
 ...tionTool.cxx => DiMuonTPSelectionTool.cxx} | 216 +++--
 .../MuonTPTools/Root/DiMuonTPTreeTool.cxx     | 437 ++++++++++
 .../Root/JPsiMuonTPEfficiencyTool.cxx         |  94 --
 .../MuonTPTools/Root/JPsiMuonTPPlotTool.cxx   |  24 -
 .../Root/JPsiMuonTPSelectionTool.cxx          | 156 ----
 .../Root/MuonIsolTPEfficiencyTool.cxx         |  32 +
 .../Root/MuonRecoTPEfficiencyTool.cxx         | 276 ++++--
 .../MuonTPTools/Root/MuonTPEfficiencyTool.cxx |  41 +-
 .../MuonTPTools/Root/MuonTPPlotTool.cxx       | 313 +++----
 .../MuonTPTools/Root/MuonTPSelectionTool.cxx  | 323 ++++---
 .../MuonTPTools/Root/MuonTPTool.cxx           |  34 +-
 .../MuonTPTools/Root/MuonTPTreeTool.cxx       | 274 ++++--
 .../Root/MuonTrigTPEfficiencyTool.cxx         |  61 +-
 .../MuonTPTools/Root/MuonTrigTPPlotTool.cxx   |  45 -
 .../MuonTPTools/Root/MuonTrigTPTreeTool.cxx   | 129 ---
 .../Root/ZmumuMuonTPIsolationTreeTool.cxx     | 227 -----
 .../MuonTPTools/Root/ZmumuMuonTPPlotTool.cxx  |  47 -
 .../MuonTPTools/Root/ZmumuMuonTPTreeTool.cxx  | 164 ----
 .../MuonTPTools/cmt/Makefile.RootCore         |   2 +-
 .../MuonTPTools/cmt/requirements              |  13 +-
 .../MuonTPTools/macros/CreateSF.py            | 266 ++++++
 .../MuonTPTools/macros/DSConfig.py            |  23 +
 .../MuonTPTools/macros/Defs.py                |  79 ++
 .../MuonTPTools/macros/EffPlots.py            | 818 ++++++++++++++++++
 .../MuonTPTools/macros/HistoDefs.py           | 229 +++++
 .../MuonTPTools/macros/Histos.py              | 715 +++++++++++++++
 .../MuonTPTools/macros/PlotUtils.py           | 281 ++++++
 .../MuonTPTools/macros/ProbePlots.py          | 254 ++++++
 .../MuonTPTools/macros/TestRecoSF.py          |  71 ++
 .../MuonTPTools/macros/Utils.py               | 253 ++++++
 .../src/components/MuonTPTools_entries.cxx    |  74 +-
 55 files changed, 4900 insertions(+), 1991 deletions(-)
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/CMakeLists.txt
 rename PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/{ZmumuMuonTPPlotTool.h => DiMuonTPPlotTool.h} (75%)
 rename PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/{ZmumuMuonTPSelectionTool.h => DiMuonTPSelectionTool.h} (76%)
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPTreeTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPEfficiencyTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPPlotTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPSelectionTool.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonIsolTPEfficiencyTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPPlotTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPTreeTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPIsolationTreeTool.h
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPTreeTool.h
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPPlotTool.cxx
 rename PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/{ZmumuMuonTPSelectionTool.cxx => DiMuonTPSelectionTool.cxx} (59%)
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPTreeTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPEfficiencyTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPPlotTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPSelectionTool.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonIsolTPEfficiencyTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPPlotTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPTreeTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPIsolationTreeTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPPlotTool.cxx
 delete mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPTreeTool.cxx
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/CreateSF.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/DSConfig.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Defs.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/EffPlots.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/HistoDefs.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Histos.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/PlotUtils.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/ProbePlots.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/TestRecoSF.py
 create mode 100644 PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Utils.py

diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/CMakeLists.txt b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/CMakeLists.txt
new file mode 100644
index 00000000000..8b4b6685db3
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/CMakeLists.txt
@@ -0,0 +1,40 @@
+################################################################################
+# Package: MuonTPTools
+################################################################################
+
+# Declare the package name:
+atlas_subdir( MuonTPTools )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthToolSupport/AsgTools
+                          DataQuality/GoodRunsLists
+                          Event/xAOD/xAODBase
+                          Event/xAOD/xAODMuon
+                          PhysicsAnalysis/MuonID/MuonIDAnalysis/MuonEfficiencyCorrections
+                          PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonPerformanceHistUtils
+                          PhysicsAnalysis/MuonID/MuonSelectorTools
+                          Trigger/TrigAnalysis/TrigDecisionTool
+                          Trigger/TrigAnalysis/TrigMuonMatching
+                          PRIVATE
+                          Event/xAOD/xAODEventInfo
+                          Event/xAOD/xAODEventShape
+                          Event/xAOD/xAODJet
+                          Event/xAOD/xAODTracking
+                          Event/xAOD/xAODTruth
+                          GaudiKernel
+                          PhysicsAnalysis/MCTruthClassifier )
+
+# External dependencies:
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_component( MuonTPTools
+                     Root/*.cxx
+                     src/components/*.cxx
+                     INCLUDE_DIRS ${ROOT_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${ROOT_LIBRARIES} AsgTools GoodRunsListsLib xAODBase xAODMuon MuonEfficiencyCorrectionsLib MuonPerformanceHistUtils MuonSelectorToolsLib TrigDecisionToolLib TrigMuonMatchingLib xAODEventInfo xAODEventShape xAODJet xAODTracking xAODTruth GaudiKernel MCTruthClassifierLib )
+
+# Install files from the package:
+atlas_install_headers( MuonTPTools )
+
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPPlotTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPPlotTool.h
similarity index 75%
rename from PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPPlotTool.h
rename to PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPPlotTool.h
index 17beae37b08..2d1dc834fc9 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPPlotTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPPlotTool.h
@@ -18,22 +18,25 @@
 #include "AsgTools/AsgTool.h"
 #include <map>
 
-class ZmumuMuonTPPlotTool:
+class DiMuonTPPlotTool:
 		public MuonTPPlotTool {
-		ASG_TOOL_CLASS(ZmumuMuonTPPlotTool, IMuonTPPlotTool)
+		ASG_TOOL_CLASS(DiMuonTPPlotTool, IMuonTPPlotTool)
 
 public:
-		ZmumuMuonTPPlotTool(std::string name);
+		DiMuonTPPlotTool(std::string name);
 
 		virtual std::vector<MuonTPEfficiencyPlotBase*> AddPlots(std::string sDir, bool isMatched);
         virtual std::vector<MuonTPCutFlowBase*> AddCutFlowPlots(std::string sDir);
 
 protected:
-		bool m_do_TPBasic;
+		bool m_do_TPBasic_JPsi;
+        bool m_do_TPBasic_Zmm;
+        bool m_do_DiLepton_Zmm;
+        bool m_do_DiLepton_JPsi;
 		bool m_do_TPFineEtaPhi;
+        bool m_do_TriggerPlots;
         bool m_do_DetRegions;
 		bool m_do_Valid;
-		bool m_do_DiLepton;
         bool m_apply_SF;
 
 };
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPSelectionTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPSelectionTool.h
similarity index 76%
rename from PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPSelectionTool.h
rename to PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPSelectionTool.h
index 5c4c0ad9384..6b5cae054fd 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPSelectionTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPSelectionTool.h
@@ -3,27 +3,24 @@
 */
 
 /*
- * ZmumuMuonTPSelectionTool.h
+ * DiMuonTPSelectionTool.h
  *
- *  Created on: Aug 26, 2014
+ *  Created on: Jun 18, 2015
  *      Author: goblirsc<at>CERN.CH
  */
 
 #ifndef ZMUMUMUONTPSELECTIONTOOL_H_
 #define ZMUMUMUONTPSELECTIONTOOL_H_
 
-/// This is the implementation of the IMuonTPSelectionTool for the Z->mm tag and probe
-/// efficiency measurement.
+/// This is the implementation of the IMuonTPSelectionTool for the tag and probe
+/// efficiency measurement using dimuon resonances (JPsi and Z).
 #include "MuonTPTools/MuonTPSelectionTool.h"
 #include "AsgTools/AsgTool.h"
 
-class ZmumuMuonTPSelectionTool:
-        virtual public IMuonTPSelectionTool,
-        virtual public asg::AsgTool,
-        public MuonTPSelectionTool{
-      ASG_TOOL_CLASS(ZmumuMuonTPSelectionTool, IMuonTPSelectionTool)
+class DiMuonTPSelectionTool:  public MuonTPSelectionTool{
+      ASG_TOOL_CLASS(DiMuonTPSelectionTool, IMuonTPSelectionTool)
 public:
-    ZmumuMuonTPSelectionTool(std::string myname);
+    DiMuonTPSelectionTool(std::string myname);
 
     virtual StatusCode initialize();
 
@@ -69,6 +66,7 @@ private:
     bool m_CBProbe;
     bool m_MSProbe;
     bool m_TruthProbe;
+    bool m_TruthMatchedProbe;
 
     bool m_only_A_side;
     bool m_only_C_side;
@@ -83,8 +81,17 @@ private:
     double m_probe_z0;
 
 
-      double m_deltaPhiCut;
+    double m_deltaPhiCut;
+    double m_deltaEtaCut;
 
+    bool m_doProbeChargeSys;
+    std::string m_ProbeCharge;
+    
+    bool m_VeryLooseProbe;
+    bool m_LooseProbe;
+    bool m_MediumProbe;
+    bool m_TightProbe;
+    bool m_HighPtProbe;
 };
 
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPTreeTool.h
new file mode 100644
index 00000000000..5f72f0076e0
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/DiMuonTPTreeTool.h
@@ -0,0 +1,121 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+    #ifndef ZMUMUMUONTPTreeTOOL_H_
+    #define ZMUMUMUONTPTreeTOOL_H_
+    #include "MuonTPTools/IMuonTPTreeTool.h"
+    #include "MuonTPTools/IMuonTPSelectionTool.h"
+    #include "MuonTPTools/IMuonTPEfficiencyTool.h"
+    #include "MuonTPTools/MuonTPTreeTool.h"
+    #include "MuonEfficiencyCorrections/fineEtaPhiBinning.h"
+    #include "MuonPerformanceHistUtils/EtaPhiBinning.h"
+    #include "AsgTools/AsgTool.h"
+    #include "MuonSelectorTools/MuonSelectionTool.h"
+    #include <map>
+
+class DiMuonTPTreeTool:
+        public MuonTPTreeTool {         // for now, a 1:1 copy
+        ASG_TOOL_CLASS(DiMuonTPTreeTool, IMuonTPTreeTool)
+
+    public:
+            DiMuonTPTreeTool(std::string name);
+        virtual StatusCode initialize();
+        virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
+        virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
+
+    protected:
+        UInt_t m_runNumber;
+        ULong64_t m_eventNumber;
+        UInt_t m_lumiblock;
+        float m_average_mu;
+        float m_actual_mu;
+        int m_PV_n;
+        
+        float m_mcEventWeight;
+        float m_pt;
+        float m_eta;
+        float m_phi;
+        int m_type;    // 1 for CB, 2 for SA, 3 for ST, 4 for CT
+        int m_author;
+        int m_quality;
+        int m_fineEtaPhi;
+        int m_detregion;
+        int m_q;
+        float m_d0;
+        float m_d0err;
+        float m_z0;
+        
+        float m_tagPt;
+        float m_tagEta;
+        float m_tagPhi;
+        int m_tag_q;
+        float m_tag_d0;
+        float m_tag_d0err;
+        float m_tag_z0;
+        
+        float m_mll;
+        float m_dPhi;
+        float m_dilep_pt;
+        float m_dilep_tof;
+        
+        float m_tag_deltaR;
+        float m_deltaR;
+        
+        
+        
+            // Extra iso stuff
+        float m_tagiso_neflowisol20;
+        float m_tagiso_topoetcone20;
+        float m_tagiso_ptcone20;
+        float m_tagiso_etcone20;
+        float m_tagiso_ptvarcone20;
+
+        float m_tagiso_neflowisol30;
+        float m_tagiso_topoetcone30;
+        float m_tagiso_ptcone30;
+        float m_tagiso_etcone30;
+        float m_tagiso_ptvarcone30;
+
+        float m_tagiso_neflowisol40;
+        float m_tagiso_topoetcone40;
+        float m_tagiso_ptcone40;
+        float m_tagiso_etcone40;
+        float m_tagiso_ptvarcone40;
+
+        float m_tag_topocore;
+
+        float m_probeiso_neflowisol20;
+        float m_probeiso_topoetcone20;
+        float m_probeiso_ptcone20;
+        float m_probeiso_etcone20;
+        float m_probeiso_ptvarcone20;
+
+        float m_probeiso_neflowisol30;
+        float m_probeiso_topoetcone30;
+        float m_probeiso_ptcone30;
+        float m_probeiso_etcone30;
+        float m_probeiso_ptvarcone30;
+
+        float m_probeiso_neflowisol40;
+        float m_probeiso_topoetcone40;
+        float m_probeiso_ptcone40;
+        float m_probeiso_etcone40;
+        float m_probeiso_ptvarcone40;
+
+        float m_probe_topocore;
+
+        float m_energyDensity_central;
+        float m_energyDensity_forward;
+            
+        
+        fineEtaPhiBinning m_fepb;
+        EtaPhiBinning m_epb;
+        ToolHandle<CP::IMuonSelectionTool> m_muon_selection_tool;
+        
+        bool m_extended_Iso_Info;
+            
+};
+
+    #endif /* ZMUMUMUONTPTreeTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPEfficiencyTool.h
index a636254589a..75fdee3ceef 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPEfficiencyTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPEfficiencyTool.h
@@ -23,6 +23,12 @@ public:
 
   /// Get Efficiency Flag
   virtual std::string efficiencyFlag() =0;
+  
+  // check if the tool represents a nominal run or a sys variation
+  virtual bool isNominal() const=0;
+
+  // return the triger item (if any configured)
+  virtual std::string triggerItem() =0;  
 };
 
 #endif
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPPlotTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPPlotTool.h
index dea4e9f0486..fbaa413c505 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPPlotTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPPlotTool.h
@@ -30,7 +30,7 @@ public:
 	 virtual StatusCode RegisterPlots (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools) = 0;
 
 	 // fill the histos
-	 virtual void fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tp_tool, ToolHandle <IMuonTPEfficiencyTool> eff_tool) = 0;
+	 virtual void fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tp_tool, ToolHandle <IMuonTPEfficiencyTool> & eff_tool) = 0;
 
 	 // fill the cut flow
 	 virtual void fillCutFlow (std::string stage, double weight, ToolHandle <IMuonTPSelectionTool> & tp_tool) = 0;
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPSelectionTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPSelectionTool.h
index 51434dde876..69840df712f 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPSelectionTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPSelectionTool.h
@@ -27,6 +27,14 @@ public:
 
   /// Get Efficiency Flag
   virtual std::string efficiencyFlag() =0;
+  
+  // check if the tool represents a nominal run or a sys variation
+  virtual bool isNominal() const=0;
+  
+  // check if the tool is a systematic variation that can not be evaluated using the nominal ntuples
+  virtual bool notIncludedInNominal() const=0;
+  
+  virtual std::vector<std::string> tagTriggerList() const = 0;
 
 };
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPTreeTool.h
index bcfbb410ea6..656bf45447d 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPTreeTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/IMuonTPTreeTool.h
@@ -25,19 +25,19 @@ class IMuonTPEfficiencyTool;
 class IMuonTPTreeTool : virtual public asg::IAsgTool {
   ASG_TOOL_INTERFACE(IMuonTPTreeTool)
 
-public:
+    public:
 
-	// used to initialize the required histos
-	 virtual StatusCode RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools) = 0;
+  // used to initialize the required histos
+  virtual StatusCode RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools) = 0;
 
-	 // fill the histos
-	 virtual void updateMatch(Probe& probe,ToolHandle <IMuonTPEfficiencyTool> eff_tool) = 0;
-    virtual void ForgetKnownProbes() = 0;
-     virtual void fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> sel_tool) = 0;
-//      virtual void 
+  // fill the histos
+  virtual void updateMatch(Probe& probe,ToolHandle <IMuonTPEfficiencyTool> & eff_tool) = 0;
+  virtual void ForgetKnownProbes() = 0;
+  virtual void fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> & sel_tool) = 0;
+  //      virtual void 
 
-	  /// retrieve booked histograms
-	  virtual std::vector< std::pair<TTree*, std::string> > retrieveBookedTrees() = 0;
+  /// retrieve booked histograms
+  virtual std::vector< std::pair<TTree*, std::string> > retrieveBookedTrees() = 0;
 };
 
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPEfficiencyTool.h
deleted file mode 100644
index 8e985f9fa33..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPEfficiencyTool.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPEfficiencyTool.h
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#ifndef JPSIMUONTPEFFICIENCYTOOL_H_
-#define JPSIMUONTPEFFICIENCYTOOL_H_
-
-#include "MuonTPTools/MuonTPEfficiencyTool.h"
-class JPsiMuonTPEfficiencyTool : public MuonTPEfficiencyTool{
-	  ASG_TOOL_CLASS(JPsiMuonTPEfficiencyTool, IMuonTPEfficiencyTool)
-public:
-	JPsiMuonTPEfficiencyTool(std::string name);
-
-    /// Match probes for efficiency calculation
-	  void dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const;
-	  bool GoodMatchMuonType(const xAOD::IParticle* probe) const;
-private:
-	 bool m_match_MS;
-     bool m_match_CB;
-     bool m_match_Medium;
-     bool m_match_ID;
-     bool m_match_CaloTag;
-     bool m_do_IDHits;
-
-};
-
-#endif /* JPSIMUONTPEFFICIENCYTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPPlotTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPPlotTool.h
deleted file mode 100644
index 4cc831ff2d2..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPPlotTool.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPPlots.h
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#ifndef JPSIMUONTPPLOTTOOL_H_
-#define JPSIMUONTPPLOTTOOL_H_
-#include "MuonTPTools/IMuonTPPlotTool.h"
-#include "MuonTPTools/IMuonTPSelectionTool.h"
-#include "MuonTPTools/IMuonTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTPPlotTool.h"
-#include "AsgTools/AsgTool.h"
-#include <map>
-
-class JPsiMuonTPPlotTool:
-		public MuonTPPlotTool {
-		ASG_TOOL_CLASS(JPsiMuonTPPlotTool, IMuonTPPlotTool)
-
-public:
-		JPsiMuonTPPlotTool(std::string name);
-
-		virtual std::vector<MuonTPEfficiencyPlotBase*> AddPlots(std::string sDir, bool isMatched);
-
-protected:
-
-};
-
-#endif /* JPSIMUONTPPLOTTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPSelectionTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPSelectionTool.h
deleted file mode 100644
index ca8244fda28..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/JPsiMuonTPSelectionTool.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPSelectionTool.h
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#ifndef JPSIMUONTPSELECTIONTOOL_H_
-#define JPSIMUONTPSELECTIONTOOL_H_
-
-/// This is the implementation of the IMuonTPSelectionTool for the Z->mm tag and probe
-/// efficiency measurement.
-#include "MuonTPTools/MuonTPSelectionTool.h"
-#include "AsgTools/AsgTool.h"
-
-class JPsiMuonTPSelectionTool:
-        virtual public IMuonTPSelectionTool,
-        virtual public asg::AsgTool,
-        public MuonTPSelectionTool{
-      ASG_TOOL_CLASS(JPsiMuonTPSelectionTool, IMuonTPSelectionTool)
-public:
-      JPsiMuonTPSelectionTool(std::string myname);
-
-      virtual StatusCode initialize();
-
-      /// Select Probes
-      ProbeContainer* selectProbes(const xAOD::MuonContainer*, const xAOD::IParticleContainer*) const;
-
-      /// Get Efficiency Flag
-      std::string efficiencyFlag() {return m_efficiencyFlag;}
-
-      /// Check if Probe and Tag are the same object
-      bool isTag(const xAOD::Muon* tag, const xAOD::IParticle* probe) const;
-
-      // helper method to check if the probe is the right type
-      bool isRightType(const xAOD::IParticle* probe) const;
-
-    private:
-
-      bool m_accept_sameCharge;
-      bool m_accept_oppCharge;
-
-      bool m_probe_ID_hits;
-
-      double m_tagIsolation;
-      double m_probeIsolation;
-
-      bool m_IDProbe;
-      bool m_CaloProbe;
-      bool m_CBProbe;
-      bool m_MSProbe;
-
-      double m_deltaPhiCut;
-
-};
-
-
-#endif /* JPSIMUONTPSELECTIONTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonIsolTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonIsolTPEfficiencyTool.h
new file mode 100644
index 00000000000..c12cd78c0c0
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonIsolTPEfficiencyTool.h
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * MuonIsolTPEfficiencyTool.h
+ *
+ *  Created on: Aug 31, 2014
+ *      Author: goblirsc / a.m.
+ */
+
+#ifndef MUONISOLTPEFFICIENCYTOOL_H_
+#define MUONISOLTPEFFICIENCYTOOL_H_
+
+#include "MuonTPTools/MuonTPEfficiencyTool.h"
+
+
+class MuonIsolTPEfficiencyTool : public MuonTPEfficiencyTool{
+	  ASG_TOOL_CLASS(MuonIsolTPEfficiencyTool, IMuonTPEfficiencyTool)
+
+public:
+    MuonIsolTPEfficiencyTool(std::string name);
+
+    // Match probes for efficiency calculation
+    void matchProbes(ProbeContainer*, const xAOD::IParticleContainer*) const;
+     
+private:
+    
+
+};
+
+#endif /* MUONISOLTPEFFICIENCYTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonRecoTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonRecoTPEfficiencyTool.h
index 9ea77b5bc44..16a1ddbfe21 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonRecoTPEfficiencyTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonRecoTPEfficiencyTool.h
@@ -14,33 +14,37 @@
 
 #include "MuonTPTools/MuonTPEfficiencyTool.h"
 class MuonRecoTPEfficiencyTool : public MuonTPEfficiencyTool{
-	  ASG_TOOL_CLASS(MuonRecoTPEfficiencyTool, IMuonTPEfficiencyTool)
-public:
-	MuonRecoTPEfficiencyTool(std::string name);
+  ASG_TOOL_CLASS(MuonRecoTPEfficiencyTool, IMuonTPEfficiencyTool)
+    public:
+  MuonRecoTPEfficiencyTool(std::string name);
 
-    /// Match probes for efficiency calculation
-	  void dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const;
-	  bool GoodMatchMuonType(const xAOD::IParticle* probe) const;
-private:
+  /// Match probes for efficiency calculation
+  virtual void matchProbes(ProbeContainer*, const xAOD::IParticleContainer*) const;
+  void dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const;
+  void ptrMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const;
+  bool GoodMatchMuonType(const xAOD::IParticle* probe) const;
+ private:
 
-	 bool m_match_MS;
-     bool m_match_CB;
-     bool m_match_Loose;
-     bool m_match_Loose_noCT;
-     bool m_match_Medium;
-     bool m_match_Tight;
-     bool m_match_ID;
-     bool m_match_CaloTag;
-     bool m_match_MuidCB;
-     bool m_match_STACO;
-     bool m_match_MuTag;
-     bool m_match_MuTagIMO;
-     bool m_match_MuidSA;
-     bool m_match_MuGirl;
-     bool m_match_MuGirlLowBeta;
-     bool m_match_CaloLikelihood;
-     bool m_match_ExtrapolateToIP;
-     bool m_do_IDHits;
+  bool m_ptrMatching;
+  bool m_match_MS;
+  bool m_match_CB;
+  bool m_match_Loose;
+  bool m_match_Loose_noCT;
+  bool m_match_Medium;
+  bool m_match_Tight;
+  bool m_match_HighPt;
+  bool m_match_ID;
+  bool m_match_CaloTag;
+  bool m_match_MuidCB;
+  bool m_match_STACO;
+  bool m_match_MuTag;
+  bool m_match_MuTagIMO;
+  bool m_match_MuidSA;
+  bool m_match_MuGirl;
+  bool m_match_MuGirlLowBeta;
+  bool m_match_CaloLikelihood;
+  bool m_match_ExtrapolateToIP;
+  bool m_do_IDHits;
 
 };
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPEfficiencyTool.h
index c465dbaf6b6..76be7f4899f 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPEfficiencyTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPEfficiencyTool.h
@@ -19,9 +19,9 @@
 #include "TrigMuonMatching/ITrigMuonMatching.h"
 
 class MuonTPEfficiencyTool
-: virtual public asg::AsgTool,
+: public asg::AsgTool,
   virtual public IMuonTPEfficiencyTool {
-  ASG_TOOL_CLASS(MuonTPEfficiencyTool, IMuonTPEfficiencyTool)
+//   ASG_TOOL_CLASS(MuonTPEfficiencyTool, IMuonTPEfficiencyTool)
     
 public:
   
@@ -32,8 +32,8 @@ public:
   virtual StatusCode initialize();
 
   /// Match probes for efficiency calculation
-  void matchProbes(ProbeContainer*, const xAOD::IParticleContainer*) const;
-
+  virtual void matchProbes(ProbeContainer*, const xAOD::IParticleContainer*) const =0;
+  
   /// dR-based matching
   virtual void dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const;
 
@@ -45,15 +45,22 @@ public:
   
   //  check for a trigger match (probe side)
   bool MatchTrigger (const xAOD::IParticle* match,  std::string trigger) const;
+  
+  // check if the tool represents a nominal matching
+  bool isNominal() const {return m_isNominal;}
+  
+  // return the triger item (if any configured)
+  std::string triggerItem() {return m_trigger_item;}
 
 protected:
 
   double m_matchPtCut; 
   double m_matchEtaCut;
-  bool m_dRMatching;
   double m_maximumDrCut;
   unsigned int m_muonAuthor;  
   std::string m_efficiencyFlag;
+  bool m_isNominal;
+  std::string m_trigger_item;
   ToolHandle<CP::IMuonSelectionTool> m_selection_tool;
   ToolHandle<CP::IMuonEfficiencyScaleFactors> m_sf_tool;
   bool m_do_sf;
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPPlotTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPPlotTool.h
index 8a45e27f72c..9a195d1ff4d 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPPlotTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPPlotTool.h
@@ -24,43 +24,45 @@
 // define the plot classes to add in the HistUtils package
 
 class MuonTPPlotTool:
-		virtual public asg::AsgTool,
+        public asg::AsgTool,
 		virtual public IMuonTPPlotTool {
-		ASG_TOOL_CLASS(MuonTPPlotTool, IMuonTPPlotTool)
+// 		ASG_TOOL_CLASS(MuonTPPlotTool, IMuonTPPlotTool)
 
 public:
-		MuonTPPlotTool(std::string name);
+        MuonTPPlotTool(std::string name);
 
-		virtual StatusCode RegisterPlots (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools);
+        virtual StatusCode RegisterPlots (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools);
 
-		virtual std::vector<MuonTPEfficiencyPlotBase*> AddPlots(std::string sDir, bool isMatched);
+        virtual std::vector<MuonTPEfficiencyPlotBase*> AddPlots(std::string sDir, bool isMatched);
         virtual std::vector<MuonTPCutFlowBase*> AddCutFlowPlots(std::string sDir);
-		 // fill the histos
-	    virtual void fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tp_tool, ToolHandle <IMuonTPEfficiencyTool> eff_tool);
-	    virtual void fillCutFlow (std::string stage, double weight, ToolHandle <IMuonTPSelectionTool> & tp_tool);
+            // fill the histos
+        virtual void fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tp_tool, ToolHandle <IMuonTPEfficiencyTool> & eff_tool);
+        virtual void fillCutFlow (std::string stage, double weight, ToolHandle <IMuonTPSelectionTool> & tp_tool);
 
-		  /// retrieve booked histograms
-		std::vector<HistData> retrieveBookedHistograms();
+            /// retrieve booked histograms
+        std::vector<HistData> retrieveBookedHistograms();
         std::vector<std::pair <TGraph*,  std::string> > retrieveBookedGraphs();
 
-		virtual void CalcEff(void);
+        virtual void CalcEff(void);
 
 
-		virtual ~MuonTPPlotTool();
+        virtual ~MuonTPPlotTool();
 protected:
 
 
-		std::string m_efficiencyFlag;
-		std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_probeTPEffPlots;
-		std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_matchTPEffPlots;
-		std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_effTPEffPlots;
-		std::map<std::string,std::vector<MuonTPCutFlowBase*> > m_TPcutFlowPlots;
+        std::string m_efficiencyFlag;
+        std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_probeTPEffPlots;
+        std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_matchTPEffPlots;
+        std::map<std::string,std::vector<MuonTPEfficiencyPlotBase*> > m_effTPEffPlots;
+        std::map<std::string,std::vector<MuonTPCutFlowBase*> > m_TPcutFlowPlots;
 
         bool m_only_A_side;
         bool m_only_C_side;
         double m_probe_abseta_min;
         double m_probe_abseta_max;
         bool m_doAsymmErrors;
+        bool m_doEffPlots;
+        bool m_doProbeMatchPlots;
 };
 
 #endif /* MUONTPPLOTTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPSelectionTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPSelectionTool.h
index a0ffb14d039..bed98f21f97 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPSelectionTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPSelectionTool.h
@@ -15,23 +15,16 @@
 #include "AsgTools/ToolHandle.h"
 #include "MuonTPTools/IMuonTPSelectionTool.h"
 #include "MuonSelectorTools/IMuonSelectionTool.h"
-#include "xAODTruth/TruthParticle.h"
 #include "TrigDecisionTool/TrigDecisionTool.h"
 #include "TrigMuonMatching/ITrigMuonMatching.h"
 #include "AsgTools/AsgToolsConf.h"
 #include "AsgTools/AsgMetadataTool.h"
-
-//  for full athena, we also use the isolation tools
-# if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-#include "RecoToolInterfaces/ITrackIsolationTool.h"
-#include "RecoToolInterfaces/ICaloTopoClusterIsolationTool.h"
-# endif
-
+#include "GoodRunsLists/IGoodRunsListSelectionTool.h"
 
 class MuonTPSelectionTool
-: virtual public asg::AsgTool,
+: public asg::AsgTool,
   virtual public IMuonTPSelectionTool {
-  ASG_TOOL_CLASS(MuonTPSelectionTool, IMuonTPSelectionTool)
+//   ASG_TOOL_CLASS(MuonTPSelectionTool, IMuonTPSelectionTool)
 
 public:
 
@@ -62,6 +55,9 @@ public:
   // helper method to select Truth probes
   bool isFinalStateTruthMuon(const xAOD::IParticle* part) const;
 
+  // helper to check if a probe is truth matched
+  bool isTruthMatched(const xAOD::IParticle* part) const;
+
   // select muons that 'probably' fired the trigger - workaround for 19.1 xAODs without trigger info!
   bool passDummyTrigger(const xAOD::Muon* tag) const;
 
@@ -73,9 +69,20 @@ public:
 
   // apply impact parameter cuts
   bool PassIPCuts(const xAOD::TrackParticle* probe, double d0cut, double d0signcut, double z0cut) const;
+  
+  // apply GRL
+  bool passGRL(const xAOD::EventInfo* info) const;
+  
+  // check if the tool represents a nominal selection
+  bool isNominal() const {return m_isNominal;}
+  
+  // check if the tool is a systematic variation that can not be evaluated using the nominal ntuples
+  virtual bool notIncludedInNominal() const {return m_isNotPartOfNominal;}
 
   virtual void AddCutFlowHist(MuonTPCutFlowBase* hist);
   virtual void FillCutFlows(std::string step, double weight =1.) const ;
+  
+  std::vector<std::string> tagTriggerList() const {return m_tag_Triggers;}
 
 protected:
 
@@ -86,19 +93,16 @@ protected:
   double m_probeEtaCut;
   double m_highMassWindow;
   double m_lowMassWindow;
+  bool m_isNominal;
+  bool m_isNotPartOfNominal;
   std::string m_efficiencyFlag;
   std::vector<std::string> m_tag_Triggers;
   ToolHandle<CP::IMuonSelectionTool> m_selection_tool;
   std::vector<MuonTPCutFlowBase*> m_cutFlows;
   ToolHandle<Trig::TrigDecisionTool> m_trigTool;
   ToolHandle<Trig::ITrigMuonMatching> m_matchTool;
+  ToolHandle<IGoodRunsListSelectionTool> m_grlTool;
   
-# if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-  ToolHandle<xAOD::ITrackIsolationTool> m_track_iso_tool;
-  ToolHandle<xAOD::ICaloTopoClusterIsolationTool> m_calo_iso_tool;
-  std::vector<xAOD::Iso::IsolationType> m_track_iso_to_run;
-  std::vector<xAOD::Iso::IsolationType> m_calo_iso_to_run;
-#   endif
   
 
 };
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTool.h
index 867d21648b8..69149a2817b 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTool.h
@@ -23,7 +23,7 @@ class IMuonTPSelectionTool;
 class IMuonTPEfficiencyTool;
 
 class MuonTPTool
-: virtual public asg::AsgTool,
+: public asg::AsgTool,
   virtual public IMuonTPTool {
   ASG_TOOL_CLASS(MuonTPTool, IMuonTPTool)
     
@@ -44,7 +44,7 @@ class MuonTPTool
   
  private:
 
-  ServiceHandle<ITHistSvc> m_histSvc;
+  //ServiceHandle<ITHistSvc> m_histSvc;
   ToolHandleArray<IMuonTPSelectionTool> m_muonTPSelectionTools;
   ToolHandleArray<IMuonTPEfficiencyTool> m_muonTPEfficiencyTools;
   std::string m_efficiencyFlag;
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTreeTool.h
index fa401f5ab88..9c762036ca9 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTreeTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTPTreeTool.h
@@ -12,6 +12,7 @@
 #ifndef MUONTPTreeTool_H_
 #define MUONTPTreeTool_H_
 #include "MuonTPTools/IMuonTPTreeTool.h"
+#include "TrigDecisionTool/TrigDecisionTool.h"
 #include "MuonTPTools/IMuonTPSelectionTool.h"
 #include "MuonTPTools/IMuonTPEfficiencyTool.h"
 #include "AsgTools/AsgTool.h"
@@ -24,39 +25,54 @@
 // define the plot classes to add in the HistUtils package
 
 class MuonTPTreeTool:
-		virtual public asg::AsgTool,
-		virtual public IMuonTPTreeTool {
-		ASG_TOOL_CLASS(MuonTPTreeTool, IMuonTPTreeTool)
+public asg::AsgTool,
+  virtual public IMuonTPTreeTool {
 
-public:
-    MuonTPTreeTool(std::string name);
+ public:
+  MuonTPTreeTool(std::string name);
+  virtual ~MuonTPTreeTool();
 
-    virtual StatusCode RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools);
+  virtual StatusCode initialize();
 
+  virtual StatusCode RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools);
 
-    virtual void updateMatch(Probe& probe, ToolHandle <IMuonTPEfficiencyTool> eff_tool);
-    virtual void fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> sel_tool);
-    virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
+  virtual void updateMatch(Probe& probe, ToolHandle <IMuonTPEfficiencyTool> & eff_tool);
+  virtual void fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> & sel_tool);
+  virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
     
+  /// retrieve booked histograms
+  std::vector< std::pair<TTree*, std::string> > retrieveBookedTrees();
 
-    /// retrieve booked histograms
-    std::vector< std::pair<TTree*, std::string> > retrieveBookedTrees();
+  virtual void FillTriggerInfo();
+  virtual void FillTagTriggerInfo(Probe & probe);
+  virtual void InitTree(TTree* tree);
+  virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
 
-    virtual void InitTree(TTree* tree);
-    virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
-
-    virtual void ForgetKnownProbes();
+  virtual void ForgetKnownProbes();
       
-
-
-		virtual ~MuonTPTreeTool();
-protected:
-
-
-        std::string m_efficiencyFlag;
-		std::map<std::string, std::pair< TTree*, std::string> > m_trees;
-        std::map<std::string, bool> m_match_flags;
-        std::map<Probe*, std::map<std::string, bool> > m_match_flags_perProbe;
-};
+ protected:
+
+  ToolHandle<Trig::TrigDecisionTool> m_trigTool;
+
+  std::string m_efficiencyFlag;
+        
+  std::map<std::string, std::pair< TTree*, std::string> > m_trees;
+        
+  std::map<std::string, bool> m_match_flags;
+  std::map<std::string, float> m_scale_factors;
+  std::map<std::string, float> m_match_dR;
+        
+  std::map<std::string, bool> m_triggers;
+  std::map<std::string, bool> m_tag_trigmatch;
+  std::map<std::string, float> m_tag_trig_dR;
+        
+  std::map<Probe*, std::map<std::string, bool> > m_match_flags_perProbe;
+  std::map<Probe*, std::map<std::string, float> > m_scale_factors_perProbe;
+  std::map<Probe*, std::map<std::string, float> > m_match_dR_perProbe;
+        
+  bool m_record_SF;
+  //         std::map<Probe*, std::map<std::string, bool> > m_tag_trigmatch_perProbe;
+  //         std::map<Probe*, std::map<std::string, float> > m_tag_trig_dR_perProbe;
+  };
 
 #endif /* MUONTPTreeTool_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPEfficiencyTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPEfficiencyTool.h
index ebd3e7284f6..2ceea312f06 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPEfficiencyTool.h
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPEfficiencyTool.h
@@ -16,7 +16,7 @@
 
 
 // FrameWork includes
-#include "GaudiKernel/ServiceHandle.h"
+//#include "GaudiKernel/ServiceHandle.h"
 #include "TrigDecisionTool/TrigDecisionTool.h"
 
 
@@ -29,12 +29,11 @@ public:
 
     // Match probes for efficiency calculation
     void matchProbes(ProbeContainer*, const xAOD::IParticleContainer*) const;
-     
+    
 private:
 
     float m_dR_L1;
     float m_dR_HLT;
-    std::string m_trigger_item;
 
 };
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPPlotTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPPlotTool.h
deleted file mode 100644
index 38429823fdc..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPPlotTool.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTrigTPPlots.h
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc /a.m.
- */
-
-#ifndef MUONTRIGTPPLOTTOOL_H_
-#define MUONTRIGTPPLOTTOOL_H_
-#include "MuonTPTools/IMuonTPPlotTool.h"
-#include "MuonTPTools/IMuonTPSelectionTool.h"
-#include "MuonTPTools/IMuonTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTPPlotTool.h"
-#include "AsgTools/AsgTool.h"
-#include <map>
-
-class MuonTrigTPPlotTool: public MuonTPPlotTool
-{
-    ASG_TOOL_CLASS(MuonTrigTPPlotTool, IMuonTPPlotTool)
-
-public:
-    MuonTrigTPPlotTool(std::string name);
-
-    virtual std::vector<MuonTPEfficiencyPlotBase*> AddPlots(std::string sDir, bool isMatched);
-    virtual std::vector<MuonTPCutFlowBase*>        AddCutFlowPlots(std::string sDir);
-
-protected:
-
-    bool m_do_TPBasic;
-    bool m_do_Valid;
-    bool m_apply_SF;    
-};
-
-#endif /* MUONTRIGTPPLOTTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPTreeTool.h
deleted file mode 100644
index 0fa4a76e273..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/MuonTrigTPTreeTool.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-#ifndef MUONTRIGTPTreeTOOL_H_
-#define MUONTRIGTPTreeTOOL_H_
-
-#include "MuonTPTools/IMuonTPTreeTool.h"
-#include "MuonTPTools/IMuonTPSelectionTool.h"
-#include "MuonTPTools/IMuonTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTPTreeTool.h"
-#include "MuonEfficiencyCorrections/fineEtaPhiBinning.h"
-#include "AsgTools/AsgTool.h"
-#include <map>
-
-class MuonTrigTPTreeTool:
-        public MuonTPTreeTool {         // for now, a 1:1 copy
-        ASG_TOOL_CLASS(MuonTrigTPTreeTool, IMuonTPTreeTool)
-
-public:
-    MuonTrigTPTreeTool(std::string name);
-
-    virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
-    virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
-
-protected:
-    float m_runNumber;
-    float m_eventNumber;
-    float m_mu;
-    float m_mcEventWeight;
-    float m_pt;
-    float m_eta;
-    float m_phi;
-    float m_ptcone40;
-    float m_etcone40;
-    int   m_fineEtaPhi;
-    int   m_q;
-    float m_tagPt;
-    float m_tagEta;
-    float m_tagPhi;
-    float m_mll;
-    float m_d0;
-    float m_d0err;
-    float m_z0;
-
-    fineEtaPhiBinning m_fepb;
-        
-};
-
-#endif /* MUONTRIGTPTreeTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPIsolationTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPIsolationTreeTool.h
deleted file mode 100644
index 3ba8752c25b..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPIsolationTreeTool.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-
-#ifndef ZMUMUMUONTPISOLATIONTreeTOOL_H_
-#define ZMUMUMUONTPISOLATIONTreeTOOL_H_
-#include "MuonTPTools/IMuonTPTreeTool.h"
-#include "MuonTPTools/IMuonTPSelectionTool.h"
-#include "MuonTPTools/IMuonTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTPTreeTool.h"
-#include "MuonEfficiencyCorrections/fineEtaPhiBinning.h"
-#include "AsgTools/AsgTool.h"
-#include <map>
-
-class ZmumuMuonTPIsolationTreeTool:
-        public MuonTPTreeTool {         // for now, a 1:1 copy
-        ASG_TOOL_CLASS(ZmumuMuonTPIsolationTreeTool, IMuonTPTreeTool)
-
-public:
-        ZmumuMuonTPIsolationTreeTool(std::string name);
-
-    virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
-    virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
-
-protected:
-    float m_runNumber;
-    float m_eventNumber;
-    float m_mu;
-    float m_mcEventWeight;
-    float m_probePt;
-    float m_probeEta;
-    float m_probePhi;
-    int m_fineEtaPhi;
-    int m_probe_q;
-    int m_tag_q;
-
-    float m_tagPt;
-    float m_tagEta;
-    float m_tagPhi;
-
-    float m_mll;
-    float m_d0;
-    float m_d0err;
-    float m_z0;
-
-// isolation value
-  float m_tagiso_neflowisol20;
-  float m_tagiso_topoetcone20;
-  float m_tagiso_ptcone20;
-  float m_tagiso_etcone20;
-  float m_tagiso_ptvarcone20;
-
-  float m_tagiso_neflowisol30;
-  float m_tagiso_topoetcone30;
-  float m_tagiso_ptcone30;
-  float m_tagiso_etcone30;
-  float m_tagiso_ptvarcone30;
-
-  float m_tagiso_neflowisol40;
-  float m_tagiso_topoetcone40;
-  float m_tagiso_ptcone40;
-  float m_tagiso_etcone40;
-  float m_tagiso_ptvarcone40;
-
-  float m_probeiso_neflowisol20;
-  float m_probeiso_topoetcone20;
-  float m_probeiso_ptcone20;
-  float m_probeiso_etcone20;
-  float m_probeiso_ptvarcone20;
-
-  float m_probeiso_neflowisol30;
-  float m_probeiso_topoetcone30;
-  float m_probeiso_ptcone30;
-  float m_probeiso_etcone30;
-  float m_probeiso_ptvarcone30;
-
-  float m_probeiso_neflowisol40;
-  float m_probeiso_topoetcone40;
-  float m_probeiso_ptcone40;
-  float m_probeiso_etcone40;
-  float m_probeiso_ptvarcone40;
-
-  int m_Npvtx;
-  float m_dPhi;
-
-    fineEtaPhiBinning m_fepb;
-        
-};
-
-#endif /* ZMUMUMUONTPISOLATIONTreeTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPTreeTool.h b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPTreeTool.h
deleted file mode 100644
index 3a605a4c1b0..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/MuonTPTools/ZmumuMuonTPTreeTool.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-
-#ifndef ZMUMUMUONTPTreeTOOL_H_
-#define ZMUMUMUONTPTreeTOOL_H_
-#include "MuonTPTools/IMuonTPTreeTool.h"
-#include "MuonTPTools/IMuonTPSelectionTool.h"
-#include "MuonTPTools/IMuonTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTPTreeTool.h"
-#include "MuonEfficiencyCorrections/fineEtaPhiBinning.h"
-#include "MuonPerformanceHistUtils/EtaPhiBinning.h"
-#include "AsgTools/AsgTool.h"
-#include <map>
-
-class ZmumuMuonTPTreeTool:
-        public MuonTPTreeTool {         // for now, a 1:1 copy
-        ASG_TOOL_CLASS(ZmumuMuonTPTreeTool, IMuonTPTreeTool)
-
-public:
-        ZmumuMuonTPTreeTool(std::string name);
-
-    virtual void FillCustomStuff(Probe& probe);        // can override to fill custom branches
-    virtual void AddCustomBranches(TTree* tree);        // can override to add custom branches
-
-protected:
-    float m_runNumber;
-    float m_eventNumber;
-    float m_mu;
-    float m_mcEventWeight;
-    float m_pt;
-    float m_eta;
-    float m_phi;
-    float m_ptcone40;
-    float m_etcone40;
-    int m_fineEtaPhi;
-    int m_detregion;
-    int m_q;
-    float m_tagPt;
-    float m_tagEta;
-    float m_tagPhi;
-    float m_mll;
-    int m_PV_n;
-    float m_d0;
-    float m_d0err;
-    float m_z0;
-
-    uint8_t m_nBL;
-    uint8_t m_nPIX;
-    uint8_t m_nSCT;
-    uint8_t m_nPIXdead;
-    uint8_t m_nSCTdead;
-    uint8_t m_nPIXholes;
-    uint8_t m_nSCTholes;
-    uint8_t m_nTRT;
-    uint8_t m_nTRTout;
-
-    fineEtaPhiBinning m_fepb;
-    EtaPhiBinning m_epb;
-        
-};
-
-#endif /* ZMUMUMUONTPTreeTOOL_H_ */
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPPlotTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPPlotTool.cxx
new file mode 100644
index 00000000000..068a4d0e46b
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPPlotTool.cxx
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * MuonTPPlots.cxx
+ *
+ *  Created on: Aug 31, 2014
+ *      Author: goblirsc
+ */
+
+#include "MuonTPTools/DiMuonTPPlotTool.h"
+#include "MuonPerformanceHistUtils/ZmumuBasicTPEfficiencyPlots.h"
+#include "MuonPerformanceHistUtils/ZmumuTagProbeDileptonPlots.h"
+#include "MuonPerformanceHistUtils/ZmumuFineEtaPhiEfficiencyPlots.h"
+#include "MuonPerformanceHistUtils/DiLeptonTPEventCutFlowPlots.h"
+#include "MuonPerformanceHistUtils/ZmumuDetRegionEfficiencyPlots.h"
+#include "MuonPerformanceHistUtils/JPsiTagProbeDileptonPlots.h"
+#include "MuonPerformanceHistUtils/JPsiBasicTPEfficiencyPlots.h"
+#include "MuonPerformanceHistUtils/MuonTrigTPEfficiencyPlots.h"
+
+DiMuonTPPlotTool::DiMuonTPPlotTool(std::string name)
+  :  MuonTPPlotTool(name){
+  declareProperty("doTrkValidPlots",m_do_Valid=false);
+  declareProperty("doZmumuKinematicPlots",m_do_TPBasic_Zmm=false);
+  declareProperty("doJPsiKinematicPlots",m_do_TPBasic_JPsi=false);
+  declareProperty("doZmumuDileptonPlots",m_do_DiLepton_Zmm=false);
+  declareProperty("doJPsiDileptonPlots",m_do_DiLepton_JPsi=false);
+  declareProperty("doFineEtaPhiPlots",m_do_TPFineEtaPhi=false);
+  declareProperty("doDetectorRegionPlots",m_do_DetRegions=false);
+  declareProperty("doTrigValidPlots",m_do_TriggerPlots=false);
+  declareProperty("ApplyScaleFactors",m_apply_SF=false);
+}
+
+std::vector<MuonTPEfficiencyPlotBase*> DiMuonTPPlotTool::AddPlots(std::string sDir, bool isMatched){
+
+  std::vector<MuonTPEfficiencyPlotBase*> out (0);
+  if (m_do_Valid) out.push_back( new MuonTPEfficiencyPlots(0, sDir, isMatched));
+  if (m_do_TPBasic_Zmm) out.push_back( new ZmumuBasicTPEfficiencyPlots(0, sDir+"/basic_", isMatched,m_apply_SF));
+  if (m_do_TPBasic_JPsi) out.push_back( new JPsiBasicTPEfficiencyPlots(0, sDir+"/basic_", isMatched,m_apply_SF));
+  if (m_do_TPFineEtaPhi) out.push_back( new ZmumuFineEtaPhiEfficiencyPlots(0, sDir+"/", isMatched,m_apply_SF));
+  if (m_do_DiLepton_Zmm) out.push_back( new ZmumuTagProbeDileptonPlots(0, sDir+"/", isMatched,m_apply_SF));
+  if (m_do_DiLepton_JPsi) out.push_back( new JPsiTagProbeDileptonPlots(0, sDir+"/", isMatched,m_apply_SF));
+  if (m_do_DetRegions) out.push_back(new ZmumuDetRegionEfficiencyPlots(0,sDir+"/",isMatched,m_apply_SF));
+  if (m_do_TriggerPlots) out.push_back(new MuonTrigTPEfficiencyPlots(0,sDir+"/",isMatched,m_apply_SF));
+  return out;
+
+}
+
+std::vector<MuonTPCutFlowBase*> DiMuonTPPlotTool::AddCutFlowPlots(std::string sDir){
+
+  std::vector<MuonTPCutFlowBase*> out (0);
+  out.push_back (new DiLeptonTPEventCutFlowPlots(0,sDir));
+  return out;
+
+}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPSelectionTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPSelectionTool.cxx
similarity index 59%
rename from PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPSelectionTool.cxx
rename to PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPSelectionTool.cxx
index f8853d68ce9..9382df0f2e2 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPSelectionTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPSelectionTool.cxx
@@ -3,60 +3,69 @@
 */
 
 /*
- * ZmumuMuonTPSelectionTool.cxx
+ * DiMuonTPSelectionTool.cxx
  *
- *  Created on: Aug 23, 2014
+ *  Created on: Jun 18, 2015
  *      Author: goblirsc
  */
 
-#include "MuonTPTools/ZmumuMuonTPSelectionTool.h"
-// #include "../MuonTPTools/ZmumuMuonTPSelectionTool.h"
+#include "MuonTPTools/DiMuonTPSelectionTool.h"
 
-ZmumuMuonTPSelectionTool::ZmumuMuonTPSelectionTool(std::string myname)
-: AsgTool(myname), MuonTPSelectionTool(myname) {
+DiMuonTPSelectionTool::DiMuonTPSelectionTool(std::string myname)
+:  MuonTPSelectionTool(myname) {
 
-  declareProperty("UseIDProbes",  m_IDProbe = false);
-  declareProperty("UseMSProbes",  m_MSProbe = false);
-  declareProperty("UseCBProbes",  m_CBProbe = false);
-  declareProperty("UseCaloProbes",  m_CaloProbe = false);
-  declareProperty("UseTruthProbes",  m_TruthProbe = false);
+  declareProperty("UseIDProbes",      m_IDProbe = false);
+  declareProperty("UseMSProbes",      m_MSProbe = false);
+  declareProperty("UseCBProbes",      m_CBProbe = false);
+  declareProperty("UseCaloProbes",    m_CaloProbe = false);
+  declareProperty("UseTruthProbes",   m_TruthProbe = false);
+  declareProperty("UseTruthMatchedProbes", m_TruthMatchedProbe = false);
 
-  declareProperty("TagTrackIsoCut",  m_tagPtConeIso = 0.2);
-  declareProperty("ProbeTrackIsoCut",  m_probePtConeIso = -1);
-  declareProperty("TagCaloIsoCut",  m_tagEtConeIso = 0.2);
-  declareProperty("ProbeCaloIsoCut",  m_probeEtConeIso = -1);
+  declareProperty("TagTrackIsoCut",   m_tagPtConeIso = 0.2);
+  declareProperty("ProbeTrackIsoCut", m_probePtConeIso = -1.00);
+  declareProperty("TagCaloIsoCut",    m_tagEtConeIso = 0.2);
+  declareProperty("ProbeCaloIsoCut",  m_probeEtConeIso = -1.00);
 
   // for background studies
 
-  declareProperty("TagTrackAntiIsoCut",  m_tag_antiPtConeIso = -1);
-  declareProperty("ProbeTrackAntiIsoCut",  m_probe_antiPtConeIso = -1);
-  declareProperty("TagCaloAntiIsoCut",  m_tag_antiEtConeIso = -1);
-  declareProperty("ProbeCaloAntiIsoCut",  m_probe_antiEtConeIso = -1);
+  declareProperty("TagTrackAntiIsoCut",   m_tag_antiPtConeIso = -1.00);
+  declareProperty("ProbeTrackAntiIsoCut", m_probe_antiPtConeIso = -1.00);
+  declareProperty("TagCaloAntiIsoCut",    m_tag_antiEtConeIso = -1.00);
+  declareProperty("ProbeCaloAntiIsoCut",  m_probe_antiEtConeIso = -1.00);
 
   declareProperty("AcceptSameCharge",  m_accept_sameCharge = false);
-  declareProperty("AcceptOppCharge",  m_accept_oppCharge = true);
-
-  declareProperty("DeltaPhiCut",      m_deltaPhiCut = -1.00);
-
-  declareProperty("EfficiencyFlag", m_efficiencyFlag = "IDProbes");
-
-  declareProperty("DoOnlyAside",      m_only_A_side = false);
-  declareProperty("DoOnlyCside",      m_only_C_side = false);
-  declareProperty("ProbeAbsEtaMin",      m_probe_abseta_min = -1.00);
-  declareProperty("ProbeAbsEtaMax",      m_probe_abseta_max = 100.00);
-
-  declareProperty("TagD0Cut",      m_tag_d0 = -1);
-  declareProperty("TagD0SignCut",      m_tag_d0Sign = -1);
-  declareProperty("TagZ0Cut",      m_tag_z0 = -1);
-  declareProperty("ProbeD0Cut",      m_probe_d0 = -1);
-  declareProperty("ProbeD0SignCut",      m_probe_d0Sign = -1);
-  declareProperty("ProbeZ0Cut",      m_probe_z0 = -1);
-
-
-  declareProperty("ProbeIDHitCut", m_probe_ID_hits = false);
+  declareProperty("AcceptOppCharge",   m_accept_oppCharge = true);
+
+  declareProperty("DeltaPhiCut",       m_deltaPhiCut = -1.00);
+  declareProperty("DeltaEtaCut",       m_deltaEtaCut = -1.00);
+
+  declareProperty("EfficiencyFlag",    m_efficiencyFlag = "IDProbes");
+
+  declareProperty("DoOnlyAside",       m_only_A_side = false);
+  declareProperty("DoOnlyCside",       m_only_C_side = false);
+  declareProperty("ProbeAbsEtaMin",    m_probe_abseta_min = -1.00);
+  declareProperty("ProbeAbsEtaMax",    m_probe_abseta_max = 100.00);
+
+  declareProperty("TagD0Cut",          m_tag_d0 = -1.00);
+  declareProperty("TagD0SignCut",      m_tag_d0Sign = -1.00);
+  declareProperty("TagZ0Cut",          m_tag_z0 = -1.00);
+  declareProperty("ProbeD0Cut",        m_probe_d0 = -1.00);
+  declareProperty("ProbeD0SignCut",    m_probe_d0Sign = -1.00);
+  declareProperty("ProbeZ0Cut",        m_probe_z0 = -1.00);
+
+  declareProperty("ProbeIDHitCut",     m_probe_ID_hits = false);
+  
+  declareProperty("doProbeChargeSys",  m_doProbeChargeSys = false); // Next time you turn this on by default for *EVERYONE*,
+  declareProperty("ProbeCharge",       m_ProbeCharge = "positive"); // at least write an email :)
+
+  declareProperty("UseVeryLooseProbes",m_VeryLooseProbe = false);
+  declareProperty("UseLooseProbes",    m_LooseProbe     = false);
+  declareProperty("UseMediumProbes",   m_MediumProbe    = false);
+  declareProperty("UseTightProbes",    m_TightProbe     = false);
+  declareProperty("UseHighPtProbes",   m_HighPtProbe    = false);
 }
 
-StatusCode ZmumuMuonTPSelectionTool::initialize()
+StatusCode DiMuonTPSelectionTool::initialize()
 {
   // ATH_CHECK(m_muonSelectionTool.retrieve());
   ATH_CHECK(m_selection_tool.retrieve());
@@ -66,11 +75,21 @@ StatusCode ZmumuMuonTPSelectionTool::initialize()
 
 //**********************************************************************
 
-ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer* tags, const xAOD::IParticleContainer* probes) const
+ProbeContainer* DiMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer* tags, const xAOD::IParticleContainer* probes) const
 {
-  // use m_muonSelectionTool to select muons
-  ProbeContainer* probeCont = new ProbeContainer();
-  FillCutFlows("Processed");
+    // use m_muonSelectionTool to select muons
+    ProbeContainer* probeCont = new ProbeContainer();
+    FillCutFlows("Processed");
+  
+    // check GRL
+    const xAOD::EventInfo* info = 0;
+    ATH_MSG_DEBUG(""<<evtStore());
+    if (evtStore()->retrieve(info, "EventInfo").isFailure()){
+        ATH_MSG_FATAL( "Unable to retrieve Event Info" );
+    }
+    if (!passGRL(info)) return probeCont;
+    FillCutFlows("GRL");
+  
   if(!Event_Trigger()) return probeCont;
   FillCutFlows("Trigger");
   bool have_tag = false;
@@ -82,14 +101,14 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
 
           FillCutFlows("TagCandidates");
           FillCutFlows("TagQuality");
+          if (!isFinalStateTruthMuon(probe)) {
+              continue;
+          }
           FillCutFlows("TagPt");
           FillCutFlows("TagEta");
           FillCutFlows("TagTrigger");
           FillCutFlows("TagIP");
           FillCutFlows("TagIsolation");
-          if (!isFinalStateTruthMuon(probe)) {
-              continue;
-          }
 
 
             // Here, we only need to apply the kinematic selection
@@ -103,11 +122,47 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
           FillCutFlows("ProbeInvMass");
           FillCutFlows("ProbeCharge");
           FillCutFlows("ProbeDeltaPhi");
+          FillCutFlows("ProbeDeltaEta");
             // in this case, fill the 'tag' slot of the probe with the probe - there is no tag for the truth efficiencies.
           probeCont->push_back( new Probe(*probe, *probe) );
           have_probe = true;
       }
   }
+
+  // truth matched muon probes are selected separately (used for truth-closure by isolation and trigger TP)
+  else if (m_TruthMatchedProbe){
+      have_tag = true;
+      for(auto probe : *probes) {
+
+          FillCutFlows("TagCandidates");
+          FillCutFlows("TagQuality");
+          if (!isTruthMatched(probe)) {
+	    continue;
+          }
+          FillCutFlows("TagPt");
+          FillCutFlows("TagEta");
+          FillCutFlows("TagTrigger");
+          FillCutFlows("TagIP");
+          FillCutFlows("TagIsolation");
+
+	  // Here, we only need to apply the kinematic selection
+          if (!PassProbeKinematics(probe)) continue;
+
+          FillCutFlows("ProbeKinematics");
+          FillCutFlows("ProbeQuality");
+          FillCutFlows("ProbeQuality");
+          FillCutFlows("ProbeIP");
+          FillCutFlows("ProbeIsolation");
+          FillCutFlows("ProbeInvMass");
+          FillCutFlows("ProbeCharge");
+          FillCutFlows("ProbeDeltaPhi");
+          FillCutFlows("ProbeDeltaEta");
+            // in this case, fill the 'tag' slot of the probe with the probe - there is no tag for the truth efficiencies.
+          probeCont->push_back( new Probe(*probe, *probe) );
+          have_probe = true;
+      }
+  }
+
   // "Real" Tag&Probe pairs
   else {
       // loop over tag container
@@ -118,7 +173,6 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
         // select good muons (combined for the time being)
         // A muon selection tool should be used, but the tool
         // should be ASG dual-tool
-//         if(tag->muonType() != xAOD::Muon::MuonType::Combined) continue;
         if (m_selection_tool->getQuality(*tag) > xAOD::Muon::Medium)  continue;
 
         if (!m_selection_tool->passedIDCuts(*tag)) continue;
@@ -177,6 +231,30 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
           double mtp = (tag->p4()+probe->p4()).M();
           if(mtp<m_lowMassWindow || mtp>m_highMassWindow) continue;
           FillCutFlows("ProbeInvMass");
+          
+	  if(m_doProbeChargeSys)
+	  {
+	      if(m_ProbeCharge=="positive")
+	      {
+                  // case of a muon probe
+                  const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(probe);
+                  if (muprobe && (muprobe->trackParticle(xAOD::Muon::Primary)->charge() < 0) ) continue;
+                  
+		  // case of an ID probe
+                  const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(probe);
+                  if (trkprobe && (trkprobe->charge() < 0) )  continue;
+             }
+	      if(m_ProbeCharge=="negative")
+	      {
+                  // case of a muon probe
+                  const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(probe);
+                  if (muprobe && (muprobe->trackParticle(xAOD::Muon::Primary)->charge() > 0) ) continue;
+                  
+		  // case of an ID probe
+                  const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(probe);
+                  if (trkprobe && (trkprobe->charge() > 0) )  continue;
+              }
+          }
 
           // Charge cut
           //if(m_oppositeCharge &&
@@ -203,6 +281,11 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
           // Delta Phi cut
           if (DeltaPhiTP(tag,probe) < m_deltaPhiCut) continue;
           FillCutFlows("ProbeDeltaPhi");
+
+          // Delta Eta cut
+          if (fabs(tag->eta()-probe->eta()) < m_deltaEtaCut) continue;
+          FillCutFlows("ProbeDeltaEta");
+
           // for each selected probe build a Probe object
           probeCont->push_back( new Probe(*tag, *probe) );
           have_probe = true;
@@ -219,7 +302,7 @@ ProbeContainer* ZmumuMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer
 
 
 
-bool ZmumuMuonTPSelectionTool::PassTagIsoCuts (const xAOD::Muon* tag) const{
+bool DiMuonTPSelectionTool::PassTagIsoCuts (const xAOD::Muon* tag) const{
      float tagiso = 0.0;
      bool haveIso = tag->isolation(tagiso,xAOD::Iso::ptcone40);
      if (m_tagPtConeIso > 0 && (!haveIso || tagiso > m_tagPtConeIso * tag->p4().Pt())) return false;
@@ -229,7 +312,7 @@ bool ZmumuMuonTPSelectionTool::PassTagIsoCuts (const xAOD::Muon* tag) const{
      if (m_tag_antiEtConeIso > 0 && (!haveEtIso || tagiso < m_tag_antiEtConeIso * tag->pt())) return false;
      return true;
 }
-bool ZmumuMuonTPSelectionTool::PassProbeIsoCuts (const xAOD::IParticle* probe) const{
+bool DiMuonTPSelectionTool::PassProbeIsoCuts (const xAOD::IParticle* probe) const{
       // probe iso cut
     float probeiso = 0.0;
     float probeEtiso = 0.0;
@@ -257,12 +340,12 @@ bool ZmumuMuonTPSelectionTool::PassProbeIsoCuts (const xAOD::IParticle* probe) c
     return true;
 }
 
-bool ZmumuMuonTPSelectionTool::isTag(const xAOD::Muon* tag, const xAOD::IParticle* probe) const
+bool DiMuonTPSelectionTool::isTag(const xAOD::Muon* tag, const xAOD::IParticle* probe) const
 {
   return (tag->p4().DeltaR(probe->p4()) < 0.01);
 }
 
-bool ZmumuMuonTPSelectionTool::PassProbeIPCuts(const xAOD::IParticle* probe) const{
+bool DiMuonTPSelectionTool::PassProbeIPCuts(const xAOD::IParticle* probe) const{
 
     const xAOD::TrackParticle* tp = 0;
     const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(probe);
@@ -277,7 +360,7 @@ bool ZmumuMuonTPSelectionTool::PassProbeIPCuts(const xAOD::IParticle* probe) con
     }
     return PassIPCuts(tp,m_probe_d0, m_probe_d0Sign, m_probe_z0);
 }
-bool ZmumuMuonTPSelectionTool::PassTagIPCuts(const xAOD::Muon* tag) const{
+bool DiMuonTPSelectionTool::PassTagIPCuts(const xAOD::Muon* tag) const{
 
     const xAOD::TrackParticle* tp = tag->primaryTrackParticle();
     if (!tp){
@@ -286,7 +369,7 @@ bool ZmumuMuonTPSelectionTool::PassTagIPCuts(const xAOD::Muon* tag) const{
     return PassIPCuts(tp,m_tag_d0, m_tag_d0Sign, m_tag_z0);
 }
 
-bool ZmumuMuonTPSelectionTool::isRightType(const xAOD::IParticle* probe) const{
+bool DiMuonTPSelectionTool::isRightType(const xAOD::IParticle* probe) const{
 
     const xAOD::Muon* muprobe = dynamic_cast <const xAOD::Muon*> (probe);
 
@@ -296,6 +379,29 @@ bool ZmumuMuonTPSelectionTool::isRightType(const xAOD::IParticle* probe) const{
 
     // otherwise, we have to manually pick the right probe
 
+    // for VeryLoose/Loose/Medium/Tight selection
+    if (m_VeryLooseProbe)
+    {
+        return (muprobe && m_selection_tool->getQuality(*muprobe) <= xAOD::Muon::VeryLoose);
+    }
+    if (m_LooseProbe)
+    {
+        return (muprobe && m_selection_tool->getQuality(*muprobe) <= xAOD::Muon::Loose);
+    }
+    if (m_MediumProbe)
+    {
+        return (muprobe && m_selection_tool->getQuality(*muprobe) <= xAOD::Muon::Medium);
+    }
+    if (m_TightProbe)
+    {
+        return (muprobe && m_selection_tool->getQuality(*muprobe) <= xAOD::Muon::Tight);
+    }
+    if (m_HighPtProbe)
+    {
+      return (muprobe && m_selection_tool->passedHighPtCuts(*muprobe));
+    }
+
+
     // MS probe if we are running on the muon collection
     if (m_MSProbe){
 //         static int n_zerophi = 0;
@@ -321,7 +427,7 @@ bool ZmumuMuonTPSelectionTool::isRightType(const xAOD::IParticle* probe) const{
 
 }
 
-bool ZmumuMuonTPSelectionTool::PassProbeKinematics (const xAOD::IParticle* probe) const{
+bool DiMuonTPSelectionTool::PassProbeKinematics (const xAOD::IParticle* probe) const{
 
     if(probe->pt() < m_probePtCut) return false;
     if(fabs(probe->eta()) > m_probeEtaCut) return false;
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPTreeTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPTreeTool.cxx
new file mode 100644
index 00000000000..2586e0df553
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/DiMuonTPTreeTool.cxx
@@ -0,0 +1,437 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * MuonTPTrees.cxx
+ *
+ *  Created on: Aug 31, 2014
+ *      Author: goblirsc
+ */
+
+#include "MuonTPTools/DiMuonTPTreeTool.h"
+#include "xAODEventInfo/EventInfo.h"
+#include "xAODEventShape/EventShape.h"
+#include "xAODTracking/VertexContainer.h"
+#include "xAODTracking/Vertex.h"
+#include "xAODTruth/TruthParticle.h"
+#include "xAODJet/JetContainer.h"
+
+DiMuonTPTreeTool::DiMuonTPTreeTool(std::string name)
+  :  MuonTPTreeTool(name),
+     m_runNumber(0),
+     m_eventNumber(0),
+     m_lumiblock(0),
+     m_average_mu(-1.),
+     m_actual_mu(-1),
+     m_PV_n(-1),
+     m_mcEventWeight(-1),
+     m_pt(-1),
+     m_eta(-1),
+     m_phi(-1),
+     m_type(-1),
+     m_author(-1),
+     m_quality(-1),
+     m_fineEtaPhi(-1),
+     m_detregion(-1),
+     m_q(-1),
+     m_d0(-1),
+     m_d0err(-1),
+     m_z0(-1),
+     m_tagPt(-1),
+     m_tagEta(-1),
+     m_tagPhi(-1),
+     m_tag_q(-1),
+     m_tag_d0(-1),
+     m_tag_d0err(-1),
+     m_tag_z0(-1),
+     m_mll(-1),
+     m_dPhi(-1),
+     m_dilep_pt(-1),
+     m_dilep_tof(-1),
+     m_tag_deltaR(-1),
+     m_deltaR(-1),
+     m_tagiso_neflowisol20(-1),
+     m_tagiso_topoetcone20(-1),
+     m_tagiso_ptcone20(-1),
+     m_tagiso_etcone20(-1),
+     m_tagiso_ptvarcone20(-1),
+
+     m_tagiso_neflowisol30(-1),
+     m_tagiso_topoetcone30(-1),
+     m_tagiso_ptcone30(-1),
+     m_tagiso_etcone30(-1),
+     m_tagiso_ptvarcone30(-1),
+
+     m_tagiso_neflowisol40(-1),
+     m_tagiso_topoetcone40(-1),
+     m_tagiso_ptcone40(-1),
+     m_tagiso_etcone40(-1),
+     m_tagiso_ptvarcone40(-1),
+
+     m_tag_topocore(-1),
+
+     m_probeiso_neflowisol20(-1),
+     m_probeiso_topoetcone20(-1),
+     m_probeiso_ptcone20(-1),
+     m_probeiso_etcone20(-1),
+     m_probeiso_ptvarcone20(-1),
+
+     m_probeiso_neflowisol30(-1),
+     m_probeiso_topoetcone30(-1),
+     m_probeiso_ptcone30(-1),
+     m_probeiso_etcone30(-1),
+     m_probeiso_ptvarcone30(-1),
+
+     m_probeiso_neflowisol40(-1),
+     m_probeiso_topoetcone40(-1),
+     m_probeiso_ptcone40(-1),
+     m_probeiso_etcone40(-1),
+     m_probeiso_ptvarcone40(-1),
+
+     m_probe_topocore(-1),
+
+     m_energyDensity_central(-1),
+     m_energyDensity_forward(-1)
+{
+  declareProperty("MuonSelectionTool",m_muon_selection_tool);  
+  declareProperty("AddExtendedIsolation",m_extended_Iso_Info = false);
+}
+
+StatusCode DiMuonTPTreeTool::initialize()
+{
+  ATH_CHECK(m_muon_selection_tool.retrieve());
+  return StatusCode::SUCCESS;
+
+}
+void DiMuonTPTreeTool::FillCustomStuff(Probe& probe){
+
+  m_energyDensity_central = 0.;
+  m_energyDensity_forward = 0.;
+  m_tag_topocore = 0.;
+  m_probe_topocore = 0.;
+
+  // Primary vertex variables
+  const xAOD::VertexContainer* primVertices = 0 ;
+  const xAOD::Vertex* pv = 0;
+  if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
+    ATH_MSG_ERROR("Found no PV candidate for IP computation!");
+  }
+  else {
+    pv = primVertices->at(0);
+  }
+  m_PV_n=0;
+  for (auto vx: *primVertices){
+    if (vx->vertexType() == xAOD::VxType::PriVtx || vx->vertexType() == xAOD::VxType::PileUp) ++m_PV_n;
+  }
+
+  // distance to clostes jet
+  m_deltaR = 99.;
+  m_tag_deltaR = 99.;
+  const xAOD::JetContainer* jets = 0;
+  if (evtStore()->retrieve(jets,"AntiKt4LCTopoJets").isFailure()){
+    ATH_MSG_WARNING( "Unable to retrieve Jet Container" );
+  }else{
+    // calculate delta R to the closest jet        
+    for(auto jet : *jets) {
+      float probe_deltaR = probe.probeTrack().p4().DeltaR(jet->p4());
+      if (probe_deltaR < m_deltaR) m_deltaR = probe_deltaR;
+      float tag_deltaR = probe.tagTrack().p4().DeltaR(jet->p4());
+      if (tag_deltaR < m_tag_deltaR) m_tag_deltaR = tag_deltaR;      
+    }
+    if (jets->size()==0) {
+      m_deltaR=-1;
+      m_tag_deltaR=-1;
+    }
+  }
+
+  // Event shape variables for isolation
+  const xAOD::EventShape* edShape = 0;
+  double rho = 0.;
+  if (evtStore()->retrieve(edShape,"TopoClusterIsoCentralEventShape").isFailure()){  // Returns a boolean, needs to be surrounded with error checks.
+    ATH_MSG_FATAL( "Unable to retrieve TopoClusterIsoCentralEventShape" );
+  } else {
+    edShape->getDensity(xAOD::EventShape::Density,rho); // Returns a boolean, needs to be surrounded with error checks.
+    m_energyDensity_central = rho;
+  }
+  if (evtStore()->retrieve(edShape,"TopoClusterIsoForwardEventShape").isFailure()){  // Returns a boolean, needs to be surrounded with error checks.
+    ATH_MSG_FATAL( "Unable to retrieve TopoClusterIsoForwardEventShape" );
+  } else {
+    edShape->getDensity(xAOD::EventShape::Density,rho); // Returns a boolean, needs to be surrounded with error checks.
+    m_energyDensity_forward = rho;
+  }
+    
+    
+  int charge = -2;
+  m_type = 0;
+  m_author = -1;
+  m_quality = -1;
+  const xAOD::Vertex* vx_tag = 0;
+  const xAOD::Vertex* vx_probe = 0;
+  // tag muon properties 
+  const xAOD::Muon* mutag = dynamic_cast<const xAOD::Muon*>(&probe.tagTrack());
+  int charge2 = -2;
+  if (mutag) {
+    charge2 = mutag->trackParticle(xAOD::Muon::Primary)->charge();
+    vx_tag = mutag->trackParticle(xAOD::Muon::Primary)->vertex();
+        
+    if (mutag->primaryTrackParticle()){
+      m_tag_d0 = mutag->primaryTrackParticle()->d0();
+      m_tag_d0err = sqrt(mutag->primaryTrackParticle()->definingParametersCovMatrix()(0,0));
+      m_tag_z0 = mutag->primaryTrackParticle()->z0();
+      if (pv){
+	m_tag_z0 = m_tag_z0 - pv->z() + mutag->primaryTrackParticle()->vz();
+      }
+    }
+    if (m_extended_Iso_Info){
+      bool ok2 = mutag->isolation(m_tagiso_etcone40,xAOD::Iso::topoetcone40);
+      if (!ok2) m_tagiso_etcone40 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptcone40,xAOD::Iso::ptcone40);
+      if (!ok2) m_tagiso_ptcone40 = -1;
+      ok2 = mutag->isolation(m_tagiso_topoetcone40,xAOD::Iso::topoetcone40);
+      if (!ok2) m_tagiso_topoetcone40 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptvarcone40,xAOD::Iso::ptvarcone40);
+      if (!ok2) m_tagiso_ptvarcone40 = -1;
+      ok2 = mutag->isolation(m_tagiso_neflowisol40,xAOD::Iso::neflowisol40);
+      if (!ok2) m_tagiso_neflowisol40 = -1;
+
+      ok2 = mutag->isolation(m_tagiso_etcone30,xAOD::Iso::topoetcone30);
+      if (!ok2) m_tagiso_etcone30 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptcone30,xAOD::Iso::ptcone30);
+      if (!ok2) m_tagiso_ptcone30 = -1;
+      ok2 = mutag->isolation(m_tagiso_topoetcone30,xAOD::Iso::topoetcone30);
+      if (!ok2) m_tagiso_topoetcone30 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptvarcone30,xAOD::Iso::ptvarcone30);
+      if (!ok2) m_tagiso_ptvarcone30 = -1;
+      ok2 = mutag->isolation(m_tagiso_neflowisol30,xAOD::Iso::neflowisol30);
+      if (!ok2) m_tagiso_neflowisol30 = -1;
+
+      ok2 = mutag->isolation(m_tagiso_etcone20,xAOD::Iso::topoetcone20);
+      if (!ok2) m_tagiso_etcone20 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptcone20,xAOD::Iso::ptcone20);
+      if (!ok2) m_tagiso_ptcone20 = -1;
+      ok2 = mutag->isolation(m_tagiso_topoetcone20,xAOD::Iso::topoetcone20);
+      if (!ok2) m_tagiso_topoetcone20 = -1;
+      ok2 = mutag->isolation(m_tagiso_ptvarcone20,xAOD::Iso::ptvarcone20);
+      if (!ok2) m_tagiso_ptvarcone20 = -1;
+      ok2 = mutag->isolation(m_tagiso_neflowisol20,xAOD::Iso::neflowisol20);
+      if (!ok2) m_tagiso_neflowisol20 = -1;
+    }
+  }
+    
+    
+  // case of a muon probe
+  const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(&probe.probeTrack());
+  if (muprobe) {
+    charge = muprobe->trackParticle(xAOD::Muon::Primary)->charge() ;
+    if (muprobe->primaryTrackParticle()){
+      m_d0 = muprobe->primaryTrackParticle()->d0();
+      m_d0err = sqrt(muprobe->primaryTrackParticle()->definingParametersCovMatrix()(0,0));
+      m_z0 = muprobe->primaryTrackParticle()->z0();
+      if (pv){
+	m_z0 = m_z0 - pv->z() + muprobe->primaryTrackParticle()->vz();
+      }
+    }
+    vx_probe = muprobe->trackParticle(xAOD::Muon::Primary)->vertex();
+    muprobe->isolationCaloCorrection(m_probe_topocore, xAOD::Iso::topoetcone, xAOD::Iso::coreCone, xAOD::Iso::IsolationCorrectionParameter::coreEnergy);
+    xAOD::Muon::Quality probe_qual = m_muon_selection_tool->getQuality(*muprobe);
+    if ( probe_qual == xAOD::Muon::Tight ) m_quality = 0; 
+    else if ( probe_qual == xAOD::Muon::Medium ) m_quality = 1; 
+    else if ( probe_qual == xAOD::Muon::Loose ) m_quality = 2; 
+    else if ( probe_qual == xAOD::Muon::VeryLoose ) m_quality = 3;
+        
+    if ( muprobe->author() == xAOD::Muon::unknown ) m_author = 0; 
+    else if ( muprobe->author() == xAOD::Muon::MuidCo ) m_author = 1; 
+    else if ( muprobe->author() == xAOD::Muon::STACO ) m_author = 2; 
+    else if ( muprobe->author() == xAOD::Muon::MuTag ) m_author = 3; 
+    else if ( muprobe->author() == xAOD::Muon::MuTagIMO ) m_author = 4; 
+    else if ( muprobe->author() == xAOD::Muon::MuidSA ) m_author = 5; 
+    else if ( muprobe->author() == xAOD::Muon::MuGirl ) m_author = 6; 
+    else if ( muprobe->author() == xAOD::Muon::MuGirlLowBeta ) m_author = 7; 
+    else if ( muprobe->author() == xAOD::Muon::CaloTag ) m_author = 8; 
+    else if ( muprobe->author() == xAOD::Muon::CaloLikelihood ) m_author = 9; 
+    else if ( muprobe->author() == xAOD::Muon::ExtrapolateMuonToIP ) m_author = 10; 
+        
+    if ( muprobe->muonType() == xAOD::Muon::Combined ) m_type = 1; // "CB"
+    else if ( muprobe->muonType() == xAOD::Muon::MuonStandAlone ) m_type = 2; // "SA"
+    else if ( muprobe->muonType() == xAOD::Muon::SegmentTagged ) m_type = 3; // "ST"
+    else if ( muprobe->muonType() == xAOD::Muon::CaloTagged ) m_type = 4; // "CT"
+        
+    if (m_extended_Iso_Info){
+      bool ok = muprobe->isolation(m_probeiso_etcone40,xAOD::Iso::topoetcone40);
+      if (!ok) m_probeiso_etcone40 = -1;
+      ok = muprobe->isolation(m_probeiso_ptcone40,xAOD::Iso::ptcone40);
+      if (!ok) m_probeiso_ptcone40 = -1;
+      ok = muprobe->isolation(m_probeiso_topoetcone40,xAOD::Iso::topoetcone40);
+      if (!ok) m_probeiso_topoetcone40 = -1;
+      ok = muprobe->isolation(m_probeiso_ptvarcone40,xAOD::Iso::ptvarcone40);
+      if (!ok) m_probeiso_ptvarcone40 = -1;
+      ok = muprobe->isolation(m_probeiso_neflowisol40,xAOD::Iso::neflowisol40);
+      if (!ok) m_probeiso_neflowisol40 = -1;
+
+      ok = muprobe->isolation(m_probeiso_etcone30,xAOD::Iso::topoetcone30);
+      if (!ok) m_probeiso_etcone30 = -1;
+      ok = muprobe->isolation(m_probeiso_ptcone30,xAOD::Iso::ptcone30);
+      if (!ok) m_probeiso_ptcone30 = -1;
+      ok = muprobe->isolation(m_probeiso_topoetcone30,xAOD::Iso::topoetcone30);
+      if (!ok) m_probeiso_topoetcone30 = -1;
+      ok = muprobe->isolation(m_probeiso_ptvarcone30,xAOD::Iso::ptvarcone30);
+      if (!ok) m_probeiso_ptvarcone30 = -1;
+      ok = muprobe->isolation(m_probeiso_neflowisol30,xAOD::Iso::neflowisol30);
+      if (!ok) m_probeiso_neflowisol30 = -1;
+
+      ok = muprobe->isolation(m_probeiso_etcone20,xAOD::Iso::topoetcone20);
+      if (!ok) m_probeiso_etcone20 = -1;
+      ok = muprobe->isolation(m_probeiso_ptcone20,xAOD::Iso::ptcone20);
+      if (!ok) m_probeiso_ptcone20 = -1;
+      ok = muprobe->isolation(m_probeiso_topoetcone20,xAOD::Iso::topoetcone20);
+      if (!ok) m_probeiso_topoetcone20 = -1;
+      ok = muprobe->isolation(m_probeiso_ptvarcone20,xAOD::Iso::ptvarcone20);
+      if (!ok) m_probeiso_ptvarcone40 = -1;
+      ok = muprobe->isolation(m_probeiso_neflowisol20,xAOD::Iso::neflowisol20);
+      if (!ok) m_probeiso_neflowisol20 = -1;
+    }
+  }
+
+  // case of an ID probe
+  const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(&probe.probeTrack());
+  if (!muprobe && trkprobe){
+    charge = trkprobe->charge();
+    vx_probe = trkprobe->vertex();
+    m_d0 = trkprobe->d0();
+    m_d0err = sqrt(trkprobe->definingParametersCovMatrix()(0,0));
+    m_z0 = trkprobe->z0();
+    //         const xAOD::Vertex* vx = trkprobe->vertex();
+    if (pv){
+      m_z0 = m_z0 - pv->z() + trkprobe->vz();
+    }
+  }
+  // case of an truth probe: rely on the sign of the pdg ID
+  const xAOD::TruthParticle* truthtrk = dynamic_cast<const xAOD::TruthParticle*>(&probe.probeTrack());
+  if (truthtrk) {
+    if (truthtrk->charge() > 0) charge = 1.0;
+    if (truthtrk->charge() < 0) charge = -1.0;
+        
+  }
+
+  const xAOD::EventInfo* info = 0;
+  ATH_MSG_DEBUG(""<<evtStore());
+  if (evtStore()->retrieve(info, "EventInfo").isFailure()){
+    ATH_MSG_FATAL( "Unable to retrieve Event Info" );
+  }
+  static bool isMC = info->eventType(xAOD::EventInfo::IS_SIMULATION);
+
+  m_runNumber = info->runNumber();
+  m_eventNumber = info->eventNumber();
+  m_lumiblock = info->lumiBlock();
+  m_average_mu = info->averageInteractionsPerCrossing();
+  m_actual_mu = info->actualInteractionsPerCrossing();
+  m_mcEventWeight = (isMC ? info->mcEventWeight() : 1.00);
+  m_pt = probe.pt() / 1000.;
+  m_eta = probe.eta();
+  m_phi = probe.phi();
+  m_fineEtaPhi = m_fepb.bin(probe.probeTrack().p4());
+  m_detregion = m_epb.symmetricBin(probe.probeTrack().p4());
+  m_q = charge;
+  m_tag_q = charge2;
+  m_tagPt = probe.tagTrack().pt() / 1000.;
+  m_tagEta = probe.tagTrack().eta();
+  m_tagPhi = probe.tagTrack().phi();
+  m_mll = (probe.tagTrack().p4()+probe.probeTrack().p4()).M();
+  m_dilep_pt = (probe.tagTrack().p4()+probe.probeTrack().p4()).Pt();
+    
+  // if we have a valid decay vertex and primary vertex, compute the time of flight
+  if (vx_tag && vx_tag == vx_probe && pv){
+    TVector3 vvx_tag (vx_tag->x(),vx_tag->y(),vx_tag->z());
+    TVector3 vpv (pv->x(),pv->y(),pv->z());
+    m_dilep_tof = (vvx_tag - vpv).Perp() * 3096. / m_dilep_pt;
+  }
+  else{
+    m_dilep_tof = -1;
+  }
+  m_dPhi = probe.tagTrack().p4().DeltaPhi(probe.probeTrack().p4());
+    
+    
+}
+void DiMuonTPTreeTool::AddCustomBranches(TTree* tree){
+
+  tree->Branch("runNumber",&m_runNumber);
+  tree->Branch("eventNumber",&m_eventNumber);
+  tree->Branch("lumiblock",&m_lumiblock);
+  tree->Branch("average_mu",&m_average_mu);
+  tree->Branch("actual_mu",&m_actual_mu);
+  tree->Branch("PV_n",&m_PV_n);
+  tree->Branch("mcEventWeight",&m_mcEventWeight);
+  tree->Branch("probe_pt",&m_pt);
+  tree->Branch("probe_eta",&m_eta);
+  tree->Branch("probe_phi",&m_phi);
+  tree->Branch("probe_type",&m_type);
+  tree->Branch("probe_author",&m_author);
+  tree->Branch("probe_quality",&m_quality);
+  tree->Branch("probe_fineEtaPhi",&m_fineEtaPhi);
+  tree->Branch("probe_detRegion",&m_detregion);
+  tree->Branch("probe_q",&m_q);
+  tree->Branch("probe_d0",&m_d0);
+  tree->Branch("probe_d0err",&m_d0err);
+  tree->Branch("probe_z0",&m_z0);
+  tree->Branch("tag_pt",&m_tagPt);
+  tree->Branch("tag_eta",&m_tagEta);
+  tree->Branch("tag_phi",&m_tagPhi);
+  tree->Branch("tag_q",&m_tag_q);
+  tree->Branch("tag_d0",&m_tag_d0);
+  tree->Branch("tag_d0err",&m_tag_d0err);
+  tree->Branch("tag_z0",&m_tag_z0);
+  tree->Branch("dilep_mll",&m_mll);
+  tree->Branch("dilep_dphi",&m_dPhi);
+  tree->Branch("dilep_pt",&m_dilep_pt);
+  tree->Branch("dilep_tof",&m_dilep_tof);
+
+  tree->Branch("tag_dRJet",&m_tag_deltaR);
+  tree->Branch("probe_dRJet",&m_deltaR);
+  
+  if (m_extended_Iso_Info){
+    tree->Branch("tag_neflowisol20",&m_tagiso_neflowisol20);
+    tree->Branch("tag_topoetcone20",&m_tagiso_topoetcone20);
+    tree->Branch("tag_ptcone20",&m_tagiso_ptcone20);
+    tree->Branch("tag_etcone20",&m_tagiso_etcone20);
+    tree->Branch("tag_ptvarcone20",&m_tagiso_ptvarcone20);
+
+    tree->Branch("tag_neflowisol30",&m_tagiso_neflowisol30);
+    tree->Branch("tag_topoetcone30",&m_tagiso_topoetcone30);
+    tree->Branch("tag_ptcone30",&m_tagiso_ptcone30);
+    tree->Branch("tag_etcone30",&m_tagiso_etcone30);
+    tree->Branch("tag_ptvarcone30",&m_tagiso_ptvarcone30);
+
+    tree->Branch("tag_neflowisol40",&m_tagiso_neflowisol40);
+    tree->Branch("tag_topoetcone40",&m_tagiso_topoetcone40);
+    tree->Branch("tag_ptcone40",&m_tagiso_ptcone40);
+    tree->Branch("tag_etcone40",&m_tagiso_etcone40);
+    tree->Branch("tag_ptvarcone40",&m_tagiso_ptvarcone40);
+
+    tree->Branch("tag_topocore",&m_tag_topocore);
+
+    tree->Branch("probe_neflowisol20",&m_probeiso_neflowisol20);
+    tree->Branch("probe_topoetcone20",&m_probeiso_topoetcone20);
+    tree->Branch("probe_ptcone20",&m_probeiso_ptcone20);
+    tree->Branch("probe_etcone20",&m_probeiso_etcone20);
+    tree->Branch("probe_ptvarcone20",&m_probeiso_ptvarcone20);
+
+    tree->Branch("probe_neflowisol30",&m_probeiso_neflowisol30);
+    tree->Branch("probe_topoetcone30",&m_probeiso_topoetcone30);
+    tree->Branch("probe_ptcone30",&m_probeiso_ptcone30);
+    tree->Branch("probe_etcone30",&m_probeiso_etcone30);
+    tree->Branch("probe_ptvarcone30",&m_probeiso_ptvarcone30);
+
+    tree->Branch("probe_neflowisol40",&m_probeiso_neflowisol40);
+    tree->Branch("probe_topoetcone40",&m_probeiso_topoetcone40);
+    tree->Branch("probe_ptcone40",&m_probeiso_ptcone40);
+    tree->Branch("probe_etcone40",&m_probeiso_etcone40);
+    tree->Branch("probe_ptvarcone40",&m_probeiso_ptvarcone40);
+
+    tree->Branch("probe_topocore",&m_probe_topocore);
+
+    tree->Branch("energyDensity_central",&m_energyDensity_central);
+    tree->Branch("energyDensity_forward",&m_energyDensity_forward);
+  }
+
+}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPEfficiencyTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPEfficiencyTool.cxx
deleted file mode 100644
index d3b06de8a2e..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPEfficiencyTool.cxx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPEfficiencyTool.cxx
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#include "MuonTPTools/JPsiMuonTPEfficiencyTool.h"
-
-JPsiMuonTPEfficiencyTool::JPsiMuonTPEfficiencyTool(std::string myname)
-: AsgTool(myname), MuonTPEfficiencyTool(myname) {
-	declareProperty("MatchToAnyMS",m_match_MS=false);
-	declareProperty("MatchToCB",m_match_CB=false);
-	declareProperty("MatchToMedium",m_match_Medium=false);
-	declareProperty("MatchToID",m_match_ID=false);
-	declareProperty("MatchToCaloTag",m_match_CaloTag=false);
-	declareProperty("IDhitCut",m_do_IDHits=true);
-
-}
-void JPsiMuonTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
-{
-  // loop over probes
-  for(auto probe : *probes) {
-    double dRMin = 1;
-    Probe* matchProbe = 0;
-
-    // loop over matches
-    for(auto match : *matches) {
-
-      // Pt Cut
-      if(match->pt() < m_matchPtCut) continue;
-
-      // Eta Cut
-      if(fabs(match->eta()) > m_matchEtaCut) continue;
-
-      // for ID tracks, we need to do this a different way...
-      xAOD::Muon* matchmuon = dynamic_cast <xAOD::Muon*>(match);
-      if (matchmuon && m_do_IDHits){
-    	  Root::TAccept matchResult = m_selection_tool->accept(*matchmuon);		// we only use the ID cuts for now
-    	  if (! matchResult.getCutResult("IDHits")) continue;
-      }
-
-      if (!GoodMatchMuonType(match)) continue;
-
-      // Calculate dR
-      double dR = deltaR(probe, match);
-      if(dR < dRMin) {
-		dRMin = dR;
-		matchProbe = probe;
-      }
-    }
-
-    // check if a matched probe is found
-    if(matchProbe && dRMin<m_maximumDrCut) matchProbe->isMatched(true);
-  }
-}
-bool JPsiMuonTPEfficiencyTool::GoodMatchMuonType(const xAOD::IParticle* probe) const{
-
-    const xAOD::Muon* mumatch = dynamic_cast <const xAOD::Muon*> (probe);
-
-    // if the particle is not a muon, assume that the user knows what TrackParticleContainer he is providing!
-    if (! mumatch) return true;
-
-    // otherwise, we have to manually pick the right probe
-
-    // ID Probe
-    if (m_match_ID){
-        return (mumatch->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) != NULL);
-    }
-    // CT Probe
-
-    if (m_match_CaloTag){
-        return (mumatch && mumatch->isAuthor(xAOD::Muon::CaloTag) );
-    }
-    // MS Probe
-    if (m_match_MS){
-        return ((mumatch->muonType() == xAOD::Muon::MuonStandAlone || mumatch->muonType() == xAOD::Muon::Combined) && mumatch->trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle)!= NULL);
-    }
-    // CB probe
-    if (m_match_CB){
-        return (mumatch->muonType() == xAOD::Muon::Combined && mumatch->trackParticle(xAOD::Muon::CombinedTrackParticle) != NULL);
-    }
-    if (m_match_Medium){
-        bool ok = (mumatch->muonType() == xAOD::Muon::Combined && mumatch->trackParticle(xAOD::Muon::CombinedTrackParticle) != NULL );
-        Root::TAccept matchResult = m_selection_tool->accept(*mumatch);		// we only use the ID cuts for now
-        ok &= mumatch->quality()==xAOD::Muon::Medium;
-        return ok;
-    }
-    return false;
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPPlotTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPPlotTool.cxx
deleted file mode 100644
index 258478f108b..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPPlotTool.cxx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPPlotTool.cxx
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#include "MuonTPTools/JPsiMuonTPPlotTool.h"
-
-JPsiMuonTPPlotTool::JPsiMuonTPPlotTool(std::string name)
-	  :  AsgTool(name),MuonTPPlotTool(name){
-}
-
-std::vector<MuonTPEfficiencyPlotBase*> JPsiMuonTPPlotTool::AddPlots(std::string sDir, bool isMatched){
-
-	std::vector<MuonTPEfficiencyPlotBase*> out (0);
-	out.push_back( new MuonTPEfficiencyPlots(0, sDir, isMatched));
-	return out;
-
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPSelectionTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPSelectionTool.cxx
deleted file mode 100644
index 79cd31607c4..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/JPsiMuonTPSelectionTool.cxx
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * JPsiMuonTPSelectionTool.cxx
- *
- *  Created on: Sep 01, 2014
- *      Author: Maximiliano Sioli
- */
-
-#include "MuonTPTools/JPsiMuonTPSelectionTool.h"
-
-JPsiMuonTPSelectionTool::JPsiMuonTPSelectionTool(std::string myname)
-: AsgTool(myname), MuonTPSelectionTool(myname) {
-
-  declareProperty("UseIDProbes",  m_IDProbe = false);
-  declareProperty("UseMSProbes",  m_MSProbe = false);
-  declareProperty("UseCBProbes",  m_CBProbe = false);
-  declareProperty("UseCaloProbes",  m_CaloProbe = false);
-
-  declareProperty("TagIsoCut",  m_tagIsolation = 0.2);
-  declareProperty("ProbeIsoCut",  m_probeIsolation = -1);
-
-  declareProperty("AcceptSameCharge",  m_accept_sameCharge = false);
-  declareProperty("AcceptOppCharge",  m_accept_oppCharge = true);
-
-  declareProperty("DeltaPhiCut",      m_deltaPhiCut = -1.00);
-
-  declareProperty("EfficiencyFlag", m_efficiencyFlag = "IDProbes");
-
-  declareProperty("ProbeIDHitCut", m_probe_ID_hits = false);
-}
-
-StatusCode JPsiMuonTPSelectionTool::initialize()
-{
-  // ATH_CHECK(m_muonSelectionTool.retrieve());
-  ATH_CHECK(m_selection_tool.retrieve());
-  return StatusCode::SUCCESS;
-}
-
-
-//**********************************************************************
-
-ProbeContainer* JPsiMuonTPSelectionTool::selectProbes(const xAOD::MuonContainer* tags, const xAOD::IParticleContainer* probes) const
-{
-  // use m_muonSelectionTool to select muons
-  ProbeContainer* probeCont = new ProbeContainer();
-
-  // loop over tag container
-  for(auto tag : *tags) {
-
-    // select good muons (combined for the time being)
-    // A muon selection tool should be used, but the tool
-    // should be ASG dual-tool
-    if(tag->muonType() != xAOD::Muon::MuonType::Combined) continue;
-    // Could also cut on tag author, likely the same author of the probed efficiency
-    // if(m_muonTagAuthor!=21 && tag->author()!=m_muonTagAuthor) continue;
-
-    Root::TAccept tagResult = m_selection_tool->accept(*tag);		// we only use the ID cuts for now
-
-    if (! tagResult.getCutResult("IDHits")) continue;
-    // Cut on tag eta, pT
-    if(tag->pt() < m_tagPtCut) continue;
-    if(fabs(tag->eta()) > m_tagEtaCut) continue;
-
-    // tag iso cut
-    float tagiso = 0.;
-    bool haveIso = tag->isolation(tagiso,xAOD::Iso::ptcone40);
-    if (m_tagIsolation > 0 && (!haveIso || tagiso > m_tagIsolation * tag->p4().Pt())) continue;
-
-    // for each selected tag, loop over probes
-    for(auto probe : *probes) {
-
-      // check the probe type
-      if (!isRightType(probe)) continue;
-
-      // remove the probe track matched to the tag
-      if(isTag(tag, probe)) continue;
-
-      // select good probe tracks,
-      // again a selecton ASG duel-tool could be used
-      // tba
-
-      // Cut on probe eta, pT
-      if(probe->pt() < m_probePtCut) continue;
-      if(fabs(probe->eta()) > m_probeEtaCut) continue;
-
-      // ID hits
-      xAOD::Muon* probemu = dynamic_cast<xAOD::Muon*> (probe);
-      if (m_probe_ID_hits && probemu) {
-    	  Root::TAccept  probeResult = m_selection_tool->accept(*probemu);
-    	  if (!probeResult.getCutResult("IDHits")) continue;
-      }
-
-      // probe iso cut
-      // NYI if (m_probeIsolation > 0 && tag->isolation(xAOD::Iso::ptcone40) > m_probeIsolation * probe->p4().Pt());
-
-      // Cut on tag-probe invariant mass
-      double mtp = (tag->p4()+probe->p4()).M();
-      if(mtp<m_lowMassWindow || mtp>m_highMassWindow) continue;
-
-      // Charge cut
-      //if(m_oppositeCharge &&
-      //	 tag->trackParticle(xAOD::Muon::Primary)->charge()
-      int cp = ChargeProd(tag,probe);
-      if (cp == 1 && !m_accept_sameCharge) continue;
-      if (cp == -1 && !m_accept_oppCharge) continue;    // does this work?
-
-      // Delta Phi cut
-      if (DeltaPhiTP(tag,probe) < m_deltaPhiCut) continue;
-      // for each selected probe build a Probe object
-      probeCont->push_back( new Probe(*tag, *probe) );
-    }
-  }
-
-  ATH_MSG_DEBUG("Number of selected probes   : " << probeCont->size() );
-
-  return probeCont;
-}
-//**********************************************************************
-
-bool JPsiMuonTPSelectionTool::isTag(const xAOD::Muon* tag, const xAOD::IParticle* probe) const
-{
-  return (tag->p4().DeltaR(probe->p4()) < 0.01);
-}
-
-bool JPsiMuonTPSelectionTool::isRightType(const xAOD::IParticle* probe) const{
-
-    const xAOD::Muon* muprobe = dynamic_cast <const xAOD::Muon*> (probe);
-
-    // if the particle is not a muon, assume that the user knows what TrackParticleContainer he is providing!
-    if (! muprobe) return true;
-
-    // otherwise, we have to manually pick the right probe
-
-    // ID Probe
-    if (m_IDProbe){
-        return (muprobe->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) != NULL);
-    }
-    // CT Probe
-
-    if (m_CaloProbe){
-        return (muprobe && muprobe->isAuthor(xAOD::Muon::CaloTag) );
-    }
-    // MS Probe
-    if (m_MSProbe){
-        return ((muprobe->muonType() == xAOD::Muon::MuonStandAlone || muprobe->muonType() == xAOD::Muon::Combined) && muprobe->trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle)!= NULL);
-    }
-    // CB probe
-    if (m_CBProbe){
-        return (muprobe->muonType() == xAOD::Muon::Combined && muprobe->trackParticle(xAOD::Muon::CombinedTrackParticle) != NULL);
-    }
-    return false;
-
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonIsolTPEfficiencyTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonIsolTPEfficiencyTool.cxx
new file mode 100644
index 00000000000..a0e9dc831ac
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonIsolTPEfficiencyTool.cxx
@@ -0,0 +1,32 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/*
+ * MuonIsolTPEfficiencyTool.cxx
+ *
+ *  Created on: Aug 31, 2014
+ *      Author: goblirsc / a.m.
+ */
+
+#include "MuonTPTools/MuonIsolTPEfficiencyTool.h"
+
+MuonIsolTPEfficiencyTool::MuonIsolTPEfficiencyTool(std::string myname)
+:  MuonTPEfficiencyTool(myname)
+{
+    
+}
+
+
+
+//---------------------------------------------------------
+void MuonIsolTPEfficiencyTool::matchProbes(ProbeContainer* probes, const xAOD::IParticleContainer* ) const
+{
+    for(auto probe : *probes)
+    {
+      // check if the probe is isolated
+      // then if it is:
+        probe->isMatched(true);
+    }
+}
+
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonRecoTPEfficiencyTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonRecoTPEfficiencyTool.cxx
index 63067d864db..0a001846d25 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonRecoTPEfficiencyTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonRecoTPEfficiencyTool.cxx
@@ -12,37 +12,38 @@
 #include "MuonTPTools/MuonRecoTPEfficiencyTool.h"
 
 MuonRecoTPEfficiencyTool::MuonRecoTPEfficiencyTool(std::string myname)
-: AsgTool(myname), MuonTPEfficiencyTool(myname) {
-	declareProperty("MatchToAnyMS",m_match_MS=false);
-	declareProperty("MatchToCB",m_match_CB=false);
-    declareProperty("MatchToLoose",m_match_Loose=false);
-	declareProperty("MatchToMedium",m_match_Medium=false);
-    declareProperty("MatchToLoose_noCaloTag",m_match_Loose_noCT=false);
-    declareProperty("MatchToTight",m_match_Tight=false);
-	declareProperty("MatchToID",m_match_ID=false);
-	declareProperty("MatchToCaloTag",m_match_CaloTag=false);
-	declareProperty("IDhitCut",m_do_IDHits=true);
-
-    declareProperty("MatchToMuidCB",m_match_MuidCB=false);
-    declareProperty("MatchToSTACO",m_match_STACO=false);
-    declareProperty("MatchToMuTag",m_match_MuTag=false);
-    declareProperty("MatchToMuTagIMO",m_match_MuTagIMO=false);
-    declareProperty("MatchToMuidSA",m_match_MuidSA=false);
-    declareProperty("MatchToMuGirl",m_match_MuGirl=false);
-    declareProperty("MatchToMuGirlLowBeta",m_match_MuGirlLowBeta=false);
-    declareProperty("MatchToCaloLikelihood",m_match_CaloLikelihood=false);
-    declareProperty("MatchToExtrapolateToIP",m_match_ExtrapolateToIP=false);
+  : MuonTPEfficiencyTool(myname) {
+  declareProperty("ptrMatching",    m_ptrMatching    = false);
+  declareProperty("MatchToAnyMS",m_match_MS=false);
+  declareProperty("MatchToCB",m_match_CB=false);
+  declareProperty("MatchToLoose",m_match_Loose=false);
+  declareProperty("MatchToMedium",m_match_Medium=false);
+  declareProperty("MatchToLoose_noCaloTag",m_match_Loose_noCT=false);
+  declareProperty("MatchToTight",m_match_Tight=false);
+  declareProperty("MatchToHighPt",m_match_HighPt=false);
+  declareProperty("MatchToID",m_match_ID=false);
+  declareProperty("MatchToCaloTag",m_match_CaloTag=false);
+  declareProperty("IDhitCut",m_do_IDHits=true);
+
+  declareProperty("MatchToMuidCB",m_match_MuidCB=false);
+  declareProperty("MatchToSTACO",m_match_STACO=false);
+  declareProperty("MatchToMuTag",m_match_MuTag=false);
+  declareProperty("MatchToMuTagIMO",m_match_MuTagIMO=false);
+  declareProperty("MatchToMuidSA",m_match_MuidSA=false);
+  declareProperty("MatchToMuGirl",m_match_MuGirl=false);
+  declareProperty("MatchToMuGirlLowBeta",m_match_MuGirlLowBeta=false);
+  declareProperty("MatchToCaloLikelihood",m_match_CaloLikelihood=false);
+  declareProperty("MatchToExtrapolateToIP",m_match_ExtrapolateToIP=false);
 
 }
 void MuonRecoTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
 {
   // loop over probes
-
   for(auto probe : *probes) {
-    double dRMin = 1;
+    double dRMin = 3;
     Probe* matchProbe = 0;
     const xAOD::Muon* best_match_muon = NULL;
-
+    probe->dr_match(-1.);
     // loop over matches
     for(auto match : *matches) {
       // Pt Cut
@@ -55,13 +56,13 @@ void MuonRecoTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IP
 
       xAOD::Muon* matchmuon = dynamic_cast <xAOD::Muon*>(match);
       if (matchmuon && m_do_IDHits){
-    	  if (!m_selection_tool->passedIDCuts(*matchmuon)) continue;
+        if (!m_selection_tool->passedIDCuts(*matchmuon)) continue;
       }
       // ID tracks
 
       if (m_match_ID){
-          xAOD::TrackParticle *trk = dynamic_cast<xAOD::TrackParticle*>(match);
-          if(!trk || (m_do_IDHits && !m_selection_tool->passedIDCuts(*trk))) continue;
+        xAOD::TrackParticle *trk = dynamic_cast<xAOD::TrackParticle*>(match);
+        if(!trk || (m_do_IDHits && !m_selection_tool->passedIDCuts(*trk))) continue;
       }
 
       // Calculate dR
@@ -69,8 +70,8 @@ void MuonRecoTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IP
 
       // test pointer-level matching! 
       if(dR < dRMin) {
-		dRMin = dR;
-		matchProbe = probe;
+        dRMin = dR;
+        matchProbe = probe;
         if (matchmuon) best_match_muon = matchmuon;
       }
     }
@@ -78,82 +79,167 @@ void MuonRecoTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IP
     // check if a matched probe is found
     probe->sfweight(1.);
     probe->isMatched(matchProbe && dRMin<m_maximumDrCut);
+    probe->dr_match(dRMin);
     if (m_do_sf && best_match_muon && probe->isMatched()){
-        float sf = 1.;
-        if (m_sf_tool->getEfficiencyScaleFactor(*best_match_muon,sf) == CP::CorrectionCode::Ok){
-            probe->sfweight(sf);
-        }
+      float sf = 1.;
+      if (m_sf_tool->getEfficiencyScaleFactor(*best_match_muon,sf) == CP::CorrectionCode::Ok){
+        probe->sfweight(sf);
+      }
     }
   }
 }
-bool MuonRecoTPEfficiencyTool::GoodMatchMuonType(const xAOD::IParticle* probe) const{
 
-    const xAOD::Muon* mumatch = dynamic_cast <const xAOD::Muon*> (probe);
 
-    // if the particle is not a muon, assume that the user knows what TrackParticleContainer he is providing!
-    if (! mumatch) return true;
+void MuonRecoTPEfficiencyTool::ptrMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
+{
+  // loop over probes
+  for(auto probe : *probes) {
+    Probe* matchProbe = 0;
+    const xAOD::Muon* best_match_muon = NULL;
 
-    // otherwise, we have to manually pick the right probe
+    const xAOD::Muon* probemuon = dynamic_cast <const xAOD::Muon*>(&(probe->probeTrack()));
+    const xAOD::TrackParticle* probetrack = dynamic_cast <const xAOD::TrackParticle*>(&(probe->probeTrack()));
+    
+    probe->dr_match(-1.);
+    // loop over matches
+    for(auto match : *matches) {
 
-    // ID Track
-    if (m_match_ID){
-        return (mumatch->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) != NULL);
-    }
-    // CT Match
+      // Pt Cut
+      if(match->pt() < m_matchPtCut) continue;
+
+      // Eta Cut
+      if(fabs(match->eta()) > m_matchEtaCut) continue;
+
+      if (!GoodMatchMuonType(match)) continue;
+
+      xAOD::Muon* matchmuon = dynamic_cast <xAOD::Muon*>(match);
+      if (matchmuon && m_do_IDHits){
+        if (!m_selection_tool->passedIDCuts(*matchmuon)) continue;
+      }
+
+      // ID tracks
+      if (m_match_ID){
+        xAOD::TrackParticle *trk = dynamic_cast<xAOD::TrackParticle*>(match);
+        if(!trk || (m_do_IDHits && !m_selection_tool->passedIDCuts(*trk))) continue;
+      }
+      
+      // Probe and Match are xAOD::Muon
+      if(probemuon && matchmuon && probemuon==matchmuon) {
+        matchProbe = probe;
+        best_match_muon = matchmuon;
+        probe->dr_match(0);
+        break;
+      }
+
+      // probe is xAOD::TrackParticle and match is xAOD::Muon
+      if(probetrack && matchmuon) {
+        if( probetrack == matchmuon->trackParticle( xAOD::Muon::InnerDetectorTrackParticle ) ||
+            probetrack == matchmuon->trackParticle( xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle ) ||
+            probetrack == matchmuon->trackParticle( xAOD::Muon::MuonSpectrometerTrackParticle ) ) {
+        matchProbe = probe;
+        probe->dr_match(0);
+        best_match_muon = matchmuon;
+        break;
+        }		
+      }
 
-    if (m_match_CaloTag){
-        return (mumatch &&  m_selection_tool->passedCaloTagQuality(*mumatch) &&  mumatch->isAuthor(xAOD::Muon::CaloTag) );
-    }
-    // MS Match
-    if (m_match_MS){
-        return ((mumatch->muonType() == xAOD::Muon::MuonStandAlone || mumatch->muonType() == xAOD::Muon::Combined) && mumatch->trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle)!= NULL);
-    }
-    // CB Match
-    if (m_match_CB){
-        return (mumatch->muonType() == xAOD::Muon::Combined && mumatch->trackParticle(xAOD::Muon::CombinedTrackParticle) != NULL);
-    }
-    if (m_match_Loose){
-        bool ok = (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Loose );
-        return ok;
-    }
-    if (m_match_Loose_noCT){
-        bool ok = (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Loose && mumatch->muonType() != xAOD::Muon::CaloTagged  );
-        return ok;
-    }
-    if (m_match_Medium){
-        bool ok = (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Medium );
-        return ok;
-    }
-    if (m_match_Tight){
-        bool ok = (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Tight );
-        return ok;
-    }
-    if (m_match_MuidCB){
-        return (mumatch->isAuthor(xAOD::Muon::MuidCo));
-    }
-    if (m_match_STACO){
-        return (mumatch->isAuthor(xAOD::Muon::STACO));
-    }
-    if (m_match_MuTag){
-        return (mumatch->isAuthor(xAOD::Muon::MuTag));
-    }
-    if (m_match_MuTagIMO){
-        return (mumatch->isAuthor(xAOD::Muon::MuTagIMO));
-    }
-    if (m_match_MuidSA){
-        return (mumatch->isAuthor(xAOD::Muon::MuidSA));
-    }
-    if (m_match_MuGirl){
-        return (mumatch->isAuthor(xAOD::Muon::MuGirl));
-    }
-    if (m_match_MuGirlLowBeta){
-        return (mumatch->isAuthor(xAOD::Muon::MuGirlLowBeta));
-    }
-    if (m_match_CaloLikelihood){
-        return (mumatch->isAuthor(xAOD::Muon::CaloLikelihood));
     }
-    if (m_match_ExtrapolateToIP){
-        return (mumatch->isAuthor(xAOD::Muon::ExtrapolateMuonToIP));
+
+    // check if a matched probe is found
+    probe->sfweight(1.);
+    probe->isMatched(matchProbe);
+    if (m_do_sf && best_match_muon && probe->isMatched()){
+      float sf = 1.;
+      if (m_sf_tool->getEfficiencyScaleFactor(*best_match_muon,sf) == CP::CorrectionCode::Ok){
+        probe->sfweight(sf);
+      }
     }
-    return false;
+  }
+}
+
+bool MuonRecoTPEfficiencyTool::GoodMatchMuonType(const xAOD::IParticle* probe) const{
+
+  const xAOD::Muon* mumatch = dynamic_cast <const xAOD::Muon*> (probe);
+
+  // if the particle is not a muon, assume that the user knows what TrackParticleContainer he is providing!
+  if (! mumatch) return true;
+
+  // otherwise, we have to manually pick the right probe
+
+  // ID Track
+  if (m_match_ID){
+    return (mumatch->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) != NULL);
+  }
+  // CT Match
+
+  if (m_match_CaloTag){
+    return (mumatch &&  m_selection_tool->passedCaloTagQuality(*mumatch) &&  mumatch->isAuthor(xAOD::Muon::CaloTag) );
+  }
+  // MS Match
+  if (m_match_MS){
+    return ((mumatch->muonType() == xAOD::Muon::MuonStandAlone || mumatch->muonType() == xAOD::Muon::Combined) 
+	    && mumatch->trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle)!= NULL);
+  }
+  // CB Match
+  if (m_match_CB){
+    return (mumatch->muonType() == xAOD::Muon::Combined && mumatch->trackParticle(xAOD::Muon::CombinedTrackParticle) != NULL);
+  }
+  if (m_match_Loose){
+    return (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Loose);
+  }
+  if (m_match_Loose_noCT){
+    return (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Loose && mumatch->muonType() != xAOD::Muon::CaloTagged);
+  }
+  if (m_match_Medium){
+    return (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Medium);
+  }
+  if (m_match_Tight){
+    return (m_selection_tool->getQuality(*mumatch) <= xAOD::Muon::Tight);
+  }
+  if (m_match_HighPt){
+    return m_selection_tool->passedHighPtCuts(*mumatch);
+  }
+  if (m_match_MuidCB){
+    return (mumatch->isAuthor(xAOD::Muon::MuidCo));
+  }
+  if (m_match_STACO){
+    return (mumatch->isAuthor(xAOD::Muon::STACO));
+  }
+  if (m_match_MuTag){
+    return (mumatch->isAuthor(xAOD::Muon::MuTag));
+  }
+  if (m_match_MuTagIMO){
+    return (mumatch->isAuthor(xAOD::Muon::MuTagIMO));
+  }
+  if (m_match_MuidSA){
+    return (mumatch->isAuthor(xAOD::Muon::MuidSA));
+  }
+  if (m_match_MuGirl){
+    return (mumatch->isAuthor(xAOD::Muon::MuGirl));
+  }
+  if (m_match_MuGirlLowBeta){
+    return (mumatch->isAuthor(xAOD::Muon::MuGirlLowBeta));
+  }
+  if (m_match_CaloLikelihood){
+    return (mumatch->isAuthor(xAOD::Muon::CaloLikelihood));
+  }
+  if (m_match_ExtrapolateToIP){
+    return (mumatch->isAuthor(xAOD::Muon::ExtrapolateMuonToIP));
+  }
+  return false;
+}
+//**********************************************************************
+
+void MuonRecoTPEfficiencyTool::matchProbes(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
+{
+  if(m_ptrMatching) ptrMatching(probes, matches);
+  else dRMatching(probes, matches);
+
+  if (msgLvl(MSG::DEBUG)) {
+    int nmatched=0;
+    for(auto probe : *probes) 
+      if(probe->isMatched())
+    nmatched++;    
+    ATH_MSG_DEBUG("Number of matched probes    : " << nmatched );
+  }
 }
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPEfficiencyTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPEfficiencyTool.cxx
index 4f01bf586e0..4b217b17397 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPEfficiencyTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPEfficiencyTool.cxx
@@ -10,18 +10,19 @@
 //**********************************************************************
 
 MuonTPEfficiencyTool::MuonTPEfficiencyTool(std::string myname)
-: AsgTool(myname),  m_matchTool("Trig::ITrigMuonMatching/TrigMuonMatching"){
+  : AsgTool(myname),  m_matchTool("Trig::ITrigMuonMatching/TrigMuonMatching"){
   
   declareProperty("MatchPtCut",     m_matchPtCut     = 0.0); 
   declareProperty("MatchEtaCut",    m_matchEtaCut    = 5.0);
-  declareProperty("dRMatching",     m_dRMatching     = true);
   declareProperty("MaximumDrCut",   m_maximumDrCut   = 0.05);
   declareProperty("MuonAuthor",     m_muonAuthor     = 12); // we need a central place for author<->algname mapping!
   declareProperty("EfficiencyFlag", m_efficiencyFlag = "CBMuons");  
+  declareProperty("IsNominal", m_isNominal=true);
   declareProperty("SelectionTool", m_selection_tool);
   declareProperty("ScaleFactorTool", m_sf_tool);
   declareProperty("ApplyScaleFactors", m_do_sf = false);
   declareProperty("TriggerMatchTool", m_matchTool);
+  declareProperty("TrigItem",        m_trigger_item="");
 }
 
 MuonTPEfficiencyTool::~MuonTPEfficiencyTool()
@@ -29,29 +30,21 @@ MuonTPEfficiencyTool::~MuonTPEfficiencyTool()
 
 StatusCode MuonTPEfficiencyTool::initialize()
 {
-   ATH_CHECK(m_selection_tool.retrieve());
-   if (m_do_sf) ATH_CHECK(m_sf_tool.retrieve());
+  ATH_CHECK(m_selection_tool.retrieve());
+  if (m_do_sf) ATH_CHECK(m_sf_tool.retrieve());
   ATH_CHECK(m_matchTool.retrieve());
 
   return StatusCode::SUCCESS;
 }
 
-
 //**********************************************************************
 
-void MuonTPEfficiencyTool::matchProbes(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
+void MuonTPEfficiencyTool::matchProbes(ProbeContainer* , const xAOD::IParticleContainer* ) const
 {
-  if(m_dRMatching) dRMatching(probes, matches);
-
-  if (msgLvl(MSG::DEBUG)) {
-    int nmatched=0;
-    for(auto probe : *probes) 
-      if(probe->isMatched())
-	nmatched++;    
-    ATH_MSG_DEBUG("Number of matched probes    : " << nmatched );
-  }
+    // do nothing by default
 }
 
+
 //**********************************************************************
 
 void MuonTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IParticleContainer* matches) const
@@ -85,19 +78,19 @@ void MuonTPEfficiencyTool::dRMatching(ProbeContainer* probes, const xAOD::IParti
       // Calculate dR
       double dR = deltaR(probe, match);
       if(dR < dRMin) {
-          dRMin = dR;
-          matchProbe = probe;
-          if (mumatch) best_match_muon = mumatch;
+	dRMin = dR;
+	matchProbe = probe;
+	if (mumatch) best_match_muon = mumatch;
       }
     }
     probe->sfweight(1.);
     // check if a matched probe is found
     probe->isMatched((matchProbe && dRMin<m_maximumDrCut));
     if (m_do_sf && best_match_muon && probe->isMatched()){
-        float sf = 1.;
-        if (m_sf_tool->getEfficiencyScaleFactor(*best_match_muon,sf) == CP::CorrectionCode::Ok){
-            probe->sfweight(sf);
-        }
+      float sf = 1.;
+      if (m_sf_tool->getEfficiencyScaleFactor(*best_match_muon,sf) == CP::CorrectionCode::Ok){
+	probe->sfweight(sf);
+      }
 
     }
   }
@@ -110,8 +103,8 @@ double MuonTPEfficiencyTool::deltaR(Probe* probe, const xAOD::IParticle* match)
 }
 //**********************************************************************
 
-  //  check for a trigger match (probe side)
+//  check for a trigger match (probe side)
 bool MuonTPEfficiencyTool::MatchTrigger (const xAOD::IParticle* match,  std::string trigger) const {
-    return m_matchTool->match(match->eta(),match->phi(),  trigger);
+  return m_matchTool->match(match->eta(),match->phi(),  trigger);
     
 }
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPPlotTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPPlotTool.cxx
index 9c588046de9..f6b232e7540 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPPlotTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPPlotTool.cxx
@@ -12,189 +12,196 @@
 #include "MuonTPTools/MuonTPPlotTool.h"
 
 MuonTPPlotTool::MuonTPPlotTool(std::string name)
-	  : AsgTool(name){
-	  declareProperty("EfficiencyFlag",        m_efficiencyFlag = "ZmmTP");
-
-      declareProperty("DoOnlyAside",      m_only_A_side = false);
-      declareProperty("DoOnlyCside",      m_only_C_side = false);
-      declareProperty("ProbeAbsEtaMin",      m_probe_abseta_min = -1.00);
-      declareProperty("ProbeAbsEtaMax",      m_probe_abseta_max = 100.00);
-      declareProperty("DoAsymmErrorGraphs",      m_doAsymmErrors = false);
+  : AsgTool(name){
+  declareProperty("EfficiencyFlag",      m_efficiencyFlag = "ZmmTP");
+  declareProperty("DoOnlyAside",         m_only_A_side = false);
+  declareProperty("DoOnlyCside",         m_only_C_side = false);
+  declareProperty("ProbeAbsEtaMin",      m_probe_abseta_min = -1.00);
+  declareProperty("ProbeAbsEtaMax",      m_probe_abseta_max = 100.00);
+  declareProperty("DoAsymmErrorGraphs",  m_doAsymmErrors = false);
+  declareProperty("ProduceEfficiencies", m_doEffPlots = false);
+  declareProperty("ProduceProbeMatchPlots", m_doProbeMatchPlots = true);
+
 }
 
 StatusCode MuonTPPlotTool::RegisterPlots (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools){
 
 
-	  // Create histograms
-	  for(auto tpSelTool : probeTools) {
-	    std::string cfdirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
-	    m_TPcutFlowPlots[cfdirs] = AddCutFlowPlots(cfdirs+"/CutFlows");
+  // Create histograms
+    for(auto tpSelTool : probeTools) {
+        std::string cfdirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
+        m_TPcutFlowPlots[cfdirs] = AddCutFlowPlots(cfdirs+"/CutFlows");
         for (auto plot :  m_TPcutFlowPlots[cfdirs]){
             plot->initialize();
             tpSelTool->AddCutFlowHist(plot);    // show this plot to the selection tool, which can then internally fill it
         }
-	    for(auto tpEffTool : effTools) {
-	      std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag()+"/"+tpEffTool->efficiencyFlag();
-	      if (m_probeTPEffPlots.find(dirs) ==m_probeTPEffPlots.end()){
-	    	  m_probeTPEffPlots[dirs] = AddPlots(dirs+"/Probes", false);
-	    	  m_matchTPEffPlots[dirs] = AddPlots(dirs+"/Matches", true);
-	    	  m_effTPEffPlots[dirs] = AddPlots(dirs+"/Efficiency", true);
-
-	    	  // now we can initialize everything
-	    	  for (auto plot :  m_probeTPEffPlots[dirs]){
-	    		  plot->initialize();
-	    	  }
-	    	  for (auto plot :  m_matchTPEffPlots[dirs]){
-	    		  plot->initialize();
-	    	  }
-	    	  for (auto plot :  m_effTPEffPlots[dirs]){
-                if (m_doAsymmErrors) {
-                    plot->SetDoAsymmErrors(m_doAsymmErrors);
-                    plot->BookAllAsymmErrors();
+        if (m_doProbeMatchPlots) {
+            for(auto tpEffTool : effTools) {
+            if (!tpEffTool->isNominal() && !tpSelTool->isNominal()) continue;
+            std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag()+"/"+tpEffTool->efficiencyFlag();
+            if (m_probeTPEffPlots.find(dirs) ==m_probeTPEffPlots.end()){
+                // 
+                m_probeTPEffPlots[dirs] = AddPlots(dirs+"/Probes", false);
+                m_matchTPEffPlots[dirs] = AddPlots(dirs+"/Matches", true);
+                //  on request,  also prepare efficiencies
+                if (m_doEffPlots) m_effTPEffPlots[dirs] = AddPlots(dirs+"/Efficiency", true);
+
+                // now we can initialize everything
+                for (auto plot :  m_probeTPEffPlots[dirs]){
+                    plot->initialize();
+                }
+                for (auto plot :  m_matchTPEffPlots[dirs]){
+                    plot->initialize();
                 }
-                plot->initialize();
-	    	  }
-	      }
-	    }
-	  }
+                for (auto plot :  m_effTPEffPlots[dirs]){
+                    if (m_doAsymmErrors) {
+                        plot->SetDoAsymmErrors(m_doAsymmErrors);
+                        plot->BookAllAsymmErrors();
+                    }
+                    plot->initialize();
+                }
+            }
+            }
+        }
+    }
   return StatusCode::SUCCESS;
 
 }
 std::vector<MuonTPEfficiencyPlotBase*> MuonTPPlotTool::AddPlots(std::string , bool ){
-	// here, you can add any MuonTPEfficiencyPlotBase* based plot you like to the output!
-	// in this base class, we don't add anything
-	return std::vector<MuonTPEfficiencyPlotBase*>(0);
+  // here, you can add any MuonTPEfficiencyPlotBase* based plot you like to the output!
+  // in this base class, we don't add anything
+  return std::vector<MuonTPEfficiencyPlotBase*>(0);
 
 }
 
 std::vector<MuonTPCutFlowBase*> MuonTPPlotTool::AddCutFlowPlots(std::string){
-    // here, you can add any MuonTPCutFlowBase* based plot you like to the output!
-    // in this base class, we don't add anything
-    return std::vector<MuonTPCutFlowBase*>(0);
+  // here, you can add any MuonTPCutFlowBase* based plot you like to the output!
+  // in this base class, we don't add anything
+  return std::vector<MuonTPCutFlowBase*>(0);
 
 }
 
- // fill the histos
- void MuonTPPlotTool::fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tpSelTool, ToolHandle <IMuonTPEfficiencyTool> eff_tool){
+// fill the histos
+void MuonTPPlotTool::fill(Probe& probe, ToolHandle <IMuonTPSelectionTool> & tpSelTool, ToolHandle <IMuonTPEfficiencyTool> & eff_tool){
 
-     double feta = fabs(probe.eta());
-     if (feta < m_probe_abseta_min) return;
-     if (feta > m_probe_abseta_max) return;
-     if (probe.eta() > 0 && m_only_A_side) return;
-     if (probe.eta() < 0 && m_only_C_side) return;
+  double feta = fabs(probe.eta());
+  if (feta < m_probe_abseta_min) return;
+  if (feta > m_probe_abseta_max) return;
+  if (probe.eta() > 0 && m_only_A_side) return;
+  if (probe.eta() < 0 && m_only_C_side) return;
      
-     std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag()+"/"+eff_tool->efficiencyFlag();
-     for (auto plot : m_probeTPEffPlots[dirs]){
-    	 plot->fill(probe);
-     }
-     for (auto plot : m_matchTPEffPlots[dirs]){
-    	 plot->fill(probe);
-     }
- }
-
- // fill the cut flow histos
- void MuonTPPlotTool::fillCutFlow(std::string stage, double weight, ToolHandle <IMuonTPSelectionTool> & tpSelTool){
-
-     std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
-     for (auto plot : m_TPcutFlowPlots[dirs]){
-         plot->fill(stage, weight);
-     }
- }
-  /// retrieve booked histograms
-  std::vector<HistData> MuonTPPlotTool::retrieveBookedHistograms(){
-
-	  std::vector<HistData> histData;
-	  for(auto plots : m_probeTPEffPlots) {
-		  for (auto hist : plots.second){
-			  std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
-			  histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
-		  }
-	  }
-	  for(auto plots : m_matchTPEffPlots) {
-		  for (auto hist : plots.second){
-			  std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
-			  histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
-		  }
-	  }
-	  for(auto plots : m_effTPEffPlots) {
-		  for (auto hist : plots.second){
-			  std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
-			  histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
-		  }
-	  }
-	  for (auto plots: m_TPcutFlowPlots) {
-          for (auto hist : plots.second){
-              std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
-              histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
-          }
-	  }
-
-	  return histData;
+  std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag()+"/"+eff_tool->efficiencyFlag();
+  for (auto plot : m_probeTPEffPlots[dirs]){
+    plot->fill(probe);
   }
-  std::vector<std::pair <TGraph*,  std::string > > MuonTPPlotTool::retrieveBookedGraphs(){
-
-      std::vector<std::pair <TGraph*,  std::string > > graphData;
-      for(auto plots : m_probeTPEffPlots) {
-          for (auto hist : plots.second){
-              std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
-              graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
-          }
-      }
-      for(auto plots : m_matchTPEffPlots) {
-          for (auto hist : plots.second){
-              std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
-              graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
-          }
-      }
-      for(auto plots : m_effTPEffPlots) {
-          for (auto hist : plots.second){
-              std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
-              graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
-          }
-      }
-
-      return graphData;
+  for (auto plot : m_matchTPEffPlots[dirs]){
+    plot->fill(probe);
   }
-void  MuonTPPlotTool::CalcEff(void){
+}
+
+// fill the cut flow histos
+void MuonTPPlotTool::fillCutFlow(std::string stage, double weight, ToolHandle <IMuonTPSelectionTool> & tpSelTool){
 
-	for(auto deniter : m_probeTPEffPlots) {
-		std::vector<MuonTPEfficiencyPlotBase*> denplots = deniter.second;
-		std::vector<MuonTPEfficiencyPlotBase*> matchplots = m_matchTPEffPlots[deniter.first];
-		std::vector<MuonTPEfficiencyPlotBase*> effplots = m_effTPEffPlots[deniter.first];
-		for (size_t i = 0; i < denplots.size();++i){
-			effplots[i]->EffiDivide(denplots[i],matchplots[i]);
-		}
-	}
+  std::string dirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
+  for (auto plot : m_TPcutFlowPlots[dirs]){
+    plot->fill(stage, weight);
+  }
 }
+/// retrieve booked histograms
+std::vector<HistData> MuonTPPlotTool::retrieveBookedHistograms(){
+
+  std::vector<HistData> histData;
+  for(auto plots : m_probeTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
+      histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
+    }
+  }
+  for(auto plots : m_matchTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
+      histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
+    }
+  }
+  for(auto plots : m_effTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
+      histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
+    }
+  }
+  for (auto plots: m_TPcutFlowPlots) {
+    for (auto hist : plots.second){
+      std::vector<HistData> histDataTmp = hist->retrieveBookedHistograms();
+      histData.insert(histData.end(), histDataTmp.begin(), histDataTmp.end());
+    }
+  }
 
+  return histData;
+}
+std::vector<std::pair <TGraph*,  std::string > > MuonTPPlotTool::retrieveBookedGraphs(){
+
+  std::vector<std::pair <TGraph*,  std::string > > graphData;
+  for(auto plots : m_probeTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
+      graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
+    }
+  }
+  for(auto plots : m_matchTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
+      graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
+    }
+  }
+  for(auto plots : m_effTPEffPlots) {
+    for (auto hist : plots.second){
+      std::vector<std::pair <TGraph*,  std::string > > graphDataTmp = hist->retrieveBookedGraphs();
+      graphData.insert(graphData.end(), graphDataTmp.begin(), graphDataTmp.end());
+    }
+  }
 
-  MuonTPPlotTool::~MuonTPPlotTool(){
-
-	  for(auto plots : m_probeTPEffPlots){
-		  for (auto plot : plots.second){
-			  delete plot;
-		  }
-	  }
-	  for(auto plots : m_matchTPEffPlots){
-		  for (auto plot : plots.second){
-			  delete plot;
-		  }
-	  }
-      for(auto plots : m_effTPEffPlots){
-          for (auto plot : plots.second){
-              delete plot;
-          }
-      }
-      for(auto plots : m_TPcutFlowPlots){
-          for (auto plot : plots.second){
-              delete plot;
-          }
-      }
-	  m_probeTPEffPlots.clear();
-	  m_matchTPEffPlots.clear();
-	  m_effTPEffPlots.clear();
-	  m_TPcutFlowPlots.clear();
+  return graphData;
+}
+void  MuonTPPlotTool::CalcEff(void){
+  if (!m_doEffPlots) return; 
+  for(auto deniter : m_probeTPEffPlots) {
+    std::vector<MuonTPEfficiencyPlotBase*> denplots = deniter.second;
+    std::vector<MuonTPEfficiencyPlotBase*> matchplots = m_matchTPEffPlots[deniter.first];
+    std::vector<MuonTPEfficiencyPlotBase*> effplots = m_effTPEffPlots[deniter.first];
+    for (size_t i = 0; i < denplots.size();++i){
+      effplots[i]->EffiDivide(denplots[i],matchplots[i]);
+    }
   }
+}
+
+
+MuonTPPlotTool::~MuonTPPlotTool(){
+
+  for(auto plots : m_probeTPEffPlots){
+    for (auto plot : plots.second){
+      delete plot;
+    }
+  }
+  for(auto plots : m_matchTPEffPlots){
+    for (auto plot : plots.second){
+      delete plot;
+    }
+  }
+  for(auto plots : m_effTPEffPlots){
+    for (auto plot : plots.second){
+      delete plot;
+    }
+  }
+  for(auto plots : m_TPcutFlowPlots){
+    for (auto plot : plots.second){
+      delete plot;
+    }
+  }
+  m_probeTPEffPlots.clear();
+  m_matchTPEffPlots.clear();
+  m_effTPEffPlots.clear();
+  m_TPcutFlowPlots.clear();
+}
 
 
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPSelectionTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPSelectionTool.cxx
index a4f8aa5379e..aaa99acdc14 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPSelectionTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPSelectionTool.cxx
@@ -6,53 +6,60 @@
 
 #include "MuonTPTools/MuonTPSelectionTool.h"
 #include "xAODTracking/VertexContainer.h"
-// #include "xAODPrimitives/​tools/​getIsolationCorrectionAccessor.h"
+#include "MCTruthClassifier/MCTruthClassifierDefs.h"
+// #include "xAODPrimitives/tools/getIsolationCorrectionAccessor.h"
+#include "xAODTruth/TruthParticleContainer.h"
 
 //**********************************************************************
 
-MuonTPSelectionTool::MuonTPSelectionTool(std::string myname) : AsgTool(myname),m_tag_Triggers(0), m_selection_tool(),m_trigTool("Trig::TrigDecisionTool/TrigDecisionTool"),  m_matchTool("Trig::ITrigMuonMatching/TrigMuonMatching"){
-  declareProperty("TagPtCut",       m_tagPtCut = 20000.0);
-  declareProperty("TagEtaCut",      m_tagEtaCut = 2.5);
-  declareProperty("ProbePtCut",     m_probePtCut = 20000.0);
-  declareProperty("ProbeEtaCut",    m_probeEtaCut = 2.5);
-  declareProperty("HighMassWindow", m_highMassWindow = 101000.0);
-  declareProperty("LowMassWindow",  m_lowMassWindow = 81000.0);
-  declareProperty("EfficiencyFlag", m_efficiencyFlag = "IDProbes");
-  declareProperty("TagTriggerList", m_tag_Triggers );
-  declareProperty("SelectionTool", m_selection_tool);
-  declareProperty("TriggerMatchTool", m_matchTool);
-  declareProperty("TriggerDecisionTool", m_trigTool);
-  
-  
-  //  track iso recomputation for the full athena release
-# if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-  declareProperty("TrackIsolationTool",        m_track_iso_tool);
-  declareProperty("CaloIsolationTool",        m_calo_iso_tool);
-  m_track_iso_to_run.push_back(xAOD::Iso::ptcone40);
-  m_calo_iso_to_run.push_back(xAOD::Iso::topoetcone40);
-# endif
+MuonTPSelectionTool::MuonTPSelectionTool(std::string myname) : 
+    AsgTool(myname),m_tag_Triggers(0), 
+    m_selection_tool(),
+    m_trigTool("Trig::TrigDecisionTool/TrigDecisionTool"),
+    m_matchTool("Trig::ITrigMuonMatching/TrigMuonMatching"), 
+    m_grlTool("GoodRunsListSelectionTool/GRLTool")
+{
+    declareProperty("TagPtCut",       m_tagPtCut = 20000.0);
+    declareProperty("TagEtaCut",      m_tagEtaCut = 2.5);
+    declareProperty("ProbePtCut",     m_probePtCut = 20000.0);
+    declareProperty("ProbeEtaCut",    m_probeEtaCut = 2.5);
+    declareProperty("HighMassWindow", m_highMassWindow = 101000.0);
+    declareProperty("LowMassWindow",  m_lowMassWindow = 81000.0);
+    declareProperty("EfficiencyFlag", m_efficiencyFlag = "IDProbes");
+    declareProperty("TagTriggerList", m_tag_Triggers );
+    declareProperty("SelectionTool",  m_selection_tool);
+    declareProperty("TriggerDecisionTool", m_trigTool);
+    declareProperty("TriggerMatchTool",    m_matchTool);
+    declareProperty("IsNominal",    m_isNominal=true);
+    declareProperty("IsNotIncludedInNominal",    m_isNotPartOfNominal=false);
+    declareProperty("GRLTool",        m_grlTool, "The private GoodRunsListSelectionTool");
+
 }
 
 StatusCode MuonTPSelectionTool::initialize()
 {
-# if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-  ATH_CHECK(m_track_iso_tool.retrieve());
-  ATH_CHECK(m_calo_iso_tool.retrieve());
-# endif
-  ATH_CHECK(m_selection_tool.retrieve());
-  ATH_CHECK(m_trigTool.retrieve());
-  ATH_CHECK(m_matchTool.retrieve());
-  return StatusCode::SUCCESS;
-
+    
+    ATH_CHECK(m_selection_tool.retrieve());
+    ATH_CHECK(m_trigTool.retrieve());
+    ATH_CHECK(m_matchTool.retrieve());
+    ATH_CHECK(m_grlTool.retrieve());
+    return StatusCode::SUCCESS;
 }
 
-
 //**********************************************************************
 
 ProbeContainer* MuonTPSelectionTool::selectProbes(const xAOD::MuonContainer* tags, const xAOD::IParticleContainer* probes) const
 {
   // use m_muonSelectionTool to select muons
   ProbeContainer* probeCont = new ProbeContainer();
+  
+    // check GRL
+    const xAOD::EventInfo* info = 0;
+    ATH_MSG_DEBUG(""<<evtStore());
+    if (evtStore()->retrieve(info, "EventInfo").isFailure()){
+        ATH_MSG_FATAL( "Unable to retrieve Event Info" );
+    }
+    if (!passGRL(info)) return probeCont;
 
   // loop over tag container
   for(auto tag : *tags) {
@@ -101,160 +108,196 @@ ProbeContainer* MuonTPSelectionTool::selectProbes(const xAOD::MuonContainer* tag
 }
 //**********************************************************************
 
+bool MuonTPSelectionTool::passGRL(const xAOD::EventInfo* info) const
+{
+    if(!info->eventType(xAOD::EventInfo::IS_SIMULATION)){
+        if(!m_grlTool->passRunLB(*info)) return false; //checks the GRL and skips to next event if not passing
+    }
+    return true;
+}
+
 bool MuonTPSelectionTool::isTag(const xAOD::Muon* tag, const xAOD::IParticle* probe) const
 {
   return ( tag->p4().DeltaR(probe->p4()) < 0.01);
 }
 int MuonTPSelectionTool::ChargeProd (const xAOD::Muon* tag, const xAOD::IParticle* probe) const {
 
-    // case of a muon probe
-    const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(probe);
-    if (muprobe) {
-        return muprobe->trackParticle(xAOD::Muon::Primary)->charge() * tag->trackParticle(xAOD::Muon::Primary)->charge();
-    }
-    // case of an ID probe
-    const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(probe);
-    if (trkprobe){
-        return trkprobe->charge() * tag->trackParticle(xAOD::Muon::Primary)->charge();
-    }
-    return 0;
+  // case of a muon probe
+  const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(probe);
+  if (muprobe) {
+    return muprobe->trackParticle(xAOD::Muon::Primary)->charge() * tag->trackParticle(xAOD::Muon::Primary)->charge();
+  }
+  // case of an ID probe
+  const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(probe);
+  if (trkprobe){
+    return trkprobe->charge() * tag->trackParticle(xAOD::Muon::Primary)->charge();
+  }
+  return 0;
 }
 double MuonTPSelectionTool::DeltaPhiTP (const xAOD::Muon* tag, const xAOD::IParticle* probe) const{
-    return fabs(tag->p4().DeltaPhi(probe->p4()));
+  return fabs(tag->p4().DeltaPhi(probe->p4()));
 }
 
 double MuonTPSelectionTool::ptcone_trk (const xAOD::IParticle* part,  double ) const{
     
-    //  this is present in the MUON1 derivation or if our tool already wrote it in a previous iteration
-    if (part->isAvailable<float>("MUON1_ptcone40")){
-        return part->auxdataConst<float>("MUON1_ptcone40");
+  //  this is present in the MUON1 derivation or if our tool already wrote it in a previous iteration
+  if (part->isAvailable<float>("MUON1_ptcone40")){
+    try{
+      return part->auxdataConst<float>("MUON1_ptcone40");
     }
-    else {  
-        //  Here,  we can manually compute the isolation *if* we are running in full athena.
-        //  In the other cases,  we just return a dummy result. 
-        # if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-        xAOD::TrackCorrection corrlist;
-        corrlist.trackbitset.set(static_cast<unsigned int>(xAOD::Iso::coreTrackPtr));
-        xAOD::TrackIsolation resultTrack;
-        const xAOD::TrackParticle* tp = dynamic_cast<const xAOD::TrackParticle*>(part);
-        if (!tp || ! m_track_iso_tool->trackIsolation(resultTrack, *tp, m_track_iso_to_run, corrlist,tp->vertex(),0)){
-            ATH_MSG_WARNING("Failed to apply the isolation for a particle");
-        }
-        static SG::AuxElement::Decorator< float > ptcone40("MUON1_ptcone40");
-        ptcone40(*part) = resultTrack.ptcones.at(0);
-        return resultTrack.ptcones.at(0);
-        # else
-        return -1;
-        # endif
+    catch(SG::ExcBadAuxVar failed){
+      // sometimes this is missing
+      ATH_MSG_WARNING("Missing PtCone40 decoration!");
+      return -1;
     }
+  }
+  else {  
+    return -1;
+  }
 }
 double MuonTPSelectionTool::etcone_trk (const xAOD::IParticle* part,  double ) const{
     
-    if (part->isAvailable<float>("MUON1_topoetcone40")){
-        return part->auxdataConst<float>("MUON1_topoetcone40");
+  if (part->isAvailable<float>("MUON1_topoetcone40")){
+    try{
+      return part->auxdataConst<float>("MUON1_topoetcone40");
     }
-    else {  
-        //  See above - similar to track isolation
-        # if defined(ASGTOOL_ATHENA) && !defined(XAOD_ANALYSIS)
-        xAOD::CaloCorrection Calocorrlist;
-        Calocorrlist.calobitset.set(static_cast<unsigned int>(xAOD::Iso::coreCone) | static_cast<unsigned int>(xAOD::Iso::pileupCorrection));
-        xAOD::CaloIsolation resultCalo; 
-        const xAOD::TrackParticle* tp = dynamic_cast<const xAOD::TrackParticle*>(part);
-        if (!tp || ! m_calo_iso_tool->caloTopoClusterIsolation(resultCalo, *tp, m_calo_iso_to_run, Calocorrlist)){
-            ATH_MSG_WARNING("Failed to apply the isolation for a particle");
-        }
-        static SG::AuxElement::Decorator< float > etcone40("MUON1_topoetcone40");
-        etcone40(*part) = resultCalo.etcones.at(0);
-        return resultCalo.etcones.at(0);
-        # else
-        return -1;
-        # endif
+    catch(SG::ExcBadAuxVar failed){
+      // sometimes this is missing
+      ATH_MSG_WARNING("Missing EtCone40 decoration!");
+      return -1;
     }
+  }
+  return -1;
 }
 bool MuonTPSelectionTool::isFinalStateTruthMuon(const xAOD::IParticle* part) const{
 
-    // first, make sure we are actually looping over truth particles!
-    const xAOD::TruthParticle* truthmu = dynamic_cast <const xAOD::TruthParticle*>(part);
-    if (!truthmu) return false;
+  // first, make sure we are actually looping over truth particles!
+  const xAOD::TruthParticle* truthmu = dynamic_cast <const xAOD::TruthParticle*>(part);
+  if (!truthmu) return false;
 
-    // check PDG ID
-//    ATH_MSG_INFO("PDG ID");
-//    if (!truthmu->isMuon()) return false;
+  // const xAOD::TruthParticle* muparent = truthmu->parent(0);
+  if (fabs(truthmu->pdgId()) != 13) return false;
+  // check the status code
+  if (truthmu->status() != 1) return false;
+  
+  if (truthmu->isAvailable<int>("truthType")){
+      try{
+        // check the muon type
+        if (truthmu->auxdata<int>("truthType") != MCTruthPartClassifier::IsoMuon ) return false; // IsoMuon
+        // check the muon parent
+        if (truthmu->auxdata<int>("truthOrigin") != MCTruthPartClassifier::ZBoson && truthmu->auxdata<int>("truthOrigin") != MCTruthPartClassifier::CCbarMeson && truthmu->auxdata<int>("truthOrigin") != MCTruthPartClassifier::JPsi ) return false;// ZBoson or CCbarMeson
+      }
+      catch(SG::ExcBadAuxVar failed){
+        ATH_MSG_WARNING("Missing Truth decorations!");
+      }  
+    }
+  
+  return true;
+}
 
-    // check the status code
-    if (truthmu->status() != 1) return false;
-    return true;
+bool MuonTPSelectionTool::isTruthMatched(const xAOD::IParticle* part) const{
+
+  // it's an xAOD::Muon
+  const xAOD::Muon* muon = dynamic_cast<const xAOD::Muon*>(part);
+  if(muon) {
+    if(muon->isAvailable<ElementLink<xAOD::TruthParticleContainer> >("truthParticleLink")) {
+      ElementLink<xAOD::TruthParticleContainer> link = muon->auxdata<ElementLink<xAOD::TruthParticleContainer> >("truthParticleLink");
+      if(link.isValid() && (*link)->auxdata<int>("truthType")==MCTruthPartClassifier::IsoMuon)
+	return true;
+    }
+  } 
+  // it's an xAOD::TrackParticle 
+  else{
+    const xAOD::TrackParticle* track = dynamic_cast<const xAOD::TrackParticle*>(part);
+    if(track && track->auxdata<int>("truthType")==MCTruthPartClassifier::IsoMuon)
+      return true;    
+  }  
+
+  return false;
 }
 
 bool MuonTPSelectionTool::passDummyTrigger(const xAOD::Muon* tag) const{
-    // until we have real trigger info, we select muons that went into the endcaps and are well above the pt threshold...
-//     (void)passTagTrigger(tag);
-    return (fabs(tag->eta()) > 1.1 && tag->pt() > 25000.);
+  // until we have real trigger info, we select muons that went into the endcaps and are well above the pt threshold...
+  //     (void)passTagTrigger(tag);
+  return (fabs(tag->eta()) > 1.1 && tag->pt() > 25000.);
 }
 bool MuonTPSelectionTool::TagTriggerMatch (const xAOD::Muon* tag) const{
 
-    //  nothing requested -> pass through
-    if (m_tag_Triggers.size() == 0) return true;
-    //  no trigger info --> dummy trigger
-    if (m_trigTool->getListOfTriggers().size() == 0) {
-        ATH_MSG_DEBUG("Running with dummy trigger - no triggers found");
-        return passDummyTrigger(tag);
-    }
-    //  require the tag to match one of our triggers
-    for (auto trig: m_tag_Triggers) {
-        ATH_MSG_DEBUG("Matching on "<<trig <<": \t"<<m_matchTool->match(tag, trig));
-        if (m_matchTool->match(tag, trig)) return true;
+  //  nothing requested -> pass through
+  if (m_tag_Triggers.size() == 0) return true;
+  //  no trigger info --> dummy trigger
+  if (m_trigTool->getListOfTriggers().size() == 0) {
+    ATH_MSG_DEBUG("Running with dummy trigger - no triggers found");
+    return passDummyTrigger(tag);
+  }
+  //  require the tag to match one of our triggers
+  bool pass = false;
+  for (auto trig: m_tag_Triggers) {
+      
+    ATH_MSG_DEBUG("Matching on "<<trig <<": \t"<<m_matchTool->match(tag, trig));
+    bool res = (m_trigTool->isPassed(trig) && m_matchTool->match(tag, trig));
+    pass|=res;
+    
+    // decorate the tag with the trigger matching outcome, for the ntuples
+    SG::AuxElement::Decorator<bool> dec_trig ( std::string("trigmatch_")+trig); 
+    dec_trig(*tag) = res;
+    float dr = -1.;
+    if (res){
+        dr = m_matchTool->minDelR(tag, trig,0.6);
     }
-    return false;
+    SG::AuxElement::Decorator<float> dr_trig ( std::string("trigmatch_dR_")+trig); 
+    dr_trig(*tag) = dr;
+  }
+  return pass;
 }
 
 void MuonTPSelectionTool::AddCutFlowHist(MuonTPCutFlowBase* hist){
-    m_cutFlows.push_back(hist);
+  m_cutFlows.push_back(hist);
 }
 void MuonTPSelectionTool::FillCutFlows(std::string step, double weight) const{
-    for (auto cf : m_cutFlows){
-        cf->fill(step.c_str(),weight);
-    }
+  for (auto cf : m_cutFlows){
+    cf->fill(step.c_str(),weight);
+  }
 }
 
 bool MuonTPSelectionTool::PassIPCuts(const xAOD::TrackParticle* tp, double d0cut, double d0signcut, double z0cut) const{
 
-    // find the PV
-    const xAOD::VertexContainer* primVertices = 0 ;
-    const xAOD::Vertex* pv = 0;
-    if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
-        ATH_MSG_ERROR("Found no PV candidate for IP computation!");
-    }
-    else {
-        pv = primVertices->at(0);
-    }
+  // find the PV
+  const xAOD::VertexContainer* primVertices = 0 ;
+  const xAOD::Vertex* pv = 0;
+  if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
+    ATH_MSG_ERROR("Found no PV candidate for IP computation!");
+  }
+  else {
+    pv = primVertices->at(0);
+  }
 
-    float d0 = 0;
-    float d0sign = 0;
-    float z0 = 0;
+  float d0 = 0;
+  float d0sign = 0;
+  float z0 = 0;
 
-    d0 = tp->d0();
-    float d0err = sqrt(tp->definingParametersCovMatrix()(0,0));
-    d0sign = fabs(d0) / (d0err != 0 ? d0err : 1e-9);
-    z0 = tp->z0();
-    if (pv) z0 += tp->vz() - pv->z();
+  d0 = tp->d0();
+  float d0err = sqrt(tp->definingParametersCovMatrix()(0,0));
+  d0sign = fabs(d0) / (d0err != 0 ? d0err : 1e-9);
+  z0 = tp->z0();
+  if (pv) z0 += tp->vz() - pv->z();
 
-    if (d0cut >= 0 && fabs(d0) > d0cut) return false;
-    if (d0signcut >= 0 && fabs(d0sign) > d0signcut) return false;
-    if (z0cut >= 0 && fabs(z0) > z0cut) return false;
+  if (d0cut >= 0 && fabs(d0) > d0cut) return false;
+  if (d0signcut >= 0 && fabs(d0sign) > d0signcut) return false;
+  if (z0cut >= 0 && fabs(z0) > z0cut) return false;
 
-    return true;
+  return true;
 }
 
 
 bool MuonTPSelectionTool::Event_Trigger (void) const{
-    // if we are not requesting a trigger, or if the DS has no trigger info, accept the event
-    ATH_MSG_DEBUG("Have "<<m_trigTool->getListOfTriggers().size() <<" Triggers");
-    if (m_tag_Triggers.size() == 0 || m_trigTool->getListOfTriggers().size() == 0) return true;
-    // otherwise see if one of our triggers is passed.
-    for (auto trig: m_tag_Triggers){
-        ATH_MSG_DEBUG("Test "<<trig <<": \t"<<m_trigTool->isPassed(trig));
-        if (m_trigTool->isPassed(trig)) return true;
-    }
-    return false;
+  // if we are not requesting a trigger, or if the DS has no trigger info, accept the event
+  ATH_MSG_DEBUG("Have "<<m_trigTool->getListOfTriggers().size() <<" Triggers");
+  if (m_tag_Triggers.size() == 0 || m_trigTool->getListOfTriggers().size() == 0) return true;
+  // otherwise see if one of our triggers is passed.
+  for (auto trig: m_tag_Triggers){
+    ATH_MSG_DEBUG("Test "<<trig <<": \t"<<m_trigTool->isPassed(trig));
+    if (m_trigTool->isPassed(trig)) return true;
+  }
+  return false;
 }
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTool.cxx
index 66f9c2d29e9..6bde06b4aa1 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTool.cxx
@@ -7,16 +7,19 @@
 #include "MuonTPTools/IMuonTPSelectionTool.h"
 #include "MuonTPTools/IMuonTPEfficiencyTool.h"
 #include "xAODEventInfo/EventInfo.h"
-#include "GaudiKernel/ITHistSvc.h"
+//#include "GaudiKernel/ITHistSvc.h"
 
 //**********************************************************************
 
 MuonTPTool::MuonTPTool(std::string myname)
 : AsgTool(myname),
-  m_histSvc("THistSvc", myname),
-  m_muonTPSelectionTools(),
-  m_muonTPEfficiencyTools(),
-  m_inefficient_evts(0)
+//     m_histSvc("THistSvc", myname),
+    m_muonTPSelectionTools(),
+    m_muonTPEfficiencyTools(),
+    m_inefficient_evts(0),
+    m_evt(-1),
+    m_run(-1),
+    m_centeta(false)
 {
     declareProperty("MuonTPSelectionTools",  m_muonTPSelectionTools);
     declareProperty("MuonTPEfficiencyTools", m_muonTPEfficiencyTools);
@@ -24,7 +27,6 @@ MuonTPTool::MuonTPTool(std::string myname)
     declareProperty("TreeTools",             m_TPTrees);
     declareProperty("EfficiencyFlag",        m_efficiencyFlag = "JPsiTP");
     declareProperty("DumpInefficientEvents", m_dump_inefficient = false);
-
     
 }
 
@@ -43,7 +45,7 @@ StatusCode MuonTPTool::initialize()
     ATH_CHECK(m_muonTPEfficiencyTools.retrieve());
     ATH_CHECK(m_TPPlots.retrieve());
     ATH_CHECK(m_TPTrees.retrieve());
-    ATH_CHECK(m_histSvc.retrieve());
+    //ATH_CHECK(m_histSvc.retrieve());
 
     if (m_dump_inefficient){
 
@@ -77,7 +79,7 @@ void MuonTPTool::runTagAndProbe(const xAOD::MuonContainer* tags, const xAOD::IPa
 
     const xAOD::EventInfo* info = 0;
     ATH_MSG_DEBUG(""<<evtStore());
-    if (evtStore()->retrieve(info).isFailure()){
+    if (evtStore()->retrieve(info, "EventInfo").isFailure()){
         ATH_MSG_FATAL( "Unable to retrieve Event Info" );
     }
     
@@ -98,6 +100,7 @@ void MuonTPTool::runTagAndProbe(const xAOD::MuonContainer* tags, const xAOD::IPa
             plots->fillCutFlow("Processed Events",1,tpSelTool);
             plots->fillCutFlow("Processed Events (Weight)",weight,tpSelTool);
         }
+        
         // Select probes
         ProbeContainer* probeCont = tpSelTool->selectProbes(tags, probes);
 
@@ -107,21 +110,22 @@ void MuonTPTool::runTagAndProbe(const xAOD::MuonContainer* tags, const xAOD::IPa
             }
         }
 
-        for(auto probe : *probeCont)
-	{
+        for(auto probe : *probeCont) {
             probe->HasSomeTrigger(false);
             probe->HasSomeTrigger_HLT(false);
-	}
+        }
         
-	// Loop on TP efficiencies for each selection
-        for(auto tpEffTool : m_muonTPEfficiencyTools)
-	{
+    // Loop on TP efficiencies for each selection
+        for(auto tpEffTool : m_muonTPEfficiencyTools){
+            // do not run 'double' variations
+            if (!tpEffTool->isNominal() && !tpSelTool->isNominal()) continue;
+            
             // Match probes
             tpEffTool->matchProbes(probeCont, matches);
 
             // Fill efficiency histograms
             for(auto probe : *probeCont)
-	    {
+            {
                 if (m_dump_inefficient && !probe->isMatched()){
                     ineff = true;
                     if (fabs(probe->eta()) > 0.1) m_centeta = false;
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTreeTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTreeTool.cxx
index fad947bc894..00e2fd045e6 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTreeTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTPTreeTool.cxx
@@ -10,100 +10,246 @@
  */
 
 #include "MuonTPTools/MuonTPTreeTool.h"
-#include <vector>
+#include "MuonTPTools/MuonTrigTPEfficiencyTool.h"
 #include <vector>
 
 MuonTPTreeTool::MuonTPTreeTool(std::string name)
-	  : AsgTool(name){
-	  declareProperty("EfficiencyFlag",        m_efficiencyFlag = "ZmmTP");
-
+  : AsgTool(name),
+    m_trigTool("Trig::TrigDecisionTool/TrigDecisionTool")
+{
+  // determines tree names
+  declareProperty("EfficiencyFlag",         m_efficiencyFlag = "ZmmTP");
+  // record scale factor info used for closure tests of the CP tools
+  declareProperty("RecordScaleFactorInfo",  m_record_SF = false);
+  declareProperty("TriggerDecisionTool",    m_trigTool);
 }
 
-StatusCode MuonTPTreeTool::RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools){
+MuonTPTreeTool::~MuonTPTreeTool() {}
 
+StatusCode MuonTPTreeTool::initialize()
+{
+  ATH_CHECK(m_trigTool.retrieve());
+  return StatusCode::SUCCESS;
+}
 
-      // Create histograms
-      for(auto tpSelTool : probeTools) {
-        std::string cfdirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
-        m_trees[cfdirs] = std::make_pair (new TTree ((std::string("TPTree_")+tpSelTool->efficiencyFlag()).c_str(),"TP"), cfdirs);
-        for(auto tpEffTool : effTools) {
-            if (m_match_flags.find(tpEffTool->efficiencyFlag()) == m_match_flags.end()){
-                m_match_flags[tpEffTool->efficiencyFlag()] = false;
-            }
-        }
-        InitTree (m_trees[cfdirs].first);
+StatusCode MuonTPTreeTool::RegisterTrees (ToolHandleArray<IMuonTPSelectionTool> & probeTools, ToolHandleArray<IMuonTPEfficiencyTool> & effTools)
+{
+  // Create histograms
+  for(auto tpSelTool : probeTools) {
+    if (tpSelTool->isNominal() || tpSelTool->notIncludedInNominal()){
+      std::string cfdirs = m_efficiencyFlag+"/"+tpSelTool->efficiencyFlag();
+      m_trees[cfdirs] = std::make_pair (new TTree ((std::string("TPTree_")+tpSelTool->efficiencyFlag()).c_str(),"TP"), cfdirs);
+            
+      // add tag trigger matching information
+      std::vector<std::string> tag_triggers = tpSelTool->tagTriggerList();
+      for (auto trig : tag_triggers){
+	if (m_tag_trigmatch.find(trig) == m_tag_trigmatch.end()){
+	  m_tag_trigmatch[trig] = false;
+	}
+	if (m_tag_trig_dR.find(trig) == m_tag_trig_dR.end()){
+	  m_tag_trig_dR[trig] = -1;
+	}
+	if (m_triggers.find(trig) == m_triggers.end()){
+	  m_triggers[trig] = false;
+	}	
       }
+            
+      for(auto tpEffTool : effTools) {
+	if (m_match_flags.find(tpEffTool->efficiencyFlag()) == m_match_flags.end()){
+	  m_match_flags[tpEffTool->efficiencyFlag()] = false;
+	}
+	if (m_scale_factors.find(tpEffTool->efficiencyFlag()) == m_scale_factors.end()){
+	  m_scale_factors[tpEffTool->efficiencyFlag()] = 1.0;
+	}
+	if (tpEffTool->isNominal()){
+	  if (m_match_dR.find(tpEffTool->efficiencyFlag()) == m_match_dR.end()){
+	    m_match_dR[tpEffTool->efficiencyFlag()] = -1.0;
+	  }
+	}
+	if (tpEffTool->triggerItem()!="" && 
+	    m_triggers.find(tpEffTool->triggerItem()) == m_triggers.end()){
+	  m_triggers[tpEffTool->triggerItem()] = false;
+	}	  
+      }
+
+      InitTree (m_trees[cfdirs].first);
+    }
+  }
 
   return StatusCode::SUCCESS;
 
 }
- // fill the histos
- void MuonTPTreeTool::fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> sel_tool){
-    std::string cfdirs = m_efficiencyFlag+"/"+sel_tool->efficiencyFlag();
-    auto tree = m_trees.find(cfdirs);
-    if (tree == m_trees.end()){
-        ATH_MSG_ERROR("Trying to fill a nonexisting tree!");
-        return;
+
+// fill the histos
+void MuonTPTreeTool::fill(Probe& probe,ToolHandle <IMuonTPSelectionTool> & sel_tool)
+{
+  std::string cfdirs = m_efficiencyFlag+"/"+sel_tool->efficiencyFlag();
+  auto tree = m_trees.find(cfdirs);
+  if (tree == m_trees.end()){
+    if (sel_tool->isNominal() || sel_tool->notIncludedInNominal()){
+      ATH_MSG_ERROR("Trying to fill a nonexisting tree!");
     }
-    TTree* OutTree = tree->second.first;
-    auto probe_map = m_match_flags_perProbe.find(&probe);
-    if (probe_map == m_match_flags_perProbe.end()){
-        ATH_MSG_WARNING("Found a probe that doesn't have any match info - intentional?");
-        for (auto entry: m_match_flags){
-            entry.second = false;
-        }
+    return;
+  }
+  TTree* OutTree = tree->second.first;
+  auto probe_map = m_match_flags_perProbe.find(&probe);
+  if (probe_map == m_match_flags_perProbe.end()){
+    ATH_MSG_WARNING("Found a probe that doesn't have any match info - intentional?");
+    for (auto entry: m_match_flags){
+      entry.second = false;
     }
-    else {
-        for (auto entry: m_match_flags){
-            m_match_flags[entry.first] = probe_map->second.at(entry.first);
-        }
+  }
+  else {
+    for (auto entry: m_match_flags){
+      //  skip double systematics cases
+      if (probe_map->second.find(entry.first) ==  probe_map->second.end()) {
+	m_match_flags[entry.first] = false;
+      }
+      else {
+	m_match_flags[entry.first] = probe_map->second.at(entry.first);
+      }
     }
-    FillCustomStuff(probe);
-    OutTree->Fill();
+  }
+  auto probe_sf_map = m_scale_factors_perProbe.find(&probe);
+  if (probe_sf_map == m_scale_factors_perProbe.end()){
+    ATH_MSG_WARNING("Found a probe that doesn't have any SF info - intentional?");
+    for (auto entry: m_scale_factors){
+      entry.second = 1.00;
+    }
+  }
+  else {
+    for (auto entry: m_scale_factors){
+      if (probe_sf_map->second.find(entry.first) ==  probe_sf_map->second.end()) {
+	m_scale_factors[entry.first] = 1.;
+      }
+      else {
+	m_scale_factors[entry.first] = probe_sf_map->second.at(entry.first);
+      }
+    }
+  }
+  auto probe_dR_map = m_match_dR_perProbe.find(&probe);
+  if (probe_dR_map == m_match_dR_perProbe.end()){
+    ATH_MSG_WARNING("Found a probe that doesn't have any dR info - intentional?");
+    for (auto entry: m_match_dR){
+      entry.second = 1.00;
+    }
+  }
+  else {
+    for (auto entry: m_match_dR){
+      if (probe_dR_map->second.find(entry.first) ==  probe_dR_map->second.end()) {
+	m_match_dR[entry.first] = -1.;
+      }
+      else {
+	m_match_dR[entry.first] = probe_dR_map->second.at(entry.first);
+      }
+    }
+  }
+  FillTriggerInfo();
+  FillTagTriggerInfo(probe);
+  FillCustomStuff(probe);
+  OutTree->Fill();
 
- }
-void MuonTPTreeTool::FillCustomStuff(Probe & ){
-    // do nothing in the default version
-}
-void MuonTPTreeTool::AddCustomBranches(TTree*){
-    // do nothing in the default version
-    // in 'your' version, do tree->Branch("something",&m_something); in here
 }
 
+void MuonTPTreeTool::FillTriggerInfo()
+{    
+  for (auto trig : m_triggers) 
+    m_triggers[trig.first] = m_trigTool->isPassed(trig.first);
+}
 
-void MuonTPTreeTool::updateMatch(Probe& probe,ToolHandle <IMuonTPEfficiencyTool> eff_tool){
-
-    if (m_match_flags_perProbe.find(&probe) == m_match_flags_perProbe.end()){
-        m_match_flags_perProbe[&probe] = std::map<std::string, bool>() ;
+void MuonTPTreeTool::FillTagTriggerInfo(Probe & probe)
+{    
+  const xAOD::Muon* tagmuon = dynamic_cast <const xAOD::Muon*>(&(probe.tagTrack()));
+  // tag is not a muon: happens for truth probes
+  if (!tagmuon) return;
+  for (auto trigstatus : m_tag_trigmatch){
+    std::string trigkey = trigstatus.first;
+    if (tagmuon->isAvailable<bool>(std::string("trigmatch_")+trigkey)){
+      m_tag_trigmatch[trigkey] = tagmuon->auxdata<bool>(std::string("trigmatch_")+trigkey);
     }
-    m_match_flags_perProbe[&probe][eff_tool->efficiencyFlag()] = probe.isMatched();
-
+    else{
+      ATH_MSG_WARNING("Missing tag trigger matching info for chain "<<trigkey<<"!");
+      m_tag_trigmatch[trigkey] = false;
+    }
+  }
+  for (auto trigstatus : m_tag_trig_dR){
+    std::string trigkey = trigstatus.first;
+    if (tagmuon->isAvailable<float>(std::string("trigmatch_dR_")+trigkey)){
+      m_tag_trig_dR[trigkey] = tagmuon->auxdata<float>(std::string("trigmatch_dR_")+trigkey);
+    }
+    else{
+      ATH_MSG_WARNING("Missing tag trigger dR info for chain "<<trigkey<<"!");
+      m_tag_trig_dR[trigkey] = -1.;
+    }
+  }
 }
 
-void MuonTPTreeTool::ForgetKnownProbes(void){
-    m_match_flags_perProbe.clear();
+void MuonTPTreeTool::FillCustomStuff(Probe & ){
+  // do nothing in the default version
 }
 
- 
-void MuonTPTreeTool::InitTree(TTree* tree){
-    for (auto flag : m_match_flags){
-        tree->Branch((std::string("matched_")+flag.first).c_str(), &(m_match_flags[flag.first]));
-    }
-    AddCustomBranches(tree);
+void MuonTPTreeTool::AddCustomBranches(TTree*){
+  // do nothing in the default version
+  // in 'your' version, do tree->Branch("something",&m_something); in here
 }
 
-  /// retrieve booked trees
-  std::vector<std::pair<TTree*, std::string> > MuonTPTreeTool::retrieveBookedTrees(){
-    std::vector<std::pair<TTree*, std::string> > OutTrees;
-    for (auto tree: m_trees){
-        OutTrees.push_back(tree.second);
-    }
-    return OutTrees;
+void MuonTPTreeTool::updateMatch(Probe& probe,ToolHandle <IMuonTPEfficiencyTool> & eff_tool)
+{
+  if (m_match_flags_perProbe.find(&probe) == m_match_flags_perProbe.end()){
+    m_match_flags_perProbe[&probe] = std::map<std::string, bool>() ;
   }
+  if (m_scale_factors_perProbe.find(&probe) == m_scale_factors_perProbe.end()){
+    m_scale_factors_perProbe[&probe] = std::map<std::string, float>() ;
+  }
+  if (m_match_dR_perProbe.find(&probe) == m_match_dR_perProbe.end()){
+    m_match_dR_perProbe[&probe] = std::map<std::string, float>() ;
+  }
+  m_match_flags_perProbe[&probe][eff_tool->efficiencyFlag()] = probe.isMatched();
+  m_scale_factors_perProbe[&probe][eff_tool->efficiencyFlag()] = probe.sfweight();
+  m_match_dR_perProbe[&probe][eff_tool->efficiencyFlag()] = probe.dr_match();
 
-  MuonTPTreeTool::~MuonTPTreeTool(){
+}
 
+void MuonTPTreeTool::ForgetKnownProbes(void)
+{
+  m_match_flags_perProbe.clear();
+  m_match_dR_perProbe.clear();
+  m_scale_factors_perProbe.clear();
+}
+
+void MuonTPTreeTool::InitTree(TTree* tree)
+{
+  // fill the match flags 
+  for (auto flag : m_match_flags){
+    tree->Branch((std::string("probe_matched_")+flag.first).c_str(), &(m_match_flags[flag.first]));
+    if (m_record_SF) tree->Branch((std::string("probe_scale_factor_")+flag.first).c_str(), &(m_scale_factors[flag.first]));
+  }
+  for (auto flag : m_match_dR){
+    tree->Branch((std::string("probe_dRMatch_")+flag.first).c_str(), &(m_match_dR[flag.first]));
+  }
+  // also fill in the tag trigger info
+  for (auto bla : m_tag_trig_dR){
+    tree->Branch((std::string("tag_matched_")+bla.first).c_str(),&(m_tag_trigmatch[bla.first]));
+    tree->Branch((std::string("tag_dRMatch_")+bla.first).c_str(),&(m_tag_trig_dR[bla.first]));
   }
+  // add branches for event triggers
+  for (auto bla : m_triggers) {
+    tree->Branch(bla.first.c_str(),&(m_triggers[bla.first]));    
+  }
+  
+  AddCustomBranches(tree);
+}
+
+/// retrieve booked trees
+std::vector<std::pair<TTree*, std::string> > MuonTPTreeTool::retrieveBookedTrees()
+{
+  std::vector<std::pair<TTree*, std::string> > OutTrees;
+  for (auto tree: m_trees){
+    OutTrees.push_back(tree.second);
+  }
+  return OutTrees;
+}
+
 
 
 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPEfficiencyTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPEfficiencyTool.cxx
index 56e3e09a5a7..42f0d6d4fcc 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPEfficiencyTool.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPEfficiencyTool.cxx
@@ -12,11 +12,10 @@
 #include "MuonTPTools/MuonTrigTPEfficiencyTool.h"
 
 MuonTrigTPEfficiencyTool::MuonTrigTPEfficiencyTool(std::string myname)
-: AsgTool(myname), MuonTPEfficiencyTool(myname)
+: MuonTPEfficiencyTool(myname)
 {
     declareProperty("dR_L1",           m_dR_L1 = 0.2);
     declareProperty("dR_HLT",          m_dR_HLT= 0.25);
-    declareProperty("TrigItem",        m_trigger_item="");
 }
 
 
@@ -31,45 +30,61 @@ void MuonTrigTPEfficiencyTool::matchProbes(ProbeContainer* probes, const xAOD::I
         
         const xAOD::Muon* matchmuon = dynamic_cast<const xAOD::Muon*>(&(probe->probeTrack()));
         if (!matchmuon)
-	{
+        {
             ATH_MSG_WARNING("Running trigger efficiency on something that is not a muon!");
             continue;
         }
         
-	// Pt Cut
-	if(matchmuon->pt()        < m_matchPtCut) continue;
-        // Eta Cut
+        // Pt Cut
+        if(matchmuon->pt()        < m_matchPtCut) continue;
+            // Eta Cut
         if(fabs(matchmuon->eta()) > m_matchEtaCut) continue;
+            
+        probe->SetCurrentTrigger(m_trigger_item);
         
-	probe->SetCurrentTrigger(m_trigger_item);
-	
-	// L1 trigger matching
-	if ( m_trigger_item.find("L1_")!=std::string::npos && m_trigger_item != "L1_AllTriggers")
-	{
-            bool trigmatchL1 = m_matchTool->matchL1(matchmuon,m_trigger_item, m_dR_L1);
+        probe->dr_match(-1.);
+        // L1 trigger matching
+        if ( m_trigger_item.find("L1_")==0 && m_trigger_item != "L1_AllTriggers")
+        {
+            bool trigmatchL1 = false;
+            try{
+                trigmatchL1 = m_matchTool->matchL1(matchmuon,m_trigger_item, m_maximumDrCut);
+            }
+            catch(SG::ExcNoAuxStore){
+                ATH_MSG_WARNING("Unable to read trigger info for L1 matching to "<<m_trigger_item);
+                trigmatchL1 = false;
+            }
             probe->isMatched(trigmatchL1);
+            best_dR_L1   = m_matchTool->minDelRL1(matchmuon,m_trigger_item,10.);
+            probe->dr_match(best_dR_L1);
             if(!trigmatchL1)  continue;
             probe->HasSomeTrigger(true);
-            best_dR_L1   = m_matchTool->minDelRL1(matchmuon,m_trigger_item);
             probe->dRL1  = best_dR_L1;
         }
-        if (m_trigger_item == "L1_AllTriggers")
-	{
+        if (m_trigger_item == "L1_AllTriggers"){
             probe->isMatched(probe->HasSomeTrigger());
         }
 
-	// HLT trigger matching
-	if ( m_trigger_item.find("HLT_")!=std::string::npos && m_trigger_item != "HLT_AllTriggers")
-	{
-            bool match_HLT_trig = m_matchTool->match(matchmuon->eta(), matchmuon->phi(), m_trigger_item);
+        // HLT trigger matching
+        if ( m_trigger_item.find("HLT_")==0 && m_trigger_item != "HLT_AllTriggers")
+        {
+            bool match_HLT_trig = false;
+            try{
+                match_HLT_trig = m_matchTool->match(matchmuon->eta(), matchmuon->phi(), m_trigger_item,m_maximumDrCut);
+            }
+            catch(SG::ExcNoAuxStore){
+                ATH_MSG_WARNING("Unable to read trigger info for HLT matching to "<<m_trigger_item);
+                match_HLT_trig = false;
+            }
             probe->isMatched(match_HLT_trig);
+            best_dR_HLT  = m_matchTool->minDelR(matchmuon,m_trigger_item,10.);
+            probe->dr_match(best_dR_HLT);
             if (!match_HLT_trig) continue;
             probe->HasSomeTrigger_HLT(true);
-            best_dR_HLT  = m_matchTool->minDelR(matchmuon,m_trigger_item);
-	    probe->dRHLT = best_dR_HLT;
+            probe->dRHLT = best_dR_HLT;
         }
-	if (m_trigger_item == "HLT_AllTriggers")
-	{
+        if (m_trigger_item == "HLT_AllTriggers")
+        {
             probe->isMatched(probe->HasSomeTrigger_HLT());
         }
     }
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPPlotTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPPlotTool.cxx
deleted file mode 100644
index 89788d6d50c..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPPlotTool.cxx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTrigTPPlotTool.cxx
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc / a.m.
- */
-
-#include "MuonTPTools/MuonTrigTPPlotTool.h"
-//#include "MuonPerformanceHistUtils/ZmumuBasicTPEfficiencyPlots.h"
-#include "MuonPerformanceHistUtils/MuonTrigTPEfficiencyPlots.h"
-//#include "MuonPerformanceHistUtils/ZmumuTagProbeDileptonPlots.h"
-#include "MuonPerformanceHistUtils/ZmumuTPEventCutFlowPlots.h"
-
-MuonTrigTPPlotTool::MuonTrigTPPlotTool(std::string name)
-	  :  AsgTool(name),MuonTPPlotTool(name)
-{
-    declareProperty("doTrkValidPlots",       m_do_Valid   = false);
-    declareProperty("doBasicKinematicPlots", m_do_TPBasic = true);
-    declareProperty("ApplyScaleFactors",     m_apply_SF   = false);
-}
-
-
-
-//--------------------------------------------------------------------------------
-std::vector<MuonTPEfficiencyPlotBase*> MuonTrigTPPlotTool::AddPlots(std::string sDir, bool isMatched)
-{
-    std::vector<MuonTPEfficiencyPlotBase*> out (0);
-    if (m_do_Valid)    out.push_back( new MuonTPEfficiencyPlots(    0, sDir, isMatched));
-    if (m_do_TPBasic)  out.push_back( new MuonTrigTPEfficiencyPlots(0, sDir, isMatched,m_apply_SF));
-    return out;
-}
-
-
-
-//--------------------------------------------------------------------------------
-std::vector<MuonTPCutFlowBase*> MuonTrigTPPlotTool::AddCutFlowPlots(std::string sDir)
-{
-    std::vector<MuonTPCutFlowBase*> out (0);
-    out.push_back (new ZmumuTPEventCutFlowPlots(0,sDir));
-    return out;
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPTreeTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPTreeTool.cxx
deleted file mode 100644
index 36cd4f552fc..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/MuonTrigTPTreeTool.cxx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTPTrees.cxx
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc / a.m.
- */
-
-#include "MuonTPTools/MuonTrigTPTreeTool.h"
-#include "xAODEventInfo/EventInfo.h"
-#include "xAODTracking/VertexContainer.h"
-
-MuonTrigTPTreeTool::MuonTrigTPTreeTool(std::string name)
-      :  AsgTool(name),MuonTPTreeTool(name){}
-
-void MuonTrigTPTreeTool::FillCustomStuff(Probe& probe)
-{
-
-    const xAOD::VertexContainer* primVertices = 0 ;
-    const xAOD::Vertex* pv = 0;
-    if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
-        ATH_MSG_ERROR("Found no PV candidate for IP computation!");
-    }
-    else {
-        pv = primVertices->at(0);
-    }
-    int charge = 0;
-    // case of a muon probe
-    charge = -2;
-    m_ptcone40 = -1;
-    m_etcone40 = -1;
-//  const xAOD::VertexContainer* vxc ("
-    const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(&probe.probeTrack());
-    if (muprobe)
-    {
-    	charge = muprobe->trackParticle(xAOD::Muon::Primary)->charge() ;
-    	bool ok = muprobe->isolation(m_etcone40,xAOD::Iso::topoetcone40);
-    	if (!ok) m_etcone40 = -1;
-    	ok = muprobe->isolation(m_ptcone40,xAOD::Iso::ptcone40);
-    	if (!ok) m_ptcone40 = -1;
-    	if (muprobe->primaryTrackParticle())
-	{
-    	    m_d0 = muprobe->primaryTrackParticle()->d0();
-    	    m_d0err = sqrt(muprobe->primaryTrackParticle()->definingParametersCovMatrix()(0,0));
-    	    m_z0 = muprobe->primaryTrackParticle()->z0();
-    	    if (pv)
-	    {
-    	    	m_z0 = m_z0 - pv->z() + muprobe->primaryTrackParticle()->vz();
-    	    }
-        }
-    }
-    // case of an ID probe
-    const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(&probe.probeTrack());
-    if (!muprobe && trkprobe)
-    {
-    	charge = trkprobe->charge();
-    	if (trkprobe->isAvailable<float>("TopoEtCone40"))
-    	{
-    		m_etcone40 =  trkprobe->auxdataConst<float>("TopoEtCone40");
-    	}
-    	else
-    	{
-    		m_etcone40 = -1.;
-    	}
-    	if (trkprobe->isAvailable<float>("PtCone40"))
-    	{
-    		m_ptcone40 =  trkprobe->auxdataConst<float>("PtCone40");
-    	}
-   	 else
-   	 {
-    		m_ptcone40 = -1.;
-   	 }
-   	 m_d0 = trkprobe->d0();
-    	m_d0err = sqrt(trkprobe->definingParametersCovMatrix()(0,0));
-    	m_z0 = trkprobe->z0();
-//  	   const xAOD::Vertex* vx = trkprobe->vertex();
-    	if (pv){
-    		m_z0 = m_z0 - pv->z() + trkprobe->vz();
-    	}
-    }
-
-    const xAOD::EventInfo* info = 0;
-    ATH_MSG_DEBUG(""<<evtStore());
-    if (evtStore()->retrieve(info).isFailure())
-    {
-        ATH_MSG_FATAL( "Unable to retrieve Event Info" );
-    }
-    static bool isMC = info->eventType(xAOD::EventInfo::IS_SIMULATION);
-
-    m_runNumber   = info->runNumber();
-    m_eventNumber = info->eventNumber();
-    m_mu = info->averageInteractionsPerCrossing();
-    m_mcEventWeight = (isMC ? info->mcEventWeight() : 1.00);
-    m_pt  = probe.pt() / 1000.;
-    m_eta = probe.eta();
-    m_phi = probe.phi();
-    m_fineEtaPhi = m_fepb.bin(probe.probeTrack().p4());
-    m_q      = charge;
-    m_tagPt  = probe.tagTrack().pt() / 1000.;
-    m_tagEta = probe.tagTrack().eta();
-    m_tagPhi = probe.tagTrack().phi();
-    m_mll    = (probe.tagTrack().p4()+probe.probeTrack().p4()).M();
-    
-    
-}
-void MuonTrigTPTreeTool::AddCustomBranches(TTree* tree)
-{
-    tree->Branch("runNumber",    &m_runNumber);
-    tree->Branch("eventNumber",  &m_eventNumber);
-    tree->Branch("mu",           &m_mu);
-    tree->Branch("mcEventWeight",&m_mcEventWeight);
-    tree->Branch("pt",           &m_pt);
-    tree->Branch("eta",          &m_eta);
-    tree->Branch("phi",          &m_phi);
-    tree->Branch("d0",           &m_d0);
-    tree->Branch("d0err",        &m_d0err);
-    tree->Branch("z0",           &m_z0);
-    tree->Branch("ptcone40",     &m_ptcone40);
-    tree->Branch("etcone40",     &m_etcone40);
-    tree->Branch("fineEtaPhi",   &m_fineEtaPhi);
-    tree->Branch("q",            &m_q);
-    tree->Branch("tagPt",        &m_tagPt);
-    tree->Branch("tagEta",       &m_tagEta);
-    tree->Branch("tagPhi",       &m_tagPhi);
-    tree->Branch("mll",          &m_mll);
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPIsolationTreeTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPIsolationTreeTool.cxx
deleted file mode 100644
index 8fc015ea54b..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPIsolationTreeTool.cxx
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTPTrees.cxx
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc
- */
-
-#include "MuonTPTools/ZmumuMuonTPIsolationTreeTool.h"
-#include "xAODEventInfo/EventInfo.h"
-#include "xAODTracking/VertexContainer.h"
-
-ZmumuMuonTPIsolationTreeTool::ZmumuMuonTPIsolationTreeTool(std::string name)
-      :  AsgTool(name),MuonTPTreeTool(name){
-}
-
-void ZmumuMuonTPIsolationTreeTool::FillCustomStuff(Probe& probe){
-
-    const xAOD::VertexContainer* primVertices = 0 ;
-    const xAOD::Vertex* pv = 0;
-    if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
-        ATH_MSG_ERROR("Found no PV candidate for IP computation!");
-    }
-    else {
-        pv = primVertices->at(0);
-    }
-
-    m_Npvtx = primVertices->size();
-
-    m_dPhi = fabs(probe.tagTrack().p4().DeltaPhi(probe.probeTrack().p4()));
-
-	int charge = 0;
-	// case of a muon probe
-    charge = -2;
-//     const xAOD::VertexContainer* vxc ("
-	const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(&probe.probeTrack());
-	if (muprobe) {
-		charge = muprobe->trackParticle(xAOD::Muon::Primary)->charge() ;
-        bool ok = muprobe->isolation(m_probeiso_etcone40,xAOD::Iso::topoetcone40);
-        if (!ok) m_probeiso_etcone40 = -1;
-        ok = muprobe->isolation(m_probeiso_ptcone40,xAOD::Iso::ptcone40);
-        if (!ok) m_probeiso_ptcone40 = -1;
-        ok = muprobe->isolation(m_probeiso_topoetcone40,xAOD::Iso::topoetcone40);
-        if (!ok) m_probeiso_topoetcone40 = -1;
-        ok = muprobe->isolation(m_probeiso_ptvarcone40,xAOD::Iso::ptvarcone40);
-        if (!ok) m_probeiso_ptvarcone40 = -1;
-        ok = muprobe->isolation(m_probeiso_neflowisol40,xAOD::Iso::neflowisol40);
-        if (!ok) m_probeiso_neflowisol40 = -1;
-
-        ok = muprobe->isolation(m_probeiso_etcone30,xAOD::Iso::topoetcone30);
-        if (!ok) m_probeiso_etcone30 = -1;
-        ok = muprobe->isolation(m_probeiso_ptcone30,xAOD::Iso::ptcone30);
-        if (!ok) m_probeiso_ptcone30 = -1;
-        ok = muprobe->isolation(m_probeiso_topoetcone30,xAOD::Iso::topoetcone30);
-        if (!ok) m_probeiso_topoetcone30 = -1;
-        ok = muprobe->isolation(m_probeiso_ptvarcone30,xAOD::Iso::ptvarcone30);
-        if (!ok) m_probeiso_ptvarcone30 = -1;
-        ok = muprobe->isolation(m_probeiso_neflowisol30,xAOD::Iso::neflowisol30);
-        if (!ok) m_probeiso_neflowisol30 = -1;
-
-        ok = muprobe->isolation(m_probeiso_etcone20,xAOD::Iso::topoetcone20);
-        if (!ok) m_probeiso_etcone20 = -1;
-        ok = muprobe->isolation(m_probeiso_ptcone20,xAOD::Iso::ptcone20);
-        if (!ok) m_probeiso_ptcone20 = -1;
-        ok = muprobe->isolation(m_probeiso_topoetcone20,xAOD::Iso::topoetcone20);
-        if (!ok) m_probeiso_topoetcone20 = -1;
-        ok = muprobe->isolation(m_probeiso_ptvarcone20,xAOD::Iso::ptvarcone20);
-        if (!ok) m_probeiso_ptvarcone40 = -1;
-        ok = muprobe->isolation(m_probeiso_neflowisol20,xAOD::Iso::neflowisol20);
-        if (!ok) m_probeiso_neflowisol20 = -1;
-
-        if (muprobe->primaryTrackParticle()){
-            m_d0 = muprobe->primaryTrackParticle()->d0();
-            m_d0err = sqrt(muprobe->primaryTrackParticle()->definingParametersCovMatrix()(0,0));
-            m_z0 = muprobe->primaryTrackParticle()->z0();
-            if (pv){
-                m_z0 = m_z0 - pv->z() + muprobe->primaryTrackParticle()->vz();
-            }
-        }
-	}
-
-
-        const xAOD::Muon* mutag = dynamic_cast<const xAOD::Muon*>(&probe.tagTrack());
-
-	int charge2 = 0;
-	charge2 = -2;
-
-        if (mutag) {
-                charge2 = mutag->trackParticle(xAOD::Muon::Primary)->charge() ;
-
-        bool ok2 = mutag->isolation(m_tagiso_etcone40,xAOD::Iso::topoetcone40);
-        if (!ok2) m_tagiso_etcone40 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptcone40,xAOD::Iso::ptcone40);
-        if (!ok2) m_tagiso_ptcone40 = -1;
-        ok2 = mutag->isolation(m_tagiso_topoetcone40,xAOD::Iso::topoetcone40);
-        if (!ok2) m_tagiso_topoetcone40 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptvarcone40,xAOD::Iso::ptvarcone40);
-        if (!ok2) m_tagiso_ptvarcone40 = -1;
-        ok2 = mutag->isolation(m_tagiso_neflowisol40,xAOD::Iso::neflowisol40);
-        if (!ok2) m_tagiso_neflowisol40 = -1;
-
-        ok2 = mutag->isolation(m_tagiso_etcone30,xAOD::Iso::topoetcone30);
-        if (!ok2) m_tagiso_etcone30 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptcone30,xAOD::Iso::ptcone30);
-        if (!ok2) m_tagiso_ptcone30 = -1;
-        ok2 = mutag->isolation(m_tagiso_topoetcone30,xAOD::Iso::topoetcone30);
-        if (!ok2) m_tagiso_topoetcone30 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptvarcone30,xAOD::Iso::ptvarcone30);
-        if (!ok2) m_tagiso_ptvarcone30 = -1;
-        ok2 = mutag->isolation(m_tagiso_neflowisol30,xAOD::Iso::neflowisol30);
-        if (!ok2) m_tagiso_neflowisol30 = -1;
-
-        ok2 = mutag->isolation(m_tagiso_etcone20,xAOD::Iso::topoetcone20);
-        if (!ok2) m_tagiso_etcone20 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptcone20,xAOD::Iso::ptcone20);
-        if (!ok2) m_tagiso_ptcone20 = -1;
-        ok2 = mutag->isolation(m_tagiso_topoetcone20,xAOD::Iso::topoetcone20);
-        if (!ok2) m_tagiso_topoetcone20 = -1;
-        ok2 = mutag->isolation(m_tagiso_ptvarcone20,xAOD::Iso::ptvarcone20);
-        if (!ok2) m_tagiso_ptvarcone20 = -1;
-        ok2 = mutag->isolation(m_tagiso_neflowisol20,xAOD::Iso::neflowisol20);
-        if (!ok2) m_tagiso_neflowisol20 = -1;
-	}
-
-	// case of an ID probe
-	const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(&probe.probeTrack());
-	if (!muprobe && trkprobe){
-	    charge = trkprobe->charge();
-        if (trkprobe->isAvailable<float>("TopoEtCone40")){
-            m_probeiso_etcone40 =  trkprobe->auxdataConst<float>("TopoEtCone40");
-        }
-        else {
-            m_probeiso_etcone40 = -1.;
-        }
-        if (trkprobe->isAvailable<float>("PtCone40")){
-            m_probeiso_ptcone40 =  trkprobe->auxdataConst<float>("PtCone40");
-        }
-        else {
-            m_probeiso_ptcone40 = -1.;
-        }
-        m_d0 = trkprobe->d0();
-        m_d0err = sqrt(trkprobe->definingParametersCovMatrix()(0,0));
-        m_z0 = trkprobe->z0();
-//         const xAOD::Vertex* vx = trkprobe->vertex();
-        if (pv){
-            m_z0 = m_z0 - pv->z() + trkprobe->vz();
-        }
-	}
-
-    const xAOD::EventInfo* info = 0;
-    ATH_MSG_DEBUG(""<<evtStore());
-    if (evtStore()->retrieve(info).isFailure()){
-        ATH_MSG_FATAL( "Unable to retrieve Event Info" );
-    }
-    static bool isMC = info->eventType(xAOD::EventInfo::IS_SIMULATION);
-
-	m_runNumber = info->runNumber();
-	m_eventNumber = info->eventNumber();
-	m_mu = info->averageInteractionsPerCrossing();
-	m_mcEventWeight = (isMC ? info->mcEventWeight() : 1.00);
-    m_probePt = probe.pt() / 1000.;
-    m_probeEta = probe.eta();
-    m_probePhi = probe.phi();
-
-    m_fineEtaPhi = m_fepb.bin(probe.probeTrack().p4());
-    m_probe_q = charge;
-    m_tag_q = charge2;
-    m_tagPt = probe.tagTrack().pt() / 1000.;
-    m_tagEta = probe.tagTrack().eta();
-    m_tagPhi = probe.tagTrack().phi();
-    m_mll = (probe.tagTrack().p4()+probe.probeTrack().p4()).M();
-    
-    
-}
-void ZmumuMuonTPIsolationTreeTool::AddCustomBranches(TTree* tree){
-
-	tree->Branch("runNumber",&m_runNumber);
-	tree->Branch("eventNumber",&m_eventNumber);
-	tree->Branch("mu",&m_mu);
-	tree->Branch("mcEventWeight",&m_mcEventWeight);
-    tree->Branch("tag_pt",&m_tagPt);
-    tree->Branch("tag_eta",&m_tagEta);
-    tree->Branch("tag_phi",&m_tagPhi);
-    tree->Branch("tagiso_neflowisol20",&m_tagiso_neflowisol20);
-    tree->Branch("tagiso_topoetcone20",&m_tagiso_topoetcone20);
-    tree->Branch("tagiso_etcone20",&m_tagiso_etcone20);
-    tree->Branch("tagiso_ptcone20",&m_tagiso_ptcone20);
-    tree->Branch("tagiso_ptvarcone20",&m_tagiso_ptvarcone20);
-    tree->Branch("tagiso_neflowisol30",&m_tagiso_neflowisol30);
-    tree->Branch("tagiso_topoetcone30",&m_tagiso_topoetcone30);
-    tree->Branch("tagiso_etcone30",&m_tagiso_etcone30);
-    tree->Branch("tagiso_ptcone30",&m_tagiso_ptcone30);
-    tree->Branch("tagiso_ptvarcone30",&m_tagiso_ptvarcone30);
-    tree->Branch("tagiso_neflowisol40",&m_tagiso_neflowisol40);
-    tree->Branch("tagiso_topoetcone40",&m_tagiso_topoetcone40);
-    tree->Branch("tagiso_etcone40",&m_tagiso_etcone40);
-    tree->Branch("tagiso_ptcone40",&m_tagiso_ptcone40);
-    tree->Branch("tagiso_ptvarcone40",&m_tagiso_ptvarcone40);
-    tree->Branch("probe_pt",&m_probePt);
-    tree->Branch("probe_eta",&m_probeEta);
-    tree->Branch("probe_phi",&m_probePhi);
-    tree->Branch("probeiso_neflowisol20",&m_probeiso_neflowisol20);
-    tree->Branch("probeiso_topoetcone20",&m_probeiso_topoetcone20);
-    tree->Branch("probeiso_etcone20",&m_probeiso_etcone20);
-    tree->Branch("probeiso_ptcone20",&m_probeiso_ptcone20);
-    tree->Branch("probeiso_ptvarcone20",&m_probeiso_ptvarcone20);
-    tree->Branch("probeiso_neflowisol30",&m_probeiso_neflowisol30);
-    tree->Branch("probeiso_topoetcone30",&m_probeiso_topoetcone30);
-    tree->Branch("probeiso_etcone30",&m_probeiso_etcone30);
-    tree->Branch("probeiso_ptcone30",&m_probeiso_ptcone30);
-    tree->Branch("probeiso_ptvarcone30",&m_probeiso_ptvarcone30);
-    tree->Branch("probeiso_neflowisol40",&m_probeiso_neflowisol40);
-    tree->Branch("probeiso_topoetcone40",&m_probeiso_topoetcone40);
-    tree->Branch("probeiso_etcone40",&m_probeiso_etcone40);
-    tree->Branch("probeiso_ptcone40",&m_probeiso_ptcone40);
-    tree->Branch("probeiso_ptvarcone40",&m_probeiso_ptvarcone40);
-    tree->Branch("d0",&m_d0);
-    tree->Branch("d0err",&m_d0err);
-    tree->Branch("z0",&m_z0);
-    tree->Branch("fineEtaPhi",&m_fineEtaPhi);
-    tree->Branch("tag_q",&m_tag_q);
-    tree->Branch("probe_q",&m_probe_q);
-    tree->Branch("mll",&m_mll);
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPPlotTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPPlotTool.cxx
deleted file mode 100644
index 4776eb2bcd2..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPPlotTool.cxx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTPPlots.cxx
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc
- */
-
-#include "MuonTPTools/ZmumuMuonTPPlotTool.h"
-#include "MuonPerformanceHistUtils/ZmumuBasicTPEfficiencyPlots.h"
-#include "MuonPerformanceHistUtils/ZmumuTagProbeDileptonPlots.h"
-#include "MuonPerformanceHistUtils/ZmumuFineEtaPhiEfficiencyPlots.h"
-#include "MuonPerformanceHistUtils/ZmumuTPEventCutFlowPlots.h"
-#include "MuonPerformanceHistUtils/ZmumuDetRegionEfficiencyPlots.h"
-
-ZmumuMuonTPPlotTool::ZmumuMuonTPPlotTool(std::string name)
-	  :  AsgTool(name),MuonTPPlotTool(name){
-	declareProperty("doTrkValidPlots",m_do_Valid=false);
-	declareProperty("doBasicKinematicPlots",m_do_TPBasic=true);
-    declareProperty("doDileptonPlots",m_do_DiLepton=true);
-    declareProperty("doFineEtaPhiPlots",m_do_TPFineEtaPhi=false);
-    declareProperty("doDetectorRegionPlots",m_do_DetRegions=false);
-    declareProperty("ApplyScaleFactors",m_apply_SF=false);
-}
-
-std::vector<MuonTPEfficiencyPlotBase*> ZmumuMuonTPPlotTool::AddPlots(std::string sDir, bool isMatched){
-
-	std::vector<MuonTPEfficiencyPlotBase*> out (0);
-	if (m_do_Valid) out.push_back( new MuonTPEfficiencyPlots(0, sDir, isMatched));
-	if (m_do_TPBasic) out.push_back( new ZmumuBasicTPEfficiencyPlots(0, sDir, isMatched,m_apply_SF));
-    if (m_do_TPFineEtaPhi) out.push_back( new ZmumuFineEtaPhiEfficiencyPlots(0, sDir, isMatched,m_apply_SF));
-    if (m_do_DiLepton) out.push_back( new ZmumuTagProbeDileptonPlots(0, sDir, isMatched,m_apply_SF));
-    if (m_do_DetRegions) out.push_back(new ZmumuDetRegionEfficiencyPlots(0,sDir,isMatched,m_apply_SF));
-	return out;
-
-}
-
-std::vector<MuonTPCutFlowBase*> ZmumuMuonTPPlotTool::AddCutFlowPlots(std::string sDir){
-
-    std::vector<MuonTPCutFlowBase*> out (0);
-    out.push_back (new ZmumuTPEventCutFlowPlots(0,sDir));
-    return out;
-
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPTreeTool.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPTreeTool.cxx
deleted file mode 100644
index ef6785c6a21..00000000000
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/Root/ZmumuMuonTPTreeTool.cxx
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
-*/
-
-/*
- * MuonTPTrees.cxx
- *
- *  Created on: Aug 31, 2014
- *      Author: goblirsc
- */
-
-#include "MuonTPTools/ZmumuMuonTPTreeTool.h"
-#include "xAODEventInfo/EventInfo.h"
-#include "xAODTracking/VertexContainer.h"
-#include "xAODTracking/Vertex.h"
-#include "xAODTruth/TruthParticle.h"
-
-ZmumuMuonTPTreeTool::ZmumuMuonTPTreeTool(std::string name)
-      :  AsgTool(name),MuonTPTreeTool(name){
-}
-
-void ZmumuMuonTPTreeTool::FillCustomStuff(Probe& probe){
-
-    const xAOD::VertexContainer* primVertices = 0 ;
-    const xAOD::Vertex* pv = 0;
-    if(evtStore()->retrieve(primVertices,"PrimaryVertices").isFailure()){
-        ATH_MSG_ERROR("Found no PV candidate for IP computation!");
-    }
-    else {
-        pv = primVertices->at(0);
-    }
-    m_PV_n=0;
-    for (auto vx: *primVertices){
-        if (vx->vertexType() == xAOD::VxType::PriVtx || vx->vertexType() == xAOD::VxType::PileUp) ++m_PV_n;
-    }
-	int charge = 0;
-	// case of a muon probe
-    charge = -2;
-    m_ptcone40 = -1;
-    m_etcone40 = -1;
-//     const xAOD::VertexContainer* vxc ("
-	const xAOD::Muon* muprobe = dynamic_cast<const xAOD::Muon*>(&probe.probeTrack());
-	if (muprobe) {
-		charge = muprobe->trackParticle(xAOD::Muon::Primary)->charge() ;
-        bool ok = muprobe->isolation(m_etcone40,xAOD::Iso::topoetcone40);
-        if (!ok) m_etcone40 = -1;
-        ok = muprobe->isolation(m_ptcone40,xAOD::Iso::ptcone40);
-        if (!ok) m_ptcone40 = -1;
-        if (muprobe->primaryTrackParticle()){
-            m_d0 = muprobe->primaryTrackParticle()->d0();
-            m_d0err = sqrt(muprobe->primaryTrackParticle()->definingParametersCovMatrix()(0,0));
-            m_z0 = muprobe->primaryTrackParticle()->z0();
-            if (pv){
-                m_z0 = m_z0 - pv->z() + muprobe->primaryTrackParticle()->vz();
-            }
-            muprobe->primaryTrackParticle()->summaryValue(m_nBL, xAOD::numberOfBLayerHits);
-            muprobe->primaryTrackParticle()->summaryValue(m_nPIX, xAOD::numberOfPixelHits);
-            muprobe->primaryTrackParticle()->summaryValue(m_nPIXholes, xAOD::numberOfPixelHoles);
-            muprobe->primaryTrackParticle()->summaryValue(m_nPIXdead, xAOD::numberOfPixelDeadSensors);
-            muprobe->primaryTrackParticle()->summaryValue(m_nSCT, xAOD::numberOfSCTHits );
-            muprobe->primaryTrackParticle()->summaryValue(m_nSCTholes, xAOD::numberOfSCTHoles  );
-            muprobe->primaryTrackParticle()->summaryValue(m_nSCTdead, xAOD::numberOfSCTDeadSensors  );
-            muprobe->primaryTrackParticle()->summaryValue(m_nTRT, xAOD::numberOfTRTHits   );
-            muprobe->primaryTrackParticle()->summaryValue(m_nTRTout, xAOD::numberOfTRTOutliers    );
-        }
-	}
-	// case of an ID probe
-	const xAOD::TrackParticle* trkprobe = dynamic_cast<const xAOD::TrackParticle*>(&probe.probeTrack());
-	if (!muprobe && trkprobe){
-	    charge = trkprobe->charge();
-        if (trkprobe->isAvailable<float>("MUON1_topoetcone40")){
-            m_etcone40 =  trkprobe->auxdataConst<float>("MUON1_topoetcone40");
-        }
-        else {
-            m_etcone40 = -1.;
-        }
-        if (trkprobe->isAvailable<float>("MUON1_ptcone40")){
-            m_ptcone40 =  trkprobe->auxdataConst<float>("MUON1_ptcone40");
-        }
-        else {
-            m_ptcone40 = -1.;
-        }
-        m_d0 = trkprobe->d0();
-        m_d0err = sqrt(trkprobe->definingParametersCovMatrix()(0,0));
-        m_z0 = trkprobe->z0();
-//         const xAOD::Vertex* vx = trkprobe->vertex();
-        if (pv){
-            m_z0 = m_z0 - pv->z() + trkprobe->vz();
-        }
-        trkprobe->summaryValue(m_nBL, xAOD::numberOfBLayerHits);
-        trkprobe->summaryValue(m_nPIX, xAOD::numberOfPixelHits);
-        trkprobe->summaryValue(m_nPIXholes, xAOD::numberOfPixelHoles);
-        trkprobe->summaryValue(m_nPIXdead, xAOD::numberOfPixelDeadSensors);
-        trkprobe->summaryValue(m_nSCT, xAOD::numberOfSCTHits );
-        trkprobe->summaryValue(m_nSCTholes, xAOD::numberOfSCTHoles  );
-        trkprobe->summaryValue(m_nSCTdead, xAOD::numberOfSCTDeadSensors  );
-        trkprobe->summaryValue(m_nTRT, xAOD::numberOfTRTHits   );
-        trkprobe->summaryValue(m_nTRTout, xAOD::numberOfTRTOutliers    );
-	}
-    // case of an truth probe: rely on the sign of the pdg ID
-    const xAOD::TruthParticle* truthtrk = dynamic_cast<const xAOD::TruthParticle*>(&probe.probeTrack());
-    if (truthtrk) {
-        if (truthtrk->charge() > 0) charge = 1.0;
-        if (truthtrk->charge() < 0) charge = -1.0;
-    }
-
-    const xAOD::EventInfo* info = 0;
-    ATH_MSG_DEBUG(""<<evtStore());
-    if (evtStore()->retrieve(info).isFailure()){
-        ATH_MSG_FATAL( "Unable to retrieve Event Info" );
-    }
-    static bool isMC = info->eventType(xAOD::EventInfo::IS_SIMULATION);
-
-	m_runNumber = info->runNumber();
-	m_eventNumber = info->eventNumber();
-	m_mu = info->averageInteractionsPerCrossing();
-	m_mcEventWeight = (isMC ? info->mcEventWeight() : 1.00);
-    m_pt = probe.pt() / 1000.;
-    m_eta = probe.eta();
-    m_phi = probe.phi();
-    m_fineEtaPhi = m_fepb.bin(probe.probeTrack().p4());
-    m_detregion = m_epb.symmetricBin(probe.probeTrack().p4());
-    m_q = charge;
-    m_tagPt = probe.tagTrack().pt() / 1000.;
-    m_tagEta = probe.tagTrack().eta();
-    m_tagPhi = probe.tagTrack().phi();
-    m_mll = (probe.tagTrack().p4()+probe.probeTrack().p4()).M();
-    
-    
-}
-void ZmumuMuonTPTreeTool::AddCustomBranches(TTree* tree){
-
-	tree->Branch("runNumber",&m_runNumber);
-	tree->Branch("eventNumber",&m_eventNumber);
-	tree->Branch("mu",&m_mu);
-	tree->Branch("mcEventWeight",&m_mcEventWeight);
-    tree->Branch("pt",&m_pt);
-    tree->Branch("eta",&m_eta);
-    tree->Branch("phi",&m_phi);
-    tree->Branch("d0",&m_d0);
-    tree->Branch("d0err",&m_d0err);
-    tree->Branch("z0",&m_z0);
-    tree->Branch("ptcone40",&m_ptcone40);
-    tree->Branch("etcone40",&m_etcone40);
-    tree->Branch("fineEtaPhi",&m_fineEtaPhi);
-    tree->Branch("detRegion",&m_detregion);
-    tree->Branch("q",&m_q);
-    tree->Branch("tagPt",&m_tagPt);
-    tree->Branch("tagEta",&m_tagEta);
-    tree->Branch("tagPhi",&m_tagPhi);
-    tree->Branch("mll",&m_mll);
-    tree->Branch("PV_n",&m_PV_n);
-
-    tree->Branch("nBL",&m_nBL);
-    tree->Branch("nPIX",&m_nPIX);
-    tree->Branch("nSCT",&m_nSCT);
-    tree->Branch("nPIXdead",&m_nPIXdead);
-    tree->Branch("nSCTdead",&m_nSCTdead);
-    tree->Branch("nSCTholes",&m_nSCTholes);
-    tree->Branch("nPIXholes",&m_nPIXholes);
-    tree->Branch("nTRT",&m_nTRT);
-    tree->Branch("nTRTout",&m_nTRTout);
-
-}
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/Makefile.RootCore b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/Makefile.RootCore
index 9662d437040..e03bf3ccedf 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/Makefile.RootCore
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/Makefile.RootCore
@@ -12,7 +12,7 @@ PACKAGE_OBJFLAGS = -DASGTOOL_STANDALONE -DASGTOOL_NOTEVENT
 PACKAGE_LDFLAGS  = 
 PACKAGE_BINFLAGS = 
 PACKAGE_LIBFLAGS = 
-PACKAGE_DEP      = AsgTools
+PACKAGE_DEP      = AsgTools xAODBase xAODMuon xAODTruth MuonPerformanceHistUtils MuonEfficiencyCorrections MuonSelectorTools TrigMuonMatching TrigDecisionTool ElectronIsolationSelection TrigConfL1Data TrigDecisionInterface TrigConfxAOD GoodRunsLists
 PACKAGE_TRYDEP   = 
 PACKAGE_CLEAN    = 
 PACKAGE_NOGRID   = 
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/requirements b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/requirements
index 46c35675ee3..3813162c20f 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/requirements
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/cmt/requirements
@@ -7,20 +7,25 @@ public
 use  AtlasPolicy                AtlasPolicy-*                   
 use  AsgTools                   AsgTools-*                      Control/AthToolSupport
 use  xAODMuon                   xAODMuon-*                      Event/xAOD
-use  xAODTruth                  xAODTruth-*                     Event/xAOD
 use  xAODBase                   xAODBase-*                      Event/xAOD
 use  MuonPerformanceHistUtils   MuonPerformanceHistUtils-*      PhysicsAnalysis/MuonID/MuonPerformanceAnalysis
 use  MuonEfficiencyCorrections  MuonEfficiencyCorrections-*     PhysicsAnalysis/MuonID/MuonIDAnalysis
 use  MuonSelectorTools          MuonSelectorTools-*             PhysicsAnalysis/MuonID
 use  TrigDecisionTool           TrigDecisionTool-*              Trigger/TrigAnalysis
-use  TrigMuonMatching         TrigMuonMatching-*                Trigger/TrigAnalysis
+use  TrigMuonMatching           TrigMuonMatching-*              Trigger/TrigAnalysis
 use  AtlasROOT                  AtlasROOT-*                     External
-use_ifndef pplist="XAOD_ANALYSIS" pkg="Reconstruction/RecoTools/RecoToolInterfaces" 
+use  GoodRunsLists              GoodRunsLists-*                 DataQuality
+# Put this back in once available
+##  use  IsolationSelection         IsolationSelection-*            PhysicsAnalysis/AnalysisCommon
 
 private
 use  GaudiInterface             GaudiInterface-*                External
 use  xAODEventInfo              xAODEventInfo-*                 Event/xAOD
-use  xAODTracking              xAODTracking-*                 Event/xAOD
+use  xAODEventShape             xAODEventShape-*                Event/xAOD
+use  xAODTracking               xAODTracking-*                  Event/xAOD
+use  xAODJet                    xAODJet-*                       Event/xAOD
+use  xAODTruth                  xAODTruth-*                     Event/xAOD
+use MCTruthClassifier           MCTruthClassifier-*             PhysicsAnalysis
 end_private
 
 public
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/CreateSF.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/CreateSF.py
new file mode 100644
index 00000000000..4b22eaf687a
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/CreateSF.py
@@ -0,0 +1,266 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import Histos
+import Utils
+import ROOT
+import DSConfig
+import Utils
+from Defs import *
+ROOT.gROOT.Macro("rootlogon.C")
+ROOT.gROOT.SetStyle("ATLAS")
+ROOT.gROOT.SetBatch(1)
+from array import array
+from PlotUtils import PlotUtils
+
+hists_final = []
+
+# this creates a 3d binning, with x = fineetaphi, y = pt (constant), z = charge (based on posq and negq histos)
+def build_3d_composite(period, raw_posq, raw_negq, jpsibins_low, jpsibins_up, jpsisys=[], isMC=False):
+
+    bins_for_hist = [abin for abin in jpsibins_low+[jpsibins_up[-1]]]
+    nptbins = len(bins_for_hist)-1
+    ptbins = array('d',bins_for_hist)
+
+    fineetaphibins = []
+    for i in range(1,raw_posq.GetNbinsX()+1):
+        fineetaphibins.append(raw_posq.GetXaxis().GetBinLowEdge(i))
+    fineetaphibins.append(raw_posq.GetXaxis().GetBinUpEdge(raw_posq.GetNbinsX()))
+    fineetaphibins = array('d',fineetaphibins)
+
+    qbins = [-2.,0.,2.]
+    nqbins = len(qbins)-1
+    qbins = array('d',qbins)
+
+    mcNaming = ""
+    if isMC:
+        mcNaming = "_MC"
+    # then create the histo
+    if len(jpsisys)>0:
+        histoname = "%s_sys_3dized_%s%s"%(raw_posq.GetName(),period,mcNaming)
+    else:
+        histoname = "%s_3dized_%s%s"%(raw_posq.GetName(),period,mcNaming)
+    h3d = ROOT.TH3F(histoname,raw_posq.GetTitle(),raw_posq.GetNbinsX(),fineetaphibins,nptbins,ptbins,nqbins,qbins)
+
+    # and fill it!
+    if len(jpsisys)>0:
+        for t in range(1,h3d.GetNbinsX()+1):
+            sys_p = raw_posq.GetBinContent(t)
+            sys_n = raw_negq.GetBinContent(t)
+            for u in range(1,h3d.GetNbinsY()+1):
+                h3d.SetBinContent(t,u,h3d.GetZaxis().FindBin(-1.),ROOT.sqrt(sys_n*sys_n+ROOT.pow(jpsisys[u-1],2)))
+                h3d.SetBinError(t,u,h3d.GetZaxis().FindBin(-1.),ROOT.sqrt(sys_n*sys_n+ROOT.pow(jpsisys[u-1],2)))
+                h3d.SetBinContent(t,u,h3d.GetZaxis().FindBin(1.),ROOT.sqrt(sys_p*sys_p+ROOT.pow(jpsisys[u-1],2)))
+                h3d.SetBinError(t,u,h3d.GetZaxis().FindBin(1.),ROOT.sqrt(sys_p*sys_p+ROOT.pow(jpsisys[u-1],2)))
+
+    else:
+        for t in range(1,h3d.GetNbinsX()+1):
+            val_p = raw_posq.GetBinContent(t)
+            err_p = raw_posq.GetBinError(t)
+            val_n = raw_negq.GetBinContent(t)
+            err_n = raw_negq.GetBinError(t)
+            for u in range(1,h3d.GetNbinsY()+1):
+                h3d.SetBinContent(t,u,h3d.GetZaxis().FindBin(-1.),val_n)
+                h3d.SetBinError(t,u,h3d.GetZaxis().FindBin(-1.),err_n)
+                h3d.SetBinContent(t,u,h3d.GetZaxis().FindBin(1.),val_p)
+                h3d.SetBinError(t,u,h3d.GetZaxis().FindBin(1.),err_p)
+
+    return h3d
+
+
+
+def createPeriod (outfile,period,probe,match,Data,MC):
+
+    ptlow = [0., 4.5, 7., 10., 15.]
+    ptup = [4.5, 7., 10., 15., 1e15]
+    jpsisys = [0.06, 0.015, 0.005, 0.0025, 0.00]
+    
+    # for pre-recommendations, copy negative eta bins of transition region to positive ones (use doPreRecEtaCopy=True):
+    testpos = Histos.TPFinalSysHistos("testpos",probe,match,DetRegions.All,"fineEtaPhi",infiles=[["MC",MC],["Data",Data]],charge="pos",corr = True,doPreRecEtaCopy=False,useAsymEff=True).HistoSets
+    testneg = Histos.TPFinalSysHistos("testneg",probe,match,DetRegions.All,"fineEtaPhi",infiles=[["MC",MC],["Data",Data]],charge="neg",corr = True,doPreRecEtaCopy=False,useAsymEff=True).HistoSets
+
+    # fill data and MC efficiency and SF
+    h_data_eff_p = testpos["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc_eff_p = testpos["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    h_sf_p = testpos["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF]
+
+    data_eff_sys_1D_p = testpos[Systematics.All][0]
+    mc_eff_sys_1D_p = testpos[Systematics.All][1]
+    sf_sys_1D_p = testpos[Systematics.All][2]
+
+    h_data_eff_n = testneg["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc_eff_n = testneg["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    h_sf_n = testneg["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF]
+
+    data_eff_sys_1D_n = testneg[Systematics.All][0]
+    mc_eff_sys_1D_n = testneg[Systematics.All][1]
+    sf_sys_1D_n = testneg[Systematics.All][2]
+
+    # convert TGraphAsymmErrors to TH1 for scale factor files
+    if h_data_eff_p.InheritsFrom("TGraphAsymmErrors"):
+        h_data_eff_p = Utils.ConvertTGraphAsymmErrors(h_data_eff_p)
+        h_mc_eff_p = Utils.ConvertTGraphAsymmErrors(h_mc_eff_p)
+        h_sf_p = Utils.ConvertTGraphAsymmErrors(h_sf_p)
+        data_eff_sys_1D_p = Utils.ConvertTGraphAsymmErrors(data_eff_sys_1D_p)
+        mc_eff_sys_1D_p = Utils.ConvertTGraphAsymmErrors(mc_eff_sys_1D_p)
+        sf_sys_1D_p = Utils.ConvertTGraphAsymmErrors(sf_sys_1D_p)
+    if h_data_eff_n.InheritsFrom("TGraphAsymmErrors"):
+        h_data_eff_n = Utils.ConvertTGraphAsymmErrors(h_data_eff_n)
+        h_mc_eff_n = Utils.ConvertTGraphAsymmErrors(h_mc_eff_n)
+        h_sf_n = Utils.ConvertTGraphAsymmErrors(h_sf_n)
+        data_eff_sys_1D_n = Utils.ConvertTGraphAsymmErrors(data_eff_sys_1D_n)
+        mc_eff_sys_1D_n = Utils.ConvertTGraphAsymmErrors(mc_eff_sys_1D_n)
+        sf_sys_1D_n = Utils.ConvertTGraphAsymmErrors(sf_sys_1D_n)
+
+
+    data_eff_3d = build_3d_composite(period, h_data_eff_p, h_data_eff_n, ptlow, ptup)
+    mc_eff_3d = build_3d_composite(period, h_mc_eff_p, h_mc_eff_n, ptlow, ptup, isMC=True)
+    sf_3d = build_3d_composite(period, h_sf_p, h_sf_n, ptlow, ptup)
+    data_eff_sys_3d = build_3d_composite(period, data_eff_sys_1D_p, data_eff_sys_1D_n, ptlow, ptup, jpsisys)
+    mc_eff_sys_3d = build_3d_composite(period, mc_eff_sys_1D_p, mc_eff_sys_1D_n, ptlow, ptup, jpsisys, isMC=True)
+    sf_sys_3d = build_3d_composite(period, sf_sys_1D_p, sf_sys_1D_n, ptlow, ptup, jpsisys)
+
+    # the systematics tool provides relative errors, so multiply
+    data_eff_sys_3d.Multiply(data_eff_3d)
+    mc_eff_sys_3d.Multiply(mc_eff_3d)
+    sf_sys_3d.Multiply(sf_3d)
+
+    # assign axis names that the SF tool knows how to interpret
+    data_eff_3d.GetXaxis().SetTitle("fine etaphi bin")
+    data_eff_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    data_eff_3d.GetZaxis().SetTitle("charge")
+
+    mc_eff_3d.GetXaxis().SetTitle("fine etaphi bin")
+    mc_eff_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    mc_eff_3d.GetZaxis().SetTitle("charge")
+
+    sf_3d.GetXaxis().SetTitle("fine etaphi bin")
+    sf_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    sf_3d.GetZaxis().SetTitle("charge")
+
+    data_eff_sys_3d.GetXaxis().SetTitle("fine etaphi bin")
+    data_eff_sys_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    data_eff_sys_3d.GetZaxis().SetTitle("charge")
+
+    mc_eff_sys_3d.GetXaxis().SetTitle("fine etaphi bin")
+    mc_eff_sys_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    mc_eff_sys_3d.GetZaxis().SetTitle("charge")
+
+    sf_sys_3d.GetXaxis().SetTitle("fine etaphi bin")
+    sf_sys_3d.GetYaxis().SetTitle("p_{T} [GeV]")
+    sf_sys_3d.GetZaxis().SetTitle("charge")
+
+    outfile.WriteTObject(data_eff_3d,"Eff_%s"%(period))
+    outfile.WriteTObject(mc_eff_3d,"MC_Eff_%s"%(period))
+    outfile.WriteTObject(sf_3d,"SF_%s"%(period))
+    outfile.WriteTObject(data_eff_sys_3d,"Eff_sys_%s"%(period))
+    outfile.WriteTObject(mc_eff_sys_3d,"MC_Eff_sys_%s"%(period))
+    outfile.WriteTObject(sf_sys_3d,"SF_sys_%s"%(period))
+
+def createCTPeriod (outfile,period,probe,Data,MC):
+
+    test = Histos.TPFinalSysHistos("test",probe,Matches.Calo,DetRegions.All,"CaloTag2D",infiles=[["MC",MC],["Data",Data]],charge=None,corr = True).HistoSets
+    
+    # fill data and MC efficiency and SF
+    h_data_eff = test["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc_eff = test["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    h_sf = test["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF]
+
+    data_eff_sys_2D = test[Systematics.All][0]
+    mc_eff_sys_2D = test[Systematics.All][1]
+    sf_sys_2D = test[Systematics.All][2]
+
+    # do not need to convert TGraphAsymmErrors to TH1 for scale factor files since CaloTag2D is 2D and thus not using TGraphAsymmErrors
+
+    # the systematics tool provides relative errors, so multiply
+    data_eff_sys_2D.Multiply(h_data_eff)
+    mc_eff_sys_2D.Multiply(h_mc_eff)
+    sf_sys_2D.Multiply(h_sf)
+
+    # assign axis names that the SF tool knows how to interpret
+    h_data_eff.GetXaxis().SetTitle("#eta")
+    h_data_eff.GetYaxis().SetTitle("p_{T} [GeV]")
+
+    h_mc_eff.GetXaxis().SetTitle("#eta")
+    h_mc_eff.GetYaxis().SetTitle("p_{T} [GeV]")
+
+    h_sf.GetXaxis().SetTitle("#eta")
+    h_sf.GetYaxis().SetTitle("p_{T} [GeV]")
+    
+    data_eff_sys_2D.GetXaxis().SetTitle("#eta")
+    data_eff_sys_2D.GetYaxis().SetTitle("p_{T} [GeV]")
+    mc_eff_sys_2D.GetXaxis().SetTitle("#eta")
+    mc_eff_sys_2D.GetYaxis().SetTitle("p_{T} [GeV]")
+    sf_sys_2D.GetXaxis().SetTitle("#eta")
+    sf_sys_2D.GetYaxis().SetTitle("p_{T} [GeV]")
+    
+    outfile.WriteTObject(h_data_eff,"Eff_%s"%(period))
+    outfile.WriteTObject(h_mc_eff,"MC_Eff_%s"%(period))
+    outfile.WriteTObject(h_sf,"SF_%s"%(period))
+    outfile.WriteTObject(data_eff_sys_2D,"Eff_sys_%s"%(period))
+    outfile.WriteTObject(mc_eff_sys_2D,"MC_Eff_sys_%s"%(period))
+    outfile.WriteTObject(sf_sys_2D,"SF_sys_%s"%(period))
+
+    
+
+if __name__ == "__main__":
+
+    # --------------------------
+    # In principle all you have to setup is defined here
+    # --------------------------
+    # MC input file
+    InputZmumu = DSConfig.Zmumu_mc15
+
+    TypesToRun = [
+                ["Medium",Probes.Calo, Matches.Medium],
+                ["Tight",Probes.Calo, Matches.Tight],
+                ["Loose",Probes.Calo, Matches.LooseNoCalo],
+                ["Calo",Probes.MStoMu, Matches.Calo],
+                 ]
+
+    periods = [
+                ["All",20322.,DSConfig.Data_periodB]
+              ]
+
+    # name of the overall period the SF file is about
+    filePeriod = "2015"
+    ## --------------------------
+
+
+    for Type in TypesToRun:
+
+        muonTypeName = Type[0]
+        Probe = Type[1]
+        Match = Type[2]
+        if Match == Matches.Calo:
+            ofile = ROOT.TFile("CaloTag_%s_SF.root"%(filePeriod),"RECREATE")
+        else: 
+            ofile = ROOT.TFile("MuonsChain_%s_%s_SF.root"%(muonTypeName,filePeriod),"RECREATE")
+        
+        ofile.cd()
+
+        # Create luminosity tree
+        LumiDataTree = ROOT.TTree('LumiData','Lumi Data')
+
+        # Create branches in the tree
+        period = ROOT.std.string("init")
+        LumiDataTree.Branch("Period",period)
+        lumi = array( 'f', [0] * len(periods) )
+        LumiDataTree.Branch( 'IntLumi', lumi, 'IntLumi/F' )
+
+        for p in periods:
+            period = ROOT.std.string(p[0])
+            lumi[0] = p[1]
+            LumiDataTree.SetBranchAddress("Period",period)
+            LumiDataTree.Fill()
+
+            DataInput = p[2]
+            # get the actual histograms per perdiod/runNumber
+            if Match == Matches.Calo:
+                createCTPeriod(outfile=ofile,period=period,probe=Probe,Data=DataInput,MC=InputZmumu)
+            else:
+                createPeriod(outfile=ofile,period=period,probe=Probe,match=Match,Data=DataInput,MC=InputZmumu)
+            
+
+        ofile.WriteTObject(LumiDataTree)
+        ofile.Close()
+
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/DSConfig.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/DSConfig.py
new file mode 100644
index 00000000000..e7ab7fdb0c4
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/DSConfig.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+
+import ROOT
+# utility class for DS meta info
+class DSconfig:
+    def __init__(self,lumi=20300.,XS=1.,nEvents=-1,colour=None,label="",filepath=""):
+        self.Lumi = lumi
+        self.Colour=colour
+        self.Label = label
+        self.Filepath = filepath
+        self.XS = XS
+        self.nEvents = nEvents
+
+
+Data_periodB = DSconfig(lumi=3900.,XS=1.,nEvents=-1,colour=ROOT.kBlack,label="Data",filepath="/ptmp/mpp/niko/MCP/GridOutput/150520/data12_8TeV.physics_Muons.periodB.root")
+
+
+Data_15_firstWeek = DSconfig(lumi=0.220,XS=1.,nEvents=-1,colour=ROOT.kBlack,label="Data 2015",filepath="/ptmp/mpp/goblirsc/MCP2014/GridOut/2015-06-09-Data15_v1b/Data15.root")
+
+
+# mc15_13TeV.361107.PowhegPythia8EvtGen_AZNLOCTEQ6L1_Zmumu.e3601_r6633_r6264
+Zmumu_mc15 = DSconfig(Data_periodB.Lumi,XS=1100.,nEvents=3294358,colour=ROOT.kRed,label="Z#rightarrow#mu#mu MC15",filepath="/afs/ipp-garching.mpg.de/home/g/goblirsc/analysis/TP_Rearrangement/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonPerformanceAlgs/share/muontp.root")
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Defs.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Defs.py
new file mode 100644
index 00000000000..6a26657c3ea
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Defs.py
@@ -0,0 +1,79 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+# definitions for the offline Zmumu analysis
+import ROOT, math
+import HistoDefs
+
+class Analysis:
+    Z_Reco = "ZmumuTPReco"
+    Z_Isol = "ZmumuTPIsol"
+    Z_Trig = "ZmumuTPTrig"
+    JP_Reco = "JPsiTPReco"
+    JP_Isol = "JPsiTPIsol"
+    JP_Trig = "JPsiTPTrig"
+    
+    
+class ChargeProducts:
+    OC="OC"
+    SC="SC"
+    OC_AntiIso="OCAntiIso"
+    SC_AntiIso="SCAntiIso"
+
+class Probes:
+    ID = "IDProbes"
+    Calo = "CaloProbes"
+    MStoID = "MSProbes_ID"
+    MStoMu = "MSProbes_Muon"
+    TruthToID = "TruthProbes_ID"
+    TruthToMu = "TruthProbes_Muon"
+
+class DetRegions:
+    All="All"
+    noCrack="noCrack"
+    Crack="Crack"
+    Barrel="Barrel"
+    Transition="Transition"
+    Endcap="Endcap"
+    CSC="CSC"
+
+class Matches:
+    Calo ="CaloTaggedMuons"
+    CB ="CombinedMuons"
+    Loose ="LooseMuons"
+    LooseNoCalo ="LooseMuons_noCaloTag"
+    Medium ="MediumMuons"
+    Tight ="TightMuons"
+    ID ="IDTracks"
+    ID_noMCP ="IDTracks_noMCP"
+
+class PlotKinds:
+    Probes="Probes"
+    Matches="Matches"
+    Efficiency="Efficiency"
+
+class HistoKinds:
+    Efficiency="Efficiency"
+    DataEfficiency="Data Efficiency"
+    MCEfficiency="MC Efficiency"
+    TruthEfficiency="Truth Efficiency"
+    SF="ScaleFactor"
+    TruthSF="Truth ScaleFactor"
+    MCTruthSF="MC/Truth ScaleFactor"
+
+class Systematics:
+    dR="dR"
+    truth="Truth"
+    BG="BG"
+    Det="DetectorRun1"
+    All="Total"
+
+ExtraCuts = {
+    DetRegions.All: "",
+    DetRegions.Crack: "abs(eta) < 0.1",
+    DetRegions.noCrack: "abs(eta) > 0.1",
+    DetRegions.Barrel: "abs(eta) > 0.1 && abs(eta) < 1.1",
+    DetRegions.Transition: "abs(eta) > 1.1 && abs(eta) < 1.3",
+    DetRegions.Endcap: "abs(eta) > 1.3 && abs(eta) < 2.0",
+    DetRegions.CSC: "abs(eta) > 2.0 && abs(eta) < 2.5",
+}
+
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/EffPlots.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/EffPlots.py
new file mode 100644
index 00000000000..edd5f8f1eab
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/EffPlots.py
@@ -0,0 +1,818 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import Histos
+import ROOT
+import DSConfig
+import Utils
+from Defs import *
+from PlotUtils import PlotUtils
+ROOT.gROOT.Macro("rootlogon.C")
+ROOT.gROOT.SetStyle("ATLAS")
+ROOT.gROOT.SetBatch(1)
+import sys
+
+histos = []
+eff_axis_ranges = []
+sf_axis_ranges = []
+
+def draw2D (histo, var, probe, match, region, conf_Data, histoKind, corr, LumiScale, analysis=Analysis.Z_Reco):
+
+    pu = PlotUtils()
+    pu.Size = 0.06*(1-pu.VerticalCanvasSplit)
+    pu.Lumi = conf_Data.Lumi/1000.
+
+
+    can = ROOT.TCanvas("Eff_%s_%s_%s_%s_%s"%(match,var,probe,region,histoKind.replace(" ","")),"Efficiencies",600,600)
+    can.cd()
+
+    histos.append(can)
+    histo.GetZaxis().SetTitle(histoKind)
+
+    if HistoKinds.SF in histoKind:
+        ROOT.gStyle.SetPalette(55)
+        histo.GetZaxis().SetRangeUser(0.85,1.15)
+    else:
+        ROOT.gStyle.SetPalette(54)
+        histo.GetZaxis().SetRangeUser(0.80,1.01)
+
+    histo.Draw("colz l")
+    #histo.Draw("same TEXT")
+
+    can.SetTopMargin(0.15)
+    can.SetRightMargin(0.2)
+    can.SetLeftMargin(0.12)
+    histo.GetYaxis().SetTitleOffset(0.7*histo.GetYaxis().GetTitleOffset())
+    histo.GetZaxis().SetTitleOffset(1.5*histo.GetZaxis().GetTitleOffset())
+    # need to find a better way to do this:
+    histo.GetZaxis().SetLabelSize(histo.GetYaxis().GetLabelSize())
+    histo.GetZaxis().SetTitleSize(histo.GetYaxis().GetTitleSize())
+
+    pu.DrawAtlas(can.GetLeftMargin(),0.92)
+    pu.DrawLumiSqrtS(can.GetLeftMargin(),0.87)
+    pu.DrawTarget(match,1-can.GetRightMargin(),0.92,31)
+    pu.DrawSource(probe,1-can.GetRightMargin(),0.87,31)
+
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        pu.DrawTLatex(can.GetLeftMargin()+0.02,can.GetBottomMargin()+0.02,"ID eff. #font[62]{not} applied")
+
+    corrstr = ""
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        corrstr = "_noIDCorr"
+    nEventsFileName = ""
+    nEventsStr = ""
+    if LumiScale != -1:
+        nEventsFileName = "_%03d"%nEventsFileNameInt
+        nEventsStr = ("_%.4fipb"%LumiScale).replace(".","pt")
+        
+    can.SaveAs ("Plots/Eff_%s_%s_%s_%s_%s%s%s.pdf"%(match,var,probe,region,histoKind.replace(" ",""),corrstr,nEventsFileName))
+    
+    if HistoKinds.SF in histoKind:
+        pu.DrawTLatex(0.5,0.96,"%s SF%s vs %s for %s probes in %s %s"%(match,corrstr,var,probe,region,nEventsStr),pu.Size*(1-pu.VerticalCanvasSplit),52,21)
+    else:
+        pu.DrawTLatex(0.5,0.96,"%s Effi%s vs %s for %s probes in %s %s"%(match,corrstr,var,probe,region,nEventsStr),pu.Size*(1-pu.VerticalCanvasSplit),52,21)
+
+    can.SaveAs("Plots/AllEffPlots.pdf")
+
+def doEffPlots1D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, LumiScale, corr = True, syshisto = None, analysis=Analysis.Z_Reco):
+
+    # check if 2 sets of histos are available -> compare them
+    if len(hists_final)>1:
+        h_ref = hists_final[1].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+        ratio2 = hists_final[1].Histos[HistoKinds.SF][HistoKinds.SF]
+        if match in Matches.ID:
+            h_ref_mc = hists_final[1].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    else:
+        h_ref = None
+
+    h_data = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    h_truth = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.TruthEfficiency]
+    ratio = hists_final[0].Histos[HistoKinds.SF][HistoKinds.SF]
+    ratiotruth = hists_final[0].Histos[HistoKinds.SF][HistoKinds.TruthSF]
+        
+    ######
+    # used for styling histo (when TGraphAsymmErrors are used)
+    h_styling = HistoDefs.initHisto(var)[0].Clone("stylingHisto")
+    # from print in Histos.py:
+    h_styling.GetXaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetXaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetXaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetXaxis().SetLabelOffset(0.00499999988824)
+    h_styling.GetYaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetYaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetYaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetYaxis().SetLabelOffset(0.00499999988824)    
+
+    h_styling_ratio = h_styling.Clone("stylingHistoRatio")
+    h_styling_ratio.GetYaxis().SetTitle("Data/MC")
+    
+    h_styling.GetYaxis().SetTitle("Efficiency")
+    ######
+
+    ##############
+    if var == "DetRegions":
+    # for week-1 data (DetRegions plot)
+        h_styling.SetLabelOffset(0.025, "X")
+        h_styling.GetXaxis().SetRangeUser(1,11)
+        for i in range(1,Utils.GetNbins(h_styling)-1):
+            h_styling.GetXaxis().SetBinLabel(i,"")
+        h_styling.GetXaxis().SetTitle("")
+
+        h_styling_ratio.SetLabelOffset(0.025, "X")
+        h_styling_ratio.GetXaxis().SetRangeUser(1,11)
+        h_styling_ratio.GetXaxis().SetTitleOffset(h_styling_ratio.GetXaxis().GetTitleOffset()*1.1)
+    ##############
+
+    pu = PlotUtils()
+    pu.Size = 0.06
+    pu.Lumi = conf_Data.Lumi/1000.
+    pu.SqrtS = 13
+
+    # for evolution plots
+    nEventsStr = ""
+    if LumiScale != -1:
+        nEventsStr = ("_%.3fipb"%LumiScale).replace(".","pt")
+    if var == "DetRegions":
+        can,p1,p2 = pu.Prepare2PadCanvas("Eff_%s_%s_%s_%s%s"%(match,var,probe,region,nEventsStr),width=1000, height=800)
+    else:
+        can,p1,p2 = pu.Prepare2PadCanvas("Eff_%s_%s_%s_%s%s"%(match,var,probe,region,nEventsStr))
+    
+    can.cd()
+    p1.Draw()
+    histos.append(p1)
+    histos.append(p2)
+    histos.append(can)
+    p1.cd()
+
+
+    # plotting style:
+    h_data.SetLineColor(ROOT.kBlack)
+    h_data.SetMarkerColor(ROOT.kBlack)
+    h_data.SetMarkerStyle(ROOT.kFullDotLarge)
+    if h_ref != None:
+        h_ref.SetLineColor(ROOT.kOrange-2)
+        h_ref.SetMarkerColor(ROOT.kOrange-2)
+        h_ref.SetMarkerStyle(ROOT.kFullSquare)
+        h_ref.SetTitle(hists_final[1].Name)
+        # for comparing Matches.ID to Matches.ID_noMCP
+        if match in Matches.ID:
+            h_ref.SetTitle(Matches.ID_noMCP)
+            h_ref_mc.SetTitle("%s MC"%(Matches.ID_noMCP))
+
+    h_mc.SetLineColor(ROOT.kRed-7)
+    h_mc.SetMarkerColor(ROOT.kRed-7)
+    h_mc.SetMarkerStyle(ROOT.kOpenCircle)
+    h_mc.SetTitle(conf_Zmumu.Label)
+
+    h_truth.SetLineColor(ROOT.kBlue-7)
+    h_truth.SetMarkerColor(ROOT.kBlue-7)
+    h_truth.SetMarkerStyle(ROOT.kOpenSquare)
+    h_truth.SetTitle("Truth MC")
+    h_data.SetTitle(conf_Data.Label)
+
+    ratio.SetLineColor(ROOT.kGreen-8)
+    ratio.SetFillColor(ratio.GetLineColor())
+    ratio.SetMarkerColor(ROOT.kBlack)
+    ratio.SetMarkerStyle(ROOT.kFullDotLarge)
+
+    if h_ref != None:
+        ratio2.SetLineColor(h_ref.GetLineColor())
+        ratio2.SetMarkerColor(h_ref.GetMarkerColor())
+        ratio2.SetMarkerStyle(ROOT.kOpenSquare)
+    else:
+        ratio2 = None
+
+    ratiotruth.SetLineColor(h_truth.GetLineColor())
+    ratiotruth.SetMarkerColor(h_truth.GetMarkerColor())
+    ratiotruth.SetMarkerStyle(ROOT.kOpenSquare)
+    ratiotruth.SetTitle("Truth MC")
+
+    ######
+    # labels and axis ranges
+    pu.AdaptLabelsTopPad([h_styling, h_truth, h_data, h_mc])
+    # for creating evolution plots, SetFancyAxisRanges_Eff has to be fixed
+    #if False:
+    if LumiScale != -1:
+        if len(eff_axis_ranges)<1:
+            eff_axis_ranges.append(pu.SetFancyAxisRanges_Eff([h_data,h_mc], maxmin = 1.05))
+            pu.SetFancyAxisRanges_Eff([h_styling], maxmin = eff_axis_ranges[0][0][0], fixRange=True)
+            #print eff_axis_ranges
+        else:
+            eff_axis_ranges.append(pu.SetFancyAxisRanges_Eff([h_data,h_mc], maxmin = eff_axis_ranges[0][0][0], fixRange=True))
+            pu.SetFancyAxisRanges_Eff([h_styling], maxmin = eff_axis_ranges[0][0][0], fixRange=True)
+            #print eff_axis_ranges
+    else:
+        eff_axis_ranges.append(pu.SetFancyAxisRanges_Eff([h_data,h_mc], maxmin = 1.05))
+        pu.SetFancyAxisRanges_Eff([h_styling], maxmin = eff_axis_ranges[0][0][0], fixRange=True)
+        del eff_axis_ranges[:]
+    ######
+        
+    h_styling.Draw("AXIS")
+    if h_mc.InheritsFrom("TGraphAsymmErrors"):
+        h_mc.Draw("sameP")
+    else:
+        h_mc.Draw("same")
+
+    if h_ref == None:
+        #h_truth.Draw("same")
+        h_truth.GetYaxis().SetTitle("Efficiency")
+    if h_ref != None:
+        if h_mc.InheritsFrom("TGraphAsymmErrors"):
+            h_ref.Draw("sameP")
+        else:
+            h_ref.Draw("same")
+        # for comparing Matches.ID to Matches.ID_noMCP
+        if match in Matches.ID:
+            h_ref_mc.Draw("same")
+    if h_mc.InheritsFrom("TGraphAsymmErrors"):
+        h_data.Draw("sameP")
+    else:
+        h_data.Draw("same")
+        
+    pu.DrawAtlas(0.19,0.4)
+    
+    if LumiScale != -1:
+        lumi=LumiScale*InputData.Lumi
+        pu.DrawLumiSqrtSEvolution(0.19,0.32,lumi=lumi)
+    else:
+        pu.DrawLumiSqrtS(0.19,0.32)
+    if h_ref != None:
+        # for comparing Matches.ID to Matches.ID_noMCP
+        if match in Matches.ID:
+            pu.DrawLegend([(h_data,"PL"), (h_ref,"PL"), (h_mc,"PL"), (h_ref_mc,"PL")],0.69,0.08,0.89,0.33)
+        else:
+            pu.DrawLegend([(h_data,"PL"), (h_ref,"PL"), (h_mc,"PL")],0.69,0.08,0.89,0.33)
+    else:
+        #pu.DrawLegend([(h_data,"PL"), (h_mc,"PL"), (h_truth,"PL")],0.69,0.08,0.89,0.33)
+        pu.DrawLegend([(h_data,"PL"), (h_mc,"PL")],0.55,0.32,1-ROOT.gPad.GetRightMargin(),0.47)
+    
+    #pu.DrawSource(probe,0.69,0.36)
+    pu.DrawTarget(match,0.19,0.24)
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        pu.DrawTLatex(0.19,0.16,"ID eff. #font[62]{not} applied")
+    
+    
+    p2.cd()
+    p2.SetGridy()
+    
+    ######
+    # labels and axis ranges
+    pu.AdaptLabelsBottomPad([h_styling_ratio,ratiotruth,ratio])
+    if syshisto != None:
+        ratioWithTotalSys = ratio.Clone("%s_TotalSys"%(ratio.GetName()))
+        # put the following into SetFancyAxisRanges_SF in order to consider the systematic bands
+        ratioWithTotalSysAxis = ratio.Clone("%s_TotalSysForFancyAxisRanges"%(ratio.GetName()))
+        if not ratio.InheritsFrom("TGraphAsymmErrors"):
+            ratioWithTotalSys.SetDirectory(0)
+            ratioWithTotalSysAxis.SetDirectory(0)
+        nbins = Utils.GetNbins(ratioWithTotalSys)
+        for i in range (0, nbins):
+            if ratio.InheritsFrom("TGraphAsymmErrors"):
+                ratioWithTotalSys.SetPointEYhigh(i,ROOT.sqrt(ratioWithTotalSys.GetErrorYhigh(i)**2.+(ratioWithTotalSys.GetY()[i]*syshisto.GetY()[i])**2.))
+                ratioWithTotalSys.SetPointEYlow(i,ROOT.sqrt(ratioWithTotalSys.GetErrorYlow(i)**2.+(ratioWithTotalSys.GetY()[i]*syshisto.GetY()[i])**2.))
+                #Currently not used in SetFancyAxisRanges_SF
+                ratioWithTotalSysAxis.SetPoint(i,ratioWithTotalSysAxis.GetX()[i],ratio.GetY()[i]+ratioWithTotalSys.GetErrorYlow(i))
+            else:
+                ratioWithTotalSys.SetBinError(i,ROOT.sqrt(ratioWithTotalSys.GetBinError(i)*ratioWithTotalSys.GetBinError(i)+ratioWithTotalSys.GetBinContent(i)*syshisto.GetBinContent(i)*ratioWithTotalSys.GetBinContent(i)*syshisto.GetBinContent(i)))
+                #Currently not used in SetFancyAxisRanges_SF
+                ratioWithTotalSysAxis.SetBinContent(i,ratio.GetBinContent(i)+ratioWithTotalSys.GetBinError(i))
+    # for creating evolution plots, SetFancyAxisRanges_SF has to be fixed
+    #if False:
+    if LumiScale != -1:
+        if len(sf_axis_ranges)<1:
+            if syshisto != None:
+                sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio,ratioWithTotalSys,ratioWithTotalSysAxis],minmax = 0.8, maxmin = 1.2))
+                pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+            else:
+                sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio],minmax = 0.8, maxmin = 1.2))
+                pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+            #print sf_axis_ranges
+        else:
+            if syshisto != None:
+                sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio,ratioWithTotalSys,ratioWithTotalSysAxis],minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True))
+                pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+            else:
+                sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio],minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True))
+                pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+            #print sf_axis_ranges
+    else:
+        if syshisto != None:
+            sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio,ratioWithTotalSys],minmax = 0.8, maxmin = 1.2))
+            pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+        else:
+            sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio],minmax = 0.8, maxmin = 1.2))
+            pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+        #print sf_axis_ranges
+        del sf_axis_ranges[:]
+    ######
+
+    h_styling_ratio.Draw("AXIS")
+    if syshisto != None:
+        ratioWithTotalSys.SetFillColor(ROOT.kOrange-3)
+        ratioWithTotalSys.SetLineColor(ROOT.kOrange-3)
+        if h_mc.InheritsFrom("TGraphAsymmErrors"):
+            ratioWithTotalSys.Draw("same2")
+            ratio.Draw("same2")
+        else:
+            ratioWithTotalSys.Draw("E2")
+            ratio.Draw("E2 same")
+    else:
+        if h_mc.InheritsFrom("TGraphAsymmErrors"):
+            ratio.Draw("same2")
+        else:
+            ratio.Draw("E2 same")
+
+    if h_ref == None:
+        #ratiotruth.Draw("same")
+        pass
+    if ratio2 != None:
+        ratio2.Draw("same")
+    if h_mc.InheritsFrom("TGraphAsymmErrors"):
+        ratio.Draw("sameP")
+    else:
+        ratio.Draw("same")
+
+        
+    ROOT.gPad.RedrawAxis()
+    corrstr = ""
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        corrstr = "_noIDCorr"
+    nEventsFileName = ""
+    nEventsStr = ""
+    if LumiScale != -1:
+        nEventsFileName = "_%04d"%nEventsFileNameInt
+        nEventsStr = ("_%.3fipb"%LumiScale).replace(".","pt")
+        p1.cd()
+        #pu.DrawTLatex(1-can.GetRightMargin(),0.94,"%.0f Zs"%(nMax),0.04,52,31)
+        can.cd()
+        can.Print("Plots/test.gif+10")
+
+    can.SaveAs ("Plots/Eff_%s_%s_%s_%s%s%s.pdf"%(match,var,probe,region,corrstr,nEventsFileName))
+    p1.cd()
+
+    pu.DrawTLatex(0.5,0.94,"%s Effi%s vs %s for %s probes in %s %s"%(match,corrstr,var,probe,region,nEventsStr),0.04,52,22)
+
+    can.SaveAs("Plots/AllEffPlots.pdf")
+
+
+def doSFValidation1D (hists_final, var, probe, match, region, conf_Data, corr = True, syshisto = None, analysis=Analysis.Z_Reco):
+
+
+    # check if 2 sets of histos are available -> compare them
+    if len(hists_final)<2:
+        return
+    
+    h_mc_SF = hists_final[1].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    ratio_SF = hists_final[1].Histos[HistoKinds.SF][HistoKinds.SF]
+
+    pu = PlotUtils()
+    pu.Size = 0.06
+    pu.Lumi = conf_Data.Lumi/1000.
+
+    can,p1,p2 = pu.Prepare2PadCanvas("SF_Valid_%s_%s_%s_%s"%(match,var,probe,region))
+    can.cd()
+
+    p1.Draw()
+
+    histos.append(p1)
+    histos.append(p2)
+    histos.append(can)
+    p1.cd()
+    
+    
+    # used for styling histo when TGraphAsymmErrors are used
+    h_styling = HistoDefs.initHisto(var)[0].Clone("stylingHisto")
+    # from print in Histos.py:
+    h_styling.GetXaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetXaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetXaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetXaxis().SetLabelOffset(0.00499999988824)
+    h_styling.GetYaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetYaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetYaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetYaxis().SetLabelOffset(0.00499999988824)
+    
+    h_styling_ratio = h_styling.Clone("stylingHisto")
+    
+    h_styling.GetYaxis().SetTitle("Efficiency")
+
+    h_data = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    ratio = hists_final[0].Histos[HistoKinds.SF][HistoKinds.SF]
+
+    #h_mc.SetFillColor(ROOT.kRed-7)
+    h_data.SetLineColor(ROOT.kBlack)
+    h_data.SetMarkerColor(ROOT.kBlack)
+    h_data.SetMarkerStyle(ROOT.kFullDotLarge)
+
+    h_mc_SF.SetFillColor(ROOT.kBlue-7)
+    h_mc_SF.SetMarkerColor(ROOT.kBlue-7)
+    h_mc_SF.SetLineColor(ROOT.kBlue-7)
+    h_mc_SF.SetMarkerSize(1.25 * h_mc_SF.GetMarkerSize())
+    h_mc_SF.SetMarkerStyle(ROOT.kOpenSquare)
+    h_mc_SF.SetTitle("MC after SF")
+
+    #h_mc.SetFillColor(ROOT.kRed-7)
+    h_mc.SetLineColor(ROOT.kRed-7)
+    h_mc.SetMarkerColor(ROOT.kRed-7)
+    h_mc.SetMarkerStyle(ROOT.kOpenCircle)
+    h_mc.SetTitle("MC before SF")
+
+    h_data.SetTitle(conf_Data.Label)
+
+    ratio.SetLineColor(h_mc.GetLineColor())
+    ratio.SetMarkerColor(h_mc.GetMarkerColor())
+    ratio.SetMarkerStyle(h_mc.GetMarkerStyle())
+    ratio.SetTitle("MC before SF")
+
+    ratio_SF.SetLineColor(h_mc_SF.GetLineColor())
+    ratio_SF.SetMarkerSize(1.25 * ratio_SF.GetMarkerSize())
+    ratio_SF.SetMarkerColor(h_mc_SF.GetMarkerColor())
+    ratio_SF.SetMarkerStyle(h_mc_SF.GetMarkerStyle())
+    ratio_SF.SetTitle("MC after SF")
+
+    pu.AdaptLabelsTopPad([h_styling,h_data,h_mc,h_mc_SF])
+    eff_axis_ranges.append(pu.SetFancyAxisRanges_Eff([h_data,h_mc,h_mc_SF], maxmin = 1.05))
+    pu.SetFancyAxisRanges_Eff([h_styling], maxmin = eff_axis_ranges[0][0][0], fixRange=True)
+    del eff_axis_ranges[:]
+    
+    h_styling.Draw("AXIS")
+    if h_data.InheritsFrom("TGraphAsymmErrors"):
+        h_mc.Draw("sameP")
+        h_mc_SF.Draw("sameP")
+        h_data.Draw("sameP")
+    else:
+        h_mc.Draw("same")
+        h_mc_SF.Draw("same")
+        h_data.Draw("same")
+
+    pu.DrawAtlas(0.19,0.4)
+    pu.DrawLumiSqrtS(0.19,0.32)
+    pu.DrawLegend([(h_data,"PL"), (h_mc,"PL"), (h_mc_SF,"PL")],0.69,0.08,0.89,0.33)
+    
+    pu.DrawSource(probe,0.69,0.36)
+    pu.DrawTarget(match,0.19,0.24)
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        pu.DrawTLatex(0.19,0.16,"ID eff. #font[62]{not} applied")
+    p2.cd()
+
+    p2.SetGridy()
+
+    pu.AdaptLabelsBottomPad([h_styling_ratio,ratio_SF,ratio])
+    h_styling_ratio.GetYaxis().SetTitle("Data/MC")
+    
+    sf_axis_ranges.append(pu.SetFancyAxisRanges_SF([ratio_SF,ratio],minmax = 0.9, maxmin = 1.1))
+    pu.SetFancyAxisRanges_SF([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+    del sf_axis_ranges[:]
+
+
+    if syshisto != None:
+        ratioWithTotalSys = ratio.Clone("%s_TotalSys"%(ratio.GetName()))
+        if not ratio.InheritsFrom("TGraphAsymmErrors"):
+            ratioWithTotalSys.SetDirectory(0)
+            nbins = ratioWithTotalSys.GetNbinsX()+1
+            for i in range (1, nbins):
+                ratioWithTotalSys.SetBinError(i,ROOT.sqrt(ratioWithTotalSys.GetBinError(i)*ratioWithTotalSys.GetBinError(i)+ratioWithTotalSys.GetBinContent(i)*syshisto.GetBinContent(i)*ratioWithTotalSys.GetBinContent(i)*syshisto.GetBinContent(i)))
+        ratioWithTotalSys.SetFillColor(ROOT.kOrange-3)
+        ratioWithTotalSys.SetLineColor(ROOT.kOrange-3)
+        ratio.SetFillColor(ROOT.kGreen-8)
+        ratio.SetLineColor(ROOT.kGreen-8)
+        ratio.SetMarkerColor(ROOT.kBlack)
+        ratio.SetMarkerStyle(ROOT.kFullDotLarge)
+        h_styling_ratio.Draw("AXIS")
+        if ratio.InheritsFrom("TGraphAsymmErrors"):
+            ratioWithTotalSys.Draw("same2")
+            ratio.Draw("same2")
+        else:
+            ratioWithTotalSys.Draw("E2 same")
+            ratio.Draw("E2 same")
+    else:
+        h_styling_ratio.Draw("AXIS")
+        if ratio.InheritsFrom("TGraphAsymmErrors"):
+            ratio.Draw("sameP")
+        else:
+            ratio.Draw("same")
+
+    if ratio.InheritsFrom("TGraphAsymmErrors"):
+        ratio_SF.Draw("sameP")
+    else:
+        ratio_SF.Draw("same")
+    ROOT.gPad.RedrawAxis()
+    chi2_prev = 0.
+    chi2_now = 0.
+    for a in range (1,Utils.GetNbins(ratio)):
+        if ratio.InheritsFrom("TGraphAsymmErrors"):
+            chi2_prev = chi2_prev + (ratio.GetY()[a] - 1.)**2 / ratio.GetN()
+            chi2_now = chi2_now + (ratio_SF.GetY()[a] - 1.)**2 / ratio_SF.GetN()
+        else:
+            chi2_prev = chi2_prev + (ratio.GetBinContent(a) - 1.)**2 / ratio.GetNbinsX()
+            chi2_now = chi2_now + (ratio_SF.GetBinContent(a) - 1.)**2 / ratio_SF.GetNbinsX()
+    chi2_prev = math.sqrt(chi2_prev)
+    chi2_now = math.sqrt(chi2_now)
+    pu.DrawTLatex(0.19, 0.5, " #frac{<(SF -1)>}{#sqrt{N_{bins}}}: %.4f before SF, %.4f after"%(chi2_prev, chi2_now))
+    corrstr = ""
+    if (not corr) and (probe == Probes.ID or probe == Probes.Calo):
+        corrstr = "_noIDCorr"
+    can.SaveAs ("Plots/SFValid_%s_%s_%s_%s%s.pdf"%(match,var,probe,region,corrstr))
+    p1.cd()
+    ROOT.gPad.RedrawAxis()
+
+    pu.DrawTLatex(0.5,0.94,"%s Effi%s vs %s for %s probes in %s"%(match,corrstr,var,probe,region),0.04,52,22)
+
+    can.SaveAs("Plots/AllEffPlots.pdf")
+    
+def doEffPlots2D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, LumiScale, corr = True, analysis=Analysis.Z_Reco):
+
+    # check if 2 sets of histos are available -> how to plot a comparison in 2D?
+    if len(hists_final)>1:
+        print "Error: Currently no 2D comparison between 2 different datasets possible!"
+        sys.exit(1)
+
+
+    h_data = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency]
+    h_mc = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency]
+    h_truth = hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.TruthEfficiency]
+
+    ratiodata = hists_final[0].Histos[HistoKinds.SF][HistoKinds.SF]
+    ratiotruth = hists_final[0].Histos[HistoKinds.SF][HistoKinds.TruthSF]
+
+    draw2D (h_data, var, probe, match, region, conf_Data, HistoKinds.DataEfficiency, corr, LumiScale)
+    draw2D (h_mc, var, probe, match, region, conf_Data, HistoKinds.MCEfficiency, corr, LumiScale)
+    draw2D (h_truth, var, probe, match, region, conf_Data, HistoKinds.TruthEfficiency, corr, LumiScale)
+
+    draw2D (ratiodata, var, probe, match, region, conf_Data, HistoKinds.SF, corr, LumiScale)
+    draw2D (ratiotruth, var, probe, match, region, conf_Data, HistoKinds.TruthSF, corr, LumiScale)
+
+def doEffPlots (var, probe, match, region, conf_Data, conf_Zmumu, inputComparison = None, corr = True, includeSys = True, doClosure = False, LumiScale=-1, doPreRecEtaCopy=False, analysis=Analysis.Z_Reco):
+
+    infiles = [
+                   ["MC",conf_Zmumu],
+                   ["Data",conf_Data]
+                   ]
+
+    hists_final = []
+
+    # for pre-recommendations, copy negative eta bins of transition region to positive ones (use doPreRecEtaCopy=True):
+    if includeSys:
+        # with systematic uncertainty bands:
+        test = Histos.TPFinalSysHistos("test",probe,match,region,var,infiles,charge=None,corr=corr,doClosure=doClosure,LumiScale=LumiScale,doPreRecEtaCopy=doPreRecEtaCopy, analysis=analysis).HistoSets
+        syshisto = test[Systematics.All][0]
+        hists_final.append(test["Nominal"])
+    else:
+        # faster (without systematic uncertainty bands):
+        hists_final.append(Histos.TPFinalHistos("test",probe,match,region,var,infiles,corr=corr,doClosure=doClosure,LumiScale=LumiScale,doPreRecEtaCopy=doPreRecEtaCopy, analysis=analysis))
+        syshisto = None
+
+
+    if inputComparison != None:
+        infiles2 = [
+                   ["MC",conf_Zmumu],
+                   ["Data",inputComparison]
+                   ]
+        hists_final.append(Histos.TPFinalHistos(inputComparison.Label,probe,match,region,var,infiles2,corr=corr,doClosure=doClosure, analysis=analysis))
+
+    if hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency].InheritsFrom("TH2"):
+        doEffPlots2D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, LumiScale, corr, analysis=analysis)
+    else:
+        doEffPlots1D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, LumiScale, corr, syshisto, analysis=analysis)
+
+
+def doSysPlot(probe,match,region,var,infiles,charge=None,corr = True, doPreRecEtaCopy=False):
+
+    testpos = Histos.TPFinalSysHistos("testpos",probe,match,region,var,infiles,charge,corr,doPreRecEtaCopy=doPreRecEtaCopy).HistoSets
+    
+    # used for styling histo when TGraphAsymmErrors are used
+    h_styling = HistoDefs.initHisto(var)[0].Clone("stylingHisto")
+    # from print in Histos.py:
+    h_styling.GetXaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetXaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetXaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetXaxis().SetLabelOffset(0.00499999988824)
+    h_styling.GetYaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetYaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetYaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetYaxis().SetLabelOffset(0.00499999988824)
+    h_styling.GetYaxis().SetTitle("Relative Systematic uncertainty (%)")
+    
+    h_truth_sys_sf = testpos[Systematics.truth][2]
+    h_dR_sys_sf = testpos[Systematics.dR][2]
+    h_BG_sys_sf = testpos[Systematics.BG][2]
+    h_Det_sys_sf = testpos[Systematics.Det][2]
+    h_total_sys_sf = testpos[Systematics.All][2]
+
+    h_stat_sf = testpos["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF]
+    
+    if h_stat_sf.InheritsFrom("TGraphAsymmErrors"):
+        for i in range (0,Utils.GetNbins(h_stat_sf)):
+            maxError = max(h_stat_sf.GetErrorYhigh(i),h_stat_sf.GetErrorYlow(i))
+            try:
+                h_stat_sf.SetPoint(i,h_stat_sf.GetX()[i],maxError/h_stat_sf.GetY()[i])
+            except ZeroDivisionError:
+                h_stat_sf.SetPoint(i,h_stat_sf.GetX()[i],0.)
+            h_total_sys_sf.SetPoint(i,h_total_sys_sf.GetX()[i],math.sqrt(h_total_sys_sf.GetY()[i]**2. + h_stat_sf.GetY()[i]**2.))
+    else:
+        for i in range (1,Utils.GetNbins(h_stat_sf)):
+            try:
+                h_stat_sf.SetBinContent(i,h_stat_sf.GetBinError(i)/h_stat_sf.GetBinContent(i))
+            except ZeroDivisionError:
+                h_stat_sf.SetBinContent(i,0.)
+            h_total_sys_sf.SetBinContent(i,math.sqrt(h_total_sys_sf.GetBinContent(i)*h_total_sys_sf.GetBinContent(i) + h_stat_sf.GetBinContent(i)*h_stat_sf.GetBinContent(i)))
+    
+    if h_stat_sf.InheritsFrom("TGraphAsymmErrors"):
+        for i in range (0,Utils.GetNbins(h_stat_sf)):
+            h_truth_sys_sf.SetPoint(i,h_truth_sys_sf.GetX()[i],h_truth_sys_sf.GetY()[i]*100.)
+            h_dR_sys_sf.SetPoint(i,h_dR_sys_sf.GetX()[i],h_dR_sys_sf.GetY()[i]*100.)
+            h_BG_sys_sf.SetPoint(i,h_BG_sys_sf.GetX()[i],h_BG_sys_sf.GetY()[i]*100.)
+            h_Det_sys_sf.SetPoint(i,h_Det_sys_sf.GetX()[i],h_Det_sys_sf.GetY()[i]*100.)
+            h_total_sys_sf.SetPoint(i,h_total_sys_sf.GetX()[i],h_total_sys_sf.GetY()[i]*100.)
+            h_stat_sf.SetPoint(i,h_stat_sf.GetX()[i],h_stat_sf.GetY()[i]*100.)
+    else:
+        for i in range (1,Utils.GetNbins(h_truth_sys_sf)):
+            h_truth_sys_sf.SetBinContent(i, h_truth_sys_sf.GetBinContent(i)*100.)
+            h_dR_sys_sf.SetBinContent(i, h_dR_sys_sf.GetBinContent(i)*100.)
+            h_BG_sys_sf.SetBinContent(i, h_BG_sys_sf.GetBinContent(i)*100.)
+            h_Det_sys_sf.SetBinContent(i, h_Det_sys_sf.GetBinContent(i)*100.)
+            h_total_sys_sf.SetBinContent(i, h_total_sys_sf.GetBinContent(i)*100.)
+            h_stat_sf.SetBinContent(i, h_stat_sf.GetBinContent(i)*100.)
+        
+    pu = PlotUtils()
+    pu.Size = 0.06 * (1 - pu.VerticalCanvasSplit)
+    pu.Lumi = infiles[1][1].Lumi / 1000.
+
+    can = ROOT.TCanvas("Sys_%s_%s_%s_%s" % (probe, match, var, charge), "Systematics", 800, 800)
+    can.cd()
+    can.SetLeftMargin(0.15)
+
+    can.SetLogy(1)
+
+ 
+
+    valuesForYRange = []
+    if h_total_sys_sf.InheritsFrom("TGraphAsymmErrors"):
+        for i in range (0,Utils.GetNbins(h_total_sys_sf)):
+            valuesForYRange.append(h_total_sys_sf.GetY()[i])
+        ymin = min(valuesForYRange)
+        ymax = max(valuesForYRange)
+    else:
+        ymin = h_total_sys_sf.GetMinimum()
+        ymax = h_total_sys_sf.GetMaximum()
+        
+    h_styling.Draw("AXIS")
+    h_styling.SetMinimum(1.0e-3)
+    h_styling.SetMaximum(ymax*1e3)
+
+
+    h_total_sys_sf.SetLineColor(ROOT.kBlack)
+    h_total_sys_sf.GetYaxis().SetTitle("Relative Systematic uncertainty (%)")
+    h_total_sys_sf.SetLineWidth(4)
+    
+    
+    h_stat_sf.SetLineColor(ROOT.kMagenta+1)
+    h_stat_sf.SetLineWidth(2)
+    
+
+    h_truth_sys_sf.SetLineColor(ROOT.kBlue)
+    h_truth_sys_sf.SetLineWidth(2)
+    h_truth_sys_sf.SetMarkerColor(h_truth_sys_sf.GetLineColor())
+    h_truth_sys_sf.SetMarkerStyle(24)
+    
+
+
+    h_dR_sys_sf.SetMarkerStyle(25)
+    h_dR_sys_sf.SetLineWidth(2)
+    h_dR_sys_sf.SetLineColor(ROOT.kGreen+1)
+    h_dR_sys_sf.SetMarkerColor(h_dR_sys_sf.GetLineColor())
+    
+
+    h_BG_sys_sf.SetLineWidth(2)
+    h_BG_sys_sf.SetMarkerStyle(26)
+    h_BG_sys_sf.SetLineColor(ROOT.kRed)
+    h_BG_sys_sf.SetMarkerColor(h_BG_sys_sf.GetLineColor())
+    
+
+    h_Det_sys_sf.SetLineWidth(2)
+    h_Det_sys_sf.SetMarkerStyle(26)
+    h_Det_sys_sf.SetLineColor(ROOT.kOrange-3)
+    h_Det_sys_sf.SetMarkerColor(h_Det_sys_sf.GetLineColor())
+    
+    
+    if h_stat_sf.InheritsFrom("TGraphAsymmErrors"):
+        h_total_sys_sf.Draw("LX same")
+        h_stat_sf.Draw("LX same")
+        h_truth_sys_sf.Draw("LX same")
+        h_dR_sys_sf.Draw("LX same")
+        h_BG_sys_sf.Draw("LX same")
+        h_Det_sys_sf.Draw("LX same")
+    else:
+        h_total_sys_sf.Draw("HIST l same")
+        h_stat_sf.Draw("HIST l same")
+        h_truth_sys_sf.Draw("HIST l same")
+        h_dR_sys_sf.Draw("HIST l same")
+        h_BG_sys_sf.Draw("HIST l same")
+        h_Det_sys_sf.Draw("HIST l same")
+
+    leg = ROOT.TLegend(.45, .68, .95, .85)
+    leg.SetFillStyle(0)
+    leg.SetBorderSize(0)
+    leg.SetTextFont(42)
+    leg.SetNColumns(2)
+    leg.AddEntry(h_truth_sys_sf, "Truth Closure", "l")
+    leg.AddEntry(h_dR_sys_sf, "Match #DeltaR", "l")
+    leg.AddEntry(h_BG_sys_sf, "Background", "l")
+    leg.AddEntry(h_Det_sys_sf, "MC14 vs MC15", "l")
+    leg.AddEntry(h_stat_sf, "Statistics", "l")
+    leg.AddEntry(h_total_sys_sf, "Total", "l")
+    leg.Draw()
+
+
+    pu.DrawAtlas(can.GetLeftMargin(), 0.91)
+    pu.DrawLumiSqrtS(can.GetLeftMargin(), 0.87)
+    pu.DrawTarget(match, 1 - can.GetRightMargin(), 0.92, 31)
+    pu.DrawSource(probe, 1 - can.GetRightMargin(), 0.87, 31)
+    if charge != None:
+        qlabel = 'charge: %s' % (charge)
+        pu.DrawTLatex(1 - can.GetRightMargin(), 0.82, qlabel, size=pu.Size, align=31)
+    histlabel = HistoKinds.SF
+    pu.DrawTLatex(can.GetLeftMargin(), 0.82, histlabel, size=pu.Size)
+
+    if charge != None:
+        can.SaveAs ("Plots/Sys_%s_%s_%s_%s_%s.pdf" % (probe, match, region, var, charge))
+    else:
+        can.SaveAs ("Plots/Sys_%s_%s_%s_%s.pdf" % (probe, match, region, var))
+
+    pu.DrawTLatex(0.5,0.94,"Systematics %s vs %s for %s probes in %s"%(match,var,probe,region),0.04,52,22)
+    can.SaveAs("Plots/AllEffPlots.pdf")
+    
+if __name__ == "__main__":
+
+    # what we want to run on:
+    InputData = DSConfig.Zmumu_mc15
+    InputZmumu = DSConfig.Zmumu_mc15
+
+    dummy = ROOT.TCanvas("dummy","dummy",800,800)
+    dummy.SaveAs("Plots/AllEffPlots.pdf[")
+    
+    # variables we want to plot:
+    # NOTE: 'fineEtaPhi' is 1D while 'etaphiFine' is 2D
+
+    
+    #######
+    # systematics plots:
+    #######
+    #doSysPlot(Probes.Calo,Matches.Medium, DetRegions.All, "eta", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.Medium, DetRegions.All, "fineEtaPhi", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True, doPreRecEtaCopy=True)
+    #doSysPlot(Probes.Calo,Matches.Medium, DetRegions.All, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.Medium, DetRegions.noCrack, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    
+    #doSysPlot(Probes.Calo,Matches.Tight, DetRegions.All, "eta", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.Tight, DetRegions.All, "fineEtaPhi", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True, doPreRecEtaCopy=True)
+    #doSysPlot(Probes.Calo,Matches.Tight, DetRegions.All, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.Tight, DetRegions.noCrack, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+
+    #doSysPlot(Probes.Calo,Matches.LooseNoCalo, DetRegions.All, "eta", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.LooseNoCalo, DetRegions.All, "fineEtaPhi", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True, doPreRecEtaCopy=True)
+    #doSysPlot(Probes.Calo,Matches.LooseNoCalo, DetRegions.All, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+    #doSysPlot(Probes.Calo,Matches.LooseNoCalo, DetRegions.noCrack, "pt", infiles=[["MC",InputZmumu],["Data",InputData]],charge=None,corr = True)
+
+    
+    
+    #######
+    # efficiency plots:
+    #######
+    #doEffPlots ("phi", Probes.Calo, Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("eta", Probes.Calo,Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("pt", Probes.Calo, Matches.LooseNoCalo,DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("pt", Probes.Calo, Matches.LooseNoCalo,DetRegions.noCrack, InputData, InputZmumu)
+    #doEffPlots ("DetRegions", Probes.Calo,Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("etaTemp", Probes.Calo,Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("etaphiFine", Probes.Calo,Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu, includeSys = False, doPreRecEtaCopy=False)
+    #doEffPlots ("fineEtaPhi", Probes.Calo,Matches.LooseNoCalo, DetRegions.All, InputData, InputZmumu, doPreRecEtaCopy=False)
+    
+    #doEffPlots ("phi", Probes.MStoMu,Matches.Calo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("eta", Probes.MStoMu,Matches.Calo, DetRegions.All, InputData, InputZmumu, includeSys = False)
+    #doEffPlots ("pt", Probes.MStoMu,Matches.Calo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("pt", Probes.MStoMu,Matches.Calo, DetRegions.Crack, InputData, InputZmumu)
+    #doEffPlots ("DetRegions", Probes.MStoMu,Matches.Calo, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("etaphiFine", Probes.MStoMu,Matches.Calo, DetRegions.All, InputData, InputZmumu, includeSys = False)
+    #doEffPlots ("CaloTag2D", Probes.MStoMu, Matches.Calo, DetRegions.All, InputData, InputZmumu, includeSys = False)
+
+    doEffPlots ("phi", Probes.Calo, Matches.Medium, DetRegions.All, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("eta", Probes.Calo, Matches.Medium,DetRegions.All, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("pt", Probes.Calo, Matches.Medium,DetRegions.All, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("pt", Probes.Calo, Matches.Medium,DetRegions.noCrack, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("DetRegions", Probes.Calo,Matches.Medium, DetRegions.All, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("etaTemp", Probes.Calo,Matches.Medium, DetRegions.All, InputData, InputZmumu, analysis=Analysis.Z_Reco)
+    doEffPlots ("etaphiFine", Probes.Calo,Matches.Medium, DetRegions.All, InputData, InputZmumu, includeSys = False, doPreRecEtaCopy=False, analysis=Analysis.Z_Reco)
+    doEffPlots ("fineEtaPhi", Probes.Calo,Matches.Medium, DetRegions.All, InputData, InputZmumu, doPreRecEtaCopy=False, analysis=Analysis.Z_Reco)
+    
+    #doEffPlots ("phi", Probes.Calo, Matches.Tight, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("eta", Probes.Calo, Matches.Tight,DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("pt", Probes.Calo, Matches.Tight,DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("pt", Probes.Calo, Matches.Tight,DetRegions.noCrack, InputData, InputZmumu)
+    #doEffPlots ("DetRegions", Probes.Calo,Matches.Tight, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("etaTemp", Probes.Calo,Matches.Tight, DetRegions.All, InputData, InputZmumu)
+    #doEffPlots ("etaphiFine", Probes.Calo,Matches.Tight, DetRegions.All, InputData, InputZmumu, includeSys = False, doPreRecEtaCopy=False)
+    #doEffPlots ("fineEtaPhi", Probes.Calo,Matches.Tight, DetRegions.All, InputData, InputZmumu, doPreRecEtaCopy=False)
+
+
+    dummy.SaveAs("Plots/AllEffPlots.pdf]")
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/HistoDefs.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/HistoDefs.py
new file mode 100644
index 00000000000..5b97590bf01
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/HistoDefs.py
@@ -0,0 +1,229 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from Defs import *
+import sys
+import math, ROOT, itertools, os.path
+from array import array 
+
+# TH2Poly for fine eta-phi binning
+def TPFineEtaPhiHist(name,title):
+    histo = ROOT.TH2Poly()
+    histo.SetName(name)
+    histo.SetTitle(title)
+    
+    barrelECTrans = 1.19
+    
+    # etabins used in 2012 analysis:
+    #etabins = [-2.75,-2.18,-1.95,-1.74,-1.52,-1.37,-1.05,-0.84,-0.63,-0.42,-0.21,0.,0.21,0.42,0.63,0.84,1.05,1.37,1.52,1.74,1.95,2.18,2.75]
+    etabins = [0.15,0.3,0.45,0.6,0.75,0.9,1.05,barrelECTrans,1.35,1.5,1.65,1.8,1.95,2.1,2.25,2.5]
+    etabins = sorted([0.]+etabins+[-binX for binX in etabins])
+    
+    phiSectorBarrel = [-2.905,-2.59,-2.12,-1.805,-1.335,-1.02,-0.55,-0.235,0.235,0.55,1.02,1.335,1.805,2.12,2.59,2.905]
+    phiSectorEC = [-3.011,-2.487,-2.225,-1.702,-1.440,-0.916,-0.655,-0.131,0.131,0.655,0.916,1.440,1.702,2.225,2.487,3.011]
+    
+    # we go like this when adding the bins:
+    # 
+    # ^  ^  ^
+    # |  | |
+    # x------->
+    
+    #correct behavior for the bin around pi: one common bin at +pi and -pi instead of 2!
+    for etaCurrent, etaNext in zip (etabins, etabins [1:] ):
+        for phiBarrelCurrent, phiBarrelNext, phiECCurrent, phiECNext in zip (phiSectorBarrel, phiSectorBarrel [1:], phiSectorEC, phiSectorEC [1:] ):
+            
+            # if we pass the threshold, different treatment
+            if (etaCurrent < -barrelECTrans) and (etaNext > -barrelECTrans):#first threshold passage
+                #
+                #
+                #      here, we do:
+                #           |1.19
+                #       1   2
+                #           3    4
+                #           6    5
+                #      8   |7
+                #
+                x = array('d',[etaCurrent, -barrelECTrans, -barrelECTrans, etaNext, etaNext, -barrelECTrans, -barrelECTrans, etaCurrent])
+                y = array('d',[phiECNext, phiECNext, phiBarrelNext, phiBarrelNext, phiBarrelCurrent, phiBarrelCurrent, phiECCurrent, phiECCurrent])
+                binNumber = histo.AddBin(8,x,y)
+                #print '(etaCurrent < -barrelECTrans) and (etaNext > -barrelECTrans), etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+            elif (etaCurrent < barrelECTrans) and (etaNext > barrelECTrans):# second threshold passage
+                #
+                #
+                #      here, we do:
+                #           |1.19
+                #           |3    4
+                #       1   2
+                #       8   7
+                #          |6     5
+                #
+                x = array('d',[etaCurrent, barrelECTrans, barrelECTrans, etaNext, etaNext, barrelECTrans, barrelECTrans, etaCurrent])
+                y = array('d',[phiBarrelNext, phiBarrelNext, phiECNext, phiECNext, phiECCurrent, phiECCurrent, phiBarrelCurrent, phiBarrelCurrent])
+                binNumber = histo.AddBin(8,x,y)
+                #print '(etaCurrent < barrelECTrans) and (etaNext > barrelECTrans), etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+            else:#normal case
+                #
+                #
+                #      here, we do:
+                #
+                #        1     2
+                #
+                #        4     3
+                #
+                if (etaNext <= -barrelECTrans) or (etaCurrent >= barrelECTrans):
+                    phiCurrent = phiECCurrent
+                    phiNext = phiECNext
+                else:
+                    phiCurrent = phiBarrelCurrent
+                    phiNext = phiBarrelNext
+                
+                x = array('d',[etaCurrent, etaNext, etaNext, etaCurrent])
+                y = array('d',[phiNext, phiNext, phiCurrent, phiCurrent])
+                binNumber = histo.AddBin(4,x,y)
+                #print 'else, etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+
+        # finally, the -pi / pi bin!
+        phiBarrelLast = phiSectorBarrel[-1]
+        phiECLast = phiSectorEC[-1]
+        
+        #      here, we fill like this:
+        #      and of course if we have no threshold
+        #      we don't have 6,7,10,11
+        #
+        #        4.........................3     <- +pi
+        #        '                         '
+        #        '                         '
+        #        5.......6                 '
+        #                7................8'  8,9 are actually *on* the vertical double line of course!
+        #                                 ''  and exactly along the line 2-3.
+        #                                 ''
+        #                                 ''
+        #                                 ''  this line has 0 width and is aligned with the other bin
+        #                                 ''  edges, so we don't see it on the histo!
+        #                                 ''  drawn twice here just to clarify that we go along that
+        #                                 ''  way twice
+        #                10...............9'
+        #        12......11                '
+        #        '                       array  '
+        #        '                         '
+        #        1.........................2      <- -pi
+        if math.fabs(etaCurrent) > barrelECTrans:
+            phiedge = phiECLast
+        else:
+            phiedge = phiBarrelLast
+        if math.fabs(etaNext) > barrelECTrans:
+            phiedger = phiECLast
+        else:
+            phiedger = phiBarrelLast
+
+        if (etaCurrent <= -barrelECTrans) and (etaNext >= -barrelECTrans):
+            xe = array('d',[etaCurrent, etaNext, etaNext, etaCurrent,etaCurrent,-barrelECTrans,-barrelECTrans,etaNext,etaNext,-barrelECTrans,-barrelECTrans,etaCurrent])
+            ye = array('d',[-math.pi,-math.pi,math.pi,math.pi,phiedge,phiedge,phiedger,phiedger,-phiedger,-phiedger,-phiedge,-phiedge])
+            binNumber = histo.AddBin(12,xe,ye)
+            #print '(etaCurrent <= -barrelECTrans) and (etaNext >= -barrelECTrans), etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+        elif (etaCurrent <= barrelECTrans) and (etaNext >= barrelECTrans):
+            xe = array('d',[etaCurrent, etaNext, etaNext, etaCurrent,etaCurrent,barrelECTrans,barrelECTrans,etaNext,etaNext,barrelECTrans,barrelECTrans,etaCurrent])
+            ye = array('d',[-math.pi,-math.pi,math.pi,math.pi,phiedge,phiedge,phiedger,phiedger,-phiedger,-phiedger,-phiedge,-phiedge])
+            binNumber = histo.AddBin(12,xe,ye)
+            #print '(etaCurrent <= barrelECTrans) and (etaNext >= barrelECTrans), etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+        else:
+            xe5 = array('d',[etaCurrent,etaNext,etaNext,etaCurrent,etaCurrent,etaNext,etaNext,etaCurrent])
+            ye5 = array('d',[-math.pi,-math.pi,math.pi,math.pi,phiedge,phiedger,-phiedger,-phiedge])
+            binNumber = histo.AddBin(8,xe5,ye5)
+            #print 'else2, etaCurrent: %s, etaNext: %s. bin: %s'%(etaCurrent, etaNext,binNumber)
+    return histo
+
+
+
+        
+# list of already created histograms
+HistoSetups = { "mll" : "mll" }
+
+# return histogram definition in the following way:
+# [ROOT.TH1F("pt_template","pt;p_{T} [GeV];Probes",len(PtBins)-1,array.array("f",PtBins)),"pt",""]
+def initHisto(name):
+
+    
+    CaloTagEtaBins =  [-2.5,-2,-1.8,-1.6,-1.5,-1.1,-0.15,0.15,1.1,1.5,1.6,1.8,2,2.5]
+    CaloTagPtBins =  [15,20,30,40,50,60,70,90,1e15]
+    PtBins = [10,15,20,25,30,35,40,50,65,80,100]
+    #etaBins = [-2.5, -1.1,-0.2,0.2,1.1,2.5] 
+    etaBins = [-2.5, 2.5]
+    
+    # 1D
+    if name == "DetRegions":
+        histo = ROOT.TH1F("DetRegions_template","DetRegions;Detector Region;Probes",12,-0.5,11.5)
+        histo.GetXaxis().SetBinLabel(1,"unknown")
+        histo.GetXaxis().SetBinLabel(2,"Barrel large")
+        histo.GetXaxis().SetBinLabel(3,"Barrel small")
+        histo.GetXaxis().SetBinLabel(4,"Barrel overlap")
+        histo.GetXaxis().SetBinLabel(5,"Feet")
+        histo.GetXaxis().SetBinLabel(6,"Transition")
+        histo.GetXaxis().SetBinLabel(7,"Endcap large")
+        histo.GetXaxis().SetBinLabel(8,"Endcap small")
+        histo.GetXaxis().SetBinLabel(9,"BEE")
+        histo.GetXaxis().SetBinLabel(10,"Forward large")
+        histo.GetXaxis().SetBinLabel(11,"Forward small")
+        histo.GetXaxis().SetBinLabel(12,"Crack")
+        histo.SetDirectory(0)
+        HistoSetups[name] = name
+        return [histo,"detRegion",""]
+    elif name == "mll":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("mll_template","mll;m_{ll} [GeV];TP Pairs",8,80000,100000),"mll",""]
+    elif name == "pt":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("pt_template","pt;p_{T} [GeV];Probes",len(PtBins)-1,array("f",PtBins)),"pt",""]
+    elif name == "eta":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("eta_template","eta;#eta;Probes",20,-2.5,2.5),"eta",""]
+    elif name == "etaTemp":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("etaTemp_template","eta;#eta;Probes",len(etaBins)-1,array("f",etaBins)),"eta",""]
+    elif name == "phi":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("phi_template","phi;#phi;Probes",20,-math.pi,math.pi),"phi",""]
+    elif name == "d0":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("d0_template","d0;d_{0} [mm];Probes",20,-0.2,0.2),"d0",""]
+    elif name == "z0":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("z0_template","z0;z_{0} [mm];Probes",20,-0.2,0.2),"z0",""]
+    elif name == "z_pt":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("z_pt_template","z_pt;p_{T}(Z) [GeV];TP Pairs",100,0,200),"1",""]
+    elif name == "fineEtaPhi":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("fineEtaPhi_template","fineEtaPhi;fine (#eta,#phi) bin;Probes",352,-175.5,176.5),"fineEtaPhi",""]
+    elif name == "fineEtaPhi_negq":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("fineEtaPhi_negq_template","fineEtaPhi_negq;fine (#eta,#phi) bin;Probes",352,-175.5,176.5),"fineEtaPhi_negq",""]
+    elif name == "fineEtaPhi_posq":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("fineEtaPhi_posq_template","fineEtaPhi_posq;fine (#eta,#phi) bin;Probes",352,-175.5,176.5),"fineEtaPhi_posq",""]
+    elif name == "DetRegions_Aside":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("DetRegions_Aside_template","DetRegions_Aside;Detector Region;Probes",14,-0.5,13.5),"detRegion","abs(eta) > 0"]
+    elif name == "DetRegions_Cside":
+        HistoSetups[name] = name
+        return [ROOT.TH1F("DetRegions_Cside_template","DetRegions_Cside;Detector Region;Probes",14,-0.5,13.5),"detRegion","abs(eta) < 0"]
+
+    # 2D
+    elif name == "etaphi":
+        HistoSetups[name] = name
+        return [ROOT.TH2F("etaphi_template","etaphi;#eta;#phi",30,-2.5,2.5,32,-math.pi,math.pi),"phi : eta",""]
+    elif name == "etapt":
+        HistoSetups[name] = name
+        return [ROOT.TH2F("etapt_template","etapt;#eta;p_{T} [GeV]",20,-2.5,2.5,10,10,120),"pt : eta",""]
+    elif name == "CaloTag2D":
+        HistoSetups[name] = name
+        return [ROOT.TH2F("CaloTag2D_template","CaloTag2D;#eta;p_{T} [GeV]",len(CaloTagEtaBins)-1,array("f",CaloTagEtaBins), len(CaloTagPtBins)-1, array("f",CaloTagPtBins)),"pt : eta",""]
+    elif name == "ptmll":
+        HistoSetups[name] = name
+        return [ROOT.TH2F("ptmll_template","ptmll;p_{T} [GeV];m_{ll} [GeV]",10,10,120,20,80000,100000),"mll : pt",""]
+    elif name == "etaphiFine":
+        HistoSetups[name] = name
+        return [TPFineEtaPhiHist("etaphiFine_template","etaphiFine;#eta;#phi;Efficiency"),"phi : eta",""]
+    
+    else:
+        print "Histogram not defined!"
+        return None
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Histos.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Histos.py
new file mode 100644
index 00000000000..e4d1a9ea611
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Histos.py
@@ -0,0 +1,715 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from Defs import *
+import Utils
+import ROOT
+import math
+import DSConfig
+import HistoDefs
+graphList = []
+
+## This class provides the basic functionality to read individual histos
+class TPHisto:
+
+    ## normal init: based on conent parameters
+    def __init__ (self, name,probe,match,region,chargeprod,kind,var, histo=None,infile=None,doClosure=False,LumiScale=-1,useAsymEff=True,analysis=Analysis.Z_Reco):
+        self.Name = name
+        self.Analysis = analysis
+        self.Probe = probe
+        self.Match = match
+        self.Region = region
+        self.ChargeProd = chargeprod
+        self.Kind = kind
+        self.Var = var
+        self.Histo = histo
+        self.Infile = infile
+        self.DoClosure = doClosure
+        self.LumiScale = LumiScale
+        self.UseAsymEff = useAsymEff
+        
+        if self.Histo == None and self.Infile != None:
+            self.Load()
+
+    ## create instance from an existing histo
+    @classmethod
+    def FromHist (out,name,h_in,fin=0):
+        if h_in == None:
+            return
+        fname = h_in.GetName()
+        Args = fname.split("_")
+        kindcand = Args[5]
+        kind = ""
+        for cand in [bla for bla in PlotKinds.__dict__.keys() if not "__" in bla ]:
+            if cand in kindcand:
+                kind = cand
+        var = kindcand.split(cand)[-1]
+        hcl = h_in.Clone("Cl_"+name+"_"+h_in.GetName())
+
+        return out(name=name,probe = Args[0],region=Args[2], chargeprod = Args[3],match=Args[4],kind=kind,var=var,histo=hcl,infile=fin)
+
+
+    # Utility methods for I/O purposes
+    def GetPlotName (self):
+        #return "_".join([self.Probe,self.Probe,self.Region,self.ChargeProd,self.Match,self.Kind])+self.Var
+        return "_".join([self.Probe,self.Region,self.Probe,self.ChargeProd,self.Match,self.Kind])+self.Var
+    def GetTreeName(self):
+        return "_".join(["TPTree",self.Probe,self.ChargeProd])
+    def GetCFName (self):
+        #return "_".join([self.Probe,self.Probe,self.Region,self.ChargeProd,self.Match,self.Kind])+self.Var
+        return "_".join([self.Probe,DetRegions.All,self.Probe,self.ChargeProd,"CutFlowsMainSelection"])
+    def GetTreePath(self):
+        return "%s/Trees/"%self.Analysis+"_".join([self.Probe,self.ChargeProd])
+    def GetPlotPath(self):
+        return  "/".join([self.Analysis,self.Probe+"_"+self.Region,self.Probe+"_"+self.ChargeProd,self.Match,self.Kind])
+    def GetFullPath(self):
+        return self.GetPlotPath()+"/"+self.GetPlotName()
+    def GetCFPath(self):
+        return  "/".join([self.Analysis,self.Probe+"_"+DetRegions.All,self.Probe+"_"+self.ChargeProd,"CutFlows"])
+    def GetFullTreePath(self):
+        return self.GetTreePath()+"/"+self.GetTreeName()
+    def GetFullCFPath(self):
+        return self.GetCFPath()+"/"+self.GetCFName()
+    # Write the histo to a file
+    def Write(self, File = None, Dir = None):
+        if File == None:
+            File = self.Infile
+        if Dir == None:
+            Dir = self.GetPlotPath()
+        if not File == None or self.Histo == None:
+            dir = ROOT.gDirectory.GetName()
+            File.cd()
+            subdirs = Dir.split("/")
+            for subdir in subdirs:
+                if not ROOT.gDirectory.GetDirectory(subdir,False):
+                    ROOT.gDirectory.mkdir(subdir)
+                    if not ROOT.gDirectory.cd(subdir):
+                        print "Writing failed - unable to walk through directory structure "+dir
+            self.Histo.Write()
+            File.cd("")
+    # Load the histo from a file
+    def Load(self, File=None, Dir=None):
+        if (self.UseAsymEff) and not ":" in HistoDefs.initHisto(self.Var)[1]:
+            if self.Kind == PlotKinds.Efficiency:
+                graph = ROOT.TGraphAsymmErrors()
+                graph.SetName(self.Name+"graph")
+                self.Histo = graph
+                graphList.append(graph)
+                return
+        if File == None:
+            File = self.Infile
+        if Dir == None:
+            Dir = self.GetPlotPath()
+        h = File.Get(Dir+"/"+self.GetPlotName())
+        if h == None or self.DoClosure or self.LumiScale!=-1:
+            self.ExtractFromTree(File,LumiScale=self.LumiScale)
+        else:
+            self.ExtractDirect(File)
+    def ExtractDirect (self,File=None,Dir=None):
+        if File == None:
+            File = self.Infile
+        if Dir == None:
+            Dir = self.GetPlotPath()
+        h = File.Get(Dir+"/"+self.GetPlotName())
+        if h == None or not hasattr(h,"GetNbinsX"):
+            print "Unable to load histo "+Dir+"/"+self.GetPlotName()
+        else:
+            self.Histo = h.Clone("Cl_"+self.Name+"_"+h.GetName())
+            if self.Var == "DetRegions":
+                #h2 = HistoSetups["DetRegions"][0].Clone(self.Histo.GetName()+"2")
+                h2 = HistoDefs.initHisto("DetRegions")[0].Clone(self.Histo.GetName()+"2")
+                h2.GetXaxis().SetTitleSize(self.Histo.GetXaxis().GetTitleSize())
+                h2.GetXaxis().SetTitleOffset(self.Histo.GetXaxis().GetTitleOffset())
+                h2.GetXaxis().SetLabelSize(self.Histo.GetXaxis().GetLabelSize())
+                h2.GetXaxis().SetLabelOffset(self.Histo.GetXaxis().GetLabelOffset())
+                h2.GetYaxis().SetTitleSize(self.Histo.GetYaxis().GetTitleSize())
+                h2.GetYaxis().SetTitleOffset(self.Histo.GetYaxis().GetTitleOffset())
+                h2.GetYaxis().SetLabelSize(self.Histo.GetYaxis().GetLabelSize())
+                h2.GetYaxis().SetLabelOffset(self.Histo.GetYaxis().GetLabelOffset())
+                h2.GetXaxis().SetTitle(self.Histo.GetXaxis().GetTitle())
+                h2.GetYaxis().SetTitle(self.Histo.GetYaxis().GetTitle())
+                for i in range (1, self.Histo.GetNbinsX()+1):
+                    if (i > h2.GetNbinsX()):
+                        h2.SetBinContent(h2.GetNbinsX(),h2.GetBinContent(h2.GetNbinsX())+self.Histo.GetBinContent(i))
+                        h2.SetBinError(h2.GetNbinsX(),math.sqrt(h2.GetBinError(h2.GetNbinsX())**2+self.Histo.GetBinError(i)**2))
+                    else:
+                        h2.SetBinContent(i,self.Histo.GetBinContent(i))
+                        h2.SetBinError(i,self.Histo.GetBinError(i))
+                        
+                self.Histo = h2
+            self.Histo.SetDirectory(0)
+            print "Note: Reading %s directly"%self.GetPlotName()
+            #print "Got a plot with %i bins"%self.Histo.GetNbinsX()
+    def PassesCuts(self, tree, eventNumber, cutlist=[]):
+        
+        weight = 1.
+        # get current event and check cuts
+        tree.GetEntry(eventNumber)
+        for cut in cutlist:
+            if "weight" in cut:
+                #print "event %s: weight %s: %s"%(eventNumber,cut,getattr(tree,cut))
+                weight = weight*float(getattr(tree,cut))
+            if cut != "1":
+                if ">=" in cut or "<=" in cut:
+                    print "%s in cuts currently not supported, take </> instead"%cut
+                if ">" in cut:
+                    if "abs[" in cut:
+                        cut = cut.replace("abs[", "")
+                        if math.fabs(getattr(tree,cut.split(">")[0])) <= float(cut.split(">")[1]):
+                            return 0.
+                    else:
+                        if getattr(tree,cut.split(">")[0]) <= float(cut.split(">")[1]):
+                            return 0.
+                elif "<" in cut:
+                    if "abs[" in cut:
+                        cut = cut.replace("abs[", "")
+                        if math.fabs(getattr(tree,cut.split("<")[0])) >= float(cut.split("<")[1]):
+                            return 0.
+                    else:
+                        if getattr(tree,cut.split("<")[0]) >= float(cut.split("<")[1]):
+                            return 0.
+                else:
+                    #print "event %s: cut %s: %s"%(eventNumber,cut,getattr(tree,cut))
+                    if getattr(tree,cut) != 1:
+                        return 0.
+
+        return weight
+
+    # reverse engineer from the existing histo
+    def ExtractFromTree(self, File=None, Dir=None, LumiScale=-1):
+        #if not self.Var in HistoDefs.HistoSetups.iterkeys():
+        ##if not self.Var in HistoDefs.Histonames.iterkeys():
+            #print "Unsupported histo requested from tree: %s"%(self.Var)
+            #self.Histo = None
+            #return
+        if File == None:
+            File = self.Infile
+        if Dir == None:
+            Dir = self.GetTreePath()
+
+        h = HistoDefs.initHisto(self.Var)[0].Clone(self.GetPlotName())
+        if h == None:
+            print "Unsupported histo requested from tree: %s"%(self.Var)
+            return
+        print Dir+"/"+self.GetTreeName()
+        # what to do here: TH2F plots need PlotKinds.Efficiency!
+#         if self.Kind != PlotKinds.Efficiency:
+
+        t = File.Get(Dir+"/"+self.GetTreeName())
+        try:
+            ntodo = t.GetEntries()
+            if LumiScale > 0:
+                ntodo = int(ntodo * LumiScale)
+        except:
+            print "Failed to load %s"%self.GetTreeName()
+            throw
+        #h = HistoSetups[self.Var][0].Clone(self.GetPlotName())
+        h.Sumw2()
+        h.GetXaxis().SetLabelSize(0.05)
+        h.GetXaxis().SetTitleSize(0.05)
+        h.GetXaxis().SetTitleOffset(1.4)
+        h.GetYaxis().SetLabelSize(0.05)
+        h.GetYaxis().SetTitleSize(0.05)
+        h.GetYaxis().SetTitleOffset(1.4)
+
+        tmpVar = self.Var
+        
+        cuts = "(%s) * (%s)"%(HistoDefs.initHisto(self.Var)[2], ExtraCuts[self.Region])
+        #cuts = "(%s) * (%s)"%(HistoSetups[self.Var][2], ExtraCuts[self.Region])
+        if len((self.Var).split('_'))>1:
+            if "posq" in ((self.Var).split('_'))[1]:
+                cuts = "(%s) * ( q > 0)"%cuts
+            elif "negq" in ((self.Var).split('_'))[1]:
+                cuts = "(%s) * ( q < 0)"%cuts
+            else:
+                print 'Error: During reading from tree, unknown variable detected: %s'%(((self.Var).split('_'))[1])
+            tmpVar = ((self.Var).split('_'))[0]
+
+        #if not "Truth" in self.Probe:
+        if not h.InheritsFrom("TH2"):
+            h.GetYaxis().SetTitle("Probes")
+        if self.Kind == PlotKinds.Matches:
+            cuts = "(%s) * (matched_%s)"%(cuts,self.Match)
+            #print cuts
+            if self.DoClosure:
+                if cuts != "":
+                    cuts = "(%s) * (scale_factor_%s)"%(cuts,self.Match)
+                else:
+                    cuts = "scale_factor_%s"%(self.Match)
+                #print cuts
+            if not h.InheritsFrom("TH2"):
+                h.GetYaxis().SetTitle("Matched Probes")
+        cuts = cuts.replace("()","(1)")
+        #print " ++++++++ Cuts are %s ++++++++++++++++"%cuts
+        if LumiScale==-1:
+            #t.Project(self.GetPlotName(),HistoSetups[tmpVar][1],cuts)
+            t.Project(self.GetPlotName(),HistoDefs.initHisto(tmpVar)[1],cuts)
+        else:
+            #if ":" in HistoSetups[tmpVar][1]:
+            if ":" in HistoDefs.initHisto(tmpVar)[1]:
+                print "Using LumiScale in 2D histos currently not supported! Running without LumiScale instead."
+                #t.Project(self.GetPlotName(),HistoSetups[tmpVar][1],cuts)
+                t.Project(self.GetPlotName(),HistoDefs.initHisto(tmpVar)[1],cuts)
+            else:
+                cuts = cuts.replace(" ", "")
+                # adjust abs() naming in order to use it later
+                cuts = cuts.replace("abs(", "abs[")
+                cuts = cuts.replace("(","")
+                cuts = cuts.replace(")","")
+                cutlist = cuts.split("*")
+                cutlist = filter(lambda a: a != "1", cutlist)
+                
+                nentries = t.GetEntries()
+                if nentries==0:
+                    print "Empty files!"
+
+                curEvt = 0
+                for event in t:
+                    if curEvt>ntodo:
+                        print "Max Number of events=%i reached!"%ntodo
+                        break
+                    else:
+                        
+                        #binno = getattr(t,HistoSetups[tmpVar][1])
+                        binno = getattr(t,HistoDefs.initHisto(tmpVar)[1])
+                        #if HistoSetups[tmpVar][1] == "detRegion" and binno > 11:
+                        if HistoDefs.initHisto(tmpVar)[1] == "detRegion" and binno > 11:
+                            binno = 11
+                        h.Fill(binno,self.PassesCuts(t,curEvt,cutlist))
+                        if curEvt % 5000 == 0:
+                            print "Event number %d out of %d " % (curEvt, nentries)
+                    curEvt += 1
+
+        print "Note: Reading %s from the TP tree"%self.GetPlotName()
+
+        h.SetDirectory(0)
+        #h.Print()
+        self.Histo = h
+
+# this guy provides a whole set of matching histos
+class TPHistoSet:
+    def __init__(self,name,probe,match,region,var,infile=None,doClosure=False,LumiScale=-1,useAsymEff=True,analysis=Analysis.Z_Reco):
+       self.Histos={}
+       self.Name = name
+       self.Analysis = analysis
+       self.Infile = infile
+       self.Probe = probe
+       self.Match = match
+       self.Region = region
+       self.Var = var
+       self.DoClosure = doClosure
+       self.LumiScale = LumiScale
+       self.UseAsymEff = useAsymEff
+       
+       print '\nCreating TPHistoSet %s for %s'%(name,infile)
+       for CP in [bla for bla in ChargeProducts.__dict__.keys() if not "__" in bla]:
+           self.Histos[CP] = {}
+           if (self.Probe == Probes.TruthToID or self.Probe == Probes.TruthToMu) and ("SC" in CP or "AntiIso" in CP):
+                continue
+           for Kind in [bla for bla in PlotKinds.__dict__.keys() if not "__" in bla]:
+               self.Histos[CP][Kind] = TPHisto(name=name,probe=probe,match=match,region=region,var=var,chargeprod = getattr(ChargeProducts,CP), kind=getattr(PlotKinds,Kind), infile=infile,histo=None,doClosure=self.DoClosure,LumiScale=self.LumiScale,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+       #self.UpdateEff()
+    def UpdateEff(self):
+        Utils.EffDivide(self.Histos[ChargeProducts.OC][PlotKinds.Matches].Histo,self.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo,self.Histos[ChargeProducts.OC][PlotKinds.Efficiency].Histo)
+
+    def ApplyIDeff (self, ideff=None):
+        if ideff!= None:
+            for k,v in self.Histos.iteritems():
+                if v["Efficiency"].Histo.InheritsFrom("TH2Poly"):
+                    Utils.PolyMultiply(v["Efficiency"].Histo,ideff.Histos[k]["Efficiency"].Histo,v["Efficiency"].Histo)
+                elif v["Efficiency"].Histo.InheritsFrom("TGraphAsymmErrors"):
+                    Utils.GraphMultiply(v["Efficiency"].Histo,ideff.Histos[k]["Efficiency"].Histo,v["Efficiency"].Histo)
+                else:
+                    v["Efficiency"].Histo.Multiply(ideff.Histos[k]["Efficiency"].Histo)
+
+    # Data-driven background correction procedure
+    def DataDrivenBG (self,SignalMC=[],IrredMC=[],RedMC=[], SysVar = ""):
+        # produce a clone of the original
+        #print "Producing a background template with fraction %.3f%% of entries"%(self.LumiScale*100.)
+        Bkg = TPHistoSet("BackgroundTemplateFrom"+self.Name,self.Probe,self.Match,self.Region,self.Var,self.Infile,doClosure=False, LumiScale=self.LumiScale,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+        # and update its contents
+        for CP in [ChargeProducts.OC, ChargeProducts.SC]:
+            for thing in ["Probes","Matches"]:
+                h_bkg = Bkg.Histos[CP][thing].Histo
+                if h_bkg == None:
+                    Bkg.Histos[CP][thing] = self.Histos[ChargeProducts.SC][thing].Histo.Clone("bkg_from"+self.Histos[ChargeProducts.SC][thing].GetName())
+                    h_bkg = Bkg.Histos[CP][thing].Histo
+                # Start out with an empty histogram
+                h_bkg.Reset("")
+
+                # a) Take the same-charge distribution from data
+                h_bkg.Add(self.Histos[ChargeProducts.SC][thing].Histo,1.)
+
+                # b) Subtract any irreducibe same-charge pairs (they are taken from MC)
+                for subtractme in SignalMC+IrredMC:                 # subtract irreducibe same sign
+                    h_bkg.Add(subtractme.Histos[ChargeProducts.SC][thing].Histo,-1.00)
+                # c) Correct the OC version for a non-unity OC/SC ratio in QCD using MC or anti-isolated data
+                if CP == ChargeProducts.OC and not self.Probe == Probes.ID:
+                    qcdOC = TPHisto(name="qcdOCtmp",probe=self.Probe,match=self.Match,region=self.Region,var="mll",chargeprod=ChargeProducts.OC_AntiIso, kind=thing, infile=self.Infile, histo=None, doClosure=False,useAsymEff=False,analysis=self.Analysis)
+                    n_qcdOC = qcdOC.Histo.Integral(1,qcdOC.Histo.GetXaxis().FindBin(80e3)) + qcdOC.Histo.Integral(qcdOC.Histo.GetXaxis().FindBin(100e3),qcdOC.Histo.GetNbinsX())
+                    qcdSC = TPHisto(name="qcdOCtmp",probe=self.Probe,match=self.Match,region=self.Region,var="mll",chargeprod=ChargeProducts.SC_AntiIso, kind=thing, infile=self.Infile, histo=None, doClosure=False,useAsymEff=False,analysis=self.Analysis)
+                    n_qcdSC = qcdSC.Histo.Integral(1,qcdSC.Histo.GetXaxis().FindBin(80e3)) + qcdSC.Histo.Integral(qcdSC.Histo.GetXaxis().FindBin(100e3),qcdSC.Histo.GetNbinsX())
+                    if n_qcdSC == 0:
+                        scale = 1
+                    else:
+                        scale = n_qcdOC / n_qcdSC
+                        if SysVar == "up":
+                            scale = 1 + 2.*(scale - 1)
+                        if SysVar == "down":
+                            scale = 1
+                    #print "BG scale is %.3f / %.3f = %.3f"%(n_qcdOC, n_qcdSC, scale)
+                    h_bkg.Scale(scale)
+                # that's it!
+        return Bkg
+
+    def ScaleToData(self,data):
+        dataint = data.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo.Integral()
+        myint = self.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo.Integral()
+        scale = dataint / myint
+        #print "Scale via norm: %.4f"%scale
+        for CP in [bla for bla in ChargeProducts.__dict__.keys() if not "__" in bla]:
+            for thing in ["Probes","Matches"]:
+                self.Histos[CP][thing].Histo.Scale(scale)
+    def ApplyXSScale(self,xs,nsample=-1,lumi=20300.):
+        if nsample < 0:
+            if self.Infile == None:
+                print "Error: Please provide either the number of MC events or a valid iput file with a cut flow if you want to do XS weighting"
+            cf = self.Histos[ChargeProducts.OC][PlotKinds.Matches].GetFullCFPath()
+            #print cf
+            hcf = self.Infile.Get(cf)
+            nsample = float(hcf.GetBinContent(1))
+        #print "nsample %.2f"%nsample
+        scale = xs * lumi / nsample
+        #print "xs is %.2f, lumi is %.4f"%(xs,lumi)
+        #print "XS scale is %.4f"%scale
+        for CP in [bla for bla in ChargeProducts.__dict__.keys() if not "__" in bla]:
+            for thing in ["Probes","Matches"]:
+                self.Histos[CP][thing].Histo.Scale(scale)
+
+    def SubtractBG(self,Backgrounds=[]):
+        if self.Probe == Probes.TruthToID or self.Probe == Probes.TruthToMu:
+            return
+        for CP in [bla for bla in ChargeProducts.__dict__.keys() if not "__" in bla]:
+            for thing in ["Probes","Matches"]:
+                tosub = self.Histos[CP][thing].Histo
+                for BG in Backgrounds:
+                    subthis = BG.Histos[CP][thing].Histo
+                    tosub.Add(subthis,-1.)
+                    #print 'ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'
+                    #print CP
+                    #print thing
+                    #print BG
+                    #print '\n\n\n\n'
+                    #for i in range(1, Utils.GetNbins(subthis)):
+                        #print subthis.GetBinContent(i), subthis.GetBinError(i)
+
+class TPFinalHistos:
+    def __init__(self,name,probe,match,region,var,infiles,corr = True,sysVar = "",doClosure=False,LumiScale=-1,doPreRecEtaCopy=False,useAsymEff=True,analysis=Analysis.Z_Reco):
+        self.Histos={}
+        self.Name = name
+        self.Analysis = analysis
+        self.Probe = probe
+        self.Match = match
+        self.Region = region
+        self.Var = var
+        self.Infiles = infiles
+        self.Corr = corr
+        self.SysVar = sysVar
+        self.DoClosure = doClosure
+        self.LumiScale = LumiScale
+        self.DoPreRecEtaCopy = doPreRecEtaCopy
+        self.UseAsymEff = useAsymEff
+
+        self.Histos[HistoKinds.Efficiency] = {}
+        self.Histos[HistoKinds.SF] = {}
+        self.Histos[PlotKinds.Probes] = {}
+
+        #print 'Creating TPHistoSet for %s'%(infiles[0][0])
+        MCHists = TPHistoSet(infiles[0][0],var=var,probe=probe,match = match, region = region, infile = ROOT.TFile(infiles[0][1].Filepath,"READ"), doClosure=self.DoClosure,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+        MCHistsScaled = TPHistoSet(infiles[0][0],var=var,probe=probe,match = match, region = region, infile = ROOT.TFile(infiles[0][1].Filepath,"READ"), doClosure=self.DoClosure,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+
+        #print 'Creating TPHistoSet for %s'%(infiles[1][0])
+        DataHists = TPHistoSet(infiles[1][0],var=var,probe=probe,match = match, region = region, infile = ROOT.TFile(infiles[1][1].Filepath,"READ"), LumiScale=self.LumiScale,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+
+        # scale MCHists first, since it is used in SubtractBG
+        MCHistsScaled.ScaleToData(DataHists)
+        #TODO: reinclude ApplyXSScale?
+        #MCHists.ApplyXSScale(infiles[0][1].XS, infiles[0][1].nEvents, infiles[0][1].Lumi)
+        BkgDataHists = DataHists.DataDrivenBG(SignalMC=[MCHistsScaled],SysVar = sysVar)
+        DataHists.SubtractBG([BkgDataHists])
+
+
+        #print 'Creating TPHistoSet for %s Truth'%(infiles[0][0])
+        if Matches.ID in match:
+            Truth = TPHistoSet("Truth",var=var,probe=Probes.TruthToID,match = match, region = region, infile = ROOT.TFile(infiles[0][1].Filepath,"READ"), doClosure=False,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+        else:
+            Truth = TPHistoSet("Truth",var=var,probe=Probes.TruthToMu,match = match, region = region, infile = ROOT.TFile(infiles[0][1].Filepath,"READ"), doClosure=False,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+
+        #print 'DataHists.UpdateEff()'
+        DataHists.UpdateEff()
+        #print 'MCHists.UpdateEff()'
+        MCHists.UpdateEff()
+        #print 'Truth.UpdateEff()'
+        Truth.UpdateEff()
+
+
+        # Apply the ID eff if we have to
+        if corr and (probe == Probes.ID or probe == Probes.Calo):
+            if "dRUp" in match:
+                match = "%s_dRUp"%(Matches.ID)
+            elif "dRDown" in match:
+                match = "%s_dRDown"%(Matches.ID)
+            else:
+                match=Matches.ID
+            DataIDHists = TPHistoSet("DataID", var=var, probe=Probes.MStoID, match=match, region=region, infile=ROOT.TFile(infiles[1][1].Filepath, "READ"),useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+            MCIDHists = TPHistoSet("MCID", var=var, probe=Probes.MStoID, match=match, region=region, infile=ROOT.TFile(infiles[0][1].Filepath, "READ"), doClosure=False,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+            MCIDHistsScaled = TPHistoSet("MCID", var=var, probe=Probes.MStoID, match=match, region=region, infile=ROOT.TFile(infiles[0][1].Filepath, "READ"), doClosure=False,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+            #TODO: reinclude ApplyXSScale?
+            #MCIDHists.ApplyXSScale(infiles[0][1].XS, infiles[0][1].nEvents, infiles[0][1].Lumi)
+            MCIDHistsScaled.ScaleToData(DataIDHists)
+            DataIDHists.SubtractBG([DataIDHists.DataDrivenBG(SignalMC=[MCIDHistsScaled],SysVar = sysVar)])
+            MCIDHists.UpdateEff()
+            DataIDHists.UpdateEff()
+
+            DataHists.ApplyIDeff(DataIDHists)
+            MCHists.ApplyIDeff(MCIDHists)
+            
+            
+        # fill probe histos:
+        self.Histos[PlotKinds.Probes]["Data"] = DataHists.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo
+        self.Histos[PlotKinds.Probes]["MC"] = MCHistsScaled.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo
+        self.Histos[PlotKinds.Probes]["Bkg"] = BkgDataHists.Histos[ChargeProducts.OC][PlotKinds.Probes].Histo
+        h_model = self.Histos[PlotKinds.Probes]["MC"].Clone('%s_model'%(self.Histos[PlotKinds.Probes]["MC"].GetName()))
+        h_dataVsModel = self.Histos[PlotKinds.Probes]["Data"].Clone('%s_DataVsModel'%(self.Histos[PlotKinds.Probes]["Data"].GetName()))
+        if not self.Histos[PlotKinds.Probes]["MC"].InheritsFrom("TGraphAsymmErrors"):
+            h_model.SetDirectory(0)
+            h_dataVsModel.SetDirectory(0)
+        h_model.Add(self.Histos[PlotKinds.Probes]["MC"],self.Histos[PlotKinds.Probes]["Bkg"],1.,1.)
+        self.Histos[PlotKinds.Probes]["Model"] = h_model
+        if self.Histos[PlotKinds.Probes]["MC"].InheritsFrom("TH2Poly"):
+            Utils.PolyDivide(self.Histos[PlotKinds.Probes]["Data"],self.Histos[PlotKinds.Probes]["Model"],h_dataVsModel)
+        elif self.Histos[PlotKinds.Probes]["MC"].InheritsFrom("TGraphAsymmErrors"):
+            Utils.GraphDivide(self.Histos[PlotKinds.Probes]["Data"],self.Histos[PlotKinds.Probes]["Model"],h_dataVsModel)
+        else:
+            h_dataVsModel.Divide(self.Histos[PlotKinds.Probes]["Data"],self.Histos[PlotKinds.Probes]["Model"],1.,1.)
+        self.Histos[PlotKinds.Probes]["DataVsModel"] = h_dataVsModel
+
+        # fill efficiency histos:
+        h_data = DataHists.Histos[ChargeProducts.OC][PlotKinds.Efficiency].Histo            
+        self.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency] = h_data
+        h_mc = MCHists.Histos[ChargeProducts.OC][PlotKinds.Efficiency].Histo
+        h_mc.SetName(h_mc.GetName().replace('Efficiency','MCEfficiency'))
+        self.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency] = h_mc
+        h_truth = Truth.Histos[ChargeProducts.OC][PlotKinds.Efficiency].Histo
+        h_truth.SetName(h_truth.GetName().replace('Efficiency','TruthEfficiency'))
+        self.Histos[HistoKinds.Efficiency][HistoKinds.TruthEfficiency] = h_truth
+                
+        # for pre-recommendations, copy negative eta bins of transition region to positive ones:
+        if self.DoPreRecEtaCopy:
+            Utils.CopyEtaBins(h_data)
+            Utils.CopyEtaBins(h_mc)
+            Utils.CopyEtaBins(h_truth)
+
+        # replace 'MCEfficiency' since it was added to h_mc above
+        ratio = h_mc.Clone(h_mc.GetName().replace('MCEfficiency','SF'))
+        ratiotruth = h_truth.Clone(h_mc.GetName().replace('MCEfficiency','SFTruth'))
+        ratiotruthMC = h_truth.Clone(h_mc.GetName().replace('MCEfficiency','SFMCByTruth'))
+        if not h_mc.InheritsFrom("TGraphAsymmErrors"):
+            ratio.SetDirectory(0)
+            ratiotruth.SetDirectory(0)
+            ratiotruthMC.SetDirectory(0)
+
+        if h_mc.InheritsFrom("TH2Poly"):
+            Utils.PolyDivide(h_data,h_mc,ratio)
+            Utils.PolyDivide(h_data,h_truth,ratiotruth)
+            Utils.PolyDivide(h_mc,h_truth,ratiotruthMC)
+        elif h_mc.InheritsFrom("TGraphAsymmErrors"):
+            Utils.GraphDivide(h_data,h_mc,ratio)
+            Utils.GraphDivide(h_data,h_truth,ratiotruth)
+            Utils.GraphDivide(h_mc,h_truth,ratiotruthMC)
+        else:
+            ratio.Divide(h_data,h_mc,1.,1.)
+            ratiotruth.Divide(h_data,h_truth,1.,1.)
+            ratiotruthMC.Divide(h_mc,h_truth,1.,1.)
+        
+        
+        for hist in [ratio,ratiotruth,ratiotruthMC]:
+            for i in range(0, Utils.GetNbins(hist)):
+                if hist.InheritsFrom("TGraphAsymmErrors"):
+                    if hist.GetErrorYhigh(i)>1.0:
+                        hist.SetPointEYhigh(i,1.0)
+                    if hist.GetErrorYlow(i)>1.0:
+                        hist.SetPointEYlow(i,1.0)
+                else:
+                    if hist.GetBinError(i)>1.0:
+                        hist.SetBinError(i,1.0)
+
+        # fill scale factor histos:
+        self.Histos[HistoKinds.SF][HistoKinds.SF] = ratio
+        self.Histos[HistoKinds.SF][HistoKinds.TruthSF] = ratiotruth
+        self.Histos[HistoKinds.SF][HistoKinds.MCTruthSF] = ratiotruthMC
+
+
+class TPFinalSysHistos:
+    def __init__(self,name,probe,match,region,var,infiles,charge=None,corr=True,doClosure=False,LumiScale=-1,doPreRecEtaCopy=False,useAsymEff=True,analysis = Analysis.Z_Reco):
+        self.HistoSets={}
+        self.Name = name
+        self.Probe = probe
+        self.Match = match
+        self.Region = region
+        self.Var = var
+        self.Infiles = infiles
+        self.Charge = charge
+        self.Corr = corr
+        self.Analysis = analysis
+        self.DoClosure = doClosure
+        self.LumiScale = LumiScale
+        self.DoPreRecEtaCopy = doPreRecEtaCopy
+        self.UseAsymEff = useAsymEff
+
+        print '\nCreating TPFinalSysHistos for %s%s'%(var,charge)
+        # fill nominal TPFinalHistos first, since they are needed for systematic evaluation
+        self.HistoSets["Nominal"] = self.CreateTPFinalHistos (self.Name,self.Probe,self.Match,self.Region,self.Var,self.Infiles,None,self.Charge,self.Corr,analysis=self.Analysis)
+
+        for syst in [bla for bla in Systematics.__dict__.keys() if not "__" in bla ]:
+            if Systematics.All != getattr(Systematics,syst):
+                print '\n\n\nSystematic: %s'%getattr(Systematics,syst)
+                self.HistoSets[getattr(Systematics,syst)] = self.CreateTPFinalHistos (self.Name+"_"+syst,self.Probe,self.Match,self.Region,self.Var,self.Infiles,syst,self.Charge,self.Corr,analysis=self.Analysis)
+
+        # fill total systematics histos -> Clone dR syst and add others in quadrature
+        totalSys = []
+        for hist in self.HistoSets[Systematics.dR]:
+            totalSys.append( hist.Clone(hist.GetName().replace(Systematics.dR,Systematics.All)) )
+        self.HistoSets[Systematics.All] = totalSys
+
+        # use add_in_quadrature(hist_add_to, hist_add_this)
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][0],self.HistoSets[Systematics.truth][0])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][0],self.HistoSets[Systematics.BG][0])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][0],self.HistoSets[Systematics.Det][0])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][1],self.HistoSets[Systematics.truth][1])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][1],self.HistoSets[Systematics.BG][1])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][1],self.HistoSets[Systematics.Det][1])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][2],self.HistoSets[Systematics.truth][2])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][2],self.HistoSets[Systematics.BG][2])
+        Utils.add_in_quadrature(self.HistoSets[Systematics.All][2],self.HistoSets[Systematics.Det][2])
+
+    def CreateTPFinalHistos (self,name,probe,match,region,var,infiles,syst,charge,corr,analysis=Analysis.Z_Reco):
+
+        if syst != None:
+            if Systematics.dR == getattr(Systematics,syst):
+                TPFinalHistos_dRup = self.CreateTPHistos(name,probe,match,region,var,infiles,"dRUp",charge,corr)
+                TPFinalHistos_dRDown = self.CreateTPHistos(name,probe,match,region,var,infiles,"dRDown",charge,corr)
+                # compare with nominal:
+                h_dR_sys_data_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_dRup.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_dRDown.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], "dR", 1.)
+                h_dR_sys_mc_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_dRup.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_dRDown.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], "dR", 1.)
+                h_dR_sys_sf = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_dRup.Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_dRDown.Histos[HistoKinds.SF][HistoKinds.SF], "dR", 1.)
+                return [h_dR_sys_data_eff, h_dR_sys_mc_eff, h_dR_sys_sf]
+            elif Systematics.truth == getattr(Systematics,syst):
+                h_truth_sys_data_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.TruthEfficiency], self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], "truth", 1.)
+                h_truth_sys_mc_eff = h_truth_sys_data_eff
+                h_truth_sys_sf = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.TruthSF], self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF], self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF], "truth", 0.5)
+                return [h_truth_sys_data_eff, h_truth_sys_mc_eff, h_truth_sys_sf]
+            elif Systematics.BG == getattr(Systematics,syst):
+                TPFinalHistos_BGUp = self.CreateTPHistos(name,probe,match,region,var,infiles,"BGUp",charge,corr)
+                TPFinalHistos_BGDown = self.CreateTPHistos(name,probe,match,region,var,infiles,"BGDown",charge,corr)
+                # compare with nominal:
+                h_BG_sys_data_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_BGUp.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_BGDown.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], "BG", 1.)
+                h_BG_sys_mc_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_BGUp.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_BGDown.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], "BG", 1.)
+                h_BG_sys_sf = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_BGUp.Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_BGDown.Histos[HistoKinds.SF][HistoKinds.SF], "BG", 1.)
+                return [h_BG_sys_data_eff, h_BG_sys_mc_eff, h_BG_sys_sf]
+            elif Systematics.Det == getattr(Systematics,syst):
+                # detector systematic compares MC14 vs MC15
+                if "MC14" in infiles[0][1].Label:
+                    #print "use %s for detector systematic evaluation"%DSConfig.Zmumu_mc15.Filepath
+                    TPFinalHistos_MC15 = self.CreateTPHistos(name,probe,match,region,var,[["MC",DSConfig.Zmumu_mc15],self.Infiles[1]],None,charge,corr,doPreRecCopy=False)
+                else:
+                    #print "use %s for detector systematic evaluation"%DSConfig.Zmumu_r20_1_3_3.Filepath
+                    TPFinalHistos_MC15 = self.CreateTPHistos(name,probe,match,region,var,[["MC",DSConfig.Zmumu_mc15],self.Infiles[1]],None,charge,corr,doPreRecCopy=False)
+                # compare with MC14:
+                h_Det_sys_data_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_MC15.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], TPFinalHistos_MC15.Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency], "Det", 1.)
+                h_Det_sys_mc_eff = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_MC15.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], TPFinalHistos_MC15.Histos[HistoKinds.Efficiency][HistoKinds.MCEfficiency], "Det", 1.)
+                h_Det_sys_sf = Utils.sysCompare(self.HistoSets["Nominal"].Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_MC15.Histos[HistoKinds.SF][HistoKinds.SF], TPFinalHistos_MC15.Histos[HistoKinds.SF][HistoKinds.SF], "Det", 1.)
+                return [h_Det_sys_data_eff, h_Det_sys_mc_eff, h_Det_sys_sf]
+            else:
+                print 'CreateTPFinalHistos() was called with unknown systematic type: %s! Abort!'%(syst)
+                return None
+        else:
+            return self.CreateTPHistos(name,probe,match,region,var,infiles,syst,charge,corr)
+
+    def CreateTPHistos (self,name,probe,match,region,var,infiles,syst,charge,corr,doPreRecCopy=True):
+
+        if charge != None:
+            if "pos" in charge:
+                var = var+"_posq"
+            elif "neg" in charge:
+                var = var+"_negq"
+            else:
+                print "Error: charge %s not recognized!"%(charge)
+                return None
+
+        BGvar = ""
+        if syst == "BGUp":
+            BGvar = "up"
+        elif syst == "BGDown":
+            BGvar = "down"
+
+        if syst == "dRUp":
+            match = "%s_dRUp"%(match)
+        elif syst == "dRDown":
+            match = "%s_dRDown"%(match)
+
+        name = 'hists_%s_%s_%s_%s'%(var, probe, match, syst)
+
+        if not doPreRecCopy:
+            print 'doing MC15 systematic: set doPreRecCopy to False'
+            return TPFinalHistos(name,probe,match,region,var,infiles,sysVar = BGvar,doClosure=self.DoClosure,LumiScale=self.LumiScale,doPreRecEtaCopy=False,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+        else:
+            return TPFinalHistos(name,probe,match,region,var,infiles,sysVar = BGvar,doClosure=self.DoClosure,LumiScale=self.LumiScale,doPreRecEtaCopy=self.DoPreRecEtaCopy,useAsymEff=self.UseAsymEff,analysis=self.Analysis)
+
+
+########## some testing code ##############
+if __name__ == "__main__":
+    bla = TPHisto (name="Test",probe = Probes.ID, match = Matches.Medium, region = DetRegions.All, kind = PlotKinds.Efficiency, var = "eta", chargeprod = ChargeProducts.OC)
+
+
+    #print bla.GetFullPath()
+    #print bla.GetFullTreePath()
+
+    import ROOT
+    #f = ROOT.TFile.Open("/afs/ipp-garching.mpg.de/home/g/goblirsc/analysis/TP_nightly/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonPerformanceAlgs/run/test.merge.root","READ")
+
+    #bla.ExtractFromTree(f)
+
+    #bla2 = TPHisto (name="Test",probe = Probes.ID, match = Matches.Medium, region = DetRegions.All, kind = PlotKinds.Efficiency, var = "eta", chargeprod = ChargeProducts.OC,infile=ROOT.TFile.Open("/afs/ipp-garching.mpg.de/home/g/goblirsc/analysis/TP_nightly/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonPerformanceAlgs/run/test.merge.root","READ"))
+
+
+    #print f.Get(bla.GetFullTreePath())
+
+    ##print [bla for bla in Matches.__dict__.keys() if not "__" in bla ]
+    #import ROOT
+    #moo = ROOT.TH1F(bla.GetPlotName(),bla.GetFullPath(),100,0,1)
+    #hist2 = TPHisto.FromHist("TestMC2",moo,None)
+    #print hist2.GetPlotName()
+    #print hist2.Histo.GetName()
+    #hist2.Write(ROOT.TFile("out.root","RECREATE"),"Test/Dir/Structure")
+
+    #bla.Load(ROOT.TFile("out.root","READ"),"Test/Dir/Structure")
+    #print bla.Histo
+
+
+
+    ## Larger scale test
+    infile = ROOT.TFile("/afs/ipp-garching.mpg.de/home/g/goblirsc/analysis/TP_nightly/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonPerformanceAlgs/run/test.merge.root")
+    aset = TPHistoSet("Blah",probe=Probes.ID, match = Matches.Medium, region = DetRegions.All, var = "etaphi", infile = infile,analysis=self.Analysis)
+    can = ROOT.TCanvas()
+    can.cd()
+    ROOT.gStyle.SetPalette(54)
+    ROOT.gPad.SetRightMargin(0.2)
+    aset.Histos[ChargeProducts.OC][PlotKinds.Efficiency].Histo.Draw("COLZ")
+    #can.SaveAs("test.pdf")
+    #for kind,hist in aset.Histos["OC"].iteritems():
+        #hist.Histo.Add(aset.Histos["SC"][kind].Histo,-1)
+    #aset.UpdateEff()
+    ##aset.Histos["OC"]["Probes"].Histo.Draw()
+    #aset.Histos["OC"]["Efficiency"].Histo.Draw()
+    can.SaveAs("Plots/test.pdf")
+
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/PlotUtils.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/PlotUtils.py
new file mode 100644
index 00000000000..c53d86c3276
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/PlotUtils.py
@@ -0,0 +1,281 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import ROOT, math
+from Defs import * 
+
+class PlotUtils:
+    def __init__(self,size=0.042,status="Internal", lumi = "20.3", sqrts = "13"):
+        self.Status = status
+        self.Size = size
+        self.Lumi = lumi # in fb^-1
+        self.SqrtS = sqrts
+        self.VerticalCanvasSplit = 0.4
+        self.Objects = []
+        
+    def DrawTLatex(self, x,y,text,size=0.042,font=42,align=11):
+        tex = ROOT.TLatex()
+        tex.SetTextAlign(align)
+        tex.SetTextSize(size)
+        tex.SetTextFont(font)
+        tex.SetNDC()
+        self.Objects.append(tex)
+        tex.DrawLatex(x,y,text)
+        
+    def DrawAtlas(self, x,y,align=11):
+        self.DrawTLatex(x,y,"#font[72]{ATLAS} %s"%self.Status,self.Size,42,align)
+    def DrawLumiSqrtS(self,x,y,align=11,lumi="20.3"):
+        if self.Lumi < 0.001:
+            lumiToPrint = "%.1f"%(self.Lumi*1e6)
+            self.DrawTLatex(x,y,"#sqrt{s} = %s TeV, %s nb^{-1}"%(self.SqrtS, lumiToPrint),self.Size,42,align)
+        elif  self.Lumi < 1.:
+            lumiToPrint = "%.1f"%(self.Lumi*1e3)
+            self.DrawTLatex(x,y,"#sqrt{s} = %s TeV, %s pb^{-1}"%(self.SqrtS, lumiToPrint),self.Size,42,align)
+        else:
+            lumiToPrint = "%.1f"%(self.Lumi)
+            self.DrawTLatex(x,y,"#sqrt{s} = %s TeV, %s fb^{-1}"%(self.SqrtS, lumiToPrint),self.Size,42,align)
+    def DrawLumiSqrtSEvolution(self,x,y,align=11,lumi="20.3"):
+        self.DrawTLatex(x,y,"#sqrt{s} = %s TeV, %s pb^{-1}"%(self.SqrtS,lumi),self.Size,42,align)
+    def DrawSource(self,probe,x,y,align=11):
+        text = ""
+        if probe == Probes.ID:
+            text = "ID Probes"
+        if probe == Probes.Calo:
+            text = "CaloTag Probes"
+        if probe == Probes.MStoID or probe == Probes.MStoMu:
+            text = "MS Probes"
+        if probe == Probes.TruthToID or probe == Probes.TruthToMu:
+            text = "Truth Efficiencies"
+        self.DrawTLatex(x,y,text,self.Size,52,align)
+    def DrawTarget(self,match,x,y,align=11):
+        text = ""
+        if match == Matches.Calo:
+            text = "CaloTag Muons"
+        if match == Matches.CB:
+            text = "Combined Muons"
+        if match == Matches.Loose:
+            text = "Loose Muons"
+        if match == Matches.LooseNoCalo:
+            text = "Loose Muons (no CaloTag)"
+        if match == Matches.Medium:
+            text = "Medium Muons"
+        if match == Matches.Tight:
+            text = "Tight Muons"
+        if match == Matches.ID:
+            text = "ID Tracks"
+        self.DrawTLatex(x,y,text,self.Size,42,align)
+        
+    def DrawLegend (self,histos,x1,y1,x2,y2):
+        leg = ROOT.TLegend(x1,y1,x2,y2)
+        self.Objects.append(leg)
+        leg.SetFillStyle(0)
+        leg.SetBorderSize(0)
+        leg.SetTextFont(42)
+        for histo in histos:
+            #if histo.GetFillColor() != ROOT.kBlack:
+                #leg.AddEntry(histo,histo.GetTitle(),"F")
+            #else:
+            leg.AddEntry(histo[0],histo[0].GetTitle(),histo[1])
+        leg.Draw()
+        
+    def Prepare2PadCanvas(self, cname, width=800, height=800):
+        can = ROOT.TCanvas(cname,cname,width,height)
+        self.Objects.append(can)
+        p1 = ROOT.TPad("p1_"+cname,cname,0.0,self.VerticalCanvasSplit,1.0,1.0)
+        p2 = ROOT.TPad("p2_"+cname,cname,0.0,0.0,1.0,self.VerticalCanvasSplit)
+        p1.SetBottomMargin(0)
+        p1.SetTopMargin(0.09)
+        p2.Draw()
+        p2.SetTopMargin(0)
+        p2.SetBottomMargin(0.4)
+        p2.SetGridy()
+        self.Objects.append(can)
+        self.Objects.append(p1)
+        self.Objects.append(p2)
+        can.cd()
+        p1.Draw()
+        p2.Draw()
+        return [can,p1,p2]
+    
+    def AdaptLabelsTopPad (self,histos):
+        labelscalefact = 1. / (1. - self.VerticalCanvasSplit)
+        for hist in histos:
+            hist.GetXaxis().SetTitleSize(labelscalefact * hist.GetXaxis().GetTitleSize())
+            hist.GetYaxis().SetTitleSize(labelscalefact * hist.GetYaxis().GetTitleSize())
+            hist.GetXaxis().SetLabelSize(labelscalefact * hist.GetXaxis().GetLabelSize())
+            hist.GetYaxis().SetLabelSize(labelscalefact * hist.GetYaxis().GetLabelSize())
+            hist.GetXaxis().SetTitleOffset(1./labelscalefact * hist.GetXaxis().GetTitleOffset())
+            hist.GetYaxis().SetTitleOffset(1./labelscalefact * hist.GetYaxis().GetTitleOffset())
+    
+    def AdaptLabelsBottomPad (self,histos):
+        labelscalefact = 1. / (self.VerticalCanvasSplit)
+        for hist in histos:
+            hist.GetXaxis().SetTitleSize(labelscalefact * hist.GetXaxis().GetTitleSize())
+            hist.GetYaxis().SetTitleSize(labelscalefact * hist.GetYaxis().GetTitleSize())
+            hist.GetXaxis().SetLabelSize(labelscalefact * hist.GetXaxis().GetLabelSize())
+            hist.GetYaxis().SetLabelSize(labelscalefact * hist.GetYaxis().GetLabelSize())
+            #hist.GetXaxis().SetTitleOffset(1./labelscalefact * hist.GetXaxis().GetTitleOffset())
+            hist.GetYaxis().SetTitleOffset(1.1/labelscalefact * hist.GetYaxis().GetTitleOffset())
+            
+    def SetFancyAxisRanges_SF (self,histos,minmax=1.0,maxmin=0.9,fixRange=False):
+        ymin = maxmin
+        ymax = minmax
+        
+        finalRanges = []
+        
+        if fixRange:
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin - (0.5 * abs(1. - ymin)),ymax + 0.5 * abs(ymax - 1))
+                #histo.GetYaxis().SetRangeUser(0.925,1.075)
+                #histo.GetYaxis().SetRangeUser(0.4,1.6)
+                histo.GetYaxis().SetNdivisions(3,ROOT.kTRUE)
+            # not yet clear yet how to apply this on the y-axis only
+            ROOT.TGaxis.SetMaxDigits(3)
+            finalRanges.append([ymin,ymax])
+        else:
+        
+            for histo in histos:
+                if histo.InheritsFrom("TGraphAsymmErrors"):
+                    if (ROOT.TMath.MaxElement(histo.GetN(),histo.GetY())<1.4) and (ROOT.TMath.MaxElement(histo.GetN(),histo.GetY()) > ymax):
+                        ymax = ROOT.TMath.MaxElement(histo.GetN(),histo.GetY())
+                    if (ROOT.TMath.MinElement(histo.GetN(),histo.GetY())>0.6) and (ROOT.TMath.MinElement(histo.GetN(),histo.GetY()) < ymin):
+                        ymin = ROOT.TMath.MinElement(histo.GetN(),histo.GetY())
+                else:
+                    if histo.GetMaximum(1.4) > ymax:
+                        ymax = histo.GetMaximum(1.4)
+                    if histo.GetMinimum(0.6) < ymin:
+                        ymin = histo.GetMinimum(0.6)
+                    
+            GoodStops = [0.0,0.3,0.4,0.5,0.65,0.7,0.75,0.8,0.9,0.95,0.98,0.99,0.995,1.005,1.01,1.02,1.05,1.1,1.2,1.25,1.3,1.35,1.5,1.6,1.7,1.72]
+            
+            ymaxl = [p for p in GoodStops  if p + 0.5 * abs(p - 1) > ymax]
+            if len (ymaxl) > 0:
+                ymax = ymaxl[0]
+            yminl = [p for p in GoodStops if p- 0.5 * abs(p - 1)  < ymin ]
+            if len (yminl) > 0:
+                ymin = yminl[-1]
+                            
+            ymin = 1. - max (abs(1.-ymax), abs(1.-ymin))
+            ymax = 1. + (1.-ymin)
+            
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin - (0.5 * abs(1. - ymin)),ymax + 0.5 * abs(ymax - 1))
+                histo.GetYaxis().SetNdivisions(3,ROOT.kTRUE)
+            # not yet clear yet how to apply this on the y-axis only
+            ROOT.TGaxis.SetMaxDigits(3)
+            finalRanges.append([ymin,ymax])
+        return finalRanges
+    
+    def SetFancyAxisRanges_SF_Probes (self,histos,minmax=1.0,maxmin=0.9,fixRange=False):
+        ymin = maxmin
+        ymax = minmax
+        
+        finalRanges = []
+        
+        if fixRange:
+            if ymin < .334:
+                histo.GetYaxis().SetRangeUser(ymin - 0.05,ymax + 0.05)
+            else:
+                for histo in histos:
+                    histo.GetYaxis().SetRangeUser(ymin - (0.5 * abs(1. - ymin)),ymax + 0.5 * abs(ymax - 1))
+                    histo.GetYaxis().SetNdivisions(3,ROOT.kTRUE)
+                    # show exponent (smaller numbers) but shift it away
+                    histo.GetXaxis().SetNoExponent(ROOT.kFALSE)
+            # not yet clear yet how to apply this on the y-axis only
+            ROOT.TGaxis.SetMaxDigits(3)
+            ROOT.TGaxis.SetExponentOffset(1.)
+            finalRanges.append([ymin,ymax])
+        else:
+            for histo in histos:
+                histo.GetXaxis().SetNoExponent(ROOT.kTRUE)
+                if histo.InheritsFrom("TGraphAsymmErrors"):
+                    if (ROOT.TMath.MaxElement(histo.GetN(),histo.GetY())<1.9) and (ROOT.TMath.MaxElement(histo.GetN(),histo.GetY()) > ymax):
+                        ymax = ROOT.TMath.MaxElement(histo.GetN(),histo.GetY())
+                    if (ROOT.TMath.MinElement(histo.GetN(),histo.GetY())>0.1) and (ROOT.TMath.MinElement(histo.GetN(),histo.GetY()) < ymin):
+                        ymin = ROOT.TMath.MinElement(histo.GetN(),histo.GetY())
+                else:
+                    if histo.GetMaximum(1.9) > ymax:
+                        ymax = histo.GetMaximum(1.9)
+                    if histo.GetMinimum(0.1) < ymin:
+                        ymin = histo.GetMinimum(0.1)
+                    
+            GoodStops = [0.0,0.1,0.3,0.4,0.5,0.65,0.7,0.75,0.8,0.9,0.95,0.98,0.99,0.995,1.005,1.01,1.02,1.05,1.1,1.2,1.25,1.3,1.35,1.5,1.6,1.7,1.9,1.72]
+            
+            ymaxl = [p for p in GoodStops  if p + 0.5 * abs(p - 1) > ymax]
+            if len (ymaxl) > 0:
+                ymax = ymaxl[0]
+            yminl = [p for p in GoodStops if p- 0.5 * abs(p - 1)  < ymin ]
+            if len (yminl) > 0:
+                ymin = yminl[-1]
+                            
+            ymin = 1. - max (abs(1.-ymax), abs(1.-ymin))
+            ymax = 1. + (1.-ymin)
+            
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin - (0.5 * abs(1. - ymin)),ymax + 0.5 * abs(ymax - 1))
+                histo.GetYaxis().SetNdivisions(3,ROOT.kTRUE)
+            # not yet clear yet how to apply this on the y-axis only
+            #ROOT.TGaxis.SetMaxDigits(2)
+            finalRanges.append([ymin,ymax])
+        return finalRanges
+
+    def SetFancyAxisRanges_Eff (self,histos,isSym=False,maxmin=0.9,fixRange=False):
+        ymin = maxmin
+        finalRanges = []
+
+        if fixRange:
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin,1.001)
+                histo.GetYaxis().SetNdivisions(4)
+                histo.GetXaxis().SetNoExponent(ROOT.kTRUE)
+            finalRanges.append([ymin])
+        else:
+            for histo in histos:
+                histo.GetXaxis().SetNoExponent(ROOT.kTRUE)
+                if histo.InheritsFrom("TGraphAsymmErrors"):
+                    if (ROOT.TMath.MinElement(histo.GetN(),histo.GetY())>0.4) and (ROOT.TMath.MinElement(histo.GetN(),histo.GetY()) < ymin):
+                        ymin = ROOT.TMath.MinElement(histo.GetN(),histo.GetY())
+                else:
+                    if histo.GetMinimum(0.4) < ymin:
+                        ymin = histo.GetMinimum(0.4)
+                
+            GoodStops = [0.01,0.401,0.501,0.601,0.701,0.801,0.851,0.931]
+
+            yminl = [p for p in GoodStops if p < ymin]
+            if len (yminl) > 0:
+                ymin = yminl[-1]
+
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin,1.001)
+                histo.GetYaxis().SetNdivisions(4)
+            finalRanges.append([ymin])
+
+        return finalRanges
+
+    def SetFancyAxisRanges (self,histos,maxmin=0.2,minmax=1.01,fixRange=False):
+        ymin = maxmin
+        ymax = minmax
+        finalRanges = []
+
+        if fixRange:
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin,ymax)
+            
+        else:
+            for histo in histos:
+                if histo.GetMinimum(0.4) < ymin:
+                    ymin = histo.GetMinimum(0.4)
+                if histo.GetMaximum()>ymax:
+                    ymax = histo.GetMaximum()*1.5
+
+            GoodStops = [0.01,0.401,0.501,0.601,0.701,0.801,0.901]
+
+            yminl = [p for p in GoodStops if p < ymin]
+            if len (yminl) > 0:
+                ymin = yminl[-1]
+
+            for histo in histos:
+                histo.GetYaxis().SetRangeUser(ymin,ymax)
+            finalRanges.append([ymin,ymax])
+            
+        return finalRanges
+            
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/ProbePlots.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/ProbePlots.py
new file mode 100644
index 00000000000..c67067f94d3
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/ProbePlots.py
@@ -0,0 +1,254 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import Histos
+import ROOT
+import DSConfig
+import Utils
+import sys
+from Defs import *
+from PlotUtils import PlotUtils
+ROOT.gROOT.Macro("rootlogon.C")
+ROOT.gROOT.SetStyle("ATLAS")
+ROOT.gROOT.SetBatch(1)
+
+histos = []
+eff_axis_ranges = []
+sf_axis_ranges = []
+
+def draw2D (hist, var, probe, match, region, conf_Data):
+    
+    pu = PlotUtils()
+    pu.Size = 0.06*(1-pu.VerticalCanvasSplit)
+    pu.Lumi = conf_Data.Lumi/1000.
+    
+    ROOT.gStyle.SetPalette(54)
+    
+    can = ROOT.TCanvas("ProbeCheck_%s_%s_%s_%s"%(var,probe,region,hist[0]),PlotKinds.Probes,800,600)
+    can.cd()
+    can.SetTopMargin(0.15)
+    can.SetRightMargin(0.2)
+    can.SetLeftMargin(0.12)
+
+    if "DataSM" in hist[0]:
+        hist[1].GetZaxis().SetTitle("Data/SM")
+    else:
+        hist[1].GetZaxis().SetTitle(PlotKinds.Probes+" "+hist[0])
+        
+    hist[1].Draw("colz")
+    hist[1].GetYaxis().SetTitleOffset(0.7*hist[1].GetYaxis().GetTitleOffset())
+    hist[1].GetZaxis().SetTitleOffset(1.5*hist[1].GetZaxis().GetTitleOffset())
+    # need to find a better way to do this:
+    hist[1].GetZaxis().SetLabelSize(hist[1].GetYaxis().GetLabelSize())
+    hist[1].GetZaxis().SetTitleSize(hist[1].GetYaxis().GetTitleSize())
+    
+    pu.DrawAtlas(can.GetLeftMargin(),0.92)
+    pu.DrawLumiSqrtS(can.GetLeftMargin(),0.87)
+    #pu.DrawTarget(match,1-can.GetRightMargin(),0.92,31)
+    pu.DrawSource(probe,1-can.GetRightMargin(),0.87,31)
+    
+    can.SaveAs ("Plots/ProbeCheck_%s_%s_%s_%s.pdf"%(var,probe,region,hist[0]))
+    
+    pu.DrawTLatex(0.5,0.94,"%s for %s probes in %s %s"%(var,probe,region,hist[0]),0.04,52,22)
+
+    can.SaveAs("Plots/AllProbePlots.pdf")
+    
+def doProbePlots1D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, log):
+
+    if len(hists_final)>1:
+        print 'Error: Something went wrong in TPFinalHistos()!'
+        sys.exit(1)
+    else:
+        h_data = hists_final[0].Histos[PlotKinds.Probes]["Data"]
+        h_bkg = hists_final[0].Histos[PlotKinds.Probes]["Bkg"]
+        h_mc = hists_final[0].Histos[PlotKinds.Probes]["MC"]
+        h_model = hists_final[0].Histos[PlotKinds.Probes]["Model"]
+        ratio = hists_final[0].Histos[PlotKinds.Probes]["DataVsModel"]
+    
+    ######
+    # used for styling histo (when TGraphAsymmErrors are used)
+    h_styling = HistoDefs.initHisto(var)[0].Clone("stylingHisto")
+    # from print in Histos.py:
+    h_styling.GetXaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetXaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetXaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetXaxis().SetLabelOffset(0.00499999988824)
+    h_styling.GetYaxis().SetTitleSize(0.0500000007451)
+    h_styling.GetYaxis().SetTitleOffset(1.39999997616)
+    h_styling.GetYaxis().SetLabelSize(0.0500000007451)
+    h_styling.GetYaxis().SetLabelOffset(0.00499999988824)
+
+    h_styling_ratio = h_styling.Clone("stylingHistoRatio")
+    h_styling_ratio.GetYaxis().SetTitle("Data/SM")
+    
+    h_styling.GetYaxis().SetTitle("Probes")
+    ######
+    
+    pu = PlotUtils()
+    pu.Size = 0.06
+    pu.Lumi = conf_Data.Lumi/1000.
+    pu.SqrtS = 13
+    
+    can,p1,p2 = pu.Prepare2PadCanvas("ProbeCheck_%s_%s_%s"%(var,probe,region))
+    can.cd()
+    p1.Draw()
+    histos.append(p1)
+    histos.append(p2)
+    histos.append(can)
+    p1.cd()
+    
+    
+    # plotting style:
+    h_data.SetMarkerStyle(ROOT.kFullDotLarge)
+    h_data.SetLineColor(ROOT.kBlack)
+    h_data.SetMarkerColor(h_data.GetLineColor())
+    h_data.SetTitle(conf_Data.Label)
+    ratio.SetMarkerStyle(ROOT.kFullDotLarge)
+    ratio.SetLineColor(h_data.GetLineColor())
+    ratio.SetMarkerColor(h_data.GetLineColor())
+    h_bkg.SetLineColor(ROOT.kOrange-2)
+    h_bkg.SetFillColor(h_bkg.GetLineColor())
+    h_bkg.SetTitle("Data-driven Background")
+    h_mc.SetLineColor(ROOT.kBlue-9)
+    h_mc.SetFillColor(h_mc.GetLineColor())
+    h_mc.SetTitle(conf_Zmumu.Label)
+
+    if (log):
+        p1.SetLogy()
+        
+    stk = ROOT.THStack("Stack","Stack")
+    stk.Add(h_bkg)
+    stk.Add(h_mc)
+    stk.Draw("HIST")
+    
+    ######
+    # labels and axis ranges
+    pu.AdaptLabelsTopPad([h_styling,stk.GetHistogram(),h_data,h_bkg,h_mc])
+    eff_axis_ranges.append(pu.SetFancyAxisRanges([stk.GetHistogram(), h_data, h_bkg, h_mc]))
+    pu.SetFancyAxisRanges([h_styling], minmax = eff_axis_ranges[0][0][1], maxmin = eff_axis_ranges[0][0][0], fixRange=True)
+    ######
+
+    h_styling.Draw("AXIS")
+    
+    if(log):
+        stk.SetMinimum(5e-1)
+        stk.GetHistogram().SetMaximum(1e3*stk.GetMaximum())
+        
+    stk.Draw("sameHIST")
+    h_data.Draw("same")
+    
+    pu.DrawAtlas(0.19,0.83)
+    pu.DrawLumiSqrtS(0.19,0.76)
+    pu.DrawLegend([(h_data,"PL"), (h_mc,"F"), (h_bkg,"F")],0.6,0.6,0.89,0.89)
+
+    p2.cd()
+    p2.SetGridy()
+    
+    ######
+    # labels and axis ranges
+    pu.AdaptLabelsBottomPad([h_styling_ratio,ratio])
+    sf_axis_ranges.append(pu.SetFancyAxisRanges_SF_Probes([ratio]))
+    pu.SetFancyAxisRanges_SF_Probes([h_styling_ratio], minmax = sf_axis_ranges[0][0][1], maxmin = sf_axis_ranges[0][0][0], fixRange=True)
+    ######
+    
+    h_styling_ratio.Draw("AXIS")
+    ratio.Draw("same")
+    
+    can.SaveAs ("Plots/ProbeCheck_%s_%s_%s.pdf"%(var,probe,region))
+    p1.cd()
+    
+    pu.DrawTLatex(0.5,0.94,"%s for %s probes in %s"%(var,probe,region),0.04,52,22)
+
+    can.SaveAs("Plots/AllProbePlots.pdf")
+    
+def doProbePlots2D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, log):
+    
+    if len(hists_final)>1:
+        print 'Error: Something went wrong in TPFinalHistos()!'
+        sys.exit(1)
+    else:
+        h_data = hists_final[0].Histos[PlotKinds.Probes]["Data"]
+        h_bkg = hists_final[0].Histos[PlotKinds.Probes]["Bkg"]
+        h_mc = hists_final[0].Histos[PlotKinds.Probes]["MC"]
+        h_model = hists_final[0].Histos[PlotKinds.Probes]["Model"]
+        ratio = hists_final[0].Histos[PlotKinds.Probes]["DataVsModel"]
+        
+    
+    draw2D (["Data",h_data], var, probe, match, region, conf_Data)
+    draw2D (["SM",h_model], var, probe, match, region, conf_Data)
+    draw2D (["DataSM",ratio], var, probe, match, region, conf_Data)
+
+def doProbePlots (var, probe, region, conf_Data, conf_Zmumu, log=True):
+    
+    match = Matches.Medium
+    if probe == Probes.MStoMu:
+        match = Matches.Calo
+        
+    infiles = [
+                   ["MC",conf_Zmumu],
+                   ["Data",conf_Data]
+                   ]
+
+    hists_final = []
+    
+    # faster (without systematic uncertainty bands):
+    hists_final.append(Histos.TPFinalHistos("test",probe,match,region,var,infiles,useAsymEff=False))
+
+    if hists_final[0].Histos[HistoKinds.Efficiency][HistoKinds.DataEfficiency].InheritsFrom("TH2"):
+        doProbePlots2D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, log)
+    else:
+        doProbePlots1D (hists_final, var, probe, match, region, conf_Data, conf_Zmumu, log)
+
+    
+if __name__ == "__main__":
+    
+    # what we want to run on:
+    InputData = DSConfig.Data_15_firstWeek
+    InputZmumu = DSConfig.Zmumu_mc15
+
+    dummy = ROOT.TCanvas("dummy","dummy",800,800)
+    dummy.SaveAs("Plots/AllProbePlots.pdf[")
+    
+    # variables we want to plot:
+    #doProbePlots ("etaphiFine", Probes.ID, DetRegions.All, InputData, InputZmumu, log=False)
+    #doProbePlots ("mll", Probes.ID, DetRegions.All, InputData, InputZmumu, log=False)
+    #doProbePlots ("pt", Probes.ID, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("eta", Probes.ID, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("d0", Probes.ID, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("z0", Probes.ID, DetRegions.All, InputData, InputZmumu)
+
+    doProbePlots ("etaphiFine", Probes.Calo, DetRegions.All, InputData, InputZmumu, log=False)
+    doProbePlots ("mll", Probes.Calo, DetRegions.All, InputData, InputZmumu, log=False)
+    doProbePlots ("pt", Probes.Calo, DetRegions.All, InputData, InputZmumu)
+    doProbePlots ("eta", Probes.Calo, DetRegions.All, InputData, InputZmumu)
+    doProbePlots ("d0", Probes.Calo, DetRegions.All, InputData, InputZmumu)
+    doProbePlots ("z0", Probes.Calo, DetRegions.All, InputData, InputZmumu)
+
+    #doProbePlots ("etaphiFine", Probes.MStoMu, DetRegions.All, InputData, InputZmumu, log=False)
+    #doProbePlots ("mll", Probes.MStoMu, DetRegions.All, InputData, InputZmumu, log=False)
+    #doProbePlots ("pt", Probes.MStoMu, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("eta", Probes.MStoMu, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("d0", Probes.MStoMu, DetRegions.All, InputData, InputZmumu)
+    #doProbePlots ("z0", Probes.MStoMu, DetRegions.All, InputData, InputZmumu)
+    
+    #doProbePlots ("etaphiFine", Probes.ID, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("mll", Probes.ID, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("pt", Probes.ID, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("eta", Probes.ID, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("d0", Probes.ID, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("z0", Probes.ID, DetRegions.noCrack, InputData, InputZmumu)
+
+    #doProbePlots ("etaphiFine", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("mll", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("pt", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("eta", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("d0", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("z0", Probes.Calo, DetRegions.noCrack, InputData, InputZmumu)
+
+    #doProbePlots ("etaphiFine", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("mll", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu, log=False)
+    #doProbePlots ("pt", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("eta", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("d0", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu)
+    #doProbePlots ("z0", Probes.MStoMu, DetRegions.noCrack, InputData, InputZmumu)
+
+    dummy.SaveAs("Plots/AllProbePlots.pdf]")
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/TestRecoSF.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/TestRecoSF.py
new file mode 100644
index 00000000000..637c9e5ce15
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/TestRecoSF.py
@@ -0,0 +1,71 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+###################################################
+# Simple macro to test reco SF files
+# 20.6.2015, goblirsc<at>cern.ch
+###################################################
+
+import ROOT 
+import os
+import commands
+import math
+import sys
+
+ROOT.gROOT.Macro("rootlogon.C")
+ROOT.gROOT.SetStyle("ATLAS")
+ROOT.gROOT.SetBatch(1)
+def GetHistos(histo, histosys, biny, binz):
+    hname = histo.GetName()+"_%i_%i"%(biny,binz)
+    hproj = histo.ProjectionX(hname,biny,biny,binz,binz)
+    hproj.SetDirectory(0)
+    hproj_sys = histosys.ProjectionX(hname+"Sys",biny,biny,binz,binz)
+    hproj_sys.SetDirectory(0)
+    for k in range (hproj_sys.GetNbinsX()+1):
+        hproj.SetBinContent(k,hproj.GetBinContent(k) + 0.1 * (biny - 1))
+        syserr = hproj_sys.GetBinContent(k)
+        hproj_sys.SetBinContent(k,hproj.GetBinContent(k))
+        hproj_sys.SetBinError(k,syserr)
+    
+        
+    return [hproj, hproj_sys]
+
+def DrawCheckPlot(histo, histo_sys):
+    plots = []
+    hname = histo.GetName()
+    for h in range (1,histo.GetNbinsZ()+1):
+        can = ROOT.TCanvas("can_%i"%h,"can",800,600)
+        can.cd()
+        leg = ROOT.TLegend(0.1,0.75,0.8,0.95)
+        leg.SetBorderSize(0)
+        leg.SetNColumns(3)
+        leg.SetFillStyle(0)
+        first = True
+        colours = [ROOT.kBlue-1, ROOT.kGreen-2, ROOT.kRed-2,ROOT.kOrange-3,ROOT.kCyan, ROOT.kMagenta+1]
+        for g in range (1,histo.GetNbinsY()+1):
+                subhistos = GetHistos(histo,histo_sys,g,h)
+                subhistos[0].SetMarkerStyle(ROOT.kDot)
+                subhistos[1].SetFillColor(colours[g])
+                plots.append(subhistos)
+                if first:
+                    subhistos[1].GetYaxis().SetRangeUser(0.9,2.)
+                    subhistos[1].Draw("E2")
+                    first = False
+                else:
+                    subhistos[1].Draw("E2same")
+                subhistos[0].Draw("same")
+                if g < histo.GetNbinsY():
+                    leg.AddEntry(subhistos[1],"%.1f GeV < pt < %.1f GeV"%(histo.GetYaxis().GetBinLowEdge(g),(histo.GetYaxis().GetBinUpEdge(g))))
+                else:
+                    leg.AddEntry(subhistos[1],"%.1f GeV < pt"%(histo.GetYaxis().GetBinLowEdge(g)))
+        chargesuff = "_posq"
+        leg.Draw()
+        if histo.GetZaxis().GetBinCenter(h) < 0:
+            chargesuff = "_negq"
+        can.SaveAs("Plots/SF_Check_%s%s.pdf"%(hname,chargesuff))
+    
+if __name__ == "__main__":
+    inf = sys.argv[-1]
+    rf = ROOT.TFile.Open(inf,"READ")
+    hsf = rf.Get("SF_All")
+    hsys = rf.Get("SF_sys_All")
+    DrawCheckPlot(hsf,hsys)
\ No newline at end of file
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Utils.py b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Utils.py
new file mode 100644
index 00000000000..1d6996a5762
--- /dev/null
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/macros/Utils.py
@@ -0,0 +1,253 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+import math, ROOT
+import inspect
+from array import array 
+
+
+## use PrintFrame() for debugging
+def PrintFrame():   
+    callerframerecord = inspect.stack()[1]      # 0 represents this line
+                                                # 1 represents line at caller
+    frame = callerframerecord[0]
+    info = inspect.getframeinfo(frame)
+    #print info.filename                       # __FILE__     -> Test.py
+    #print info.function                       # __FUNCTION__ -> Main
+    print info.lineno
+
+## Some utility methods used for the Z TP
+def CalcEff (probes,matches):
+    t = probes[0]
+    dt = probes[1]
+    h = matches[0]
+    dh = matches[1]
+    #print "++++++++++++++++++ got %.4f +/- %.4f trials, %.5f / %.4f matches"%(t,dt,h,dh)
+    if t == 0:
+        return [1.0,1.0]
+        #t = 1
+    m = t - h
+    #print "dt = %.4f, dh = %.4f"%(dt,dh)
+    dm = math.sqrt(abs(dt*dt-dh*dh))
+    #print "        ++++++++++++++++++ and got %.4f +/- %.4f misses"%(m,dm)
+    eff = h/t
+    deff = math.sqrt(abs(((h*dm)**2+(m*dh)**2)/(t**4)))
+    #print "        ++++++++++++++++++ Eff is %.4f +/- %.4f"%(eff,deff)
+    #print "%.0f / %.0f -> %.4f"%(h,t,eff)
+    return [eff,deff]
+
+def CalcEffAsym (probes,matches):
+    t = probes[0]
+    dt = probes[1]
+    h = matches[0]
+    dh = matches[1]
+    #print "++++++++++++++++++ got %.4f +/- %.4f trials, %.5f / %.4f matches"%(t,dt,h,dh)
+    if t == 0:
+        return [1.0,0.0,1.0]
+        #t = 1
+    m = t - h
+    #print "dt = %.4f, dh = %.4f"%(dt,dh)
+    dm = math.sqrt(abs(dt*dt-dh*dh))
+    #print "        ++++++++++++++++++ and got %.4f +/- %.4f misses"%(m,dm)
+    eff = h/t
+    deff = math.sqrt(abs(((h*dm)**2+(m*dh)**2)/(t**4)))
+    
+    # use equation (11) from page 49 of https://cds.cern.ch/record/1247341/files/ATL-COM-PHYS-2010-124.pdf
+    N = t
+    if N == 0.:
+        N = 1.
+    sigmaPos = (2.*eff+1./N+math.sqrt(4.*eff*(1.-eff)/N+1./N**2))/(2.+2./N)-eff
+    sigmaNeg = (2.*eff+1./N-math.sqrt(4.*eff*(1.-eff)/N+1./N**2))/(2.+2./N)-eff
+
+    #print "        ++++++++++++++++++ asym Eff is %.4f + %.4f %.4f"%(eff,sigmaPos,sigmaNeg)
+    return [eff,sigmaPos,abs(sigmaNeg)]
+
+def EffDivide (num,den,eff):
+    nbinsNum = GetNbins(num)
+    #print 'in EffDivide: numerator has %s bins'%nbinsNum
+    #print num.GetBinContent(0)
+    for i in range (0, nbinsNum):
+        #print "bin %s: num: %s, den: %s"%(i, num.GetBinContent(i), den.GetBinContent(i))
+        if (num.GetBinContent(i) > den.GetBinContent(i)):
+            num.SetBinContent(i,den.GetBinContent(i))
+            
+    if eff.InheritsFrom("TGraphAsymmErrors"):
+        for i in range (0, nbinsNum):
+            effiAsym = CalcEffAsym([den.GetBinContent(i),den.GetBinError(i)], [num.GetBinContent(i),num.GetBinError(i)])
+            eff.SetPoint(eff.GetN(),num.GetBinCenter(i),effiAsym[0])
+            #print "bin %s: up: %s, down: %s"%(i, effiAsym[1], effiAsym[2])
+            eff.SetPointEYhigh(eff.GetN()-1, effiAsym[1])
+            eff.SetPointEYlow(eff.GetN()-1, effiAsym[2])
+            eff.SetPointEXhigh(eff.GetN()-1, num.GetBinWidth(i)/2.)
+            eff.SetPointEXlow(eff.GetN()-1, num.GetBinWidth(i)/2.)
+    else:
+        for i in range (0, nbinsNum):
+            effi = CalcEff([den.GetBinContent(i),den.GetBinError(i)], [num.GetBinContent(i),num.GetBinError(i)])
+            eff.SetBinContent(i,effi[0])
+            eff.SetBinError(i,effi[1])
+
+## Some utility methods for algebra in root
+def PolyDivide (num,den,ratio):
+    nbins = GetNbins(num)
+    for i in range (1, nbins):
+        if 0.!=den.GetBinContent(i):
+            ratio.SetBinContent(i,num.GetBinContent(i)/den.GetBinContent(i))
+            ratio.SetBinError(i,math.sqrt((num.GetBinError(i)/den.GetBinContent(i))**2.+(den.GetBinError(i)*num.GetBinContent(i)/den.GetBinContent(i)**2.)**2.))
+        else:
+            ratio.SetBinContent(i,0.)
+            ratio.SetBinError(i,0.)
+
+def PolyMultiply (fac1,fac2,res):
+    nbins = GetNbins(fac1)
+    for i in range (1, nbins):
+        res.SetBinContent(i,fac1.GetBinContent(i)*fac2.GetBinContent(i))
+        res.SetBinError(i,math.sqrt((fac2.GetBinError(i)*fac1.GetBinContent(i))**2.+(fac1.GetBinError(i)*fac2.GetBinContent(i))**2.))
+        
+def GraphDivide (num,den,ratio):
+    nPoints = GetNbins(num)
+    for i in range (0, nPoints):
+        if 0.!=den.GetY()[i]:
+            ratio.SetPoint(i,num.GetX()[i],num.GetY()[i]/den.GetY()[i])
+            ratio.SetPointEYhigh(i,math.sqrt((num.GetErrorYhigh(i)/den.GetY()[i])**2.+(den.GetErrorYhigh(i)*num.GetY()[i]/den.GetY()[i]**2.)**2.))
+            ratio.SetPointEYlow(i,math.sqrt((num.GetErrorYlow(i)/den.GetY()[i])**2.+(den.GetErrorYlow(i)*num.GetY()[i]/den.GetY()[i]**2.)**2.))
+        else:
+            ratio.SetPoint(i,num.GetX()[i],0.)
+            ratio.SetPointEYhigh(i,0.)
+            ratio.SetPointEYlow(i,0.)
+    
+def GraphMultiply (fac1,fac2,res):
+    nPoints = GetNbins(fac1)
+    for i in range (0, nPoints):
+        res.SetPoint(i,fac1.GetX()[i],fac1.GetY()[i]*fac2.GetY()[i])
+        res.SetPointEYhigh(i,math.sqrt((fac2.GetErrorYhigh(i)*fac1.GetY()[i])**2.+(fac1.GetErrorYhigh(i)*fac2.GetY()[i])**2.))
+        res.SetPointEYlow(i,math.sqrt((fac2.GetErrorYlow(i)*fac1.GetY()[i])**2.+(fac1.GetErrorYlow(i)*fac2.GetY()[i])**2.))
+
+def GetNbins(histo):
+    nbins = 0
+    if histo.InheritsFrom("TH2Poly"):
+        nbins = histo.GetNumberOfBins()+1
+    elif histo.InheritsFrom("TH2"):
+        nbins = (histo.GetNbinsX()+2)*(histo.GetNbinsY()+2)
+    elif histo.InheritsFrom("TH1"):
+        nbins = histo.GetNbinsX()+2
+    elif histo.InheritsFrom("TGraphAsymmErrors"):
+        nbins = histo.GetN()
+    else:
+        print "GetNbins(): no supported histogram type!"
+        return -1
+
+    return nbins
+
+def ConvertTGraphAsymmErrors(graph):
+    nPoints = GetNbins(graph)
+    binCenters = []
+    for i in range (0, nPoints):
+        binCenters.append(graph.GetX()[i])
+        
+    histo = ROOT.TH1F(graph.GetName(),graph.GetName(),len(binCenters)-1,array("f",binCenters))
+    histo.SetDirectory(0)
+    
+    for i in range (0, nPoints):
+        histo.SetBinContent(i,graph.GetY()[i])
+        maxError = max(graph.GetErrorYhigh(i),graph.GetErrorYlow(i))
+        histo.SetBinError(i,maxError)
+    return histo
+    
+
+## Some utility methods for systematics evaluation
+def fill_sys_bin (binNumber, h_nom, h_up, h_down, h_sys, weight):
+    if h_nom.InheritsFrom("TGraphAsymmErrors"):
+        nom_val = h_nom.GetY()[binNumber]
+        up_val = h_up.GetY()[binNumber]
+        down_val = h_down.GetY()[binNumber]
+    else:
+        nom_val = h_nom.GetBinContent(binNumber)
+        up_val = h_up.GetBinContent(binNumber)
+        down_val = h_down.GetBinContent(binNumber)
+
+    sup = math.fabs(up_val - nom_val)
+    sdown = math.fabs(down_val - nom_val)
+#     print 'bin: %s nom_val: %s sup: %s, sdown: %s'%(binNumber,nom_val,sup,sdown)
+
+    # for now, we symmetrize using the larger of the deviations
+    if (nom_val == 0):
+        nom_val = 0.001
+    smax = ROOT.TMath.Max(sup,sdown)/nom_val * weight
+    
+    if h_nom.InheritsFrom("TGraphAsymmErrors"):
+        statYhigh = h_nom.GetErrorYhigh(binNumber)/nom_val * weight
+        statYlow = h_nom.GetErrorYlow(binNumber)/nom_val * weight
+        
+        h_sys.SetPoint(binNumber,h_sys.GetX()[binNumber],smax)
+        h_sys.SetPointEYhigh(binNumber,statYhigh)
+        h_sys.SetPointEYlow(binNumber,statYlow)
+    else:
+        stat = h_nom.GetBinError(binNumber)/nom_val * weight
+        
+        h_sys.SetBinContent(binNumber,smax)
+        h_sys.SetBinError(binNumber,stat)
+
+def sysCompare(h_nom, h_up, h_down, sysType, weight):
+    sys = h_nom.Clone('%s_sys_%s'%(h_nom.GetName(),sysType))
+    if not sys.InheritsFrom("TGraphAsymmErrors"):
+        sys.SetDirectory(0)
+
+    nbins = GetNbins(sys)
+
+    for ibin in range(0,nbins):
+        fill_sys_bin(ibin,h_nom,h_up,h_down,sys,weight)
+
+    return sys
+
+def add_in_quadrature(hist_add_to, hist_add_this):
+    # loop over the bins - here we need the actual types
+    nbins = GetNbins(hist_add_to)
+
+    for k in range(0,nbins):
+        if hist_add_to.InheritsFrom("TGraphAsymmErrors"):
+            sys = hist_add_to.GetY()[k]
+            add_sys = hist_add_this.GetY()[k]
+            sys = ROOT.sqrt(sys*sys+add_sys*add_sys)
+            hist_add_to.SetPoint(k,hist_add_to.GetX()[k],sys)
+        else:
+            sys = hist_add_to.GetBinContent(k)
+            add_sys = hist_add_this.GetBinContent(k)
+            sys = ROOT.sqrt(sys*sys+add_sys*add_sys)
+            hist_add_to.SetBinContent(k,sys)
+        
+def CopyEtaBins(hist):
+    nbins = GetNbins(hist)
+    #print '\n\n\n\n\n\n\nin CopyEtaBins\n\n\n\n\n\n\n' 
+    #print nbins
+    
+    if hist.InheritsFrom("TGraphAsymmErrors"):
+        print 'TODO: CopyEtaBins for graphs'
+    else:
+        # fineEtaPhiBinning has 352 bins (22 eta bins, 16 phi bins each)
+        # abseta >= 1.05 and abseta < 1.37 -> etabin = -6*16 (negative eta), etabin = 5*16 (positive eta)
+        if nbins == 354:
+            for k in range(0,nbins):
+                # k=1 equals bin -11*16+1 = -175
+                #print k-176
+                # copy bins (from -95 to -80) to (81 to 96), this means 81-96 to 257-272
+                if k in [257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272]:
+                    hist.SetBinContent(k,hist.GetBinContent(k-176))
+                    hist.SetBinError(k,hist.GetBinError(k-176))
+                    #print k
+       
+        # TPFineEtaPhiHist binning
+        if nbins == 513:
+            for k in range(0,nbins):
+                #print k
+                ## copy bins (for 1.35<abs(eta)<1.5), this means 97-112 to 401-416
+                # copy bins (for 1.19<abs(eta)<1.35), this means 113-128 to 385-400
+                # copy bins (for 1.05<abs(eta)<1.19), this means 129-144 to 369-384
+                #if (k > 400 and k < 417):
+                    #hist.SetBinContent(k,hist.GetBinContent(k-304))
+                    #hist.SetBinError(k,hist.GetBinError(k-304))
+                if (k > 384 and k < 401):
+                    hist.SetBinContent(k,hist.GetBinContent(k-272))
+                    hist.SetBinError(k,hist.GetBinError(k-272))
+                if (k > 368 and k < 385):
+                    hist.SetBinContent(k,hist.GetBinContent(k-240))
+                    hist.SetBinError(k,hist.GetBinError(k-240))
+                    
\ No newline at end of file
diff --git a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/src/components/MuonTPTools_entries.cxx b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/src/components/MuonTPTools_entries.cxx
index 682865ecad6..bedd339300b 100644
--- a/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/src/components/MuonTPTools_entries.cxx
+++ b/PhysicsAnalysis/MuonID/MuonPerformanceAnalysis/MuonTPTools/src/components/MuonTPTools_entries.cxx
@@ -1,56 +1,56 @@
 // MuonTPTools_entries.cxx
 
 #include "MuonTPTools/MuonTPTool.h"
+
 #include "MuonTPTools/MuonTPSelectionTool.h"
+#include "MuonTPTools/DiMuonTPSelectionTool.h"
+
 #include "MuonTPTools/MuonTPEfficiencyTool.h"
-#include "MuonTPTools/ZmumuMuonTPPlotTool.h"
-#include "MuonTPTools/MuonTPPlotTool.h"
-#include "MuonTPTools/MuonTPTreeTool.h"
-#include "MuonTPTools/ZmumuMuonTPTreeTool.h"
-#include "MuonTPTools/ZmumuMuonTPIsolationTreeTool.h"
-#include "MuonTPTools/ZmumuMuonTPSelectionTool.h"
 #include "MuonTPTools/MuonRecoTPEfficiencyTool.h"
 #include "MuonTPTools/MuonTrigTPEfficiencyTool.h"
-#include "MuonTPTools/MuonTrigTPPlotTool.h"
-#include "MuonTPTools/MuonTrigTPTreeTool.h"
-#include "MuonTPTools/JPsiMuonTPPlotTool.h"
-#include "MuonTPTools/JPsiMuonTPSelectionTool.h"
-#include "MuonTPTools/JPsiMuonTPEfficiencyTool.h"
+#include "MuonTPTools/MuonIsolTPEfficiencyTool.h"
+
+#include "MuonTPTools/MuonTPPlotTool.h"
+#include "MuonTPTools/DiMuonTPPlotTool.h"
+
+#include "MuonTPTools/MuonTPTreeTool.h"
+#include "MuonTPTools/DiMuonTPTreeTool.h"
+
 #include "GaudiKernel/DeclareFactoryEntries.h"
 
 DECLARE_TOOL_FACTORY(MuonTPTool)
-DECLARE_TOOL_FACTORY(MuonTPSelectionTool)
-DECLARE_TOOL_FACTORY(MuonTPEfficiencyTool)
-DECLARE_TOOL_FACTORY(ZmumuMuonTPSelectionTool)
-DECLARE_TOOL_FACTORY(MuonTPPlotTool)
-DECLARE_TOOL_FACTORY(MuonTPTreeTool)
-DECLARE_TOOL_FACTORY(ZmumuMuonTPPlotTool)
-DECLARE_TOOL_FACTORY(ZmumuMuonTPTreeTool)
-DECLARE_TOOL_FACTORY(ZmumuMuonTPIsolationTreeTool)
+
+// DECLARE_TOOL_FACTORY(MuonTPSelectionTool)
+DECLARE_TOOL_FACTORY(DiMuonTPSelectionTool)
+
+// DECLARE_TOOL_FACTORY(MuonTPEfficiencyTool)
 DECLARE_TOOL_FACTORY(MuonRecoTPEfficiencyTool)
 DECLARE_TOOL_FACTORY(MuonTrigTPEfficiencyTool)
-DECLARE_TOOL_FACTORY(MuonTrigTPPlotTool)
-DECLARE_TOOL_FACTORY(MuonTrigTPTreeTool)
-DECLARE_TOOL_FACTORY(JPsiMuonTPSelectionTool)
-DECLARE_TOOL_FACTORY(JPsiMuonTPPlotTool)
-DECLARE_TOOL_FACTORY(JPsiMuonTPEfficiencyTool)
+DECLARE_TOOL_FACTORY(MuonIsolTPEfficiencyTool)
+
+// DECLARE_TOOL_FACTORY(MuonTPPlotTool)
+DECLARE_TOOL_FACTORY(DiMuonTPPlotTool)
+// DECLARE_TOOL_FACTORY(JPsiMuonTPPlotTool)
+
+// DECLARE_TOOL_FACTORY(MuonTPTreeTool)
+DECLARE_TOOL_FACTORY(DiMuonTPTreeTool)
 
 DECLARE_FACTORY_ENTRIES(MuonTPTools) {
   DECLARE_TOOL(MuonTPTool)
-  DECLARE_TOOL(MuonTPSelectionTool)
-  DECLARE_TOOL(MuonTPEfficiencyTool)
-  DECLARE_TOOL(ZmumuMuonTPSelectionTool)
-  DECLARE_TOOL(ZmumuMuonTPPlotTool)
-  DECLARE_TOOL(ZmumuMuonTPTreeTool)
-  DECLARE_TOOL(ZmumuMuonTPIsolationTreeTool)
+  
+//   DECLARE_TOOL(MuonTPSelectionTool)
+  DECLARE_TOOL(DiMuonTPSelectionTool)
+  
+//   DECLARE_TOOL(MuonTPEfficiencyTool)
   DECLARE_TOOL(MuonRecoTPEfficiencyTool)
   DECLARE_TOOL(MuonTrigTPEfficiencyTool)
-  DECLARE_TOOL(MuonTrigTPPlotTool)
-  DECLARE_TOOL(MuonTrigTPTreeTool)
-  DECLARE_TOOL(MuonTPPlotTool)
-  DECLARE_TOOL(MuonTPTreeTool)
-  DECLARE_TOOL(JPsiMuonTPSelectionTool)
-  DECLARE_TOOL(JPsiMuonTPPlotTool)
-  DECLARE_TOOL(JPsiMuonTPEfficiencyTool)
+  DECLARE_TOOL(MuonIsolTPEfficiencyTool)
+  
+//   DECLARE_TOOL(MuonTPPlotTool)
+  DECLARE_TOOL(DiMuonTPPlotTool)
+  
+//   DECLARE_TOOL(MuonTPTreeTool)
+  DECLARE_TOOL(DiMuonTPTreeTool)
+  
 }
 
-- 
GitLab