diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METAssociationTool.h b/Reconstruction/MET/METReconstruction/METReconstruction/METAssociationTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..17225519ae3a2f6c9dff64e7f6f4eae9f77b6711
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METAssociationTool.h
@@ -0,0 +1,117 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssociationTool.h 
+// Header file for class METAssociationTool
+//
+// This is a scheduler for the MET Reconstruction, and sets up
+// the sequence in which the individual terms are constructed.
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METASSOCIATIONTOOL_H
+#define METRECONSTRUCTION_METASSOCIATIONTOOL_H 1
+
+// STL includes
+#include <string>
+
+// FrameWork includes
+#include "AsgTools/ToolHandle.h"
+#include "AsgTools/AsgTool.h"
+
+// METRecoInterface includes
+#include "METRecoInterface/IMETRecoTool.h"
+#include "METRecoInterface/IMETAssocToolBase.h"
+
+// EDM includes
+#include "xAODMissingET/MissingETContainer.h"
+#include "xAODMissingET/MissingETAssociationMap.h"
+#include "xAODMissingET/MissingETAuxAssociationMap.h"
+
+// Timing
+#include "TStopwatch.h"
+
+// Forward declaration
+
+namespace met{
+  /* @brief Top-level class scheduling MET reconstruction tools
+   *
+   *  @author  Peter Loch <loch_AT_physics.arizona.edu>
+   *  @author  Silvia Resconi <Silvia.Resconi_AT_cern.ch>
+   *  @author  Teng Jian Khoo <Teng.Jian.Khoo_AT_cern.ch>
+   *  
+   *  @date    Nov. 21, 2013
+   *  @version v1.0
+   *
+   *  The METAssociationTool can be called within an Athena algorithm or a ROOT programme
+   *  to carry out the reconstruction of a MET configuration, and will produce a
+   *  MissingETContainer, the contents of which will be the MissingET objects produced
+   *  by the various tools scheduled by METAssociationTool.
+   *
+   */
+  class METAssociationTool final
+    : virtual public asg::AsgTool,
+      virtual public IMETRecoTool
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METAssociationTool, IMETRecoTool)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name (does this have to be a non-const
+    // std::string and not a const reference?)
+    METAssociationTool(const std::string& name);
+
+    // AsgTool Hooks
+    StatusCode initialize();
+    StatusCode execute() const;
+    StatusCode finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+  private: 
+
+    /// Default constructor: 
+    METAssociationTool();
+    virtual ~METAssociationTool();
+
+    // Run the MET tools here
+    StatusCode buildMET(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap) const;
+
+    // Data members
+    std::string m_metsuffix;
+    std::string m_mapname;
+    std::string m_corename;
+    ToolHandleArray<IMETAssocToolBase> m_metassociators;
+
+  }; 
+
+}
+
+// I/O operators
+//////////////////////
+
+/////////////////////////////////////////////////////////////////// 
+// Inline methods: 
+/////////////////////////////////////////////////////////////////// 
+
+
+#endif //> !METRECONSTRUCTION_METASSOCIATIONTOOL_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..8173aebbbb6c10817ffe0d4956f4777dd990f4ee
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METAssociator.h
@@ -0,0 +1,124 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssociator.h 
+// Header file for class METAssociator
+//
+// This is the base class for tools that construct MET terms
+// from other object collections.
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METASSOCIATOR_H
+#define METRECONSTRUCTION_METASSOCIATOR_H
+
+// STL includes
+#include <string>
+
+// FrameWork includes
+#include "AsgTools/AsgTool.h"
+#include "AsgTools/ToolHandle.h"
+
+// Tracking Tool
+#include "InDetTrackSelectionTool/IInDetTrackSelectionTool.h"
+
+// METRecoInterface includes
+#include "METRecoInterface/IMETAssocToolBase.h"
+
+#include "xAODCaloEvent/CaloClusterContainer.h"
+#include "xAODTracking/TrackParticle.h"
+#include "xAODTracking/Vertex.h"
+#include "xAODPFlow/PFOContainer.h"
+#include "xAODPFlow/PFO.h"
+#include "PFlowUtils/IRetrievePFOTool.h"
+
+namespace met {
+  class METAssociator
+    : virtual public asg::AsgTool,
+      virtual public IMETAssocToolBase
+  { 
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public:
+
+    // Constructor w/ name
+    METAssociator(const std::string& name);
+    // Default Destructor
+    virtual ~METAssociator(); 
+
+    // AsgTool Handles
+    virtual StatusCode initialize();
+    virtual StatusCode execute   (xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    virtual StatusCode finalize  ();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Protected methods: 
+    /////////////////////////////////////////////////////////////////// 
+    protected:
+
+    std::string m_input_data_key;
+    std::string m_pvcoll;
+    std::string m_trkcoll;
+    std::string m_clcoll;
+
+    bool m_pflow;    
+    int m_signalstate;
+
+    ToolHandle<CP::IRetrievePFOTool> m_pfotool;
+    std::vector<const xAOD::TrackParticle*> m_goodtracks;
+    ToolHandle<InDet::IInDetTrackSelectionTool> m_trkseltool;
+
+    // reconstruction process to be defined in the individual tools
+    // pure virtual -- we have no default
+    virtual StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap) = 0;
+    StatusCode retrieveConstituents(const xAOD::CaloClusterContainer*& tcCont,const xAOD::Vertex*& pv,const xAOD::TrackParticleContainer*& trkCont,const xAOD::PFOContainer*& pfoCont);
+
+    void filterTracks(const xAOD::TrackParticleContainer* tracks,
+		      const xAOD::Vertex* pv);
+    bool acceptTrack (const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) const;
+    bool acceptChargedPFO(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) const;
+    bool isGoodEoverP(const xAOD::TrackParticle* trk,const xAOD::CaloClusterContainer*& tcCont) const;
+
+    StatusCode fillAssocMap(xAOD::MissingETAssociationMap* metMap,
+			    const xAOD::IParticleContainer* hardObjs);
+    virtual StatusCode extractPFO(const xAOD::IParticle* obj,
+				  std::vector<const xAOD::IParticle*>& pfolist,
+				  MissingETBase::Types::constvec_t& pfovec,
+				  MissingETBase::Types::constvec_t& trkvec,
+				  const xAOD::PFOContainer* pfoCont,
+				  const xAOD::Vertex* pv) = 0;
+    virtual StatusCode extractTracks(const xAOD::IParticle* obj,
+				     std::vector<const xAOD::IParticle*>& constlist,
+				     MissingETBase::Types::constvec_t& trkvec,
+				     const xAOD::CaloClusterContainer* tcCont,
+				     const xAOD::Vertex* pv) = 0;
+    virtual StatusCode extractTopoClusters(const xAOD::IParticle* obj,
+					   std::vector<const xAOD::IParticle*>& tclist,
+					   MissingETBase::Types::constvec_t& tcvec,
+				           const xAOD::CaloClusterContainer* tcCont) = 0;
+    static inline bool greaterPt(const xAOD::IParticle* part1, const xAOD::IParticle* part2) {
+      return part1->pt()>part2->pt();
+    }
+    static inline bool greaterPtPFO(const xAOD::PFO* part1, const xAOD::PFO* part2) {
+      if (part1->charge()==0 && part2->charge()!=0) return false;
+      if (part1->charge()!=0 && part2->charge()==0) return true;
+      if (part1->charge()==0 && part2->charge()==0) return part1->ptEM()>part2->ptEM();
+      return part1->pt()>part2->pt();
+    }
+    /////////////////////////////////////////////////////////////////// 
+    // Private methods: 
+    /////////////////////////////////////////////////////////////////// 
+    private:
+
+    // Default Constructor
+    METAssociator();
+  };
+}
+
+#endif // METRECONSTRUCTION_METASSOCBUILDERTOOL_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METBuilderTool.h b/Reconstruction/MET/METReconstruction/METReconstruction/METBuilderTool.h
index 0e18d73da6dbb3ef6948bcceb7ccafc5a876387e..eb44d26dd853ddcceb1d256ce1db63448cf5db4d 100644
--- a/Reconstruction/MET/METReconstruction/METReconstruction/METBuilderTool.h
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METBuilderTool.h
@@ -139,8 +139,6 @@ namespace met {
 
   }; 
 
-  inline bool greaterPt(const xAOD::IParticle* part1, const xAOD::IParticle* part2);
-
 }
 
 // I/O operators
