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

Generated on Mon Nov 23 05:25:56 2009 for loon by  doxygen 1.3.9.1