//_____________________________________________________________________________ Int_t THaVDC::ConstructTracks( TClonesArray* tracks, Int_t mode ) { // Construct tracks from pairs of upper and lower UV tracks and add // them to 'tracks' #ifdef WITH_DEBUG if( fDebug>1 ) { cout << "-----------------------------------------------\n"; cout << "ConstructTracks: "; if( mode == 0 ) cout << "iterating"; if( mode == 1 ) cout << "coarse tracking"; if( mode == 2 ) cout << "fine tracking"; cout << endl; } #endif UInt_t theStage = ( mode == 1 ) ? kCoarse : kFine; fUVpairs->Clear(); Int_t nUpperTracks = fUpper->GetNUVTracks(); Int_t nLowerTracks = fLower->GetNUVTracks(); #ifdef WITH_DEBUG if( fDebug>1 ) cout << "nUpper/nLower = " << nUpperTracks << " " << nLowerTracks << endl; #endif // No tracks at all -> can't have any tracks if( nUpperTracks == 0 && nLowerTracks == 0 ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "No tracks.\n"; #endif return 0; } Int_t nTracks = 0; // Number of valid particle tracks through the detector Int_t nPairs = 0; // Number of UV track pairs to consider // One plane has no tracks, the other does // -> maybe recoverable with loss of precision // FIXME: Only do this if missing cluster recovery flag set if( nUpperTracks == 0 || nLowerTracks == 0 ) { //FIXME: Put missing cluster recovery code here //For now, do nothing #ifdef WITH_DEBUG if( fDebug>1 ) cout << "missing cluster " << nUpperTracks << " " << nUpperTracks << endl; #endif return 0; } THaVDCUVTrack *track, *partner; THaVDCTrackPair *thePair; for( int i = 0; i < nLowerTracks; i++ ) { track = fLower->GetUVTrack(i); if( !track ) continue; for( int j = 0; j < nUpperTracks; j++ ) { partner = fUpper->GetUVTrack(j); if( !partner ) continue; // Create new UV track pair. thePair = new( (*fUVpairs)[nPairs++] ) THaVDCTrackPair( track, partner ); // Explicitly mark these UV tracks as unpartnered track->SetPartner( NULL ); partner->SetPartner( NULL ); // Compute goodness of match parameter thePair->Analyze( fUSpacing ); } } #ifdef WITH_DEBUG if( fDebug>1 ) cout << nPairs << " pairs.\n"; #endif // Initialize some counters int n_exist = 0, n_mod = 0; int n_oops = 0; // How many tracks already exist in the global track array? if( tracks ) n_exist = tracks->GetLast()+1; // Sort pairs in order of ascending goodness of match if( nPairs > 1 ) fUVpairs->Sort(); // Mark pairs as partners, starting with the best matches, // until all tracks are marked. for( int i = 0; i < nPairs; i++ ) { if( !(thePair = static_cast<THaVDCTrackPair*>( fUVpairs->At(i) )) ) continue; #ifdef WITH_DEBUG if( fDebug>1 ) { cout << "Pair " << i << ": " << thePair->GetUpper()->GetUCluster()->GetPivotWireNum() << " " << thePair->GetUpper()->GetVCluster()->GetPivotWireNum() << " " << thePair->GetLower()->GetUCluster()->GetPivotWireNum() << " " << thePair->GetLower()->GetVCluster()->GetPivotWireNum() << " " << thePair->GetError() << endl; } #endif // Stop if track matching error too big if( thePair->GetError() > fErrorCutoff ) break; // Get the tracks of the pair track = thePair->GetLower(); partner = thePair->GetUpper(); if( !track || !partner ) continue; //FIXME: debug #ifdef WITH_DEBUG if( fDebug>1 ) { cout << "dUpper/dLower = " << thePair->GetProjectedDistance( track,partner,fUSpacing) << " " << thePair->GetProjectedDistance( partner,track,-fUSpacing); } #endif // Skip pairs where any of the tracks already has a partner if( track->GetPartner() || partner->GetPartner() ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << " ... skipped.\n"; #endif continue; } #ifdef WITH_DEBUG if( fDebug>1 ) cout << " ... good.\n"; #endif // Make the tracks of this pair each other's partners. This prevents // tracks from being associated with more than one valid pair. track->SetPartner( partner ); partner->SetPartner( track ); thePair->SetStatus(1); nTracks++; // Compute global track values and get TRANSPORT coordinates for tracks. // Replace local cluster slopes with global ones, // which have higher precision. THaVDCCluster *tu = track->GetUCluster(), *tv = track->GetVCluster(), *pu = partner->GetUCluster(), *pv = partner->GetVCluster(); Double_t du = pu->GetIntercept() - tu->GetIntercept(); Double_t dv = pv->GetIntercept() - tv->GetIntercept(); Double_t mu = du / fUSpacing; Double_t mv = dv / fVSpacing; tu->SetSlope(mu); tv->SetSlope(mv); pu->SetSlope(mu); pv->SetSlope(mv); // Recalculate the UV track's detector coordinates using the global // U,V slopes. track->CalcDetCoords(); partner->CalcDetCoords(); #ifdef WITH_DEBUG if( fDebug>2 ) cout << "Global track parameters: " << mu << " " << mv << " " << track->GetTheta() << " " << track->GetPhi() << endl; #endif // If the 'tracks' array was given, add THaTracks to it // (or modify existing ones). if (tracks) { // Decide whether this is a new track or an old track // that is being updated THaVDCTrackID* thisID = new THaVDCTrackID(track,partner); THaTrack* theTrack = NULL; bool found = false; int t; for( t = 0; t < n_exist; t++ ) { theTrack = static_cast<THaTrack*>( tracks->At(t) ); // This test is true if an existing track has exactly the same clusters // as the current one (defined by track/partner) if( theTrack && theTrack->GetCreator() == this && *thisID == *theTrack->GetID() ) { found = true; break; } // FIXME: for debugging n_oops++; } UInt_t flag = theStage; if( nPairs > 1 ) flag |= kMultiTrack; if( found ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << t << " modified.\n"; #endif delete thisID; ++n_mod; } else { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << tracks->GetLast()+1 << " added.\n"; #endif theTrack = AddTrack(*tracks, 0.0, 0.0, 0.0, 0.0, thisID ); // theTrack->SetID( thisID ); // theTrack->SetCreator( this ); theTrack->AddCluster( track ); theTrack->AddCluster( partner ); if( theStage == kFine ) flag |= kReassigned; } theTrack->SetD(track->GetX(), track->GetY(), track->GetTheta(), track->GetPhi()); theTrack->SetFlag( flag ); Double_t chi2=0; Int_t nhits=0; track->CalcChisquare(chi2,nhits); partner->CalcChisquare(chi2,nhits); theTrack->SetChi2(chi2,nhits-4); // Nconstraints - Nparameters // calculate the TRANSPORT coordinates CalcFocalPlaneCoords(theTrack, kRotatingTransport); } } #ifdef WITH_DEBUG if( fDebug>1 ) cout << nTracks << " good tracks.\n"; #endif // Delete tracks that were not updated if( tracks && n_exist > n_mod ) { bool modified = false; for( int i = 0; i < tracks->GetLast()+1; i++ ) { THaTrack* theTrack = static_cast<THaTrack*>( tracks->At(i) ); // Track created by this class and not updated? if( (theTrack->GetCreator() == this) && ((theTrack->GetFlag() & kStageMask) != theStage ) ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << i << " deleted.\n"; #endif tracks->RemoveAt(i); modified = true; } } // Get rid of empty slots - they may cause trouble in the Event class and // with global variables. // Note that the PIDinfo and vertices arrays are not reordered. // Therefore, PID and vertex information must always be retrieved from the // track objects, not from the PID and vertex TClonesArrays. // FIXME: Is this really what we want? if( modified ) tracks->Compress(); } return nTracks; }
//_____________________________________________________________________________ Int_t THaVDC::ConstructTracks( TClonesArray* tracks, Int_t mode ) { // Construct tracks from pairs of upper and lower points and add // them to 'tracks' // TODO: // Only make combos whose projections are close // do a real 3D fit, not just compute 3D chi2? #ifdef WITH_DEBUG if( fDebug>1 ) { cout << "-----------------------------------------------\n"; cout << "ConstructTracks: "; if( mode == 0 ) cout << "iterating"; if( mode == 1 ) cout << "coarse tracking"; if( mode == 2 ) cout << "fine tracking"; cout << endl; } #endif UInt_t theStage = ( mode == 1 ) ? kCoarse : kFine; fLUpairs->Clear(); Int_t nUpper = fUpper->GetNPoints(); Int_t nLower = fLower->GetNPoints(); #ifdef WITH_DEBUG if( fDebug>1 ) cout << "nUpper/nLower = " << nUpper << " " << nLower << endl; #endif // One plane has no tracks, the other does // -> maybe recoverable with loss of precision // FIXME: Only do this if missing cluster recovery flag set if( (nUpper == 0) xor (nLower == 0) ) { //FIXME: Put missing cluster recovery code here //For now, do nothing #ifdef WITH_DEBUG if( fDebug>1 ) cout << "missing cluster " << nLower << " " << nUpper << endl; #endif } Int_t nPairs = 0; // Number of point pairs to consider for( int i = 0; i < nLower; i++ ) { THaVDCPoint* lowerPoint = fLower->GetPoint(i); assert(lowerPoint); for( int j = 0; j < nUpper; j++ ) { THaVDCPoint* upperPoint = fUpper->GetPoint(j); assert(upperPoint); // Compute projection error of the selected pair of points // i.e., how well the two points point at each other. // Don't bother with pairs that are obviously mismatched Double_t error = THaVDCPointPair::CalcError( lowerPoint, upperPoint, fSpacing ); if( error >= fErrorCutoff ) continue; // Create new point pair THaVDCPointPair* thePair = new( (*fLUpairs)[nPairs++] ) THaVDCPointPair( lowerPoint, upperPoint, GetSpacing() ); // Explicitly mark these points as unpartnered lowerPoint->SetPartner( 0 ); upperPoint->SetPartner( 0 ); // Further analyze this pair //TODO: Several things come to mind, to be tested: // - calculate global slope // - recompute drift distances using global slope // - refit cluster using new distances // - calculate global chi2 // - sort pairs by this global chi2 later? // - could do all of this before deciding to keep this pair thePair->Analyze(); } } #ifdef WITH_DEBUG if( fDebug>1 ) cout << nPairs << " pairs.\n"; #endif // Initialize counters int n_exist = 0, n_mod = 0; int n_oops = 0; // How many tracks already exist in the global track array? if( tracks ) n_exist = tracks->GetLast()+1; // Sort pairs in order of ascending matching error if( nPairs > 1 ) fLUpairs->Sort(); Int_t nTracks = 0; // Number of reconstructed tracks // Mark pairs as partners, starting with the best matches, // until all tracks are marked. for( int i = 0; i < nPairs; i++ ) { THaVDCPointPair* thePair = static_cast<THaVDCPointPair*>( fLUpairs->At(i) ); assert( thePair ); assert( thePair->GetError() < fErrorCutoff ); #ifdef WITH_DEBUG if( fDebug>1 ) { cout << "Pair " << i << ": "; thePair->Print("NOHEAD"); } #endif // Skip pairs where any of the points already has at least one used cluster if( thePair->HasUsedCluster() ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << " ... skipped.\n"; #endif continue; } #ifdef WITH_DEBUG if( fDebug>1 ) cout << " ... good.\n"; #endif // Get the points of the pair THaVDCPoint* lowerPoint = thePair->GetLower(); THaVDCPoint* upperPoint = thePair->GetUpper(); assert( lowerPoint && upperPoint ); // All partnered pairs must have a used cluster and hence never get here, // else there is a bug in the underlying logic assert( lowerPoint->GetPartner() == 0 && upperPoint->GetPartner() == 0 ); // Use the pair. This partners the points, marks its clusters as used // and calculates global slopes thePair->Use(); nTracks++; #ifdef WITH_DEBUG if( fDebug>2 ) { thePair->Print("TRACKP"); } #endif // If the 'tracks' array was given, add THaTracks to it // (or modify existing ones). if (tracks) { // Decide whether this is a new track or an old track // that is being updated THaVDCTrackID* thisID = new THaVDCTrackID(lowerPoint,upperPoint); THaTrack* theTrack = 0; bool found = false; int t; for( t = 0; t < n_exist; t++ ) { theTrack = static_cast<THaTrack*>( tracks->At(t) ); // This test is true if an existing track has exactly the same clusters // as the current one (defined by lowerPoint/upperPoint) if( theTrack && theTrack->GetCreator() == this && *thisID == *theTrack->GetID() ) { found = true; break; } #ifdef WITH_DEBUG // FIXME: for debugging n_oops++; #endif } UInt_t flag = theStage; if( nPairs > 1 ) flag |= kMultiTrack; if( found ) { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << t << " modified.\n"; #endif delete thisID; ++n_mod; } else { #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << tracks->GetLast()+1 << " added.\n"; #endif theTrack = AddTrack(*tracks, 0.0, 0.0, 0.0, 0.0, thisID ); // theTrack->SetID( thisID ); // theTrack->SetCreator( this ); theTrack->AddCluster( lowerPoint ); theTrack->AddCluster( upperPoint ); assert( tracks->IndexOf(theTrack) >= 0 ); theTrack->SetTrkNum( tracks->IndexOf(theTrack)+1 ); thePair->Associate( theTrack ); if( theStage == kFine ) flag |= kReassigned; } theTrack->SetD(lowerPoint->GetX(), lowerPoint->GetY(), lowerPoint->GetTheta(), lowerPoint->GetPhi()); theTrack->SetFlag( flag ); // Calculate the TRANSPORT coordinates CalcFocalPlaneCoords(theTrack); // Calculate the chi2 of the track from the distances to the wires // in the associated clusters chi2_t chi2 = thePair->CalcChi2(); theTrack->SetChi2( chi2.first, chi2.second - 4 ); } } #ifdef WITH_DEBUG if( fDebug>1 ) cout << nTracks << " good tracks.\n"; #endif // Delete tracks that were not updated if( tracks && n_exist > n_mod ) { // bool modified = false; for( int i = 0; i < tracks->GetLast()+1; i++ ) { THaTrack* theTrack = static_cast<THaTrack*>( tracks->At(i) ); // Track created by this class and not updated? if( (theTrack->GetCreator() == this) && ((theTrack->GetFlag() & kStageMask) != theStage ) ) { // First, release clusters pointing to this track for( int j = 0; j < nPairs; j++ ) { THaVDCPointPair* thePair = static_cast<THaVDCPointPair*>( fLUpairs->At(i) ); assert(thePair); if( thePair->GetTrack() == theTrack ) { thePair->Associate(0); break; } } // Then, remove the track tracks->RemoveAt(i); // modified = true; #ifdef WITH_DEBUG if( fDebug>1 ) cout << "Track " << i << " deleted.\n"; #endif } } // Get rid of empty slots - they may cause trouble in the Event class and // with global variables. // Note that the PIDinfo and vertices arrays are not reordered. // Therefore, PID and vertex information must always be retrieved from the // track objects, not from the PID and vertex TClonesArrays. // FIXME: Is this really what we want? // FIXME: invalidates some or all the track numbers in the clusters // if( modified ) // tracks->Compress(); } // Assign index to each track (0 = first/"best", 1 = second, etc.) for( int i = 0; i < tracks->GetLast()+1; i++ ) { THaTrack* theTrack = static_cast<THaTrack*>( tracks->At(i) ); assert( theTrack ); theTrack->SetIndex(i); } return nTracks; }