@@ -150,8 +148,4 @@ namespace met {
 // Inline methods: 
 /////////////////////////////////////////////////////////////////// 
 
-bool met::greaterPt(const xAOD::IParticle* part1, const xAOD::IParticle* part2) {
-  return part1->pt()>part2->pt();
-}
-
 #endif //> !METRECONSTRUCTION_METBUILDERTOOL_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METCaloRegionsTool.h b/Reconstruction/MET/METReconstruction/METReconstruction/METCaloRegionsTool.h
index a2eb0332b953d9bddf8ec07c5a6d5ea1435f4381..97297bb755b7d1a64becf9840b73e61e0d1334fb 100644
--- a/Reconstruction/MET/METReconstruction/METReconstruction/METCaloRegionsTool.h
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METCaloRegionsTool.h
@@ -34,11 +34,7 @@
 #include "xAODCaloEvent/CaloClusterContainer.h"
 #include "xAODCaloEvent/CaloClusterFwd.h"
 
-#ifndef XAOD_STANDALONE
-#include "CaloEvent/CaloCellContainer.h"
-#else
 class CaloCellContainer;
-#endif
 
 namespace met{
 
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METEgammaAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METEgammaAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f47a6653977f0768385b2c9b998315894b66a00
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METEgammaAssociator.h
@@ -0,0 +1,75 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METEgammaAssociator.h 
+// Header file for class METEgammaAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METEGAMMAASSOCIATOR_H
+#define METRECONSTRUCTION_METEGAMMAASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METEgammaAssociator
+    : virtual public METAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METEgammaAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METEgammaAssociator(const std::string& name);
+    virtual ~METEgammaAssociator();
+
+    // AsgTool Hooks
+    StatusCode initialize();
+    StatusCode finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode extractTopoClusters(const xAOD::IParticle* obj,
+				   std::vector<const xAOD::IParticle*>& tclist,
+				   MissingETBase::Types::constvec_t& tcvec,
+				   const xAOD::CaloClusterContainer* tcCont);
+    double m_tcMatch_dR;
+    double m_tcMatch_maxRat;
+    double m_tcMatch_tolerance;
+    unsigned short m_tcMatch_method;
+
+    private:
+ 
+    /// Default constructor: 
+    METEgammaAssociator();
+
+    // track overlap removal
+    bool m_eg_doTracks;
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METEGAMMAASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METElectronAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METElectronAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..783b9bad47337bed16595d21c0d8306b978ba2d8
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METElectronAssociator.h
@@ -0,0 +1,77 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METElectronAssociator.h 
+// Header file for class METElectronAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METELECTRONASSOCIATOR_H
+#define METRECONSTRUCTION_METELECTRONASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METEgammaAssociator.h"
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METElectronAssociator final
+    : virtual public METEgammaAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METElectronAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METElectronAssociator(const std::string& name);
+    ~METElectronAssociator();
+
+    // AsgTool Hooks
+    StatusCode  initialize();
+    StatusCode  finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractPFO(const xAOD::IParticle* obj,
+			  std::vector<const xAOD::IParticle*>& pfolist,
+			  MissingETBase::Types::constvec_t& pfovec,
+			  MissingETBase::Types::constvec_t& trkvec,
+			  const xAOD::PFOContainer* pfoCont,
+			  const xAOD::Vertex* pv) final;
+    StatusCode extractTracks(const xAOD::IParticle* obj,
+			     std::vector<const xAOD::IParticle*>& constlist,
+			     MissingETBase::Types::constvec_t& trkvec,
+			     const xAOD::CaloClusterContainer* tcCont,
+			     const xAOD::Vertex* pv) final;
+
+    private:
+ 
+    /// Default constructor: 
+    METElectronAssociator();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METELECTRONASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METJetAssocTool.h b/Reconstruction/MET/METReconstruction/METReconstruction/METJetAssocTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..33cf47fca4e5a1b5739d0a03f7763a1a9ad5ba62
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METJetAssocTool.h
@@ -0,0 +1,81 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METJetAssocTool.h 
+// Header file for class METJetAssocTool
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METJETASSOCTOOL_H
+#define METRECONSTRUCTION_METJETASSOCTOOL_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METJetAssocTool final
+    : virtual public METAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METJetAssocTool, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METJetAssocTool(const std::string& name);
+    ~METJetAssocTool();
+
+    // AsgTool Hooks
+    StatusCode  initialize();
+    StatusCode  finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractPFO(const xAOD::IParticle*,
+			  std::vector<const xAOD::IParticle*>&,
+			  MissingETBase::Types::constvec_t&,
+			  MissingETBase::Types::constvec_t&,
+			  const xAOD::PFOContainer*,
+			  const xAOD::Vertex*){return StatusCode::FAILURE;} // should not be called
+
+    StatusCode extractTracks(const xAOD::IParticle*,
+			     std::vector<const xAOD::IParticle*>&,
+			     MissingETBase::Types::constvec_t&, 
+			     const xAOD::CaloClusterContainer*,
+			     const xAOD::Vertex*){return StatusCode::FAILURE;} // should not be called
+    StatusCode extractTopoClusters(const xAOD::IParticle*,
+				   std::vector<const xAOD::IParticle*>&,
+				   MissingETBase::Types::constvec_t&, 
+				   const xAOD::CaloClusterContainer*){return StatusCode::FAILURE;} // should not be called
+
+    private:
+ 
+    /// Default constructor: 
+    METJetAssocTool();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METJETASSOCTOOL_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METMuonAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METMuonAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d5f2f855d9658f4c8c517170034bd52c5464c78
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METMuonAssociator.h
@@ -0,0 +1,80 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METMuonAssociator.h 
+// Header file for class METMuonAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METMUONASSOCIATOR_H
+#define METRECONSTRUCTION_METMUONASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METMuonAssociator final
+    : virtual public METAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METMuonAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METMuonAssociator(const std::string& name);
+    ~METMuonAssociator();
+
+    // AsgTool Hooks
+    StatusCode  initialize();
+    StatusCode  finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractTopoClusters(const xAOD::IParticle* obj,
+				   std::vector<const xAOD::IParticle*>& tclist,
+				   MissingETBase::Types::constvec_t& tcvec,
+				   const xAOD::CaloClusterContainer* tcCont);
+    StatusCode extractPFO(const xAOD::IParticle* obj,
+			  std::vector<const xAOD::IParticle*>& pfolist,
+			  MissingETBase::Types::constvec_t& pfovec,
+			  MissingETBase::Types::constvec_t& trkvec,
+			  const xAOD::PFOContainer* pfoCont,
+			  const xAOD::Vertex* pv) final;
+    StatusCode extractTracks(const xAOD::IParticle* obj,
+			     std::vector<const xAOD::IParticle*>& constlist,
+			     MissingETBase::Types::constvec_t& trkvec,
+			     const xAOD::CaloClusterContainer* tcCont,
+			     const xAOD::Vertex* pv) final;
+
+    private:
+ 
+    /// Default constructor: 
+    METMuonAssociator();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METMUONASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METPhotonAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METPhotonAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..49a479fc24ebc7f291ffe7a732861cac19c3e7f4
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METPhotonAssociator.h
@@ -0,0 +1,76 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METPhotonAssociator.h 
+// Header file for class METPhotonAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METPHOTONASSOCIATOR_H
+#define METRECONSTRUCTION_METPHOTONASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METEgammaAssociator.h"
+
+namespace met{
+  class METPhotonAssociator final
+    : virtual public METEgammaAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METPhotonAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METPhotonAssociator(const std::string& name);
+    ~METPhotonAssociator();
+
+    // AsgTool Hooks
+    StatusCode  initialize();
+    StatusCode  finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractPFO(const xAOD::IParticle* obj,
+			  std::vector<const xAOD::IParticle*>& pfolist,
+			  MissingETBase::Types::constvec_t& pfovec,
+			  MissingETBase::Types::constvec_t& trkvec,
+			  const xAOD::PFOContainer* pfoCont,
+			  const xAOD::Vertex* pv) final;
+    StatusCode extractTracks(const xAOD::IParticle* obj,
+			     std::vector<const xAOD::IParticle*>& constlist,
+			     MissingETBase::Types::constvec_t& trkvec,
+			     const xAOD::CaloClusterContainer* tcCont,
+			     const xAOD::Vertex* pv) final;
+
+    private:
+ 
+    /// Default constructor: 
+    METPhotonAssociator();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METPHOTONASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METReconstructionDict.h b/Reconstruction/MET/METReconstruction/METReconstruction/METReconstructionDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..d57ffdae0d0bb03ab501a6127daa015e574f870e
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METReconstructionDict.h
@@ -0,0 +1,34 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef METRECONSTRUCTIONDICT_H
+#define METRECONSTRUCTIONDICT_H
+
+#if defined(__GCCXML__) and not defined(EIGEN_DONT_VECTORIZE)
+#define EIGEN_DONT_VECTORIZE
+#endif // __GCCXML__
+
+#include "METReconstruction/METBuilderTool.h"
+#include "METReconstruction/METElectronTool.h"
+#include "METReconstruction/METPhotonTool.h"
+#include "METReconstruction/METTauTool.h"
+#include "METReconstruction/METJetTool.h"
+#include "METReconstruction/METMuonTool.h"
+#include "METReconstruction/METSoftTermsTool.h"
+#include "METReconstruction/METTruthTool.h"
+#include "METReconstruction/METCaloRegionsTool.h"
+#include "METReconstruction/METRegionsTool.h"
+#include "METReconstruction/METTrackFilterTool.h"
+#include "METReconstruction/METRecoTool.h"
+
+#include "METReconstruction/METAssociator.h"
+#include "METReconstruction/METJetAssocTool.h"
+#include "METReconstruction/METElectronAssociator.h"
+#include "METReconstruction/METPhotonAssociator.h"
+#include "METReconstruction/METTauAssociator.h" 
+#include "METReconstruction/METMuonAssociator.h"
+#include "METReconstruction/METSoftAssociator.h"
+#include "METReconstruction/METAssociationTool.h"
+
+#endif //METRECONSTRUCTIONDICT_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METSoftAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METSoftAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6bb11cf5d61a262657295df3253bdc3ea9563dc
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METSoftAssociator.h
@@ -0,0 +1,81 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METSoftAssociator.h 
+// Header file for class METSoftAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METSOFTASSOCIATOR_H
+#define METRECONSTRUCTION_METSOFTASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METSoftAssociator final
+    : virtual public METAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METSoftAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METSoftAssociator(const std::string& name);
+    ~METSoftAssociator();
+
+    // AsgTool Hooks
+    StatusCode initialize();
+    StatusCode finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractPFO(const xAOD::IParticle*,
+			  std::vector<const xAOD::IParticle*>&,
+			  MissingETBase::Types::constvec_t&,
+			  MissingETBase::Types::constvec_t&,
+			  const xAOD::PFOContainer*,
+			  const xAOD::Vertex*){return StatusCode::FAILURE;} // should not be called
+
+    StatusCode extractTracks(const xAOD::IParticle*,
+			     std::vector<const xAOD::IParticle*>&,
+			     MissingETBase::Types::constvec_t&, 
+			     const xAOD::CaloClusterContainer*,
+			     const xAOD::Vertex*){return StatusCode::FAILURE;} // should not be called
+    StatusCode extractTopoClusters(const xAOD::IParticle*,
+				   std::vector<const xAOD::IParticle*>&,
+				   MissingETBase::Types::constvec_t&, 
+				   const xAOD::CaloClusterContainer*){return StatusCode::FAILURE;} // should not be called
+
+    private:
+ 
+    /// Default constructor: 
+    METSoftAssociator();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METSOFTASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METTauAssociator.h b/Reconstruction/MET/METReconstruction/METReconstruction/METTauAssociator.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe105183981b0888e4fa32d9d66daad7c948256f
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METTauAssociator.h
@@ -0,0 +1,80 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METTauAssociator.h 
+// Header file for class METTauAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+#ifndef METRECONSTRUCTION_METTAUASSOCIATOR_H
+#define METRECONSTRUCTION_METTAUASSOCIATOR_H 1
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+
+namespace met{
+  class METTauAssociator final
+    : virtual public METAssociator
+  { 
+    // This macro defines the constructor with the interface declaration
+    ASG_TOOL_CLASS(METTauAssociator, IMETAssocToolBase)
+
+
+    /////////////////////////////////////////////////////////////////// 
+    // Public methods: 
+    /////////////////////////////////////////////////////////////////// 
+    public: 
+
+    // Constructor with name
+    METTauAssociator(const std::string& name);
+    ~METTauAssociator();
+
+    // AsgTool Hooks
+    StatusCode  initialize();
+    StatusCode  finalize();
+
+    /////////////////////////////////////////////////////////////////// 
+    // Const methods: 
+    ///////////////////////////////////////////////////////////////////
+
+    /////////////////////////////////////////////////////////////////// 
+    // Non-const methods: 
+    /////////////////////////////////////////////////////////////////// 
+
+    /////////////////////////////////////////////////////////////////// 
+    // Private data: 
+    /////////////////////////////////////////////////////////////////// 
+    protected: 
+
+    StatusCode executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap);
+    StatusCode extractTopoClusters(const xAOD::IParticle* obj,
+				   std::vector<const xAOD::IParticle*>& tclist,
+				   MissingETBase::Types::constvec_t& tcvec,
+				   const xAOD::CaloClusterContainer* tcCont);
+    StatusCode extractPFO(const xAOD::IParticle* obj,
+			  std::vector<const xAOD::IParticle*>& pfolist,
+			  MissingETBase::Types::constvec_t& pfovec,
+			  MissingETBase::Types::constvec_t& trkvec,
+			  const xAOD::PFOContainer* pfoCont,
+			  const xAOD::Vertex* pv) final;
+    StatusCode extractTracks(const xAOD::IParticle* obj,
+			     std::vector<const xAOD::IParticle*>& constlist,
+			     MissingETBase::Types::constvec_t& trkvec,
+			     const xAOD::CaloClusterContainer* tcCont,
+			     const xAOD::Vertex* pv) final;
+
+    private:
+ 
+    /// Default constructor: 
+    METTauAssociator();
+
+  }; 
+
+}
+
+#endif //> !METRECONSTRUCTION_METTAUASSOCIATOR_H
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/METTrackFilterTool.h b/Reconstruction/MET/METReconstruction/METReconstruction/METTrackFilterTool.h
index 79c27eb14f1b615d57c73f1a04b9c217c7ff2ce9..d104e11af0955ca94dfa0965882d8e8ecaafa425 100644
--- a/Reconstruction/MET/METReconstruction/METReconstruction/METTrackFilterTool.h
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/METTrackFilterTool.h
@@ -28,6 +28,14 @@
 #include "xAODTracking/TrackParticleFwd.h"
 #include "xAODTracking/VertexFwd.h"
 #include "xAODTracking/VertexContainerFwd.h"
+#include "xAODEgamma/ElectronFwd.h"
+#include "xAODEgamma/ElectronContainer.h"
+
+#include "xAODMuon/Muon.h"
+#include "xAODMuon/MuonContainer.h"
+
+#include "InDetTrackSelectionTool/IInDetTrackSelectionTool.h"
+#include "TrackVertexAssociationTool/ITrackVertexAssociationTool.h"
 
 namespace met{
 
@@ -64,22 +72,42 @@ namespace met{
     // Private data: 
     /////////////////////////////////////////////////////////////////// 
   protected: 
-    StatusCode  executeTool(xAOD::MissingET* metTerm, xAOD::MissingETComponentMap* metMap);
+    StatusCode executeTool(xAOD::MissingET* metTerm, xAOD::MissingETComponentMap* metMap);
     // Accept functions
-    bool isPVTrack         (const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) const;
-    bool isGoodEoverP      (const xAOD::TrackParticle* trk,
-			    const std::vector<const xAOD::IParticle*>& trkList,
-			    const xAOD::CaloClusterContainer* clusters) const;
+    // bool isPVTrack(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) const;
+    bool isGoodEoverP(const xAOD::TrackParticle* trk,
+		      const std::vector<const xAOD::IParticle*>& trkList,
+		      const xAOD::CaloClusterContainer* clusters) const;
 
   private:
     // Default constructor: 
     METTrackFilterTool();
 
+    StatusCode buildTrackMET(xAOD::MissingETComponentMap* const metMap,
+			     xAOD::MissingET* const metTerm,
+			     const xAOD::Vertex* const pv,
+			     const std::vector<const xAOD::Electron*>& selElectrons,
+			     const std::vector<const xAOD::Muon*>& selMuons,
+			     const std::vector<const xAOD::TrackParticle*>& softTracks) const;
+
+    bool isElTrack(const xAOD::TrackParticle &trk, const std::vector<const xAOD::Electron*>& electrons, size_t &el_index ) const;
+    bool isMuTrack(const xAOD::TrackParticle &trk, const std::vector<const xAOD::Muon*>& muons) const;
+
+    ToolHandle<InDet::IInDetTrackSelectionTool> m_trkseltool;
+    ToolHandle<CP::ITrackVertexAssociationTool> m_trkToVertexTool;
+
+    void selectElectrons(const xAOD::ElectronContainer &elCont, std::vector<const xAOD::Electron*>& electrons) const;
+    void selectMuons(const xAOD::MuonContainer &muCont, std::vector<const xAOD::Muon*>& muons) const;
+
     bool m_trk_doPVsel;
-    double m_trk_d0Max;
-    double m_trk_z0Max;
+    // double m_trk_d0Max;
+    // double m_trk_z0Max;
     std::string m_pv_inputkey;
-    const xAOD::VertexContainer* m_pv_cont;
+    std::string m_el_inputkey;
+    std::string m_mu_inputkey;
+
+    bool m_doVxSep;
+    bool m_doLepRecovery;
 
     bool m_trk_doEoverPsel;
     std::string m_cl_inputkey;
diff --git a/Reconstruction/MET/METReconstruction/METReconstruction/selection.xml b/Reconstruction/MET/METReconstruction/METReconstruction/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..09c9b5445e37272d07f855afa4a80a31848c3820
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/METReconstruction/selection.xml
@@ -0,0 +1,30 @@
+<lcgdict>
+   <class name="met::METBuilderTool" />
+   <class name="met::METElectronTool" />
+   <class name="met::METPhotonTool" />
+   <class name="met::METTauTool" />
+   <class name="met::METJetTool" />
+   <class name="met::METMuonTool" />
+   <class name="met::METSoftTermsTool" />
+   <class name="met::METTruthTool" />
+   <class name="met::METCaloRegionsTool" />
+   <class name="met::METRegionsTool" />
+   <class name="met::METTrackFilterTool" />
+   <class name="met::METRecoTool" />
+
+   <class name="met::METAssociator" />
+   <class name="met::METJetAssocTool" />
+   <class name="met::METElectronAssociator" />
+   <class name="met::METPhotonAssociator" />
+   <class name="met::METTauAssociator" /> 
+   <class name="met::METMuonAssociator" />
+   <class name="met::METSoftAssociator" />
+   <class name="met::METAssociationTool" />
+
+  <!-- Suppress the unwanted classes found by ROOT 6. -->
+  <!-- Hopefully we can remove these extra lines at one point... -->
+  <exclusion>
+    <class name="SG::IConstAuxStore" />
+    <class name="DataLink<SG::IConstAuxStore>" />
+  </exclusion>
+</lcgdict>
diff --git a/Reconstruction/MET/METReconstruction/Root/METAssociationTool.cxx b/Reconstruction/MET/METReconstruction/Root/METAssociationTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..341b5b927ca987cab240e700b790149c87993876
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METAssociationTool.cxx
@@ -0,0 +1,177 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssociationTool.cxx 
+// Implementation file for class METAssociationTool
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METAssociationTool.h"
+
+// MET EDM
+#include "xAODMissingET/MissingET.h"
+#include "xAODMissingET/MissingETContainer.h"
+#include "xAODMissingET/MissingETComposition.h"
+#include "xAODMissingET/MissingETAuxContainer.h"
+#include "xAODMissingET/MissingETAuxComponentMap.h"
+
+#include <iomanip>
+
+namespace met {
+
+  using xAOD::MissingET;
+  using xAOD::MissingETContainer;
+  using xAOD::MissingETComposition;
+  using xAOD::MissingETAuxContainer;
+  //
+  using std::string;
+  using std::setw;
+  using std::setprecision;
+  using std::fixed;
+
+  /////////////////////////////////////////////////////////////////// 
+  // Public methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // Constructors
+  ////////////////
+  METAssociationTool::METAssociationTool(const std::string& name) : 
+    AsgTool(name)
+  {
+    declareProperty( "METAssociators", m_metassociators           );
+    declareProperty( "METSuffix",   m_metsuffix = "AntiKt4LCTopo" );
+  }
+
+  // Destructor
+  ///////////////
+  METAssociationTool::~METAssociationTool()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METAssociationTool::initialize()
+  {
+    ATH_MSG_INFO ("Initializing " << name() << "...");
+
+    if( m_metsuffix.size()==0 ) {
+      ATH_MSG_ERROR("Output suffix for MET names must be provided.");
+      return StatusCode::FAILURE;
+    } else {
+      m_corename = "MET_Core_"+m_metsuffix;
+      m_mapname = "METAssoc_"+m_metsuffix;
+      ATH_MSG_INFO("Tool configured to build MET with names:");
+      ATH_MSG_INFO("   Core container  ==> " << m_corename);
+      ATH_MSG_INFO("   Association map ==> " << m_mapname);
+    }
+
+    // retrieve builders
+    for(ToolHandleArray<IMETAssocToolBase>::const_iterator iBuilder=m_metassociators.begin();
+	iBuilder != m_metassociators.end(); ++iBuilder) {
+      ToolHandle<IMETAssocToolBase> tool = *iBuilder;
+      if( tool.retrieve().isFailure() ) {
+	ATH_MSG_FATAL("Failed to retrieve tool: " << tool->name());
+	return StatusCode::FAILURE;
+      };
+      ATH_MSG_INFO("Retrieved tool: " << tool->name() );
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METAssociationTool::execute() const
+  {
+    ATH_MSG_DEBUG ("In execute: " << name() << "...");
+
+    if( evtStore()->contains<xAOD::MissingETAssociationMap>(m_mapname) ) {
+      ATH_MSG_WARNING("Association map \"" << m_mapname << "\" is already present, exiting.");
+      return StatusCode::SUCCESS;
+    }
+
+    // Create a MissingETAssociationMap with its aux store
+    xAOD::MissingETAssociationMap* metMap = new xAOD::MissingETAssociationMap();
+    if( evtStore()->record(metMap, m_mapname).isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAssociationMap: " << m_mapname);
+      return StatusCode::SUCCESS;
+    }
+    xAOD::MissingETAuxAssociationMap* metAuxMap = new xAOD::MissingETAuxAssociationMap();
+    if( evtStore()->record(metAuxMap, m_mapname+"Aux.").isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAuxAssociationMap: " << m_mapname+"Aux.");
+      return StatusCode::SUCCESS;
+    }
+    metMap->setStore(metAuxMap);
+
+    if( evtStore()->contains<MissingETContainer>(m_corename) ) {
+      ATH_MSG_WARNING("MET_Core container \"" << m_corename << "\" is already present, exiting.");
+      return StatusCode::SUCCESS;
+    }
+    MissingETContainer* metCont = new MissingETContainer();
+    if( evtStore()->record(metCont, m_corename).isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETContainer: " << m_corename);
+      return StatusCode::SUCCESS;
+    }
+    MissingETAuxContainer* metAuxCont = new MissingETAuxContainer();
+    if( evtStore()->record(metAuxCont, m_corename+"Aux.").isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAuxContainer: " << m_corename+"Aux.");
+      return StatusCode::SUCCESS;
+    }
+    metCont->setStore(metAuxCont);
+
+    if( buildMET(metCont, metMap).isFailure() ) {
+      ATH_MSG_WARNING("Failed in MissingET reconstruction");
+      return StatusCode::SUCCESS;
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METAssociationTool::finalize()
+  {
+    ATH_MSG_INFO ("Finalizing " << name() << "...");
+
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  StatusCode METAssociationTool::buildMET(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap) const
+  {
+    // Run the MET reconstruction tools in sequence
+    for(ToolHandleArray<IMETAssocToolBase>::const_iterator iBuilder=m_metassociators.begin();
+	iBuilder != m_metassociators.end(); ++iBuilder) {
+      ToolHandle<IMETAssocToolBase> tool = *iBuilder;
+      if (tool->execute(metCont,metMap).isFailure()){
+        ATH_MSG_WARNING("Failed to execute tool: " << tool->name());
+        return StatusCode::FAILURE;
+      }
+    }
+    bool foundOverlaps = metMap->identifyOverlaps();
+    ATH_MSG_DEBUG( (foundOverlaps ? "Overlaps" : "No overlaps") << " identified!");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c026fc0532f1f9d962fa6201a560d5b0cab22dcc
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METAssociator.cxx
@@ -0,0 +1,300 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssociator.cxx 
+// Implementation for class METAssociator
+//
+// This is the base class for tools that construct MET terms
+// from other object collections.
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METAssociator.h"
+#include "xAODMissingET/MissingETComposition.h"
+#include "xAODMissingET/MissingETContainer.h"
+#include "xAODMissingET/MissingETAssociationMap.h"
+
+// Tracking EDM
+#include "xAODTracking/Vertex.h"
+#include "xAODTracking/TrackParticle.h"
+
+// Track errors
+#include "EventPrimitives/EventPrimitivesHelpers.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  /////////////////////////////////////////////////////////////////// 
+  // Public methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // Constructors
+  ////////////////
+  METAssociator::METAssociator(const std::string& name) :
+    AsgTool(name),
+    m_signalstate(-1)
+  {
+    declareProperty( "InputCollection",   m_input_data_key                    );
+    declareProperty( "PrimVxColl",        m_pvcoll    = "PrimaryVertices"     );
+    declareProperty( "TrkColl",           m_trkcoll   = "InDetTrackParticles" );
+    declareProperty( "ClusColl",          m_clcoll    = "CaloCalTopoClusters" );
+    declareProperty( "PFlow",             m_pflow     = false                 );
+    declareProperty( "PFOTool",           m_pfotool                           );
+
+    declareProperty( "TrackSelectorTool", m_trkseltool                        );
+  }
+
+  // Destructor
+  ///////////////
+  METAssociator::~METAssociator()
+  {} 
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METAssociator::initialize()
+  {
+    ATH_MSG_INFO ("Initializing " << name() << "...");
+
+    ATH_CHECK( m_trkseltool.retrieve() );
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METAssociator::execute(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap)
+  {
+    ATH_MSG_DEBUG ("In execute: " << name() << "...");
+    if(!metCont) {
+      ATH_MSG_WARNING("Invalid pointer to MissingETContainer supplied! Abort.");
+      return StatusCode::FAILURE;
+    }
+
+    if(!metMap) {
+      ATH_MSG_WARNING("Invalid pointer to MissingETAssociationMap supplied! Abort.");
+      return StatusCode::FAILURE;
+    }
+
+    // will set the signal state for the first event with jets
+    if(m_signalstate<0) {
+      if(metMap->size()>0) { //allow for misc association
+	const MissingETAssociation* assoc = metMap->front();
+	if(!assoc->isMisc()) {
+	  m_signalstate = assoc->refJet()->getConstituentsSignalState();
+	  ATH_MSG_INFO("Configured METAssociator with signal state " << m_signalstate);
+	}
+      }
+    }
+
+    return this->executeTool(metCont, metMap);
+  }
+
+  StatusCode METAssociator::retrieveConstituents(const xAOD::CaloClusterContainer*& tcCont,const xAOD::Vertex*& pv,const xAOD::TrackParticleContainer*& trkCont,const xAOD::PFOContainer*& pfoCont)
+  {
+    ATH_MSG_DEBUG ("In execute: " << name() << "...");
+    tcCont = 0;
+    if( evtStore()->retrieve(tcCont, m_clcoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve topocluster container " << m_clcoll << " for overlap removal");
+      return StatusCode::FAILURE;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved topocluster collection");
+
+    const VertexContainer *vxCont = 0;
+    pv = 0;
+    if( evtStore()->retrieve(vxCont, m_pvcoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve primary vertex container " << m_pvcoll);
+      return StatusCode::FAILURE;
+    } else if(vxCont->empty()) {
+      ATH_MSG_WARNING("Event has no primary vertices!");
+      return StatusCode::FAILURE;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved primary vertex container");
+    for(const auto& vx : *vxCont) {
+      if(vx->vertexType()==VxType::PriVtx)
+	{pv = vx; break;}
+    }
+    if(!pv) {
+      ATH_MSG_WARNING("Failed to find primary vertex!");
+      return StatusCode::FAILURE;
+    } else {
+      ATH_MSG_VERBOSE("Primary vertex has z = " << pv->z());
+    }
+
+    trkCont=0;
+    ATH_CHECK( evtStore()->retrieve(trkCont, m_trkcoll) );
+
+    // filterTracks(trkCont,pv);
+
+    if(m_pflow) {
+      pfoCont = 0;
+      if( evtStore()->contains<xAOD::PFOContainer>("EtmissParticleFlowObjects") ) {
+	ATH_CHECK(evtStore()->retrieve(pfoCont,"EtmissParticleFlowObjects"));
+      } else {
+	pfoCont = m_pfotool->retrievePFO(CP::EM, CP::all);
+	ATH_CHECK( evtStore()->record(pfoCont,"EtmissParticleFlowObjects"));
+      }
+      if(!pfoCont) {
+	ATH_MSG_WARNING("Unable to retrieve input pfo container");
+	return StatusCode::FAILURE;
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METAssociator::finalize()
+  {
+    ATH_MSG_INFO ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  StatusCode METAssociator::fillAssocMap(xAOD::MissingETAssociationMap* metMap,
+					 const xAOD::IParticleContainer* hardObjs)
+  //					 std::vector<const xAOD::IParticle*>& mutracks)
+  {
+    const CaloClusterContainer* tcCont;
+    const Vertex* pv;
+    const TrackParticleContainer* trkCont;
+    const PFOContainer* pfoCont;
+
+    if (retrieveConstituents(tcCont,pv,trkCont,pfoCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to retrieve constituent containers");
+      return StatusCode::FAILURE;
+    }
+
+    std::vector<const IParticle*> constlist;
+    constlist.reserve(20);
+    std::vector<const IParticle*> hardObjs_tmp;
+    for(const auto& obj : *hardObjs) {
+      hardObjs_tmp.push_back(obj);
+    }
+    std::sort(hardObjs_tmp.begin(),hardObjs_tmp.end(),greaterPt);
+
+    for(const auto& obj : hardObjs_tmp) {
+      if(obj->pt()<5e3 && obj->type()!=xAOD::Type::Muon) continue;
+      constlist.clear();
+      MissingETBase::Types::constvec_t tcvec,trkvec;
+      ATH_MSG_VERBOSE( "Object type, pt, eta, phi = " << obj->type() << ", " << obj->pt() << ", " << obj->eta() << "," << obj->phi() );
+      if (m_pflow) {
+	ATH_CHECK( this->extractPFO(obj,constlist,tcvec,trkvec,pfoCont,pv) );
+      } else {
+        ATH_CHECK( this->extractTopoClusters(obj,constlist,tcvec,tcCont) );
+        ATH_CHECK( this->extractTracks(obj,constlist,trkvec,tcCont,pv) );
+      }
+      bool inserted(false);
+      inserted = MissingETComposition::insert(metMap,obj,constlist,tcvec,trkvec);
+      if(inserted) {
+	const MissingETAssociation* assoc = MissingETComposition::getAssociation(metMap,obj);
+	ATH_MSG_VERBOSE( obj->type() << " is associated to jet " << assoc->refJet()->index() << " with pt " << assoc->refJet()->pt() );
+      } else {
+	ATH_MSG_VERBOSE( "Add " << obj->type() << " as miscellaneous object" );
+	if(!obj->type()==xAOD::Type::Tau)
+	  inserted = MissingETComposition::insertMisc(metMap,obj,constlist,tcvec,trkvec);
+      }
+    }  
+    return StatusCode::SUCCESS;
+  }
+  
+  void METAssociator::filterTracks(const xAOD::TrackParticleContainer* tracks,
+				   const xAOD::Vertex* pv) {
+    for(const auto& trk : *tracks) {
+      m_goodtracks.clear();
+      if(acceptTrack(trk,pv)) m_goodtracks.push_back(trk);
+    }
+  }
+  
+  // Accept Track
+  ////////////////
+  bool METAssociator::acceptTrack(const xAOD::TrackParticle* trk, const xAOD::Vertex* vx) const
+  {
+    //if(fabs(trk->pt())<500/*MeV*/ || fabs(trk->eta())>2.5) return false;
+    // could add some error checking to make sure we successfully read the details
+    //uint8_t nPixHits(0), nSctHits(0);
+    //trk->summaryValue(nPixHits,xAOD::numberOfPixelHits);
+    //if(nPixHits<1) return false;
+    //trk->summaryValue(nSctHits,xAOD::numberOfSCTHits);
+    //if(nSctHits<6) return false;
+    //if(fabs(trk->d0())>1.5) return false;
+    //if(fabs(trk->z0() + trk->vz() - vx->z()) > 1.5) return false;
+    //return true;
+
+    const Root::TAccept& accept = m_trkseltool->accept( *trk, vx );
+    // uint8_t nBLHits(0), expectBLHit(false);
+    // if(trk->summaryValue(nBLHits,xAOD::numberOfBLayerHits)) {
+    //   ATH_MSG_VERBOSE("Track has " << (int) nBLHits << " b-layer hits");
+    // }
+    // if(trk->summaryValue(expectBLHit,xAOD::expectBLayerHit)) {
+    //   ATH_MSG_VERBOSE("Track expected b-layer hit: " << (bool) expectBLHit);
+    // }
+    // ATH_MSG_VERBOSE("From auxdata: expect hit ? " << (bool) trk->auxdata<uint8_t>("expectBLayerHit")
+    // 		    << " Nhits = " << (int) trk->auxdata<uint8_t>("numberOfBLayerHits"));
+    
+    // if(!accept && fabs(trk->z0() + trk->vz() - vx->z())*sin(trk->theta()) < 1.5) {
+    //   for(size_t icut=0; icut<accept.getNCuts(); ++icut) {
+    // 	ATH_MSG_VERBOSE("Cut " << accept.getCutName(icut) << ": result = " << accept.getCutResult(icut));
+    //   }
+    // }
+    return accept;
+  }
+
+
+  bool METAssociator::acceptChargedPFO(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) const
+  {
+    if(fabs((trk->z0() - pv->z()+trk->vz())*sin(trk->theta())) > 2) return false;
+    return true;
+  }
+
+
+  bool METAssociator::isGoodEoverP(const xAOD::TrackParticle* trk,const xAOD::CaloClusterContainer*& tcCont) const
+  {
+
+    if( (fabs(trk->eta())<1.5 && trk->pt()>200e3) ||
+	(fabs(trk->eta())>=1.5 && trk->pt()>120e3) ) {
+
+      // Get relative error on qoverp
+      float Rerr = Amg::error(trk->definingParametersCovMatrix(),4)/fabs(trk->qOverP());
+      ATH_MSG_VERBOSE( "Track momentum error (%): " << Rerr*100 );
+
+      // first compute track and calo isolation variables
+      float ptcone20 = 0;
+      for(const auto& testtrk : m_goodtracks) {
+	if(testtrk==trk) continue;
+	if(testtrk->p4().DeltaR(trk->p4()) < 0.2) {
+	  ptcone20 += testtrk->pt();
+	}
+      }
+      float isolfrac = ptcone20 / trk->pt();
+      ATH_MSG_VERBOSE( "Track isolation fraction: " << isolfrac );
+
+      float etcone10 = 0.;
+      for(const auto& clus : *tcCont) {
+	if(clus->p4().DeltaR(trk->p4()) < 0.1) {
+	  etcone10 += clus->pt();
+	}
+      }
+      float EoverP = etcone10/trk->pt();
+      ATH_MSG_VERBOSE( "Track E/P: " << EoverP );
+
+      if(isolfrac<0.1) {
+	// isolated track cuts
+	if(Rerr>0.4) return false;
+	else if (EoverP<0.65 && (EoverP>0.1 || Rerr>0.1)) return false;
+      } else {
+	// non-isolated track cuts
+	float trkptsum = ptcone20+trk->pt();
+	if(EoverP/trkptsum<0.6 && ptcone20/trkptsum<0.6) return false;
+      }
+    }
+    return true;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METCaloRegionsTool.cxx b/Reconstruction/MET/METReconstruction/Root/METCaloRegionsTool.cxx
index 45460ab7cadfa7065d15d849a11fcfea7dbd54c8..65f9c81ba70d8ef54cf0220c65d731fdf69cdc85 100644
--- a/Reconstruction/MET/METReconstruction/Root/METCaloRegionsTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METCaloRegionsTool.cxx
@@ -16,7 +16,10 @@
 #include "METReconstruction/METCaloRegionsTool.h"
 
 // MET EDM
-#include "xAODMissingET/MissingETComposition.h"
+#if defined(XAOD_STANDALONE) || defined(XAOD_ANALYSIS)
+#else
+#include "CaloEvent/CaloCellContainer.h"
+#endif
 
 namespace met {
 
@@ -28,7 +31,6 @@ namespace met {
   using xAOD::CaloClusterContainer;
   //
   using xAOD::MissingET;
-  using xAOD::MissingETComposition;
   using xAOD::MissingETContainer;
 
   // Initialize CaloRegionNames
@@ -96,6 +98,14 @@ namespace met {
     // Create the container and push back the new MET terms 
     MissingETBase::Types::bitmask_t source = MissingETBase::Source::Calo | MissingETBase::Source::clusterEM();
     MissingETContainer* metCont = dynamic_cast<MissingETContainer*>( metTerm_EMB->container() );
+
+    // Check dynamic_cast for coverity
+    if(!metCont) {
+      ATH_MSG_WARNING("Unsuccesful dynamic_cast");
+      return StatusCode::SUCCESS;
+    }
+
+    // Push region terms to the container
     for( int i=0; i < REGIONS_TOTAL; ++i) {
       // Create the new terms 
       if( i > 0 ) { 
@@ -106,27 +116,32 @@ namespace met {
       metCont->at(i)->setSource( source );      
     }
       
+    StatusCode sc = StatusCode::SUCCESS;
+
     // Either Cells or Clusters
     if(m_calo_useCells) {
       // Retrieve the cell container
-      const CaloCellContainer*   caloCellCont = 0;
-      #ifndef XAOD_STANDALONE
-      if( evtStore()->retrieve(caloCellCont, m_input_data_key).isFailure() ) {
+      const CaloCellContainer* caloCellCont = 0;
+      #if defined(XAOD_STANDALONE) || defined(XAOD_ANALYSIS)
+      #else
+      sc = evtStore()->retrieve(caloCellCont, m_input_data_key);
+      if( sc.isFailure() ) {
         ATH_MSG_WARNING("Unable to retrieve input cell cluster container");
         return StatusCode::SUCCESS;
       }
       #endif
       // Fill MET
-      return fillCellMet(metCont,caloCellCont);
+      sc = fillCellMet(metCont,caloCellCont);
     } else {
       // Retrieve the calo container
       const CaloClusterContainer*   caloClusCont = 0;
-      if( evtStore()->retrieve(caloClusCont, m_input_data_key).isFailure() ) {
+      sc = evtStore()->retrieve(caloClusCont, m_input_data_key);
+      if( sc.isFailure() ) {
         ATH_MSG_WARNING("Unable to retrieve input calo cluster container");
         return StatusCode::SUCCESS;
       }
       // Fill MET
-      return fillClusterMet(metCont,caloClusCont);
+      sc=fillClusterMet(metCont,caloClusCont);
     } // end if use clusters if/else
 
     // Debug information
@@ -142,6 +157,10 @@ namespace met {
                     );      
     } // end debug information
 
+    if(sc.isFailure()) { 
+      ATH_MSG_WARNING("Unable to fill cell/cluster MET"); 
+    } 
+    
     return StatusCode::SUCCESS;
   }
 
@@ -194,7 +213,9 @@ namespace met {
   // Fill Cell MET
   StatusCode METCaloRegionsTool::fillCellMet(xAOD::MissingETContainer* metContainer,
                                              const CaloCellContainer* caloCellContainer) {
-    #ifndef XAOD_STANDALONE
+    #if defined (XAOD_STANDALONE) || defined(XAOD_ANALYSIS)
+    ATH_MSG_WARNING("Cell information is only available in athena framework");
+    #else
     // Loop over all cells
     for( CaloCellContainer::const_iterator iCell=caloCellContainer->begin();
        iCell!=caloCellContainer->end(); ++iCell ) {
@@ -222,8 +243,6 @@ namespace met {
                      et_cell);
       } // end if energy>0 if
     } // end of loop overall cells
-    #else
-    ATH_MSG_WARNING("Cell information is only available in athena framework");
     #endif
     return StatusCode::SUCCESS;
   } // end of fillCellMet
diff --git a/Reconstruction/MET/METReconstruction/Root/METEgammaAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METEgammaAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e9273270233755deb101e3c5756e6a9a0e4bd8ae
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METEgammaAssociator.cxx
@@ -0,0 +1,147 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METEgammaAssociator.cxx 
+// Implementation file for class METEgammaAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METEgammaAssociator.h"
+
+// Egamma EDM
+#include "xAODEgamma/EgammaFwd.h"
+#include "xAODEgamma/ElectronContainer.h"
+#include "xAODEgamma/PhotonContainer.h"
+#include "xAODCaloEvent/CaloClusterContainer.h"
+
+// Calo helpers
+#include "xAODCaloEvent/CaloClusterChangeSignalState.h"
+
+// Tracking EDM
+#include "xAODTracking/Vertex.h"
+
+namespace met {
+
+  using xAOD::IParticle;
+  //
+  using xAOD::Egamma;
+  //
+  using xAOD::CaloCluster;
+  //
+  using xAOD::VertexContainer;
+
+  // Constructors
+  ////////////////
+  METEgammaAssociator::METEgammaAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name)
+  {
+    declareProperty( "TCMatchDeltaR",     m_tcMatch_dR        = 0.1 );
+    declareProperty( "TCMatchMaxRat",     m_tcMatch_maxRat    = 1.5 );
+    declareProperty( "TCMatchTolerance",  m_tcMatch_tolerance = 0.2 );
+    declareProperty( "TCMatchMethod",     m_tcMatch_method    = 0   );
+  }
+
+  // Destructor
+  ///////////////
+  METEgammaAssociator::~METEgammaAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METEgammaAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METEgammaAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  //**********************************************************************
+  // Get Egamma constituents
+  StatusCode METEgammaAssociator::extractTopoClusters(const xAOD::IParticle* obj,
+					std::vector<const xAOD::IParticle*>& tclist,
+					MissingETBase::Types::constvec_t& tcvec,
+				        const xAOD::CaloClusterContainer* tcCont)
+  {
+    const Egamma *eg = static_cast<const xAOD::Egamma*>(obj);
+    // safe to assume a single SW cluster?
+    // will do so for now...
+    const CaloCluster* swclus = eg->caloCluster();
+    double eg_cl_e = swclus->e();
+
+    // the matching strategy depends on how the cluster container is sorted
+    // easier if it's sorted in descending pt order
+    // we'll worry about optimisation later
+    std::vector<const xAOD::CaloCluster*> nearbyTC;
+    CaloClusterChangeSignalStateList stateHelperList;
+    nearbyTC.reserve(10);
+    for(const auto& cl : *tcCont) {
+      // this can probably be done more elegantly
+      double dR = swclus->p4().DeltaR(cl->p4());
+      if(dR<m_tcMatch_dR && cl->e()>0) {
+	// could consider also requirements on the EM fraction or depth
+	nearbyTC.push_back(cl);
+	stateHelperList.add(cl, CaloCluster::State(m_signalstate));
+      } // match TC in a cone around SW cluster
+    }
+    ATH_MSG_VERBOSE("Found " << nearbyTC.size() << " nearby topoclusters");
+
+    bool doSum = true;
+    double sumE_tc = 0.;
+    const CaloCluster* bestbadmatch = 0;
+    std::sort(nearbyTC.begin(),nearbyTC.end(),greaterPt);
+    for(const auto& cl : nearbyTC) {
+      double tcl_e = cl->e();
+      // skip cluster if it's above our bad match threshold
+      // FIXME: What to do with these poor matches?
+      if(tcl_e>m_tcMatch_maxRat*eg_cl_e) {
+	ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (tcl_e/eg_cl_e));
+	if( !bestbadmatch || (fabs(tcl_e/eg_cl_e-1.) < fabs(bestbadmatch->e()/eg_cl_e-1.)) ) bestbadmatch = cl;
+	continue;
+      }
+
+      ATH_MSG_VERBOSE("E match with new cluster: " << fabs(sumE_tc+tcl_e - eg_cl_e) / eg_cl_e);
+      if( (doSum = (fabs(sumE_tc+tcl_e - eg_cl_e) < fabs(sumE_tc - eg_cl_e))) ) {
+	ATH_MSG_VERBOSE("Accept topocluster with pt " << cl->pt() << ", e " << cl->e() << " in sum.");
+	ATH_MSG_VERBOSE("E match with new cluster: " << fabs(sumE_tc+tcl_e - eg_cl_e) / eg_cl_e);
+	ATH_MSG_VERBOSE("Energy ratio of TC to eg: " << tcl_e / eg_cl_e);
+	tclist.push_back(cl);
+	sumE_tc += tcl_e;
+	tcvec += MissingETBase::Types::constvec_t(*cl);
+      } // if we will retain the topocluster
+    } // loop over nearby clusters
+    if(sumE_tc<1e-9 && bestbadmatch) {
+      ATH_MSG_VERBOSE("No better matches found -- add bad match topocluster with pt "
+		      << bestbadmatch->pt() << ", e " << bestbadmatch->e() << ".");
+      tclist.push_back(bestbadmatch);
+      tcvec += MissingETBase::Types::constvec_t(*bestbadmatch);
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METEgammaTool.cxx b/Reconstruction/MET/METReconstruction/Root/METEgammaTool.cxx
index b8d20d7ae2cf12e45554a49f30e6dc124354f960..03e85fa201b806661575a7ab39c5fbc27882ba07 100644
--- a/Reconstruction/MET/METReconstruction/Root/METEgammaTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METEgammaTool.cxx
@@ -51,6 +51,10 @@ namespace met {
   // Public methods: 
   /////////////////////////////////////////////////////////////////// 
 
+  static bool greaterPt(const xAOD::IParticle* part1, const xAOD::IParticle* part2) {
+    return part1->pt()>part2->pt();
+  }
+
   // Constructors
   ////////////////
   METEgammaTool::METEgammaTool(const std::string& name) : 
@@ -68,7 +72,7 @@ namespace met {
     declareProperty( "ClusOQ",            m_eg_clusOQ      = 0x0    );
     declareProperty( "TestClusOQ",        m_eg_testClusOQ  = false  ); // could e.g. veto BADCLUSELECTRON
 
-    declareProperty( "TopoClusKey",       m_tcCont_key = "CaloCalTopoCluster" );
+    declareProperty( "TopoClusKey",       m_tcCont_key = "CaloCalTopoClusters" );
     declareProperty( "TCMatchDeltaR",     m_tcMatch_dR        = 0.1 );
     declareProperty( "TCMatchMaxRat",     m_tcMatch_maxRat    = 1.5 );
     declareProperty( "TCMatchTolerance",  m_tcMatch_tolerance = 0.2 );
@@ -178,20 +182,23 @@ namespace met {
     bool goodmatch = false;
     bool doSum = true;
     double sumE_tc = 0.;
+    const CaloCluster* bestbadmatch = 0;
     std::sort(nearbyTC.begin(),nearbyTC.end(),greaterPt);
     for(vector<const xAOD::CaloCluster*>::const_iterator iClus=nearbyTC.begin();
-	iClus!=nearbyTC.end() && doSum; ++iClus) {
+	iClus!=nearbyTC.end(); ++iClus) {
       double tcl_e = (*iClus)->e();
       // skip cluster if it's above our bad match threshold
       if(tcl_e>m_tcMatch_maxRat*eg_cl_e) {
 	ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (tcl_e/eg_cl_e));
+	if( !bestbadmatch || (fabs(tcl_e/eg_cl_e-1.) < fabs(bestbadmatch->e()/eg_cl_e-1.)) ) bestbadmatch = *iClus;
 	continue;
       }
 
       switch(m_tcMatch_method) {
       case 0:
 	// sum clusters until the next cluster to be added will make the energy match worse
-	doSum = ( fabs(sumE_tc+tcl_e - eg_cl_e) < fabs(sumE_tc - eg_cl_e));
+	doSum = ( fabs(sumE_tc+tcl_e - eg_cl_e) < fabs(sumE_tc - eg_cl_e) );
+	ATH_MSG_VERBOSE("E match with new cluster: " << fabs(sumE_tc+tcl_e - eg_cl_e) / eg_cl_e);
 	break;
       case 1:
 	// sum clusters until we either find one very good cluster match
@@ -204,11 +211,15 @@ namespace met {
 	tclist.push_back(*iClus);
 	sumE_tc += tcl_e;
 	if(tclist.size()==1) goodmatch = fabs(tcl_e/eg_cl_e-1)<m_tcMatch_tolerance;
-	ATH_MSG_VERBOSE("Accept topocluster in sum.");
-	ATH_MSG_VERBOSE("Energy ratio of TC to eg: " << tcl_e / swclus->e());
+	ATH_MSG_VERBOSE("Accept topocluster with pt " << (*iClus)->pt() << ", e " << (*iClus)->e() << " in sum.");
+	ATH_MSG_VERBOSE("Energy ratio of TC to eg: " << tcl_e / eg_cl_e);
 	ATH_MSG_VERBOSE("Do we have a good match? " << (goodmatch ? "YES" : "NO"));
       } // if we will retain the topocluster
     } // loop over nearby clusters
+    if(sumE_tc<1e-9 && bestbadmatch) {
+      tclist.push_back(bestbadmatch);
+      sumE_tc += bestbadmatch->e();
+    }
     ATH_MSG_VERBOSE("Egamma links " << eg->nCaloClusters() << " clusters");
     ATH_MSG_VERBOSE("Identified " << tclist.size() << " matched topoclusters");
     ATH_MSG_VERBOSE("Egamma energy: " << eg->e());
diff --git a/Reconstruction/MET/METReconstruction/Root/METElectronAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METElectronAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d713c7b8eafdeedaee91558bbbfb29e695765858
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METElectronAssociator.cxx
@@ -0,0 +1,169 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METElectronAssociator.cxx 
+// Implementation file for class METElectronAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METElectronAssociator.h"
+
+// Egamma EDM
+#include "xAODEgamma/ElectronContainer.h"
+#include "xAODEgamma/EgammaxAODHelpers.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METElectronAssociator::METElectronAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name),
+    METEgammaAssociator(name)
+  {}
+
+  // Destructor
+  ///////////////
+  METElectronAssociator::~METElectronAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METElectronAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METElectronAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // executeTool
+  ////////////////
+  StatusCode METElectronAssociator::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap) 
+  {
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+
+    const ElectronContainer* elCont(0);
+    if( evtStore()->retrieve(elCont, m_input_data_key).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input electron container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+
+    ATH_MSG_DEBUG("Successfully retrieved electron collection");
+    if (fillAssocMap(metMap,elCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to fill map with electron container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+
+  StatusCode METElectronAssociator::extractTracks(const xAOD::IParticle* obj,
+						  std::vector<const xAOD::IParticle*>& constlist,
+						  MissingETBase::Types::constvec_t& trkvec,
+						  const xAOD::CaloClusterContainer* /*tcCont*/,
+					          const xAOD::Vertex* pv)
+  {
+    const Electron *el = static_cast<const Electron*>(obj);
+    for(size_t iTrk=0; iTrk<el->nTrackParticles(); ++iTrk) {
+      const TrackParticle* eltrk = EgammaHelpers::getOriginalTrackParticleFromGSF(el->trackParticle(iTrk));
+      // if(acceptTrack(eltrk,pv) && isGoodEoverP(eltrk,tcCont) && el->p4().DeltaR(eltrk->p4())<0.1) {
+      if(acceptTrack(eltrk,pv) && el->p4().DeltaR(eltrk->p4())<0.1) {
+	ATH_MSG_VERBOSE("Accept electron track " << eltrk << " px, py = " << eltrk->p4().Px() << ", " << eltrk->p4().Py());
+	constlist.push_back(eltrk);
+	trkvec += *eltrk;
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  //**********************************************************************
+  // Get Egamma constituents
+  StatusCode METElectronAssociator::extractPFO(const xAOD::IParticle* obj,
+					       std::vector<const xAOD::IParticle*>& pfolist,
+					       MissingETBase::Types::constvec_t& pfovec,
+					       MissingETBase::Types::constvec_t& trkvec,
+					       const xAOD::PFOContainer* pfoCont,
+					       const xAOD::Vertex* pv)
+  {
+    const Electron *el = static_cast<const Electron*>(obj);
+    // safe to assume a single SW cluster?
+    // will do so for now...
+    const CaloCluster* swclus = el->caloCluster();
+    double eg_cl_e = swclus->e();
+
+    // the matching strategy depends on how the cluster container is sorted
+    // easier if it's sorted in descending pt order
+    // we'll worry about optimisation later
+    std::vector<const PFO*> nearbyPFO;
+    nearbyPFO.reserve(10);
+    for(const auto& pfo : *pfoCont) {
+      std::vector<const IParticle*> cls;
+      bool match = false;
+      if (pfo->charge()==0) {
+        if (swclus->p4().DeltaR(pfo->p4EM())<m_tcMatch_dR && pfo->eEM()>0) match = true;
+        //pfo->associatedParticles(PFODetails::CaloCluster,cls);
+        //for(const auto& cl : cls) {
+        //  if (!cl) continue;
+        //  double dR = swclus->p4().DeltaR(cl->p4());
+        //  if(dR<0.1 && cl->e()>0) match = true;
+        //}
+      }
+      for(size_t iTrk=0; iTrk<el->nTrackParticles(); ++iTrk) {
+        const TrackParticle* eltrk = EgammaHelpers::getOriginalTrackParticleFromGSF(el->trackParticle(iTrk));
+        if(pfo->charge()!=0 && acceptChargedPFO(eltrk,pv) && pfo->track(0) == eltrk) match = true;
+      }
+      if (match) nearbyPFO.push_back(pfo);
+    }
+    ATH_MSG_VERBOSE("Found " << nearbyPFO.size() << " nearby pfos");
+
+    bool doSum = true;
+    double sumE_pfo = 0.;
+    std::sort(nearbyPFO.begin(),nearbyPFO.end(),greaterPtPFO);
+    for(const auto& pfo : nearbyPFO) {
+      double pfo_e = (pfo->charge()==0 ? pfo->eEM() : pfo->e());
+      // skip cluster if it's above our bad match threshold
+      if(pfo->eEM()>m_tcMatch_maxRat*eg_cl_e) {
+        ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (pfo->eEM()/eg_cl_e));
+	continue;
+      }
+
+      if( (doSum = fabs(sumE_pfo+pfo->e()-eg_cl_e) < fabs(sumE_pfo - eg_cl_e)) ) {
+	pfolist.push_back(pfo);
+	sumE_pfo += pfo_e;
+	pfovec += (pfo->charge()==0 ? MissingETBase::Types::constvec_t(pfo->ptEM()*cos(pfo->phiEM()),pfo->ptEM()*sin(pfo->phiEM()),pfo->ptEM()*cosh(pfo->etaEM()),pfo->eEM(),pfo->eEM()) : MissingETBase::Types::constvec_t(*pfo));
+        trkvec += MissingETBase::Types::constvec_t(*pfo);
+      } // if we will retain the topocluster
+      else {break;}
+    } // loop over nearby clusters
+
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METJetAssocTool.cxx b/Reconstruction/MET/METReconstruction/Root/METJetAssocTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c41e88c9e5ffd5cbdaf9e27f45183868f058f05d
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METJetAssocTool.cxx
@@ -0,0 +1,135 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METJetAssocTool.cxx 
+// Implementation file for class METJetAssocTool
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METJetAssocTool.h"
+
+// MET EDM
+#include "xAODMissingET/MissingETComposition.h"
+
+// Jet EDM
+#include "xAODJet/JetContainer.h"
+#include "xAODJet/JetAttributes.h"
+
+// Tracking EDM
+#include "xAODTracking/Vertex.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METJetAssocTool::METJetAssocTool(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name)
+  {}
+
+  // Destructor
+  ///////////////
+  METJetAssocTool::~METJetAssocTool()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METJetAssocTool::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METJetAssocTool::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // executeTool
+  ////////////////
+  StatusCode METJetAssocTool::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap) 
+  {
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+
+    // Retrieve the jet container
+    const JetContainer* jetCont = 0;
+    if( evtStore()->retrieve(jetCont, m_input_data_key).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input jet container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved jet collection");
+
+    // Retrieve the vertices
+    const VertexContainer* vxCont = 0;
+    if( evtStore()->retrieve(vxCont,"PrimaryVertices").isFailure() ) { // configurable
+      ATH_MSG_WARNING("Unable to retrieve vertex container");
+      return StatusCode::FAILURE;
+    } 
+    const Vertex* pv = 0;
+    ATH_MSG_DEBUG("Successfully retrieved vertex collection");
+    for(const auto& vx : *vxCont) {
+      if(vx->vertexType()==VxType::PriVtx)
+	{pv = vx; break;}
+    }
+    if(!pv) {
+      ATH_MSG_WARNING("Failed to find primary vertex!");
+      return StatusCode::FAILURE;
+    }
+
+    // Create jet associations
+    MissingETBase::Types::constvec_t trkvec;
+    for(const auto& jet : *jetCont) {
+      std::vector<const IParticle*> selectedTracks;
+      if (m_pflow) {
+        for (size_t consti = 0; consti < jet->numConstituents(); consti++) {
+          const xAOD::PFO *pfo = dynamic_cast<const xAOD::PFO*>(jet->rawConstituent(consti));
+          if (pfo->charge()!=0) trkvec += *pfo;
+        }
+      } else {
+        std::vector<const IParticle*> jettracks;
+        jet->getAssociatedObjects<IParticle>(JetAttribute::GhostTrack,jettracks);
+
+	selectedTracks.reserve(jettracks.size());
+	for(const auto& trk : jettracks) {
+	  const TrackParticle* pTrk = dynamic_cast<const TrackParticle*>(trk);
+	  if( acceptTrack(pTrk,pv) ) {
+	    selectedTracks.push_back(trk);
+	    ATH_MSG_VERBOSE("Accept track " << trk << " px, py = " << trk->p4().Px() << ", " << trk->p4().Py());
+	  }
+	}
+      }
+      MissingETComposition::add(metMap,jet,selectedTracks);
+      if (m_pflow) metMap->back()->setJetTrkVec(trkvec);
+      ATH_MSG_VERBOSE("Added association " << metMap->findIndex(jet) << " pointing to jet " << jet);
+      ATH_MSG_VERBOSE("Jet pt, eta, phi = " << jet->pt() << ", " << jet->eta() << "," << jet->phi() );
+
+    }
+    MissingETComposition::addMiscAssociation(metMap);
+    ATH_MSG_DEBUG("Added miscellaneous association");
+
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METJetFilterTool.cxx b/Reconstruction/MET/METReconstruction/Root/METJetFilterTool.cxx
index 30d1f02036c8c142c86904de8d8283bb6187da0d..f57889138c29b674326e2e31963a15579c859c17 100644
--- a/Reconstruction/MET/METReconstruction/Root/METJetFilterTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METJetFilterTool.cxx
@@ -96,6 +96,10 @@ namespace met {
 	  fabs(jet->eta()) < m_jet_maxEtaJVF ) {
 	vector<float> jvf;
 	jet->getAttribute<vector<float> >(JetAttribute::JVF,jvf);
+	if(!jet->getAttribute<vector<float> >(JetAttribute::JVF,jvf)) {
+	  ATH_MSG_WARNING("Jet JVF unavailable!");
+	  return false;
+	}
 	ATH_MSG_VERBOSE("Jet JVF = " << jvf[0]);
 	if( fabs(jvf[0]) < m_jet_minAbsJVF ) return false;
       }
diff --git a/Reconstruction/MET/METReconstruction/Root/METJetTool.cxx b/Reconstruction/MET/METReconstruction/Root/METJetTool.cxx
index 80fac487247d6aff3792cfa8362a9c8bca4d12b0..163e319020802cd36bf29f5e1e156c6b619f608f 100644
--- a/Reconstruction/MET/METReconstruction/Root/METJetTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METJetTool.cxx
@@ -129,6 +129,7 @@ namespace met {
   {
 
     const Jet* jet = dynamic_cast<const Jet*>(object);
+    m_signalstate = jet->getConstituentsSignalState();
 
     ATH_MSG_VERBOSE("Retrieving jet constituents.");
     // first get the topoclusters
@@ -141,16 +142,14 @@ namespace met {
     vector<const IParticle*> constit_vec;
     constit_vec.reserve(jet->numConstituents());
     CaloClusterChangeSignalStateList stateHelperList;
-    //stateHelperList.reserve(jet->numConstituents());
     for(JetConstituentVector::const_iterator iClus = constit.begin();
 	iClus!=constit.end(); ++iClus) {
       sumE_allclus += (*iClus)->e();
       const CaloCluster* pClus = dynamic_cast<const CaloCluster*>( (*iClus)->rawConstituent() );
-      // create a helper to change the signal state and retain it until the end of the method
-      // signal state will be reset when it goes out of scope
-      //CaloClusterChangeSignalState stateHelper(pClus, CaloCluster::State(m_signalstate));
       stateHelperList.add(pClus, CaloCluster::State(m_signalstate));
 
+      ATH_MSG_VERBOSE("Constit E = " << pClus->e());
+
       constit_vec.push_back(pClus);
     } // loop over jet constituents
     ATH_MSG_VERBOSE( "Jet E = " << jet->e() << ", cluster energy sum = " << sumE_allclus );
@@ -165,6 +164,7 @@ namespace met {
 	  iClus!=constit_vec.end(); ++iClus) {
 	sumE_unique += (*iClus)->e();
 	acceptedSignals.push_back(*iClus);
+	ATH_MSG_VERBOSE("Unique constit E = " << (*iClus)->e());
       } // loop over jet unique constituents
       double scalef = sumE_unique / sumE_allclus;
       // weight as an entire object with the unused E fraction
@@ -236,20 +236,23 @@ namespace met {
 	  this->addToMET(*iJet,signalList,metTerm,metMap,objWeight);
 	} else {
 	  if( m_jet_doMinWetPtCut ) { 
-	    if( objWeight.wet() > m_jet_minWet ) {
-              ATH_MSG_VERBOSE("Jet weighted energy is above threshold -- add to MET");
-	      this->addToMET(*iJet,signalList,metTerm,metMap,objWeight);
-	      ATH_MSG_VERBOSE("Jet px = " << (*iJet)->px()
-			      << ", weighted px = " << (*iJet)->px()*objWeight.wpx()
-			      << ", MET px = " << metTerm->mpx() );
-            }
-	  } else {
             if( (*iJet)->pt()*objWeight.wet() > m_jet_minPt ) {
 	      ATH_MSG_VERBOSE("Jet unique energy is above threshold -- add to MET.");
               this->addToMET(*iJet,signalList,metTerm,metMap,objWeight);
               ATH_MSG_VERBOSE("Jet px = " << (*iJet)->px()
 			      << ", weighted px = " << (*iJet)->px()*objWeight.wpx()
 			      << ", MET px = " << metTerm->mpx() );
+              ATH_MSG_VERBOSE("Jet pt = " << (*iJet)->pt()
+			      << ", weighted pt = " << (*iJet)->pt()*objWeight.wet()
+			      << ", MET pt = " << metTerm->met() );
+            }
+	  } else {
+	    if( objWeight.wet() > m_jet_minWet ) {
+              ATH_MSG_VERBOSE("Jet weighted energy is above threshold -- add to MET");
+	      this->addToMET(*iJet,signalList,metTerm,metMap,objWeight);
+	      ATH_MSG_VERBOSE("Jet px = " << (*iJet)->px()
+			      << ", weighted px = " << (*iJet)->px()*objWeight.wpx()
+			      << ", MET px = " << metTerm->mpx() );
             }
           } // end if minWet
 	}
diff --git a/Reconstruction/MET/METReconstruction/Root/METMuonAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METMuonAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..f0eb2a78fd34684d8a88e65ad3ab7d46b9a3aad8
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METMuonAssociator.cxx
@@ -0,0 +1,139 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METMuonAssociator.cxx 
+// Implementation file for class METMuonAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METMuonAssociator.h"
+
+// Muon EDM
+#include "xAODMuon/MuonContainer.h"
+
+// Tracking EDM
+#include "xAODTracking/Vertex.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METMuonAssociator::METMuonAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name)
+  {}
+
+  // Destructor
+  ///////////////
+  METMuonAssociator::~METMuonAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METMuonAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METMuonAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+  // executeTool
+  ////////////////
+  StatusCode METMuonAssociator::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap)
+  {
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+
+    const MuonContainer* muonCont(0);
+    if( evtStore()->retrieve(muonCont, m_input_data_key).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input muon container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved muon collection");
+    if (fillAssocMap(metMap,muonCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to fill map with muon container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Get constituents
+  StatusCode METMuonAssociator::extractTopoClusters(const xAOD::IParticle* /*obj*/,
+						    std::vector<const xAOD::IParticle*>& /*tclist*/,
+						    MissingETBase::Types::constvec_t& /*tcvec*/,
+						    const xAOD::CaloClusterContainer* /*tcCont*/)
+  {
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METMuonAssociator::extractTracks(const xAOD::IParticle *obj,
+					      std::vector<const xAOD::IParticle*>& constlist,
+					      MissingETBase::Types::constvec_t& trkvec,
+					      const xAOD::CaloClusterContainer* /*tcCont*/,
+					      const xAOD::Vertex* pv)
+  {
+    const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
+    const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
+    //if(idtrack && acceptTrack(idtrack,pv) && isGoodEoverP(idtrack,tcCont)) {
+    if(idtrack && acceptTrack(idtrack,pv)) {
+      ATH_MSG_VERBOSE("Accept muon track " << idtrack << " px, py = " << idtrack->p4().Px() << ", " << idtrack->p4().Py());
+      ATH_MSG_VERBOSE("Muon ID track ptr: " << idtrack);
+      constlist.push_back(idtrack);
+      trkvec += *idtrack;
+      // if(mu->pt()>10e3 && (mu->muonType()==xAOD::Muon::Combined || mu->muonType()==xAOD::Muon::SegmentTagged)) {
+      //   mutracks.push_back(idtrack);
+      // }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Get constituents
+  StatusCode METMuonAssociator::extractPFO(const xAOD::IParticle* obj,
+					   std::vector<const xAOD::IParticle*>& pfolist,
+					   MissingETBase::Types::constvec_t& pfovec,
+					   MissingETBase::Types::constvec_t& trkvec,
+					   const xAOD::PFOContainer* pfoCont,
+					   const xAOD::Vertex* pv)
+  {  
+    const xAOD::Muon *mu = static_cast<const xAOD::Muon*>(obj);
+    const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
+    if(idtrack && acceptChargedPFO(idtrack,pv)) {
+      for(const auto& pfo : *pfoCont) {
+	if (pfo->charge()!=0 && pfo->track(0) == idtrack) {
+	  pfolist.push_back(pfo);
+	  trkvec += *idtrack;
+	  pfovec += *idtrack;
+	}
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METMuonTool.cxx b/Reconstruction/MET/METReconstruction/Root/METMuonTool.cxx
index 70151d142f77731e4a9bd1c360ee9f7e38184b30..b7118afb7a69771fd98bc2f7088c4bb134787940 100644
--- a/Reconstruction/MET/METReconstruction/Root/METMuonTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METMuonTool.cxx
@@ -121,9 +121,9 @@ namespace met {
 	if(nPrecision<m_mu_nPrecisionHits) return false;
       } // only if we use SA muons
     } // selection for StandAlone muons
-    else {
+    else if(mu->muonType()==Muon::Combined || mu->muonType()==Muon::SegmentTagged) {
       if(fabs(mu->eta())>m_mu_maxEta) return false;
-      
+
       // could add some error checking to make sure we successfully read the details
       uint8_t nPixHits(0), nSctHits(0);
       if(!mu->primaryTrackParticleLink().isValid()) return false;
@@ -133,7 +133,8 @@ namespace met {
       if(nPixHits<m_mu_nPixHits) return false;
       if(nPixHits+nSctHits<m_mu_nSiHits) return false;
     } // selection for SegmentTagged and Combined muons
-
+    else {return false;} // don't accept forward muons or calo tagged
+  
     return true;
   }
 
diff --git a/Reconstruction/MET/METReconstruction/Root/METPhotonAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METPhotonAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7c10b71a07d26a24f62c076a56b2b0cf0ac7380e
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METPhotonAssociator.cxx
@@ -0,0 +1,195 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METPhotonAssociator.cxx 
+// Implementation file for class METPhotonAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METPhotonAssociator.h"
+
+// Egamma EDM
+#include "xAODEgamma/PhotonContainer.h"
+#include "xAODEgamma/EgammaxAODHelpers.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METPhotonAssociator::METPhotonAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name),
+    METEgammaAssociator(name)
+  {}
+
+  // Destructor
+  ///////////////
+  METPhotonAssociator::~METPhotonAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METPhotonAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METPhotonAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // executeTool
+  ////////////////
+  StatusCode METPhotonAssociator::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap) 
+  {
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+
+    const xAOD::PhotonContainer* phCont(0);
+    if( evtStore()->retrieve(phCont, m_input_data_key).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input photon container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+
+    ATH_MSG_DEBUG("Successfully retrieved photon collection");
+
+    if (fillAssocMap(metMap,phCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to fill map with photon container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METPhotonAssociator::extractTracks(const xAOD::IParticle* obj,
+						std::vector<const xAOD::IParticle*>& constlist,
+						MissingETBase::Types::constvec_t& trkvec,
+						const xAOD::CaloClusterContainer* /*tcCont*/,
+					        const xAOD::Vertex* pv)
+  {
+    const xAOD::Photon *ph = static_cast<const xAOD::Photon*>(obj);
+    std::vector<const xAOD::TrackParticle*> phtrks;
+    for(size_t iVtx=0; iVtx<ph->nVertices(); ++iVtx) {
+      const xAOD::Vertex* phvx = ph->vertex(iVtx);
+      for(size_t iTrk=0; iTrk<phvx->nTrackParticles(); ++iTrk) {
+	// if(!phvx->trackParticle(iTrk)) {
+	//   ATH_MSG_VERBOSE("Invalid photon trackparticle pointer");
+	// }
+	const xAOD::TrackParticle* phtrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(phvx->trackParticle(iTrk));
+	// if(acceptTrack(phtrk,pv) && isGoodEoverP(phtrk,tcCont)) {
+	if(acceptTrack(phtrk,pv)) {
+	  // bool matchedmu = false;
+	  // for(const auto& mutrk : mutracks) {
+	  //   if( (matchedmu = (phtrk == mutrk)) ) {
+	  // 	ATH_MSG_VERBOSE("Veto track matched to muon");
+	  // 	break;
+	  //   }
+	  // }
+	  bool duplicate = false;
+	  for(const auto& gamtrk : phtrks) {
+	    if( (duplicate = (phtrk == gamtrk)) ) {
+	      ATH_MSG_VERBOSE("Veto duplicate track");
+	      break;
+	    }
+	  }
+	  // if(!matchedmu && !duplicate) {
+	  if(!duplicate) {
+	    ATH_MSG_VERBOSE("Accept photon track " << phtrk << " px, py = " << phtrk->p4().Px() << ", " << phtrk->p4().Py());
+	    ATH_MSG_VERBOSE("              track eta, phi = " << phtrk->p4().Eta() << ", " << phtrk->p4().Phi());
+	    constlist.push_back(phtrk);
+	    trkvec += *phtrk;
+	    phtrks.push_back(phtrk);
+	  }
+	}
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+  //**********************************************************************
+  // Get Egamma constituents
+  StatusCode METPhotonAssociator::extractPFO(const xAOD::IParticle* obj,
+					     std::vector<const xAOD::IParticle*>& pfolist,
+					     MissingETBase::Types::constvec_t& pfovec,
+					     MissingETBase::Types::constvec_t& trkvec,
+					     const xAOD::PFOContainer* pfoCont,
+					     const xAOD::Vertex* pv)
+  {
+    const xAOD::Photon *ph = static_cast<const xAOD::Photon*>(obj);
+    // safe to assume a single SW cluster?
+    // will do so for now...
+    const xAOD::CaloCluster* swclus = ph->caloCluster();
+    double eg_cl_e = swclus->e();
+
+    // the matching strategy depends on how the cluster container is sorted
+    // easier if it's sorted in descending pt order
+    // we'll worry about optimisation later
+    std::vector<const xAOD::PFO*> nearbyPFO;
+    nearbyPFO.reserve(10);
+    for(const auto& pfo : *pfoCont) {
+      std::vector<const IParticle*> cls;
+      bool match = false;
+      if (pfo->charge()==0) {
+        if (swclus->p4().DeltaR(pfo->p4EM())<0.1 && pfo->eEM()>0) match = true;
+        //pfo->associatedParticles(PFODetails::CaloCluster,cls);
+        //for(const auto& cl : cls) {
+        //  if (!cl) continue;
+        //  double dR = swclus->p4().DeltaR(cl->p4());
+        //  if(dR<0.1 && cl->e()>0) match = true;
+        //}
+      }
+      for(size_t iVtx=0; iVtx<ph->nVertices(); ++iVtx) {
+        const xAOD::Vertex* phvx = ph->vertex(iVtx);
+        for(size_t iTrk=0; iTrk<phvx->nTrackParticles(); ++iTrk) {
+          const xAOD::TrackParticle* phtrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(phvx->trackParticle(iTrk));
+          if(pfo->charge()!=0 && acceptChargedPFO(phtrk,pv) && pfo->track(0) == phtrk) match = true; 
+        }
+      }
+      if (match) nearbyPFO.push_back(pfo);
+    }
+    ATH_MSG_VERBOSE("Found " << nearbyPFO.size() << " nearby pfos");
+
+    bool doSum = true;
+    double sumE_pfo = 0.;
+    std::sort(nearbyPFO.begin(),nearbyPFO.end(),greaterPtPFO);
+    for(const auto& pfo : nearbyPFO) {
+      double pfo_e = (pfo->charge()==0 ? pfo->eEM() : pfo->e());
+      // skip cluster if it's above our bad match threshold
+      if(pfo->eEM()>m_tcMatch_maxRat*eg_cl_e) {
+        ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (pfo->eEM()/eg_cl_e));
+	continue;
+      }
+
+      if( (doSum = fabs(sumE_pfo+pfo->e()-eg_cl_e) < fabs(sumE_pfo - eg_cl_e)) ) {
+	pfolist.push_back(pfo);
+	sumE_pfo += pfo_e;
+	pfovec += (pfo->charge()==0 ? MissingETBase::Types::constvec_t(pfo->ptEM()*cos(pfo->phiEM()),pfo->ptEM()*sin(pfo->phiEM()),pfo->ptEM()*cosh(pfo->etaEM()),pfo->eEM(),pfo->eEM()) : MissingETBase::Types::constvec_t(*pfo));
+        trkvec += MissingETBase::Types::constvec_t(*pfo);
+      } // if we will retain the topocluster
+      else {break;}
+    } // loop over nearby clusters
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METSoftAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METSoftAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..091bbe408f4b52888b557f73a260b5235c57210d
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METSoftAssociator.cxx
@@ -0,0 +1,114 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METSoftAssociator.cxx 
+// Implementation file for class METSoftAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METSoftAssociator.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METSoftAssociator::METSoftAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name)
+  {
+  }
+
+  // Destructor
+  ///////////////
+  METSoftAssociator::~METSoftAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METSoftAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METSoftAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // executeTool
+  ////////////////
+  StatusCode METSoftAssociator::executeTool(xAOD::MissingETContainer* metCont, xAOD::MissingETAssociationMap* metMap) 
+  {
+
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+    const xAOD::CaloClusterContainer* tcCont;
+    const xAOD::Vertex* pv;
+    const xAOD::TrackParticleContainer* trkCont;
+    const xAOD::PFOContainer* pfoCont;
+    if (retrieveConstituents(tcCont,pv,trkCont,pfoCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to retrieve constituent containers");
+      return StatusCode::FAILURE;
+    }
+
+    // Create a MissingETContainer with its aux store
+    MissingET* metCoreCl = new MissingET(0.,0.,0.,"SoftClusCore",MissingETBase::Source::softEvent() | MissingETBase::Source::cluster());
+    metCont->push_back(metCoreCl);
+    MissingET* metCoreTrk = new MissingET(0.,0.,0.,"PVSoftTrkCore",MissingETBase::Source::softEvent() | MissingETBase::Source::track());
+    metCont->push_back(metCoreTrk);
+    if (m_pflow) {
+      const IParticleContainer* uniquePFOs = metMap->getUniqueSignals(pfoCont,MissingETBase::UsageHandler::Policy::ParticleFlow);
+      for(const auto& sig : *uniquePFOs) {
+	const PFO *pfo = dynamic_cast<const PFO*>(sig);
+	if (pfo->charge()!=0) {
+	  if (acceptChargedPFO(pfo->track(0),pv)) {
+	    *metCoreTrk += sig;
+	    *metCoreCl += sig;
+	  }
+	} else {
+	  TLorentzVector corrected = pfo->GetVertexCorrectedEMFourVec(*pv);
+	  if (pfo->eEM()>0) metCoreCl->add(corrected.Px(),corrected.Py(),corrected.Pt());
+	}
+      }
+    } else {
+      const IParticleContainer* uniqueClusters = metMap->getUniqueSignals(tcCont);
+      for(const auto& cl : *uniqueClusters) {
+	if (cl->e()>0) *metCoreCl += cl;
+      }
+      const IParticleContainer* uniqueTracks = metMap->getUniqueSignals(trkCont);
+      for(const auto& trk : *uniqueTracks) {
+	// if(acceptTrack(dynamic_cast<const TrackParticle*>(trk),pv) && isGoodEoverP(dynamic_cast<const TrackParticle*>(trk),tcCont)) {
+	ATH_MSG_VERBOSE("Test core track with pt " << trk->pt());
+	if(acceptTrack(dynamic_cast<const TrackParticle*>(trk),pv)) {
+	  ATH_MSG_VERBOSE("Add core track with pt " << trk->pt());
+	  *metCoreTrk += trk;
+	}
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METSoftTermsTool.cxx b/Reconstruction/MET/METReconstruction/Root/METSoftTermsTool.cxx
index b58995166cf52e0df605622145c7bef5cfb178f6..fa52907e1edee71889024d8b64a63bb301eb8243 100644
--- a/Reconstruction/MET/METReconstruction/Root/METSoftTermsTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METSoftTermsTool.cxx
@@ -150,23 +150,25 @@ namespace met {
 
   bool METSoftTermsTool::accept(const xAOD::CaloCluster* clus) const
   {
+    if(!clus) return false;
     if(m_cl_vetoNegE && clus->e()<0) return false;
     if(m_cl_onlyNegE && clus->e()>0) return false;
 
     return true;
   }
 
-  bool METSoftTermsTool::accept(const xAOD::TrackParticle* trk) const
+  bool METSoftTermsTool::accept(const xAOD::TrackParticle* /*trk*/) const
   {
+    // if(!trk) return false;
 
-    if(fabs(trk->pt())<500/*MeV*/ || fabs(trk->eta())>2.5) return false;
-
-    // could add some error checking to make sure we successfully read the details
-    uint8_t nPixHits(0), nSctHits(0);
-    trk->summaryValue(nPixHits,xAOD::numberOfPixelHits);
-    if(nPixHits<1) return false;
-    trk->summaryValue(nSctHits,xAOD::numberOfSCTHits);
-    if(nSctHits<6) return false;
+//    if(fabs(trk->pt())<500/*MeV*/ || fabs(trk->eta())>2.5) return false;
+//
+//    // could add some error checking to make sure we successfully read the details
+//    uint8_t nPixHits(0), nSctHits(0);
+//    trk->summaryValue(nPixHits,xAOD::numberOfPixelHits);
+//    if(nPixHits<1) return false;
+//    trk->summaryValue(nSctHits,xAOD::numberOfSCTHits);
+//    if(nSctHits<6) return false;
 
     return true;
   }
diff --git a/Reconstruction/MET/METReconstruction/Root/METTauAssociator.cxx b/Reconstruction/MET/METReconstruction/Root/METTauAssociator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..7d86d32bc62d8246daf3222786dbd2df2f0ab16b
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/Root/METTauAssociator.cxx
@@ -0,0 +1,200 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METTauAssociator.cxx 
+// Implementation file for class METTauAssociator
+//
+//  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+//
+// Author: P Loch, S Resconi, TJ Khoo, AS Mete
+/////////////////////////////////////////////////////////////////// 
+
+// METReconstruction includes
+#include "METReconstruction/METTauAssociator.h"
+
+// MET EDM
+#include "xAODMissingET/MissingETComposition.h"
+
+// Tau EDM
+#include "xAODTau/TauJetContainer.h"
+
+// Calo helpers
+#include "xAODCaloEvent/CaloClusterChangeSignalState.h"
+
+// Tracking EDM
+#include "xAODTracking/Vertex.h"
+
+namespace met {
+
+  using namespace xAOD;
+
+  // Constructors
+  ////////////////
+  METTauAssociator::METTauAssociator(const std::string& name) : 
+    AsgTool(name),
+    METAssociator(name)
+  {}
+
+  // Destructor
+  ///////////////
+  METTauAssociator::~METTauAssociator()
+  {}
+
+  // Athena algtool's Hooks
+  ////////////////////////////
+  StatusCode METTauAssociator::initialize()
+  {
+    ATH_MSG_VERBOSE ("Initializing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METTauAssociator::finalize()
+  {
+    ATH_MSG_VERBOSE ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  /////////////////////////////////////////////////////////////////// 
+  // Const methods: 
+  ///////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////// 
+  // Non-const methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  /////////////////////////////////////////////////////////////////// 
+  // Protected methods: 
+  /////////////////////////////////////////////////////////////////// 
+
+  // executeTool
+  ////////////////
+  StatusCode METTauAssociator::executeTool(xAOD::MissingETContainer* /*metCont*/, xAOD::MissingETAssociationMap* metMap) 
+  {
+    ATH_MSG_VERBOSE ("In execute: " << name() << "...");
+
+    const TauJetContainer* tauCont(0);
+    if( evtStore()->retrieve(tauCont, m_input_data_key).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input electron container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+
+    ATH_MSG_DEBUG("Successfully retrieved electron collection");
+    if (fillAssocMap(metMap,tauCont).isFailure()) {
+      ATH_MSG_WARNING("Unable to fill map with tau container " << m_input_data_key);
+      return StatusCode::FAILURE;
+    }
+    return StatusCode::SUCCESS;
+  }
+
+
+  //*********************************************************************************************************
+  // Get tau constituents
+  StatusCode METTauAssociator::extractTopoClusters(const xAOD::IParticle *obj,
+						   std::vector<const xAOD::IParticle*>& tclist,
+						   MissingETBase::Types::constvec_t& tcvec,
+				        	   const xAOD::CaloClusterContainer* /*tcCont*/)
+  {  
+    const TauJet* tau = static_cast<const TauJet*>(obj);
+    const Jet* seedjet = *tau->jetLink();
+    JetConstituentVector constit = seedjet->getConstituents();
+    CaloClusterChangeSignalStateList stateHelperList;
+    ATH_MSG_VERBOSE("Current tau has " << constit.size() << " constituents.");
+    // test for used topoclusters, and retrieve unused ones (ok until/unless we use PFlow taus)
+    // only use clusters for computing the overlap removal relative to other objects
+    for(const auto& cl : constit) {
+      // TEMP: use jet seed axis
+      //       taus will provide an accessor
+      double dR = seedjet->p4().DeltaR(cl->rawConstituent()->p4());
+      if(dR>0.2) continue;
+      // skip cluster if dR>0.2
+      const CaloCluster* pClus = dynamic_cast<const CaloCluster*>( cl->rawConstituent() );
+      stateHelperList.add(pClus, CaloCluster::State(m_signalstate));
+      tclist.push_back(pClus);
+      tcvec += MissingETBase::Types::constvec_t(*pClus);
+    } // loop over jet constituents
+    return StatusCode::SUCCESS;
+  }
+
+
+  StatusCode METTauAssociator::extractTracks(const xAOD::IParticle *obj,
+					     std::vector<const xAOD::IParticle*>& constlist,
+					     MissingETBase::Types::constvec_t& trkvec,
+					     const xAOD::CaloClusterContainer* /*tcCont*/,
+					     const xAOD::Vertex* pv)
+  {
+    const TauJet* tau = static_cast<const TauJet*>(obj);
+    const Jet* jet = *tau->jetLink();
+    for(size_t iTrk=0; iTrk<tau->nTracks(); ++iTrk) {
+      const TrackParticle* tautrk = tau->track(iTrk);
+      // if(acceptTrack(tautrk,pv) && isGoodEoverP(tautrk,tcCont)) {
+      if(acceptTrack(tautrk,pv)) {
+	// bool matchedmu = false;
+	// for(const auto& mutrk : mutracks) {
+	//   if( (matchedmu = (tautrk == mutrk)) ) {
+	//     ATH_MSG_VERBOSE("Veto track matched to muon");
+	// 	break;
+	//   }
+	// }
+	// if(!matchedmu) {
+	ATH_MSG_VERBOSE("Accept tau track " << tautrk << " px, py = " << tautrk->p4().Px() << ", " << tautrk->p4().Py());
+	constlist.push_back(tautrk);
+	trkvec += *tautrk;
+	// }
+      }
+    }
+    for(size_t iTrk=0; iTrk<tau->nOtherTracks(); ++iTrk) {
+      const TrackParticle* tautrk = tau->otherTrack(iTrk);
+      double dR = jet->p4().DeltaR(tautrk->p4());
+      //if(dR<0.2 && acceptTrack(tautrk,pv) && isGoodEoverP(tautrk,tcCont)) {
+      if(dR<0.2 && acceptTrack(tautrk,pv)) {
+	// bool matchedmu = false;
+	// for(const auto& mutrk : mutracks) {
+	//   if( (matchedmu = (tautrk == mutrk)) ) {
+	//     ATH_MSG_VERBOSE("Veto track matched to muon");
+	// 	break;
+	//   }
+	// }
+	// if(!matchedmu) {
+	ATH_MSG_VERBOSE("Accept track " << tautrk << " px, py = " << tautrk->p4().Px() << ", " << tautrk->p4().Py());
+	constlist.push_back(tautrk);
+	trkvec += *tautrk;
+	// }
+      }
+    }
+    return StatusCode::SUCCESS;
+  }
+  //*********************************************************************************************************
+  // Get tau constituents
+  StatusCode METTauAssociator::extractPFO(const xAOD::IParticle* obj,
+					  std::vector<const xAOD::IParticle*>& pfolist,
+					  MissingETBase::Types::constvec_t& pfovec,
+					  MissingETBase::Types::constvec_t& trkvec,
+					  const xAOD::PFOContainer* pfoCont,
+					  const xAOD::Vertex* pv)
+  {  
+    const TauJet* tau = static_cast<const TauJet*>(obj);
+    const Jet* seedjet = *tau->jetLink();
+    for(const auto& pfo : *pfoCont) {
+      bool match = false;
+      if (pfo->charge()==0 && seedjet->p4().DeltaR(pfo->p4EM())<0.2) match = true;
+      for(size_t iTrk=0; iTrk<tau->nTracks(); ++iTrk) {
+	const TrackParticle* tautrk = tau->track(iTrk);
+	if(acceptChargedPFO(tautrk,pv) && pfo->charge()!=0 && tautrk==pfo->track(0)) match = true; 
+      }
+      for(size_t iTrk=0; iTrk<tau->nOtherTracks(); ++iTrk) {
+	const TrackParticle* tautrk = tau->otherTrack(iTrk);
+	double dR = seedjet->p4().DeltaR(tautrk->p4());
+	if(dR<0.2 && acceptChargedPFO(tautrk,pv) && pfo->charge()!=0 && tautrk==pfo->track(0)) match = true;
+      }
+      if (!match) continue; 
+      pfolist.push_back(pfo);
+      if (pfo->charge()) trkvec += MissingETBase::Types::constvec_t(*pfo);
+      pfovec += (pfo->charge()==0 ? MissingETBase::Types::constvec_t(pfo->ptEM()*cos(pfo->phiEM()),pfo->ptEM()*sin(pfo->phiEM()),pfo->ptEM()*cosh(pfo->etaEM()),pfo->eEM(),pfo->eEM()) : MissingETBase::Types::constvec_t(*pfo));
+    }
+    return StatusCode::SUCCESS;
+  }
+
+}
diff --git a/Reconstruction/MET/METReconstruction/Root/METTauTool.cxx b/Reconstruction/MET/METReconstruction/Root/METTauTool.cxx
index 7e27ad63c6609dd896f4dcd3590cd3df64862c4e..ded1d869bf88f6b6c61e53fdfba6d4d6d14e0ab2 100644
--- a/Reconstruction/MET/METReconstruction/Root/METTauTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METTauTool.cxx
@@ -247,25 +247,25 @@ namespace met {
 	if ( this->resolveOverlap(*iTau,metMap,signalList,objWeight) ) {
 	  // add if not overlapping anything
 	  this->addToMET(*iTau,signalList,metTerm,metMap,objWeight);
-	} else {
+	} else { // no overlaps
 	  if( m_tau_doMinWetPtCut ) {
-	    if ( objWeight.wet() > m_tau_minWet ) {
+            if( (*iTau)->pt()*objWeight.wet() > m_tau_minPt ) {
               ATH_MSG_VERBOSE("Tau weighted energy is above threshold -- add to MET");
 	      this->addToMET(*iTau,signalList,metTerm,metMap,objWeight);
 	      //ATH_MSG_VERBOSE("Tau px = " << (*iTau)->px()
               //             << " , weighted px = " << (*iTau)->px()*objWeight.wpx()
               //             << " ,MET px = " << metTerm->mpx() );
-            }
+            } // if passes weighted pt cut
           } else {
-            if( (*iTau)->pt()*objWeight.wet() > m_tau_minPt ) {
+	    if ( objWeight.wet() > m_tau_minWet ) {
               ATH_MSG_VERBOSE("Tau weighted energy is above threshold -- add to MET");
 	      this->addToMET(*iTau,signalList,metTerm,metMap,objWeight);
 	      //ATH_MSG_VERBOSE("Tau px = " << (*iTau)->px()
               //             << " , weighted px = " << (*iTau)->px()*objWeight.wpx()
               //             << " ,MET px = " << metTerm->mpx() );
-            }
-          } // end if minWet
-	}
+            } // if passes weight cut
+          } // end if do weighted pt cut
+	} // overlapping
       } // if passing selection
     } // loop on tau container
     return StatusCode::SUCCESS;
diff --git a/Reconstruction/MET/METReconstruction/Root/METTrackFilterTool.cxx b/Reconstruction/MET/METReconstruction/Root/METTrackFilterTool.cxx
index cff589ca54e983ab79f169e573aecd93164778a9..64bd36db46c1258c139f0bc7f28a2c489c1470a3 100644
--- a/Reconstruction/MET/METReconstruction/Root/METTrackFilterTool.cxx
+++ b/Reconstruction/MET/METReconstruction/Root/METTrackFilterTool.cxx
@@ -27,26 +27,21 @@
 // Calo EDM
 #include "xAODCaloEvent/CaloClusterContainer.h"
 
+// Egamma EDM
+#include "xAODEgamma/EgammaxAODHelpers.h"
+#include "xAODEgamma/Electron.h"
+
 // Track errors
 #include "EventPrimitives/EventPrimitivesHelpers.h"
 
+// ConstDV
+#include "AthContainers/ConstDataVector.h"
+
 namespace met {
 
   using std::vector;
   //
-  using xAOD::IParticle;
-  //
-  using xAOD::TrackParticle;
-  using xAOD::TrackParticleContainer;
-  using xAOD::VertexContainer;
-  //
-  using xAOD::CaloCluster;
-  using xAOD::CaloClusterContainer;
-  //
-  using xAOD::MissingET;
-  using xAOD::MissingETComposition;
-  using xAOD::MissingETComponent;
-  using xAOD::MissingETComponentMap;
+  using namespace xAOD;
 
   /////////////////////////////////////////////////////////////////// 
   // Public methods: 
@@ -58,12 +53,19 @@ namespace met {
     AsgTool(name),
     METRefinerTool(name)
   {
-    declareProperty( "DoPVSel",         m_trk_doPVsel = true                 );
-    declareProperty( "TrackD0Max",      m_trk_d0Max = 1.5                    );
-    declareProperty( "TrackZ0Max",      m_trk_z0Max = 1.5                    );
-    declareProperty( "InputPVKey",      m_pv_inputkey = "PrimaryVertices"    );
-    declareProperty( "DoEoverPSel",     m_trk_doEoverPsel = true             );
-    declareProperty( "InputClusterKey", m_cl_inputkey = "CaloCalTopoCluster" );
+    declareProperty( "DoPVSel",           m_trk_doPVsel = true              );
+    // declareProperty( "TrackD0Max",      m_trk_d0Max = 1.5                    );
+    // declareProperty( "TrackZ0Max",      m_trk_z0Max = 1.5                    );
+    declareProperty( "InputPVKey",        m_pv_inputkey = "PrimaryVertices" );
+    declareProperty( "DoEoverPSel",       m_trk_doEoverPsel = false             );
+    declareProperty( "InputClusterKey",   m_cl_inputkey = "CaloCalTopoClusters" );
+    declareProperty( "InputElectronKey",  m_el_inputkey = "Electrons"       );
+    declareProperty( "InputMuonKey",      m_mu_inputkey = "Muons"           );
+
+    declareProperty( "DoVxSep",           m_doVxSep = false                 );
+    declareProperty( "TrackSelectorTool", m_trkseltool                      );
+    declareProperty( "TrackVxAssocTool",  m_trkToVertexTool                 );
+    declareProperty( "DoLepRecovery",     m_doLepRecovery=false             );
   }
 
   // Destructor
@@ -76,6 +78,10 @@ namespace met {
   StatusCode METTrackFilterTool::initialize()
   {
     ATH_MSG_INFO ("Initializing " << name() << "...");
+    ATH_CHECK(m_trkseltool.retrieve());
+    ATH_CHECK(m_trkToVertexTool.retrieve());
+
+    if(m_doVxSep) ATH_MSG_INFO("Building TrackMET for each vertex");
 
     return StatusCode::SUCCESS;
   }
@@ -100,15 +106,14 @@ namespace met {
   /////////////////////////////////////////////////////////////////// 
 
   // Implement for now, but should move to common tools when possible
-  bool METTrackFilterTool::isPVTrack(const xAOD::TrackParticle* trk,
-				     const xAOD::Vertex* pv) const
-  {
-
-    if(trk->d0()>m_trk_d0Max) return false;
-    if(fabs(trk->z0()+trk->vz() - pv->z()) > m_trk_z0Max) return false;
-
-    return true;
-  }
+  // bool METTrackFilterTool::isPVTrack(const xAOD::TrackParticle* /*trk*/,
+  // 				     const xAOD::Vertex* /*pv*/) const
+  // {
+  //   if(!trk || !pv) return false;
+  //   if(fabs(trk->d0())>m_trk_d0Max) return false;
+  //   if(fabs(trk->z0()+trk->vz() - pv->z()) > m_trk_z0Max) return false;
+  //   return true;
+  // }
 
   bool METTrackFilterTool::isGoodEoverP(const xAOD::TrackParticle* trk,
 					const std::vector<const xAOD::IParticle*>& trkList,
@@ -163,32 +168,32 @@ namespace met {
 
     ATH_MSG_DEBUG ("In execute: " << name() << "...");
 
-    if(m_trk_doPVsel) {
-      m_pv_cont = 0;
-      if( evtStore()->retrieve( m_pv_cont, m_pv_inputkey).isFailure() ) {
-        ATH_MSG_WARNING("Unable to retrieve input primary vertex container");
-        return StatusCode::SUCCESS;
-      }
-      if(m_pv_cont->size()>0) {
-	ATH_MSG_DEBUG("Main primary vertex has z = " << (*m_pv_cont)[0]->z());
-      } else{
-	ATH_MSG_WARNING("Event has no primary vertices");
-	return StatusCode::SUCCESS;
-      }
-    }
+    std::vector<const xAOD::Electron*> selElectrons;
+    std::vector<const xAOD::Muon*> selMuons;
 
-    const CaloClusterContainer* cl_cont = 0;
-    if(m_trk_doEoverPsel) {
-      if( evtStore()->retrieve( cl_cont, m_cl_inputkey).isFailure() ) {
-        ATH_MSG_WARNING("Unable to retrieve input calocluster container");
-        return StatusCode::SUCCESS;
-      }
-    }
+    if(m_doLepRecovery)
+    {
+      const ElectronContainer* elCont;
+      const MuonContainer* muCont;
+      ATH_CHECK(evtStore()->retrieve(elCont,m_el_inputkey));
+      ATH_CHECK(evtStore()->retrieve(muCont,m_mu_inputkey));
+
+      selectElectrons(*elCont, selElectrons);
+      selectMuons(*muCont, selMuons);
+    }     
+
+    // const CaloClusterContainer* cl_cont = 0;
+    // if(m_trk_doEoverPsel) {
+    //   if( evtStore()->retrieve( cl_cont, m_cl_inputkey).isFailure() ) {
+    //     ATH_MSG_WARNING("Unable to retrieve input calocluster container");
+    //     return StatusCode::FAILURE;
+    //   }
+    // }
 
     MissingETComponentMap::iterator iter = MissingETComposition::find(metMap,metTerm);
     if(iter==metMap->end()) {
       ATH_MSG_WARNING("Could not find current METComponent in MET Map!");
-      return StatusCode::SUCCESS;
+      return StatusCode::FAILURE;
     }
     MissingETComponent* newComp = *iter;
     newComp->setStatusWord(MissingETBase::Status::Tags::correctedTerm(MissingETBase::Status::Nominal,
@@ -197,38 +202,192 @@ namespace met {
     // Extract the component corresponding to the Track SoftTerms
     MissingETBase::Types::bitmask_t src_ST_idTrk = MissingETBase::Source::SoftEvent | MissingETBase::Source::idTrack();
     MissingETBase::Types::bitmask_t src_ST_refTrk = MissingETBase::Source::softEvent() | MissingETBase::Source::track();
+    metTerm->setSource(src_ST_refTrk);
+
     MissingETComponentMap::const_iterator citer = MissingETComposition::find(metMap,src_ST_idTrk);
     if(citer==metMap->end()) {
       ATH_MSG_WARNING("Could not find Soft ID Track component in MET Map!");
-      return StatusCode::SUCCESS;
+      return StatusCode::FAILURE;
+    }
+    vector<const TrackParticle*> softTracks;
+    softTracks.reserve((*citer)->size());
+    for(const auto& obj : (*citer)->objects()) {
+      const TrackParticle* trk = dynamic_cast<const TrackParticle*>(obj);
+      if(trk) {softTracks.push_back(trk);}
+      else {ATH_MSG_WARNING("Track filter given an object of type " << obj->type());}
     }
-    vector<const IParticle*> softTrackList = (*citer)->objects();
 
-    metTerm->setSource(src_ST_refTrk);
+    const Vertex* pv=0;
+    const VertexContainer* vxCont = 0;
+    vector<const Vertex*> vertices;
+    if(m_trk_doPVsel) {
+      if( evtStore()->retrieve( vxCont, m_pv_inputkey).isFailure() ) {
+        ATH_MSG_WARNING("Unable to retrieve input primary vertex container");
+        return StatusCode::FAILURE;
+      }
+      if(vxCont->size()>0) {
+	vertices.reserve(vxCont->size());
+	for(const auto& vx : *vxCont) {
+	  if(vx->vertexType()==VxType::PriVtx) {pv = vx;}
+	  vertices.push_back(vx);
+	}
+	ATH_MSG_DEBUG("Main primary vertex has z = " << pv->z());
+      } else{
+	ATH_MSG_WARNING("Event has no primary vertices");
+	return StatusCode::FAILURE;
+      }
+      if(!pv) {
+	ATH_MSG_WARNING("Did not find a primary vertex in the container.");
+	return StatusCode::FAILURE;
+      }
+    }
+
+    if(m_doVxSep) {
+      xAOD::TrackVertexAssociationMap trktovxmap=m_trkToVertexTool->getUniqueMatchMap(softTracks, vertices);
+
+      // initialize metContainer and metTerm
+      MissingETContainer* metCont = static_cast<MissingETContainer*>( metTerm->container() );
+
+      bool firstVx(true);
+      std::string basename = metTerm->name()+"_vx";
+      for(const auto& vx : *vxCont){
+	if(vx->vertexType()==VxType::PriVtx || vx->vertexType()==VxType::PileUp) {
+	  MissingET *met_vx = metTerm;
+	  if(!firstVx) {
+	    met_vx = new MissingET(0. ,0. ,0. );
+	    metCont->push_back(met_vx);
+	    met_vx->setSource(metTerm->source());
+	    MissingETComposition::add(metMap, met_vx);
+	  }
+	  met_vx->setName(basename+std::to_string(vx->index()));
+	  ATH_MSG_VERBOSE("Building " << met_vx->name());
+
+	  ATH_MSG_VERBOSE("Number of tracks associated to vertex " << vx->index() << ": "<< (trktovxmap[vx]).size());
+	  
+	  ATH_CHECK( buildTrackMET(metMap,metTerm,vx,selElectrons,selMuons,trktovxmap[vx]) );
+	  firstVx = false;
+	}
+      }
+    } else {
+      ATH_CHECK( buildTrackMET(metMap,metTerm,pv,selElectrons,selMuons,softTracks) );
+    }
+
+    return StatusCode::SUCCESS;
+  }
+
+  StatusCode METTrackFilterTool::buildTrackMET(xAOD::MissingETComponentMap* const metMap,
+					       xAOD::MissingET* const metTerm,
+					       const xAOD::Vertex* const pv,
+					       const std::vector<const xAOD::Electron*>& selElectrons,
+					       const std::vector<const xAOD::Muon*>& selMuons,
+					       const std::vector<const xAOD::TrackParticle*>& softTracks) const {
 
     vector<const IParticle*> dummyList;
 
+    const MissingETComponent* metComp = MissingETComposition::getComponent(metMap,metTerm);
+    if(!metComp) {
+      ATH_MSG_WARNING("Failed to find MissingETComponent for MET term " << metTerm->name());
+      return StatusCode::FAILURE;
+    }
     // Loop over the tracks and select only good ones
-    for( vector<const IParticle*>::const_iterator iPar=softTrackList.begin();
-	 iPar!=softTrackList.end(); ++iPar ) {
-      MissingETBase::Types::weight_t trackWeight = (*citer)->weight(*iPar);
-      const TrackParticle* trk = dynamic_cast<const TrackParticle*>(*iPar);
-      ATH_MSG_VERBOSE("Filter track with pt " << trk->pt());
+    for( const auto& trk : softTracks ) {
+      MissingETBase::Types::weight_t trackWeight = metComp->weight(trk);
       // Could/should use common implementation of addToMET here -- derive builder and refiner from a common base tool?
       bool passFilters = true;
-      if(m_trk_doPVsel && !isPVTrack(trk,(*m_pv_cont)[0])) passFilters = false;
-      if(m_trk_doEoverPsel && !isGoodEoverP(trk,softTrackList,cl_cont)) passFilters = false;
-      if(passFilters) {
-	ATH_MSG_VERBOSE("Add to MET.");
-	metTerm->add(trk->pt()*cos(trk->phi())*trackWeight.wpx(),
-		     trk->pt()*sin(trk->phi())*trackWeight.wpy(),
-		     trk->pt()*trackWeight.wet());
-	MissingETComposition::insert(metMap,metTerm,*iPar,dummyList,trackWeight);
+      //      if(m_trk_doPVsel && !isPVTrack(trk,(*vxCont)[0])) passFilters = false;
+      //      if(m_trk_doEoverPsel && !isGoodEoverP(trk,softTracks,cl_cont)) passFilters = false;
+      if(m_trk_doPVsel) {
+	if(!(m_trkseltool->accept( *trk, pv ))) passFilters=false;
+      } else {
+	if(!(m_trkseltool->accept( trk ))) passFilters=false;
+      }
+
+      bool isMuon=false;
+      bool isElectron=false;
+      size_t el_index=-1;
+
+      if(m_doLepRecovery) {
+        isMuon=isMuTrack(*trk,selMuons);
+        isElectron=isElTrack(*trk,selElectrons, el_index);
+      }
+
+      bool isLepton=(isMuon||isElectron);
+
+      if(passFilters || (m_doLepRecovery && isLepton)) {
+        if(!passFilters && isElectron && m_doLepRecovery) {
+	  //electron track fails, replace with electron pt
+          const Electron* el = selElectrons[el_index];
+
+          metTerm->add(el->pt()*cos(trk->phi())*trackWeight.wpx(),
+              el->pt()*sin(trk->phi())*trackWeight.wpy(),
+              el->pt()*trackWeight.wet());
+          MissingETComposition::insert(metMap,metTerm,el,dummyList,trackWeight);
+        } else {
+	  ATH_MSG_VERBOSE("Add track with pt " << trk->pt() <<" to MET.");
+	  metTerm->add(trk->pt()*cos(trk->phi())*trackWeight.wpx(),
+		       trk->pt()*sin(trk->phi())*trackWeight.wpy(),
+		       trk->pt()*trackWeight.wet());
+	  MissingETComposition::insert(metMap,metTerm,trk,dummyList,trackWeight);
+        }
       }
     }
     return StatusCode::SUCCESS;
   }
 
+  bool METTrackFilterTool::isElTrack(const xAOD::TrackParticle &trk, const std::vector<const xAOD::Electron*>& electrons, size_t &el_index) const
+  {
+    for(unsigned int eli=0; eli<electrons.size(); ++eli) {
+      const xAOD::Electron *el=electrons.at(eli);
+      if(&trk==xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(el->trackParticle())) {
+	el_index=eli;
+	return true;
+      }
+    }
+    return false;
+  }
+
+  bool METTrackFilterTool::isMuTrack(const xAOD::TrackParticle &trk, const std::vector<const xAOD::Muon*>& muons) const
+  {
+    for(unsigned mui=0;mui<muons.size();mui++) {
+      //        if(((muon_list.at(mui))->trackParticle(xAOD::Muon::InnerDetectorTrackParticle))->pt()==trk->pt())
+      if(((muons.at(mui))->trackParticle(xAOD::Muon::InnerDetectorTrackParticle))==&trk) {
+	return true;
+      }
+    }
+    return false;
+  }
+
+  void METTrackFilterTool::selectElectrons(const xAOD::ElectronContainer &elCont, std::vector<const xAOD::Electron*>& electrons) const
+  {
+    for(unsigned int eli=0; eli< elCont.size(); eli++) {
+      const xAOD::Electron *el=elCont.at(eli);
+      if( (el)->author()&0x1  //electron author
+	  && (el)->pt()>10000   // electron pt
+	  && fabs(el->eta())<2.47  // electron eta
+          ) {
+	if(!((fabs((el)->eta())>1.37) && (fabs((el)->eta())<1.52) )) {
+	  // crack region
+	  electrons.push_back(el);
+	}
+      }
+    }
+  }
+  
+
+  void METTrackFilterTool::selectMuons(const xAOD::MuonContainer &muCont, std::vector<const xAOD::Muon*>& muons) const
+  {
+    for(unsigned int mui=0; mui<muCont.size();mui++) {
+      const xAOD::Muon *mu=muCont.at(mui);
+      if( (mu->muonType()==xAOD::Muon::Combined)
+	  && (mu->pt()>6000.)
+	  && fabs(mu->eta())<2.5
+	  ) {
+	muons.push_back(mu);
+      }
+    }
+  }
+
+
   /////////////////////////////////////////////////////////////////// 
   // Const methods: 
   ///////////////////////////////////////////////////////////////////
diff --git a/Reconstruction/MET/METReconstruction/cmt/requirements b/Reconstruction/MET/METReconstruction/cmt/requirements
index 3c47bb5b35747748a63a482838d33785fdd90e15..16c344cb2a36b64daeefa63cdaf3ebd0a5cbed3c 100644
--- a/Reconstruction/MET/METReconstruction/cmt/requirements
+++ b/Reconstruction/MET/METReconstruction/cmt/requirements
@@ -17,14 +17,17 @@ use METRecoInterface	METRecoInterface-*	Reconstruction/MET
 
 ## Public EDM usage
 use xAODMissingET	xAODMissingET-*		Event/xAOD
-use xAODEgamma		xAODEgamma-*		Event/xAOD
 use xAODCaloEvent	xAODCaloEvent-*		Event/xAOD
 use xAODTracking	xAODTracking-*		Event/xAOD
 use xAODTruth		xAODTruth-*		Event/xAOD
 use xAODJet		xAODJet-*		Event/xAOD
+use xAODEgamma		xAODEgamma-*		Event/xAOD
+use xAODMuon		xAODMuon-*		Event/xAOD
 use xAODPFlow		xAODPFlow-*		Event/xAOD
 use PFlowUtils		PFlowUtils-*		Reconstruction/PFlow
-use CaloEvent           CaloEvent-*             Calorimeter
+
+use InDetTrackSelectionTool InDetTrackSelectionTool-* InnerDetector/InDetRecTools
+use TrackVertexAssociationTool TrackVertexAssociationTool-* InnerDetector/InDetRecTools
 
 ## ROOT for timing
 use AtlasROOT		AtlasROOT-*		External
@@ -34,9 +37,10 @@ private
 use AthenaBaseComps     AthenaBaseComps-*       Control
 
 ## EDM
-use xAODMuon		xAODMuon-*		Event/xAOD
+use AthContainers AthContainers-* Control
 use xAODTau		xAODTau-*		Event/xAOD
-#use xAODEventInfo      xAODEventInfo-*         Event/xAOD
+use xAODEventInfo       xAODEventInfo-*         Event/xAOD
+use CaloEvent           CaloEvent-*             Calorimeter
 
 ##
 
@@ -45,8 +49,13 @@ use EventPrimitives	EventPrimitives-*	Event
 
 end_private
 
+include_dirs $(METReconstruction_root)/src
+
 branches METReconstruction src src/components doc python share Root
 
+# Apply the cmake-specific command to access the private headers
+apply_pattern cmake_add_command command="include_directories(src)"
+
 ## default is to make component library
 library METReconstruction *.cxx ../Root/*.cxx -s=components *.cxx
 
@@ -57,3 +66,6 @@ apply_pattern declare_python_modules files="../python/*.py"
 private
 macro DOXYGEN_INPUT "" Doxygen "../src ../Root ../$(package) ../doc ../share ../python ../cmt/fragments"
 end_private
+
+use AtlasReflex AtlasReflex-* External -no-auto-imports
+apply_pattern lcgdict dict=METReconstruction selectionfile=selection.xml headerfiles="../METReconstruction/METReconstructionDict.h"
diff --git a/Reconstruction/MET/METReconstruction/python/METAssocConfig.py b/Reconstruction/MET/METReconstruction/python/METAssocConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b2fdd5c442e8682d86c60d11637c3da10fbf04d
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/python/METAssocConfig.py
@@ -0,0 +1,165 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from AthenaCommon import CfgMgr
+
+#################################################################################
+# Define some default values
+
+clusterSigStates = {
+    'EMScale':0,
+    'LocHad':1
+}
+
+defaultInputKey = {
+   'Ele'       :'Electrons',
+   'Gamma'     :'Photons',
+   'Tau'       :'TauJets',
+   'LCJet'     :'AntiKt4LCTopoJets',
+   'EMJet'     :'AntiKt4EMTopoJets',
+   'PFlowJet'  :'AntiKt4EMPFlowJets',
+   'Muon'      :'Muons',
+   'Soft'      :'',
+   'ClusColl'  :'CaloCalTopoClusters',
+   'TrkColl'   :'InDetTrackParticles',
+   'PrimVxColl':'PrimaryVertices',
+   'Truth'     :'TruthParticles',
+   }
+
+# # old naming scheme
+# defaultInputKey = {
+#     'Ele'       :'ElectronCollection',
+#     'Gamma'     :'PhotonCollection',
+#     'Tau'       :'TauRecContainer',
+#     'LCJet'     :'AntiKt4LCTopoJets',
+#     'EMJet'     :'AntiKt4EMTopoJets',
+#     'PFlowJet'  :'AntiKt4EMPFlowJets',
+#     'Muon'      :'Muons',
+#     'Soft'      :'',
+#     'ClusColl'  :'CaloCalTopoCluster',
+#     'TrkColl'   :'InDetTrackParticles',
+#     'PrimVxColl':'PrimaryVertices',
+#     'Truth'     :'TruthParticle',
+#     }
+
+prefix = 'METAssocConfig:   '
+
+#################################################################################
+# Configuration of builders
+
+class AssocConfig:
+    def __init__(self,objType='',inputKey=''):
+        self.objType = objType
+        self.inputKey = inputKey
+
+def getAssociator(config,suffix,doPFlow):
+    tool = None
+
+    from AthenaCommon.AppMgr import ToolSvc
+    # Construct tool and set defaults for case-specific configuration
+    if config.objType == 'Ele':
+        tool = CfgMgr.met__METElectronAssociator('MET_ElectronAssociator_'+suffix)
+    if config.objType == 'Gamma':
+        tool = CfgMgr.met__METPhotonAssociator('MET_PhotonAssociator_'+suffix)
+    if config.objType == 'Tau':
+        tool = CfgMgr.met__METTauAssociator('MET_TauAssociator_'+suffix)
+    if config.objType == 'LCJet':
+        tool = CfgMgr.met__METJetAssocTool('MET_LCJetAssocTool_'+suffix)
+    if config.objType == 'EMJet':
+        tool = CfgMgr.met__METJetAssocTool('MET_EMJetAssocTool_'+suffix)
+    if config.objType == 'PFlowJet':
+        tool = CfgMgr.met__METJetAssocTool('MET_PFlowJetAssocTool_'+suffix)
+    if config.objType == 'Muon':
+        tool = CfgMgr.met__METMuonAssociator('MET_MuonAssociator_'+suffix)
+    if config.objType == 'Soft':
+        tool = CfgMgr.met__METSoftAssociator('MET_SoftAssociator_'+suffix)
+    if doPFlow:
+        pfotool = CfgMgr.CP__RetrievePFOTool('MET_PFOTool_'+suffix)
+        ToolSvc += pfotool
+        tool.PFOTool = pfotool
+        tool.PFlow=True
+    # set input/output key names
+    if config.inputKey == '':
+        tool.InputCollection = defaultInputKey[config.objType]
+        config.inputKey = tool.InputCollection
+        tool.ClusColl = defaultInputKey['ClusColl']
+        tool.TrkColl = defaultInputKey['TrkColl']
+    else:
+        tool.InputCollection = config.inputKey
+
+    trkseltool=CfgMgr.InDet__InDetTrackSelectionTool("IDTrkSel_METAssoc",
+                                                     CutLevel="TightPrimary",
+                                                     maxZ0SinTheta=1.5,
+                                                     maxD0overSigmaD0=3)
+    ToolSvc += trkseltool
+    tool.TrackSelectorTool = trkseltool
+    ToolSvc += tool
+    return tool
+
+#################################################################################
+# Top level MET configuration
+
+class METAssocConfig:
+    def outputCollections(self):
+        return 'MET_Core_'+self.suffix,'MET_Reference_'+self.suffix
+    #
+    def outputMap(self):
+        return 'METAssoc_'+self.suffix
+    #
+    def setupAssociators(self,buildconfigs):
+        print prefix, 'Setting up associators for MET config '+self.suffix
+        for config in buildconfigs:
+            if config.objType in self.associators:
+                print prefix, 'Config '+self.suffix+' already contains a associator of type '+config.objType
+                raise LookupError
+            else:
+                associator = getAssociator(config,self.suffix,self.doPFlow)
+                self.associators[config.objType] = associator
+                self.assoclist.append(associator)
+                print prefix, '  Added '+config.objType+' tool named '+associator.name()
+    #
+    def __init__(self,suffix,buildconfigs=[],
+                 doPFlow=False):
+        print prefix, 'Creating MET config \''+suffix+'\''
+        self.suffix = suffix
+        self.doPFlow = doPFlow
+        self.associators = {}
+        self.assoclist = [] # need an ordered list
+        #
+        self.setupAssociators(buildconfigs)
+
+# Set up a top-level tool with mostly defaults
+def getMETAssocTool(topconfig):
+    assocTool = CfgMgr.met__METAssociationTool('MET_AssociationTool_'+topconfig.suffix,
+                                       METAssociators = topconfig.assoclist,
+                                       METSuffix = topconfig.suffix)
+    return assocTool
+
+# Allow user to configure reco tools directly or get more default configurations
+def getMETAssocAlg(algName='METAssociation',configs={},tools=[]):
+
+    assocTools = []
+    assocTools += tools
+
+    from METReconstruction.METRecoFlags import metFlags
+    if configs=={} and tools==[]:
+        print prefix, 'Taking configurations from METRecoFlags'
+        configs = metFlags.METAssocConfigs()
+        print configs
+    for key,conf in configs.iteritems():
+        print prefix, 'Generate METAssocTool for MET_'+key
+        assoctool = getMETAssocTool(conf)
+        assocTools.append(assoctool)
+        metFlags.METAssocTools()[key] = assoctool
+
+    from AthenaCommon.AppMgr import ToolSvc
+    for tool in assocTools:
+        ToolSvc += tool
+        print prefix, 'Added METAssocTool \''+tool.name()+'\' to alg '+algName
+
+    assocAlg = CfgMgr.met__METRecoAlg(name=algName,
+                                      RecoTools=assocTools)
+#    assocAlg.OutputLevel=DEBUG
+    return assocAlg
+
+# Allow user to configure reco tools directly or get more default configurations
+#def getMETMakerAlg(algName='METMaker'):
diff --git a/Reconstruction/MET/METReconstruction/python/METConfig_Associator.py b/Reconstruction/MET/METReconstruction/python/METConfig_Associator.py
new file mode 100644
index 0000000000000000000000000000000000000000..005b55cb67118a5c7a12c143b3260764b1e3a4c1
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/python/METConfig_Associator.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from METReconstruction.METRecoFlags import metFlags
+from METReconstruction.METAssocConfig import AssocConfig, METAssocConfig
+
+from RecExConfig.RecFlags import rec
+doInDet = rec.doInDet()
+
+############################################################################
+# AntiKt4LCTopo
+JetType = 'LCJet'
+
+associators = [AssocConfig(JetType),
+               AssocConfig('Muon'),
+               AssocConfig('Ele'),
+               AssocConfig('Gamma'),
+               AssocConfig('Tau'),
+               AssocConfig('Soft')]
+cfg_akt4lc = METAssocConfig('AntiKt4LCTopo',
+                            associators,
+                            doPFlow=False
+                            )
+
+metFlags.METAssocConfigs()[cfg_akt4lc.suffix] = cfg_akt4lc
+metFlags.METAssocOutputList().append(cfg_akt4lc.suffix)
+
+############################################################################
+# AntiKt4EMTopo
+JetType = 'EMJet'
+    
+associators = [AssocConfig(JetType),
+               AssocConfig('Muon'),
+               AssocConfig('Ele'),
+               AssocConfig('Gamma'),
+               AssocConfig('Tau'),
+               AssocConfig('Soft')]
+cfg_akt4em = METAssocConfig('AntiKt4EMTopo',
+                            associators,
+                            doPFlow=False
+                            )
+
+metFlags.METAssocConfigs()[cfg_akt4em.suffix] = cfg_akt4em
+metFlags.METAssocOutputList().append(cfg_akt4em.suffix)
+
+############################################################################
+# PFlow
+if doInDet and metFlags.DoPFlow():
+    JetType = 'PFlowJet'
+    
+    associators = [AssocConfig(JetType),
+                   AssocConfig('Muon'),
+                   AssocConfig('Ele'),
+                   AssocConfig('Gamma'),
+                   AssocConfig('Tau'),
+                   AssocConfig('Soft')]
+    cfg_akt4pf = METAssocConfig('AntiKt4EMPFlow',
+                                associators,
+                                doPFlow=True
+                                )
+
+    metFlags.METAssocConfigs()[cfg_akt4pf.suffix] = cfg_akt4pf
+    metFlags.METAssocOutputList().append(cfg_akt4pf.suffix)
diff --git a/Reconstruction/MET/METReconstruction/python/METConfig_Calo.py b/Reconstruction/MET/METReconstruction/python/METConfig_Calo.py
new file mode 100644
index 0000000000000000000000000000000000000000..360d2b147cea7f94f33a74349b5810d745ad3c2c
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/python/METConfig_Calo.py
@@ -0,0 +1,41 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from METReconstruction.METRecoFlags import metFlags
+from METReconstruction.METRecoConfig import BuildConfig, RefConfig, METConfig,clusterSigStates
+#from METReconstruction.METRecoConfig_Associator import BuildConfig, RefConfig, METConfig,clusterSigStates
+
+############################################################################
+# EMTopo
+
+cfg_emt = METConfig('EMTopo',[BuildConfig('SoftClus','EMTopo')],
+                    doRegions=True
+                    )
+cfg_emt.builders['SoftClus'].SignalState = clusterSigStates['EMScale']
+
+metFlags.METConfigs()[cfg_emt.suffix] = cfg_emt
+metFlags.METOutputList().append(cfg_emt.suffix)
+metFlags.METOutputList().append(cfg_emt.suffix+"Regions")
+
+############################################################################
+# LocHadTopo
+
+cfg_lht = METConfig('LocHadTopo',[BuildConfig('SoftClus','LocHadTopo')],
+                    doRegions=True
+                    )
+cfg_lht.builders['SoftClus'].SignalState = clusterSigStates['LocHad']
+
+metFlags.METConfigs()[cfg_lht.suffix] = cfg_lht
+metFlags.METOutputList().append(cfg_lht.suffix)
+metFlags.METOutputList().append(cfg_lht.suffix+"Regions")
+
+
+############################################################################
+# Calo regions
+
+cfg_calo = METConfig('Calo',
+                     [BuildConfig('CaloReg')],
+                     doCells=True
+                     )
+
+metFlags.METConfigs()[cfg_calo.suffix] = cfg_calo
+metFlags.METOutputList().append(cfg_calo.suffix)
diff --git a/Reconstruction/MET/METReconstruction/python/METConfig_RefFinal.py b/Reconstruction/MET/METReconstruction/python/METConfig_RefFinal.py
index 7760d5c569a9a2fd1d3d4564bf6dc50666c059fe..2b698f2ee8b5ec2e58312040f12a22f24df6a953 100644
--- a/Reconstruction/MET/METReconstruction/python/METConfig_RefFinal.py
+++ b/Reconstruction/MET/METReconstruction/python/METConfig_RefFinal.py
@@ -5,6 +5,8 @@ from METReconstruction.METRecoConfig import BuildConfig, RefConfig, METConfig,cl
 
 from RecExConfig.RecFlags import rec
 doInDet = rec.doInDet()
+from JetRec.JetRecFlags import jetFlags
+jetsUseTracks = jetFlags.useTracks()
 
 ############################################################################
 # MET_RefFinal
@@ -16,13 +18,12 @@ rf_builders = [BuildConfig('Ele'),
                BuildConfig('Muon'),
                BuildConfig('SoftClus'),
                BuildConfig('SoftTrk')]
-rf_refiners = [RefConfig('JetFilter','RefJet_JVFCut'),
-               RefConfig('TrackFilter','PVSoftTrk')]
+rf_refiners = [RefConfig('TrackFilter','PVSoftTrk')]
 cfg_mrf = METConfig('RefFinal',
                     rf_builders,
                     rf_refiners,
                     doSum=True,
-                    doTracks=doInDet,
+                    doTracks=(doInDet and jetsUseTracks),
                     doRegions=True
                     )
 
@@ -62,38 +63,7 @@ cfg_mrf.builders['Muon'].MinNprecision    = 3
 #
 cfg_mrf.builders['SoftClus'].VetoNegEClus = True
 cfg_mrf.builders['SoftClus'].SignalState = clusterSigStates['LocHad']
-#
-cfg_mrf.refiners['JetFilter'].DoJVFCut  = True
-cfg_mrf.refiners['JetFilter'].MinAbsJVF = 0.25
-cfg_mrf.refiners['JetFilter'].MaxPtJVF  = 50e3 # only apply for pt<50
-cfg_mrf.refiners['JetFilter'].MaxEtaJVF = 2.4  # only apply to central jets
-#
-cfg_mrf.refiners['TrackFilter'].DoPVSel = True
-cfg_mrf.refiners['TrackFilter'].TrackD0Max = 1.5
-cfg_mrf.refiners['TrackFilter'].TrackZ0Max = 1.5
 
 metFlags.METConfigs()[cfg_mrf.suffix] = cfg_mrf
 metFlags.METOutputList().append(cfg_mrf.suffix)
 metFlags.METOutputList().append(cfg_mrf.suffix+"Regions")
-
-############################################################################
-# LocHadTopo
-
-cfg_lht = METConfig('LocHadTopo',[BuildConfig('SoftClus','LocHadTopo')],
-                    doRegions=True
-                    )
-cfg_lht.builders['SoftClus'].SignalState = clusterSigStates['LocHad']
-
-metFlags.METConfigs()[cfg_lht.suffix] = cfg_lht
-metFlags.METOutputList().append(cfg_lht.suffix)
-metFlags.METOutputList().append(cfg_lht.suffix+"Regions")
-
-############################################################################
-# Nominal TrackMET
-
-cfg_trk = METConfig('Track',[BuildConfig('SoftTrk','Track')],[RefConfig('TrackFilter','PVTrack')],
-                    doTracks=doInDet)
-
-metFlags.METConfigs()[cfg_trk.suffix] = cfg_trk
-metFlags.METOutputList().append(cfg_trk.suffix)
-metFlags.METOutputList().append(cfg_trk.suffix+"Regions")
diff --git a/Reconstruction/MET/METReconstruction/python/METConfig_Track.py b/Reconstruction/MET/METReconstruction/python/METConfig_Track.py
new file mode 100644
index 0000000000000000000000000000000000000000..51a6d04c6681ffa2c54af7f9db7f7cee19295fe8
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/python/METConfig_Track.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+
+from METReconstruction.METRecoFlags import metFlags
+from METReconstruction.METRecoConfig import BuildConfig, RefConfig, METConfig,clusterSigStates
+
+from RecExConfig.RecFlags import rec
+doInDet = rec.doInDet()
+
+cfg_trk = METConfig('Track',[BuildConfig('SoftTrk','Track')],
+                    [RefConfig('TrackFilter','PVTrack')],
+                    doTracks=doInDet)
+
+cfg_trk.refiners['TrackFilter'].DoLepRecovery=True
+cfg_trk.refiners['TrackFilter'].DoVxSep=True
+# Old input names
+#cfg_trk.refiners['TrackFilter'].InputClusterKey="CaloCalTopoCluster"
+#cfg_trk.refiners['TrackFilter'].InputElectronKey="ElectronCollection"
+metFlags.METConfigs()[cfg_trk.suffix] = cfg_trk
+metFlags.METOutputList().append(cfg_trk.suffix)
diff --git a/Reconstruction/MET/METReconstruction/python/METRecoConfig.py b/Reconstruction/MET/METReconstruction/python/METRecoConfig.py
index 30fadf61dd44bf94d0946e83f87a3caf28976007..54ada5057f5e71ee7c99933977a16276368ea848 100644
--- a/Reconstruction/MET/METReconstruction/python/METRecoConfig.py
+++ b/Reconstruction/MET/METReconstruction/python/METRecoConfig.py
@@ -21,18 +21,33 @@ defaultAuthor = {
 }
 
 defaultInputKey = {
-    'Ele'      :'ElectronCollection',
-    'Gamma'    :'PhotonCollection',
-    'Tau'      :'TauRecContainer',
-    'Jet'      :'AntiKt4LCTopoJets',
-    'Muon'     :'Muons',
-    'SoftTrk'  :'InDetTrackParticles',
-    'SoftClus' :'CaloCalTopoCluster',
-    'SoftPFlow':'neutralJetETMissPFO_eflowRec',
-    'PrimaryVx':'PrimaryVertices',
-    'Truth'    :'TruthParticle',
-    'Calo'     :'AllCalo'
-    }
+   'Ele'      :'Electrons',
+   'Gamma'    :'Photons',
+   'Tau'      :'TauJets',
+   'Jet'      :'AntiKt4LCTopoJets',
+   'Muon'     :'Muons',
+   'SoftTrk'  :'InDetTrackParticles',
+   'SoftClus' :'CaloCalTopoClusters',
+   'SoftPFlow':'JetETMissNeutralParticleFlowObjects',
+   'PrimaryVx':'PrimaryVertices',
+   'Truth'    :'TruthParticles',
+   'Calo'     :'AllCalo'
+   }
+
+# # old naming scheme
+# defaultInputKey = {
+#     'Ele'      :'ElectronCollection',
+#     'Gamma'    :'PhotonCollection',
+#     'Tau'      :'TauRecContainer',
+#     'Jet'      :'AntiKt4LCTopoJets',
+#     'Muon'     :'Muons',
+#     'SoftTrk'  :'InDetTrackParticles',
+#     'SoftClus' :'CaloCalTopoCluster',
+#     'SoftPFlow':'neutralJetETMissPFO_eflowRec',
+#     'PrimaryVx':'PrimaryVertices',
+#     'Truth'    :'TruthParticle',
+#     'Calo'     :'AllCalo'
+# }
 
 defaultOutputKey = {
     'Ele'      :'RefEle',
@@ -108,6 +123,7 @@ def getBuilder(config,suffix,doTracks,doCells):
             tool.UseCells    = False                   
             config.inputKey  = defaultInputKey['SoftClus']
         config.outputKey = config.objType
+
     # set input/output key names
     if config.inputKey == '':
         tool.InputCollection = defaultInputKey[config.objType]
@@ -134,15 +150,27 @@ class RefConfig:
 
 def getRefiner(config,suffix):
     tool = None
+
+    from AthenaCommon.AppMgr import ToolSvc
     if config.type == 'TrackFilter':
         tool = CfgMgr.met__METTrackFilterTool('MET_TrackFilterTool_'+suffix)
         tool.InputPVKey = defaultInputKey['PrimaryVx']
+        trkseltool=CfgMgr.InDet__InDetTrackSelectionTool("IDTrkSel_MET",
+                                                         CutLevel="TightPrimary",
+                                                         maxZ0SinTheta=1.5,
+                                                         maxD0overSigmaD0=3)
+        ToolSvc += trkseltool
+        #
+        trkvxtool=CfgMgr.CP__TightTrackVertexAssociationTool("TightTrackVertexAssociationTool", dzSinTheta_cut=1.5, doPV=False)
+        ToolSvc += trkvxtool
+        #
+        tool.TrackSelectorTool=trkseltool
+        tool.TrackVxAssocTool=trkvxtool
     if config.type == 'JetFilter':
         tool = CfgMgr.met__METJetFilterTool('MET_JetFilterTool_'+suffix)
     if config.type == 'MuonEloss':
         tool = CfgMgr.met__METMuonElossTool('MET_MuonElossTool_'+suffix)
     tool.MissingETKey = config.outputKey
-    from AthenaCommon.AppMgr import ToolSvc
     ToolSvc += tool
     return tool
 
diff --git a/Reconstruction/MET/METReconstruction/python/METRecoFlags.py b/Reconstruction/MET/METReconstruction/python/METRecoFlags.py
index 80ffb220f2018fa7a25bc03c6007861dbd2381df..f79b59f0d6b1d1b0d21ee53cad00d2b32a3a5590 100644
--- a/Reconstruction/MET/METReconstruction/python/METRecoFlags.py
+++ b/Reconstruction/MET/METReconstruction/python/METRecoFlags.py
@@ -11,6 +11,11 @@ class DoRegions(JobProperty):
     allowedTypes = ['bool'] 
     StoredValue  = False
 
+class DoPFlow(JobProperty):
+    statusOn = True
+    allowedTypes = ['bool'] 
+    StoredValue  = True
+
 class METConfigs(JobProperty):
     statusOn = True
     allowedTypes = ['dict'] 
@@ -26,11 +31,30 @@ class METOutputList(JobProperty):
     allowedTypes = ['list'] 
     StoredValue  = []
 
+class METAssocConfigs(JobProperty):
+    statusOn = True
+    allowedTypes = ['dict'] 
+    StoredValue  = {}
+
+class METAssocTools(JobProperty):
+    statusOn = True
+    allowedTypes = ['dict'] 
+    StoredValue  = {}
+
+class METAssocOutputList(JobProperty):
+    statusOn = True
+    allowedTypes = ['list'] 
+    StoredValue  = []
+
 jobproperties.add_Container(METRecoFlags)
 
 jobproperties.METRecoFlags.add_JobProperty(DoRegions)
+jobproperties.METRecoFlags.add_JobProperty(DoPFlow)
 jobproperties.METRecoFlags.add_JobProperty(METConfigs)
 jobproperties.METRecoFlags.add_JobProperty(METOutputList)
 jobproperties.METRecoFlags.add_JobProperty(METRecoTools)
+jobproperties.METRecoFlags.add_JobProperty(METAssocConfigs)
+jobproperties.METRecoFlags.add_JobProperty(METAssocOutputList)
+jobproperties.METRecoFlags.add_JobProperty(METAssocTools)
 
 metFlags = jobproperties.METRecoFlags
diff --git a/Reconstruction/MET/METReconstruction/share/BuildAssociation.py b/Reconstruction/MET/METReconstruction/share/BuildAssociation.py
new file mode 100644
index 0000000000000000000000000000000000000000..35f8d1e30a8774365499eecdd2b39c6c9b6453ed
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/share/BuildAssociation.py
@@ -0,0 +1,155 @@
+import AthenaPoolCnvSvc.ReadAthenaPool
+from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+from AthenaCommon.AppMgr import ServiceMgr
+from AthenaCommon import CfgMgr
+
+from glob import glob
+#filelist = ['../../athxaod/files/mc14_8TeV.147806.PowhegPythia8_AU2CT10_Zee.merge.AOD.e1169_s1896_s1912_r5591_r5625_tid01512387_00/AOD.01512387._001662.pool.root.1']
+filelist = ["/afs/cern.ch/user/b/boliu/workdir/dataset/mc14_8TeV.117050.PowhegPythia_P2011C_ttbar.merge.AOD.e1727_s1933_s1911_r5591_r5625_tid01507243_00/AOD.01507243._011158.pool.root.1"]
+
+#filelist = ['../../athxaod/newfiler.root']
+#filelist = ['xAOD.sklim.pool.root']
+#filelist = ['/afs/cern.ch/user/s/schaffer/public/public1/work-19.x.EventSizes/build/run/devval_0_0809_100evts/myAOD.pool.root']
+#filelist = ['/afs/cern.ch/user/c/christos/public/AOD_forRob.pool.root']
+ServiceMgr.EventSelector.InputCollections = filelist
+
+verbose = False
+
+######################################################################
+# Rerun MET reco to fix track-vertex associations
+from METReconstruction.METRecoFlags import metFlags
+from METReconstruction.METRecoConfig import BuildConfig, RefConfig, METConfig, getMETRecoAlg
+
+rf_builders = [BuildConfig('Ele'),
+               BuildConfig('Gamma'),
+               BuildConfig('Tau'),
+               BuildConfig('Jet'),
+               BuildConfig('Muon'),
+               BuildConfig('SoftClus'),
+               BuildConfig('SoftTrk')]
+rf_refiners = [RefConfig('TrackFilter','PVSoftTrk'),
+               RefConfig('JetFilter','RefJet_JVFCut')]
+cfg_mrf = METConfig('RefFinalFix',
+                    rf_builders,
+                    rf_refiners,
+                    doSum=True,
+                    doTracks=True
+                    )
+cfg_mrf.builders['Tau'].MinWet=1.
+metconfigs = {
+    'RefFinalFix':cfg_mrf
+    }
+metAlg = getMETRecoAlg('METReconstruction',metconfigs)
+
+# The tools are accessible via the configurations in metFlags
+from AthenaCommon.AppMgr import ToolSvc
+metMaker = CfgMgr.met__METMaker('METMaker',
+                                JetPtCut=0e3,
+                                DoJetJvfCut=False,
+                                );
+ToolSvc += metMaker
+
+makerAlg = CfgMgr.met__METMakerAlg('METMakerAlg',
+                                   METCoreName='MET_Core',
+                                   METName='MET_RefAssoc',
+                                   Maker=metMaker)
+
+## Set up default configurations
+from METUtilities.METUtilConfig import getMETUtilAlg,METUtilConfig,getMETRebuilder
+csttool = getMETRebuilder(METUtilConfig('RefFinalFix',{'Soft':'SoftClus'}, {},'RefCST'))
+tsttool = getMETRebuilder(METUtilConfig('RefFinalFix',{'Soft':'PVSoftTrk'},{},'RefTST'))
+utilAlg = getMETUtilAlg('METUtilAlg')
+csttool.CalibJetPtCut=0e3
+tsttool.CalibJetPtCut=0e3
+csttool.DoJetJVFCut=False
+tsttool.DoJetJVFCut=False
+ToolSvc += csttool
+ToolSvc += tsttool
+utilAlg.Rebuilders = [csttool,tsttool]
+
+
+pfotool = CfgMgr.CP__RetrievePFOTool('MET_PFOTool')
+from AthenaCommon.AppMgr import ToolSvc
+ToolSvc += pfotool
+
+trkseltool=CfgMgr.InDet__InDetTrackSelectionTool(CutLevel="TightPrimary")
+ToolSvc += trkseltool
+
+
+
+assocAlg = CfgMgr.met__METAssocAlg('METAssocAlg',PFOTool=pfotool, TrackSelectorTool=trkseltool)
+
+from AthenaCommon.AlgSequence import AlgSequence
+topSequence = AlgSequence()
+from GaudiSequencer.PyComps import PyEvtFilter
+filterseq = CfgMgr.AthSequencer('AthFilterSeq')
+#the following lines are examples, pick one...
+#filterseq += PyEvtFilter(evt_list=[1980130,287866,1706011,2226793,146377,146604,1904442,1297008,1298451,1072953]) #will execute main sequence only for these eventnumbers
+#filterseq += PyEvtFilter(evt_list=[1108077])
+filterseq += metAlg
+filterseq += assocAlg
+filterseq += utilAlg
+filterseq += makerAlg
+
+if verbose:
+    metAlg.OutputLevel=VERBOSE
+    assocAlg.OutputLevel=VERBOSE
+    makerAlg.OutputLevel=VERBOSE
+    metMaker.OutputLevel=VERBOSE
+    cfg_mrf.builders['Ele'].OutputLevel=VERBOSE
+    cfg_mrf.builders['Gamma'].OutputLevel=VERBOSE
+    cfg_mrf.builders['Tau'].OutputLevel=VERBOSE
+    cfg_mrf.builders['Muon'].OutputLevel=VERBOSE
+    cfg_mrf.builders['Jet'].OutputLevel=VERBOSE
+    cfg_mrf.builders['SoftTrk'].OutputLevel=VERBOSE
+    cfg_mrf.refiners['TrackFilter'].OutputLevel=VERBOSE
+
+#from Valkyrie.JobOptCfg import ValgrindSvc
+#svcMgr += ValgrindSvc( OutputLevel = DEBUG,
+#                       ProfiledAlgs = ['METAssocAlg','METAssocAlg'],
+#                       ProfiledIntervals = ['METAssocAlg.execute'])
+
+from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties
+pmon_properties.PerfMonFlags.doSemiDetailedMonitoring=True
+
+from OutputStreamAthenaPool.MultipleStreamManager import MSMgr
+xaodStream = MSMgr.NewPoolRootStream( 'StreamAOD', 'xAOD.METAssoc.testassoc.pool.root' )
+xaodStream.AddItem('xAOD::MissingETAssociationMap_v1#METAssoc_Akt4LC')
+xaodStream.AddItem('xAOD::MissingETAuxAssociationMap_v1#METAssoc_Akt4LCAux.')
+xaodStream.AddItem('xAOD::EventInfo_v1#EventInfo')
+xaodStream.AddItem('xAOD::EventAuxInfo_v1#EventInfoAux.')
+#xaodStream.AddItem('xAOD::ElectronContainer#ElectronCollection')
+#xaodStream.AddItem('xAOD::ElectronAuxContainer#ElectronCollectionAux.')
+#xaodStream.AddItem('xAOD::PhotonContainer#PhotonCollection')
+#xaodStream.AddItem('xAOD::PhotonAuxContainer#PhotonCollectionAux.')
+#xaodStream.AddItem('xAOD::TauJetContainer_v1#TauRecContainer')
+#xaodStream.AddItem('xAOD::TauJetAuxContainer_v1#TauRecContainerAux.')
+#xaodStream.AddItem('xAOD::JetContainer_v1#AntiKt4LCTopoJets')
+#xaodStream.AddItem('xAOD::JetAuxContainer_v1#AntiKt4LCTopoJetsAux.')
+#xaodStream.AddItem('xAOD::MuonContainer_v1#Muons')
+#xaodStream.AddItem('xAOD::MuonAuxContainer_v1#MuonsAux.')
+#xaodStream.AddItem('xAOD::MissingETComponentMap_v1#METMap_RefFinalFix')
+#xaodStream.AddItem('xAOD::MissingETAuxComponentMap_v1#METMap_RefFinalFixAux.')
+#xaodStream.AddItem('xAOD::CaloClusterContainer_v1#egClusterCollection');
+#xaodStream.AddItem('xAOD::CaloClusterAuxContainer_v1#egClusterCollectionAux.');
+#xaodStream.AddItem('xAOD::CaloClusterContainer_v1#CaloCalTopoCluster');
+#xaodStream.AddItem('xAOD::CaloClusterAuxContainer_v1#CaloCalTopoClusterAux.');
+#xaodStream.AddItem('xAOD::TrackParticleContainer_v1#*')
+#xaodStream.AddItem('xAOD::TrackParticleAuxContainer_v1#*')
+#xaodStream.AddItem('xAOD::VertexContainer_v1#*')
+#xaodStream.AddItem('xAOD::VertexAuxContainer_v1#*')
+xaodStream.AddItem('xAOD::MissingETContainer_v1#MET_Core')
+xaodStream.AddItem('xAOD::MissingETAuxContainer_v1#MET_CoreAux.')
+xaodStream.AddItem('xAOD::MissingETContainer_v1#MET_RefAssoc')
+xaodStream.AddItem('xAOD::MissingETAuxContainer_v1#MET_RefAssocAux.')
+xaodStream.AddItem('xAOD::MissingETContainer_v1#MET_RefFinalFix')
+xaodStream.AddItem('xAOD::MissingETAuxContainer_v1#MET_RefFinalFixAux.')
+xaodStream.AddItem('xAOD::MissingETContainer_v1#MET_RefCST')
+xaodStream.AddItem('xAOD::MissingETAuxContainer_v1#MET_RefCSTAux.')
+xaodStream.AddItem('xAOD::MissingETContainer_v1#MET_RefTST')
+xaodStream.AddItem('xAOD::MissingETAuxContainer_v1#MET_RefTSTAux.')
+xaodStream.AcceptAlgs(['PyEvtFilter'])
+
+theApp.EvtMax = 100
+ServiceMgr.EventSelector.SkipEvents = 0
+#ServiceMgr.MessageSvc.defaultLimit = 9999
diff --git a/Reconstruction/MET/METReconstruction/share/METReconstructionOutputAODList_jobOptions.py b/Reconstruction/MET/METReconstruction/share/METReconstructionOutputAODList_jobOptions.py
index 8e21bd9d447db23287f1390ef09c1e787a759270..da94662e50062a1d954039be396df2930c23c931 100644
--- a/Reconstruction/MET/METReconstruction/share/METReconstructionOutputAODList_jobOptions.py
+++ b/Reconstruction/MET/METReconstruction/share/METReconstructionOutputAODList_jobOptions.py
@@ -3,14 +3,26 @@ MissingETAODList = []
 outputlist = []
 from METReconstruction.METRecoFlags import metFlags
 if len(metFlags.METOutputList())==0:
-    outputlist = ['Truth','Track','LocHadTopo','RefFinal','Calo',
-                  'TruthRegions','TrackRegions','LocHadTopoRegions','RefFinalRegions']
+    outputlist = ['Truth','EMTopo','LocHadTopo','Calo','Track',
+                  'TruthRegions','EMTopoRegions','LocHadTopoRegions']
 else:
     outputlist = metFlags.METOutputList()
 
 for config in outputlist:
-    MissingETAODList.append( 'xAOD::MissingETContainer_v1#MET_'+config )
-    MissingETAODList.append( 'xAOD::MissingETAuxContainer_v1#MET_'+config+'Aux.' )
-    if not config == 'Calo':
-        MissingETAODList.append( 'xAOD::MissingETComponentMap_v1#METMap_'+config )
-        MissingETAODList.append( 'xAOD::MissingETAuxComponentMap_v1#METMap_'+config+'Aux.' )
+    MissingETAODList.append( 'xAOD::MissingETContainer#MET_'+config )
+    MissingETAODList.append( 'xAOD::MissingETAuxContainer#MET_'+config+'Aux.' )
+    if config == 'Truth':
+        MissingETAODList.append( 'xAOD::MissingETComponentMap#METMap_'+config )
+        MissingETAODList.append( 'xAOD::MissingETAuxComponentMap#METMap_'+config+'Aux.' )
+
+if len(metFlags.METAssocOutputList())==0:
+    assocoutput = ['AntiKt4LCTopo','AntiKt4EMTopo','AntiKt4EMPFlow']
+else:
+    assocoutput = metFlags.METAssocOutputList()
+for config in assocoutput:
+	MissingETAODList.append( 'xAOD::MissingETAssociationMap#METAssoc_'+config )
+	MissingETAODList.append( 'xAOD::MissingETAuxAssociationMap#METAssoc_'+config+'Aux.' )
+	MissingETAODList.append( 'xAOD::MissingETContainer#MET_Core_'+config )
+	MissingETAODList.append( 'xAOD::MissingETAuxContainer#MET_Core_'+config+'Aux.' )
+	MissingETAODList.append( 'xAOD::MissingETContainer#MET_Reference_'+config )
+	MissingETAODList.append( 'xAOD::MissingETAuxContainer#MET_Reference_'+config+'Aux.' )
diff --git a/Reconstruction/MET/METReconstruction/share/METReconstructionOutputESDList_jobOptions.py b/Reconstruction/MET/METReconstruction/share/METReconstructionOutputESDList_jobOptions.py
index 588b400cb53e431d808d332c3805fbcca0aa9dd4..705a5034fc03eca71e6ff7ff5800c072e1beb2c0 100644
--- a/Reconstruction/MET/METReconstruction/share/METReconstructionOutputESDList_jobOptions.py
+++ b/Reconstruction/MET/METReconstruction/share/METReconstructionOutputESDList_jobOptions.py
@@ -3,14 +3,26 @@ MissingETESDList = []
 outputlist = []
 from METReconstruction.METRecoFlags import metFlags
 if len(metFlags.METOutputList())==0:
-    outputlist = ['Truth','Track','LocHadTopo','RefFinal','Calo',
-                  'TruthRegions','TrackRegions','LocHadTopoRegions','RefFinalRegions']
+    outputlist = ['Truth','EMTopo','LocHadTopo','Calo','Track'
+                  'TruthRegions','EMTopoRegions','LocHadTopoRegions']
 else:
     outputlist = metFlags.METOutputList()
 
 for config in outputlist:
-    MissingETESDList.append( 'xAOD::MissingETContainer_v1#MET_'+config )
-    MissingETESDList.append( 'xAOD::MissingETAuxContainer_v1#MET_'+config+'Aux.' )
-    if not config == 'Calo':
-        MissingETESDList.append( 'xAOD::MissingETComponentMap_v1#METMap_'+config )
-        MissingETESDList.append( 'xAOD::MissingETAuxComponentMap_v1#METMap_'+config+'Aux.' )
+    MissingETESDList.append( 'xAOD::MissingETContainer#MET_'+config )
+    MissingETESDList.append( 'xAOD::MissingETAuxContainer#MET_'+config+'Aux.' )
+    if config == 'Truth':
+        MissingETESDList.append( 'xAOD::MissingETComponentMap#METMap_'+config )
+        MissingETESDList.append( 'xAOD::MissingETAuxComponentMap#METMap_'+config+'Aux.' )
+
+if len(metFlags.METAssocOutputList())==0:
+    assocoutput = ['AntiKt4LCTopo','AntiKt4EMTopo','AntiKt4EMPFlow']
+else:
+    assocoutput = metFlags.METAssocOutputList()
+for config in assocoutput:
+	MissingETESDList.append( 'xAOD::MissingETAssociationMap#METAssoc_'+config )
+	MissingETESDList.append( 'xAOD::MissingETAuxAssociationMap#METAssoc_'+config+'Aux.' )
+	MissingETESDList.append( 'xAOD::MissingETContainer#MET_Core_'+config )
+	MissingETESDList.append( 'xAOD::MissingETAuxContainer#MET_Core_'+config+'Aux.' )
+	MissingETESDList.append( 'xAOD::MissingETContainer#MET_Reference_'+config )
+	MissingETESDList.append( 'xAOD::MissingETAuxContainer#MET_Reference_'+config+'Aux.' )
diff --git a/Reconstruction/MET/METReconstruction/share/METReconstruction_jobOptions.py b/Reconstruction/MET/METReconstruction/share/METReconstruction_jobOptions.py
index f3c04ad4956e421b3254f8ecde0e6d3b1490ce8c..d81230e1c3f0e503b6985d2f8ada01d74c0819b4 100644
--- a/Reconstruction/MET/METReconstruction/share/METReconstruction_jobOptions.py
+++ b/Reconstruction/MET/METReconstruction/share/METReconstruction_jobOptions.py
@@ -1,16 +1,29 @@
 from AthenaCommon.AlgSequence import AlgSequence
 topSequence = AlgSequence()
 
-import METReconstruction.METConfig_RefFinal
-import METReconstruction.METConfig_CaloReg
-#import METReconstruction.METConfig_PFlow
-from RecExConfig.RecFlags import rec
-if rec.doTruth:
+import METReconstruction.METConfig_Calo
+import METReconstruction.METConfig_Track
+if rec.doTruth():
     import METReconstruction.METConfig_Truth
 
 from METReconstruction.METRecoFlags import metFlags
 from METReconstruction.METRecoConfig import getMETRecoAlg
 
 metAlg = getMETRecoAlg('METReconstruction')
-
 topSequence += metAlg
+
+# Set up default configurations
+import METReconstruction.METConfig_Associator
+from METReconstruction.METAssocConfig import getMETAssocAlg
+
+# Get the configuration directly from METRecoFlags
+# Can also provide a dict of configurations or list of RecoTools or both
+assocAlg = getMETAssocAlg('METAssociation')
+from AthenaCommon.AlgSequence import AlgSequence
+topSequence = AlgSequence()
+topSequence += assocAlg
+
+from METUtilities.METMakerConfig import getMETMakerAlg
+for key,conf in metFlags.METAssocConfigs().iteritems():
+    makerAlg = getMETMakerAlg(conf.suffix)
+    topSequence += makerAlg
diff --git a/Reconstruction/MET/METReconstruction/share/RunMETReco.py b/Reconstruction/MET/METReconstruction/share/RunMETReco.py
index cd9592d09ad076861a0e5bcf1bdbe33b12fa495e..38c86951fb7cf4bbe62050a2ce91eb1b8d61f0ce 100644
--- a/Reconstruction/MET/METReconstruction/share/RunMETReco.py
+++ b/Reconstruction/MET/METReconstruction/share/RunMETReco.py
@@ -3,61 +3,54 @@ from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
 from AthenaCommon.AppMgr import ServiceMgr
 from AthenaCommon import CfgMgr
 
-filelist = ["AOD.nomet.pool.root"]
+filelist = ["myAOD.pool.root"]
+from glob import glob
+#filelist = glob('/r03/atlas/khoo/Data_2014/DC14xAOD/mc14_8TeV.117050.PowhegPythia_P2011C_ttbar.merge.AOD.e1727_s1933_s1911_r5591_r5625/*')
+#filelist = glob('/r03/atlas/khoo/Data_2014/DC14xAOD/mc14_13TeV.110401.PowhegPythia_P2012_ttbar_nonallhad.merge.AOD.e2928_s1982_s2008_r5787_r5853/*')
 ServiceMgr.EventSelector.InputCollections = filelist
 
-# Set up default configurations
-import METReconstruction.METConfig_RefFinal
-import METReconstruction.METConfig_Truth
-import METReconstruction.METConfig_CaloReg
-#import METReconstruction.METConfig_PFlow
+#import METReconstruction.METConfig_RefFinal
 
-#from METReconstruction.METRecoFlags import metFlags
-from METReconstruction.METRecoConfig import getMETRecoAlg
+from METReconstruction.METRecoFlags import metFlags
 
-# Get the configuration directly from METRecoFlags
-# Can also provide a dict of configurations or list of RecoTools or both
-metAlg = getMETRecoAlg('METReconstruction')
+##############################################################################
 
+from AthenaCommon.AppMgr import ToolSvc
 from AthenaCommon.AlgSequence import AlgSequence
 topSequence = AlgSequence()
-topSequence += metAlg
-topSequence += CfgMgr.met__METReaderAlg("METReader")
 
-# The tools are accessible via the configurations in metFlags
-topSequence.METReconstruction.OutputLevel = DEBUG
-from AthenaCommon.AppMgr import ToolSvc
-ToolSvc.MET_RecoTool_RefFinal.OutputLevel = VERBOSE
-ToolSvc.MET_RecoTool_LocHadTopo.OutputLevel = VERBOSE
-ToolSvc.MET_RecoTool_Calo.OutputLevel = VERBOSE
-ToolSvc.MET_RecoTool_Truth.OutputLevel = VERBOSE
+##############################################################################
 
-from Valkyrie.JobOptCfg import ValgrindSvc
-svcMgr += ValgrindSvc( OutputLevel = DEBUG,
-                       ProfiledAlgs = ["METReconstruction"],
-                       ProfiledIntervals = ["METReconstruction.execute"])
+metFlags.DoPFlow.set_Value_and_Lock(False)
 
-from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties
-pmon_properties.PerfMonFlags.doSemiDetailedMonitoring=True
+from AthenaCommon.Resilience import protectedInclude
+protectedInclude("METReconstruction/METReconstruction_jobOptions.py")
 
 write_xAOD = True
 if write_xAOD:
 
     # The list of output containers/maps is autogenerated and stored in metFlags
     # This jO extracts them with the appropriate formatting
-    from AthenaCommon.Resilience import protectedInclude
     protectedInclude("METReconstruction/METReconstructionOutputAODList_jobOptions.py")
 
     from OutputStreamAthenaPool.MultipleStreamManager import MSMgr
-    xaodStream = MSMgr.NewPoolStream( "StreamAOD", "xAOD.pool.root" )
+    xaodStream = MSMgr.NewPoolRootStream( "StreamAOD", "xAOD.8TeV.pool.root" )
     for item in MissingETAODList:
         xaodStream.AddItem(item)
 
-    ServiceMgr.AthenaPoolCnvSvc.PoolAttributes += [
-        "DEFAULT_SPLITLEVEL='99'" ]
-
-    # Force POOL to just simply use the StoreGate keys as branch names:
-    ServiceMgr.AthenaPoolCnvSvc.SubLevelBranchName = "<key>"
+from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties
+pmon_properties.PerfMonFlags.doSemiDetailedMonitoring=True
 
-theApp.EvtMax = -1
+# assocRefAlg.OutputLevel=VERBOSE
+# topSequence.METAssociation.OutputLevel=VERBOSE
+# ToolSvc.MET_AssociationTool_AntiKt4LCTopo.OutputLevel=VERBOSE
+# ToolSvc.MET_LCJetAssocTool_AntiKt4LCTopo.OutputLevel=VERBOSE
+# ToolSvc.MET_PhotonAssociator_AntiKt4LCTopo.OutputLevel=VERBOSE
+# ToolSvc.MET_SoftAssociator_AntiKt4LCTopo.OutputLevel=VERBOSE
+# ToolSvc.MET_JetTool_RefFinal2.OutputLevel=VERBOSE
+# ToolSvc.METMaker_AntiKt4LCTopo.OutputLevel=VERBOSE
+# ToolSvc.METMaker_Test.OutputLevel=VERBOSE
+
+theApp.EvtMax = 40
 ServiceMgr.EventSelector.SkipEvents = 0
+ServiceMgr.MessageSvc.defaultLimit = 99999
diff --git a/Reconstruction/MET/METReconstruction/share/RunMETReco_Associator.py b/Reconstruction/MET/METReconstruction/share/RunMETReco_Associator.py
new file mode 100644
index 0000000000000000000000000000000000000000..27669599894a8dfc5df2d977db3fbefc09224715
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/share/RunMETReco_Associator.py
@@ -0,0 +1,53 @@
+import AthenaPoolCnvSvc.ReadAthenaPool
+from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+from AthenaCommon.AppMgr import ServiceMgr
+from AthenaCommon import CfgMgr
+
+import METReconstruction.METConfig_Calo
+
+from RecExConfig.RecFlags import rec
+if rec.doTruth:
+    import METReconstruction.METConfig_Truth
+
+filelist = ["/afs/cern.ch/user/b/boliu/workdir/dataset/mc14_8TeV.117050.PowhegPythia_P2011C_ttbar.merge.AOD.e1727_s1933_s1911_r5591_r5625_tid01507243_00/AOD.01507243._011158.pool.root.1"]
+ServiceMgr.EventSelector.InputCollections = filelist
+
+# Set up default configurations
+import METReconstruction.METConfig_Associator
+
+#from METReconstruction.METRecoFlags import metFlags
+from METReconstruction.METRecoConfig_Associator import getMETRecoAlg
+
+# Get the configuration directly from METRecoFlags
+# Can also provide a dict of configurations or list of RecoTools or both
+metAlg = getMETRecoAlg('METReconstruction')
+from AthenaCommon.AlgSequence import AlgSequence
+topSequence = AlgSequence()
+topSequence += metAlg
+
+# The tools are accessible via the configurations in metFlags
+from AthenaCommon.AppMgr import ToolSvc
+
+from Valkyrie.JobOptCfg import ValgrindSvc
+svcMgr += ValgrindSvc( OutputLevel = DEBUG,
+                       ProfiledAlgs = ["METReconstruction"],
+                       ProfiledIntervals = ["METReconstruction.execute"])
+
+from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties
+pmon_properties.PerfMonFlags.doSemiDetailedMonitoring=True
+
+write_xAOD = True
+if write_xAOD:
+
+    # The list of output containers/maps is autogenerated and stored in metFlags
+    # This jO extracts them with the appropriate formatting
+    from AthenaCommon.Resilience import protectedInclude
+    protectedInclude("METReconstruction/METReconstructionOutputAODList_jobOptions.py")
+
+    from OutputStreamAthenaPool.MultipleStreamManager import MSMgr
+    xaodStream = MSMgr.NewPoolRootStream( "StreamAOD", "xAOD.pool.root" )
+    for item in MissingETAODList:
+        xaodStream.AddItem(item)
+
+theApp.EvtMax = -1
+ServiceMgr.EventSelector.SkipEvents = 0
diff --git a/Reconstruction/MET/METReconstruction/src/METAssocAlg.cxx b/Reconstruction/MET/METReconstruction/src/METAssocAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3ad59913f51ba3ebd8699879c0300c44fb94523c
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/src/METAssocAlg.cxx
@@ -0,0 +1,864 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssocAlg.cxx
+
+#include "METAssocAlg.h"
+
+#include "xAODMissingET/MissingETContainer.h"
+#include "xAODMissingET/MissingETAuxContainer.h"
+#include "xAODMissingET/MissingETComposition.h"
+#include "xAODMissingET/MissingETAssociationMap.h"
+#include "xAODMissingET/MissingETAuxAssociationMap.h"
+
+#include "xAODEgamma/EgammaxAODHelpers.h"
+#include "AthContainers/ConstDataVector.h"
+
+// Track errors
+#include "EventPrimitives/EventPrimitivesHelpers.h"
+
+#include "xAODEventInfo/EventInfo.h"
+
+using std::string;
+using std::vector;
+using namespace xAOD;
+
+using std::string;
+
+namespace met {
+
+  static inline bool greaterPt(const xAOD::IParticle* part1, const xAOD::IParticle* part2) {
+    return part1->pt()>part2->pt();
+  }
+  static inline bool greaterPtPFO(const xAOD::PFO* part1, const xAOD::PFO* part2) {
+    if (part1->charge()==0 && part2->charge()!=0) return false;
+    if (part1->charge()!=0 && part2->charge()==0) return true;
+    if (part1->charge()==0 && part2->charge()==0) return part1->ptEM()>part2->ptEM();
+    return part1->pt()>part2->pt();
+  }
+
+  //**********************************************************************
+
+  METAssocAlg::METAssocAlg(const std::string& name,
+			   ISvcLocator* pSvcLocator )
+    : ::AthAlgorithm( name, pSvcLocator ) {
+    declareProperty( "METContainer",         m_contname  = "MET_Core" );
+    declareProperty( "METAssociationMap",    m_mapname   = "METAssoc" );
+
+    declareProperty( "JetColl",              m_jetcoll   = "AntiKt4LCTopoJets"      );
+    declareProperty( "EleColl",              m_elecoll   = "ElectronCollection"     );
+    declareProperty( "GammaColl",            m_gammacoll = "PhotonCollection"       );
+    declareProperty( "TauColl",              m_taucoll   = "TauRecContainer"        );
+    declareProperty( "MuonColl",             m_muoncoll  = "Muons"                  );
+    declareProperty( "PrimVxColl",           m_pvcoll    = "PrimaryVertices"        );
+    declareProperty( "TrkColl",              m_trkcoll   = "InDetTrackParticles"    );
+    declareProperty( "ClusColl",             m_clcoll    = "CaloCalTopoCluster"     );
+    declareProperty( "PFlow",                m_pflow     = false                    );
+    declareProperty( "PFOTool",              m_pfotool                              );
+    declareProperty( "TrackSelectorTool",     m_trkseltool );
+  }
+
+  //**********************************************************************
+
+  METAssocAlg::~METAssocAlg() { }
+
+  //**********************************************************************
+
+  StatusCode METAssocAlg::initialize() {
+    ATH_MSG_INFO("Initializing " << name() << "...");
+  
+    return StatusCode::SUCCESS;
+  }
+
+  //**********************************************************************
+
+  StatusCode METAssocAlg::finalize() {
+    ATH_MSG_INFO ("Finalizing " << name() << "...");
+    return StatusCode::SUCCESS;
+  }
+
+  //**********************************************************************
+
+  StatusCode METAssocAlg::execute() { 
+    ATH_MSG_VERBOSE("Executing " << name() << "...");
+    // Loop over tools.
+
+    // Create a MissingETAssociationMap with its aux store
+    MissingETAssociationMap* metMap = new MissingETAssociationMap();
+    if( evtStore()->record(metMap, m_mapname).isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAssociationMap: " << m_mapname);
+      return StatusCode::SUCCESS;
+    }
+    MissingETAuxAssociationMap* metAuxMap = new MissingETAuxAssociationMap();
+    if( evtStore()->record(metAuxMap, m_mapname+"Aux.").isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAuxAssociationMap: " << m_mapname+"Aux.");
+      return StatusCode::SUCCESS;
+    }
+    metMap->setStore(metAuxMap);
+
+    // Apply track selection filters
+    const CaloClusterContainer* tcCont(0);
+    if( evtStore()->retrieve(tcCont, m_clcoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve topocluster container " << m_clcoll << " for overlap removal");
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved topocluster collection");
+
+    const VertexContainer* vxCont(0);
+    if( evtStore()->retrieve(vxCont, m_pvcoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve primary vertex container " << m_pvcoll);
+      return StatusCode::SUCCESS;
+    } else if(vxCont->empty()) {
+      ATH_MSG_WARNING("Event has no primary vertices!");
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved primary vertex container");
+
+    const TrackParticleContainer* tracks=0;
+    ATH_CHECK( evtStore()->retrieve(tracks, m_trkcoll) );
+
+    filterTracks(tracks,(*vxCont)[0]);
+
+    const PFOContainer* pfoCont = m_pfotool->retrievePFO(CP::EM, CP::all);
+    if(!pfoCont) {
+      ATH_MSG_WARNING("Unable to retrieve input pfo container");
+      return StatusCode::SUCCESS;
+    }
+
+    ATH_CHECK(m_trkseltool.retrieve());
+
+    // Generate association objects from the jets in the event ******************
+    const JetContainer* jetCont(0);
+    if( evtStore()->retrieve(jetCont, m_jetcoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input jet container " << m_jetcoll);
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved jet collection");
+
+    CHECK( setupJetAssoc(metMap, jetCont, (*vxCont)[0]) );
+
+    /// Muons
+    /// Do muons before electrons and photons to remove track overlaps
+
+    const MuonContainer* muonCont(0);
+    if( evtStore()->retrieve(muonCont, m_muoncoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input muon container " << m_muoncoll);
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved muon collection");
+
+    // vector<const IParticle*> mutracks;
+    CHECK( setupMuons(metMap, muonCont, (*vxCont)[0], pfoCont));
+
+    /// Electrons
+
+    const ElectronContainer* elCont(0);
+    if( evtStore()->retrieve(elCont, m_elecoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input electron container " << m_elecoll);
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved electron collection");
+    CHECK( setupElectrons(metMap, elCont, tcCont, (*vxCont)[0], pfoCont));
+
+    /// Photons
+
+    const PhotonContainer* phCont(0);
+    if( evtStore()->retrieve(phCont, m_gammacoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input photon container " << m_gammacoll);
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved photon collection");
+    CHECK( setupPhotons(metMap, phCont, tcCont, (*vxCont)[0], pfoCont));
+
+    /// Taus
+
+    const TauJetContainer* tauCont(0);
+    if( evtStore()->retrieve(tauCont, m_taucoll).isFailure() ) {
+      ATH_MSG_WARNING("Unable to retrieve input tau container " << m_taucoll);
+      return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("Successfully retrieved tau collection");
+
+    CHECK( setupTaus(metMap, tauCont, (*vxCont)[0], pfoCont));
+
+    // Do internal overlap-finding **********************************************
+
+    bool foundOverlaps = metMap->identifyOverlaps();
+    if(foundOverlaps) ATH_MSG_DEBUG("Overlaps identified!");
+
+    // Create a MissingETContainer with its aux store
+    MissingETContainer* newMet = new MissingETContainer();
+    if( evtStore()->record(newMet, m_contname).isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETContainer: " << m_contname);
+      return StatusCode::SUCCESS;
+    }
+    MissingETAuxContainer* metAuxCont = new MissingETAuxContainer();
+    if( evtStore()->record(metAuxCont, m_contname+"Aux.").isFailure() ) {
+      ATH_MSG_WARNING("Unable to record MissingETAuxContainer: " << m_contname+"Aux.");
+      return StatusCode::SUCCESS;
+    }
+    newMet->setStore(metAuxCont);
+
+    MissingET* metCoreCl = new MissingET(0.,0.,0.,"SoftClusCore",MissingETBase::Source::softEvent() | MissingETBase::Source::cluster());
+    newMet->push_back(metCoreCl);
+    MissingET* metCoreTrk = new MissingET(0.,0.,0.,"PVSoftTrkCore",MissingETBase::Source::softEvent() | MissingETBase::Source::track());
+    newMet->push_back(metCoreTrk);
+    const IParticleContainer* uniqueClusters;
+    if (m_pflow) uniqueClusters = metMap->getUniqueSignals(pfoCont,MissingETBase::UsageHandler::Policy::ParticleFlow);
+    else uniqueClusters = metMap->getUniqueSignals(tcCont);
+    for(IParticleContainer::const_iterator iSig=uniqueClusters->begin();iSig!=uniqueClusters->end();iSig++) {
+      if (m_pflow) {
+        const xAOD::PFO *pfo = dynamic_cast<const xAOD::PFO*>(*iSig);
+        if (pfo->charge()==0) {
+	  TLorentzVector corrected = pfo->GetVertexCorrectedEMFourVec(*((*vxCont)[0]));
+          if (pfo->eEM()>0) metCoreCl->add(corrected.Px(),corrected.Py(),corrected.Pt());
+          continue;
+        } else if (!acceptChargedPFO(pfo->track(0),(*vxCont)[0])) continue;
+        *metCoreTrk += *iSig;
+      }
+     if ((*iSig)->e()>0) *metCoreCl += *iSig;
+    }
+    if (m_pflow) return StatusCode::SUCCESS;
+
+    const IParticleContainer* uniqueTracks = metMap->getUniqueSignals(tracks);
+    for(const auto& trk : *uniqueTracks) {
+//      if(acceptTrack(dynamic_cast<const TrackParticle*>(trk),(*vxCont)[0]) && isGoodEoverP(dynamic_cast<const TrackParticle*>(trk))) {
+      if(acceptTrack(dynamic_cast<const TrackParticle*>(trk),(*vxCont)[0]) ) {
+	ATH_MSG_VERBOSE("Add core track with pt " << trk->pt());
+	*metCoreTrk += trk;
+      }
+    }
+
+    delete uniqueClusters;
+    delete uniqueTracks;
+    
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Create jet associations
+  StatusCode METAssocAlg::setupJetAssoc(xAOD::MissingETAssociationMap* metMap,
+					const xAOD::JetContainer* jets,
+					const xAOD::Vertex* pv)
+  {
+    for(const auto& jet : *jets) {
+      ATH_MSG_VERBOSE("Jet pt, eta, phi = " << jet->pt() << ", " << jet->eta() << "," << jet->phi() );
+      std::vector<const IParticle*> selectedTracks;
+      if (m_pflow) {
+        for (size_t consti = 0; consti < jet->numConstituents(); consti++) {
+          const PFO *pfo = dynamic_cast<const PFO*>(jet->rawConstituent(consti));
+          if (pfo->charge()!=0) selectedTracks.push_back(pfo->track(0));
+        }
+      } else {
+        std::vector<const IParticle*> jettracks;
+        jet->getAssociatedObjects<IParticle>(JetAttribute::GhostTrack,jettracks);
+        selectedTracks = selectTracks(jettracks,pv);
+      }
+      MissingETComposition::add(metMap,jet,selectedTracks);
+      ATH_MSG_VERBOSE("Added association " << metMap->findIndex(jet) << " pointing to jet " << jet);
+    }
+    MissingETComposition::addMiscAssociation(metMap);
+    ATH_MSG_VERBOSE("Added miscellaneous association");
+
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Do muon track finding
+  StatusCode METAssocAlg::setupMuons(xAOD::MissingETAssociationMap* metMap,
+				     const xAOD::MuonContainer* muons,
+				     const xAOD::Vertex* pv,
+				     const xAOD::PFOContainer* pfoCont)
+  //				     std::vector<const xAOD::IParticle*>& mutracks)
+  {
+    vector<const IParticle*> constlist;
+    constlist.reserve(2);
+    for(const auto& mu : *muons) {
+      //      if(mu->pt()<5e3) continue;
+      ATH_MSG_VERBOSE( "Muon px, py, pt = " << mu->p4().Px() << ", " << mu->p4().Py() << ", " << mu->pt() );
+      constlist.clear();
+      MissingETBase::Types::constvec_t tcvec;
+      MissingETBase::Types::constvec_t trkvec;
+      //      ATH_MSG_VERBOSE( "Muon pt, eta, phi = " << mu->pt() << ", " << mu->eta() << "," << mu->phi() );
+      const TrackParticle* idtrack = mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
+      if(idtrack) {
+	//	if(acceptTrack(idtrack,pv) && isGoodEoverP(idtrack)) {
+	if(acceptTrack(idtrack,pv) ) {
+	  ATH_MSG_VERBOSE("Accept muon track " << idtrack << " px, py = " << idtrack->p4().Px() << ", " << idtrack->p4().Py());
+	  ATH_MSG_VERBOSE("Muon ID track ptr: " << idtrack);
+          if (m_pflow) {
+            for(const auto& pfo : *pfoCont) {
+              if (pfo->charge()!=0 && pfo->track(0) == idtrack) {
+                constlist.push_back(pfo);
+	        trkvec += *idtrack;
+              }
+              if (pfo->charge()==0 && mu->cluster() && mu->cluster()->p4().DeltaR(pfo->p4EM())<0.1 && pfo->eEM()>0) constlist.push_back(pfo);
+            }
+	  } else {
+	    constlist.push_back(idtrack);
+	    trkvec += *idtrack;
+          }
+	  // if(mu->pt()>10e3 && (mu->muonType()==xAOD::Muon::Combined || mu->muonType()==xAOD::Muon::SegmentTagged)) {
+	  //   mutracks.push_back(idtrack);
+	  // }
+	}
+      }
+      ATH_MSG_VERBOSE( "Muon track px, py, pt = " << trkvec.cpx() << ", " << trkvec.cpy() << ", " << trkvec.cpt() );
+
+      bool inserted(false);
+      inserted = MissingETComposition::insert(metMap,mu,constlist,tcvec,trkvec);
+      if(inserted) {
+	const MissingETAssociation* assoc = MissingETComposition::getAssociation(metMap,mu);
+	ATH_MSG_VERBOSE( "Muon is associated to jet " << assoc->refJet()->index() << " with pt " << assoc->refJet()->pt() );
+	ATH_MSG_VERBOSE( "Muon-jet deltaR = " << mu->p4().DeltaR(assoc->refJet()->p4()) );
+      } else {
+	ATH_MSG_VERBOSE( "Add muon as miscellaneous object" );
+	inserted = MissingETComposition::insertMisc(metMap,mu,constlist,tcvec,trkvec);
+      }
+      ATH_MSG_VERBOSE( (inserted ? "Successfully" : "Unsuccessfully" ) << " inserted muon into association map");
+    }
+    ATH_MSG_VERBOSE("Done with muon setup");
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Do electron topocluster finding
+  StatusCode METAssocAlg::setupElectrons(xAOD::MissingETAssociationMap* metMap,
+					 const xAOD::ElectronContainer* electrons,
+					 const xAOD::CaloClusterContainer* clusters,
+					 const xAOD::Vertex* pv,
+					 const xAOD::PFOContainer* pfoCont)
+  //					 std::vector<const xAOD::IParticle*>& mutracks)
+  {
+    vector<const xAOD::IParticle*> constlist;
+    constlist.reserve(10);    
+    ConstDataVector<ElectronContainer> electrons_tmp(SG::VIEW_ELEMENTS);
+    for(const auto& ph : *electrons) {
+      electrons_tmp.push_back(ph);
+    }
+    std::sort(electrons_tmp.begin(),electrons_tmp.end(),greaterPt);
+
+    for(const auto& el : electrons_tmp) {
+      // if(el->pt()<5e3) continue;
+      ATH_MSG_VERBOSE( "Electron px, py, pt = " << el->p4().Px() << ", " << el->p4().Py() << ", " << el->pt() );
+      constlist.clear();
+      MissingETBase::Types::constvec_t tcvec,trkvec;
+      //      ATH_MSG_VERBOSE( "Electron pt, eta, phi = " << el->pt() << ", " << el->eta() << "," << el->phi() );
+      if (m_pflow) this->extractPFO(el,pfoCont,constlist,tcvec,trkvec,pv);
+      else {
+        this->extractTopoClusters(el,clusters,constlist,tcvec);
+        this->extractTracks(el,pv,constlist,trkvec);
+      }
+      ATH_MSG_VERBOSE( "Electron has " << constlist.size() << " topoclusters." );
+
+      ATH_MSG_VERBOSE( "Electron tc px, py, pt, sumpt = " << tcvec.cpx() << ", " << tcvec.cpy() << ", " << tcvec.cpt() << ", " << tcvec.sumpt() );
+      ATH_MSG_VERBOSE( "Electron track px, py, pt, sumpt = " << trkvec.cpx() << ", " << trkvec.cpy() << ", " << trkvec.cpt() << ", " << trkvec.sumpt() );
+
+      bool inserted(false);
+      inserted = MissingETComposition::insert(metMap,el,constlist,tcvec,trkvec);
+      if(inserted) {
+	const MissingETAssociation* assoc = MissingETComposition::getAssociation(metMap,el);
+	ATH_MSG_VERBOSE( "Electron is associated to jet " << assoc->refJet()->index() << " with pt " << assoc->refJet()->pt() );
+	ATH_MSG_VERBOSE( "Electron-jet deltaR = " << el->p4().DeltaR(assoc->refJet()->p4()) );
+      } else {
+	ATH_MSG_VERBOSE( "Add electron as miscellaneous object" );
+	inserted = MissingETComposition::insertMisc(metMap,el,constlist,tcvec,trkvec);
+      }
+      ATH_MSG_VERBOSE( (inserted ? "Successfully" : "Unsuccessfully" ) << " inserted electron into association map");
+    }  
+    ATH_MSG_VERBOSE("Done with electron setup");
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Do photon topocluster finding
+  StatusCode METAssocAlg::setupPhotons(xAOD::MissingETAssociationMap* metMap,
+				       const xAOD::PhotonContainer* photons,
+				       const xAOD::CaloClusterContainer* clusters,
+				       const xAOD::Vertex* pv,
+				       const xAOD::PFOContainer* pfoCont)
+  //				       std::vector<const xAOD::IParticle*>& mutracks)
+  {
+    vector<const xAOD::IParticle*> constlist;
+    constlist.reserve(10);
+    ConstDataVector<PhotonContainer> photons_tmp(SG::VIEW_ELEMENTS);
+    for(const auto& ph : *photons) {
+      photons_tmp.push_back(ph);
+    }
+    std::sort(photons_tmp.begin(),photons_tmp.end(),greaterPt);    
+
+    for(const auto& ph : photons_tmp) {
+      // if(ph->pt()<5e3) continue;
+      ATH_MSG_VERBOSE( "Photon px, py, pt = " << ph->p4().Px() << ", " << ph->p4().Py() << ", " << ph->pt() );
+      constlist.clear();
+      MissingETBase::Types::constvec_t tcvec,trkvec;
+      if (m_pflow) this->extractPFO(ph,pfoCont,constlist,tcvec,trkvec,pv);
+      else {
+        this->extractTopoClusters(ph,clusters,constlist,tcvec);
+        ATH_MSG_VERBOSE( "Photon has " << constlist.size() << " topoclusters." );
+        this->extractTracks(ph,pv,constlist,trkvec);
+      }
+
+      ATH_MSG_VERBOSE( "Photon tc px, py, pt, sumpt = " << tcvec.cpx() << ", " << tcvec.cpy() << ", " << tcvec.cpt() << ", " << tcvec.sumpt() );
+      ATH_MSG_VERBOSE( "Photon track px, py, pt, sumpt = " << trkvec.cpx() << ", " << trkvec.cpy() << ", " << trkvec.cpt() << ", " << trkvec.sumpt() );
+
+      bool inserted(false);
+      inserted = MissingETComposition::insert(metMap,ph,constlist,tcvec,trkvec);
+      if(inserted) {
+	const MissingETAssociation* assoc = MissingETComposition::getAssociation(metMap,ph);
+	ATH_MSG_VERBOSE( "Photon is associated to jet " << assoc->refJet()->index() << " with pt " << assoc->refJet()->pt() );
+	ATH_MSG_VERBOSE( "Photon-jet deltaR = " << ph->p4().DeltaR(assoc->refJet()->p4()) );
+      } else {
+	ATH_MSG_VERBOSE( "Add photon as miscellaneous object" );
+	inserted = MissingETComposition::insertMisc(metMap,ph,constlist,tcvec,trkvec);
+      }
+      ATH_MSG_VERBOSE( (inserted ? "Successfully" : "Unsuccessfully" ) << " inserted photon into association map");
+    }
+    ATH_MSG_VERBOSE("Done with photons setup");
+    return StatusCode::SUCCESS;
+  }
+
+  //*********************************************************************************************************
+  // Do tau topocluster finding
+  StatusCode METAssocAlg::setupTaus(xAOD::MissingETAssociationMap* metMap,
+				    const xAOD::TauJetContainer* taus,
+				    const xAOD::Vertex* pv,
+				    const xAOD::PFOContainer* pfoCont)
+  //				    std::vector<const xAOD::IParticle*>& mutracks)
+  {
+    vector<const xAOD::IParticle*> constlist;
+    constlist.reserve(20);
+    ConstDataVector<TauJetContainer> taus_tmp(SG::VIEW_ELEMENTS);
+    for(const auto& ph : *taus) {
+      taus_tmp.push_back(ph);
+    }
+    std::sort(taus_tmp.begin(),taus_tmp.end(),greaterPt);    
+
+    for(const auto& tau : taus_tmp) {
+      // if(tau->pt()<5e3) continue;
+      ATH_MSG_VERBOSE( "Tau px, py, pt = " << tau->p4().Px() << ", " << tau->p4().Py() << ", " << tau->pt() );
+      constlist.clear();
+      MissingETBase::Types::constvec_t tcvec,trkvec;
+      if (m_pflow) this->extractPFO(tau,pfoCont,constlist,tcvec,trkvec,pv);
+      else {
+        this->extractTopoClusters(tau,constlist,tcvec);
+        this->extractTracks(tau,pv,constlist,trkvec);
+      }
+
+      ATH_MSG_VERBOSE( "Tau tc px, py, pt, sumpt = " << tcvec.cpx() << ", " << tcvec.cpy() << ", " << tcvec.cpt() << ", " << tcvec.sumpt() );
+      ATH_MSG_VERBOSE( "Tau track px, py, pt, sumpt = " << trkvec.cpx() << ", " << trkvec.cpy() << ", " << trkvec.cpt() << ", " << trkvec.sumpt() );
+
+      bool inserted(false);
+      inserted = MissingETComposition::insert(metMap,tau,constlist,tcvec,trkvec);
+      ATH_MSG_VERBOSE( (inserted ? "Successfully" : "Unsuccessfully" ) << " inserted tau into association map");
+      const MissingETAssociation* assoc = MissingETComposition::getAssociation(metMap,tau);
+      if(assoc) {
+	ATH_MSG_VERBOSE( "Tau is associated to jet " << assoc->refJet()->index() << " with pt " << assoc->refJet()->pt() );
+	ATH_MSG_VERBOSE( "Tau-jet deltaR = " << tau->p4().DeltaR(assoc->refJet()->p4()) );
+	const Jet* seedjet = *tau->jetLink();
+	ATH_MSG_VERBOSE( "Tau has seed jet " << seedjet->index() << " with pt " << seedjet->pt() );
+      }
+    }  
+
+    ATH_MSG_VERBOSE("Done with tau setup");
+    return StatusCode::SUCCESS;
+  }
+  //**********************************************************************
+  // Get Egamma constituents
+  void METAssocAlg::extractPFO(const xAOD::Egamma* eg,
+				       const xAOD::PFOContainer* pfoCont,
+				       std::vector<const xAOD::IParticle*>& pfolist,
+				       MissingETBase::Types::constvec_t& pfovec,
+				       MissingETBase::Types::constvec_t& trkvec,
+				       const xAOD::Vertex* pv)
+  {
+    // safe to assume a single SW cluster?
+    // will do so for now...
+    const CaloCluster* swclus = eg->caloCluster();
+    double eg_cl_e = swclus->e();
+    const xAOD::Electron* elec = (eg->type()==xAOD::Type::ObjectType::Electron) ? dynamic_cast<const xAOD::Electron*>(eg) : NULL;
+    const xAOD::Photon* ph = (eg->type()==xAOD::Type::ObjectType::Photon) ? dynamic_cast<const xAOD::Photon*>(eg) : NULL;
+
+    // the matching strategy depends on how the cluster container is sorted
+    // easier if it's sorted in descending pt order
+    // we'll worry about optimisation later
+    vector<const xAOD::PFO*> nearbyPFO;
+    nearbyPFO.reserve(10);
+    for(const auto& pfo : *pfoCont) {
+      std::vector<const IParticle*> cls;
+      bool match = false;
+      if (pfo->charge()==0) {
+        if (swclus->p4().DeltaR(pfo->p4EM())<0.1 && pfo->eEM()>0) match = true;
+        //pfo->associatedParticles(PFODetails::CaloCluster,cls);
+        //for(const auto& cl : cls) {
+        //  if (!cl) continue;
+        //  double dR = swclus->p4().DeltaR(cl->p4());
+        //  if(dR<0.1 && cl->e()>0) match = true;
+        //}
+      }
+      if (elec) {
+        for(size_t iTrk=0; iTrk<elec->nTrackParticles(); ++iTrk) {
+          const TrackParticle* eltrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(elec->trackParticle(iTrk));
+          if(pfo->charge()!=0 && acceptChargedPFO(eltrk,pv) && pfo->track(0) == eltrk) match = true;
+       }
+      }
+      if (ph) {
+        for(size_t iVtx=0; iVtx<ph->nVertices(); ++iVtx) {
+          const Vertex* phvx = ph->vertex(iVtx);
+          for(size_t iTrk=0; iTrk<phvx->nTrackParticles(); ++iTrk) {
+            const TrackParticle* phtrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(phvx->trackParticle(iTrk));
+            if(pfo->charge()!=0 && acceptChargedPFO(phtrk,pv) && pfo->track(0) == phtrk) match = true; 
+          }
+	}
+      }
+      if (match) nearbyPFO.push_back(pfo);
+    }
+    ATH_MSG_VERBOSE("Found " << nearbyPFO.size() << " nearby pfos");
+
+    bool doSum = true;
+    double sumE_pfo = 0.;
+    std::sort(nearbyPFO.begin(),nearbyPFO.end(),greaterPtPFO);
+    for(const auto& pfo : nearbyPFO) {
+      double pfo_e = (pfo->charge()==0 ? pfo->eEM() : pfo->e());
+      // skip cluster if it's above our bad match threshold
+      if(pfo->eEM()>2*eg_cl_e) {
+        ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (pfo->eEM()/eg_cl_e));
+	continue;
+      }
+
+      if( (doSum = fabs(sumE_pfo+pfo->e()-eg_cl_e) < fabs(sumE_pfo - eg_cl_e)) ) {
+	pfolist.push_back(pfo);
+	sumE_pfo += pfo_e;
+	pfovec += (pfo->charge()==0 ? MissingETBase::Types::constvec_t(pfo->ptEM()*cos(pfo->phiEM()),pfo->ptEM()*sin(pfo->phiEM()),pfo->ptEM()*cosh(pfo->etaEM()),pfo->eEM(),pfo->eEM()) : MissingETBase::Types::constvec_t(*pfo));
+        trkvec += MissingETBase::Types::constvec_t(*pfo);
+      } // if we will retain the topocluster
+      else {break;}
+    } // loop over nearby clusters
+  }
+
+  void METAssocAlg::extractTracks(const xAOD::TauJet* tau,
+				  const xAOD::Vertex* pv,
+				  std::vector<const xAOD::IParticle*>& constlist,
+				  MissingETBase::Types::constvec_t& trkvec)
+  {
+    const Jet* jet = *tau->jetLink();
+    for(size_t iTrk=0; iTrk<tau->nTracks(); ++iTrk) {
+      const TrackParticle* tautrk = tau->track(iTrk);
+      //	if(acceptTrack(tautrk,pv) && isGoodEoverP(tautrk)) {
+      if(acceptTrack(tautrk,pv) ) {
+	// bool matchedmu = false;
+	// for(const auto& mutrk : mutracks) {
+	//   if( (matchedmu = (tautrk == mutrk)) ) {
+	//     ATH_MSG_VERBOSE("Veto track matched to muon");
+	// 	break;
+	//   }
+	// }
+	// if(!matchedmu) {
+	ATH_MSG_VERBOSE("Accept tau track " << tautrk << " px, py = " << tautrk->p4().Px() << ", " << tautrk->p4().Py());
+	constlist.push_back(tautrk);
+	trkvec += *tautrk;
+	// }
+      }
+    }
+    for(size_t iTrk=0; iTrk<tau->nOtherTracks(); ++iTrk) {
+      const xAOD::TrackParticle* tautrk = tau->otherTrack(iTrk);
+      double dR = jet->p4().DeltaR(tautrk->p4());
+      //	if(dR<0.2 && acceptTrack(tautrk,pv) && isGoodEoverP(tautrk)) {
+      if(dR<0.2 && acceptTrack(tautrk,pv) ) {
+	// bool matchedmu = false;
+	// for(const auto& mutrk : mutracks) {
+	//   if( (matchedmu = (tautrk == mutrk)) ) {
+	//     ATH_MSG_VERBOSE("Veto track matched to muon");
+	// 	break;
+	//   }
+	// }
+	// if(!matchedmu) {
+	ATH_MSG_VERBOSE("Accept track " << tautrk << " px, py = " << tautrk->p4().Px() << ", " << tautrk->p4().Py());
+	constlist.push_back(tautrk);
+	trkvec += *tautrk;
+	// }
+      }
+    }
+  }
+  void METAssocAlg::extractTracks(const xAOD::Photon* ph,
+				  const xAOD::Vertex* pv,
+				  std::vector<const xAOD::IParticle*>& constlist,
+				  MissingETBase::Types::constvec_t& trkvec)
+  {
+    vector<const xAOD::TrackParticle*> phtrks;
+    for(size_t iVtx=0; iVtx<ph->nVertices(); ++iVtx) {
+      const Vertex* phvx = ph->vertex(iVtx);
+      for(size_t iTrk=0; iTrk<phvx->nTrackParticles(); ++iTrk) {
+	// if(!phvx->trackParticle(iTrk)) {
+	//   ATH_MSG_INFO("Invalid photon trackparticle pointer");
+	// }
+	const TrackParticle* phtrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(phvx->trackParticle(iTrk));
+	//	  if(acceptTrack(phtrk,pv) && isGoodEoverP(phtrk) && ph->p4().DeltaR(phtrk->p4())<0.1) {
+	if(acceptTrack(phtrk,pv) && ph->p4().DeltaR(phtrk->p4())<0.2) {
+	  // bool matchedmu = false;
+	  // for(const auto& mutrk : mutracks) {
+	  //   if( (matchedmu = (phtrk == mutrk)) ) {
+	  // 	ATH_MSG_VERBOSE("Veto track matched to muon");
+	  // 	break;
+	  //   }
+	  // }
+	  bool duplicate = false;
+	  for(const auto& gamtrk : phtrks) {
+	    if( (duplicate = (phtrk == gamtrk)) ) {
+	      ATH_MSG_VERBOSE("Veto duplicate track");
+	      break;
+	    }
+	  }
+	  // if(!matchedmu && !duplicate) {
+	  if(!duplicate) {
+	    ATH_MSG_VERBOSE("Accept photon track " << phtrk << " px, py = " << phtrk->p4().Px() << ", " << phtrk->p4().Py());
+	    ATH_MSG_VERBOSE("              track eta, phi = " << phtrk->p4().Eta() << ", " << phtrk->p4().Phi());
+	    ATH_MSG_VERBOSE("Delta R = " << ph->p4().DeltaR(phtrk->p4()));
+	    constlist.push_back(phtrk);
+	    trkvec += *phtrk;
+	    phtrks.push_back(phtrk);
+	  }
+	}
+      }
+    }
+  }
+  void METAssocAlg::extractTracks(const xAOD::Electron* el,
+				  const xAOD::Vertex* pv,
+				  std::vector<const xAOD::IParticle*>& constlist,
+				  MissingETBase::Types::constvec_t& trkvec)
+  {
+    for(size_t iTrk=0; iTrk<el->nTrackParticles(); ++iTrk) {
+      const TrackParticle* eltrk = xAOD::EgammaHelpers::getOriginalTrackParticleFromGSF(el->trackParticle(iTrk));
+      //	if(acceptTrack(eltrk,pv) && isGoodEoverP(eltrk) && el->p4().DeltaR(eltrk->p4())<0.1) {
+      if(acceptTrack(eltrk,pv)  && el->p4().DeltaR(eltrk->p4())<0.1) {
+	// bool matchedmu = false;
+	// for(const auto& mutrk : mutracks) {
+	//   if( (matchedmu=(eltrk == mutrk))) {
+	//     ATH_MSG_VERBOSE("Veto track matched to muon");
+	//     break;
+	//   }
+	// }
+	// if(!matchedmu) {
+	ATH_MSG_VERBOSE("Accept electron track " << eltrk << " px, py = " << eltrk->p4().Px() << ", " << eltrk->p4().Py());
+	constlist.push_back(eltrk);
+	trkvec += *eltrk;
+      }
+    }
+  }
+  //**********************************************************************
+  // Get Egamma constituents
+  void METAssocAlg::extractTopoClusters(const xAOD::Egamma* eg,
+					const xAOD::CaloClusterContainer* tcCont,
+					std::vector<const xAOD::IParticle*>& tclist,
+					MissingETBase::Types::constvec_t& tcvec)
+  {
+    // safe to assume a single SW cluster?
+    // will do so for now...
+    const CaloCluster* swclus = eg->caloCluster();
+    double eg_cl_e = swclus->e();
+
+    // the matching strategy depends on how the cluster container is sorted
+    // easier if it's sorted in descending pt order
+    // we'll worry about optimisation later
+    vector<const xAOD::CaloCluster*> nearbyTC;
+    nearbyTC.reserve(10);
+    for(const auto& cl : *tcCont) {
+      // this can probably be done more elegantly
+      double dR = swclus->p4().DeltaR(cl->p4());
+      if(dR<0.1 && cl->e()>0) {
+	// could consider also requirements on the EM fraction or depth
+	nearbyTC.push_back(cl);
+      } // match TC in a cone around SW cluster
+    }
+    ATH_MSG_VERBOSE("Found " << nearbyTC.size() << " nearby topoclusters");
+
+    bool doSum = true;
+    double sumE_tc = 0.;
+    const CaloCluster* bestbadmatch = 0;
+    std::sort(nearbyTC.begin(),nearbyTC.end(),greaterPt);
+    for(const auto& cl : nearbyTC) {
+      double tcl_e = cl->e();
+      // skip cluster if it's above our bad match threshold
+      // FIXME: What to do with these poor matches?
+      if(tcl_e>1.5*eg_cl_e) {
+	ATH_MSG_VERBOSE("Reject topocluster in sum. Ratio vs eg cluster: " << (tcl_e/eg_cl_e));
+	if( !bestbadmatch || (fabs(tcl_e/eg_cl_e-1.) < fabs(bestbadmatch->e()/eg_cl_e-1.)) ) bestbadmatch = cl;
+	continue;
+      }
+
+      ATH_MSG_VERBOSE("E match with new cluster: " << fabs(sumE_tc+tcl_e - eg_cl_e) / eg_cl_e);
+      if( (doSum = (fabs(sumE_tc+tcl_e - eg_cl_e) < fabs(sumE_tc - eg_cl_e))) ) {
+	ATH_MSG_VERBOSE("Accept topocluster with pt " << cl->pt() << ", e " << cl->e() << " in sum.");
+	ATH_MSG_VERBOSE("E match with new cluster: " << fabs(sumE_tc+tcl_e - eg_cl_e) / eg_cl_e);
+	ATH_MSG_VERBOSE("Energy ratio of TC to eg: " << tcl_e / eg_cl_e);
+	tclist.push_back(cl);
+	sumE_tc += tcl_e;
+	tcvec += MissingETBase::Types::constvec_t(*cl);
+      } // if we will retain the topocluster
+    } // loop over nearby clusters
+    if(sumE_tc<1e-9 && bestbadmatch) {
+      ATH_MSG_VERBOSE("No better matches found -- add bad match topocluster with pt "
+		      << bestbadmatch->pt() << ", e " << bestbadmatch->e() << ".");
+      tclist.push_back(bestbadmatch);
+      tcvec += MissingETBase::Types::constvec_t(*bestbadmatch);
+    }
+  }
+
+  //*********************************************************************************************************
+  // Get tau constituents
+  void METAssocAlg::extractPFO(const xAOD::TauJet* tau,
+				       const xAOD::PFOContainer* pfoCont,
+				       std::vector<const xAOD::IParticle*>& pfolist,
+				       MissingETBase::Types::constvec_t& pfovec,
+				       MissingETBase::Types::constvec_t& trkvec,
+				       const xAOD::Vertex* pv)
+  {  
+    const Jet* seedjet = *tau->jetLink();
+    JetConstituentVector constit = seedjet->getConstituents();
+    ATH_MSG_VERBOSE("Current tau has " << constit.size() << " constituents.");
+    for(const auto& pfo : *pfoCont) {
+      bool match = false;
+      if (pfo->charge()==0 && seedjet->p4().DeltaR(pfo->p4EM())<0.2) match = true;;
+      for(size_t iTrk=0; iTrk<tau->nTracks(); ++iTrk) {
+	const TrackParticle* tautrk = tau->track(iTrk);
+	if(acceptChargedPFO(tautrk,pv) && pfo->charge()!=0 && tautrk==pfo->track(0)) match = true; 
+      }
+      for(size_t iTrk=0; iTrk<tau->nOtherTracks(); ++iTrk) {
+	const xAOD::TrackParticle* tautrk = tau->otherTrack(iTrk);
+	double dR = seedjet->p4().DeltaR(tautrk->p4());
+	if(dR<0.2 && acceptChargedPFO(tautrk,pv) && pfo->charge()!=0 && tautrk==pfo->track(0)) match = true;
+      }
+      if (!match) continue; 
+      pfolist.push_back(pfo);
+      if (pfo->charge()) trkvec += MissingETBase::Types::constvec_t(*pfo);
+      pfovec += (pfo->charge()==0 ? MissingETBase::Types::constvec_t(pfo->ptEM()*cos(pfo->phiEM()),pfo->ptEM()*sin(pfo->phiEM()),pfo->ptEM()*cosh(pfo->etaEM()),pfo->eEM(),pfo->eEM()) : MissingETBase::Types::constvec_t(*pfo));
+    }
+  }
+
+  //*********************************************************************************************************
+  // Get tau constituents
+  void METAssocAlg::extractTopoClusters(const xAOD::TauJet* tau,
+					std::vector<const xAOD::IParticle*>& tclist,
+					MissingETBase::Types::constvec_t& tcvec)
+  {  
+    const Jet* seedjet = *tau->jetLink();
+    JetConstituentVector constit = seedjet->getConstituents();
+    ATH_MSG_VERBOSE("Current tau has " << constit.size() << " constituents.");
+    // test for used topoclusters, and retrieve unused ones (ok until/unless we use PFlow taus)
+    // only use clusters for computing the overlap removal relative to other objects
+    for(const auto& cl : constit) {
+      // TEMP: use jet seed axis
+      //       taus will provide an accessor
+      double dR = seedjet->p4().DeltaR(cl->rawConstituent()->p4());
+      if(dR>0.2) continue;
+      // skip cluster if dR>0.2
+      const CaloCluster* pClus = dynamic_cast<const CaloCluster*>( cl->rawConstituent() );
+      tclist.push_back(pClus);
+      tcvec += MissingETBase::Types::constvec_t(*pClus);
+    } // loop over jet constituents
+  }
+
+  bool METAssocAlg::acceptChargedPFO(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv) {
+    if(fabs((trk->z0() - pv->z()+trk->vz())*sin(trk->theta())) > 2) return false;
+    return true;
+  }
+
+
+  bool METAssocAlg::acceptTrack(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv)
+  {
+    //    if(!trk || !pv) return false;
+
+  //  if(fabs(trk->pt())<500/*MeV*/ || fabs(trk->eta())>2.5) return false;
+
+  //  // could add some error checking to make sure we successfully read the details
+  //  uint8_t nPixHits(0), nSctHits(0);
+  //  trk->summaryValue(nPixHits,xAOD::numberOfPixelHits);
+  //  if(nPixHits<1) return false;
+  //  trk->summaryValue(nSctHits,xAOD::numberOfSCTHits);
+  //  if(nSctHits<6) return false;
+
+  //  if(fabs(trk->d0())>1.5) return false;
+  //  if(fabs(trk->z0() + trk->vz() - pv->z()) > 1.5) return false;
+
+    if(!(m_trkseltool->accept( *trk, pv ))) return false; 
+    else return true;
+
+  }
+
+  bool METAssocAlg::isGoodEoverP(const xAOD::TrackParticle* trk) {
+
+    if( (fabs(trk->eta())<1.5 && trk->pt()>200e3) ||
+	(fabs(trk->eta())>=1.5 && trk->pt()>120e3) ) {
+
+      const CaloClusterContainer *clusters = 0;
+      if( evtStore()->retrieve(clusters, m_clcoll).isFailure() ) {
+	ATH_MSG_WARNING("Unable to retrieve topocluster container " << m_clcoll << " for overlap removal");
+	return StatusCode::SUCCESS;
+      }
+
+      // Get relative error on qoverp
+      float Rerr = Amg::error(trk->definingParametersCovMatrix(),4)/fabs(trk->qOverP());
+      ATH_MSG_VERBOSE( "Track momentum error (%): " << Rerr*100 );
+
+      // first compute track and calo isolation variables
+      float ptcone20 = 0;
+      for(const auto& testtrk : m_goodtracks) {
+	if(testtrk==trk) continue;
+	if(testtrk->p4().DeltaR(trk->p4()) < 0.2) {
+	  ptcone20 += testtrk->pt();
+	}
+      }
+      float isolfrac = ptcone20 / trk->pt();
+      ATH_MSG_VERBOSE( "Track isolation fraction: " << isolfrac );
+
+      float etcone10 = 0.;
+      for(const auto& clus : *clusters) {
+	if(clus->p4().DeltaR(trk->p4()) < 0.1) {
+	  etcone10 += clus->pt();
+	}
+      }
+      float EoverP = etcone10/trk->pt();
+      ATH_MSG_VERBOSE( "Track E/P: " << EoverP );
+
+      if(isolfrac<0.1) {
+	// isolated track cuts
+	if(Rerr>0.4) return false;
+	else if (EoverP<0.65 && (EoverP>0.1 || Rerr>0.1)) return false;
+      } else {
+	// non-isolated track cuts
+	float trkptsum = ptcone20+trk->pt();
+	if(EoverP/trkptsum<0.6 && ptcone20/trkptsum<0.6) return false;
+      }
+    }
+    return true;
+  }
+
+  void METAssocAlg::filterTracks(const xAOD::TrackParticleContainer* tracks,
+				 const xAOD::Vertex* pv) {
+    for(const auto& trk : *tracks) {
+      m_goodtracks.clear();
+      if(acceptTrack(trk,pv)) m_goodtracks.push_back(trk);
+    }
+  }
+
+  std::vector<const xAOD::IParticle*> METAssocAlg::selectTracks(const std::vector<const xAOD::IParticle*>& tracksin,
+								const xAOD::Vertex* pv)
+  {
+    std::vector<const xAOD::IParticle*> tracksout;
+    tracksout.reserve(tracksin.size());
+    for(const auto& trk : tracksin) {
+      const TrackParticle* pTrk = dynamic_cast<const TrackParticle*>(trk);
+//      if( acceptTrack(pTrk,pv) && isGoodEoverP(pTrk) ) {
+      if( acceptTrack(pTrk,pv) ) {
+	tracksout.push_back(trk);
+	ATH_MSG_VERBOSE("Accept track " << trk << " px, py = " << trk->p4().Px() << ", " << trk->p4().Py());
+      }
+    }
+    return tracksout;
+  }
+
+  //**********************************************************************
+
+}
+
diff --git a/Reconstruction/MET/METReconstruction/src/METAssocAlg.h b/Reconstruction/MET/METReconstruction/src/METAssocAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4919aea6568f5ebf8aeb50b65f7fd4729043288
--- /dev/null
+++ b/Reconstruction/MET/METReconstruction/src/METAssocAlg.h
@@ -0,0 +1,145 @@
+///////////////////////// -*- C++ -*- /////////////////////////////
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+// METAssocAlg.h
+
+#ifndef METAssocAlg_H
+#define METAssocAlg_H
+
+#include "AthenaBaseComps/AthAlgorithm.h"
+#include "GaudiKernel/ToolHandle.h"
+
+#include "xAODMissingET/MissingETAssociationMap.h"
+
+#include "xAODEgamma/EgammaFwd.h"
+#include "xAODEgamma/ElectronContainer.h"
+#include "xAODEgamma/PhotonContainer.h"
+#include "xAODMuon/MuonContainer.h"
+#include "xAODJet/JetContainer.h"
+#include "xAODTau/TauJetContainer.h"
+#include "xAODCaloEvent/CaloClusterContainer.h"
+#include "xAODTracking/TrackParticle.h"
+#include "xAODTracking/Vertex.h"
+#include "xAODPFlow/PFOContainer.h"
+#include "xAODPFlow/PFO.h"
+#include "PFlowUtils/IRetrievePFOTool.h"
+#include "InDetTrackSelectionTool/IInDetTrackSelectionTool.h"
+
+class IMETRecoTool;
+
+namespace met {
+  class METAssocAlg : public AthAlgorithm { 
+
+  public: 
+
+    /// Constructor with parameters:
+    METAssocAlg(const std::string& name, ISvcLocator* pSvcLocator);
+
+    /// Destructor:
+    ~METAssocAlg(); 
+
+    /// Athena algorithm's Hooks
+    StatusCode  initialize();
+    StatusCode  execute();
+    StatusCode  finalize();
+
+  private: 
+
+    /// Default constructor:
+    METAssocAlg();
+
+    StatusCode setupJetAssoc(xAOD::MissingETAssociationMap* metMap,
+			     const xAOD::JetContainer* jets,
+			     const xAOD::Vertex* pv);
+    StatusCode setupMuons(xAOD::MissingETAssociationMap* metMap,
+			  const xAOD::MuonContainer* muons,
+			  const xAOD::Vertex* pv,
+			  const xAOD::PFOContainer* pfoCont);
+    //			  std::vector<const xAOD::IParticle*>& mutracks);
+    StatusCode setupElectrons(xAOD::MissingETAssociationMap* metMap,
+			      const xAOD::ElectronContainer* electrons,
+			      const xAOD::CaloClusterContainer* clusters,
+			      const xAOD::Vertex* pv,
+			      const xAOD::PFOContainer* pfoCont);
+			      // std::vector<const xAOD::IParticle*>& mutracks);
+    StatusCode setupPhotons(xAOD::MissingETAssociationMap* metMap,
+			    const xAOD::PhotonContainer* photons,
+			    const xAOD::CaloClusterContainer* clusters,
+			    const xAOD::Vertex* pv,
+			    const xAOD::PFOContainer* pfoCont);
+			    // std::vector<const xAOD::IParticle*>& mutracks);
+    StatusCode setupTaus(xAOD::MissingETAssociationMap* metMap,
+			 const xAOD::TauJetContainer* taus,
+			 const xAOD::Vertex* pv,
+			 const xAOD::PFOContainer* pfoCont);
+			 // std::vector<const xAOD::IParticle*>& mutracks);
+
+    void extractTopoClusters(const xAOD::Egamma* eg,
+			     const xAOD::CaloClusterContainer* tcCont,
+			     std::vector<const xAOD::IParticle*>& tclist,
+			     MissingETBase::Types::constvec_t& tcvec);
+    void extractTopoClusters(const xAOD::TauJet* tau,
+			     std::vector<const xAOD::IParticle*>& tclist,
+			     MissingETBase::Types::constvec_t& tcvec);
+    void extractTracks(const xAOD::TauJet* tau,
+		       const xAOD::Vertex* pv,
+		       std::vector<const xAOD::IParticle*>& constlist,
+		       MissingETBase::Types::constvec_t& trkvec);
+    void extractTracks(const xAOD::Electron* el,
+		       const xAOD::Vertex* pv,
+		       std::vector<const xAOD::IParticle*>& constlist,
+		       MissingETBase::Types::constvec_t& trkvec);
+    void extractTracks(const xAOD::Photon* ph,
+		       const xAOD::Vertex* pv,
+		       std::vector<const xAOD::IParticle*>& constlist,
+		       MissingETBase::Types::constvec_t& trkvec);
+    void extractPFO(const xAOD::TauJet* tau,
+		    const xAOD::PFOContainer* pfoCont,
+		    std::vector<const xAOD::IParticle*>& pfolist,
+		    MissingETBase::Types::constvec_t& pfovec,
+		    MissingETBase::Types::constvec_t& trkvec,
+		    const xAOD::Vertex* pv);
+    void extractPFO(const xAOD::Egamma* eg,
+		    const xAOD::PFOContainer* pfoCont,
+		    std::vector<const xAOD::IParticle*>& pfolist,
+		    MissingETBase::Types::constvec_t& pfovec,
+		    MissingETBase::Types::constvec_t& trkvec,
+		    const xAOD::Vertex* pv);
+
+    bool acceptTrack(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv);
+    bool acceptChargedPFO(const xAOD::TrackParticle* trk, const xAOD::Vertex* pv);
+    bool isGoodEoverP(const xAOD::TrackParticle* trk);
+    void filterTracks(const xAOD::TrackParticleContainer* tracks,
+		      const xAOD::Vertex* pv);
+    std::vector<const xAOD::IParticle*> selectTracks(const std::vector<const xAOD::IParticle*>& tracksin,
+						     const xAOD::Vertex* pv);
+
+    // store list of accepted tracks for track isolation checks
+    std::vector<const xAOD::TrackParticle*> m_goodtracks;
+
+    // configurable data members
+    std::string m_contname;
+    std::string m_mapname;
+
+    std::string m_jetcoll;
+    std::string m_elecoll;
+    std::string m_gammacoll;
+    std::string m_taucoll;
+    std::string m_muoncoll;
+    std::string m_pvcoll;
+    std::string m_trkcoll;
+    std::string m_clcoll;
+
+    bool m_pflow;    
+
+    ToolHandle<CP::IRetrievePFOTool> m_pfotool;
+    ToolHandle<InDet::IInDetTrackSelectionTool> m_trkseltool;
+
+  };
+
+}
+
+#endif
diff --git a/Reconstruction/MET/METReconstruction/src/components/METReconstruction_entries.cxx b/Reconstruction/MET/METReconstruction/src/components/METReconstruction_entries.cxx
index 758a79c0496374f5c542b04ebbf9f469811cccb8..62ebe9fed9bf56bdf4fa91cabf0c708824e28e18 100644
--- a/Reconstruction/MET/METReconstruction/src/components/METReconstruction_entries.cxx
+++ b/Reconstruction/MET/METReconstruction/src/components/METReconstruction_entries.cxx
@@ -2,6 +2,7 @@
 
 // Top level tool
 #include "METReconstruction/METRecoTool.h"
+#include "METReconstruction/METAssociationTool.h"
 // Builders
 #include "METReconstruction/METElectronTool.h"
 #include "METReconstruction/METPhotonTool.h"
@@ -9,6 +10,12 @@
 #include "METReconstruction/METTauTool.h"
 #include "METReconstruction/METMuonTool.h"
 #include "METReconstruction/METSoftTermsTool.h"
+#include "METReconstruction/METElectronAssociator.h"
+#include "METReconstruction/METPhotonAssociator.h"
+#include "METReconstruction/METJetAssocTool.h"
+#include "METReconstruction/METTauAssociator.h"
+#include "METReconstruction/METMuonAssociator.h"
+#include "METReconstruction/METSoftAssociator.h"
 // Truth tool
 #include "METReconstruction/METTruthTool.h"
 // CaloRegions
@@ -19,18 +26,26 @@
 #include "METReconstruction/METMuonElossTool.h"
 #include "METReconstruction/METRegionsTool.h"
 // Algs
-#include "../src/METRecoAlg.h"
-#include "../src/METReaderAlg.h"
+#include "METRecoAlg.h"
+#include "METReaderAlg.h"
+#include "METAssocAlg.h"
 
 using namespace met;
 
 DECLARE_TOOL_FACTORY(METRecoTool)
+DECLARE_TOOL_FACTORY(METAssociationTool)
 DECLARE_TOOL_FACTORY(METElectronTool)
 DECLARE_TOOL_FACTORY(METPhotonTool)
 DECLARE_TOOL_FACTORY(METJetTool)
 DECLARE_TOOL_FACTORY(METTauTool)
 DECLARE_TOOL_FACTORY(METMuonTool)
 DECLARE_TOOL_FACTORY(METSoftTermsTool)
+DECLARE_TOOL_FACTORY(METElectronAssociator)
+DECLARE_TOOL_FACTORY(METPhotonAssociator)
+DECLARE_TOOL_FACTORY(METJetAssocTool)
+DECLARE_TOOL_FACTORY(METTauAssociator)
+DECLARE_TOOL_FACTORY(METMuonAssociator)
+DECLARE_TOOL_FACTORY(METSoftAssociator)
 //
 DECLARE_TOOL_FACTORY(METTruthTool)
 DECLARE_TOOL_FACTORY(METCaloRegionsTool)
@@ -42,6 +57,7 @@ DECLARE_TOOL_FACTORY(METRegionsTool)
 //
 DECLARE_ALGORITHM_FACTORY(METRecoAlg)
 DECLARE_ALGORITHM_FACTORY(METReaderAlg)
+DECLARE_ALGORITHM_FACTORY(METAssocAlg)
 
 DECLARE_FACTORY_ENTRIES(METReconstruction) {
   DECLARE_TOOL(METRecoTool)
@@ -51,6 +67,13 @@ DECLARE_FACTORY_ENTRIES(METReconstruction) {
   DECLARE_TOOL(METTauTool)
   DECLARE_TOOL(METMuonTool)
   DECLARE_TOOL(METSoftTermsTool)
+  DECLARE_TOOL(METAssociationTool)
+  DECLARE_TOOL(METElectronAssociator)
+  DECLARE_TOOL(METPhotonAssociator)
+  DECLARE_TOOL(METJetAssocTool)
+  DECLARE_TOOL(METTauAssociator)
+  DECLARE_TOOL(METMuonAssociator)
+  DECLARE_TOOL(METSoftAssociator)
     //
   DECLARE_TOOL(METTruthTool)
   DECLARE_TOOL(METCaloRegionsTool)
@@ -62,4 +85,5 @@ DECLARE_FACTORY_ENTRIES(METReconstruction) {
     //
   DECLARE_ALGORITHM(METRecoAlg)
   DECLARE_ALGORITHM(METReaderAlg)
+  DECLARE_ALGORITHM(METAssocAlg)
 }