diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/AnalysisConfigMT_Ntuple.h b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/AnalysisConfigMT_Ntuple.h
new file mode 100644
index 0000000000000000000000000000000000000000..53ae3c41e9fb1aa87c991efaa048ffee0425d115
--- /dev/null
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/AnalysisConfigMT_Ntuple.h
@@ -0,0 +1,53 @@
+/* emacs: this is -*- c++ -*- */
+/**
+ **     @file    AnalysisConfigMT_Ntuple.h
+ **
+ **              Ehis is the MT analysis class - we really don;t want to 
+ **              have to duplicate everything so we instead just inherit 
+ **              from the normal class and just implement the new loop 
+ **              method 
+ **
+ **
+ **     @author  mark sutton
+ **     @date    Monday 18th May  2020 22:55:37 BST 
+ **
+ **     Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+ **/
+
+
+#ifndef TrigInDetAnalysisExample_AnalysisConfigMT_Ntuple_H
+#define TrigInDetAnalysisExample_AnalysisConfigMT_Ntuple_H
+
+#include "TrigInDetAnalysisExample/AnalysisConfig_Ntuple.h"
+
+
+class AnalysisConfigMT_Ntuple : public AnalysisConfig_Ntuple { 
+    
+public:
+    
+    // Full constructor: test/reference/selection
+    // - analysisInstanceName: the name of the analysis chain being created
+    // - xxxChainName: the name of the chain to be used as test/reference/selection; must be "StoreGate" in case of direct access to SG containers
+    // - xxxType: the type of tracks to be retrieved from the test/reference/selection chain or container
+    // - xxxKey:  the key for tracks to be retrieved from the test/reference/selection chain or container
+    // - roiInfo: in case the test chain is a real chain, this is used to specify RoI widths; in case the test chain is a fake chain, this is used 
+    //   for RoI position too
+    // - all standard operations are performed in loops over 0=test 1=reference 2=selection
+
+  AnalysisConfigMT_Ntuple( TIDARoiDescriptor* roiInfo, 
+			   const std::vector<std::string>& chainNames, std::string outputFileName="TrkNtuple.root", 
+			   double tauEtCutOffline=0.0, int TruthPdgId = 0, bool keepAllEvents_=false ) : 
+    AnalysisConfig_Ntuple( roiInfo, chainNames, outputFileName, tauEtCutOffline, TruthPdgId, keepAllEvents_ ) 
+  { }  
+
+  virtual ~AnalysisConfigMT_Ntuple() { }
+
+protected:
+
+  virtual void loop();
+
+};
+
+  
+#endif  // TrigInDetAnalysisExample_AnalysisConfigMT_Ntuple_H
+
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/T_AnalysisConfigMT_Tier0.h b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/T_AnalysisConfigMT_Tier0.h
index f38a8b025d7618db130d77772fc6ad1d7898bd1f..938129828f10bb17d7366bb0dce7604a94283a32 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/T_AnalysisConfigMT_Tier0.h
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/TrigInDetAnalysisExample/T_AnalysisConfigMT_Tier0.h
@@ -226,19 +226,12 @@ protected:
 
   virtual void loop() {
 
-    //    bool dbg = true;
-
     //    std::cout <<  "AnalysisConfigMT_Tier0::loop() for " << T_AnalysisConfig<T>::m_analysisInstanceName << std::endl;
 
-    //    std::cout <<  "\n\n\tAnalysisConfigMT_Tier0::loop() for " << T_AnalysisConfig<T>::m_analysisInstanceName << std::endl;
-
-
     if( m_provider->msg().level() <= MSG::VERBOSE) {
       m_provider->msg(MSG::VERBOSE) <<  "AnalysisConfigMT_Tier0::loop() for " << T_AnalysisConfig<T>::m_analysisInstanceName <<  endmsg;
     }
 
-    //    std::cout <<  "\tAnalysisConfigMT_Tier0::loop() for " << T_AnalysisConfig<T>::m_analysisInstanceName <<  std::endl;
-
     // get (offline) beam position
     double xbeam = 0;
     double ybeam = 0;
@@ -253,12 +246,8 @@ protected:
       }
     }
 
