diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/CMakeLists.txt b/Trigger/TrigAnalysis/TriggerMatchingTool/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..701bd630e43f4e3af3f21f37294bd58babfb9a33
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/CMakeLists.txt
@@ -0,0 +1,42 @@
+################################################################################
+# Package: TriggerMatchingTool
+################################################################################
+
+# Declare the package name:
+atlas_subdir( TriggerMatchingTool )
+
+# Declare the package's dependencies:
+atlas_depends_on_subdirs( PUBLIC
+                          Control/AthToolSupport/AsgTools
+                          Event/xAOD/xAODBase
+                          GaudiKernel
+                          Trigger/TrigAnalysis/TrigDecisionTool
+                          Trigger/TrigEvent/TrigNavStructure
+                          PRIVATE
+                          Control/AthAnalysisBaseComps
+                          Event/FourMomUtils )
+
+# External dependencies:
+find_package( Boost COMPONENTS filesystem thread system )
+find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread )
+
+# Component(s) in the package:
+atlas_add_library( TriggerMatchingToolLib
+                   Root/*.cxx
+                   src/*.cxx
+                   PUBLIC_HEADERS TriggerMatchingTool
+                   PRIVATE_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
+                   LINK_LIBRARIES AsgTools xAODBase GaudiKernel TrigNavStructure TrigDecisionToolLib
+                   PRIVATE_LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AthAnalysisBaseComps FourMomUtils )
+
+atlas_add_component( TriggerMatchingTool
+                     src/components/*.cxx
+                     INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
+                     LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AsgTools xAODBase GaudiKernel TrigDecisionToolLib TrigNavStructure AthAnalysisBaseComps FourMomUtils TriggerMatchingToolLib )
+
+atlas_add_dictionary( TriggerMatchingToolDict
+                      TriggerMatchingTool/TriggerMatchingToolDict.h
+                      TriggerMatchingTool/selection.xml
+                      INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${ROOT_INCLUDE_DIRS}
+                      LINK_LIBRARIES ${Boost_LIBRARIES} ${ROOT_LIBRARIES} AsgTools xAODBase GaudiKernel TrigDecisionToolLib TrigNavStructure AthAnalysisBaseComps FourMomUtils TriggerMatchingToolLib )
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/LinkDef.h b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/LinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9fa452558b6689ef1035f603096f64ab7ab8510
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/LinkDef.h
@@ -0,0 +1,12 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifdef __CINT__
+
+#pragma link off all globals;
+#pragma link off all classes;
+#pragma link off all functions;
+#pragma link C++ nestedclass;
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingImplementation.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingImplementation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..370766276d328f08484c58cfed85c09991cf45f3
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingImplementation.cxx
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TriggerMatchingTool/MatchingImplementation.h"
+#include "TriggerMatchingTool/MatchingTool.h"
+#include "MinimalSumAssociation.h"
+
+namespace Trig {
+
+MatchingImplementation::MatchingImplementation(MatchingTool& mt, double threshold) : asg::AsgMessaging("MatchingImplementation"), m_tool(mt), m_threshold(threshold) {
+  msg().setLevel(MSG::DEBUG);
+  m_strategies[Trig::MatchingStrategy::MinimalSum] = std::unique_ptr<IAssociationStrategy>(new MinimalSumAssociation());
+}
+
+Trig::TrigDecisionTool* MatchingImplementation::tdt(){
+  return m_tool.m_trigDecTool.operator->();
+}
+
+bool MatchingImplementation::assocIsMatched(IAssociationStrategy::index_assignment_t association, const std::vector<std::vector<double> >& matrix){
+  int ndim =  matrix.size();
+  if(!ndim) return false;
+
+  bool result = true;
+  for(auto trig_reco : association){
+    double distance = matrix[trig_reco.first][trig_reco.second];
+    bool single_assoc =  distance < m_threshold;
+    result = result && single_assoc;
+    ATH_MSG_DEBUG("reco: " << trig_reco.first << " associated to trig: " << trig_reco.second <<
+		  " with distance: " << distance << " ok: " << single_assoc << " overall: " << result);
+  }
+  return result;
+}
+
+bool MatchingImplementation::matchDistanceMatrix(const std::vector<std::vector<double> >& matrix, const Trig::MatchingStrategy::Strategy strategy){
+  int nrows =  matrix.size();
+  int ncols = matrix.at(0).size();
+
+  ATH_MSG_DEBUG("matching a " << nrows << "x" << ncols << "matrix now");
+
+  auto MSG_MATRIX = MSG::DEBUG;
+  if(msgLvl(MSG_MATRIX)){
+    msg() << MSG_MATRIX << "===========" << endreq;
+    for(auto& row : matrix){
+      msg() << MSG_MATRIX << "|";
+      for(auto distance : row){ 
+	msg() << MSG_MATRIX << distance << " , ";
+      }
+      msg() << MSG_MATRIX << "|" << endreq;
+    }
+    msg() << MSG_MATRIX << "===========" << endreq;
+  }
+
+  auto association_map = m_strategies[strategy]->associate(matrix);
+  return assocIsMatched(association_map,matrix);
+}
+
+}
\ No newline at end of file
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingTool.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..c4974aeae23b6604c9992bd61f8762da6f5aa377
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MatchingTool.cxx
@@ -0,0 +1,203 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TriggerMatchingTool/MatchingTool.h"
+#include "TriggerMatchingTool/MatchingImplementation.h"
+#include "xAODBase/IParticle.h"
+
+#include "FourMomUtils/xAODP4Helpers.h"
+
+namespace Trig {
+
+MatchingTool::MatchingTool(const std::string& name) : 
+  asg::AsgTool(name),
+  m_impl(new Trig::MatchingImplementation(*this)),
+  m_trigDecTool("Trig::TrigDecisionTool/TrigDecisionTool"),
+  m_matchingThreshold(0)
+{
+  declareProperty( "TrigDecisionTool", m_trigDecTool);
+
+#ifndef XAOD_STANDALONE
+//  declareProperty( "DefaultMatchingThreshold", m_matchingThreshold = 0.4)->declareUpdateHandler(&MatchingTool::updateThreshold, this );
+   auto props = getProperties();
+ 	for( Property* prop : props ) {
+      if( prop->name() != "OutputLevel" ) {
+         continue;
+      }
+      prop->declareUpdateHandler( &MatchingTool::updateOutputLevel, this );
+      break;
+   }
+#else
+//   declareProperty( "DefaultMatchingThreshold", m_matchingThreshold = 0.4);
+#endif
+
+}
+
+#ifndef XAOD_STANDALONE
+void MatchingTool::updateOutputLevel(Property& p) {
+   this->msg_update_handler(p); //calls original handler
+   impl()->msg().setLevel(AthMessaging::msg().level()); //pass on our message level to the matchingimplementation
+}
+
+void MatchingTool::updateThreshold(Property& /*p*/) {
+   ATH_MSG_DEBUG("Matching Threshold is updated to:" << m_matchingThreshold);
+   impl()->setThreshold( m_matchingThreshold );
+}
+#endif
+
+MatchingTool::~MatchingTool(){
+  delete m_impl;
+}
+
+StatusCode MatchingTool::initialize() {
+  impl()->setThreshold( m_matchingThreshold );
+
+  ATH_CHECK( m_trigDecTool.retrieve() );
+
+  return StatusCode::SUCCESS;
+}
+
+bool MatchingTool::matchCombination(const std::vector<const xAOD::IParticle*>& recoObjects, Trig::Combination& comb){
+  std::map<xAOD::Type::ObjectType,std::vector<const xAOD::IParticle*> > type_separated;
+  
+  for(const auto& obj : recoObjects){
+    if(type_separated.find(obj->type()) == type_separated.end()){
+      std::vector<const xAOD::IParticle*> typevec;
+      type_separated[obj->type()] = typevec;
+    }
+    type_separated[obj->type()].push_back(obj);
+  }
+  
+  ATH_MSG_DEBUG("found: " << type_separated.size() << " unique objects types to match");
+  for(auto& type_vec : type_separated){
+    ATH_MSG_DEBUG("type: " << type_vec.first << "(" << type_vec.second.size() << " elements)");
+  }
+  
+  bool overall_status = true;
+  std::map<xAOD::Type::ObjectType,bool> status;
+  for(auto& type_vec : type_separated){
+    auto single_status =  matchSingleType(type_vec.second, comb);
+    ATH_MSG_DEBUG("type: " << type_vec.first << " status: " << single_status);
+    status[type_vec.first] = single_status;
+    overall_status = overall_status && single_status;
+  }
+  
+  return overall_status;
+}
+
+bool MatchingTool::matchSingleType(const std::vector<const xAOD::IParticle*>& recoObjects, Trig::Combination& comb){
+  ATH_MSG_DEBUG("matching combination with " << comb.tes().size() << " TEs");
+  
+  auto recoType = recoObjects.at(0)->type();
+  ATH_MSG_DEBUG("reco type is " << recoType);
+
+  HLT::class_id_type clid = 0;
+  std::string container_typename("");
+
+  if(m_typeMap.isKnown(recoType)){
+    auto clid_container = m_typeMap.get(recoType);
+    clid = clid_container.first;
+    container_typename = clid_container.second;
+    ATH_MSG_DEBUG("getting trigger features (clid: " << clid << " and type: " << container_typename << ")");
+  }
+  else{
+    ATH_MSG_WARNING("could not find corresponding trigger type, can't match");
+    return false;
+  }
+  
+  auto iparticle_feats = comb.getIParticle(clid,container_typename);
+  
+  ATH_MSG_DEBUG("found: " << iparticle_feats.size() << " xAOD::IParticle");
+  
+  for(auto& feat : iparticle_feats){
+    ATH_MSG_DEBUG(" ==> pt: " << feat.cptr()->pt() << " and eta: " << feat.cptr()->eta() << " address: " << feat.cptr());
+  }
+
+  if(recoObjects.size() > iparticle_feats.size()){
+    ATH_MSG_WARNING("more reco objects (" << recoObjects.size() << ") than trigger object (" << iparticle_feats.size() << "). no hope of matching!");
+    return false;
+  }
+  
+  ATH_MSG_DEBUG("now matching: " << recoObjects.size() << " reco objects to " << iparticle_feats.size() << " trigger objects");
+  
+  std::vector<const xAOD::IParticle*> trigObjects;
+  for(auto& feat : iparticle_feats){trigObjects.push_back(feat.cptr());}
+
+  auto distance_matrix = distanceMatrix(recoObjects,trigObjects);
+
+  ATH_MSG_DEBUG("made distance matrix");
+
+  bool match_result = impl()->matchDistanceMatrix(distance_matrix);
+
+  ATH_MSG_DEBUG("got matching result: " << match_result);
+  
+  return match_result;
+}
+
+bool MatchingTool::match(const xAOD::IParticle& recoObject, const std::string& chain, double matchThreshold) {
+   impl()->setThreshold( matchThreshold );
+   std::vector<const xAOD::IParticle*> recoObjects(1,&recoObject);
+   bool out = match(recoObjects, chain);
+   impl()->setThreshold( m_matchingThreshold );
+   return out;
+}
+
+bool MatchingTool::match(const std::vector<const xAOD::IParticle*>& recoObjects, const std::string& chain, double matchThreshold) {
+   impl()->setThreshold( matchThreshold );
+   bool out = match(recoObjects, chain);
+   impl()->setThreshold( m_matchingThreshold );
+   return out;
+}
+
+bool MatchingTool::match(const std::vector<const xAOD::IParticle*>& recoObjects, const std::string& chain){
+  ATH_MSG_DEBUG("matching " << recoObjects.size() << " reco objects to chain: " << chain );
+  
+  auto chainGroup = impl()->tdt()->getChainGroup(chain);
+  bool decision = chainGroup->isPassed();
+  ATH_MSG_DEBUG(chain << " is passed: " << decision);
+  if(!decision) return false;
+  
+  auto featureContainer = chainGroup->features();
+  auto combinations = featureContainer.getCombinations();
+  
+  ATH_MSG_DEBUG("chain has: " << combinations.size() << " combos");
+  
+  bool result = false;
+  for(auto& comb : combinations){
+    bool combResult = matchCombination(recoObjects,comb);
+    ATH_MSG_DEBUG("matching result for this combination: " << combResult);
+    result = result || combResult;
+    if(result) break; //no need to continue if result is true
+  }
+
+  ATH_MSG_DEBUG("overall matching result: " << result);
+  
+  return result;
+}
+
+Trig::MatchingImplementation* MatchingTool::impl(){
+  return m_impl;
+}
+
+double MatchingTool::IParticleMetric(const xAOD::IParticle* lhs, const xAOD::IParticle* rhs){
+  return xAOD::P4Helpers::deltaR(lhs,rhs,false /*use pseudorapidity to avoid calling p4*/);//return lhs->p4().DeltaR(rhs->p4());
+}
+
+std::vector<std::vector<double> > MatchingTool::distanceMatrix(const std::vector<const xAOD::IParticle*>& reco,
+							       const std::vector<const xAOD::IParticle*>& trigger){
+  std::vector<std::vector<double> > rows;
+  for(const auto& rec : reco){
+    std::vector<double> distances_to_rec;
+    for(const auto& trig : trigger){
+      distances_to_rec.push_back(IParticleMetric(rec,trig));
+    }
+    rows.push_back(distances_to_rec);
+  }
+  return rows;
+}
+
+} //Trig namespace
+
+
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..da85d43587bf75d292d1747c647e52f489a0abb0
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.cxx
@@ -0,0 +1,40 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "MinimalSumAssociation.h"
+#include "munkres.h"
+
+
+MinimalSumAssociation::MinimalSumAssociation() : asg::AsgMessaging("MinimalSumAssociation"){
+  msg().setLevel(MSG::DEBUG);
+}
+
+IAssociationStrategy::index_assignment_t MinimalSumAssociation::associate(const std::vector<std::vector<double> >& matrix){
+  IAssociationStrategy::index_assignment_t resultmap;
+  int nrows =  matrix.size();
+  int ncols = matrix.at(0).size();
+  
+  auto workmatrix = matrix;
+  //if we have more columns than rows we pad the matrix to make it square
+  if(nrows < ncols){
+    for(int i = (ncols - nrows); i > 0;i--){
+      workmatrix.push_back(std::vector<double>(ncols,0));
+    }
+  }
+
+  munkres::vec_type costs;
+  costs.reserve(ncols);
+  munkres munk(workmatrix);
+  
+  bool debug = false;
+  auto result = munk.run(costs,debug);
+  
+  for(int i = 0;i < nrows;++i){
+    resultmap[i] = result[i];
+  }
+
+  return resultmap;
+}
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.h b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.h
new file mode 100644
index 0000000000000000000000000000000000000000..5ca655b13d0b8594018e6bfe697bf315f1a19261
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/MinimalSumAssociation.h
@@ -0,0 +1,20 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_MINIMALSUMASSOCIATION_H
+#define TRIGGERMATCHINGTOOL_MINIMALSUMASSOCIATION_H
+
+#include "TriggerMatchingTool/IAssociationStrategy.h"
+#include "AsgTools/AsgMessaging.h"
+
+
+class MinimalSumAssociation : public IAssociationStrategy, public asg::AsgMessaging {
+public:
+  MinimalSumAssociation();
+  index_assignment_t associate(const std::vector<std::vector<double> >& matrix);
+};
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/TypeMap.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/TypeMap.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b3349df8f02df11536eb42daeaf2322c60cfd705
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/TypeMap.cxx
@@ -0,0 +1,25 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TriggerMatchingTool/TypeMap.h"
+
+TypeMap::TypeMap(){
+  m_typemap[xAOD::Type::Muon] = std::make_pair(1178459224, "xAOD::MuonContainer" ); 
+  m_typemap[xAOD::Type::Electron] = std::make_pair(1087532415, "xAOD::ElectronContainer"); 
+  m_typemap[xAOD::Type::Photon] = std::make_pair(1105575213, "xAOD::PhotonContainer");
+  m_typemap[xAOD::Type::Tau] = std::make_pair(1177172564, "xAOD::TauJetContainer");
+}
+
+bool TypeMap::isKnown(const xAOD::Type::ObjectType& recoType){
+  auto it = m_typemap.find(recoType);
+  return (it!=m_typemap.end());
+}
+
+TypeMap::clid_string_t TypeMap::get(const xAOD::Type::ObjectType& recoType){
+  auto it = m_typemap.find(recoType);
+  if(it!=m_typemap.end()){
+    return it->second;
+  }
+  return std::make_pair(0,"");
+}
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8da000f9928b33b136a0471740f79e90fd02f985
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.cxx
@@ -0,0 +1,292 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "munkres.h"
+#include "boost/io/ios_state.hpp"
+
+munkres::munkres(matrix_type costs):
+  m_costmatrix(costs),
+  m_costs_orig(costs),
+  m_step(0),
+  m_dim(costs.size())
+{
+    m_rowIsCovered = std::vector<bool>(m_dim,false);
+    m_colIsCovered = std::vector<bool>(m_dim,false);
+    vec_type maskrow(m_dim,0);
+    for(int i=0;i<m_dim;++i) m_maskmatrix.push_back(maskrow);
+}
+
+munkres::result_type munkres::run(vec_type& costvector, bool debug){
+  if(debug) printcosts();
+  bool done = false;
+  m_step = 1;
+  while(!done){
+    if(debug){
+      std::cout << "doing step " << m_step << std::endl;
+      printcosts();
+      printmask();
+    }
+    switch(m_step){
+      case 1:
+        step_one();
+        break;
+      case 2:
+        step_two();
+        break;
+      case 3:
+        step_three();
+        break;
+      case 4:
+        step_four();
+        break;
+      case 5:
+        step_five();
+        break;
+      case 6:
+        step_six();
+        break;      
+      case 7:
+        done = true;
+        break;
+    }
+  }
+  if(debug) std::cout << "done running munkres algorithm: " << std::endl;
+  result_type result;
+  costvector.clear();
+
+  for(int row=0;row<m_dim;++row){
+    int col = find_in_row(row,kStar);
+    result.push_back(col);
+    costvector.push_back(m_costs_orig[row][result.back()]);
+  }
+
+  if(debug){
+    printcosts();
+    for(uint i=0;i<result.size();++i) std::cout << "row: " << i << " -> col: " << result[i] << " cost: " << m_costs_orig[i][result[i]]<< std::endl;
+  }
+  return result;
+}
+
+void munkres::step_one(){
+  //subtract row minimum from each row element
+  //then go to step 2
+  for(int row=0;row<m_dim;++row){
+    double min = m_costmatrix[row][0];
+    for(int col=0;col<m_dim;++col){ // find minimum
+      if(m_costmatrix[row][col] < min) min = m_costmatrix[row][col];
+    }
+    for(int col=0;col<m_dim;++col){ // subtract from all elements
+      m_costmatrix[row][col] -= min;
+    }
+  }
+  m_step = 2;
+}
+
+void munkres::step_two(){
+  //star a zero matrix element if there is no other zero in it column or row
+  //we will cover each row and column that have a zero so we know we don't have to 
+  //check these rows and columns anymore for zeros to star
+  //then go to step 3
+
+  for(int row=0;row<m_dim;++row){
+    for(int col=0;col<m_dim;++col){
+      if(!m_rowIsCovered[row] && !m_colIsCovered[col] && m_costmatrix[row][col] == 0){
+        m_rowIsCovered[row] = true;
+        m_colIsCovered[col] = true;
+        m_maskmatrix[row][col] = 1;
+      }
+    }
+  }
+  //reset cover vectors
+  for(int i=0;i<m_dim;++i){
+    m_rowIsCovered[i] = false;
+    m_colIsCovered[i] = false;    
+  }
+  m_step = 3;
+}
+
+void munkres::step_three(){
+  //cover each column with a starred zero
+  //if we have m_dim coered columns we're done and exit
+  //else we continue with step four
+
+  for(int row=0;row<m_dim;++row){
+    for(int col=0;col<m_dim;++col){
+      if(m_maskmatrix[row][col] == 1) m_colIsCovered[col] = true;   // this is a starred zero cover column
+    }
+  }
+
+  int nCoveredCols = 0;
+  for(int col=0;col<m_dim;++col) if(m_colIsCovered[col]) nCoveredCols++;
+  
+  m_step = (nCoveredCols == m_dim) ? 7 : 4;
+}
+
+void munkres::find_a_zero(int& row, int& col){
+  for(row=0;row<m_dim;++row){
+    for(col=0;col<m_dim;++col){
+      if(m_costmatrix[row][col] == 0 && !m_colIsCovered[col] && !m_rowIsCovered[row]) return;
+    }
+  }
+  //not returned until now set flags
+  row = -1;
+  col = -1;
+}
+
+int munkres::find_in_row(const int row, markertype what){
+  for(int col = 0;col<m_dim;++col) if(m_maskmatrix[row][col] == what) return col;
+  //not returned until now
+  return -1;
+}
+
+int munkres::find_in_col(const int col, markertype what){
+  for(int row = 0;row<m_dim;++row) if(m_maskmatrix[row][col] == what) return row;
+  //not returned until now
+  return -1;  
+}
+
+void munkres::step_four(){
+  // Find a noncovered zero and prime it.
+  // If there is no starred zero in the row containing this primed zero, Go to Step 5.
+  // Otherwise, cover this row and uncover the column containing the starred zero.
+  // Continue in this manner until there are no uncovered zeros left.
+  // Save the smallest uncovered value and Go to Step 6.
+
+  bool done = false;
+  while(!done){
+    int row, col;
+    find_a_zero(row,col);
+    if(row == -1){
+      //there is no uncovered zero go to step 6
+      done = true;
+      m_step = 6;
+    }
+    else{
+      // std::cout << "found uncovered zero at " << row << ", " << col << std::endl;
+      //check if there is a starred zero in this row
+      m_maskmatrix[row][col]=2;
+      int starred0atcol = find_in_row(row,kStar);
+      if(starred0atcol != -1){
+        m_rowIsCovered[row] = true;
+        m_colIsCovered[starred0atcol] = false;
+        // printcosts();
+        // printmask();
+      }else{
+        done = true;
+        m_step = 5;
+      }
+    }
+  }
+}
+
+void munkres::augment_path(const std::vector<coords>& p){
+  for(unsigned int i = 0;i<p.size();++i){
+    const int row = p[i].first;
+    const int col = p[i].second;
+    if(m_maskmatrix[row][col] == kStar){
+      m_maskmatrix[row][col] = 0; //unstar each star;
+    }
+    else{//primed zeros
+      m_maskmatrix[row][col] = kStar; //star each primed and unprime it;
+    }
+  }
+}
+
+void munkres::erase_primes_and_covers(){
+  for(int row=0;row<m_dim;++row){
+    m_rowIsCovered[row] = false;
+    m_colIsCovered[row] = false;//queadratic matrix
+    for(int col=0;col<m_dim;++col){
+      if(m_maskmatrix[row][col] == kPrime) m_maskmatrix[row][col] = 0;
+    }
+  }
+}
+
+void munkres::step_five(){
+  // Construct a series of alternating primed and starred zeros as follows.
+  // Let Z0 represent the uncovered primed zero found in Step 4.
+  // Let Z1 denote the starred zero in the column of Z0 (if any).
+  // Let Z2 denote the primed zero in the row of Z1 (there will always be one). 
+  // Continue until the series terminates at a primed zero that has no starred zero in its column.
+  // Unstar each starred zero of the series, star each primed zero of the series,
+  // erase all primes and uncover every line in the matrix.  Return to Step 3. 
+
+  bool done = false;
+  std::vector<coords> path;
+  int row,col;
+  find_a_zero(row,col);
+
+  path.push_back(coords(row,col));
+
+  int n = 0;
+  while(!done && n<4){n++;
+    int starred0atrow = find_in_col(path.back().second,kStar);
+    if(starred0atrow > -1){
+      path.push_back(coords(starred0atrow,path.back().second));
+    }
+    else{
+      done = true;
+    }
+    if(!done){
+      int primed0atcol = find_in_row(path.back().first,kPrime);
+      path.push_back(coords(path.back().first,primed0atcol));
+    }
+  }
+  // std::cout << "found path: " << std::endl;
+  // for(unsigned int i=0;i<path.size();++i){
+  //   std::cout << "(" << path[i].first << "," << path[i].second << ")" <<  ((i<path.size()-1) ? "->" : "" );
+  // } std::cout << std::endl;
+  
+  augment_path(path);
+  erase_primes_and_covers();
+  
+  m_step = 3;
+}
+
+double munkres::find_min_uncov(){
+  double min = 1e10;
+  for(int row=0;row<m_dim;++row){
+    for(int col=0;col<m_dim;++col){
+      if(!m_rowIsCovered[row] && !m_colIsCovered[col] && m_costmatrix[row][col] < min){
+        min = m_costmatrix[row][col];
+      }
+    }
+  }
+  return min;
+}
+
+void munkres::step_six(){
+  // Add the value found in Step 4 to every element of each covered row,
+  // and subtract it from every element of each uncovered column.
+  // Return to Step 4 without altering any stars, primes, or covered lines.
+  // Notice that this step uses the smallest uncovered value in the cost matrix to modify the matrix. 
+
+  double minuncov = find_min_uncov();
+  for(int row=0;row<m_dim;++row){
+    for(int col=0;col<m_dim;++col){
+      if(m_rowIsCovered[row])   m_costmatrix[row][col] += minuncov;
+      if(!m_colIsCovered[col])  m_costmatrix[row][col] -= minuncov;
+    }
+  }
+  m_step = 4;
+}
+
+void munkres::printmatrix(const matrix_type& m){
+  boost::io::ios_all_saver ias(std::cout);
+  std::cout << std::setw(5) << std::setprecision(3) << "cov|";
+  for(int col=0;col<m_dim;++col){
+    std::cout << std::setw(7) << std::setprecision(3) << (m_colIsCovered[col] ? "+|" : "|");
+  } std::cout << std::endl;
+
+  for(int row=0;row<m_dim;++row){
+    std::cout << std::setw(5) << std::setprecision(3) << (m_rowIsCovered[row] ? "+ |" : "|");
+    for(int col=0;col<m_dim;++col){
+      std::cout << std::setw(5) << std::setprecision(3) << m[row][col];
+      if(m_maskmatrix[row][col] == kPrime)  std::cout << "'";
+      if(m_maskmatrix[row][col] == kStar)   std::cout << "*";
+      else                                  std::cout << " ";
+      std::cout << "|";
+    } std::cout << std::endl;
+  }
+}
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.h b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.h
new file mode 100644
index 0000000000000000000000000000000000000000..d525f8984decbf23aa41d5aba1fdf8ba7effdfff
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/Root/munkres.h
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef MUNKRES_H
+#define MUNKRES_H
+
+#include <iostream>
+#include <vector>
+#include <iomanip>
+#include <map>
+
+// adapted for C++ from http://csclab.murraystate.edu/bob.pilgrim/445/munkres.html
+// standalone code at: https://github.com/lukasheinrich/munkres-cpp
+
+class munkres{
+public:
+  typedef std::vector<double> vec_type;
+  typedef std::vector<vec_type > matrix_type;
+  typedef std::pair<int,int> coords;
+  typedef std::vector<int> result_type;
+
+  enum markertype {kStar = 1, kPrime = 2};
+
+  munkres(matrix_type costs);
+  void printcosts(){printmatrix(m_costmatrix);}
+  result_type run(vec_type& costvector, bool debug = false);
+
+private:
+  void step_one();
+  void step_two();
+  void step_three();
+  void step_four();
+  void step_five();
+  void step_six();
+
+  void printmask() {printmatrix(m_maskmatrix);}
+  void printmatrix(const matrix_type&);
+
+  void    find_a_zero(int& row,int& col);
+  int     find_in_row(const int row, markertype what);
+  int     find_in_col(const int col, markertype what);
+  double  find_min_uncov();
+
+  void  augment_path(const std::vector<coords>& path);
+  void  erase_primes_and_covers();
+
+  matrix_type m_costmatrix;
+  matrix_type m_costs_orig;
+  matrix_type m_maskmatrix;
+  int m_step;
+
+  std::vector<bool>   m_rowIsCovered;
+  std::vector<bool>   m_colIsCovered;
+  const int m_dim;
+};
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IAssociationStrategy.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IAssociationStrategy.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a952a25765ecb65e8ed00cea5c5e3cde7aa168c
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IAssociationStrategy.h
@@ -0,0 +1,20 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_IASSOCIATIONSTRATEGY_H
+#define TRIGGERMATCHINGTOOL_IASSOCIATIONSTRATEGY_H
+
+#include <map>
+#include <vector>
+
+class IAssociationStrategy {
+public:
+  virtual ~IAssociationStrategy(){}
+  typedef std::map<unsigned int,unsigned int> index_assignment_t;
+  virtual index_assignment_t associate(const std::vector<std::vector<double> >& matrix) = 0;
+};
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IMatchingTool.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IMatchingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8c180a44e67961cbaba608ec248d6977ace75c8
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/IMatchingTool.h
@@ -0,0 +1,39 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef IMATCHINGTOOL_H
+#define IMATCHINGTOOL_H
+
+
+// Framework include(s):
+#include "AsgTools/IAsgTool.h"
+
+namespace xAOD{
+  class IParticle;
+}
+
+
+
+namespace Trig {
+
+class MatchingImplementation;
+
+class IMatchingTool : virtual public asg::IAsgTool {
+  ASG_TOOL_INTERFACE(IMatchingTool)
+public:
+
+  ///single object trigger matching. matchThreshold is typically the deltaR requirement to obtain positive matching
+  virtual bool match(const xAOD::IParticle& recoObject, const std::string& chain, double matchThreshold=0.1) = 0;
+  ///multi-object trigger matching
+  virtual bool match(const std::vector<const xAOD::IParticle*>& recoObjects, const std::string& chain, double matchThreshold=0.1) = 0;
+
+protected:
+  virtual MatchingImplementation* impl() = 0;
+};
+
+}
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingImplementation.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingImplementation.h
new file mode 100644
index 0000000000000000000000000000000000000000..e95bad4ea473a657d5eed4576fcf7a0929575bf3
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingImplementation.h
@@ -0,0 +1,48 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef TRIGGERMATCHINGTOOL_MATCHINGIMPLEMENTATION_H
+#define TRIGGERMATCHINGTOOL_MATCHINGIMPLEMENTATION_H
+
+#include <map>
+
+#include "TriggerMatchingTool/MatchingTool.h"
+#include "TriggerMatchingTool/IAssociationStrategy.h"
+#include "AsgTools/AsgMessaging.h"
+
+namespace Trig {
+
+
+class TrigDecisionTool;
+
+
+class MatchingTool;
+
+namespace MatchingStrategy {
+    enum Strategy {
+      MinimalSum = 0,
+      MaximalMatched = 1
+    };
+}
+
+
+class MatchingImplementation : public asg::AsgMessaging {
+public:
+  MatchingImplementation(MatchingTool& mt, double threshold=0.4);
+  Trig::TrigDecisionTool* tdt();
+  bool matchDistanceMatrix(const std::vector<std::vector<double> >& matrix, const Trig::MatchingStrategy::Strategy strategy = Trig::MatchingStrategy::MinimalSum);
+  inline void setThreshold(double in) { m_threshold=in; }
+private:
+  bool assocIsMatched(IAssociationStrategy::index_assignment_t association, const std::vector<std::vector<double> >& matrix);
+  MatchingTool& m_tool;
+  std::map<Trig::MatchingStrategy::Strategy,std::unique_ptr<IAssociationStrategy> > m_strategies;
+  double m_threshold; //the distance threshold for a match
+};
+
+}
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingTool.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3120c7fc7b27784f4a6b19e5e1e004762a0652a
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/MatchingTool.h
@@ -0,0 +1,64 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_MATCHINGTOOL_H
+#define TRIGGERMATCHINGTOOL_MATCHINGTOOL_H
+
+// Framework include(s):
+#include "AsgTools/AsgTool.h"
+#include "AsgTools/ToolHandle.h"
+
+#include "TriggerMatchingTool/IMatchingTool.h"
+#include "TriggerMatchingTool/TypeMap.h"
+#include "TriggerMatchingTool/IMatchingTool.h"
+#include "TrigDecisionTool/Combination.h"
+#include "TrigDecisionTool/TrigDecisionTool.h"
+
+namespace Trig {
+
+class MatchingTool : public asg::AsgTool, 
+		     virtual public Trig::IMatchingTool {
+  ASG_TOOL_CLASS(MatchingTool,IMatchingTool)
+
+public:
+  friend class MatchingImplementation;
+  MatchingTool(const std::string& name);
+  ~MatchingTool();
+  StatusCode initialize();
+
+  bool match(const std::vector<const xAOD::IParticle*>& recoObjects, const std::string& chain);
+  bool match(const std::vector<const xAOD::IParticle*>& recoObjects, const std::string& chain, double matchTreshold);
+  bool match(const xAOD::IParticle& recoObjects, const std::string& chain, double matchTreshold);
+
+protected:
+  MatchingImplementation* impl();
+
+  bool matchSingleType(const std::vector<const xAOD::IParticle*>& subRecoObjects, Trig::Combination& comb);
+
+  bool matchCombination(const std::vector<const xAOD::IParticle*>& recoObjects, Trig::Combination& comb);
+
+
+#ifndef XAOD_STANDALONE
+  void updateOutputLevel(Property& p);
+  void updateThreshold(Property& p);
+#endif
+
+private:
+
+  double IParticleMetric(const xAOD::IParticle* lhs, const xAOD::IParticle* rhs);
+  std::vector<std::vector<double> > distanceMatrix(const std::vector<const xAOD::IParticle*>& reco,
+						   const std::vector<const xAOD::IParticle*>& trigger);
+  
+  
+  MatchingImplementation* m_impl;  
+  TypeMap m_typeMap;
+  ToolHandle<Trig::TrigDecisionTool> m_trigDecTool;
+  double m_matchingThreshold;
+};
+
+}
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TriggerMatchingToolDict.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TriggerMatchingToolDict.h
new file mode 100644
index 0000000000000000000000000000000000000000..8df3475e9b06014fdbbfe2c03f464e192e25328a
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TriggerMatchingToolDict.h
@@ -0,0 +1,11 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#ifndef TRIGGERMATCHINGTOOL_TRIGGERMATCHINGTOOLDICT_H
+#define TRIGGERMATCHINGTOOL_TRIGGERMATCHINGTOOLDICT_H
+
+#include "TriggerMatchingTool/MatchingTool.h"
+
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TypeMap.h b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TypeMap.h
new file mode 100644
index 0000000000000000000000000000000000000000..d55a79043a60aac925c634ac1cf18ea9a9718950
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/TypeMap.h
@@ -0,0 +1,23 @@
+// Dear emacs, this is -*- c++ -*-
+
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_TYPEMAP_H
+#define TRIGGERMATCHINGTOOL_TYPEMAP_H
+
+#include "TrigNavStructure/Types.h"
+#include "xAODBase/IParticle.h"
+#include <map>
+
+class TypeMap {
+public:
+  typedef std::pair<HLT::class_id_type,std::string> clid_string_t;
+  TypeMap();
+  bool isKnown(const xAOD::Type::ObjectType& recoType);
+  clid_string_t get(const xAOD::Type::ObjectType& recoType);
+private:
+  std::map<xAOD::Type::ObjectType,clid_string_t> m_typemap;
+};
+#endif
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml
new file mode 100644
index 0000000000000000000000000000000000000000..255b7689e33dfb9453aebaa8600765757a4748ef
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/TriggerMatchingTool/selection.xml
@@ -0,0 +1,6 @@
+
+<lcgdict>
+   <namespace name="Trig" />
+   <class name="Trig::MatchingTool" />
+   <class name="Trig::IMatchingTool" />
+</lcgdict>
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/Makefile.RootCore b/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/Makefile.RootCore
new file mode 100644
index 0000000000000000000000000000000000000000..7400da22852ffae7d7ddaa663aa751bafef68d7c
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/Makefile.RootCore
@@ -0,0 +1,60 @@
+# this makefile also gets parsed by shell scripts
+# therefore it does not support full make syntax and features
+# edit with care
+
+# for full documentation check:
+# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile
+
+
+# the name of the package:
+PACKAGE              = TriggerMatchingTool
+
+# the libraries to link with this one:
+PACKAGE_PRELOAD      = 
+
+# additional compilation flags to pass (not propagated to dependent packages):
+PACKAGE_CXXFLAGS     = 
+
+# additional compilation flags to pass (propagated to dependent packages):
+PACKAGE_OBJFLAGS     = 
+
+# additional linker flags to pass (for compiling the library):
+PACKAGE_LDFLAGS      = 
+
+# additional linker flags to pass (for compiling binaries):
+PACKAGE_BINFLAGS     = 
+
+# additional linker flags to pass (propagated to client libraries):
+PACKAGE_LIBFLAGS     = 
+
+# the list of packages we depend on:
+PACKAGE_DEP          = AsgTools TrigDecisionTool xAODBase FourMomUtils
+
+# the list of packages we use if present, but that we can work without :
+PACKAGE_TRYDEP       = 
+
+# list pattern of scripts to link directly into binary path:
+PACKAGE_SCRIPTS      = 
+
+# whether to use pedantic compilation:
+PACKAGE_PEDANTIC     = 1
+
+# whether to turn *off* optimization (set to dict to do it only for
+# dictionaries):
+PACKAGE_NOOPT        = 0
+
+# whether to build no library (needs to be set if no source files are
+# present):
+PACKAGE_NOCC         = 0
+
+# whether we build a reflex dictionary:
+PACKAGE_REFLEX       = 1
+
+# the list of all unit tests that should be called in recursive testing,
+# i.e. in unit tests that call other unit tests
+# for that unit tests need to pass on all machines, and run very fast
+PACKAGE_RECURSIVE_UT = 
+
+
+
+include $(ROOTCOREDIR)/Makefile-common
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/requirements b/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/requirements
new file mode 100644
index 0000000000000000000000000000000000000000..40f7657aec6e44f6225b54d7099600a842191591
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/cmt/requirements
@@ -0,0 +1,35 @@
+package TriggerMatchingTool
+author Lukas Heinrich <lukas.heinrich@cern.ch>
+
+use  AtlasPolicy                AtlasPolicy-*
+
+
+public
+use  GaudiInterface             GaudiInterface-*                External
+use AsgTools		AsgTools-*		Control/AthToolSupport
+use TrigDecisionTool	TrigDecisionTool-*	Trigger/TrigAnalysis
+use TrigNavStructure	TrigNavStructure-*	Trigger/TrigEvent
+use xAODBase		xAODBase-*		Event/xAOD
+
+private
+use AtlasBoost          AtlasBoost-*            External
+use FourMomUtils        FourMomUtils-*          Event
+
+use AthAnalysisBaseComps AthAnalysisBaseComps-* Control
+
+#uncomment the next line to use ROOT libraries in your package
+#use AtlasROOT AtlasROOT-* External
+
+#use xAODEventInfo xAODEventInfo-* Event/xAOD
+
+end_private
+
+
+apply_pattern dual_use_library files="../Root/*.cxx ../src/*.cxx"
+
+#Reflex Dictionary Generation:
+private
+use AtlasReflex AtlasReflex-* External
+apply_pattern lcgdict dict=TriggerMatchingTool selectionfile=selection.xml headerfiles="../TriggerMatchingTool/TriggerMatchingToolDict.h"
+end_private
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/share/TestMatchingToolAlgJobOptions.py b/Trigger/TrigAnalysis/TriggerMatchingTool/share/TestMatchingToolAlgJobOptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..b207a969f500814604ad18b31c0124ab6265b3fe
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/share/TestMatchingToolAlgJobOptions.py
@@ -0,0 +1,18 @@
+#Skeleton joboption for a simple analysis job
+
+theApp.EvtMax=10                                         #says how many events to run over. Set to -1 for all events
+
+import AthenaPoolCnvSvc.ReadAthenaPool                   #sets up reading of POOL files (e.g. xAODs)
+inputfile = os.environ.get("ASG_TEST_FILE_MC", "/afs/cern.ch/user/a/asgbase/patspace/xAODs/r6630/mc15_13TeV.361106.PowhegPythia8EvtGen_AZNLOCTEQ6L1_Zee.recon.AOD.e3601_s2576_s2132_r6630_tid05358812_00/AOD.05358812._000010.pool.root.1")
+svcMgr.EventSelector.InputCollections=[inputfile]
+
+#optional: configure the matching tool
+ToolSvc += CfgMgr.Trig__MatchingTool("MyMatchingTool",OutputLevel=DEBUG)
+
+algseq = CfgMgr.AthSequencer("AthAlgSeq")                              #gets the main AthSequencer
+algseq += CfgMgr.TestMatchingToolAlg()                                 #adds an instance of your alg to it
+
+
+
+include("AthAnalysisBaseComps/SuppressLogging.py")              #Optional include to suppress as much athena output as possible. Keep at bottom of joboptions so that it doesn't suppress the logging of the things you have configured above
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/share/testAthenaMatchingTool.py b/Trigger/TrigAnalysis/TriggerMatchingTool/share/testAthenaMatchingTool.py
new file mode 100755
index 0000000000000000000000000000000000000000..e04ac1e7323aa5dd6ef2958d77a08d221f4c2b5c
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/share/testAthenaMatchingTool.py
@@ -0,0 +1,52 @@
+from AthenaCommon.AthenaCommonFlags import athenaCommonFlags
+from RecExConfig.RecFlags import rec
+from RecExConfig.RecAlgsFlags import recAlgs
+from InDetRecExample.InDetJobProperties import InDetFlags
+InDetFlags.doSecVertexFinder.set_Value_and_Lock(False)
+from AthenaCommon.AppMgr import ToolSvc
+
+
+athenaCommonFlags.FilesInput=["/afs/cern.ch/user/a/asgbase/patspace/xAODs/r6630/mc15_13TeV.361106.PowhegPythia8EvtGen_AZNLOCTEQ6L1_Zee.recon.AOD.e3601_s2576_s2132_r6630_tid05358812_00/AOD.05358812._000010.pool.root.1"]
+athenaCommonFlags.EvtMax=10
+#athenaCommonFlags.EvtMax=-1
+rec.readAOD=True
+# switch off detectors
+rec.doForwardDet=False
+rec.doInDet=False
+rec.doCalo=False
+rec.doMuon=False
+rec.doEgamma=False
+rec.doTrigger = True; recAlgs.doTrigger=False # disable trigger (maybe necessary if detectors switched off)
+rec.doMuon=False
+rec.doMuonCombined=False
+rec.doWriteAOD=False
+rec.doWriteESD=False
+rec.doDPD=False
+rec.doTruth=False
+
+
+# autoconfiguration might trigger undesired feature
+rec.doESD.set_Value_and_Lock(False) # uncomment if do not run ESD making algorithms
+rec.doWriteESD.set_Value_and_Lock(False) # uncomment if do not write ESD
+rec.doAOD.set_Value_and_Lock(False) # uncomment if do not run AOD making algorithms
+rec.doWriteAOD.set_Value_and_Lock(False) # uncomment if do not write AOD
+rec.doWriteTAG.set_Value_and_Lock(False) # uncomment if do not write TAG
+include ("RecExCommon/RecExCommon_topOptions.py")
+ToolSvc.TrigDecisionTool.TrigDecisionKey='xTrigDecision'
+from AthenaCommon.AlgSequence import AlgSequence
+from AthenaCommon.AppMgr import ToolSvc
+theJob = AlgSequence()
+ 
+ToolSvc += CfgMgr.Trig__MatchingTool("MyMatchingTool",OutputLevel=DEBUG)
+
+
+#algseq = CfgMgr.AthSequencer("AthAlgSeq")                              #gets the main AthSequencer
+#algseq += CfgMgr.TestMatchingToolAlg()                                 #adds an instance of your alg to it
+
+ 
+from TriggerMatchingTool.TriggerMatchingToolConf import TestMatchingToolAlg
+alg = TestMatchingToolAlg()
+theJob += alg
+ 
+include("TriggerTest/TriggerTestCommon.py")
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fad009e52b79980aebaae469deac9cf3276af953
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.cxx
@@ -0,0 +1,92 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "TestMatchingToolAlg.h"
+#include "xAODBase/IParticleContainer.h"
+
+StatusCode TestMatchingToolAlg::initialize() {
+  m_tmt.setTypeAndName("Trig::MatchingTool/MyMatchingTool");
+  CHECK(m_tmt.retrieve()); //important to retrieve here, because TrigDecisionTool must be initialized before event loop
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TestMatchingToolAlg::execute() {  
+
+  //For more documentation on the tool, see: https://twiki.cern.ch/twiki/bin/view/Atlas/XAODMatchingTool
+  //As of Feb 2016:
+  //Recommended threshold for egamma triggers: 0.07
+  //Recommended threshold for muon triggers: 0.1
+
+  //here's an example of using the tool
+  const xAOD::IParticleContainer* electrons = 0;
+  const xAOD::IParticleContainer *taus = 0;
+  const xAOD::IParticleContainer *muons = 0;
+  CHECK( evtStore()->retrieve( electrons, "Electrons" ));
+  CHECK( evtStore()->retrieve( muons, "Muons" ) );
+  CHECK( evtStore()->retrieve( taus, "TauJets" ) );
+  if(electrons) ATH_MSG_INFO("Offline Electron container size " << electrons->size());
+  if(muons) ATH_MSG_INFO("Offline Muon container size " << muons->size());
+  if(taus) ATH_MSG_INFO("Offline Tau container size " << taus->size());
+  //tool takes a vector of IParticles, and a trigger chain expression
+  //can also take a single IParticle for single object trigger matching
+  std::vector<const xAOD::IParticle*> myParticles;
+
+  //here's an example of a single object trigger
+  if (electrons) {
+    for(uint i = 0; i< electrons->size(); i++) {
+      myParticles.clear();
+      myParticles.push_back( electrons->at(i) );
+      ATH_MSG_INFO("HLT_e17_lhloose Matching Decision = " << m_tmt->match(myParticles,"HLT_e17_lhloose",0.07 /*explicit dR threhsold*/) );
+      
+      // here's an example of a combined trigger
+      // e-mu
+      if(muons){
+          for(uint j = 0; j < muons->size(); j++) {
+              myParticles.clear();
+              myParticles.push_back(electrons->at(i));
+              myParticles.push_back(muons->at(j));
+              ATH_MSG_INFO("HLT_e17_lhloose_mu14 = " << m_tmt->match(myParticles,"HLT_e17_lhloose_mu14"));
+          }
+      }
+      // e-tau
+      if(taus){
+        for(uint j = 0; j < taus->size(); j++) {
+          myParticles.clear();
+          myParticles.push_back(electrons->at(i));
+          myParticles.push_back(taus->at(j));
+          ATH_MSG_INFO("HLT_e17_lhmedium_iloose_tau25_medium1_tracktwo = " << m_tmt->match(myParticles,"HLT_e17_lhmedium_iloose_tau25_medium1_tracktwo"));
+        }
+      }
+    }
+  }
+
+  // here's an example for muon trigger, using the method for single-object trigger matching
+  if(muons){
+      for(auto muon : *muons) {
+          ATH_MSG_INFO("HLT_mu18 = " << m_tmt->match(*muon,"HLT_mu18"));
+      }
+  }
+  // here's an examplefor a tau trigger
+  if(taus){
+      for(uint j = 0; j < taus->size(); j++) {
+          myParticles.clear();
+          myParticles.push_back(taus->at(j));
+          ATH_MSG_INFO("HLT_tau25_loose1_ptonly = " << m_tmt->match(myParticles,"HLT_tau25_loose1_ptonly"));
+      }
+  }
+
+  //here's an example for a dilepton trigger
+  //form pairs to test a dilepton trigger
+  for(uint i = 0; i< electrons->size()-1; i++) {
+      for(uint j = i+1; j < electrons->size(); j++) {
+          myParticles.clear();
+          myParticles.push_back( electrons->at(i) );
+          myParticles.push_back( electrons->at(j) );
+          ATH_MSG_INFO("HLT_2e17_lhloose Matching Decision = " << m_tmt->match(myParticles,"HLT_2e17_lhloose") );
+      }
+  }
+
+  return StatusCode::SUCCESS;
+}
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.h b/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.h
new file mode 100644
index 0000000000000000000000000000000000000000..65066d4fc511145bece9922601daba39b13b2fcf
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/src/TestMatchingToolAlg.h
@@ -0,0 +1,26 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TRIGGERMATCHINGTOOL_TESTMATCHINGTOOLALG_H
+#define TRIGGERMATCHINGTOOL_TESTMATCHINGTOOLALG_H 1
+
+#include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h"
+
+#include "TriggerMatchingTool/IMatchingTool.h"
+
+class TestMatchingToolAlg: public ::AthAnalysisAlgorithm { 
+ public: 
+  TestMatchingToolAlg( const std::string& name, ISvcLocator* pSvcLocator ) : AthAnalysisAlgorithm( name, pSvcLocator ) {}
+  virtual ~TestMatchingToolAlg() {}
+
+  virtual StatusCode  initialize();
+  virtual StatusCode  execute();
+
+ private: 
+
+  ToolHandle<Trig::IMatchingTool> m_tmt;
+
+}; 
+
+#endif //> !TRIGGERMATCHINGTOOL_TESTMATCHINGTOOLALG_H
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4837306b21e33777a6ddfcc9bf874463bfcefa3c
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_entries.cxx
@@ -0,0 +1,16 @@
+#include "GaudiKernel/DeclareFactoryEntries.h"
+#include "TriggerMatchingTool/MatchingTool.h"
+
+DECLARE_NAMESPACE_TOOL_FACTORY( Trig, MatchingTool )
+
+
+
+#include "../TestMatchingToolAlg.h"
+DECLARE_ALGORITHM_FACTORY( TestMatchingToolAlg )
+
+
+
+DECLARE_FACTORY_ENTRIES( TriggerMatchingTool ) {
+  DECLARE_ALGORITHM( TestMatchingToolAlg );
+  DECLARE_NAMESPACE_TOOL(Trig, MatchingTool)
+}
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_load.cxx b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_load.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d82dcdb6a7a4645023019aea26becb6e0606c1e6
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/src/components/TriggerMatchingTool_load.cxx
@@ -0,0 +1,4 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES( TriggerMatchingTool )
+
diff --git a/Trigger/TrigAnalysis/TriggerMatchingTool/test/TriggerMatchingTool.xml b/Trigger/TrigAnalysis/TriggerMatchingTool/test/TriggerMatchingTool.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d903c919690a54bf59ea49528623afe60a31788b
--- /dev/null
+++ b/Trigger/TrigAnalysis/TriggerMatchingTool/test/TriggerMatchingTool.xml
@@ -0,0 +1,13 @@
+ <?xml version="1.0"?>
+<atn>
+   <TEST name="TestMatchingToolAlg" type="athena" suite="ASGTests">
+      <options_atn>TriggerMatchingTool/TestMatchingToolAlgJobOptions.py</options_atn>
+      <timelimit>5</timelimit>
+      <author> Lukas Heinrich </author>
+      <mailto> lukas.heinrich@cern.ch </mailto>
+      <expectations>
+         <errorMessage>FAILURE (ERROR)</errorMessage>
+         <returnValue>0</returnValue>
+      </expectations>
+   </TEST>
+</atn>