Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

AlgFitTrackCam.cxx

Go to the documentation of this file.
00001 
00002 // Package: CandFitTrackCam - A Simplified implementation of the Kalman filter
00003 //
00004 // AlgFitTrackCam.cxx
00005 //
00006 // marshall@hep.phy.cam.ac.uk
00008 // 10/19/2006
00009 // Latest version of the code. Includes ND Spectrometer Swim.
00010 //
00011 // Note: Sets all fitted track properties in CandFitTrackHandle,
00012 // CandTrackHandle, CandRecoHandle and CandHandle
00013 //
00014 
00015 #include <cassert>
00016 #include <cmath>
00017 #include <float.h>
00018 
00019 #include <TMath.h>
00020 
00021 #include "MessageService/MsgService.h"
00022 #include "MinosObjectMap/MomNavigator.h"
00023 
00024 #include "Algorithm/AlgConfig.h"
00025 #include "Algorithm/AlgFactory.h"
00026 #include "Algorithm/AlgHandle.h"
00027 
00028 #include "Candidate/CandContext.h"
00029 
00030 #include "CandFitTrackCam/AlgFitTrackCam.h"
00031 #include "CandFitTrackCam/AlgFitTrackCam.h"
00032 #include "CandFitTrackCam/CandFitTrackCamHandle.h"
00033 
00034 #include "Calibrator/Calibrator.h"
00035 
00036 #include "Validity/VldContext.h"
00037 
00038 #include "CandData/CandRecord.h"
00039 #include "CandData/CandHeader.h"
00040 
00041 #include "RecoBase/CandStrip.h"
00042 #include "RecoBase/CandStripHandle.h"
00043 #include "RecoBase/CandTrackHandle.h"
00044 #include "RecoBase/AlgTrack.h"
00045 #include "RecoBase/CandSliceHandle.h"
00046 #include "RecoBase/CandStripListHandle.h"
00047 #include "CandDigit/CandDigitListHandle.h"
00048 
00049 #include "BField/BField.h"
00050 
00051 #include "Swimmer/SwimGeo.h"
00052 #include "Swimmer/SwimSwimmer.h"
00053 #include "Swimmer/SwimStepper.h"
00054 #include "Swimmer/SwimPrintStepAction.h"
00055 #include "Swimmer/SwimParticle.h"
00056 #include "Swimmer/SwimZCondition.h"
00057 #include "Swimmer/SwimPlaneInterface.h"
00058 
00059 #include "GeoSwimmer/GeoSwimmer.h"
00060 #include "GeoSwimmer/GeoSwimParticle.h"
00061 #include "GeoSwimmer/GeoSwimZCondition.h"
00062 
00063 #include "UgliGeometry/UgliGeomHandle.h"
00064 
00065 #include "DataUtil/GetMomFromRange.h"
00066 
00067 #include <sys/time.h>
00068 
00069 ClassImp(AlgFitTrackCam)
00070 
00071 CVSID("$Id: AlgFitTrackCam.cxx,v 1.75 2009/12/28 19:18:05 musser Exp $");
00072 
00074 AlgFitTrackCam::AlgFitTrackCam()
00075 {
00076 }
00078 
00079 
00081 AlgFitTrackCam::~AlgFitTrackCam()
00082 {
00083 }
00085 
00086 
00088 void AlgFitTrackCam::RunAlg(AlgConfig & ac, 
00089                             CandHandle &ch, CandContext &cx)
00090 {
00091 
00092   // cout << "DOGWOOD3  ----------- " << endl;
00093 
00094   // get alg parameters
00095   if(!ac.Get("UseGeoSwimmer",UseGeoSwimmer)) cout << "Couldn't Get UseGeoSwimmer\n";
00096 
00097  // Standard set-up
00098   assert(ch.InheritsFrom("CandFitTrackCamHandle"));
00099   CandFitTrackCamHandle &cth = dynamic_cast<CandFitTrackCamHandle &>(ch);
00100   
00101   nbfield=0;
00102   bave=0;
00103   TIter FitTrackStripItr = cth.GetDaughterIterator();
00104   while(CandStripHandle* FitTrackStrip = dynamic_cast<CandStripHandle*>(FitTrackStripItr())) cth.RemoveDaughter(FitTrackStrip);
00105   
00106   assert(cx.GetDataIn());
00107   
00108   // Get the track from the track finder
00109   assert(cx.GetDataIn()->InheritsFrom("CandTrackHandle"));
00110   track = dynamic_cast<const CandTrackHandle*>(cx.GetDataIn());
00111   if( !track || track->GetNDaughters()<1 )  { return; }
00112   cth.SetFinderTrack((CandTrackHandle*)(track));
00113   
00114   const CandSliceHandle* slice = dynamic_cast<const CandSliceHandle*>(track->GetCandSlice());
00115   assert(slice);
00116   cth.SetCandSlice(slice);
00117   
00118   
00120   // Track fitter //
00122   // Switch for screen output
00123   debug=false;
00124   
00125   // Initialisations
00127   if( track->GetEndZ() > track->GetVtxZ() )  {ZIncreasesWithTime=true;}
00128   else {ZIncreasesWithTime=false;}
00129   
00130   SaveData=false;
00131   SwimThroughShower=false;
00132   PassTrack=true;
00133   
00134   MaxPlane=-20;
00135   MinPlane=500;
00136 
00137   DeltaZ=-99;
00138   DeltaPlane=-99;
00139   ShowerEntryPlane=-99;
00140   
00141   NIter=0; TotalNSwimFail=0; NumFinderStrips=0;
00142   
00143   for (unsigned int i=0; i<5; ++i) {
00144     x_k[i]=0; x_k_minus[i]=0; H_k[i]=0; K_k[i]=0;
00145     VtxCov[i]=-999; EndCov[i]=-999;
00146     for (unsigned int j=0; j<5; ++j) {
00147       C_k[i][j]=0; C_k_minus[i][j]=0; C_k_intermediate[i][j]=0;
00148       F_k[i][j]=0; F_k_minus[i][j]=0;
00149       Q_k[i][j]=0; Q_k_minus[i][j]=0;
00150       Identity[i][j]=0;
00151     }
00152   }
00153   
00154   Identity[0][0]=1; Identity[1][1]=1; Identity[2][2]=1; Identity[3][3]=1; Identity[4][4]=1; 
00156   
00157   
00158   // Set initial parameters
00160   x_k_minus[0]=track->GetVtxU();
00161   x_k_minus[1]=track->GetVtxV();
00162   if(track->GetVtxDirCosZ()!=0.) {
00163     x_k_minus[2]=track->GetVtxDirCosU()/track->GetVtxDirCosZ();
00164     x_k_minus[3]=track->GetVtxDirCosV()/track->GetVtxDirCosZ();
00165   }
00166   x_k_minus[4]=0.;
00167   x_k4_biased=0;
00169   
00170   
00171   // Get header information
00173   CandRecord* candrec = (CandRecord*)(cx.GetCandRecord());
00174   assert(candrec);
00175   
00176   vldc = (VldContext*)(candrec->GetVldContext());
00177   assert(vldc);
00178   
00179   CandHeader* candhead = (CandHeader*)(candrec->GetCandHeader());
00180   assert(candhead);
00181   
00182   MSG("AlgFitTrackCam",Msg::kSynopsis) << "RunAlg, New track, Run: " << candhead->GetRun() 
00183                                     << " Snarl: " << candhead->GetSnarl() << endl;
00185   
00186   
00187   // Run the high level methods
00189   InitialFramework(slice,cx);
00190   GetFitData(MinPlane,MaxPlane);
00191   RunTheFitter(cth);
00193   
00194   
00195   // Clear up
00197   if(vldc->GetDetector()==Detector::kNear) {CleanNDLists(cth,cx);}
00198   
00199   for (unsigned int i=0; i<490; ++i) {
00200     InitTrkStripData[i].clear();
00201     SlcStripData[i].clear();
00202     TrkStripData[i].clear();
00203     FilteredData[i].clear();
00204   }
00206 }
00208 
00209 
00210 
00212 void AlgFitTrackCam::InitialFramework(const CandSliceHandle* slice,CandContext &cx)
00213 {
00214   // Store CandStripHandles and make the strips accessible by plane number
00215   Detector::Detector_t detector = vldc->GetDetector();
00216 
00217   TIter SlcStripItr = slice->GetDaughterIterator();
00218   TIter TrkStripItr = track->GetDaughterIterator();
00219   
00220   // Store all strips in slice
00221   int SlicePlane; 
00222 
00223   while(CandStripHandle* SlcStrip = dynamic_cast<CandStripHandle*>(SlcStripItr()))
00224     {
00225       SlicePlane=SlcStrip->GetPlane();
00226       if(detector==Detector::kNear && SlicePlane>=121) {continue;}
00227 
00228       StripStruct temp;
00229       temp.csh=SlcStrip;
00230      
00231       SlcStripData[SlicePlane].push_back(temp);
00232     }
00233   SlcStripItr.Reset();
00234 
00235 
00236   // Store all track strips found, except those in the Near Spectrometer
00237   int TrackPlane; 
00238   MeanTrackTime=0;
00239 
00240   while(CandStripHandle* TrkStrip = dynamic_cast<CandStripHandle*>(TrkStripItr()))
00241     {    
00242       TrackPlane=TrkStrip->GetPlane();
00243       if(detector==Detector::kNear && TrackPlane>=121) {continue;}
00244 
00245       StripStruct temp;
00246       temp.csh=TrkStrip;
00247 
00248       InitTrkStripData[TrackPlane].push_back(temp);
00249       NumFinderStrips++;
00250       
00251       // Identify ends of initial track
00252       if (TrackPlane>MaxPlane) {MaxPlane=TrackPlane;}
00253       if (TrackPlane<MinPlane) {MinPlane=TrackPlane;}
00254 
00255       if(detector==Detector::kNear) {MeanTrackTime+=NDStripBegTime(TrkStrip);}
00256     }
00257   TrkStripItr.Reset();
00258 
00259   // For DeMuxing ND Spectrometer
00260   if(detector==Detector::kNear) {
00261     if(NumFinderStrips!=0) {MeanTrackTime/=double(NumFinderStrips);}
00262     GenerateNDSpectStrips(slice,cx);
00263   }
00264 
00265 } 
00267 
00268 
00269 
00271 void AlgFitTrackCam::ShowerStrips()
00272 {
00273   MSG("AlgFitTrackCam",Msg::kDebug) << "ShowerStrips, Look for large vertex shower" << endl;
00274      
00275   // Initialisations
00276   int Increment; int NumberOfStrips;
00277   int Plane; int NewPlane;
00278 
00279   int VtxShwWindow=8; 
00280   int StripsForShw=4;
00281   double PEThreshold=2.;
00282 
00283   if(ZIncreasesWithTime==true) {Plane=MinPlane; Increment=1;}
00284   else {Plane=MaxPlane; Increment=-1;}
00285   NewPlane=Plane;
00286 
00287 
00288   // Identify any vertex showers
00290   while(abs(Plane-NewPlane)<=VtxShwWindow && NewPlane>=MinPlane && NewPlane<=MaxPlane) {
00291 
00292     if(SlcStripData[NewPlane].size()>0) {
00293       NumberOfStrips=0;
00294 
00295 
00296       // Set the number of hits on a plane required for the plane to be identified as 'in the 
00297       // shower'. We account for the gradient of the track, with the factor of 0.25 representing
00298       // the approximate ratio of strip thickness to strip width.
00299       if(FilteredData[NewPlane].size()>0) {
00300         if(SlcStripData[NewPlane][0].csh->GetPlaneView()==2) {
00301           StripsForShw=min(7,int( 4+(0.25*fabs(FilteredData[NewPlane][0].x_k2)) ));
00302         }
00303         else {StripsForShw=min(7,int( 4+(0.25*fabs(FilteredData[NewPlane][0].x_k3)) ));}
00304       }
00305       else {StripsForShw=4;}
00306 
00307 
00308       // Count number of strips on plane with greater than 2PEs
00309       for(unsigned int j=0; j<SlcStripData[NewPlane].size(); ++j) {
00310         if(SlcStripData[NewPlane][j].csh->GetCharge()>PEThreshold) {NumberOfStrips++;}
00311       }
00312 
00313 
00314       // If a vertex shower is found, note that we should use the Swimmer
00315       // to find the most likely track strips inside the shower
00316       if(NumberOfStrips>=StripsForShw) {ShowerEntryPlane=NewPlane; SwimThroughShower=true; break;}
00317       
00318       NewPlane+=Increment;
00319     }
00320     else {NewPlane+=Increment;}
00321   }
00323 
00324 
00325  
00326   // Find the plane at which the 'clean' section of track enters the shower
00328   if(SwimThroughShower==true) {
00329     NewPlane=ShowerEntryPlane+Increment;
00330     int PlanesSinceLastHit=0;
00331     int PlaneWindow=4;
00332 
00333     while(PlanesSinceLastHit<PlaneWindow && NewPlane>=MinPlane && NewPlane<=MaxPlane) {
00334       if(SlcStripData[NewPlane].size()>0) {
00335         NumberOfStrips=0;
00336 
00337         // Account for gradient of track, as before
00338         if(FilteredData[NewPlane].size()>0) { 
00339           if(SlcStripData[NewPlane][0].csh->GetPlaneView()==2) {
00340             StripsForShw=min(7,int(4+(0.25*fabs(FilteredData[NewPlane][0].x_k2)) ));
00341           }
00342           else {StripsForShw=min(7,int(4+(0.25*fabs(FilteredData[NewPlane][0].x_k3)) ));}
00343         }
00344         else {StripsForShw=4;}
00345 
00346 
00347         // Count number of strips on plane with greater than 2PEs
00348         for(unsigned int j=0; j<SlcStripData[NewPlane].size(); ++j) {
00349           if(SlcStripData[NewPlane][j].csh->GetCharge()>PEThreshold) {NumberOfStrips++;}
00350         }
00351         if(NumberOfStrips>=StripsForShw) {
00352           ShowerEntryPlane=NewPlane; NewPlane+=Increment; PlanesSinceLastHit=0;
00353         }
00354         else {PlanesSinceLastHit++; NewPlane+=Increment;}
00355         
00356       }
00357       else {PlanesSinceLastHit++; NewPlane+=Increment;}
00358     }
00359   }
00361 }
00363 
00364 
00365 
00367 void AlgFitTrackCam::RunTheFitter(CandFitTrackCamHandle &cth)
00368 {
00369   MSG("AlgFitTrackCam",Msg::kSynopsis) << "RunTheFitter, Call methods in the appropriate order" << endl;
00370   GetInitialCovarianceMatrix(true);
00371   
00372   // Control the iterations backwards and forwards
00374   Detector::Detector_t detector = vldc->GetDetector();
00375 
00376   // Control iterations over a track for which ZIncreasesWithTime
00377   if(ZIncreasesWithTime==true)
00378     {
00379       // First iteration
00380       NIter++;
00381       LastIteration=false;
00382 
00383       // Vtx to End
00384       StoreFilteredData(MinPlane);   
00385       SaveData=true; GoForwards(); 
00386       ResetCovarianceMatrix();
00387       
00388       // End back to vtx, swimming through any large vtx shower
00389       ShowerStrips();  // Try to identify vtx showers, now we have an idea of gradient
00390       if(SwimThroughShower==true) {RemoveTrkHitsInShw();}
00391       
00392       for (unsigned int i=0; i<490; ++i) {FilteredData[i].clear();}
00393       StoreFilteredData(MaxPlane); GoBackwards();
00394       
00395       if(SwimThroughShower==true) {ShowerSwim();}
00396       ResetCovarianceMatrix();
00397 
00398       bool StripsFound = FindTheStrips(cth,false);
00399       EndofRangePlane=MaxPlane;
00400       // Second iteration
00401       if(StripsFound==true) { // Guard against finding no strips
00402         for(int nint=0;nint<2;nint++){  
00403           if(nint==0) MSG("AlgFitTrackCam",Msg::kSynopsis) << "Bias Fit" << endl;
00404           if(nint==1) MSG("AlgFitTrackCam",Msg::kSynopsis) << "Un-Biased Fit" << endl;
00405           NIter++;
00406           if(nint==1)LastIteration = true;
00407           
00408           // Vtx to End again, identifying any strips in ND spectrometer
00409           for (unsigned int i=0; i<490; ++i) {TrkStripData[i].clear();} 
00410           GetFitData(MinPlane,MaxPlane);
00411 
00412           // for (unsigned int i=0; i<490; ++i) { FilteredData[i].clear(); }
00413           StoreFilteredData(MinPlane);          
00414           SaveData=true; GoForwards();
00415           
00416           if(detector==Detector::kNear && nint==0) {SpectrometerSwim(cth);}
00417           ResetCovarianceMatrix();
00418           
00419           // End back to vtx again
00420           //for (unsigned int i=0; i<490; ++i) { FilteredData[i].clear(); }
00421           StoreFilteredData(EndofRangePlane);    
00422           SaveData=true; GoBackwards();
00423           
00424           if(nint==0) {
00425             x_k4_biased= x_k[4];
00426             eqp_biased = pow(VtxCov[4],0.5);
00427           }
00428           ResetCovarianceMatrix();
00429         }
00430       }
00431       else {PassTrack=false;}
00432     }
00433   
00434   
00435   // Control iterations over a track for which ZDecreasesWithTime
00436   else
00437     {
00438       // First iteration
00439       NIter++;
00440       LastIteration=false;
00441 
00442       // Vtx to End
00443       StoreFilteredData(MaxPlane); 
00444       SaveData=true; GoBackwards(); 
00445       ResetCovarianceMatrix();
00446  
00447       // End back to vtx, swimming through any large vtx shower and
00448       // identifying any strips in ND spectrometer
00449       ShowerStrips();  // Try to identify vtx showers, now we have an idea of gradient
00450       if(SwimThroughShower==true) {RemoveTrkHitsInShw();}
00451 
00452       for (unsigned int i=0; i<490; ++i) {FilteredData[i].clear();}
00453       StoreFilteredData(MinPlane); GoForwards();
00454 
00455       if(SwimThroughShower==true) {ShowerSwim();}
00456 
00457       if(detector==Detector::kNear) {SpectrometerSwim(cth);}
00458       ResetCovarianceMatrix();
00459 
00460       bool StripsFound = FindTheStrips(cth,false);
00461       EndofRangePlane=MinPlane;
00462       // Second iteration
00463       if(StripsFound==true) { // Guard against finding no strips
00464         for(int nint=0;nint<2;nint++){  
00465           if(nint==1)LastIteration = true;                
00466           NIter++;
00467 
00468           // Vtx to End again
00469           for (unsigned int i=0; i<490; ++i) {TrkStripData[i].clear();} 
00470           GetFitData(MinPlane,MaxPlane);
00471 
00472           //for (unsigned int i=0; i<490; ++i) {FilteredData[i].clear();}
00473           StoreFilteredData(MaxPlane);    
00474           SaveData=true; GoBackwards(); 
00475           ResetCovarianceMatrix();
00476           
00477           // End to Vtx again
00478           //for (unsigned int i=0; i<490; ++i) {FilteredData[i].clear();}
00479           StoreFilteredData(EndofRangePlane);
00480           SaveData=true; GoForwards(); 
00481 
00482           ResetCovarianceMatrix();
00483           if(nint==0) {
00484             x_k4_biased= x_k[4];
00485             eqp_biased = pow(VtxCov[4],0.5);
00486           }
00487         }
00488       }
00489       else {PassTrack=false;}
00490 
00491     }
00493   
00494   
00495 
00496   // Organise the output
00498 
00499   // If the fit was successful
00500   if(x_k[4]!=0. && PassTrack==true) {
00501         
00502     //JAM modify tweak following range bias removal
00503     // Tweak q/p to remove offset
00504     //    x_k[4]*=1.01+(0.1*fabs(x_k[4]));
00505 
00506     x_k4_biased *=1.01+(0.1*fabs(x_k[4]));
00507     // x_k[4] *=1.013; // (moved to SetTrackProperties)
00508 
00509     // Find final strips and add them to the fitted track
00510     FillGapsInTrack();
00511     bool FinalStripsFound = FindTheStrips(cth,true);
00512     
00513     // If final strips found, set the fitted track properties
00514     if(FinalStripsFound==true) {
00515 
00516       // Check there is >1 strip in each view. If not, then fail track.
00517       int NumInUView=0; int NumInVView=0;
00518       
00519       TIter FitTrackStripItr = cth.GetDaughterIterator();
00520       while(CandStripHandle* FitTrackStrip = dynamic_cast<CandStripHandle*>(FitTrackStripItr())){
00521         if(FitTrackStrip->GetPlaneView()==2) {NumInUView++;}
00522         else if(FitTrackStrip->GetPlaneView()==3) {NumInVView++;}
00523         
00524         if(NumInUView>1 && NumInVView>1) {break;}
00525       }
00526       
00527       if(NumInUView>1 && NumInVView>1) {
00528         cth.SetPass(1);
00529         SetTrackProperties(cth);
00530       }
00531       else {
00532         PassTrack=false;
00533       }
00534       
00535     }
00536     // Otherwise fail the track at this final stage
00537     else {
00538       PassTrack=false;
00539     }
00540   }
00541   
00542   
00543   // If the fit has failed (e.g. q/p is zero and/or u, v are nonsense)
00544   if(x_k[4]==0. || PassTrack==false) {
00545  
00546     // Remove any existing strips in the failed fitted track
00547     vector<CandStripHandle*> Daughters;
00548 
00549     TIter FitTrackStripItr = cth.GetDaughterIterator();
00550     while(CandStripHandle* FitTrackStrip = dynamic_cast<CandStripHandle*>(FitTrackStripItr()))
00551       {Daughters.push_back(FitTrackStrip);}
00552 
00553     for(unsigned int i=0; i<Daughters.size(); ++i) {cth.RemoveDaughter(Daughters[i]);}
00554     Daughters.clear();
00555 
00556 
00557     // Put strips from track finder in failed fitted track
00558     TIter TrkStripItr = track->GetDaughterIterator();
00559     while(CandStripHandle* TrkStrip = dynamic_cast<CandStripHandle*>(TrkStripItr()))
00560       {cth.AddDaughterLink(*TrkStrip);}
00561     
00562     // Set position/direction properties using the finder track
00563     cth.SetPass(0); 
00564     cth.SetMomentumCurve(0.); cth.SetEMCharge(0); cth.SetVtxQPError(-999.);
00565     SetPropertiesFromFinderTrack(cth);
00566   }
00568 }  
00570 
00572 void AlgFitTrackCam::RemoveTrkHitsInShw()
00573 {
00574   // If the 'clean' section of track is large enough, remove the track finding
00575   // data for planes before the ShowerEntryPlane
00576   MSG("AlgFitTrackCam",Msg::kDebug) << "RemoveTrkHitsInShw, Discard track finding data in shower" << endl;
00577 
00578   int NumTrackStripsLeft=0;
00579   
00580   if(ZIncreasesWithTime==true) {
00581     for(int i=ShowerEntryPlane; i<=MaxPlane; ++i) {
00582       if(TrkStripData[i].size()>0) {NumTrackStripsLeft++;}
00583     }
00584   }
00585   else if(ZIncreasesWithTime==false) {
00586     for(int i=MinPlane; i<=ShowerEntryPlane; ++i) {
00587       if(TrkStripData[i].size()>0) {NumTrackStripsLeft++;}
00588     }
00589   }
00590   
00591   // Carry out removal if there will be 6 or more strips left afterwards
00592   if(NumTrackStripsLeft>5) { 
00593     if(ZIncreasesWithTime==true) {
00594       for(int i=MinPlane; i<=ShowerEntryPlane; ++i) {TrkStripData[i].clear();}
00595     }   
00596     else if(ZIncreasesWithTime==false) {
00597       for(int i=ShowerEntryPlane; i<=MaxPlane; ++i) {TrkStripData[i].clear();    }
00598     }
00599   } 
00600   // Otherwise note that we should not run the ShowerSwim method
00601   else {
00602     MSG("AlgFitTrackCam",Msg::kDebug) << "RemoveTrkHitsInShw, not enough hits after removal. Must use all finder data." << endl;
00603     SwimThroughShower=false;
00604   }
00605   
00606   
00607   // Find the new max and min planes
00608   MaxPlane=-20; MinPlane=500;
00609   for (int i=0; i<490; ++i) {   
00610     if(TrkStripData[i].size()>0) {
00611       if(i>MaxPlane) {MaxPlane=i;}
00612       if(i<MinPlane) {MinPlane=i;}
00613     }
00614   }
00615 
00616 }
00618 
00619 
00621 void AlgFitTrackCam::ShowerSwim()
00622 {
00623   // Method is called if we have a large shower near the track vertex
00624   //
00625   // The Swimmer is used to find the most likely track strip in the shower
00626   // and this strip is added to the fit
00627   MSG("AlgFitTrackCam",Msg::kDebug) << "ShowerSwim, improved track finding in shower" << endl;
00628 
00629   // Initialisations
00630   int Plane; int NewPlane;
00631   double StateVector[5]; double NState[5];
00632   bool GoForward; bool SwimBack;
00633   int PlanesSinceLastHit=0;
00634   int PlaneView;
00635   int Increment;
00636   
00637   double StripDistance; double MinDistanceToStrip;
00638   double StripWidth=4.108e-2;
00639 
00640 
00641   if(ZIncreasesWithTime==true) {GoForward=false; Plane=MinPlane; Increment=-1;}
00642   else {GoForward=true; Plane=MaxPlane; Increment=1;}
00643 
00644   NewPlane=Plane+Increment;
00645 
00646 
00647   // Continue until we reach a 4 plane window with no likely hit or we reach 
00648   // the end of the detector
00649   while(PlanesSinceLastHit<4 && NewPlane>0 && NewPlane<=485) {
00650     if(SlcStripData[NewPlane].size()>0) {
00651 
00652       if(SlcStripData[NewPlane][0].csh->GetPlaneView()==2) {PlaneView=0;}
00653       else {PlaneView=1;}
00654       
00655       for(int i=0; i<5; ++i) {StateVector[i]=x_k_minus[i];}
00656       SwimBack=Swim(StateVector, NState, Plane, NewPlane, GoForward);
00657       if(!SwimBack){break;}
00658       for(int i=0; i<5; ++i) {x_k[i]=NState[i];}
00659  
00660  
00661       // Find the closest strip (within a distance 'MinDistanceToStrip') and
00662       // temporarily store CandStripHandle
00663       // Results are very sensitive to value of MinDistanceToStrip
00664       CandStripHandle* CurrentStrip=0;
00665       MinDistanceToStrip=(1.5*StripWidth)+ fabs(0.0055*x_k[PlaneView+2]);
00666       
00667       for(unsigned int j=0; j<SlcStripData[NewPlane].size(); ++j) {
00668         StripDistance=fabs(SlcStripData[NewPlane][j].csh->GetTPos()-x_k[PlaneView]);
00669         
00670         if(StripDistance<MinDistanceToStrip) {
00671           MinDistanceToStrip=StripDistance;
00672           CurrentStrip=SlcStripData[NewPlane][j].csh;
00673         }
00674       }            
00675       
00676       // If we find a likely track strip, add it to the fit data and call the Kalman
00677       // update equations before repeating process to find next track strips in the shower
00678       if(CurrentStrip) {
00679         StripStruct temp;
00680         temp.csh = CurrentStrip;
00681         InitTrkStripData[NewPlane].push_back(temp);
00682         
00683         // Convert the strip to data required for Kalman fit
00684         GetFitData(NewPlane,NewPlane);
00685 
00686         // Carry out the Kalman fit
00687         if (PlaneView==1) {H_k[0]=0; H_k[1]=1; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
00688         else {H_k[0]=1; H_k[1]=0; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
00689         
00690         bool CombiPropagatorOk=GetCombiPropagator(Plane,NewPlane,GoForward);
00691         
00692         if(CombiPropagatorOk ) {
00693           GetNoiseMatrix(Plane,NewPlane);
00694           ExtrapCovMatrix();
00695           CalcKalmanGain(NewPlane);
00696           UpdateStateVector(Plane,NewPlane,GoForward);
00697           UpdateCovMatrix();
00698           MoveArrays();
00699           StoreFilteredData(NewPlane);
00700           
00701           if(ZIncreasesWithTime) {MinPlane=NewPlane; Plane=MinPlane;}
00702           else {MaxPlane=NewPlane; Plane=MaxPlane;}
00703           NewPlane=Plane+Increment;
00704           
00705           PlanesSinceLastHit=0;
00706         }
00707       }
00708       else {NewPlane+=Increment; PlanesSinceLastHit++;}
00709       
00710     }
00711     else {NewPlane+=Increment; PlanesSinceLastHit++;}
00712   }
00713   
00714   // Note that shower swim is complete
00715   SwimThroughShower=false;
00716 
00717 }
00719 
00720 
00721 
00723 void AlgFitTrackCam::GetFitData(int Plane1, int Plane2)
00724 {
00725   // Loop over the initial track strip data and create the final data for fitting
00726   //  MSG("AlgFitTrackCam",Msg::kDebug) << "GetFitData" << endl;
00727 
00728   // Initialisations
00729   double MisalignmentError=4e-6;  // Squared error for misalignment of strips
00730   double SumChargeTPos=0; double SumCharge=0; int MaxStrip=-20; int MinStrip=200;
00731   bool NewStripFound=true;
00732 
00733   int ThisStrip;
00734 
00735   // Get the data for region between the planes specified
00736   for(int i=Plane1; i<=Plane2; ++i) {
00737     if(InitTrkStripData[i].size()>0) {     
00738       
00739       // Find max and min strip numbers for strips in plane
00740       for(unsigned int j=0; j<InitTrkStripData[i].size(); ++j) {
00741         if(InitTrkStripData[i][j].csh->GetStrip()<MinStrip) {MinStrip=InitTrkStripData[i][j].csh->GetStrip();}
00742         if(InitTrkStripData[i][j].csh->GetStrip()>MaxStrip) {MaxStrip=InitTrkStripData[i][j].csh->GetStrip();}  
00743       }
00744 
00745 
00746       // Find continuous groups of strips
00748       NewStripFound=true;
00749       
00750       while(NewStripFound==true) {
00751         
00752         NewStripFound=false;
00753         
00754         for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
00755 
00756           ThisStrip=SlcStripData[i][j].csh->GetStrip();
00757 
00758           if( ThisStrip==(MaxStrip+1) ) {
00759             MaxStrip+=1;
00760             NewStripFound=true;
00761             
00762             InitTrkStripData[i].push_back(SlcStripData[i][j]);
00763           }
00764           
00765           if( ThisStrip==(MinStrip-1) ) {
00766             MinStrip-=1;
00767             NewStripFound=true;
00768             
00769             InitTrkStripData[i].push_back(SlcStripData[i][j]);
00770           }
00771         }
00772       }
00774 
00775 
00776 
00777       // Get the data for fitting
00779       for(unsigned int j=0; j<InitTrkStripData[i].size(); ++j) {
00780         SumCharge+=InitTrkStripData[i][j].csh->GetCharge();
00781 
00782         // JAM 11/08:  Change to support strip rotations
00783         PlaneView::PlaneView_t plnvw =InitTrkStripData[i][j].csh->GetPlaneView();
00784         Double_t orthopos = track->GetV(InitTrkStripData[i][j].csh->GetPlane());
00785         if(plnvw == PlaneView::kV){
00786           orthopos = track->GetU(InitTrkStripData[i][j].csh->GetPlane());
00787         }
00788         // JAM 11/08:  to activate strip rotation support add orthopos as argument to GetTPos()
00789         SumChargeTPos+=InitTrkStripData[i][j].csh->GetCharge()*InitTrkStripData[i][j].csh->GetTPos();
00790       }
00791 
00792       // Charge weighted TPos and Flat distribution error
00793       if(SumCharge!=0.) {
00794         TrkDataStruct temp;
00795         
00796         temp.ZPos=InitTrkStripData[i][0].csh->GetZPos();
00797         temp.PlaneView=InitTrkStripData[i][0].csh->GetPlaneView();
00798 
00799         temp.TPos=SumChargeTPos/SumCharge;
00800         temp.TPosError=( (1.406305333e-4 * (1 + MaxStrip-MinStrip) )+ MisalignmentError);
00801         
00802         TrkStripData[i].push_back(temp);
00803       }
00805 
00806 
00807       // Reset      
00808       SumChargeTPos=0; SumCharge=0; MaxStrip=-20; MinStrip=200;
00809     }
00810   }
00811   
00812 }
00814 
00815 
00816 
00818 void AlgFitTrackCam::FillGapsInTrack()
00819 {
00820   // If there is no filtered data for a plane (between MinPlane and MaxPlane),
00821   // but this plane has hits in the slice, we interpolate from the nearest 
00822   // state vectors
00823   //
00824   // As with all filtered data, the interpolated data will be compared to
00825   // strip positions in the FindTheStrips method
00826   //  MSG("AlgFitTrackCam",Msg::kDebug) << "FillGapsInTrack" << endl;
00827 
00828 
00829   int CurrentPlane; int ForwardsPlane; int BackwardsPlane;
00830   int Plane; int NewPlane;  bool GoForward;
00831   double StateVector[5]; double Prediction[5]; bool GetPrediction;
00832   for(int i=0; i<5; i++) { Prediction[i]=0.; }
00833 
00834 
00835   for (int i=MinPlane; i<=MaxPlane; ++i) {   
00836     if(SlcStripData[i].size()>0) {
00837  
00838       if(FilteredData[i].size()==0) {
00839 
00840 
00841         // Find nearest filtered state vectors (within two planes) and ZPos differences
00843         // Forwards
00844         CurrentPlane=i+1; ForwardsPlane=-99;
00845 
00846         while(CurrentPlane<=MaxPlane && CurrentPlane<=(i+2)) {
00847           if(FilteredData[CurrentPlane].size()>0) {ForwardsPlane=CurrentPlane; break;}
00848           else {CurrentPlane++;}
00849         }
00850 
00851         // Backwards
00852         CurrentPlane=i-1; BackwardsPlane=-99;
00853 
00854         while(CurrentPlane>=MinPlane && CurrentPlane>=(i-2) ) {
00855           if(FilteredData[CurrentPlane].size()>0) {BackwardsPlane=CurrentPlane; break;}
00856           else {CurrentPlane--;}
00857         }
00859 
00860 
00861         // Find and store possible new filtered data, range and dS
00863         if(ForwardsPlane!=-99 && BackwardsPlane!=-99) {
00864 
00865           // Swimmer method
00866           GetPrediction=false;
00867           NewPlane=i;
00868           if(ZIncreasesWithTime==true) {Plane=ForwardsPlane; GoForward=false;}
00869           else{Plane=BackwardsPlane; GoForward=true;}
00870           if(FilteredData[Plane].size()>0) {
00871             StateVector[0] = FilteredData[Plane][0].x_k0;
00872             StateVector[1] = FilteredData[Plane][0].x_k1;
00873             StateVector[2] = FilteredData[Plane][0].x_k2;
00874             StateVector[3] = FilteredData[Plane][0].x_k3;
00875             StateVector[4] = FilteredData[Plane][0].x_k4;           
00876             GetPrediction=Swim(StateVector, Prediction, Plane, NewPlane, GoForward);
00877             
00878             if(GetPrediction==true) {
00879               // Store possible new state vector
00880               FiltDataStruct temp;
00881               temp.x_k0 = Prediction[0];
00882               temp.x_k1 = Prediction[1];
00883               temp.x_k2 = Prediction[2]; 
00884               temp.x_k3 = Prediction[3];
00885               temp.x_k4 = Prediction[4];              
00886               FilteredData[i].push_back(temp);
00887             }
00888           }
00889 
00890         }
00892       }
00893     }
00894   }
00895 
00896 }
00898 
00899 
00900 
00902 bool AlgFitTrackCam::FindTheStrips(CandFitTrackCamHandle &cth, bool MakeTheTrack)
00903 { 
00904   // Given output data from Kalman filter, we find the strips that match most closely
00905   // and store the CandStripHandles in plane order in InitTrkStripData
00906   //
00907   // At end of track fitting, method is called with MakeTheTrack==true, so fit track
00908   // strips are finalised
00909 
00910   // JM ADDED 6/07:  Add pulse height requirement for first 3 hits at track vertex, and 
00911   //                 remove isolated single hit at vertex. This reduces tendency to add 
00912   //                 extra hits upstream of vertex.
00913   
00914   // Initialisations
00916   for (unsigned int i=0; i<490; ++i) {InitTrkStripData[i].clear();}
00917 
00918   double Extrem1=0; double Extrem2=0;
00919   double StripCentre=0;
00920   double StripWidth=4.108e-2;
00921   double HalfStripWidth=0.5*StripWidth;
00922   double TwoStripWidth=2.*StripWidth;  
00923   double PEthresh = 3.0;
00924   double MinDistanceToStrip;
00926   
00927   int NoOfHitPlanes=0; int Counter=0; int PlanesAdded=0;
00928   Bool_t foundMIP=false; 
00929   Bool_t RemovedHit=false;
00930   //  int InitMaxPlane = MaxPlane;
00931   float minDist;
00932   for (int i=MinPlane; i<=MaxPlane; ++i) {if(FilteredData[i].size()>0) {NoOfHitPlanes++;} }
00933 
00934   // Loop over the entire output from Kalman filter
00936   
00937   if(ZIncreasesWithTime==true){
00938     for (int i=MinPlane; i<=MaxPlane; ++i) {
00939       if(FilteredData[i].size()>0) {
00940         Counter++;
00941         int numStrips = 0;
00942         minDist=1e6;
00943         // Mark the possible extremities in transverse position within scintillator
00944         // by multiplying gradient by half scintillator thickness and adding or subtracting
00945         if(SlcStripData[i][0].csh->GetPlaneView()==2) {
00946           Extrem1=FilteredData[i][0].x_k0 + (0.0055*FilteredData[i][0].x_k2);
00947           Extrem2=FilteredData[i][0].x_k0 - (0.0055*FilteredData[i][0].x_k2);
00948         }
00949         else {
00950           Extrem1=FilteredData[i][0].x_k1 + (0.0055*FilteredData[i][0].x_k3);
00951           Extrem2=FilteredData[i][0].x_k1 - (0.0055*FilteredData[i][0].x_k3);
00952         }
00953         
00954         // Add strips in the case that only one strip can have its centre within 
00955         // half a strip width of an extremal position...
00957         bool PlaneAdded=false;
00958         if(fabs(Extrem1-Extrem2)<StripWidth) {
00959           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
00960             StripCentre=SlcStripData[i][j].csh->GetTPos();
00961             MinDistanceToStrip=HalfStripWidth;
00962             if(fabs(StripCentre-Extrem1)<minDist)minDist =fabs(StripCentre-Extrem1);
00963             if(fabs(StripCentre-Extrem2)<minDist)minDist =fabs(StripCentre-Extrem2);
00964             if(fabs(StripCentre-Extrem1)<HalfStripWidth || fabs(StripCentre-Extrem2)<HalfStripWidth) {
00965               if(Counter>1 || SlcStripData[i][j].csh->GetCharge()>PEthresh || foundMIP==true || SlcStripData[i].size()==1){
00966                 foundMIP=true;
00967                 if(MakeTheTrack==true) {cth.AddDaughterLink(*SlcStripData[i][j].csh);}        
00968                 InitTrkStripData[i].push_back(SlcStripData[i][j]);
00969         
00970                 if(!PlaneAdded)PlanesAdded++;
00971                 PlaneAdded=true;
00972               } 
00973               
00974               numStrips++;
00975             }
00976           }
00977         }
00979         
00980         
00981         // ...Otherwise, cover the cases where multiple strips can have their centre
00982         // within half a strip width of an extremal position
00984         else {
00985           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
00986             StripCentre=SlcStripData[i][j].csh->GetTPos();          
00987             MinDistanceToStrip=HalfStripWidth;      
00988             if(fabs(StripCentre-Extrem1)<minDist)minDist =fabs(StripCentre-Extrem1);
00989             if(fabs(StripCentre-Extrem2)<minDist)minDist =fabs(StripCentre-Extrem2);
00990 
00991             if( fabs(StripCentre-Extrem1)<HalfStripWidth || fabs(StripCentre-Extrem2)<HalfStripWidth
00992                 || (Extrem1>StripCentre && Extrem2<StripCentre) 
00993                 || (Extrem1<StripCentre && Extrem2>StripCentre) ) {
00994               if(Counter>1 || SlcStripData[i][j].csh->GetCharge()>PEthresh || foundMIP==true){
00995                 foundMIP=true;
00996                 if(MakeTheTrack==true) {cth.AddDaughterLink(*SlcStripData[i][j].csh);}
00997                 InitTrkStripData[i].push_back(SlcStripData[i][j]);
00998                 if(!PlaneAdded)PlanesAdded++;
00999                 PlaneAdded=true;
01000               }
01001               numStrips++;            
01002             }
01003           }
01004         }
01006         // If we have found no strips, we consider looking further, finding the closest  
01007         // strip within a distance 'MinDistanceToStrip' of an extremal position
01009         if(numStrips==0) {
01010           CandStripHandle* CurrentStrip=0;
01011           
01012           // Be more demanding near track vertex
01013           if(Counter>2) {
01014             MinDistanceToStrip = TwoStripWidth;
01015             if(MakeTheTrack==true) MinDistanceToStrip = 2*TwoStripWidth;
01016           }
01017           else {MinDistanceToStrip=StripWidth;}
01018           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
01019             StripCentre=SlcStripData[i][j].csh->GetTPos();
01020             
01021             // Find the closest strip and temporarily store its CandStripHandle
01022             if(fabs(StripCentre-Extrem1)<minDist)minDist =fabs(StripCentre-Extrem1);
01023             if(fabs(StripCentre-Extrem2)<minDist)minDist =fabs(StripCentre-Extrem2);
01024             if(fabs(StripCentre-Extrem1)<MinDistanceToStrip) {
01025               MinDistanceToStrip=StripCentre-Extrem1;
01026               CurrentStrip=SlcStripData[i][j].csh;
01027             }
01028             if(fabs(StripCentre-Extrem2)<MinDistanceToStrip) {
01029               MinDistanceToStrip=StripCentre-Extrem2;
01030               CurrentStrip=SlcStripData[i][j].csh;
01031             }
01032           }
01033           
01034           // If we have found a strip then we add it
01035           if(CurrentStrip) {
01036             if(Counter>1 || CurrentStrip->GetCharge()>PEthresh || foundMIP==true){
01037               foundMIP=true;
01038               if(MakeTheTrack==true) {cth.AddDaughterLink(*CurrentStrip);}          
01039               StripStruct temp;
01040               temp.csh = CurrentStrip;
01041               InitTrkStripData[i].push_back(temp);
01042               PlanesAdded++;
01043               PlaneAdded=true;
01044             }
01045           }
01046         }
01047       }
01048       if(PlanesAdded==3 && !RemovedHit ){  // remove first hit if it is separated by >1 plane from second
01049         Int_t np = 0;
01050         Int_t planebuf[3];
01051         Int_t pln = MinPlane;
01052         while(np<3 && pln<490){
01053           if(InitTrkStripData[pln].size()>0){
01054             planebuf[np] = InitTrkStripData[pln][0].csh->GetPlane();
01055             np++;
01056           }
01057           pln++;
01058         }
01059         if(np==3 && SlcStripData[planebuf[0]].size()>1){
01060           if(abs(planebuf[1]-planebuf[0])/abs(planebuf[2]-planebuf[1])>1.5){
01061             for(unsigned int j=0; j<InitTrkStripData[planebuf[0]].size(); ++j) {
01062               CandStripHandle* Strip = InitTrkStripData[planebuf[0]][j].csh;     
01063               cth.RemoveDaughter(Strip);
01064               RemovedHit=true;
01065             }
01066             InitTrkStripData[planebuf[0]].clear();
01067           }
01068         }
01069       }
01070     }
01071   }
01072   else{
01073     for (int i=MaxPlane; i>=MinPlane; --i) {   
01074       if(FilteredData[i].size()>0) {
01075         Counter++;
01076         int numStrips=0;
01077         
01078         
01079         // Mark the possible extremities in transverse position within scintillator
01080         // by multiplying gradient by half scintillator thickness and adding or subtracting
01081         if(SlcStripData[i][0].csh->GetPlaneView()==2) {
01082           Extrem1=FilteredData[i][0].x_k0 + (0.0055*FilteredData[i][0].x_k2);
01083           Extrem2=FilteredData[i][0].x_k0 - (0.0055*FilteredData[i][0].x_k2);
01084         }
01085         else {
01086           Extrem1=FilteredData[i][0].x_k1 + (0.0055*FilteredData[i][0].x_k3);
01087           Extrem2=FilteredData[i][0].x_k1 - (0.0055*FilteredData[i][0].x_k3);
01088         }
01089         
01090         
01091         // Add strips in the case that only one strip can have its centre within 
01092         // half a strip width of an extremal position...
01094         bool PlaneAdded=false;
01095         if(fabs(Extrem1-Extrem2)<StripWidth) {
01096           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
01097             StripCentre=SlcStripData[i][j].csh->GetTPos();
01098             
01099             if(fabs(StripCentre-Extrem1)<HalfStripWidth || fabs(StripCentre-Extrem2)<HalfStripWidth) {
01100               if(Counter>1 || SlcStripData[i][j].csh->GetCharge()>PEthresh || foundMIP|| SlcStripData[i].size()==1){
01101                 foundMIP=true;
01102                 if(MakeTheTrack==true) {cth.AddDaughterLink(*SlcStripData[i][j].csh);}
01103                 InitTrkStripData[i].push_back(SlcStripData[i][j]);
01104                 numStrips++;
01105                 if(!PlaneAdded)PlanesAdded++;
01106                 PlaneAdded=true;
01107               }      
01108             }
01109           }
01110         }
01112         
01113         
01114         // ...Otherwise, cover the cases where multiple strips can have their centre
01115         // within half a strip width of an extremal position
01117         else {
01118           bool PlaneAdded=false;
01119           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
01120             StripCentre=SlcStripData[i][j].csh->GetTPos();
01121             
01122             if( fabs(StripCentre-Extrem1)<HalfStripWidth || fabs(StripCentre-Extrem2)<HalfStripWidth
01123                 || (Extrem1>StripCentre && Extrem2<StripCentre) 
01124                 || (Extrem1<StripCentre && Extrem2>StripCentre) ) {
01125               if(Counter>1 || SlcStripData[i][j].csh->GetCharge()>PEthresh || foundMIP){
01126                 foundMIP=true;
01127                 if(MakeTheTrack==true) {cth.AddDaughterLink(*SlcStripData[i][j].csh);}          
01128                 InitTrkStripData[i].push_back(SlcStripData[i][j]);
01129                 numStrips++;
01130                 if(!PlaneAdded)PlanesAdded++;
01131                 PlaneAdded=true;
01132               }
01133             }
01134           }
01135         }
01137         
01138         // If we have found no strips, we consider looking further, finding the closest  
01139         // strip within a distance 'MinDistanceToStrip' of an extremal position
01141         if(numStrips==0) {
01142           CandStripHandle* CurrentStrip=0;
01143           
01144           // Be more demanding near track vertex
01145           if(Counter>2) {
01146             MinDistanceToStrip = TwoStripWidth;
01147             if(MakeTheTrack==true) MinDistanceToStrip = 2*TwoStripWidth;
01148           }
01149           else {MinDistanceToStrip=StripWidth;}
01150           
01151           for(unsigned int j=0; j<SlcStripData[i].size(); ++j) {
01152             StripCentre=SlcStripData[i][j].csh->GetTPos();
01153             
01154             // Find the closest strip and temporarily store its CandStripHandle
01155             if(fabs(StripCentre-Extrem1)<MinDistanceToStrip) {
01156               MinDistanceToStrip=StripCentre-Extrem1;
01157               CurrentStrip=SlcStripData[i][j].csh;
01158             }
01159             if(fabs(StripCentre-Extrem2)<MinDistanceToStrip) {
01160               MinDistanceToStrip=StripCentre-Extrem2;
01161               CurrentStrip=SlcStripData[i][j].csh;
01162             }
01163           }
01164           
01165           // If we have found a strip then we add it
01166           if(CurrentStrip) {
01167             if(Counter>1 || CurrentStrip->GetCharge()>PEthresh || foundMIP){
01168               foundMIP=true;    
01169               if(MakeTheTrack==true) {cth.AddDaughterLink(*CurrentStrip);}
01170               StripStruct temp;
01171               temp.csh = CurrentStrip;
01172               InitTrkStripData[i].push_back(temp);
01173               PlanesAdded++;
01174               PlaneAdded=true;
01175             }
01176           }
01177         }
01179       }
01180      if(PlanesAdded==3 && !RemovedHit){  // remove first hit if it is separated by >1 plane from second
01181         Int_t np = 0;
01182         Int_t planebuf[3];
01183         Int_t pln = MaxPlane;
01184         while(np<3 && pln>=0){
01185           if(InitTrkStripData[pln].size()>0){
01186             planebuf[np]= InitTrkStripData[pln][0].csh->GetPlane();
01187             np++;
01188           }
01189           pln--;
01190         }
01191         if(np==3 && SlcStripData[planebuf[0]].size()>1){
01192           if(abs(planebuf[1]-planebuf[0])/abs(planebuf[2]-planebuf[1])>1.5){
01193           for(unsigned int j=0; j<InitTrkStripData[planebuf[0]].size(); ++j) {
01194             CandStripHandle* Strip = InitTrkStripData[planebuf[0]][j].csh;       
01195             cth.RemoveDaughter(Strip);
01196             RemovedHit=true;
01197           }
01198           InitTrkStripData[planebuf[0]].clear();
01199           }
01200         }
01201       }
01202     }  
01203   }
01205   
01206 
01207   // Find new max and min planes
01208   MaxPlane=-20; MinPlane=500;
01209   for (int i=0; i<490; ++i) {   
01210     if(InitTrkStripData[i].size()>0) {
01211       if(i>MaxPlane) {MaxPlane=i;}
01212       if(i<MinPlane) {MinPlane=i;}
01213     }
01214   }
01215 
01216   if(MaxPlane==-20 || MinPlane==500) {return false;}
01217   else {return true;}
01218 
01219 }
01221 
01222 
01223 
01225 void AlgFitTrackCam::GoForwards()
01226 { 
01227   // Carry out the Kalman fit along the track in the direction of increasing z
01228   MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoForwards, carry out fit in positive z direction" << endl; 
01229   MSG("AlgFitTrackCam",Msg::kSynopsis) << "Fitting from StartPlane=" << MinPlane << " to EndPlane=" << MaxPlane << endl;
01230 
01231   // JAM in 2nd iteration, stop when end of range is reached.
01232  
01233   Int_t StartPlane = MinPlane; Int_t EndPlane=MaxPlane;
01234   if(!ZIncreasesWithTime){
01235     StartPlane = EndofRangePlane;
01236   }
01237   else EndofRangePlane = MaxPlane;
01238 
01239   for (int i=StartPlane; i<=EndPlane; ++i) {
01240     EndofRange = false;
01241     if (TrkStripData[i].size()>0) {
01242       if (PassTrack) {
01243         // Find Next Plane
01244         int NewPlane=-99;
01245         int k=(i+1);
01246         while (k<=MaxPlane) {
01247           if (TrkStripData[k].size()>0) {NewPlane=k; break;}
01248           ++k;
01249         }
01250         if (NewPlane!=-99) {
01251           // Define measurement function
01252           if (TrkStripData[NewPlane][0].PlaneView==3) {H_k[0]=0; H_k[1]=1; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
01253           else if (TrkStripData[NewPlane][0].PlaneView==2)  {H_k[0]=1; H_k[1]=0; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
01254           
01255           MSG("AlgFitTrackCam",Msg::kVerbose) << "GoForwards, Plane " << i << " ZPos " << TrkStripData[i][0].ZPos 
01256                                               << " PlaneView " << TrkStripData[i][0].PlaneView << endl;
01257           MSG("AlgFitTrackCam",Msg::kVerbose) << " NewPlane " << NewPlane << " NewZPos " << TrkStripData[NewPlane][0].ZPos 
01258                                               << " NewPlaneView " << TrkStripData[NewPlane][0].PlaneView << endl;
01259           
01260           bool CombiPropagatorOk=GetCombiPropagator(i,NewPlane,true);
01261           
01262           if(CombiPropagatorOk ) {
01263             GetNoiseMatrix(i,NewPlane);
01264             ExtrapCovMatrix();
01265             CalcKalmanGain(NewPlane);
01266             UpdateStateVector(i,NewPlane,true);
01267             UpdateCovMatrix();
01268             MoveArrays();
01269             if(SaveData) {StoreFilteredData(NewPlane);}
01270             MSG("AlgFitTrackCam",Msg::kVerbose) << "GoForwards, Filtered q/p " << x_k[4] << endl;
01271           }
01272           else 
01273             {
01274               PassTrack=false; 
01275             }
01276         }
01277         
01278       }
01279       else {MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoForwards, Outside of detector - track failed" << endl;}
01280     }
01281     //JAM end of range found
01282     if(EndofRange && LastIteration && ZIncreasesWithTime){
01283       EndofRangePlane=i;
01284       MSG("AlgFitTrackCam",Msg::kSynopsis) << "End of range on plane " << EndofRangePlane << endl;
01285       break;
01286     }
01287   }
01288 
01289 
01290   // Store entries from covariance matrix for use in setting track properties
01291   if(NIter>1) {
01292     if(ZIncreasesWithTime==true) {
01293       EndCov[0]=C_k[0][0]; EndCov[1]=C_k[1][1];
01294       EndCov[2]=C_k[2][2]; EndCov[3]=C_k[3][3];
01295       EndCov[4]=C_k[4][4];
01296     }
01297     else {
01298       VtxCov[0]=C_k[0][0]; VtxCov[1]=C_k[1][1];
01299       VtxCov[2]=C_k[2][2]; VtxCov[3]=C_k[3][3];
01300       VtxCov[4]=C_k[4][4];
01301     }
01302   }
01303 
01304   MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoForwards, Finished" << endl;
01305 }
01307 
01308 
01309 
01311 void AlgFitTrackCam::GoBackwards()
01312 { 
01313   // Carry out the Kalman fit along the track in the direction of decreasing z
01314   MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoBackwards, carry out fit in negative z direction" << endl;
01315   MSG("AlgFitTrackCam",Msg::kSynopsis) << "Fitting from StartPlane=" << MaxPlane << " to EndPlane=" << MinPlane << " end of range plane = " << EndofRangePlane << endl;
01316 
01317   Int_t StartPlane = MaxPlane; Int_t EndPlane=MinPlane;
01318   if(ZIncreasesWithTime){
01319     StartPlane = EndofRangePlane;
01320   }
01321   else EndofRangePlane = MinPlane;
01322  
01323   for (int i=StartPlane; i>=EndPlane; --i) {  
01324     if (TrkStripData[i].size()>0) {
01325       if (PassTrack) {
01326 
01327         //Find Prev Plane
01328         int NewPlane=-99;
01329         int k=(i-1);
01330         while (k>=MinPlane) {
01331           if (TrkStripData[k].size()>0) {NewPlane=k; break;}
01332           --k;
01333         }
01334         
01335         
01336         if (NewPlane!=-99) {
01337           // Define measurement function
01338           if (TrkStripData[NewPlane][0].PlaneView==3) {H_k[0]=0; H_k[1]=1; H_k[2]=0; H_k[3]=0; H_k[4]=0;}         else if (TrkStripData[NewPlane][0].PlaneView==2)  {H_k[0]=1; H_k[1]=0; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
01339           
01340           MSG("AlgFitTrackCam",Msg::kVerbose) << "GoBackwards, Plane " << i << " ZPos " << TrkStripData[i][0].ZPos 
01341                                               << " PlaneView " << TrkStripData[i][0].PlaneView << endl;
01342           MSG("AlgFitTrackCam",Msg::kVerbose) << " NewPlane " << NewPlane << " NewZPos " << TrkStripData[NewPlane][0].ZPos 
01343                                               << " NewPlaneView " << TrkStripData[NewPlane][0].PlaneView << endl;
01344           
01345           bool CombiPropagatorOk=GetCombiPropagator(i,NewPlane,false);
01346           
01347           if(CombiPropagatorOk ) {
01348             GetNoiseMatrix(i,NewPlane);
01349             ExtrapCovMatrix();
01350             CalcKalmanGain(NewPlane);
01351             UpdateStateVector(i,NewPlane,false);
01352             UpdateCovMatrix();
01353             MoveArrays();
01354             if(SaveData) {StoreFilteredData(NewPlane);}
01355             MSG("AlgFitTrackCam",Msg::kVerbose) << "GoBackwards, Filtered q/p " << x_k[4] << endl;
01356           }
01357           else {
01358             PassTrack=false;
01359           }
01360         }
01361         
01362       }
01363       else {MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoBackwards, Outside detector - track failed" << endl;}
01364     }
01365     //JAM end of range found
01366     if(EndofRange && LastIteration && !ZIncreasesWithTime){
01367       EndofRangePlane = i;
01368       break;
01369     }
01370 
01371   }
01372 
01373 
01374   // Store entries from covariance matrix for use in setting track properties
01375   if(NIter>1) {
01376     if(ZIncreasesWithTime==true) {
01377       VtxCov[0]=C_k[0][0]; VtxCov[1]=C_k[1][1];
01378       VtxCov[2]=C_k[2][2]; VtxCov[3]=C_k[3][3];
01379       VtxCov[4]=C_k[4][4];
01380     }
01381     else {
01382       EndCov[0]=C_k[0][0]; EndCov[1]=C_k[1][1];
01383       EndCov[2]=C_k[2][2]; EndCov[3]=C_k[3][3];
01384       EndCov[4]=C_k[4][4];
01385     }
01386   }
01387 
01388   MSG("AlgFitTrackCam",Msg::kSynopsis) << "GoBackwards, Finished" << endl;
01389 }
01391 
01392 
01393 
01395 bool AlgFitTrackCam::GetCombiPropagator(const int Plane, const int NewPlane, const bool GoForward)
01396 {
01397   // Combination propagator, essentially same as SR propagator, but
01398   // generation of matrix reduces calls to swimmer by 80%
01399   //  MSG("AlgFitTrackCam",Msg::kDebug) << "GetCombiPropagator" << endl;
01400 
01401   for (int i=0; i<5; ++i) {
01402     for (int j=0; j<5; ++j) {
01403       F_k_minus[i][j]=0;  
01404     }
01405   }
01406 
01407   F_k_minus[0][0]=1; F_k_minus[1][1]=1; 
01408   F_k_minus[2][2]=1; F_k_minus[3][3]=1;
01409   
01410   DeltaZ=fabs(TrkStripData[NewPlane][0].ZPos-TrkStripData[Plane][0].ZPos);
01411   DeltaPlane=abs(NewPlane-Plane);
01412 
01413   // Swimmer section for last column
01414   double PState[5];  double NState[5];  double StateVector[5];
01415   double Increment=0.01;
01416   bool SwimInc=false; bool SwimDec=false;
01417   int nswimfail=0;
01418   
01419   if(GoForward==true) {F_k_minus[0][2]=DeltaZ; F_k_minus[1][3]=DeltaZ;}
01420   else if(GoForward==false) {F_k_minus[0][2]=-DeltaZ; F_k_minus[1][3]=-DeltaZ;}
01421   
01422   
01423   // Give swimmer fixed number of opportunities for successful swim
01424   while((SwimInc==false || SwimDec==false) && nswimfail<=10) {
01425     
01426     Increment=0.05*fabs(x_k_minus[4]); 
01427     if(Increment<.01) {Increment=.01;}
01428        
01429     for(int j=0; j<5; ++j) {StateVector[j]=x_k_minus[j];}  
01430     
01431     // Increment then swim
01432     StateVector[4]+=Increment;
01433     SwimInc=Swim(StateVector, NState, Plane, NewPlane, GoForward);
01434     
01435     StateVector[4]=x_k_minus[4];
01436     
01437     // Decrement then swim
01438     StateVector[4]-=Increment;
01439     SwimDec=Swim(StateVector, PState, Plane, NewPlane, GoForward);
01440     
01441     // If swim failed, double momentum and swim again
01442     if(SwimInc==false || SwimDec==false) {
01443       MSG("AlgFitTrackCam",Msg::kVerbose) << "GetCombiPropagator, Swim failed - Double momentum and swim again" << endl;
01444       x_k_minus[4]*=0.5;
01445       nswimfail++; TotalNSwimFail++;
01446       break;
01447     }
01448     
01449     // Form last row of propagator matrix.  Need to transpose to get proper Kalman F_k_minus
01450     else {
01451       if(Increment!=0.) {
01452         for(int j=0; j<5; ++j) {
01453           F_k_minus[j][4] = (NState[j]-PState[j]) / (2*Increment);
01454         }
01455       }
01456       else {F_k_minus[4][4]=1;}
01457     }
01458     
01459   } // End while statement
01460   
01461   if(nswimfail>10) {MSG("AlgFitTrackCam",Msg::kDebug) << "GetCombiPropagator, nswimfail>10, fail track" << endl; return false;}
01462 
01463 
01464   // Display
01465   if(debug) {
01466     cout << "Combi F_k_minus" << endl;
01467     for(int i=0; i<5; ++i) {  
01468       for(int j=0; j<5; ++j) {
01469         cout << F_k_minus[i][j] << " ";
01470       }
01471       cout << endl;
01472     }
01473   }
01474   
01475   return true;
01476 }
01478 
01479 
01480 
01482 bool AlgFitTrackCam::Swim(double* StateVector, double* Output, const int Plane, 
01483                           const int NewPlane,const bool GoForward, double* dS, double* Range, double* dE)
01484 {
01485   //  MSG("AlgFitTrackCam",Msg::kDebug) << "Swim" << endl;
01486 
01487   // Initialisations
01488   // customize for bfield scaling.
01489   BField * bf = new BField(*vldc,-1,0);
01490   SwimSwimmer* myswimmer = new SwimSwimmer(*vldc,bf);
01491   
01492   if(UseGeoSwimmer) GeoSwimmer::Instance()->Initialize(*vldc);
01493  
01494   double invSqrt2 = pow(1./2.,0.5);
01495   double charge = 0.;
01496   bool done = false;
01497     
01498   if(fabs(StateVector[4])>1.e-10) {
01499     double modp = fabs(1./StateVector[4]);
01500     
01501     // Fix, to account for fact the cosmic muons could move in direction of negative z
01502     if(ZIncreasesWithTime==false) {modp=-modp;}
01503     
01504     double dsdz = pow((1.+pow(StateVector[2],2)+pow(StateVector[3],2)),0.5);
01505     double dxdz = invSqrt2*(StateVector[2]-StateVector[3]);
01506     double dydz = invSqrt2*(StateVector[2]+StateVector[3]);
01507     
01508     // Set up current muon details
01509     if(StateVector[4]>0.) charge = 1.;
01510     else if(StateVector[4]<0.) charge = -1.;
01511     
01512     TVector3 position(invSqrt2*(StateVector[0]-StateVector[1]),
01513                       invSqrt2*(StateVector[0]+StateVector[1]),
01514                       SlcStripData[Plane][0].csh->GetZPos());
01515 
01516     TVector3 momentum(modp*(dxdz/dsdz),
01517                       modp*(dydz/dsdz),
01518                       modp/dsdz);
01519 
01520     TVector3 bfield = bf->GetBField(position);
01521     bave += TMath::Sqrt(bfield[0]*bfield[0]+bfield[1]*bfield[1]+bfield[2]*bfield[2]);
01522     nbfield++;
01523 
01524     SwimParticle muon(position,momentum);
01525     muon.SetCharge(charge);
01526     SwimZCondition zc(SlcStripData[NewPlane][0].csh->GetZPos());
01527     // Do the swim, accounting for direction of motion w.r.t time too
01528     if( (GoForward==true && ZIncreasesWithTime==true)  || (GoForward==false && ZIncreasesWithTime==false) ) {
01529       if(UseGeoSwimmer) {
01530         done = GeoSwimmer::Instance()->SwimForward(muon,SlcStripData[NewPlane][0].csh->GetZPos());
01531       } else {
01532         done = myswimmer->SwimForward(muon,zc);
01533       }
01534     }
01535     else if( (GoForward==true && ZIncreasesWithTime==false)  || (GoForward==false && ZIncreasesWithTime==true) ) {
01536       if(UseGeoSwimmer) {
01537         done = GeoSwimmer::Instance()->SwimBackward(muon,SlcStripData[NewPlane][0].csh->GetZPos());
01538       } else {
01539         done = myswimmer->SwimBackward(muon,zc);
01540       }
01541     }
01542     if(done==true) {
01543       if(muon.GetDirection().Z()!=0. && muon.GetMomentumModulus()!=0.) {
01544         Output[0]=invSqrt2*(muon.GetPosition().Y()+muon.GetPosition().X());
01545         Output[1]=invSqrt2*(muon.GetPosition().Y()-muon.GetPosition().X());
01546         Output[2]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())+(muon.GetDirection().X()/muon.GetDirection().Z()));
01547         Output[3]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())-(muon.GetDirection().X()/muon.GetDirection().Z()));
01548         Output[4]=muon.GetCharge()/muon.GetMomentumModulus();
01549         // Get range and dS from the Swimmer
01550         if(dS) {*dS=muon.GetS();} if(Range) {*Range=muon.GetRange();} if(dE){*dE=muon.GetMomentumModulus()-momentum.Mag();} 
01551       }
01552       else {done=false;}
01553     }
01554     
01555   }
01556 
01557   else{
01558     // If infinite momentum, use straight line extrapolation
01559     double delz = (SlcStripData[NewPlane][0].csh->GetZPos()-SlcStripData[Plane][0].csh->GetZPos());
01560     Output[0]=StateVector[0] + StateVector[2]*delz;
01561     Output[1]=StateVector[1] + StateVector[3]*delz;
01562     Output[2]=StateVector[2];
01563     Output[3]=StateVector[3];
01564     Output[4]=StateVector[4];
01565 
01566     done=true;
01567   }    
01568   
01569   delete myswimmer;
01570   delete bf;
01571   return done;
01572 }
01574 
01575 
01576 
01578 bool AlgFitTrackCam::Swim(double* StateVector, double* Output, const double z, 
01579                           const int NewPlane,const bool GoForward, double* dS, double* Range, double* dE)
01580 {
01581   //  MSG("AlgFitTrackCam",Msg::kDebug) << "Swim, specified starting Z" << endl;
01582 
01583   // Initialisations
01584   // customize for bfield scaling.
01585   BField * bf = new BField(*vldc,-1,0);
01586   SwimSwimmer* myswimmer = new SwimSwimmer(*vldc,bf);
01587   
01588   if(UseGeoSwimmer) GeoSwimmer::Instance()->Initialize(*vldc);
01589 
01590   double invSqrt2 = pow(1./2.,0.5);
01591   double charge = 0.;
01592   bool done = false;
01593     
01594   if(fabs(StateVector[4])>1.e-10) {
01595     double modp = fabs(1./StateVector[4]);
01596     
01597     // Fix, to account for fact the cosmic muons could move in direction of negative z
01598     if(ZIncreasesWithTime==false) {modp=-modp;}
01599     
01600     double dsdz = pow((1.+pow(StateVector[2],2)+pow(StateVector[3],2)),0.5);
01601     double dxdz = invSqrt2*(StateVector[2]-StateVector[3]);
01602     double dydz = invSqrt2*(StateVector[2]+StateVector[3]);
01603     
01604     // Set up current muon details
01605     if(StateVector[4]>0.) charge = 1.;
01606     else if(StateVector[4]<0.) charge = -1.;
01607     
01608     TVector3 position(invSqrt2*(StateVector[0]-StateVector[1]),
01609                       invSqrt2*(StateVector[0]+StateVector[1]),
01610                       z);
01611 
01612     TVector3 momentum(modp*(dxdz/dsdz),
01613                       modp*(dydz/dsdz),
01614                       modp/dsdz);
01615     SwimParticle muon(position,momentum);
01616     muon.SetCharge(charge);
01617     SwimZCondition zc(SlcStripData[NewPlane][0].csh->GetZPos());
01618 
01619    
01620     // Do the swim, accounting for direction of motion w.r.t time too
01621     if( (GoForward==true && ZIncreasesWithTime==true)  || (GoForward==false && ZIncreasesWithTime==false) ) {
01622       if(UseGeoSwimmer) {
01623         done = GeoSwimmer::Instance()->SwimForward(muon,SlcStripData[NewPlane][0].csh->GetZPos());
01624       } else {
01625         done = myswimmer->SwimForward(muon,zc);
01626       } 
01627     }
01628     else if( (GoForward==true && ZIncreasesWithTime==false)  || (GoForward==false && ZIncreasesWithTime==true) ) {
01629       if(UseGeoSwimmer) {
01630         done = GeoSwimmer::Instance()->SwimBackward(muon,SlcStripData[NewPlane][0].csh->GetZPos());
01631 
01632       } else {
01633         done = myswimmer->SwimBackward(muon,zc);
01634       }     
01635     }
01636     if(done==true) {
01637       if(muon.GetDirection().Z()!=0. && muon.GetMomentumModulus()!=0.) {
01638         Output[0]=invSqrt2*(muon.GetPosition().Y()+muon.GetPosition().X());
01639         Output[1]=invSqrt2*(muon.GetPosition().Y()-muon.GetPosition().X());
01640         Output[2]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())+(muon.GetDirection().X()/muon.GetDirection().Z()));
01641         Output[3]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())-(muon.GetDirection().X()/muon.GetDirection().Z()));
01642         Output[4]=muon.GetCharge()/muon.GetMomentumModulus();
01643         // Get range and dS from the Swimmer
01644         if(dS) {*dS=muon.GetS();} if(Range) {*Range=muon.GetRange();} if(dE){*dE=muon.GetMomentumModulus()-momentum.Mag();} 
01645       }
01646       else {done=false;}
01647     }
01648     
01649   }
01650 
01651   else{
01652     // If infinite momentum, use straight line extrapolation
01653     double delz = (SlcStripData[NewPlane][0].csh->GetZPos()-z);
01654     Output[0]=StateVector[0] + StateVector[2]*delz;
01655     Output[1]=StateVector[1] + StateVector[3]*delz;
01656     Output[2]=StateVector[2];
01657     Output[3]=StateVector[3];
01658     Output[4]=StateVector[4];
01659 
01660     done=true;
01661   }    
01662   
01663   delete myswimmer;
01664   delete bf;
01665 
01666   return done;
01667 }
01669 
01670 
01671 
01673 bool AlgFitTrackCam::Swim(double* StateVector, double* Output, const int Plane, 
01674                           const double Zend,const bool GoForward, double* dS, double* Range, double* dE)
01675 {
01676   //  MSG("AlgFitTrackCam",Msg::kDebug) << "Swim, specified end Z" << endl;
01677 
01678   // Initialisations
01679   // customize for bfield scaling.
01680 
01681   BField * bf = new BField(*vldc,-1,0);
01682   SwimSwimmer* myswimmer = new SwimSwimmer(*vldc,bf);
01683 
01684   if(UseGeoSwimmer) GeoSwimmer::Instance()->Initialize(*vldc);
01685 
01686   double invSqrt2 = pow(1./2.,0.5);
01687   double charge = 0.;
01688   bool done = false;
01689     
01690   if(fabs(StateVector[4])>1.e-10) {
01691     double modp = fabs(1./StateVector[4]);
01692     
01693     // Fix, to account for fact the cosmic muons could move in direction of negative z
01694     if(ZIncreasesWithTime==false) {modp=-modp;}
01695     
01696     double dsdz = pow((1.+pow(StateVector[2],2)+pow(StateVector[3],2)),0.5);
01697     double dxdz = invSqrt2*(StateVector[2]-StateVector[3]);
01698     double dydz = invSqrt2*(StateVector[2]+StateVector[3]);
01699   
01700     // Set up current muon details
01701     if(StateVector[4]>0.) charge = 1.;
01702     else if(StateVector[4]<0.) charge = -1.;
01703     
01704     TVector3 position(invSqrt2*(StateVector[0]-StateVector[1]),
01705                       invSqrt2*(StateVector[0]+StateVector[1]),
01706                       SlcStripData[Plane][0].csh->GetZPos());
01707 
01708 
01709     TVector3 momentum(modp*(dxdz/dsdz),
01710                       modp*(dydz/dsdz),
01711                       modp/dsdz);
01712     SwimParticle muon(position,momentum);
01713     muon.SetCharge(charge);
01714     SwimZCondition zc(Zend);
01715  
01716     // Do the swim, accounting for direction of motion w.r.t time too
01717     if( (GoForward==true && ZIncreasesWithTime==true)  || (GoForward==false && ZIncreasesWithTime==false) ) {
01718       if(UseGeoSwimmer){
01719         done = GeoSwimmer::Instance()->SwimForward(muon,Zend);
01720       } else {
01721         done = myswimmer->SwimForward(muon,zc);
01722       }   
01723     }
01724     else if( (GoForward==true && ZIncreasesWithTime==false)  || (GoForward==false && ZIncreasesWithTime==true) ) {
01725       if(UseGeoSwimmer){
01726         done = GeoSwimmer::Instance()->SwimBackward(muon,Zend);
01727       } else {
01728         done = myswimmer->SwimBackward(muon,zc);
01729       }    
01730     }
01731     if(done==true) {
01732       if(muon.GetDirection().Z()!=0. && muon.GetMomentumModulus()!=0.) {
01733         Output[0]=invSqrt2*(muon.GetPosition().Y()+muon.GetPosition().X());
01734         Output[1]=invSqrt2*(muon.GetPosition().Y()-muon.GetPosition().X());
01735         Output[2]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())+(muon.GetDirection().X()/muon.GetDirection().Z()));
01736         Output[3]=invSqrt2*((muon.GetDirection().Y()/muon.GetDirection().Z())-(muon.GetDirection().X()/muon.GetDirection().Z()));
01737         Output[4]=muon.GetCharge()/muon.GetMomentumModulus();
01738         // Get range and dS from the Swimmer
01739         if(dS) {*dS=muon.GetS();} if(Range) {*Range=muon.GetRange();} if(dE){*dE=muon.GetMomentumModulus()-momentum.Mag();}
01740       }
01741       else {done=false;}
01742     }
01743     
01744   }
01745 
01746   else{
01747     // If infinite momentum, use straight line extrapolation
01748     double delz = (Zend-SlcStripData[Plane][0].csh->GetZPos());
01749     Output[0]=StateVector[0] + StateVector[2]*delz;
01750     Output[1]=StateVector[1] + StateVector[3]*delz;
01751     Output[2]=StateVector[2];
01752     Output[3]=StateVector[3];
01753     Output[4]=StateVector[4];
01754 
01755     done=true;
01756   }    
01757   
01758   delete myswimmer;
01759   delete bf;
01760   return done;
01761 }
01763 
01764 
01765 
01767 void AlgFitTrackCam::ResetCovarianceMatrix()
01768 {
01769   // Simple method reset variables/arrays to allow propagation again
01770 
01771   DeltaPlane=0; DeltaZ=0; 
01772   GetInitialCovarianceMatrix(false);
01773 }
01775 
01776 
01777 
01779 void AlgFitTrackCam::GetInitialCovarianceMatrix(const bool FirstIteration)
01780 {
01781   //  MSG("AlgFitTrackCam",Msg::kDebug) << "GetInitialCovarianceMatrix" << endl;
01782 
01783   if(FirstIteration==true) {
01784     
01785     for(int i=0; i<5; ++i) {
01786       for(int j=0; j<5; ++j) {
01787         C_k_minus[i][j]=0.;
01788       }
01789     }
01790     
01791     // Diagonal terms
01792     C_k_minus[0][0]=0.25; C_k_minus[1][1]=0.25; 
01793     C_k_minus[2][2]=100.; C_k_minus[3][3]=100.; 
01794     C_k_minus[4][4]=1.;
01795     
01796     // Off diagonal terms. Taken from SR - Origin of this?
01797     if(ZIncreasesWithTime==true) {
01798       C_k_minus[0][4]=7.5e-5;  C_k_minus[1][4]=7.5e-5;
01799       C_k_minus[4][0]=7.5e-5;  C_k_minus[4][1]=7.5e-5;
01800     }
01801     else if(ZIncreasesWithTime==false) {
01802       C_k_minus[0][4]=-7.5e-5;  C_k_minus[1][4]=-7.5e-5;
01803       C_k_minus[4][0]=-7.5e-5;  C_k_minus[4][1]=-7.5e-5;
01804     }
01805     
01806     
01807   }
01808 
01809   else if(FirstIteration==false) {
01810     // Results are very sensitive to this multiplication. A large number means
01811     // that further iterations start with the same uncertainties as the first,
01812     // albeit with improved "track finder" strips
01813     for(int i=0; i<5; ++i) {C_k_minus[i][i]*=100;}
01814     
01815     
01816     // Make sure not larger than very first covariance elements
01817     C_k_minus[0][0]=min(C_k_minus[0][0],0.25); C_k_minus[1][1]=min(C_k_minus[1][1],0.25);
01818     C_k_minus[2][2]=min(C_k_minus[2][2],100.); C_k_minus[3][3]=min(C_k_minus[3][3],100.);
01819     C_k_minus[4][4]=min(C_k_minus[4][4],1.);
01820 
01821     double cov_xqp = 7.5e-5;             // Taken from SR - Origin of this?
01822     
01823     for(int i=0; i<2; ++i){
01824       if(fabs(C_k_minus[i][4])>cov_xqp) C_k_minus[i][4] = (C_k_minus[i][4] > 0 ? cov_xqp : -cov_xqp);
01825       if(fabs(C_k_minus[4][i])>cov_xqp) C_k_minus[4][i] = (C_k_minus[4][i] > 0 ? cov_xqp : -cov_xqp);
01826     }
01827 
01828     cov_xqp /= 0.06;                     // Taken from SR - Origin of this?
01829 
01830     for(int i=2; i<4; ++i){
01831       if(fabs(C_k_minus[i][4])>cov_xqp) C_k_minus[i][4] = (C_k_minus[i][4] > 0 ? cov_xqp : -cov_xqp);
01832       if(fabs(C_k_minus[4][i])>cov_xqp) C_k_minus[4][i] = (C_k_minus[4][i] > 0 ? cov_xqp : -cov_xqp);
01833     }
01834   }
01835 
01836 
01837   // Display
01838   if(debug) {
01839     cout << "Initial covariance matrix" << endl;
01840     for(int p=0; p<5; ++p){
01841       for(int q=0; q<5; ++q){
01842         cout << C_k_minus[p][q] << " ";
01843       }  
01844       cout << endl;
01845     }
01846   }
01847 
01848 }
01850 
01851 
01852 
01854 void AlgFitTrackCam::GetNoiseMatrix(const int Plane, const int NewPlane)
01855 {
01856   // This method is essentially the same as in SR fitter
01857   //  MSG("AlgFitTrackCam",Msg::kDebug) << "GetNoiseMatrix" << endl;
01858 
01859   for (int p=0; p<5; ++p) {
01860     for (int q=0; q<5; ++q) {
01861       Q_k_minus[p][q]=0;    }
01862   }
01863   
01864   // Get gradients, etc from x_k_minus
01865   double dsdzSquared = 1.+pow(x_k_minus[2],2)+pow(x_k_minus[3],2);
01866   double dsdz = pow(dsdzSquared,0.5);
01867 
01868   // Implement noise matrix as in SR
01869   if (DeltaPlane!=-99 && DeltaZ!=-99) {  
01870     double qp = x_k_minus[4];
01871     if(fabs(qp)<0.01) qp = (qp>0 ? 0.01 : -0.01);
01872     int izdir = ((NewPlane-Plane)>0 ? 0 : 1);
01873   
01874     double LocalRadiationLength=(dsdz * double(DeltaPlane) * 1.47); // 1.47 radiation lengths per iron plane
01875 
01876     double SigmaMS=(0.0136 * fabs(qp) * pow(LocalRadiationLength,0.5)
01877                     * (1. + (0.038 * log(LocalRadiationLength)) ));
01878     double SigmaMSSquared=pow(SigmaMS,2);
01879 
01880     double Sigma33Squared=0.5*SigmaMSSquared*dsdzSquared*(1.+pow(x_k_minus[2],2));
01881 
01882     double Sigma34Squared=0.5*SigmaMSSquared*dsdzSquared*(x_k_minus[2]*x_k_minus[3]);
01883 
01884     double Sigma44Squared=0.5*SigmaMSSquared*dsdzSquared*(1.+pow(x_k_minus[3],2));;
01885 
01886 
01887     // Treat steel as discrete scatter
01888     SwimGeo *spil = SwimGeo::Instance(*(const_cast<VldContext*>(vldc))); // Get edges of steel
01889     double z1 = spil->GetSteel(TrkStripData[Plane][0].ZPos,izdir)->GetZ();
01890     double z2 = spil->GetSteel(z1,izdir)->GetZ();
01891   
01892     double dzscatter = fabs(TrkStripData[NewPlane][0].ZPos-0.5*(z1+z2));
01893     double dzscatter2 = pow(dzscatter,2);
01894   
01895     UgliGeomHandle ugh(*vldc);
01896     BField bf(*vldc,-1,0);
01897     TVector3 uvz;
01898 
01899     uvz(0) = x_k_minus[0];
01900     uvz(1) = x_k_minus[1];
01901     uvz(2) = ugh.GetNearestSteelPlnHandle(TrkStripData[Plane][0].ZPos).GetZ0();
01902 
01903     TVector3 buvz = bf.GetBField(uvz, true);
01904     buvz[0] *= 0.3;
01905     buvz[1] *= 0.3;
01906     buvz[2] *= 0.3;
01907 
01908     double beta2inv = 1.0-0.0011*qp*qp;
01909 
01910     double eloss = 0.038 * double(DeltaPlane);
01911     double sigmaeloss2 = 0.25*eloss*dsdz*beta2inv*qp*qp;
01912     sigmaeloss2 *= sigmaeloss2;
01913 
01914 
01915     // Fill elements of noise matrix
01916     Q_k_minus[0][0]=dzscatter2*Sigma33Squared;
01917     Q_k_minus[0][1]=dzscatter2*Sigma34Squared;
01918     Q_k_minus[0][2]=dzscatter*Sigma33Squared;
01919     Q_k_minus[0][3]=dzscatter*Sigma34Squared;
01920     Q_k_minus[0][4]=dzscatter*sigmaeloss2*double(DeltaPlane)*buvz(1)*0.0254*dsdz*(1.+pow(x_k_minus[2],2));
01921 
01922     Q_k_minus[1][0]=dzscatter2*Sigma34Squared;
01923     Q_k_minus[1][1]=dzscatter2*Sigma44Squared;
01924     Q_k_minus[1][2]=dzscatter*Sigma34Squared;
01925     Q_k_minus[1][3]=dzscatter*Sigma44Squared;
01926     Q_k_minus[1][4]=dzscatter*sigmaeloss2*double(DeltaPlane)*buvz(0)*0.0254*dsdz*(1.+pow(x_k_minus[3],2));
01927 
01928     Q_k_minus[2][0]=dzscatter*Sigma33Squared;
01929     Q_k_minus[2][1]=dzscatter*Sigma34Squared;
01930     Q_k_minus[2][2]=Sigma33Squared;
01931     Q_k_minus[2][3]=Sigma34Squared;
01932     Q_k_minus[2][4]=sigmaeloss2*double(DeltaPlane)*buvz(1)*0.0254*dsdz*(1.+pow(x_k_minus[2],2));
01933 
01934     Q_k_minus[3][0]=dzscatter*Sigma34Squared;
01935     Q_k_minus[3][1]=dzscatter*Sigma44Squared;
01936     Q_k_minus[3][2]=Sigma34Squared;
01937     Q_k_minus[3][3]=Sigma44Squared;
01938     Q_k_minus[3][4]=sigmaeloss2*double(DeltaPlane)*buvz(0)*0.0254*dsdz*(1.+pow(x_k_minus[3],2));
01939 
01940     Q_k_minus[4][0]=dzscatter*sigmaeloss2*double(DeltaPlane)*buvz(1)*0.0254*dsdz*(1.+pow(x_k_minus[2],2));
01941     Q_k_minus[4][1]=dzscatter*sigmaeloss2*double(DeltaPlane)*buvz(0)*0.0254*dsdz*(1.+pow(x_k_minus[3],2));
01942     Q_k_minus[4][2]=sigmaeloss2*double(DeltaPlane)*buvz(1)*0.0254*dsdz*(1.+pow(x_k_minus[2],2));
01943     Q_k_minus[4][3]=sigmaeloss2*double(DeltaPlane)*buvz(0)*0.0254*dsdz*(1.+pow(x_k_minus[3],2));
01944     Q_k_minus[4][4]=sigmaeloss2;
01945   }
01946  
01947 
01948   // Display
01949   if(debug) {
01950     cout << "1e6 * Q_k_minus" << endl;
01951     for(int i=0; i<5; ++i) {
01952       for(int j=0; j<5; ++j) {
01953         cout << 1e6*Q_k_minus[i][j] << " ";
01954       }
01955       cout << endl;
01956     }
01957   }
01958 
01959 }
01961 
01962 
01963 
01965 void AlgFitTrackCam::ExtrapCovMatrix()
01966 {
01967   // C_k_intermediate = (F_k_minus * C_k_minus * F_k_minus^T) + Q_k_minus
01968   //  MSG("AlgFitTrackCam",Msg::kDebug) << "ExtrapCovMatrix" << endl;
01969 
01970   for (int i=0; i<5; ++i) {
01971     for (int j=0; j<5; ++j) {  
01972       C_k_intermediate[i][j]=0;
01973       
01974       for (int l=0; l<5; ++l) {
01975         for (int m=0; m<5; ++m) {   
01976           C_k_intermediate[i][j]+=F_k_minus[i][m]*C_k_minus[m][l]*F_k_minus[j][l];
01977         }
01978       }
01979 
01980       C_k_intermediate[i][j]+=Q_k_minus[i][j];
01981     }
01982     
01983   }
01984 
01985 
01986   // Diagonal elements should be positive
01987   double covlim = 1.e-8;
01988 
01989   for(int i=0; i<5; ++i) {
01990     if(C_k_intermediate[i][i]<covlim) {
01991       MSG("AlgFitTrackCam",Msg::kVerbose) << "Negative diagonal element in C_k_intermediate" << endl;
01992       C_k_intermediate[i][i]=covlim;
01993     }
01994   }
01995 
01996 
01997   // Display
01998   if(debug) {
01999     cout << "C_k_intermediate" << endl;
02000     for(int i=0; i<5; ++i) {
02001       for(int j=0; j<5; ++j) {
02002         cout << C_k_intermediate[i][j] << " ";
02003       }
02004       cout << endl;
02005     }
02006   }
02007   
02008 }
02010 
02011 
02012 
02014 void AlgFitTrackCam::CalcKalmanGain(const int NewPlane)
02015 {
02016   // K_k = C_k_intermediate * H_k^T * ( V_k + H_k * C_k_intermediate * H_k^T )^-1
02017   //  MSG("AlgFitTrackCam",Msg::kDebug) << "CalcKalmanGain" << endl;
02018 
02019   double Denominator=0;
02020 
02021   // H_k has only one non-zero element, so we can reduce matrix multiplication required
02022   if(TrkStripData[NewPlane][0].PlaneView==2) {Denominator=C_k_intermediate[0][0];}
02023   else {Denominator=C_k_intermediate[1][1];}
02024   
02025 
02026   // Add uncertainty in measurement
02027   Denominator+=TrkStripData[NewPlane][0].TPosError;
02028 
02029   MSG("AlgFitTrackCam",Msg::kVerbose) << "V_k " << TrkStripData[NewPlane][0].TPosError 
02030                                       << ", Kalman Gain Denominator " << Denominator << endl;
02031 
02032   if (Denominator!=0.) {
02033     for (int i=0; i<5; ++i) {
02034       K_k[i]=0;
02035       
02036       for (int m=0; m<5; ++m) {K_k[i]+=(C_k_intermediate[i][m])*(H_k[m]);}
02037       
02038       K_k[i]=K_k[i]/Denominator;
02039     }
02040 
02041     MSG("AlgFitTrackCam",Msg::kVerbose) << "Kalman Gain: " 
02042                                         << K_k[0] << " " << K_k[1] << " " << K_k[2] << " "
02043                                         << K_k[3] << " " << K_k[4] << endl;
02044   }
02045   else MSG("AlgFitTrackCam",Msg::kDebug) << "V_k + (H_k * C_k_intermediate * H_k_transpose) is zero!" << endl;
02046 }
02048 
02049 
02050 
02052 void AlgFitTrackCam::UpdateStateVector(const int Plane, const int NewPlane, const bool GoForward)
02053 {  
02054   // x_k = (F_k_minus * x_k_minus) + K_k(m_k - (H_k * F_k_minus * x_k_minus) )
02055   //  MSG("AlgFitTrackCam",Msg::kDebug) << "UpdateStateVector" << endl;
02056 
02057 
02058   double HFx=0;
02059   double m_k=0;
02060   double MeasurementFactor=0;
02061   int nswimfail=0;
02062 
02063 
02064   // Calculate F_k_minus * x_k_minus, using the Swimmer
02065   // Also get an accurate measure of dS and Range from the Swimmer
02067   double StateVector[5];
02068   double Prediction[5];
02069   bool GetPrediction=false;
02070 
02071   for(int i=0; i<5; ++i) {StateVector[i]=x_k_minus[i];}
02072 
02073   // Prediction could be used without GeoSwimmer calculation. Prediction is initialized with linear extrapolation.
02074   for(int i=0; i<5; i++) {
02075     double delz = (SlcStripData[NewPlane][0].csh->GetZPos()-SlcStripData[Plane][0].csh->GetZPos());
02076     Prediction[0]=StateVector[0] + StateVector[2]*delz;
02077     Prediction[1]=StateVector[1] + StateVector[3]*delz;
02078     Prediction[2]=StateVector[2];
02079     Prediction[3]=StateVector[3];
02080     Prediction[4]=StateVector[4];
02081   }
02082 
02083   // Do the swim
02085   while(GetPrediction==false && nswimfail<=10) {
02086     MSG("AlgFitTrackCam",Msg::kVerbose) << " state " << StateVector[0] << " " 
02087                                         << StateVector[1] << " " << StateVector[2] << " " 
02088                                         << StateVector[3] << " " << StateVector[4] << endl;   
02089     
02090     GetPrediction=Swim(StateVector, Prediction, Plane, NewPlane, GoForward);
02091     
02092     MSG("AlgFitTrackCam",Msg::kVerbose) << " predict state " << Prediction[0] << " " 
02093                                         << Prediction[1] << " " << Prediction[2] << " " 
02094                                         << Prediction[3] << " " << Prediction[4] << endl;
02095 
02096     if(GetPrediction==false) {
02097       StateVector[4]*=0.5; 
02098       nswimfail++; TotalNSwimFail++;
02099       MSG("AlgFitTrackCam",Msg::kVerbose) << "UpdateStateVector, Prediction failed - Double momentum and swim again" << endl;
02100     }
02101   }
02102 
02103   if(nswimfail>10) {  // Swim shouldn't fail, as it succeeded to get the propagator
02104     MSG("AlgFitTrackCam",Msg::kDebug) << "UpdateStateVector, nswimfail>10, fail track" << endl;
02105     PassTrack=false;
02106   }
02108 
02109   
02111 
02112 
02113   //  MSG("AlgFitTrackCam",Msg::kDebug) << "UpdateStateVector, Check predicted state " << endl;
02114   CheckValues(Prediction, NewPlane);
02115 
02116 
02117   // Calculate H_k * F_k_minus * x_k_minus
02119   if(TrkStripData[NewPlane][0].PlaneView==2) {HFx=Prediction[0];}
02120   if(TrkStripData[NewPlane][0].PlaneView==3) {HFx=Prediction[1];}
02121 
02122   MSG("AlgFitTrackCam",Msg::kVerbose) << "HFx " << HFx << endl;
02124 
02125   
02126   // Read in measurement
02128   m_k=TrkStripData[NewPlane][0].TPos;
02129   MSG("AlgFitTrackCam",Msg::kVerbose) << "m_k " << TrkStripData[NewPlane][0].TPos << endl;
02130   
02131   MeasurementFactor=(m_k-HFx);
02133 
02134   
02135   // Calculate x_k
02137   for (int i=0; i<5; ++i) {
02138     x_k[i]=0.;
02139     x_k[i]+=Prediction[i]+(K_k[i]*MeasurementFactor);
02140   }
02142 
02143 
02144   //  MSG("AlgFitTrackCam",Msg::kDebug) << "UpdateStateVector, Check filtered state " << endl;
02145   CheckValues(x_k, NewPlane);
02146 
02147 
02148   // Care with multiple range corrections - do not want to flip sign
02149   // (multiple corrections mean sign changes can occur even though absolute value stays same)
02150   
02151   double Maxqp = 4.;
02152   if(fabs(x_k_minus[4])==Maxqp && 
02153      ( (GoForward==true && ZIncreasesWithTime==true) 
02154        || (GoForward==false && ZIncreasesWithTime==false) ) ) 
02155     {
02156       if(!LastIteration) x_k[4] = (x_k_minus[4]>0 ? Maxqp : -Maxqp);
02157     }
02158 
02159   //if on last plane, disregard a flip in the charge sign
02160   //if(x_k_minus[4]!=0){
02161   //  if( x_k[4]/x_k_minus[4]<0 && 
02162   //      ( (GoForward==true  && ZIncreasesWithTime==true  && NewPlane >= EndofRangePlane ) 
02163   //     || (GoForward==false && ZIncreasesWithTime==false && NewPlane <= EndofRangePlane ) ) ) 
02164   //   {
02165   //     MSG("AlgFitTrackCam",Msg::kSynopsis) << " Disregard charge flip in final plane: NewPlane=" << NewPlane << " " << x_k[4] << "-> " << -x_k[4] << endl;
02166   //      x_k[4] = -x_k[4];
02167   //    }
02168   // }  
02169 
02170   // if on last plane, disregard a charge sign that conflicts with the majority curvature of the track (set cut at 2/3 of track)
02171   if( (GoForward==true && ZIncreasesWithTime==true && NewPlane >= EndofRangePlane ) 
02172    || (GoForward==false && ZIncreasesWithTime==false && NewPlane <= EndofRangePlane ) )
02173     {
02174       double majority_curvature = this->MajorityCurvature();
02175       MSG("AlgFitTrackCam",Msg::kDebug) << " Checking Last Plane: Q/P=" << x_k[4] << " MajorityCurvature = " << majority_curvature << endl;
02176 
02177       if( ( majority_curvature<-0.33 && x_k[4]>0.0 )
02178        || ( majority_curvature>+0.33 && x_k[4]<0.0 ) ){
02179         MSG("AlgFitTrackCam",Msg::kDebug) << " Disregard charge sign in last plane: NewPlane=" << NewPlane << " " << x_k[4] << "-> " << -x_k[4] << endl;
02180         x_k[4] = -x_k[4];
02181       }
02182     }
02183   
02184   // Display
02185   MSG("AlgFitTrackCam",Msg::kVerbose) << "Filtered State vector: "
02186                                       << x_k[0] << " " << x_k[1] << " " << x_k[2] << " "
02187                                       << x_k[3] << " " << x_k[4] << endl;
02188 }
02190 
02192 double AlgFitTrackCam::MajorityCurvature()
02193 { 
02194   //  MSG("AlgFitTrackCam",Msg::kDebug) << "MajorityCurvature" << endl;
02195 
02196   Double_t majority_curvature = 0.0;
02197   Double_t majority_counter = 0.0;
02198   Double_t total_counter = 0.0;
02199 
02200   for(int i=MinPlane; i<=MaxPlane; ++i) {
02201     if( FilteredData[i].size()>0 ) {
02202       if( FilteredData[i][0].x_k4>0.0 ) majority_counter += 1.0;
02203       if( FilteredData[i][0].x_k4<0.0 ) majority_counter -= 1.0;
02204       total_counter += 1.0;
02205     }
02206   }
02207 
02208   if( total_counter>0.0 ){
02209     majority_curvature = majority_counter/total_counter;
02210   }
02211   
02212   return majority_curvature;
02213 }
02215 
02216 
02218 void AlgFitTrackCam::UpdateCovMatrix()
02219 {
02220   // C_k = (Identity - (K_k * H_k) ) * C_k_intermediate
02221   //  MSG("AlgFitTrackCam",Msg::kDebug) << "UpdateCovMatrix" << endl;
02222 
02223   for (int i=0; i<5; ++i) {
02224     for (int j=0; j<5; ++j) {  
02225       C_k[i][j]=0;
02226       for (int m=0; m<5; ++m) {   
02227         C_k[i][j]+=(Identity[i][m] - K_k[i]*H_k[m]) * C_k_intermediate[m][j];
02228       }
02229     }
02230   }
02231 
02232 
02233   // Diagonal elements should be positive
02234   double covlim = 1.e-8;
02235 
02236   for(int i=0; i<5; ++i) {
02237     if(C_k[i][i]<covlim) {
02238       MSG("AlgFitTrackCam",Msg::kVerbose) << "Negative diagonal element in C_k" << endl;
02239       C_k[i][i]=covlim;
02240     }
02241   }
02242 
02243 
02244   // Display
02245   if(debug) {
02246     cout << "Filtered Covariance matrix" << endl;
02247     for(int i=0; i<5; ++i) {
02248       for(int j=0; j<5; ++j) {
02249         cout << C_k[i][j] << " ";
02250       }
02251       cout << endl;  
02252     }
02253   }
02254 
02255 }
02257 
02258 
02259 
02261 void AlgFitTrackCam::MoveArrays()
02262 {
02263   // Move k to k-1 ready to consider next hit
02264   //  MSG("AlgFitTrackCam",Msg::kDebug) << "MoveArrays" << endl;
02265 
02266   for (int i=0; i<5; ++i) {
02267     for (int j=0; j<5; ++j) { 
02268       C_k_minus[i][j]=C_k[i][j];
02269     }
02270   }
02271   
02272   for (int l=0; l<5; ++l) {
02273     x_k_minus[l]=x_k[l];
02274   }
02275 }
02277 
02278 
02279 
02281 void AlgFitTrackCam::CheckValues(double* Input, const int NewPlane)
02282 {
02283   // Make range and gradient corrections
02284   // Possible source of offset in q/p resolutions
02285 
02286   // Range check
02287     
02288   double Maxqp=4.; double Maxqpfrac=1.2;
02289   double Range=track->GetRange(NewPlane);
02290 
02291   //JAM signal end of range found
02292   // JAM 11/09 end of range changes from 100 to  250 MeV 
02293   //  if(fabs(Input[4])>10.0) EndofRange=true; 
02294 
02295   if(fabs(Input[4])>4.0) EndofRange=true; 
02296 
02297    if(Range>0. && (Maxqpfrac*500/Range)<Maxqp) {Maxqp=(Maxqpfrac*500/Range);}
02298   MSG("AlgFitTrackCam",Msg::kVerbose) << " Range " << Range << " Maxqp " << Maxqp << endl;
02299 
02300 
02301   // JAM 11/09 
02302   //  if(LastIteration) Maxqp=40;
02303 
02304   if(fabs(Input[4])>Maxqp){
02305     MSG("AlgFitTrackCam",Msg::kVerbose) << "CheckValues, Range check correction" << endl;
02306     Input[4]=(Input[4]>0 ? Maxqp : -Maxqp);
02307   }
02308   
02309   
02310   // Gradient check
02311   double Maxgradient=25.;
02312 
02313   if(fabs(Input[2])>Maxgradient) {
02314     MSG("AlgFitTrackCam",Msg::kVerbose) << "CheckValues, Gradient correction, U" << endl;
02315     Input[2]=(Input[2]>0 ? Maxgradient : -Maxgradient);
02316   }
02317 
02318   if(fabs(Input[3])>Maxgradient) {
02319     MSG("AlgFitTrackCam",Msg::kVerbose) << "CheckValues, Gradient correction, V" << endl;
02320     Input[3]=(Input[3]>0 ? Maxgradient : -Maxgradient);
02321   }
02322   
02323 
02324   // Check u and v values are not rubbish
02325   if(fabs(Input[0])<5000. && fabs(Input[1])<5000.) {PassTrack=true;}
02326   else {
02327     PassTrack=false;
02328   }
02329 }
02331 
02332 
02333 
02335 void AlgFitTrackCam::StoreFilteredData(const int NewPlane)
02336 {
02337   // Store the data required for matching Kalman output data to strips
02338   MSG("AlgFitTrackCam",Msg::kVerbose) << "StoreFilteredData" << endl;
02339 
02340   FiltDataStruct temp;
02341   
02342   temp.x_k0=x_k[0]; temp.x_k1=x_k[1];
02343   temp.x_k2=x_k[2]; temp.x_k3=x_k[3];
02344   temp.x_k4=x_k[4];
02345 
02346   //  FilteredData[NewPlane].push_back(temp);
02347   FilteredData[NewPlane].insert(FilteredData[NewPlane].begin(),temp);
02348 
02349   MSG("AlgFitTrackCam",Msg::kSynopsis) << " StoreData [" << NewPlane << "]  x_k[4] = " << x_k[4] << " Entry=" << FilteredData[NewPlane].size() << endl; 
02350 }
02352 
02353 
02354 
02356 void AlgFitTrackCam::SetTrackProperties(CandFitTrackCamHandle &cth)
02357 { 
02358   int VtxPlane;
02359   int EndPlane;
02360   double dsdz;
02361   double VtxQP;
02362 
02363   if(nbfield>0) bave /=nbfield;
02364   
02365   // Carry out the assignment of variables to the new fitted track 
02366   MSG("AlgFitTrackCam",Msg::kSynopsis) << "Set Track Properties:" << endl;
02367  
02368   // Vertex and End Plane
02370 
02371   if(ZIncreasesWithTime==true) {VtxPlane=MinPlane; EndPlane=MaxPlane;}
02372   else {VtxPlane=MaxPlane; EndPlane=MinPlane;}
02373 
02374   // Momentum, charge and error on q/p
02376 
02377   // look up q/p value in vertex plane
02378   VtxQP = FilteredData[VtxPlane][0].x_k4;
02379 
02380   // apply tweak of 1.3%
02381   VtxQP *= 1.013;
02382 
02383   // if(x_k[4]!=0.) {cth.SetMomentumCurve(fabs(1./x_k[4]));}
02384   // cth.SetRangeBiasedQP(x_k4_biased);
02385   // if(x_k[4]>0.) {cth.SetEMCharge(1.);}
02386   // else if(x_k[4]<0.) {cth.SetEMCharge(-1.);}
02387   // cth.SetVtxQPError(pow(VtxCov[4],0.5));
02388 
02389 // Protect from curvature below float precision
02390   Double_t pcabsinvtemp = TMath::Max(TMath::Abs(VtxQP), (Double_t) FLT_MIN);
02391   cth.SetMomentumCurve(1./pcabsinvtemp);
02392 
02393   cth.SetRangeBiasedQP(x_k4_biased);
02394   cth.SetRangeBiasedEQP(eqp_biased);
02395 
02396   if( VtxQP>0.0 ) {cth.SetEMCharge(1.);}
02397   else if( VtxQP<0.0 ) {cth.SetEMCharge(-1.);}
02398   cth.SetVtxQPError(pow(VtxCov[4],0.5));
02399 
02400   MSG("AlgFitTrackCam",Msg::kSynopsis)  << " Q/P = " << VtxQP << ", Q/P(biased) = " << x_k4_biased << ", sigma(Q/P) = " << pow(VtxCov[4],0.5) << " Sigma Q/P _biased "<< eqp_biased << endl; 
02401   
02402   // Positions and angles  
02404 
02405   // Vtx and end coordinates  
02406   cth.SetVtxU(FilteredData[VtxPlane][0].x_k0);
02407   cth.SetVtxV(FilteredData[VtxPlane][0].x_k1);
02408   cth.SetVtxZ(SlcStripData[VtxPlane][0].csh->GetZPos());
02409   cth.SetVtxPlane(VtxPlane);
02410   
02411   cth.SetEndU(FilteredData[EndPlane][0].x_k0);
02412   cth.SetEndV(FilteredData[EndPlane][0].x_k1);
02413 
02414   cth.SetEndZ(SlcStripData[EndPlane][0].csh->GetZPos());
02415   cth.SetEndPlane(EndPlane);
02416   
02417   
02418   // Vtx and end direction cosines
02419   dsdz=pow(1.+pow(FilteredData[VtxPlane][0].x_k2,2)+pow(FilteredData[VtxPlane][0].x_k3,2),0.5);
02420   if(ZIncreasesWithTime==false) {dsdz=-dsdz;}
02421   
02422   cth.SetVtxDirCosU(FilteredData[VtxPlane][0].x_k2/dsdz);
02423   cth.SetVtxDirCosV(FilteredData[VtxPlane][0].x_k3/dsdz);
02424   cth.SetVtxDirCosZ(1./dsdz);
02425   
02426   cth.SetDirCosU(FilteredData[VtxPlane][0].x_k2/dsdz);
02427   cth.SetDirCosV(FilteredData[VtxPlane][0].x_k3/dsdz);
02428   cth.SetDirCosZ(1./dsdz);
02429     
02430   dsdz=pow(1.+pow(FilteredData[EndPlane][0].x_k2,2)+pow(FilteredData[EndPlane][0].x_k3,2),0.5);
02431   if(ZIncreasesWithTime==false) {dsdz=-dsdz;}
02432   
02433   cth.SetEndDirCosU(FilteredData[EndPlane][0].x_k2/dsdz);
02434   cth.SetEndDirCosV(FilteredData[EndPlane][0].x_k3/dsdz);
02435   cth.SetEndDirCosZ(1./dsdz);
02436   
02437   // End q/p value
02438   cth.SetEndQP(FilteredData[EndPlane][0].x_k4);
02439     
02440   // Errors on vtx positions and angles  
02441   cth.SetVtxUError(pow(VtxCov[0],0.5));
02442   cth.SetVtxVError(pow(VtxCov[1],0.5));
02443   cth.SetVtxdUError(pow(VtxCov[2],0.5));
02444   cth.SetVtxdVError(pow(VtxCov[3],0.5)); 
02445   
02446   // Errors on end positions, angles and q/p
02447   cth.SetEndUError(pow(EndCov[0],0.5));
02448   cth.SetEndVError(pow(EndCov[1],0.5));
02449   cth.SetEnddUError(pow(EndCov[2],0.5));
02450   cth.SetEnddVError(pow(EndCov[3],0.5)); 
02451   cth.SetEndQPError(pow(EndCov[4],0.5)); 
02452 
02454 
02455   cth.SetBave(bave);
02456 
02457   // More variables to be set, in order to ensure compatibility
02459   cth.SetNTrackStrip(cth.GetNDaughters());
02460   cth.SetNTrackDigit(cth.GetNDigit());
02461   
02462   cth.SetNIterate(NIter);
02463   cth.SetNSwimFail(TotalNSwimFail);
02464   
02465   
02466   // Obtain "fitting data" for the final track strips
02467   for (int i=0; i<490; ++i) {TrkStripData[i].clear();} 
02468   GetFitData(MinPlane,MaxPlane);
02469   
02470   
02471   // Set tpos error and Calculate chi2, NDOF
02472   double Chi2=0; double Chi2Contrib=0; int NDOF=0; double FilteredTPos=0;
02473   
02474   for(int i=MinPlane; i<=MaxPlane; ++i) {
02475     if(TrkStripData[i].size()>0) {
02476       
02477       if(TrkStripData[i][0].TPosError>0.) {
02478         cth.SetTrackPointError(i,pow(TrkStripData[i][0].TPosError,0.5));
02479         
02480         if(TrkStripData[i][0].PlaneView==2) {FilteredTPos=FilteredData[i][0].x_k0;}
02481         else {FilteredTPos=FilteredData[i][0].x_k1;}
02482         
02483         Chi2Contrib = pow((TrkStripData[i][0].TPos-FilteredTPos),2) / TrkStripData[i][0].TPosError;
02484         cth.SetPlaneChi2(i,Chi2Contrib);        
02485         
02486         Chi2+=Chi2Contrib;
02487         
02488         NDOF++;
02489       }
02490     }
02491   }
02492   cth.SetChi2(Chi2);
02493   cth.SetNDOF(NDOF-5); // Number of constraints set to 5
02494   
02495   
02496   // Assign U, V and q/p values
02497   for(int i=MinPlane; i<=MaxPlane; ++i) {
02498     if(FilteredData[i].size()>0) {
02499       cth.SetU(i,FilteredData[i][0].x_k0);
02500       cth.SetV(i,FilteredData[i][0].x_k1);
02501       cth.SetPlaneQP(i,FilteredData[i][0].x_k4);
02502     }
02503   }
02504   
02505   
02506   // Set Trace and TraceZ
02507   CalculateTrace(cth);
02508   
02509   
02510   // Fill time and range maps
02511   SetT(&cth);
02512   SetRangeAnddS(cth);
02513   
02514   
02515   // Set momentum to our best estimate (range or curvature)
02516   cth.SetMomentum(cth.GetMomentumCurve());
02517   if(cth.IsContained()){
02518     cth.SetMomentum(cth.GetMomentumRange());
02519   }
02520   
02521   
02522   // Identify track strips inside in vertex shower
02523   
02524   TIter FitTrackStripItr = cth.GetDaughterIterator();
02525   while(CandStripHandle* FitTrackStrip = dynamic_cast<CandStripHandle*>(FitTrackStripItr()))
02526     {
02527       if(ShowerEntryPlane!=-99) {
02528         if( (ZIncreasesWithTime==true && FitTrackStrip->GetPlane()<=ShowerEntryPlane)
02529             || (ZIncreasesWithTime==false && FitTrackStrip->GetPlane()>=ShowerEntryPlane) ) {
02530           cth.SetInShower(FitTrackStrip,2);
02531         }
02532         else {cth.SetInShower(FitTrackStrip,0);}
02533       }
02534       else {cth.SetInShower(FitTrackStrip,0);}
02535     }
02536   
02537   
02538   // Set all time related variables
02539   TimingFit(cth);
02540   
02541   
02542   // Calibrate, to get track pulse height in MIPs, GeV, etc
02543   Calibrator& cal = Calibrator::Instance();
02544   cal.ReInitialise(*vldc);
02545   Calibrate(&cth);
02546 
02547 
02548 }
02550 
02551 
02552 
02554 void AlgFitTrackCam::TimingFit(CandFitTrackCamHandle &cth)
02555 {
02556   //  MSG("AlgFitTrackCam",Msg::kSynopsis) << "TimingFit" << endl;
02557 
02558   // Initialisations
02560   double s; double t; double q; double w; int n=0; 
02561   double Uncertainty=1.0; double MinUncertainty=1.0; 
02562   double MinCT=-3000.;
02563   
02564   // Time of first strip in track
02565   StripListTime=9.e30;
02566 
02567   // Create an offset such that dS=0 at the MinPlane
02568   double dSOffset=0.; double Sign=-1.; double dS[490];
02569   if(ZIncreasesWithTime==true) {dSOffset=cth.GetdS(MinPlane); Sign=1.;}
02570 
02571   // Store data needed in arrays. Charge is in PEs.
02572   double Qp[490];  double Qm[490];
02573   double CTp[490]; double CTm[490];
02574   int Skipp[490];  int Skipm[490];
02575   double C=3.e8;   
02576 
02577   double ErrorParam[3];
02578   ErrorParam[0]=1.; ErrorParam[1]=0.; ErrorParam[2]=0.;
02579 
02580   // Zero the arrays
02581   for(int i=0; i<490; ++i) { 
02582     dS[i]=0.; CTm[i]=0.; CTp[i]=0.; 
02583     Qp[i]=0.; Qm[i]=0.; 
02584     Skipp[i]=0; Skipm[i]=0;
02585   }
02586   // End of Initialisations
02588 
02589 
02590   // Copy track strips into vector
02592   vector<StripStruct> TimeFitStripData[490];
02593 
02594   TIter MyStripItr = cth.GetDaughterIterator();
02595 
02596   while(CandStripHandle* MyStrip = dynamic_cast<CandStripHandle*>(MyStripItr()))
02597     {    
02598       int MyPlane = MyStrip->GetPlane();
02599      
02600       StripStruct temp;
02601       temp.csh = MyStrip;
02602 
02603       if( cth.GetdS(MyPlane)>-0.99 ){               // distance must be greater
02604         TimeFitStripData[MyPlane].push_back(temp);  // than default value of -1
02605       }
02606       
02607     } 
02609 
02610 
02611   // Organise timing for the Far Detector
02613   if(vldc->GetDetector()==Detector::kFar) {  
02614 
02615     // Parameters for time fit residual vs PEs
02616     // (consistent with AlgTrackCam::WeightsForTimingFits() method)
02617     // ErrorParam[0]=0.56; ErrorParam[1]=0.50; ErrorParam[2]=-0.34; // (OLD)
02618     ErrorParam[0]=0.58; ErrorParam[1]=0.69; ErrorParam[2]=-0.33; // (NEW)
02619     MinUncertainty=ErrorParam[0];
02620 
02621     // Loop over all planes
02622     for(int i=MinPlane; i<=MaxPlane; ++i) {
02623         
02624       if(TimeFitStripData[i].size()>0) {
02625         dS[i]=Sign*(dSOffset-cth.GetdS(i));
02626         
02627         CTp[i]=C*cth.GetT(i,StripEnd::kPositive);
02628         CTm[i]=C*cth.GetT(i,StripEnd::kNegative);
02629         
02630         if(CTp[i]>MinCT && CTp[i]<StripListTime) {StripListTime=CTp[i];}
02631         if(CTm[i]>MinCT && CTm[i]<StripListTime) {StripListTime=CTm[i];}
02632         
02633         for(unsigned int j=0; j<TimeFitStripData[i].size(); ++j) {
02634           Qp[i]+=TimeFitStripData[i][j].csh->GetCharge(StripEnd::kPositive);
02635           Qm[i]+=TimeFitStripData[i][j].csh->GetCharge(StripEnd::kNegative);
02636         }
02637       }
02638     }
02639 
02640     // Subtract StripList time
02641     if(StripListTime<8.e30) {
02642       for(int i=MinPlane; i<=MaxPlane; ++i) {
02643         if(TimeFitStripData[i].size()>0) {
02644           CTp[i]-=StripListTime;
02645           CTm[i]-=StripListTime;
02646         }
02647       }
02648     }
02649     else {StripListTime=0.;}
02650 
02651   } // End Far Detector Section
02653 
02654 
02655 
02656   // Organise timing for the Near Detector
02658   if(vldc->GetDetector()==Detector::kNear) {
02659     // Parameters for PE vs time fit residual
02660     MinUncertainty=1.19;
02661     ErrorParam[0]=1.13; ErrorParam[1]=0.63; ErrorParam[2]=-0.21;
02662 
02663     double Index=1.77; double DistFromCentre=0.; double CTime=0.;  double FibreDist=0.;    
02664     double halfLength=0.; double DigChg=0.; double PlaneDigChg;
02665 
02666     StripEnd::StripEnd_t StpEnd = StripEnd::kUnknown;
02667     CandStripHandle* strip; CandDigitHandle* digit;
02668 
02669     UgliGeomHandle ugh = UgliGeomHandle(*vldc);
02670     UgliStripHandle striphandle;
02671 
02672 
02673     // Loop over all planes
02674     for(int i=MinPlane; i<=MaxPlane; ++i)
02675       {
02676         if(TimeFitStripData[i].size()>0) {dS[i]=Sign*(dSOffset-cth.GetdS(i));}
02677         PlaneDigChg=0.;
02678 
02679         // Loop over track strips on plane. Only +ve StripEnds should have charge.
02680         for(unsigned int j=0; j<TimeFitStripData[i].size(); ++j) {
02681           strip = TimeFitStripData[i][j].csh;
02682           CandDigitHandleItr digitItr(strip->GetDaughterIterator());
02683 
02684           Qp[i]+=strip->GetCharge(StripEnd::kPositive);
02685 
02686 
02687           // Loop over digits on strip. 
02689           while( (digit = digitItr()) ) { 
02690             StpEnd=digit->GetPlexSEIdAltL().GetEnd();
02691 
02692             if(StpEnd==StripEnd::kPositive) {
02693               FibreDist = 0.; DistFromCentre = 0.; CTime=0.; DigChg=0.;
02694               UgliStripHandle stripHandle = ugh.GetStripHandle(strip->GetStripEndId());
02695               halfLength = stripHandle.GetHalfLength(); 
02696          
02697               if(strip->GetPlaneView()==2) {DistFromCentre = cth.GetV(i);}
02698               if(strip->GetPlaneView()==3) {DistFromCentre = -cth.GetU(i);}
02699               
02700               FibreDist = (halfLength + DistFromCentre + stripHandle.ClearFiber(StpEnd) 
02701                            + stripHandle.WlsPigtail(StpEnd));
02702               
02703               CTime = C*(strip->GetTime(StpEnd)) - Index*FibreDist;
02704               DigChg=digit->GetCharge();
02705               
02706               PlaneDigChg+=DigChg; CTp[i]+=DigChg*CTime;
02707 
02708               if(CTime>MinCT && CTime<StripListTime) {StripListTime=CTime;}
02709             }
02710           }
02712         }
02713         if(PlaneDigChg>0.) CTp[i]/=PlaneDigChg;
02714       }
02715 
02716 
02717     // Subtract StripList time
02718     if(StripListTime<8.e30) {
02719       for(int i=MinPlane; i<=MaxPlane; ++i) {
02720         if(TimeFitStripData[i].size()>0) {
02721           CTp[i]-=StripListTime;
02722         }
02723       }
02724     }
02725     else {StripListTime=0.;}
02726     
02727   } // End near detector section
02729     
02730     
02731 
02732   // Carry out a simple straight line fit for T vs dS
02734   // Sqt: sum of charge*time, Sqss: sum of charge*dS*dS, etc.
02735   double Sqs=0; double Sqt=0; double Sqss=0; double Sqst=0; double Sqtt=0; double Sq=0;
02736   double TimeSlope=-999; double TimeOffset=-999; double RMS=-999;
02737   double CTCut = 0.; bool CalculateChi2=true;
02738 
02739   
02740   // On first iteration, carry out simple fit. Remove outlying points on subsequent passes.
02741   for(int itr=0; itr<3; ++itr) {
02742  
02743     for(int i=MinPlane; i<=MaxPlane; ++i) { 
02744 
02745       // Only consider planes where we found our final strips
02746       if(TimeFitStripData[i].size()>0) { 
02747         
02748         // For positive strip ends      
02749         s=dS[i]; q=Qp[i]; t=CTp[i];
02750 
02751         if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02752         else {Uncertainty=MinUncertainty;}
02753         w = 1.0/pow(Uncertainty,2.0);
02754 
02755         if(q>0. && t>MinCT && Skipp[i]==0) {
02756           if(itr==0) {Sq+=w; Sqs+=w*s; Sqt+=w*t; Sqss+=w*s*s; Sqst+=w*s*t; Sqtt+=w*t*t; n++;}
02757           
02758           else if(fabs(t-TimeOffset-(s*TimeSlope)) > CTCut) {
02759             Sqs-=w*s; Sqt-=w*t; Sqss-=w*s*s; Sqst-=w*s*t; Sqtt-=w*t*t; Sq-=w; n--; Skipp[i]=1;
02760           }
02761         }
02762 
02763 
02764         // For negative strip ends
02765         s=dS[i]; q=Qm[i]; t=CTm[i];
02766 
02767         if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02768         else {Uncertainty=MinUncertainty;}
02769         w = 1.0/pow(Uncertainty,2.0);
02770 
02771         if(q>0. && t>MinCT && Skipm[i]==0) {
02772           if(itr==0) {Sq+=w; Sqs+=w*s; Sqt+=w*t; Sqss+=w*s*s; Sqst+=w*s*t; Sqtt+=w*t*t; n++;}
02773           
02774           else if(fabs(t-TimeOffset-(s*TimeSlope)) > CTCut) {
02775             Sqs-=w*s; Sqt-=w*t; Sqss-=w*s*s; Sqst-=w*s*t; Sqtt-=w*t*t; Sq-=w; n--; Skipm[i]=1;
02776           }
02777         }
02778 
02779       }
02780     }
02781     
02782     // Calculate parameters
02783     if( (Sq*Sqss-Sqs*Sqs)!=0. && Sq!=0. ) {
02784       TimeSlope  = (Sq*Sqst-Sqs*Sqt)/(Sq*Sqss-Sqs*Sqs);
02785       TimeOffset = (Sqt*Sqss-Sqs*Sqst)/(Sq*Sqss-Sqs*Sqs);
02786       if( ((Sqtt/Sq)-((Sqt/Sq)*(Sqt/Sq)))>0. ) {
02787         RMS = pow((Sqtt/Sq)-((Sqt/Sq)*(Sqt/Sq)),0.5);
02788         CTCut = 3.+RMS;
02789       }
02790       else {CTCut = 3.5;}
02791     }
02792     else  {CalculateChi2=false; break;}
02793   }
02795 
02796 
02797 
02798   // Set timing properties for the fitted track
02800   if(n!=0 && CalculateChi2==true) {
02801 
02802     // Offset, slope and vtx/end times
02804     cth.SetTimeOffset((TimeOffset+StripListTime)/C);
02805     cth.SetTimeSlope(TimeSlope/C);
02806 
02807     if(ZIncreasesWithTime==true) {
02808       cth.SetVtxT((TimeOffset+StripListTime)/C); 
02809       cth.SetEndT((TimeOffset+StripListTime)/C+(dS[MaxPlane]*TimeSlope/C));
02810     }
02811     else {
02812       cth.SetEndT((TimeOffset+StripListTime)/C); 
02813       cth.SetVtxT((TimeOffset+StripListTime)/C+(dS[MaxPlane]*TimeSlope/C));
02814     }
02816 
02817 
02818     // Chi2
02820     double Residual2; double Chi2=0; 
02821  
02822     for(int i=MinPlane; i<=MaxPlane; ++i) { 
02823       
02824       if(TimeFitStripData[i].size()>0) { 
02825         // For positive strip ends
02826         s=dS[i]; q=Qp[i]; t=CTp[i];
02827         if(q>0. && t>MinCT && Skipp[i]==0) {
02828           Residual2=pow(t-TimeOffset-(s*TimeSlope),2);
02829 
02830           // From a rough parameterisation of uncertainty (in CT) vs number of PEs
02831           if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02832           else {Uncertainty=MinUncertainty;}
02833 
02834           if(Uncertainty!=0.) {Chi2+=Residual2/pow(Uncertainty,2);}
02835         }
02836 
02837 
02838         // For negative strip ends
02839         q=Qm[i]; t=CTm[i];
02840         if(q>0. && t>MinCT && Skipm[i]==0) {
02841           Residual2=pow(t-TimeOffset-(s*TimeSlope),2);
02842 
02843           // From a rough parameterisation of uncertainty (in CT) vs number of PEs
02844           if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02845           else {Uncertainty=MinUncertainty;}
02846           
02847           if(Uncertainty!=0.) {Chi2+=Residual2/pow(Uncertainty,2);}
02848         }
02849       }
02850       
02851     }
02852     // Set these properties
02853     cth.SetTimeFitChi2(Chi2);
02854     cth.SetNTimeFitDigit(n);
02855   }
02857 
02858 
02859 
02860   // Now carry out fits with gradients constrained to be +/- c
02862   double CTIntercept[2]; double Csigma[2]; double Ctrunc[2]; 
02863   double ChiSqPositive=-999; double ChiSqNegative=-999; 
02864   int ChiSqNdfPos=-999; int ChiSqNdfNeg=-999;  
02865   double Swtt[2]; double Swt[2]; double Sw[2]; int npts[2]={0,0};
02866 
02867   if(Sq!=0.) {
02868     CTIntercept[0]=Sqt/Sq; Csigma[0]=-99999.9; Ctrunc[0]=-99999.9;
02869     CTIntercept[1]=Sqt/Sq; Csigma[1]=-99999.9; Ctrunc[1]=-99999.9;
02870     
02871     for(int itr=0; itr<2; ++itr)
02872       {
02873         Swtt[0]=0.; Swt[0]=0.; Sw[0]=0.; npts[0]=0;
02874         Swtt[1]=0.; Swt[1]=0.; Sw[1]=0.; npts[1]=0;
02875         
02876         for(int i=0; i<490; ++i)
02877           {
02878             // For positive strip ends
02879             if(Qp[i]>0. && CTp[i]>MinCT) {
02880               q=Qp[i]; 
02881 
02882               if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02883               else {Uncertainty=MinUncertainty;}
02884               w = 1.0/pow(Uncertainty,2.0);
02885 
02886               t=CTp[i]-dS[i]+CTIntercept[0];
02887               if(Ctrunc[0]<0. || fabs(t)<Ctrunc[0]) {Swtt[0]+=w*t*t; Swt[0]+=w*t; Sw[0]+=w; ++npts[0];}
02888               
02889               t=CTp[i]+dS[i]+CTIntercept[1];
02890               if(Ctrunc[1]<0. || fabs(t)<Ctrunc[1]) {Swtt[1]+=w*t*t; Swt[1]+=w*t; Sw[1]+=w; ++npts[1];}
02891             }
02892             
02893             // For negative strip ends
02894             if(Qm[i]>0. && CTm[i]>MinCT) {
02895               q=Qm[i]; 
02896 
02897               if (q<25) {Uncertainty = ErrorParam[0]+exp(ErrorParam[1]+ErrorParam[2]*q);}
02898               else {Uncertainty=MinUncertainty;}
02899               w = 1.0/pow(Uncertainty,2.0);
02900 
02901               t=CTm[i]-dS[i]+CTIntercept[0];
02902               if(Ctrunc[0]<0. || fabs(t)<Ctrunc[0]) {Swtt[0]+=w*t*t; Swt[0]+=w*t; Sw[0]+=w; ++npts[0];}
02903               
02904               t=CTm[i]+dS[i]+CTIntercept[1];
02905               if(Ctrunc[1]<0. || fabs(t)<Ctrunc[1]) {Swtt[1]+=w*t*t; Swt[1]+=w*t; Sw[1]+=w; ++npts[1];}
02906             }
02907           }
02908         
02909         // Results for fit with gradient +C
02910         if(npts[0]>1 && Sw[0]!=0.) {
02911           CTIntercept[0]=CTIntercept[0]-Swt[0]/Sw[0]; Csigma[0]=0.; 
02912           if((Swtt[0]/Sw[0])-(Swt[0]/Sw[0])*(Swt[0]/Sw[0])>0.) {Csigma[0]=pow((Swtt[0]/Sw[0])-(Swt[0]/Sw[0])*(Swt[0]/Sw[0]),0.5);}
02913           ChiSqPositive=Csigma[0]; ChiSqNdfPos=npts[0]-1; 
02914           Ctrunc[0]=Csigma[0]+3.;
02915         }
02916         
02917         // Results for fit with gradient -C
02918         if(npts[1]>1 && Sw[1]!=0.) {
02919           CTIntercept[1]=CTIntercept[1]-Swt[1]/Sw[1]; Csigma[1]=0.;
02920           if((Swtt[1]/Sw[1])-(Swt[1]/Sw[1])*(Swt[1]/Sw[1])>0.) {Csigma[1]=pow((Swtt[1]/Sw[1])-(Swt[1]/Sw[1])*(Swt[1]/Sw[1]),0.5);}
02921           ChiSqNegative=Csigma[1]; ChiSqNdfNeg=npts[1]-1; 
02922           Ctrunc[1]=Csigma[1]+3.;
02923         }
02924         
02925       }
02926   }
02927   // Set these properties
02928   cth.SetTimeForwardFitRMS(ChiSqPositive);
02929   cth.SetTimeForwardFitNDOF(ChiSqNdfPos);
02930   cth.SetTimeBackwardFitRMS(ChiSqNegative);
02931   cth.SetTimeBackwardFitNDOF(ChiSqNdfNeg);
02933    
02934 }
02936 
02937 
02938 
02940 void AlgFitTrackCam::SetRangeAnddS(CandFitTrackCamHandle& cth)
02941 {
02942 
02943   // Set range and dS as calculated by the swimmer
02944   MSG("AlgFitTrackCam",Msg::kSynopsis) <<  "SetRangeAnddS from swimmer values between " << MinPlane << "/" << MaxPlane << endl;
02945 
02946   UgliGeomHandle ugh = UgliGeomHandle(*vldc);
02947 
02948   int ZDir; int VtxPlane; int EndPlane; int Increment;
02949   Detector::Detector_t detector = vldc->GetDetector();
02950   double dS; double dRange; double dP;
02951 
02952 
02953   // Start at the end of the track and calculate the required additions to range
02955 
02956   // find ending Z position (defined as Z position where muon has 100 MeV of residual energy.  This corresponds to 1/2 inch of Fe.
02957 
02958   // NOTE: Average dP for 1" iron is 95 MeV.
02959  
02960   if(ZIncreasesWithTime==true) {ZDir=1; EndPlane=MaxPlane; VtxPlane=MinPlane; Increment=-1;}
02961   else {ZDir=-1; EndPlane=MinPlane; VtxPlane=MaxPlane; Increment=1;}
02962 
02963   PlexPlaneId plnid(detector,EndPlane,false);
02964   PlexPlaneId endplnid(detector,EndPlane,false);
02965 
02966   double Zscint = SlcStripData[EndPlane][0].csh->GetZPos();
02967   double Znextscint = Zscint;
02968 
02969   UgliScintPlnHandle scintpln = ugh.GetScintPlnHandle(plnid); 
02970   double Zend = Zscint + double(ZDir)*scintpln.GetHalfThickness();
02971 
02972   PlexPlaneId nextscint =  endplnid.GetAdjoinScint(ZDir);
02973   UgliScintPlnHandle nextscintpln = ugh.GetScintPlnHandle(nextscint);
02974   if(nextscintpln.IsValid() && nextscint.GetPlaneView()!=PlaneView::kUnknown){
02975     Znextscint = nextscintpln.GetZ0();
02976   }
02977   else{
02978     nextscint = endplnid;
02979   }
02980 
02981   plnid = plnid.GetAdjoinSteel(ZDir);
02982   if(plnid.IsValid()){
02983     UgliSteelPlnHandle steelpln = ugh.GetSteelPlnHandle(plnid);
02984     Zend = steelpln.GetZ0() - double(ZDir)*steelpln.GetHalfThickness();
02985   }
02986 
02987   // add two planes of steel for the ND spectrometer
02988   if(detector==Detector::kNear && EndPlane>=121) {
02989     for(int i=0;i<2;i++){
02990       if(plnid.GetAdjoinSteel(ZDir).IsValid()){
02991         PlexPlaneId plnid_after = plnid.GetAdjoinSteel(ZDir);
02992         if(plnid_after.IsValid()) {
02993           plnid = plnid_after;
02994           UgliSteelPlnHandle steelpln = ugh.GetSteelPlnHandle(plnid);
02995           Zend = steelpln.GetZ0() - double(ZDir)*steelpln.GetHalfThickness();
02996         }
02997       }
02998     }
02999   }
03000 
03001   // Determine whether track stops in coil
03002   float u_end = FilteredData[EndPlane][0].x_k0;
03003   float v_end = FilteredData[EndPlane][0].x_k1;
03004   float du_end = FilteredData[EndPlane][0].x_k2;
03005   float dv_end = FilteredData[EndPlane][0].x_k3;
03006   float delz = Znextscint-Zscint;
03007   float u_extrap = u_end +delz*du_end;
03008   float v_extrap = v_end +delz*dv_end;
03009   float x_extrap = 0.707*(u_extrap-v_extrap);
03010   float y_extrap = 0.707*(u_extrap+v_extrap);
03011 
03012   PlaneCoverage::PlaneCoverage_t kPC = PlaneCoverage::kComplete;
03013   if(detector==Detector::kNear) kPC=PlaneCoverage::kNearFull;
03014 
03015   bool isInOutline = fPL.IsInside(x_extrap,y_extrap,nextscint.GetPlaneView(),kPC,false);
03016   bool isInCoil = isInOutline && !fPL.IsInside(x_extrap,y_extrap,nextscint.GetPlaneView(),kPC,true);
03017 
03018   double S = 0; double Range = 0; double Prange = 0.0;
03019   double StateVector[5]; double Output[5];
03020   double chargesign = -1;
03021   bool GoForward = true; bool done=true; bool swimOK=true;
03022 
03023   // if in coil find midpoint and swim towards last hit from there
03024   if(isInCoil){
03025     float zCoil = Znextscint;
03026     float u_extrapC = u_extrap;
03027     float v_extrapC = v_extrap;
03028     float x_extrapC = x_extrap;
03029     float y_extrapC = y_extrap;
03030     while(isInCoil){
03031       zCoil -= 1.0*Munits::cm*ZDir;
03032       float delzC = zCoil - Zscint;
03033       u_extrapC = u_end +delzC*du_end;
03034       v_extrapC = v_end +delzC*dv_end;
03035       x_extrapC = 0.707*(u_extrapC-v_extrapC);
03036       y_extrapC = 0.707*(u_extrapC+v_extrapC);
03037       isInCoil = !fPL.IsInside(x_extrapC,y_extrapC,nextscint.GetPlaneView(),kPC,true) && ((zCoil>Zscint && ZDir==1) || (zCoil<Zscint && ZDir==-1)) ;        
03038     }
03039     float zMinCoil = zCoil;
03040     if(zMinCoil<Zscint && ZDir==1)  zMinCoil=Zscint;
03041     if(zMinCoil>Zscint && ZDir==-1) zMinCoil=Zscint;
03042 
03043     zCoil = Znextscint;
03044     isInCoil = true;
03045     while(isInCoil){
03046       zCoil += 1.0*Munits::cm*ZDir;
03047       float delzC = zCoil - Zscint;
03048       u_extrapC = u_end +delzC*du_end;
03049       v_extrapC = v_end +delzC*dv_end;
03050       x_extrapC = 0.707*(u_extrapC-v_extrapC);
03051       y_extrapC = 0.707*(u_extrapC+v_extrapC);
03052       float zmin; float zmax;
03053       ugh.GetZExtent(zmin,zmax);
03054       isInCoil = !fPL.IsInside(x_extrapC,y_extrapC,nextscint.GetPlaneView(),kPC,true) && ((zCoil<zmax && ZDir==1) || (zCoil>zmin && ZDir==-1));        
03055     }
03056     float zMaxCoil = zCoil;
03057     float zmin; float zmax;
03058     ugh.GetZExtent(zmin,zmax);
03059     if(zMaxCoil>zmax && ZDir==1)  zMaxCoil=zmax;
03060     if(zMaxCoil<zmin && ZDir==-1) zMaxCoil=zmin;
03061 
03062     // now swim from mid-coil back to endplane
03063     float zMidCoil = 0.5*(zMinCoil + zMaxCoil);
03064     float delzC  = zMidCoil -Zscint;
03065     u_extrapC = u_end +delzC*du_end;
03066     v_extrapC = v_end +delzC*dv_end;
03067     x_extrapC = 0.707*(u_extrapC-v_extrapC);
03068     y_extrapC = 0.707*(u_extrapC+v_extrapC);
03069     
03070     StateVector[0] = u_extrapC; Output[0]=StateVector[0];
03071     StateVector[1] = v_extrapC; Output[1]=StateVector[1];
03072     StateVector[2] = FilteredData[EndPlane][0].x_k2; Output[2]=StateVector[2];
03073     StateVector[3] = FilteredData[EndPlane][0].x_k3; Output[3]=StateVector[3];
03074     chargesign = -1;
03075     if(FilteredData[EndPlane][0].x_k4!=0.) {chargesign =  FilteredData[EndPlane][0].x_k4/fabs(FilteredData[EndPlane][0].x_k4);}
03076     
03077     GoForward = !ZIncreasesWithTime;
03078     StateVector[4] = 10.*chargesign; Output[4]=StateVector[4]; 
03079 
03080     double dsdz = pow((1. + pow(StateVector[2],2) + pow(StateVector[3],2)),0.5);    
03081     // set fallback to nominal energy loss in case coil swim fails
03082     Prange = 0.095*dsdz;
03083     if(detector==Detector::kNear && EndPlane>121) Prange = 0.2*dsdz;  
03084     Prange += 0.5*dsdz*0.1*fabs(zMaxCoil-zMinCoil)*2.357*1.97;
03085 
03086     swimOK = Swim(StateVector, Output, zMidCoil, EndPlane , GoForward, &dS, &dRange, &dP);
03087    
03088     if(swimOK ){
03089       S = dS; Range = dRange; Prange = fabs(dP);
03090       cth.SetdS(EndPlane,S); 
03091       cth.SetRange(EndPlane,Range);
03092     }
03093     if(!swimOK) {Output[4] = chargesign/Prange;}
03094   
03095   }
03096 
03097   else{
03098     // normal case - track does not end in coil
03099     if((Zend<Zscint && ZDir==1) || (Zend>Zscint && ZDir==-1)) {
03100       MSG("AlgFitTrackCam",Msg::kWarning) << " Zend on wrong side of last scint! " << endl;
03101       Zend=Zscint;
03102     }
03103     
03104     // now swim to Zend
03105     StateVector[0]=FilteredData[EndPlane][0].x_k0; Output[0]=StateVector[0];
03106     StateVector[1]=FilteredData[EndPlane][0].x_k1; Output[1]=StateVector[1];
03107     StateVector[2]=FilteredData[EndPlane][0].x_k2; Output[2]=StateVector[2];
03108     StateVector[3]=FilteredData[EndPlane][0].x_k3; Output[3]=StateVector[3];
03109     StateVector[4]=FilteredData[EndPlane][0].x_k4; Output[4]=StateVector[4];
03110     chargesign = -1;
03111     if(StateVector[4]!=0.) {chargesign = StateVector[4]/fabs(StateVector[4]);}
03112     
03113     GoForward = ZIncreasesWithTime;
03114     done = Swim(StateVector, Output, EndPlane, Zend, GoForward,  &dS, &dRange, &dP);
03115     
03116     GoForward = !ZIncreasesWithTime;
03117     double dsdz = pow((1. + pow(StateVector[2],2) + pow(StateVector[3],2)),0.5); 
03118     S = 0; Range = 10.0*dsdz; Prange = 0.095*dsdz;
03119     swimOK = false;
03120     if(done){
03121       for(int j=0;j<5;j++) {StateVector[j]=Output[j];}
03122       
03123       // now swim from Zend to EndPlane
03124       StateVector[4] = chargesign * 10.52;  // start @ P = 100 MeV (Eloss in 1/2 " Iron)
03125       swimOK = Swim(StateVector, Output, Zend, EndPlane , GoForward, &dS, &dRange, &dP);
03126       if(swimOK){
03127         S += dS; Range += dRange; Prange += fabs(dP);
03128         cth.SetdS(EndPlane,S); 
03129         cth.SetRange(EndPlane,Range);
03130       }
03131     }
03132     if(!swimOK) {Output[4] = chargesign/Prange;}
03133   }
03134   
03135   int thisplane = EndPlane;
03136   // now swim back to vertex
03137   bool firstplane=true;
03138  for(int i=EndPlane+Increment; Increment*i<=Increment*VtxPlane; i+=Increment) {
03139     if(FilteredData[i].size()>0) {
03140       double delU = FilteredData[i][0].x_k0 - StateVector[0] ;
03141       double delV = FilteredData[i][0].x_k1 - StateVector[1] ;
03142       double dSperPlane=0.;
03143       if(thisplane!=i) {dSperPlane = pow(delU*delU + delV*delV,0.5)/double(abs(thisplane-i));}
03144 
03145       // only update state vector if change in U/V is reasonable.
03146       if(dSperPlane < 1.5*Munits::m) {
03147         StateVector[0]=FilteredData[i][0].x_k0;
03148         StateVector[1]=FilteredData[i][0].x_k1;
03149         StateVector[2]=FilteredData[i][0].x_k2;
03150         StateVector[3]=FilteredData[i][0].x_k3;
03151 
03152         chargesign=-1;
03153         if(FilteredData[i][0].x_k4!=0.) {chargesign = FilteredData[i][0].x_k4/fabs(FilteredData[i][0].x_k4);}
03154       }
03155 
03156       StateVector[4] = chargesign * fabs(Output[4]);
03157       done = Swim(StateVector, Output, thisplane, i , GoForward, &dS, &dRange, &dP);
03158       if(done){
03159         S+=dS; Range+=dRange; Prange+=fabs(dP);
03160         cth.SetdS(i,S); cth.SetRange(i,Range);
03161         firstplane=false;
03162       }
03163       else {
03164         MSG("AlgFitTrackCam",Msg::kDebug) << " swim fail " << endl;
03165       }
03166       thisplane=i;
03167     }
03168   }
03169 
03170   PlexPlaneId vtxplnid(detector,VtxPlane,false);
03171   PlexPlaneId plnid_before = vtxplnid.GetAdjoinSteel(-ZDir);
03172   
03173   if(plnid_before.IsValid()) {
03174     plnid = plnid_before;
03175     UgliSteelPlnHandle steelpln = ugh.GetSteelPlnHandle(plnid);
03176     double Zstart = steelpln.GetZ0();
03177     StateVector[0]=FilteredData[VtxPlane][0].x_k0;
03178     StateVector[1]=FilteredData[VtxPlane][0].x_k1;
03179     StateVector[2]=FilteredData[VtxPlane][0].x_k2;
03180     StateVector[3]=FilteredData[VtxPlane][0].x_k3;
03181     StateVector[4]=Output[4];
03182     Swim(StateVector, Output, VtxPlane, Zstart, GoForward, &dS,&dRange,&dP);
03183     S+=dS; Range+=dRange; Prange+=fabs(dP);
03184 
03185     cth.SetRange(VtxPlane,Range);
03186     cth.SetdS(VtxPlane,S);
03187   }
03188 
03189   // if Prange < 21 GeV, use this value.  Otherwise, use finder track energy, which is somewhat less prone to gross errors.
03190  
03191   // apply fudge factor for nominal steel thickness in ND geometry.
03192   //********* !!!!!!!!!!!!! ***********
03193   float ecorr = 1.0;
03194  if(vldc->GetDetector()==Detector::kNear && vldc->GetSimFlag()==SimFlag::kData) ecorr = 1.008; 
03195   
03196   cth.SetMomentumRange(Prange*ecorr);
03197   CandTrackHandle* findertrack = cth.GetFinderTrack();
03198   if(((detector==Detector::kFar && Prange>21.) || (detector==Detector::kNear && Prange>12.)) && findertrack) {cth.SetMomentumRange(findertrack->GetMomentum());}
03199 }
03201 
03202 
03203 
03205 void AlgFitTrackCam::SetPropertiesFromFinderTrack(CandFitTrackCamHandle &cth)
03206 {
03207   // This method is only called if the fit fails. We set properties from finder track.
03208   // This clearly does not include fitted properties such as q/p or QPVtxError.
03209  MSG("AlgFitTrackCam",Msg::kSynopsis) << "SetPropertiesFromFinderTrack" << endl;
03210   cth.SetDirCosU(track->GetDirCosU());
03211   cth.SetDirCosV(track->GetDirCosV());
03212   cth.SetDirCosZ(track->GetDirCosZ());
03213   cth.SetVtxU(track->GetVtxU());
03214   cth.SetVtxV(track->GetVtxV());
03215   cth.SetVtxZ(track->GetVtxZ());
03216   cth.SetVtxT(track->GetVtxT());
03217   cth.SetVtxPlane(track->GetVtxPlane());
03218 
03219   cth.SetEndDirCosU(track->GetEndDirCosU());
03220   cth.SetEndDirCosV(track->GetEndDirCosV());
03221   cth.SetEndDirCosZ(track->GetEndDirCosZ());
03222   cth.SetEndU(track->GetEndU());
03223   cth.SetEndV(track->GetEndV());
03224   cth.SetEndZ(track->GetEndZ());
03225   cth.SetEndT(track->GetEndT());
03226   cth.SetEndPlane(track->GetEndPlane());
03227 
03228   cth.SetMomentumRange(track->GetMomentum());
03229   cth.SetMomentum(track->GetMomentum());
03230 
03231   cth.SetTimeSlope(track->GetTimeSlope());
03232   cth.SetTimeOffset(track->GetTimeOffset());
03233   cth.SetTimeFitChi2(track->GetTimeFitChi2());
03234   cth.SetNTimeFitDigit(track->GetNTimeFitDigit());
03235   cth.SetTimeForwardFitRMS(track->GetTimeForwardFitRMS());
03236   cth.SetTimeForwardFitNDOF(track->GetTimeForwardFitNDOF());
03237   cth.SetTimeBackwardFitRMS(track->GetTimeBackwardFitRMS());
03238   cth.SetTimeBackwardFitNDOF(track->GetTimeBackwardFitNDOF());
03239 
03240 
03241   // Set quantities required at each plane in finder track
03242   int direction=1;
03243   if(ZIncreasesWithTime==false) {direction=-1;}
03244 
03245   for(int i=cth.GetVtxPlane(); i*direction<=cth.GetEndPlane()*direction; i+=direction){
03246     if(track->IsTPosValid(i)) {
03247       cth.SetTrackPointError(i,track->GetTrackPointError(i));
03248       cth.SetdS(i,track->GetdS(i));
03249       cth.SetRange(i,track->GetRange(i));
03250       cth.SetU(i,track->GetU(i));
03251       cth.SetV(i,track->GetV(i));
03252     }
03253   }
03254 
03255   CalculateTrace(cth);  
03256   SetT(&cth);
03257 
03258   Calibrator& cal = Calibrator::Instance();
03259   cal.ReInitialise(*vldc);
03260   Calibrate(&cth);
03261 
03262 
03263 }
03265 
03266 
03267 
03268 
03270 void AlgFitTrackCam::GenerateNDSpectStrips(const CandSliceHandle *slice,CandContext &cx)
03271 {
03272   MSG("AlgFitTrackCam",Msg::kDebug) << "GenerateNDSpectStrips" << endl;
03273 
03274   bool AlreadyAssigned;
03275 
03276 
03277   CandContext cxx(this,cx.GetMom());
03278 
03279   // Get singleton instance of AlgFactory
03280   AlgFactory &af = AlgFactory::GetInstance();
03281   AlgHandle stripah = af.GetAlgHandle("AlgStripSR","default");
03282 
03283   // Store CandStripHandles and make the strips accessible by plane number
03284   TIter SlcStripItr = slice->GetDaughterIterator();
03285   StripStruct temp;
03286   
03287   // Store all strips in slice
03288   while(CandStripHandle* SlcStrip = dynamic_cast<CandStripHandle*>(SlcStripItr()))  {
03289     if (SlcStrip->GetPlane()>120 && (SlcStrip->GetPlaneView()==PlaneView::kU || SlcStrip->GetPlaneView()==PlaneView::kV) ) {
03290       AlreadyAssigned=false;
03291       
03292       TIter digitItr(SlcStrip->GetDaughterIterator());
03293       CandDigitHandle* dig = dynamic_cast<CandDigitHandle*>(digitItr());              
03294       const PlexSEIdAltL& altl = dig->GetPlexSEIdAltL();
03295       int siz = altl.size();
03296       
03297       for (int ind = 0; ind<siz; ++ind) {
03298         // Only want to make the single copy of an assigned strip
03299         if(AlreadyAssigned) {break;}
03300         
03301         TObjArray diglist;  
03302         TIter newstripdauItr(SlcStrip->GetDaughterIterator());
03303         
03304         while(CandDigitHandle* olddig = dynamic_cast<CandDigitHandle*>(newstripdauItr())) {
03305           CandDigitHandle* newdig = olddig->DupHandle();
03306           PlexSEIdAltL& newaltl = newdig->GetPlexSEIdAltLWritable(); 
03307           
03308           // Don't make any strips which have already been assigned to a 'better' track
03309           if(NumFinderStrips<=newaltl.GetBestWeight()) {AlreadyAssigned=true; delete newdig;}
03310           else {
03311             for (int newind = 0; newind < siz; ++newind) {
03312               if(newind==ind){newaltl[newind].SetWeight((float)NumFinderStrips);}
03313               else{newaltl[newind].SetWeight((float)0.);}
03314             }
03315             
03316             newdig->SetCandRecord(olddig->GetCandRecord());
03317             diglist.Add(newdig);   // diglist does not own newdig. These must be explicitly deleted 
03318           }
03319         
03320         }
03321         // Only make a new strip if we have any digits  
03322         if(1+diglist.GetLast()>0) {
03323           cxx.SetDataIn(&diglist);
03324           CandStripHandle newstrip = CandStrip::MakeCandidate(stripah,cxx);
03325           newstrip.SetCandRecord(slice->GetCandRecord());
03326           CandStripHandle* daustrip = new CandStripHandle(newstrip);
03327           
03328           for (int i=0; i<=diglist.GetLast(); ++i) {
03329             CandDigitHandle* deldig =  dynamic_cast<CandDigitHandle*>(diglist.At(i));
03330             delete deldig;
03331           }
03332           temp.csh=daustrip;      
03333           SlcStripData[SlcStrip->GetPlane()].push_back(temp);
03334         }
03335       }
03336     }
03337   }
03338   SlcStripItr.Reset();
03339 }
03340 
03342 
03343 
03344 
03346 void AlgFitTrackCam::SpectrometerSwim(CandFitTrackCamHandle &cth)
03347 {
03348   MSG("AlgFitTrackCam",Msg::kDebug) << "SpectrometerSwim, improved track finding in spectrometer" << endl;
03349 
03350   // Initialisations
03351   // Sort out the lists for the ND spectrometer
03352   bool AddedStrip = false;
03353   int Plane; int NewPlane;
03354   double StateVector[5]; double NState[5]; double temp_x_k[5];
03355   bool GoForward; bool SpectSwim;
03356   int ActivePlanesSinceLastHit=0;
03357   int PlaneView; int Increment; int Counter;
03358   double LastHitTimes[2]={MeanTrackTime,MeanTrackTime};
03359   double TimeWindow=40.e-9;
03360 
03361   double StripDistance; double MinDistanceToStrip;
03362   double SwimError2;
03363   double StripWidth = 4.108e-2;
03364   double PlanePitch = 0.0594;
03365 
03366   bool TrackInActiveRegion;
03367   GoForward=true; Plane=MaxPlane; Increment=1;
03368 
03369   // Linear extrapolation from end of track to start of spectrometer.
03370   // Count number of active planes  
03371   while(ActivePlanesSinceLastHit<6 && Plane<121) {
03372     Plane += Increment;
03373     double u = x_k_minus[0] + x_k_minus[2]*(Plane-MaxPlane)*PlanePitch;
03374     double v = x_k_minus[1] + x_k_minus[3]*(Plane-MaxPlane)*PlanePitch;
03375 
03376     // 15 Feb 2008 - mitigate symptoms of a problem elsewhere - huge u and v can cause crash.
03377     if(fabs(u) > 5000 || fabs(v) > 5000){
03378       MSG("AlgFitTrackCam", Msg::kError) << "SpectrometerSwim - unexpectedly large u or v (u="
03379                                          << u << " v=" << v << ") bailing out." << endl;
03380       return;
03381     }
03382 
03383     if (NDPlaneIsActive(Plane, u, v, 0.3)) ActivePlanesSinceLastHit++;
03384   }
03385 
03386   // If we are clearly not near spectrometer, return from method
03387   if(ActivePlanesSinceLastHit>5 || abs(121-MaxPlane)>=40) {return;}
03388 
03389   // Set initial positions for swim
03390   ActivePlanesSinceLastHit=0;
03391   Plane = MaxPlane;  NewPlane = Plane+1;
03392 
03393   // Continue until we reach a 8 plane gap (counting only active planes) since prior
03394   // hit or we reach the end of the detector
03395   while(ActivePlanesSinceLastHit<8 && abs(NewPlane-Plane)<=70 && NewPlane<=290 && PassTrack==true) {
03396     
03397     PlexPlaneId plexPlane(Detector::kNear,NewPlane, 0); 
03398     if(SlcStripData[NewPlane].size()>0 && plexPlane.IsValid() && plexPlane.GetPlaneCoverage()!=PlaneCoverage::kNoActive) {
03399 
03400       if(SlcStripData[NewPlane][0].csh->GetPlaneView()==2) {PlaneView=0;}
03401       else {PlaneView=1;}
03402       
03403       for(int i=0; i<5; ++i) {StateVector[i]=x_k_minus[i];}
03404 
03405       // For the purposes of spectrometer track hit finding, don't allow track to range out before
03406       // we have swum all the hit spectrometer planes in this slice
03407       SpectSwim = Swim(StateVector, NState, Plane, NewPlane, GoForward);
03408 
03409       // If swim has failed and there is a large gap to next hit plane, stop the spectrometer swim.
03410       if(!SpectSwim && (NewPlane-Plane)>=40) {
03411         break;}
03412 
03413       // If swim has failed, but there is no large gap, make a momentum correction and swim again.
03414       if(!SpectSwim && StateVector[4]!=0) {
03415         Counter=0;
03416         // Double momentum and attempt to swim again
03417         while(!SpectSwim && Counter<2) {
03418           StateVector[4]*=0.5;  
03419           SpectSwim = Swim(StateVector, NState, Plane, NewPlane, GoForward);
03420           
03421           if(!SpectSwim) {Counter++;}
03422         }
03423       }
03424       
03425       if(!SpectSwim) {break;}
03426 
03427       for(int i=0; i<5; ++i) {temp_x_k[i]=NState[i];}
03428 
03429       // Calculate error in track extrapolation, based on covariance matrix on-diagonal elements
03430       SwimError2 = C_k[PlaneView][PlaneView] + (C_k[PlaneView+2][PlaneView+2]*PlanePitch*PlanePitch*(NewPlane-Plane)*(NewPlane-Plane)); 
03431       MinDistanceToStrip = 3.0 * pow(StripWidth*StripWidth + SwimError2,0.5);
03432       
03433 
03434       // Find the closest strip (within a distance 'MinDistanceToStrip') and temporarily store CandStripHandle
03435       CandStripHandle* CurrentStrip = 0;      
03436       for(unsigned int j=0; j<SlcStripData[NewPlane].size(); ++j) {
03437         StripDistance = fabs(SlcStripData[NewPlane][j].csh->GetTPos()-temp_x_k[PlaneView]);
03438 
03439         if(StripDistance<MinDistanceToStrip 
03440            && fabs(0.5*(LastHitTimes[0]+LastHitTimes[1])-NDStripBegTime(SlcStripData[NewPlane][j].csh,temp_x_k[0],temp_x_k[1]))<TimeWindow) {
03441           MinDistanceToStrip=StripDistance;
03442           CurrentStrip=SlcStripData[NewPlane][j].csh;
03443         }
03444       }
03445 
03446       // If we find a likely track strip, add it to the fit data and call the Kalman
03447       // update equations before repeating process to find next track strips in the shower
03448       if(CurrentStrip) {
03449         LastHitTimes[1]=LastHitTimes[0];
03450         LastHitTimes[0]=NDStripBegTime(CurrentStrip,temp_x_k[0],temp_x_k[1]);
03451 
03452         StripStruct temp;
03453         temp.csh = CurrentStrip;
03454         InitTrkStripData[NewPlane].push_back(temp);
03455         
03456         // Convert the strip to data required for Kalman fit
03457         GetFitData(NewPlane,NewPlane);
03458         
03459         // Carry out the Kalman fit
03460         if (PlaneView==1) {H_k[0]=0; H_k[1]=1; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
03461         else {H_k[0]=1; H_k[1]=0; H_k[2]=0; H_k[3]=0; H_k[4]=0;}
03462         
03463         bool CombiPropagatorOk = GetCombiPropagator(Plane,NewPlane,GoForward);
03464 
03465         if(CombiPropagatorOk) {
03466           GetNoiseMatrix(Plane,NewPlane);
03467           ExtrapCovMatrix();
03468           CalcKalmanGain(NewPlane);
03469           UpdateStateVector(Plane,NewPlane,GoForward);
03470           UpdateCovMatrix();
03471           MoveArrays();
03472           StoreFilteredData(NewPlane);
03473           
03474           MaxPlane=NewPlane; Plane=MaxPlane;
03475           NewPlane=Plane+Increment;
03476           
03477           ActivePlanesSinceLastHit=0;
03478         }
03479 
03480         // Extend finder track, including the ND Spectrometer hits found in the fit
03482 
03483        
03484         CandTrackHandle * findertrack = cth.GetFinderTrack();
03485         if(findertrack) {
03486           bool SlushyOnEntry = CandHandle::IsSlushyEnabled();
03487           CandHandle::SetSlushyEnabled(kTRUE);
03488           AddedStrip = true;
03489           findertrack->AddDaughterLink(*CurrentStrip);
03490           findertrack->SetEndPlane(CurrentStrip->GetPlane());
03491           findertrack->SetEndZ(CurrentStrip->GetZPos());
03492           findertrack->SetEndU(FilteredData[CurrentStrip->GetPlane()][0].x_k0);
03493           findertrack->SetEndV(FilteredData[CurrentStrip->GetPlane()][0].x_k1);
03494           double dsdz = sqrt(1+pow(FilteredData[CurrentStrip->GetPlane()][0].x_k2,2)+pow(FilteredData[CurrentStrip->GetPlane()][0].x_k3,2));
03495           if(!ZIncreasesWithTime) dsdz=-dsdz;
03496           findertrack->SetEndDirCosU(FilteredData[CurrentStrip->GetPlane()][0].x_k2/dsdz);
03497           findertrack->SetEndDirCosV(FilteredData[CurrentStrip->GetPlane()][0].x_k3/dsdz);
03498           findertrack->SetEndDirCosZ(1/dsdz);
03499           if(!SlushyOnEntry) CandHandle::SetSlushyEnabled(kFALSE);
03500         }
03502         
03503       }
03504       else {
03505         TrackInActiveRegion=NDPlaneIsActive(NewPlane, temp_x_k[0], temp_x_k[1], 0.3);
03506         if(plexPlane.IsValid() && plexPlane.GetPlaneCoverage()!=PlaneCoverage::kNoActive && TrackInActiveRegion) 
03507           {ActivePlanesSinceLastHit++;}
03508         NewPlane+=Increment;
03509       }
03510     }
03511     else {
03512       double u = x_k_minus[0] + x_k_minus[2]*(NewPlane-Plane)*PlanePitch;
03513       double v = x_k_minus[1] + x_k_minus[3]*(NewPlane-Plane)*PlanePitch;
03514       
03515       TrackInActiveRegion=NDPlaneIsActive(NewPlane, u, v, 0.3); 
03516       
03517       if(plexPlane.IsValid() && plexPlane.GetPlaneCoverage()!=PlaneCoverage::kNoActive && TrackInActiveRegion) 
03518         {ActivePlanesSinceLastHit++;}
03519       NewPlane+=Increment; 
03520     }
03521   }
03522 
03523   
03524   // Sort out range and dS for finder track
03526   if(AddedStrip) {
03527     CandTrackHandle * findertrack = cth.GetFinderTrack();
03528     if(findertrack) {
03529       bool SlushyOnEntry = CandHandle::IsSlushyEnabled();
03530       CandHandle::SetSlushyEnabled(kTRUE);
03531       
03532       SetUVZT(findertrack);
03533       Double_t range = findertrack->GetRange();
03534       if (range>0.) {
03535         findertrack->SetMomentum(GetMomFromRange(range));   
03536       }
03537       if(!SlushyOnEntry) CandHandle::SetSlushyEnabled(kFALSE);
03538     }
03539   }
03541   EndofRangePlane=MaxPlane;
03542 }
03544 
03545 
03546 
03548 bool AlgFitTrackCam::NDPlaneIsActive(int plane, float u, float v, float projErr)
03549 { 
03550   // Method to determine whether this u/v position is active
03551 
03552   PlexPlaneId plexPlane(Detector::kNear,plane, 0); 
03553   if(!plexPlane.IsValid()) {return false;}
03554   if(plexPlane.GetPlaneCoverage()==PlaneCoverage::kNoActive) {return false;}
03555   if(projErr<0.3)projErr=0.3;
03556   float x = 0.707*(u-v);
03557   float y = 0.707*(u+v);
03558   float dist,xedge,yedge;
03559   fPL.DistanceToEdge(x, y,
03560                      plexPlane.GetPlaneView(),
03561                      plexPlane.GetPlaneCoverage(),
03562                      dist, xedge, yedge);
03563   bool isInside = fPL.IsInside(x, y,
03564                                plexPlane.GetPlaneView(),
03565                                plexPlane.GetPlaneCoverage());
03566   isInside &= dist>projErr;
03567 
03568   return isInside;
03569 }
03571 
03572 
03573 
03575 void AlgFitTrackCam::CleanNDLists(CandFitTrackHandle &cth,CandContext &cx)
03576 {
03577 
03578 
03579   // Sort out the lists for the ND spectrometer
03580 
03581   // Delete the strip handles created in GenerateNDSpectStrips.
03582   // All strip handles not added to a track daughter list are deleted here.
03584   for(int iplane=121; iplane<=290; ++iplane){
03585     for(unsigned int i=0; i<SlcStripData[iplane].size(); ++i){
03586       CandStripHandle* delstrip = SlcStripData[iplane][i].csh;
03587       delete delstrip; 
03588     }
03589   }
03591 
03592   bool SlushyOnEntry = CandHandle::IsSlushyEnabled();
03593   CandHandle::SetSlushyEnabled(kTRUE);
03594 
03595   // Get DigitList and StripList from CandRecord
03597   const MomNavigator* mom = cx.GetMom();
03598   CandRecord* crec = dynamic_cast<CandRecord *> (mom->GetFragment("CandRecord", "PrimaryCandidateRecord"));
03599 
03600   // DupHandle step added by gmieg.  Must delete StripList and DigitList.
03601   CandStripListHandle* StripListOH = dynamic_cast<CandStripListHandle *>
03602     (crec->FindCandHandle("CandStripListHandle"));
03603   CandStripListHandle* StripList = StripListOH->DupHandle();
03604 
03605   CandDigitListHandle* DigitListOH = dynamic_cast<CandDigitListHandle *>
03606     (crec->FindCandHandle("CandDigitListHandle","canddigitlist"));
03607   CandDigitListHandle* DigitList = DigitListOH->DupHandle();
03608 
03609   CandSliceHandle* Slice = dynamic_cast<CandSliceHandle*>(cth.GetCandSliceWritable());
03611 
03612  
03613   // Compare new fitted track, with DeMuxed spectrometer strips, 
03614   // to StripList, Slice and DigitList
03616   vector<CandStripHandle*> StripsToAdd;
03617   vector<CandStripHandle*> StripsToRemove;
03618 
03619   vector<CandStripHandle*> SliceStripsToAdd;
03620   vector<CandStripHandle*> SliceStripsToRemove;
03621 
03622   vector<CandDigitHandle*> DigitsToAdd;
03623   vector<CandDigitHandle*> DigitsToRemove;
03624 
03625 
03626   CandStripHandleItr TrkStripItr(cth.GetDaughterIterator());
03627   for(CandStripHandle* TrkStrip=TrkStripItr(); TrkStrip; TrkStrip=TrkStripItr()){
03628 
03629     if(TrkStrip->GetPlane()>120 ) {
03630       CandDigitHandleItr TrkDigitItr(TrkStrip->GetDaughterIterator());
03631       CandDigitHandle* TrkDigit = dynamic_cast<CandDigitHandle*>(TrkDigitItr());
03632 
03633       // Sort out StripList
03635       if(StripList) {
03636         bool AddedTrkStrip = false;
03637         CandStripHandleItr stripItr(StripList->GetDaughterIterator());
03638         
03639         for(CandStripHandle* strip=stripItr(); strip ; strip=stripItr()) {
03640           if(strip->GetPlane()==TrkStrip->GetPlane()){
03641             CandDigitHandleItr digitItr(strip->GetDaughterIterator());
03642             CandDigitHandle* digit = dynamic_cast<CandDigitHandle*>(digitItr());
03643             bool SameCandStrip = false;
03644             bool SameHit = false;
03645             
03646             if(TrkStrip->IsEqual(strip)) {SameCandStrip = true;}
03647             
03648             if(digit->GetChannelId()==TrkDigit->GetChannelId() &&
03649                strip->GetCharge(CalDigitType::kNone)==TrkStrip->GetCharge(CalDigitType::kNone))
03650               {SameHit=true;}
03651             
03652             if(!SameCandStrip && SameHit) {
03653               StripsToRemove.push_back(strip);
03654               if(!AddedTrkStrip) {StripsToAdd.push_back(TrkStrip);}
03655               AddedTrkStrip=true;
03656             }
03657           }
03658         }
03659       }
03661       
03662 
03663 
03664       // Sort out Slice
03666       if(Slice){
03667         bool AddedTrkStrip = false;
03668         CandStripHandleItr stripItr(Slice->GetDaughterIterator());
03669 
03670         for(CandStripHandle* strip=stripItr(); strip; strip=stripItr()) {
03671           if(strip->GetPlane()==TrkStrip->GetPlane()){
03672             CandDigitHandleItr digitItr(strip->GetDaughterIterator());
03673             CandDigitHandle* digit = dynamic_cast<CandDigitHandle*>(digitItr());
03674             bool SameCandStrip = false;
03675             bool SameHit = false;
03676 
03677             if(TrkStrip->IsEqual(strip)) {SameCandStrip=true;}
03678 
03679             if(digit->GetChannelId()==TrkDigit->GetChannelId() &&
03680                strip->GetCharge(CalDigitType::kNone)==TrkStrip->GetCharge(CalDigitType::kNone))
03681               {SameHit=true;}
03682 
03683             if(!SameCandStrip && SameHit) {
03684               SliceStripsToRemove.push_back(strip);
03685               if(!AddedTrkStrip) {SliceStripsToAdd.push_back(TrkStrip);}
03686               AddedTrkStrip=true;
03687             }
03688           }
03689         }
03690       }
03692 
03693 
03694       // Loop over track strip Digits, and rationalise DigitList
03696       if(DigitList) {
03697         CandDigitHandleItr TrkDigitItr2(TrkStrip->GetDaughterIterator());
03698         for(TrkDigit=TrkDigitItr2(); TrkDigit ; TrkDigit=TrkDigitItr2()) {
03699           bool AddedTrkDigit=false;
03700           CandDigitHandleItr DigitItr(DigitList->GetDaughterIterator());
03701 
03702           for(CandDigitHandle* digit=DigitItr(); digit; digit=DigitItr()) {
03703             bool SameCandDigit=false;
03704             bool SameHit=false;
03705 
03706             if(TrkDigit->IsEqual(digit)) {SameCandDigit=true;}
03707 
03708             if(digit->GetChannelId()==TrkDigit->GetChannelId() &&
03709                digit->GetCharge(CalDigitType::kNone)==TrkDigit->GetCharge(CalDigitType::kNone))
03710               {SameHit=true;}
03711 
03712             if(!SameCandDigit && SameHit) {
03713               DigitsToRemove.push_back(digit);
03714               if(!AddedTrkDigit) {DigitsToAdd.push_back(TrkDigit);}
03715               AddedTrkDigit=true;
03716             }
03717           }
03718         }
03719       }
03721     
03723     }
03724   } // End loop over track strips
03725 
03726 
03727   // Now make the actual modifications to the lists
03729   for(unsigned int i=0; i<StripsToAdd.size(); ++i) {StripList->AddDaughterLink(*(StripsToAdd[i]));}
03730   for(unsigned int i=0; i<StripsToRemove.size(); ++i) {StripList->RemoveDaughter(StripsToRemove[i]);}
03731   StripsToAdd.clear();
03732   StripsToRemove.clear();
03733 
03734   for(unsigned int i=0; i<SliceStripsToAdd.size(); ++i) {Slice->AddDaughterLink(*(SliceStripsToAdd[i]));}
03735   for(unsigned int i=0; i<SliceStripsToRemove.size(); ++i) {Slice->RemoveDaughter(SliceStripsToRemove[i]);}
03736   SliceStripsToAdd.clear();
03737   SliceStripsToRemove.clear();
03738 
03739   for(unsigned int i=0; i<DigitsToAdd.size(); ++i) {DigitList->AddDaughterLink(*(DigitsToAdd[i]));}
03740   for(unsigned int i=0; i<DigitsToRemove.size(); ++i) {DigitList->RemoveDaughter(DigitsToRemove[i]);}
03741   DigitsToAdd.clear();
03742   DigitsToRemove.clear();
03744 
03745   
03747 
03748   // Must delete DupHandle StripList and Digitlist (gmieg)
03749   delete StripList;
03750   delete DigitList;
03751 
03752   if(!SlushyOnEntry) CandHandle::SetSlushyEnabled(kFALSE); 
03753 }
03755 
03756 
03757 
03759 double AlgFitTrackCam::NDStripBegTime(CandStripHandle* Strip, double U, double V)
03760 {
03761   double BegTime=999; double Time=0;
03762   double Index=1.77; double DistFromCentre=0.; 
03763   double FibreDist=0.; double halfLength=0.;
03764 
03765   // Get from track. Otherwise, will have guessed using Swimmer
03766   if(U==0) {U=track->GetU(Strip->GetPlane());}
03767   if(V==0) {V=track->GetV(Strip->GetPlane());}
03768 
03769   StripEnd::StripEnd_t StpEnd = StripEnd::kUnknown;
03770   CandDigitHandle* digit;
03771   
03772   UgliGeomHandle ugh = UgliGeomHandle(*vldc);
03773   UgliStripHandle Striphandle;
03774 
03775   CandDigitHandleItr digitItr(Strip->GetDaughterIterator());
03776 
03777 
03778   // Loop over digits on Strip. 
03780   while( (digit = digitItr()) ) { 
03781     StpEnd=digit->GetPlexSEIdAltL().GetEnd();
03782     
03783     if(StpEnd==StripEnd::kPositive) {
03784       FibreDist = 0.; DistFromCentre = 0.; Time=0.;
03785       UgliStripHandle StripHandle = ugh.GetStripHandle(Strip->GetStripEndId());
03786       halfLength = StripHandle.GetHalfLength(); 
03787       
03788       if(Strip->GetPlaneView()==2) {DistFromCentre = V;}
03789       if(Strip->GetPlaneView()==3) {DistFromCentre = -U;}
03790               
03791       FibreDist = (halfLength + DistFromCentre + StripHandle.ClearFiber(StpEnd) 
03792                    + StripHandle.WlsPigtail(StpEnd));
03793       
03794       Time = digit->GetSubtractedTime(CalTimeType::kT0) - (Index/3.e8)*FibreDist;
03795 
03796       if(Time<BegTime) {BegTime=Time;}
03797     }
03798   }
03799   
03800   return BegTime;
03801 }
03803 
03804 
03805 
03807 void AlgFitTrackCam::Trace(const char * /* c */) const
03808 {
03809 }

Generated on Mon Feb 15 11:06:18 2010 for loon by  doxygen 1.3.9.1