Skip to content
Snippets Groups Projects
THcHallCSpectrometer.cxx 21.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • //*-- Author :    Stephen Wood 20-Apr-2012
    
    //////////////////////////////////////////////////////////////////////////
    //
    // THcHallCSpectrometer
    //
    // A standard Hall C spectrometer.
    // Contains no standard detectors,
    //  May add hodoscope
    //
    // The usual name of this object is either "H", "S", or "P"
    // for HMS, SOS, or suPerHMS respectively
    //
    // Defines the functions FindVertices() and TrackCalc(), which are common
    // to both the LeftHRS and the RightHRS.
    //
    // Special configurations of the HRS (e.g. more detectors, different 
    // detectors) can be supported in on e of three ways:
    //
    //   1. Use the AddDetector() method to include a new detector
    //      in this apparatus.  The detector will be decoded properly,
    //      and its variables will be available for cuts and histograms.
    //      Its processing methods will also be called by the generic Reconstruct()
    //      algorithm implemented in THaSpectrometer::Reconstruct() and should
    //      be correctly handled if the detector class follows the standard 
    //      interface design.
    //
    //   2. Write a derived class that creates the detector in the
    //      constructor.  Write a new Reconstruct() method or extend the existing
    //      one if necessary.
    //
    //   3. Write a new class inheriting from THaSpectrometer, using this
    //      class as an example.  This is appropriate if your HRS 
    //      configuration has fewer or different detectors than the 
    //      standard HRS. (It might not be sensible to provide a RemoveDetector() 
    //      method since Reconstruct() relies on the presence of the 
    //      standard detectors to some extent.)
    //
    //  For timing calculations, S1 is treated as the scintillator at the
    //  'reference distance', corresponding to the pathlength correction
    //  matrix.
    //
    
    Zafar's avatar
    Zafar committed
    //
    //  Golden track using scin. Zafar Ahmed. August 19 2014
    //      Goldent track is moved to THcHallCSpectrometer::TrackCalc()
    //      if  fSelUsingScin == 0 then golden track is calculated just 
    //      like podd. i.e. it is the first track with minimum chi2/ndf 
    //      with sorting ON
    //
    //      if fSelUsingScin == 1 then golden track is calculetd just like
    //      engine/HTRACKING/h_select_best_track_using_scin.h. This method 
    //      gives the best track with minimum value of chi2/ndf but with 
    //      additional cuts on the tracks. These cuts are on dedx, beta 
    //      and on energy.
    //
    
    //////////////////////////////////////////////////////////////////////////
    
    #include "THcHallCSpectrometer.h"
    #include "THaTrackingDetector.h"
    
    #include "THcGlobals.h"
    #include "THcParmList.h"
    
    #include "THaTrack.h"
    #include "THaTrackProj.h"
    #include "THaTriggerTime.h"
    #include "TMath.h"
    #include "TList.h"
    
    Zafar's avatar
    Zafar committed
    
    #include "THcRawShowerHit.h"
    #include "THcSignalHit.h"
    
    #include "THcShower.h"
    
    Zafar's avatar
    Zafar committed
    #include "THcHitList.h"
    #include "THcHodoscope.h"
    
    Zafar's avatar
    Zafar committed
    #include <vector>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    
    Zafar's avatar
    Zafar committed
    using std::vector;
    
    using namespace std;
    
    //_____________________________________________________________________________
    THcHallCSpectrometer::THcHallCSpectrometer( const char* name, const char* description ) :
      THaSpectrometer( name, description )
    {
      // Constructor. Defines the standard detectors for the HRS.
      //  AddDetector( new THaTriggerTime("trg","Trigger-based time offset"));
    
      //sc_ref = static_cast<THaScintillator*>(GetDetector("s1"));
    
    
    }
    
    //_____________________________________________________________________________
    THcHallCSpectrometer::~THcHallCSpectrometer()
    {
      // Destructor
    
    Zafar's avatar
    Zafar committed
    
      delete [] fX2D;                 fX2D = NULL;               // Ahmed
      delete [] fY2D;                 fY2D = NULL;               // Ahmed
      
      delete [] f2XHits;              f2XHits = NULL;            // Ahmed  
      delete [] f2YHits;              f2YHits = NULL;            // Ahmed  
    
    
    }
    
    //_____________________________________________________________________________
    Bool_t THcHallCSpectrometer::SetTrSorting( Bool_t set )
    {
      if( set )
        fProperties |= kSortTracks;
      else
        fProperties &= ~kSortTracks;
    
      return set;
    }
    
    //_____________________________________________________________________________
    Bool_t THcHallCSpectrometer::GetTrSorting() const
    {
      return ((fProperties & kSortTracks) != 0);
    }
     
    //_____________________________________________________________________________
    
    void THcHallCSpectrometer::InitializeReconstruction()
    {
      fNReconTerms = 0;
      for(Int_t i=0;i<fNReconTerms;i++) {
        for(Int_t j=0;j<4;j++) {
          fReconCoeff[i][j] = 0.0;
        }
        for(Int_t j=0;j<5;j++) {
          fReconExponents[i][j] = 0;
        }
      }
      fAngSlope_x = 0.0;
      fAngSlope_y = 0.0;
      fAngOffset_x = 0.0;
      fAngOffset_y = 0.0;
      fDetOffset_x = 0.0;
      fDetOffset_y = 0.0;
      fZTrueFocus = 0.0;
    }
    //_____________________________________________________________________________
    Int_t THcHallCSpectrometer::ReadDatabase( const TDatime& date )
    
      static const char* const here = "THcHallCSpectrometer::ReadDatabase";
    
      cout << "In THcHallCSpectrometer::ReadDatabase()" << endl;
    
    Zafar's avatar
    Zafar committed
      MAXHODHITS = 30;
      
      fX2D           = new Double_t [MAXHODHITS];
      fY2D           = new Double_t [MAXHODHITS];
    
      f2XHits        = new Int_t [16];
      f2YHits        = new Int_t [16];
    
      // --------------- To get energy from THcShower ----------------------
    
      const char* detector_name = "hod";  
      //THaApparatus* app = GetDetector();
      THaDetector* det = GetDetector("hod");
      // THaDetector* det = app->GetDetector( shower_detector_name );
      
      if( !dynamic_cast<THcHodoscope*>(det) ) {
        Error("THcHallCSpectrometer", "Cannot find hodoscope detector %s",
        	  detector_name );
         return fStatus = kInitError;
      }
      
      fHodo = static_cast<THcHodoscope*>(det);     // fHodo is a membervariable
      // fShower = static_cast<THcShower*>(det);     // fShower is a membervariable
      
      // --------------- To get energy from THcShower ----------------------
    
    
    
      // Get the matrix element filename from the variable store
      // Read in the matrix
    
      InitializeReconstruction();
    
      char prefix[2];
    
      cout << " GetName() " << GetName() << endl;
    
      prefix[0]=tolower(GetName()[0]);
      prefix[1]='\0';
    
      string reconCoeffFilename;
      DBRequest list[]={
    
    Zafar's avatar
    Zafar committed
        {"_recon_coeff_filename", &reconCoeffFilename,     kString               },
        {"theta_offset",          &fThetaOffset,           kDouble               },
        {"phi_offset",            &fPhiOffset,             kDouble               },
        {"delta_offset",          &fDeltaOffset,           kDouble               },
        {"thetacentral_offset",   &fThetaCentralOffset,    kDouble               },
        {"_oopcentral_offset",    &fOopCentralOffset,      kDouble               },
        {"pcentral_offset",       &fPCentralOffset,        kDouble               },
        {"pcentral",              &fPCentral,              kDouble               },
        {"theta_lab",             &fTheta_lab,             kDouble               },
        {"sel_using_scin",        &fSelUsingScin,          kInt,            0,  1},
        {"sel_ndegreesmin",       &fSelNDegreesMin,        kDouble,         0,  1},
        {"sel_dedx1min",          &fSeldEdX1Min,           kDouble,         0,  1},
        {"sel_dedx1max",          &fSeldEdX1Max,           kDouble,         0,  1},
        {"sel_betamin",           &fSelBetaMin,            kDouble,         0,  1},
        {"sel_betamax",           &fSelBetaMax,            kDouble,         0,  1},
        {"sel_etmin",             &fSelEtMin,              kDouble,         0,  1},
        {"sel_etmax",             &fSelEtMax,              kDouble,         0,  1},
        {"hodo_num_planes",       &fNPlanes,               kInt                  },
        {"scin_2x_zpos",          &fScin2XZpos,            kDouble,         0,  1},
        {"scin_2x_dzpos",         &fScin2XdZpos,           kDouble,         0,  1},
        {"scin_2y_zpos",          &fScin2YZpos,            kDouble,         0,  1},
        {"scin_2y_dzpos",         &fScin2YdZpos,           kDouble,         0,  1},
    
        {0}
      };
      gHcParms->LoadParmValues((DBRequest*)&list,prefix);
    
    Zafar's avatar
    Zafar committed
    
      cout << "\n\n\nhodo planes = " << fNPlanes << endl;
    
      cout << " fPcentral = " <<  fPCentral << " " <<fPCentralOffset << endl; 
      cout << " fThate_lab = " <<  fTheta_lab << " " <<fThetaCentralOffset << endl; 
      fPCentral= fPCentral*(1.+fPCentralOffset/100.);
    
      // Check that these offsets are in radians
      fTheta_lab=fTheta_lab + fThetaCentralOffset*TMath::RadToDeg();
      Double_t ph = 0.0+fPhiOffset*TMath::RadToDeg();
    
      SetCentralAngles(fTheta_lab, ph, false);
      Double_t off_x = 0.0, off_y = 0.0, off_z = 0.0;
      fPointingOffset.SetXYZ( off_x, off_y, off_z );
      
    
      ifstream ifile;
      ifile.open(reconCoeffFilename.c_str());
      if(!ifile.is_open()) {
        Error(here, "error opening reconstruction coefficient file %s",reconCoeffFilename.c_str());
        return kInitError; // Is this the right return code?
      }
      
      string line="!";
      int good=1;
      while(good && line[0]=='!') {
        good = getline(ifile,line).good();
        cout << line << endl;
      }
      // Read in focal plane rotation coefficients
      // Probably not used, so for now, just paste in fortran code as a comment
      while(good && line.compare(0,4," ---")!=0) {
        //  if(line(1:13).eq.'h_ang_slope_x')read(line,1201,err=94)h_ang_slope_x
        //  if(line(1:13).eq.'h_ang_slope_y')read(line,1201,err=94)h_ang_slope_y
        //  if(line(1:14).eq.'h_ang_offset_x')read(line,1201,err=94)h_ang_offset_x
        //  if(line(1:14).eq.'h_ang_offset_y')read(line,1201,err=94)h_ang_offset_y
        //  if(line(1:14).eq.'h_det_offset_x')read(line,1201,err=94)h_det_offset_x
        //  if(line(1:14).eq.'h_det_offset_y')read(line,1201,err=94)h_det_offset_y
        //  if(line(1:14).eq.'h_z_true_focus')read(line,1201,err=94)h_z_true_focus
        good = getline(ifile,line).good();
      }
      // Read in reconstruction coefficients and exponents
      line=" ";
      good = getline(ifile,line).good();
      cout << line << endl;
      fNReconTerms = 0;
      cout << "Reading matrix elements" << endl;
      while(good && line.compare(0,4," ---")!=0) {
        if(fNReconTerms >= fMaxReconElements) {
          Error(here, "too much data in reconstruction coefficient file %s",reconCoeffFilename.c_str());
          return kInitError; // Is this the right return code?
        }
        sscanf(line.c_str()," %le %le %le %le %1d%1d%1d%1d%1d"
    	   ,&fReconCoeff[fNReconTerms][0],&fReconCoeff[fNReconTerms][1]
    	   ,&fReconCoeff[fNReconTerms][2],&fReconCoeff[fNReconTerms][3]
    	   ,&fReconExponents[fNReconTerms][0]
    	   ,&fReconExponents[fNReconTerms][1]
    	   ,&fReconExponents[fNReconTerms][2]
    	   ,&fReconExponents[fNReconTerms][3]
    	   ,&fReconExponents[fNReconTerms][4]);
        // Parse line into fReconCoeff[fNReconTerms][0 - 3] and
        //                 fReconExponents[fNReconTerms][0 - 5]
        fNReconTerms++;
        good = getline(ifile,line).good();    
      }
      if(!good) {
        Error(here, "error processing reconstruction coefficient file %s",reconCoeffFilename.c_str());
        return kInitError; // Is this the right return code?
      }
    
      return kOK;
    }
    
    //_____________________________________________________________________________
    Int_t THcHallCSpectrometer::FindVertices( TClonesArray& tracks )
    {
      // Reconstruct target coordinates for all tracks found in the focal plane.
    
      // In Hall A, this is passed off to the tracking detectors.
      // In Hall C, we do the target traceback here since the traceback should
      // not depend on which tracking detectors are used.
    
    
    Zafar's avatar
    Zafar committed
      fNtracks = tracks.GetLast()+1;
    
    
      for (Int_t it=0;it<tracks.GetLast()+1;it++) {
        THaTrack* track = static_cast<THaTrack*>( tracks[it] );
    
        Double_t hut[5];
        Double_t hut_rot[5];
        
        hut[0] = track->GetX()/100.0 + fZTrueFocus*track->GetTheta() + fDetOffset_x;//m
        hut[1] = track->GetTheta() + fAngOffset_x;//radians
        hut[2] = track->GetY()/100.0 + fZTrueFocus*track->GetPhi() + fDetOffset_y;//m
        hut[3] = track->GetPhi() + fAngOffset_y;//radians
    
        Double_t gbeam_y = 0.0;// This will be the y position from the fast raster
    
        hut[4] = -gbeam_y/100.0;
    
        // Retrieve the focal plane coordnates
        // Do the transpormation
        // Stuff results into track
        hut_rot[0] = hut[0];
        hut_rot[1] = hut[1] + hut[0]*fAngSlope_x;
        hut_rot[2] = hut[2];
        hut_rot[3] = hut[3] + hut[2]*fAngSlope_y;
        hut_rot[4] = hut[4];
    
        // Compute COSY sums
        Double_t sum[4];
        for(Int_t k=0;k<4;k++) {
          sum[k] = 0.0;
        }
        for(Int_t iterm=0;iterm<fNReconTerms;iterm++) {
          Double_t term=1.0;
          for(Int_t j=0;j<5;j++) {
    	if(fReconExponents[iterm][j]!=0) {
    	  term *= pow(hut_rot[j],fReconExponents[iterm][j]);
    	}
          }
          for(Int_t k=0;k<4;k++) {
    	sum[k] += term*fReconCoeff[iterm][k];
          }
        }
        // Transfer results to track
        // No beam raster yet
        //; In transport coordinates phi = hyptar = dy/dz and theta = hxptar = dx/dz 
        //;    but for unknown reasons the yp offset is named  htheta_offset
        //;    and  the xp offset is named  hphi_offset
    
        track->SetTarget(0.0, sum[1]*100.0, sum[0]+fPhiOffset, sum[2]+fThetaOffset);
        track->SetDp(sum[3]*100.0+fDeltaOffset);	// Percent.  (Don't think podd cares if it is % or fraction)
        // There is an hpcentral_offset that needs to be applied somewhere.
        // (happly_offs)
        track->SetMomentum(fPCentral*(1+track->GetDp()/100.0));
    
    Zafar's avatar
    Zafar committed
    
      // ------------------ Moving it to TrackCalc --------------------
    
      /*
    
      // If enabled, sort the tracks by chi2/ndof
      if( GetTrSorting() )
        fTracks->Sort();
      
      // Find the "Golden Track". 
      if( GetNTracks() > 0 ) {
        // Select first track in the array. If there is more than one track
        // and track sorting is enabled, then this is the best fit track
        // (smallest chi2/ndof).  Otherwise, it is the track with the best
        // geometrical match (smallest residuals) between the U/V clusters
        // in the upper and lower VDCs (old behavior).
        // 
        // Chi2/dof is a well-defined quantity, and the track selected in this
        // way is immediately physically meaningful. The geometrical match
        // criterion is mathematically less well defined and not usually used
        // in track reconstruction. Hence, chi2 sortiing is preferable, albeit
        // obviously slower.
    
        fGoldenTrack = static_cast<THaTrack*>( fTracks->At(0) );
        fTrkIfo      = *fGoldenTrack;
        fTrk         = fGoldenTrack;
      } else
        fGoldenTrack = NULL;
    
    
    Zafar's avatar
    Zafar committed
      */
      // ------------------ Moving it to TrackCalc --------------------
    
    
      return 0;
    }
    
    //_____________________________________________________________________________
    Int_t THcHallCSpectrometer::TrackCalc()
    {
    
    Zafar's avatar
    Zafar committed
    
      if ( fSelUsingScin == 0 ) {
        
        if( GetTrSorting() )
          fTracks->Sort();
        
        // Find the "Golden Track". 
        //  if( GetNTracks() > 0 ) {
        if( fNtracks > 0 ) {
          // Select first track in the array. If there is more than one track
          // and track sorting is enabled, then this is the best fit track
          // (smallest chi2/ndof).  Otherwise, it is the track with the best
          // geometrical match (smallest residuals) between the U/V clusters
          // in the upper and lower VDCs (old behavior).
          // 
          // Chi2/dof is a well-defined quantity, and the track selected in this
          // way is immediately physically meaningful. The geometrical match
          // criterion is mathematically less well defined and not usually used
          // in track reconstruction. Hence, chi2 sortiing is preferable, albeit
          // obviously slower.
          
          fGoldenTrack = static_cast<THaTrack*>( fTracks->At(0) );
          fTrkIfo      = *fGoldenTrack;
          fTrk         = fGoldenTrack;
        } else
          fGoldenTrack = NULL;
      }
    
      if ( fSelUsingScin == 1 ){
        if( fNtracks > 0 ) {
          
          Double_t fY2Dmin, fX2Dmin, fZap, ft, fChi2PerDeg; //, fShowerEnergy;
          Double_t fHitPos4, fHitPos3, fHitDist3, fHitDist4; //, fChi2Min;
          Int_t i, j, itrack, ip, ihit; //, fGoodTimeIndex = -1;
          Int_t  fHitCnt4, fHitCnt3, fRawIndex = -1, fGoodRawPad;
          
          fChi2Min = 10000000000.0;   fGoodTrack = -1;   fY2Dmin = 100.;
          fX2Dmin = 100.;             fZap = 0.;
    
          for ( itrack = 0; itrack < fNtracks; itrack++ ){
    	
    	THaTrack* goodTrack = static_cast<THaTrack*>( fTracks->At(itrack) );      
            if (!goodTrack) return -1;
    	
    	if ( goodTrack->GetNDoF() > fSelNDegreesMin ){
    	  fChi2PerDeg =  goodTrack->GetChi2() / goodTrack->GetNDoF();
    	  
    	  if( ( goodTrack->GetDedx()    > fSeldEdX1Min )   && 
    	      ( goodTrack->GetDedx()    < fSeldEdX1Max )   && 
    	      ( goodTrack->GetBeta()    > fSelBetaMin  )   &&
    	      ( goodTrack->GetBeta()    < fSelBetaMax  )   &&
    	      ( goodTrack->GetEnergy()  > fSelEtMin    )   && 
    	      ( goodTrack->GetEnergy()  < fSelEtMax    ) )  	    	    
    	    {
    	      
    	      for ( j = 0; j < 16; j++ ){ f2XHits[j] = 0; }
    	      for ( j = 0; j < 16; j++ ){ f2YHits[j] = 0; }
    	      
    	      for ( ip = 0; ip < fNPlanes; ip++ ){
    		for ( ihit = 0; ihit < fHodo->GetNScinHits(ip); ihit++ ){
    		  fRawIndex ++;		  
    		  fGoodRawPad = fHodo->GetGoodRawPad(fRawIndex)-1;
    
    		  if ( ip == 2 )
    		    f2XHits[fGoodRawPad] = 0;
    		  
    		  if ( ip == 3 )
    		    f2YHits[fGoodRawPad] = 0;
    		  
    		} // loop over hits of a plane
    	      } // loop over planes 
    	      
    	      fHitPos4  = goodTrack->GetY() + goodTrack->GetPhi() * ( fScin2YZpos + 0.5 * fScin2YdZpos );
    	      fHitCnt4  = TMath::Nint( ( fHodo->GetHodoCenter4() - fHitPos4 ) / fHodo->GetScin2YSpacing() ) + 1;
    	      fHitCnt4  = TMath::Max( TMath::Min(fHitCnt4,TMath::Nint(10) ) , 1); // scin_2y_nr = 10
    	      fHitDist4 = fHitPos4 - ( fHodo->GetHodoCenter4() - fHodo->GetScin2YSpacing() * ( fHitCnt4 - 1 ) );
    	      	      
    	      //----------------------------------------------------------------
    
    	      if ( fNtracks > 1 ){     // Plane 4		
    		fZap = 0.;
    		ft = 0;
    		
    		for ( i = 0; i < 10; i++ ){
    		  
    		  if ( f2YHits[fGoodRawPad] == 1 ) {
    		    
    		    fY2D[itrack] = TMath::Abs(fHitCnt4-i-1);
    		    ft ++;
    		    
    		    if   ( ft == 1 )                              fZap = fY2D[itrack];
    		    if ( ( ft == 2 ) && ( fY2D[itrack] < fZap ) ) fZap = fY2D[itrack]; 		    
    		    if ( ( ft == 3 ) && ( fY2D[itrack] < fZap ) ) fZap = fY2D[itrack]; 
    		    if ( ( ft == 4 ) && ( fY2D[itrack] < fZap ) ) fZap = fY2D[itrack]; 
    		    if ( ( ft == 5 ) && ( fY2D[itrack] < fZap ) ) fZap = fY2D[itrack]; 
    		    if ( ( ft == 6 ) && ( fY2D[itrack] < fZap ) ) fZap = fY2D[itrack]; 
    
    		  } // condition for fHodScinHit[4][i]
    		} // loop over 10
    		fY2D[itrack] = fZap; 
    	      } // condition for track. Plane 4
    
    	      if ( fNtracks == 1 ) fY2D[itrack] = 0.;
    
    	      fHitPos3  = goodTrack->GetX() + goodTrack->GetTheta() * ( fScin2XZpos + 0.5 * fScin2XdZpos );
    	      fHitCnt3  = TMath::Nint( ( fHitPos3 - fHodo->GetHodoCenter3() ) / fHodo->GetScin2XSpacing() ) + 1;
    	      fHitCnt3  = TMath::Max( TMath::Min(fHitCnt3,TMath::Nint(16) ) , 1); // scin_2x_nr = 16
    	      fHitDist3 = fHitPos3 - ( fHodo->GetScin2XSpacing() * ( fHitCnt3 - 1 ) + fHodo->GetHodoCenter3() );
    
    	      //----------------------------------------------------------------
    
    	      if ( fNtracks > 1 ){     // Plane 3
    		fZap = 0.;
    		ft = 0;
    
    		for ( i = 0; i < 16; i++ ){
    		  if ( f2XHits[fGoodRawPad] == 1 ) {
    		    fX2D[itrack] = TMath::Abs(fHitCnt3-i-1);
    		    ft ++;
    		    if   ( ft == 1 )                              fZap = fX2D[itrack];
    		    if ( ( ft == 2 ) && ( fX2D[itrack] < fZap ) ) fZap = fX2D[itrack]; 		    
    		    if ( ( ft == 3 ) && ( fX2D[itrack] < fZap ) ) fZap = fX2D[itrack]; 
    		    if ( ( ft == 4 ) && ( fX2D[itrack] < fZap ) ) fZap = fX2D[itrack]; 
    		    if ( ( ft == 5 ) && ( fX2D[itrack] < fZap ) ) fZap = fX2D[itrack]; 
    		    if ( ( ft == 6 ) && ( fX2D[itrack] < fZap ) ) fZap = fX2D[itrack]; 
    		    
    		  } // condition for fHodScinHit[4][i]
    		} // loop over 16
    		fX2D[itrack] = fZap; 
    	      } // condition for track. Plane 3
    
    	      //----------------------------------------------------------------
    
    	      if ( fNtracks == 1 ) 
    		fX2D[itrack] = 0.;
    	      
    	      if ( fY2D[itrack] <= fY2Dmin ) {
    		if ( fY2D[itrack] < fY2Dmin ) {
    		  fX2Dmin = 100.;
    		  fChi2Min = 10000000000.;
    		} // fY2D min
    		
    		if ( fX2D[itrack] <= fX2Dmin ){
    		  if ( fX2D[itrack] < fX2Dmin ){
    		    fChi2Min = 10000000000.0;
    		  } // condition fX2D
    		  if ( fChi2PerDeg < fChi2Min ){
    
    		    fGoodTrack = itrack; // fGoodTrack = itrack
    		    fY2Dmin = fY2D[itrack];
    		    fX2Dmin = fX2D[itrack];
    		    fChi2Min = fChi2PerDeg;
    
    		    fGoldenTrack = static_cast<THaTrack*>( fTracks->At( fGoodTrack ) );
    		    fTrkIfo      = *fGoldenTrack;
    		    fTrk         = fGoldenTrack;
    		  }		  
    		} // condition fX2D
    	      } // condition fY2D
    	    } // conditions for dedx, beta and trac energy	
    	  
    	} // confition for fNFreeFP greater than fSelNDegreesMin
          } // loop over tracks      
    
          if ( fGoodTrack == -1 ){
    	
    	fChi2Min = 10000000000.0;
    	for (Int_t iitrack = 0; iitrack < fNtracks; iitrack++ ){
    	  THaTrack* aTrack = dynamic_cast<THaTrack*>( fTracks->At(iitrack) );
    	  if (!aTrack) return -1;
    	  
    	  if ( aTrack->GetNDoF() > fSelNDegreesMin ){
    	    fChi2PerDeg =  aTrack->GetChi2() / aTrack->GetNDoF();
    	    
    	    if ( fChi2PerDeg < fChi2Min ){
    	      
    	      fGoodTrack = iitrack;
    	      fChi2Min = fChi2PerDeg;
    	      
    	      fGoldenTrack = static_cast<THaTrack*>( fTracks->At(fGoodTrack) );
    	      fTrkIfo      = *fGoldenTrack;
    	      fTrk         = fGoldenTrack;
    
    	    }
    	  }
    	} // loop over trakcs
    	
          } // Condition for fNtrack > 0
    
        } else //  condtion fSelUsingScin == 1
          fGoldenTrack = NULL;
        
      }
    
    
      return TrackTimes( fTracks );
    }
    
    //_____________________________________________________________________________
    Int_t THcHallCSpectrometer::TrackTimes( TClonesArray* Tracks ) {
      // Do the actual track-timing (beta) calculation.
      // Use multiple scintillators to average together and get "best" time at S1.
      //
      // To be useful, a meaningful timing resolution should be assigned
      // to each Scintillator object (part of the database).
    
    Zafar's avatar
    Zafar committed
    
    
    //_____________________________________________________________________________
    Int_t THcHallCSpectrometer::ReadRunDatabase( const TDatime& date )
    {
      // Override THaSpectrometer with nop method.  All needed kinamatics
      // read in ReadDatabase.
      
      return kOK;
    }
    
    
    //_____________________________________________________________________________
    ClassImp(THcHallCSpectrometer)