-    //  m_first = true;
-
     if ( m_first ) {
 
-      //      std::cout << "\tloop() first event setup" << std::endl;
-
       m_first = false;
       
       m_provider->msg(MSG::VERBOSE) << " using beam position\tx=" << xbeam << "\ty=" << ybeam << endmsg;
@@ -267,8 +256,6 @@ protected:
 	
 	std::vector<std::string> configuredChains  = (*(m_tdt))->getListOfTriggers("L2_.*, EF_.*, HLT_.*");
 	
-	//	std::cout << "\tloop() (first eveny printout) Configured chains " << configuredChains.size() << std::endl;
-	
        	for ( unsigned i=0 ; i<configuredChains.size() ; i++ ) {
 	  //	std::cout << "Configured chain " << configuredChains[i]  << std::endl;
 	  m_provider->msg(MSG::VERBOSE)  << "Chain " << configuredChains[i]  << endmsg;
@@ -629,17 +616,10 @@ protected:
       if ( m_chainNames[ichain].passed() ) decisiontype = _decisiontype;
       else                                 decisiontype = TrigDefs::alsoDeactivateTEs;
 
+      /// useful debug information to be kept in for the time being 
       //      if ( decisiontype==TrigDefs::requireDecision ) std::cout << "\tSUTT TrigDefs::requireDecision " << decisiontype << std::endl;
       //      if ( decisiontype==TrigDefs::Physics )         std::cout << "\tSUTT TrigDefs::Physics "         << decisiontype << std::endl;
 
-
-      /// and the index of the collection (if any)
-      /// disable this feature at the moment - put back in when we have the more important 
-      /// stuff working  
-      //      const std::string& key_index_string = m_chainNames[ichain].extra();
-      //      unsigned key_index = 0;
-      //      if ( key_index_string!="" ) key_index = std::atoi( key_index_string.c_str() );
-
       if ( chainname!="" && m_provider->msg().level() <= MSG::VERBOSE ) {
 
         m_provider->msg(MSG::VERBOSE) << "status for chain " << chainname
@@ -651,6 +631,7 @@ protected:
         m_provider->msg(MSG::VERBOSE) << chainname << "\tpassed: " << (*m_tdt)->isPassed( chainname ) << endmsg;
       }
 
+      /// useful debug information to be kept in
       //      std::cout << "\tstatus for chain " << chainname
       //		<< "\tpass "           << (*m_tdt)->isPassed( chainname )
       //		<< "\tpassdt "         << (*m_tdt)->isPassed( chainname, decisiontype )
@@ -662,7 +643,6 @@ protected:
 
       if ( chainname!="" && !this->m_keepAllEvents && !(*m_tdt)->isPassed( chainname, decisiontype ) ) continue;
 
-      //      std::cout << "\tchain " << m_chainNames[ichain] << "\tchainname " << chainname << "\tvtx " << vtx_name << "\troi " << roi_name << std::endl;
 
       /// Get chain combinations and loop on them
       /// - loop made on chain selected as the one steering RoI creation
@@ -691,7 +671,6 @@ protected:
 		
         chain.addRoi( *roiInfo );
 	
-
 	if ( m_provider->evtStore()->template contains<xAOD::TrackParticleContainer>(key) ) {
 	  this->template selectTracks<xAOD::TrackParticleContainer>( m_selectorTest, key );
 	  refbeamspot = this->template getBeamspot<xAOD::TrackParticleContainer>( key );
@@ -736,33 +715,21 @@ protected:
 
 	  if ( roi_key=="SuperRoi" && iroi>1 ) continue; 
 	
-	  //	  std::cout << "\troi: get link ..." << std::endl;
+	  //	  std::cout << "\troi: get link " << roi_key << " ..." << std::endl;
 
 	  const ElementLink<TrigRoiDescriptorCollection> roi_link = roi_info.link;
 
-	  //	  std::cout << "\troi: read link ..." << std::endl;
-
 	  const TrigRoiDescriptor* const* roiptr = roi_link.cptr();
 
-	  //	  std::cout << "\troi: link ..." << roiptr << std::endl;
-
-	  
 	  if ( roiptr == 0 ) { 
-	    //	    std::cerr << "\treadback link is null  DAMMIT !!!" << std::endl;
 	    continue;
 	  }  
 
 	  //	  std::cout << "\troi: link deref ..." << *roiptr << std::endl;
 
-
 	  if (m_provider->msg().level() <= MSG::VERBOSE) {
 	    m_provider->msg(MSG::VERBOSE) << " RoI descriptor for seeded chain " << chainname << " " << **roiptr << endmsg;
 	  }
-
-
-	  //	  TIDARoiDescriptor* roiInfo = 0;
-	  
-	  //	  if ( dbg ) std::cout << "\tlink looks ok ..." << std::endl;
 	 
 	  TIDARoiDescriptor* roiInfo = new TIDARoiDescriptor( TIDARoiDescriptorBuilder(**roiptr) );
 	 
@@ -776,7 +743,6 @@ protected:
 
 	  // beamspot stuff not needed for xAOD::TrackParticles
 
-
 	  /// create analysis chain
 
 	  chain.addRoi( *roiInfo );
@@ -787,47 +753,36 @@ protected:
 
 	  chain.back().addTracks(testtracks);
 	
-#if 0
-	  if ( dbg ) { 
-	    std::cout << "\tTIDA analysis for chain: " << chainname << "\t key: " << key << "\t" << **roiptr << std::endl;
-	    std::cout << "\tcollections: " << chain.back() << std::endl; 
-	  }
-#endif
-	  
-	  if ( roiInfo ) delete roiInfo;
-	  
-	}
 
-
-
-#if 0
-	if ( vtx_name!="" ) { 
-	    
-	  m_provider->msg(MSG::VERBOSE) << "\tFetch xAOD::VertexContainer for chain " << chainConfig << " with key " << vtx_name << endmsg;
-	  
-	  std::vector< Trig::Feature<xAOD::VertexContainer> > xaodtrigvertices = c->get<xAOD::VertexContainer>(vtx_name);
-	  
-	  if ( xaodtrigvertices.empty() ) { 
-	    m_provider->msg(MSG::WARNING) << "\tNo xAOD::VertexContainer for chain " << chainConfig << " for key " << vtx_name << endmsg;
-	  }
+	  /// now get the vertices 
 	  
-	  else {
+	  if ( vtx_name!="" ) { 
 	    
-	    m_provider->msg(MSG::VERBOSE) << "\txAOD::VertexContainer found with size  " << xaodtrigvertices.size() << "\t" << vtx_name << endmsg;
+	    m_provider->msg(MSG::VERBOSE) << "\tFetch xAOD::VertexContainer for chain " << chainConfig << " with key " << vtx_name << endmsg;
+
 	    
-	    for (  unsigned iv=0  ;  iv<xaodtrigvertices.size()  ;  iv++ ) {
-	      
-	      const xAOD::VertexContainer* vert = xaodtrigvertices[iv].cptr();
-	      
-	      m_provider->msg(MSG::VERBOSE) << "\t" << iv << "  xAOD VxContainer for " << chainConfig << " " << vert << " key " << vtx_name << endmsg;
-	      
-	      xAOD::VertexContainer::const_iterator vtxitr = vert->begin();
+	    std::pair< xAOD::VertexContainer::const_iterator, 
+		       xAOD::VertexContainer::const_iterator > vtx_itrpair = this->template getCollection<xAOD::VertexContainer>( roi_link, vtx_name );
+	    
+	    if ( vtx_itrpair.first == vtx_itrpair.second ) { 
+	      m_provider->msg(MSG::WARNING) << "\tNo xAOD::Vertex for chain " << chainName << " for key " << vtx_name << endmsg;
+	    }
+	    else {
 	      
-	      for ( ; vtxitr != vert->end(); ++vtxitr) {
+	      m_provider->msg(MSG::INFO) << "\txAOD::VertexContainer found with size  " << (vtx_itrpair.second - vtx_itrpair.first) 
+					 << "\t" << vtx_name << endmsg;
+	            
+	      xAOD::VertexContainer::const_iterator vtxitr = vtx_itrpair.first; 
+	            
+	      for (  ; vtxitr!=vtx_itrpair.second  ;  vtxitr++ ) {
+		
 		/// leave this code commented so that we have a record of the change - as soon as we can 
 		/// fix the missing track multiplicity from the vertex this will need to go back  
 		//  if ( ( (*vtxitr)->nTrackParticles()>0 && (*vtxitr)->vertexType()!=0 ) || vtx_name=="EFHistoPrmVtx" ) {
-		if ( (*vtxitr)->vertexType()!=0 || vtx_name=="EFHistoPrmVtx" ) {
+		if ( (*vtxitr)->vertexType()!=0  || vtx_name=="EFHistoPrmVtx" ) {
+ 
+		  m_provider->msg(MSG::VERBOSE) << "\tvertex " << chainConfig << " " << (*vtxitr) << "\t name" << vtx_name << endmsg;
+		
 		  chain.back().addVertex( TIDA::Vertex( (*vtxitr)->x(),
 							(*vtxitr)->y(),
 							(*vtxitr)->z(),
@@ -844,12 +799,20 @@ protected:
 	      }
 	    }
 	    
-	  }
+	  } /// retrieve online vertices
 	  
-	} /// retrieve online vertices
-	
+#if 0
+	  if ( dbg ) { 
+	    std::cout << "\tTIDA analysis for chain: " << chainname << "\t key: " << key << "\t" << **roiptr << std::endl;
+	    std::cout << "\tcollections: " << chain.back() << std::endl; 
+	  }
 #endif
-	
+	  
+	  if ( roiInfo ) delete roiInfo;
+	  
+	}
+
+
       } /// "offline" of "roi" type chains
 	
 	
@@ -911,6 +874,11 @@ protected:
             this->template selectTracks<TruthParticleContainer>( &selectorTruth, "SpclMC");
             foundTruth = true;
           }
+          else if ( m_provider->evtStore()->template contains<xAOD::TruthParticleContainer>("TruthParticles") ) {
+            /// xAOD::TruthParticles
+            this->template selectTracks<xAOD::TruthParticleContainer>( &selectorTruth, "TruthParticles");
+            foundTruth = true;
+          }
           else if ( m_provider->evtStore()->template contains<TruthParticleContainer>("") ) {
             /// anything else?
             this->template selectTracks<TruthParticleContainer>( &selectorTruth, "");
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/AnalysisConfigMT_Ntuple.cxx b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/AnalysisConfigMT_Ntuple.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..0062f100314f961b4ac81c8bab6b751ffeb6f47d
--- /dev/null
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/AnalysisConfigMT_Ntuple.cxx
@@ -0,0 +1,1282 @@
+/**
+ **     @file    AnalysisConfigMT_Ntuple.cxx
+ **
+ **     @author  mark sutton
+ **
+ **     Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+ **/
+
+#include "TrigInDetAnalysisExample/AnalysisConfigMT_Ntuple.h"
+
+#include "xAODTruth/TruthParticleContainer.h"
+#include "xAODTruth/TruthVertexContainer.h"
+
+#include "TrigInDetAnalysis/Filter_AcceptAll.h"
+#include "TrigInDetAnalysisUtils/Filter_etaPT.h"
+#include "TrigInDetAnalysisUtils/Filter_RoiSelector.h"
+#include "TrigInDetAnalysisUtils/Filters.h"
+
+#include "TrigInDetAnalysis/TIDDirectory.h"
+#include "TrigInDetAnalysisUtils/TIDARoiDescriptorBuilder.h"
+
+std::string date();
+
+
+//function to find true taus
+const HepMC::GenParticle* fromParent( int pdg_id, const HepMC::GenParticle* p, bool printout=false );
+  
+
+
+template<class T>
+void remove_duplicates(std::vector<T>& vec) {
+  std::sort(vec.begin(), vec.end());
+  vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
+}
+
+
+
+
+void AnalysisConfigMT_Ntuple::loop() {
+
+        m_provider->msg(MSG::INFO) << "" << "AnalysisConfig_Ntuple::loop() for " << m_analysisInstanceName 
+				   << " compiled " << __DATE__ << " " << __TIME__ << "\t: " << date() << "" << endmsg;
+
+	// get (offline) beam position
+	double xbeam = 0;
+	double ybeam = 0;
+	double zbeam = 0;
+	std::vector<double> beamline;
+
+	bool foundOffline = false;
+
+	if ( m_iBeamCondSvc ) {
+
+	  const Amg::Vector3D& vertex = m_iBeamCondSvc->beamPos();
+	  xbeam = vertex[0];
+	  ybeam = vertex[1];
+	  zbeam = vertex[2];
+
+	  //	  m_provider->msg(MSG::INFO) << " using beam position\tx=" << xbeam << "\ty=" << ybeam << "\tz=" << zbeam <<endmsg; 
+	  beamline.push_back(xbeam);
+	  beamline.push_back(ybeam);
+	  beamline.push_back(zbeam);
+	  //     m_provider->msg(MSG::INFO) << " beamline values : " << beamline[0] << "\t" << beamline[1]  << "\t" << beamline[2] << endmsg;	
+	}
+
+	// get (online) beam position
+	double xbeam_online = 0;
+	double ybeam_online = 0;
+	double zbeam_online = 0;
+
+	std::vector<double> beamline_online;
+
+	if ( m_iOnlineBeamCondSvc ) {
+
+	  const Amg::Vector3D& vertex = m_iOnlineBeamCondSvc->beamPos();
+	  xbeam_online = vertex[0];
+	  ybeam_online = vertex[1];
+	  zbeam_online = vertex[2];
+
+	  beamline_online.push_back( xbeam_online );
+	  beamline_online.push_back( ybeam_online );
+	  beamline_online.push_back( zbeam_online );
+
+	  //	  m_provider->msg(MSG::INFO) << " using online beam position" 
+	  //				     << "\tx=" << xbeam_online 
+	  //				     << "\ty=" << ybeam_online 
+	  //				     << "\tz=" << zbeam_online << endmsg; 
+	}
+
+	//	m_provider->msg(MSG::INFO) << " offline beam position\tx=" << xbeam        << "\ty=" << ybeam        << "\tz=" << zbeam        << endmsg; 
+	//	m_provider->msg(MSG::INFO) << " online  beam position\tx=" << xbeam_online << "\ty=" << ybeam_online << "\tz=" << zbeam_online << endmsg; 
+
+	/// list the configured chains
+
+	static std::set<std::string> configuredHLTChains;
+
+	std::vector<ChainString> chainNames;
+
+	static bool tida_first = true;
+	
+	if ( tida_first ) { 
+
+		std::vector<std::string> configuredChains  = (*m_tdt)->getListOfTriggers("L2_.*, EF_.*, HLT_.*");
+
+		//		m_provider->msg(MSG::INFO) << "" << configuredChains.size() << " Configured Chains" << "" << endmsg;
+		for ( unsigned i=0 ; i<configuredChains.size() ; i++ ) { 
+		  //  m_provider->msg(MSG::INFO) << "" << "Chain " << configuredChains[i] << "   (ACN)" << endmsg;
+		  configuredHLTChains.insert( configuredChains[i] );
+		  
+		}
+
+		tida_first = false;
+
+		std::vector<ChainString>::iterator chainitr = m_chainNames.begin();
+
+		/// handle wildcard chain selection - but only the first time
+		while ( chainitr!=m_chainNames.end() ) {
+
+		  /// get chain
+		  ChainString& chainName = (*chainitr);
+
+		  /// get matching chains
+		  
+		  std::vector<std::string> selectChains;
+		  selectChains.clear();
+		  if ( chainitr->head()=="" ) selectChains.push_back("");
+		  else                        selectChains = (*m_tdt)->getListOfTriggers( chainName.head() );
+		  
+		  for ( unsigned iselected=0 ; iselected<selectChains.size() ; iselected++ ) {
+ 
+		      if ( chainName.tail()!="" )    selectChains[iselected] += ":key="+chainName.tail();
+		      if ( chainName.extra()!="" )   selectChains[iselected] += ":index="+chainName.extra();
+		   
+		      if ( chainName.element()!="" ) selectChains[iselected] += ":te="+chainName.element(); 
+		      if ( chainName.roi()!="" )     selectChains[iselected] += ":roi="+chainName.roi();
+		      if ( chainName.vtx()!="" )     selectChains[iselected] += ":vtx="+chainName.vtx();
+		     
+		      if ( !chainName.passed() )    selectChains[iselected] += ";DTE";
+		     
+		      /// replace wildcard with actual matching chains ...
+		      chainNames.push_back( ChainString(selectChains[iselected]) );
+
+		      m_provider->msg(MSG::INFO) << "" << "Matching chain " << selectChains[iselected] << "" << endmsg;
+		     
+		  }
+		  
+		  chainitr++;
+		}
+		
+		m_chainNames = chainNames;
+	}
+
+
+	Filter_AcceptAll filter;
+	/// FIXME: should really have hardcoded limits encoded as 
+	///        const variables 
+	Filter_etaPT       filterRef(5,500);   
+	Filter_etaPT       filter_etaPT(3.0,1000);
+	Filter_pdgIdpTeta  filter_pdgIdpTeta(m_TruthPdgId,3.0,1000); // |eta|<3, pt>1GeV 
+
+	TrackFilter*        truthFilter = &filter_etaPT;
+
+	//tau filtering done separately to include mothers
+	if ( m_TruthPdgId!=0 && m_TruthPdgId!=15 ) truthFilter = &filter_pdgIdpTeta;
+
+	TrigTrackSelector selectorTruth( truthFilter ); 
+
+	TrigTrackSelector selectorRef( &filter_etaPT ); 
+	TrigTrackSelector selectorTest( &filter ); 
+
+
+	selectorTruth.setBeamline( xbeam, ybeam, zbeam ); 
+	selectorRef.setBeamline( xbeam, ybeam, zbeam ); 
+	selectorTest.setBeamline( xbeam_online, ybeam_online, zbeam_online ); 
+
+
+	selectorTruth.correctTracks( true );
+	selectorRef.correctTracks( true );
+	selectorTest.correctTracks( true );
+	
+
+	// clear the ntuple TIDA::Event class
+	m_event->clear();
+
+	const xAOD::EventInfo* pEventInfo = 0;
+
+	unsigned           run_number         = 0;
+	unsigned long long event_number       = 0;
+	unsigned           lumi_block         = 0;
+	unsigned           bunch_crossing_id  = 0;
+	unsigned           time_stamp         = 0;
+	double             mu_val             = 0;
+
+	if ( m_provider->evtStore()->retrieve(pEventInfo).isFailure() ) {
+		m_provider->msg(MSG::DEBUG) << "Failed to get EventInfo " << endmsg;
+	} 
+	else {
+		run_number        = pEventInfo->runNumber();
+		event_number      = pEventInfo->eventNumber();
+		lumi_block        = pEventInfo->lumiBlock();
+		time_stamp        = pEventInfo->timeStamp();
+		bunch_crossing_id = pEventInfo->bcid();
+		mu_val            = pEventInfo->averageInteractionsPerCrossing();
+	}
+
+	m_provider->msg(MSG::INFO) << "run "     << run_number 
+				   << "\tevent " << event_number 
+				   << "\tlb "    << lumi_block << endmsg;
+
+	m_event->run_number(run_number);
+	m_event->event_number(event_number);
+	m_event->lumi_block(lumi_block);
+	m_event->time_stamp(time_stamp);
+	m_event->bunch_crossing_id(bunch_crossing_id);
+	m_event->mu(mu_val);
+
+	// build a chain group on the fly and use the reference
+	const Trig::ChainGroup* L2chain=(*m_tdt)->getChainGroup("L2_.*");
+	const Trig::ChainGroup* EFchain=(*m_tdt)->getChainGroup("EF_.*");
+	const Trig::ChainGroup* HLTchain=(*m_tdt)->getChainGroup("HLT_.*");
+
+	m_provider->msg(MSG::DEBUG) << "" 
+		<< "L2 pass " << L2chain->isPassed()  << "\t" 
+		<< "EF pass " << EFchain->isPassed()  << "\t" 
+		<< "HLT pass " << HLTchain->isPassed() << ""
+		<< endmsg;
+       
+	/// check whether the chains have actually run, otherwise there's no point
+	/// doing anything
+
+	bool analyse = false;
+
+	unsigned decisiontype_ = TrigDefs::Physics;
+	
+	if ( requireDecision() ) decisiontype_ = TrigDefs::requireDecision;
+
+
+#if 0
+	/// stupid TDT debug
+	{
+	  std::cout << "SUTT status of all chains " << std::endl;
+	  std::vector<std::string> configuredChains  = (*m_tdt)->getListOfTriggers("L2_.*, EF_.*, HLT_.*");
+	  
+	  m_provider->msg(MSG::INFO) << "" << configuredChains.size() << " Configured Chains" << "" << endmsg;
+
+	  int npassed = 0;
+
+	  std::vector<std::string> passed;
+
+
+
+	  for ( unsigned i=0 ; i<configuredChains.size() ; i++ ) { 
+
+	    std::string chainName = configuredChains[i];
+
+#if 0
+	    std::cout << "" << "Chain " << configuredChains[i]
+		      << "\tpassed:     " <<   (*m_tdt)->isPassed(configuredChains[i], decisiontype_ )  << " ( type " << decisiontype_ << ") : "  
+		      << "\trequiredec: " <<   (*m_tdt)->isPassed(configuredChains[i], TrigDefs::requireDecision)  << "   (ACN)" << std::endl;
+#endif
+	    if ( (*m_tdt)->isPassed(configuredChains[i], decisiontype_ ) ) { 
+	      npassed++;
+	      passed.push_back(configuredChains[i]);
+	    }	  
+	  
+	    
+	    
+	    if ( chainName.find("_split")!=std::string::npos ) { 
+
+	      Trig::FeatureContainer f = (*m_tdt)->features( chainName );
+	      Trig::FeatureContainer::combination_const_iterator comb(f.getCombinations().begin()); 
+	      Trig::FeatureContainer::combination_const_iterator combEnd(f.getCombinations().end());
+	      
+	      while ( comb!=combEnd ) { 
+		
+		std::string vnames[2] = { "xPrimVx", "EFHistoPrmVtx" };
+		
+		for ( unsigned iv=0 ; iv<2 ; iv++ ) { 
+		  std::vector< Trig::Feature<xAOD::VertexContainer> > fvtx = comb->get<xAOD::VertexContainer>( vnames[iv] );
+		  
+		  for ( unsigned ivt=0 ; ivt<fvtx.size() ; ivt++ ) { 
+		    
+		    const xAOD::VertexContainer* vert = fvtx[ivt].cptr();
+		      
+		    xAOD::VertexContainer::const_iterator vit = vert->begin();
+		    
+		    for ( ; vit != vert->end(); ++vit ) {
+		      std::cout << "\t" << vnames[iv] 
+				<< "\tx " << (*vit)->x() << "\ty " << (*vit)->y() << "\tz " << (*vit)->z() 
+				<< "\tntracks " <<  (*vit)->nTrackParticles()
+				<< std::endl;
+		    }
+		  }
+		}		
+		
+		comb++;
+	      }
+	    }	
+	  }
+	  
+       	}
+#endif
+
+
+
+	/// bomb out if no chains passed and not told to keep all events  
+
+
+
+	int passed_chains = 0;
+
+	m_provider->msg(MSG::INFO) << "Checking " << m_chainNames.size() << " chains" << endmsg;
+	
+	if ( m_chainNames.empty() ) {
+	  m_provider->msg(MSG::WARNING) << "No chains to check" << endmsg;
+	  return;
+	}
+
+	for ( unsigned ichain=0 ; ichain<m_chainNames.size() ; ichain++ ) {
+  
+		const std::string& chainName = m_chainNames[ichain].head();
+
+		// Only for trigger chains
+
+		if (chainName.find("L2")  == std::string::npos && 
+		    chainName.find("EF")  == std::string::npos && 
+		    chainName.find("HLT") == std::string::npos ) continue;
+
+		if ( configuredHLTChains.find(chainName)==configuredHLTChains.end() ) {
+			m_provider->msg(MSG::WARNING) << "" << "Chain " << chainName 
+				<< " is not configured for this event" << ""
+				<< endmsg;
+			continue;
+		}
+
+		
+		std::string roistring = "";
+		if ( m_chainNames[ichain].roi()!=""  ) roistring += "\troi " + m_chainNames[ichain].roi();  
+
+		bool passPhysics = (*m_tdt)->isPassed(chainName); 
+
+		m_provider->msg(MSG::INFO) << "Chain "  << chainName << "\troi " << roistring 
+					   << "\tpres " << (*m_tdt)->getPrescale(chainName)
+					   << ( passPhysics ? "" : "" ) << "\tpass physics  " <<  passPhysics << ( passPhysics ? "" : "" ) 
+					   << "\t: ( pass " << (*m_tdt)->isPassed(chainName, decisiontype_ ) << "\tdec type " << decisiontype_ << " ) " << endmsg;
+
+		if ( (*m_tdt)->isPassed(chainName, decisiontype_ ) ) { 
+		  analyse = true;
+		  passed_chains++;
+		}
+
+	} /// finished loop over chains
+
+
+
+	/// bomb out if no chains passed and not told to keep all events and found no 
+	/// offline objects 
+	if ( !analyse && !m_keepAllEvents && !foundOffline ) { 
+	  m_provider->msg(MSG::INFO) << "No chains passed unprescaled - not processing this event: " << run_number << " " << event_number << " " << lumi_block << endmsg; 
+	  return;
+	}
+	
+
+	m_provider->msg(MSG::INFO) << "Chains passed " << passed_chains << endmsg;
+
+
+	/// for Monte Carlo get the truth particles if requested to do so
+
+	//  const TruthParticleContainer*  mcpartTES = 0;
+
+	selectorTruth.clear();
+
+	m_provider->msg(MSG::INFO) << "MC Truth flag " << m_mcTruth << endmsg; 
+	const TrigInDetTrackTruthMap* truthMap = 0;
+	bool foundTruth = false;
+	if ( m_mcTruth && m_TruthPdgId!=15) { 
+		m_provider->msg(MSG::INFO) << "getting Truth" << endmsg; 
+		if ( m_provider->evtStore()->retrieve(truthMap, "TrigInDetTrackTruthMap").isFailure()) {
+		        // m_provider->msg(MSG::WARNING) << "TrigInDetTrackTruthMap not found" << endmsg;
+			m_hasTruthMap = false;
+		}
+		else {
+			m_provider->msg(MSG::INFO) << "TrigInDetTrackTruthMap found" << endmsg;
+			m_hasTruthMap = true;
+		}
+		if (m_provider->evtStore()->contains<TruthParticleContainer>("INav4MomTruthEvent")) {
+			//ESD
+			selectTracks<TruthParticleContainer>( &selectorTruth, "INav4MomTruthEvent" );
+			foundTruth = true;
+		}
+		else if (m_provider->evtStore()->contains<TruthParticleContainer>("SpclMC")) {
+			/// AOD
+			selectTracks<TruthParticleContainer>( &selectorTruth, "SpclMC");
+			foundTruth = true;
+		}
+		else if (m_provider->evtStore()->contains<TruthParticleContainer>("")) {
+			/// anything else?
+			selectTracks<TruthParticleContainer>( &selectorTruth, "");
+			foundTruth = true;
+		}
+		else if (m_provider->evtStore()->contains<xAOD::TruthParticleContainer>("TruthParticles")) {
+			/// anything else?
+		        selectTracks<xAOD::TruthParticleContainer>( &selectorTruth, "TruthParticles" );
+			foundTruth = true;
+		}
+		else { 
+			m_provider->msg(MSG::WARNING) << "Truth not found - none whatsoever!" << endmsg; 
+		}
+	}
+
+
+	/// No lovely truth particle collections, so will need to 
+	/// navigate through the egregious McTruthCollection, looking 
+	/// at the GenParticles on each GenVertex in the collection
+	/// lovely...
+
+	if ( m_mcTruth && !foundTruth ) { 
+
+		m_provider->msg(MSG::INFO) << "getting Truth" << endmsg; 
+
+		/// selectTracks<TruthParticleContainer>( &selectorTruth, "INav4MomTruthEvent" );
+
+		const DataHandle<McEventCollection> mcevent;
+
+		/// now as a check go through the GenEvent collection
+
+		std::string collectionNames[4] = { "GEN_AOD", "TruthEvent", "", "G4Truth" };
+
+		std::string collectionName = "";
+
+		bool foundcollection = false;
+
+		for ( int ik=0 ; ik<4 ; ik++ ) { 
+
+			m_provider->msg(MSG::INFO) << "Try McEventCollection: " << collectionNames[ik] << endmsg;
+
+			if (!m_provider->evtStore()->contains<McEventCollection>(collectionNames[ik]) ) { 
+				m_provider->msg(MSG::INFO) << "No McEventCollection: " << collectionNames[ik] << endmsg;
+				continue;
+			}
+
+			m_provider->msg(MSG::INFO) << "evtStore()->retrieve( mcevent, " << collectionNames[ik] << " )" << endmsg;  
+
+			if ( m_provider->evtStore()->retrieve( mcevent, collectionNames[ik] ).isFailure() ) {     
+				m_provider->msg(MSG::INFO) << "Failed to get McEventCollection: " << collectionNames[ik] << endmsg;
+			}
+			else { 
+				// found this collectionName
+				collectionName = collectionNames[ik];
+				m_provider->msg(MSG::INFO) << "Found McEventCollection: " << collectionName << endmsg;
+				foundcollection = true;
+				break;
+			}
+		}
+
+		// not found any collection
+		if ( !foundcollection ) { 
+
+			m_provider->msg(MSG::WARNING) << "No MC Truth Collections of any sort, whatsoever!!!" << endmsg;
+
+			//    m_tree->Fill();
+
+			//    return StatusCode::FAILURE;
+
+			return;
+		}
+
+		//////////////////////////////////////////////////////////////////////////////////
+		/// This is a nasty hack  to find the truth collections 
+		/// why, why, why, why, why oh why, is it sooooo 
+		/// difficult to navigate through this nonsense  
+		/// it's not at all tidy, and should be rewritten, 
+		/// but probably never will be
+
+		m_provider->msg(MSG::INFO) << "Found McEventCollection: " << collectionName << "\tNevents " << mcevent->size() << endmsg;
+
+		/// count the number of interactions of each sort
+		/// this is actually *very stupid*, there are a *lot*
+		/// of "processes" with *no* particles in them for some 
+		/// reason, whoever programed this f**cked up structure 
+		/// that needs this sort of fannying around to navigate 
+
+		McEventCollection::const_iterator evitr(mcevent->begin());
+		McEventCollection::const_iterator evend(mcevent->end());
+
+		unsigned ie = 0; /// count of "events" - or interactions
+		unsigned ip = 0; /// count of particles
+		
+		unsigned ie_ip = 0; /// count of "events with some particles"
+		
+		while ( evitr!=evend ) { 
+		  
+		  int _ip = 0; /// count of particles in this interaction 
+		  
+		  int pid = (*evitr)->signal_process_id();
+		  
+		  //      if ( (*evitr)->particles_size()>0 ) std::cout << "process " << "\tpid " << pid << std::endl;  
+		  
+		  if ( pid!=0 && (*evitr)->particles_size()>0 ) { /// hooray! actually found a sensible event
+		    
+		    /// go through the particles
+		    HepMC::GenEvent::particle_const_iterator pitr((*evitr)->particles_begin());
+		    HepMC::GenEvent::particle_const_iterator pend((*evitr)->particles_end());
+		    
+		    while ( pitr!=pend ) { 
+		      
+		      //	int pdg_id = (*pitr)->pdg_id();
+		      //	std::cout << ip++ << "\tparticle " << pdg_id << "\t" << "(*pitr)->pT()" << std::endl; 
+		      
+		      //if tau job, only select if have a tau somewhere along chain, otherwise just add
+		      if ( (m_TruthPdgId==15 && fromParent(m_TruthPdgId, *pitr)!=0) || m_TruthPdgId!=15 ) {
+			
+			/// select the ones of interest 
+			selectorTruth.selectTrack( *pitr );
+		      }
+		      
+		      
+		      ++_ip;
+		      
+		      ++pitr; 
+		      
+		    }
+		    
+		    
+		  }
+		  
+		  ++ie;
+		  ++evitr;
+		  
+		  if ( _ip>0 ) {
+		    /// if there were some particles in this interaction ...
+		    //	m_provider->msg(MSG::INFO) << "Found " << ie << "\tpid " << pid << "\t with " << ip << " TruthParticles (GenParticles)" << endmsg;
+		    ++ie_ip;  
+		    ip += _ip;
+		  }
+		}
+		
+		m_provider->msg(MSG::INFO) << "Found " << ip << " TruthParticles (GenParticles) in " << ie_ip << " GenEvents out of " << ie << endmsg;
+		
+		m_provider->msg(MSG::INFO) << "selected " << selectorTruth.size() << " TruthParticles (GenParticles)" << endmsg;
+
+		////////////////////////////////////////////////////////////////////////////////////////
+
+		if ( !(ip>0) ) {    
+			m_provider->msg(MSG::WARNING) << "NO TRUTH PARTICLES - returning" << endmsg;
+			return; /// need to be careful here, if not requiring truth *only* should not return
+		}
+
+	}
+
+
+
+	// clear the ntuple TIDA::Event class
+	m_event->clear();
+
+	/// get (offline) reference tracks 
+
+	/// get offline tracks
+
+	m_provider->msg(MSG::INFO) << " Offline tracks " << endmsg;
+
+	selectorRef.clear();
+
+	if      (m_provider->evtStore()->contains<xAOD::TrackParticleContainer>("InDetTrackParticles")) {
+	  selectTracks<xAOD::TrackParticleContainer>( &selectorRef, "InDetTrackParticles" );
+	}
+	else if (m_provider->evtStore()->contains<Rec::TrackParticleContainer>("TrackParticleCandidate")) {
+	  selectTracks<Rec::TrackParticleContainer>( &selectorRef, "TrackParticleCandidate" );
+        }
+	else { 
+	  m_provider->msg(MSG::WARNING) << " Offline tracks not found " << endmsg;
+	}
+	
+
+	/// get the offline vertices into our structure
+	
+	std::vector<TIDA::Vertex> vertices;
+
+	//	std::vector<TIDA::Vertex> vertices;
+	
+	m_provider->msg(MSG::VERBOSE) << "fetching AOD Primary vertex container" << endmsg;
+
+	const xAOD::VertexContainer* xaodVtxCollection = 0;
+
+	if ( m_provider->evtStore()->retrieve( xaodVtxCollection, "PrimaryVertices" ).isFailure()) {
+	  m_provider->msg(MSG::WARNING) << "xAOD Primary vertex container not found with key " << "PrimaryVertices" <<  endmsg;
+	}
+	
+	if ( xaodVtxCollection!=0 ) { 
+	  
+	  m_provider->msg(MSG::INFO) << "xAOD Primary vertex container " << xaodVtxCollection->size() <<  " entries" << endmsg;
+
+	  xAOD::VertexContainer::const_iterator vtxitr = xaodVtxCollection->begin();
+	  for ( ; vtxitr != xaodVtxCollection->end(); vtxitr++ ) {
+
+	    /// useful debug information - leave in 
+	    //	    std::cout << "SUTT  xAOD::Vertex::type() " << (*vtxitr)->type() << "\tvtxtype " << (*vtxitr)->vertexType() << "\tntrax " << (*vtxitr)->nTrackParticles() << std::endl; 
+
+	    if ( (*vtxitr)->nTrackParticles()>0 && (*vtxitr)->vertexType()!=0 ) {
+              vertices.push_back( TIDA::Vertex( (*vtxitr)->x(),
+						(*vtxitr)->y(),
+						(*vtxitr)->z(),
+						/// variances                                                                                          
+						(*vtxitr)->covariancePosition()(Trk::x,Trk::x),
+						(*vtxitr)->covariancePosition()(Trk::y,Trk::y),
+						(*vtxitr)->covariancePosition()(Trk::z,Trk::z),
+						(*vtxitr)->nTrackParticles(),
+						/// quality                                                                                            
+						(*vtxitr)->chiSquared(),
+						(*vtxitr)->numberDoF() ) );
+            }
+
+	  }
+	}
+
+
+	/// add offline Vertices to the Offline chain
+	
+	
+	/// add the truth particles if needed
+	
+	if ( m_mcTruth ) {
+	  m_event->addChain( "Truth" ); 
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addTracks(selectorTruth.tracks());
+	}
+
+
+	/// now add the vertices
+
+	/// useful debug information - leave in  
+	//	std::cout << "SUTT Nvertices " << vertices.size() << "\ttype 101 " << vertices_full.size() << std::endl;
+
+	for ( unsigned i=0 ; i<vertices.size() ; i++ )  { 
+	  m_provider->msg(MSG::INFO) << "vertex " << i << " " << vertices[i] << endmsg;
+	  m_event->addVertex(vertices[i]);
+	}
+	
+
+	/// offline object counters 
+
+	int Noff  = 0;
+	int Nmu   = 0;
+	int Nel   = 0;
+        int Ntau  = 0;
+
+
+	/// now add the offline vertices
+
+	if ( m_doOffline || m_doVertices ) { 	  
+	  m_event->addChain( "Vertex" );
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addVertices( vertices );
+	}	 
+
+
+	/// now add the offline tracks
+
+	if ( m_doOffline ) { 
+	  
+	  m_event->addChain( "Offline" );
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addTracks(selectorRef.tracks());
+	
+	  if ( selectorRef.getBeamX()!=0 || selectorRef.getBeamY()!=0 || selectorRef.getBeamZ()!=0 ) { 
+	    std::vector<double> beamline_;
+	    beamline_.push_back( selectorRef.getBeamX() );
+	    beamline_.push_back( selectorRef.getBeamY() );
+	    beamline_.push_back( selectorRef.getBeamZ() );
+	    m_event->back().back().addUserData(beamline_);
+	  }
+	  else { 
+	    m_event->back().back().addUserData(beamline);
+	  }
+
+
+
+	  Noff = selectorRef.tracks().size();
+	  
+	  m_provider->msg(MSG::DEBUG) << "ref tracks.size() " << selectorRef.tracks().size() << endmsg; 
+	  for ( int ii=selectorRef.tracks().size() ; ii-- ; ) m_provider->msg(MSG::DEBUG) << "  ref track " << ii << " " << *selectorRef.tracks()[ii] << endmsg;  
+	  
+	}
+
+	/// navigate through the requested storegate TEST chains
+	
+	for ( unsigned ichain=0 ; ichain<m_chainNames.size() ; ichain++ ) {  
+	  
+	  m_provider->msg(MSG::INFO)<< "chain:\t" << m_chainNames[ichain] << endmsg;
+
+	  /// get the chain, collection and TE names and track index 
+
+	  const std::string& chainname      = m_chainNames[ichain].head();
+	  const std::string& collectionname = m_chainNames[ichain].tail();
+
+	  if ( chainname!="" )      continue;
+	  if ( collectionname=="" ) continue;
+
+	  /// useful debug information - leave this here
+
+	  //	  const std::string& index          = m_chainNames[ichain].extra();
+	  //	  const std::string& element        = m_chainNames[ichain].element();
+
+	  //	  std::cout << "\tchain: " << chainname << "\tcollection: " << collectionname << "\tindex: " << index << "\tte: " << element << std::endl;  
+
+	  /// here we *only* want collections with no specified chain
+	  /// name, then we look in storegate for the collections directly
+
+	  selectorTest.clear();
+
+	  bool found = false;
+	  
+	  std::string collection_test = collectionname;
+	  size_t pos = collectionname.find("/");
+	  if ( pos!=std::string::npos ) collection_test = collectionname.substr( pos+1, collectionname.size()-pos );
+
+	  if (m_provider->evtStore()->contains<Rec::TrackParticleContainer>(collection_test)) {
+	    found = selectTracks<Rec::TrackParticleContainer>( &selectorTest, collectionname );
+	  }
+	  else if (m_provider->evtStore()->contains<xAOD::TrackParticleContainer>(collection_test)) {
+	    found = selectTracks<xAOD::TrackParticleContainer>( &selectorTest, collectionname );
+	  }
+	  else if (m_provider->evtStore()->contains<TrigInDetTrackCollection>(collection_test)) {
+	    found = selectTracks<TrigInDetTrackCollection>( &selectorTest, collectionname );
+	  }
+	  else if (m_provider->evtStore()->contains<TrackCollection>(collection_test)) {
+	    found = selectTracks<TrackCollection>( &selectorTest, collectionname );
+	  }
+	  else { 
+	    m_provider->msg(MSG::WARNING) << "\tcollection " << collectionname << " not found" << endmsg;
+	  }
+	  
+	  if ( found ) { 
+	    
+	    m_event->addChain( collectionname );
+	    m_event->back().addRoi(TIDARoiDescriptor(true));
+	    m_event->back().back().addTracks(selectorTest.tracks());
+	    
+	    if ( selectorTest.getBeamX()!=0 || selectorTest.getBeamY()!=0 || selectorTest.getBeamZ()!=0 ) { 
+	      std::vector<double> beamline_;
+	      beamline_.push_back( selectorTest.getBeamX() );
+	      beamline_.push_back( selectorTest.getBeamY() );
+	      beamline_.push_back( selectorTest.getBeamZ() );
+	      m_event->back().back().addUserData(beamline_);
+	    }
+	    else { 
+	      m_event->back().back().addUserData(beamline);
+	    }
+	    
+	    int Ntest = selectorTest.tracks().size();
+	    
+	    m_provider->msg(MSG::INFO) << "collection " << collectionname << "\ttest tracks.size() " << Ntest << endmsg; 
+	    for ( int ii=Ntest ; ii-- ; ) m_provider->msg(MSG::DEBUG) << "  test track " << ii << " " << *selectorTest.tracks()[ii] << endmsg;
+	  }
+	}	  
+
+
+	std::string ElectronRef[7] =  { 
+	  "", 
+	  "TightCB", "MediumCB", "LooseCB",
+	  "TightLH", "MediumLH", "LooseLH" };
+ 
+
+	/// new electron selection 
+
+	for ( size_t ielec=0 ; ielec<m_electronType.size() ; ielec++ ) {
+	  /// hmm, if we stored the types as a map it would be more 
+	  /// straightforward than having to stick all this in a loop
+
+	  int itype = -1;
+	  for ( int it=0 ; it<7 ; it++ ) if ( m_electronType[ielec]==ElectronRef[it] ) itype = it; 
+	  if ( itype<0 ) continue;
+
+	  std::vector<TrackTrigObject> elevec;
+	  
+	  /// useful debug information ...
+	  //	  std::cout << "\tElectrons selection " << ielec << " " << m_electronType[ielec] 
+	  //		    << "\t" << itype << " " << ElectronRef[itype] << "\t" << m_rawElectrons[ielec] << std::endl;
+	  
+	  int Nel_ = processElectrons( selectorRef, &elevec, itype, ( m_rawElectrons[ielec]=="raw" ? true : false ) );
+	  
+	  	  
+          if ( Nel_ < 1 ) continue;
+      
+          Nel += Nel_;	
+
+	  std::string echain = std::string("Electrons");
+          if ( m_electronType[ielec]!="" )    echain += "_" + m_electronType[ielec];
+	  if ( m_rawElectrons[ielec]=="raw" ) echain += "_raw";
+	  
+	  m_event->addChain( echain );
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addTracks(selectorRef.tracks());
+	  m_event->back().back().addObjects( elevec );
+
+	  // leave this in util fully validated ...
+	  // std::cout << m_event->back() << std::endl;
+	  
+	  if ( selectorRef.getBeamX()!=0 || selectorRef.getBeamY()!=0 || selectorRef.getBeamZ()!=0 ) { 
+	    std::vector<double> beamline_;
+	    beamline_.push_back( selectorRef.getBeamX() );
+	    beamline_.push_back( selectorRef.getBeamY() );
+	    beamline_.push_back( selectorRef.getBeamZ() );
+	    m_event->back().back().addUserData(beamline_);
+	  }
+	  else { 	  
+	    m_event->back().back().addUserData(beamline);
+	  }
+	}
+	
+       
+
+	std::string MuonRef[5] =  { "", "Tight", "Medium", "Loose", "VeryLoose" };
+
+	/// get muons 
+	for ( size_t imuon=0 ; imuon<m_muonType.size() ; imuon++ ) {
+	  
+	  m_provider->msg(MSG::INFO) << "fetching offline muons " << endmsg; 
+
+          int muonType = -1;
+          for ( int it=0 ; it<5 ; it++ ) if ( m_muonType[imuon] == MuonRef[it] ) muonType=it; 
+          if ( muonType<0 ) continue; 
+
+	  int Nmu_ = processMuons( selectorRef, muonType );
+
+          if ( Nmu_ < 1 ) continue;
+
+          Nmu += Nmu_;
+
+	  m_provider->msg(MSG::INFO) << "found " << Nmu << " offline muons " << endmsg; 
+
+          std::string mchain = "Muons";
+          if ( m_muonType[imuon]!="" )  mchain += "_" + m_muonType[imuon];
+
+	  m_event->addChain(mchain);
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addTracks(selectorRef.tracks());
+	  if ( selectorRef.getBeamX()!=0 || selectorRef.getBeamY()!=0 || selectorRef.getBeamZ()!=0 ) { 
+	      std::vector<double> beamline_;
+	      beamline_.push_back( selectorRef.getBeamX() );
+	      beamline_.push_back( selectorRef.getBeamY() );
+	      beamline_.push_back( selectorRef.getBeamZ() );
+	      m_event->back().back().addUserData(beamline_);
+	  }
+	  else { 	  
+	      m_event->back().back().addUserData(beamline);
+	  }
+
+	  m_provider->msg(MSG::DEBUG) << "ref muon tracks.size() " << selectorRef.tracks().size() << endmsg; 
+	  for ( int ii=selectorRef.tracks().size() ; ii-- ; ) m_provider->msg(MSG::INFO) << "  ref muon track " << ii << " " << *selectorRef.tracks()[ii] << endmsg;  
+	}
+	
+
+
+
+	/// get muons 
+	if ( m_doMuonsSP ) { 
+	  
+	  m_provider->msg(MSG::INFO) << "fetching offline muons " << endmsg; 
+
+          int muonType = 0;
+
+	  Nmu += processMuons( selectorRef, muonType );
+
+	  m_provider->msg(MSG::INFO) << "found " << Nmu << " offline muons " << endmsg; 
+
+	  m_event->addChain("MuonsSP");
+	  m_event->back().addRoi(TIDARoiDescriptor(true));
+	  m_event->back().back().addTracks(selectorRef.tracks());
+
+	  m_provider->msg(MSG::DEBUG) << "ref muon tracks.size() " << selectorRef.tracks().size() << endmsg; 
+	  for ( int ii=selectorRef.tracks().size() ; ii-- ; ) m_provider->msg(MSG::INFO) << "  ref muon track " << ii << " " << *selectorRef.tracks()[ii] << endmsg;  
+	}
+	
+
+
+	/// new tau selection 
+	std::string TauRef[4] = { "", "Tight", "Medium", "Loose" };
+	
+
+	for ( size_t itau=0 ; itau<m_tauType.size() ; itau++ ) {
+	  /// hmm, if we stored the types as a map it would be more 
+	  /// straightforward than having to stick all this in a loop
+
+	  int itype = -1;
+	  for ( int it=0 ; it<4 ; it++ ) if ( m_tauType[itau]==TauRef[it] ) itype = it; 
+	  if ( itype<0 ) continue;
+
+	  /// use same threshold for 1 and 3 prong ??
+	  int requireNtracks = 0;
+	  if  ( m_tauProngs[itau]=="3Prong" ) requireNtracks = 3;	
+	  if  ( m_tauProngs[itau]=="1Prong" ) requireNtracks = 1;
+
+	  std::vector<TrackTrigObject> tauvec; 
+
+	  int Ntau_ = processTaus( selectorRef, &tauvec, itype, requireNtracks, 20000 ); 
+
+	  Ntau += Ntau_;
+
+	  if ( Ntau_ > 0 ) { 
+	    /// only add a tau collection if there are actually the 
+	    /// relevant taus
+	    std::string tchain = std::string("Taus");
+	    if (   m_tauType[itau] != "" ) tchain += "_" + m_tauType[itau];
+	    if ( m_tauProngs[itau] != "" ) tchain += "_" + m_tauProngs[itau];
+	    
+	    m_event->addChain( tchain );
+	    m_event->back().addRoi(TIDARoiDescriptor(true));
+	    m_event->back().back().addTracks(selectorRef.tracks());
+	    m_event->back().back().addObjects( tauvec ) ; 
+
+	    // leave this in util fully validated ...
+	    //	    std::cout << m_event->back() << std::endl;
+
+	    if ( selectorRef.getBeamX()!=0 || selectorRef.getBeamY()!=0 || selectorRef.getBeamZ()!=0 ) { 
+	      std::vector<double> beamline_;
+	      beamline_.push_back( selectorRef.getBeamX() );
+	      beamline_.push_back( selectorRef.getBeamY() );
+	      beamline_.push_back( selectorRef.getBeamZ() );
+	      m_event->back().back().addUserData(beamline_);
+	    }
+	    else { 	  
+	      m_event->back().back().addUserData(beamline);
+	    }
+	  }
+	}
+	
+	/// useful debug information 0 leave here 
+	//	std::cout << "SUTT Ntaus: " << Ntau << std::endl;
+	
+	if ( Nmu==0 && Noff==0 && Nel==0 && Ntau==0 ) m_provider->msg(MSG::INFO) << "No offline objects found " << endmsg;
+	else foundOffline = true;
+
+
+	// now loop over all relevant chains to get the trigger tracks...
+	for ( unsigned ichain=0 ; ichain<m_chainNames.size() ; ichain++ ) {  
+
+		// create chains for ntpl
+
+		/// get the chain name
+		const std::string& chainName = m_chainNames[ichain].head();
+
+		/// and the name of the collection (if any)    
+		const std::string& collectionName = m_chainNames[ichain].tail();
+
+
+		if( chainName.find("L2_")==std::string::npos && 
+		    chainName.find("EF_")==std::string::npos && 
+		    chainName.find("HLT_")==std::string::npos ) continue;
+
+		
+		m_provider->msg(MSG::INFO) << "chain " << chainName 
+					   << "\tprescale " << (*m_tdt)->getPrescale(chainName)
+					   << "\tpass "     << (*m_tdt)->isPassed(chainName) << " physics " 
+					   << "  (req dec " << (*m_tdt)->isPassed(chainName, decisiontype_ ) << " dec type " << decisiontype_ << ")"
+					   << endmsg;
+		
+		/// now decide whether we want all the TEs for this chain, or just those 
+		/// that are still active
+		unsigned decisiontype;
+                if ( m_chainNames[ichain].passed() ) decisiontype = decisiontype_;
+		else                                 decisiontype = TrigDefs::alsoDeactivateTEs;
+
+
+		/// if the chain did not pass, skip this chain completely 
+		if ( !(*m_tdt)->isPassed( chainName, decisiontype_ ) ) continue;
+
+
+		/// new MT TDT feature access  
+		
+
+		std::string roi_key  = m_chainNames[ichain].roi();
+		std::string vtx_name = m_chainNames[ichain].vtx();
+
+
+#if 0
+		/// this code needs to be here to be eventually replaced when 
+		/// the TDT combination feature retrieval has been implemented
+		/// at that point it can be replaced by the appropriate 
+		/// code using the new TDT feature access
+
+		if ( roi_name!="" ) { 
+
+		  std::string roi_name_tmp = roi_name;
+		  std::string roi_tename   = "";
+		  
+		  if ( roi_name.find("/")!=std::string::npos ) { 
+		    roi_name_tmp = roi_name.substr( roi_name.find("/")+1, roi_name.size()-roi_name.find("/") );
+		    roi_tename   = roi_name.substr( 0, roi_name.find("/") );
+		  }
+		  
+		  roist = comb->get<TrigRoiDescriptor>( roi_name_tmp, decisiontype_, roi_tename );
+		  
+		  if ( roist.size()>0 ) { 
+		    for ( unsigned ir=0 ; ir<roist.size() ; ir++ ) m_provider->msg(MSG::INFO) << "\t\tRetrieved roi  " << roi_name << "\t" << *roist[ir].cptr() << endmsg; 
+		  }
+		  else { 
+		    m_provider->msg(MSG::WARNING) << "\t\tRequested roi  " << roi_name << " not found" << endmsg; 
+		  }
+		  
+		}
+		else { 
+		  roist = comb->get<TrigRoiDescriptor>("forID1"); 
+		  if ( roist.empty() ) roist = comb->get<TrigRoiDescriptor>("forID"); 
+		  if ( roist.empty() ) roist = comb->get<TrigRoiDescriptor>(""); 
+		  if ( roist.empty() ) roist = comb->get<TrigRoiDescriptor>("initialRoI"); 
+		}			  
+#endif
+		
+
+		std::vector< TrigCompositeUtils::LinkInfo<TrigRoiDescriptorCollection> > rois = 
+		  (*m_tdt)->template features<TrigRoiDescriptorCollection>( chainName, 
+									    decisiontype, 
+									    roi_key, 
+									    TrigDefs::lastFeatureOfType, 
+									    "roi" );
+		 
+		/// leave this here for the moment until we know everything is working ...
+		// const unsigned int featureCollectionMode = const std::string& navElementLinkKey = "roi") const;
+		
+		int iroi = 0; /// count of how many rois processed so far
+
+		/// if no rois for this chain then move along
+
+		if ( rois.size()==0 ) continue;
+
+		/// create the analysis chain
+
+		m_event->addChain( m_chainNames[ichain] );
+
+		TIDA::Chain& chain = m_event->back();
+
+
+		for ( const TrigCompositeUtils::LinkInfo<TrigRoiDescriptorCollection> roi_info : rois ) {
+		    
+		  iroi++;
+
+		  /// don't extract any additional rois if a superRoi is requested: 
+		  /// In this case, the superRoi would be shared between the different 
+		  /// chains 
+
+		  if ( roi_key=="SuperRoi" && iroi>1 ) continue; 
+		  
+		  const ElementLink<TrigRoiDescriptorCollection> roi_link = roi_info.link;
+
+		  const TrigRoiDescriptor* const* roiptr = roi_link.cptr();
+
+		  if ( roiptr == 0 ) { 
+		    //    std::cerr << "\treadback link is null  DAMMIT !!!" << std::endl;
+		    continue;
+		  }  
+
+		  if (m_provider->msg().level() <= MSG::VERBOSE) {
+		    m_provider->msg(MSG::VERBOSE) << " RoI descriptor for seeded chain " << chainName << " " << **roiptr << endmsg;
+		  }
+
+		  TIDARoiDescriptor* roi_tmp = new TIDARoiDescriptor( TIDARoiDescriptorBuilder(**roiptr) );		   
+
+		  /// get the tracks 
+
+		  //////////////////////////////////
+
+		  ///   useful cocumentation line ... 
+		  ///   std::string keys[5] = { "TrigJetRec", "TrigSplitJet", "TrigSuperRoi", "forID", "" };
+			  
+		  //   m_provider->msg(MSG::INFO) << "using chain roi " << *roid << endmsg;
+		  m_provider->msg(MSG::INFO) << "TIDARoi " << *roi_tmp << "\tcollectionName: " << collectionName << endmsg;
+			      
+		  /// this should *never* be the case, and we should only run this 
+		  /// bit of code once the first time round the loop anyhow
+			      
+		  selectorTest.clear();
+
+
+		  if ( chainName.find("HLT_")!=std::string::npos ) {
+		    if ( selectTracks<xAOD::TrackParticleContainer>( &selectorTest, roi_link,  collectionName ) ); 
+		    else m_provider->msg(MSG::WARNING) << "\tNo track collection " << collectionName << " found"  << endmsg;  
+		  }
+		  
+		  /// fetch vertices if available ...
+		  
+		  std::vector<TIDA::Vertex> tidavertices;	
+		  
+		  if ( vtx_name!="" ) { 
+		    
+		    m_provider->msg(MSG::INFO) << "\tFetch xAOD::VertexContainer for chain " << chainName << " with key " << vtx_name << endmsg;
+		    
+		    /// MT Vertex access
+		    
+		    std::pair< xAOD::VertexContainer::const_iterator, 
+			       xAOD::VertexContainer::const_iterator > vtx_itrpair = getCollection<xAOD::VertexContainer>( roi_link, vtx_name );
+		    
+		    if ( vtx_itrpair.first == vtx_itrpair.second ) { 
+		      m_provider->msg(MSG::WARNING) << "\tNo xAOD::Vertex for chain " << chainName << " for key " << vtx_name << endmsg;
+		    }
+		    else {
+		      
+		      m_provider->msg(MSG::INFO) << "\txAOD::VertexContainer found with size  " << (vtx_itrpair.second - vtx_itrpair.first) 
+						 << "\t" << vtx_name << endmsg;
+		      
+		      xAOD::VertexContainer::const_iterator vtxitr = vtx_itrpair.first; 
+		      
+		      for (  ; vtxitr!=vtx_itrpair.second  ;  vtxitr++ ) {
+			
+			/// leave this code commented so that we have a record of the change - as soon as we can 
+			/// fix the missing track multiplicity from the vertex this will need to go back  
+			//  if ( ( (*vtxitr)->nTrackParticles()>0 && (*vtxitr)->vertexType()!=0 ) || vtx_name=="EFHistoPrmVtx" ) {
+			if ( (*vtxitr)->vertexType()!=0  || vtx_name=="EFHistoPrmVtx" ) {
+			  tidavertices.push_back( TIDA::Vertex( (*vtxitr)->x(),
+								(*vtxitr)->y(),
+								(*vtxitr)->z(),
+								/// variances
+								(*vtxitr)->covariancePosition()(Trk::x,Trk::x),
+								(*vtxitr)->covariancePosition()(Trk::y,Trk::y),
+								(*vtxitr)->covariancePosition()(Trk::z,Trk::z),
+								(*vtxitr)->nTrackParticles(),
+								/// quality
+								(*vtxitr)->chiSquared(),
+								(*vtxitr)->numberDoF() ) );
+			}
+		      }
+		      
+		    }
+		    
+		  }
+
+#if 0 
+		  //// not yet ready to get the jet yet - this can come once everything else is working 
+		  // now get the jets if they are present
+		  std::vector<TrackTrigObject> jets; 
+		  if ( chainName.find("HLT_j")!=std::string::npos ) { 
+		    if ( get_jets( comb, jets ) == 0 ) m_provider->msg(MSG::WARNING) << "\tjets could not be retrieved " << endmsg; 
+		  }			  		    
+#endif
+		  
+		  const std::vector<TIDA::Track*>& testTracks = selectorTest.tracks();
+		  m_provider->msg(MSG::DEBUG) << "\ttest tracks.size() " << testTracks.size() << endmsg; 
+		  for (unsigned int ii=0; ii < testTracks.size(); ii++) {
+		    m_provider->msg(MSG::DEBUG) << "  test track " << ii << "for chain " << chainName + ":" + collectionName << " " << *testTracks[ii] << endmsg;  
+		  }
+		  
+		  
+		  // only add chain if there are any rois - also add beamline position for postprocessing
+		  
+		  
+		  if ( roi_tmp == 0 ) { 
+		    if ( testTracks.size()>0 ) m_provider->msg(MSG::WARNING) << "\ttest tracks.size() " << testTracks.size() << "found but no roi!!!" << endmsg;
+		    roi_tmp = new TIDARoiDescriptor(true);
+		  }
+		  
+		  
+		  
+		  chain.addRoi( *roi_tmp );
+		  chain.back().addTracks(testTracks);
+		  chain.back().addVertices(tidavertices);
+		  chain.back().addUserData(beamline_online);
+		  
+#if 0
+		  /// jets can't be added yet
+		  if ( chainName.find("HLT_j")!=std::string::npos ) chain.back().addObjects( jets );
+#endif
+		  
+		  if ( selectorTest.getBeamX()!=0 || selectorTest.getBeamY()!=0 || selectorTest.getBeamZ()!=0 ) { 
+		    std::vector<double> beamline_;
+		    beamline_.push_back( selectorTest.getBeamX() );
+		    beamline_.push_back( selectorTest.getBeamY() );
+		    beamline_.push_back( selectorTest.getBeamZ() );
+		    chain.back().addUserData(beamline_);
+		  }
+		  else { 	  
+		    if ( beamline_online.size()>3 ) chain.back().addUserData(beamline_online);
+		  }
+		  
+		  
+		  //			m_provider->msg(MSG::INFO) << " done" << endmsg;      
+		  
+		  if ( roi_tmp ) delete roi_tmp;
+		  roi_tmp = 0;
+		}
+		
+		
+	}
+
+#if 0
+	/// don;t include this code at the moment ...
+
+	{ 
+	  /// strip out the offline tracks not in any Roi ...
+
+	  if ( filterOnRoi() || m_ptmin>0 ) { 
+	    
+	    TIDA::Chain* offline = 0;
+	    
+	    std::vector<std::string> chainnames = m_event->chainnames();
+	    
+	    /// get the offline chain
+	    
+	    for ( size_t ic=chainnames.size() ; ic-- ; ) {
+	      if ( chainnames[ic] == "Offline" ) {
+		offline = &(m_event->chains()[ic]);
+		break;
+	      }
+	    }
+	    
+	    if ( offline ) { 
+	      
+	      std::vector<TIDA::Chain>& chains = m_event->chains();
+	      std::vector<TIDA::Chain>::iterator citr = chains.begin();
+	      
+	      std::vector<std::pair<double,double> > philims;
+	      
+	      for ( ; citr!=chains.end() ; citr++ ) {
+		if ( citr->name().find("HLT_")!=std::string::npos ) { 
+		  for ( size_t ir=0 ; ir<citr->size() ; ir++ ) {
+		    TIDARoiDescriptor& roi = citr->rois()[ir].roi();
+		    if ( roi.composite() ) { 
+		      for ( size_t isub=0 ; isub<roi.size() ; isub++ ) { 
+			philims.push_back( std::pair<double,double>( roi[isub]->phiMinus(), roi[isub]->phiPlus() ) ); 
+		      }
+		    }
+		    else philims.push_back( std::pair<double,double>( roi.phiMinus(), roi.phiPlus() ) ); 
+		  }
+		}
+	      }
+	      
+	      remove_duplicates( philims );
+
+	      for ( size_t iroi=0 ; iroi<offline->size() ; iroi++ ) {
+		
+		std::vector<TIDA::Track>& tracks = offline->rois()[iroi].tracks();
+		
+		/// may well put the reporting back in, so leaving this 
+		/// this in place  
+		//  size_t Noffline = tracks.size();
+
+		for ( std::vector<TIDA::Track>::iterator it=tracks.begin() ; it<tracks.end() ; ) {
+		  bool inc = true;
+		  if ( m_ptmin>0 ) { 
+		    if ( std::fabs(it->pT())<m_ptmin ) { inc=false; tracks.erase( it ); }
+		  }
+		  if ( inc && filterOnRoi() ) { 
+		    bool remove_track = true;
+		    for ( size_t isub=0 ; isub<philims.size() ; isub++ ) { 
+		      
+		      if ( philims[isub].first < philims[isub].second ) { 
+			if ( it->phi()>=philims[isub].first && it->phi()<=philims[isub].second ) { 
+			  remove_track = false; 
+			  break;
+			}
+		      }
+		      else  {
+			if ( it->phi()>=philims[isub].first || it->phi()<=philims[isub].second ) { 
+			  remove_track = false; 
+			  break;
+			}
+		      }
+		    }
+		    if ( remove_track ) { inc=false; tracks.erase( it ); }
+		  }
+		  if ( inc ) it++;
+		}
+		
+		/// may well put the reporting back in, so leaving this 
+		/// this in place  		
+		//  m_provider->msg(MSG::DEBUG) << "TIDA::Roi offline track reduction: " << Noffline << " -> " << tracks.size() << endmsg;
+		
+	      }
+	     
+	    }
+	    	    
+	  }
+	}
+
+#endif
+
+	//	if ( m_printInfo ) m_provider->msg(MSG::INFO) << "FILL TREE\n" << (*m_event) << endmsg;      
+	if ( mTree ) mTree->Fill();
+	
+}
+
+
+
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/TrigTestMonToolAC.cxx b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/TrigTestMonToolAC.cxx
index feae91074beeb7673b147284bc47707ac68681c5..5cd63ff43884d5a23f006164c674071ede6c1be5 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/TrigTestMonToolAC.cxx
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisExample/src/TrigTestMonToolAC.cxx
@@ -17,6 +17,7 @@
 #include "TrigInDetAnalysisExample/TrigTestMonToolAC.h"
 #include "TrigInDetAnalysisExample/AnalysisConfig_Tier0.h"
 #include "TrigInDetAnalysisExample/AnalysisConfig_Ntuple.h"
+#include "TrigInDetAnalysisExample/AnalysisConfigMT_Ntuple.h"
 #include "TrigInDetAnalysisExample/ChainString.h"
 
 #include "AthenaMonitoring/AthenaMonManager.h"
@@ -123,9 +124,9 @@ StatusCode TrigTestMonToolAC::init() {
 
   msg(MSG::DEBUG) << " ----- enter init() ----- " << endmsg;
 
-  msg(MSG::INFO) << "TrigTestMonToolAC::init() " << gDirectory->GetName() << endmsg;
+  msg(MSG::INFO) << "TrigTestMonToolAC::init() " << gDirectory->GetName() << " " << __DATE__ << endmsg;
 
-  //  std::cout << "TrigTestMonToolAC::init() SUTT buildNtuple " << m_buildNtuple << std::endl;
+  std::cout << "SUTT TrigTestMonToolAC::init() SUTT buildNtuple " << m_buildNtuple << " " << __DATE__ << std::endl;
   
   // roi width information
   //  m_roiInfo.etaHalfWidth(m_etaWidth);
@@ -133,9 +134,23 @@ StatusCode TrigTestMonToolAC::init() {
   //  m_roiInfo.zedHalfWidth(m_zedWidth);
   
   if ( m_buildNtuple ) { 
-    m_sequences.push_back( new AnalysisConfig_Ntuple( &m_roiInfo, m_ntupleChainNames, 
-						      m_outputFileName, m_tauEtCutOffline, m_selectTruthPdgId, 
-						      m_keepAllEvents ) );
+    if ( m_tdt->getNavigationFormat() == "TriggerElement" ) { 
+
+      std::cout << "\n\nSUTT creating AnalysisConfig_Ntuple() COCK !!!\n\n" << std::endl;  
+
+      m_sequences.push_back( new AnalysisConfig_Ntuple( &m_roiInfo, m_ntupleChainNames, 
+							m_outputFileName, m_tauEtCutOffline, m_selectTruthPdgId, 
+							m_keepAllEvents ) );
+    }
+    else { 
+
+      std::cout << "\n\nSUTT creating AnalysisConfigMT_Ntuple()\n\n" << std::endl;  
+
+      m_sequences.push_back( new AnalysisConfigMT_Ntuple( &m_roiInfo, m_ntupleChainNames, 
+							  m_outputFileName, m_tauEtCutOffline, m_selectTruthPdgId, 
+							  m_keepAllEvents ) );
+    }
+
     m_sequences.back()->releaseData(m_releaseMetaData);
     if ( m_requireDecision ) m_sequences.back()->setRequireDecision(true);
     if ( m_mcTruth )         m_sequences.back()->setMCTruth(m_mcTruth);
@@ -273,9 +288,6 @@ StatusCode TrigTestMonToolAC::book(bool newEventsBlock, bool newLumiBlock, bool
 	
 	msg(MSG::INFO) << ""  << "booking a Tier0 chain " << m_chainNames[i] << " " << endmsg;
 	
-	//	std::cout  << ""  << "booking a Tier0 chain " << m_chainNames[i] << " " << std::endl;
-
-	//	if ( m_legacy && m_tdt->getNavigationFormat() == "TriggerElement" ) { 
 	if ( m_tdt->getNavigationFormat() == "TriggerElement" ) { 
 	
 	  m_sequences.push_back( new AnalysisConfig_Tier0(m_chainNames[i], 
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/CMakeLists.txt b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/CMakeLists.txt
index b5f57a5be873794698bfdeb6d7754d35e4356f34..8137f81113fc726eb3151ca01ef5c56a63f55980 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/CMakeLists.txt
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/CMakeLists.txt
@@ -17,6 +17,7 @@ atlas_depends_on_subdirs( PUBLIC
 			  Event/xAOD/xAODMuon
 			  Event/xAOD/xAODEgamma
 			  Event/xAOD/xAODTau
+			  Event/xAOD/xAODTruth
                           Tracking/TrkEvent/TrkParameters
                           Tracking/TrkEvent/TrkTrack
                           Tracking/TrkEvent/TrkTrackSummary
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/T_AnalysisConfig.h b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/T_AnalysisConfig.h
index 230263358685f9c5eb73ec61fa3c9a1ab024a3ef..6b20b7cd5da9f79846c6e5c485247d5b6024000b 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/T_AnalysisConfig.h
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/T_AnalysisConfig.h
@@ -301,6 +301,37 @@ protected:
 
   /// new MT feature access
 
+  template<class Collection>
+  std::pair< typename Collection::const_iterator, typename Collection::const_iterator >
+  getCollection( const ElementLink<TrigRoiDescriptorCollection>& roi_link,
+		 const std::string& key="" )  {
+
+    /// will need this printout for debugging the feature access, so leave this commented
+    /// until it has been properly debugged, then it can be removed
+    //    std::cout << "try " << key << "\t" << m_provider->evtStore()->template transientContains<Collection>(key) << std::endl;
+
+    /// will not use the te name here, but keep it on just the                                                                                       
+    /// same for the time being, for subsequent development                                                                                          
+    std::string key_collection = key;
+    std::string key_tename     = "";
+    size_t pos = key_collection.find("/");
+    if ( pos!=std::string::npos ) {
+      key_collection = key.substr( pos+1, key.size()-pos );
+      key_tename     = key.substr( 0, pos );
+    }
+
+    std::pair< typename Collection::const_iterator,
+	       typename Collection::const_iterator > itrpair;
+
+    SG::ReadHandle<Collection> handle(key);
+
+    itrpair = (*m_tdt)->associateToEventView( handle, roi_link );
+
+    return itrpair;
+  }
+
+
+
   template<class Collection>
   bool selectTracks( TrigTrackSelector* selector, 
 		     //		     const TrigCompositeUtils::LinkInfo<TrigRoiDescriptorCollection> roi_link,  
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/TrigTrackSelector.h b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/TrigTrackSelector.h
index 8da01df22003656ce4b03c1475442086cd4894a7..09a6a6f20557963f5d378a0e1746aadf5a11addf 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/TrigTrackSelector.h
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/TrigInDetAnalysisUtils/TrigTrackSelector.h
@@ -32,6 +32,7 @@
 #include "AtlasHepMC/GenEvent.h"
 #include "AtlasHepMC/GenVertex.h"
 #include "AtlasHepMC/GenParticle.h"
+#include "xAODTruth/TruthParticleContainer.h"
 
 
 ///// FrameWork includes
@@ -63,8 +64,10 @@ class TrigTrackSelector : public TrackSelector {
 
 public:
 
-  //  TrigTrackSelector( bool (*selector)(const TIDA::Track*)=NULL ) : TrackSelector(selector) {  } 
-  TrigTrackSelector( TrackFilter* selector );
+  /// use a radius of 47 mm corresponding to the Run 1 pixel inner radius
+  /// For the IBL it should be 32 mm, but this was kept as 47 mm for consistency 
+  /// of the definition. this should be changed to 32 mm for Run 3
+  TrigTrackSelector( TrackFilter* selector, double radius=47 );
 
   ~TrigTrackSelector() { clear(); }
 
@@ -97,6 +100,9 @@ public:
   // extract all the tracks from a TrackParticle collection and add them
   void selectTracks( const TruthParticleContainer* truthtracks );
 
+  // extract all the tracks from a TrackParticle collection and add them
+  void selectTracks( const xAOD::TruthParticleContainer* truthtracks );
+
 
   bool selectTrack( const HepMC::GenParticle* track );
 
@@ -107,6 +113,8 @@ public:
   // add a TruthParticle 
   bool selectTrack( const TruthParticle* track );
 
+  bool selectTrack( const xAOD::TruthParticle* track );
+
 
   // make a TIDA::Track from a GenParticle 
   TIDA::Track* makeTrack( const HepMC::GenParticle* track );
@@ -123,8 +131,6 @@ public:
   void selectTracks( const TrackCollection* trigtracks );
 
 
-#ifdef XAODTRACKING_TRACKPARTICLE_H
-
   /// legacy run 2 selector access
 
   bool selectTrack( const xAOD::TrackParticle* track, void* =0);
@@ -136,8 +142,6 @@ public:
   void selectTracks( xAOD::TrackParticleContainer::const_iterator trackitr, 
 		     xAOD::TrackParticleContainer::const_iterator trackend, void* =0);
 
-#endif
-
 
 
   void correctToBeamline( double& z0,    double& dz0, 
@@ -154,7 +158,9 @@ private:
   double m_yBeam;
   double m_zBeam;
 
-  bool m_correctTrkTracks;
+  bool   m_correctTrkTracks;
+
+  double m_radius;
 
 };
 
diff --git a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/src/TrigTrackSelector.cxx b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/src/TrigTrackSelector.cxx
index 6ddae1704249c1dc71559dbd921f2845c92d8b2d..e514a67bccb84fdbf58b2be13556f4b9e36bff51 100644
--- a/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/src/TrigTrackSelector.cxx
+++ b/Trigger/TrigAnalysis/TrigInDetAnalysisUtils/src/TrigTrackSelector.cxx
@@ -10,11 +10,13 @@
 
 #include "TrigInDetAnalysisUtils/TrigTrackSelector.h"
 
-  //  TrigTrackSelector( bool (*selector)(const TIDA::Track*)=NULL ) : TrackSelector(selector) {  } 
-TrigTrackSelector::TrigTrackSelector( TrackFilter* selector ) : 
+#include "xAODTruth/TruthVertexContainer.h"
+
+
+TrigTrackSelector::TrigTrackSelector( TrackFilter* selector, double radius ) : 
     TrackSelector(selector), m_id(0), m_xBeam(0), m_yBeam(0), m_zBeam(0),
-    //m_first(true),
-    m_correctTrkTracks(false) {  } 
+    m_correctTrkTracks(false), 
+    m_radius(radius) {  } 
 
 
 bool TrigTrackSelector::selectTrack( const TrigInDetTrack* track, const TrigInDetTrackTruthMap* truthMap ) {     
@@ -260,7 +262,7 @@ void TrigTrackSelector::selectTracks( const Rec::TrackParticleContainer* trigtra
 
 
 
-// extract all the tracks from a TrackParticle collection and add them
+// extract all the tracks from a TruthParticle collection and add them
 void TrigTrackSelector::selectTracks( const TruthParticleContainer* truthtracks ) { 
     
     //    std::cout << "\t\t\tSUTT \tTrackParticleContainer->size() = " << trigtracks->size() << std::endl;
@@ -278,6 +280,24 @@ void TrigTrackSelector::selectTracks( const TruthParticleContainer* truthtracks
     
 }
 
+// extract all the tracks from a xAOD::TruthParticle collection and add them
+void TrigTrackSelector::selectTracks( const xAOD::TruthParticleContainer* truthtracks ) { 
+    
+  xAOD::TruthParticleContainer::const_iterator  trackitr = truthtracks->begin();
+  xAOD::TruthParticleContainer::const_iterator  trackend = truthtracks->end();
+  
+  while ( trackitr!=trackend ) { 
+    
+    selectTrack( *trackitr );
+      
+    trackitr++;
+
+  } // loop over tracks
+    
+}
+
+
+// add a TruthParticle from a GenParticle - easy, bet it doesn't work 
 bool TrigTrackSelector::selectTrack( const HepMC::GenParticle* track ) {
   
     /// not a "final state" particle
@@ -314,6 +334,144 @@ bool TrigTrackSelector::selectTrack( const TruthParticle* track ) {
 }
 
 
+
+
+// add an xAOD::TruthParticle 
+bool TrigTrackSelector::selectTrack( const xAOD::TruthParticle* track ) { 
+
+  if ( track ) { 
+        
+    /// lazy just to avoid a find-replace of measPer to track
+    const xAOD::TruthParticle* measPer = track;
+
+    double pT    = measPer->pt(); 
+    double eta   = measPer->eta();
+    double phi   = measPer->phi();
+  
+    // AAARCH!!!!! the TrackParticle pT is NOT SIGNED!!!! ( I ask you! ) 
+    if ( measPer->charge()<0 && pT>0 ) pT *= -1;
+
+    /// need to calculate the origin, and the beamline, and the d0 and z0 
+    /// with respect to the beamline
+    /// leave this in until we have checked whether everything is implemented correctly
+    //      double xbeam = getBeamX(); // track->vx(); 
+    //      double ybeam = getBeamY(); // track->vy(); 
+    //      double zbeam = getBeamZ(); // track->vz(); 
+      
+    if ( !track->hasProdVtx() ) return false; 
+
+    /// need to calculate d0 and z0 correctly.
+
+    double xp[3] = { measPer->prodVtx()->x(), measPer->prodVtx()->y(), measPer->prodVtx()->z() };
+
+    double theta = 2*std::atan( std::exp( -eta ) );
+    double z0 = xp[2] - (xp[0]*std::cos(phi) + xp[1]*std::sin(phi))/std::tan(theta);
+    double d0 = xp[1]*std::cos(phi) -  xp[0]*std::sin(phi);
+      
+    double xd[3] = { 0, 0, 0 };
+      
+    if ( track->hasDecayVtx() ) { 
+      xd[0] = track->decayVtx()->x();
+      xd[1] = track->decayVtx()->y();
+      xd[2] = track->decayVtx()->z();
+    }
+      
+    double rp = std::sqrt( xp[0]*xp[0] + xp[1]*xp[1] ); 
+    double rd = std::sqrt( xd[0]*xd[0] + xd[1]*xd[1] ); 
+      
+      
+    bool final_state = false; 
+      
+    /// the is our new "final state" requirement
+    /// the inner and outer radii are in some sense 
+    /// arbitrary - these correspond to an envelope
+    /// around the pixel detector, so the track must 
+    /// pass through the entire pixel detector 
+    /// NB: In order to ensure you don't miss any 
+    ///     tracks they really need to be the same
+    ///     ie if a track brems in your "volume"
+    ///     then you will miss that track, and
+    ///     also the resulting track, even if it is
+    ///     a high et track  
+    const double inner_radius = m_radius; /// was hardcoded as 47 - now this can be set from the constructor
+    const double outer_radius = m_radius;
+    if ( (  track->hasProdVtx() && rp<=inner_radius ) && 
+	 ( !track->hasDecayVtx() || rd>outer_radius ) ) final_state = true; 
+      
+    /// leave this in for the moment - we may need to uncomment this afterall
+    //    if ( track->status() == 3 ) final_state = false;         /// check its not a documentation particle
+      
+    if ( !final_state ) return 0; 
+    
+    double deta = 0;
+    double dphi = 0;
+    double dz0  = 0;
+    double dd0  = 0;
+
+    double dpT  = 0; 
+
+    int nBlayerHits = 0;
+    int nPixelHits  = 0;
+    int nSctHits    = 0;
+    int nStrawHits  = 0;
+    int nTrtHits    = 0;
+      
+    double chi2 = 0;
+    double dof  = 0;
+
+    bool expectBL = false;
+
+    nSctHits   += 0;
+    nPixelHits += 0;
+
+    /// get the total number of holes as well
+    int nSiHits     = 0;
+
+    unsigned long id = (unsigned long)track;
+
+    unsigned bitmap = 0;
+
+    int trackAuthor = 0;
+
+#if 0
+    std::cout << "\t\t\tSUTT TP track" 
+	      << "\teta=" << eta  
+	      << "\tphi=" << phi  
+	      << "\tz0="  << z0 
+	      << "\tpT="  << pT 
+	      << "\td0="  << d0
+	      << "\tfitter=" << fitter
+	      << "\tauthor=" << trackAuthor
+	      << "\tVTX x " << xp[0]<< "\ty " << xp[1] << "\tz " << xp[2] 
+	      << std::endl;
+#endif
+
+    // Create and save Track
+      
+    TIDA::Track* t = new TIDA::Track( eta,   phi,  z0,  d0,  pT, chi2, dof,
+				      deta,  dphi, dz0, dd0, dpT,
+				      nBlayerHits, nPixelHits, nSctHits, nSiHits,
+				      nStrawHits,  nTrtHits,   bitmap, 0,
+				      trackAuthor,  false, -1, -1,  
+				      expectBL, id) ;  
+
+    /// useful debug info - leave in
+    //      std::cout << "SUTT TP track " << *t << "\t0x" << std::hex << bitmap << std::dec << std::endl; 
+      
+    if ( !addTrack( t ) ){
+      delete t;
+      return false;
+    }
+    return true;
+      
+  }
+  return false;
+     
+}
+
+
+
+
 // make a TIDA::Track from a GenParticle 
 TIDA::Track* TrigTrackSelector::makeTrack( const HepMC::GenParticle* track ) { 
     unsigned long id = (unsigned long)track;
@@ -838,11 +996,11 @@ bool TrigTrackSelector::selectTrack( const xAOD::TrackParticle* track, void* ) {
 	if ( patternrec[ipr] ) {
 	  icount++;
 	  trackAuthor |= (ipr >> 16);
-	  static bool first = true;
-	  if ( first && icount>1 ) { 
-	    std::cerr << "more than one pattern rec strategy " << ipr << "\t(suppressing further output)" << std::endl;
-	    first = false;
-	  }
+	  // static bool first = true;
+	  // if ( first && icount>1 ) { 
+	  //   std::cerr << "more than one pattern rec strategy " << ipr << "\t(suppressing further output)" << std::endl;
+	  //   first = false;
+	  // }
 	}
       }