Skip to content

Instantly share code, notes, and snippets.

@mazurov
Created January 12, 2012 15:47
Show Gist options
  • Save mazurov/1601205 to your computer and use it in GitHub Desktop.
Save mazurov/1601205 to your computer and use it in GitHub Desktop.
// Include files
// from Gaudi
#include "GaudiKernel/AlgFactory.h"
#include "Event/Track.h"
// local
#include "FastVeloTracking.h"
//-----------------------------------------------------------------------------
// Implementation file for class : FastVeloTracking
//
// 2010-09-09 : Olivier Callot
//-----------------------------------------------------------------------------
// Declaration of the Algorithm Factory
DECLARE_ALGORITHM_FACTORY( FastVeloTracking )
//=============================================================================
// Standard constructor, initializes variables
//=============================================================================
FastVeloTracking::FastVeloTracking( const std::string& name,
ISvcLocator* pSvcLocator)
: GaudiAlgorithm ( name , pSvcLocator )
{
declareProperty( "OutputTracksName" , m_outputLocation = LHCb::TrackLocation::Velo );
declareProperty( "HitManagerName" , m_hitManagerName = "FastVeloHitManager" );
declareProperty( "OnlyForward" , m_onlyForward = false );
declareProperty( "OnlyBackward" , m_onlyBackward = false );
declareProperty( "HLT1Only" , m_HLT1Only = false );
declareProperty( "HLT2Complement" , m_HLT2Complement = false );
declareProperty( "MaxRZForExtra" , m_maxRZForExtra = 200 );
declareProperty( "StateAtBeam" , m_stateAtBeam = true );
declareProperty( "ResetUsedFlags" , m_resetUsedFlags = false );
declareProperty( "ZVertexMin" , m_zVertexMin = -170. *Gaudi::Units::mm );
declareProperty( "ZVertexMax" , m_zVertexMax = +120. *Gaudi::Units::mm );
declareProperty( "ZVertexMaxBack" , m_zVertexMaxBack = +1200. *Gaudi::Units::mm );
declareProperty( "MaxRSlope" , m_maxRSlope = 0.450 );
declareProperty( "rMatchTol4" , m_rMatchTol4 = 1.00 );
declareProperty( "rMatchTol3" , m_rMatchTol3 = 1.10 );
declareProperty( "rExtraTol" , m_rExtraTol = 4.0 );
declareProperty( "rOverlapTol" , m_rOverlapTol = 1.0 );
declareProperty( "MaxMissed" , m_maxMissed = 1 );
declareProperty( "MinToTag" , m_minToTag = 4 );
declareProperty( "PhiMatchZone" , m_phiMatchZone = 0.410 ); // sin(22.5 degrees) = 0.38, some tolerance
declareProperty( "PhiCentralZone" , m_phiCentralZone = 0.040 ); // in overlap...
declareProperty( "MaxDelta2" , m_maxDelta2 = 0.05 );
declareProperty( "FractionFound" , m_fractionFound = 0.70 );
declareProperty( "MaxChi2PerHit" , m_maxChi2PerHit = 12. );
declareProperty( "MaxChi2ToAdd" , m_maxChi2ToAdd = 40. );
declareProperty( "MaxQFactor" , m_maxQFactor = 6. );
declareProperty( "MaxQFactor3" , m_maxQFactor3 = 3. );
declareProperty( "DeltaQuality" , m_deltaQuality = 0.5 );
declareProperty( "FractionForMerge", m_fractionForMerge= 0.70 );
declareProperty( "PhiUnusedFirstTol", m_phiUnusedFirstTol = 5. );
declareProperty( "PhiUnusedSecondTol", m_phiUnusedSecondTol = 10. );
// Parameters for debugging
declareProperty( "DebugToolName" , m_debugToolName = "" );
declareProperty( "WantedKey" , m_wantedKey = -100 );
declareProperty( "TimingMeasurement" , m_doTiming = false );
}
//=============================================================================
// Destructor
//=============================================================================
FastVeloTracking::~FastVeloTracking() {}
//=============================================================================
// Initialization
//=============================================================================
StatusCode FastVeloTracking::initialize() {
StatusCode sc = GaudiAlgorithm::initialize(); // must be executed first
if ( sc.isFailure() ) return sc; // error printed already by GaudiAlgorithm
if ( msgLevel(MSG::DEBUG) ) debug() << "==> Initialize" << endmsg;
m_hitManager = tool<FastVeloHitManager>( "FastVeloHitManager", m_hitManagerName );
m_debugTool = 0;
if ( "" != m_debugToolName ) m_debugTool = tool<IPatDebugTool>( m_debugToolName );
if ( m_doTiming) {
m_timerTool = tool<ISequencerTimerTool>( "SequencerTimerTool/Timer", this );
m_timeTotal = m_timerTool->addTimer( "Fast Velo total" );
m_timerTool->increaseIndent();
m_timePrepare = m_timerTool->addTimer( "Fast Velo prepare" );
m_timeFwd4 = m_timerTool->addTimer( "Fast Velo forward quadruplets" );
m_timeBkwd4 = m_timerTool->addTimer( "Fast Velo backward quadruplets" );
m_timeFwd3 = m_timerTool->addTimer( "Fast Velo forward triplets" );
m_timeBkwd3 = m_timerTool->addTimer( "Fast Velo backward triplets" );
m_timeSpace = m_timerTool->addTimer( "Fast Velo space tracks" );
m_timeUnused = m_timerTool->addTimer( "Fast velo unused Phi" );
m_timeFinal = m_timerTool->addTimer( "Fast velo store tracks" );
m_timerTool->decreaseIndent();
}
return StatusCode::SUCCESS;
}
//=============================================================================
// Main execution
//=============================================================================
StatusCode FastVeloTracking::execute() {
if ( msgLevel(MSG::DEBUG) ) debug() << "==> Execute" << endmsg;
m_isDebug = msgLevel( MSG::DEBUG );
if ( m_doTiming ){
m_timerTool->start( m_timeTotal );
m_timerTool->start( m_timePrepare );
}
LHCb::Tracks* outputTracks;
if ( exist<LHCb::Tracks>( m_outputLocation ) ) {
outputTracks = get<LHCb::Tracks>( m_outputLocation );
} else {
outputTracks = new LHCb::Tracks();
put(outputTracks, m_outputLocation );
}
outputTracks->reserve(500);
m_hitManager->buildFastHits();
if ( m_resetUsedFlags ) m_hitManager->resetUsedFlags();
m_tracks.clear();
m_spaceTracks.clear();
unsigned int sensorNb;
//== If needed, debug the cluster associated to the requested MC particle.
if ( 0 <= m_wantedKey ) {
info() << "--- Looking for Track " << m_wantedKey << endmsg;
for ( sensorNb = m_hitManager->firstRSensor(); m_hitManager->lastRSensor() >= sensorNb; ++sensorNb ) {
for ( unsigned int zone = 0; 4 > zone ; ++zone ) {
for ( FastVeloHits::const_iterator itH = m_hitManager->hits( sensorNb, zone ).begin();
m_hitManager->hits( sensorNb, zone ).end() != itH; ++itH ) {
if ( matchKey( *itH ) ) printCoord( *itH, " " );
}
}
}
}
//== First, look for quadruplets
double minZ = m_zVertexMin + 200.; // 200 mrad, 40 mm radius -> 200 mm in z
double maxZ = m_zVertexMax - 200.;
if ( m_doTiming ) m_timerTool->stop( m_timePrepare );
//== Find quadruplet, if not HLT2 complement only. Do forward and backward if needed
if ( !m_HLT2Complement ) {
if ( !m_onlyBackward ) {
if ( m_doTiming ) m_timerTool->start( m_timeFwd4 );
for ( sensorNb = m_hitManager->lastRSensor(); m_hitManager->firstRSensor()+8 < sensorNb; --sensorNb ) {
if ( m_hitManager->sensor(sensorNb)->z() < minZ ) break;
findQuadruplets( sensorNb, true ); // forward
}
if ( m_doTiming ) m_timerTool->stop( m_timeFwd4 );
}
if ( !m_onlyForward ) {
if ( m_doTiming ) m_timerTool->start( m_timeBkwd4 );
for ( sensorNb = m_hitManager->firstRSensor(); m_hitManager->lastRSensor() > sensorNb+8; ++sensorNb ) {
if ( m_hitManager->sensor(sensorNb)->z() > maxZ ) break;
findQuadruplets( sensorNb, false ); // backward
}
if ( m_doTiming ) m_timerTool->stop( m_timeBkwd4 );
}
}
//== Find triplets if not HLT1, backward and/or forward
if ( !m_HLT1Only ) {
if ( !m_onlyBackward ) {
if ( m_doTiming ) m_timerTool->start( m_timeFwd3 );
for ( sensorNb = m_hitManager->lastRSensor(); m_hitManager->firstRSensor()+6 < sensorNb; --sensorNb ) {
if ( m_hitManager->sensor(sensorNb)->z() < minZ ) break;
findUnusedTriplets( sensorNb, true ); // forward
}
if ( m_doTiming ) m_timerTool->stop( m_timeFwd3 );
}
if ( !m_onlyForward ) {
if ( m_doTiming ) m_timerTool->start( m_timeBkwd3 );
for ( sensorNb = m_hitManager->firstRSensor(); m_hitManager->lastRSensor() > sensorNb+6; ++sensorNb ) {
if ( m_hitManager->sensor(sensorNb)->z() > maxZ ) break;
findUnusedTriplets( sensorNb, false ); // backward
}
if ( m_doTiming ) m_timerTool->stop( m_timeBkwd3 );
}
}
if ( m_doTiming ) m_timerTool->start( m_timeSpace );
std::stable_sort( m_tracks.begin(), m_tracks.end(), FastVeloTrack::DecreasingByRLength() );
for ( FastVeloTracks::iterator itT = m_tracks.begin(); m_tracks.end() != itT; ++itT ) {
makeSpaceTracks( *itT );
}
if ( m_doTiming ) m_timerTool->stop( m_timeSpace );
//== Perform the recovery, starting from Phi hits, with some constraints:
//== Not HLT1, not too many tracks, space has foudn some OR there were not that many.
if ( !m_HLT1Only &&
m_maxRZForExtra > m_tracks.size() &&
( m_tracks.size() * 0.5 <= m_spaceTracks.size() ||
m_tracks.size() < 20 ) ) {
if ( m_doTiming ) m_timerTool->start( m_timeUnused );
findUnusedPhi();
if ( m_doTiming ) m_timerTool->stop( m_timeUnused );
}
if ( m_doTiming ) m_timerTool->start( m_timeFinal );
mergeSpaceClones(); // Cleanup tracks with different R, same phis...
makeLHCbTracks( outputTracks );
if ( m_doTiming ) m_timerTool->stop( m_timeFinal );
//== Debugging information: Status of all hits from the wanted track.
if ( 0 <= m_wantedKey ) {
info() << "*** Final status of hits for Track " << m_wantedKey << endmsg;
for ( sensorNb = m_hitManager->firstRSensor(); m_hitManager->lastRSensor() >= sensorNb; ++sensorNb ) {
for ( unsigned int zone = 0; 4 > zone ; ++zone ) {
for ( FastVeloHits::const_iterator itH = m_hitManager->hits( sensorNb, zone ).begin();
m_hitManager->hits( sensorNb, zone ).end() != itH; ++itH ) {
if ( matchKey( *itH ) ) printCoord( *itH, "R " );
}
}
}
for ( sensorNb = m_hitManager->firstPhiSensor(); m_hitManager->lastPhiSensor() >= sensorNb; ++sensorNb ) {
for ( unsigned int zone = 0; 2 > zone ; ++zone ) {
for ( FastVeloHits::const_iterator itH = m_hitManager->hits( sensorNb, zone ).begin();
m_hitManager->hits( sensorNb, zone ).end() != itH; ++itH ) {
if ( matchKey( *itH ) ) printCoord( *itH, "Phi" );
}
}
}
}
if ( m_doTiming ) m_timerTool->stop( m_timeTotal );
return StatusCode::SUCCESS;
}
//=============================================================================
// Finalize
//=============================================================================
StatusCode FastVeloTracking::finalize() {
if ( msgLevel(MSG::DEBUG) ) debug() << "==> Finalize" << endmsg;
return GaudiAlgorithm::finalize(); // must be called after all other actions
}
//=========================================================================
// Find quadruplets in RZ, i.e. 4 hits, with optionally a hole.
// Extend the track if possible.
//=========================================================================
void FastVeloTracking::findQuadruplets( unsigned int sens0, bool forward ) {
FastVeloSensor* sensor0 = m_hitManager->sensor( sens0 );
for ( unsigned int zone = 0; 4 > zone; ++zone ) {
if ( sensor0->hits( zone ).empty() ) continue;
//== 4 cases: no holes, s3 missing, s2 missing, s1 missing
FastVeloSensor* sensor1 = m_hitManager->sensor( sensor0->next( forward ) );
FastVeloSensor* sensor2 = m_hitManager->sensor( sensor1->next( forward ) );
FastVeloSensor* sensor3 = m_hitManager->sensor( sensor2->next( forward ) );
for ( int iCase = 0; 4 > iCase; ++iCase) {
if ( iCase == 1 ) sensor3 = m_hitManager->sensor( sensor3->next( forward ) );
if ( iCase == 2 ) sensor2 = m_hitManager->sensor( sensor2->next( forward ) );
if ( iCase == 3 ) sensor1 = m_hitManager->sensor( sensor1->next( forward ) );
if ( sensor1->hits( zone ).empty() ) continue;
if ( sensor2->hits( zone ).empty() ) continue;
if ( sensor3->hits( zone ).empty() ) continue;
double z0 = sensor0->z();
double z1 = sensor1->z();
double z2 = sensor2->z();
double z3 = sensor3->z();
double zFrac1 = ( z1 - z0 ) / ( z3 - z0 );
double zFrac2 = ( z2 - z0 ) / ( z3 - z0 );
if ( m_isDebug ) {
info()<< "Checking sensors [" << sensor0->number() << "] [" << sensor1->number()
<< "] [" << sensor2->number() << "] [" << sensor3->number()
<< "] zone " << zone
<< " nbCoord " << sensor0->hits(zone).size() << " " << sensor1->hits(zone).size()
<< " " << sensor2->hits(zone).size() << " " << sensor3->hits(zone).size()
<< endmsg;
}
FastVeloHits::const_iterator c0, c3, first3;
first3 = sensor3->hits(zone).begin();
for ( c0 = sensor0->hits(zone).begin(); sensor0->hits(zone).end() != c0 ; ++c0 ) {
if ( 0 < (*c0)->nbUsed() ) continue;
double r0 = (*c0)->global();
double rMin = r0 + m_maxRSlope * (z3 - z0);
double rMax = r0 + 1.; //== Allow parallel tracks
double rMaxNormal = r0 * ( z3 - m_zVertexMin ) / ( z0 - m_zVertexMin );
if ( !forward) { // tracks should have -ve gradient
rMin = r0 - m_maxRSlope * (z3 - z0);
rMax = r0 * ( z3 - m_zVertexMaxBack ) / ( z0 - m_zVertexMaxBack );
rMaxNormal = rMax;
}
if ( 0 != m_debugTool && matchKey( *c0 ) ) {
info() << format( "4.%d: rMin %8.3f rMax %8.3f ", iCase, rMin, rMax );
printCoord ( *c0, "St0 " );
}
// loop over clusters in fourth station finding a possible match
for ( c3 = first3; sensor3->hits(zone).end() != c3 ; ++c3 ) {
if ( 0 != iCase && 0 < (*c3)->nbUsed() ) continue; // cluster already used
double r3 = (*c3)->global();
if ( rMin > r3 ) {
first3 = c3;
continue;
}
if ( rMax <= r3 ) break;
//== Sensor 1
double rPred = r0 + zFrac1 * (r3-r0);
double rPitch = sensor1->rPitch( rPred );
double tol = m_rMatchTol4 * rPitch;
if ( 0 != m_debugTool && matchKey( *c0 ) && matchKey( *c3) ) {
info() << format( "4.%d: rPred %8.3f (tol %6.3f)", iCase, rPred, tol );
printCoord ( *c3, "St3 " );
}
FastVeloHit* ok1 = closestHit( sensor1->hits(zone) , rPred, tol );
if ( NULL == ok1 ) continue;
//== Sensor 2
rPred = r0 + zFrac2 * (r3-r0);
rPitch = sensor2->rPitch( rPred );
tol = m_rMatchTol4 * rPitch;
if ( 0 != m_debugTool && matchKey( *c0 ) && matchKey( *c3) ) {
info() << format( "4.%d: rPred %8.3f (tol %6.3f)", iCase, rPred, tol );
printCoord ( ok1, "St1 " );
}
FastVeloHit* ok2 = closestHit( sensor2->hits(zone), rPred, tol );
if ( NULL == ok2 ) continue;
m_debug = m_isDebug;
if ( 0 != m_debugTool ) {
if ( matchKey( *c0 ) || matchKey( ok1 ) || matchKey( ok2 ) || matchKey( *c3 )) m_debug = true;
if ( m_debug ) {
info() << "=== valid quadruplet ===" << endmsg;
printCoord ( *c0, "St0 " );
printCoord ( ok1, "St1 " );
printCoord ( ok2, "St2 " );
printCoord ( *c3, "St3 " );
}
}
// create track
FastVeloTrack newTrack;
newTrack.addRHit( *c0 );
newTrack.addRHit( ok1 );
newTrack.addRHit( ok2 );
newTrack.addRHit( *c3 );
newTrack.setBackward( !forward );
int nMiss = extendTrack( newTrack, sensor3, zone, forward );
if ( 1 >= newTrack.nbRHits() - newTrack.nbUsedRHits() ) {
if( m_debug ) info() << "Killed too few new hits : " << newTrack.nbUsedRHits()
<< " used from " << newTrack.nbRHits() << endmsg;
continue;
}
newTrack.setMissedSensors( nMiss ); // store the number of missed stations to put on LHCb::Track later
int setSector = zone;
if ( sensor0->isRight() ) setSector += 4;
newTrack.setZone( setSector );
//== Try to add hits on the other half station, if sector 0/3 and forward
if ( 0 == zone || 3 == zone ) {
addOppositeSideRHits( newTrack, zone, sensor0, forward );
}
if ( forward && ( sens0 <= 33 && sens0 >= 30 ) ) { // large Z gap -> may need to recover...
extendTrack( newTrack, sensor0, zone, !forward );
}
if ( forward ) {
std::sort( newTrack.rHits().begin(), newTrack.rHits().end(), FastVeloHit::IncreasingByZ() );
} else {
std::sort( newTrack.rHits().begin(), newTrack.rHits().end(), FastVeloHit::DecreasingByZ() );
}
m_tracks.push_back( newTrack );
if ( m_debug ) {
info() << " -- stored n=" << m_tracks.size()-1 << endmsg;
printRTrack( newTrack );
}
if ( m_minToTag <= newTrack.nbRHits() ) {
newTrack.tagUsedRHits();
rMax = rMaxNormal;
}
}
}
}
}
}
//=========================================================================
// Merge space track clones: Test PHI ( m_fractionForMerge) and R >1
//=========================================================================
void FastVeloTracking::mergeSpaceClones( ) {
if ( m_spaceTracks.size() < 2 ) return;
for ( FastVeloTracks::iterator itT1 = m_spaceTracks.begin(); m_spaceTracks.end()-1 != itT1; ++itT1 ) {
if ( (*itT1).backward() ) continue;
if ( !(*itT1).isValid() ) continue;
for ( FastVeloTracks::iterator itT2 = itT1+1; m_spaceTracks.end() != itT2; ++itT2 ) {
m_debug = m_isDebug;
//== different zones -> can not be clone
if ( (*itT1).zone() != (*itT2).zone () ) continue;
if ( (*itT2).backward() ) continue;
if ( !(*itT2).isValid() ) continue;
unsigned int minWanted = (*itT1).phiHits().size();
if ( (*itT2).phiHits().size() < minWanted ) minWanted = (*itT2).phiHits().size();
unsigned int nCommon = 0;
for ( FastVeloHits::const_iterator itH = (*itT2).phiHits().begin();
(*itT2).phiHits().end() != itH; ++itH ) {
if ( std::find( (*itT1).phiHits().begin(), (*itT1).phiHits().end(), *itH ) != (*itT1).phiHits().end() ) nCommon++;
if ( matchKey( *itH ) ) m_debug = true;
}
bool badFirst = false;
bool badSecond = false;
if ( minWanted * m_fractionForMerge <= nCommon ) {
unsigned int nRCommon = 0;
unsigned int rWanted = (*itT1).rHits().size();
if ( (*itT2).rHits().size() < rWanted ) rWanted = (*itT2).rHits().size();
for ( FastVeloHits::const_iterator itH = (*itT2).rHits().begin();
(*itT2).rHits().end() != itH; ++itH ) {
if ( std::find( (*itT1).rHits().begin(), (*itT1).rHits().end(), *itH ) != (*itT1).rHits().end() ) nRCommon++;
}
if ( rWanted * m_fractionForMerge > nRCommon ) continue;
if ( (*itT1).phiHits().size() > minWanted ) {
badSecond = true;
} else if ( (*itT2).phiHits().size() > minWanted ) {
badFirst = true;
} else {
if ( (*itT1).qFactor() < (*itT2).qFactor() ) {
badSecond = true;
} else {
badFirst = true;
}
}
if ( m_debug ) {
info() << "Compare track " << itT1 - m_spaceTracks.begin() << " to " << itT2 - m_spaceTracks.begin()
<< ", found " << nCommon << " common hits for " << minWanted << endmsg;
}
if ( badFirst ) {
(*itT1).setValid( false );
if ( m_debug ) info() << " Invalidate track " << itT1 - m_spaceTracks.begin() << endmsg;
}
if ( badSecond ) {
(*itT2).setValid( false );
if ( m_debug ) info() << " Invalidate track " << itT2 - m_spaceTracks.begin() << endmsg;
}
}
}
}
}
//=========================================================================
// Find triplets in RZ with unused hits, i.e. 3 hits, with optionally a hole.
// Extend the track if possible.
//=========================================================================
void FastVeloTracking::findUnusedTriplets( unsigned int sens0, bool forward ) {
FastVeloSensor* sensor0 = m_hitManager->sensor( sens0 );
for ( unsigned int zone = 0; 4 > zone; ++zone ) {
if ( sensor0->hits( zone ).empty() ) continue;
//== 4 cases: no holes, s3 missing, s2 missing, s1 missing
FastVeloSensor* sensor1 = m_hitManager->sensor( sensor0->next( forward ) );
FastVeloSensor* sensor2 = m_hitManager->sensor( sensor1->next( forward ) );
for ( int iCase = 0; 3 > iCase; ++iCase) {
if ( iCase == 1 ) sensor2 = m_hitManager->sensor( sensor2->next( forward ) );
if ( iCase == 2 ) sensor1 = m_hitManager->sensor( sensor1->next( forward ) );
if ( sensor1->hits( zone ).empty() ) continue;
if ( sensor2->hits( zone ).empty() ) continue;
double z0 = sensor0->z();
double z1 = sensor1->z();
double z2 = sensor2->z();
double zFrac = ( z1 - z0 ) / ( z2 - z0 );
if ( m_isDebug ) {
info()<< "Checking sensors [" << sensor0->number() << "] [" << sensor1->number()
<< "] [" << sensor2->number() << "] zone " << zone
<< " nbCoord " << sensor0->hits(zone).size() << " " << sensor1->hits(zone).size()
<< " " << sensor2->hits(zone).size()
<< endmsg;
}
FastVeloHits::const_iterator c0, c2, first2;
first2 = sensor2->hits(zone).begin();
for ( c0 = sensor0->hits(zone).begin(); sensor0->hits(zone).end() != c0 ; ++c0 ) {
if ( 0 < (*c0)->nbUsed() ) continue;
double r0 = (*c0)->global();
double rMin = r0 + m_maxRSlope * (z2 - z0);
double rMax = r0;
if ( !forward) { // tracks should have -ve gradient and come from the vertex area
rMin = r0 - m_maxRSlope * (z2 - z0);
rMax = r0 * ( z2 - m_zVertexMaxBack ) / ( z0 - m_zVertexMaxBack );
}
if ( 0 != m_debugTool && matchKey( *c0 ) ) {
info() << format( "3.%d: rMin %8.3f rMax %8.3f ", iCase, rMin, rMax );
printCoord ( *c0, "St0 " );
}
// loop over clusters in third station finding a possible match
for ( c2 = first2; sensor2->hits(zone).end() != c2 ; ++c2 ) {
if ( 0 < (*c2)->nbUsed() ) continue; // cluster already used
double r2 = (*c2)->global();
if ( rMin > r2 ) {
first2 = c2;
continue;
}
if ( rMax <= r2 ) break;
//== Sensor 1
double rPred = r0 + zFrac * (r2-r0);
double rPitch = sensor1->rPitch( rPred );
double tol = m_rMatchTol3 * rPitch;
if ( 0 != m_debugTool && matchKey( *c0 ) && matchKey( *c2) ) {
info() << format( "3.%d: rPred %8.3f (tol %6.3f) ", iCase, rPred, tol );
printCoord ( *c2, "St2 " );
}
FastVeloHit* ok1 = closestUnusedHit( sensor1->hits(zone), rPred, tol );
if ( NULL == ok1 ) continue;
m_debug = m_isDebug;
if ( 0 != m_debugTool ) {
if ( matchKey( *c0 ) || matchKey( ok1 ) || matchKey( *c2 )) m_debug = true;
if ( m_debug ) {
info() << "=== valid triplet ===" << endmsg;
printCoord ( *c0, "St0 " );
printCoord ( ok1, "St1 " );
printCoord ( *c2, "St2 " );
}
}
// create track
FastVeloTrack newTrack;
newTrack.addRHit( *c0 );
newTrack.addRHit( ok1 );
newTrack.addRHit( *c2 );
newTrack.setBackward( !forward );
int nMiss = extendTrack( newTrack, sensor2, zone, forward );
newTrack.setMissedSensors( nMiss ); // store the number of missed stations to put on LHCb::Track later
if ( 1 >= newTrack.nbRHits() - newTrack.nbUsedRHits() ) {
if( m_debug ) info() << "Killed too few new hits" << endmsg;
continue;
}
//== Tracks with last 3 sensors, a gap, a single other. remove the last one.
if ( sens0 > 39 && newTrack.rHits().size() == 4 ) {
if ( newTrack.rHits().back()->sensor() < 34 ) {
newTrack.rHits().pop_back();
}
}
//== More demanding for minimal tracks of 3 clusters
if ( 3 == newTrack.nbRHits() ) {
int nMissBack = extendTrack( newTrack, sensor0, zone, !forward );
if ( m_maxMissed < nMissBack ) {
if ( m_debug ) info() << "Short track with missed sensors before." << endmsg;
continue;
}
}
int setSector = zone;
if ( sensor0->isRight() ) setSector += 4;
newTrack.setZone( setSector );
//== Try to add hits on the other half station, if sector 0/3 and forward
if ( forward && ( 0 == zone || 3 == zone ) ) {
addOppositeSideRHits( newTrack, zone, sensor0, forward );
}
//== 3 hit tracks: If sharing hits, take the 'best' one
if ( newTrack.rHits().size() == 3 ) {
bool reject = false;
for ( FastVeloTracks::iterator itT = m_tracks.begin();
m_tracks.end() != itT; ++itT ) {
if ( (*itT).rHits().size() != 3 ) continue;
int nCommon = 0;
for ( FastVeloHits::const_iterator itH = (*itT).rHits().begin();
(*itT).rHits().end() != itH; ++itH ) {
if ( std::find( newTrack.rHits().begin(), newTrack.rHits().end(), *itH ) != newTrack.rHits().end() ) nCommon++;
}
if ( 0 != nCommon ) {
if ( m_debug ) info() << "Share " << nCommon << " hits with "
<< itT - m_tracks.begin() << ", chi2 : "
<< newTrack.rChi2() << " / " << (*itT).rChi2();
if ( newTrack.rChi2() > (*itT).rChi2() ) {
if ( m_debug ) info() << " -> rejected" << endmsg;
} else {
if ( m_debug ) info() << " -> replace it" << endmsg;
(*itT) = newTrack;
}
reject = true;
break;
}
}
if ( reject ) continue;
}
if ( forward ) {
std::sort( newTrack.rHits().begin(), newTrack.rHits().end(), FastVeloHit::IncreasingByZ() );
} else {
std::sort( newTrack.rHits().begin(), newTrack.rHits().end(), FastVeloHit::DecreasingByZ() );
}
m_tracks.push_back( newTrack );
if ( m_debug ) {
info() << " -- stored n=" << m_tracks.size()-1
<< " nbRHits " << newTrack.nbRHits()
<< " chi2 " << newTrack.rChi2() << endmsg;
printRTrack( newTrack );
}
if ( m_minToTag <= newTrack.nbRHits() ) newTrack.tagUsedRHits();
}
}
}
}
}
//=========================================================================
// Get the closest hit in the window.
//=========================================================================
FastVeloHit* FastVeloTracking::closestHit( FastVeloHits& hits, double coord, double tol ) {
double minDist = tol;
FastVeloHit* best = NULL;
for ( FastVeloHits::const_iterator itH = hits.begin(); hits.end() != itH ; ++itH ) {
double dist = (*itH)->global() - coord;
if ( dist < -minDist ) continue;
if ( dist > minDist ) break;
minDist = fabs( dist );
best = *itH;
}
return best;
}
//=========================================================================
// Get the closest hit in the window.
//=========================================================================
FastVeloHit* FastVeloTracking::closestUnusedHit( FastVeloHits& hits, double coord, double tol ) {
double minDist = tol;
FastVeloHit* best = NULL;
for ( FastVeloHits::const_iterator itH = hits.begin(); hits.end() != itH ; ++itH ) {
double dist = (*itH)->global() - coord;
if ( dist < -minDist ) continue;
if ( dist > minDist ) break;
if ( 0 != (*itH)->nbUsed() ) continue;
minDist = fabs( dist );
best = *itH;
}
return best;
}
//=========================================================================
// Convert the local track to LHCb tracks
//=========================================================================
void FastVeloTracking::makeLHCbTracks( LHCb::Tracks* outputTracks ) {
for ( FastVeloTracks::iterator itT = m_spaceTracks.begin(); m_spaceTracks.end() != itT; ++itT ) {
if ( (*itT).rHits().size() < 3 || (*itT).phiHits().size() < 3 ) (*itT).setValid( false );
if ( !(*itT).isValid() ) continue;
LHCb::Track *newTrack = new LHCb::Track();
newTrack->setType( LHCb::Track::Velo );
newTrack->setHistory( LHCb::Track::PatFastVelo );
newTrack->setPatRecStatus( LHCb::Track::PatRecIDs );
if ( m_debug ) {
info() << "=== Store track Nb " << outputTracks->size() << endmsg;
printCoords( (*itT).rHits(), "Stored R " );
printCoords( (*itT).phiHits(), "Stored Phi " );
}
//== Add the number of found + missed R hits. Note that 'missed' is incomplete as we stop
//== searching missed sensors after the maximum number of missed sensors has been reached.
//== Multiply by 2 to mimic the previous implementation in Pat.
newTrack->addInfo( LHCb::Track::nPRVelo3DExpect, 2 * ( (*itT).nbRHits() + (*itT).nbMissedSensors() ) );
double zMin = 1.e9;
double zMax = -1.e9;
for ( FastVeloHits::iterator itR = (*itT).rHits().begin();
(*itT).rHits().end() != itR; ++itR ) {
newTrack->addToLhcbIDs( (*itR)->lhcbID() );
if ( (*itR)->z() > zMax ) zMax = (*itR)->z();
if ( (*itR)->z() < zMin ) zMin = (*itR)->z();
}
for ( FastVeloHits::iterator itP = (*itT).phiHits().begin();
(*itT).phiHits().end() != itP; ++itP ) {
newTrack->addToLhcbIDs( (*itP)->lhcbID() );
if ( (*itP)->z() > zMax ) zMax = (*itP)->z();
if ( (*itP)->z() < zMin ) zMin = (*itP)->z();
}
LHCb::State state;
//== Define backward as z closest to beam downstream of hits
double zBeam = (*itT).zBeam();
bool backward = zBeam > zMax;
newTrack->setFlag( LHCb::Track::Backward, backward );
if ( m_stateAtBeam ) {
state.setLocation( LHCb::State::ClosestToBeam );
state.setState( (*itT).state( zBeam ) );
state.setCovariance( (*itT).covariance( zBeam ) );
newTrack->addToStates( state );
} else {
state.setLocation( LHCb::State::FirstMeasurement );
state.setState( (*itT).state( zMin ) );
state.setCovariance( (*itT).covariance( zMin ) );
newTrack->addToStates( state );
}
if ( !backward ) {
state.setLocation( LHCb::State::EndVelo );
state.setState( (*itT).state( zMax ) );
state.setCovariance( (*itT).covariance( zMax ) );
newTrack->addToStates( state );
}
outputTracks->insert( newTrack );
}
}
//=========================================================================
// Extend a track towards vertex
//=========================================================================
int FastVeloTracking::extendTrack( FastVeloTrack &newTrack, FastVeloSensor* sensor,
unsigned int zone, bool forward ) {
//== Extrapolate until too many consecutive hits missed.
int nMiss = 0;
while ( m_maxMissed >= nMiss ) {
int nextSensor = sensor->next( forward );
if ( 0 > nextSensor ) break; // No other sensor...
sensor = m_hitManager->sensor( nextSensor );
double z = sensor->z();
double rPred = newTrack.rPred( z ); // new predicted co-ord
double trTol = sqrt( newTrack.rErr2( z ) );
const DeVeloRType* rSensor = sensor->rSensor();
double rPitch = rSensor->rPitch( rPred );
double tol = m_rExtraTol * trTol + rPitch;
if ( m_debug ) {
info() << format( " sensor %3d z%7.1f tol %5.3f pred %8.3f",
sensor->number(), z, tol, rPred ) << endmsg;
}
if ( rSensor->rMin(zone) > rPred ) break; // no longer inside.
if ( rSensor->rMax(zone) < rPred ) break; // no longer inside.
//== Select the best hit when extrapolating
FastVeloHit* best = closestHit( sensor->hits( zone ), rPred, tol );
if ( 0 != best ) {
nMiss = 0;
newTrack.addRHit( best );
if ( m_debug ) printCoord( best, "add " );
} else {
++nMiss; // no hit found
}
}
return nMiss;
}
//=========================================================================
// Add hits from the other side of the detector (overlap tracks)
//=========================================================================
void FastVeloTracking::addOppositeSideRHits( FastVeloTrack &newTrack, const int &zone,
FastVeloSensor* firstSensor, bool forward ) {
int sensorNb = firstSensor->number() + 1;
if ( sensorNb > (int)m_hitManager->lastRSensor() ) sensorNb = sensorNb - 2;
// since zones are ordered in global phi, we always have to flip
int otherZone = 3-zone;
if ( m_debug ) info() << " +++ extend to the other side, start at sensor " << sensorNb << endmsg;
//== Extrapolate until too many consecutive hits missed,
FastVeloHits extraHits;
while ( 0 <= sensorNb ) {
FastVeloSensor* sensor = m_hitManager->sensor( sensorNb );
double z = sensor->z();
double rPred = newTrack.rPred( z );
double rPitch = sensor->rPitch( rPred );
double tol = m_rOverlapTol * rPitch; // for overlap
if ( m_debug ) {
info() << format( "Opp: sensor %3d z%7.1f tol %5.3f pred %8.3f",
sensor->number(), z, tol, rPred ) << endmsg;
}
if ( forward && sensor->rMin() > rPred ) break; // no longer inside.
if ( !forward && sensor->rMax() < rPred ) break; // no longer inside.
//== Select the best hit when extrapolating
FastVeloHit* best = closestHit( sensor->hits( otherZone ), rPred, tol );
if ( 0 != best ) {
extraHits.push_back( best );
if ( m_debug ) printCoord( best, "add " );
}
sensorNb = sensor->next( forward );
}
if ( 2 < extraHits.size() ) {
for ( FastVeloHits::const_iterator itH = extraHits.begin(); extraHits.end() != itH; ++itH ) {
newTrack.addRHit( *itH );
}
}
}
//=========================================================================
// Make space tracks...
//=========================================================================
void FastVeloTracking::makeSpaceTracks( FastVeloTrack& input ) {
m_debug = m_isDebug;
FastVeloHits::iterator itH;
if ( NULL != m_debugTool ) {
for ( itH = input.rHits().begin(); input.rHits().end() != itH; ++itH ) {
if ( matchKey( *itH ) ) m_debug = true;
}
}
int nbLeft = 0;
int nbRight = 0;
unsigned int lowSensor = 1000;
unsigned int highSensor = 0;
for ( itH = input.rHits().begin(); input.rHits().end() != itH; ++itH ) {
if ( (*itH)->sensor() > highSensor ) highSensor = (*itH)->sensor();
if ( (*itH)->sensor() < lowSensor ) lowSensor = (*itH)->sensor();
if ( m_hitManager->sensor( (*itH)->sensor() )->isRight() ) {
++nbRight;
} else {
++nbLeft;
}
}
highSensor = highSensor + 64 + 2;
lowSensor = lowSensor + 64 - 2;
bool forward = !input.backward();
bool inOverlap = nbLeft > 2 && nbRight > 2;
m_cosPhi = m_hitManager->cosPhi( input.zone() );
m_sinPhi = m_hitManager->sinPhi( input.zone() );
if ( inOverlap ) {
m_cosPhi = 0;
m_sinPhi = m_sinPhi/fabs(m_sinPhi);
}
bool isVertical = ((input.zone()+1)/2)%2 == 0 ; // zones 0, 3, 4, 7
double signOfSolution = 1.;
if ( input.zone() < 1 || input.zone() > 4 ) signOfSolution = -1.;
int firstSensor = m_hitManager->lastPhiSensor();
// int lastSensor = m_hitManager->firstPhiSensor(); // not used
int step = -2;
if ( input.zone() < 4 ) firstSensor -= 1; // other side
if( !forward ) {
firstSensor = m_hitManager->firstPhiSensor();
// lastSensor = m_hitManager->lastPhiSensor();
step = +2;
if ( input.zone() > 3 ) firstSensor += 1; // other side
}
if ( isVertical ) step /= 2; // look on both sides
FastVeloSensor* first = m_hitManager->sensor( firstSensor );
double rOffset = first->rOffset( input.zone()%4 );
while( input.rPred( first->z() ) - rOffset > first->rMax() ||
input.rPred( first->z() ) - rOffset < first->rMin() ) {
FastVeloSensor* temp = m_hitManager->sensor( first->number() + step );
if ( 0 == temp ) break;
first = temp;
rOffset = first->rOffset( input.zone()%4 );
}
FastVeloSensor* last = first;
rOffset = last->rOffset( input.zone()%4 );
while( input.rPred( last->z() ) - rOffset < last->rMax() &&
input.rPred( last->z() ) - rOffset > last->rMin() ) {
FastVeloSensor* temp = m_hitManager->sensor( last->number() + step );
if ( 0 == temp ) break;
last = temp;
rOffset = last->rOffset( input.zone()%4 );
if ( last->number() + step > m_hitManager->lastPhiSensor() ) break;
}
if ( m_debug ) info() << "Space tracking. Zone " << input.zone() << " from " << first->number()
<< " to " << last->number() << " restrict to " << lowSensor << " - " << highSensor
<< " isVertical " << isVertical << " inOverlap " << inOverlap
<< " forward " << forward << " nbRight " << nbRight << " Left " << nbLeft << endreq;
//== Define the sine of the distance as measure of the track. Store those in the correct range
FastVeloSensor* sensor = first;
int firstSensorWithHit = -1;
std::vector< FastVeloHits > goodPhiHits(21, FastVeloHits() );
while ( sensor != last ) {
if ( sensor->number() > highSensor || sensor->number() < lowSensor ) {
sensor = m_hitManager->sensor( sensor->number() + step );
continue;
}
unsigned int module = sensor->number()/2 - 32;
double rPred = input.rInterpolated( sensor->z() ) - sensor->rOffset( input.zone()%4 );
double x0 = sensor->xCentre();
double y0 = sensor->yCentre();
double dR2 = rPred * rPred - x0 * x0 - y0 * y0;
double xPred = rPred * m_cosPhi + x0;
double yPred = rPred * m_sinPhi + y0;
double maxDSin = m_phiMatchZone;
if ( inOverlap ) maxDSin = m_phiCentralZone;
double minDist = -maxDSin * rPred;
double maxDist = maxDSin * rPred;
for ( unsigned int zone = 0; 2 > zone ; ++zone ) {
if ( rPred < sensor->rMin( zone ) || rPred > sensor->rMax( zone ) ) continue;
double minR = 0.4 * (sensor->rMin( zone ) + sensor->rMax( zone ) ); // .8 of centre
for ( itH = sensor->hits(zone).begin(); sensor->hits(zone).end() != itH; ++itH ) {
double dx = (*itH)->xStripCentre()-x0;
double dy = (*itH)->yStripCentre()-y0;
if ( m_cosPhi * dx + m_sinPhi * dy < minR ) continue; //scalar product OK
double dist = (*itH)->distance( xPred, yPred );
if ( dist < minDist || dist > maxDist ) continue;
double a = (*itH)->a();
double b = (*itH)->b();
double c = (*itH)->c();
double x = 0.;
double y = 0.;
if ( isVertical ) {
double bEq = b * c + a * b * x0 - a * a * y0;
double cEq = c * c + 2 * a * c * x0 - a * a * dR2;
y = - bEq + signOfSolution * sqrt( bEq * bEq - cEq );
x = ( - c - b * y ) / a;
} else {
double bEq = a * c + a * b * y0 - b * b * x0;
double cEq = c * c + 2 * b * c * y0 - b * b * dR2;
x = - bEq + signOfSolution * sqrt( bEq * bEq - cEq );
y = ( - c - a * x ) / b;
}
(*itH)->setGlobalPosition( x, y );
double dSin = ( y * m_cosPhi - x * m_sinPhi)/rPred;
(*itH)->setGlobal( dSin );
if ( m_debug && matchKey( *itH ) ) {
double xMc = m_debugTool->xTrue( m_wantedKey, sensor->z() );
double yMc = m_debugTool->yTrue( m_wantedKey, sensor->z() );
double rMc = sqrt( xMc * xMc + yMc * yMc );
info() << format( "x%7.3f y%7.3f R%7.3f dSin%7.3f, MC: %7.3f %7.3f R%7.3f dist%7.3f",
x, y, sqrt( x*x + y*y ), dSin,
xMc, yMc, rMc, (*itH)->distance( xMc, yMc ) );
printCoord( *itH, ":" );
}
if ( fabs( dSin ) > maxDSin ) continue;
(*itH)->setZ( sensor->z( x, y ) );
(*itH)->setPhiWeight( rPred );
if ( 0 > firstSensorWithHit ) firstSensorWithHit = sensor->number();
goodPhiHits[module].push_back( *itH );
}
}
sensor = m_hitManager->sensor( sensor->number() + step );
}
//== Sort and find the station range;
unsigned int firstStation = 0;
unsigned int lastStation = 20;
unsigned int station;
for ( station = 0; 21 > station; ++station ) {
if ( goodPhiHits[station].size() == 0 ) {
if ( station == firstStation ) ++firstStation;
} else {
lastStation = station;
if ( goodPhiHits[station].size() > 1 ) std::sort( goodPhiHits[station].begin(), goodPhiHits[station].end(),
FastVeloHit::LowerByGlobal() );
}
}
int stationStep = 1;
if ( forward ) {
unsigned int tmp = firstStation;
firstStation = lastStation;
lastStation = tmp;
stationStep = -1;
}
unsigned int nbStations = abs( int(lastStation) - int(firstStation) ) + 1;
if ( nbStations > input.rHits().size() ) nbStations = input.rHits().size();
if ( inOverlap ) {
nbStations = nbRight;
if ( nbLeft > nbRight ) nbStations = nbLeft;
}
unsigned int minNbPhi = int( m_fractionFound * nbStations );
if ( 3 > minNbPhi ) minNbPhi = 3;
if ( m_debug ) {
info() << "Space search from station " << firstStation << " to " << lastStation
<< " minNbPhi " << minNbPhi << endmsg;
printCoords( input.rHits(), "R " );
sensor = first;
while ( sensor != last ) {
for ( unsigned int zone = 0; 2 > zone ; ++zone ) {
for ( itH = sensor->hits(zone).begin(); sensor->hits(zone).end() != itH; ++itH ) {
if ( matchKey( *itH ) ) printCoord( *itH, "Phi" );
}
}
sensor = m_hitManager->sensor( sensor->number() + step );
}
//== Display the list of selected hits
info() <<"--- goodPhiHits ---" << endmsg;
for ( station = firstStation; lastStation+stationStep != station; station += stationStep ) {
std::sort( goodPhiHits[station].begin(), goodPhiHits[station].end(), FastVeloHit::LowerByGlobal() );
printCoords( goodPhiHits[station], "Selected " );
if ( stationStep == -1 && station == 0 ) break;
}
}
FastVeloTracks newTracks;
//== Search sensors for 'lists' with low angle, i.e. d(global)/dz
FastVeloHits::iterator itH1, itH2, itH3;
unsigned int s1, s2, s3;
double z1;
s1 = firstStation;
s2 = s1 + stationStep;
s3 = s2 + stationStep;
bool hasFullLength = false;
for ( int iCase = 0; 5 > iCase; ++iCase ) {
if ( 2 == iCase ) s3 += stationStep;
if ( 3 == iCase ) s2 += stationStep;
if ( 4 == iCase ) s1 += stationStep;
if ( s1 > 20 || s2 > 20 || s3 > 20 ) continue; // protect agains access to no existent modules
for ( itH1 = goodPhiHits[s1].begin(); goodPhiHits[s1].end() != itH1; ++itH1 ) {
if ( 0 == iCase && 0 != (*itH1)->nbUsed() ) continue;
z1 = (*itH1)->z();
double rPred = input.rInterpolated( z1 );
double minDelta2 = m_maxDelta2;
FastVeloHit* best2 = NULL;
for ( itH2 = goodPhiHits[s2].begin(); goodPhiHits[s2].end() != itH2; ++itH2 ) {
if ( 0 == iCase && 0 != (*itH2)->nbUsed() ) continue;
double dist = fabs( ( (*itH2)->global() - (*itH1)->global() ) * rPred / ( (*itH2)->z() - z1 ) );
if ( minDelta2 > dist ) {
best2 = *itH2;
if ( m_debug ) {
info() << "+++ iCase " << iCase << " Try pair with dist = " << dist << " s3 = " << s3 << endmsg;
printCoord( *itH1, "s1" );
printCoord( best2, "s2" );
}
//== Check that this pair is not already on an existing candidate
bool reject = false;
for ( FastVeloTracks::iterator itT = newTracks.begin(); newTracks.end() != itT ; ++itT ) {
if ( std::find( (*itT).phiHits().begin(), (*itT).phiHits().end(), *itH1 ) != (*itT).phiHits().end() ) {
if ( std::find( (*itT).phiHits().begin(), (*itT).phiHits().end(), best2 ) != (*itT).phiHits().end() ) {
reject = true;
break;
}
}
}
if ( reject ) {
if ( m_debug ) info() << "Already used hits..." << endmsg;
continue;
}
double dz = z1 - best2->z();
double tx = ( (*itH1)->xGlobal() - best2->xGlobal() ) / dz;
double ty = ( (*itH1)->yGlobal() - best2->yGlobal() ) / dz;
double x0 = (*itH1)->xGlobal() - tx * z1;
double y0 = (*itH1)->yGlobal() - ty * z1;
double minDelta3 = 1.e9;
FastVeloHit* best3 = NULL;
for ( itH3 = goodPhiHits[s3].begin(); goodPhiHits[s3].end() != itH3; ++itH3 ) {
if ( 0 == iCase && 0 != (*itH3)->nbUsed() ) continue;
if ( 1 == iCase &&
0 == (*itH1)->nbUsed() &&
0 == (best2)->nbUsed() &&
0 == (*itH3)->nbUsed()) continue; // already tried in iCase = 0.
double dist = (*itH3)->chi2( x0 + (*itH3)->z() * tx, y0 + (*itH3)->z() * ty );
if ( minDelta3 > dist ) {
minDelta3 = dist;
best3 = *itH3;
}
}
if ( minDelta3 > 4 * m_maxChi2ToAdd ) continue;
if ( m_debug ) {
info() << "+++ Found triplet with minDelta3 = " << minDelta3 << endmsg;
printCoord( *itH1, "s1" );
printCoord( best2, "s2" );
printCoord( best3, "s3" );
}
//== Update Z of the R sensors
for ( itH = input.rHits().begin(); input.rHits().end() != itH ; ++itH ) {
FastVeloSensor* _sensor = m_hitManager->sensor( (*itH)->sensor() );
double x = x0 + tx * _sensor->z();
double y = y0 + ty * _sensor->z();
(*itH)->setZ( _sensor->z( x, y ) );
}
FastVeloTrack temp;
temp.setPhiClusters( input, x0, tx, y0, ty, *itH1, best2, best3 );
if ( m_debug ) printTrack( temp, "Initial track" );
bool ok = temp.removeWorstMultiple( m_maxChi2PerHit, 3 );
if ( !ok ) {
if ( m_debug ) info() << "Triplet not acceptable: not enough good phi " << endmsg;
continue;
}
if ( inOverlap ) {
temp.addBestClusterOtherSensor( goodPhiHits[s1], m_maxChi2ToAdd );
temp.addBestClusterOtherSensor( goodPhiHits[s2], m_maxChi2ToAdd );
temp.addBestClusterOtherSensor( goodPhiHits[s3], m_maxChi2ToAdd );
ok = temp.removeWorstMultiple( m_maxChi2PerHit, 3 );
if ( !ok ) {
if ( m_debug ) info() << "After adding other side: Not enough phi " << endmsg;
continue;
}
}
temp.updateRParameters();
int nbMissed = 0;
double lastZ = best3->z();
for ( unsigned int s = s3 + stationStep; lastStation+stationStep != s; s += stationStep ){
if ( goodPhiHits[s].size() != 0 ) {
if ( m_debug ) {
info() << "Try to add more on station " << s << endmsg;
for ( itH = goodPhiHits[s].begin(); goodPhiHits[s].end() != itH; ++itH ) {
info() << format( "Dist%8.3f Chi2%8.2f", temp.distance( *itH ), temp.chi2( *itH ) );
printCoord( *itH, "Selected " );
}
}
double addChi2 = m_maxChi2ToAdd;
if ( fabs( goodPhiHits[s].front()->z() - lastZ ) > 140. ) addChi2 = 4 * addChi2;
bool ok1 = temp.addBestPhiCluster( goodPhiHits[s], addChi2 );
if ( !ok1 ) {
nbMissed++;
} else {
if ( inOverlap ) temp.addBestClusterOtherSensor( goodPhiHits[s], m_maxChi2ToAdd );
if ( m_debug ) printTrack( temp, "After adding" );
}
} else {
nbMissed++;
}
if ( nbMissed > 2 ) break;
}
temp.updateRParameters();
ok = temp.removeWorstMultiple( m_maxChi2PerHit, minNbPhi );
if ( !ok ) {
if ( m_debug ) info() << "Rejected , not enough phi = "
<< temp.phiHits().size() << " for " << minNbPhi << endreq;
continue;
}
//== Overall quality should be good enough...
if ( m_maxQFactor < temp.qFactor() ) {
if ( m_debug ) info() << "Rejected , qFactor = " << temp.qFactor() << endreq;
continue;
}
//== Check that the R hits are within the correct zone
int nbOutOfZone = 0;
for ( itH = input.rHits().begin(); input.rHits().end() != itH ; ++itH ) {
FastVeloSensor* _sensor = m_hitManager->sensor( (*itH)->sensor() );
double x = temp.xAtHit( *itH ) - _sensor->xCentre();
double y = temp.yAtHit( *itH ) - _sensor->yCentre();
if ( isVertical && fabs(x) > fabs(y) + 0.1 ) ++nbOutOfZone;
if (!isVertical && fabs(x) < fabs(y) - 0.1 ) ++nbOutOfZone;
}
if ( nbOutOfZone > 1 ) {
if ( m_debug ) {
info() << "The azimuth is incompatible with the R zone" << endmsg;
for ( itH = input.rHits().begin(); input.rHits().end() != itH ; ++itH ) {
FastVeloSensor* _sensor = m_hitManager->sensor( (*itH)->sensor() );
double x = temp.xAtHit( *itH ) - _sensor->xCentre();
double y = temp.yAtHit( *itH ) - _sensor->yCentre();
info() << format( "x%8.3f y%8.3f ", x, y );
printCoord( *itH, "Out" );
}
}
continue;
}
//== Check that there are phi hits on the same side as the R hits...
int nbPhiLeft = 0;
int nbPhiRight = 0;
for ( itH = temp.phiHits().begin(); temp.phiHits().end() != itH ; ++itH ) {
if ( m_hitManager->sensor( (*itH)->sensor() )->isRight() ) {
nbPhiRight++;
} else {
nbPhiLeft++;
}
}
if ( nbLeft * nbPhiLeft + nbRight * nbPhiRight == 0 ) {
if ( m_debug ) {
info() << "Phi and R are all on opposite sides: Left R " << nbLeft << " Phi " << nbPhiLeft
<< " Right R " << nbRight << " phi " << nbPhiRight << ". Reject" << endmsg;
}
continue;
}
if ( ok ) { //== Store it.
if ( m_debug ) {
info() << "**** Accepted qFactor : " << temp.qFactor() << " ***" << endmsg;
printTrack( temp );
}
newTracks.push_back( temp );
if ( temp.phiHits().size() >= temp.rHits().size() ) hasFullLength = true;
}
}
}
}
if ( iCase > 0 && hasFullLength ) break;
}
//== If no track found AND in overlap: Try all hits first
if ( inOverlap && 0 == newTracks.size() ) {
s1 = firstStation;
s2 = s1 + stationStep;
s3 = s2 + stationStep;
if ( s1 < 21 && s2 < 21 && s3 < 21 ) { // protect agains access to no existent modules
FastVeloHits all(goodPhiHits[s1]);
station = s2;
while ( lastStation+stationStep != station ) {
for ( itH = goodPhiHits[station].begin(); goodPhiHits[station].end() != itH; ++itH ) all.push_back( *itH );
station += stationStep;
if ( station > 20 ) break;
}
FastVeloTrack temp;
temp.setPhiClusters( input, m_cosPhi, m_sinPhi, all.begin(), all.end() );
if ( m_debug ) {
info() << "+++ Try with all hits on stations " << s1 << " to " << station
<< ", minNbPhi " << minNbPhi << endmsg;
printTrack( temp );
}
bool ok = temp.removeWorstMultiple( m_maxChi2PerHit, minNbPhi );
if ( ok ) {
//== Overall quality should be good enough...
if ( m_maxQFactor < temp.qFactor() ) {
if ( m_debug ) info() << "Rejected , qFactor = " << temp.qFactor() << endreq;
ok = false;
}
if ( ok ) { //== Store it.
if ( m_debug ) {
info() << "**** Accepted qFactor : " << temp.qFactor() << " ***" << endmsg;
printTrack( temp );
}
newTracks.push_back( temp );
}
}
}
}
//== Last chance: This is a fake overlap. Split....
if ( inOverlap && 0 == newTracks.size() ) {
FastVeloHits other;
for ( itH = input.rHits().begin(); input.rHits().end() != itH; ++itH ) {
if ( (*itH)->zone() != (input.zone()%4) ) {
other.push_back( *itH );
itH = input.rHits().erase( itH );
itH--;
}
}
bool localDebug = m_debug;
if ( localDebug ) {
info() <<"=== Try with hits from the Main zone itself ===" << endmsg;
printCoords( input.rHits(), "Main " );
}
makeSpaceTracks( input );
input.rHits() = other;
input.setZone( 7 - input.zone() );
if ( localDebug ) {
info() <<"=== Try with hits from the other zone ===" << endmsg;
printCoords( input.rHits(), "Other" );
}
makeSpaceTracks( input );
return;
}
//== Any need for merging tracks ?
if ( m_debug ) info() <<"Before merge clones, size " << newTracks.size() << endmsg;
mergeClones( newTracks );
FastVeloTracks::iterator itTr;
double maxQual = 1.e10;
unsigned int maxLen = 0;
//== Get the properties of the best candidate. Invalidate tracks with 3 or 4 clusters and all already used.
for ( itTr = newTracks.begin(); newTracks.end() != itTr; ++itTr ) {
if ( !(*itTr).isValid() ) continue;
if ( 4 > (*itTr).phiHits().size() &&
0 == (*itTr).nbUnusedPhiHits() ) {
(*itTr).setValid( false );
if ( m_debug ) printTrack( *itTr, "Reject track: less than 4 phi, all already used..." );
continue;
}
if ( (*itTr).phiHits().size() >= maxLen ) maxLen = (*itTr).phiHits().size();
}
unsigned int minExpected = maxLen;
if ( 4 < maxLen ) minExpected = minExpected-1;
for ( itTr = newTracks.begin(); newTracks.end() != itTr; ++itTr ) {
if ( !(*itTr).isValid() ) continue;
if ( minExpected <= (*itTr).phiHits().size() ) {
if ( maxQual > (*itTr).qFactor() ) maxQual = (*itTr).qFactor();
}
}
if ( 3 < maxLen ) maxQual += m_deltaQuality;
//== Store the good candidates
bool foundSpaceTrack = false;
for ( itTr = newTracks.begin(); newTracks.end() != itTr; ++itTr ) {
if ( !(*itTr).isValid() ) continue;
if ( m_debug ) {
info() << "Test track " << itTr - newTracks.begin() << " nbPhiHits " << (*itTr).phiHits().size()
<< " (min " << minExpected << ") qFact " << (*itTr).qFactor()
<< " (max " << maxQual << ")";
}
if ( minExpected > (*itTr).phiHits().size() ||
maxQual < (*itTr).qFactor() ) {
if ( m_debug ) info() << endmsg;
continue;
}
//== Stronger test on 3+3 hit tracks
if ( (*itTr).rHits().size() == 3 &&
(*itTr).phiHits().size() == 3 ) {
if ( (*itTr).qFactor() > m_maxQFactor3 ) {
if ( m_debug ) {
info() << "Short track. qFactor too low : " << (*itTr).qFactor() << endmsg;
printTrack( *itTr );
}
continue;
}
}
if ( !(*itTr).removeWorstRAndPhi( m_maxChi2PerHit, 6 ) ) {
if ( m_debug ) {
info() << "Track with less than 3 R or Phi after cleanup" << endmsg;
printTrack( *itTr );
}
continue;
}
if ( m_debug ) {
info() << " ... stored as " << m_spaceTracks.size() << endmsg;
printTrack( *itTr );
}
(*itTr).tagUsedPhiHits();
(*itTr).setBackward( input.backward() );
m_spaceTracks.push_back( *itTr );
foundSpaceTrack = true;
}
if ( !foundSpaceTrack ) {
if ( m_minToTag <= input.nbRHits() ) input.untagUsedRHits();
}
}
//=========================================================================
// Merge tracks sharing hits, tag clones.
//=========================================================================
void FastVeloTracking::mergeClones ( FastVeloTracks& tracks ) {
if ( tracks.size() <= 1 ) return;
FastVeloTracks::iterator it1, it2;
for ( it1 = tracks.begin(); tracks.end()-1 > it1 ; ++it1 ) {
int n1 = (*it1).phiHits().size();
for ( it2 = it1+1; tracks.end() != it2 ; ++it2 ) {
if ( !(*it2).isValid() ) continue;
int n2 = (*it2).phiHits().size();
int minN = n1 > n2 ? n2 : n1;
int nCommon = 0;
FastVeloHits::const_iterator itH;
for ( itH = (*it1).phiHits().begin(); (*it1).phiHits().end() != itH ; ++itH ) {
if ( std::find( (*it2).phiHits().begin(), (*it2).phiHits().end(), *itH ) != (*it2).phiHits().end() ) ++nCommon;
}
if ( nCommon > m_fractionForMerge * minN ) {
if ( n2 > n1 ) {
(*it1).setValid( false );
} else if ( n1 > n2 ) {
(*it2).setValid( false );
} else if ( (*it1).qFactor() < (*it2).qFactor() ) {
(*it2).setValid( false );
} else {
(*it1).setValid( false );
}
}
}
}
}
//=========================================================================
// Try to find tracks with unused phi clusters, only forward
//=========================================================================
void FastVeloTracking::findUnusedPhi( ) {
m_debug = m_isDebug;
if ( 0 <= m_wantedKey ) info() << endmsg << "===== Unused Phi procesing ====" << endmsg;
double phiUnusedFirstTol = m_phiUnusedFirstTol;
double phiUnusedSecondTol = m_phiUnusedSecondTol;
double maxQFactor = m_maxQFactor;
int firstSensor = m_hitManager->lastPhiSensor();
int lastSensor = firstSensor - 15;
if ( m_tracks.size() < 10 ) { // clean event (e.g. Velo open)
phiUnusedFirstTol = 20.;
phiUnusedSecondTol = 20.;
maxQFactor = 2.;
lastSensor = firstSensor - 30;
}
for ( int phi0 = firstSensor; lastSensor <= phi0; --phi0 ) {
int phi1 = phi0 - 2;
int phi2 = phi1 - 2;
FastVeloSensor* s0 = m_hitManager->sensor( phi0 );
FastVeloSensor* s1 = m_hitManager->sensor( phi1 );
FastVeloSensor* s2 = m_hitManager->sensor( phi2 );
FastVeloSensor* r0 = m_hitManager->sensor( phi0-64 );
FastVeloSensor* r1 = m_hitManager->sensor( phi1-64 );
FastVeloSensor* r2 = m_hitManager->sensor( phi2-64 );
for ( unsigned int zone = 0; 2 > zone ; ++zone ) {
for ( FastVeloHits::iterator itH0 = s0->hits(zone).begin(); s0->hits(zone).end() != itH0; ++itH0 ) {
if ( 0 != (*itH0)->nbUsed() ) continue;
for ( unsigned int zone1 = 0; zone+1 > zone1 ; ++zone1 ) {
for ( FastVeloHits::iterator itH1 = s1->hits(zone1).begin(); s1->hits(zone1).end() != itH1; ++itH1 ) {
if ( 0 != (*itH1)->nbUsed() ) continue;
double d1 = (*itH1)->distance( (*itH0)->xStripCentre(), (*itH0)->yStripCentre() );
if ( matchKey( *itH0 ) && matchKey( *itH1 ) ) {
info() << "S0 " << phi0 << " z0 " << zone << " S1 " << phi1 << " z1 " << zone1 << " d1 " << d1 << endmsg;
}
if ( fabs( d1 ) > phiUnusedFirstTol ) continue;
double xSeed = .5 * ( (*itH0)->xStripCentre() + (*itH1)->xStripCentre() );
double ySeed = .5 * ( (*itH0)->yStripCentre() + (*itH1)->yStripCentre() );
if ( 0 != m_debugTool ) {
m_debug = m_isDebug;
if ( matchKey( *itH0 ) || matchKey( *itH1 ) ) {
m_debug = true;
info() << "Extrapolate, d1 " << d1 << endmsg;
printCoord( *itH0, "phi0" );
printCoord( *itH1, "phi1" );
}
}
for ( unsigned int zone2 = 0; zone1+1 > zone2 ; ++zone2 ) {
for ( FastVeloHits::iterator itH2 = s2->hits(zone2).begin(); s2->hits(zone2).end() != itH2; ++itH2 ) {
if ( 0 != (*itH2)->nbUsed() ) continue;
double d2 = (*itH2)->distance( xSeed, ySeed );
if ( m_debug ) {
info() << " ++ D2 " << d2 ;
printCoord( *itH2, " : " );
}
if ( fabs( d2 ) > phiUnusedSecondTol ) continue;
if ( m_debug ) {
info() << "*** FindUnusedPhi : phi triplet, d2 = " << d2 << endmsg;
printCoord( *itH0, "phi0" );
printCoord( *itH1, "phi1" );
printCoord( *itH2, "phi2" );
}
int rZone = 0;
if ( fabs( xSeed - r0->xCentre() ) > fabs( ySeed - r0->yCentre() ) ) rZone = 1;
if ( xSeed * ySeed > 0 ) rZone = 3 - rZone;
if ( m_debug ) info() << "Looking in R zone " << rZone << " sensor " << r0->number()
<< " xSeed " << xSeed << " ySeed " << ySeed
<< " xCentre " << r0->xCentre() << " yCentre " << r0 -> yCentre() << endmsg;
for ( FastVeloHits::const_iterator itR0 = r0->hits(rZone).begin();
r0->hits(rZone).end() != itR0; ++itR0 ) {
if ( (*itR0)->rLocal() < s0->rMin( zone ) ||
(*itR0)->rLocal() > s0->rMax( zone ) ) continue;
(*itR0)->setStartingPoint( xSeed, ySeed );
int nbUnused = 0;
if ( 0 == (*itR0)->nbUsed() ) nbUnused++;
FastVeloTrack temp;
int spaceZone = rZone;
if ( xSeed < 0 ) spaceZone = 4 + rZone;
temp.setPhiClusters( *itR0, spaceZone, *itH0, *itH1, *itH2 );
temp.updatePhiWeights();
if ( m_debug ) {
double xLocal = temp.xAtZ( r1->z() ) - r1->xCentre();
double yLocal = temp.yAtZ( r1->z() ) - r1->yCentre();
double rLocal = sqrt( xLocal * xLocal + yLocal * yLocal );
info() << format( "rPred %8.3f zone%2d", rLocal, rZone );
printCoord( *itR0, "R0 " );
}
if ( !temp.addBestRCluster( r1, 400.) ) continue;
temp.updatePhiWeights();
if ( 0 == temp.rHits().back()->nbUsed() ) nbUnused++;
if ( m_debug ) {
double xLocal = temp.xAtZ( r2->z() ) - r2->xCentre();
double yLocal = temp.yAtZ( r2->z() ) - r2->yCentre();
double rLocal = sqrt( xLocal * xLocal + yLocal * yLocal );
info() << format( "rPred %8.3f zone%2d", rLocal, rZone );
printCoord( temp.rHits().back(), "R1 " );
}
if ( !temp.addBestRCluster( r2, m_maxChi2ToAdd ) ) continue;
if ( 0 == temp.rHits().back()->nbUsed() ) nbUnused++;
if ( m_debug ) {
info() << format( "qFactor %8.3f NbUnused%2d ", temp.qFactor(), nbUnused );
printCoord( temp.rHits().back(), "R2 " );
printTrack( temp );
}
if ( 2 > nbUnused ) continue;
if ( temp.qFactor() > maxQFactor ) continue;
FastVeloSensor* s = r2;
int nMiss = 0;
while ( 0 <= s->next( true ) && nMiss <= m_maxMissed ) {
s = m_hitManager->sensor( s->next( true ) );
if ( temp.rAtZ( s->z() ) < s->rMin() ) break;
if ( !temp.addBestRCluster( s, m_maxChi2ToAdd ) ) nMiss++;
FastVeloSensor* phiSensor = m_hitManager->sensor( s->number() + 64 );
int phiZone = 0;
double rInPhi = temp.rAtZ( phiSensor->z() );
if ( temp.rAtZ( phiSensor->z() ) > phiSensor->rMax( 0 ) ) phiZone = 1;
for ( FastVeloHits::iterator itH = phiSensor->hits(phiZone).begin();
phiSensor->hits(phiZone).end() != itH ; ++itH ) {
(*itH)->setPhiWeight(rInPhi );
}
if ( !temp.addBestPhiCluster( phiSensor->hits(phiZone), m_maxChi2ToAdd ) ) nMiss++;
}
if ( !temp.removeWorstRAndPhi( m_maxChi2PerHit, 6 ) ) {
if ( m_debug ) {
info() << "Track with less than 3 R or Phi after cleanup" << endmsg;
printTrack( temp );
}
continue;
}
if ( m_debug ) {
info() << "*** Good track, qFactor " << temp.qFactor() << endmsg;
printTrack( temp );
}
temp.tagUsedRHits();
temp.tagUsedPhiHits();
m_spaceTracks.push_back( temp );
}
}
}
}
}
}
}
}
m_debug = m_isDebug;
}
//=========================================================================
// Debug tool: Print the coordinate
//=========================================================================
void FastVeloTracking::printCoord( const FastVeloHit* hit, std::string title ) {
info() << " " << title
<< format( " sensor %3d z%7.1f zone%2d strip%5d coord%8.3f local%8.3f size%2d frac %5.2f used%2d ",
hit->sensor(), hit->z(), hit->zone(), hit->cluster().channelID().strip(), hit->global(), hit->rLocal(),
hit->cluster().pseudoSize(), hit->cluster().interStripFraction() , hit->nbUsed() );
LHCb::LHCbID myId = hit->lhcbID();
if ( 0 != m_debugTool ) m_debugTool->printKey( info(), myId );
if ( matchKey( hit ) ) info() << " ***";
info() << endreq;
}
//=========================================================================
// Debug a track, with all its hits
//=========================================================================
void FastVeloTracking::printTrack( FastVeloTrack& track, std::string header ) {
if ( "" != header ) info() << "*** " << header << " ***" << endmsg;
for ( FastVeloHits::iterator itH = track.rHits().begin(); track.rHits().end() != itH ; ++itH ) {
info() << format( "Dist%8.3f Chi2%8.2f", track.distance( *itH ), track.chi2( *itH ) );
printCoord( *itH, " R " );
}
for ( FastVeloHits::iterator itH = track.phiHits().begin(); track.phiHits().end() != itH ; ++itH ) {
info() << format( "Dist%8.3f Chi2%8.2f", track.distance( *itH ), track.chi2( *itH ) );
printCoord( *itH, " Phi " );
}
info() << endmsg;
}
//=========================================================================
// Debug a R track, with all its hits
//=========================================================================
void FastVeloTracking::printRTrack( FastVeloTrack& track, std::string header ) {
if ( "" != header ) info() << "*** " << header << " ***" << endmsg;
for ( FastVeloHits::iterator itH = track.rHits().begin(); track.rHits().end() != itH ; ++itH ) {
double d = track.rPred( (*itH)->z() )-(*itH)->global();
info() << format( "Dist%8.3f Chi2%8.2f", d, d * d * (*itH)->weight() );
printCoord( *itH, " R " );
}
info() << endmsg;
}
//=========================================================================
// Print a vector of hits
//=========================================================================
void FastVeloTracking::printCoords( FastVeloHits& hits, std::string header ) {
for ( FastVeloHits::iterator itH = hits.begin(); hits.end() != itH ; ++itH ) {
printCoord( *itH, header );
}
}
//=============================================================================
// $Id: $
#ifndef FASTVELOTRACKING_H
#define FASTVELOTRACKING_H 1
// Include files
// from Gaudi
#include "GaudiAlg/GaudiAlgorithm.h"
#include "PatKernel/IPatDebugTool.h"
#include "GaudiAlg/ISequencerTimerTool.h"
#include "FastVeloHitManager.h"
#include "FastVeloTrack.h"
/** @class FastVeloTracking FastVeloTracking.h
* Fast implementation of teh Velo tracking
*
* @author Olivier Callot
* @date 2010-09-09
*/
class FastVeloTracking : public GaudiAlgorithm {
public:
/// Standard constructor
FastVeloTracking( const std::string& name, ISvcLocator* pSvcLocator );
virtual ~FastVeloTracking( ); ///< Destructor
virtual StatusCode initialize(); ///< Algorithm initialization
virtual StatusCode execute (); ///< Algorithm execution
virtual StatusCode finalize (); ///< Algorithm finalization
void findQuadruplets( unsigned int sens0, bool forward );
void findUnusedTriplets( unsigned int sens0, bool forward );
FastVeloHit* closestHit( FastVeloHits& hits, double coord, double tol );
FastVeloHit* closestUnusedHit( FastVeloHits& hits, double coord, double tol );
int extendTrack( FastVeloTrack& newTrack, FastVeloSensor* sensor,
unsigned int zone, bool forward );
void addOppositeSideRHits( FastVeloTrack& newTrack, const int &zone,
FastVeloSensor* sensor, bool forward );
void makeLHCbTracks( LHCb::Tracks* output );
void makeSpaceTracks( FastVeloTrack& input );
void mergeSpaceClones();
void findUnusedPhi();
void mergeClones( FastVeloTracks& tracks );
//== Debugging methods
bool matchKey( const FastVeloHit* hit ) {
if ( m_debugTool ) {
LHCb::LHCbID id = hit->lhcbID();
return m_debugTool->matchKey( id, m_wantedKey );
}
return false;
}
void printCoord( const FastVeloHit* hit, std::string title );
void printTrack( FastVeloTrack& track, std::string header = "" );
void printRTrack( FastVeloTrack& track, std::string header = "" );
void printCoords( FastVeloHits& hits, std::string header = "" );
protected:
private:
std::string m_outputLocation;
std::string m_hitManagerName;
//== Overall control parameters
bool m_onlyForward;
bool m_onlyBackward;
bool m_HLT1Only;
bool m_HLT2Complement;
unsigned int m_maxRZForExtra;
bool m_stateAtBeam;
bool m_resetUsedFlags;
//== Paramaters for RZ search
double m_zVertexMin; ///< Minimal Z of a vertex for forward tracks
double m_zVertexMax; ///< Maximal Z of a vertex for defining last sensor in backward tracks
double m_zVertexMaxBack; ///< Maximal Z of a vertex for backward tracks
double m_maxRSlope; ///< Maximum RZ slope considered
double m_rMatchTol4; ///< R match tolerance in a quadruplet, in pitch unit
double m_rMatchTol3; ///< R match tolerance in a triplet, in pitch unit
double m_rExtraTol; ///< R match tol. extrapolating, in pitch unit
double m_rOverlapTol; ///< R match in overlap, in pitch unit
int m_maxMissed; ///< Maximum number of consecutive missed sensors
unsigned int m_minToTag; ///< Minimum number of hit on track to tag as used
double m_phiMatchZone;
double m_phiCentralZone;
double m_maxDelta2;
double m_fractionFound;
double m_maxChi2PerHit;
double m_maxChi2ToAdd;
double m_maxQFactor;
double m_maxQFactor3;
double m_deltaQuality;
double m_fractionForMerge;
double m_phiUnusedFirstTol;
double m_phiUnusedSecondTol;
//== Debugging controls
std::string m_debugToolName;
int m_wantedKey;
IPatDebugTool* m_debugTool;
bool m_isDebug;
bool m_debug;
bool m_doTiming;
ISequencerTimerTool* m_timerTool;
int m_timeTotal;
int m_timePrepare;
int m_timeFwd4;
int m_timeBkwd4;
int m_timeFwd3;
int m_timeBkwd3;
int m_timeSpace;
int m_timeUnused;
int m_timeFinal;
//== Working variables
FastVeloHitManager* m_hitManager;
FastVeloTracks m_tracks; ///< Vector of tracks used during the processing
FastVeloTracks m_spaceTracks; ///< Vector of tracks used during the processing
double m_cosPhi;
double m_sinPhi;
};
#endif // FASTVELOTRACKING_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment