diff --git a/Reconstruction/tauRecTools/Root/LinkDef.h b/Reconstruction/tauRecTools/Root/LinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..f9fa452558b6689ef1035f603096f64ab7ab8510
--- /dev/null
+++ b/Reconstruction/tauRecTools/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/Reconstruction/tauRecTools/Root/TauBuilderTool.cxx b/Reconstruction/tauRecTools/Root/TauBuilderTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..239735e88a813f92568e64df768723f5ccd466e3
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauBuilderTool.cxx
@@ -0,0 +1,308 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "tauRecTools/TauBuilderTool.h"
+
+#include "xAODJet/Jet.h"
+#include "xAODJet/JetContainer.h"
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+#include "xAODTau/TauDefs.h"
+
+#include "tauRecTools/TauEventData.h"
+
+
+//________________________________________
+TauBuilderTool::TauBuilderTool(const std::string& type) :
+  asg::AsgTool(type),
+  m_tauContainerName("TauJets"),
+  m_tauAuxContainerName("TauJetsAux."),
+  m_seedContainerName(""),
+  m_maxEta(2.5),
+  m_minPt(10000),
+  m_doCreateTauContainers(false)
+{
+  declareProperty("TauContainer", m_tauContainerName);
+  declareProperty("TauAuxContainer", m_tauAuxContainerName);
+  declareProperty("SeedContainer", m_seedContainerName);
+  declareProperty("MaxEta", m_maxEta);
+  declareProperty("MinPt", m_minPt);
+  declareProperty("doCreateTauContainers", m_doCreateTauContainers);
+  declareProperty("Tools", m_tools, "List of ITauToolBase tools");
+}
+
+//________________________________________
+TauBuilderTool::~TauBuilderTool(){}
+
+//________________________________________
+StatusCode TauBuilderTool::initialize(){
+  StatusCode sc;
+
+  //ATH_MSG_INFO("FF::TauBuilder :: initialize()");
+
+  //-------------------------------------------------------------------------
+  // No tools allocated!
+  //-------------------------------------------------------------------------
+  if (m_tools.size() == 0) {
+    ATH_MSG_ERROR("no tools given!");
+    return StatusCode::FAILURE;
+  }
+
+  //-------------------------------------------------------------------------
+  // Allocate tools
+  //-------------------------------------------------------------------------
+  ToolHandleArray<ITauToolBase> ::iterator itT = m_tools.begin();
+  ToolHandleArray<ITauToolBase> ::iterator itTE = m_tools.end();
+  ATH_MSG_INFO("List of tools in execution sequence:");
+  ATH_MSG_INFO("------------------------------------");
+
+  unsigned int tool_count = 0;
+
+  for (; itT != itTE; ++itT) {
+    sc = itT->retrieve();
+    if (sc.isFailure()) {
+      ATH_MSG_WARNING("Cannot find tool named <" << *itT << ">");
+    } else {
+      ++tool_count;
+      //ATH_MSG_INFO((*itT)->type() << " - " << (*itT)->name());
+      ATH_MSG_INFO((*itT)->name());
+      //If you want to utlize TauCandidate In Tools, 
+      //decalre TauCandidate in your class, and pass its address
+      //to function below
+      (*itT)->setTauEventData(&m_data);
+    }
+  }
+  ATH_MSG_INFO(" ");
+  ATH_MSG_INFO("------------------------------------");
+
+  if (tool_count == 0) {
+    ATH_MSG_ERROR("could not allocate any tool!");
+    return StatusCode::FAILURE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauBuilderTool::execute(){
+
+  StatusCode sc;
+  m_data.clear();
+
+  xAOD::TauJetContainer * pContainer = 0;
+  xAOD::TauJetAuxContainer* pAuxContainer = 0;
+
+
+
+  if (m_doCreateTauContainers) {        
+    //-------------------------------------------------------------------------
+    // Create and Record containers
+    //-------------------------------------------------------------------------
+
+    pContainer = new xAOD::TauJetContainer();
+    sc = evtStore()->record( pContainer, m_tauContainerName ) ;
+    if (sc.isFailure()) {
+      ATH_MSG_ERROR("Unable to record TauContainer in TDS");
+      delete pContainer;
+      return StatusCode::FAILURE;
+    }
+
+    pAuxContainer = new xAOD::TauJetAuxContainer();
+    sc = evtStore()->record( pAuxContainer, m_tauAuxContainerName ) ;
+    if (sc.isFailure()) {
+      ATH_MSG_ERROR("Unable to record TauContainer in TDS");
+      delete pContainer;
+      return StatusCode::FAILURE;
+    }
+      
+    pContainer->setStore( pAuxContainer );
+    ATH_MSG_DEBUG( "Recorded xAOD tau jets with key: "
+		   << m_tauAuxContainerName );
+
+  } else {
+    //-------------------------------------------------------------------------
+    // retrieve Tau Containers from StoreGate
+    //-------------------------------------------------------------------------
+    sc = evtStore()->retrieve(pContainer, m_tauContainerName);
+    if (sc.isFailure()) {
+      ATH_MSG_FATAL("Failed to retrieve " << m_tauContainerName);
+      return StatusCode::FAILURE;
+    }
+
+    sc = evtStore()->retrieve(pAuxContainer, m_tauAuxContainerName);
+    if (sc.isFailure()) {
+      ATH_MSG_FATAL("Failed to retrieve " << m_tauAuxContainerName);
+      return StatusCode::FAILURE;
+    }
+
+  }
+
+  //not strictly necessary to set the containers
+  //but probably safer for tools to access
+  //the tau container via TauEventData than
+  //IParticle::container() (griffith)
+  m_data.xAODTauContainer = pContainer;
+  m_data.tauAuxContainer = pAuxContainer;
+
+  //-------------------------------------------------------------------------
+  // Initialize tools for this event
+  //-------------------------------------------------------------------------
+  ToolHandleArray<ITauToolBase> ::iterator itT = m_tools.begin();
+  ToolHandleArray<ITauToolBase> ::iterator itTE = m_tools.end();
+  for (; itT != itTE; ++itT) {
+    sc = (*itT)->eventInitialize();
+    if (sc != StatusCode::SUCCESS)
+      return StatusCode::FAILURE;
+  }
+
+  ////////////////////////////////////////////////////////
+
+    
+  //---------------------------------------------------------------------
+  // Retrieve seed Container from TDS, return `failure' if not
+  // existing
+  //---------------------------------------------------------------------
+  const xAOD::JetContainer * pSeedContainer;
+  sc = evtStore()->retrieve(pSeedContainer, m_seedContainerName);
+  // XXX still need to fix this. Currently only handle jets
+  // const DataHandle<INavigable4MomentumCollection> pSeedContainer;
+  // sc = evtStore()->retrieve(pSeedContainer, m_seedContainerName);
+  if (sc.isFailure() || !pSeedContainer) {
+    ATH_MSG_FATAL("No seed container with key:" << m_seedContainerName);
+    return StatusCode::FAILURE;
+  }
+
+  //probably not necessary, but in case a tool wants this in the future
+  //probably safer to retrieve via TauEventData than 
+  //*(pTau.jetLink())->container()
+  m_data.seedContainer = pSeedContainer;
+
+  //---------------------------------------------------------------------
+  // Loop over seeds
+  //---------------------------------------------------------------------
+  xAOD::JetContainer::const_iterator itS = pSeedContainer->begin();
+  xAOD::JetContainer::const_iterator itSE = pSeedContainer->end();
+  // XXX still need to fix this. Currently only handle jets
+  // INavigable4MomentumCollection::const_iterator itS = pSeedContainer->begin();
+  // INavigable4MomentumCollection::const_iterator itSE = pSeedContainer->end();
+
+  ATH_MSG_VERBOSE("Number of seeds in the container: " << pSeedContainer->size());
+
+  for (; itS != itSE; ++itS) {
+    const xAOD::Jet *pSeed = (*itS);
+    ATH_MSG_VERBOSE("Seeds eta:" << pSeed->eta() << ", pt:" << pSeed->pt());
+
+    if (fabs(pSeed->eta()) > m_maxEta) {
+      ATH_MSG_VERBOSE("--> Seed rejected, eta out of range!");
+      continue;
+    }
+
+    if (fabs(pSeed->pt()) < m_minPt) {
+      ATH_MSG_VERBOSE("--> Seed rejected, pt out of range!");
+      continue;
+    }
+
+    //-----------------------------------------------------------------
+    // Seed passed cuts --> create tau candidate
+    //-----------------------------------------------------------------
+    xAOD::TauJet* pTau = new xAOD::TauJet();
+    pContainer->push_back( pTau );
+    pTau->setJet(pSeedContainer, pSeed);
+
+    //-----------------------------------------------------------------
+    // Process the candidate
+    //-----------------------------------------------------------------
+    ToolHandleArray<ITauToolBase>::iterator itT = m_tools.begin();
+    ToolHandleArray<ITauToolBase>::iterator itTE = m_tools.end();
+
+    //-----------------------------------------------------------------
+    // Loop stops when Failure indicated by one of the tools
+    //-----------------------------------------------------------------
+    for (; itT != itTE; ++itT) {
+      ATH_MSG_VERBOSE("Invoking tool " << (*itT)->name());
+
+      sc = (*itT)->execute(*pTau);
+
+      if (sc.isFailure())
+	break;
+    }
+
+    if (sc.isSuccess()) {
+            
+         
+      ATH_MSG_VERBOSE("The tau candidate has been registered");
+
+      //-----------------------------------------------------------------
+      // Process the candidate using endTools
+      //-----------------------------------------------------------------
+      //keep this here for future use (in case more than one seeding algo exist)
+      /*
+	ToolHandleArray<ITauToolBase> ::iterator p_itET = m_endTools.begin();
+	ToolHandleArray<ITauToolBase> ::iterator p_itETE = m_endTools.end();
+	for (; p_itET != p_itETE; ++p_itET) {
+	ATH_MSG_VERBOSE("Invoking endTool " << (*p_itET)->name());
+	p_sc = (*p_itET)->execute(&m_data);
+	if (p_sc.isFailure())
+	break;
+	}
+      */
+      //////////////////////////////////////////////////////
+
+    } else if (!sc.isSuccess()) {
+      //TODO:cleanup of EndTools not necessary??
+      //keep this here for future use (in case more than one seeding algo exist)
+      /*
+	ToolHandleArray<ITauToolBase> ::iterator p_itT1 = m_tools.begin();
+	for (; p_itT1 != p_itT; ++p_itT1)
+	(*p_itT1)->cleanup(&m_data);
+	(*p_itT1)->cleanup(&m_data);
+      */
+      //m_data.xAODTauContainer->pop_back();
+      pContainer->pop_back();
+    } else
+      //m_data.xAODTauContainer->pop_back();
+      pContainer->pop_back();
+  }
+
+
+
+  //-------------------------------------------------------------------------
+  // Finalize tools for this event
+  //-------------------------------------------------------------------------
+
+  itT = m_tools.begin();
+  itTE = m_tools.end();
+  for (; itT != itTE; ++itT) {
+    sc = (*itT)->eventFinalize();
+    if (sc != StatusCode::SUCCESS)
+      return StatusCode::FAILURE;
+  }
+
+  //keep this here for future use (in case more than one seeding algo exist)
+  /*
+    p_itET = m_endTools.begin();
+    p_itETE = m_endTools.end();
+    for (; p_itET != p_itETE; ++p_itET) {
+    p_sc = (*p_itET)->eventFinalize(&m_data);
+    if (p_sc != StatusCode::SUCCESS)
+    return StatusCode::FAILURE;
+    }
+  */
+
+  ///////////////////////////////////////////////////////
+
+  // locking of containers is moved to separate tau tool
+
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauBuilderTool::finalize(){
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/tauRecTools/Root/TauCalibrateLC.cxx b/Reconstruction/tauRecTools/Root/TauCalibrateLC.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0ad9767fb2d1dcc7e3e649c586b87b612d37649f
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauCalibrateLC.cxx
@@ -0,0 +1,292 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//tau
+#include "tauRecTools/TauCalibrateLC.h"
+#include "xAODTau/TauJet.h"
+#include "tauRecTools/TauEventData.h"
+
+//compilation error if attempting to include CLHEP first
+//ASGTOOL_ATHENA defined here:
+//https://svnweb.cern.ch/trac/atlasoff/browser/Control/AthToolSupport/AsgTools/trunk/AsgTools/AsgToolsConf.h
+//included eventually from ITauToolBase
+#ifdef ASGTOOL_ATHENA
+#include "CLHEP/Vector/LorentzVector.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+using CLHEP::GeV;
+#else
+#define GeV 1000
+#endif
+
+// root
+#include "TFile.h"
+#include "TF1.h"
+#include "TH1D.h"
+
+/********************************************************************/
+TauCalibrateLC::TauCalibrateLC(const std::string& name) :
+TauRecToolBase(name),
+m_doEnergyCorr(false),
+m_doAxisCorr(false),
+m_printMissingContainerINFO(true),
+m_clusterCone(0.2)  //not used
+{
+    declareProperty("tauContainerKey", tauContainerKey = "TauJets");
+    declareProperty("calibrationFile", calibrationFile = "EnergyCalibrationLC2012.root");
+    declareProperty("vertexContainerKey", vertexContainerKey = "PrimaryVertices");
+    declareProperty("doEnergyCorrection", m_doEnergyCorr);
+    declareProperty("doAxisCorrection",    m_doAxisCorr);
+    declareProperty("ClusterCone", m_clusterCone); //not used
+}
+
+/********************************************************************/
+TauCalibrateLC::~TauCalibrateLC() {
+}
+
+/********************************************************************/
+StatusCode TauCalibrateLC::initialize() {
+
+    std::string fullPath = find_file(calibrationFile);
+
+    TFile * file = TFile::Open(fullPath.c_str(), "READ");
+
+    if (!file) {
+        ATH_MSG_FATAL("Failed to open " << fullPath);
+        return StatusCode::FAILURE;
+    }
+
+    // get the histogram defining eta binning
+    std::string key = "etaBinning";
+    TObject * obj = file->Get(key.c_str());
+    etaBinHist = NULL;
+    if (obj) {
+        etaBinHist = dynamic_cast<TH1 *> (obj);
+    }
+    if (etaBinHist) {
+        TH1 * tmp = const_cast<TH1*> (etaBinHist);
+        tmp->SetDirectory(0);
+    } else {
+        ATH_MSG_FATAL("Failed to get an object with  key " << key);
+        return StatusCode::FAILURE;
+    }
+
+    //retrieve number of eta bins from file
+    m_nEtaBins = etaBinHist->GetNbinsX(); //member var
+    if (m_nEtaBins==6)
+        ATH_MSG_INFO("using 2011 tau energy calibration");
+    else if (m_nEtaBins==5)
+        ATH_MSG_INFO("using 2012 tau energy calibration");
+    else {
+        ATH_MSG_FATAL("Wrong or broken tau energy calibration file");
+        return StatusCode::FAILURE;
+    }
+    
+    // get the histogram with eta corrections
+    key = "etaCorrection";
+    obj = file->Get(key.c_str());
+    etaCorrectionHist = NULL;
+    if (obj) {
+        etaCorrectionHist = dynamic_cast<TH1 *> (obj);
+    }
+    if (etaCorrectionHist) {
+        TH1 * tmp = const_cast<TH1*> (etaCorrectionHist);
+        tmp->SetDirectory(0);
+    } else {
+        ATH_MSG_FATAL("Failed to get an object with  key " << key);
+        return StatusCode::FAILURE;
+    }
+
+    TString tmpSlopKey[nProngBins] = {"slopeNPV1P", "slopeNPV3P"};
+    TString tmpFuncBase[nProngBins] = {"OneP_Eta_", "MultiP_Eta_"};
+
+    for (int i = 0; i < nProngBins; i++) {
+        obj = file->Get(tmpSlopKey[i]); // get pile-up slope histograms
+        slopeNPVHist[i] = NULL;
+        if (obj) {
+            slopeNPVHist[i] = dynamic_cast<TH1 *> (obj);
+        }
+        if (slopeNPVHist[i]) {
+            TH1 * tmp = const_cast<TH1*> (slopeNPVHist[i]);
+            tmp->SetDirectory(0);
+        } else {
+            ATH_MSG_FATAL("Failed to get an object with  key " << tmpSlopKey[i]);
+            return StatusCode::FAILURE;
+        }
+
+        for (int j = 0; j < m_nEtaBins; j++) {
+            TString key = tmpFuncBase[i];
+            key += j;
+            TObject * obj = file->Get(key);
+            calibFunc[i][j] = NULL;
+            if (obj) {
+                calibFunc[i][j] = dynamic_cast<TF1*> (obj);
+            }
+            if (calibFunc[i][j]) {
+              // The cast succeeded.
+            } else {
+                ATH_MSG_FATAL("Failed to get an object with  key " << key);
+                return StatusCode::FAILURE;
+            }
+        }
+    }
+    m_averageNPV = slopeNPVHist[0]->GetBinContent(0); // underflow is the average number of reconstructed primary vertices
+    m_minNTrackAtVertex = static_cast<unsigned int> (slopeNPVHist[0]->GetBinContent(slopeNPVHist[0]->GetNbinsX() + 1)); //overflow is the minimum number of tracks at vertex 
+
+    ATH_MSG_DEBUG("averageNPV                                 = " << m_averageNPV);
+    ATH_MSG_DEBUG("minimum number of tracks at primary vertex = " << m_minNTrackAtVertex);
+
+    file->Close();
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode TauCalibrateLC::execute(xAOD::TauJet& pTau) 
+{ 
+     
+    // energy calibration depends on number of tracks - 1p or Mp
+    int prongBin = 1; //Mp
+    if (pTau.nTracks() <= 1) prongBin = 0; //1p
+
+    // set tau energy scale 
+    if (m_doEnergyCorr) {
+
+        // get detector axis values
+	double eta = pTau.etaDetectorAxis();
+        double absEta = std::abs(eta);
+        int etaBin = etaBinHist->GetXaxis()->FindBin(absEta) - 1;
+        
+        if (etaBin>=m_nEtaBins) etaBin = m_nEtaBins-1; // correction from last bin should be applied on all taus outside stored eta range
+
+        // get primary vertex container
+        StatusCode sc;
+        const xAOD::VertexContainer * vxContainer = 0;
+
+        // for tau trigger
+        bool inTrigger = tauEventData()->inTrigger();
+
+	int nVertex = 0;
+        
+	// Only retrieve the container if we are not in trigger
+        if (sc.isFailure() || !inTrigger ) {
+	  // try standard 
+	  if (evtStore()->retrieve(vxContainer, vertexContainerKey).isFailure() || !vxContainer) {
+	    if (m_printMissingContainerINFO) {
+	      ATH_MSG_WARNING(vertexContainerKey << " container not found --> skip TauEnergyCalibrationLC (no further info) ");
+	      m_printMissingContainerINFO=false;
+	    }
+	    return StatusCode::SUCCESS;
+	  }
+	  
+	  // Calculate nVertex
+	  xAOD::VertexContainer::const_iterator vx_iter = vxContainer->begin();
+	  xAOD::VertexContainer::const_iterator vx_end = vxContainer->end();
+	  
+	  for (; vx_iter != vx_end; ++vx_iter) {
+            if ((*vx_iter)->nTrackParticles() >= m_minNTrackAtVertex)
+	      ++nVertex;
+	  }
+	  
+	  ATH_MSG_DEBUG("calculated nVertex " << nVertex );           
+
+	} else {
+
+	  StatusCode scMu = StatusCode::FAILURE;
+	  double muTemp = 0.0;
+
+	    if (tauEventData()->hasObject("AvgInteractions")) scMu = tauEventData()->getObject("AvgInteractions", muTemp);
+	    
+	    if(scMu.isSuccess()){
+	      ATH_MSG_DEBUG("AvgInteractions object in tau candidate = " << muTemp);
+	      nVertex = muTemp;
+	    } else {
+	      ATH_MSG_DEBUG("No AvgInteractions object in tau candidate - using default value");
+	      nVertex = m_averageNPV;
+	    }
+
+	}
+
+        // get detector axis energy
+        // was saved by TauAxisSetter
+        double energyLC = pTau.p4(xAOD::TauJetParameters::DetectorAxis).E() / GeV;            //was sumClusterVector.e() / GeV;
+	
+        if (energyLC <= 0) {
+            ATH_MSG_DEBUG("tau energy at LC scale is " << energyLC << "--> set energy=0.001");           
+            //TODO: we can not set tau energy to 0 due to bug in P4Helpers during deltaR calculation
+            //will set it to 0.001 MeV
+	    pTau.setP4(0.001, pTau.eta(), pTau.phi(), pTau.m());
+            return StatusCode::SUCCESS;
+        }
+
+        double slopeNPV = slopeNPVHist[prongBin]->GetBinContent(etaBin + 1);
+        double offset = slopeNPV * (nVertex - m_averageNPV);
+
+        // FF: March,2014
+        // no offset correction for trigger        
+        //if (inTrigger) offset = 0.;
+
+        if (energyLC - offset <= 0) {
+            ATH_MSG_DEBUG("after pile-up correction energy would be = " << energyLC - offset << " --> setting offset=0 now!");
+            offset = 0;
+        }
+
+        // apply offset correction
+        double energyPileupCorr = energyLC - offset;
+
+        double calibConst = 1.0;
+        if (energyPileupCorr > 0 and energyPileupCorr < 10000) // from 0 to 10 TeV
+        {
+            calibConst = calibFunc[prongBin][etaBin]->Eval(energyPileupCorr);
+
+            if (calibConst <= 0) {
+                ATH_MSG_DEBUG("calibration constant = " << calibConst);
+                ATH_MSG_DEBUG("prongBin             = " << prongBin);
+                ATH_MSG_DEBUG("etaBin               = " << etaBin);
+                ATH_MSG_DEBUG("energyPileupCorr     = " << energyPileupCorr);
+                ATH_MSG_DEBUG("energyLC             = " << energyLC);
+                calibConst = 1.0;
+            }
+        }
+
+        double energyFinal = energyPileupCorr / calibConst;
+
+	pTau.setP4(energyFinal * GeV / cosh( pTau.eta() ), pTau.eta(), pTau.phi(), pTau.m());
+
+	pTau.setP4(xAOD::TauJetParameters::TauEnergyScale, pTau.pt(), pTau.eta(), pTau.phi(), pTau.m());
+      
+ 	pTau.setDetail(xAOD::TauJetParameters::TESCalibConstant, static_cast<float>( calibConst ) );
+	pTau.setDetail(xAOD::TauJetParameters::TESOffset, static_cast<float>( offset * GeV ) );
+      
+        ATH_MSG_DEBUG("Energy at LC scale = " << energyLC << " pile-up offset " << offset << " calib. const. = " << calibConst << " final energy = " << energyFinal);
+    }
+    
+    // final tau axis
+    if (m_doAxisCorr) {
+
+        // get tau intermediate axis values
+        double eta = pTau.eta();
+        double absEta = std::abs(eta);
+        double etaCorr = eta;
+
+        if (absEta)
+            etaCorr = (eta / absEta)*(absEta - etaCorrectionHist->GetBinContent(etaCorrectionHist->GetXaxis()->FindBin(absEta)));
+
+        ATH_MSG_DEBUG("eta " << eta << "; corrected eta = " << etaCorr);
+
+	pTau.setP4( pTau.e() / cosh( etaCorr ), etaCorr, pTau.phi(), pTau.m());
+
+	pTau.setP4(xAOD::TauJetParameters::TauEtaCalib, pTau.pt(), pTau.eta(), pTau.phi(), pTau.m());
+     
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Finalize
+//-----------------------------------------------------------------------------
+
+StatusCode TauCalibrateLC::finalize() {
+    return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/Root/TauCommonCalcVars.cxx b/Reconstruction/tauRecTools/Root/TauCommonCalcVars.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..506e136fb346af6df83ec2d633e604eccfc6a13a
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauCommonCalcVars.cxx
@@ -0,0 +1,253 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauCommonCalcVars.cxx
+// package:     Reconstruction/tauRec
+// authors:     Stan Lai
+// date:        2008-05-18
+// 
+// This class calculates tau variables after core seed reconstruction           
+//
+// 17/03/2010: (AK) change to P4Helpers
+// 16/05/2011: (FF) fix if primaryVertexContainer==NULL (coverity 21734)
+//   Dez 2011: (FF) switch to full LC calibrated tau 4-vector for some variables
+//-----------------------------------------------------------------------------
+//TODO: rename
+
+//#include <GaudiKernel/IToolSvc.h>
+//#include <GaudiKernel/ListItem.h>
+
+#include "tauRecTools/TauEventData.h"
+
+#include "tauRecTools/TauCommonCalcVars.h"
+#include "tauRecTools/KineUtils.h"
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauCommonCalcVars::TauCommonCalcVars(const std::string &name) :
+TauRecToolBase(name) {
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauCommonCalcVars::~TauCommonCalcVars() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauCommonCalcVars::initialize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+
+StatusCode TauCommonCalcVars::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauCommonCalcVars::execute(xAOD::TauJet& pTau) {
+
+    /////////////////////////////////////////////////
+    // Calculate variables that are always valid   
+    ////////////////////////////////////////////////
+
+    // Leading track pT and et/pt(lead track)
+    if (pTau.nTracks() > 0) {
+      pTau.setDetail( xAOD::TauJetParameters::leadTrkPt, static_cast<float>( pTau.track(0)->pt() ) );
+      
+      float emscale_ptEM = 0;
+      float emscale_ptHad = 0;
+      
+      if ( !pTau.detail( xAOD::TauJetParameters::etEMAtEMScale, emscale_ptEM ) ) 
+	{
+	  ATH_MSG_DEBUG("retrieval of tau detail failed. stopping calculation of further variables");
+	  return StatusCode::SUCCESS;
+	}
+
+      if ( !pTau.detail( xAOD::TauJetParameters::etHadAtEMScale, emscale_ptHad ) )
+	{
+	  ATH_MSG_DEBUG("retrieval of tau detail failed. stopping calculation of further variables");
+	  return StatusCode::SUCCESS;
+	}
+      
+      //EM scale
+
+      pTau.setDetail( xAOD::TauJetParameters::etOverPtLeadTrk, static_cast<float>( (emscale_ptEM + emscale_ptHad) / pTau.track(0)->pt() ) );
+
+        //switch to LC energy scale
+        //pDetails->setEtOverPtLeadTrk(pDetails->LC_TES_precalib() / fabs(pTau.track(0)->pt()));
+    }
+
+    // XXX still need to decide whether we want to fill loose track variables anymore
+    // // Leading loose track pT and et/pt(lead loose track)
+    // if (pDetails->nLooseTrk() > 0) {
+    //     pDetails->setLeadLooseTrkPt(pDetails->looseTrk(0)->pt());
+    //     //EM scale
+    //     pDetails->setEtOverPtLeadLooseTrk((pDetails->seedCalo_etHadCalib() + pDetails->seedCalo_etEMCalib()) / fabs(pDetails->looseTrk(0)->pt()));
+    //     //LC scale
+    //     //pDetails->setEtOverPtLeadLooseTrk(pDetails->LC_TES_precalib() / fabs(pDetails->looseTrk(0)->pt()));
+    // }
+
+    // invariant mass of track system
+    if ((pTau.nTracks() + pTau.nWideTracks()) > 0) {
+
+        TLorentzVector sumOfTrackVector;
+	TLorentzVector tempTrackVector;
+
+        for (unsigned int i = 0; i != pTau.nTracks(); ++i)
+	  {
+	    tempTrackVector.SetPtEtaPhiM( pTau.track(i)->pt(),  pTau.track(i)->eta(),  pTau.track(i)->phi(),  pTau.track(i)->m());
+            sumOfTrackVector += tempTrackVector;
+	  }
+        for (unsigned int i = 0; i != pTau.nWideTracks(); ++i)
+	  {
+	    tempTrackVector.SetPtEtaPhiM( pTau.wideTrack(i)->pt(),  pTau.wideTrack(i)->eta(),  pTau.wideTrack(i)->phi(),  pTau.wideTrack(i)->m());
+            sumOfTrackVector += tempTrackVector;
+	  }
+
+	pTau.setDetail( xAOD::TauJetParameters::massTrkSys, static_cast<float>( sumOfTrackVector.M() ) );
+	float tempfloat = 0;
+	if ( pTau.detail( xAOD::TauJetParameters::massTrkSys, tempfloat ) )
+		ATH_MSG_VERBOSE("set massTrkSys " << tempfloat);
+    }
+
+    // width of track system squared (trkWidth2)
+    if (pTau.nTracks() > 1) {
+
+        double leadTrkPhi = pTau.track(0)->phi();
+        double leadTrkEta = pTau.track(0)->eta();
+
+        double ptSum = 0;
+        double sumWeightedDR = 0;
+        double sumWeightedDR2 = 0;
+
+        for (unsigned int i = 0; i != pTau.nTracks(); ++i) {
+
+	  double deltaR = Tau1P3PKineUtils::deltaR(leadTrkEta, leadTrkPhi, pTau.track(i)->eta(), pTau.track(i)->phi() );     
+
+	  ptSum += pTau.track(i)->pt();
+	  sumWeightedDR += deltaR * (pTau.track(i)->pt());
+	  sumWeightedDR2 += deltaR * deltaR * (pTau.track(i)->pt());
+        }
+
+        for (unsigned int i = 0; i != pTau.nWideTracks(); ++i) {
+
+	  double deltaR = Tau1P3PKineUtils::deltaR(leadTrkEta, leadTrkPhi, pTau.wideTrack(i)->eta(), pTau.wideTrack(i)->phi() );     
+	  
+	  ptSum += pTau.wideTrack(i)->pt();
+	  sumWeightedDR += deltaR * (pTau.wideTrack(i)->pt());
+	  sumWeightedDR2 += deltaR * deltaR * (pTau.wideTrack(i)->pt());
+        }
+
+        double trkWidth2 = sumWeightedDR2 / ptSum - sumWeightedDR * sumWeightedDR / ptSum / ptSum;
+
+        if (trkWidth2 > 0.) pTau.setDetail( xAOD::TauJetParameters::trkWidth2, static_cast<float>( trkWidth2 ) );
+        else pTau.setDetail( xAOD::TauJetParameters::trkWidth2, static_cast<float>( 0. ) );
+    }
+
+    // Calculation for seedCalo_trkAvgDist and seedCalo_trkRmsDist
+    
+    //FF: use now the 4-vector of the tau intermediate axis
+    //P4EEtaPhiM P4CaloSeed(1., pDetails->seedCalo_eta(), pDetails->seedCalo_phi(), 0.);
+
+    if ((pTau.nWideTracks() + pTau.nTracks()) > 0) {
+
+        double ptSum = 0;
+        double innerPtSum = 0;
+        double sumWeightedDR = 0;
+        double innerSumWeightedDR = 0;
+        double sumWeightedDR2 = 0;
+
+        for (unsigned int i = 0; i != pTau.nTracks(); ++i) {
+
+          double deltaR = Tau1P3PKineUtils::deltaR(pTau.eta(), pTau.phi(), pTau.track(i)->eta(), pTau.track(i)->phi() );     
+	
+	  ptSum += pTau.track(i)->pt();
+	  sumWeightedDR += deltaR * (pTau.track(i)->pt());
+	  sumWeightedDR2 += deltaR * deltaR * (pTau.track(i)->pt());
+
+	  //add calculation of innerTrkAvgDist
+	  innerPtSum += pTau.track(i)->pt();
+	  innerSumWeightedDR += deltaR * (pTau.track(i)->pt());
+        }
+
+        for (unsigned int i = 0; i != pTau.nWideTracks(); ++i) {
+
+          double deltaR = Tau1P3PKineUtils::deltaR(pTau.eta(), pTau.phi(), pTau.wideTrack(i)->eta(), pTau.wideTrack(i)->phi() );     
+          
+	  ptSum += pTau.wideTrack(i)->pt();
+	  sumWeightedDR += deltaR * (pTau.wideTrack(i)->pt());
+	  sumWeightedDR2 += deltaR * deltaR * (pTau.wideTrack(i)->pt());
+        }
+
+        if (ptSum > 0.0001) {
+	  // seedCalo_trkAvgDist
+	  pTau.setDetail( xAOD::TauJetParameters::trkAvgDist, static_cast<float>( sumWeightedDR / ptSum ) );
+
+	  float tempfloat;
+	  if ( pTau.detail( xAOD::TauJetParameters::trkAvgDist, tempfloat ) )
+	    ATH_MSG_VERBOSE("set seedCalo_trkAvgDist " << tempfloat );
+
+	  // seedCalo_trkRmsDist
+	  double trkRmsDist2 = sumWeightedDR2 / ptSum - sumWeightedDR * sumWeightedDR / ptSum / ptSum;
+	  if (trkRmsDist2 > 0) {
+	    pTau.setDetail( xAOD::TauJetParameters::trkRmsDist, static_cast<float>( sqrt(trkRmsDist2) ) );
+	  } else {
+	    pTau.setDetail( xAOD::TauJetParameters::trkRmsDist, static_cast<float>( 0. ) );
+	  }
+	  if ( pTau.detail( xAOD::TauJetParameters::trkRmsDist, tempfloat ) )
+	    ATH_MSG_VERBOSE("set seedCalo_trkRmsDist " << tempfloat );
+        }
+
+         if (ptSum > 0.0) {
+	   
+     	  // SumPtTrkFrac
+     	  pTau.setDetail( xAOD::TauJetParameters::SumPtTrkFrac, static_cast<float>( 1. - innerPtSum/ptSum ) );
+     	  // FIXME!!! put pileup correction here once availabe
+     	  // FIXME!!! for now set corrected version same as uncorrected
+     	  pTau.setDetail( xAOD::TauJetParameters::SumPtTrkFracCorrected, static_cast<float>( 1. - innerPtSum/ptSum ) );
+      
+       	 } else {
+
+	   pTau.setDetail( xAOD::TauJetParameters::SumPtTrkFrac, static_cast<float>( 0.0 ) );
+	   pTau.setDetail( xAOD::TauJetParameters::SumPtTrkFracCorrected, static_cast<float>( 0.0 ) );
+
+	 }
+
+	 if (ptSum > 0.00 && innerPtSum > 0.0) {
+	   
+	   ATH_MSG_DEBUG("innerSumWeightedDR = " << innerSumWeightedDR << " innerPtSum = " << innerPtSum << " ptSum = " << ptSum );
+	   
+     	   // InnerTrkAvgDist
+     	   pTau.setDetail( xAOD::TauJetParameters::innerTrkAvgDist, static_cast<float>( innerSumWeightedDR / innerPtSum ) );
+     	   // FIXME!!! put pileup correction here once availabe
+     	   // FIXME!!! for now set corrected version same as uncorrected
+     	   pTau.setDetail( xAOD::TauJetParameters::innerTrkAvgDistCorrected, static_cast<float>( innerSumWeightedDR / innerPtSum ) );
+	   
+	 } else {
+     	   pTau.setDetail( xAOD::TauJetParameters::innerTrkAvgDist, static_cast<float>( 0.0 ));
+     	   pTau.setDetail( xAOD::TauJetParameters::innerTrkAvgDistCorrected, static_cast<float>( 0.0 ));
+	 }
+
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+
diff --git a/Reconstruction/tauRecTools/Root/TauGenericPi0Cone.cxx b/Reconstruction/tauRecTools/Root/TauGenericPi0Cone.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..77f9cb398c823d5958956ff5b4564ac08356db17
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauGenericPi0Cone.cxx
@@ -0,0 +1,102 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauGenericPi0Cone.cxx
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-04
+//
+//
+//-----------------------------------------------------------------------------
+
+//#include <GaudiKernel/IToolSvc.h>
+//#include <GaudiKernel/ListItem.h>
+
+#include "FourMomUtils/P4Helpers.h"
+//#include "FourMom/P4EEtaPhiM.h"
+//#include "Particle/TrackParticle.h"
+
+#include "tauRecTools/TauEventData.h"
+//#include "tauEvent/TauCommonDetails.h"
+//#include "tauEvent/TauJetParameters.h"
+
+#include "tauRecTools/TauGenericPi0Cone.h"
+#include "tauRecTools/TauTrackFilterUtils.h"
+
+#include "TLorentzVector.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauGenericPi0Cone::TauGenericPi0Cone(const std::string &name) :
+TauRecToolBase(name) {
+}
+
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauGenericPi0Cone::~TauGenericPi0Cone() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauGenericPi0Cone::initialize() {
+    ATH_MSG_VERBOSE("TauGenericPi0Cone Initialising");
+
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+
+StatusCode TauGenericPi0Cone::finalize() {
+    ATH_MSG_VERBOSE("TauGenericPi0Cone Finalizing");
+
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauGenericPi0Cone::execute(xAOD::TauJet& pTau) {
+    ATH_MSG_VERBOSE("TauGenericPi0Cone Executing");
+
+    TLorentzVector tau;
+    tau.SetPtEtaPhiE(pTau.pt()/1000, //GeV
+                     pTau.eta(),
+                     pTau.phi(),
+                     pTau.e()/1000); //GeV
+
+    int nProng = pTau.trackFilterProngs();
+    int flag = pTau.trackFilterQuality();
+    float pi0angle = 0.; //TODO sane default value
+
+    // Get pi0 cone
+    if(flag != 0){
+        int recProng = 0;
+        if((nProng == 3)||(nProng == 2)) recProng = 3;
+        if(nProng == 1) recProng = 1;
+        pi0angle = TauTrackFilterUtils::ComputePi0Cone(recProng,tau);
+     }
+
+    // Convert to dR.
+    m_pi0conedr = std::min(pi0angle*cosh(tau.Eta()), 0.2);
+
+    // Store result
+    pTau.setPi0ConeDR(m_pi0conedr);
+
+    return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/tauRecTools/Root/TauIDPileupCorrection.cxx b/Reconstruction/tauRecTools/Root/TauIDPileupCorrection.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5e4251b4b8cc141aed872e13639eb0b8a2ea68eb
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauIDPileupCorrection.cxx
@@ -0,0 +1,252 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//#include "CLHEP/Vector/LorentzVector.h"
+//#include "CLHEP/Units/SystemOfUnits.h"
+
+// root
+#include "TFile.h"
+#include "TObject.h"
+#include "TCollection.h"
+#include "TF1.h"
+#include "TH1D.h"
+#include "TKey.h"
+
+//tau
+#include "xAODTau/TauJet.h"
+#include "tauRecTools/TauEventData.h"
+#include "tauRecTools/TauIDPileupCorrection.h"
+
+#include "xAODEventInfo/EventInfo.h"
+
+//using CLHEP::GeV;
+
+/********************************************************************/
+TauIDPileupCorrection::TauIDPileupCorrection(const std::string& name) :
+TauRecToolBase(name)
+{
+    declareProperty("averageEstimator", m_averageEstimator=20.);
+    declareProperty("minNTrack", m_minNTrackAtVertex=2);
+
+    declareProperty("tauContainerKey", m_tauContainerKey = "TauJets");
+    declareProperty("calibrationFile1Prong", m_file1P = "fitted.pileup_1prong_hlt.root");
+    declareProperty("calibrationFile3Prong", m_file3P = "fitted.pileup_multiprongs_hlt.root");
+    declareProperty("vertexContainerKey", m_vertexContainerKey = "PrimaryVertices");
+    declareProperty("useMu", m_useMu = false);
+}
+
+/********************************************************************/
+TauIDPileupCorrection::~TauIDPileupCorrection() {
+}
+
+/********************************************************************/
+StatusCode TauIDPileupCorrection::initialize() {
+
+
+  // Open the 1P and 3P files
+  std::string fullPath = find_file(m_file1P);
+  TFile * file1P = TFile::Open(fullPath.c_str(), "READ");
+  
+  if (!file1P) {
+    ATH_MSG_FATAL("Failed to open " << fullPath);
+    return StatusCode::FAILURE;
+  }
+  
+  // Loop over file contents
+  TIter keyIterator1P(file1P->GetListOfKeys());
+  
+  while ( TObject *myObject = keyIterator1P() )
+    {
+      TKey* myKey = (TKey*)myObject;
+      
+      ATH_MSG_DEBUG("Found a key of type: " << myKey->GetClassName());
+      
+      if(std::string(myKey->GetClassName()) == "TF1")
+	{
+	  ATH_MSG_DEBUG("Key is a TF1: " << myKey->GetName());
+	  // Copy the function to local map
+	  m_calibFunctions1P[myKey->GetName()] = *((TF1*)file1P->Get(myKey->GetName()));
+	}
+    }
+  
+  file1P->Close();
+  
+  fullPath = find_file(m_file3P);
+  TFile * file3P = TFile::Open(fullPath.c_str(), "READ");  
+
+  TIter keyIterator3P(file3P->GetListOfKeys());
+  
+  while ( TObject *myObject = keyIterator3P() )
+    {
+      TKey* myKey = (TKey*)myObject;
+      
+      ATH_MSG_DEBUG("Found a key of type: " << myKey->GetClassName());
+      
+      if(std::string(myKey->GetClassName()) == "TF1")
+	{
+	  ATH_MSG_DEBUG("Key is a TF1: " << myKey->GetName());
+	  // Copy the function to local map
+	  m_calibFunctions3P[myKey->GetName()] = *((TF1*)file3P->Get(myKey->GetName()));
+	}
+    }
+
+  file3P->Close();
+
+  ATH_MSG_DEBUG("Found " << m_calibFunctions1P.size() << " variables to correct in 1P");
+  ATH_MSG_DEBUG("Found " << m_calibFunctions3P.size() << " variables to correct in 3P");
+
+  // Here comes the ugly part: define the equivalency of details and strings
+  m_conversion.push_back(TauConversion("tau_centFrac_fit", xAOD::TauJetParameters::centFrac, xAOD::TauJetParameters::centFracCorrected));
+  m_conversion.push_back(TauConversion("tau_massTrkSys_fit", xAOD::TauJetParameters::massTrkSys, xAOD::TauJetParameters::massTrkSysCorrected));
+  m_conversion.push_back(TauConversion("tau_EMPOverTrkSysP_fit", xAOD::TauJetParameters::EMPOverTrkSysP, xAOD::TauJetParameters::EMPOverTrkSysPCorrected));
+  m_conversion.push_back(TauConversion("tau_InnerTrkAvgDist_fit", xAOD::TauJetParameters::innerTrkAvgDist, xAOD::TauJetParameters::innerTrkAvgDistCorrected));
+  m_conversion.push_back(TauConversion("tau_SumPtTrkFrac_fit", xAOD::TauJetParameters::SumPtTrkFrac, xAOD::TauJetParameters::SumPtTrkFracCorrected));
+  m_conversion.push_back(TauConversion("tau_etOverPtLeadTrk_fit", xAOD::TauJetParameters::etOverPtLeadTrk, xAOD::TauJetParameters::etOverPtLeadTrkCorrected));
+  m_conversion.push_back(TauConversion("tau_approx_ptRatio_fit", xAOD::TauJetParameters::ptRatioEflowApprox, xAOD::TauJetParameters::ptRatioEflowApproxCorrected));
+  m_conversion.push_back(TauConversion("tau_approx_vistau_m_fit", xAOD::TauJetParameters::mEflowApprox, xAOD::TauJetParameters::mEflowApproxCorrected));
+  m_conversion.push_back(TauConversion("tau_ChPiEMEOverCaloEME_fit", xAOD::TauJetParameters::ChPiEMEOverCaloEME, xAOD::TauJetParameters::ChPiEMEOverCaloEMECorrected));
+  m_conversion.push_back(TauConversion("tau_trFlightPathSig_fit", xAOD::TauJetParameters::trFlightPathSig, xAOD::TauJetParameters::trFlightPathSigCorrected));
+  m_conversion.push_back(TauConversion("tau_dRmax_fit", xAOD::TauJetParameters::dRmax, xAOD::TauJetParameters::dRmaxCorrected));
+  m_conversion.push_back(TauConversion("tau_AbsipSigLeadTrk_BS_fit", xAOD::TauJetParameters::ipSigLeadTrk, xAOD::TauJetParameters::ipSigLeadTrkCorrected));
+  m_conversion.push_back(TauConversion("tau_ipSigLeadTrk_fit", xAOD::TauJetParameters::ipSigLeadTrk, xAOD::TauJetParameters::ipSigLeadTrkCorrected));
+  
+  return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode TauIDPileupCorrection::execute(xAOD::TauJet& pTau) 
+{ 
+    // get detector axis values
+    //double eta = pTau.etaDetectorAxis();
+    //double absEta = std::abs(eta);
+
+    // get primary vertex container
+    StatusCode sc;
+    const xAOD::VertexContainer * vxContainer = 0;
+    
+    // for tau trigger
+    bool inTrigger = tauEventData()->inTrigger();
+   
+    // check if we were asked to use mu instead of nVertex from the container
+    //TODO read the input root file to decide if we should use mu
+    bool useMu = m_useMu;
+
+    double nVertex = 0;
+    
+    // Only retrieve the container if we are not in trigger
+    if ((sc.isFailure() || !inTrigger) && !useMu) {
+      // try standard 
+      if (evtStore()->retrieve(vxContainer, m_vertexContainerKey).isFailure() || !vxContainer) {
+	if (m_printMissingContainerINFO) {
+	  ATH_MSG_WARNING(m_vertexContainerKey << " container not found --> skip TauEnergyCalibrationLC (no further info) ");
+	  m_printMissingContainerINFO=false;
+	}
+	return StatusCode::SUCCESS;
+      }
+    
+      // Calculate nVertex
+      xAOD::VertexContainer::const_iterator vx_iter = vxContainer->begin();
+      xAOD::VertexContainer::const_iterator vx_end = vxContainer->end();
+      
+      for (; vx_iter != vx_end; ++vx_iter) {
+	if ((*vx_iter)->nTrackParticles() >= m_minNTrackAtVertex)
+	  ++nVertex;
+      }
+    
+      ATH_MSG_DEBUG("calculated nVertex " << nVertex );           
+    
+    } else {
+
+      StatusCode scMu = StatusCode::FAILURE;
+      double muTemp = 0.0;
+      
+      if (tauEventData()->hasObject("AvgInteractions")) scMu = tauEventData()->getObject("AvgInteractions", muTemp);
+      else if (!inTrigger) {
+        // Get mu from EventInfo
+        const xAOD::EventInfo *eventInfo;
+        StatusCode scEI = StatusCode::FAILURE;
+        scEI = evtStore()->retrieve(eventInfo, "EventInfo");
+        if (scEI.isFailure() || !eventInfo) {
+          ATH_MSG_ERROR("Could not retrieve EventInfo");
+          return StatusCode::FAILURE;
+        }
+        muTemp = eventInfo->averageInteractionsPerCrossing();
+      }
+      
+      if(scMu.isSuccess()){
+	ATH_MSG_DEBUG("AvgInteractions object in tau candidate = " << muTemp);
+      } else {
+	ATH_MSG_DEBUG("No AvgInteractions object in tau candidate or averageInteractionsPerCrossing in EventInfo");
+      }
+    
+      nVertex = muTemp;
+    }
+    
+
+    // Possibly get a new averageEstimator
+    // TODO read averageEstimator from the root file
+    double averageEstimator = m_averageEstimator;
+
+    // Start corrections
+    for(unsigned int i=0; i<m_conversion.size(); i++)
+      {
+	
+	ATH_MSG_DEBUG("Attempting to correct variable " << m_conversion[i].detailName);
+	float correction = 0;
+
+	if(pTau.nTracks() <= 1)
+	  {
+	    // No calibration function available
+	    if(m_calibFunctions1P.count(m_conversion[i].detailName) < 1)
+	      continue;
+	    
+	    ATH_MSG_DEBUG("Variable correction function found");
+	    
+	    // Calculate correction
+	    correction = m_calibFunctions1P[m_conversion[i].detailName].Eval(nVertex) - m_calibFunctions1P[m_conversion[i].detailName].Eval(averageEstimator);
+	  }
+
+	if(pTau.nTracks() > 1)
+	  {
+	    // No calibration function available
+	    if(m_calibFunctions3P.count(m_conversion[i].detailName) < 1)
+	      continue;
+	    
+	    ATH_MSG_DEBUG("Variable correction function found");
+	    
+	    // Calculate correction
+	    correction = m_calibFunctions3P[m_conversion[i].detailName].Eval(nVertex) - m_calibFunctions3P[m_conversion[i].detailName].Eval(averageEstimator);
+	  }
+	
+	
+	ATH_MSG_DEBUG("Correction is: " << correction);
+	ATH_MSG_DEBUG("For Pile-up Estimator: " << nVertex);
+	
+	// Retrieve current value and set corrected value
+	float uncorrectedValue;
+	pTau.detail(m_conversion[i].detailUncorr, uncorrectedValue);
+
+	float correctedValue;
+	if (m_conversion[i].detailName == "tau_AbsipSigLeadTrk_BS_fit"
+	    || m_conversion[i].detailName == "tau_ipSigLeadTrk_fit")
+	  correctedValue = fabs(uncorrectedValue) - correction;
+	else 
+	  correctedValue = uncorrectedValue - correction;
+	
+	pTau.setDetail(m_conversion[i].detailCorr, correctedValue);
+	
+	ATH_MSG_DEBUG("Old value is: " << uncorrectedValue);
+	ATH_MSG_DEBUG("New value is: " << correctedValue);
+      }
+    
+    return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Finalize
+//-----------------------------------------------------------------------------
+
+StatusCode TauIDPileupCorrection::finalize() {
+    return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/Root/TauProcessorTool.cxx b/Reconstruction/tauRecTools/Root/TauProcessorTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..969dd75d70ae47ce047362ddbcef0fee2687649a
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauProcessorTool.cxx
@@ -0,0 +1,268 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "tauRecTools/TauProcessorTool.h"
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTracking/VertexContainer.h"
+#include "xAODTracking/VertexAuxContainer.h"
+#include "xAODPFlow/PFOContainer.h"
+#include "xAODPFlow/PFOAuxContainer.h"
+
+
+//________________________________________
+TauProcessorTool::TauProcessorTool(const std::string& type) :
+  asg::AsgTool(type),
+  m_tauContainerName("TauJets"),
+  m_tauAuxContainerName("TauJetsAux."),
+  m_AODmode(false)
+{
+  declareProperty("TauContainer", m_tauContainerName);
+  declareProperty("TauAuxContainer", m_tauAuxContainerName);
+  declareProperty("Tools", m_tools, "List of ITauToolBase tools");
+  declareProperty("runOnAOD", m_AODmode); //AODS are input file
+  declareProperty("deepCopyChargedPFOContainer", m_deep_copy_chargedPFOContainer=true);
+  declareProperty("deepCopyHadronicPFOContainer", m_deep_copy_hadronicPFOContainer=true);
+  declareProperty("deepCopyNeutralPFOContainer", m_deep_copy_neutralPFOContainer=true);
+  declareProperty("deepCopySecVtxContainer", m_deep_copy_SecVtxContainer=true);  
+}
+
+//________________________________________
+TauProcessorTool::~TauProcessorTool(){}
+
+//________________________________________
+StatusCode TauProcessorTool::initialize(){
+
+
+  //ATH_MSG_INFO("FF::TauProcessor :: initialize()");
+
+  //-------------------------------------------------------------------------
+  // No tools allocated!
+  //-------------------------------------------------------------------------
+  if (m_tools.size() == 0) {
+    ATH_MSG_ERROR("no tools given!");
+    return StatusCode::FAILURE;
+  }
+
+  StatusCode sc;
+    
+  //-------------------------------------------------------------------------
+  // Allocate tools
+  //-------------------------------------------------------------------------
+  ToolHandleArray<ITauToolBase> ::iterator itT = m_tools.begin();
+  ToolHandleArray<ITauToolBase> ::iterator itTE = m_tools.end();
+  ATH_MSG_INFO("List of tools in execution sequence:");
+  ATH_MSG_INFO("------------------------------------");
+
+  unsigned int tool_count = 0;
+
+  for (; itT != itTE; ++itT) {
+    sc = itT->retrieve();
+    if (sc.isFailure()) {
+      ATH_MSG_WARNING("Cannot find tool named <" << *itT << ">");
+    } else {
+      ++tool_count;
+      ATH_MSG_INFO((*itT)->name());
+      //If you want to utlize TauCandidate In Tools, 
+      //decalre TauCandidate in your class, and pass its address
+      //to function below
+      (*itT)->setTauEventData(&m_data);
+    }
+  }
+  ATH_MSG_INFO(" ");
+  ATH_MSG_INFO("------------------------------------");
+
+  if (tool_count == 0) {
+    ATH_MSG_ERROR("could not allocate any tool!");
+    return StatusCode::FAILURE;
+  }
+
+  ///////////////////////////////////////////////////////////////////////////
+
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauProcessorTool::execute(){
+  
+  StatusCode sc;
+  m_data.clear();
+
+  if(m_AODmode){
+    //-------------------------------------------------------------------------
+    // In AODMode, deep copy all PFOs BEFORE reading in tau
+    //-------------------------------------------------------------------------
+    if(m_deep_copy_SecVtxContainer){
+      xAOD::VertexContainer* pSecVtxContainer(0);
+      xAOD::VertexAuxContainer* pSecVtxAuxContainer(0);
+      xAOD::Vertex* v(0);
+      ATH_CHECK(deepCopy(pSecVtxContainer, pSecVtxAuxContainer, v, "TauSecondaryVertices"));
+    }
+
+    if(m_deep_copy_neutralPFOContainer){
+      xAOD::PFOContainer* neutralPFOContainer(0);
+      xAOD::PFOAuxContainer* neutralPFOAuxStore(0);
+      xAOD::PFO* p(0);
+      //container name hard-coded, but configurable in tool where objects are created in core reco
+      ATH_CHECK(deepCopy(neutralPFOContainer, neutralPFOAuxStore, p, "TauNeutralParticleFlowObjects"));
+    }
+
+    if(m_deep_copy_hadronicPFOContainer){
+      xAOD::PFOContainer* hadronicPFOContainer(0);
+      xAOD::PFOAuxContainer* hadronicPFOAuxStore(0);
+      xAOD::PFO* p(0);
+      //container name hard-coded, but configurable in tool where objects are created in core reco
+      ATH_CHECK(deepCopy(hadronicPFOContainer, hadronicPFOAuxStore, p, "TauHadronicParticleFlowObjects"));
+    }
+
+    if(m_deep_copy_chargedPFOContainer){
+      xAOD::PFOContainer* chargedPFOContainer(0);
+      xAOD::PFOAuxContainer* chargedPFOAuxStore(0);
+      xAOD::PFO* p(0);
+      //container name hard-coded, but configurable in tool where objects are created in core reco
+      ATH_CHECK(deepCopy(chargedPFOContainer, chargedPFOAuxStore, p, "TauChargedParticleFlowObjects"));
+    }
+    //-------------------------------------------------------------------------
+    // End pre-tau reading operations
+    //-------------------------------------------------------------------------
+  }
+
+
+  const xAOD::TauJetContainer*     pContainerOriginal(0);
+  const xAOD::TauJetAuxContainer*     pAuxContainerOriginal(0);
+
+  //-------------------------------------------------------------------------
+  // retrieve Tau Containers from StoreGate
+  //-------------------------------------------------------------------------
+  sc = evtStore()->retrieve(pContainerOriginal, m_tauContainerName);
+  if (sc.isFailure()) {
+    if (m_AODmode) {
+      // don't exit Athena if there is no Tau Container in (D)AODs when running in AOD mode
+      // just exit TauProcessor
+      // reason: somebody might use slimmed (D)AODs, where not needed containers are not present
+      ATH_MSG_WARNING("Failed to retrieve " << m_tauContainerName << "! Will exit TauProcessor now!!");
+      return StatusCode::SUCCESS;
+    }
+    else {
+      ATH_MSG_FATAL("Failed to retrieve " << m_tauContainerName);
+      return StatusCode::FAILURE;
+    }
+  } 
+
+  sc = evtStore()->retrieve(pAuxContainerOriginal, m_tauAuxContainerName);
+  if (sc.isFailure()) {
+    if (m_AODmode) {
+      // don't exit Athena if there is no Tau AuxContainer in (D)AODs when running in AOD mode
+      // just exit TauProcessor
+      // reason: somebody might use slimmed (D)AODs, where not needed containers are not present
+      ATH_MSG_WARNING("Failed to retrieve " << m_tauAuxContainerName << "! Will exit TauProcessor now!!");
+      return StatusCode::SUCCESS;
+    }
+    else {
+      ATH_MSG_FATAL("Failed to retrieve " << m_tauAuxContainerName);
+      return StatusCode::FAILURE;
+    }
+  } 
+
+  xAOD::TauJetContainer* pContainer = const_cast<xAOD::TauJetContainer*> (pContainerOriginal);
+  xAOD::TauJetAuxContainer* pAuxContainer = const_cast<xAOD::TauJetAuxContainer*> (pAuxContainerOriginal);
+
+  if(m_AODmode){
+    pContainer=0;
+    pAuxContainer=0;
+    xAOD::TauJet* tau(0);
+    ATH_CHECK(deepCopy(pContainer, pAuxContainer, tau, m_tauContainerName, m_tauAuxContainerName));
+  }
+
+  m_data.xAODTauContainer = pContainer;
+  m_data.tauAuxContainer = pAuxContainer;
+
+  //-------------------------------------------------------------------------
+  // Initialize tools for this event
+  //-------------------------------------------------------------------------
+  ToolHandleArray<ITauToolBase> ::iterator itT = m_tools.begin();
+  ToolHandleArray<ITauToolBase> ::iterator itTE = m_tools.end();
+  for (; itT != itTE; ++itT) {
+    sc = (*itT)->eventInitialize();
+    if (sc != StatusCode::SUCCESS)
+      return StatusCode::FAILURE;
+  }
+
+  ////////////////////////////////////////////////////////
+
+  //loop over taus
+  xAOD::TauJetContainer::iterator tau_it  = pContainer->begin();
+  xAOD::TauJetContainer::iterator tau_end = pContainer->end();
+    
+  for(; tau_it != tau_end; ++tau_it) {
+        
+    //-----------------------------------------------------------------
+    // set tau candidate data for easy handling
+    //-----------------------------------------------------------------
+
+    //-----------------------------------------------------------------
+    // Process the candidate
+    //-----------------------------------------------------------------
+    ToolHandleArray<ITauToolBase>::iterator itT = m_tools.begin();
+    ToolHandleArray<ITauToolBase>::iterator itTE = m_tools.end();
+
+    //-----------------------------------------------------------------
+    // Loop stops when Failure indicated by one of the tools
+    //-----------------------------------------------------------------
+    for (; itT != itTE; ++itT) {
+      ATH_MSG_VERBOSE("Invoking tool " << (*itT)->name());
+
+      sc = (*itT)->execute(**tau_it);
+
+      if (sc.isFailure())
+	break;
+    }
+
+    if (sc.isSuccess()) {
+          
+      ATH_MSG_VERBOSE("The tau candidate has been modified");
+
+    } else if (!sc.isSuccess()) {
+      //TODO:cleanup of EndTools not necessary??
+      //keep this here for future use (in case more than one seeding algo exist)
+      /*
+	ToolHandleArray<ITauToolBase> ::iterator p_itT1 = m_tools.begin();
+	for (; p_itT1 != p_itT; ++p_itT1)
+	(*p_itT1)->cleanup(&m_data);
+	(*p_itT1)->cleanup(&m_data);
+      */
+      //delete m_data.tau;
+    } else  {
+      //delete m_data.tau;
+    }
+  }
+
+
+
+  //-------------------------------------------------------------------------
+  // Finalize tools for this event
+  //-------------------------------------------------------------------------
+
+  itT = m_tools.begin();
+  itTE = m_tools.end();
+  for (; itT != itTE; ++itT) {
+    sc = (*itT)->eventFinalize();
+    if (sc != StatusCode::SUCCESS)
+      return StatusCode::FAILURE;
+  }
+
+
+  ///////////////////////////////////////////////////////
+  // locking of containers is moved to separate tau tool
+ 
+
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauProcessorTool::finalize(){
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/tauRecTools/Root/TauRecToolBase.cxx b/Reconstruction/tauRecTools/Root/TauRecToolBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a7f834cb1f237e18bf1112cd879c2a7cda98dca6
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauRecToolBase.cxx
@@ -0,0 +1,58 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "PathResolver/PathResolver.h"
+
+
+
+TauEventData defaultTauEventData;
+
+//________________________________________
+std::string TauRecToolBase::find_file(const std::string& fname) const {
+  static const std::string m_tauRecToolsTag="tauRecTools/00-00-00/";
+  std::string full_path = PathResolverFindCalibFile(m_tauRecToolsTag+fname);
+  if(full_path=="") full_path = PathResolverFindCalibFile(fname);
+  return full_path;
+}
+
+//________________________________________
+void TauRecToolBase::setTauEventData(TauEventData* data){
+  m_data=data;
+  if(m_data==0) {
+    m_data=&defaultTauEventData;
+    m_data->clear();
+  }
+}
+
+//________________________________________
+TauRecToolBase::TauRecToolBase(const std::string& name) :
+  asg::AsgTool(name) {
+
+}
+
+//________________________________________
+StatusCode TauRecToolBase::initialize(){
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauRecToolBase::eventInitialize(){
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauRecToolBase::execute(xAOD::TauJet&){
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauRecToolBase::eventFinalize(){
+  return StatusCode::SUCCESS;
+}
+
+//________________________________________
+StatusCode TauRecToolBase::finalize(){
+  return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/Root/TauTrackFilter.cxx b/Reconstruction/tauRecTools/Root/TauTrackFilter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..938f9566e7f013408450db4d56236c5acb56b176
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauTrackFilter.cxx
@@ -0,0 +1,352 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauTrackFilter.cxx
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-04
+//
+//
+//-----------------------------------------------------------------------------
+
+//#include <GaudiKernel/IToolSvc.h>
+//#include <GaudiKernel/ListItem.h>
+
+#include "FourMomUtils/P4Helpers.h"
+//#include "FourMom/P4EEtaPhiM.h"
+
+#include "tauRecTools/TauEventData.h"
+
+#include "tauRecTools/TauTrackFilter.h"
+#include "tauRecTools/TauTrackFilterUtils.h"
+
+#include "xAODTracking/TrackParticleContainer.h"
+
+#include "TLorentzVector.h"
+
+void TrackFilterAlg(TLorentzVector tau,
+                    std::vector<TLorentzVector>* inputtracks20,
+                    std::vector<int>* inputtracks20charge,
+                    std::vector<TLorentzVector>* inputtracks40,
+                    std::vector<int>* inputtracks40charge,
+                    std::vector<TLorentzVector>* outputtracksgood,
+                    std::vector<int>* outputtracksgoodcharge,
+                    std::vector<TLorentzVector>* outputtracksbad,
+                    std::vector<int>* outputtracksbadcharge,
+                    int& nProng,
+                    int& flag);
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauTrackFilter::TauTrackFilter(const std::string &name ) :
+TauRecToolBase(name) {
+    declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles");
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauTrackFilter::~TauTrackFilter() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauTrackFilter::initialize() {
+    ATH_MSG_VERBOSE("TauTrackFilter Initialising");
+
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+
+StatusCode TauTrackFilter::finalize() {
+    ATH_MSG_VERBOSE("TauTrackFilter Finalizing");
+
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauTrackFilter::execute(xAOD::TauJet& pTau) {
+    ATH_MSG_VERBOSE("TauTrackFilter Executing");
+
+    StatusCode sc;
+
+    const xAOD::TrackParticleContainer *trackContainer;
+
+    //TODO: trigger uses getObject
+    sc = evtStore()->retrieve(trackContainer, m_trackContainerName);
+    if (sc.isFailure() || !trackContainer) {
+        ATH_MSG_DEBUG(" No track container found in TDS !!");
+        return StatusCode::SUCCESS;
+    }
+
+    TLorentzVector tau;
+    tau.SetPtEtaPhiE(pTau.pt()/1000, //GeV
+                     pTau.eta(),
+                     pTau.phi(),
+                     pTau.e()/1000); //GeV
+
+    std::vector<TLorentzVector>* inputtracks20 = new std::vector<TLorentzVector>;
+    std::vector<TLorentzVector>* inputtracks40 = new std::vector<TLorentzVector>;
+    std::vector<int>* inputtracks20charge = new std::vector<int>;
+    std::vector<int>* inputtracks40charge = new std::vector<int>;
+    std::vector<TLorentzVector>* outputtracksgood = new std::vector<TLorentzVector>;
+    std::vector<TLorentzVector>* outputtracksbad = new std::vector<TLorentzVector>;
+    std::vector<int>* outputtracksgoodcharge = new std::vector<int>;
+    std::vector<int>* outputtracksbadcharge = new std::vector<int>;
+    int nProng = 0;
+    int flag = 0;
+
+    std::vector<unsigned int> inputtracks20index;
+    std::vector<unsigned int> inputtracks40index;
+
+    m_TrkPass.clear();
+
+    for(unsigned int j=0; j<pTau.nTracks(); j++ ) {
+        const xAOD::TrackParticle *TauJetTrack = pTau.track(j);
+        TLorentzVector inputTrack;
+        inputTrack.SetPtEtaPhiE(TauJetTrack->pt()/1000, //GeV
+                                TauJetTrack->eta(),
+                                TauJetTrack->phi(),
+                                TauJetTrack->e()/1000); //GeV
+        float dR = tau.DeltaR(inputTrack);
+        if (dR < 0.2) {
+            inputtracks20->push_back(inputTrack);
+            inputtracks20charge->push_back(TauJetTrack->charge());
+            inputtracks20index.push_back(j);
+        }
+        else if (dR < 0.4) {
+            inputtracks40->push_back(inputTrack);
+            inputtracks40charge->push_back(TauJetTrack->charge());
+            inputtracks40index.push_back(j);
+        }
+
+        // Add default status to track pass/fail member.
+        m_TrkPass.push_back(false);
+    }
+
+    // Run the main algorithm
+    TrackFilterAlg(tau,
+                   inputtracks20,
+                   inputtracks20charge,
+                   inputtracks40,
+                   inputtracks40charge,
+                   outputtracksgood,
+                   outputtracksgoodcharge,
+                   outputtracksbad,
+                   outputtracksbadcharge,
+                   nProng,
+                   flag);
+
+    // Store results
+    for (unsigned int j=0; j<outputtracksgood->size(); j++ ) {
+        for (unsigned int k=0; k<inputtracks20->size(); k++ ) {
+            if (outputtracksgood->at(j) == inputtracks20->at(k)) {
+                m_TrkPass.at(inputtracks20index.at(k)) = true;
+            }
+        }
+        for (unsigned int k=0; k<inputtracks40->size(); k++ ) {
+            if (outputtracksgood->at(j) == inputtracks40->at(k)) {
+                m_TrkPass.at(inputtracks40index.at(k)) = true;
+            }
+        }
+    }
+    m_nProng = nProng;
+    m_flag = flag;
+
+    // Cleanup
+    delete inputtracks20;
+    delete inputtracks20charge;
+    delete inputtracks40;
+    delete inputtracks40charge;
+    delete outputtracksgood;
+    delete outputtracksbad;
+    delete outputtracksgoodcharge;
+    delete outputtracksbadcharge;
+
+    // Set values in EDM
+    for (unsigned int numTrack=0; numTrack<m_TrkPass.size(); numTrack++) {
+      pTau.setTrackFlag(pTau.track(numTrack), xAOD::TauJetParameters::failTrackFilter, !m_TrkPass.at(numTrack));
+    }
+    pTau.setTrackFilterProngs(m_nProng);
+    pTau.setTrackFilterQuality(m_flag);
+
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Main algorithm
+//-----------------------------------------------------------------------------
+void TrackFilterAlg(TLorentzVector tau,
+                    std::vector<TLorentzVector>* inputtracks20,
+                    std::vector<int>* inputtracks20charge,
+                    std::vector<TLorentzVector>* inputtracks40,
+                    std::vector<int>* inputtracks40charge,
+                    std::vector<TLorentzVector>* outputtracksgood,
+                    std::vector<int>* outputtracksgoodcharge,
+                    std::vector<TLorentzVector>* outputtracksbad,
+                    std::vector<int>* outputtracksbadcharge,
+                    int& nProng,
+                    int& flag) {
+
+   std::vector<TauTrackFilterUtils::TrackInfo> unsorted,tracks,SScombination;
+   TauTrackFilterUtils::TrackInfo track;
+   unsigned int tracknum = inputtracks20->size();
+   unsigned int widetracknum = inputtracks40->size();
+   for(unsigned int i=0;i<tracknum;i++){
+      track.p4 = (*inputtracks20)[i];
+      track.charge = (*inputtracks20charge)[i];
+      unsorted.push_back(track);
+   }
+   while (unsorted.size() > 0){
+      float trackP = unsorted[0].p4.P();
+      int index = 0;
+      for(unsigned int i=1;i<unsorted.size();i++){
+         if(unsorted[i].p4.P() > trackP){
+            index = i;
+            trackP = unsorted[i].p4.P();
+         }
+      }
+      tracks.push_back(unsorted[index]);
+      tracks[tracks.size()-1].index = tracks.size()-1;
+      unsorted.erase(unsorted.begin()+index);            
+   }
+//Step 2: Test 3 Prong Hypothesis
+//Step 2a: Arrange combinations of tracks for testing
+   
+   bool test3prong = true, test2prong = true, test1prong = true;
+   for(unsigned int i=0;i<widetracknum;i++){
+   	outputtracksbad->push_back((*inputtracks40)[i]);
+   	outputtracksbadcharge->push_back((*inputtracks40charge)[i]);
+   }
+   if(tracknum > 4){ //Anything with more than 4 tracks is a fake.
+      flag = 0;
+      test3prong = false;
+      test2prong = false;
+      test1prong = false;
+   }
+   if(tracknum < 3) test3prong = false; //Don't test 3 prong if fewer than 3 tracks
+   if(tracknum < 2) test2prong = false; //Don't test 2 prong if fewer than 2 tracks
+   if(tracknum < 1){
+      flag = 0;
+      test1prong = false; //Don't test 1 prong if no tracks within dR < 0.2 of tau
+   }
+   if(test3prong){
+		//Test 3 Highest pT Tracks
+      bool isSS = false;
+      std::vector<TauTrackFilterUtils::TrackInfo> combination;
+      int charge = 0; TLorentzVector threetrack;
+      for(unsigned int i=0;i<3;i++){
+      	combination.push_back(tracks[i]); //Only Care about 3 Highest pT Tracks
+         charge+=tracks[i].charge;
+         threetrack+=tracks[i].p4;
+      }
+      if((tracknum == 3) && (abs(charge)!=1)) isSS = true; //Reject all same-sign combinations
+//Step 2b: Check kinematics of track combinations against shrinking cones and mass boundaries
+//         for(unsigned int i=0;i<combinations.size();i++){
+		bool goodcombo = false;
+		if(tracknum == 4){
+      	char eqn[] = "pol2";
+   		float a[] = {1.51673, -0.000150534, 2.64226e-06};
+			float mass99 = TauTrackFilterUtils::Compute1dim(tau.P(),a,3,eqn);
+			if((threetrack.M() < mass99)&&(TauTrackFilterUtils::pass3prong(combination,tau))){
+				goodcombo=true;
+				flag = 2;
+			}
+         else flag = 0;
+         test1prong=false;
+         test2prong=false;
+		}
+      else if(TauTrackFilterUtils::pass3prong(combination, tau)){
+         goodcombo=true;
+         flag = 1;
+      }
+      if(goodcombo){  //A Combination is found which passes 3prong hypothesis
+         for(unsigned int i=0;i<combination.size();i++){
+            if (isSS) SScombination.push_back(combination[i]);
+            outputtracksgood->push_back(combination[i].p4);
+            outputtracksgoodcharge->push_back(combination[i].charge);
+         }
+         if(isSS) flag = 0;
+         else flag = 1;
+         nProng = 3;
+         test1prong = false;
+         test2prong = false;
+         if(!test1prong){ //Fill Bad Track in the Case of 4 trk taus
+            if(tracknum == 4){
+            	outputtracksbad->push_back(tracks[3].p4);
+            	outputtracksbadcharge->push_back(tracks[3].charge);
+            }
+         }
+      }
+   }//End 3 Prong Test Conditional
+   if (test2prong){
+      std::vector<TauTrackFilterUtils::TrackInfo> pair;
+      for(unsigned int i=0;i<2;i++) pair.push_back(tracks[i]);
+      if(TauTrackFilterUtils::pass2prong(pair,tau)){
+      	nProng = 2;
+         for(unsigned int i=0;i<pair.size();i++){ //Fill Good Tracks
+            outputtracksgood->push_back(pair[i].p4);
+            outputtracksgoodcharge->push_back(pair[i].charge);
+         }
+         test1prong = false;
+         if(tracknum == 3){
+            flag = 2;
+         	outputtracksbad->push_back(tracks[2].p4); //Fill Bad Track in Case of 3 trk Taus
+         	outputtracksbadcharge->push_back(tracks[2].charge);
+         }
+         else flag = 1; //Good 2 Prong if only 2 trks
+      }
+   }//End 2 Prong Test Conditional
+//Step 4: Check tracks that don't pass 2 prong hypothesis against 1 prong hypothesis
+     if (test1prong){
+         char eqn[] = "([0]*exp([1]*x))*pol6(2)+[9]";
+         float a[10];
+         a[0] = 0.079586;
+         a[1] = -0.0289929;
+         a[2] = 7.06684;
+         a[3] = -0.158835;
+         a[4] = 0.000607181;
+         a[5] = 6.8445e-05;
+         a[6] = -6.79205e-07;
+         a[7] = 2.13158e-09;
+         a[8] = -5.11643e-13;
+         a[9] = 0.030376;
+         float ratio10 = TauTrackFilterUtils::Compute1dim(tau.P(),a,10,eqn);
+         bool goodcase = false;
+         if(tracknum == 1) goodcase = true;
+         if(tracknum == 2){
+            if(tracks[1].p4.Pt()/tracks[0].p4.Pt() < ratio10) goodcase = true; //Test 2trk taus most likely to actually be 1pngs
+         }
+         if((TauTrackFilterUtils::pass1prong(tracks[0].p4,tau))&&(goodcase)){ //A track is found which passes 1prong hypothesis
+            outputtracksgood->push_back(tracks[0].p4);
+            outputtracksgoodcharge->push_back(tracks[0].charge);
+            nProng = 1;
+            if (tracknum == 2){
+               flag = 2;
+            	outputtracksbad->push_back(tracks[1].p4); //Fill Bad Track in Case of 3 trk Taus
+            	outputtracksbadcharge->push_back(tracks[1].charge);
+            }
+            else flag = 1;
+         }
+         else flag = 0; //Fake Tau
+     }//End 1 Prong Test Conditional
+
+     return;
+}
+
diff --git a/Reconstruction/tauRecTools/Root/TauTrackFilterUtils.cxx b/Reconstruction/tauRecTools/Root/TauTrackFilterUtils.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4c05a1ada32c13a1a3f508f743a7bfe860b19db0
--- /dev/null
+++ b/Reconstruction/tauRecTools/Root/TauTrackFilterUtils.cxx
@@ -0,0 +1,264 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauTrackFilterUtils.cxx
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-13
+//
+//
+//-----------------------------------------------------------------------------
+
+#include "TF1.h"
+#include "TLorentzVector.h"
+#include "tauRecTools/TauTrackFilterUtils.h"
+#include <vector>
+#include <iostream>
+#include <string>
+
+using namespace TauTrackFilterUtils;
+
+bool TauTrackFilterUtils::pass3prong(std::vector<TauTrackFilterUtils::TrackInfo> combination,TLorentzVector tau){
+
+   //Step 1: calculate angles
+   TauTrackFilterUtils::TrackPair lp, lm, sp, ls, ms, mp;
+   
+   lm.angle = fabs(combination[0].p4.Angle(combination[1].p4.Vect()));
+   lm.mass = (combination[0].p4+combination[1].p4).M();
+   lm.charge = combination[0].charge*combination[1].charge;
+   ls.angle = fabs(combination[0].p4.Angle(combination[2].p4.Vect()));
+   ls.mass = (combination[0].p4+combination[2].p4).M();
+   ls.charge = combination[0].charge*combination[2].charge;
+   ms.angle = fabs(combination[1].p4.Angle(combination[2].p4.Vect()));
+   ms.mass = (combination[1].p4+combination[2].p4).M();
+   ms.charge = combination[1].charge*combination[2].charge;
+
+	lp = lm;
+	if(ls.angle > lp.angle){
+		mp = lp;
+		lp = ls;
+	}
+	else mp = ls;
+	if(ms.angle > lp.angle){
+		sp = mp;
+		mp = lp;
+		lp = ms;
+	}   
+	else if(ms.angle > mp.angle){
+		sp = mp;
+		mp = ms;
+	}
+	else sp = ms;
+
+   //if (lp.angle < mp.angle) ATH_MSG_WARNING("Largest angle is smaller than medium angle!");
+   //if (lp.angle < sp.angle) ATH_MSG_WARNING("Largest angle is smaller than smallest angle!");
+   //if (mp.angle < sp.angle) ATH_MSG_WARNING("Medium angle is smaller than smallest angle!");
+   
+   //Step 3: calculate 99% angles
+   float lp99 = 0, sp99 = 0, lm99 = 0, ls99 = 0;
+   float p = tau.P(), eta = fabs(tau.Eta());
+   
+   float a[9][4];
+   int npar = 4, npol = 3;
+
+a[0][0] = 0.179041; a[1][0] = -0.0531058; a[2][0] = 0; 
+a[0][1] = -0.0146875; a[1][1] = 0.00414247; a[2][1] = -0.000612045; 
+a[0][2] = 0.0188939; a[1][2] = -0.00452375; a[2][2] = 0.00120015; 
+a[0][3] = 58.3066; a[1][3] = -48.2594; a[2][3] = 26.8864; 
+   lp99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.0741985; a[1][0] = -0.0181941; a[2][0] = 0; 
+a[0][1] = -0.0149252; a[1][1] = 0.00512965; a[2][1] = -0.00125462; 
+a[0][2] = 0.00802004; a[1][2] = -0.00252272; a[2][2] = 0.000761022; 
+a[0][3] = 25.0145; a[1][3] = 0; a[2][3] = 0; 
+   sp99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.102084; a[1][0] = -0.0256446; a[2][0] = 0; 
+a[0][1] = -0.014259; a[1][1] = 0.00465467; a[2][1] = -0.00122856; 
+a[0][2] = 0.010552; a[1][2] = -0.00176856; a[2][2] = 0.000446776; 
+a[0][3] = 36.0848; a[1][3] = -16.1489; a[2][3] = 10.2994; 
+   lm99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.152783; a[1][0] = -0.0390978; a[2][0] = 0; 
+a[0][1] = -0.0139914; a[1][1] = 0.00352551; a[2][1] = -0.000624039; 
+a[0][2] = 0.0159925; a[1][2] = -0.00332104; a[2][2] = 0.00100568; 
+a[0][3] = 43.5804; a[1][3] = -18.681; a[2][3] = 6.29988; 
+   ls99 = ComputeAngle(p,eta,a,npar,npol);
+	   
+   //Step 4: compare angles and track masses, pass if all pass, fail otherwise
+   if((lp.angle > lp99)||(sp.angle > sp99)||(lm.angle > lm99)||(ls.angle > ls99)) return false; //One or more of the angles has failed - not a three prong tau
+   return true; //Track combination is a 3prong candidate!
+} //End pass3prong (efficiency studies)
+
+bool TauTrackFilterUtils::pass2prong(std::vector<TauTrackFilterUtils::TrackInfo> pair,TLorentzVector tau){
+   float angle = fabs(pair[0].p4.Angle(pair[1].p4.Vect()));
+   int  charge = pair[0].charge*pair[1].charge;
+
+   // Used to have more vars, but some were unused.
+   //float lt99 = 0, mt99 = 0, st99 = 0, ct99 = 0, lp99 = 0, mp99 = 0, sp99 = 0, los99 = 0, sos99 = 0, ss99 = 0, lm99 = 0, ls99 = 0, ms99 = 0;
+   float lp99 = 0, mp99 = 0, sp99 = 0, los99 = 0, sos99 = 0, ss99 = 0, lm99 = 0;
+   float p = tau.P(), eta = fabs(tau.Eta());
+   
+   float a[9][4];
+   int npar = 4, npol = 9;
+
+   a[0][0] = 0.0584232; a[1][0] = -0.0177642; a[2][0] = 0; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+   a[0][1] = 0.0447435; a[1][1] = -0.659295; a[2][1] = 2.99202; a[3][1] = -6.10742; a[4][1] = 6.34017; a[5][1] = -3.49095; a[6][1] = 0.972228; a[7][1] = -0.107807; a[8][1] = 0; 
+   a[0][2] = -0.249078; a[1][2] = 3.75779; a[2][2] = -18.9563; a[3][2] = 45.4474; a[4][2] = -59.333; a[5][2] = 44.722; a[6][2] = -19.4586; a[7][2] = 4.54039; a[8][2] = -0.4399; 
+   a[0][3] = 124.481; a[1][3] = -1129.76; a[2][3] = 5198.92; a[3][3] = -10538.1; a[4][3] = 10741.4; a[5][3] = -5757; a[6][3] = 1548.86; a[7][3] = -164.644; a[8][3] = 0; 
+   //lt99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.057286; a[1][0] = -0.0168061; a[2][0] = 0; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+a[0][1] = 0.0640448; a[1][1] = -0.922493; a[2][1] = 4.10239; a[3][1] = -8.19704; a[4][1] = 8.35619; a[5][1] = -4.52961; a[6][1] = 1.24415; a[7][1] = -0.136244; a[8][1] = 0; 
+a[0][2] = -0.222389; a[1][2] = 3.34829; a[2][2] = -16.8256; a[3][2] = 40.1156; a[4][2] = -52.0129; a[5][2] = 38.9152; a[6][2] = -16.8076; a[7][2] = 3.89426; a[8][2] = -0.374831; 
+a[0][3] = 97.8443; a[1][3] = -804.025; a[2][3] = 3412.76; a[3][3] = -6058.05; a[4][3] = 5028.88; a[5][3] = -1940.87; a[6][3] = 281.19; a[7][3] = 0; a[8][3] = 0; 
+   //ct99 = ComputeAngle(p,eta,a,npar,npol);
+   npol = 3;
+a[0][0] = 0.0665222; a[1][0] = 0; a[2][0] = 0; 
+a[0][1] = -0.018755; a[1][1] = 0.00258183; a[2][1] = 0; 
+a[0][2] = 0.045607; a[1][2] = -0.0234824; a[2][2] = 0.00375319; 
+a[0][3] = 43.8011; a[1][3] = -10.0462; a[2][3] = 0; 
+   //mt99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.156972; a[1][0] = -0.0333305; a[2][0] = 0; 
+a[0][1] = -0.0231364; a[1][1] = 0.0120482; a[2][1] = -0.00289192; 
+a[0][2] = 0.0490898; a[1][2] = -0.0273084; a[2][2] = 0.00547379; 
+a[0][3] = 33.1651; a[1][3] = 0; a[2][3] = 0; 
+   //st99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.179041; a[1][0] = -0.0531058; a[2][0] = 0; 
+a[0][1] = -0.0146875; a[1][1] = 0.00414247; a[2][1] = -0.000612045; 
+a[0][2] = 0.0188939; a[1][2] = -0.00452375; a[2][2] = 0.00120015; 
+a[0][3] = 58.3066; a[1][3] = -48.2594; a[2][3] = 26.8864; 
+   lp99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.142962; a[1][0] = -0.0397119; a[2][0] = 0; 
+a[0][1] = -0.014084; a[1][1] = 0.00437622; a[2][1] = -0.000992845; 
+a[0][2] = 0.0145659; a[1][2] = -0.00270987; a[2][2] = 0.00079432; 
+a[0][3] = 42.4831; a[1][3] = -25.893; a[2][3] = 13.6075; 
+   mp99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.0741985; a[1][0] = -0.0181941; a[2][0] = 0; 
+a[0][1] = -0.0149252; a[1][1] = 0.00512965; a[2][1] = -0.00125462; 
+a[0][2] = 0.00802004; a[1][2] = -0.00252272; a[2][2] = 0.000761022; 
+a[0][3] = 25.0145; a[1][3] = 0; a[2][3] = 0; 
+   sp99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.177021; a[1][0] = -0.0800858; a[2][0] = 0.017266; 
+a[0][1] = -0.0145132; a[1][1] = 0.00508756; a[2][1] = -0.00133994; 
+a[0][2] = 0.0174059; a[1][2] = -0.00407948; a[2][2] = 0.00130897; 
+a[0][3] = 59.5959; a[1][3] = -51.819; a[2][3] = 28.742; 
+   los99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.126153; a[1][0] = -0.0504026; a[2][0] = 0.0100601; 
+a[0][1] = -0.01373; a[1][1] = 0.0040825; a[2][1] = -0.00103933; 
+a[0][2] = 0.0121626; a[1][2] = -0.00239224; a[2][2] = 0.000832398; 
+a[0][3] = 43.6455; a[1][3] = -34.4061; a[2][3] = 17.558; 
+   sos99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.159394; a[1][0] = -0.0461081; a[2][0] = 0; 
+a[0][1] = -0.0148102; a[1][1] = 0.00429109; a[2][1] = -0.000670516; 
+a[0][2] = 0.0167114; a[1][2] = -0.00539364; a[2][2] = 0.00175181; 
+a[0][3] = 48.371; a[1][3] = -35.9336; a[2][3] = 19.3991; 
+   ss99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.102084; a[1][0] = -0.0256446; a[2][0] = 0; 
+a[0][1] = -0.014259; a[1][1] = 0.00465467; a[2][1] = -0.00122856; 
+a[0][2] = 0.010552; a[1][2] = -0.00176856; a[2][2] = 0.000446776; 
+a[0][3] = 36.0848; a[1][3] = -16.1489; a[2][3] = 10.2994; 
+   lm99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.152783; a[1][0] = -0.0390978; a[2][0] = 0; 
+a[0][1] = -0.0139914; a[1][1] = 0.00352551; a[2][1] = -0.000624039; 
+a[0][2] = 0.0159925; a[1][2] = -0.00332104; a[2][2] = 0.00100568; 
+a[0][3] = 43.5804; a[1][3] = -18.681; a[2][3] = 6.29988; 
+   //ls99 = ComputeAngle(p,eta,a,npar,npol);
+a[0][0] = 0.160615; a[1][0] = -0.0284831; a[2][0] = -0.00879631; 
+a[0][1] = -0.0140811; a[1][1] = 0.00344844; a[2][1] = -0.000421752; 
+a[0][2] = 0.0173056; a[1][2] = -0.00371573; a[2][2] = 0.00112158; 
+a[0][3] = 59.28; a[1][3] = -48.2821; a[2][3] = 26.3103; 
+   //ms99 = ComputeAngle(p,eta,a,npar,npol);
+   
+   if ((angle < lm99)&&((angle < lp99)||(angle < mp99)||(angle < sp99))){   
+   	if((charge == -1)&&((angle < los99)||(angle < sos99))) return true;
+   	else if((charge == 1)&&(angle < ss99)) return true;
+   	else return false;
+   }
+   else return false;
+} //End pass2prong
+
+bool TauTrackFilterUtils::pass1prong(TLorentzVector track,TLorentzVector tau){
+   //Step 1: Compute Angle Between Track and Tau
+   float angle = fabs(track.Angle(tau.Vect()));
+   //Step 2: Compute 99% angle
+   float p = tau.P(), eta = fabs(tau.Eta());
+   
+   int npar = 4, npol = 3;
+   float a[3][4];
+   
+   a[0][0] = 0.120777; a[1][0] = -0.0261681; a[2][0] = 0;
+   a[0][1] = -0.0307174; a[1][1] = 0.0170112; a[2][1] = -0.00381298;
+   a[0][2] = 0.0662689; a[1][2] = -0.0402811; a[2][2] = 0.00760013;
+   a[0][3] = 24.512; a[1][3] = 0; a[2][3] = 0;
+   float angle99 = ComputeAngle(p,eta,a,npar,npol);
+
+   //Step 3: compare angles and return decision
+   if(angle > angle99) return false; //Track angle exceeds kinematic boundary
+   else return true;
+} //End pass1prong
+
+float TauTrackFilterUtils::ComputePi0Cone(int recProngs,TLorentzVector tau){
+   float angle = -1;
+   float atrue = 0, arec = 0;
+   float p = tau.P(), eta = fabs(tau.Eta());   
+   int npar = 4, npol = 9;
+   float a[9][4];
+   switch(recProngs){
+      case 3:  //3 Prong Case
+         a[0][0] = 0.0419208; a[1][0] = 0.0481497; a[2][0] = -0.0225545; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+         a[0][1] = -0.00568661; a[1][1] = -0.00336825; a[2][1] = 0.00172832; a[3][1] = 0; a[4][1] = 0; a[5][1] = 0; a[6][1] = 0; a[7][1] = 0; a[8][1] = 0; 
+         a[0][2] = 0.00177496; a[1][2] = 0.00296773; a[2][2] = -0.00123081; a[3][2] = 0; a[4][2] = 0; a[5][2] = 0; a[6][2] = 0; a[7][2] = 0; a[8][2] = 0; 
+         a[0][3] = 90.9262; a[1][3] = -89.7105; a[2][3] = 49.0447; a[3][3] = 0; a[4][3] = 0; a[5][3] = 0; a[6][3] = 0; a[7][3] = 0; a[8][3] = 0; 
+         atrue = ComputeAngle(p,eta,a,npar,npol);
+         a[0][0] = 0.187427; a[1][0] = -0.0816934; a[2][0] = 0.0116366; a[3][0] = 0; a[4][0] = 0; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+         a[0][1] = -0.00961135; a[1][1] = 0.0188071; a[2][1] = -0.0279819; a[3][1] = 0.0175981; a[4][1] = -0.00374356; a[5][1] = 0; a[6][1] = 0; a[7][1] = 0; a[8][1] = 0; 
+         a[0][2] = 0.0139015; a[1][2] = -0.0572689; a[2][2] = 0.0897538; a[3][2] = -0.0543513; a[4][2] = 0.0110609; a[5][2] = 0; a[6][2] = 0; a[7][2] = 0; a[8][2] = 0; 
+         a[0][3] = -57.066; a[1][3] = 731.569; a[2][3] = -2351.02; a[3][3] = 3576.75; a[4][3] = -2802.87; a[5][3] = 1081.43; a[6][3] = -161.098; a[7][3] = 0; a[8][3] = 0; 
+         arec = ComputeAngle(p,eta,a,npar,npol);
+         break;
+      case 1: //1 Prong Case
+         a[0][0] = 0.077467; a[1][0] = -0.0648352; a[2][0] = 0.15807; a[3][0] = -0.111211; a[4][0] = 0.0223358; a[5][0] = 0; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+         a[0][1] = -0.0212485; a[1][1] = 0.213133; a[2][1] = -1.10606; a[3][1] = 2.81065; a[4][1] = -3.95237; a[5][1] = 3.21507; a[6][1] = -1.50167; a[7][1] = 0.373201; a[8][1] = -0.0381986; 
+         a[0][2] = 0.0180949; a[1][2] = -0.215859; a[2][2] = 1.06949; a[3][2] = -2.61577; a[4][2] = 3.56621; a[5][2] = -2.82425; a[6][2] = 1.28799; a[7][2] = -0.313272; a[8][2] = 0.0314451; 
+         a[0][3] = 55.3658; a[1][3] = 83.3644; a[2][3] = -243.958; a[3][3] = 303.823; a[4][3] = -257.709; a[5][3] = 125.826; a[6][3] = -23.0882; a[7][3] = 0; a[8][3] = 0; 
+         atrue = ComputeAngle(p,eta,a,npar,npol);
+         a[0][0] = 0.0887773; a[1][0] = 0.183147; a[2][0] = -0.53342; a[3][0] = 0.511497; a[4][0] = -0.207361; a[5][0] = 0.0299467; a[6][0] = 0; a[7][0] = 0; a[8][0] = 0; 
+         a[0][1] = 0.00529589; a[1][1] = -0.0931825; a[2][1] = 0.331541; a[3][1] = -0.501175; a[4][1] = 0.356803; a[5][1] = -0.118988; a[6][1] = 0.0150108; a[7][1] = 0; a[8][1] = 0; 
+         a[0][2] = -0.0152482; a[1][2] = 0.203442; a[2][2] = -0.799957; a[3][2] = 1.29237; a[4][2] = -0.943621; a[5][2] = 0.315001; a[6][2] = -0.0392101; a[7][2] = 0; a[8][2] = 0; 
+         a[0][3] = 46.0655; a[1][3] = -61.8671; a[2][3] = 278.08; a[3][3] = -385.329; a[4][3] = 199.816; a[5][3] = -34.0016; a[6][3] = 0; a[7][3] = 0; a[8][3] = 0; 
+         arec = ComputeAngle(p,eta,a,npar,npol);
+         break;
+      default:
+         //ATH_MSG_WARNING("Incorrect number of prongs!");
+         return angle;
+   }
+   if (atrue > arec) angle = atrue;
+   else angle = arec;
+   return angle;
+} //End ComputePi0Cone
+
+float TauTrackFilterUtils::ComputeAngle(float p, float eta, float a[9][4], int npar, int npol, char eqn[]){
+   char name[10];
+   char poleqn[10];
+   
+   //TF1* etacoeff[npar]; //FIXME variable length array, use something like: = new TF1[npar];
+   std::vector<TF1> etacoeff;
+   TF1* pcone = new TF1("pcone",eqn); 
+   for(int i=0;i<npar;i++){
+      sprintf(name,"p%i",i);
+      sprintf(poleqn,"pol%i",npol);
+      etacoeff.push_back(TF1(name,poleqn));
+      for(int j=0;j<npol;j++) etacoeff.at(i).SetParameter(j,a[j][i]);
+		  pcone->SetParameter(i,etacoeff.at(i).Eval(eta));
+   }
+   float angle = pcone->Eval(p);
+   delete pcone;
+   return angle;
+}
+
+float TauTrackFilterUtils::Compute1dim(float p, float a[10], int npar, char eqn[]){
+   TF1* pcone = new TF1("pcone",eqn); 
+   for(int i=0;i<npar;i++) pcone->SetParameter(i,a[i]);
+   float angle = pcone->Eval(p);
+   delete pcone;
+   return angle;
+}
diff --git a/Reconstruction/tauRecTools/cmt/Makefile.RootCore b/Reconstruction/tauRecTools/cmt/Makefile.RootCore
new file mode 100644
index 0000000000000000000000000000000000000000..2d489eb6af629b7314a27b85e262bb16c63f2e76
--- /dev/null
+++ b/Reconstruction/tauRecTools/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              = tauRecTools
+
+# 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 xAODTau PathResolver xAODEventInfo FourMomUtils xAODTracking
+
+# 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       = 0
+
+# 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/Reconstruction/tauRecTools/cmt/requirements b/Reconstruction/tauRecTools/cmt/requirements
new file mode 100644
index 0000000000000000000000000000000000000000..f3d298d3f7e631fb1db6af99cd1d1aa3f0ed7ba9
--- /dev/null
+++ b/Reconstruction/tauRecTools/cmt/requirements
@@ -0,0 +1,76 @@
+package tauRecTools
+
+author S. Rajagopalan <srinir@bnl.gov>
+author J. Griffiths <griffith@cern.ch>
+
+public
+use  AtlasPolicy                AtlasPolicy-*                   
+use  AsgTools                   AsgTools-*                      Control/AthToolSupport
+use  xAODTau                    xAODTau-*                       Event/xAOD
+use  AtlasBoost                 AtlasBoost-*                    External
+use  AtlasROOT                  AtlasROOT-*                     External
+use  xAODTracking               xAODTracking-*                  Event/xAOD
+use  AthLinks                   AthLinks-*                      Control
+
+private
+use  xAODJet                    xAODJet-*                       Event/xAOD
+use  AthContainers              AthContainers-*                 Control
+use  PathResolver               PathResolver-*                  Tools
+use  GaudiInterface             GaudiInterface-*                External
+use  FourMomUtils               FourMomUtils-*                  Event
+use  FourMom                    FourMom-*                       Event
+use  AnalysisUtils              AnalysisUtils-*                 PhysicsAnalysis/AnalysisCommon
+use  AtlasAIDA                  AtlasAIDA-*                     External
+use  AtlasCLHEP                 AtlasCLHEP-*                    External
+use  AtlasDetDescr              AtlasDetDescr-*                 DetectorDescription
+use  CaloEvent                  CaloEvent-*                     Calorimeter
+use  CaloGeoHelpers             CaloGeoHelpers-*                Calorimeter
+use  CaloIdentifier             CaloIdentifier-*                Calorimeter
+use  CaloUtils                  CaloUtils-*                     Calorimeter
+use  CxxUtils                   CxxUtils-*                      Control
+use  EventKernel                EventKernel-*                   Event
+use  ITrackToVertex             ITrackToVertex-*                Reconstruction/RecoTools
+use  CaloInterface              CaloInterface-*                 Calorimeter
+use  InDetRecToolInterfaces     InDetRecToolInterfaces-*        InnerDetector/InDetRecTools
+use  JetEDM                     JetEDM-*                        Reconstruction/Jet
+use  JetEvent                   JetEvent-*                      Reconstruction/Jet
+use  NavFourMom                 NavFourMom-*                    Event
+use  Particle                   Particle-*                      Reconstruction
+use  RecoToolInterfaces         RecoToolInterfaces-*            Reconstruction/RecoTools
+use TrkLinks                    TrkLinks-*              Tracking/TrkEvent
+use  TrkParameters              TrkParameters-*                 Tracking/TrkEvent
+use  TrkParticleBase            TrkParticleBase-*               Tracking/TrkEvent
+use TrkParametersIdentificationHelpers TrkParametersIdentificationHelpers-* Tracking/TrkEvent
+use  TrkToolInterfaces          TrkToolInterfaces-*             Tracking/TrkTools
+use  TrkTrackSummary            TrkTrackSummary-*               Tracking/TrkEvent
+use  TrkVertexFitterInterfaces  TrkVertexFitterInterfaces-*     Tracking/TrkVertexFitter
+use  TrkVertexFitters           TrkVertexFitters-*              Tracking/TrkVertexFitter
+use TrkVxEdmCnv                 TrkVxEdmCnv-*           Tracking/TrkVertexFitter
+use  VxVertex                   VxVertex-*                      Tracking/TrkEvent
+use  tauEvent                   tauEvent-*                      Reconstruction
+use  xAODCaloEvent              xAODCaloEvent-*                 Event/xAOD
+use  xAODPFlow                  xAODPFlow-*                     Event/xAOD
+use  xAODEventInfo              xAODEventInfo-*                 Event/xAOD
+
+
+
+
+# Specify the required ROOT components for cmake (transparent to CMT)
+apply_pattern cmake_add_command command="find_package(ROOT COMPONENTS TMVA)"
+
+ 
+public
+
+#macro_append tauRec_shlibflags "-L$(ROOTSYS)/lib -lCore -lCint -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lm -ldl -lpthread -rdynamic"
+#macro_append ROOT_linkopts " -lTMVA"
+
+apply_pattern dual_use_library files="*.cxx *.c ../Root/*.cxx"
+
+apply_pattern declare_joboptions files="*.txt *.py"
+
+apply_pattern declare_runtime files="*.root *.dat *.xml" 
+
+apply_pattern declare_python_modules files="*.py"
+
+apply_tag ROOTTMVALibs 
+
diff --git a/Reconstruction/tauRecTools/src/CaloClusterVariables.cxx b/Reconstruction/tauRecTools/src/CaloClusterVariables.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ce6db2f5739825be0506c17c167f15e947c4f425
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/CaloClusterVariables.cxx
@@ -0,0 +1,202 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CaloClusterVariables.h"
+#include "tauEvent/TauJet.h"
+#include "boost/foreach.hpp"
+#include "math.h"
+
+const double CaloClusterVariables::DEFAULT = -1111.;
+
+//****************************************
+// constructor
+//****************************************
+
+CaloClusterVariables::CaloClusterVariables() :
+m_numConstit((int) DEFAULT),
+m_effNumConstit_int((int) DEFAULT),
+m_effNumConstit(DEFAULT),
+m_aveRadius(DEFAULT),
+m_aveEffRadius(DEFAULT),
+m_totMass(DEFAULT),
+m_effMass(DEFAULT),
+m_totEnergy(DEFAULT),
+m_effEnergy(DEFAULT),
+m_numCells(0),
+m_doVertexCorrection(false) {
+}
+
+//*******************************************
+// update/fill the cluster based variables
+//*******************************************
+
+bool CaloClusterVariables::update(const xAOD::TauJet& pTau, bool inAODmode) {
+
+    const xAOD::Jet* pSeed = *pTau.jetLink();
+    if(!pSeed) return false;
+
+    xAOD::JetConstituentVector::const_iterator nav_it = pSeed->getConstituents().begin();
+    xAOD::JetConstituentVector::const_iterator nav_itE = pSeed->getConstituents().end();
+    const xAOD::CaloCluster* pCluster;
+   
+    unsigned int sumCells = 0;
+
+    std::vector<xAOD::CaloVertexedCluster> constituents;
+    for (; nav_it != nav_itE; ++nav_it) {
+      pCluster = dynamic_cast<const xAOD::CaloCluster*> ( (*nav_it)->rawConstituent() );
+      if (!pCluster) continue;
+
+      // XXX moved the calculation of num cells up because later on we don't have access to the actual clusters anymore
+      if(!inAODmode) sumCells += pCluster->size();
+
+      // correct cluster
+      if (pTau.vertexLink() && m_doVertexCorrection)
+        constituents.emplace_back (*pCluster, (*pTau.vertexLink())->position());
+      else
+        constituents.emplace_back (*pCluster);
+    }
+
+    this->m_numConstit = (int) constituents.size();
+
+    // Order constituents by energy
+    sort(constituents.begin(), constituents.end(), CaloClusterCompare());
+
+    //****************************************
+    // Looping over all constituents
+    //****************************************
+
+    double sum_px = 0;
+    double sum_py = 0;
+    double sum_pz = 0;
+    double sum_e = 0;
+    double sum_of_E2 = 0;
+    double sum_radii = 0;
+    CLHEP::HepLorentzVector centroid = calculateTauCentroid(this->m_numConstit, constituents);
+
+    for (const xAOD::CaloVertexedCluster& c : constituents) {
+        double energy = c.e();
+        sum_of_E2 += energy*energy;
+
+        double px = c.p4().Px();
+        double py = c.p4().Py();
+        double pz = c.p4().Pz();
+        // FF: phi is wrong in case px,py AND pz is negative when using HepLorentzVector(px,py,pz,1)
+        // because phi = atan(py/px)
+        // in trigger many clusters have negative energies/momentum
+        // negative values of px and py are only treated correctly if pz is positive.
+        // Otherwise px and py must be taken as positive values
+        // so using cluster eta/phi directly instead of creating a HLV.
+        //CLHEP::HepLorentzVector constituentHLV(px, py, pz, 1);
+        //sum_radii += centroid.deltaR(constituentHLV);
+        double dr = std::sqrt( std::pow(c.eta() - centroid.eta(),2) + std::pow(c.phi() - centroid.phi(),2));
+        sum_radii += dr;
+        sum_e += energy;
+        sum_px += px;
+        sum_py += py;
+        sum_pz += pz;
+    }
+
+    // Sum up the energy for constituents
+    this->m_totEnergy = sum_e;
+
+    // Calculate the mass of the constituents
+    if (this->m_numConstit < 2) this->m_totMass = DEFAULT;
+    else {
+        double mass2 = sum_e * sum_e - (sum_px * sum_px + sum_py * sum_py + sum_pz * sum_pz);
+        this->m_totMass = mass2 > 0 ? sqrt(mass2) : -sqrt(-mass2);
+    }
+
+    // Calculate the average radius of the constituents wrt the tau centroid
+    this->m_aveRadius = this->m_numConstit > 0 ? sum_radii / this->m_numConstit : DEFAULT;
+
+    // sum of cells for the tau candidate
+    this->m_numCells = sumCells;
+    
+    // Effective number of constituents
+    this->m_effNumConstit = sum_of_E2 > 0 ? (sum_e * sum_e) / (sum_of_E2) : DEFAULT;
+
+    this->m_effNumConstit_int = int(ceil(this->m_effNumConstit));
+
+    // A problem!
+    if (this->m_effNumConstit_int > this->m_numConstit) return false;
+
+    // Avoid segfault, happens when we try to iterate below if sum_of_E2 was 0 or negative
+    if (this->m_effNumConstit_int < 0) return false;
+
+    //****************************************
+    // Now: Looping over effective constituents
+    //****************************************
+
+    sum_px = 0;
+    sum_py = 0;
+    sum_pz = 0;
+    sum_e = 0;
+    sum_of_E2 = 0;
+    sum_radii = 0;
+    centroid = calculateTauCentroid(this->m_effNumConstit_int, constituents);
+
+    int icount = this->m_effNumConstit_int;
+    for (const xAOD::CaloVertexedCluster& c : constituents) {
+      if (icount <= 0) break;
+      --icount;
+
+        double energy = c.e();
+	//XXXchange to use tlorentzvector
+        double px = c.p4().Px();
+        double py = c.p4().Py();
+        double pz = c.p4().Pz();
+        // FF: see comment above
+        //CLHEP::HepLorentzVector constituentHLV(px, py, pz, 1);
+        //sum_radii += centroid.deltaR(constituentHLV);
+        double dr = std::sqrt( std::pow(c.eta() - centroid.eta(),2) + std::pow(c.phi() - centroid.phi(),2));
+        sum_radii += dr;
+
+        sum_e += energy;
+        sum_px += px;
+        sum_py += py;
+        sum_pz += pz;
+    }
+
+    // Sum up the energy for effective constituents
+    this->m_effEnergy = sum_e;
+
+    // Calculate the mass of the constituents
+    if (this->m_effNumConstit_int < 2) this->m_effMass = DEFAULT;
+    else {
+        double mass2 = sum_e * sum_e - (sum_px * sum_px + sum_py * sum_py + sum_pz * sum_pz);
+        this->m_effMass = mass2 > 0 ? sqrt(mass2) : -sqrt(-mass2);
+    }
+
+    // Calculate the average radius of the constituents wrt the tau centroid
+    this->m_aveEffRadius = this->m_effNumConstit_int > 0 ? sum_radii / this->m_effNumConstit_int : DEFAULT;
+
+    return true;
+}
+
+
+//*****************************************
+// Calculate the geometrical center of the
+// tau constituents
+//*****************************************
+CLHEP::HepLorentzVector CaloClusterVariables::calculateTauCentroid(int nConst, const std::vector<xAOD::CaloVertexedCluster>& constituents) {
+
+    double px = 0;
+    double py = 0;
+    double pz = 0;
+    double current_px, current_py, current_pz, modulus;
+
+    for (const xAOD::CaloVertexedCluster& c : constituents) {
+      if (nConst <= 0) break;
+      --nConst;
+        current_px = c.p4().Px();
+        current_py = c.p4().Py();
+        current_pz = c.p4().Pz();
+        modulus = sqrt(current_px * current_px + current_py * current_py + current_pz * current_pz);
+        px += current_px / modulus;
+        py += current_py / modulus;
+        pz += current_pz / modulus;
+    }
+    CLHEP::HepLorentzVector centroid(px, py, pz, 1);
+    return centroid;
+}
diff --git a/Reconstruction/tauRecTools/src/CaloClusterVariables.h b/Reconstruction/tauRecTools/src/CaloClusterVariables.h
new file mode 100644
index 0000000000000000000000000000000000000000..88bf7c428509ccb116d423df356c7c7ef92f8b18
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/CaloClusterVariables.h
@@ -0,0 +1,81 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef CALOCLUSTERVARIABLES_H
+#define CALOCLUSTERVARIABLES_H
+
+#include <vector>
+#include "CaloUtils/CaloVertexedCluster.h"
+//#include "CaloEvent/CaloVertexedCluster.h"
+#include "CxxUtils/fpcompare.h"
+#include "xAODTau/TauJet.h"
+
+/** Provide calculations of cluster based variables using the clusters associated to the jet seed of the tau candidate. */
+class CaloClusterVariables {
+public:
+
+    static const double DEFAULT;
+
+    CaloClusterVariables();
+
+    ~CaloClusterVariables() {
+    }
+
+    bool update(const xAOD::TauJet& pTau, bool inAODmode=false); //!< update the internal variables for the given tau
+
+    void setVertexCorrection(bool flag) {m_doVertexCorrection=flag;}
+
+    // ID Variables
+    unsigned int numConstituents() { return (unsigned int) m_numConstit; }
+
+    double totalMass()     { return m_totMass; }
+    double effectiveMass() { return m_effMass; }
+    
+    double effectiveNumConstituents()  { return m_effNumConstit; }
+    int effectiveNumConstituents_int() { return m_effNumConstit_int; }
+
+    double averageEffectiveRadius() { return m_aveEffRadius; }
+    double averageRadius()          { return m_aveRadius; }
+
+    // Energy Variables
+    double totalEnergy()     { return m_totEnergy; }
+    double effectiveEnergy() { return m_effEnergy; }
+
+    //cells
+    unsigned int numCells() { return m_numCells; }
+
+private:
+    int m_numConstit;
+    int m_effNumConstit_int;
+    double m_effNumConstit;
+    double m_aveRadius;
+    double m_aveEffRadius;
+    double m_totMass;
+    double m_effMass;
+    double m_totEnergy;
+    double m_effEnergy;
+    unsigned int m_numCells;
+
+    /** Calculate the geometrical center of the tau constituents */
+		CLHEP::HepLorentzVector calculateTauCentroid(int nConst, const std::vector<xAOD::CaloVertexedCluster>& constituents);
+    
+    /** 
+     * Enable cell origin correction.
+     * Eta and phi of the cells are corrected wrt to the origin of the tau vertex
+     */
+    bool m_doVertexCorrection;
+};
+
+//-------------------------------------------------------------------------
+//! Descending order by energy
+//-------------------------------------------------------------------------
+struct CaloClusterCompare { 
+  bool operator()(const xAOD::CaloVertexedCluster& left, const xAOD::CaloVertexedCluster& right) {
+        //volatile double leftE = left.e();
+        //volatile double rightE = right.e();
+        return CxxUtils::fpcompare::greater (left.e(),right.e());
+    }
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/JetSeedBuilder.cxx b/Reconstruction/tauRecTools/src/JetSeedBuilder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b7a829e895e3c889871583aad23ed1749c09e2d8
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/JetSeedBuilder.cxx
@@ -0,0 +1,221 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+NAME:     JetSeedBuilder.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  N. Meyer
+CREATED:  Nov 27 2007
+
+17/03/2010: AK: change to P4Helpers
+16/05/2011: FF: fix rare case if no jet_seed found at all (coverity 21744)
+  Dec 2011: FF: changes for tauRec4
+ ********************************************************************/
+
+#include "EventKernel/SignalStateHelper.h"
+#include "FourMomUtils/P4Helpers.h"
+
+#include "xAODJet/Jet.h"
+#include "xAODJet/JetContainer.h"
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+#include "xAODTau/TauJet.h"
+
+#include "JetSeedBuilder.h"
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+JetSeedBuilder::JetSeedBuilder(const std::string& name) :
+  TauRecToolBase(name),
+  m_jetCollectionName("AntiKt4LCTopoJets"),
+  m_maxJetdist(0.1),
+  m_minJetPt(10000.0),
+  m_switch_jets_em_scale(false) {
+  declareProperty("JetCollection", m_jetCollectionName);
+  declareProperty("maxDist", m_maxJetdist);
+  declareProperty("minPt", m_minJetPt);
+  declareProperty("SwitchJetsEmScale", m_switch_jets_em_scale);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+JetSeedBuilder::~JetSeedBuilder() {
+}
+
+
+void JetSeedBuilder::print() const {
+  
+}
+
+//-------------------------------------------------------------------------
+// initialize
+//-------------------------------------------------------------------------
+
+StatusCode JetSeedBuilder::initialize() {
+	return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// initialize
+//-------------------------------------------------------------------------
+
+StatusCode JetSeedBuilder::finalize() {
+	return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// Event Finalize
+//-------------------------------------------------------------------------
+
+StatusCode JetSeedBuilder::eventFinalize() {
+	return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// execute
+//-------------------------------------------------------------------------
+
+StatusCode JetSeedBuilder::execute(xAOD::TauJet& pTau) {
+
+	StatusCode sc;
+
+	ATH_MSG_DEBUG("Starting execute");
+
+	bool inTrigger = tauEventData()->inTrigger();
+
+	if(inTrigger)
+		ATH_MSG_DEBUG("inTrigger read properly");
+
+	const xAOD::JetContainer *pJetColl;
+
+	if (sc.isSuccess() && inTrigger) {
+		// called by Trigger
+		// retrieve JetCollection for trigger
+		ATH_MSG_DEBUG("Try to retrieve object from DataContainer");
+		//sc = tauEventData()->getObject("JetCollection", pJetColl);
+		// Try a different approach: grab it directly
+		sc = true;
+		pJetColl = tauEventData()->seedContainer;
+		if (sc.isFailure() || !pJetColl) {
+			ATH_MSG_DEBUG("no JetCollection for trigger available");
+			ATH_MSG_DEBUG("retrieve standard JetCollection <" << m_jetCollectionName << ">");
+			// retrieve standard jet collection
+			sc = evtStore()->retrieve(pJetColl, m_jetCollectionName);
+			if (sc.isFailure()) {
+				ATH_MSG_WARNING("no JetCollection retrieved");
+				return StatusCode::FAILURE;
+			}
+		}
+	} else {
+		// called by offline tauRec
+		// retrieve standard jet collection
+		sc = evtStore()->retrieve(pJetColl, m_jetCollectionName);
+		if (sc.isFailure()) {
+			ATH_MSG_WARNING("no JetCollection retrieved");
+			return StatusCode::FAILURE;
+		}
+	}
+
+	ATH_MSG_DEBUG("Pulling out the seed");
+
+	const xAOD::Jet* pJetSeed = 0;
+	if (pTau.jetLink().isValid()) pJetSeed = * pTau.jetLink();
+	if (!pJetSeed) {
+		ATH_MSG_DEBUG("seed is not a jet -> tau will not be reconstructed");
+		return StatusCode::FAILURE;
+	}
+
+	ATH_MSG_DEBUG("Seed extracted");
+	ATH_MSG_DEBUG("seed is Jet with"
+			<< " pt=" << pJetSeed->pt()
+			<< " eta=" << pJetSeed->eta()
+			<< " phi=" << pJetSeed->phi()
+	);
+
+	xAOD::TauJetContainer* pContainer = tauEventData()->xAODTauContainer;
+	if(pContainer==0){
+	  pContainer = static_cast<xAOD::TauJetContainer*> (pTau.container());
+	}
+	if(pContainer==0) {
+	  ATH_MSG_FATAL("Can't find tau Container");
+	  return StatusCode::FAILURE;
+	}
+	
+	xAOD::TauJetContainer::iterator itTau = pContainer->begin();
+	xAOD::TauJetContainer::iterator itTauE = pContainer->end();
+
+	for (; itTau != itTauE; ++itTau) {
+	  if( (*itTau) == &pTau ) continue;
+		if ( (*itTau)->jetLink().isValid() ) {
+			if ( pJetSeed == ( * (*itTau)->jetLink() ) ) {
+				ATH_MSG_DEBUG("seed already used");
+				return StatusCode::FAILURE;
+			}
+		}
+	}
+
+	///XXX need to decide whether to remove this, because there's no author flag in xAOD::TauJet
+
+	//***********************************************************************
+	// set author to both-seeded because we don't want to break any analysis
+	// most of the analyses are using author==3 or author==1
+	// so setting author=3 should be safe for everybody
+	// calo seeded tau
+	// pTau.setAuthor(TauJetParameters::tauRec);
+	// // track seeded tau
+	// pTau.setAuthor(TauJetParameters::tau1P3P);
+	//***********************************************************************
+
+	//
+	// ATTENTION: direction will be overwritten later by TauAxis and TauEnergyCalibration
+	//
+	if (inTrigger && pJetSeed->e() < 0) {
+		// SL/SX trigger mode with negative jet_seed - do not set TauJet eta and phi in JetSeedBuilder
+		ATH_MSG_DEBUG("TauJet eta/phi will be set in Level2 Trigger for negative energy jet");
+
+		pTau.setDetail(xAOD::TauJetParameters::seedCalo_eta , static_cast<float>( pTau.eta() ) );
+		pTau.setDetail(xAOD::TauJetParameters::seedCalo_phi , static_cast<float>( pTau.phi() ) );
+
+		pTau.setP4(pJetSeed->pt(),pTau.eta(),pTau.phi(),0.0);
+
+	} else {
+		if (m_switch_jets_em_scale) {
+			ATH_MSG_INFO("trying to set seed jet signal state to EMSCALE, but this code has not been migrated to xAOD::Jet yet");
+			//XXX still need to look up how signal states are handled for the xAOD jets
+			// SignalStateHelper sigstateH(P4SignalState::JETEMSCALE);
+			// sigstateH.controlObject(pJetSeed);
+		}
+
+		pTau.setDetail(xAOD::TauJetParameters::seedCalo_eta , static_cast<float>( pJetSeed->eta() ) );
+		pTau.setDetail(xAOD::TauJetParameters::seedCalo_phi , static_cast<float>( pJetSeed->phi() ) );
+		if ( pJetSeed->pt() > 1e-7)
+			pTau.setP4(static_cast<float>( pJetSeed->pt() ) ,static_cast<float>( pJetSeed->eta() ) ,static_cast<float>( pJetSeed->phi() ) ,0.0 );
+		else
+			pTau.setP4(static_cast<float>( pJetSeed->pt() ) ,static_cast<float>( pJetSeed->eta() ) ,static_cast<float>( pJetSeed->phi() ) , 0.0 );
+
+		//store 4-vector of seed
+		pTau.setP4( xAOD::TauJetParameters::JetSeed, pJetSeed->pt(), pJetSeed->eta(), pJetSeed->phi(), pJetSeed->m() );
+	}
+
+	// set now the link to the jet seed
+	// if not already set
+	if(!pTau.jetLink().isValid() || (*pTau.jetLink())!=pJetSeed ) pTau.setJet(pJetColl, pJetSeed);
+
+	if ( pTau.jetLink().isValid() ) {
+		ATH_MSG_DEBUG("seed associated with tau is Jet with"
+				<< " pt=" << (*pTau.jetLink())->pt()
+				<< " eta=" << (*pTau.jetLink())->eta()
+				<< " phi=" << (*pTau.jetLink())->phi()
+		);
+	}
+
+	return StatusCode::SUCCESS;
+}
+
+
diff --git a/Reconstruction/tauRecTools/src/JetSeedBuilder.h b/Reconstruction/tauRecTools/src/JetSeedBuilder.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ee4fb3916a82284f2a9488431c0586c969767ec
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/JetSeedBuilder.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_JETSEEDBUILDER_H
+#define	TAUREC_JETSEEDBUILDER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+
+/**
+ * @brief Class to build tauRec seeds from topojets.
+ * 
+ *  Sets the jet ElementLink and basic kinematic variables in TauJet by searching a matching jet to the tau direction.
+ *  Also the mass of the tau is set to 0.
+ *  With tauRec4 the JetSeedBuilder method is the only one to search for a tau candidates. 
+ *  The author of the tau candidate is set 1 (former calo-only seeded) and 3 (former calo+track-seeded) to keep backwards compatibility.
+ *  
+ * @author N.Meyer <nicom@cern.ch>
+ * @author Felix Friedrich
+*/
+
+class JetSeedBuilder : virtual public TauRecToolBase {
+public:
+
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+    ASG_TOOL_CLASS2( JetSeedBuilder, TauRecToolBase, ITauToolBase )
+    JetSeedBuilder(const std::string& name);
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    virtual ~JetSeedBuilder();
+
+    virtual StatusCode initialize();
+
+    virtual StatusCode finalize();
+
+    virtual void print() const ;
+
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+    virtual StatusCode eventFinalize();
+
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+
+private:
+    std::string m_jetCollectionName;
+    float m_maxJetdist;
+    float m_minJetPt;
+    bool m_switch_jets_em_scale;
+};
+
+#endif	/* JETSEEDBUILDER_H */
+
diff --git a/Reconstruction/tauRecTools/src/LockTauContainers.cxx b/Reconstruction/tauRecTools/src/LockTauContainers.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b843044b7d40c56209d57bfdc47bde39436c5898
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/LockTauContainers.cxx
@@ -0,0 +1,68 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+
+#include "LockTauContainers.h"
+
+//**********************************
+// Constructor
+//**********************************
+
+LockTauContainers::LockTauContainers(
+        const std::string& name) :
+  TauRecToolBase(name) {
+}
+
+
+//************************************
+// initialize method
+//************************************
+
+StatusCode LockTauContainers::initialize() {
+  return StatusCode::SUCCESS;
+}
+
+//************************************
+// finalize method
+//************************************
+
+StatusCode LockTauContainers::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+//************************************
+// event finalize method
+//************************************
+
+StatusCode LockTauContainers::eventFinalize() {
+    ATH_MSG_VERBOSE("LockTauContainers::eventFinialize");
+    
+    //-------------------------------------------------------------------------
+    // Lock Containers
+    //-------------------------------------------------------------------------
+    
+    xAOD::TauJetContainer* pContainer = tauEventData()->xAODTauContainer;
+    xAOD::TauJetAuxContainer *pAuxContainer = tauEventData()->tauAuxContainer;
+
+    StatusCode sc;
+
+    if (pContainer)
+        sc = evtStore()->setConst(pContainer);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("Cannot set tau container to const");
+        return StatusCode::FAILURE;
+    }
+
+    if (pAuxContainer)
+        sc = evtStore()->setConst(pAuxContainer);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("Cannot set tau aux container to const");
+        return StatusCode::FAILURE;
+    }
+
+    ATH_MSG_VERBOSE("all tau containers are now locked");
+    return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/src/LockTauContainers.h b/Reconstruction/tauRecTools/src/LockTauContainers.h
new file mode 100644
index 0000000000000000000000000000000000000000..4dc291c80d3fb819a65469972a4bea2e4f999af5
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/LockTauContainers.h
@@ -0,0 +1,35 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_LOCKTAUCONTAINERS_H
+#define	TAUREC_LOCKTAUCONTAINERS_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+/**
+ * @brief  Set tau containers to const to prevent downstream modification.
+ * 
+ * @author Felix Friedrich
+ */
+
+class LockTauContainers : virtual public TauRecToolBase
+{
+    public: 
+  LockTauContainers(const std::string& name);
+  
+  ASG_TOOL_CLASS2(LockTauContainers, TauRecToolBase, ITauToolBase);
+
+        ~LockTauContainers() { }
+
+        virtual StatusCode initialize();
+        virtual StatusCode finalize();  
+        virtual StatusCode execute(xAOD::TauJet&)      { return StatusCode::SUCCESS; }
+        virtual StatusCode eventFinalize();
+	virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+
+	virtual void print() const {}
+};
+
+#endif	/* TAUREC_LOCKTAUCONTAINERS_H */
+
diff --git a/Reconstruction/tauRecTools/src/PhotonConversionPID.cxx b/Reconstruction/tauRecTools/src/PhotonConversionPID.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1d570ff11435ded73635d1851cc3b0d03e1b8cfc
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/PhotonConversionPID.cxx
@@ -0,0 +1,149 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+NAME:     PhotonConversionPID.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  Michael Boehler <michael.boehler@desy.de>
+CREATED:  November 2008
+ ********************************************************************/
+
+#include "PhotonConversionPID.h"
+
+#include "xAODTracking/VertexContainer.h" 
+#include "TrkParticleBase/LinkToTrackParticleBase.h"
+#include "TrkTrackSummary/TrackSummary.h"
+#include "AthContainers/ConstDataVector.h"
+
+PhotonConversionPID::PhotonConversionPID(const std::string& name)
+ :
+TauRecToolBase(name),
+m_ownPolicy(static_cast<int> (SG::VIEW_ELEMENTS)) {
+
+    declareProperty("OwnPolicy", m_ownPolicy);
+    declareProperty("ConversionCandidatesName", m_ConversionCandidatesName = "ConversionCandidate");
+    declareProperty("ConversionOutputName", m_ConversionOutputName = "ConversionsPID_Container");
+    declareProperty("ElectronProbability", m_eProb_cut = 0.9);
+}
+
+/********************************************************************/
+PhotonConversionPID::~PhotonConversionPID() {
+}
+
+/********************************************************************/
+StatusCode PhotonConversionPID::initialize() {
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode PhotonConversionPID::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode PhotonConversionPID::eventFinalize() {
+
+    // ------------------------------------------------------------------ 
+    //               Retrieving VxCandidates (conversions)
+    // ------------------------------------------------------------------ 
+    const xAOD::VertexContainer* ConvContainer;
+    StatusCode sc = evtStore()->retrieve(ConvContainer, m_ConversionCandidatesName);
+
+    if (sc.isFailure() || !ConvContainer) {
+        ATH_MSG_DEBUG(" No VxCandidates container found in TDS !!");
+        return StatusCode::SUCCESS;
+    } else {
+        ATH_MSG_VERBOSE("Processing Conversion Container Name = " << m_ConversionCandidatesName);
+    }
+
+    ATH_MSG_DEBUG("VxContainer " << m_ConversionCandidatesName << " contains " << ConvContainer->size() << " vertices. ");
+
+
+    // ------------------------------------------------------------------------------------------------- 
+    //      Create and record the empty container VxCandidates (conversions after PID)
+    // ------------------------------------------------------------------------------------------------- 
+    ATH_MSG_DEBUG(" Recording identified conversion collection with key: " << m_ConversionOutputName);
+
+    ConstDataVector<xAOD::VertexContainer>* ConversionContainerPID = new ConstDataVector<xAOD::VertexContainer>(static_cast<SG::OwnershipPolicy> (m_ownPolicy));
+
+    sc = evtStore()->record(ConversionContainerPID, m_ConversionOutputName);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("execute() : cannot record CaloCellContainer " << m_ConversionOutputName);
+        return sc;
+    }
+
+    // Loop over ConversionVertex Container:
+    xAOD::VertexContainer::const_iterator itr = ConvContainer->begin();
+    xAOD::VertexContainer::const_iterator itrE = ConvContainer->end();
+
+    for (; itr != itrE; ++itr) {
+
+        const xAOD::Vertex* vxcand = (*itr);
+
+        ATH_MSG_VERBOSE("Tracks at vertex: " << vxcand->nTrackParticles());
+
+        bool isTrk1_Conv = false;
+        bool isTrk2_Conv = false;
+
+        // loop over all tracks of the vertex
+        for (unsigned int i = 0; i < vxcand->nTrackParticles(); i++) {
+            /*
+            // these lines navigate from a VxCandidate to the track summary of each track at vertex
+            Trk::VxTrackAtVertex* tmpVxAtVtx = (*trklist)[i];
+            Trk::ITrackLink* trkLink = tmpVxAtVtx->trackOrParticleLink();
+            Trk::LinkToTrackParticleBase * linkToTrack_part = dynamic_cast<Trk::LinkToTrackParticleBase *> (trkLink);
+            if (!linkToTrack_part) {
+                ATH_MSG_WARNING("dynamic_cast of LinkToTrackParticleBase failed");
+                continue;
+            }
+
+            const Trk::TrackParticleBase* TP_Base = linkToTrack_part->cachedElement();
+            if (!TP_Base) {
+                ATH_MSG_WARNING("could not get TrackParticleBase from linkToTrack_part");
+                continue;
+            }
+
+            const Trk::TrackSummary* summary = TP_Base->trackSummary();
+            */
+            const xAOD::TrackParticle *track = vxcand->trackParticle(i);
+            float eProbabilityHT;
+            if (track && track->summaryValue(eProbabilityHT, xAOD::SummaryType::eProbabilityHT)) {
+                //---------------------------------------------------------------
+                // Checks ID of Conversion Candidates (eProb based on TRT PID)
+                ATH_MSG_VERBOSE("Track " << i + 1 << "  PID: " << eProbabilityHT);
+
+                if (eProbabilityHT > m_eProb_cut) {
+
+                    // both conv tracks pass PID cut (in case of double track conv)
+                    if (i == 0) {
+                        isTrk1_Conv = true;
+                    }
+                    if (i == 1 || vxcand->nTrackParticles() == 1) {
+                        isTrk2_Conv = true;
+                    }
+                }
+
+                //------------------------------------------------------------------
+                // after both tracks have been tested and passed the PID cut the 
+                // Conversions are stored in the new Conversion Container
+                if (isTrk1_Conv == true && isTrk2_Conv == true) {
+                    ATH_MSG_VERBOSE("                   Conversion accepted");
+                    ConversionContainerPID->push_back(vxcand);
+                }
+
+
+            } else {
+                // here a new track summary can be provided (not yet implemented)
+                ATH_MSG_WARNING("No Track Summary has been found! NO Photon Conversion Identification has been made!!!! ");
+            }
+
+        } // end track loop
+    } // end vertex loop
+
+    ATH_MSG_DEBUG("After ID " << ConversionContainerPID->size() << " Conversion are stored in " << m_ConversionOutputName);
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
diff --git a/Reconstruction/tauRecTools/src/PhotonConversionPID.h b/Reconstruction/tauRecTools/src/PhotonConversionPID.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc85bdaf2a3bcb6b107517d338b802d366b3604b
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/PhotonConversionPID.h
@@ -0,0 +1,49 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_PHOTONCONVERSIONPID_H
+#define TAUREC_PHOTONCONVERSIONPID_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+/**
+ * @brief This tool identifies Conversion Candidates via a cut on the electron probability provided by the TRT PID Tool. 
+ * 
+ *  Such Photon Conversions are needed e.g. to find Photon Conversions within the tau decay cone.
+ * 
+ * @author M. Boehler
+ */
+
+class PhotonConversionPID : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+
+  PhotonConversionPID(const std::string& name);
+  ASG_TOOL_CLASS2(PhotonConversionPID, TauRecToolBase, ITauToolBase);
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    ~PhotonConversionPID();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventFinalize();
+    virtual StatusCode execute(xAOD::TauJet&) { return StatusCode::SUCCESS; }
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    int m_ownPolicy;
+
+    std::string m_ConversionCandidatesName;
+    std::string m_ConversionOutputName;
+
+    double m_eProb_cut;
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/PhotonConversionVertex.cxx b/Reconstruction/tauRecTools/src/PhotonConversionVertex.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6bab0395ceb0651620c5f24af7b07791e719dd7e
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/PhotonConversionVertex.cxx
@@ -0,0 +1,152 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+NAME:     PhotonConversionVertex.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  KG Tan <Kong.Guan.Tan@cern.ch>
+CREATED:  May 2011
+
+This tool identifies conversion candidates in/near (definable) a
+tau decay cone by reconstructing the conversion vertices and
+applying a set of cuts optimized for tau conversions on the vertex
+parameters.
+ ********************************************************************/
+
+#include "PhotonConversionVertex.h"
+
+#include "tauEvent/TauJetContainer.h"
+#include "xAODTracking/TrackParticleContainer.h"
+#include "xAODTracking/VertexContainer.h"
+#include "InDetRecToolInterfaces/IVertexFinder.h"
+#include "AthContainers/ConstDataVector.h"
+
+PhotonConversionVertex::PhotonConversionVertex(const std::string& name) :
+TauRecToolBase(name),
+m_vertexFinderTool("InDet::InDetConversionFinderTools") {
+    declareProperty("TauRecContainer", m_inputTauJetContainerName = "TauJets");
+    declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles");
+    declareProperty("OutputConversionVertexContainerName", m_outputConversionVertexContainerName = "ConversionsVertex_Container");
+    declareProperty("MaxTauJetDr", m_maxTauJetDr = 0.5);
+    declareProperty("ConversionFinderTool", m_vertexFinderTool);
+}
+
+PhotonConversionVertex::~PhotonConversionVertex() {
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+StatusCode PhotonConversionVertex::initialize() {
+    // Get the VertexFinderTool
+    if (!retrieveTool(m_vertexFinderTool)) return StatusCode::FAILURE;
+
+    return StatusCode::SUCCESS;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+StatusCode PhotonConversionVertex::finalize() {
+    return StatusCode::SUCCESS;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+StatusCode PhotonConversionVertex::eventFinalize() {
+    // get the jet container from TauEventData, or the StoreGate if it can't find it
+    xAOD::TauJetContainer* tauJetCont = tauEventData()->xAODTauContainer;
+    if (!tauJetCont) {
+        if (!openContainer(tauJetCont, m_inputTauJetContainerName))
+            return StatusCode::FAILURE;
+    }
+
+    // get the track particle container from StoreGate
+    const xAOD::TrackParticleContainer* trackParticleCont = 0;
+    if (!openContainer(trackParticleCont, m_inputTrackParticleContainerName)) return StatusCode::FAILURE;
+
+    // Define container to store
+    xAOD::VertexContainer* conversionCandidatesVxCont = 0;
+    xAOD::VertexAuxContainer* conversionCandidatesVxContAux = 0;
+    conversionCandidatesVxCont = new xAOD::VertexContainer(); // No need to run conversion finding if no tracks are found!
+    conversionCandidatesVxContAux = new xAOD::VertexAuxContainer(); // No need to run conversion finding if no tracks are found!
+    std::pair<xAOD::VertexContainer*, xAOD::VertexAuxContainer*> convContPair;
+
+    // Redo conversion over the tau seed cones, or over entire region
+    if (m_maxTauJetDr > 0.) {
+
+        if (tauJetCont->size() > 0) {
+
+            // Create a temporary TrackParticle container that contains tracks within the tau seed cones
+            ConstDataVector<xAOD::TrackParticleContainer> tempCont (SG::VIEW_ELEMENTS);
+            for (xAOD::TrackParticleContainer::const_iterator tpcItr = trackParticleCont->begin(); tpcItr != trackParticleCont->end(); ++tpcItr) {
+                double minTauDr = getMinDrTauDecay(tauJetCont, *tpcItr);
+                if (minTauDr < m_maxTauJetDr) {
+                    tempCont.push_back(*tpcItr);
+                }
+            }
+            ATH_MSG_VERBOSE("Number of tracks within tau seed cones for conversion finding: " << tempCont.size());
+
+            // Run the conversion finding algorithm over the tau seed cones
+            convContPair = m_vertexFinderTool->findVertex(tempCont.asDataVector());
+            conversionCandidatesVxCont = convContPair.first;
+            conversionCandidatesVxContAux = convContPair.second;
+        } 
+/**
+        else {
+            conversionCandidatesVxCont = new xAOD::VertexContainer(); // No need to run conversion finding if no tracks are found!
+            conversionCandidatesVxContAux = new xAOD::VertexAuxContainer(); // No need to run conversion finding if no tracks are found!
+        }
+**/
+    } else {
+        ATH_MSG_VERBOSE("Running over entire region! Number of tracks: " << trackParticleCont->size());
+
+        // Run the conversion finding algorithm over the entire region!
+        convContPair = m_vertexFinderTool->findVertex(trackParticleCont);
+        conversionCandidatesVxCont = convContPair.first;
+        conversionCandidatesVxContAux = convContPair.second;
+    }
+
+    // Perform the storing
+    ATH_MSG_VERBOSE("Number of conversion vertices found: " << conversionCandidatesVxCont->size());
+    conversionCandidatesVxCont->setStore( conversionCandidatesVxContAux );
+
+    if (!saveContainer(conversionCandidatesVxCont, m_outputConversionVertexContainerName)) return StatusCode::FAILURE;
+    if (!saveContainer(conversionCandidatesVxContAux, m_outputConversionVertexContainerName+"Aux")) return StatusCode::FAILURE;
+
+    return StatusCode::SUCCESS;
+}
+
+template <class T>
+bool PhotonConversionVertex::openContainer(T* &container, std::string containerName) {
+    StatusCode sc = evtStore()->retrieve(container, containerName);
+    if (!container || sc.isFailure())
+        ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate");
+    return container;
+}
+
+template <class T>
+bool PhotonConversionVertex::saveContainer(T* &container, std::string containerName) {
+    StatusCode sc = evtStore()->record(container, containerName);
+    if (!container || sc.isFailure())
+        ATH_MSG_FATAL("Container (" << containerName << ") cannot be saved in StoreGate");
+    return container;
+}
+
+template <class T>
+bool PhotonConversionVertex::retrieveTool(T &tool) {
+    if (tool.retrieve().isFailure()) {
+        ATH_MSG_FATAL("Failed to retrieve tool " << tool);
+        return false;
+    } else {
+        ATH_MSG_VERBOSE("Retrieved tool " << tool);
+    }
+    return true;
+}
+
+double PhotonConversionVertex::getMinDrTauDecay(const xAOD::TauJetContainer* tauJetCont, const xAOD::TrackParticle *trackParticle) {
+    double minDR = 99999.;
+    for (xAOD::TauJetContainer::const_iterator tjcItr = tauJetCont->begin(); tjcItr != tauJetCont->end(); ++tjcItr) {
+        const xAOD::TauJet *tauJet = *tjcItr;
+        double dR = trackParticle->p4().DeltaR(tauJet->p4());
+        if (dR < minDR) minDR = dR;
+    }
+    return minDR;
+}
diff --git a/Reconstruction/tauRecTools/src/PhotonConversionVertex.h b/Reconstruction/tauRecTools/src/PhotonConversionVertex.h
new file mode 100644
index 0000000000000000000000000000000000000000..0f6d2dc2d17296ff91f9b89e5ee7a4f63eada48f
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/PhotonConversionVertex.h
@@ -0,0 +1,91 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_PHOTONCONVERSIONVERTEX_H
+#define TAUREC_PHOTONCONVERSIONVERTEX_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+
+namespace Analysis {
+    class TauJetContainer;
+}
+
+namespace Rec {
+    class TrackParticle;
+}
+
+namespace InDet {
+    class IVertexFinder;
+}
+
+/**
+ * @brief Class that runs the tau conversion finding algorithm
+ * 
+ *  This tool identifies conversion candidates
+ *  in/near (definable) a tau decay cone by reconstructing the conversion vertices 
+ *  and applying a set of cuts optimized for tau conversions on the vertex parameters.
+ * 
+ * @author KG Tan <Kong.Guan.Tan@cern.ch>
+ * 
+ */
+
+class PhotonConversionVertex : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor and Destructor
+    //-------------------------------------------------------------
+    PhotonConversionVertex(const std::string& name);
+    ASG_TOOL_CLASS2(PhotonConversionVertex, TauRecToolBase, ITauToolBase);
+    ~PhotonConversionVertex();
+
+    //-------------------------------------------------------------
+    //! Algorithm functions
+    //-------------------------------------------------------------
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventFinalize();
+    virtual StatusCode execute(xAOD::TauJet&) { return StatusCode::SUCCESS; }
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    //-------------------------------------------------------------
+    //! Convenience functions to handle storegate objects
+    //-------------------------------------------------------------
+    template <class T>
+    bool openContainer(T* &container, std::string containerName);
+
+    template <class T>
+    bool saveContainer(T* &container, std::string containerName);
+
+    template <class T>
+    bool retrieveTool(T &tool);
+
+    //-------------------------------------------------------------
+    //! Gets the minimum dR between a particle and a set of taus
+    //-------------------------------------------------------------
+    double getMinDrTauDecay(const xAOD::TauJetContainer* tauJetCont, const xAOD::TrackParticle *trackParticle);
+
+private:
+    //-------------------------------------------------------------
+    //! Storegate names of input containers and output containers
+    //-------------------------------------------------------------
+    std::string m_inputTauJetContainerName;
+    std::string m_inputTrackParticleContainerName;
+    std::string m_outputConversionVertexContainerName;
+
+    //-------------------------------------------------------------
+    //! Input parameters for conversion finding
+    //-------------------------------------------------------------
+    double m_maxTauJetDr;
+
+    //-------------------------------------------------------------
+    //! Tool used by conversion finding, initialised in job options
+    //-------------------------------------------------------------
+    ToolHandle<InDet::IVertexFinder> m_vertexFinderTool;
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauAxisSetter.cxx b/Reconstruction/tauRecTools/src/TauAxisSetter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fd298e988e025d51abaffe5edebe9b13d6025110
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauAxisSetter.cxx
@@ -0,0 +1,168 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "CLHEP/Vector/LorentzVector.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "FourMomUtils/P4Helpers.h"
+#include "FourMom/P4EEtaPhiM.h"
+#include "JetEvent/Jet.h"
+#include "CaloEvent/CaloCluster.h"
+
+//tau
+#include "tauRecTools/TauEventData.h"
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+#include "xAODTau/TauJet.h"
+
+#include "CaloUtils/CaloVertexedCluster.h"
+
+#include "TauAxisSetter.h"
+
+/********************************************************************/
+TauAxisSetter::TauAxisSetter(const std::string& name) :
+TauRecToolBase(name),
+m_clusterCone(0.2),
+m_doCellCorrection(false),
+m_doAxisCorrection(true)
+{
+    declareProperty("ClusterCone", m_clusterCone);
+    declareProperty("tauContainerKey", tauContainerKey = "TauJets");
+    declareProperty("CellCorrection", m_doCellCorrection);
+    declareProperty("AxisCorrection", m_doAxisCorrection = true);
+}
+
+/********************************************************************/
+TauAxisSetter::~TauAxisSetter() { }
+
+/********************************************************************/
+StatusCode TauAxisSetter::initialize()
+{
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauAxisSetter::eventInitialize() 
+{
+    return StatusCode::SUCCESS;
+      
+}
+
+/********************************************************************/
+StatusCode TauAxisSetter::execute(xAOD::TauJet& pTau)
+{
+
+    const xAOD::Jet* pJetSeed = (*pTau.jetLink());
+    if (!pJetSeed) {
+        ATH_MSG_WARNING("tau does not have jet seed for LC calibration");
+        return StatusCode::SUCCESS;
+    }
+
+    xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin();
+    xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end();
+
+    ///////////////////////////////////////////////////////////////////////////
+    //calculate barycenter
+    TLorentzVector sumAllClusterVector;
+    TLorentzVector tempClusterVector;
+    for (; cItr != cItrE; ++cItr) {
+      tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() );
+
+      sumAllClusterVector += tempClusterVector;
+    }
+    TLorentzVector BaryCenter; 
+    BaryCenter.SetPtEtaPhiM(1., sumAllClusterVector.Eta(), sumAllClusterVector.Phi(), 0.);
+
+    
+    ///////////////////////////////////////////////////////////////////////////
+    // calculate detector axis
+    TLorentzVector tauDetectorAxis;
+    // count number of constituents in core cone. could be zero!
+    int nConstituents = 0;
+    for (cItr = pJetSeed->getConstituents().begin(); cItr != cItrE; ++cItr) {
+	tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() );
+
+	ATH_MSG_VERBOSE("cluster in detector axis loop:" << (*cItr)->pt()<< " " << (*cItr)->eta() << " " << (*cItr)->phi()  << " " << (*cItr)->e() );
+	ATH_MSG_VERBOSE("delta R is " << BaryCenter.DeltaR(tempClusterVector) );
+
+        if (BaryCenter.DeltaR(tempClusterVector) > m_clusterCone)
+            continue;
+
+	nConstituents++;
+	tauDetectorAxis += tempClusterVector;
+    }
+    
+    if  (nConstituents == 0)
+      {
+	StatusCode sc;
+	bool isCosmics = false;
+	if (tauEventData()->hasObject("IsCosmics?")) {
+	  sc = tauEventData()->getObject("IsCosmics?", isCosmics);
+	}
+	 
+	// If running cosmic triggers, don't worry about not having clusters in tau
+	if(tauEventData()->inTrigger() && isCosmics){
+	  ATH_MSG_WARNING("this tau candidate does not have any constituent clusters! breaking off tau tool chain and not recording this candidate!");
+	} else {
+	  ATH_MSG_DEBUG("this tau candidate does not have any constituent clusters! breaking off tau tool chain and not recording this candidate!");
+	}
+	return StatusCode::FAILURE;
+      }
+
+    ATH_MSG_VERBOSE("jet axis:" << (*pTau.jetLink())->pt()<< " " << (*pTau.jetLink())->eta() << " " << (*pTau.jetLink())->phi()  << " " << (*pTau.jetLink())->e() );
+    // save values for detector axis.
+    // FixMe: consider dropping these details variables as they are duplicated in the detector axis 4 vector
+    pTau.setDetail(xAOD::TauJetParameters::LC_TES_precalib , static_cast<float>( tauDetectorAxis.Pt() ) );		  
+    pTau.setDetail(xAOD::TauJetParameters::seedCalo_eta, static_cast<float>( tauDetectorAxis.Eta() ) );
+    pTau.setDetail(xAOD::TauJetParameters::seedCalo_phi, static_cast<float>( tauDetectorAxis.Phi() ) );
+    ATH_MSG_VERBOSE("detector axis:" << tauDetectorAxis.Pt()<< " " << tauDetectorAxis.Eta() << " " << tauDetectorAxis.Phi()  << " " << tauDetectorAxis.E() );
+
+    // detectorAxis (set default) 
+    pTau.setP4(tauDetectorAxis.Pt(), tauDetectorAxis.Eta(), tauDetectorAxis.Phi(), pTau.m());
+    // save detectorAxis 
+    pTau.setP4(xAOD::TauJetParameters::DetectorAxis, tauDetectorAxis.Pt(), tauDetectorAxis.Eta(), tauDetectorAxis.Phi(), tauDetectorAxis.M());
+
+    ///////////////////////////////////////////////////////////////////////////
+    // calculate tau intermediate axis (corrected for tau vertex)
+    // not needed at trigger level
+    if(m_doAxisCorrection)
+      {
+	TLorentzVector tauInterAxis;
+	
+	for (cItr = pJetSeed->getConstituents().begin(); cItr != cItrE; ++cItr) {
+	  tempClusterVector.SetPtEtaPhiE( (*cItr)->pt(), (*cItr)->eta(), (*cItr)->phi(), (*cItr)->e() );
+	  if (BaryCenter.DeltaR(tempClusterVector) > m_clusterCone)
+	    continue;
+	  
+	  const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); 
+	  if (!cluster) continue;
+	  
+	  if (pTau.vertexLink())
+	    tauInterAxis += xAOD::CaloVertexedCluster(*cluster, (*pTau.vertexLink())->position()).p4();
+	  else
+	    tauInterAxis += xAOD::CaloVertexedCluster(*cluster).p4();
+	}
+	
+	// save values for tau intermediate axis
+	// energy will be overwritten by EnergyCalibrationLC (if correctEnergy is enabled)
+	// direction will be overwritten by EnergyCalibrationLC (if correctAxis is enabled)
+	
+	// intermediate axis( set default) 
+	pTau.setP4(tauInterAxis.Pt(), tauInterAxis.Eta(), tauInterAxis.Phi(), pTau.m());
+	
+	ATH_MSG_VERBOSE("tau axis:" << tauInterAxis.Pt()<< " " << tauInterAxis.Eta() << " " << tauInterAxis.Phi()  << " " << tauInterAxis.E() );
+	
+	// save intermediateAxis 
+	pTau.setP4(xAOD::TauJetParameters::IntermediateAxis, tauInterAxis.Pt(), tauInterAxis.Eta(), tauInterAxis.Phi(), tauInterAxis.M());
+      }
+    
+    return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Finalize
+//-----------------------------------------------------------------------------
+StatusCode TauAxisSetter::finalize()
+{
+    return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/src/TauAxisSetter.h b/Reconstruction/tauRecTools/src/TauAxisSetter.h
new file mode 100644
index 0000000000000000000000000000000000000000..a95997784976474acf95fe6f6dae57e890500a9d
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauAxisSetter.h
@@ -0,0 +1,52 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUAXISSETTER_H
+#define TAUREC_TAUAXISSETTER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+
+/**
+ * @brief Set Tau "Detector Axis" and "Intermediate Axis". 
+ * 
+ *  Note that both axes starts from the barycenter of the cluster associated to the jet seed. 
+ *  Then only the 4-vectors of clusters in a cone of dR around these barycenter are summed up, forming the new axis.
+ *  For the "Intermediate Axis" the clusters are correct wrt tau vertex in this step (barycenter remains the same).
+ *  Using this procedure, the axes are different from the original jet seed axis.
+ * 
+ * @author Margar Simonyan
+ * @author Felix Friedrich
+ *                                                                              
+ */
+
+class TauAxisSetter : virtual public TauRecToolBase {
+public:
+
+    TauAxisSetter(const std::string& name);
+    ASG_TOOL_CLASS2(TauAxisSetter, TauRecToolBase, ITauToolBase);
+    ~TauAxisSetter();
+
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+    virtual void print() const { }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+
+private:
+    std::string tauContainerKey;
+    
+    double m_clusterCone;
+    /** 
+     * enable cell origin correction 
+     * eta and phi of the cells are corrected wrt to the origin of the tau vertex
+     */
+    bool m_doCellCorrection;
+    bool m_doAxisCorrection;
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauCalibrateEM.cxx b/Reconstruction/tauRecTools/src/TauCalibrateEM.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6f4533d973cbc1a6f1cdc2afaddb819f509aad6f
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauCalibrateEM.cxx
@@ -0,0 +1,187 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TFile.h"
+#include "TF1.h"
+#include "GaudiKernel/Property.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+#include "EventKernel/SignalStateHelper.h"
+#include "JetEvent/Jet.h"
+
+#include "xAODTau/TauJet.h"
+#include "tauRecTools/TauEventData.h"
+#include "tauRecTools/ITauToolBase.h"
+#include "TauCalibrateEM.h"
+
+using CLHEP::GeV;
+
+//-------------------------------------------------------------------------
+// Constructor
+//------------------------------------------------------------------------
+
+TauCalibrateEM::TauCalibrateEM(const std::string& name) :
+TauRecToolBase(name) {
+    declareProperty("response_functions_file", m_response_functions_file = "EMTES_Fits_Oct2010.root");
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauCalibrateEM::~TauCalibrateEM() {
+}
+
+//-------------------------------------------------------------------------
+// initialize
+//-------------------------------------------------------------------------
+
+StatusCode TauCalibrateEM::initialize() {
+
+    std::string response_functions_path = find_file(m_response_functions_file);
+    TFile* f = TFile::Open(response_functions_path.c_str(), "READ");
+
+    m_f1_1p_lem = new TF1(*((TF1*) f->Get("OneP_LowEMF_Eta_All")));
+    m_f1_1p_hem_barrel = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_0")));
+    m_f1_1p_hem_crack = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_1")));
+    m_f1_1p_hem_endcap = new TF1(*((TF1*) f->Get("OneP_HighEMF_Eta_2")));
+    m_f1_mp_barrel = new TF1(*((TF1*) f->Get("MultiP_Eta_0")));
+    m_f1_mp_crack = new TF1(*((TF1*) f->Get("MultiP_Eta_1")));
+    m_f1_mp_endcap = new TF1(*((TF1*) f->Get("MultiP_Eta_2")));
+
+    m_min_1p_lem.first = m_f1_1p_lem->GetMinimumX(1.5, 3.0);
+    m_min_1p_lem.second = m_f1_1p_lem->Eval(m_min_1p_lem.first);
+    m_min_1p_hem_barrel.first = m_f1_1p_hem_barrel->GetMinimumX(1.5, 3.0);
+    m_min_1p_hem_barrel.second = m_f1_1p_hem_barrel->Eval(m_min_1p_hem_barrel.first);
+    m_min_1p_hem_crack.first = m_f1_1p_hem_crack->GetMinimumX(1.5, 3.0);
+    m_min_1p_hem_crack.second = m_f1_1p_hem_crack->Eval(m_min_1p_hem_crack.first);
+    m_min_1p_hem_endcap.first = m_f1_1p_hem_endcap->GetMinimumX(1.5, 3.0);
+    m_min_1p_hem_endcap.second = m_f1_1p_hem_endcap->Eval(m_min_1p_hem_endcap.first);
+    m_min_mp_barrel.first = m_f1_mp_barrel->GetMinimumX(2.0, 3.0);
+    m_min_mp_barrel.second = m_f1_mp_barrel->Eval(m_min_mp_barrel.first);
+    m_min_mp_crack.first = m_f1_mp_crack->GetMinimumX(2.0, 3.0);
+    m_min_mp_crack.second = m_f1_mp_crack->Eval(m_min_mp_crack.first);
+    m_min_mp_endcap.first = m_f1_mp_endcap->GetMinimumX(2.5, 3.5);
+    m_min_mp_endcap.second = m_f1_mp_endcap->Eval(m_min_mp_endcap.first);
+
+    f->Close();
+    return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// execute
+//-------------------------------------------------------------------------
+
+StatusCode TauCalibrateEM::execute(xAOD::TauJet& pTau) {
+
+    const xAOD::Jet* pJetSeed = (*pTau.jetLink());
+
+    // XXX still need to migrate to signalstate handling of xAOD::Jet
+    // SignalStateHelper sigstateH(P4SignalState::JETEMSCALE);
+    // sigstateH.controlObject(pJetSeed);
+
+    float emscale_ptEM = 0;
+    float emscale_ptHad = 0;
+    
+    if ( !pTau.detail( xAOD::TauJetParameters::etEMAtEMScale, emscale_ptEM ) ) 
+      {
+	ATH_MSG_DEBUG("retrieval of tau detail failed. not calculating new em scale pt");
+	return StatusCode::SUCCESS;
+      }
+
+    if ( !pTau.detail( xAOD::TauJetParameters::etHadAtEMScale, emscale_ptHad ) )
+      {
+	ATH_MSG_DEBUG("retrieval of tau detail failed. not calculating new em scale pt");
+	return StatusCode::SUCCESS;
+      }
+
+    double emscale_pt = emscale_ptEM + emscale_ptHad;
+    double emscale_eta = pJetSeed->eta();
+    double emfrac = (emscale_pt != 0) ? emscale_ptEM / emscale_pt : 0.;
+
+
+    ATH_MSG_DEBUG("input variables: em_pt " << emscale_pt << " eta " << emscale_eta << " ntrack " << pTau.nTracks() << " emfrac " << emfrac);
+
+    double new_pt = evaluate_new_pt(emscale_pt / GeV, fabs(emscale_eta), pTau.nTracks(), emfrac);
+
+
+    // do NOT set TauJet energy, as this will be done in tauCalibrateLC
+    //pTau.setE( new_pt * GeV * cosh( pTau.eta() ) );
+
+    // instead fill place holder in TauCommonDetails
+    //pDetails->setSeedCalo_etEMCalib(new_pt * GeV);
+    
+    pTau.setDetail( xAOD::TauJetParameters::EM_TES_scale, static_cast<float>( new_pt * GeV ) );
+
+    return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Finalize
+//-----------------------------------------------------------------------------
+
+StatusCode TauCalibrateEM::finalize() {
+    delete m_f1_1p_lem;
+    delete m_f1_1p_hem_barrel;
+    delete m_f1_1p_hem_crack;
+    delete m_f1_1p_hem_endcap;
+    delete m_f1_mp_barrel;
+    delete m_f1_mp_crack;
+    delete m_f1_mp_endcap;
+
+    return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// calculate new tau pt at EM scale
+//-----------------------------------------------------------------------------
+
+double TauCalibrateEM::evaluate_new_pt(double pt, double eta, int ntrack, double emfrac) {
+
+    if (pt <= 0)return 0;
+    double ln_pt = log(pt);
+    if (ln_pt > 8.5) return pt;
+
+    if (ntrack <= 1) {
+        // corrections for single prong taus
+
+        if (emfrac < 0.15) {
+            // corrections for low EMF      
+            if (ln_pt < m_min_1p_lem.first) return pt / m_min_1p_lem.second;
+            else return pt / m_f1_1p_lem->Eval(ln_pt);
+        } else {
+            // corrections for high EMF
+
+            if (eta < 1.3) {
+                if (ln_pt < m_min_1p_hem_barrel.first) return pt / m_min_1p_hem_barrel.second;
+                else return pt / m_f1_1p_hem_barrel->Eval(ln_pt);
+            } else if (eta < 1.6) {
+                if (ln_pt < m_min_1p_hem_crack.first) return pt / m_min_1p_hem_crack.second;
+                else return pt / m_f1_1p_hem_crack->Eval(ln_pt);
+            } else {
+                if (ln_pt < m_min_1p_hem_endcap.first) return pt / m_min_1p_hem_endcap.second;
+                else return pt / m_f1_1p_hem_endcap->Eval(ln_pt);
+            }
+        }
+
+    } else {
+        // corrections for multi-prong taus
+
+        if (eta < 1.3) {
+            if (ln_pt < m_min_mp_barrel.first) return pt / m_min_mp_barrel.second;
+            else return pt / m_f1_mp_barrel->Eval(ln_pt);
+        } else if (eta < 1.6) {
+            if (ln_pt < m_min_mp_crack.first) return pt / m_min_mp_crack.second;
+            else return pt / m_f1_mp_crack->Eval(ln_pt);
+        } else {
+            if (ln_pt < m_min_mp_endcap.first) return pt / m_min_mp_endcap.second;
+            else return pt / m_f1_mp_endcap->Eval(ln_pt);
+        }
+    }
+
+    return pt;
+}
+
+// EOF
+
+
diff --git a/Reconstruction/tauRecTools/src/TauCalibrateEM.h b/Reconstruction/tauRecTools/src/TauCalibrateEM.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c3d228b1e91ef5be11152cd7f417286363c44cc
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauCalibrateEM.h
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCALIBRATEEM_H
+#define	TAUREC_TAUCALIBRATEEM_H
+
+#include <string>
+#include <tauRecTools/TauRecToolBase.h>
+
+class TF1;
+
+/** implementation of tau EM energy scale (depreciated) */
+class TauCalibrateEM : virtual public TauRecToolBase {
+public:
+    TauCalibrateEM(const std::string& name);
+    ASG_TOOL_CLASS2(TauCalibrateEM, TauRecToolBase, ITauToolBase);
+    ~TauCalibrateEM();
+
+    virtual StatusCode initialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();
+
+    virtual void print() const { }
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+private:
+    // private methods
+    double evaluate_new_pt(double pt, double eta, int ntrack, double emfrac);
+
+    // configurables
+    std::string m_response_functions_file;
+
+    // private data
+    TF1* m_f1_1p_lem;
+    TF1* m_f1_1p_hem_barrel;
+    TF1* m_f1_1p_hem_crack;
+    TF1* m_f1_1p_hem_endcap;
+    TF1* m_f1_mp_barrel;
+    TF1* m_f1_mp_crack;
+    TF1* m_f1_mp_endcap;
+
+    std::pair<double, double> m_min_1p_lem;
+    std::pair<double, double> m_min_1p_hem_barrel;
+    std::pair<double, double> m_min_1p_hem_crack;
+    std::pair<double, double> m_min_1p_hem_endcap;
+    std::pair<double, double> m_min_mp_barrel;
+    std::pair<double, double> m_min_mp_crack;
+    std::pair<double, double> m_min_mp_endcap;
+
+};
+
+#endif	/* TAUCALIBRATEEM_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauCellVariables.cxx b/Reconstruction/tauRecTools/src/TauCellVariables.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..b62c6c17c4af6d569b0818f370efbad486ba6ac3
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauCellVariables.cxx
@@ -0,0 +1,392 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+NAME:     TauCellVariables.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  S. Rajagopalan
+CREATED:  March 15, 2001
+
+Aug 2001: Add (e,px,py,pz) for sum of EM cells (FEP)
+Veto cell if track is within 0.8*size. Hence 1 cell if track
+is in center, more otherwise.
+ 
+Sep 2001: Take account of larger cells in third layer
+
+Nov 2001: Omit third layer of EM calorimeter from EM sums. This layer
+can become quite thick in the barrel, so it is more likely to
+be hadronic, while photons are mainly contained in the first
+two layers. (D. Lissauer suggested this.)
+
+Dec 2002: Add tau likelihood calculation.
+Feb 2003: Fix phi wrapping for et-weighted phi calculation.
+Jan 2004: Use CLHEP units. Use phi = (-pi,pi].
+Feb 2004: Fix identifiers, add taucmsdrdR
+March 2004: Fix CaloCluster -> CaloEnergyCluster
+Jul 2004: force -PI < phi < PI
+Jul 2004: move to I4Momentum
+Aug 2004: admit arbitrary seeds
+23/10/2006 - (AK) fixing some compilation warnings (unused parameter)
+18/04/2007 - (AK) fixing some compilation warnings (unused parameter)
+18/01/2008 - (NM) use etaCalo/phiCalo for merged algo, set tauJet eta/phi if not set by tau1p3p
+16/03/2010 - (AK) use the cell id instead of the pointer
+17/03/2010 - (AK) change to P4Helpers
+16/05/2011 - (FF) introduce possibility to correct cell origin wrt to primary vertex and beamspot
+Jan 2012   - (FF) add cellEnergyRing variables
+ ********************************************************************/
+
+#include <algorithm> 
+#include <math.h>
+#include <vector>
+#include <sstream>
+
+#include "GaudiKernel/Property.h"
+#include "CLHEP/Units/SystemOfUnits.h"
+
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "CaloUtils/CaloCellList.h"
+#include "CaloEvent/CaloCluster.h"
+#include "CaloEvent/CaloCell.h"
+#include "CaloEvent/CaloSamplingHelper.h"
+#include "CaloUtils/CaloVertexedCell.h"
+#include "CaloIdentifier/CaloID.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloGeoHelpers/CaloSampling.h"
+#include "Particle/TrackParticle.h"
+#include "FourMom/P4EEtaPhiM.h"
+
+#include "xAODTau/TauJet.h"
+#include "xAODJet/Jet.h"
+#include "tauRecTools/KineUtils.h"
+#include "TauCellVariables.h"
+
+using CLHEP::GeV;
+
+TauCellVariables::TauCellVariables(const std::string& name) :
+  TauRecToolBase(name),
+m_cellEthr(0.2 * GeV),
+m_stripEthr(0.2 * GeV),
+m_EMSumThr(0.5 * GeV),
+m_EMSumR(0.2),
+m_cellCone(0.2),
+m_doCellCorrection(false) //FF: don't do cell correction by default
+{
+
+    declareProperty("CellEthreshold", m_cellEthr);
+    declareProperty("StripEthreshold", m_stripEthr);
+    declareProperty("EMSumThreshold", m_EMSumThr);
+    declareProperty("EMSumRadius", m_EMSumR);
+    declareProperty("CellCone", m_cellCone);
+    declareProperty("CellCorrection", m_doCellCorrection);
+}
+
+TauCellVariables::~TauCellVariables() {
+}
+
+StatusCode TauCellVariables::finalize() {
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TauCellVariables::initialize() {
+    
+    ATH_MSG_VERBOSE("TauCellVariables::initialize"); // DEBUG
+    
+    StatusCode sc;
+
+    // retrieve all helpers from det store
+    sc = detStore()->retrieve(m_emid);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("Unable to retrieve LArEM_ID helper from DetectorStore");
+        return sc;
+    }
+    ATH_MSG_VERBOSE("Storegate retrieved"); // DEBUG
+
+    sc = detStore()->retrieve(m_tileid);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR("Unable to retrieve TileID helper from DetectorStore");
+        return sc;
+    }
+    ATH_MSG_VERBOSE("TileID from DetectorStore"); // DEBUG
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauCellVariables::eventInitialize() {
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauCellVariables::execute(xAOD::TauJet& pTau) {
+
+    ATH_MSG_VERBOSE("execute"); // DEBUG
+
+    AtlasDetectorID AtlasID;
+
+    int numStripCell = 0;
+    int numEMCell = 0;
+
+    double sumCellE = 0.;
+    double sumEMCellE = 0.;
+
+    double eta = 0.;
+    double phi = 0.;
+    double stripEta = 0.;
+    double stripEta2 = 0.;
+
+    double EMRadius = 0.;
+
+    double sumStripET = 0.;
+    double sumCellET = 0.;
+    double sumEMCellET = 0.;
+    double sumCellET12 = 0.;
+
+    double ET1Sum = 0;
+
+    double EMET1Sum = 0;
+    double EMET4Sum = 0;
+
+    double HadRadius = 0.;
+    double sumHadCellET = 0.;
+
+    double cellEta, cellPhi, cellET, cellEnergy;
+    
+    std::vector<double> vCellRingEnergy(8,0.); //size=8, init with 0.
+
+    ATH_MSG_VERBOSE("get cluster position, use for cell loop");
+
+    ATH_MSG_VERBOSE("position is eta=" << pTau.eta() << " phi=" << pTau.phi() );
+
+    //use tau vertex to correct cell position
+    bool applyCellCorrection = false;
+    if (m_doCellCorrection && pTau.vertexLink()) {
+       applyCellCorrection = true;
+    }
+
+    ///////////////////////////////////////////////////////////////////////
+    // loop over all cells of the tau (placed there by the TauSeedBuilder)
+  
+    const xAOD::Jet* pJetSeed = (*pTau.jetLink());
+    if (!pJetSeed) {
+      ATH_MSG_WARNING("tau does not have jet seed for cell variable calculation");
+      return StatusCode::SUCCESS;
+    }
+
+    xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin();
+    xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end();
+
+    unsigned int num_cells = 0;
+
+    std::bitset<200000> cellSeen;
+
+    for (; cItr != cItrE; ++cItr) {
+      
+      const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); 
+
+      CaloClusterCellLink::const_iterator firstcell = cluster->getCellLinks()->begin();
+      CaloClusterCellLink::const_iterator lastcell = cluster->getCellLinks()->end();
+      
+
+      // ATH_MSG_VERBOSE( "in loop over clusters and cells : cluster  phi= " << cluster->phi() << ", eta= " << cluster->eta()<< ", energy= " << cluster->e() << ", et= " <<cluster->pt() );
+    
+    const CaloCell *cell;
+    double dR;
+    
+    //loop over cells and calculate the variables
+    for (; firstcell != lastcell; ++firstcell) {
+        cell = *firstcell;
+
+
+	if (cellSeen.test(cell->caloDDE()->calo_hash())) {
+	  //already encountered this cell
+	  continue;
+	}
+	else {
+	  //New cell
+	  cellSeen.set(cell->caloDDE()->calo_hash());
+	}
+        ++num_cells;
+
+	// ATH_MSG_VERBOSE( "in loop over clusters and cells : phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() );
+
+        // correct cell for tau vertex
+        if (applyCellCorrection) {
+          //ATH_MSG_INFO( "before cell correction: phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() );
+          CaloVertexedCell vxCell (*cell, (*pTau.vertexLink())->position());
+          cellPhi = vxCell.phi();
+          cellEta = vxCell.eta();
+          cellET = vxCell.et();
+          cellEnergy = vxCell.energy();
+        }
+        else {
+          cellPhi = cell->phi();
+          cellEta = cell->eta();
+          cellET = cell->et();
+          cellEnergy = cell->energy();          
+        }
+        
+        CaloSampling::CaloSample calo = cell->caloDDE()->getSampling();
+
+        // Use cells those are in DR < m_cellCone of eta,phi of tau intermediate axis:
+	dR = Tau1P3PKineUtils::deltaR(pTau.eta(),pTau.phi(),cellEta,cellPhi);
+        
+        if (dR < m_cellCone) {
+            // Global sums
+            sumCellE += cellEnergy;
+
+            eta += cellEnergy * cellEta;
+
+            // Must handle phi wrapping! Compute relative to cluster phi:
+            double dphicc = cellPhi - pTau.phi();
+            if (dphicc > M_PI) dphicc = dphicc - 2 * M_PI;
+            if (dphicc < -M_PI) dphicc = dphicc + 2 * M_PI;
+            
+            phi += cellEnergy*dphicc;
+
+            // If cell is an EM cell, include in sum for EM radius and for
+            // total EM (e,px,py,pz)
+            // Nov 2000: Only include first 2 layers in EM
+
+            if (dR < 0.1) ET1Sum += cellET;
+
+            if ((calo == CaloSampling::PreSamplerB) ||
+                (calo == CaloSampling::PreSamplerE) ||
+
+                (calo == CaloSampling::EMB1) ||
+                (calo == CaloSampling::EME1) ||
+
+                (calo == CaloSampling::EMB2) ||
+                (calo == CaloSampling::EME2) ||
+
+                (calo == CaloSampling::EMB3) ||
+                (calo == CaloSampling::EME3)) {
+                if (dR < 0.1) EMET1Sum += cellET;
+                if (dR < m_cellCone) EMET4Sum += cellET;
+            }
+
+            if ((calo == CaloSampling::PreSamplerB) ||
+                (calo == CaloSampling::PreSamplerE) ||
+
+                (calo == CaloSampling::EMB1) ||
+                (calo == CaloSampling::EME1) ||
+
+                (calo == CaloSampling::EMB2) ||
+                (calo == CaloSampling::EME2)) {
+
+                sumEMCellE += cellEnergy;
+
+                // If cell is a strip cell, sum for stripET calculation:
+                if (((calo == CaloSampling::EMB1) ||
+                    (calo == CaloSampling::EME1)) // to be investigated
+                    && (fabs(cellEta) < 2.5)) {
+                    sumStripET += cellET;
+                    stripEta += cellEta * cellET;
+                    stripEta2 += pow(cellEta, 2) * cellET;
+                    if (cellEnergy > m_stripEthr) numStripCell += 1;
+                } // end of strip cells
+
+                EMRadius += dR*cellET;
+                sumEMCellET += cellET;
+                if (cellEnergy > m_cellEthr) numEMCell += 1;
+
+            }// end of EM cells
+            else { // HAD cells
+                HadRadius += dR*cellET;
+                sumHadCellET += cellET;
+            }
+
+            //  Sum cells in 0.1 < DR < 0.2 for Econe calculation
+            sumCellET += cellET;
+            if (dR > 0.1 && dR < 0.2) sumCellET12 += cellET;
+
+        }// end of dR <  m_cellCone
+        else {
+            // nothing
+        }
+
+        // vCellRingEnergy[0] is a dummy value
+        if (dR < 0.05) vCellRingEnergy[1] += cellET;
+        if (dR >= 0.05 && dR < 0.075) vCellRingEnergy[2] += cellET;
+        if (dR >= 0.075 && dR < 0.1) vCellRingEnergy[3] += cellET;
+        if (dR >= 0.1 && dR < 0.125) vCellRingEnergy[4] += cellET;
+        if (dR >= 0.125 && dR < 0.15) vCellRingEnergy[5] += cellET;
+        if (dR >= 0.15 && dR < 0.2) vCellRingEnergy[6] += cellET;
+        if (dR >= 0.2 && dR < 0.4) vCellRingEnergy[7] += cellET;
+
+    } // end of loop over CaloCells
+
+    }// end of loop over seed jet constituents
+
+    ATH_MSG_DEBUG(num_cells << " cells in seed");
+
+    //////////////////////////////////////////////////////////////////////////
+    // save variables
+    // keep this here until we know nobody complains that these were removed together with all extra details variables
+    // pExtraDetails->setSeedCalo_sumCellEnergy(sumCellE);
+    // pExtraDetails->setSeedCalo_sumEMCellEnergy(sumEMCellE);
+    // pExtraDetails->setSeedCalo_nEMCell(numEMCell);
+    // pExtraDetails->setSeedCalo_stripEt(sumStripET);
+    //
+
+    pTau.setDetail(xAOD::TauJetParameters::nStrip , numStripCell );
+
+    // if (fabs(EMET4Sum) > 0.000001)
+    //     pExtraDetails->setSeedCalo_EMCentFrac(EMET1Sum / EMET4Sum);
+    // else
+    //     pExtraDetails->setSeedCalo_EMCentFrac(0);
+
+    if (fabs(sumStripET) > 0.000001) {
+        stripEta = stripEta / sumStripET;
+        stripEta2 = stripEta2 / sumStripET;
+    } else {
+        stripEta = 0;
+        stripEta2 = -1.0;
+    }
+
+    pTau.setDetail(xAOD::TauJetParameters::stripWidth2 , static_cast<float>(stripEta2 - stripEta * stripEta) );
+
+    if (fabs(sumEMCellET) > 0.000001) {
+        EMRadius = EMRadius / sumEMCellET;
+    } else {
+        EMRadius = -1.0;
+    }
+    if (fabs(sumHadCellET) > 0.000001) {
+        HadRadius = HadRadius / sumHadCellET;
+    } else {
+        HadRadius = -1.0;
+    }
+    
+    pTau.setDetail(xAOD::TauJetParameters::EMRadius , static_cast<float>( EMRadius ) );
+    pTau.setDetail(xAOD::TauJetParameters::etEMAtEMScale , static_cast<float>( sumEMCellET ) );
+    pTau.setDetail(xAOD::TauJetParameters::hadRadius , static_cast<float>( HadRadius ) );
+    pTau.setDetail(xAOD::TauJetParameters::etHadAtEMScale , static_cast<float>( sumHadCellET ) );
+    
+    if (fabs(sumCellET) > 0.000001) {
+      pTau.setDetail(xAOD::TauJetParameters::centFrac , static_cast<float>( ET1Sum / sumCellET ) );
+      pTau.setDetail(xAOD::TauJetParameters::isolFrac , static_cast<float>( sumCellET12 / sumCellET ) );
+    } else {
+      pTau.setDetail(xAOD::TauJetParameters::centFrac , static_cast<float>( 0.0 ) );
+      pTau.setDetail(xAOD::TauJetParameters::isolFrac , static_cast<float>( -1.0 ) );
+    }
+
+    //save cell ring energies
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing1 , static_cast<float>( vCellRingEnergy[1] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing2 , static_cast<float>( vCellRingEnergy[2] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing3 , static_cast<float>( vCellRingEnergy[3] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing4 , static_cast<float>( vCellRingEnergy[4] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing5 , static_cast<float>( vCellRingEnergy[5] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing6 , static_cast<float>( vCellRingEnergy[6] ) );
+
+    pTau.setDetail(xAOD::TauJetParameters::cellBasedEnergyRing7 , static_cast<float>( vCellRingEnergy[7] ) );
+
+    return StatusCode::SUCCESS;
+}
+
+
+
+
diff --git a/Reconstruction/tauRecTools/src/TauCellVariables.h b/Reconstruction/tauRecTools/src/TauCellVariables.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3977c1a5df618626b9b4d5ae771048bb46d30d6
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauCellVariables.h
@@ -0,0 +1,53 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCELLVARIABLES_H
+#define	TAUREC_TAUCELLVARIABLES_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+class LArEM_ID;
+class TileID;
+
+/**
+ * @brief Calculate tau calorimeter variables from cell information.
+ * 
+ * @authors  Srini Rajagopalan, Anna Kaczmarska, Felix Friedrich
+ */
+
+class TauCellVariables : virtual public TauRecToolBase {
+
+public:
+    TauCellVariables(const std::string& name);
+    ASG_TOOL_CLASS2(TauCellVariables, TauRecToolBase, ITauToolBase);
+    ~TauCellVariables();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+
+    virtual void print() const { }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+private:
+    double m_cellEthr;  //!< EM cell E threshold
+    double m_stripEthr; //!< cell E threshold for strips
+    double m_EMSumThr;  //!< threshold for 4-vector EM sum
+    double m_EMSumR;    //!< radius for 4-vector EM sum
+    double m_cellCone;  //!< outer cone for cells used in calculations
+
+    const LArEM_ID* m_emid;
+    const TileID* m_tileid;
+
+    /** 
+     * enable cell origin correction 
+     * eta and phi of the cells are corrected wrt to the origin of the tau vertex
+     */
+    bool m_doCellCorrection;
+};
+
+#endif	/* TAUREC_TAUCELLVARIABLES_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauConversionFinder.cxx b/Reconstruction/tauRecTools/src/TauConversionFinder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..41e2b4f77cca1e6772f8af4c2f5e74c9cbdfca07
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauConversionFinder.cxx
@@ -0,0 +1,154 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+NAME:     TauConversionFinder.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  Michael Boehler <michael.boehler@desy.de>
+CREATED:  November 2008
+
+This tool identifies if a tau track is reconstructed as photon 
+conversion track too.
+ ********************************************************************/
+
+#include "TauConversionFinder.h"
+
+#include "xAODTracking/VertexContainer.h" 
+#include "GaudiKernel/IToolSvc.h"
+#include "TrkParticleBase/LinkToTrackParticleBase.h"
+#include "TrkTrackSummary/TrackSummary.h"
+
+/********************************************************************/
+TauConversionFinder::TauConversionFinder(const std::string& name) :
+  TauRecToolBase(name) {
+
+    declareProperty("ConversionCandidatesName", m_ConversionCandidatesName = "ConversionsPID_Container"); //ConversionCandidate
+    declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles");
+    declareProperty("DoNormalTracks", m_do_normal = true);
+    declareProperty("MinElectronProbability", m_eProb_cut = 0.9);
+    declareProperty("AdjustTauCharge", m_adjust_tau_charge = false);
+
+}
+
+/********************************************************************/
+TauConversionFinder::~TauConversionFinder() {
+}
+
+/********************************************************************/
+StatusCode TauConversionFinder::initialize() {
+    ATH_MSG_VERBOSE("TauConversionFinder Initialising");
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode TauConversionFinder::finalize() {
+    ATH_MSG_VERBOSE("TauConversionFinder Finalizing");
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode TauConversionFinder::eventFinalize() {
+
+    StatusCode sc;
+
+//    const Rec::TrackParticleContainer *trackContainer;
+    const xAOD::TrackParticleContainer* trackContainer = 0;
+
+    //TODO: trigger uses getObject
+    sc = evtStore()->retrieve(trackContainer, m_trackContainerName);
+    if (sc.isFailure() || !trackContainer) {
+        ATH_MSG_DEBUG(" No track container found in TDS !!");
+        return StatusCode::SUCCESS;
+    }
+
+    // ------------------------------------------------------------------ 
+    //               Retrieving VxCandidates (conversions)
+    // ------------------------------------------------------------------   
+    const xAOD::VertexContainer* ConvContainer;
+
+    sc = evtStore()->retrieve(ConvContainer, m_ConversionCandidatesName);
+    if (sc.isFailure() || !ConvContainer) {
+        ATH_MSG_DEBUG(" No VxCandidates container found in TDS !!");
+        return StatusCode::SUCCESS;
+    } else {
+        ATH_MSG_VERBOSE("Processing Conversion Container Name = " << m_ConversionCandidatesName);
+    }
+    ATH_MSG_VERBOSE("VxContainer " << m_ConversionCandidatesName << " contains " << ConvContainer->size() << " vertices. ");
+
+    // ------------------------------------------------------------------ 
+    //                    Check number of Tau Tracks
+    // ------------------------------------------------------------------ 
+    if (!m_do_normal) { 
+        return StatusCode::SUCCESS;
+    }
+
+    // running in eventFinalize
+    // therefore need to loop over all tau candidates 
+    xAOD::TauJetContainer *pTauJetCont = tauEventData()->xAODTauContainer;
+
+    for (xAOD::TauJetContainer::iterator tjcItr = pTauJetCont->begin(); tjcItr != pTauJetCont->end(); ++tjcItr) {
+        
+        xAOD::TauJet& pTau = **tjcItr;
+
+        unsigned int numTracks = pTau.nTracks();
+
+        m_numProng = numTracks;
+
+        if (m_do_normal)
+            ATH_MSG_VERBOSE("Number of tau tracks before ConversionFinder (TauJet): " << m_numProng);
+
+        // Loop over Conversion Container placed by TauPhotonConversionFinder
+        xAOD::VertexContainer::const_iterator itr = ConvContainer->begin();
+        xAOD::VertexContainer::const_iterator itrE = ConvContainer->end();
+
+        for (; itr != itrE; ++itr) {
+
+            const xAOD::Vertex* vxcand = (*itr);
+
+            for (unsigned int i = 0; i < vxcand->nTrackParticles(); ++i) {
+
+                const Trk::Track* conv_trk = vxcand->trackParticle(i)->track();
+
+                // just check if the track is reconstructed only by TRT
+                //--------------------------------------------
+                // Find conversion in normal tau tracks
+                if (m_do_normal) {
+                    for (unsigned int j = 0; j < numTracks; ++j) {
+                        const xAOD::TrackParticle *pTauTrack = pTau.track(j);
+                        const Trk::Track* tau_trk_def = pTauTrack->track();
+
+                        if (conv_trk == tau_trk_def) {
+
+                            if (conv_trk->trackSummary()->getPID(Trk::eProbabilityHT) > m_eProb_cut) {
+                              if (!pTau.trackFlag(pTauTrack, xAOD::TauJetParameters::isConversion)) {
+                                  ElementLink<xAOD::TrackParticleContainer> phoConvLink ;
+                                  phoConvLink.setElement(pTauTrack) ;
+                                  phoConvLink.setStorableObject( *trackContainer ) ;
+                                  phoConvLink.index();
+                                  pTau.addTrackLink( phoConvLink ) ;
+                                  pTau.setTrackFlag(pTauTrack, xAOD::TauJetParameters::isConversion, true);
+                                    if (m_adjust_tau_charge)
+                                        pTau.setCharge(pTau.charge() - pTau.track(j)->charge());
+
+                                    m_numProng--;
+                                }
+                            }
+                        }
+                    }
+                }
+
+            }//end of loop over Tracks at vertex
+        }// end of loop over VxContainer
+
+
+        if (m_do_normal)
+            ATH_MSG_VERBOSE("Number of tau tracks after ConversionFinder (TauJet): " << m_numProng);
+    }// end of loop over TauJetContainer
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
diff --git a/Reconstruction/tauRecTools/src/TauConversionFinder.h b/Reconstruction/tauRecTools/src/TauConversionFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b9d3b78be9bcd7ccb2d2a81c703346579465b04
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauConversionFinder.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCONVERSIONFINDER_H
+#define TAUREC_TAUCONVERSIONFINDER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+/**
+ * @brief This tool identifies if a tau track is reconstructed as photon conversion track too.
+ * 
+ * @author M. Boehler
+ */
+
+class TauConversionFinder : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+    TauConversionFinder(const std::string& name);
+    ASG_TOOL_CLASS2(TauConversionFinder, TauRecToolBase, ITauToolBase);
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    ~TauConversionFinder();
+
+    virtual StatusCode initialize();
+    virtual StatusCode eventFinalize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode execute(xAOD::TauJet&) { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    std::string m_vxCandidatesName;
+    std::string m_trackContainerName;
+    std::string m_ConversionCandidatesName;
+
+    bool m_do_normal;
+    double m_eProb_cut;
+    bool m_adjust_tau_charge;
+
+    int m_numProng;
+
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauConversionTagger.cxx b/Reconstruction/tauRecTools/src/TauConversionTagger.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..a11b1151d499cafd38c69498b5bc9a731e2d4f90
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauConversionTagger.cxx
@@ -0,0 +1,176 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauConversionTagger.cxx
+// package:     Reconstruction/tauRec
+// authors:     Dimitris Varouchas
+// date:        2013-11-08
+//
+//
+//-----------------------------------------------------------------------------
+//TODO:
+
+#include <GaudiKernel/IToolSvc.h>
+#include <GaudiKernel/ListItem.h>
+
+#include "FourMomUtils/P4Helpers.h"
+#include "FourMom/P4EEtaPhiM.h"
+#include "CLHEP/Vector/LorentzVector.h"
+#include "Particle/TrackParticle.h"
+
+#include "TrkParameters/TrackParameters.h"
+
+#include "tauRecTools/TauEventData.h"
+#include "tauEvent/TauCommonDetails.h"
+#include "tauEvent/TauJetParameters.h"
+
+#include "TauConversionTagger.h"
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauConversionTagger::TauConversionTagger(const std::string &name) :
+  TauRecToolBase(name),
+        m_trackToVertexTool("Reco::TrackToVertex")
+{
+    declareProperty("ConversionTaggerVersion", m_ConvTaggerVer = 1);
+    declareProperty("TrackContainerName", m_trackContainerName = "InDetTrackParticles");
+    declareProperty("TrackToVertexTool", m_trackToVertexTool);
+    declareProperty ("TRTRatio", m_doTRTRatio = true);
+    declareProperty ("FullInfo", m_storeFullSummary = false);
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauConversionTagger::~TauConversionTagger() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauConversionTagger::initialize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+
+StatusCode TauConversionTagger::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauConversionTagger::execute(xAOD::TauJet& pTau) {
+
+  StatusCode sc;
+
+  sc = m_trackToVertexTool.retrieve();
+  if(sc.isFailure()) {
+    ATH_MSG_ERROR("Could not retrieve TrackToVertexTool");
+    return StatusCode::FAILURE;
+  } 
+
+  //2012 data reporocessing bug
+  //events with no vertices had taus w/ associated tracks
+  if(pTau.vertexLink().isValid()==0) return StatusCode::SUCCESS;
+
+  for(unsigned int j=0; j<pTau.nTracks(); j++ ) {
+
+    const xAOD::TrackParticle *TauJetTrack = pTau.track(j);
+    const Trk::Perigee* perigee = m_trackToVertexTool->perigeeAtVertex(*TauJetTrack, (*pTau.vertexLink())->position());
+
+    // Declare TrackSummary info
+    // Note: all must be of type uint8_t for summaryValue filling to work in xAOD
+    // TODO: check if these default values are sane
+    uint8_t nBLHits             = 0;
+    uint8_t expectBLayerHit     = 0;
+    uint8_t nTRTHighTHits       = 0;
+    uint8_t nTRTHighTOutliers   = 0;
+    float   nTRTHighT_outl      = 0.;
+    uint8_t nTRTXenon           = 0;
+    uint8_t nTRTHits            = 0;
+    uint8_t nTRTOutliers        = 0;
+
+    // Fill TrackSummary info
+    TauJetTrack->summaryValue(nBLHits,xAOD::numberOfBLayerHits);
+    TauJetTrack->summaryValue(expectBLayerHit,xAOD::expectBLayerHit);
+    TauJetTrack->summaryValue(nTRTHighTHits,xAOD::numberOfTRTHighThresholdHits);
+    TauJetTrack->summaryValue(nTRTHighTOutliers,xAOD::numberOfTRTHighThresholdOutliers);
+    nTRTHighT_outl = nTRTHighTHits + nTRTHighTOutliers;
+    TauJetTrack->summaryValue(nTRTXenon,xAOD::numberOfTRTXenonHits);
+    TauJetTrack->summaryValue(nTRTHits,xAOD::numberOfTRTHits);
+    TauJetTrack->summaryValue(nTRTOutliers,xAOD::numberOfTRTOutliers);
+
+    // TODO: check if default value is sane
+    m_TRTHighTOutliersRatio = 0.;
+    if (m_doTRTRatio || m_storeFullSummary) {
+      if (nTRTXenon > 0)
+        m_TRTHighTOutliersRatio = nTRTHighT_outl / nTRTXenon;
+      else if (nTRTHits + nTRTOutliers > 0)
+        m_TRTHighTOutliersRatio = nTRTHighT_outl / (nTRTHits+nTRTOutliers);
+    }
+
+    double pt = TauJetTrack->pt();
+    double d0 = perigee->parameters()[Trk::d0];
+
+
+    m_TrkIsConv = false;
+
+    double Rconv = sqrt(fabs(d0)*pt/(0.15*2.));
+    double auxprod= d0 * perigee->parameters()[Trk::qOverP];
+    double rconvii= auxprod > 0 ? Rconv : -Rconv;
+    delete perigee; //cleanup necessary to prevent mem leak
+
+    if ( m_ConvTaggerVer==0 ) {
+
+      m_a_cut[0][0]=0.0003;  m_b_cut[0][0]=0.1725;
+      m_a_cut[0][1]=0.0003;  m_b_cut[0][1]=0.2025;
+
+      if ( nBLHits==0 && expectBLayerHit ){
+	if( m_TRTHighTOutliersRatio > -m_a_cut[0][0]*Rconv + m_b_cut[0][0] && (-rconvii) > 40 && pt < 20000 ) m_TrkIsConv=true;
+      }
+      else {
+	if( m_TRTHighTOutliersRatio > -m_a_cut[0][1]*Rconv + m_b_cut[0][1] && (-rconvii) > 40 && pt < 20000 ) m_TrkIsConv=true;
+    	}
+    }
+
+    else if ( m_ConvTaggerVer==1 ) {
+
+      m_a_cut[1][0]=0.0003;  m_b_cut[1][0]=0.1725;
+      m_a_cut[1][1]=0.0003;  m_b_cut[1][1]=0.2025;
+
+
+      if(nBLHits==0 ){
+      	if( m_TRTHighTOutliersRatio > -m_a_cut[1][0]*Rconv + m_b_cut[1][0] && (-rconvii) > 40 && pt < 20000 ) m_TrkIsConv=true;
+      }
+      else {
+      	if( m_TRTHighTOutliersRatio > -m_a_cut[1][1]*Rconv + m_b_cut[1][1] && (-rconvii) > 40 && pt < 20000 ) m_TrkIsConv=true;
+      }
+    }
+
+    else {
+
+      ATH_MSG_WARNING("No tau conversion tagger compatible with version "<<m_ConvTaggerVer);
+      return false;
+    }
+
+    ATH_MSG_VERBOSE("Is tau track a conversion? : " << m_TrkIsConv);
+    if (m_TrkIsConv && !pTau.trackFlag(TauJetTrack, xAOD::TauJetParameters::isConversion))
+      pTau.setTrackFlag(TauJetTrack, xAOD::TauJetParameters::isConversion, true);
+  }
+
+  return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauConversionTagger.h b/Reconstruction/tauRecTools/src/TauConversionTagger.h
new file mode 100644
index 0000000000000000000000000000000000000000..af124dd8c75a4aa261ad2de95fd7d43e9f71a328
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauConversionTagger.h
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCONVERSIONTAGGER_H
+#define	TAUREC_TAUCONVERSIONTAGGER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "ITrackToVertex/ITrackToVertex.h"
+
+/**
+ * @brief This tool identifies if a tau track originates from a photon conversion track.
+ * 
+ * @author D. Varouchas
+ */
+
+
+class TauConversionTagger : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+    TauConversionTagger( const std::string& name );
+    ASG_TOOL_CLASS2(TauConversionTagger, TauRecToolBase, ITauToolBase);
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    ~TauConversionTagger();
+
+    virtual StatusCode initialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    
+    std::string m_trackContainerName;
+
+    int m_ConvTaggerVer; 
+    bool m_TrkIsConv;
+    bool m_storeFullSummary;
+    bool m_doTRTRatio;
+    float m_a_cut[2][2], m_b_cut[2][2];	    
+    float m_TRTHighTOutliersRatio;
+    ToolHandle<Reco::ITrackToVertex> m_trackToVertexTool;
+
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauElectronVetoVariables.cxx b/Reconstruction/tauRecTools/src/TauElectronVetoVariables.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..8c4e9c740a80ed064d3deb0b7ed9d1350b779fc8
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauElectronVetoVariables.cxx
@@ -0,0 +1,384 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        tau1p3pEleVeto.cxx
+// package:     Reconstruction/tauRec
+// authors:     Zofia Czyczula
+// date:        2006-09-27
+//
+// 
+// This tool veto electrons.
+//
+// MODIFIED:
+// 02-04-2007 - (AK) protection against missing egamma Collection
+// 25-03-2008 - (AK for ZC) upgade of the code
+// 28-03-1008 - (AK) fix for protection against missing egamma Collection 
+//               ERROR->WARNING
+// 15/04/2008 - (AK) fixing compilation warning bug #35463
+// 03-10-2008 - (ZC) upgarade of the code 
+// 16/03/2010 - (AK) use the cell id instead of the pointer 
+//-----------------------------------------------------------------------------
+
+////
+//TODO: this is cell based and use tracking variables -> can not run on AOD 
+//TODO: rename
+//
+
+#include <algorithm>
+#include <math.h>
+#include <sstream>
+
+#include "GaudiKernel/ListItem.h"
+#include "GaudiKernel/IToolSvc.h"
+#include "GaudiKernel/Property.h"
+
+#include "CaloUtils/CaloCellList.h"
+#include "CaloEvent/CaloCluster.h"
+#include "CaloEvent/CaloCell.h"
+#include "CaloUtils/CaloVertexedCell.h"
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "CaloIdentifier/CaloID.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloGeoHelpers/CaloSampling.h"
+
+#include "xAODTau/TauJet.h"
+#include "xAODJet/Jet.h"
+#include "tauRecTools/KineUtils.h"
+
+#include "TrkParametersIdentificationHelpers/TrackParametersIdHelper.h"
+#include "RecoToolInterfaces/IParticleCaloExtensionTool.h"
+#include "TauElectronVetoVariables.h"
+
+using CLHEP::GeV;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+TauElectronVetoVariables::TauElectronVetoVariables(const std::string &name) :
+TauRecToolBase(name),
+m_doCellCorrection(false), //FF: don't do cell correction by default
+m_caloExtensionTool("Trk::ParticleCaloExtensionTool/ParticleCaloExtensionTool")
+{
+    declareProperty("CellCorrection", m_doCellCorrection);
+    declareProperty("ParticleCaloExtensionTool",   m_caloExtensionTool );
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+TauElectronVetoVariables::~TauElectronVetoVariables() { }
+
+//-------------------------------------------------------------------------
+// Finalizer
+//-------------------------------------------------------------------------
+StatusCode TauElectronVetoVariables::finalize()
+{
+  return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// Initializer
+//-------------------------------------------------------------------------
+StatusCode TauElectronVetoVariables::initialize()
+{
+    if (m_caloExtensionTool.retrieve().isFailure()) {
+      ATH_MSG_ERROR("Cannot find tool named <" << m_caloExtensionTool << ">");
+      return StatusCode::FAILURE;
+    }
+    return StatusCode::SUCCESS;
+}
+StatusCode TauElectronVetoVariables::eventInitialize()
+{
+    return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// Execution
+//-------------------------------------------------------------------------
+StatusCode TauElectronVetoVariables::execute(xAOD::TauJet& pTau)
+{
+
+    if (pTau.nTracks() < 1) {
+        return StatusCode::SUCCESS;
+    }
+
+    ATH_MSG_VERBOSE(name() << " in execute() ...");
+
+    float detPhiTrk = 0.;
+    float detEtaTrk = 0.;
+    float clEtaTrk = 0.;
+    float distEtaTrk = 0.;
+
+    float energy_3phi[101] = {0.0};
+    float eta[101] = {0.0};
+    int max1 = 0;
+    int max2 = 0;
+    int max = 0;
+    int n = 0;
+    float Emax1 = 0.;
+    float Emax2 = 0.;
+    float etamaxcut = 0.158;
+    float phimaxcut = 0.1;
+    float signum_eta = 0.;
+
+    signum_eta = pTau.track(0)->eta() / fabs(pTau.track(0)->eta());
+
+    float sumETCellsLAr = 0.;
+    float eta0cut = 0.075;
+    float eta1cut = 0.0475;
+    float eta2cut = 0.075;
+    float eta3cut = 1.5;
+    float phi0cut = 0.3;
+    float phi1cut = 0.3;
+    float phi2cut = 0.075;
+    float phi3cut = 0.075;
+    float etareg = 0.;
+    float etacase1 = 1.8;
+    float etagran1 = 0.00315;
+    float etagran2 = 0.00415;
+    float sumETCellsHad1 = 0.;
+    float etahadcut = 0.2;
+    float phihadcut = 0.2;
+
+    const CaloCell *pCell;
+
+    //use tau vertex to correct cell position
+    bool applyCellCorrection = false;
+    if (m_doCellCorrection && pTau.vertexLink()) {
+       applyCellCorrection = true;
+    }
+
+    //---------------------------------------------------------------------
+    // Calculate eta, phi impact point of leading track at calorimeter layers EM 0,1,2,3
+    //---------------------------------------------------------------------
+    Trk::TrackParametersIdHelper parsIdHelper;
+        
+    const int numOfsampEM = 4;
+    double eta_extrapol[4];
+    double phi_extrapol[4];
+
+    for (int i = 0; i < numOfsampEM; ++i) {
+      eta_extrapol[i] = -11111.;
+      phi_extrapol[i] = -11111.;
+    }
+
+    // get the extrapolation into the calo
+    const Trk::CaloExtension* caloExtension = 0;
+    if( !m_caloExtensionTool->caloExtension(*pTau.track(0),caloExtension) || caloExtension->caloLayerIntersections().empty() ){
+      ATH_MSG_WARNING("extrapolation of leading track to calo surfaces failed  " );
+      return StatusCode::SUCCESS;
+    }
+
+    // loop over calo layers
+    for( auto cur = caloExtension->caloLayerIntersections().begin(); cur != caloExtension->caloLayerIntersections().end() ; ++cur ){
+      
+      // only use entry layer
+      if( !parsIdHelper.isEntryToVolume((*cur)->cIdentifier()) ) continue;
+      
+      CaloSampling::CaloSample sample = parsIdHelper.caloSample((*cur)->cIdentifier());
+      int index = -1;
+      if( sample == CaloSampling::PreSamplerE || sample == CaloSampling::PreSamplerB ) index = 0;
+      else if( sample == CaloSampling::EME1 || sample == CaloSampling::EMB1 )          index = 1;
+      else if( sample == CaloSampling::EME2 || sample == CaloSampling::EMB2 )          index = 2;
+      else if( sample == CaloSampling::EME3 || sample == CaloSampling::EMB3 )          index = 3;
+      if( index < 0 ) continue;
+      eta_extrapol[index] = (*cur)->position().eta();
+      phi_extrapol[index] = (*cur)->position().phi();
+    }
+
+    for (int i = 0; i < numOfsampEM; ++i) {
+      if ( eta_extrapol[i] < -11110. || phi_extrapol[i] < -11110. )
+	{
+	  ATH_MSG_DEBUG("extrapolation of leading track to calo surfaces failed for sampling : " << i );
+	  return StatusCode::SUCCESS;
+	}
+    }
+
+    const xAOD::Jet* pJetSeed = (*pTau.jetLink());
+    if (!pJetSeed) {
+      ATH_MSG_WARNING("tau does not have jet seed for electron veto cell variable calculation");
+      return StatusCode::SUCCESS;
+    }
+
+    xAOD::JetConstituentVector::const_iterator cItr = pJetSeed->getConstituents().begin();
+    xAOD::JetConstituentVector::const_iterator cItrE = pJetSeed->getConstituents().end();
+
+    std::bitset<200000> cellSeen;
+
+    for (; cItr != cItrE; ++cItr) {
+      
+      const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*cItr)->rawConstituent() ); 
+      
+      CaloClusterCellLink::const_iterator pCellIter  = cluster->getCellLinks()->begin();
+      CaloClusterCellLink::const_iterator pCellIterE = cluster->getCellLinks()->end();
+     
+
+      double cellPhi;
+      double cellEta;
+      double cellET;
+    for (; pCellIter != pCellIterE; pCellIter++) {
+
+        pCell = *pCellIter;
+	
+	if (cellSeen.test(pCell->caloDDE()->calo_hash())) {
+	  //already encountered this cell
+	  continue;
+	}
+	else {
+	  //New cell
+	  cellSeen.set(pCell->caloDDE()->calo_hash());
+	}
+
+
+        if (applyCellCorrection) {
+          //ATH_MSG_INFO( "before cell correction: phi= " << cell->phi() << ", eta= " << cell->eta()<< ", energy= " << cell->energy() << ", et= " <<cell->et() );
+          CaloVertexedCell vxCell (*pCell, (*pTau.vertexLink())->position());
+          cellPhi = vxCell.phi();
+          cellEta = vxCell.eta();
+          cellET = vxCell.et();
+        }
+        else {
+          cellPhi = pCell->phi();
+          cellEta = pCell->eta();
+          cellET = pCell->et();
+        }
+	
+        int sampling = pCell->caloDDE()->getSampling();
+        if (sampling == 4) sampling = 0;
+        if (sampling == 5) sampling = 1;
+        if (sampling == 6) sampling = 2;
+        if (sampling == 7) sampling = 3;
+        if (sampling == 18) sampling = 12;
+        if (sampling == 8) sampling = 12;
+        if (sampling == 15) sampling = 12;
+        if (sampling == 19) sampling = 13;
+        if (sampling == 16) sampling = 13;
+        if (sampling == 20) sampling = 14;
+        if (sampling == 17) sampling = 14;
+	
+        int i = 2;
+        if (sampling < 4) i = sampling;
+        if (sampling == 12 || sampling == 13 || sampling == 14) i = 3;
+
+        detPhiTrk = Tau1P3PKineUtils::deltaPhi( cellPhi, phi_extrapol[i] );
+	detEtaTrk = std::fabs( cellEta - eta_extrapol[i] );
+	clEtaTrk = eta_extrapol[i];
+	distEtaTrk = cellEta - eta_extrapol[i];
+
+        if ((sampling == 0 && detEtaTrk < eta0cut && detPhiTrk < phi0cut) ||
+                (sampling == 1 && detEtaTrk < eta1cut && detPhiTrk < phi1cut) ||
+                (sampling == 2 && detEtaTrk < eta2cut && detPhiTrk < phi2cut) ||
+                (sampling == 3 && detEtaTrk < eta3cut && detPhiTrk < phi3cut)) {
+
+            sumETCellsLAr += cellET;
+        }
+
+        if (sampling == 12 && detEtaTrk < etahadcut && detPhiTrk < phihadcut) sumETCellsHad1 += cellET;
+
+        if (fabs(cellEta) > 0.8 && fabs(cellEta) <= 1.2 && (sampling == 13 || sampling == 14) && detEtaTrk < etahadcut && detPhiTrk < phihadcut) {
+            sumETCellsHad1 += cellET;
+        }
+
+        if (fabs(pTau.track(0)->eta()) <= 1.7) {
+            if (sampling == 1 && detEtaTrk < etamaxcut && detPhiTrk <= phimaxcut) {
+                if ((fabs(cellEta) < 1.37 || fabs(cellEta) > 1.52) && fabs(cellEta) < 1.85) {
+                    if (fabs(clEtaTrk) <= etacase1 && fabs(cellEta) <= etacase1) {
+                        n = 50 + int(distEtaTrk / etagran1);
+                    }
+                    if (fabs(clEtaTrk) <= etacase1 && fabs(cellEta) > etacase1) {
+                        n = 50 + int(signum_eta * ((etacase1 - fabs(clEtaTrk)) / etagran1 + (-etacase1 + fabs(cellEta)) / etagran2));
+                    }
+                    energy_3phi[n] = energy_3phi[n] + cellET / GeV;
+                    eta[n] = signum_eta * (clEtaTrk - cellEta);
+                } else {
+                    energy_3phi[n] = 0;
+                    eta[n] = 0;
+                }
+            }
+        } else {
+            energy_3phi[n] = 0;
+            eta[n] = 0;
+        }
+
+        if (fabs(cellEta) <= etacase1) {
+            etareg = 0.00315;
+        } else {
+            etareg = 0.00415;
+        }
+        
+    } //end cell loop
+
+    }// end jet constituent loop
+
+    for (int m1 = 0; m1 < 101; m1++) {
+        if ((energy_3phi[m1] > Emax1)) {
+            Emax1 = energy_3phi[m1];
+            max1 = m1;
+        }
+    }
+
+    for (int m2 = 1; m2 < 100; m2++) {
+        if (m2 == max1) continue;
+
+        if ((energy_3phi[m2] > Emax2) && (energy_3phi[m2] > energy_3phi[m2 - 1]) && (energy_3phi[m2] > energy_3phi[m2 + 1])) {
+            Emax2 = energy_3phi[m2];
+            max2 = m2;
+        }
+    }
+
+    if (fabs(eta[max1]) >= etareg) {
+        max = max1;
+    } else {
+        max = max2;
+    }
+
+
+    float TRTratio = -9999.0;
+    uint8_t TRTHTHits;
+    uint8_t TRTHTOutliers;
+    uint8_t TRTHits;
+    uint8_t TRTOutliers;
+      
+    if ( !pTau.track(0)->summaryValue( TRTHits, xAOD::SummaryType::numberOfTRTHits ) )
+      {
+	ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate");
+	return StatusCode::SUCCESS;
+      }
+    if ( !pTau.track(0)->summaryValue( TRTHTHits, xAOD::SummaryType::numberOfTRTHighThresholdHits ) )
+      {
+	ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate");
+	return StatusCode::SUCCESS;
+      }
+    if ( !pTau.track(0)->summaryValue( TRTOutliers, xAOD::SummaryType::numberOfTRTOutliers ) )
+      {
+	ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate");
+	return StatusCode::SUCCESS;
+      }
+    if ( !pTau.track(0)->summaryValue( TRTHTOutliers, xAOD::SummaryType::numberOfTRTHighThresholdOutliers ) )
+      {
+	ATH_MSG_DEBUG("retrieval of track summary value failed. Not filling electron veto variables for this one prong candidate");
+	return StatusCode::SUCCESS;
+      }
+      
+
+      if (TRTHits + TRTOutliers != 0) {
+	TRTratio = float( TRTHTHits + TRTHTOutliers) / float( TRTHits + TRTOutliers );
+        } else {
+            TRTratio = 0.0;
+        }
+    // }
+
+    pTau.setDetail(xAOD::TauJetParameters::TRT_NHT_OVER_NLT , TRTratio );
+    pTau.setDetail(xAOD::TauJetParameters::secMaxStripEt , energy_3phi[max] );
+    pTau.setDetail(xAOD::TauJetParameters::hadLeakEt , static_cast<float>( sumETCellsHad1 / ( pTau.track(0)->pt() ) ) );
+    pTau.setDetail(xAOD::TauJetParameters::sumEMCellEtOverLeadTrkPt , static_cast<float>( ( sumETCellsLAr / ( pTau.track(0)->pt() ) ) ) );
+
+
+    return StatusCode::SUCCESS;
+}
+
+
+
+
diff --git a/Reconstruction/tauRecTools/src/TauElectronVetoVariables.h b/Reconstruction/tauRecTools/src/TauElectronVetoVariables.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1c4cf9fbeef87c9cc0e4fa431cff5a35468e7ea
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauElectronVetoVariables.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAU1P3PELEVETO_H
+#define TAUREC_TAU1P3PELEVETO_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+
+namespace Trk {
+  class IParticleCaloExtensionTool;
+}
+
+/**
+ * @brief Calculate variables sensitive on electrons.
+ * 
+ *  The variables are mainly used by the electron veto in the TauDiscriminant package.
+ * 
+ * @author Zofia Czyczula
+ */
+
+class TauElectronVetoVariables : virtual public TauRecToolBase {
+public:
+
+    TauElectronVetoVariables(const std::string& name);
+    ASG_TOOL_CLASS2(TauElectronVetoVariables, TauRecToolBase, ITauToolBase);
+
+    virtual ~TauElectronVetoVariables();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize();
+
+    virtual void print() const { }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    bool m_doCellCorrection; //!< enable cell origin correction
+    ToolHandle< Trk::IParticleCaloExtensionTool >  m_caloExtensionTool;
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.cxx b/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ffb8834c2f884f986185394eb78d2e486585e7d2
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.cxx
@@ -0,0 +1,571 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauPi0ClusterCreator.cxx
+// package:     Reconstruction/tauEvent
+// authors:     Benedict Winter, Will Davey, Stephanie Yuen
+// date:        2012-10-09
+//
+//-----------------------------------------------------------------------------
+
+#include "CaloUtils/CaloClusterStoreHelper.h"
+#include "CaloGeoHelpers/CaloSampling.h"
+#include "FourMomUtils/P4Helpers.h"
+#include "xAODJet/Jet.h"
+
+#include "TauPi0ClusterCreator.h"
+
+
+using std::vector;
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauPi0ClusterCreator::TauPi0ClusterCreator( const string& name) :
+
+    TauRecToolBase(name)
+    , m_inputPi0ClusterContainerName("TauPi0SubtractedClusters")
+    , m_outputPi0ClusterContainerName("TauPi0Clusters")
+    , m_neutralPFOContainerName("TauNeutralParticleFlowObjects")
+    , m_hadronicClusterPFOContainerName("TauHadronicParticleFlowObjects")
+    , m_clusterEtCut(500.)
+{
+
+    declareProperty("InputPi0ClusterContainerName",  m_inputPi0ClusterContainerName);
+    declareProperty("OutputPi0ClusterContainerName", m_outputPi0ClusterContainerName);
+    declareProperty("NeutralPFOContainerName",       m_neutralPFOContainerName);
+    declareProperty("HadronicClusterPFOContainerName", m_hadronicClusterPFOContainerName);
+    declareProperty("ClusterEtCut",                  m_clusterEtCut);
+    declareProperty("AODMode",                       m_AODmode=false);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauPi0ClusterCreator::~TauPi0ClusterCreator() 
+{
+}
+
+
+StatusCode TauPi0ClusterCreator::initialize() 
+{
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0ClusterCreator::finalize() 
+{
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0ClusterCreator::eventInitialize() 
+{
+    // create new CaloClusterContainer 
+    // this container will later persistified
+    // so it will get ownership of the objects
+    ATH_MSG_VERBOSE("record container " << m_outputPi0ClusterContainerName);
+    //---------------------------------------------------------------------
+    // Create container for Pi0
+    //---------------------------------------------------------------------
+    m_pOutputPi0CaloClusterContainer = CaloClusterStoreHelper::makeContainer(&*evtStore(),   
+									     m_outputPi0ClusterContainerName,    
+									     msg()                  
+									     );
+
+    //---------------------------------------------------------------------
+    // Create neutral PFO container
+    //---------------------------------------------------------------------
+    if(!m_AODmode){
+      m_neutralPFOContainer = new xAOD::PFOContainer();
+      m_neutralPFOAuxStore = new xAOD::PFOAuxContainer();
+      m_neutralPFOContainer->setStore(m_neutralPFOAuxStore);
+      CHECK( evtStore()->record(m_neutralPFOContainer, m_neutralPFOContainerName ) );
+      CHECK( evtStore()->record( m_neutralPFOAuxStore, m_neutralPFOContainerName + "Aux." ) );
+    }
+    else {
+      CHECK( evtStore()->retrieve(m_neutralPFOContainer, m_neutralPFOContainerName) );
+      CHECK( evtStore()->retrieve(m_neutralPFOAuxStore, m_neutralPFOContainerName+"Aux.") );
+    }
+
+    //---------------------------------------------------------------------
+    // Create hadronic cluster PFO container
+    //---------------------------------------------------------------------
+    if(!m_AODmode){
+      m_hadronicClusterPFOContainer = new xAOD::PFOContainer();
+      m_hadronicClusterPFOAuxStore = new xAOD::PFOAuxContainer();
+      m_hadronicClusterPFOContainer->setStore(m_hadronicClusterPFOAuxStore);
+      CHECK( evtStore()->record(m_hadronicClusterPFOContainer, m_hadronicClusterPFOContainerName ) );
+      CHECK( evtStore()->record( m_hadronicClusterPFOAuxStore, m_hadronicClusterPFOContainerName + "Aux." ) );
+    }
+    else{
+      CHECK( evtStore()->record(m_hadronicClusterPFOContainer, m_hadronicClusterPFOContainerName) );
+      CHECK( evtStore()->record(m_hadronicClusterPFOAuxStore, m_hadronicClusterPFOContainerName + "Aux.") );
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0ClusterCreator::execute(xAOD::TauJet& pTau) 
+{
+
+    // Any tau needs to have PFO vectors. Set empty vectors before nTrack cut
+    vector<ElementLink<xAOD::PFOContainer> > empty;
+    pTau.setProtoChargedPFOLinks(empty);
+    pTau.setProtoNeutralPFOLinks(empty);
+    pTau.setProtoPi0PFOLinks(empty);
+    pTau.setHadronicPFOLinks(empty);
+
+    // Any tau needs to have PanTauCellBasedProto 4mom. Set it to 0 before nTrack cut
+    pTau.setP4(xAOD::TauJetParameters::PanTauCellBasedProto, 0.0, 0.0, 0.0, 0.0);
+
+    //---------------------------------------------------------------------
+    // only run shower subtraction on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+        return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("ClusterCreator: new tau. \tpt = " << pTau.pt() << "\teta = " << pTau.eta() << "\tphi = " << pTau.phi() << "\tnprongs = " << pTau.nTracks());
+
+    //---------------------------------------------------------------------
+    // retrieve the CaloClusterContainer created by the CaloClusterMaker
+    //---------------------------------------------------------------------
+    const xAOD::CaloClusterContainer *pPi0ClusterContainer;
+    CHECK( evtStore()->retrieve(pPi0ClusterContainer, m_inputPi0ClusterContainerName) );
+
+    //---------------------------------------------------------------------
+    // TODO: May want to use tau vertex in the future to calculate some cluster moments (DELTA_THETA, etc.).
+    // Doesn't help now, since all moments are calculated wrt 0.0.0 atm.
+    //---------------------------------------------------------------------
+
+
+    // Retrieve Ecal1 shots and match them to clusters
+    //---------------------------------------------------------------------
+    std::vector<const xAOD::PFO*> shotVector;
+    unsigned nShots = pTau.nShotPFOs();
+    for(unsigned iShot=0;iShot<nShots;++iShot){
+        const xAOD::PFO* thisShot = pTau.shotPFO(iShot);
+        shotVector.push_back( thisShot );
+    }
+    std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap = getClusterToShotMap(shotVector, *pPi0ClusterContainer, pTau);
+
+    xAOD::CaloClusterContainer::const_iterator clusterItr   (pPi0ClusterContainer->begin()),
+                                               clusterItrEnd(pPi0ClusterContainer->end());
+    for (; clusterItr != clusterItrEnd; ++clusterItr){
+        
+        // selection
+        if ((*clusterItr)->pt() < m_clusterEtCut)   continue;
+        // Cluster container has clusters for all taus.
+        // Only run on clusters that belong to this tau
+        if ((*clusterItr)->p4().DeltaR(pTau.p4()) > .4) continue;
+
+        // Get shots in this cluster. Need to use (CaloCluster*) (*clusterItr) 
+        // (not a copy!) since the pointer will otherwise be different than in clusterToShotMap
+        std::vector<unsigned> shotsInCluster = getShotsMatchedToCluster( shotVector, clusterToShotMap, (xAOD::CaloCluster*) (*clusterItr));
+
+        // Make a copy of the cluster to store in output container.
+        xAOD::CaloCluster* pPi0Cluster = new xAOD::CaloCluster( *(*clusterItr) );
+
+        // store pi0 calo cluster in the output container
+        m_pOutputPi0CaloClusterContainer->push_back(pPi0Cluster);
+
+        // Calculate input variables for fake supression. 
+        // Do this before applying the vertex correction, 
+        // since the position of the cluster in the 
+        // calorimeter is required.
+        float EM1CoreFrac = getEM1CoreFrac(pPi0Cluster);
+        int NHitsInEM1 = getNPhotons(shotVector, shotsInCluster);
+        vector<int> NPosECellsInLayer = getNPosECells(pPi0Cluster);
+        vector<float> firstEtaWRTClusterPositionInLayer = get1stEtaMomWRTCluster(pPi0Cluster);
+        vector<float> secondEtaWRTClusterPositionInLayer = get2ndEtaMomWRTCluster(pPi0Cluster);
+
+        // Retrieve cluster moments that are used for fake supression and that are not stored in AOD
+        // for every cluster. Do this after applying the vertex correction, since the moments 
+        // (especcially DELTA_PHI and DELTA_THETA) must be calculated WRT the tau vertex
+        double CENTER_MAG = 0.0;
+        double FIRST_ETA = 0.0;
+        double SECOND_R = 0.0;
+        double SECOND_LAMBDA = 0.0;
+        double DELTA_PHI = 0.0;
+        double DELTA_THETA = 0.0;
+        double CENTER_LAMBDA = 0.0;
+        double LATERAL = 0.0;
+        double LONGITUDINAL = 0.0;
+        double ENG_FRAC_EM = 0.0;
+        double ENG_FRAC_MAX = 0.0;
+        double ENG_FRAC_CORE = 0.0;
+        double SECOND_ENG_DENS = 0.0;
+
+        // TODO: Replace numbers by human readable enums
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 404, CENTER_MAG) ) ATH_MSG_WARNING("Couldn't retrieve CENTER_MAG moment. Set it to 0.");
+
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 102, FIRST_ETA) )       ATH_MSG_WARNING("Couldn't retrieve FIRST_ETA moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 201, SECOND_R) )        ATH_MSG_WARNING("Couldn't retrieve SECOND_R moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 202, SECOND_LAMBDA) )   ATH_MSG_WARNING("Couldn't retrieve SECOND_LAMBDA moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 301, DELTA_PHI) )       ATH_MSG_WARNING("Couldn't retrieve DELTA_PHI moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 302, DELTA_THETA) )     ATH_MSG_WARNING("Couldn't retrieve DELTA_THETA moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 501, CENTER_LAMBDA) )   ATH_MSG_WARNING("Couldn't retrieve CENTER_LAMBDA moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 601, LATERAL) )         ATH_MSG_WARNING("Couldn't retrieve LATERAL moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 602, LONGITUDINAL) )    ATH_MSG_WARNING("Couldn't retrieve LONGITUDINAL moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 701, ENG_FRAC_EM) )     ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_EM moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 702, ENG_FRAC_MAX) )    ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_MAX moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 703, ENG_FRAC_CORE) )   ATH_MSG_WARNING("Couldn't retrieve ENG_FRAC_CORE moment. Set it to 0.");
+        if( !pPi0Cluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 805, SECOND_ENG_DENS) ) ATH_MSG_WARNING("Couldn't retrieve SECOND_ENG_DENS moment. Set it to 0.");
+
+       	float E_EM1 = pPi0Cluster->eSample(CaloSampling::EMB1) + pPi0Cluster->eSample(CaloSampling::EME1);
+	      float E_EM2 = pPi0Cluster->eSample(CaloSampling::EMB2) + pPi0Cluster->eSample(CaloSampling::EME2);
+        
+        // create neutral PFO. Set BDTScore to dummy value <-1. The BDT score is calculated within TauPi0Selector.cxx.
+        xAOD::PFO* neutralPFO = new xAOD::PFO();
+        m_neutralPFOContainer->push_back( neutralPFO );
+
+        // Create element link from tau to neutral PFO
+        ElementLink<xAOD::PFOContainer> PFOElementLink;
+        PFOElementLink.toContainedElement( *m_neutralPFOContainer, neutralPFO );
+        pTau.addProtoNeutralPFOLink( PFOElementLink );
+
+        // Set PFO variables
+        ElementLink<xAOD::CaloClusterContainer> clusElementLink;
+        clusElementLink.toContainedElement( *m_pOutputPi0CaloClusterContainer, pPi0Cluster );
+        neutralPFO->setClusterLink( clusElementLink );
+        
+        neutralPFO->setP4( (float) pPi0Cluster->pt(), (float) pPi0Cluster->eta(), (float) pPi0Cluster->phi(), (float) pPi0Cluster->m());
+        neutralPFO->setBDTPi0Score( (float) -9999. );
+        neutralPFO->setCharge( 0. );
+        neutralPFO->setCenterMag( (float) CENTER_MAG);
+        neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, -1);
+
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_FIRST_ETA,       (float) FIRST_ETA);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_R,        (float) SECOND_R);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_LAMBDA,   (float) SECOND_LAMBDA);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_PHI,       (float) DELTA_PHI);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_THETA,     (float) DELTA_THETA);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_CENTER_LAMBDA,   (float) CENTER_LAMBDA);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_LATERAL,         (float) LATERAL);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_LONGITUDINAL,    (float) LONGITUDINAL);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_EM,     (float) ENG_FRAC_EM);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_MAX,    (float) ENG_FRAC_MAX);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_CORE,   (float) ENG_FRAC_CORE);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_ENG_DENS, (float) SECOND_ENG_DENS);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM1,      (float) E_EM1);
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM2,      (float) E_EM2);
+
+
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_EM1CoreFrac, EM1CoreFrac);
+        neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NHitsInEM1, NHitsInEM1);
+        neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_PS,  NPosECellsInLayer.at(0));
+        neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM1, NPosECellsInLayer.at(1));
+        neutralPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM2, NPosECellsInLayer.at(2));
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM1, firstEtaWRTClusterPositionInLayer.at(1));
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM2, firstEtaWRTClusterPositionInLayer.at(2));
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM1, secondEtaWRTClusterPositionInLayer.at(1));
+        neutralPFO->setAttribute<float>(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM2, secondEtaWRTClusterPositionInLayer.at(2));
+
+        // Store shot element links in neutral PFO
+        std::vector<ElementLink<xAOD::IParticleContainer> > shotlinks;
+        for(unsigned iShot = 0;iShot<shotsInCluster.size();++iShot){
+            ElementLink<xAOD::PFOContainer> shotPFOElementLink = pTau.shotPFOLinks().at(shotsInCluster.at(iShot));
+            ElementLink<xAOD::IParticleContainer> shotElementLink;
+            shotPFOElementLink.toPersistent();
+            shotElementLink.resetWithKeyAndIndex( shotPFOElementLink.persKey(), shotPFOElementLink.persIndex() ); 
+            if (!shotElementLink.isValid()) ATH_MSG_WARNING("Created an invalid element link to xAOD::PFO");
+            shotlinks.push_back(shotElementLink);
+        }
+        if(!neutralPFO->setAssociatedParticleLinks( xAOD::PFODetails::TauShot,shotlinks)) 
+            ATH_MSG_WARNING("Couldn't add shot links to neutral PFO!");
+    }
+
+    // Create hadronic PFOs, put them in output container and store links to tau
+    if(!setHadronicClusterPFOs(pTau)){
+        ATH_MSG_ERROR("Could not set hadronic PFOs");
+        return StatusCode::FAILURE;
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+
+StatusCode TauPi0ClusterCreator::eventFinalize() 
+{
+    // pt sort container at the end of the event
+    // if(m_pOutputPi0CaloClusterContainer->size()) AnalysisUtils::Sort::pT(m_pOutputPi0CaloClusterContainer);
+
+    //----------------------------------------------------------------------
+    // Register cluster container in StoreGate
+    //----------------------------------------------------------------------
+    CHECK( CaloClusterStoreHelper::finalizeClusters(&(*evtStore()),
+                                                    m_pOutputPi0CaloClusterContainer,
+                                                    m_outputPi0ClusterContainerName,
+                                                    msg()));
+  
+    return StatusCode::SUCCESS;
+}
+
+// Functions used to calculate BDT variables other than those provided by the CaloClusterMomentsMaker
+float TauPi0ClusterCreator::getEM1CoreFrac(
+    const xAOD::CaloCluster* pi0Candidate)
+{
+    float coreEnergy=0.;
+    float sumEPosCellsEM1=0.;
+
+    const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks();
+    CaloClusterCellLink::const_iterator cellInClusterItr  = theCellLink->begin();
+    CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end();
+    for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){
+        CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr;
+        int sampling = cellInCluster->caloDDE()->getSampling();
+        if(sampling!=1 && sampling!=5) continue;
+        float cellE = cellInCluster->e() * cellInClusterItr.weight();
+        if(cellE<=0) continue;
+        sumEPosCellsEM1 += cellE;
+        float cellEtaWRTCluster = cellInCluster->eta()-pi0Candidate->eta();
+        float cellPhiWRTCluster = P4Helpers::deltaPhi(cellInCluster->phi(), pi0Candidate->phi());
+        if(fabs(cellPhiWRTCluster) > 0.05 || fabs(cellEtaWRTCluster) > 2 * 0.025/8.) continue;
+        coreEnergy+=cellE;
+    }
+    if(sumEPosCellsEM1<=0.) return 0.;
+    return coreEnergy/sumEPosCellsEM1;
+}
+
+// Do cluster to shot matching. 
+// A cluster is matched to a shot if the seed cell of the shot is in the cluster
+std::map<unsigned, xAOD::CaloCluster*> TauPi0ClusterCreator::getClusterToShotMap(
+    const std::vector<const xAOD::PFO*> shotVector, 
+    const xAOD::CaloClusterContainer& pPi0ClusterContainer,
+    const xAOD::TauJet &pTau)
+{
+    std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap;
+    for(unsigned iShot = 0;iShot<shotVector.size();++iShot){
+        int seedHash_int = -1;
+        if( shotVector.at(iShot)->attribute(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash_int) == false) {
+            std::cout << "WARNING: Couldn't find seed hash. Set it to -1, no cluster will be associated to shot." << std::endl;
+        }
+        const IdentifierHash seedHash = (const IdentifierHash) seedHash_int; 
+        xAOD::CaloClusterContainer::const_iterator clusterItr   (pPi0ClusterContainer.begin()),
+                                                   clusterItrEnd(pPi0ClusterContainer.end());
+        float weightInCluster=-1.;
+        float weightInPreviousCluster=-1;
+        for (; clusterItr != clusterItrEnd; ++clusterItr){
+            xAOD::CaloCluster* cluster = (xAOD::CaloCluster*) (*clusterItr);
+            weightInCluster=-1.;
+            if (cluster->p4().Et() < m_clusterEtCut) continue; // Not interested in clusters that fail the Et cut
+            // Cluster container has clusters for all taus.
+            // Only run on clusters that belong to this tau
+            if (cluster->p4().DeltaR(pTau.p4()) > .4)  continue;
+            const CaloClusterCellLink* theCellLink = cluster->getCellLinks();
+            CaloClusterCellLink::const_iterator cellItr  = theCellLink->begin();
+            CaloClusterCellLink::const_iterator cellItrE = theCellLink->end();
+            for(;cellItr!=cellItrE; ++cellItr){
+                CaloCell* cellInCluster = (CaloCell*) *cellItr;
+                // Check if seed cell is in cluster.
+                if(cellInCluster->caloDDE()->calo_hash()!=seedHash) continue;
+                weightInCluster = cellItr.weight();
+                // found cell, no need to loop over other cells
+                break;
+            }
+            if(weightInCluster<0) continue;
+            // Check if cell was already found in a previous cluster
+            if(weightInPreviousCluster<0){
+                // Cell not found in a previous cluster. 
+                // Have to check whether cell is shared with other cluster
+                clusterToShotMap[iShot] = cluster;
+                weightInPreviousCluster = weightInCluster;
+            }
+            else{
+                // Cell has been found in a previous cluster
+                // assign shot to this cluster if it has larger weight for the cell
+                // otherwise the shots keeps assigned to the previous cluster
+                if(weightInCluster>weightInPreviousCluster){
+                    clusterToShotMap[iShot] = cluster;
+                }
+                // No need to loop over other clusters as cells can not be shared by more than two clusters
+                break;
+            }
+        }
+    }
+    return clusterToShotMap;
+}
+
+std::vector<unsigned> TauPi0ClusterCreator::getShotsMatchedToCluster(
+    const std::vector<const xAOD::PFO*> shotVector,
+    std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap, 
+    xAOD::CaloCluster* pPi0Cluster)
+{
+    std::vector<unsigned> shotsMatchedToCluster;
+    for(unsigned iShot = 0;iShot<shotVector.size();++iShot){
+        std::map<unsigned, xAOD::CaloCluster*>::iterator itr = clusterToShotMap.find(iShot);
+        if(itr==clusterToShotMap.end()) continue;
+        if(itr->second!=pPi0Cluster) continue;
+        shotsMatchedToCluster.push_back(iShot);
+    }
+    return shotsMatchedToCluster;
+}
+
+int TauPi0ClusterCreator::getNPhotons(
+    const std::vector<const xAOD::PFO*> shotVector,
+    std::vector<unsigned> shotsInCluster
+    )
+{
+    int nPhotons = 0;
+    for(unsigned iShot = 0;iShot<shotsInCluster.size();++iShot){
+        int curNPhotons=0;
+        if(shotVector.at(shotsInCluster.at(iShot))->attribute(xAOD::PFODetails::PFOAttributes::tauShots_nPhotons,curNPhotons) == false)
+            ATH_MSG_WARNING("Can't find NHitsInEM1. Set it to 0.");
+        nPhotons+=curNPhotons;
+    }
+    return nPhotons;
+}
+
+vector<int> TauPi0ClusterCreator::getNPosECells(
+    const xAOD::CaloCluster* pi0Candidate)
+{
+    vector<int> nPosECellsInLayer(3,0); // 3 layers initialised with 0 +ve cells
+
+    const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks();
+    CaloClusterCellLink::const_iterator cellInClusterItr  = theCellLink->begin();
+    CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end();
+
+    for(;cellInClusterItr!=cellInClusterItrE; ++cellInClusterItr){
+        CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr;
+        int sampling = cellInCluster->caloDDE()->getSampling();
+        // Get cell layer: PSB and PSE belong to layer 0,  
+        // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. 
+        int cellLayer = sampling%4;  
+        if(cellLayer < 3 && cellInCluster->e() > 0) nPosECellsInLayer[cellLayer]++;
+    }
+    return nPosECellsInLayer;
+}
+
+
+vector<float> TauPi0ClusterCreator::get1stEtaMomWRTCluster(
+    const xAOD::CaloCluster* pi0Candidate)
+{
+    vector<float> firstEtaWRTClusterPositionInLayer (4, 0.);  //init with 0. for 0-3 layers
+    vector<float> sumEInLayer (4, 0.); //init with 0. for 0-3 layers
+
+    const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks();
+    CaloClusterCellLink::const_iterator cellInClusterItr  = theCellLink->begin();
+    CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end();
+
+    for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){
+        CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr;
+        int sampling = cellInCluster->caloDDE()->getSampling();
+        // Get cell layer: PSB and PSE belong to layer 0,  
+        // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. 
+        int cellLayer = sampling%4;
+        
+        float cellEtaWRTClusterPos=cellInCluster->eta()-pi0Candidate->eta();
+        float cellE=cellInCluster->e();
+        if(cellE<=0  || cellLayer>=3) continue;
+        firstEtaWRTClusterPositionInLayer[cellLayer]+=cellEtaWRTClusterPos*cellE;
+        sumEInLayer[cellLayer]+=cellE;
+    }
+
+    for(int iLayer=0;iLayer<4;++iLayer){
+        if(sumEInLayer[iLayer]!=0) 
+            firstEtaWRTClusterPositionInLayer[iLayer]/=fabs(sumEInLayer[iLayer]);
+        else firstEtaWRTClusterPositionInLayer[iLayer]=0.;
+    }
+    return firstEtaWRTClusterPositionInLayer;
+}
+
+vector<float> TauPi0ClusterCreator::get2ndEtaMomWRTCluster(
+    const xAOD::CaloCluster* pi0Candidate)
+{
+      vector<float> secondEtaWRTClusterPositionInLayer (4, 0.); //init with 0. for 0-3 layers
+      vector<float> sumEInLayer (4, 0.); //init with 0. for 0-3 layers
+
+      const CaloClusterCellLink* theCellLink = pi0Candidate->getCellLinks();
+      CaloClusterCellLink::const_iterator cellInClusterItr  = theCellLink->begin();
+      CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end();
+
+      for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){
+            CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr;
+            int sampling = cellInCluster->caloDDE()->getSampling();
+            // Get cell layer: PSB and PSE belong to layer 0,  
+            // EMB1 and EME1 to layer 1, EMB2 and EME2 to layer 2. 
+            int cellLayer = sampling%4;
+
+            float cellEtaWRTClusterPos=cellInCluster->eta()-pi0Candidate->eta();
+            float cellE=cellInCluster->e();
+            if(cellE<=0  || cellLayer>=3) continue;
+            secondEtaWRTClusterPositionInLayer[cellLayer]+=cellEtaWRTClusterPos*cellEtaWRTClusterPos*cellE;
+            sumEInLayer[cellLayer]+=cellE;
+      }
+
+      for(int iLayer=0;iLayer<4;++iLayer){
+            if(sumEInLayer[iLayer]!=0) 
+                secondEtaWRTClusterPositionInLayer[iLayer]/=fabs(sumEInLayer[iLayer]);
+            else secondEtaWRTClusterPositionInLayer[iLayer]=0.;
+      }
+      return secondEtaWRTClusterPositionInLayer;
+}
+
+bool TauPi0ClusterCreator::setHadronicClusterPFOs(
+    xAOD::TauJet& pTau)
+{
+    const xAOD::Jet* tauJetSeed = (*pTau.jetLink());
+    if (!tauJetSeed) {
+        ATH_MSG_ERROR("Could not retrieve tau jet seed");
+        return false;
+    }
+    xAOD::JetConstituentVector::const_iterator clusterItr   = tauJetSeed->getConstituents().begin();
+    xAOD::JetConstituentVector::const_iterator clusterItrE  = tauJetSeed->getConstituents().end();
+    for (; clusterItr != clusterItrE; ++clusterItr){
+        // Procedure: 
+        // - Calculate cluster energy in Hcal. This is to treat -ve energy cells correctly
+        // - Then set 4momentum via setP4(E/cosh(eta), eta, phi, m). This forces the PFO to have the correct energy and mass
+        // - Ignore clusters outside 0.2 cone and those with overall negative energy or negative energy in Hcal
+
+        // Get xAOD::CaloClusters from jet constituent
+        const xAOD::CaloCluster* cluster = dynamic_cast<const xAOD::CaloCluster*>( (*clusterItr)->rawConstituent() );
+        if (!cluster) continue;
+
+        // Don't create PFOs for clusters with overall (Ecal+Hcal) negative energy (noise)
+        if(cluster->e()<=0.) continue;
+
+        // Only need clusters in core cone. Others are not needed for subtraction
+        if(pTau.p4().DeltaR(cluster->p4()) > 0.2) continue;
+
+        // Loop over cells to calculate cluster energy in Hcal
+        double clusterE_Hcal=0.;
+        const CaloClusterCellLink* theCellLink = cluster->getCellLinks();
+        CaloClusterCellLink::const_iterator cellInClusterItr  = theCellLink->begin();
+        CaloClusterCellLink::const_iterator cellInClusterItrE = theCellLink->end();
+        for(;cellInClusterItr!=cellInClusterItrE;++cellInClusterItr){
+            CaloCell* cellInCluster = (CaloCell*) *cellInClusterItr;
+
+            //Get only HCAL cells
+            int sampling = cellInCluster->caloDDE()->getSampling();
+            if (sampling < 8) continue;
+
+            double cellE = cellInCluster->e()*cellInClusterItr.weight();
+            clusterE_Hcal+=cellE;
+        }
+        // Don't save PFOs for clusters with negative energy in Hcal 
+        if(clusterE_Hcal<=0.) continue;
+
+        // Create hadronic PFO
+        xAOD::PFO* hadronicPFO = new xAOD::PFO();
+        m_hadronicClusterPFOContainer->push_back( hadronicPFO );
+
+        // Set 4mom. Eta and phi are taken from cluster
+        double cluster_Pt_Hcal = clusterE_Hcal/std::cosh(cluster->eta());
+        hadronicPFO->setP4( (float) cluster_Pt_Hcal, (float) cluster->eta(), (float) cluster->phi(), (float) 0.);
+
+        // TODO: May want to set element link to the cluster the PFO is originating from
+        // ElementLink<xAOD::CaloClusterContainer> clusElementLink;
+        // clusElementLink.toContainedElement( CLUSTERCONTAINER, cluster );
+        // hadronicPFO->setClusterLink( clusElementLink );
+
+        // Create element link from tau to hadronic PFO
+        ElementLink<xAOD::PFOContainer> PFOElementLink;
+        PFOElementLink.toContainedElement( *m_hadronicClusterPFOContainer, hadronicPFO );
+        pTau.addHadronicPFOLink( PFOElementLink );
+    }
+    return true;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.h b/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecf128c0d7f33307227f8cb45dfbe21cf9b202d5
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ClusterCreator.h
@@ -0,0 +1,100 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPI0CLUSTERCREATOR_H
+#define	TAUREC_TAUPI0CLUSTERCREATOR_H
+
+#include <string>
+#include <vector>
+#include "tauRecTools/TauRecToolBase.h"
+#include "xAODPFlow/PFOAuxContainer.h"
+
+using std::vector;
+
+/**
+ * @brief Creates Pi0 clusters (Pi0 Finder).
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch> 
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch>
+ */
+
+class TauPi0ClusterCreator : virtual public TauRecToolBase {
+public:
+    TauPi0ClusterCreator(const std::string& name) ;
+    ASG_TOOL_CLASS2(TauPi0ClusterCreator, TauRecToolBase, ITauToolBase);
+    virtual ~TauPi0ClusterCreator();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize();
+
+    virtual void print() const { }
+
+    
+private:
+
+
+    /** @brief fraction of cluster enegry in central EM1 cells */
+    float getEM1CoreFrac( const xAOD::CaloCluster* /*pi0Candidate*/);
+    
+    /** @brief number of cells from cluster with positive energy in PS, EM1 and EM2 */
+    vector<int> getNPosECells( const xAOD::CaloCluster* /*pi0Candidate*/);
+
+    std::map<unsigned, xAOD::CaloCluster*> getClusterToShotMap(
+        const std::vector<const xAOD::PFO*> shotVector,
+        const xAOD::CaloClusterContainer& pPi0ClusterContainer,
+        const xAOD::TauJet &pTau);
+
+    std::vector<unsigned> getShotsMatchedToCluster(
+        const std::vector<const xAOD::PFO*> shotVector,
+        std::map<unsigned, xAOD::CaloCluster*> clusterToShotMap,
+        xAOD::CaloCluster* pPi0Cluster);
+
+    int getNPhotons( const std::vector<const xAOD::PFO*> /*shotVector*/, 
+                     std::vector<unsigned> /*shotsInCluster*/);
+
+    /** @brief first eta moment in PS, EM1 and EM2 w.r.t cluster eta: (eta_i - eta_cluster) */
+    vector<float> get1stEtaMomWRTCluster( const xAOD::CaloCluster* /*pi0Candidate*/);
+
+    /** @brief second eta moment in PS, EM1 and EM2 w.r.t cluster eta: (eta_i - eta_cluster)^2 */ 
+    vector<float> get2ndEtaMomWRTCluster(const xAOD::CaloCluster* /*pi0Candidate*/);
+
+    /** @brief get hadronic cluster PFOs*/
+    bool setHadronicClusterPFOs(xAOD::TauJet& pTau);
+
+    /** @brief input cluster container of pi0 candidates */
+    // TODO: input cluster container name
+    std::string m_inputPi0ClusterContainerName;
+    
+    /** @brief output cluster container of pi0 candidates */
+    // TODO: output cluster container name
+    std::string m_outputPi0ClusterContainerName;
+
+    /** @brief new neutral PFO container and name */
+    xAOD::PFOContainer* m_neutralPFOContainer;
+    std::string m_neutralPFOContainerName;
+    xAOD::PFOAuxContainer* m_neutralPFOAuxStore;
+
+    /** @brief new hadronic cluster PFO container and name */
+    xAOD::PFOContainer* m_hadronicClusterPFOContainer;
+    std::string m_hadronicClusterPFOContainerName;
+    xAOD::PFOAuxContainer* m_hadronicClusterPFOAuxStore;
+    
+
+    /** @brief pt threshold for pi0 candidate clusters */
+    double m_clusterEtCut;
+
+    /** @brief in AODMode (probaby never true) */
+    bool m_AODmode;
+
+    /** @brief output cluster container */
+    xAOD::CaloClusterContainer*  m_pOutputPi0CaloClusterContainer;
+
+};
+
+#endif	/* TAUPI0CLUSTERCREATOR_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.cxx b/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..25c6287eab37d33a1dff62b832149d88f1e79d79
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.cxx
@@ -0,0 +1,369 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauPi0ClusterScaler.cxx
+// package:     Reconstruction/tauRec
+// authors:     Stephanie Yuen, Benedict Winter, Will Davey
+// date:        2014-08-04
+//
+//-----------------------------------------------------------------------------
+
+#include <vector>
+
+#include "TauPi0ClusterScaler.h"
+#include "xAODPFlow/PFO.h"
+
+#include "TrkParametersIdentificationHelpers/TrackParametersIdHelper.h"
+#include "RecoToolInterfaces/IParticleCaloExtensionTool.h"
+#include "xAODTau/TauJet.h"
+#include "tauRecTools/ITauToolBase.h"
+
+using std::vector;
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauPi0ClusterScaler::TauPi0ClusterScaler( const string& name ) :
+    TauRecToolBase(name)
+    , m_caloExtensionTool("Trk::ParticleCaloExtensionTool/ParticleCaloExtensionTool")
+    , m_chargedPFOContainerName("TauChargedParticleFlowObjects")
+{
+    declareProperty("ParticleCaloExtensionTool", m_caloExtensionTool);
+    declareProperty("ChargedPFOContainerName", m_chargedPFOContainerName); 
+    declareProperty("runOnAOD", m_AODmode=false);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauPi0ClusterScaler::~TauPi0ClusterScaler()
+{
+}
+
+
+StatusCode TauPi0ClusterScaler::initialize()
+{
+    // retrieve tools
+    ATH_MSG_DEBUG( "Retrieving tools" );
+    CHECK( m_caloExtensionTool.retrieve() );
+    // Create vector with default values
+    for (int layer = 0 ; layer != CaloCell_ID::FCAL0; ++layer) {
+        m_defaultValues.push_back(-10.);
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0ClusterScaler::eventInitialize() {
+
+    //---------------------------------------------------------------------
+    // Create charged PFO container
+    //---------------------------------------------------------------------
+  if(!m_AODmode){
+    m_chargedPFOContainer = new xAOD::PFOContainer();
+    m_chargedPFOAuxStore = new xAOD::PFOAuxContainer();
+    m_chargedPFOContainer->setStore(m_chargedPFOAuxStore);
+    CHECK( evtStore()->record(m_chargedPFOContainer, m_chargedPFOContainerName ) );
+    CHECK( evtStore()->record( m_chargedPFOAuxStore, m_chargedPFOContainerName + "Aux." ) );
+  }
+  else{
+    CHECK( evtStore()->retrieve(m_chargedPFOContainer, m_chargedPFOContainerName) );
+    CHECK( evtStore()->retrieve( m_chargedPFOAuxStore, m_chargedPFOContainerName + "Aux." ) );
+  }
+    return StatusCode::SUCCESS;
+
+}
+
+StatusCode TauPi0ClusterScaler::finalize()
+{
+  StatusCode sc = AlgTool::finalize();
+  return sc;
+}
+
+
+StatusCode TauPi0ClusterScaler::execute(xAOD::TauJet& pTau)
+{
+    // Clear vector of cell-based charged PFO Links. Required when rerunning on xAOD level.
+    pTau.clearProtoChargedPFOLinks();
+
+    //---------------------------------------------------------------------
+    // only run on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+        return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("ClusterScaler: new tau. \tpt = " << pTau.pt() << "\teta = " << pTau.eta() << "\tphi = " << pTau.phi() << "\tnprongs = " << pTau.nTracks());
+
+    //---------------------------------------------------------------------
+    // get tau tracks
+    //---------------------------------------------------------------------
+    vector<const xAOD::TrackParticle*> tracks;
+    for(unsigned iTrack = 0; iTrack<pTau.nTracks();++iTrack){
+        const xAOD::TrackParticle* track = pTau.track(iTrack);
+        tracks.push_back(track);
+    }
+
+    //---------------------------------------------------------------------
+    // prepare extrapolation of tracks to calo layers 
+    //---------------------------------------------------------------------
+    // clear vectors related to track extrapolation
+    // have to do that for each tau so it cannot be done in eventInitialize,
+    // which is called once per event (and not once per tau)
+    m_tracksEtaAtSampling.clear();
+    m_tracksPhiAtSampling.clear();
+    m_extrapolatedSamplings.clear();
+    // Fill with default values
+    for(int layer = 0 ; layer != CaloCell_ID::FCAL0; ++layer) {
+         m_extrapolatedSamplings.push_back(false);
+    }
+    for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+        m_tracksEtaAtSampling.push_back( m_defaultValues );
+        m_tracksPhiAtSampling.push_back( m_defaultValues );
+    }
+
+    //---------------------------------------------------------------------
+    // get energy in HCal associated to the different tracks
+    //---------------------------------------------------------------------
+    vector<vector<ElementLink<xAOD::IParticleContainer> > > hadPFOLinks;
+    vector<double> EestInEcal = this->getEstEcalEnergy(tracks,pTau, hadPFOLinks);
+
+    //---------------------------------------------------------------------
+    // Create charged PFOs
+    //---------------------------------------------------------------------
+    for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+        const xAOD::TrackParticle* track = tracks.at(iTrack);
+        xAOD::PFO* chargedPFO = new xAOD::PFO();
+        m_chargedPFOContainer->push_back(chargedPFO);
+        ElementLink<xAOD::TrackParticleContainer> myTrackLink = pTau.trackLinks().at(iTrack);
+        if(!chargedPFO->setTrackLink(myTrackLink)) ATH_MSG_WARNING("Could not add Track to PFO");
+        chargedPFO->setCharge(track->charge());
+        chargedPFO->setP4(track->pt(),track->eta(),track->phi(),track->m());
+        // Create element link from tau to charged PFO
+        ElementLink<xAOD::PFOContainer> PFOElementLink;
+        PFOElementLink.toContainedElement( *m_chargedPFOContainer, chargedPFO );
+        // Create element links to hadronic PFOs associated to tracks
+        if(!chargedPFO->setAssociatedParticleLinks(xAOD::PFODetails::TauShot,hadPFOLinks.at(iTrack)))
+            ATH_MSG_WARNING("Couldn't add hadronic PFO links to charged PFO!");
+        pTau.addProtoChargedPFOLink( PFOElementLink );
+    }
+
+    //---------------------------------------------------------------------
+    // get closest EM cluster to track for subtraction
+    //---------------------------------------------------------------------
+    vector<float> smallestDRSquared;
+    vector<int> closestCluster;
+    for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+        // The following vectors will store information on the clusters closest to the tracks
+        smallestDRSquared.push_back( 0.0016 ); // TODO: retune, for now match clusters that are closer than DR=0.04 to the track
+        closestCluster.push_back(-1);
+    }
+
+    int thisCluster = 0;
+    unsigned nNeutPFO = pTau.nProtoNeutralPFOs();
+    for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++, thisCluster++) {
+        const xAOD::PFO* curNeutPFO_const = pTau.protoNeutralPFO( iNeutPFO );
+        int maxESample = 2;
+        if (fabs(curNeutPFO_const->eta()) > 1.45) maxESample = 6;
+        // check if tracks have been extrapolated to this sampling. Do so if this is not the case
+        if(m_extrapolatedSamplings.at(maxESample)==false){
+           this->getExtrapolatedPositions(tracks,maxESample);
+           m_extrapolatedSamplings.at(maxESample)=true;
+        }
+
+        for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+            if(EestInEcal.at(iTrack)<0.001) continue; // No need to subtract
+
+            TLorentzVector extTrack;
+            extTrack.SetPtEtaPhiE(tracks.at(iTrack)->pt(), m_tracksEtaAtSampling.at(iTrack).at(maxESample), m_tracksPhiAtSampling.at(iTrack).at(maxESample), tracks.at(iTrack)->e());
+            // get eta/phi distance of cell to track
+            double deltaEta = extTrack.Eta()-curNeutPFO_const->eta();
+            double deltaPhi = TVector2::Phi_mpi_pi( extTrack.Phi() - curNeutPFO_const->phi());;
+
+            double deltaRToTrack_squared = deltaEta*deltaEta+deltaPhi*deltaPhi;
+            ATH_MSG_DEBUG("Track number " << iTrack << ", extTrack.Eta() = " << extTrack.Eta() << ", extTrack.Phi() = " << extTrack.Phi());
+
+            if(deltaRToTrack_squared>=smallestDRSquared.at(iTrack)) continue;
+            smallestDRSquared.at(iTrack) = deltaRToTrack_squared;
+            closestCluster.at(iTrack) = thisCluster;
+        }
+    }
+
+    //---------------------------------------------------------------------
+    // Set cluster energies to what they originally were before subtraction, in case subtraction is rerun on xAOD level
+    //---------------------------------------------------------------------
+    for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++) {
+        const xAOD::PFO* curNeutPFO_const = pTau.protoNeutralPFO( iNeutPFO );
+        xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const);
+        //float originalE = 0;
+        //curNeutPFO->attribute(xAOD::PFODetails::PFOAttributes::protoasymmetryInEM1WRTTrk,originalE);
+        //curNeutPFO->setP4(originalE/TMath::CosH(curNeutPFO->eta()), curNeutPFO->eta(), curNeutPFO->phi(), curNeutPFO->m());
+
+        // Retrieve original 4momentum from the cluster linked to the PFO
+        double originalPt  = curNeutPFO->cluster(0)->pt();
+        double originalEta = curNeutPFO->cluster(0)->eta(); 
+        double originalPhi = curNeutPFO->cluster(0)->phi();
+        double originalM   = curNeutPFO->cluster(0)->m();
+        //ATH_MSG_INFO("PFO 4mom: pt << "<<curNeutPFO->pt()<<"\teta"<<curNeutPFO->eta()<<"\tphi"<<curNeutPFO->phi()<<"\tm"<<curNeutPFO->m()<<"\te"<<curNeutPFO->e()             );
+        //ATH_MSG_INFO("Cl  4mom: pt << "<<originalPt      <<"\teta"<<originalEta      <<"\tphi"<<originalPhi      <<"\tm"<<originalM <<"\te"<<curNeutPFO->cluster(0)->e()<<"\n");
+        curNeutPFO->setP4(originalPt, originalEta, originalPhi, originalM);
+    }
+
+    //---------------------------------------------------------------------
+    // scale charged pion energy out of closest EMNeutPFO to track
+    //---------------------------------------------------------------------
+    thisCluster = 0;
+    for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++, thisCluster++) {
+        const xAOD::PFO* curNeutPFO_const = pTau.protoNeutralPFO( iNeutPFO );
+        xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const);
+
+        float originalE = curNeutPFO->e();
+        //ATH_MSG_INFO("iNeutPFO " << iNeutPFO << "\t before sub " << originalE/1000);
+        //Scale out charged pion energy for each track
+        for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+            if(thisCluster!=closestCluster.at(iTrack)) continue; // No EMNeutPFO found
+            if(EestInEcal.at(iTrack)<0.001) continue;   // No need to subtract
+            if(originalE - EestInEcal.at(iTrack) >0. ){
+                float newE = originalE - EestInEcal.at(iTrack);
+                curNeutPFO->setP4(newE/TMath::CosH(curNeutPFO->eta()) , curNeutPFO->eta(), curNeutPFO->phi(), curNeutPFO->m());
+                //ATH_MSG_INFO("should subtract " << EestInEcal.at(iTrack)/1000 << " GeV from EMNeutPFO " << iNeutPFO);
+                //float orgE = curNeutPFO->cluster(0)->e();
+                //ATH_MSG_INFO("orgE = " << orgE << "\tPFO->e() = " << curNeutPFO->e());
+            }
+            // Set it to something that will make the EMNeutPFO fail the pt cut
+            else {
+              curNeutPFO->setP4(100 , curNeutPFO->eta(), curNeutPFO->phi(), curNeutPFO->m());
+              //ATH_MSG_INFO("should remove EMNeutPFO " << iNeutPFO);
+            }
+        }
+        //ATH_MSG_INFO("iNeutPFO " << iNeutPFO << "\t after sub " << curNeutPFO->e()/1000);
+        //ATH_MSG_INFO("");
+    }
+
+    ATH_MSG_DEBUG("End of TauPi0ClusterScaler::execute");
+
+    return StatusCode::SUCCESS;
+}
+
+void TauPi0ClusterScaler::getExtrapolatedPositions(
+    vector<const xAOD::TrackParticle*> tracks,
+    int sampling)
+{
+    for (unsigned iTrack = 0 ; iTrack < tracks.size(); ++iTrack ) {
+        // get the extrapolation into the calo
+        ATH_MSG_DEBUG( "Try extrapolation of track with pt = " << tracks.at(iTrack)->pt() << ", eta " << tracks.at(iTrack)->eta() << ", phi" << tracks.at(iTrack)->phi()
+                      << " to layer " << sampling);
+        const Trk::CaloExtension* caloExtension = 0;
+        if (!m_caloExtensionTool->caloExtension(*tracks.at(iTrack),caloExtension)
+            || caloExtension->caloLayerIntersections().size() < (unsigned int)(sampling+1)) return;
+
+        // store if track extrapolation successful, only use entry layer
+        const Trk::TrackParameters* param_at_calo = caloExtension->caloLayerIntersections().at(sampling);
+        if (param_at_calo) {
+            ATH_MSG_DEBUG( "Extrapolated track with eta=" << tracks.at(iTrack)->eta()
+                            << " phi="<<tracks.at(iTrack)->phi()
+                            << " to eta=" << param_at_calo->position().eta()
+                            << " phi="<<param_at_calo->position().phi()
+                            );
+            m_tracksEtaAtSampling.at(iTrack).at(sampling)=param_at_calo->position().eta();
+            m_tracksPhiAtSampling.at(iTrack).at(sampling)=param_at_calo->position().phi();
+        }
+        else ATH_MSG_DEBUG("Could not extrapolate track with pt = " << tracks.at(iTrack)->pt() << ", eta " << tracks.at(iTrack)->eta() << ", phi" << tracks.at(iTrack)->phi()
+                          << " to layer " << sampling);
+    }
+}
+
+vector<double> TauPi0ClusterScaler::getEstEcalEnergy(
+    vector<const xAOD::TrackParticle*> tracks,
+    const xAOD::TauJet& pTau,
+    vector<vector<ElementLink<xAOD::IParticleContainer> > >& hadPFOLinks)
+{
+    // Vector that stores hadronic energy and PFO links associated to tracks
+    vector<ElementLink<xAOD::IParticleContainer> > emptyLinkVector;
+    vector<double> EHcal;
+        for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+        EHcal.push_back(0.);
+        hadPFOLinks.push_back(emptyLinkVector);
+    }
+
+    ATH_MSG_DEBUG("new tau. eta = " << pTau.eta() << "\t phi = " << pTau.phi() );
+
+    //int PFONumber = -1;
+    unsigned nHadPFO = pTau.nHadronicPFOs();
+    for(unsigned int iHadPFO=0; iHadPFO<nHadPFO; iHadPFO++){
+        const xAOD::PFO* curHadPFO = pTau.hadronicPFO( iHadPFO );
+        
+        /*
+        // For debugging...
+        PFONumber++;
+        double deltaEtaToTau = pTau.eta()-curHadPFO->eta();
+        double deltaPhiToTau = TVector2::Phi_mpi_pi( pTau.phi() - curHadPFO->phi());
+
+        double deltaRToTau_squared = deltaEtaToTau*deltaEtaToTau+deltaPhiToTau*deltaPhiToTau;
+        ATH_MSG_INFO("PFO number << " << PFONumber << "\t energy = " << curHadPFO->e() << "\t eta = " << curHadPFO->eta() << "\t phi = " << curHadPFO->phi() <<
+                     "\t deltaEtaToTau = " << deltaEtaToTau << "\t deltaPhiToTau = " << deltaPhiToTau << "\t deltaRToTau_squared = " << deltaRToTau_squared );
+        */
+
+        // Decide which sampling to extrapolate to. Choose Hcal samplings that usually contain most energy (|eta| dependent)
+        int                                   sample = 13; //         |eta| <= 1.0
+        if     ( fabs(curHadPFO->eta())>1.5 ) sample =  9; //  1.5 <  |eta| 
+        else if( fabs(curHadPFO->eta())>1.0 ) sample = 19; //  1.0 <  |eta| <= 1.5
+
+        // check if tracks have been extrapolated to this sampling. Do so if this is not the case
+        if(m_extrapolatedSamplings.at(sample)==false){
+           this->getExtrapolatedPositions(tracks,sample);
+           ATH_MSG_DEBUG("Extrapolate to layer " << sample << "\teta = "
+                         << m_tracksEtaAtSampling.at(0).at(sample) << "\t phi = " << m_tracksPhiAtSampling.at(0).at(sample) );
+           m_extrapolatedSamplings.at(sample)=true;
+        }
+
+        // Assign PFO to track
+        int closestTrack = -1;
+        double dRToClosestTrack_squared = 0.16; // XXX can be tuned later
+        for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+            const xAOD::TrackParticle* track = tracks.at(iTrack);
+
+            // set extrapolated track direction
+            TLorentzVector extTrack;
+            extTrack.SetPtEtaPhiE(track->pt(), m_tracksEtaAtSampling.at(iTrack).at(sample), m_tracksPhiAtSampling.at(iTrack).at(sample), track->e());
+
+            // get eta/phi distance of cell to track
+            double deltaEta = extTrack.Eta()-curHadPFO->eta();
+            double deltaPhi = TVector2::Phi_mpi_pi( extTrack.Phi() - curHadPFO->phi());;
+            double deltaRToTrack_squared = deltaEta*deltaEta+deltaPhi*deltaPhi;
+
+            if(deltaRToTrack_squared>=dRToClosestTrack_squared) continue;
+            closestTrack = iTrack;
+            dRToClosestTrack_squared = deltaRToTrack_squared;
+        }
+        if(closestTrack == -1){
+            //ATH_MSG_INFO("dRToClosestTrack_squared = " << dRToClosestTrack_squared << ". Skip PFO for Hcal estimate. \tPFO_energy = " << curHadPFO->e()/1000.);
+            continue; // Didn't find a track
+        }
+        EHcal.at(closestTrack) += curHadPFO->e();
+
+        ElementLink<xAOD::PFOContainer> hadPFOElementLink = pTau.hadronicPFOLinks().at(iHadPFO);
+        ElementLink<xAOD::IParticleContainer> hadElementLink;
+        hadPFOElementLink.toPersistent();
+        hadElementLink.resetWithKeyAndIndex( hadPFOElementLink.persKey(), hadPFOElementLink.persIndex() );
+        if (!hadElementLink.isValid()) ATH_MSG_WARNING("Created an invalid element link to xAOD::PFO");
+        hadPFOLinks.at(closestTrack).push_back(hadElementLink);
+        //ATH_MSG_INFO("PFO associated to track " << closestTrack << "\tPFO_energy = " << curHadPFO->e()/1000. << "\tEHcal.at(closestTrack) = " << EHcal.at(closestTrack) );
+    }
+    // Get energy estimate in ECAL
+    vector<double> E_ests;
+    for(unsigned iTrack = 0; iTrack<tracks.size();++iTrack){
+        double E_est = tracks.at(iTrack)->e()-EHcal.at(iTrack);
+        // energy cant be less than 0
+        if(E_est < 0) E_est = 0.;
+        // energy cant be more than track momentum
+        if(E_est > tracks.at(iTrack)->e()) E_est = tracks.at(iTrack)->e();
+        E_ests.push_back(E_est);
+    }
+    return E_ests;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.h b/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.h
new file mode 100644
index 0000000000000000000000000000000000000000..2cc3ed5960158c2e0bb9ccaa761258c2896b466a
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ClusterScaler.h
@@ -0,0 +1,71 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPI0CLUSTERSCALER_H
+#define TAUREC_TAUPI0CLUSTERSCALER_H
+
+#include <string>
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "xAODPFlow/PFO.h"
+#include "xAODPFlow/PFOAuxContainer.h"
+
+/**
+ * @brief scale cluster energy to take care of charged pion energy
+ *
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch> 
+ * @author Will Davey <will.davey@cern.ch> 
+ */
+
+namespace Trk {
+    class IParticleCaloExtensionTool;
+}
+class TauPi0ClusterScaler : virtual public TauRecToolBase {
+public:
+    TauPi0ClusterScaler(const std::string& name);
+    ASG_TOOL_CLASS2(TauPi0ClusterScaler, TauRecToolBase, ITauToolBase);
+    virtual ~TauPi0ClusterScaler();
+
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+
+    /** @brief tool handles */
+    ToolHandle<Trk::IParticleCaloExtensionTool> m_caloExtensionTool;
+
+    /** @brief extrapolated position of tracks and vector of bools to keep track for which samplings this has already been done */
+    std::vector<std::vector<double> > m_tracksEtaAtSampling;
+    std::vector<std::vector<double> > m_tracksPhiAtSampling;
+    std::vector<bool> m_extrapolatedSamplings;
+    std::vector<double> m_defaultValues;
+
+    /** @brief get extrapolated track position at each layer */
+    void getExtrapolatedPositions( std::vector<const xAOD::TrackParticle*>,
+                                   int sampling);
+
+    /** @brief new charged PFO container and name */
+    xAOD::PFOContainer* m_chargedPFOContainer;
+    std::string m_chargedPFOContainerName;
+    xAOD::PFOAuxContainer* m_chargedPFOAuxStore;
+
+    /** @brief run on AOD */
+    bool m_AODmode;
+
+    /** @brief estimate energy deposited in Ecal by each charged pion */
+    std::vector<double> getEstEcalEnergy(
+            std::vector<const xAOD::TrackParticle*> tracks,
+            const xAOD::TauJet& pTau,
+            std::vector<std::vector<ElementLink<xAOD::IParticleContainer> > >& hadPFOLinks);
+            
+};
+
+#endif  /* TAUPI0CLUSTERSCALER_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0CreateROI.cxx b/Reconstruction/tauRecTools/src/TauPi0CreateROI.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6ad60e747784283857d040154cda62a9167904bd
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0CreateROI.cxx
@@ -0,0 +1,173 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauPi0CreateROI.cxx
+// package:     Reconstruction/tauEvent
+// authors:     Will Davey, Benedict Winter, Stephanie Yuen
+// date:        2012-10-09
+//-----------------------------------------------------------------------------
+
+#include <TString.h>
+
+#include "GaudiKernel/IToolSvc.h"
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloUtils/CaloCellList.h"
+#include "CaloInterface/ICaloCellMakerTool.h"
+
+#include "AthContainers/OwnershipPolicy.h"
+#include "NavFourMom/INavigable4MomentumCollection.h"
+
+#include "TauPi0CreateROI.h"
+
+#include <boost/scoped_ptr.hpp>
+
+using std::vector;
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauPi0CreateROI::TauPi0CreateROI(   const string& name ) :
+     TauRecToolBase(name)
+    , m_cellMakerTool("")
+    , m_calo_dd_man(NULL)
+    , m_calo_id(NULL)
+    , m_caloCellContainerName("AllCalo")
+    , m_pPi0CellContainer(NULL)
+    , m_pi0CellContainerName("TauCommonPi0Cells")
+{
+    declareProperty("CellMakerTool", m_cellMakerTool);
+    declareProperty("CaloCellContainerName",   m_caloCellContainerName);
+    declareProperty("Pi0CellContainerName",    m_pi0CellContainerName);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauPi0CreateROI::~TauPi0CreateROI() {
+}
+
+StatusCode TauPi0CreateROI::initialize() {
+    
+    // retrieve tools
+    ATH_MSG_DEBUG( "Retrieving tools" );
+    CHECK( m_cellMakerTool.retrieve() );
+    
+    // initialize calo cell geo
+    m_calo_dd_man  = CaloDetDescrManager::instance();
+    m_calo_id      = m_calo_dd_man->getCaloCell_ID();
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0CreateROI::eventInitialize() {
+    
+    const CaloCell_ID* cellID;
+    if((detStore()->retrieve(cellID)).isFailure()){
+        ATH_MSG_ERROR("Unable to retrieve caloCell_ID helper from DetectorStore");
+        return StatusCode::FAILURE;
+    }
+
+    // Get hash range
+    IdentifierHash hashMax;
+    hashMax = cellID->calo_cell_hash_max();
+    ATH_MSG_VERBOSE("CaloCell Hash Max: " << hashMax);
+
+    // Reset addedCellsMap
+    m_addedCellsMap.clear();
+    for (unsigned i = 0; i < hashMax; i++) {
+        m_addedCellsMap.push_back(NULL);
+    }
+
+    //---------------------------------------------------------------------
+    // Create CustomCellContainer and register in StoreGate
+    //---------------------------------------------------------------------
+    m_pPi0CellContainer = new CaloCellContainer(SG::OWN_ELEMENTS);
+    CHECK( evtStore()->record(m_pPi0CellContainer, m_pi0CellContainerName) );
+
+    // symlink as INavigable4MomentumCollection (as in CaloRec/CaloCellMaker)
+    CHECK(evtStore()->symLink(m_pPi0CellContainer, static_cast<INavigable4MomentumCollection*> (0)));
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0CreateROI::execute(xAOD::TauJet& pTau) {
+
+    //---------------------------------------------------------------------
+    // only run on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+        return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("new tau. \tpt = " << pTau.pt() << "\teta = " << pTau.eta() << "\tphi = " << pTau.phi() << "\tnprongs = " << pTau.nTracks());
+
+    //---------------------------------------------------------------------
+    // retrieve cells around tau 
+    //---------------------------------------------------------------------
+    // get all calo cell container
+    const CaloCellContainer *pCellContainer = NULL;
+    CHECK( evtStore()->retrieve(pCellContainer, m_caloCellContainerName) );
+    
+    // get only EM cells within dR<0.4
+    vector<CaloCell_ID::SUBCALO> emSubCaloBlocks;
+    emSubCaloBlocks.push_back(CaloCell_ID::LAREM);
+    boost::scoped_ptr<CaloCellList> pCells(new CaloCellList(pCellContainer,emSubCaloBlocks)); 
+    pCells->select(pTau.eta(), pTau.phi(), 0.4); // TODO: change hardcoded 0.4 to tau cone variable, (or func. from TauJet)?
+
+    //---------------------------------------------------------------------
+    // Put Ecal cells in output container
+    //---------------------------------------------------------------------
+
+    CaloCellList::list_iterator cellItr(pCells->begin()), cellItrE(pCells->end());
+    for(; cellItr != cellItrE; ++cellItr) {
+        const CaloCell* cell = (*cellItr);
+
+        // only keep cells that are in Ecal (PS, EM1, EM2 and EM3, both barrel and endcap).
+        int samp = cell->caloDDE()->getSampling();
+        if(samp>7) continue;
+
+        // Store cell in output container
+        storeCell(cell);
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0CreateROI::eventFinalize() {
+
+    //---------------------------------------------------------------------
+    // use the m_cellMakerTool to finalize the custom CaloCellContainer
+    //---------------------------------------------------------------------
+    CHECK( m_cellMakerTool->process(static_cast<CaloCellContainer*> (m_pPi0CellContainer)) );
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0CreateROI::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+void TauPi0CreateROI::storeCell(const CaloCell* cell){
+    // Store cell in output container if it is a new cell
+    // Produce a copy of the cell, in order to prevent 
+    // the energy of the original cell to be changed. 
+    // Store unweighted cells, since the cell weights are applied during reclustering
+    
+    //Ask cell for it's hash
+    const IdentifierHash cellHash = cell->caloDDE()->calo_hash();
+    //Check if this cell is already part of reducedCellContainer
+    bool isNewCell = (m_addedCellsMap.at(cellHash)==NULL);
+
+    if(isNewCell){
+        CaloCell* copyCell = cell->clone();
+        m_pPi0CellContainer->push_back(const_cast<CaloCell*> (copyCell));
+        m_addedCellsMap[cellHash] = copyCell;
+    }
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0CreateROI.h b/Reconstruction/tauRecTools/src/TauPi0CreateROI.h
new file mode 100644
index 0000000000000000000000000000000000000000..75a6bacfed58b3d4455c57df3f4eefa8864e6b2c
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0CreateROI.h
@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPI0CREATEROI_H
+#define	TAUREC_TAUPI0CREATEROI_H
+
+#include <string>
+#include <vector>
+
+#include "GaudiKernel/ToolHandle.h"
+#include "tauRecTools/TauRecToolBase.h"
+
+#include "xAODTau/TauJet.h"
+
+class ICaloCellMakerTool;
+
+/**
+ * @brief Create ROIs for the Pi0 finder.
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch> 
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch>
+ */
+
+class TauPi0CreateROI : virtual public TauRecToolBase {
+public:
+    TauPi0CreateROI(const std::string& name);
+    ASG_TOOL_CLASS2(TauPi0CreateROI, TauRecToolBase, ITauToolBase);
+    virtual ~TauPi0CreateROI();
+
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize();
+    virtual StatusCode finalize();
+
+    virtual void cleanup(xAOD::TauJet* ) { }
+    virtual void print() const { }
+
+private:
+
+    /** @brief store cell in output container */ 
+    void storeCell(const CaloCell* /* cell*/);
+
+    /** @brief tool handles */
+    ToolHandle<ICaloCellMakerTool> m_cellMakerTool;
+
+    /** @brief calo cell navigation */
+    const CaloDetDescrManager* m_calo_dd_man;
+    const CaloCell_ID* m_calo_id;
+ 
+    /** @brief all calo cell container name */
+    std::string m_caloCellContainerName;
+  
+    /** @brief output cell container and name*/ 
+    CaloCellContainer *m_pPi0CellContainer;
+    std::string m_pi0CellContainerName;
+
+    /** @brief hash map in order to keep track, which cells have been added to output cell container*/
+    std::vector<CaloCell*> m_addedCellsMap;
+};
+
+#endif	/* TAUPI0CREATEROI_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.cxx b/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..e9ca28113d9120bf5be740ef7ef36b4678202601
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.cxx
@@ -0,0 +1,234 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauPi0ScoreCalculator.cxx
+// package:     Reconstruction/tauRec
+// authors:     Benedict Winter, Will Davey
+// date:        2012-10-09
+//
+//-----------------------------------------------------------------------------
+
+#include <vector>
+
+#include "TauPi0ScoreCalculator.h"
+#include "xAODPFlow/PFO.h"
+
+#include "TMVA/Reader.h"
+
+using std::vector;
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauPi0ScoreCalculator::TauPi0ScoreCalculator( const string& name ) :
+    TauRecToolBase(name)
+    , m_readerOption("Silent:!Color")
+{
+    declareProperty("ReaderOption",            m_readerOption);
+    declareProperty("BDTWeightFile",           m_weightfile);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauPi0ScoreCalculator::~TauPi0ScoreCalculator() 
+{
+}
+
+
+StatusCode TauPi0ScoreCalculator::initialize() 
+{
+  //---------------------------------------------------------------------
+  // Create TMVA reader
+  //---------------------------------------------------------------------
+  m_tmvaReader = new TMVA::Reader(TString(m_readerOption));
+
+  if (msgLvl(MSG::DEBUG)) m_tmvaReader->SetVerbose(true);
+
+  int spectator = 1.;
+  m_tmvaReader->AddSpectator( "nTau"                            ,&spectator);
+  m_tmvaReader->AddSpectator( "nTau_test : = nTau%5"            ,&spectator);
+  m_tmvaReader->AddSpectator( "Sample"                          ,&spectator);
+  m_tmvaReader->AddSpectator( "Pi0Cluster_type"                 ,&spectator);
+  m_tmvaReader->AddSpectator( "Pi0Cluster_BDTScore_old"         ,&spectator);
+  m_tmvaReader->AddVariable( "Pi0Cluster_Abs_FIRST_ETA"         ,&m_Abs_FIRST_ETA);
+  m_tmvaReader->AddVariable( "Pi0Cluster_SECOND_R"              ,&m_SECOND_R);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_SECOND_LAMBDA"         ,&m_SECOND_LAMBDA);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_Abs_DELTA_PHI"         ,&m_Abs_DELTA_PHI);
+  m_tmvaReader->AddVariable( "Pi0Cluster_Abs_DELTA_THETA"       ,&m_Abs_DELTA_THETA);
+  m_tmvaReader->AddVariable( "Pi0Cluster_CENTER_LAMBDA_helped"  ,&m_CENTER_LAMBDA_helped);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_LATERAL"               ,&m_LATERAL);
+  m_tmvaReader->AddVariable( "Pi0Cluster_LONGITUDINAL"          ,&m_LONGITUDINAL);
+  m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_EM"           ,&m_ENG_FRAC_EM);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_MAX"          ,&m_ENG_FRAC_MAX);
+  m_tmvaReader->AddVariable( "Pi0Cluster_ENG_FRAC_CORE"         ,&m_ENG_FRAC_CORE);
+  m_tmvaReader->AddVariable( "Pi0Cluster_log_SECOND_ENG_DENS"   ,&m_log_SECOND_ENG_DENS);
+  m_tmvaReader->AddVariable( "Pi0Cluster_EcoreOverEEM1"         ,&m_EcoreOverEEM1);
+// m_tmvaReader->AddVariable( "Pi0Cluster_NHitsInEM1"             ,&m_NHitsInEM1);
+// m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_PS"          ,&m_NPosCells_PS);
+  m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_EM1"        ,&m_NPosCells_EM1);
+  m_tmvaReader->AddVariable( "Pi0Cluster_NPosECells_EM2"        ,&m_NPosCells_EM2);
+  m_tmvaReader->AddVariable( "Pi0Cluster_AbsFirstEtaWRTClusterPosition_EM1" ,&m_firstEtaWRTCluster_EM1);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_AbsFirstEtaWRTClusterPosition_EM2" ,&m_firstEtaWRTCluster_EM2);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_secondEtaWRTClusterPosition_EM1" ,&m_secondEtaWRTCluster_EM1);
+  m_tmvaReader->AddVariable( "Pi0Cluster_secondEtaWRTClusterPosition_EM2" ,&m_secondEtaWRTCluster_EM2);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_energy_EM1"            ,&m_energy_EM1);
+//  m_tmvaReader->AddVariable( "Pi0Cluster_energy_EM2"            ,&m_energy_EM2);
+
+  if (bookMethod(m_tmvaReader, "BDT method").isFailure()) return StatusCode::FAILURE;
+ 
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0ScoreCalculator::finalize()
+{
+  StatusCode sc = AlgTool::finalize();
+  delete m_tmvaReader;
+  return sc;
+}
+
+
+StatusCode TauPi0ScoreCalculator::execute(xAOD::TauJet& pTau) 
+{
+    //---------------------------------------------------------------------
+    // only run on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+        return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("ScoreCalculator: new tau. \tpt = " << pTau.pt() << "\teta = " << pTau.eta() << "\tphi = " << pTau.phi() << "\tnprongs = " << pTau.nTracks());
+
+    //---------------------------------------------------------------------
+    // retrieve neutral PFOs from tau, calculate BDT scores and store them in PFO
+    //---------------------------------------------------------------------
+    unsigned nNeutPFO = pTau.nProtoNeutralPFOs();
+    for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++) {
+        const xAOD::PFO* curNeutPFO_const = pTau.protoNeutralPFO( iNeutPFO );
+        float BDTScore = calculateScore(curNeutPFO_const);
+        xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const);
+        curNeutPFO->setBDTPi0Score((float) BDTScore);
+    }
+
+    ATH_MSG_DEBUG("End of TauPi0ScoreCalculator::execute");
+
+    return StatusCode::SUCCESS;
+}
+
+
+float TauPi0ScoreCalculator::calculateScore(const xAOD::PFO* neutralPFO)
+{
+    m_Abs_FIRST_ETA=0.;
+    m_SECOND_R=0.;
+    m_SECOND_LAMBDA=0.;
+    m_Abs_DELTA_PHI=0.;
+    m_Abs_DELTA_THETA=0.;
+    m_CENTER_LAMBDA_helped=0.;
+    m_LATERAL=0.;
+    m_LONGITUDINAL=0.;
+    m_ENG_FRAC_EM=0.;
+    m_ENG_FRAC_MAX=0.;
+    m_ENG_FRAC_CORE=0.;
+    m_log_SECOND_ENG_DENS=0.;
+    m_EcoreOverEEM1=0.;
+    // Need to convert int variables to floats after retrieving them
+    int NHitsInEM1=0;
+    int NPosCells_PS=0;
+    int NPosCells_EM1=0;
+    int NPosCells_EM2=0;
+    m_firstEtaWRTCluster_EM1=0.;
+    m_firstEtaWRTCluster_EM2=0.;
+    m_secondEtaWRTCluster_EM1=0.;
+    m_secondEtaWRTCluster_EM2=0.;
+    m_energy_EM1=0.;
+    m_energy_EM2=0.;
+
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_FIRST_ETA,m_Abs_FIRST_ETA) == false)
+        ATH_MSG_WARNING("Can't find FIRST_ETA. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_R,m_SECOND_R) == false)
+        ATH_MSG_WARNING("Can't find SECOND_R. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_LAMBDA,m_SECOND_LAMBDA) == false)
+        ATH_MSG_WARNING("Can't find SECOND_LAMBDA. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_PHI,m_Abs_DELTA_PHI) == false)
+        ATH_MSG_WARNING("Can't find DELTA_PHI. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_DELTA_THETA,m_Abs_DELTA_THETA) == false)
+        ATH_MSG_WARNING("Can't find DELTA_THETA. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_CENTER_LAMBDA,m_CENTER_LAMBDA_helped) == false) 
+        ATH_MSG_WARNING("Can't find CENTER_LAMBDA. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_LATERAL,m_LATERAL) == false)
+        ATH_MSG_WARNING("Can't find LATERAL. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_LONGITUDINAL,m_LONGITUDINAL) == false) 
+        ATH_MSG_WARNING("Can't find LONGITUDINAL. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_EM,m_ENG_FRAC_EM) == false) 
+        ATH_MSG_WARNING("Can't find ENG_FRAC_EM. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_MAX,m_ENG_FRAC_MAX) == false) 
+        ATH_MSG_WARNING("Can't find ENG_FRAC_MAX. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_ENG_FRAC_CORE,m_ENG_FRAC_CORE) == false) 
+        ATH_MSG_WARNING("Can't find ENG_FRAC_CORE. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_SECOND_ENG_DENS,m_log_SECOND_ENG_DENS) == false) 
+        ATH_MSG_WARNING("Can't find SECOND_ENG_DENS. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_EM1CoreFrac,m_EcoreOverEEM1) == false) 
+        ATH_MSG_WARNING("Can't find EM1CoreFrac. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NHitsInEM1,NHitsInEM1) == false) 
+        ATH_MSG_WARNING("Can't find NHitsInEM1. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_PS,NPosCells_PS) == false) 
+        ATH_MSG_WARNING("Can't find NPosECells_PS. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM1,NPosCells_EM1) == false) 
+        ATH_MSG_WARNING("Can't find NPosECells_EM1. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_NPosECells_EM2,NPosCells_EM2) == false) 
+        ATH_MSG_WARNING("Can't find NPosECells_EM2. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM1,m_firstEtaWRTCluster_EM1) == false) 
+        ATH_MSG_WARNING("Can't find firstEtaWRTClusterPosition_EM1. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_firstEtaWRTClusterPosition_EM2,m_firstEtaWRTCluster_EM2) == false) 
+        ATH_MSG_WARNING("Can't find firstEtaWRTClusterPosition_EM2. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM1,m_secondEtaWRTCluster_EM1) == false) 
+        ATH_MSG_WARNING("Can't find secondEtaWRTClusterPosition_EM1. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_secondEtaWRTClusterPosition_EM2,m_secondEtaWRTCluster_EM2) == false) 
+        ATH_MSG_WARNING("Can't find secondEtaWRTClusterPosition_EM2. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM1,m_energy_EM1) == false) 
+        ATH_MSG_WARNING("Can't find energy_EM1. Set it to 0.");
+    if(neutralPFO->attribute(xAOD::PFODetails::PFOAttributes::cellBased_energy_EM2,m_energy_EM2) == false) 
+        ATH_MSG_WARNING("Can't find energy_EM2. Set it to 0.");
+    // Apply variable transformations
+    m_Abs_FIRST_ETA   = fabs(m_Abs_FIRST_ETA);
+    m_Abs_DELTA_PHI   = fabs(m_Abs_DELTA_PHI);
+    m_Abs_DELTA_THETA = fabs(m_Abs_DELTA_THETA);
+    m_CENTER_LAMBDA_helped = fmin(m_CENTER_LAMBDA_helped, 1000.);
+    if(m_log_SECOND_ENG_DENS==0.) m_log_SECOND_ENG_DENS=-50.;
+    else m_log_SECOND_ENG_DENS = log(m_log_SECOND_ENG_DENS);
+    // Convert ints to floats so they can be read by the TMVA reader
+    m_NHitsInEM1 = (float) NHitsInEM1;
+    m_NPosCells_PS = (float) NPosCells_PS;
+    m_NPosCells_EM1 = (float) NPosCells_EM1;
+    m_NPosCells_EM2 = (float) NPosCells_EM2;
+    m_firstEtaWRTCluster_EM1 = fabs(m_firstEtaWRTCluster_EM1);
+    m_firstEtaWRTCluster_EM2 = fabs(m_firstEtaWRTCluster_EM2);
+
+    // Calculate BDT score
+    float BDTScore = m_tmvaReader->EvaluateMVA( "BDT method" );
+     
+    return BDTScore;
+}
+
+StatusCode TauPi0ScoreCalculator::bookMethod(TMVA::Reader *reader, const std::string &methodName) const 
+{
+    if (m_weightfile == ""){
+        ATH_MSG_ERROR("No weight file given");
+        return StatusCode::FAILURE;
+    }
+    std::string resolvedFileName = find_file(m_weightfile);
+    if (resolvedFileName != "") {
+        ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName );
+    } 
+    else {
+        ATH_MSG_ERROR( "Parameterisation file " << m_weightfile << " not found" );
+        return StatusCode::FAILURE;
+    }
+    reader->BookMVA( methodName, resolvedFileName);
+    return StatusCode::SUCCESS;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.h b/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ac6c3148439d5092bd3938739b4c9bc418ed025
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0ScoreCalculator.h
@@ -0,0 +1,80 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPI0SCORECALCULATOR_H
+#define	TAUREC_TAUPI0SCORECALCULATOR_H
+
+#include <string>
+#include "tauRecTools/TauRecToolBase.h"
+#include "xAODPFlow/PFO.h"
+
+namespace TMVA{
+    class Reader;
+}
+
+/**
+ * @brief Selectes pi0Candidates (Pi0 Finder).
+ * 
+ * @author Veit Scharf
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch> 
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch>
+ */
+
+class TauPi0ScoreCalculator : virtual public TauRecToolBase {
+public:
+    TauPi0ScoreCalculator(const std::string& name);
+    ASG_TOOL_CLASS2(TauPi0ScoreCalculator, TauRecToolBase, ITauToolBase);
+    virtual ~TauPi0ScoreCalculator();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+
+    std::string m_readerOption;
+    TMVA::Reader *m_tmvaReader;
+
+    std::string m_weightfile;
+
+    float m_Abs_FIRST_ETA;
+    float m_SECOND_R;
+    float m_SECOND_LAMBDA;
+    float m_Abs_DELTA_PHI;
+    float m_Abs_DELTA_THETA;
+    float m_CENTER_LAMBDA_helped;
+    float m_LATERAL;
+    float m_LONGITUDINAL;
+    float m_ENG_FRAC_EM;
+    float m_ENG_FRAC_MAX;
+    float m_ENG_FRAC_CORE;
+    float m_log_SECOND_ENG_DENS;
+    float m_EcoreOverEEM1;
+    float m_NHitsInEM1;
+    float m_NPosCells_PS;
+    float m_NPosCells_EM1;
+    float m_NPosCells_EM2;
+    float m_firstEtaWRTCluster_EM1;
+    float m_firstEtaWRTCluster_EM2;
+    float m_secondEtaWRTCluster_EM1;
+    float m_secondEtaWRTCluster_EM2;
+    float m_energy_EM1;
+    float m_energy_EM2;
+
+    /** @brief function used to calculate BDT score */
+    float calculateScore(const xAOD::PFO* neutralPFO);
+
+    /** @brief Book TMVA methods. */
+    StatusCode bookMethod(TMVA::Reader *reader, const std::string &methodName) const;
+
+};
+
+#endif	/* TAUPI0SCORECALCULATOR_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0Selector.cxx b/Reconstruction/tauRecTools/src/TauPi0Selector.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..4d6c9a91bd9933e2c5c186f36e21c536c42b00fc
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0Selector.cxx
@@ -0,0 +1,170 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauPi0Selector.cxx
+// package:     Reconstruction/tauRec
+// authors:     Benedict Winter, Will Davey
+// date:        2012-10-09
+//
+//-----------------------------------------------------------------------------
+
+#include "TauPi0Selector.h"
+#include "FourMomUtils/P4Helpers.h"
+#include "CaloUtils/CaloVertexedCluster.h"
+
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauPi0Selector::TauPi0Selector( const string& name ) :
+    TauRecToolBase(name)
+{
+    declareProperty("ClusterEtCut",             m_clusterEtCut);
+    declareProperty("ClusterBDTCut_1prong",     m_clusterBDTCut_1prong);
+    declareProperty("ClusterBDTCut_mprong",     m_clusterBDTCut_mprong);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauPi0Selector::~TauPi0Selector() 
+{
+}
+
+StatusCode TauPi0Selector::initialize()
+{
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0Selector::finalize()
+{
+  return StatusCode::SUCCESS;
+}
+
+StatusCode TauPi0Selector::execute(xAOD::TauJet& pTau) 
+{
+    // Clear vector of cell-based pi0 PFO Links. Required when rerunning on xAOD level.
+    pTau.clearProtoPi0PFOLinks();
+    // Set proto decay mode to "not set". Will be overwritten for taus with 1-5 tracks
+    pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_NotSet);
+
+    //---------------------------------------------------------------------
+    // only run on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+        return StatusCode::SUCCESS;
+    }
+
+    // Set proto decay mode to "other". Will be overwritten for taus with 1 or 3 tracks
+    pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_Other);
+
+    //---------------------------------------------------------------------
+    // retrieve neutral PFOs from tau. Apply selection and create links to
+    // Pi0NeutralPFOs 
+    //---------------------------------------------------------------------
+    int nRecoPi0s=0;
+    unsigned nNeutPFO = pTau.nProtoNeutralPFOs();
+    for(unsigned int iNeutPFO=0; iNeutPFO<nNeutPFO; iNeutPFO++) {
+        const xAOD::PFO* curNeutPFO_const = pTau.protoNeutralPFO( iNeutPFO );
+
+        // Set number of pi0s to 0 for all neutral PFOs. Required when rerunning on xAOD level
+        xAOD::PFO* curNeutPFO = const_cast<xAOD::PFO*>(curNeutPFO_const);
+        curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, 0);
+
+        // Get eta bin
+        int etaBin = getPi0Cluster_etaBin( curNeutPFO->p4().Eta() );
+
+        // Preselection
+        if(curNeutPFO->p4().Et() < m_clusterEtCut.at(etaBin)) continue;
+        if(pTau.p4().DeltaR(curNeutPFO->p4()) > 0.2) continue; // TODO: Replace by shrinking cone?
+
+        // BDT Selection
+        float BDTScore = curNeutPFO->bdtPi0Score();
+        ATH_MSG_DEBUG("etaBin = " << etaBin << ", m_clusterEtCut.at(etaBin) = " <<m_clusterEtCut.at(etaBin) << ", m_clusterBDTCut_1prong.at(etaBin) = " 
+                                  << m_clusterBDTCut_1prong.at(etaBin) << ", m_clusterBDTCut_mprong.at(etaBin) = " << m_clusterBDTCut_mprong.at(etaBin));
+        if( (pTau.nTracks()==1 && BDTScore < m_clusterBDTCut_1prong.at(etaBin)) || (pTau.nTracks()>1 && BDTScore < m_clusterBDTCut_mprong.at(etaBin)) ) continue;
+
+        // Set number of pi0s
+        int nHitsInEM1 = 0;
+        if(!curNeutPFO->attribute(xAOD::PFODetails::cellBased_NHitsInEM1, nHitsInEM1)) ATH_MSG_WARNING("Couldn't retrieve nHitsInEM1. Will set it to 0.");
+        if(nHitsInEM1<3){ 
+            curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, 1);
+            nRecoPi0s++;
+        }   
+        else{ 
+            curNeutPFO->setAttribute<int>(xAOD::PFODetails::PFOAttributes::nPi0Proto, 2);
+            nRecoPi0s+=2;
+        }
+
+        // Set element link to Pi0tagged PFO
+        ElementLink<xAOD::PFOContainer> pfoLink = pTau.protoNeutralPFOLinks().at(iNeutPFO);
+        pTau.addProtoPi0PFOLink(pfoLink);
+    }
+    // Calculate visTau hlv and store it in pPi0Details.
+    TLorentzVector p4 = getP4(pTau);
+    pTau.setP4(xAOD::TauJetParameters::PanTauCellBasedProto, p4.Pt(),p4.Eta(),p4.Phi(),p4.M());
+    // pTau.setPtPanTauCellBasedProto( p4.Pt());
+    // pTau.setEtaPanTauCellBasedProto(p4.Eta());
+    // pTau.setPhiPanTauCellBasedProto(p4.Phi());
+    // pTau.setEPanTauCellBasedProto(  p4.E());
+    // pTau.setMPanTauCellBasedProto(  p4.M());
+
+    if(pTau.nTracks()==1){
+      if(nRecoPi0s==0)      pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_1p0n);
+      else if(nRecoPi0s==1) pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_1p1n);
+      else                  pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_1pXn);
+    }
+    if(pTau.nTracks()==3){
+      if(nRecoPi0s==0) pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_3p0n);
+      else             pTau.setPanTauDetail(xAOD::TauJetParameters::pantau_CellBasedInput_DecayModeProto, xAOD::TauJetParameters::DecayMode::Mode_3pXn);
+    }
+
+    
+    return StatusCode::SUCCESS;
+}
+
+int TauPi0Selector::getPi0Cluster_etaBin(double Pi0Cluster_eta){
+    int Pi0Cluster_etaBin = -1;
+    double Pi0Cluster_noCorr_ABSeta = fabs(Pi0Cluster_eta);
+
+    if( Pi0Cluster_noCorr_ABSeta < 0.80 ) Pi0Cluster_etaBin = 0;
+    else if( Pi0Cluster_noCorr_ABSeta < 1.40 ) Pi0Cluster_etaBin = 1;
+    else if( Pi0Cluster_noCorr_ABSeta < 1.50 ) Pi0Cluster_etaBin = 2;
+    else if( Pi0Cluster_noCorr_ABSeta < 1.90 ) Pi0Cluster_etaBin = 3;
+    else Pi0Cluster_etaBin = 4;
+    return Pi0Cluster_etaBin;
+}
+
+TLorentzVector TauPi0Selector::getP4(const xAOD::TauJet& pTau)
+{
+    // Get 4mom of first charged PFO, which is available for all taus that are treated in this algorithm
+    const xAOD::PFO* firstChargedPFO = pTau.protoChargedPFO( 0 );
+    TLorentzVector p4 = firstChargedPFO->p4();
+    // Add other PFO momenta
+    unsigned nChargedPFO = pTau.nProtoChargedPFOs();
+    for(unsigned int iChargedPFO=1; iChargedPFO<nChargedPFO; iChargedPFO++){
+        const xAOD::PFO* curChargedPFO = pTau.protoChargedPFO( iChargedPFO );
+        p4+=curChargedPFO->p4();
+    }
+    unsigned nPi0NeutPFO = pTau.nProtoPi0PFOs();
+    for(unsigned int iPi0NeutPFO=0; iPi0NeutPFO<nPi0NeutPFO; iPi0NeutPFO++){
+        const xAOD::PFO* curPi0NeutPFO = pTau.protoPi0PFO( iPi0NeutPFO );
+        TLorentzVector cluster_corrP4;
+        if(pTau.vertexLink())
+          cluster_corrP4 = xAOD::CaloVertexedCluster(*curPi0NeutPFO->cluster(0) , (*pTau.vertexLink())->position()).p4();
+        else
+          cluster_corrP4 = xAOD::CaloVertexedCluster(*curPi0NeutPFO->cluster(0)).p4();
+        TLorentzVector pi0_corrP4;
+        double pi0_corrP  = std::sqrt(curPi0NeutPFO->e()*curPi0NeutPFO->e()-134.9766*CLHEP::MeV*134.9766*CLHEP::MeV);
+        double pi0_corrPt = pi0_corrP/TMath::CosH(cluster_corrP4.Eta());
+        pi0_corrP4.SetPtEtaPhiM(pi0_corrPt,cluster_corrP4.Eta(),cluster_corrP4.Phi(),134.9766*CLHEP::MeV);
+        p4+=pi0_corrP4;
+    }
+    return p4;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauPi0Selector.h b/Reconstruction/tauRecTools/src/TauPi0Selector.h
new file mode 100644
index 0000000000000000000000000000000000000000..096d0922c083f6d23cd2548f04b7dd8eaf37a098
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauPi0Selector.h
@@ -0,0 +1,44 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPI0SELECTOR_H
+#define	TAUREC_TAUPI0SELECTOR_H
+
+#include <string>
+#include "tauRecTools/TauRecToolBase.h"
+
+/**
+ * @brief Selects pi0s
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch> 
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch>
+ */
+
+class TauPi0Selector : virtual public TauRecToolBase {
+public:
+    TauPi0Selector(const std::string& name);
+    ASG_TOOL_CLASS2(TauPi0Selector, TauRecToolBase, ITauToolBase);
+    virtual ~TauPi0Selector();
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+
+    std::vector<float> m_clusterEtCut;
+    std::vector<float> m_clusterBDTCut_1prong;
+    std::vector<float> m_clusterBDTCut_mprong;
+    /** @brief function used to get eta bin of Pi0Cluster */
+    int getPi0Cluster_etaBin(double Pi0Cluster_eta);
+    /** @brief function used to calculate the visible tau 4 momentum */
+    TLorentzVector getP4(const xAOD::TauJet& tauJet);
+};
+
+#endif	/* TAUPI0SELECTOR_H */
diff --git a/Reconstruction/tauRecTools/src/TauShotFinder.cxx b/Reconstruction/tauRecTools/src/TauShotFinder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..befd3bda457174a1afd2cca0e6c14d67db87af3b
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauShotFinder.cxx
@@ -0,0 +1,564 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauShotFinder.cxx
+// package:     Reconstruction/tauRec
+// authors:     Will Davey, Benedict Winter, Stephanie Yuen
+// date:        2013-05-22
+//
+//-----------------------------------------------------------------------------
+
+#include <boost/scoped_ptr.hpp>
+
+#include "GaudiKernel/IToolSvc.h"
+
+#include "CaloEvent/CaloCellContainer.h"
+#include "xAODCaloEvent/CaloClusterContainer.h"
+#include "xAODCaloEvent/CaloClusterKineHelper.h"
+#include "CaloIdentifier/CaloCell_ID.h"
+#include "CaloIdentifier/LArNeighbours.h"
+#include "CaloUtils/CaloClusterStoreHelper.h"
+#include "CaloUtils/CaloCellList.h"
+#include "CaloUtils/CaloCellESort.h"
+#include "CaloInterface/IHadronicCalibrationTool.h"
+#include "FourMomUtils/P4Helpers.h"
+#include "TauShotFinder.h"
+#include "TauShotVariableHelpers.h"
+//#include "TMVA/Reader.h"
+#include "xAODPFlow/PFOContainer.h"
+#include "xAODPFlow/PFOAuxContainer.h"
+#include "xAODPFlow/PFO.h"
+
+using std::vector;
+using std::string;
+
+//-------------------------------------------------------------------------
+// Constructor
+//-------------------------------------------------------------------------
+
+TauShotFinder::TauShotFinder(   const string& name ) :
+    TauRecToolBase(name)
+    , m_caloWeightTool("H1WeightToolCSC12Generic")
+    , m_caloCellContainerName("AllCalo")
+    , m_shotClusterContainer(NULL)
+    , m_shotClusterContainerName("TauShotClusters")
+    , m_shotPFOContainerName("TauShotParticleFlowObjects")
+    , m_calo_dd_man(NULL)
+    , m_calo_id(NULL)
+{
+    declareProperty("CaloWeightTool", m_caloWeightTool);
+    declareProperty("CaloCellContainerName", m_caloCellContainerName); 
+    declareProperty("ShotClusterContainerName", m_shotClusterContainerName);
+    declareProperty("ShotPFOContainerName",  m_shotPFOContainerName);
+//    declareProperty("ReaderOption",          m_readerOption);
+//    declareProperty("BDTWeightFile_barrel",  m_weightfile_barrel);
+//    declareProperty("BDTWeightFile_endcap1", m_weightfile_endcap1);
+//    declareProperty("BDTWeightFile_endcap2", m_weightfile_endcap2);
+    declareProperty("NCellsInEta",           m_nCellsInEta);
+    declareProperty("MinPtCut",              m_minPtCut);
+    declareProperty("AutoDoubleShotCut",     m_autoDoubleShotCut);
+    declareProperty("MergedBDTScoreCut",     m_mergedBDTScoreCut);
+}
+
+//-------------------------------------------------------------------------
+// Destructor
+//-------------------------------------------------------------------------
+
+TauShotFinder::~TauShotFinder() {
+}
+
+StatusCode TauShotFinder::initialize() {
+    
+    // retrieve tools
+    ATH_MSG_DEBUG( "Retrieving tools" );
+    CHECK( m_caloWeightTool.retrieve() );
+
+    // initialize calo cell geo
+    m_calo_dd_man  = CaloDetDescrManager::instance();
+    m_calo_id      = m_calo_dd_man->getCaloCell_ID();
+
+    /*
+    //---------------------------------------------------------------------
+    // Create TMVA readers
+    //---------------------------------------------------------------------
+    m_tmvaReader_barrel = new TMVA::Reader(TString(m_readerOption));
+    if (msgLvl(MSG::DEBUG)) m_tmvaReader_barrel->SetVerbose(true);
+    m_tmvaReader_barrel->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC);
+    m_tmvaReader_barrel->AddVariable("shot_stdpt_5"                 ,&G_STDPT_5 );
+    m_tmvaReader_barrel->AddVariable("shot_stdeta_5"                ,&G_STDETA_5 );
+    m_tmvaReader_barrel->AddVariable("shot_deltapt_min"             ,&G_DELTAPT_MIN );
+
+    m_tmvaReader_endcap1 = new TMVA::Reader(TString(m_readerOption));
+    if (msgLvl(MSG::DEBUG)) m_tmvaReader_endcap1->SetVerbose(true);
+    m_tmvaReader_endcap1->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC);
+    m_tmvaReader_endcap1->AddVariable("shot_stdpt_5"                 ,&G_STDPT_5 );
+    m_tmvaReader_endcap1->AddVariable("shot_stdeta_5"                ,&G_STDETA_5 );
+    m_tmvaReader_endcap1->AddVariable("shot_deltapt_min"             ,&G_DELTAPT_MIN );
+
+    m_tmvaReader_endcap2 = new TMVA::Reader(TString(m_readerOption));
+    if (msgLvl(MSG::DEBUG)) m_tmvaReader_endcap2->SetVerbose(true);
+    m_tmvaReader_endcap2->AddVariable("(shot_pt_3-shot_pt)/shot_pt_3",&G_PTFRAC);
+    m_tmvaReader_endcap2->AddVariable("shot_stdpt_5"                 ,&G_STDPT_5 );
+    m_tmvaReader_endcap2->AddVariable("shot_stdeta_5"                ,&G_STDETA_5 );
+    m_tmvaReader_endcap2->AddVariable("shot_deltapt_min"             ,&G_DELTAPT_MIN );
+
+    if (bookMethod(m_tmvaReader_barrel, m_tmvaReader_endcap1, m_tmvaReader_endcap2, "BDT method").isFailure()) return StatusCode::FAILURE;
+    */
+
+    // setupCuts();
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauShotFinder::finalize()
+{
+  StatusCode sc = AlgTool::finalize();
+  /*
+  delete m_tmvaReader_barrel;
+  delete m_tmvaReader_endcap1;
+  delete m_tmvaReader_endcap2;
+  */
+  return sc;
+}
+
+StatusCode TauShotFinder::eventInitialize() {
+
+    //---------------------------------------------------------------------
+    // Create Shot ClusterContainer and register in StoreGate
+    //---------------------------------------------------------------------
+    m_shotClusterContainer = CaloClusterStoreHelper::makeContainer(&*evtStore(),   
+								 m_shotClusterContainerName,    
+								 msg()                  
+								 );
+
+    //---------------------------------------------------------------------
+    // Create Shot PFO container
+    //---------------------------------------------------------------------
+    m_PFOShotContainer = new xAOD::PFOContainer();
+    CHECK( evtStore()->record(m_PFOShotContainer, m_shotPFOContainerName ) );
+    m_PFOShotAuxStore = new xAOD::PFOAuxContainer();
+    CHECK( evtStore()->record( m_PFOShotAuxStore, m_shotPFOContainerName + "Aux." ) );
+    m_PFOShotContainer->setStore(m_PFOShotAuxStore);
+
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauShotFinder::execute(xAOD::TauJet& pTau) {
+
+    // Any tau needs to have shot PFO vectors. Set empty vectors before nTrack cut
+    vector<ElementLink<xAOD::PFOContainer> > empty;
+    pTau.setShotPFOLinks(empty);
+    
+    //---------------------------------------------------------------------
+    // only run shower subtraction on 1-5 prong taus 
+    //---------------------------------------------------------------------
+    if (pTau.nTracks() == 0 || pTau.nTracks() >5 ) {
+       return StatusCode::SUCCESS;
+    }
+    ATH_MSG_DEBUG("");
+    ATH_MSG_DEBUG("New tau");
+
+    //---------------------------------------------------------------------
+    // retrieve cells around tau 
+    //---------------------------------------------------------------------
+    // get all calo cell container
+    const CaloCellContainer *pCellContainer = NULL;
+    CHECK( evtStore()->retrieve(pCellContainer, m_caloCellContainerName) );
+    
+    // get only EM cells within dR<0.2
+    // TODO: might be possible to select only EM1 cells, but probbaly wont 
+    //       speed things up much anyway
+    vector<CaloCell_ID::SUBCALO> emSubCaloBlocks;
+    emSubCaloBlocks.push_back(CaloCell_ID::LAREM);
+    boost::scoped_ptr<CaloCellList> pCells(new CaloCellList(pCellContainer,emSubCaloBlocks)); 
+
+    // TODO: change hardcoded 0.2 to tau cone variable, (or func. from TauJet?)
+    pCells->select(pTau.eta(), pTau.phi(), 0.4); 
+
+    // Dump cells into a std::vector since CaloCellList wont allow sorting
+    // (maybe this can be done faster at some point).
+    // Also apply very basic preselection
+    std::vector<const CaloCell*> cells;
+    CaloCellList::list_iterator cellItr = pCells->begin();
+    for(; cellItr!=pCells->end();++cellItr){
+        // require cells above 100 MeV
+        if( (*cellItr)->pt()*m_caloWeightTool->wtCell(*cellItr) < 100. ) continue;
+        // require cells in EM1 
+        int samp = (*cellItr)->caloDDE()->getSampling();
+        if( !( samp == CaloCell_ID::EMB1 || samp == CaloCell_ID::EME1 ) ) continue;
+        cells.push_back(*cellItr);
+    }
+    // sort cells in descending pt 
+    std::sort(cells.begin(),cells.end(),ptSort(*this));
+    
+    //---------------------------------------------------------------------
+    // shot seeding 
+    //---------------------------------------------------------------------
+    // get seed cells
+    std::vector<const CaloCell*> seedCells; 
+    std::set<IdentifierHash> seedCellHashes;
+    cellItr = cells.begin();
+    for(; cellItr != cells.end(); ++cellItr) {
+        const CaloCell* cell = (*cellItr);
+        const IdentifierHash cellHash = cell->caloDDE()->calo_hash();
+
+        // apply seed selection on nearest neighbours
+        std::vector<IdentifierHash> nextEta, prevEta;
+        m_calo_id->get_neighbours(cellHash,LArNeighbours::nextInEta,nextEta);
+        m_calo_id->get_neighbours(cellHash,LArNeighbours::prevInEta,prevEta);
+        std::vector<IdentifierHash> neighbours = nextEta;
+        neighbours.insert(neighbours.end(),prevEta.begin(),prevEta.end()); 
+        bool status = true;
+        std::vector<IdentifierHash>::iterator hashItr = neighbours.begin();
+        for(;hashItr!=neighbours.end();++hashItr){
+            // must not be next to seed cell (TODO: maybe this requirement can be removed)
+            if( seedCellHashes.find(*hashItr) != seedCellHashes.end() ){
+                status = false;
+                break;
+            }
+            // must be maximum
+            const CaloCell* neigCell = pCellContainer->findCell(*hashItr);
+            if( !neigCell ) continue;
+            if( neigCell->pt()*m_caloWeightTool->wtCell(neigCell) >= cell->pt()*m_caloWeightTool->wtCell(cell) ){
+                status = false;
+                break;
+            }
+        }
+        if( !status ) continue;        
+        seedCells.push_back(cell); 
+        seedCellHashes.insert(cellHash);
+    } // preselected cells
+    ATH_MSG_DEBUG("seedCells.size() = " << seedCells.size());
+    
+    // merge across phi and construct shots
+    while( seedCells.size() ){
+        
+        const CaloCell* cell = seedCells.front(); 
+        const IdentifierHash seedHash = cell->caloDDE()->calo_hash();
+
+        // look for match across phi in current seeds
+        const CaloCell* nextPhi = NULL;
+        const CaloCell* prevPhi = NULL;
+        for( cellItr = seedCells.begin(); cellItr!=seedCells.end(); ++cellItr){
+            if( (*cellItr) == cell ) continue;
+            IdentifierHash shotCellHash = (*cellItr)->caloDDE()->calo_hash();
+            if( this->isPhiNeighbour(seedHash,shotCellHash,true) )       nextPhi = (*cellItr);
+            else if( this->isPhiNeighbour(seedHash,shotCellHash,false) ) prevPhi = (*cellItr);
+        }
+       
+        const CaloCell* mergePhi = NULL;
+        if( nextPhi && prevPhi ){
+            // take higest-pt if merged up and down
+            if( nextPhi->pt()*m_caloWeightTool->wtCell(nextPhi) > prevPhi->pt()*m_caloWeightTool->wtCell(prevPhi) ) mergePhi = nextPhi;
+            else                                mergePhi = prevPhi;
+        }
+        else if (nextPhi) mergePhi = nextPhi;
+        else if (prevPhi) mergePhi = prevPhi;
+
+        // get neighbours in 5x1 window
+        std::vector<const CaloCell*> windowNeighbours = this->getNeighbours(pCellContainer,cell,2);
+        if( mergePhi ){
+            std::vector<const CaloCell*> mergeCells = this->getNeighbours(pCellContainer,mergePhi,2);
+            windowNeighbours.push_back(mergePhi);
+            windowNeighbours.insert(windowNeighbours.end(),mergeCells.begin(),mergeCells.end());
+        }
+
+        
+        // create seed cluster
+        xAOD::CaloCluster* shotCluster = CaloClusterStoreHelper::makeCluster(pCellContainer);
+        shotCluster->getCellLinks()->reserve(windowNeighbours.size()+1);
+        shotCluster->addCell(pCellContainer->findIndex(seedHash), 1.);
+        cellItr = windowNeighbours.begin();
+        for( ; cellItr!=windowNeighbours.end(); ++cellItr)
+            shotCluster->addCell(pCellContainer->findIndex((*cellItr)->caloDDE()->calo_hash()),1.0);
+        CaloClusterKineHelper::calculateKine(shotCluster,true,true);
+        m_shotClusterContainer->push_back(shotCluster);
+        
+        // create shot PFO and store it in output container
+        xAOD::PFO* shot = new xAOD::PFO();
+        m_PFOShotContainer->push_back( shot );
+
+        // Create element link from tau to shot
+        ElementLink<xAOD::PFOContainer> PFOElementLink;
+        PFOElementLink.toContainedElement( *m_PFOShotContainer, shot );
+        pTau.addShotPFOLink( PFOElementLink );
+       
+        if( mergePhi ){
+            // interpolate position
+            double dPhi = TVector2::Phi_mpi_pi( mergePhi->phi() - cell->phi());
+            double ratio = mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi)/(cell->pt()*m_caloWeightTool->wtCell(cell) + mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi));
+            float phi = cell->phi()+dPhi*ratio;
+            float pt = cell->pt()*m_caloWeightTool->wtCell(cell)+mergePhi->pt()*m_caloWeightTool->wtCell(mergePhi);
+
+            shot->setP4( (float) pt, (float) cell->eta(), (float) phi, (float) cell->m());
+        }
+        else shot->setP4( (float) cell->pt()*m_caloWeightTool->wtCell(cell), (float) cell->eta(), (float) cell->phi(), (float) cell->m());
+        
+        shot->setBDTPi0Score( (float) -9999. );
+        shot->setCharge( 0. );
+        double center_mag = 0.0;
+        // No need to calculate cluster moments atm.
+        //if( !shotCluster->retrieveMoment((xAOD::CaloCluster_v1::MomentType) 404, center_mag) ) ATH_MSG_WARNING("Couldn't retrieve CENTER_MAG moment. Set it to 0.");
+        shot->setCenterMag( (float) center_mag);
+        
+        ElementLink<xAOD::CaloClusterContainer> clusElementLink;
+        clusElementLink.toContainedElement( *m_shotClusterContainer, shotCluster );
+        shot->setClusterLink( clusElementLink );
+        shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_nCellsInEta, m_nCellsInEta);
+        shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash);
+
+        // Get cell block for variable calculations
+        std::vector<std::vector<const CaloCell*> > cellBlock = TauShotVariableHelpers::getCellBlock(shot, m_calo_id);
+
+        // Some DEBUG statements
+        if (msgLvl(MSG::DEBUG)) { 
+          if(cell->pt()*m_caloWeightTool->wtCell(cell)>300){
+            ATH_MSG_DEBUG("");
+            ATH_MSG_DEBUG("New shot. \t block size phi = " << cellBlock.size() << " \t block size eta = " << cellBlock.at(0).size() << "\t shot->pt() = " << shot->pt());
+            for(unsigned iCellPhi = 0; iCellPhi<cellBlock.size();++iCellPhi){
+              for(unsigned iCellEta = 0; iCellEta<cellBlock.at(iCellPhi).size();++iCellEta){
+                const CaloCell* cell = cellBlock.at(iCellPhi).at(iCellEta);
+                if( cell==NULL ) ATH_MSG_DEBUG("Cell" << iCellPhi << iCellEta << ": \t NULL" );
+                else            ATH_MSG_DEBUG("Cell"<<iCellPhi<<iCellEta<<":\tPt = "<< cell->pt()*m_caloWeightTool->wtCell(cell)<<"\teta = "<<cell->eta()<<"\tphi = "<<cell->phi());
+              }
+            }
+          }
+        }
+        // Get eta bin
+        int etaBin = getEtaBin(cell->eta());
+
+        // set variables used for photon counting
+        m_pt1=TauShotVariableHelpers::ptWindow(cellBlock,1,m_caloWeightTool);
+        m_pt3=TauShotVariableHelpers::ptWindow(cellBlock,3,m_caloWeightTool);
+        m_pt5=TauShotVariableHelpers::ptWindow(cellBlock,5,m_caloWeightTool);
+        // The folliwing variables are not needed atm
+        /*
+        m_ws5=TauShotVariableHelpers::ws5(cellBlock,m_caloWeightTool);
+        m_sdevEta5_WRTmean=TauShotVariableHelpers::sdevEta_WRTmean(cellBlock,m_caloWeightTool);
+        m_sdevEta5_WRTmode=TauShotVariableHelpers::sdevEta_WRTmode(cellBlock,m_caloWeightTool);
+        m_sdevPt5=TauShotVariableHelpers::sdevPt(cellBlock,m_caloWeightTool);
+        m_deltaPt12_min=TauShotVariableHelpers::deltaPt12_min(cellBlock,m_caloWeightTool);
+        m_Fside_3not1=TauShotVariableHelpers::Fside(cellBlock,3,1,m_caloWeightTool);
+        m_Fside_5not1=TauShotVariableHelpers::Fside(cellBlock,5,1,m_caloWeightTool);
+        m_Fside_5not3=TauShotVariableHelpers::Fside(cellBlock,5,3,m_caloWeightTool);
+        m_fracSide_3not1=TauShotVariableHelpers::fracSide(cellBlock,3,1,m_caloWeightTool);
+        m_fracSide_5not1=TauShotVariableHelpers::fracSide(cellBlock,5,1,m_caloWeightTool);
+        m_fracSide_5not3=TauShotVariableHelpers::fracSide(cellBlock,5,3,m_caloWeightTool);
+        m_pt1OverPt3=TauShotVariableHelpers::ptWindowFrac(cellBlock,3,1,m_caloWeightTool);
+        m_pt3OverPt5=TauShotVariableHelpers::ptWindowFrac(cellBlock,5,3,m_caloWeightTool);
+        
+
+        // Same variable names as in Stephanie's private code
+        G_PTFRAC=m_fracSide_3not1;
+        G_STDPT_5=m_sdevPt5;
+        G_STDETA_5=fmin(m_sdevEta5_WRTmean,0.0036);
+        G_DELTAPT_MIN=fmax(-1000.,fmin(m_deltaPt12_min,2000));
+
+        // Calculate BDT scores
+        float mergedBDTScore=getMergedBDTScore(etaBin);
+        */
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Calculate number of photons in shot
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        //int nPhotons = getNPhotons(etaBin, mergedBDTScore, m_pt1);
+        int nPhotons = getNPhotons(etaBin, 1, m_pt1);
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        // Set variables in shot PFO
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt1, m_pt1);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt3, m_pt3);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt5, m_pt5);
+        // The folliwing variables are not needed atm
+        /*
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_ws5, m_ws5);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevEta5_WRTmean, m_sdevEta5_WRTmean);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevEta5_WRTmode, m_sdevEta5_WRTmode);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_sdevPt5, m_sdevPt5);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_deltaPt12_min, m_deltaPt12_min);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_3not1, m_Fside_3not1);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_5not1, m_Fside_5not1);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_Fside_5not3, m_Fside_5not3);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_3not1, m_fracSide_3not1);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_5not1, m_fracSide_5not1);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_fracSide_5not3, m_fracSide_5not3);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt1OverPt3, m_pt1OverPt3);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_pt3OverPt5, m_pt3OverPt5);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_mergedScore, mergedBDTScore);
+        shot->setAttribute<float>(xAOD::PFODetails::PFOAttributes::tauShots_signalScore, -1.);
+        */
+        shot->setAttribute<int>(xAOD::PFODetails::PFOAttributes::tauShots_nPhotons, nPhotons);
+
+        // remove shot(s) from list
+        vector<const CaloCell*>::iterator cellItrNonConst;
+        cellItrNonConst = std::find(seedCells.begin(),seedCells.end(),cell);
+        seedCells.erase(cellItrNonConst);
+        if( mergePhi ){
+            cellItrNonConst = std::find(seedCells.begin(),seedCells.end(),mergePhi);
+            seedCells.erase(cellItrNonConst);
+        }
+
+        /*
+        ATH_MSG_DEBUG("Storing shot. pt: " << shot->pt()
+                        << ", eta: " << shot->eta()
+                        << ", phi: " << shot->phi()
+                        );
+        */
+          
+    } // seed cells
+    
+    
+    return StatusCode::SUCCESS;
+}
+
+StatusCode TauShotFinder::eventFinalize() {
+    CHECK( CaloClusterStoreHelper::finalizeClusters(&*evtStore(),
+                            m_shotClusterContainer,
+                            m_shotClusterContainerName,
+                            msg()) );
+
+    return StatusCode::SUCCESS;
+}
+
+std::vector<const CaloCell*> TauShotFinder::getNeighbours(const CaloCellContainer* pCellContainer, 
+                                           const CaloCell* cell, 
+                                           int maxDepth)
+{
+    std::vector<const CaloCell*> cells;
+    this->addNeighbours(pCellContainer,cell,cells,0,maxDepth,true);  //next
+    this->addNeighbours(pCellContainer,cell,cells,0,maxDepth,false); //prev
+    return cells; 
+}
+
+void TauShotFinder::addNeighbours(const CaloCellContainer* pCellContainer,
+                                  const CaloCell* cell, 
+                                  std::vector<const CaloCell*>& cells,
+                                  int depth,
+                                  int maxDepth,
+                                  bool next)
+{
+    depth++; 
+    if( depth > maxDepth ) return;
+
+    const IdentifierHash cellHash = cell->caloDDE()->calo_hash();
+    std::vector<IdentifierHash> neigHashes;
+    if( next )
+        m_calo_id->get_neighbours(cellHash,LArNeighbours::nextInEta,neigHashes);
+    else
+        m_calo_id->get_neighbours(cellHash,LArNeighbours::prevInEta,neigHashes);
+    
+    std::vector<IdentifierHash>::iterator hashItr = neigHashes.begin();
+    for( ; hashItr!=neigHashes.end(); ++hashItr ){
+        const CaloCell* newCell = pCellContainer->findCell(*hashItr);
+        if(!newCell)continue;
+        cells.push_back(newCell);
+        this->addNeighbours(pCellContainer,newCell,cells,depth,maxDepth,next);
+        // no EM1 cell should have more than one neighbor. Just add this neigbor for now
+        // FIXME: Check whether it happens that a cell has > 1 neighbors
+        break; 
+    } 
+}
+
+bool TauShotFinder::isPhiNeighbour(IdentifierHash cell1Hash, IdentifierHash cell2Hash, bool next){
+    std::vector<IdentifierHash> neigHashes;
+    if( next ) m_calo_id->get_neighbours(cell1Hash,LArNeighbours::nextInPhi,neigHashes);
+    else       m_calo_id->get_neighbours(cell1Hash,LArNeighbours::prevInPhi,neigHashes);
+    std::vector<IdentifierHash>::iterator itr = neigHashes.begin();
+    for( ; itr!=neigHashes.end(); ++itr ){
+        if(cell2Hash == (*itr)) return true;
+    } 
+    return false;
+}
+
+float TauShotFinder::getEtaBin(float seedEta){
+    float absSeedEta=fabs(seedEta);
+    if(fabs(absSeedEta)<0.80)      return 0; // Central Barrel
+    else if(fabs(absSeedEta)<1.39) return 1; // Outer Barrel
+    else if(fabs(absSeedEta)<1.51) return 2; // crack
+    else if(fabs(absSeedEta)<1.80) return 3; // endcap, fine granularity
+    else return 4;                           // endcap, coarse granularity
+}
+
+/*
+float TauShotFinder::getMergedBDTScore(int etaBin){
+    float BDTScore = -1;
+    if(etaBin==0)      BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" );  // barrel1
+    else if(etaBin==1) BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" );  // barrel2
+    else if(etaBin==2) BDTScore = m_tmvaReader_barrel->EvaluateMVA( "BDT method" );  // just use barrel BDT for now to check how it looks in data
+    else if(etaBin==3) BDTScore = m_tmvaReader_endcap1->EvaluateMVA( "BDT method" ); // endcap1
+    else if(etaBin==4) BDTScore = m_tmvaReader_endcap2->EvaluateMVA( "BDT method" ); // endcap2
+    return BDTScore;
+}
+*/
+
+float TauShotFinder::getNPhotons(int etaBin, float mergedBDTScore, float seedEnergy){
+    if(etaBin==2) return 0; // no photon counting in crack atm
+    ATH_MSG_DEBUG("etaBin = " << etaBin  << ", seedEnergy = " << seedEnergy << ", m_minPtCut.at(etaBin) = " << m_minPtCut.at(etaBin) << ", m_autoDoubleShotCut.at(etaBin) = " 
+       << m_autoDoubleShotCut.at(etaBin) << ", mergedBDTScore = " << mergedBDTScore << ", m_mergedBDTScoreCut.at(etaBin) = " << m_mergedBDTScoreCut.at(etaBin) );
+    if( seedEnergy < m_minPtCut.at(etaBin) ) return 0;
+    if( seedEnergy > m_autoDoubleShotCut.at(etaBin) ) return 2;
+    if( mergedBDTScore < m_mergedBDTScoreCut.at(etaBin) ) return 2;
+    return 1;
+}
+
+// some really slick c++ way of doing sort (since we need to use the member m_caloWeightTool)
+// how about learing a thing or two from python...
+TauShotFinder::ptSort::ptSort( const TauShotFinder& info ) : m_info(info) { } 
+bool TauShotFinder::ptSort::operator()( const CaloCell* c1, const CaloCell* c2 ){
+     return  c1->pt()*m_info.m_caloWeightTool->wtCell(c1) > c2->pt()*m_info.m_caloWeightTool->wtCell(c2);  
+}
+
+/*
+StatusCode TauShotFinder::bookMethod(TMVA::Reader *reader_barrel, 
+                                     TMVA::Reader *reader_endcap1, 
+                                     TMVA::Reader *reader_endcap2, 
+                                     const std::string &methodName) const 
+{
+    if (m_weightfile_barrel == ""){
+        ATH_MSG_ERROR("No weight m_weightfile_barrel given");
+        return StatusCode::FAILURE;
+    }
+    if (m_weightfile_endcap1 == ""){
+        ATH_MSG_ERROR("No weight m_weightfile_endcap1 given");
+        return StatusCode::FAILURE;
+    }
+    if (m_weightfile_endcap2 == ""){
+        ATH_MSG_ERROR("No weight m_weightfile_endcap2 given");
+        return StatusCode::FAILURE;
+    }
+    std::string resolvedFileName = find_file(m_weightfile_barrel);
+    if (resolvedFileName != ""){
+        ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName );
+    }
+    else {
+        ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_barrel << " not found" );
+        return StatusCode::FAILURE;
+    }
+    reader_barrel->BookMVA( methodName, resolvedFileName);
+
+    resolvedFileName = find_file(m_weightfile_endcap1);
+    if (resolvedFileName != ""){
+        ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName );
+    }
+    else {
+        ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_endcap1 << " not found" );
+        return StatusCode::FAILURE;
+    }
+    reader_endcap1->BookMVA( methodName, resolvedFileName);
+
+    resolvedFileName = find_file(m_weightfile_endcap2);
+    if (resolvedFileName != ""){
+        ATH_MSG_DEBUG( "Parameterisation file found: " << resolvedFileName );
+    }
+    else {
+        ATH_MSG_ERROR( "Parameterisation file " << m_weightfile_endcap2 << " not found" );
+        return StatusCode::FAILURE;
+    }
+    reader_endcap2->BookMVA( methodName, resolvedFileName);
+    return StatusCode::SUCCESS;
+}
+*/
+// EOF
diff --git a/Reconstruction/tauRecTools/src/TauShotFinder.h b/Reconstruction/tauRecTools/src/TauShotFinder.h
new file mode 100755
index 0000000000000000000000000000000000000000..2800791be0030a2d28e7c92b524275d990e96bf3
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauShotFinder.h
@@ -0,0 +1,166 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUSHOTFINDER_H
+#define	TAUREC_TAUSHOTFINDER_H
+
+//#include <string>
+//#include <vector>
+//#include <map>
+
+#include "GaudiKernel/ToolHandle.h"
+#include "tauRecTools/TauRecToolBase.h"
+#include "xAODPFlow/PFOAuxContainer.h"
+#include "xAODCaloEvent/CaloClusterAuxContainer.h"
+
+//#include "CaloIdentifier/CaloCell_ID.h"
+
+class CaloDetDescrManager;
+class CaloCell_ID;
+class IHadronicCalibrationTool;
+
+/*
+namespace TMVA{
+    class Reader;
+}
+*/
+
+/**
+ * @brief Find photon shots in the EM1 strip layer.
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch>
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch> 
+ */
+
+class TauShotFinder : virtual public TauRecToolBase {
+public:
+    TauShotFinder(const std::string& name);
+    ASG_TOOL_CLASS2(TauShotFinder, TauRecToolBase, ITauToolBase);
+    virtual ~TauShotFinder();
+
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize();
+    virtual StatusCode finalize();
+
+    virtual void print() const { }
+
+
+private:
+
+    /** @brief tool handles */
+    ToolHandle<IHadronicCalibrationTool> m_caloWeightTool;
+
+    /** @brief all calo cell container name */
+    std::string m_caloCellContainerName;
+    /** @brief new shot cluster container and name */ 
+    xAOD::CaloClusterContainer* m_shotClusterContainer;
+    std::string m_shotClusterContainerName;
+
+    /** @brief new shot PFO container and name */
+    xAOD::PFOContainer* m_PFOShotContainer;
+    std::string m_shotPFOContainerName;
+    xAOD::PFOAuxContainer* m_PFOShotAuxStore;
+
+
+    /** @brief calo cell navigation */
+    const CaloDetDescrManager* m_calo_dd_man;
+    const CaloCell_ID* m_calo_id;
+
+    /** @brief readers */
+    /*
+    std::string m_readerOption;
+
+    TMVA::Reader *m_tmvaReader_barrel;
+    std::string m_weightfile_barrel;
+
+    TMVA::Reader *m_tmvaReader_endcap1;
+    std::string m_weightfile_endcap1;
+
+    TMVA::Reader *m_tmvaReader_endcap2;
+    std::string m_weightfile_endcap2;
+    */
+
+    /** @brief Thanks C++ for ruining my day */
+    struct ptSort
+    { 
+         ptSort( const TauShotFinder& info );
+         const TauShotFinder& m_info;
+         bool operator()( const CaloCell* c1, const CaloCell* c2 );
+    };
+
+    /** @brief get neighbour cells */
+    std::vector<const CaloCell*> getNeighbours(const CaloCellContainer*,const CaloCell*,int /*maxDepth*/);
+
+    void addNeighbours(const CaloCellContainer*,
+                       const CaloCell* cell,
+                       std::vector<const CaloCell*>& cells,
+                       int depth,
+                       int maxDepth,
+                       bool next);
+
+    bool isPhiNeighbour(IdentifierHash cell1Hash, IdentifierHash cell2Hash, bool next);
+
+    /** @brief get eta bin */
+    float getEtaBin(float /*seedEta*/);
+  
+    /** @brief get merged BDTscore */
+    // float getMergedBDTScore(int /*etaBin*/);
+
+    /** @brief get NPhotons in shot */
+    float getNPhotons(int /*etaBin*/, 
+                      float /*mergedBDTScore*/, 
+                      float /*seedEnergy*/);
+
+    
+    /** @brief Book TMVA methods. */
+    /*
+    StatusCode bookMethod(TMVA::Reader *reader_barrel, 
+                          TMVA::Reader *reader_endcap1, 
+                          TMVA::Reader *reader_endcap2, 
+                          const std::string &methodName) const;
+    */
+
+    // number of cells in eta
+    int m_nCellsInEta;
+
+    // cut values
+    std::vector<float> m_minPtCut;
+    std::vector<float> m_autoDoubleShotCut;
+    std::vector<float> m_mergedBDTScoreCut;
+  
+    // BDT input variables
+    float m_pt1;
+    float m_pt3;
+    float m_pt5;
+    /*
+    float m_ws5;
+    float m_sdevEta5_WRTmean;
+    float m_sdevEta5_WRTmode;
+    float m_sdevPt5;
+    float m_deltaPt12_min;
+    float m_Fside_3not1;
+    float m_Fside_5not1;
+    float m_Fside_5not3;
+    float m_fracSide_3not1;
+    float m_fracSide_5not1;
+    float m_fracSide_5not3;
+    float m_pt1OverPt3;
+    float m_pt3OverPt5;
+    */
+
+    /*
+    // FIXME: same variable names as in Stephanie's private code atm
+    float G_PTFRAC;
+    float G_STDPT_5;
+    float G_STDETA_5;
+    float G_DELTAPT_MIN;
+    */
+
+};
+
+#endif	/* TAUSHOTFINDER_H */
+
diff --git a/Reconstruction/tauRecTools/src/TauShotVariableHelpers.cxx b/Reconstruction/tauRecTools/src/TauShotVariableHelpers.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..3645dd3b5db95f8884e4c39f18458878b2e9db5b
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauShotVariableHelpers.cxx
@@ -0,0 +1,358 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @brief implementation of photon shot variable calculation 
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch>
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch> 
+ */
+
+#include "TauShotVariableHelpers.h"
+
+using xAOD::PFO;
+using std::vector;
+
+namespace TauShotVariableHelpers {
+    std::vector<std::vector<const CaloCell*> > getCellBlock(xAOD::PFO* shot, const CaloCell_ID* calo_id){
+        std::vector<std::vector<const CaloCell*> > cellVector;
+        std::vector<const CaloCell*> oneEtaLayer;
+        int nCellsInEta = 0;
+        if( shot->attribute(xAOD::PFODetails::PFOAttributes::tauShots_nCellsInEta, nCellsInEta) == false) {
+            std::cout << "WARNING: Couldn't find nCellsInEta. Return empty cell block." << std::endl;
+            return cellVector;
+        }
+        int seedHash = 0;
+        if( shot->attribute(xAOD::PFODetails::PFOAttributes::tauShots_seedHash, seedHash) == false) {
+            std::cout << "WARNING: Couldn't find seed hash. Return empty cell block." << std::endl;
+            return cellVector;
+        }
+        for(int iCell=0;iCell<nCellsInEta;++iCell) oneEtaLayer.push_back(NULL);
+        // have two layers in phi
+        cellVector.push_back(oneEtaLayer);
+        cellVector.push_back(oneEtaLayer);
+        // get cluster from shot
+        const xAOD::CaloCluster* cluster = shot->cluster(0);
+        const CaloClusterCellLink* theCellLink = cluster->getCellLinks();
+        CaloClusterCellLink::const_iterator cellItr  = theCellLink->begin();
+        CaloClusterCellLink::const_iterator cellItrE = theCellLink->end();
+
+        // get seed cell from shot cluster
+        const CaloCell* seedCell=NULL;
+        for(;cellItr!=cellItrE;++cellItr){
+            if((*cellItr)->caloDDE()->calo_hash()!=(unsigned) seedHash) continue;
+            seedCell = *cellItr;
+            break;
+        }
+        if(seedCell==NULL){
+          std::cout << "WARNING: Couldn't find seed cell in shot cluster. Return empty cell block." << std::endl;
+          return cellVector;
+        }
+        
+        // get merged cell in phi. Keep NULL if shot is not merged across phi
+        const CaloCell* mergedCell = NULL;
+        std::vector<IdentifierHash> nextInPhi;
+        std::vector<IdentifierHash> prevInPhi;
+        calo_id->get_neighbours(seedCell->caloDDE()->calo_hash(),LArNeighbours::nextInPhi,nextInPhi);
+        calo_id->get_neighbours(seedCell->caloDDE()->calo_hash(),LArNeighbours::prevInPhi,prevInPhi);
+        for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){
+            std::vector<IdentifierHash>::iterator itr = nextInPhi.begin();
+            for( ; itr!=nextInPhi.end(); ++itr ){
+                if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                mergedCell = (*cellItr);
+                break;
+            }
+            if(mergedCell!=NULL) break;
+            itr = prevInPhi.begin();
+            for( ; itr!=prevInPhi.end(); ++itr ){
+                if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                mergedCell = (*cellItr);
+                break;
+            }
+            if(mergedCell!=NULL) break;
+        }
+        // store cells in the eta layer, which contains the seed cell
+        int nCellsFromSeed = 1;
+        const CaloCell* lastCell = seedCell;
+        cellVector.at(0).at(nCellsInEta/2) = seedCell; // store seed cell
+        std::vector<IdentifierHash> next;
+        while(lastCell!=NULL && nCellsFromSeed<nCellsInEta/2+1){
+            calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::nextInEta,next);
+            lastCell = NULL;
+            for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){
+                std::vector<IdentifierHash>::iterator itr = next.begin();
+                for( ; itr!=next.end(); ++itr ){
+                    if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                    cellVector.at(0).at(nCellsInEta/2+nCellsFromSeed) = (*cellItr);
+                    lastCell = (*cellItr);
+                }
+            }
+            nCellsFromSeed++;
+        }
+        nCellsFromSeed = 1;
+        lastCell = seedCell;
+        while(lastCell!=NULL && nCellsFromSeed<nCellsInEta/2+1){
+            calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::prevInEta,next);
+            lastCell = NULL;
+            for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){
+                std::vector<IdentifierHash>::iterator itr = next.begin();
+                for( ; itr!=next.end(); ++itr ){
+                    if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                    cellVector.at(0).at(nCellsInEta/2-nCellsFromSeed) = (*cellItr);
+                    lastCell = (*cellItr);
+                }
+            }
+            nCellsFromSeed++;
+        }
+        // store cells in the eta layer, which contains the merged cell
+        int nCellsFromMerged = 1;
+        lastCell = mergedCell; // is NULL if shot is not merged
+        cellVector.at(1).at(nCellsInEta/2) = mergedCell; // store merged cell
+        while(lastCell!=NULL && nCellsFromMerged<nCellsInEta/2+1){
+            calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::nextInEta,next);
+            lastCell = NULL;
+            for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){
+                std::vector<IdentifierHash>::iterator itr = next.begin();
+                for( ; itr!=next.end(); ++itr ){
+                    if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                    cellVector.at(1).at(nCellsInEta/2+nCellsFromMerged) = (*cellItr);
+                    lastCell = (*cellItr);
+                }
+            }
+            nCellsFromMerged++;
+        }
+        nCellsFromMerged = 1;
+        lastCell = mergedCell;
+        while(lastCell!=NULL && nCellsFromMerged<nCellsInEta/2+1){
+            calo_id->get_neighbours(lastCell->caloDDE()->calo_hash(),LArNeighbours::prevInEta,next);
+            lastCell = NULL;
+            for(cellItr=theCellLink->begin();cellItr!=cellItrE;++cellItr){
+                std::vector<IdentifierHash>::iterator itr = next.begin();
+                for( ; itr!=next.end(); ++itr ){
+                    if((*cellItr)->caloDDE()->calo_hash() != (*itr)) continue;
+                    cellVector.at(1).at(nCellsInEta/2-nCellsFromMerged) = (*cellItr);
+                    lastCell = (*cellItr);
+                }
+            }
+            nCellsFromMerged++;
+        }
+        return cellVector;
+    
+    }
+
+
+    float mean_eta(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        float sumEta=0.;
+        float sumWeight=0.;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            vector<const CaloCell*>::iterator itrEta = itrPhi->begin();
+            for( ; itrEta!=itrPhi->end(); ++itrEta ){
+                if((*itrEta) == NULL) continue;
+                sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta);
+                sumEta    += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * (*itrEta)->eta();
+            }
+        }
+        if(sumWeight<=0.) return -99999.;
+        return sumEta/sumWeight;
+    }
+
+    float mean_pt(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        float sumPt=0.;
+        int nCells = 0;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            vector<const CaloCell*>::iterator itrEta = itrPhi->begin();
+            for( ; itrEta!=itrPhi->end(); ++itrEta ){
+                if((*itrEta) == NULL) continue;
+                sumPt  += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta);
+                nCells ++;
+            }
+        }
+        if(nCells==0) return -99999.;
+        return sumPt/nCells;
+    }
+
+    float ptWindow(vector<vector<const CaloCell*> > shotCells, int windowSize, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        // window size should be odd and noti be larger than eta window of shotCells
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        if( windowSize%2!=1 )        return 0.;
+        if( windowSize > nCells_eta) return 0.;
+        float ptWindow  = 0.;
+        for(int iCell = 0; iCell != nCells_eta; ++iCell ){
+            if(fabs(iCell-seedIndex)>windowSize/2) continue;
+            if(shotCells.at(0).at(iCell) != NULL) ptWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell) != NULL) ptWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+        }
+        return ptWindow;
+    }
+
+    float ws5(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        float sumWeight=0.;
+        float sumDev2=0.;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            for(unsigned iCell = 0; iCell != itrPhi->size(); ++iCell ){
+                if(itrPhi->at(iCell) == NULL) continue;
+                sumWeight += itrPhi->at(iCell)->pt()*m_caloWeightTool->wtCell(itrPhi->at(iCell));
+                sumDev2   += itrPhi->at(iCell)->pt()*m_caloWeightTool->wtCell(itrPhi->at(iCell)) * pow(iCell-seedIndex,2);
+            }
+        }
+        if(sumWeight<=0. || sumDev2 <0.) return -99999.;
+        return sqrt( sumDev2 / sumWeight );
+    }
+
+    float sdevEta_WRTmean(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        float mean = mean_eta(shotCells, m_caloWeightTool); 
+        float sumWeight=0.;
+        float sumDev2=0.;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            vector<const CaloCell*>::iterator itrEta = itrPhi->begin();
+            for( ; itrEta!=itrPhi->end(); ++itrEta ){
+                if((*itrEta) == NULL) continue;
+                sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta);
+                sumDev2   += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * pow((*itrEta)->eta() - mean,2);
+            }
+        }
+        if(sumWeight<=0. || sumDev2 <0.) return -99999.;
+        return sqrt( sumDev2 / sumWeight );
+    }
+
+    float sdevEta_WRTmode(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        float mode = shotCells.at(0).at(seedIndex)->eta();
+        float sumWeight=0.;
+        float sumDev2=0.;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            vector<const CaloCell*>::iterator itrEta = itrPhi->begin();
+            for( ; itrEta!=itrPhi->end(); ++itrEta ){
+                if((*itrEta) == NULL) continue;
+                sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta);
+                sumDev2   += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) * pow((*itrEta)->eta() - mode,2);
+            }
+        }
+        if(sumWeight<=0. || sumDev2 <0.) return -99999.;
+        return sqrt( sumDev2 / sumWeight );
+    }
+
+    float sdevPt(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        float mean = mean_pt(shotCells, m_caloWeightTool);
+        float sumWeight=0.;
+        float sumDev2=0.;
+        vector<vector<const CaloCell*> >::iterator itrPhi = shotCells.begin();
+        for( ; itrPhi!=shotCells.end(); ++itrPhi ){
+            vector<const CaloCell*>::iterator itrEta = itrPhi->begin();
+            for( ; itrEta!=itrPhi->end(); ++itrEta ){
+                if((*itrEta) == NULL) continue;
+                sumWeight += (*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta);
+                sumDev2   += pow((*itrEta)->pt()*m_caloWeightTool->wtCell(*itrEta) - mean,2);
+            }
+        }
+        if(sumWeight<=0. || sumDev2 <0.) return -99999.;
+        return sqrt(sumDev2)/sumWeight;
+    }
+
+    float deltaPt12_min(vector<vector<const CaloCell*> > shotCells, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        bool haveLeft  = false;
+        bool haveRight = false;
+        float deltaPt_left  = 0.;
+        float deltaPt_right = 0.;
+        if(shotCells.at(0).at(seedIndex-1)!=NULL && shotCells.at(0).at(seedIndex-2)!=NULL){
+            haveLeft  = true;
+            deltaPt_left =  shotCells.at(0).at(seedIndex-1)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex-1))
+                           -shotCells.at(0).at(seedIndex-2)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex-2));
+            if(shotCells.at(1).at(seedIndex-1)!=NULL && shotCells.at(1).at(seedIndex-2)!=NULL){
+                deltaPt_left += shotCells.at(1).at(seedIndex-1)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex-1))
+                               -shotCells.at(1).at(seedIndex-2)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex-2));
+            }
+        }
+        if(shotCells.at(0).at(seedIndex+1)!=NULL && shotCells.at(0).at(seedIndex+2)!=NULL){
+            haveRight = true;
+            deltaPt_right =  shotCells.at(0).at(seedIndex+1)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex+1))
+                            -shotCells.at(0).at(seedIndex+2)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(seedIndex+2));
+            if(shotCells.at(1).at(seedIndex+1)!=NULL && shotCells.at(1).at(seedIndex+2)!=NULL){
+                deltaPt_right += shotCells.at(1).at(seedIndex+1)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex+1))
+                                -shotCells.at(1).at(seedIndex+2)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(seedIndex+1));
+            }
+        }
+        if(haveLeft && haveRight) return fmin(deltaPt_left,deltaPt_right);
+        if(haveLeft)              return deltaPt_left;
+        if(haveRight)             return deltaPt_right;
+        else                      return -1.;
+    }
+
+
+    float Fside(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        // window sizes should be odd and windows should be not larger than eta window of shotCells
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.;
+        if( largerWindow <= smallerWindow)           return 0.;
+        if( largerWindow > nCells_eta)   return 0.;
+        float pt_largerWindow  = 0.;
+        float pt_smallerWindow = 0.;
+        for(int iCell = 0; iCell != nCells_eta; ++iCell ){
+            if(fabs(iCell-seedIndex)>largerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+            if(fabs(iCell-seedIndex)>smallerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+        }
+        if(pt_smallerWindow==0.) return -99999.;
+        return (pt_largerWindow-pt_smallerWindow)/pt_smallerWindow;
+    }
+
+    float fracSide(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        // window sizes should be odd and windows should be not larger than eta window of shotCells
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.;
+        if( largerWindow <= smallerWindow)           return 0.;
+        if( largerWindow > nCells_eta)   return 0.;
+        float pt_largerWindow  = 0.;
+        float pt_smallerWindow = 0.;
+        for(int iCell = 0; iCell != nCells_eta; ++iCell ){
+            if(fabs(iCell-seedIndex)>largerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+            if(fabs(iCell-seedIndex)>smallerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+        }
+        if(pt_largerWindow==0.) return -99999.;
+        return (pt_largerWindow-pt_smallerWindow)/pt_largerWindow;
+    }
+
+    float ptWindowFrac(vector<vector<const CaloCell*> > shotCells, int largerWindow, int smallerWindow, ToolHandle<IHadronicCalibrationTool>& m_caloWeightTool){
+        // window sizes should be odd and windows should be not larger than eta window of shotCells
+        int nCells_eta = shotCells.at(0).size();
+        int seedIndex = nCells_eta/2;
+        if( largerWindow%2!=1 || smallerWindow%2!=1) return 0.;
+        if( largerWindow <= smallerWindow)           return 0.;
+        if( largerWindow > nCells_eta)   return 0.;
+        float pt_largerWindow  = 0.;
+        float pt_smallerWindow = 0.;
+        for(int iCell = 0; iCell != nCells_eta; ++iCell ){
+            if(fabs(iCell-seedIndex)>largerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_largerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+            if(fabs(iCell-seedIndex)>smallerWindow/2) continue;
+            if(shotCells.at(0).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(0).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(0).at(iCell));
+            if(shotCells.at(1).at(iCell)!=NULL) pt_smallerWindow+=shotCells.at(1).at(iCell)->pt()*m_caloWeightTool->wtCell(shotCells.at(1).at(iCell));
+        }
+        if(pt_largerWindow==0.) return -99999.;
+        return pt_smallerWindow/pt_largerWindow;
+    }
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauShotVariableHelpers.h b/Reconstruction/tauRecTools/src/TauShotVariableHelpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..e2e9b76f8d4ad315c4b9bb865265230825274f4c
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauShotVariableHelpers.h
@@ -0,0 +1,79 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/**
+ * @brief implementation of photon shot variable calculation 
+ * 
+ * @author Will Davey <will.davey@cern.ch> 
+ * @author Benedict Winter <benedict.tobias.winter@cern.ch>
+ * @author Stephanie Yuen <stephanie.yuen@cern.ch> 
+ */
+
+#ifndef TAUSHOTVARIABLEHELPERS_H
+#define TAUSHOTVARIABLEHELPERS_H
+
+#include "xAODPFlow/PFO.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "CaloInterface/IHadronicCalibrationTool.h"
+
+namespace TauShotVariableHelpers {
+
+    /** @brief get cell block with (currently) 5x2 cells in correct order for variable calculations */
+    std::vector<std::vector<const CaloCell*> > getCellBlock(xAOD::PFO* shot,
+                                                            const CaloCell_ID* calo_id);
+
+    /** @brief mean eta, used by other functions */
+    float mean_eta(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                   ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief mean pt, used by other functions */ 
+    float mean_pt(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                  ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief pt in windows */
+    float ptWindow(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                   int /*windowSize*/, 
+                   ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief ws5 variable (egamma) */
+    float ws5(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                          ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief standard deviation in eta WRT mean */
+    float sdevEta_WRTmean(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                          ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief standard deviation in eta WRT mode */
+    float sdevEta_WRTmode(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                          ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief normalized standard deviation in pt */
+    float sdevPt(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                             ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief pT diff b/w lead and sub-lead cell */
+    float deltaPt12_min(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                        ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief Fside variable (egamma) */
+    float Fside(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                int /*largerWindow*/, 
+                int /*smallerWindow*/, 
+                ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief similar than Fside but in unit of eta instead of number of cells */
+    float fracSide(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                   int /*largerWindow*/, 
+                   int /*smallerWindow*/, 
+                   ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+
+    /** @brief pt window fraction */
+    float ptWindowFrac(std::vector<std::vector<const CaloCell*> > /*shotCells*/, 
+                       int /*largerWindow*/, 
+                       int /*smallerWindow*/, 
+                       ToolHandle<IHadronicCalibrationTool>& /*m_caloWeightTool*/);
+}
+
+#endif // TAUSHOTVARIABLEHELPERS_H
+
diff --git a/Reconstruction/tauRecTools/src/TauSubstructureVariables.cxx b/Reconstruction/tauRecTools/src/TauSubstructureVariables.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..971f24203a16dbc376881540211eab3891f24326
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauSubstructureVariables.cxx
@@ -0,0 +1,398 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//********************************************************************//
+// NAME:     TauSubstructureVariables.cxx                             //
+// PACKAGE:  offline/Reconstruction/tauRec                            //
+// AUTHORS:  M. Trottier-McDonald                                     //
+// CREATED:  January 11 2010                                          //
+//********************************************************************//
+
+#include <algorithm> 
+#include <math.h>
+#include <sstream>
+
+#include "GaudiKernel/Property.h"
+#include "FourMomUtils/P4Helpers.h"
+
+#include "AnalysisUtils/AnalysisMisc.h"
+
+#include "xAODJet/Jet.h"
+#include "xAODTau/TauJet.h"
+
+#include "CaloClusterVariables.h"
+#include "TauSubstructureVariables.h"
+
+#include "tauRecTools/KineUtils.h"
+#include "CaloUtils/CaloVertexedCluster.h"
+//#include "CaloEvent/CaloVertexedCluster.h"
+
+using CLHEP::GeV;
+
+const double TauSubstructureVariables::DEFAULT = -1111.;
+
+//**********************************
+// Constructor
+//**********************************
+
+TauSubstructureVariables::TauSubstructureVariables( const std::string& name ) :
+		TauRecToolBase(name),
+		m_maxPileUpCorrection(4 * GeV),
+		m_pileUpAlpha(1.0),
+		m_doVertexCorrection(false), //FF: don't do cell correction by default
+		m_inAODmode(false) {
+	declareProperty("maxPileUpCorrection", m_maxPileUpCorrection);
+	declareProperty("pileUpAlpha", m_pileUpAlpha);
+	declareProperty("VertexCorrection", m_doVertexCorrection);
+	declareProperty("inAODmode", m_inAODmode);
+}
+
+
+//**********************************
+// Destructor
+//**********************************
+
+TauSubstructureVariables::~TauSubstructureVariables() {
+}
+
+
+//***********************************
+// Initialize method
+//***********************************
+
+StatusCode TauSubstructureVariables::initialize() {
+	return StatusCode::SUCCESS;
+}
+
+//***********************************
+// Finalize method
+//***********************************
+
+StatusCode TauSubstructureVariables::finalize() {
+	return StatusCode::SUCCESS;
+}
+
+StatusCode TauSubstructureVariables::eventInitialize() {
+	return StatusCode::SUCCESS;
+}
+
+
+//************************************
+// Execute method
+//************************************
+
+StatusCode TauSubstructureVariables::execute(xAOD::TauJet& pTau) {
+	// Getting our hands on the TauJet object
+	//----------------------------------------
+
+	// Getting the jet seed
+	// By asking taujet instead of TauEventData->seed, we take advantage of the machinery already
+	// in place to retrieve a jet seed for track only candidates.
+	//------------------------------------------------------------------------------------------------
+	const xAOD::Jet* taujetseed = (*pTau.jetLink());
+
+	//*****************************************************
+	// calculate some tau substructure variables
+	//*****************************************************
+
+	CaloClusterVariables CaloClusterVariablesTool;
+	CaloClusterVariablesTool.setVertexCorrection(m_doVertexCorrection);
+
+	bool isFilled = CaloClusterVariablesTool.update(pTau, m_inAODmode);
+
+	if (!isFilled) {
+		if (!taujetseed) ATH_MSG_DEBUG("Taujet->jet() pointer is NULL: calo cluster variables will be set to -1111");
+		else ATH_MSG_DEBUG("problem in calculating calo cluster variables -> will be set to -1111");
+
+		pTau.setDetail(xAOD::TauJetParameters::numCells , static_cast<int>(0) );
+		pTau.setDetail(xAOD::TauJetParameters::numTopoClusters , static_cast<int>(DEFAULT) );
+		pTau.setDetail(xAOD::TauJetParameters::numEffTopoClusters , static_cast<float>(DEFAULT) );
+		pTau.setDetail(xAOD::TauJetParameters::topoInvMass,  static_cast<float>(DEFAULT) );
+		pTau.setDetail(xAOD::TauJetParameters::effTopoInvMass,  static_cast<float>(DEFAULT) );
+		pTau.setDetail(xAOD::TauJetParameters::topoMeanDeltaR,  static_cast<float>(DEFAULT) );
+		pTau.setDetail(xAOD::TauJetParameters::effTopoMeanDeltaR,  static_cast<float>(DEFAULT) );
+
+	} else {
+		// Getting the variables
+		//-----------------------
+		double TopoInvMass = CaloClusterVariablesTool.totalMass();
+		double EffTopoInvMass = CaloClusterVariablesTool.effectiveMass();
+		unsigned int NumTopoClusters = CaloClusterVariablesTool.numConstituents();
+		double NumEffTopoClusters = CaloClusterVariablesTool.effectiveNumConstituents();
+		double TopoMeanDeltaR = CaloClusterVariablesTool.averageRadius();
+		double EffTopoMeanDeltaR = CaloClusterVariablesTool.averageEffectiveRadius();
+		unsigned int Ncells = CaloClusterVariablesTool.numCells();
+
+		ATH_MSG_VERBOSE(" Substructure variables: ");
+		ATH_MSG_VERBOSE("-------------------------");
+		ATH_MSG_VERBOSE("       TopoInvMass: " << TopoInvMass);
+		ATH_MSG_VERBOSE("    EffTopoInvMass: " << EffTopoInvMass);
+		ATH_MSG_VERBOSE("   NumTopoClusters: " << NumTopoClusters);
+		ATH_MSG_VERBOSE("NumEffTopoClusters: " << NumEffTopoClusters);
+		ATH_MSG_VERBOSE("    TopoMeanDeltaR: " << TopoMeanDeltaR);
+		ATH_MSG_VERBOSE(" EffTopoMeanDeltaR: " << EffTopoMeanDeltaR);
+		ATH_MSG_VERBOSE("          NumCells: " << Ncells);
+
+		//Record the variables
+		//---------------------
+
+		if (!m_inAODmode) pTau.setDetail(xAOD::TauJetParameters::numCells ,  static_cast<int>  (Ncells)             );
+		pTau.setDetail(xAOD::TauJetParameters::numTopoClusters            ,  static_cast<int>  (NumTopoClusters)    );
+		pTau.setDetail(xAOD::TauJetParameters::numEffTopoClusters         ,  static_cast<float>(NumEffTopoClusters) );
+		pTau.setDetail(xAOD::TauJetParameters::topoInvMass                ,  static_cast<float>(TopoInvMass)	     );
+		pTau.setDetail(xAOD::TauJetParameters::effTopoInvMass             ,  static_cast<float>(EffTopoInvMass)     );
+		pTau.setDetail(xAOD::TauJetParameters::topoMeanDeltaR             ,  static_cast<float>(TopoMeanDeltaR)     );
+		pTau.setDetail(xAOD::TauJetParameters::effTopoMeanDeltaR          ,  static_cast<float>(EffTopoMeanDeltaR)  );
+
+	}
+
+	//*****************************************************
+	// calculate some new cluster based ID variables
+	//*****************************************************
+
+	if (taujetseed == NULL) {
+
+		// No jet seed? Warning! Fill variables with dummy values
+		//--------------------------------------------------------
+
+		ATH_MSG_DEBUG("Taujet->jet() pointer is NULL: substructure variables will be set to -1111");
+
+		pTau.setDetail(xAOD::TauJetParameters::lead2ClusterEOverAllClusterE, static_cast<float>(DEFAULT)  );
+		pTau.setDetail(xAOD::TauJetParameters::lead3ClusterEOverAllClusterE, static_cast<float>(DEFAULT)  );
+		pTau.setDetail(xAOD::TauJetParameters::caloIso           	    	, static_cast<float>(DEFAULT)  );
+		pTau.setDetail(xAOD::TauJetParameters::caloIsoCorrected            , static_cast<float>(DEFAULT)  );
+		pTau.setDetail(xAOD::TauJetParameters::dRmax                       , static_cast<float>(DEFAULT)  );
+
+		return StatusCode::SUCCESS;
+	}
+
+	// New cluster-based variables
+	float totalEnergy(0.);
+	float calo_iso(0.);
+	float dr(0.);
+
+	unsigned int num_clusters(0);
+	const xAOD::CaloCluster* incluster;
+	std::vector<const xAOD::CaloCluster*> vClusters;
+
+	TLorentzVector leadClusVec;
+	TLorentzVector subLeadClusVec;
+	TLorentzVector approxSubstructure4Vec;
+	double clusELead = -1111.0;
+	double clusESubLead = -1111.0;
+
+	// loop over all clusters of the jet seed
+	xAOD::JetConstituentVector jcv = taujetseed->getConstituents();
+	xAOD::JetConstituentVector::const_iterator nav_it   = jcv.begin();
+	xAOD::JetConstituentVector::const_iterator nav_itE  = jcv.end();
+	for (; nav_it != nav_itE; ++nav_it) {
+		++num_clusters;
+
+		incluster = dynamic_cast<const xAOD::CaloCluster*>( (*nav_it)->rawConstituent() );
+		if (!incluster) continue;
+
+		// save all clusters of jet seed
+		vClusters.push_back(incluster);
+
+		// calc total energy
+		totalEnergy += incluster->e();
+
+		//apply Vertex correction on a temporary
+		TLorentzVector tempclusvec;
+		if (m_doVertexCorrection && pTau.vertexLink())
+			tempclusvec = xAOD::CaloVertexedCluster(*incluster, (*pTau.vertexLink())->position()).p4();
+		else
+			tempclusvec = xAOD::CaloVertexedCluster(*incluster).p4();
+
+		dr = Tau1P3PKineUtils::deltaR(pTau.eta(),pTau.phi(), tempclusvec.Eta(), tempclusvec.Phi());
+		if (0.2 <= dr && dr < 0.4) 
+		  {
+		    calo_iso += tempclusvec.Et();
+		  }
+		else if (dr < 0.2)
+		  {
+		    double clusEnergyBE = ( incluster->energyBE(0) + incluster->energyBE(1) + incluster->energyBE(2) );
+		    
+		    if (clusEnergyBE > clusELead) 
+		      {
+			//change current leading cluster to subleading
+			clusESubLead = clusELead;
+			subLeadClusVec = leadClusVec;
+
+			//set energy and 4-vector of leading cluster
+			clusELead = clusEnergyBE;
+			leadClusVec.SetPtEtaPhiM(clusELead/cosh(tempclusvec.Eta()), tempclusvec.Eta(), tempclusvec.Phi(), 0);
+		      }
+		    else if (clusEnergyBE > clusESubLead) 
+		      {
+			//set energy and 4-vector of subleading cluster only
+			clusESubLead = clusEnergyBE;
+			subLeadClusVec.SetPtEtaPhiM(clusESubLead/cosh(tempclusvec.Eta()), tempclusvec.Eta(), tempclusvec.Phi(), 0);
+		      }
+
+		  }
+		
+	}
+
+	if (clusELead > 0.) {
+	  approxSubstructure4Vec += leadClusVec;
+	}
+	if (clusESubLead > 0.) {
+	  approxSubstructure4Vec += subLeadClusVec;
+	  }
+	
+	// now sort cluster by energy
+	AnalysisUtils::Sort::e(&vClusters);
+
+	// determine energy sum of leading 2 and leading 3 clusters
+	float sum2LeadClusterE(0.);
+	float sum3LeadClusterE(0.);
+	std::vector<const xAOD::CaloCluster*>::const_iterator icluster(vClusters.begin());
+	std::vector<const xAOD::CaloCluster*>::const_iterator icluster_end(vClusters.end());
+
+	for (; icluster != icluster_end && icluster != vClusters.begin() + 3; ++icluster) {
+		if (icluster < vClusters.begin() + 2) {
+			sum2LeadClusterE += (*icluster)->e();
+		}
+		sum3LeadClusterE += (*icluster)->e();
+	}
+
+	//record variables
+	if (totalEnergy != 0) {
+		ATH_MSG_VERBOSE(" lead2ClusterEOverAllClusterE: " << sum2LeadClusterE / totalEnergy);
+		ATH_MSG_VERBOSE(" lead3ClusterEOverAllClusterE: " << sum3LeadClusterE / totalEnergy);
+
+		pTau.setDetail(xAOD::TauJetParameters::lead2ClusterEOverAllClusterE, static_cast<float>(sum2LeadClusterE / totalEnergy)  );
+		pTau.setDetail(xAOD::TauJetParameters::lead3ClusterEOverAllClusterE, static_cast<float>(sum3LeadClusterE / totalEnergy)  );
+	}
+
+	ATH_MSG_VERBOSE(" caloIso: " << calo_iso);
+	pTau.setDetail(xAOD::TauJetParameters::caloIso, static_cast<float>(calo_iso)  );
+
+
+	// calculate calorimeter energies in different layers
+	float PSSEnergy(0.);
+	float EMEnergy(0.);
+	float HADEnergy(0.);
+	icluster = vClusters.begin();
+	for (; icluster != icluster_end; ++icluster) {
+		float clEnergy = (*icluster)->e();
+
+		//Calculate the fractions of energy in different calorimeter layers
+		const xAOD::CaloCluster *cl = *icluster;
+		float PreSampler = cl->eSample(CaloSampling::PreSamplerB) + cl->eSample(CaloSampling::PreSamplerE);
+		float EMLayer1   = cl->eSample(CaloSampling::EMB1) + cl->eSample(CaloSampling::EME1);
+		float EMLayer2   = cl->eSample(CaloSampling::EMB2) + cl->eSample(CaloSampling::EME2);
+
+		float Energy = cl->rawE();
+		float PSSF = Energy != 0 ? (PreSampler + EMLayer1) / Energy : 0;
+		float EM2F = Energy != 0 ? EMLayer2 / Energy : 0;
+		float EMF = PSSF + EM2F;
+
+		PSSEnergy += PSSF * clEnergy;
+		EMEnergy  += EMF * clEnergy;
+		HADEnergy += (Energy != 0) ? (1 - EMF) * clEnergy : 0;
+	}
+
+	// calculate trk momentum
+	float trkSysMomentum(0.);
+	for (unsigned int i(0); i < pTau.nTracks(); ++i) {
+		trkSysMomentum += pTau.track(i)->pt()	* cosh(pTau.track(i)->eta());
+
+		//adding the core tracks to the approximate substructure 4 vector
+		approxSubstructure4Vec += pTau.track(i)->p4();
+	}
+
+	// set new approximate energy flow variables for tau ID
+	pTau.setDetail(xAOD::TauJetParameters::ptRatioEflowApprox, static_cast<float>(approxSubstructure4Vec.Pt()/ pTau.detail<float>(xAOD::TauJetParameters::LC_TES_precalib)) );
+	pTau.setDetail(xAOD::TauJetParameters::mEflowApprox, static_cast<float>(approxSubstructure4Vec.M()) );
+
+
+	float fPSSFraction 			= (totalEnergy != 0) ? PSSEnergy / totalEnergy : DEFAULT;
+	float fChPIEMEOverCaloEME 	= (EMEnergy != 0) ? (trkSysMomentum - HADEnergy) / EMEnergy : DEFAULT;
+	float fEMPOverTrkSysP 		= DEFAULT;
+	if (pTau.nTracks() > 0) fEMPOverTrkSysP = (trkSysMomentum != 0) ? EMEnergy / trkSysMomentum : DEFAULT;
+
+	pTau.setDetail(xAOD::TauJetParameters::PSSFraction,		static_cast<float>(fPSSFraction));
+	pTau.setDetail(xAOD::TauJetParameters::ChPiEMEOverCaloEME,	static_cast<float>(fChPIEMEOverCaloEME));
+	pTau.setDetail(xAOD::TauJetParameters::EMPOverTrkSysP,		static_cast<float>(fEMPOverTrkSysP));
+
+
+	// get primary vertex container
+	// CALO_ISO_CORRECTED
+	// JVF and PT_PILEUP
+	// jvf and sumPtTrk are now a vector and the old run1-type jvf value is stored in the 0-th element
+	// sumPtTrk is calculated wrt Vertices
+
+	float jvf(0.0);
+	float sumPtTrk(0.0);
+
+	// for tau trigger: JVF and sumPtTrack are not available
+	bool inTrigger = tauEventData()->inTrigger();
+
+	if (!inTrigger)
+	{
+		std::vector<float> sumPtTrkvec;
+		std::vector<float> jvfvec;
+
+		// ToDo still need to check if the 500MeV threshold is correct
+		taujetseed->getAttribute(xAOD::JetAttribute::SumPtTrkPt500, sumPtTrkvec);
+		taujetseed->getAttribute(xAOD::JetAttribute::JVF, jvfvec);
+
+		if (!jvfvec.empty() && !sumPtTrkvec.empty()) {
+			// ToDo need to check if first vertex is the vertex we want to use here!
+			jvf = jvfvec[0];
+			sumPtTrk = sumPtTrkvec[0];
+		}
+		else {
+			ATH_MSG_WARNING("jvf value vector and/or sumPtTrk vector returned from seed jet is empty!");
+		}
+	}
+
+	float pt_pileup = (1.0 - jvf) * sumPtTrk;
+
+	const float max_pileup_correction = m_maxPileUpCorrection;
+	const float alpha = m_pileUpAlpha;
+	float pileup_correction = alpha * pt_pileup;
+
+	ATH_MSG_VERBOSE("   --------------------------------------");
+	ATH_MSG_VERBOSE("   Pile-up correction parameter");
+	ATH_MSG_VERBOSE("   -> sumPtTrk:        " << sumPtTrk);
+	ATH_MSG_VERBOSE("   -> jvf:             " << jvf);
+	ATH_MSG_VERBOSE("   -> pt_pileup:       " << pt_pileup);
+	ATH_MSG_VERBOSE("   -> alpha:           " << alpha);
+	ATH_MSG_VERBOSE("   -> max pileup corr: " << max_pileup_correction);
+
+	if (pileup_correction > max_pileup_correction) {
+		pileup_correction = max_pileup_correction;
+	}
+	const float calo_iso_corrected = calo_iso - pileup_correction;
+
+	ATH_MSG_VERBOSE("   -> pileup corr:     " << pileup_correction);
+	ATH_MSG_VERBOSE("   --------------------------------------");
+
+	//record variable
+	ATH_MSG_VERBOSE(" caloIsoCorrected: " << calo_iso_corrected);
+	pTau.setDetail(xAOD::TauJetParameters::caloIsoCorrected, static_cast<float>(calo_iso_corrected)  );
+
+	// calculate dRMax
+	unsigned int numTrack(pTau.nTracks());
+	if (numTrack > 0) {
+		float dRmin = -1 * -1111;
+		float dRmax = -1111;
+		float dR;
+
+		for (unsigned int i(0); i < numTrack; ++i) {
+			if (pTau.track(i) == 0) continue;
+			dR = Tau1P3PKineUtils::deltaR( pTau.track(i)->eta(), pTau.track(i)->phi(), pTau.eta(), pTau.phi() );
+			if (dRmin > dR) dRmin = dR;
+			if (dRmax < dR) dRmax = dR;
+		}
+		//record variable
+		ATH_MSG_VERBOSE(" dRmax: " << dRmax);
+		pTau.setDetail(xAOD::TauJetParameters::dRmax, static_cast<float>(dRmax)  );
+	}
+
+	return StatusCode::SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/src/TauSubstructureVariables.h b/Reconstruction/tauRecTools/src/TauSubstructureVariables.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5038d6125017265f94ce28a9996e65ce9ee8cf9
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauSubstructureVariables.h
@@ -0,0 +1,54 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUSUBSTRUCTUREBUILDER_H
+#define TAUREC_TAUSUBSTRUCTUREBUILDER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+/**
+ * @brief Calculate variables from the tau substructure.
+ * 
+ * @author M. Trottier-McDonald
+ * @author Felix Friedrich
+ * 
+ */
+
+class TauSubstructureVariables : virtual public TauRecToolBase
+{
+    public: 
+        
+        static const double DEFAULT;
+
+        TauSubstructureVariables(const std::string& name);
+	ASG_TOOL_CLASS2(TauSubstructureVariables, TauRecToolBase, ITauToolBase);
+	
+        ~TauSubstructureVariables();
+
+        virtual StatusCode execute(xAOD::TauJet& pTau);
+
+        virtual StatusCode initialize();
+        virtual StatusCode finalize();
+        virtual StatusCode eventInitialize();
+
+	virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+	virtual void print() const { }
+
+    private:
+        /** Maximal pile up correction in GeV for a tau candidate.
+         *  Used for the caloIso corrected variable.
+         */
+        double m_maxPileUpCorrection; 
+        double m_pileUpAlpha;         //!< slope of the pileup correction
+        
+        /** 
+         * enable cell origin correction 
+         * eta and phi of the cells are corrected wrt to the origin of the tau vertex
+         */
+        bool m_doVertexCorrection;
+        bool m_inAODmode; //!< don't update everything if running on AODs
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauTestDump.cxx b/Reconstruction/tauRecTools/src/TauTestDump.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..1289173e2ccbfbf2a148439fbcb2c5374e615d80
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauTestDump.cxx
@@ -0,0 +1,112 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauTestDump.cxx
+// package:     Reconstruction/tauRec
+// authors:     Felix Friedrich
+// date:        2012-11-05
+// 
+//-----------------------------------------------------------------------------
+
+#include <GaudiKernel/IToolSvc.h>
+#include <GaudiKernel/ListItem.h>
+
+#include "FourMomUtils/P4Helpers.h"
+#include "FourMom/P4EEtaPhiM.h"
+#include "CLHEP/Vector/LorentzVector.h"
+#include "Particle/TrackParticle.h"
+
+
+#include "tauRecTools/TauEventData.h"
+//#include "tauEvent/TauCommonDetails.h"
+//#include "tauEvent/TauPi0Details.h"
+//#include "tauEvent/TauPi0Cluster.h"
+#include "xAODTau/TauJet.h"
+
+//#include "tauEvent/TauJetParameters.h"        
+
+#include "TauTestDump.h"
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauTestDump::TauTestDump(const std::string &name ) :
+TauRecToolBase(name) {
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauTestDump::~TauTestDump() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauTestDump::initialize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+
+StatusCode TauTestDump::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauTestDump::execute(xAOD::TauJet& pTau) {
+
+    ATH_MSG_INFO("=== TAU TEST DUMP BEGIN ==================== ");
+  
+    ATH_MSG_INFO("Tau recorded with: pt="<< pTau.pt() <<", eta=" <<pTau.eta()<<", phi="<<pTau.phi());
+    float tfFlightPathSig;
+    float ipSigLeadTrk;
+    pTau.detail(xAOD::TauJetParameters::ipSigLeadTrk, ipSigLeadTrk);
+    pTau.detail(xAOD::TauJetParameters::trFlightPathSig,tfFlightPathSig );
+    ATH_MSG_INFO(" numTrack="<<pTau.nTracks() << ", tfFlightPathSig=" << tfFlightPathSig <<", ipSigLeadTrk=" << ipSigLeadTrk );
+    
+    //stop here
+    return StatusCode::SUCCESS;
+
+    /* Unreachable due to the above return statement. Disabled to shut coverity up.
+    if (pTau.nTracks() != 1) {
+      // Pi0 calculated only for 1p taus --> leave test case
+      ATH_MSG_INFO("Pi0 calculated only for 1p taus --> leave test case");
+      return StatusCode::SUCCESS;
+    }
+
+    // Default PFO pi0
+    ATH_MSG_INFO("dumping pi0 standard");
+    if (pTau.nPi0PFOs()>0) {
+	    for (unsigned int i=0; i<pTau.nPi0PFOs();++i) ATH_MSG_INFO(pTau.pi0PFO(i)->e()<< " ");
+    }
+    else ATH_MSG_INFO("no pi0 cand");
+
+    // Cell-based PFO pi0
+    ATH_MSG_INFO("dumping pi0 cell-based");
+    if (pTau.nProtoPi0PFOs()>0) {
+	    for (unsigned int i=0; i<pTau.nProtoPi0PFOs();++i) ATH_MSG_INFO(pTau.protoPi0PFO(i)->e()<< " ");
+    }
+    else ATH_MSG_INFO("no pi0 cand");
+
+    ATH_MSG_INFO("end dumping pi0");
+    
+    ATH_MSG_INFO("=== TAU TEST DUMP END ==================== ");
+
+    return StatusCode::SUCCESS;
+    */
+}
+
+
diff --git a/Reconstruction/tauRecTools/src/TauTestDump.h b/Reconstruction/tauRecTools/src/TauTestDump.h
new file mode 100644
index 0000000000000000000000000000000000000000..1256c97b7ce71469fc72153af8fef7e9921e4fa4
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauTestDump.h
@@ -0,0 +1,38 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUTESTDUMP_H
+#define TAUREC_TAUTESTDUMP_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+
+/**
+ * @brief Tau Tool for developing, testing and debugging 
+ * 
+ *  
+ * 
+ * @author Felix Friedrich
+ */
+
+class TauTestDump : virtual public TauRecToolBase {
+public:
+    //-----------------------------------------------------------------
+    // Constructor and destructor
+    //-----------------------------------------------------------------
+    TauTestDump(const std::string& name);
+    ASG_TOOL_CLASS2(TauTestDump, TauRecToolBase, ITauToolBase);
+    ~TauTestDump();
+    
+    virtual StatusCode initialize();                 
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();  
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+};
+
+#endif // TAUREC_TAUTESTDUMP_H
diff --git a/Reconstruction/tauRecTools/src/TauTrackFinder.cxx b/Reconstruction/tauRecTools/src/TauTrackFinder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9ab9fa9621f3d231ff9238c7081e533d0ffe7750
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauTrackFinder.cxx
@@ -0,0 +1,640 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TrkToolInterfaces/ITrackSelectorTool.h"
+#include "TrkParametersIdentificationHelpers/TrackParametersIdHelper.h"
+#include "RecoToolInterfaces/IParticleCaloExtensionTool.h"
+
+#include "xAODTau/TauJet.h"
+#include "xAODTau/TauJetContainer.h"
+
+#include "TauTrackFinder.h"
+#include "tauRecTools/KineUtils.h"
+#include "tauRecTools/TrackSort.h"
+
+
+TauTrackFinder::TauTrackFinder(const std::string& name ) :
+		TauRecToolBase(name),
+                m_caloExtensionTool("Trk::ParticleCaloExtensionTool/ParticleCaloExtensionTool"),
+		m_trackSelectorTool_tau(""),
+		m_trackToVertexTool("Reco::TrackToVertex"),
+		m_z0maxDelta(1000),
+		m_applyZ0cut(false),
+		m_storeInOtherTrks(true),
+		m_bypassSelector(false),
+		m_bypassExtrapolator(false)
+{
+	declareProperty("MaxJetDrTau", m_maxJetDr_tau = 0.2);
+	declareProperty("MaxJetDrWide", m_maxJetDr_wide = 0.4);
+	declareProperty("TrackSelectorToolTau", m_trackSelectorTool_tau);
+	declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles");
+        declareProperty("ParticleCaloExtensionTool",   m_caloExtensionTool );
+        declareProperty("TrackToVertexTool",m_trackToVertexTool);
+	declareProperty("maxDeltaZ0wrtLeadTrk", m_z0maxDelta);
+	declareProperty("removeTracksOutsideZ0wrtLeadTrk", m_applyZ0cut);
+        declareProperty("StoreRemovedCoreWideTracksInOtherTracks", m_storeInOtherTrks = true);
+	declareProperty("BypassSelector", m_bypassSelector = false);
+	declareProperty("BypassExtrapolator", m_bypassExtrapolator = false);
+}
+
+TauTrackFinder::~TauTrackFinder() {
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::initialize() {
+
+	// Get the TrackSelectorTool
+	if (!retrieveTool(m_trackSelectorTool_tau)) return StatusCode::FAILURE;
+
+	// Get the TJVA
+	if (!retrieveTool(m_trackToVertexTool)) return StatusCode::FAILURE;
+	if (!retrieveTool(m_caloExtensionTool)) return StatusCode::FAILURE;
+
+	return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::finalize() {
+	return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::eventInitialize() {
+	return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::eventFinalize() {
+	return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::execute(xAOD::TauJet& pTau) {
+
+	ATH_MSG_VERBOSE("TauTrackFinder Executing");
+
+	StatusCode sc;
+	// get the track particle container from StoreGate
+	const xAOD::TrackParticleContainer* trackParticleCont = 0;
+
+	//for tau trigger
+	bool inTrigger = tauEventData()->inTrigger();
+	if (inTrigger)   sc = tauEventData()->getObject( "TrackContainer", trackParticleCont );
+
+	if( !inTrigger || !trackParticleCont || sc.isFailure() ) {
+		// try standard
+		if (!openContainer(trackParticleCont, m_inputTrackParticleContainerName)) {
+			if (!inTrigger) return StatusCode::FAILURE; // in offline we don't reconstruct tau candidates without having a track container
+			else return StatusCode::SUCCESS; // we don't want stop trigger if there is no track container
+		}
+	}
+
+	std::vector<const xAOD::TrackParticle*> tauTracks;
+	std::vector<const xAOD::TrackParticle*> wideTracks;
+	std::vector<const xAOD::TrackParticle*> otherTracks;
+
+	const xAOD::Vertex* pVertex = pTau.vertexLink()!=0 ? (*pTau.vertexLink()) : NULL;
+	// retrieve tracks wrt a vertex
+	// as a vertex is used: tau origin / PV / beamspot / 0,0,0 (in this order, depending on availability)
+	getTauTracksFromPV(pTau, *trackParticleCont, pVertex, tauTracks, wideTracks, otherTracks);
+
+
+	this->resetDeltaZ0Cache();
+	// remove core and wide tracks outside a maximal delta z0 wrt lead core track
+	if (m_applyZ0cut) {
+		this->removeOffsideTracksWrtLeadTrk(tauTracks, wideTracks, otherTracks, pVertex, m_z0maxDelta);
+	}
+
+	//clear tracks first (needed for "rerun mode" if called on AODs again)
+	pTau.clearTrackLinks();
+	pTau.clearWideTrackLinks();
+	pTau.clearOtherTrackLinks();
+
+	bool alreadyUsed = false;
+	//check for tracks used in multiple taus
+	xAOD::TauJetContainer* pContainer = tauEventData()->xAODTauContainer;
+	if(pContainer==0){
+	  pContainer = static_cast<xAOD::TauJetContainer*> (pTau.container());
+	}
+	if(pContainer==0) {
+	  ATH_MSG_FATAL("Can't find tau Container");
+	  return StatusCode::FAILURE;
+	}
+
+	
+	for (std::vector<const xAOD::TrackParticle*>::iterator track_it = tauTracks.begin(); track_it != tauTracks.end() ;)
+	{
+		alreadyUsed = false;
+
+		//loop over all up-to-now reconstructed tau candidates
+		xAOD::TauJetContainer::const_iterator tau_it = pContainer->begin();
+		xAOD::TauJetContainer::const_iterator tau_end = pContainer->end();
+		for( ; tau_it != tau_end; tau_it++ )
+		{
+		        if( (*tau_it) == &pTau ) continue;
+			//loop over core tracks
+			for (unsigned int j = 0; j < (*tau_it)->nTracks(); ++j)
+			{
+				if ((*track_it) == (*tau_it)->track(j))
+				{
+					ATH_MSG_WARNING("Found a track that is identical with a track already associated to another tau. Will not add this track to more than one tau candidate");
+					alreadyUsed = true;
+				}
+			}
+		}
+
+		//if this track has already been used by another tau, don't associate it to this new one
+		if (alreadyUsed)    track_it = tauTracks.erase(track_it);
+		else ++track_it;
+	}
+
+
+	// associated track to tau candidate and calculate charge
+	float charge = 0;
+	for (unsigned int i = 0; i < tauTracks.size(); ++i) {
+		const xAOD::TrackParticle* trackParticle = tauTracks.at(i);
+
+		ATH_MSG_VERBOSE(name() 	<< " adding core track nr: " << i
+				<< " eta " << trackParticle->eta()
+				<< " phi " << trackParticle->phi()
+		);
+		charge += trackParticle->charge();
+		ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle;
+		linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle);
+		pTau.addTrackLink(linkToTrackParticle);
+		ATH_MSG_VERBOSE(name() 	<< " added core track nr: " << i
+				<< " eta " << pTau.track(i)->eta()
+				<< " phi " << pTau.track(i)->phi()
+		);
+	}
+	// set the charge, which is defined by the core tau tracks only
+	pTau.setCharge(charge);
+
+	/// FIXME hide the logic to create element links inside xAODTau
+	/// was
+	// for (unsigned int i = 0; i < wideTracks.size(); ++i)
+	//     details->addSeedCalo_wideTrk(trackParticleCont, wideTracks.at(i));
+	for (unsigned int i = 0; i < wideTracks.size(); ++i) {
+		const xAOD::TrackParticle* trackParticle = wideTracks.at(i);
+
+		ATH_MSG_VERBOSE(name() 	<< " adding wide track nr: " << i
+				<< " eta " << trackParticle->eta()
+				<< " phi " << trackParticle->phi()
+		);
+		ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle;
+		linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle);
+		pTau.addWideTrackLink(linkToTrackParticle);
+		ATH_MSG_VERBOSE(name() 	<< " added wide track nr: " << i
+				<< " eta " << pTau.wideTrack(i)->eta()
+				<< " phi " << pTau.wideTrack(i)->phi()
+		);
+	}
+
+	/// was
+	// for (unsigned int i = 0; i < otherTracks.size(); ++i)
+	//     details->addOtherTrk(trackParticleCont, otherTracks.at(i));
+	for (unsigned int i = 0; i < otherTracks.size(); ++i) {
+		const xAOD::TrackParticle* trackParticle = otherTracks.at(i);
+
+		ATH_MSG_VERBOSE(name() 	<< " adding other track nr: " << i
+				<< " eta " << trackParticle->eta()
+				<< " phi " << trackParticle->phi()
+		);
+		ElementLink<xAOD::TrackParticleContainer> linkToTrackParticle;
+		linkToTrackParticle.toContainedElement(*trackParticleCont, trackParticle);
+		pTau.addOtherTrackLink(linkToTrackParticle);
+		ATH_MSG_VERBOSE(name() 	<< " added other track nr: " << i
+				<< " eta " << pTau.otherTrack(i)->eta()
+				<< " phi " << pTau.otherTrack(i)->phi()
+		);
+	}
+
+
+	ATH_MSG_DEBUG("numTrack: " << "/" << pTau.nTracks());
+	ATH_MSG_DEBUG("charge: " << "/" << pTau.charge());
+
+	// extrapolate core tracks to calorimeter surface
+	// store information only in ExtraDetailsContainer
+
+	if(!m_bypassExtrapolator)
+	  {
+	    sc = extrapolateToCaloSurface(pTau);
+	    if (sc.isFailure() && !sc.isRecoverable()) {
+	      ATH_MSG_ERROR("couldn't extrapolate tracks to calo surface");
+	      return StatusCode::FAILURE;
+	    }
+	  }
+	
+	return StatusCode::SUCCESS;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+TauTrackFinder::TauTrackType TauTrackFinder::tauTrackType( const xAOD::TauJet& pTau,
+		const xAOD::TrackParticle& trackParticle,
+		const xAOD::Vertex* primaryVertex)
+{
+	//ATH_MSG_VERBOSE("tau axis:" << pTau.hlv().perp()<< " " << pTau.hlv().eta() << " " << pTau.hlv().phi()  << " " << pTau.hlv().e() );
+	double dR = Tau1P3PKineUtils::deltaR(pTau.eta(),pTau.phi(),trackParticle.eta(),trackParticle.phi());
+
+	if (dR > m_maxJetDr_wide) return NotTauTrack;
+
+	bool goodTrack = true;
+	if(!m_bypassSelector)
+	  goodTrack = m_trackSelectorTool_tau->decision(trackParticle, primaryVertex);
+	
+	if (goodTrack) {
+	  if (dR > m_maxJetDr_tau)
+	    return TauTrackWide;
+	  else
+	    return TauTrackCore;
+	} else
+	  return TauTrackOther;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+void TauTrackFinder::getTauTracksFromPV( const xAOD::TauJet& pTau,
+		const xAOD::TrackParticleContainer& trackParticleCont,
+		const xAOD::Vertex* primaryVertex,
+		std::vector<const xAOD::TrackParticle*> &tauTracks,
+		std::vector<const xAOD::TrackParticle*> &wideTracks,
+		std::vector<const xAOD::TrackParticle*> &otherTracks)
+{
+	for (xAOD::TrackParticleContainer::const_iterator tpcItr = trackParticleCont.begin(); tpcItr != trackParticleCont.end(); ++tpcItr) {
+		const xAOD::TrackParticle *trackParticle = *tpcItr;
+
+		TauTrackType type = tauTrackType(pTau, *trackParticle, primaryVertex);
+
+		if (type == TauTrackCore)
+			tauTracks.push_back(trackParticle);
+		else if (type == TauTrackWide)
+			wideTracks.push_back(trackParticle);
+		else if (type == TauTrackOther)
+			otherTracks.push_back(trackParticle);
+
+	}
+	std::sort(tauTracks.begin(), tauTracks.end(), TrackSort());
+	std::sort(wideTracks.begin(), wideTracks.end(), TrackSort());
+	std::sort(otherTracks.begin(), otherTracks.end(), TrackSort());
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauTrackFinder::extrapolateToCaloSurface(xAOD::TauJet& pTau) {
+
+	//apparently unused: const int numOfsampEM = 4;
+
+        Trk::TrackParametersIdHelper parsIdHelper;
+
+	for (unsigned int itr = 0; itr < 10 && itr < pTau.nTracks(); ++itr) {
+
+		const xAOD::TrackParticle *orgTrack = pTau.track(itr);
+                
+                if( !orgTrack ) continue;
+
+                // get the extrapolation into the calo
+                const Trk::CaloExtension* caloExtension = 0;
+                if( !m_caloExtensionTool->caloExtension(*orgTrack,caloExtension) || caloExtension->caloLayerIntersections().empty() ) continue;
+
+                // loop over calo layers
+                for( auto cur = caloExtension->caloLayerIntersections().begin(); cur != caloExtension->caloLayerIntersections().end() ; ++cur ){
+                  
+                  // only use entry layer
+                  if( !parsIdHelper.isEntryToVolume((*cur)->cIdentifier()) ) continue;
+
+                  CaloSampling::CaloSample sample = parsIdHelper.caloSample((*cur)->cIdentifier());
+                  
+                  if( sample == CaloSampling::EME1 || sample == CaloSampling::EMB1 ){
+                    pTau.setTrackEtaStrip( itr,  (*cur)->position().eta() );
+                    pTau.setTrackPhiStrip( itr,  (*cur)->position().phi() );
+                    break;
+                  }
+                }
+		// //---------------------------------------------------------------------
+		// // Extrapolate to all layers
+		// //---------------------------------------------------------------------
+		// const DataVector< const Trk::TrackParameters >* pTrk = m_trackToCalo->getParametersInCalo(*orgTrack, Trk::pion, Trk::alongMomentum); //FIXME
+
+		// //---------------------------------------------------------------------
+		// // Calculate eta, phi impact point at calorimeter layers EM 0,1,2,3
+		// //---------------------------------------------------------------------
+		// double eta_extrapol[4];
+		// double phi_extrapol[4];
+
+		// for (int i = 0; i < numOfsampEM; ++i) {
+		// 	eta_extrapol[i] = -11111.;
+		// 	phi_extrapol[i] = -11111.;
+		// }
+
+		// // XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet
+		// // if (pTrk && (*pTrk)[IExtrapolateToCaloTool::PreSampler]) {
+		// // 	eta_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().eta();
+		// // 	phi_extrapol[0] = (*pTrk)[IExtrapolateToCaloTool::PreSampler]->position().phi();
+		// // }
+
+		// if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Strips]) {
+		// 	eta_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().eta();
+		// 	phi_extrapol[1] = (*pTrk)[IExtrapolateToCaloTool::Strips]->position().phi();
+
+		// if (msgLvl(MSG::VERBOSE)) 
+		//   { //only if desired msg level is requested
+		//     ATH_MSG_VERBOSE(name() << " extrapolation in strip layer : "  
+		// 		    << " track nr " << itr
+		// 		    << " impact point eta " << eta_extrapol[1]
+		// 		    << " impact point phi " << phi_extrapol[1]
+		// 		    );
+		//   }
+	
+		// pTau.setTrackEtaStrip( itr,  (*pTrk)[IExtrapolateToCaloTool::Strips]->position().eta() );
+		// pTau.setTrackPhiStrip( itr,  (*pTrk)[IExtrapolateToCaloTool::Strips]->position().phi() );
+		
+		// if (msgLvl(MSG::VERBOSE)) 
+		//   { //only if desired msg level is requested
+		//     ATH_MSG_VERBOSE(name() << " extrapolation in strip layer stored in tau : "  
+		// 		    << " track nr " << itr
+		// 		    << " impact point eta " << pTau.trackEtaStrip(itr)
+		// 		    << " impact point phi " << pTau.trackPhiStrip(itr)
+		// 		    );
+		//   }
+	
+		// }
+
+		// XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet
+		// if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Middle]) {
+		// 	eta_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().eta();
+		// 	phi_extrapol[2] = (*pTrk)[IExtrapolateToCaloTool::Middle]->position().phi();
+		// }
+
+		// if (pTrk && (*pTrk)[IExtrapolateToCaloTool::Back]) {
+		// 	eta_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().eta();
+		// 	phi_extrapol[3] = (*pTrk)[IExtrapolateToCaloTool::Back]->position().phi();
+		// }
+
+
+		// for (int i = 0; i < numOfsampEM; ++i) {
+		//     pExtraDetails->etaLooseTrkCaloSamp()[itr][i] = eta_extrapol[i];
+		//     pExtraDetails->phiLooseTrkCaloSamp()[itr][i] = phi_extrapol[i];
+		// }
+
+		// // in the past this was filled by tau1P3PTrackMatchCalo
+		// for (int i = 0; i < numOfsampEM; ++i) {
+		//     pExtraDetails->etaTrkCaloSamp()[itr][i] = eta_extrapol[i];
+		//     pExtraDetails->phiTrkCaloSamp()[itr][i] = phi_extrapol[i];
+		// }
+
+		//if (pTrk) delete pTrk;
+
+		// XXX commenting this out as long as it's not clear whether these variables will be stored in xAOD::TauJet
+		// if (msgLvl(MSG::VERBOSE)) { //only if desired msg level is requested
+		//   for (int i = 0; i < numOfsampEM; ++i) {
+		//     ATH_MSG_VERBOSE(name() << " extrapolation for loose trk in samp : " << i
+		//                     << " track nr " << itr
+		//                     << " impact point eta " << pExtraDetails->etaLooseTrkCaloSamp()[itr][i]
+		//                     << " impact point phi " << pExtraDetails->phiLooseTrkCaloSamp()[itr][i]
+		//                     );
+		//     ATH_MSG_VERBOSE(name() << " extrapolation in samp : " << i
+		//                     << " track nr " << itr
+		//                     << " impact point eta " << pExtraDetails->etaTrkCaloSamp()[itr][i]
+		//                     << " impact point phi " << pExtraDetails->phiTrkCaloSamp()[itr][i]
+		//                     );
+		//   }
+		// }
+
+	}
+
+	return StatusCode::SUCCESS;
+
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+void TauTrackFinder::removeOffsideTracksWrtLeadTrk(std::vector<const Rec::TrackParticle*> &tauTracks,
+                                       std::vector<const Rec::TrackParticle*> &wideTracks,
+                                       std::vector<const Rec::TrackParticle*> &otherTracks,
+                                       const Trk::RecVertex* tauOrigin,
+                                       double maxDeltaZ0)
+{
+    float MAX=1e5;
+    this->resetDeltaZ0Cache();
+
+    // need at least one core track to have a leading trk to compare with
+    if (tauTracks.size()<1) return;
+
+    //check if position is available for origin
+    /** FIXME: This causes compilation error after eigen migration
+    if (tauOrigin)
+        if (!tauOrigin->position())
+            tauOrigin = 0;
+    */
+
+    // get lead trk parameters
+    const Rec::TrackParticle *leadTrack = tauTracks.at(0);
+    float z0_leadTrk = getZ0(leadTrack, tauOrigin);
+
+    if (z0_leadTrk > MAX-1) return; // bad lead trk -> do nothing
+
+    ATH_MSG_VERBOSE("before z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size());
+
+    std::vector<const Rec::TrackParticle*>::iterator itr;
+
+    // check core tracks
+    // skip leading track, because it is the reference
+    itr = tauTracks.begin()+1;
+    while (itr!=tauTracks.end()) {
+        float z0 = getZ0(*itr, tauOrigin);
+        float deltaZ0=z0 - z0_leadTrk;
+
+        ATH_MSG_VERBOSE("core Trks: deltaZ0= " << deltaZ0);
+        m_vDeltaZ0coreTrks.push_back(deltaZ0);
+
+        if ( fabs(deltaZ0) < maxDeltaZ0 ) {++itr;}
+        else {
+            if (m_storeInOtherTrks) otherTracks.push_back(*itr);
+            itr = tauTracks.erase(itr); //remove from core track collection
+        }
+    }
+
+    // check wide tracks
+    itr = wideTracks.begin();
+    while (itr!=wideTracks.end()) {
+        float z0 = getZ0(*itr, tauOrigin);
+        float deltaZ0=z0 - z0_leadTrk;
+
+        ATH_MSG_VERBOSE("wide Trks: deltaZ0= " << deltaZ0);
+        m_vDeltaZ0wideTrks.push_back(deltaZ0);
+
+        if ( fabs(deltaZ0) < maxDeltaZ0 ) { ++itr; }
+        else {
+            if (m_storeInOtherTrks) otherTracks.push_back(*itr);
+            itr = wideTracks.erase(itr); //remove from wide track collection
+        }
+    }
+
+    ATH_MSG_VERBOSE("after z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size());
+
+    // sort again
+    std::sort(tauTracks.begin(), tauTracks.end(), TrackSort());
+    std::sort(wideTracks.begin(), wideTracks.end(), TrackSort());
+    std::sort(otherTracks.begin(), otherTracks.end(), TrackSort());
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+void TauTrackFinder::removeOffsideTracksWrtLeadTrk(std::vector<const xAOD::TrackParticle*> &tauTracks,
+						   std::vector<const xAOD::TrackParticle*> &wideTracks,
+						   std::vector<const xAOD::TrackParticle*> &otherTracks,
+						   const xAOD::Vertex* tauOrigin,
+						   double maxDeltaZ0)
+{
+    float MAX=1e5;
+    this->resetDeltaZ0Cache();
+
+    // need at least one core track to have a leading trk to compare with
+    if (tauTracks.size()<1) return;
+
+    //check if position is available for origin
+    /** FIXME: This causes compilation error after eigen migration
+    if (tauOrigin)
+        if (!tauOrigin->position())
+            tauOrigin = 0;
+    */
+
+    // get lead trk parameters
+    const xAOD::TrackParticle *leadTrack = tauTracks.at(0);
+    float z0_leadTrk = getZ0(leadTrack, tauOrigin);
+
+    if (z0_leadTrk > MAX-1) return; // bad lead trk -> do nothing
+
+    ATH_MSG_VERBOSE("before z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size());
+
+    std::vector<const xAOD::TrackParticle*>::iterator itr;
+
+    // check core tracks
+    // skip leading track, because it is the reference
+    itr = tauTracks.begin()+1;
+    while (itr!=tauTracks.end()) {
+        float z0 = getZ0(*itr, tauOrigin);
+        float deltaZ0=z0 - z0_leadTrk;
+
+        ATH_MSG_VERBOSE("core Trks: deltaZ0= " << deltaZ0);
+        m_vDeltaZ0coreTrks.push_back(deltaZ0);
+
+        if ( fabs(deltaZ0) < maxDeltaZ0 ) {++itr;}
+        else {
+            if (m_storeInOtherTrks) otherTracks.push_back(*itr);
+            itr = tauTracks.erase(itr); //remove from core track collection
+        }
+    }
+
+    // check wide tracks
+    itr = wideTracks.begin();
+    while (itr!=wideTracks.end()) {
+        float z0 = getZ0(*itr, tauOrigin);
+        float deltaZ0=z0 - z0_leadTrk;
+
+        ATH_MSG_VERBOSE("wide Trks: deltaZ0= " << deltaZ0);
+        m_vDeltaZ0wideTrks.push_back(deltaZ0);
+
+        if ( fabs(deltaZ0) < maxDeltaZ0 ) { ++itr; }
+        else {
+            if (m_storeInOtherTrks) otherTracks.push_back(*itr);
+            itr = wideTracks.erase(itr); //remove from wide track collection
+        }
+    }
+
+    ATH_MSG_VERBOSE("after z0 cut: #coreTracks=" << tauTracks.size() << ", #wideTracks=" << wideTracks.size() << ", #otherTracks=" << otherTracks.size());
+
+    // sort again
+    std::sort(tauTracks.begin(), tauTracks.end(), TrackSort());
+    std::sort(wideTracks.begin(), wideTracks.end(), TrackSort());
+    std::sort(otherTracks.begin(), otherTracks.end(), TrackSort());
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+float TauTrackFinder::getZ0(const Rec::TrackParticle* track, const Trk::RecVertex* vertex)
+{
+    float MAX=1e5;
+
+    if (!track) return MAX;
+    if (!track->measuredPerigee()->covariance()) {
+         ATH_MSG_WARNING("Bad track; can't find perigee at vertex.");
+         return MAX;
+    }
+
+    const Trk::Perigee* perigee = 0;
+    if (vertex) perigee = m_trackToVertexTool->perigeeAtVertex(*track, vertex->position());
+    else        perigee = m_trackToVertexTool->perigeeAtVertex(*track); //will use beamspot or 0,0,0 instead
+
+    if (!perigee) {
+        ATH_MSG_WARNING("Bad track; can't find perigee at vertex.");
+        return MAX;
+    }
+
+    float z0 = perigee->parameters()[Trk::z0];
+
+    delete perigee; //cleanup necessary to prevent mem leak
+
+    return z0;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+float TauTrackFinder::getZ0(const xAOD::TrackParticle* track, const xAOD::Vertex* vertex)
+{
+    float MAX=1e5;
+
+    if (!track) return MAX;
+
+    const Trk::Perigee* perigee = 0;
+    if (vertex) perigee = m_trackToVertexTool->perigeeAtVertex(*track, vertex->position());
+    else        perigee = m_trackToVertexTool->perigeeAtVertex(*track); //will use beamspot or 0,0,0 instead
+
+    if (!perigee) {
+        ATH_MSG_WARNING("Bad track; can't find perigee at vertex.");
+        return MAX;
+    }
+
+    float z0 = perigee->parameters()[Trk::z0];
+
+    delete perigee; //cleanup necessary to prevent mem leak
+
+    return z0;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+void TauTrackFinder::getDeltaZ0Values(std::vector<float>& vDeltaZ0coreTrks, std::vector<float>& vDeltaZ0wideTrks)
+{
+  vDeltaZ0coreTrks.clear();
+  vDeltaZ0coreTrks = m_vDeltaZ0coreTrks;
+
+  vDeltaZ0wideTrks.clear();
+  vDeltaZ0wideTrks = m_vDeltaZ0wideTrks;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+void TauTrackFinder::resetDeltaZ0Cache()
+{
+    m_vDeltaZ0coreTrks.clear();
+    m_vDeltaZ0wideTrks.clear();
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Helpers
+template <class T>
+bool TauTrackFinder::openContainer(T* &container, std::string containerName, bool printFATAL) {
+    StatusCode sc = evtStore()->retrieve(container, containerName);
+    if (sc.isFailure() || !container) {
+      if (printFATAL) ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate");
+      return 0;
+    }
+    return container;
+}
+
+template <class T>
+bool TauTrackFinder::retrieveTool(T & tool) {
+    if (tool.retrieve().isFailure()) {
+        ATH_MSG_FATAL("Failed to retrieve tool " << tool);
+        return false;
+    } else {
+        ATH_MSG_VERBOSE("Retrieved tool " << tool);
+    }
+    return true;
+}
diff --git a/Reconstruction/tauRecTools/src/TauTrackFinder.h b/Reconstruction/tauRecTools/src/TauTrackFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6ad1425b930618c48a9a95dcd3db9e372015347
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauTrackFinder.h
@@ -0,0 +1,154 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUTRACKFINDER_H
+#define TAUREC_TAUTRACKFINDER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "ITrackToVertex/ITrackToVertex.h"
+
+#include "xAODTracking/Vertex.h"
+#include "xAODTracking/TrackParticle.h"
+#include "xAODTracking/TrackParticleContainer.h"
+
+#include "VxVertex/RecVertex.h"
+
+namespace Trk {
+  class ITrackSelectorTool;
+  class IParticleCaloExtensionTool;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+/** 
+ * @brief Associate tracks to the tau candidate.
+ * 
+ *  The tracks have to pass dedicated quality criteria and have to 
+ *  match to a primary vertex consistent with the tau origin.
+ * 
+ * @author KG Tan <Kong.Guan.Tan@cern.ch>
+ * @author Felix Friedrich
+ */
+
+class TauTrackFinder : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor and Destructor
+    //-------------------------------------------------------------
+    TauTrackFinder(const std::string& name);
+    ASG_TOOL_CLASS2(TauTrackFinder, TauRecToolBase, ITauToolBase);
+    ~TauTrackFinder();
+
+    //-------------------------------------------------------------
+    //! Enumerator defining type of tau track
+    //-------------------------------------------------------------
+    enum TauTrackType
+    {
+        TauTrackCore  = 0,
+        TauTrackWide  = 1,
+        TauTrackOther = 2,
+        NotTauTrack   = 3
+    };
+
+    //-------------------------------------------------------------
+    //! Algorithm functions
+    //-------------------------------------------------------------
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize();
+    virtual StatusCode finalize();
+    
+    virtual void print() const { }
+    
+    //-------------------------------------------------------------
+    //! Extrapolate track eta and phi to the calorimeter middle surface
+    //-------------------------------------------------------------
+    StatusCode extrapolateToCaloSurface(xAOD::TauJet& pTau);
+
+    TauTrackType tauTrackType( const xAOD::TauJet& tauJet,
+    		const xAOD::TrackParticle& trackParticle,
+    		const xAOD::Vertex* primaryVertex);
+
+    void getTauTracksFromPV( const xAOD::TauJet& tauJet,
+    		const xAOD::TrackParticleContainer& trackParticleCont,
+    		const xAOD::Vertex* primaryVertex,
+    		std::vector<const xAOD::TrackParticle*> &tauTracks,
+    		std::vector<const xAOD::TrackParticle*> &wideTracks,
+    		std::vector<const xAOD::TrackParticle*> &otherTracks);
+
+    // old style AOD version
+    void removeOffsideTracksWrtLeadTrk(std::vector<const Rec::TrackParticle*> &tauTracks,
+                                           std::vector<const Rec::TrackParticle*> &wideTracks,
+                                           std::vector<const Rec::TrackParticle*> &otherTracks,
+                                           const Trk::RecVertex* tauOrigin,
+                                           double maxDeltaZ0);
+
+    // new xAOD version
+    void removeOffsideTracksWrtLeadTrk(std::vector<const xAOD::TrackParticle*> &tauTracks,
+                                           std::vector<const xAOD::TrackParticle*> &wideTracks,
+                                           std::vector<const xAOD::TrackParticle*> &otherTracks,
+                                           const xAOD::Vertex* tauOrigin,
+                                           double maxDeltaZ0);
+
+    void  getDeltaZ0Values(std::vector<float>& vDeltaZ0coreTrks, std::vector<float>& vDeltaZ0wideTrks);
+    void  resetDeltaZ0Cache();
+
+private:
+    //-------------------------------------------------------------
+    //! Some internally used functions
+    //-------------------------------------------------------------
+    float getZ0(const Rec::TrackParticle* track, const Trk::RecVertex* vertex);  //AOD version
+    float getZ0(const xAOD::TrackParticle* track, const xAOD::Vertex* vertex);   //xAOD version
+
+private:
+    //-------------------------------------------------------------
+    //! Storegate names of input containers and output containers
+    //-------------------------------------------------------------
+    std::string m_inputTauJetContainerName;
+    std::string m_inputTrackParticleContainerName;
+    std::string m_inputPrimaryVertexContainerName;
+
+    //-------------------------------------------------------------
+    //! tools
+    //-------------------------------------------------------------
+    ToolHandle< Trk::IParticleCaloExtensionTool >  m_caloExtensionTool;
+    ToolHandle<Trk::ITrackSelectorTool> m_trackSelectorTool_tau;
+    ToolHandle<Reco::ITrackToVertex> m_trackToVertexTool;
+    
+    //-------------------------------------------------------------
+    //! Input parameters for algorithm
+    //-------------------------------------------------------------
+    double  m_maxJetDr_tau;
+    double  m_maxJetDr_wide;
+    
+    //-------------------------------------------------------------
+    // z0 cuts
+    //-------------------------------------------------------------
+    float m_z0maxDelta;
+    bool m_applyZ0cut;
+    bool m_storeInOtherTrks;
+    std::vector<float> m_vDeltaZ0coreTrks;
+    std::vector<float> m_vDeltaZ0wideTrks;
+
+    //-------------------------------------------------------------
+    // Bypass TrackSelectorTool / Extrapolation
+    //-------------------------------------------------------------
+
+    bool m_bypassSelector;
+    bool m_bypassExtrapolator;
+
+    //-------------------------------------------------------------
+    //! Convenience functions to handle storegate objects
+    //-------------------------------------------------------------
+    template <class T>
+    bool openContainer(T* &container, std::string containerName, bool printFATAL=false);
+
+    template <class T>
+    bool retrieveTool(T &tool);
+
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/src/TauVertexFinder.cxx b/Reconstruction/tauRecTools/src/TauVertexFinder.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..237f302cb852466868c14d4f53ba906add79bfc3
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauVertexFinder.cxx
@@ -0,0 +1,211 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#include "TauVertexFinder.h"
+
+#include "VxVertex/RecVertex.h"
+#include "VxVertex/VxCandidate.h"
+
+#include "xAODTracking/VertexContainer.h"
+#include "xAODTracking/Vertex.h"
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+#include "xAODTau/TauJet.h"
+
+TauVertexFinder::TauVertexFinder(const std::string& name ) :
+TauRecToolBase(name),
+m_printMissingContainerINFO(true),
+m_maxJVF(-100.),
+m_assocTracksName(""),
+m_trackVertexAssocName("")
+{
+    declareProperty("UseTJVA", m_useTJVA=true);
+    declareProperty("PrimaryVertexContainer", m_inputPrimaryVertexContainerName = "PrimaryVertices");
+    declareProperty("AssociatedTracks",m_assocTracksName);
+    declareProperty("TrackVertexAssociation",m_trackVertexAssocName);
+}
+
+TauVertexFinder::~TauVertexFinder() {
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauVertexFinder::initialize() {
+    if (m_useTJVA) ATH_MSG_INFO("using TJVA to determine tau vertex");
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauVertexFinder::finalize() {
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauVertexFinder::eventInitialize() {
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauVertexFinder::eventFinalize() {
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+StatusCode TauVertexFinder::execute(xAOD::TauJet& pTau) {
+  
+  // get the primary vertex container from StoreGate
+  //do it here because of tau trigger
+  const xAOD::VertexContainer* vxContainer = 0;
+  const xAOD::Vertex* primaryVertex = 0;
+  
+  StatusCode sc;
+  //for tau trigger
+  sc = tauEventData()->getObject("VxPrimaryCandidate", vxContainer);
+  
+  if (sc.isFailure() || !vxContainer) { //not in trigger mode or no vxContainer was set by trigger
+        ATH_MSG_DEBUG("no VxPrimaryCandidateContainer for trigger -> try standard way");
+        if (!openContainer(vxContainer, m_inputPrimaryVertexContainerName)) {
+          if (m_printMissingContainerINFO) {
+            ATH_MSG_INFO(m_inputPrimaryVertexContainerName << " container not found --> skip TauVertexFinder (no further info)");
+            m_printMissingContainerINFO=false;
+          }
+          return StatusCode::SUCCESS;
+        }
+
+        // find default PrimaryVertex (needed if TJVA is switched off or fails)
+        // see: https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/VertexReselectionOnAOD
+        // code adapted from 
+        // https://svnweb.cern.ch/trac/atlasoff/browser/Tracking/TrkEvent/VxVertex/trunk/VxVertex/PrimaryVertexSelector.h
+        if (vxContainer->size()>0) {   
+          // simple loop through and get the primary vertex
+          xAOD::VertexContainer::const_iterator vxIter    = vxContainer->begin();
+          xAOD::VertexContainer::const_iterator vxIterEnd = vxContainer->end();
+          for ( size_t ivtx = 0; vxIter != vxIterEnd; ++vxIter, ++ivtx ){
+            // the first and only primary vertex candidate is picked
+            if ( (*vxIter)->vertexType() ==  xAOD::VxType::PriVtx){
+              primaryVertex = (*vxIter);
+              break;
+            }
+          }
+        }
+    }
+    else { // trigger mode
+      // find default PrimaryVertex (highest sum pt^2)
+      if (vxContainer->size()>0) primaryVertex = (*vxContainer)[0];
+    }
+    
+    ATH_MSG_VERBOSE("size of VxPrimaryContainer is: "  << vxContainer->size() );
+    
+    // associate vertex to tau
+    if (primaryVertex) pTau.setVertex(vxContainer, primaryVertex);
+       
+    //stop here if TJVA is disabled or vertex container is empty
+    if (!m_useTJVA || vxContainer->size()==0) return StatusCode::SUCCESS;
+
+    // try to find new PV with TJVA
+    ATH_MSG_DEBUG("TJVA enabled -> try to find new PV for the tau candidate");
+
+    ElementLink<xAOD::VertexContainer> newPrimaryVertexLink = getPV_TJVA(pTau, *vxContainer );
+    if (newPrimaryVertexLink.isValid()) {
+      // set new primary vertex
+      // will overwrite default one which was set above
+      pTau.setVertexLink(newPrimaryVertexLink);
+      // save highest JVF value
+      pTau.setDetail(xAOD::TauJetParameters::TauJetVtxFraction,static_cast<float>(m_maxJVF));
+      ATH_MSG_DEBUG("TJVA vertex found and set");
+    }
+    else {
+      ATH_MSG_DEBUG("couldn't find new PV for TJVA");
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ElementLink<xAOD::VertexContainer> TauVertexFinder::getPV_TJVA(const xAOD::TauJet& pTau, const xAOD::VertexContainer& vertices)
+{
+	const xAOD::Jet* pJetSeed = (*pTau.jetLink());
+
+    // the implementation follows closely the example given in modifyJet(...) in https://svnweb.cern.ch/trac/atlasoff/browser/Reconstruction/Jet/JetMomentTools/trunk/Root/JetVertexFractionTool.cxx#15
+
+    // Get the tracks associated to the jet
+    std::vector<const xAOD::TrackParticle*> assocTracks;
+    if (! pJetSeed->getAssociatedObjects(m_assocTracksName, assocTracks)) {
+    	ATH_MSG_ERROR("Could not retrieve the AssociatedObjects named \""<< m_assocTracksName <<"\" from jet");
+    	return ElementLink<xAOD::VertexContainer>();
+    }
+
+    // Get the TVA object
+    const jet::TrackVertexAssociation* tva = NULL;
+    if (evtStore()->retrieve(tva,m_trackVertexAssocName).isFailure()) {
+    	ATH_MSG_ERROR("Could not retrieve the TrackVertexAssociation from evtStore: " << m_trackVertexAssocName);
+    	return ElementLink<xAOD::VertexContainer>();
+    }
+
+    // Calculate Jet Vertex Fraction
+    std::vector<float> jvf;
+    jvf.resize(vertices.size());
+    for (size_t iVertex = 0; iVertex < vertices.size(); ++iVertex) {
+      jvf.at(iVertex) = getJetVertexFraction(vertices.at(iVertex),assocTracks,tva);
+    }
+    
+    // Get the highest JVF vertex and store maxJVF for later use
+    // Note: the official JetMomentTools/JetVertexFractionTool doesn't provide any possibility to access the JVF value, but just the vertex.
+    m_maxJVF=-100.;
+    size_t maxIndex = 0;
+    for (size_t iVertex = 0; iVertex < jvf.size(); ++iVertex) {
+    	if (jvf.at(iVertex) > m_maxJVF) {
+          m_maxJVF = jvf.at(iVertex);
+          maxIndex = iVertex;
+        }
+    }
+
+    // Set the highest JVF vertex
+    ElementLink<xAOD::VertexContainer> vtxlink = ElementLink<xAOD::VertexContainer>(vertices,vertices.at(maxIndex)->index());
+
+    return vtxlink;
+}
+
+// reimplementation of JetVertexFractionTool::getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const
+// avoid to call this specific tool only for this easy purpose
+// see https://svnweb.cern.ch/trac/atlasoff/browser/Reconstruction/Jet/JetMomentTools/trunk/Root/JetVertexFractionTool.cxx
+float TauVertexFinder::getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const
+{
+    float sumTrackPV = 0;
+    float sumTrackAll = 0;
+    for (size_t iTrack = 0; iTrack < tracks.size(); ++iTrack)
+    {
+        const xAOD::TrackParticle* track = tracks.at(iTrack);
+        const xAOD::Vertex* ptvtx = tva->associatedVertex(track);
+        if (ptvtx != nullptr) {  // C++11 feature
+        	if (ptvtx->index() == vertex->index()) sumTrackPV += track->pt();
+        }
+        sumTrackAll += track->pt();
+
+    }
+    return sumTrackAll!=0 ? sumTrackPV/sumTrackAll : 0;
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// Helpers
+template <class T>
+bool TauVertexFinder::openContainer(T* &container, std::string containerName, bool printFATAL) {
+    StatusCode sc = evtStore()->retrieve(container, containerName);
+    if (sc.isFailure() || !container) {
+      if (printFATAL) ATH_MSG_FATAL("Container (" << containerName << ") not found in StoreGate");
+      return 0;
+    }
+    return container;
+}
+
+template <class T>
+bool TauVertexFinder::retrieveTool(T & tool) {
+    if (tool.retrieve().isFailure()) {
+        ATH_MSG_FATAL("Failed to retrieve tool " << tool);
+        return false;
+    } else {
+        ATH_MSG_VERBOSE("Retrieved tool " << tool);
+    }
+    return true;
+}
diff --git a/Reconstruction/tauRecTools/src/TauVertexFinder.h b/Reconstruction/tauRecTools/src/TauVertexFinder.h
new file mode 100644
index 0000000000000000000000000000000000000000..de30101ac0ea1b522a52a58993f13f7d5c819f75
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauVertexFinder.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUVERTEXFINDER_H
+#define TAUREC_TAUVERTEXFINDER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+#include "xAODTracking/VertexContainer.h"
+#include "JetEDM/TrackVertexAssociation.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+/** 
+ * @brief Associate a vertex (origin) to the tau candidate.
+ * 
+ *  The vertex has to be consistent with the origin of tau jet seed.
+ *  The vertex is determined in the following order: TJVA -> first PV in vertex container -> 0
+ *  Attention: all downstream tau variables will be calculated to the vertex set here!
+ * 
+ * @author KG Tan <Kong.Guan.Tan@cern.ch>
+ * @author Felix Friedrich <Felix.Friedrich@cern.ch>
+ */
+
+class TauVertexFinder : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor and Destructor
+    //-------------------------------------------------------------
+    TauVertexFinder(const std::string& name);
+    ASG_TOOL_CLASS2(TauVertexFinder, TauRecToolBase, ITauToolBase);
+    ~TauVertexFinder();
+
+    //-------------------------------------------------------------
+    //! Algorithm functions
+    //-------------------------------------------------------------
+    virtual StatusCode initialize();
+    virtual StatusCode eventInitialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventFinalize();
+    virtual StatusCode finalize();
+
+    virtual void cleanup(xAOD::TauJet* ) { }
+    virtual void print() const { }
+
+    ElementLink<xAOD::VertexContainer> getPV_TJVA(const xAOD::TauJet& tauJet, const xAOD::VertexContainer& vertices);
+
+private:
+    float getJetVertexFraction(const xAOD::Vertex* vertex, const std::vector<const xAOD::TrackParticle*>& tracks, const jet::TrackVertexAssociation* tva) const;
+        
+    //-------------------------------------------------------------
+    //! Convenience functions to handle storegate objects
+    //-------------------------------------------------------------
+    template <class T>
+    bool openContainer(T* &container, std::string containerName, bool printFATAL=false);
+
+    template <class T>
+    bool retrieveTool(T &tool);
+
+private:
+    bool m_printMissingContainerINFO;
+    float m_maxJVF;
+
+    //-------------------------------------------------------------
+    //! Configureables
+    //-------------------------------------------------------------
+    bool m_useTJVA;
+    std::string m_inputPrimaryVertexContainerName;
+    std::string m_assocTracksName;
+    std::string m_trackVertexAssocName;    
+};
+
+#endif // not TAUREC_TAUVERTEXFINDER_H
diff --git a/Reconstruction/tauRecTools/src/TauVertexVariables.cxx b/Reconstruction/tauRecTools/src/TauVertexVariables.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..ec30ed28c283d34821737f6a3f612dcd3ac5c633
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauVertexVariables.cxx
@@ -0,0 +1,339 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+
+#include "Particle/TrackParticle.h"
+#include "Particle/TrackParticleContainer.h"
+#include "TrkParameters/TrackParameters.h"
+
+#include "xAODTracking/TrackParticleContainer.h"
+
+#include "TrkVertexFitterInterfaces/ITrackToVertexIPEstimator.h"
+#include "TrkVertexFitterInterfaces/IVertexFitter.h"
+#include "TrkVertexFitterInterfaces/IVertexSeedFinder.h"
+#include "TrkVertexFitters/AdaptiveVertexFitter.h"
+#include "TrkVxEdmCnv/IVxCandidateXAODVertex.h"
+#include "TrkLinks/LinkToXAODTrackParticle.h"
+
+#include "tauRecTools/TauEventData.h"
+#include "TauVertexVariables.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+
+TauVertexVariables::TauVertexVariables(const std::string &name ) :
+  TauRecToolBase(name),
+  m_primaryVertexKey("PrimaryVertices"),
+  m_useOldSeedFinderAPI(false),
+  m_fitTool("Trk::AdaptiveVertexFitter"),
+  m_SeedFinder("Trk::CrossDistancesSeedFinder"),
+  m_xaodConverter("Trk::VxCandidateXAODVertex"),
+  m_pSecVtxContainer(0),
+  m_pSecVtxAuxContainer(0){
+  declareProperty("PrimaryVertexKey", m_primaryVertexKey);
+  declareProperty("TrackParticleContainer", m_inputTrackParticleContainerName = "InDetTrackParticles");
+  declareProperty("TrackToVertexIPEstimator", m_trackToVertexIPEstimator);
+  declareProperty("VertexFitter", m_fitTool);
+  declareProperty("SeedFinder", m_SeedFinder);
+  declareProperty("XAODConverter",m_xaodConverter);
+  declareProperty("useOldSeedFinderAPI",m_useOldSeedFinderAPI);
+	declareProperty("runOnAOD", m_AODmode);//AODS are input file 
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+
+TauVertexVariables::~TauVertexVariables() {
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializer
+//-----------------------------------------------------------------------------
+
+StatusCode TauVertexVariables::initialize() {
+	CHECK( m_trackToVertexIPEstimator.retrieve() );
+	CHECK( m_fitTool.retrieve() );
+	CHECK( m_SeedFinder.retrieve() );
+	if (m_useOldSeedFinderAPI) CHECK( m_xaodConverter.retrieve() );
+
+	if (m_useOldSeedFinderAPI) {
+		ATH_MSG_INFO("using AOD-style API of the AdaptiveVertexFitter");
+	}
+	else {
+		ATH_MSG_INFO("using new xAOD-style API of the AdaptiveVertexFitter");
+	}
+
+	return StatusCode::SUCCESS;
+}
+
+StatusCode TauVertexVariables::eventInitialize() {
+
+  bool inTrigger = tauEventData()->inTrigger();
+  
+  // Only store the vertex containers if we are offline?
+  if(!inTrigger)
+    {
+      // Secondary Vertex Container for tau decay vertex
+      if(!m_AODmode){
+	m_pSecVtxContainer = new xAOD::VertexContainer();
+	m_pSecVtxAuxContainer = new xAOD::VertexAuxContainer();
+	m_pSecVtxContainer->setStore( m_pSecVtxAuxContainer );
+      
+	CHECK( evtStore()->record( m_pSecVtxContainer, "TauSecondaryVertices" ) );
+	CHECK( evtStore()->record( m_pSecVtxAuxContainer, "TauSecondaryVerticesAux." ) );
+      }
+      else {
+	CHECK( evtStore()->retrieve( m_pSecVtxContainer, "TauSecondaryVertices") );
+	CHECK( evtStore()->retrieve( m_pSecVtxAuxContainer, "TauSecondaryVerticesAux.") );
+      }
+    }
+  
+  return StatusCode::SUCCESS;
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Finalizer
+//-----------------------------------------------------------------------------
+StatusCode TauVertexVariables::finalize() {
+	return StatusCode::SUCCESS;
+}
+
+
+//-----------------------------------------------------------------------------
+// Execution
+//-----------------------------------------------------------------------------
+StatusCode TauVertexVariables::execute(xAOD::TauJet& pTau) {
+
+	ATH_MSG_DEBUG("executing TauVertexVariables");
+
+	// for tau trigger
+	bool inTrigger = tauEventData()->inTrigger();
+	if (inTrigger) ATH_MSG_DEBUG("We're in the Trigger");
+	
+	// impact parameter variables for standard tracks
+	if (pTau.nTracks() > 0) {
+
+	  const Trk::ImpactParametersAndSigma* myIPandSigma(0);
+	  const xAOD::Vertex* vxcand = nullptr;
+	  
+	  if (inTrigger) {
+	  
+	    StatusCode scBeam = StatusCode::FAILURE;
+	  
+	    if (tauEventData()->hasObject("Beamspot")) scBeam = tauEventData()->getObject("Beamspot", vxcand);
+
+	    if(scBeam){
+	      myIPandSigma = m_trackToVertexIPEstimator->estimate(pTau.track(0), vxcand);
+	    } else {
+	      ATH_MSG_DEBUG("No Beamspot object in tau candidate");
+	    }
+	  
+	  }  else if (pTau.vertexLink()) {
+
+	    vxcand = *(pTau.vertexLink()) ;
+
+	    //check if vertex has a valid type (skip if vertex has type NoVtx)
+	    if (vxcand->vertexType() > 0){
+	      myIPandSigma = m_trackToVertexIPEstimator->estimate(pTau.track(0), vxcand);
+	    }
+
+	  }
+	  
+	  if (myIPandSigma != 0) {
+	    pTau.setDetail(xAOD::TauJetParameters::ipSigLeadTrk, (float)( myIPandSigma->IPd0 / myIPandSigma->sigmad0 ));
+	    pTau.setDetail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, (float)( myIPandSigma->IPz0SinTheta / myIPandSigma->sigmaz0SinTheta ));
+	  } else {
+	    ATH_MSG_DEBUG("trackToVertexIPestimator failed for a standard track!");
+	    pTau.setDetail(xAOD::TauJetParameters::ipSigLeadTrk, (float)(-999.));
+	    pTau.setDetail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, (float)(-999.));
+	  }
+	  
+	  delete myIPandSigma;
+
+	} else {
+
+	  ATH_MSG_DEBUG("Tau has no tracks");
+
+	}
+
+
+	float ipSigLeadTrk;
+	float ipZ0SinThetaSigLeadTrk;
+
+	if (pTau.detail(xAOD::TauJetParameters::ipSigLeadTrk, ipSigLeadTrk))
+		ATH_MSG_VERBOSE("IP significance lead track " << ipSigLeadTrk);
+	if (pTau.detail(xAOD::TauJetParameters::ipZ0SinThetaSigLeadTrk, ipZ0SinThetaSigLeadTrk))
+		ATH_MSG_VERBOSE("IP Z0 significance lead track " << ipZ0SinThetaSigLeadTrk);
+
+	//try to find secondary vertex
+	//look for secondary vertex if more than 1 track
+	pTau.setDetail(xAOD::TauJetParameters::trFlightPathSig, (float)(-1111.));
+	if (pTau.nTracks() < 2) {
+		return StatusCode::SUCCESS;
+	}
+
+	const xAOD::VertexContainer* vxContainer = 0;
+	StatusCode sc=StatusCode::SUCCESS;
+	if (sc.isSuccess() && inTrigger)   sc = tauEventData()->getObject("VxPrimaryCandidate", vxContainer);
+	// retrieve vertex container, exit if not found
+	else sc = evtStore()->retrieve(vxContainer, m_primaryVertexKey);
+
+	if (sc.isFailure() || !vxContainer) {
+		ATH_MSG_WARNING("No vertex container found. Skipping secondary vertex fitting.");
+		return StatusCode::SUCCESS;
+	}
+
+	const xAOD::TrackParticleContainer* trackParticleCont = 0;
+	if (inTrigger)   sc = tauEventData()->getObject( "TrackContainer", trackParticleCont );
+	// retrieve track particle container, exit if not found
+	else sc = evtStore()->retrieve(trackParticleCont, m_inputTrackParticleContainerName);
+	if (sc.isFailure() || !trackParticleCont) {
+		ATH_MSG_WARNING("No track particle container found. Skipping secondary vertex fitting.");
+		return StatusCode::SUCCESS;
+	}
+
+	// get xAOD TrackParticles and Trk::Tracks
+	std::vector<const xAOD::TrackParticle*> xaodTracks;
+	std::vector<const Trk::Track*> origTracks;
+	for (unsigned i = 0; i < pTau.nTracks(); ++i) {
+		xaodTracks.push_back(pTau.track(i));
+		ATH_MSG_VERBOSE("xAOD::TrackParticle " <<i<<": "<< pTau.track(i)->pt() << " "  << pTau.track(i)->eta()  << " "  << pTau.track(i)->phi());
+		if (pTau.track(i)->track()) {
+			origTracks.push_back(pTau.track(i)->track());
+
+			// for debugging
+			/*
+            ATH_MSG_DEBUG("Trk::Track " <<i<<": "<< (*pTau.track(i)->track())->pt() << " "  << (*pTau.track(i)->track())->eta()  << " "  << (*pTau.track(i)->track())->phi());
+            const Trk::TrackParameters * tmpMeasPer = (*pTau.track(i)->track())->perigeeParameters();
+			const AmgSymMatrix(5)* cov = tmpMeasPer->covariance();
+			ATH_MSG_DEBUG("   TrackParameters: pT="<< tmpMeasPer->pT() << ", eta="  << tmpMeasPer->eta()  << ", x="  << tmpMeasPer->position().x() << ", y="<< tmpMeasPer->position().y() <<", z="<< tmpMeasPer->position().z());
+			ATH_MSG_DEBUG("   covariance ="<< *cov);
+			 */
+			// for debugging
+		}
+		else {
+			ATH_MSG_WARNING("no Trk::Track for xAOD::TrackParticle");
+		}
+	}
+
+	// get the starting point for the fit using Trk::Tracks
+	Trk::Vertex* seedPoint = new Trk::Vertex(m_SeedFinder->findSeed(origTracks));
+	ATH_MSG_VERBOSE("seedPoint x/y/perp=" << seedPoint->position().x() << " "<< seedPoint->position().y() << " "<< seedPoint->position().perp());
+	if (!seedPoint) {
+		ATH_MSG_WARNING("no seedPoint: Can not calculate secondary vertex!");
+		return StatusCode::SUCCESS;
+	}
+
+	// fitting the vertex itself
+	xAOD::Vertex* xAODvertex(0);
+	if (!m_useOldSeedFinderAPI) { // use new xAOD API of VertexFitter
+		xAODvertex = m_fitTool->fit(xaodTracks, *seedPoint);
+		if (xAODvertex && !inTrigger) {
+			ATH_MSG_VERBOSE("using new xAOD API: Secondary Vertex found and recorded! x="<<xAODvertex->position().x()<< ", y="<<xAODvertex->position().y()<<", perp="<<xAODvertex->position().perp());
+			m_pSecVtxContainer->push_back(xAODvertex);
+		}
+	}
+	else { // use standard AOD-style API of VertexFitter
+		Trk::VxCandidate* tmpVxCandidate = m_fitTool->fit(origTracks, *seedPoint);
+		if (tmpVxCandidate) {
+			ATH_MSG_VERBOSE("using old AOD API:Secondary Vertex found and recorded! x="<<tmpVxCandidate->recVertex().position().x()<< ", y="<<tmpVxCandidate->recVertex().position().y()<<", perp="<<tmpVxCandidate->recVertex().position().perp());
+
+			//******************************************************************
+			// convert VxCandidate to xAOD::Vertex
+			//******************************************************************
+
+			// assigning the input xAOD tracks to the fitted vertex
+			// this means: after that procedure the Trk::VxCandidate knows already the links to the xAOD tracks (which have to be identical with the Trk:Tracks used in the VertexFitter!)
+			// this is needed for the converting, otherwise the new xAODVertex don't have the track links
+			if(tmpVxCandidate->vxTrackAtVertex() != 0 && tmpVxCandidate->vxTrackAtVertex()->size() !=0) {
+				for(unsigned int i = 0; i <xaodTracks.size(); ++i) {
+					Trk::LinkToXAODTrackParticle * linkTT = new Trk::LinkToXAODTrackParticle;
+					linkTT->setElement(xaodTracks[i]);
+					linkTT->setStorableObject(*trackParticleCont);
+					// vxtrackatvertex takes ownership!
+					(*(tmpVxCandidate->vxTrackAtVertex()))[i]->setOrigTrack(linkTT);
+				}
+			}
+
+			xAODvertex = new xAOD::Vertex();
+			if (!inTrigger) m_pSecVtxContainer->push_back(xAODvertex);
+			// perform the final converting now
+			if( m_xaodConverter->createXAODVertex(*tmpVxCandidate,xAODvertex).isFailure() ) {
+				ATH_MSG_ERROR("Failed to create xAODVertex for VxCandidate. Don't set any secondary vertex for tau!");
+				return StatusCode::SUCCESS;
+			}
+			delete tmpVxCandidate;
+		}
+	}
+	delete seedPoint;
+
+	if (!xAODvertex) {
+		ATH_MSG_WARNING("no secondary vertex found!");
+		return StatusCode::SUCCESS;
+	}
+
+	// get the transverse flight path significance
+	float trFlightPS = trFlightPathSig(pTau, *xAODvertex);
+	pTau.setDetail(xAOD::TauJetParameters::trFlightPathSig, (float)(trFlightPS));
+	ATH_MSG_VERBOSE("transverse flight path significance="<<trFlightPS);
+
+	// Note, we only attach the 2nd vertex if at offline, otherwise, break the trigger persistency
+	if  (!inTrigger) {
+		pTau.setSecondaryVertex(m_pSecVtxContainer, xAODvertex); 		// set the link to the vertex
+	}
+	else {
+		delete xAODvertex; // delete the vertex when in trigger mode, because we can not save it
+	}
+
+	return StatusCode::SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// calculate the transverse flight path significance
+//-------------------------------------------------------------------------
+double TauVertexVariables::trFlightPathSig(const xAOD::TauJet& pTau, const xAOD::Vertex& secVertex) {
+
+	const xAOD::Vertex* pVertex = 0;
+	if (pTau.vertexLink()) pVertex = *pTau.vertexLink();
+	if (!pVertex) {
+		ATH_MSG_WARNING("No primary vertex information for calculation of transverse flight path significance");
+		return -11111.;
+	}
+
+	double fpx = secVertex.position().x() - pVertex->position().x();
+	double fpy = secVertex.position().y() - pVertex->position().y();
+	double fpt = (secVertex.position() - pVertex->position()).perp();
+
+	if (fpt == 0) {
+		ATH_MSG_WARNING("delta pt of (secVtx - priVtx) is 0!");
+		return -11111.;
+	}
+
+	double sigma_fpt2 = (fpx * fpx * secVertex.covariancePosition()(Trk::x, Trk::x) +
+			fpx * fpy * secVertex.covariancePosition()(Trk::x, Trk::y) +
+			fpy * fpx * secVertex.covariancePosition()(Trk::y, Trk::x) +
+			fpy * fpy * secVertex.covariancePosition()(Trk::y, Trk::y)) / (fpt * fpt);
+
+	if (sigma_fpt2 <= 0) {
+		ATH_MSG_WARNING("sigma delta pt of (secVtx - priVtx) is 0!");
+		return -11111.;
+	}
+
+	double sigma_fpt = sqrt(sigma_fpt2);
+	double sign = 0;
+
+	if (fpx * pTau.p4().Px() + fpy * pTau.p4().Py() > 0.) sign = 1.;
+	else sign = -1.;
+
+	//ATH_MSG_INFO(sign << " " <<fpt << " " << sigma_fpt << " " << sign * fpt / sigma_fpt);
+	return sign * fpt / sigma_fpt;
+}
+
diff --git a/Reconstruction/tauRecTools/src/TauVertexVariables.h b/Reconstruction/tauRecTools/src/TauVertexVariables.h
new file mode 100644
index 0000000000000000000000000000000000000000..54789149c51d708049c60494798fe73b1cfb182c
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/TauVertexVariables.h
@@ -0,0 +1,67 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUVERTEXVARIABLES_H
+#define	TAUREC_TAUVERTEXVARIABLES_H
+
+#include "xAODTracking/VertexContainer.h"
+#include "xAODTracking/VertexAuxContainer.h"
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+
+// forwards
+class TauEventData;
+namespace Trk {
+	class ITrackToVertexIPEstimator;
+    class IVertexFitter;
+    class IVertexSeedFinder;
+    class IVxCandidateXAODVertex;
+}
+
+/**
+ *  
+ * @brief Class for calculating vertex variables.
+ *
+ * @authors Stan Lai, Felix Friedrich
+ */
+
+class TauVertexVariables : virtual public TauRecToolBase {
+public:
+    //-----------------------------------------------------------------
+    // Constructor and destructor
+    //-----------------------------------------------------------------
+    TauVertexVariables(const std::string& name);
+    ASG_TOOL_CLASS2(TauVertexVariables, TauRecToolBase, ITauToolBase);
+    ~TauVertexVariables();
+    
+    virtual StatusCode initialize();
+    virtual StatusCode execute(xAOD::TauJet&);
+    virtual StatusCode eventInitialize();
+    virtual StatusCode finalize();
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+    
+    //-------------------------------------------------------------
+    //! determines the transverse flight path significance from
+    //! the primary vertex and the secondary vertex of tau candidate
+    //-------------------------------------------------------------
+    double trFlightPathSig(const xAOD::TauJet& pTau, const xAOD::Vertex& secVertex);
+
+private:
+    std::string m_primaryVertexKey;
+    std::string m_inputTrackParticleContainerName;
+    bool m_useOldSeedFinderAPI;
+    bool m_AODmode;
+    ToolHandle< Trk::ITrackToVertexIPEstimator > m_trackToVertexIPEstimator;
+    ToolHandle< Trk::IVertexFitter >     m_fitTool; //!< Pointer to the base class of the fit algtools
+    ToolHandle< Trk::IVertexSeedFinder > m_SeedFinder;
+    ToolHandle< Trk::IVxCandidateXAODVertex > m_xaodConverter;  // necessary to convert VxCandidate to xAOD::Vertex in case old API is used
+
+    xAOD::VertexContainer* m_pSecVtxContainer;
+    xAOD::VertexAuxContainer* m_pSecVtxAuxContainer;
+};
+
+#endif	/* TAUREC_TAUVERTEXVARIABLES_H */
+
diff --git a/Reconstruction/tauRecTools/src/components/tauRecTools_entries.cxx b/Reconstruction/tauRecTools/src/components/tauRecTools_entries.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..905298fe21a84add140340d726ddce784cc7660e
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/components/tauRecTools_entries.cxx
@@ -0,0 +1,62 @@
+#include "../JetSeedBuilder.h"
+#include "../LockTauContainers.h"
+#include "../TauAxisSetter.h"
+#include "../TauCalibrateEM.h"
+#include "tauRecTools/TauCalibrateLC.h"
+#include "tauRecTools/TauIDPileupCorrection.h"
+#include "../TauCellVariables.h"
+#include "../TauTrackFinder.h"
+#include "../TauVertexFinder.h"
+#include "../TauElectronVetoVariables.h"
+#include "tauRecTools/TauCommonCalcVars.h"
+#include "../TauShotFinder.h"
+#include "../TauPi0ClusterCreator.h"
+#include "../TauPi0CreateROI.h"
+#include "../TauPi0ClusterScaler.h"
+#include "../TauPi0ScoreCalculator.h"
+#include "../TauPi0Selector.h"
+#include "../TauSubstructureVariables.h"
+#include "../TauConversionFinder.h"
+#include "../PhotonConversionPID.h"
+#include "../PhotonConversionVertex.h"
+#include "../TauConversionTagger.h"
+#include "../TauVertexVariables.h"
+#include "../tauCalibrateWeightTool.h"  //for trigger
+#include "tauRecTools/TauTrackFilter.h"
+#include "tauRecTools/TauGenericPi0Cone.h"
+#include "../TauTestDump.h"
+#include "tauRecTools/TauProcessorTool.h"
+#include "tauRecTools/TauBuilderTool.h"
+
+
+#include "GaudiKernel/DeclareFactoryEntries.h"
+
+DECLARE_TOOL_FACTORY( JetSeedBuilder             )
+DECLARE_TOOL_FACTORY( LockTauContainers          )
+DECLARE_TOOL_FACTORY( TauAxisSetter         )
+DECLARE_TOOL_FACTORY( TauCalibrateEM             )
+DECLARE_TOOL_FACTORY( TauCalibrateLC             )
+DECLARE_TOOL_FACTORY( TauIDPileupCorrection             )
+DECLARE_TOOL_FACTORY( TauCellVariables           )
+DECLARE_TOOL_FACTORY( TauTrackFinder             )
+DECLARE_TOOL_FACTORY( TauVertexFinder            )
+DECLARE_TOOL_FACTORY( TauElectronVetoVariables             )
+DECLARE_TOOL_FACTORY( TauCommonCalcVars          )
+DECLARE_TOOL_FACTORY( TauShotFinder              )
+DECLARE_TOOL_FACTORY( TauPi0ClusterCreator   )
+DECLARE_TOOL_FACTORY( TauPi0CreateROI        )
+DECLARE_TOOL_FACTORY( TauPi0ClusterScaler  )
+DECLARE_TOOL_FACTORY( TauPi0ScoreCalculator  )
+DECLARE_TOOL_FACTORY( TauPi0Selector        )
+DECLARE_TOOL_FACTORY( TauSubstructureVariables     )
+DECLARE_TOOL_FACTORY( PhotonConversionPID )
+DECLARE_TOOL_FACTORY( PhotonConversionVertex )
+DECLARE_TOOL_FACTORY( TauConversionFinder )
+DECLARE_TOOL_FACTORY( TauConversionTagger )
+DECLARE_TOOL_FACTORY( TauVertexVariables )
+DECLARE_TOOL_FACTORY( tauCalibrateWeightTool )
+DECLARE_TOOL_FACTORY( TauTrackFilter )
+DECLARE_TOOL_FACTORY( TauGenericPi0Cone )
+DECLARE_TOOL_FACTORY( TauTestDump )
+DECLARE_TOOL_FACTORY( TauProcessorTool             )
+DECLARE_TOOL_FACTORY( TauBuilderTool             )
diff --git a/Reconstruction/tauRecTools/src/components/tauRecTools_load.cxx b/Reconstruction/tauRecTools/src/components/tauRecTools_load.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..6b1c2188830c28bd0ce8c55d51143773b065ebdd
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/components/tauRecTools_load.cxx
@@ -0,0 +1,4 @@
+#include "GaudiKernel/LoadFactoryEntries.h"
+
+LOAD_FACTORY_ENTRIES(tauRecTools)
+
diff --git a/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.cxx b/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..d0fb365cadef91089c65782ace0d850fa2e868ab
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.cxx
@@ -0,0 +1,391 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+/********************************************************************
+(depreciated!)
+
+NAME:     tauCalibrateWeightTool.cxx
+PACKAGE:  offline/Reconstruction/tauRec
+
+AUTHORS:  M.Heldmann
+CREATED:  March 22, 2005
+MODIFIED: July 15, 2005 ( Include pT dependent correction )
+23/10/2006 - (AK) fixing some compilation warnings (unused parameter)
+18/04/2007 - (AK) fixing some compilation warnings (unused parameter)
+29/06/2007 - (SL) fixing some compilation warnings
+13/12/2008 - (AK) change to extrapolation of TP instead of Track+code cleaning
+16/03/2010 - (AK) use the cell id instead of the pointer
+17/03/2010 - (AK) change to P4Helpers
+14/12/2011 - (FF) change to use tau axis  and numTrack (not seedCalo_)
+ ********************************************************************/
+#include "tauRecTools/TauEventData.h"
+#include "tauEvent/TauCommonDetails.h"
+#include "CaloEvent/CaloCluster.h"
+#include "CaloEvent/CaloCell.h"
+#include "AtlasDetDescr/AtlasDetectorID.h"
+#include "CaloIdentifier/CaloID.h"
+#include "CaloGeoHelpers/CaloSampling.h"
+
+#include "CLHEP/Units/SystemOfUnits.h"
+
+// INCLUDE GAUDI HEADER FILES:
+#include "GaudiKernel/Property.h"
+#include "AIDA/IHistogram1D.h"
+
+#include <algorithm> 
+#include <math.h>
+
+#include "FourMomUtils/P4Helpers.h"
+#include "FourMom/P4EEtaPhiM.h"
+
+#include "CaloInterface/IHadronicCalibrationTool.h"
+#include "TF1.h"
+
+#include "tauCalibrateWeightTool.h"
+/********************************************************************/
+
+tauCalibrateWeightTool::tauCalibrateWeightTool(const std::string& name) :
+    TauRecToolBase(name),
+    m_calibrateType( tauCalibrateWeightTool::calCells ),
+    m_caloWeightTool(this),
+    m_cellWeightTool("CellWeightTool2004"),
+    m_applyCellWeightEM(true),
+    m_applyCellWeightHad(true),
+    m_applyPtEtaCorrFactors(true),
+    m_validCaloWeightTool(true),
+    m_doEtaInterpolation(false),
+    m_cellCone(0.4)
+{
+    declareProperty( "calibrateType", m_calibrateType );
+    // Calibration Tool 
+    declareProperty("CellWeightTool",m_cellWeightTool);
+    declareProperty("ApplyCellWeightEM", m_applyCellWeightEM);
+    declareProperty("ApplyCellWeightHad", m_applyCellWeightHad);
+    declareProperty("ApplyPtEtaCorrFactors", m_applyPtEtaCorrFactors);
+    declareProperty("pTNumberOfBins", m_nptbins );
+    declareProperty("etaNumberOfBins", m_netabins );
+
+    declareProperty("pTPoints",m_ptpoints=std::vector<float>(10,0));
+    declareProperty("etaPoints",m_etapoints=std::vector<float>(10,0));
+    declareProperty("pTetaCorrectionsNtr1",m_ptetacorrectionsntr1=std::vector<float>(100,0));
+    declareProperty("pTetaCorrectionsNtr23",m_ptetacorrectionsntr23=std::vector<float>(100,0));
+
+    declareProperty("FudgeFactor",m_fudge=1);
+    declareProperty("DoEtaInterpolation", m_doEtaInterpolation);
+    declareProperty("CellCone",m_cellCone);
+    declareProperty("CaloWeightTool",m_caloWeightTool);
+}
+
+tauCalibrateWeightTool::~tauCalibrateWeightTool()
+{ 
+}
+
+StatusCode tauCalibrateWeightTool::initialize()
+{ 
+    StatusCode sc;
+    ATH_MSG_INFO( "Calibrating using fitted weights. " );
+
+    // retrieve all helpers from det store
+    sc = detStore()->retrieve(m_emid);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR( "Unable to retrieve LArEM_ID helper from DetectorStore" );
+        return sc;
+    }
+
+    sc = detStore()->retrieve(m_tileid);
+    if (sc.isFailure()) {
+        ATH_MSG_ERROR( "Unable to retrieve TileID helper from DetectorStore" );
+        return sc;
+    }
+
+    // Tool service
+    IToolSvc* myToolSvc;
+    sc = service("ToolSvc",myToolSvc);
+    if ( sc.isFailure() ) {				        
+        ATH_MSG_FATAL( "Tool Service not found" );
+        return StatusCode::FAILURE;         
+    }
+
+    // Fetch cell weight tool
+    sc = m_caloWeightTool.retrieve();
+    if ( sc.isFailure() ) {
+        ATH_MSG_ERROR( "Cannot find tool named <" << m_cellWeightTool << ">" );
+        m_validCaloWeightTool = false;         
+
+        return StatusCode::FAILURE;
+    }
+    else {
+        if( m_caloWeightTool != 0 ) {
+            ATH_MSG_INFO( "Will use the CaloWeightTool named: " << m_cellWeightTool );
+            m_validCaloWeightTool = true; 
+        }
+    }
+
+    if ( (int)m_ptpoints.size() != m_nptbins || (int)m_etapoints.size() != m_netabins ) {
+        ATH_MSG_FATAL( "wrong number of points for interpolation" );
+        return StatusCode::FAILURE;
+    }
+
+    for ( int i = 0; i < m_nptbins - 1; ++i ) {
+        if ( m_ptpoints[i] >= m_ptpoints[i+1]) {
+            ATH_MSG_FATAL( "Correction factor coordinates must be ordered in Pt and unique" );
+            return StatusCode::FAILURE;
+        }
+    }
+    m_ptpoints.push_back(0);     //makes the boundary conditions easyer to handle
+
+    for ( int i = 0; i < m_netabins - 1; ++i ) {
+        if ( m_etapoints[i] >= m_etapoints[i+1]) {
+            ATH_MSG_FATAL( "Correction factor coordinates must be ordered in eta and unique" );
+            return StatusCode::FAILURE;
+        }
+    }
+    m_etapoints.push_back(0);
+
+    if ( (int)m_ptetacorrectionsntr1.size() != (m_nptbins * m_netabins) ) {
+        ATH_MSG_FATAL( "Wrong number of correction factors for 1 Track" );
+        return StatusCode::FAILURE;
+    }
+
+    if ( (int)m_ptetacorrectionsntr23.size() != (m_nptbins * m_netabins) ) {
+        ATH_MSG_FATAL( "Wrong number of correction factors for 2 and 3 Tracks" );
+        return StatusCode::FAILURE;
+    }
+
+    return StatusCode::SUCCESS;
+}
+
+/********************************************************************/
+StatusCode tauCalibrateWeightTool::execute(xAOD::TauJet&)
+{ 
+	/*
+	 * FF: March 2014
+	 * This Tool is not migrated yet to xAOD. Unclear if still needed. Only client was TauTrigger.
+	 * FF will investigate.
+	 *
+	 *
+    Analysis :: TauJet *tau = data->tau;
+    Analysis :: TauCommonDetails *details = dynamic_cast<Analysis :: TauCommonDetails *>(data->details);
+
+    // Detector identifiers
+    AtlasDetectorID AtlasID;
+
+    // Variables for sums
+    double sumEM = 0;
+    double sumE = 0;
+    double sumAccb3 = 0;
+    double sumHad = 0;
+    double sumTile1 = 0;
+
+    double sumScint = 0;
+    double sumGap   = 0;
+
+    double dR;
+
+    // loop over all cells of the tau (placed there by the tauSeedBuilder)
+    typedef NavigationToken<CaloCell,NavigationDefaults::DefaultWeight,CaloCellIDFcn> token_t;
+    token_t nt;
+
+    pTau.fillToken( nt );
+
+    token_t::const_iterator nt_iter = nt.begin();
+    token_t::const_iterator nt_end = nt.end();
+
+    const CaloCell *cell;
+
+    double etaSeed = pTau.eta(); //FF  details->seedCalo_eta();
+    double phiSeed = pTau.phi(); //FF  details->seedCalo_phi();
+
+    P4EEtaPhiM P4Seed( 1., etaSeed, phiSeed, 0. );	
+
+    for ( ; nt_iter != nt_end; nt_iter++ ) {
+        cell = (*nt_iter);
+
+        // Cell ET and index for ET range
+        // This is made symmetric around zero so that noise (not yet included)
+        // does not produce a shift.
+        double cellET = cell->et();
+
+        CaloSampling::CaloSample calo = cell->caloDDE()->getSampling();
+
+        // Use cells that are in DR < m_cellCone of eta,phi of jet:
+        dR = P4Helpers::deltaR( P4Seed, cell->eta(), cell->phi() );
+
+        if ( dR < m_cellCone ) {
+            double calWeight = 1.;
+
+            // Check which kind of calib tools have been selected
+            // and Get calibration weight 
+
+            if (m_validCaloWeightTool) calWeight = m_caloWeightTool->wtCell( cell ); 
+
+            sumE += cell->e();
+
+            switch ( calo ) {
+                case CaloSampling::PreSamplerB:
+                case CaloSampling::PreSamplerE:
+                case CaloSampling::EMB1:
+                case CaloSampling::EME1:
+                case CaloSampling::EMB2:
+                case CaloSampling::EME2:
+                    sumEM += (m_applyCellWeightEM ? calWeight*cellET : cellET);
+                    break;
+                case CaloSampling::EMB3:
+                    sumAccb3 += cellET;
+
+                case CaloSampling::EME3:
+                    // Only include first two EM layers in EM sum; add third to HAD
+                    // Keep track of ACCB3 for cryostat correction below
+                    sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET);
+                    break;
+
+                case CaloSampling::TileBar0:
+                    sumTile1 += cellET;
+
+                case CaloSampling::TileBar1:
+                case CaloSampling::TileBar2:
+                    sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET);
+                    break;
+                case CaloSampling::TileExt0:
+                case CaloSampling::TileExt1:
+                case CaloSampling::TileExt2:
+                    sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET);
+                    break;
+                case CaloSampling::TileGap1:      
+                    // scintillator ?
+                    // Gap Scintillator is included in Gap
+                    // Hence do NOT add it separately
+                    // MH I don't know what's it like now .... but I guess its seperated
+                    sumScint += cellET;
+                case CaloSampling::TileGap2:
+                case CaloSampling::TileGap3:
+                    sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET);
+                    sumGap += cellET;
+                    break;
+                case CaloSampling::HEC0:
+                case CaloSampling::HEC1:
+                case CaloSampling::HEC2:
+                case CaloSampling::HEC3:
+                    sumHad += (m_applyCellWeightHad ? calWeight*cellET : cellET);
+                    break;
+                case CaloSampling::FCAL0:
+                case CaloSampling::FCAL1:
+                case CaloSampling::FCAL2:
+	        case CaloSampling::MINIFCAL0:
+	        case CaloSampling::MINIFCAL1:
+	        case CaloSampling::MINIFCAL2:
+	        case CaloSampling::MINIFCAL3:
+                case CaloSampling::Unknown:
+                    break;
+            }
+        }         // end dR cut
+        else
+        {
+            ATH_MSG_VERBOSE( "cell with energy " << cell->e() << " outside of cell cone" );
+        }
+
+    }         // end cell loop
+
+    // Cryostat correction uses geometric mean of last layer of EM and
+    // first layer of tile:
+
+    if(sumAccb3<0.) sumAccb3=0.;
+    if(sumTile1<0.) sumTile1=0.;
+
+    double wtCryo = 1.;    
+
+    if (m_validCaloWeightTool) wtCryo = m_caloWeightTool->wtCryo();
+    double sumCryo = (m_applyCellWeightHad ? wtCryo*sqrt(sumAccb3*sumTile1) : sqrt(sumAccb3*sumTile1));
+
+    // Weight fudge factor. The H1 weights are taken to be independent of
+    // eta. This factor is applied to the hadronic energy to produce a
+    // more uniform response.
+
+    details->setSeedCalo_etEMCalib(sumEM);
+    details->setSeedCalo_etHadCalib((sumHad+sumCryo));
+
+    double et = details->seedCalo_etEMCalib()+details->seedCalo_etHadCalib();
+    double eta = fabs( etaSeed );
+    double corr = 1;
+
+    if (m_applyPtEtaCorrFactors) {    
+
+        ATH_MSG_VERBOSE( "energy: " << details->seedCalo_etEMCalib() << " " <<details->seedCalo_etHadCalib() << " " << sumEM <<" "<<sumHad<<" "<<sumCryo );
+
+        int lowpt_idx = 0;
+        int loweta_idx = 0;
+
+        double lowpt_frac = 0;
+        double loweta_frac = 0;
+
+        while ( lowpt_idx < m_nptbins-1 && et > m_ptpoints[lowpt_idx+1] )
+            lowpt_idx++;
+
+        lowpt_frac = ( m_ptpoints[lowpt_idx+1] - et ) / ( m_ptpoints[lowpt_idx+1] - m_ptpoints[lowpt_idx] );   // will be >1 if et is out of bounds
+
+        if ( lowpt_frac > 1 )
+            lowpt_frac =  1;
+        if( lowpt_frac < 0 ) {   //should never happen, only if ptNumberOfBins is set wrong (which is checked now)
+            ATH_MSG_ERROR( "FIXME: lowpt_frac < 0 !!" );
+        }
+
+        while ( loweta_idx < m_netabins-1 && eta > m_etapoints[loweta_idx+1] )
+            loweta_idx++;
+
+        if(m_doEtaInterpolation)
+            loweta_frac = ( m_etapoints[loweta_idx+1] - eta ) / ( m_etapoints[loweta_idx+1] - m_etapoints[loweta_idx] );   // will be >1 if eta is out of bounds, 
+        else
+            loweta_frac = 1;    
+
+        if ( loweta_frac > 1)
+            loweta_frac = 1;
+        if( loweta_frac < 0 ) {    //should never happen, only if etaNumberOfBins is set wrong
+            ATH_MSG_ERROR( "FIXME: loweta_frac < 0 !!" );
+        }
+
+        double coeff_matrix[2][2] = { {0, 0}, {0, 0} };
+
+        //FF changed from seeddCalo_numTrack to numTrack
+        if ( pTau.numTrack() <= 1 ) {
+            coeff_matrix[0][0] = m_ptetacorrectionsntr1[lowpt_idx*m_netabins+loweta_idx];
+            if( lowpt_idx < m_nptbins-1 )
+                coeff_matrix[1][0] = m_ptetacorrectionsntr1[(lowpt_idx+1)*m_netabins+loweta_idx];
+            if( loweta_idx < m_netabins-1 )
+                coeff_matrix[0][1] = m_ptetacorrectionsntr1[lowpt_idx*m_netabins+(loweta_idx+1)];
+            if( lowpt_idx < m_nptbins-1 && loweta_idx < m_netabins-1 )
+                coeff_matrix[1][1] = m_ptetacorrectionsntr1[(lowpt_idx+1)*m_netabins+(loweta_idx+1)];
+        } else {
+            coeff_matrix[0][0] = m_ptetacorrectionsntr23[lowpt_idx*m_netabins+loweta_idx];
+            if( lowpt_idx < m_nptbins-1 )
+                coeff_matrix[1][0] = m_ptetacorrectionsntr23[(lowpt_idx+1)*m_netabins+loweta_idx];
+            if( loweta_idx < m_netabins-1 )
+                coeff_matrix[0][1] = m_ptetacorrectionsntr23[lowpt_idx*m_netabins+(loweta_idx+1)];
+            if( lowpt_idx < m_nptbins-1 && loweta_idx < m_netabins-1 )
+                coeff_matrix[1][1] = m_ptetacorrectionsntr23[(lowpt_idx+1)*m_netabins+(loweta_idx+1)];
+        }
+
+        corr = ( coeff_matrix[0][0] * lowpt_frac * loweta_frac ) + ( coeff_matrix[1][0] * (1-lowpt_frac) * loweta_frac );
+        corr += ( coeff_matrix[0][1] * lowpt_frac * (1-loweta_frac) ) + ( coeff_matrix[1][1] * (1-lowpt_frac) * (1-loweta_frac) );
+
+    } // end if (m_applyPtEtaCorrFactors)
+
+    ATH_MSG_VERBOSE( "corrected energy: " << et << "*" << corr << "=" << et*corr );
+
+
+    //pTau.setE( et*cosh( details->seedCalo_eta() )*corr*m_fudge );
+	*/
+
+    //return StatusCode::SUCCESS;
+	// print error so that everybody knows this tool isn't working in case it is called.
+	ATH_MSG_ERROR( "This Tool is not yet migrated to xAOD!" );
+	return StatusCode::SUCCESS;
+}
+
+//-----------------------------------------------------------------------------
+// Finalize
+//-----------------------------------------------------------------------------
+StatusCode tauCalibrateWeightTool :: finalize()
+{
+    return StatusCode :: SUCCESS;
+}
diff --git a/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.h b/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..2300acfe756992b9990a1a7bd58072877425d212
--- /dev/null
+++ b/Reconstruction/tauRecTools/src/tauCalibrateWeightTool.h
@@ -0,0 +1,82 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCALIBRATEWEIGHTTOOL_H
+#define TAUREC_TAUCALIBRATEWEIGHTTOOL_H
+/********************************************************************
+(depreciated!)
+
+NAME:     tauCalibrateWeightTool.h
+PACKAGE:  offline/Reconstruction/tauRec
+AUTHORS:  M.Heldmann
+CREATED:  March 15, 2005
+
+See comments in tauCalibrateWeightTool.cxx.
+
+13/12/2008 - (AK) change to extrapolation of TP instead of Track+code cleaning
+ ********************************************************************/
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "GaudiKernel/ToolHandle.h"
+
+
+class TauEventData;
+class LArEM_ID;
+class TileID;
+//namespace AIDA {
+//class IHistogram1D;
+//}
+class IHadronicCalibrationTool;
+
+//-------------------------------------------------------------
+//! Class for applying H1-weighting on calorimeter cells and fudge factor for tau energy
+//-------------------------------------------------------------
+class tauCalibrateWeightTool : virtual public TauRecToolBase
+{
+    public:
+        enum calibrateType { calCells = 0, calJets, calTracks, calCluster, calTopocluster };
+
+        tauCalibrateWeightTool(const std::string& name);
+	ASG_TOOL_CLASS2(tauCalibrateWeightTool, TauRecToolBase, ITauToolBase);
+        ~tauCalibrateWeightTool();
+
+        virtual StatusCode initialize();
+        virtual StatusCode finalize();
+        virtual StatusCode execute(xAOD::TauJet& pTau);
+	virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+	virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+	virtual void print() const { }
+
+        // Accessor methods:
+
+    private:
+        int m_calibrateType;
+        ToolHandle<IHadronicCalibrationTool> m_caloWeightTool;
+
+        const LArEM_ID* m_emid;
+        const TileID* m_tileid;
+
+        std::string m_cellWeightTool;
+        std::vector<float> m_poly;
+
+        bool m_applyCellWeightEM;
+        bool m_applyCellWeightHad;
+        bool m_applyPtEtaCorrFactors;
+        bool m_validCaloWeightTool;
+        bool m_doEtaInterpolation;
+
+        float m_fudge;
+        double m_cellCone;
+
+        int m_nptbins;
+        int m_netabins;
+
+        std::vector<float> m_ptpoints;
+        std::vector<float> m_etapoints;
+        std::vector<float> m_ptetacorrectionsntr1;
+        std::vector<float> m_ptetacorrectionsntr23;
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/ITauToolBase.h b/Reconstruction/tauRecTools/tauRecTools/ITauToolBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb5e5645f233f2efea5f2048b278d641973895c6
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/ITauToolBase.h
@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ITOOLBASE_TAU_H
+#define ITOOLBASE_TAU_H
+
+#include "AsgTools/IAsgTool.h"
+#include "tauRecTools/TauEventData.h"
+
+/**
+ * @brief The base class for all tau tools.
+ * 
+ * @author Lukasz Janyst
+ * @author Justin Griffiths
+ * Thanks to Lianyou Shan, Lorenz Hauswald
+ */
+
+class ITauToolBase : virtual public asg::IAsgTool
+{
+ public:
+
+  ASG_TOOL_INTERFACE(ITauToolBase)    
+
+  virtual ~ITauToolBase() {}
+
+  //-----------------------------------------------------------------
+  //! Tool initializer
+  //-----------------------------------------------------------------
+  virtual StatusCode initialize() = 0;
+
+  //-----------------------------------------------------------------
+  //! Event initializer - called at the beginning of each event
+  //-----------------------------------------------------------------
+  virtual StatusCode eventInitialize() = 0;
+
+  //-----------------------------------------------------------------
+  //! Execute - called for each tau candidate
+  //-----------------------------------------------------------------
+  virtual StatusCode execute(xAOD::TauJet& pTau) = 0;
+
+  //-----------------------------------------------------------------
+  //! Event finalizer - called at the end of each event
+  //-----------------------------------------------------------------
+  virtual StatusCode eventFinalize() = 0;
+
+  //-----------------------------------------------------------------
+  //! Finalizer
+  //-----------------------------------------------------------------
+  virtual StatusCode finalize() = 0;
+
+  virtual void setTauEventData(TauEventData* data) = 0;
+
+};
+
+#endif // TOOLBASE_TAU_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/ITauToolExecBase.h b/Reconstruction/tauRecTools/tauRecTools/ITauToolExecBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef03c83ef5c3f853bdfa32d5603ae6325fe05406
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/ITauToolExecBase.h
@@ -0,0 +1,42 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ITAUTOOLEXECBASE_TAU_H
+#define ITAUTOOLEXECBASE_TAU_H
+
+#include <string>
+
+#include "AsgTools/AsgTool.h"
+
+/**
+ * @brief The base class for all tau tools that act as algorithms.
+ * 
+ * @author Justin Griffiths
+ */
+
+
+class ITauToolExecBase : virtual public asg::IAsgTool
+{
+ public:
+
+  virtual ~ITauToolExecBase() {}
+
+  //-----------------------------------------------------------------
+  //! Tool initializer
+  //-----------------------------------------------------------------
+  virtual StatusCode initialize() = 0;
+
+  //-----------------------------------------------------------------
+  //! Execute - called for each tau candidate
+  //-----------------------------------------------------------------
+  virtual StatusCode execute() = 0;
+
+  //-----------------------------------------------------------------
+  //! Finalizer
+  //-----------------------------------------------------------------
+  virtual StatusCode finalize() = 0;
+
+};
+
+#endif // ITAUTOOLEXECBASE_TAU_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/KineUtils.h b/Reconstruction/tauRecTools/tauRecTools/KineUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..28d5e0bf25734cf82cbdb1f5d5c1e94bc585fd6f
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/KineUtils.h
@@ -0,0 +1,70 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_KINEUTILS_H
+#define TAUREC_KINEUTILS_H
+
+
+#include <string>
+#include "TVector2.h"
+
+//static const double kPI  = 3.1415927;
+//static const double k2PI = 2*3.1415927;
+
+//!
+//! @class Tau1P3PKineUtils
+//! @brief Provides methods for simple kinematical calculations
+//!
+//! Provides methods for simple kinematical calculations: absolute value
+//! of difference in pseudorapidity, in phi position, half-opening angle
+//! in ( eta, phi ) space
+//!
+
+class Tau1P3PKineUtils
+{
+    public:
+        //!
+        //! Calculates absolute value for difference in eta position
+        //!
+        //! @param x eta position of object 1
+        //! @param y eta position of object 2
+        //!
+        static double deltaEta(double eta1, double eta2) { return std::fabs( eta1 - eta2);} 
+
+        //!
+        //! Calculates absolute value for difference in phi position,
+        //! corrected for 2pi symmetry
+        //!
+        //! @param x phi  position of object 1
+        //! @param y phi  position of object 2
+        //!
+
+        /*
+        static double deltaPhi(double phi1, double phi2)
+        {
+
+            double dphi = std :: fabs( phi1 - phi2 );
+            if( dphi  >  kPI ) dphi -= k2PI;
+            return std :: fabs( dphi );
+        }
+        */
+        static double deltaPhi(double phi1, double phi2)
+        {
+            return TVector2::Phi_mpi_pi(phi1-phi2);
+        }
+
+        //!
+        //! Calculates half-opening angle in (eta,phi) space
+        //!
+        //! @param x detphi of two objects 
+        //! @param y deteta of two objects
+        //!
+        static double deltaR(double de,double dp) { return std::sqrt(de*de+dp*dp); }
+        static double deltaR(double eta1, double phi1, double eta2, double phi2) {
+        	return std::sqrt(deltaEta(eta1,eta2)*deltaEta(eta1,eta2)+deltaPhi(phi1,phi2)*deltaPhi(phi1,phi2));
+        }
+
+};
+
+#endif 
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauBuilderTool.h b/Reconstruction/tauRecTools/tauRecTools/TauBuilderTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..c8776c84da2aafdcbefc7d47903980906cbdb2b9
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauBuilderTool.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUBUILDERTOOL_H
+#define TAUREC_TAUBUILDERTOOL_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "tauRecTools/ITauToolExecBase.h"
+#include "AsgTools/ToolHandleArray.h"
+
+/**
+ * @brief Implementation of tauRec/TauBuilder as a tool.
+ * 
+ * @author Justin Griffiths
+ * @authors (tauRec/TauBuilder.h)    Srini Rajagopalan, Michael Heldmann, Lukasz Janyst, Anna Kaczmarska, Felix Friedrich
+ *                                                                              
+ */
+
+class TauBuilderTool : public asg::AsgTool, virtual public ITauToolExecBase {
+ public:
+
+  ASG_TOOL_CLASS1( TauBuilderTool, ITauToolExecBase )
+    
+    TauBuilderTool(const std::string& type);
+  ~TauBuilderTool();
+
+  virtual StatusCode initialize();
+  virtual StatusCode execute();
+  virtual StatusCode finalize();
+
+ private:
+  std :: string                 m_tauContainerName;             //!< tau output container
+  std :: string                 m_tauAuxContainerName;             //!< tau output aux store container
+  std::string m_seedContainerName;            //!< seed input container
+  double m_maxEta; //!< only build taus with eta_seed < m_maxeta
+  double m_minPt;  //!< only build taus with pt_seed > m_minpt
+
+  /** switch to create tau containers, 
+   * if false tau containers will be updated only 
+   */ 
+  bool m_doCreateTauContainers;               
+  ToolHandleArray<ITauToolBase>  m_tools;
+  TauEventData m_data;
+
+ public:
+
+};
+
+#endif //TAUREC_TAUBUILDERTOOL_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauCalibrateLC.h b/Reconstruction/tauRecTools/tauRecTools/TauCalibrateLC.h
new file mode 100644
index 0000000000000000000000000000000000000000..44e29116bdc215428062817e07917aca551edd76
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauCalibrateLC.h
@@ -0,0 +1,63 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCALIBRATELC_H
+#define TAUREC_TAUCALIBRATELC_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+class TH1;
+class TF1;
+
+/**
+ * @brief Implementation of tau energy scale (TES) with eta and pile-up correction.
+ * 
+ *  The energy and eta (direction) correction are done separatly and steered by flags.
+ * 
+ * @author Margar Simonyan
+ * @author Felix Friedrich
+ *                                                                              
+ */
+
+class TauCalibrateLC : virtual public TauRecToolBase {
+public:
+
+  ASG_TOOL_CLASS2( TauCalibrateLC, TauRecToolBase, ITauToolBase )
+
+  TauCalibrateLC(const std::string& type);
+    ~TauCalibrateLC();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+
+private:
+    std::string tauContainerKey;
+    std::string vertexContainerKey;
+    std::string calibrationFile; //!< energy calibration file
+
+    static const int nProngBins = 2;
+
+    const TF1 * calibFunc[nProngBins][10]; //maximum 10 eta bins; might not be used on the whole 
+    const TH1 * slopeNPVHist[nProngBins];
+    const TH1 * etaBinHist;
+    const TH1 * etaCorrectionHist;
+
+    unsigned int m_minNTrackAtVertex;
+    int    m_nEtaBins;
+    double m_averageNPV;
+
+    bool m_doEnergyCorr; //!< switch for energy correction
+    bool m_doAxisCorr;   //!< switch for eta correction
+    bool m_printMissingContainerINFO;
+
+  double m_clusterCone; //obsolete
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauCommonCalcVars.h b/Reconstruction/tauRecTools/tauRecTools/TauCommonCalcVars.h
new file mode 100644
index 0000000000000000000000000000000000000000..8dad05a149cf104e497c3ac6c43f9c5944d283d1
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauCommonCalcVars.h
@@ -0,0 +1,40 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUCOMMONCALCVARS_H
+#define TAUREC_TAUCOMMONCALCVARS_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+
+/**
+ * @brief Calculate variables which rely on tracks and precalculated cell/cluster information.
+ * 
+ *  All variables here can be recalculated using AODs.
+ * 
+ * @author Stan Lai
+ * @author Felix Friedrich
+ */
+
+class TauCommonCalcVars : virtual public TauRecToolBase {
+public:
+    //-----------------------------------------------------------------
+    // Constructor and destructor
+    //-----------------------------------------------------------------
+    TauCommonCalcVars(const std::string& name);
+    ASG_TOOL_CLASS2(TauCommonCalcVars, TauRecToolBase, ITauToolBase)
+    ~TauCommonCalcVars();
+    
+    virtual StatusCode initialize();                 
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();  
+
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+};
+
+#endif // TAUREC_TAUCOMMONCALCVARS_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauEventData.h b/Reconstruction/tauRecTools/tauRecTools/TauEventData.h
new file mode 100644
index 0000000000000000000000000000000000000000..1778c99d6a16c387a4b69fbaafc968108f65e5ff
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauEventData.h
@@ -0,0 +1,128 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_EVENT_DATA_H
+#define TAUREC_EVENT_DATA_H
+//-----------------------------------------------------------------------------
+// file:        TauEventData.h was TauCandidateData.h
+// package:     Reconstruction/tauEvent
+// authors:     Lukasz Janyst
+// date:        2007-02-13
+//
+//  MODIFICATIONS
+// 2008-04-22 nicom: moved setObject()/getObject() to TauEventData
+//
+//-----------------------------------------------------------------------------
+
+#include <string>
+#include <map>
+#include <boost/any.hpp>
+
+#include "xAODTau/TauJetContainer.h"
+#include "xAODTau/TauJetAuxContainer.h"
+#include "AsgTools/StatusCode.h"
+
+/**
+ * @brief   The tau candidate object.
+ * 
+ *  Holds all containers and information needed for the tau reconstruction process.
+ * 
+ * @authors    Lukasz Janyst
+ */
+
+class TauEventData
+{
+public:
+    //-----------------------------------------------------------------
+    //! Associate some object to a key - this is meant to be used by
+    //! TrigTauRec to pass container pointers to tauRec tools
+    //-----------------------------------------------------------------
+    template <typename P>
+        void setObject( std :: string key, P ptr );
+
+    //-----------------------------------------------------------------
+    //! Check if something has been associated with given key
+    //-----------------------------------------------------------------
+    bool hasObject( std :: string key ) const;
+
+    //-----------------------------------------------------------------
+    //! Get the pointer associated with given key, if types don't
+    //! match boost :: bad_any_cast exception is thrown
+    //-----------------------------------------------------------------
+    template <typename P>
+        StatusCode getObject( std :: string key, P &ptr );
+  
+    xAOD::TauJetContainer* xAODTauContainer=0;
+    xAOD::TauJetAuxContainer *tauAuxContainer=0;
+    /* //think about changing this to IParticle */
+    /* const xAOD::Jet  *seed=0; */
+    const xAOD::JetContainer *seedContainer=0;
+    unsigned int                        detailsNum;
+
+    std :: map<std :: string, boost :: any> m_ptrMap;
+
+    void clear();
+
+    inline void setInTrigger(bool v=true);
+    inline bool inTrigger();
+   
+ private:
+    //don't clear this infomation
+    bool m_inTrigger = false;
+
+};
+
+//-------------------------------------------------------------------------
+// Set pointer
+//-------------------------------------------------------------------------
+    template <typename P>
+inline void TauEventData :: setObject( std :: string key, P ptr )
+{
+    m_ptrMap[key] = ptr;
+}
+
+//-------------------------------------------------------------------------
+// Get pointer
+//-------------------------------------------------------------------------
+    template <typename P>
+inline StatusCode TauEventData :: getObject( std :: string key, P &ptr )
+{
+    std :: map< std :: string, boost :: any> :: iterator p_it;
+    p_it = m_ptrMap.find( key );
+    if( p_it == m_ptrMap.end() )
+        return StatusCode :: FAILURE;
+
+    ptr = boost :: any_cast<P>( (*p_it).second );
+    return StatusCode :: SUCCESS;
+}
+
+//-------------------------------------------------------------------------
+// Test if any pointer has been associated with given key
+//-------------------------------------------------------------------------
+inline bool TauEventData :: hasObject( std :: string key ) const
+{
+    return m_ptrMap.find( key ) != m_ptrMap.end();
+}
+
+//-------------------------------------------------------------------------
+// reset all information, nothing is deleted assuming pointers
+// owned by storegate
+//-------------------------------------------------------------------------
+inline void TauEventData :: clear(){
+  xAODTauContainer=0;
+  tauAuxContainer=0;
+  seedContainer=0;
+  detailsNum=0;
+  m_ptrMap.clear();
+}
+
+inline void TauEventData :: setInTrigger(bool v){
+  m_inTrigger=v;
+}
+
+inline bool TauEventData :: inTrigger(){
+  return m_inTrigger;
+}
+
+#endif // TAU_CANDIDATE_DATA
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauGenericPi0Cone.h b/Reconstruction/tauRecTools/tauRecTools/TauGenericPi0Cone.h
new file mode 100644
index 0000000000000000000000000000000000000000..43b9c0db64d4272c3fd7e1e774f3bac69fb8669b
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauGenericPi0Cone.h
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauGenericPi0Cone.h
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-04
+//
+//
+//-----------------------------------------------------------------------------
+
+#ifndef TAUREC_TAUGENERICPI0CONE_H
+#define	TAUREC_TAUGENERICPI0CONE_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+class TauGenericPi0Cone : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+    TauGenericPi0Cone(const std::string& name);
+    ASG_TOOL_CLASS2(TauGenericPi0Cone, TauRecToolBase, ITauToolBase)
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    ~TauGenericPi0Cone();
+
+    virtual StatusCode initialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    
+    float m_pi0conedr;
+
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauIDPileupCorrection.h b/Reconstruction/tauRecTools/tauRecTools/TauIDPileupCorrection.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e5996ff8e289edffbfe8cea751afc2b39fbfd93
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauIDPileupCorrection.h
@@ -0,0 +1,74 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUIDPILEUPCORRECTION_H
+#define TAUREC_TAUIDPILEUPCORRECTION_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "xAODTau/TauDefs.h"
+
+class TH1;
+class TF1;
+
+/**
+ * @brief Implementation of tool to correct tau ID variables for pile-up in a generic way
+ * 
+ *  Input comes from 2 ROOT files with TF1 functions containing the mean variable value
+ *  as a function of the chosen pile-up estimator (Nvtx offline, mu online)
+ *
+ *  The correspondence between the ROOT File curve names and the TauParameters is handled
+ *  via a small structure defined in initialize
+ *
+ * @author M. Beckingham
+ * @author P.O. DeViveiros
+ * @author M. Janus
+ *                                                                              
+ */
+
+class TauIDPileupCorrection : virtual public TauRecToolBase {
+public:
+
+    TauIDPileupCorrection(const std::string& name) ;
+    ASG_TOOL_CLASS2(TauIDPileupCorrection, TauRecToolBase, ITauToolBase)
+    ~TauIDPileupCorrection();
+
+    virtual StatusCode initialize();
+    virtual StatusCode finalize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+
+    virtual void print() const { }
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+    virtual void cleanup(xAOD::TauJet* ) { }
+
+
+private:
+    std::string m_tauContainerKey;
+    std::string m_vertexContainerKey;
+    std::string m_file1P; //!< energy calibration file
+    std::string m_file3P; //!< energy calibration file
+    
+    std::map<std::string, TF1> m_calibFunctions1P;
+    std::map<std::string, TF1> m_calibFunctions3P;
+    
+    struct TauConversion {
+      std::string detailName;
+      xAOD::TauJetParameters::Detail detailUncorr;
+      xAOD::TauJetParameters::Detail detailCorr;
+      
+    TauConversion(std::string name, xAOD::TauJetParameters::Detail detail1, xAOD::TauJetParameters::Detail detail2)
+    : detailName(name), detailUncorr(detail1), detailCorr(detail2)
+      { }
+    };
+    
+    std::vector<TauConversion> m_conversion;
+    
+    double m_averageEstimator;
+    unsigned int m_minNTrackAtVertex;
+    bool m_printMissingContainerINFO;
+    bool m_useMu;
+    
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauProcessorTool.h b/Reconstruction/tauRecTools/tauRecTools/TauProcessorTool.h
new file mode 100644
index 0000000000000000000000000000000000000000..01593ccea63bd2af8f483ec71877591fdb9a7d61
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauProcessorTool.h
@@ -0,0 +1,93 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TAUPROCESSORTOOL_H
+#define TAUREC_TAUPROCESSORTOOL_H
+
+#include "tauRecTools/TauRecToolBase.h"
+#include "tauRecTools/ITauToolExecBase.h"
+#include "AsgTools/ToolHandleArray.h"
+
+/**
+ * @brief Implementation of tauRec/TauProcessor as a tool.
+ * 
+ * @author Justin Griffiths
+ *                                                                              
+ */
+
+class TauProcessorTool : public asg::AsgTool, virtual public ITauToolExecBase {
+ public:
+
+  ASG_TOOL_CLASS1( TauProcessorTool, ITauToolExecBase )
+    
+  TauProcessorTool(const std::string& type);
+  ~TauProcessorTool();
+
+  virtual StatusCode initialize();
+  virtual StatusCode execute();
+  virtual StatusCode finalize();
+
+ private:
+  std :: string                 m_tauContainerName;
+  std :: string                 m_tauAuxContainerName; 
+  bool                          m_AODmode;
+  bool                          m_deep_copy_chargedPFOContainer;
+  bool                          m_deep_copy_hadronicPFOContainer;
+  bool                          m_deep_copy_neutralPFOContainer;
+  bool                          m_deep_copy_SecVtxContainer;
+  TauEventData m_data;
+  ToolHandleArray<ITauToolBase>  m_tools;
+
+ public:
+  //-------------------------------------------------------------------------
+  // make a deep copy of conatiner a
+  // xAOD::TauJetContainer *cont(0);
+  // xAOD::TauJetAuxContainer* contAux(0);
+  // xAOD::TauJet* tau(0);
+  // ATH_CHECK( ITauToolBase::deepCopy( cont, contAux, tau, "TauJets", "TauJetsAux.") );
+  // tau is only used to infer type of object in T...
+  //-------------------------------------------------------------------------
+  template<class T, class U, class V>
+    StatusCode deepCopy(T*& containerOut, U*& containerStoreOut, const V* dummyContainerType, 
+			const std::string& containername,  std::string containerNameAux="");
+
+
+};
+
+template<class T, class U, class V>
+  StatusCode TauProcessorTool::deepCopy(T*& container, U*& containerStore, const V* /*dummyContainerElementType*/, 
+				    const std::string& containerName, std::string containerNameAux){
+  if(containerNameAux=="") {
+    containerNameAux=containerName;
+    containerNameAux+="Aux.";
+  }
+
+  const T* constContainer(0);
+  const U* constAuxContainer(0);
+
+  ATH_CHECK( evtStore()->retrieve(constContainer, containerName) );
+  ATH_CHECK( evtStore()->retrieve(constAuxContainer, containerNameAux) );
+  if(container==0 && containerStore==0){
+    container = new T();
+    containerStore = new U();
+    container->setStore(containerStore);
+  }
+  else{
+    ATH_MSG_FATAL("Proviced non-null containters, not initializing please provide null containers: ");
+    return StatusCode::FAILURE;
+  }
+  for( const V* v : *constContainer ){
+    V* newV = new V();
+    container->push_back(newV);
+    *newV = *v;    
+  }  
+
+  ATH_CHECK( evtStore()->overwrite(container, containerName, true, false) );
+  ATH_CHECK( evtStore()->overwrite(containerStore, containerNameAux, true, false) );
+
+  return StatusCode::SUCCESS;
+}
+
+
+#endif //TAUREC_TAUPROCESSORTOOL_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauRecToolBase.h b/Reconstruction/tauRecTools/tauRecTools/TauRecToolBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b0a6deb15f12c025a8f8bc9587e819ccf315e4c
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauRecToolBase.h
@@ -0,0 +1,73 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAURECTOOLBASE_H
+#define TAURECTOOLBASE_H
+/**
+ * @brief The base class for all tau tools.
+ * 
+ * @author Lukasz Janyst
+ * @author Justin Griffiths
+ * Thanks to Lianyou Shan, Lorenz Hauswald
+ */
+
+#include <string>
+
+#include "tauRecTools/TauEventData.h"
+#include "tauRecTools/ITauToolBase.h"
+#include "AsgTools/AsgTool.h"
+
+extern TauEventData defaultTauEventData;
+
+class TauRecToolBase : public asg::AsgTool, virtual public ITauToolBase {
+ public:
+
+  ASG_TOOL_INTERFACE(TauRecToolBase)
+  ASG_TOOL_CLASS1( TauRecToolBase, ITauToolBase )
+
+    TauRecToolBase(const std::string& name);
+  virtual ~TauRecToolBase() {}
+
+  //-----------------------------------------------------------------
+  //! Tool initializer
+  //-----------------------------------------------------------------
+  virtual StatusCode initialize();
+
+  //-----------------------------------------------------------------
+  //! Event initializer - called at the beginning of each event
+  //-----------------------------------------------------------------
+  virtual StatusCode eventInitialize();
+
+  //-----------------------------------------------------------------
+  //! Execute - called for each tau candidate
+  //-----------------------------------------------------------------
+  virtual StatusCode execute(xAOD::TauJet& pTau);
+
+  //-----------------------------------------------------------------
+  //! Event finalizer - called at the end of each event
+  //-----------------------------------------------------------------
+  virtual StatusCode eventFinalize();
+
+  //-----------------------------------------------------------------
+  //! Finalizer
+  //-----------------------------------------------------------------
+  virtual StatusCode finalize();
+
+  std::string find_file(const std::string& fname) const;
+
+  void setTauEventData(TauEventData* data);
+  TauEventData* tauEventData();
+
+
+
+ protected:
+  TauEventData* m_data = 0;
+
+};
+
+inline TauEventData* TauRecToolBase::tauEventData() { 
+  return m_data;
+}
+
+#endif //TAURECTOOLBASE_H
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauTrackFilter.h b/Reconstruction/tauRecTools/tauRecTools/TauTrackFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..0489bb13348af91d084d9a019aa110256ff52129
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauTrackFilter.h
@@ -0,0 +1,50 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauTrackFilter.h
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-04
+//
+//
+//-----------------------------------------------------------------------------
+
+#ifndef TAUREC_TAUTRACKFILTER_H
+#define	TAUREC_TAUTRACKFILTER_H
+
+#include "tauRecTools/TauRecToolBase.h"
+
+class TauTrackFilter : virtual public TauRecToolBase {
+public:
+    //-------------------------------------------------------------
+    //! Constructor
+    //-------------------------------------------------------------
+    TauTrackFilter(const std::string& name);
+    ASG_TOOL_CLASS2(TauTrackFilter, TauRecToolBase, ITauToolBase)
+
+    //-------------------------------------------------------------
+    //! Destructor
+    //-------------------------------------------------------------
+    ~TauTrackFilter();
+
+    virtual StatusCode initialize();
+    virtual StatusCode execute(xAOD::TauJet& pTau);
+    virtual StatusCode finalize();
+    virtual StatusCode eventInitialize() { return StatusCode::SUCCESS; }
+    virtual StatusCode eventFinalize() { return StatusCode::SUCCESS; }
+
+    virtual void print() const { }
+
+private:
+    
+    std::string m_trackContainerName;
+    std::vector<bool> m_TrkPass;
+    int m_nProng;
+    int m_flag;
+    //TODO some of this probably need to be public to be useful...
+
+};
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/TauTrackFilterUtils.h b/Reconstruction/tauRecTools/tauRecTools/TauTrackFilterUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..443f965f46cd9f53e9f8b1d01344793507c35ff3
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TauTrackFilterUtils.h
@@ -0,0 +1,46 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+//-----------------------------------------------------------------------------
+// file:        TauTrackFilterUtils.h
+// package:     Reconstruction/tauRec
+// authors:     Robert Clarke, Blake Burghgrave
+// date:        2014-01-13
+//
+//
+//-----------------------------------------------------------------------------
+
+#ifndef TAUREC_TAUTRACKFILTERUTILS_H
+#define	TAUREC_TAUTRACKFILTERUTILS_H
+
+#include "TF1.h"
+#include "TLorentzVector.h"
+#include <vector>
+#include <iostream>
+#include <string>
+
+namespace TauTrackFilterUtils {
+
+    struct TrackInfo{
+        TLorentzVector p4;
+        int            charge;
+        int            index;
+    };
+
+    struct TrackPair{
+        float angle;
+        float mass;
+        int charge;
+    };
+
+    bool     pass3prong(std::vector<TauTrackFilterUtils::TrackInfo> combination,TLorentzVector tau);
+    bool     pass2prong(std::vector<TauTrackFilterUtils::TrackInfo> pair,TLorentzVector tau);
+    bool     pass1prong(TLorentzVector track,TLorentzVector tau);
+    float    ComputePi0Cone(int recProngs,TLorentzVector tau);
+    float    ComputeAngle(float p, float eta, float a[9][4], int npar, int npol, char eqn[] = (char*)"[0]*exp([1]*x)+[2]+[3]/(x*x)");
+    float    Compute1dim(float p, float a[10], int npar, char eqn[]);
+
+}
+
+#endif
diff --git a/Reconstruction/tauRecTools/tauRecTools/TrackSort.h b/Reconstruction/tauRecTools/tauRecTools/TrackSort.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fa2290d6dd0d614bd0576dd6ff4df7b7df05260
--- /dev/null
+++ b/Reconstruction/tauRecTools/tauRecTools/TrackSort.h
@@ -0,0 +1,48 @@
+/*
+  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef TAUREC_TRACKSORT_H
+#define TAUREC_TRACKSORT_H
+
+#ifdef ASGTOOL_ATHENA
+#include "Particle/TrackParticle.h"
+#include "Particle/TrackParticleContainer.h"
+#endif
+#include "AthLinks/ElementLink.h"
+#include "xAODTracking/TrackParticle.h"
+
+/**
+ * @brief Helper method to sort tracks
+ * 
+ * Usage:
+ * sort(track_begin, track_end, tauTrackSort);
+ * We want pt0 > pt1 > ..., so the test on ptInvVert is < .
+ * 
+ */
+
+class TrackSort {
+
+    public:
+        TrackSort(){ };
+
+#ifdef ASGTOOL_ATHENA
+        bool operator() (const ElementLink<Rec::TrackParticleContainer>& t1, const ElementLink<Rec::TrackParticleContainer> &t2) const
+        {
+            return fabs( (*t1)->pt() ) > fabs( (*t2)->pt() );
+        };
+
+        bool operator() ( const Rec::TrackParticle *t1, const Rec::TrackParticle *t2 ) const
+        {
+            return fabs( t1->pt() ) > fabs( t2->pt() );
+        };
+#endif
+
+        bool operator() ( const xAOD::TrackParticle *t1, const xAOD::TrackParticle *t2 ) const
+        {
+            return fabs( t1->pt() ) > fabs( t2->pt() );
+        };
+
+};
+
+#endif