StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
TrackFitter.h
1 #ifndef TRACK_FITTER_H
2 #define TRACK_FITTER_H
3 
4 #include "GenFit/ConstField.h"
5 #include "GenFit/EventDisplay.h"
6 #include "GenFit/Exception.h"
7 #include "GenFit/FieldManager.h"
8 #include "GenFit/KalmanFitStatus.h"
9 #include "GenFit/GblFitter.h"
10 
11 #include "GenFit/KalmanFitter.h"
12 #include "GenFit/KalmanFitterInfo.h"
13 #include "GenFit/KalmanFitterRefTrack.h"
14 #include "GenFit/MaterialEffects.h"
15 #include "GenFit/PlanarMeasurement.h"
16 #include "GenFit/RKTrackRep.h"
17 #include "GenFit/SpacepointMeasurement.h"
18 #include "GenFit/StateOnPlane.h"
19 #include "GenFit/TGeoMaterialInterface.h"
20 #include "GenFit/Track.h"
21 #include "GenFit/TrackPoint.h"
22 
23 #include "Criteria/SimpleCircle.h"
24 
25 #include "TDatabasePDG.h"
26 #include "TGeoManager.h"
27 #include "TMath.h"
28 #include "TRandom.h"
29 #include "TRandom3.h"
30 #include "TVector3.h"
31 
32 #include <vector>
33 #include <memory>
34 
35 #include "StFwdTrackMaker/Common.h"
36 
37 #include "StFwdTrackMaker/include/Tracker/FwdHit.h"
38 #include "StFwdTrackMaker/include/Tracker/TrackFitter.h"
39 #include "StFwdTrackMaker/include/Tracker/STARField.h"
40 #include "StFwdTrackMaker/include/Tracker/FwdGeomUtils.h"
41 
42 #include "StarGenerator/UTIL/StarRandom.h"
43 
44 /* Cass for fitting tracks(space points) with GenFit
45  *
46  */
47 class TrackFitter {
48 
49 // Accessors and options
50  public:
51  genfit::FitStatus getStatus() { return mFitStatus; }
52  genfit::AbsTrackRep *getTrackRep() { return mTrackRep; }
53  genfit::Track *getTrack() { return mFitTrack; }
54  void setGenerateHistograms( bool gen) { mGenHistograms = gen;}
55 
56 
57  public:
58  // ctor
59  // provide the main configuration object
60  TrackFitter(FwdTrackerConfig _mConfig, TString geoCache) : mConfig(_mConfig), mGeoCache(geoCache) {
61  mTrackRep = 0;
62  mFitTrack = 0;
63  }
64 
65 
66  void setup() {
67 
68  // the geometry manager that GenFit will use
69  TGeoManager * gMan = nullptr;
70 
71  // Setup the Geometry used by GENFIT
72  LOG_INFO << "StFwdTrackMaker is loading the geometry cache: " << mConfig.get<string>("Geometry", mGeoCache.Data()).c_str() << endm;
73  TGeoManager::Import(mConfig.get<string>("Geometry", mGeoCache.Data()).c_str());
74  gMan = gGeoManager;
75  // Set up the material interface and set material effects on/off from the config
76  genfit::MaterialEffects::getInstance()->init(new genfit::TGeoMaterialInterface());
77 
78  // Set Material Stepper debug level
79  genfit::MaterialEffects::getInstance()->setDebugLvl( mConfig.get<int>("TrackFitter.MaterialEffects:DebugLvl", 0) );
80 
81  genfit::MaterialEffects::getInstance()->setEnergyLossBetheBloch( mConfig.get<int>("TrackFitter.MaterialEffects.EnergyLossBetheBloch", true) );
82  genfit::MaterialEffects::getInstance()->setNoiseBetheBloch( mConfig.get<int>("TrackFitter.MaterialEffects.NoiseBetheBloch", true) );
83  genfit::MaterialEffects::getInstance()->setNoiseCoulomb( mConfig.get<int>("TrackFitter.MaterialEffects.NoiseCoulomb", true) );
84  genfit::MaterialEffects::getInstance()->setEnergyLossBrems( mConfig.get<int>("TrackFitter.MaterialEffects.EnergyLossBrems", true) );
85  genfit::MaterialEffects::getInstance()->setNoiseBrems( mConfig.get<int>("TrackFitter.MaterialEffects.NoiseBrems", true) );
86  genfit::MaterialEffects::getInstance()->ignoreBoundariesBetweenEqualMaterials( mConfig.get<int>("TrackFitter.MaterialEffects.ignoreBoundariesBetweenEqualMaterials", true) );
87 
88  // do this last to override
89  genfit::MaterialEffects::getInstance()->setNoEffects( !mConfig.get<bool>("TrackFitter:MaterialEffects", false)); // negated, true means defaul is all effects on (noEffects off)
90  if (!mConfig.get<bool>("TrackFitter:MaterialEffects", false)){
91  LOG_INFO << "Turning OFF GenFit Material Effects in stepper" << endm;
92  }
93 
94  // Determine which Magnetic field to use
95  // Either constant field or real field from StarFieldAdaptor
96  if (mConfig.get<bool>("TrackFitter:constB", false)) {
97  mBField = std::unique_ptr<genfit::AbsBField>(new genfit::ConstField(0., 0., 5.)); // 0.5 T Bz
98  LOG_INFO << "StFwdTrackMaker: Tracking with constant magnetic field" << endl;
99  } else if (mConfig.get<bool>("TrackFitter:zeroB", false)) {
100  mBField = std::unique_ptr<genfit::AbsBField>(new genfit::ConstField(0., 0., 0.)); // ZERO FIELD
101  LOG_INFO << "StFwdTrackMaker: Tracking with ZERO magnetic field" << endl;
102  } else {
103  mBField = std::unique_ptr<genfit::AbsBField>(new StarFieldAdaptor());
104  LOG_INFO << "StFwdTrackMaker: Tracking with StarFieldAdapter" << endl;
105  }
106  // we must have one of the two available fields at this point
107  // note, the pointer is still bound to the lifetime of the TackFitter
108  genfit::FieldManager::getInstance()->init(mBField.get());
109 
110  // initialize the main mFitter using a KalmanFitter with reference tracks
111  mFitter = std::unique_ptr<genfit::AbsKalmanFitter>(new genfit::KalmanFitterRefTrack());
112 
113  // Here we load several options from the config,
114  // to customize the mFitter behavior
115  mFitter->setMaxFailedHits(mConfig.get<int>("TrackFitter.KalmanFitterRefTrack:MaxFailedHits", -1)); // default -1, no limit
116  mFitter->setDebugLvl(mConfig.get<int>("TrackFitter.KalmanFitterRefTrack:DebugLvl", 0)); // default 0, no output
117  mFitter->setMaxIterations(mConfig.get<int>("TrackFitter.KalmanFitterRefTrack:MaxIterations", 4)); // default 4 iterations
118  mFitter->setMinIterations(mConfig.get<int>("TrackFitter.KalmanFitterRefTrack:MinIterations", 0)); // default 0 iterations
119 
120  // FwdGeomUtils looks into the loaded geometry and gets detector z locations if present
121  FwdGeomUtils fwdGeoUtils( gMan );
122 
123  // these default values are the default if the detector is
124  // a) not found in the geometry
125  // b) not provided in config
126 
127  // NOTE: these defaults are needed since the geometry file might not include FST (bug being worked on separately)
128  mFSTZLocations = fwdGeoUtils.fstZ(
129  mConfig.getVector<double>("TrackFitter.Geometry:fst",
130  {140.286011, 154.286011, 168.286011 }
131  // 144.633,158.204,171.271
132  )
133  );
134 
135  if ( fwdGeoUtils.fstZ( 0 ) < 1.0 ) { // returns 0.0 on failure
136  LOG_WARN << "Using FST z-locations from config or defautl, may not match hits" << endm;
137  }
138 
139  const double dzInnerFst = 1.715 + 0.04; // cm relative to "center" of disk + residual...
140  const double dzOuterFst = 0.240 + 0.04; // cm relative to "center" of disk
141 
142  // Now add the Si detector planes at the desired location
143  std::stringstream sstr;
144  sstr << "Adding FST Planes at: ";
145  string delim = "";
146  for (auto z : mFSTZLocations) {
147  mFSTPlanes.push_back(
148  genfit::SharedPlanePtr(
149  // these normals make the planes face along z-axis
150  new genfit::DetPlane(TVector3(0, 0, z), TVector3(1, 0, 0), TVector3(0, 1, 0) )
151  )
152  );
153 
154  // Inner Module FST planes
155  mFSTPlanesInner.push_back(
156  genfit::SharedPlanePtr(
157  // these normals make the planes face along z-axis
158  new genfit::DetPlane(TVector3(0, 0, z - dzInnerFst), TVector3(1, 0, 0), TVector3(0, 1, 0) )
159  )
160  );
161  mFSTPlanesInner.push_back(
162  genfit::SharedPlanePtr(
163  // these normals make the planes face along z-axis
164  new genfit::DetPlane(TVector3(0, 0, z + dzInnerFst), TVector3(1, 0, 0), TVector3(0, 1, 0) )
165  )
166  );
167  // Outer Module FST planes
168  mFSTPlanesOuter.push_back(
169  genfit::SharedPlanePtr(
170  // these normals make the planes face along z-axis
171  new genfit::DetPlane(TVector3(0, 0, z - dzOuterFst), TVector3(1, 0, 0), TVector3(0, 1, 0) )
172  )
173  );
174  mFSTPlanesOuter.push_back(
175  genfit::SharedPlanePtr(
176  // these normals make the planes face along z-axis
177  new genfit::DetPlane(TVector3(0, 0, z + dzOuterFst), TVector3(1, 0, 0), TVector3(0, 1, 0) )
178  )
179  );
180 
181  sstr << delim << z << " (-dzInner=" << z - dzInnerFst << ", +dzInner=" << z+dzInnerFst << ", -dzOuter=" << z - dzOuterFst << ", +dzOuter=" << z + dzOuterFst << ")";
182  delim = ", ";
183  }
184  LOG_DEBUG << sstr.str() << endm;
185 
186  // Now load FTT
187  // mConfig.getVector<>(...) requires a default, hence the
188  mFTTZLocations = fwdGeoUtils.fttZ(
189  mConfig.getVector<double>("TrackFitter.Geometry:ftt", {281.082,304.062,325.058,348.068})
190  );
191 
192  if ( fwdGeoUtils.fttZ( 0 ) < 1.0 ) { // returns 0.0 on failure
193  LOG_WARN << "Using FTT z-locations from config or default, may not match hits" << endm;
194  }
195 
196  if ( mFTTZLocations.size() != 4 ){
197  LOG_ERROR << "Wrong number of FTT layers, got " << mFTTZLocations.size() << " but expected 4" << endm;
198  }
199 
200  sstr.str("");
201  sstr.clear();
202  sstr << "Adding FTT Planes at: ";
203  delim = "";
204  for (auto z : mFTTZLocations) {
205  mFTTPlanes.push_back(
206  genfit::SharedPlanePtr(
207  // these normals make the planes face along z-axis
208  new genfit::DetPlane(TVector3(0, 0, z), TVector3(1, 0, 0), TVector3(0, 1, 0))
209  )
210  );
211  sstr << delim << z;
212  delim = ", ";
213  }
214  LOG_DEBUG << sstr.str() << endm;
215 
216  // get default vertex values used in simulation from the config
217  mVertexSigmaXY = mConfig.get<double>("TrackFitter.Vertex:sigmaXY", 1.0);
218  mVertexSigmaZ = mConfig.get<double>("TrackFitter.Vertex:sigmaZ", 30.0);
219  mVertexPos = mConfig.getVector<double>("TrackFitter.Vertex:pos", {0.0,0.0,0.0});
220  mIncludeVertexInFit = mConfig.get<bool>("TrackFitter.Vertex:includeInFit", false);
221 
222  if ( mGenHistograms )
223  makeHistograms();
224  }
225 
226  void makeHistograms() {
227  std::string n = "";
228  mHist["ECalProjPosXY"] = new TH2F("ECalProjPosXY", ";X;Y", 1000, -500, 500, 1000, -500, 500);
229  mHist["ECalProjSigmaXY"] = new TH2F("ECalProjSigmaXY", ";#sigma_{X};#sigma_{Y}", 50, 0, 0.5, 50, 0, 0.5);
230  mHist["ECalProjSigmaR"] = new TH1F("ECalProjSigmaR", ";#sigma_{XY} (cm) at ECAL", 50, 0, 0.5);
231 
232  mHist["SiProjPosXY"] = new TH2F("SiProjPosXY", ";X;Y", 1000, -500, 500, 1000, -500, 500);
233  mHist["SiProjSigmaXY"] = new TH2F("SiProjSigmaXY", ";#sigma_{X};#sigma_{Y}", 150, 0, 15, 150, 0, 15);
234 
235  mHist["VertexProjPosXY"] = new TH2F("VertexProjPosXY", ";X;Y", 100, -5, 5, 100, -5, 5);
236  mHist["VertexProjSigmaXY"] = new TH2F("VertexProjSigmaXY", ";#sigma_{X};#sigma_{Y}", 150, 0, 20, 150, 0, 20);
237 
238  mHist["VertexProjPosZ"] = new TH1F("VertexProjPosZ", ";Z;", 100, -50, 50);
239  mHist["VertexProjSigmaZ"] = new TH1F("VertexProjSigmaZ", ";#sigma_{Z};", 100, 0, 10);
240 
241  mHist["SiWrongProjPosXY"] = new TH2F("SiWrongProjPosXY", ";X;Y", 1000, -500, 500, 1000, -500, 500);
242  mHist["SiWrongProjSigmaXY"] = new TH2F("SiWrongProjSigmaXY", ";#sigma_{X};#sigma_{Y}", 50, 0, 0.5, 50, 0, 0.5);
243 
244  mHist["SiDeltaProjPosXY"] = new TH2F("SiDeltaProjPosXY", ";X;Y", 1000, 0, 20, 1000, 0, 20);
245 
246  mHist["FstDiffZVsR"] = new TH2F( "FstDiffZVsR", ";R;dz", 400, 0, 40, 500, -5, 5 );
247  mHist["FstDiffZVsPhiSliceInner"] = new TH2F( "FstDiffZVsPhiSliceInner", ";slice;dz", 15, 0, 15, 500, -5, 5 );
248  mHist["FstDiffZVsPhiSliceOuter"] = new TH2F( "FstDiffZVsPhiSliceOuter", ";slice;dz", 15, 0, 15, 500, -5, 5 );
249 
250  mHist["FstDiffZVsPhiOuter"] = new TH2F( "FstDiffZVsPhiOuter", ";slice;dz", 628, 0, TMath::Pi()*2, 500, -5, 5 );
251 
252  mHist["CorrFstDiffZVsPhiSliceInner"] = new TH2F( "CorrFstDiffZVsPhiSliceInner", ";slice;dz", 15, 0, 15, 500, -5, 5 );
253  mHist["CorrFstDiffZVsPhiSliceOuter"] = new TH2F( "CorrFstDiffZVsPhiSliceOuter", ";slice;dz", 15, 0, 15, 500, -5, 5 );
254 
255 
256  n = "seed_curv";
257  mHist[n] = new TH1F(n.c_str(), ";curv", 1000, 0, 10000);
258  n = "seed_pT";
259  mHist[n] = new TH1F(n.c_str(), ";pT (GeV/c)", 500, 0, 10);
260  n = "seed_eta";
261  mHist[n] = new TH1F(n.c_str(), ";eta", 500, 0, 5);
262 
263  n = "delta_fit_seed_pT";
264  mHist[n] = new TH1F(n.c_str(), ";#Delta( fit, seed ) pT (GeV/c)", 500, -5, 5);
265  n = "delta_fit_seed_eta";
266  mHist[n] = new TH1F(n.c_str(), ";#Delta( fit, seed ) eta", 500, 0, 5);
267  n = "delta_fit_seed_phi";
268  mHist[n] = new TH1F(n.c_str(), ";#Delta( fit, seed ) phi", 500, -5, 5);
269 
270  n = "FitStatus";
271  mHist[n] = new TH1F(n.c_str(), ";", 5, 0, 5);
272  FwdTrackerUtils::labelAxis(mHist[n]->GetXaxis(), {"Total", "Pass", "Fail", "GoodCardinal", "Exception"});
273 
274  n = "FitDuration";
275  mHist[n] = new TH1F(n.c_str(), "; Duraton (ms)", 5000, 0, 50000);
276 
277  n = "FailedFitDuration";
278  mHist[n] = new TH1F(n.c_str(), "; Duraton (ms)", 500, 0, 50000);
279  }
280 
281  // writes mHistograms stored in map only if mGenHistograms is true
282  void writeHistograms() {
283  if ( !mGenHistograms )
284  return;
285  for (auto nh : mHist) {
286  nh.second->SetDirectory(gDirectory);
287  nh.second->Write();
288  }
289  }
290 
291  /* Convert the 3x3 covmat to 2x2 by dropping z
292  *
293  */
294  TMatrixDSym CovMatPlane(KiTrack::IHit *h){
295  TMatrixDSym cm(2);
296  cm(0, 0) = static_cast<FwdHit*>(h)->_covmat(0, 0);
297  cm(1, 1) = static_cast<FwdHit*>(h)->_covmat(1, 1);
298  cm(0, 1) = static_cast<FwdHit*>(h)->_covmat(0, 1);
299  return cm;
300  }
301 
302 
303  /* FitSimpleCircle
304  * Used to determine a seed transverse momentum based on space points
305  * Takes a list of space points KiTrack::IHit *
306  * Takes three indecise used to lookup three of the possible hits within the list
307  */
308  float fitSimpleCircle(Seed_t trackCand, size_t i0, size_t i1, size_t i2) {
309  float curv = 0;
310 
311  // ensure that no index is outside of range for FST or FTT volumes
312  if (i0 > 12 || i1 > 12 || i2 > 12)
313  return 0;
314 
315  try {
316  KiTrack::SimpleCircle sc(trackCand[i0]->getX(), trackCand[i0]->getY(), trackCand[i1]->getX(), trackCand[i1]->getY(), trackCand[i2]->getX(), trackCand[i2]->getY());
317  curv = sc.getRadius();
318  } catch (KiTrack::InvalidParameter &e) {
319  // if we got here we failed to get a valid seed. We will still try to move forward but the fit will probably fail
320  }
321 
322  // make sure the curv is valid
323  if (isinf(curv))
324  curv = 999999.9;
325 
326  return curv;
327  }
328 
329  /* seedState
330  * Determines the seed position and momentum for a list of space points
331  */
332  float seedState(Seed_t trackCand, TVector3 &seedPos, TVector3 &seedMom) {
333  // we require at least 4 hits, so this should be gauranteed
334  if(trackCand.size() < 3){
335  // failure
336  return 0.0;
337  }
338 
339 
340  // we want to use the LAST 3 hits, since silicon doesnt have R information
341  TVector3 p0, p1, p2;
342  // use the closest hit to the interaction point for the seed pos
343  FwdHit *hit_closest_to_IP = static_cast<FwdHit *>(trackCand[0]);
344 
345  // maps from <key=vol_id> to <value=index in trackCand>
346  std::map<size_t, size_t> vol_map;
347 
348  // init the map
349  for (size_t i = 0; i < 13; i++)
350  vol_map[i] = -1;
351 
352  for (size_t i = 0; i < trackCand.size(); i++) {
353  auto fwdHit = static_cast<FwdHit *>(trackCand[i]);
354  vol_map[abs(fwdHit->_vid)] = i;
355  // find the hit closest to IP for the initial position seed
356  if (hit_closest_to_IP->getZ() > fwdHit->getZ())
357  hit_closest_to_IP = fwdHit;
358  }
359 
360  // now get an estimate of the pT from several overlapping simple circle fits
361  // enumerate the available partitions
362  // 12 11 10
363  // 12 11 9
364  // 12 10 9
365  // 11 10 9
366  vector<float> curvs;
367  curvs.push_back(fitSimpleCircle(trackCand, vol_map[12], vol_map[11], vol_map[10]));
368  curvs.push_back(fitSimpleCircle(trackCand, vol_map[12], vol_map[11], vol_map[9]));
369  curvs.push_back(fitSimpleCircle(trackCand, vol_map[12], vol_map[10], vol_map[9]));
370  curvs.push_back(fitSimpleCircle(trackCand, vol_map[11], vol_map[10], vol_map[9]));
371 
372  // average them and exclude failed fits
373  float mcurv = 0;
374  float nmeas = 0;
375 
376  for (size_t i = 0; i < curvs.size(); i++) {
377  if (mGenHistograms)
378  this->mHist["seed_curv"]->Fill(curvs[i]);
379  if (curvs[i] > 10) {
380  mcurv += curvs[i];
381  nmeas += 1.0;
382  }
383  }
384 
385  if (nmeas >= 1)
386  mcurv = mcurv / nmeas;
387  else
388  mcurv = 10;
389 
390  // Now lets get eta information
391  // simpler, use farthest points from IP
392  if (vol_map[9] < 13)
393  p0.SetXYZ(trackCand[vol_map[9]]->getX(), trackCand[vol_map[9]]->getY(), trackCand[vol_map[9]]->getZ());
394 
395  if (vol_map[10] < 13)
396  p1.SetXYZ(trackCand[vol_map[10]]->getX(), trackCand[vol_map[10]]->getY(), trackCand[vol_map[10]]->getZ());
397 
398  const double K = 0.00029979; //K depends on the units used for Bfield
399  double pt = mcurv * K * 5; // pT from average measured curv
400  double dx = (p1.X() - p0.X());
401  double dy = (p1.Y() - p0.Y());
402  double dz = (p1.Z() - p0.Z());
403  double phi = TMath::ATan2(dy, dx);
404  double Rxy = sqrt(dx * dx + dy * dy);
405  double theta = TMath::ATan2(Rxy, dz);
406  // double eta = -log( tantheta / 2.0 );
407  // these starting conditions can probably be improvd, good study for student
408 
409  seedMom.SetPtThetaPhi(pt, theta, phi);
410  seedPos.SetXYZ(hit_closest_to_IP->getX(), hit_closest_to_IP->getY(), hit_closest_to_IP->getZ());
411 
412  if (mGenHistograms) {
413  this->mHist["seed_pT"]->Fill(seedMom.Pt());
414  this->mHist["seed_eta"]->Fill(seedMom.Eta());
415  }
416 
417  return mcurv;
418  }
419 
420 
421  genfit::MeasuredStateOnPlane projectToFst(size_t si_plane, genfit::Track *fitTrack) {
422  if (si_plane > 2) {
423  genfit::MeasuredStateOnPlane nil;
424  return nil;
425  }
426 
427  auto detSi = mFSTPlanes[si_plane];
428  genfit::MeasuredStateOnPlane tst = fitTrack->getFittedState(1);
429  auto TCM = fitTrack->getCardinalRep()->get6DCov(tst);
430 
431  // this returns the track length if needed
432  fitTrack->getCardinalRep()->extrapolateToPlane(tst, detSi);
433 
434  TCM = fitTrack->getCardinalRep()->get6DCov(tst);
435 
436  // can get the projected positions if needed
437  float x = tst.getPos().X();
438  float y = tst.getPos().Y();
439  float z = tst.getPos().Z();
440  // and the uncertainties
441  LOG_DEBUG << "Track Uncertainty at FST (plane=" << si_plane << ") @ x= " << x << ", y= " << y << ", z= " << z << " : " << sqrt(TCM(0, 0)) << ", " << sqrt(TCM(1, 1)) << endm;
442 
443  return tst;
444  }
445 
446  genfit::SharedPlanePtr getFstPlane( FwdHit * h ){
447 
448  size_t planeId = h->getSector();
449 
450  TVector3 hitXYZ( h->getX(), h->getY(), h->getZ() );
451 
452  double phi = hitXYZ.Phi();
453  if ( phi < 0 ) phi = TMath::Pi() * 2 + phi;
454  const double phi_slice = phi / (TMath::Pi() / 6.0); // 2pi/12
455  const int phi_index = ((int)phi_slice);
456  const double r =sqrt( pow(hitXYZ.x(), 2) + pow(hitXYZ.y(), 2) );
457 
458  const size_t idx = phi_index % 2;
459  auto planeCorr = mFSTPlanesInner[planeId*2 + idx];
460  if ( r > 16 ){
461  planeCorr = mFSTPlanesOuter[planeId*2 + idx];
462  }
463  double cdz = (h->getZ() - planeCorr->getO().Z());
464 
465  if ( cdz > 0.010 ) {
466  LOG_WARN << "FST Z =" << h->getZ() << " vs CORR Plane Z = " << planeCorr->getO().Z() << " DIFF: " << cdz << " phi_slice = " << phi_slice << ", phi_index = " << phi_index << " R=" << hitXYZ.Pt() << " idx=" << idx << endm;
467  }
468 
469  return planeCorr;
470 
471  }
472 
473  /* RefitTracksWithSiHits
474  * Takes a previously fit track re-fits it with the newly added silicon hits
475  *
476  */
477  TVector3 refitTrackWithSiHits(genfit::Track *originalTrack, Seed_t si_hits) {
478  // mem leak, global track is overwritten without delete.
479  TVector3 pOrig = originalTrack->getCardinalRep()->getMom(originalTrack->getFittedState(1, originalTrack->getCardinalRep()));
480 
481  // auto cardinalStatus = originalTrack->getFitStatus(originalTrack->getCardinalRep());
482 
483  if (originalTrack->getFitStatus(originalTrack->getCardinalRep())->isFitConverged() == false) {
484  // in this case the original track did not converge so we should not refit.
485  // probably never get here due to previous checks
486  return pOrig;
487  }
488 
489  // Setup the Track Reps
490  auto trackRepPos = new genfit::RKTrackRep(mPdgPositron);
491  auto trackRepNeg = new genfit::RKTrackRep(mPdgElectron);
492 
493  // get the space points on the original track
494  auto trackPoints = originalTrack->getPointsWithMeasurement();
495 
496  if ((trackPoints.size() < (mFTTZLocations.size() +1) && mIncludeVertexInFit) || trackPoints.size() < mFTTZLocations.size() ) {
497  // we didnt get enough points for a refit
498  return pOrig;
499  }
500 
501  TVectorD rawCoords = trackPoints[0]->getRawMeasurement()->getRawHitCoords();
502  double z = mFSTZLocations[0]; //first FTT plane, used if we dont have PV in fit
503  if (mIncludeVertexInFit)
504  z = rawCoords(2);
505 
506  TVector3 seedPos(rawCoords(0), rawCoords(1), z);
507  TVector3 seedMom = pOrig;
508 
509  // Create the ref track using the seed state
510  auto mFitTrack = new genfit::Track(trackRepPos, seedPos, seedMom);
511  mFitTrack->addTrackRep(trackRepNeg);
512 
513  genfit::Track &fitTrack = *mFitTrack;
514 
515  size_t firstFTTIndex = 0;
516  if (mIncludeVertexInFit) {
517  // clone the PRIMARY VERTEX into this track
518  fitTrack.insertPoint(new genfit::TrackPoint(trackPoints[0]->getRawMeasurement(), &fitTrack));
519  firstFTTIndex = 1; // start on hit index 1 below
520  }
521 
522  // initialize the hit coords on plane
523  TVectorD hitCoords(2);
524  hitCoords[0] = 0;
525  hitCoords[1] = 0;
526 
527  size_t planeId(0);
528  int hitId(5);
529 
530  // add the hits to the track
531  for (auto h : si_hits) {
532  if ( nullptr == h ) continue; // if no Si hit in this plane, skip
533 
534  hitCoords[0] = h->getX();
535  hitCoords[1] = h->getY();
536  genfit::PlanarMeasurement *measurement = new genfit::PlanarMeasurement(hitCoords, CovMatPlane(h), h->getSector(), ++hitId, nullptr);
537 
538  planeId = h->getSector();
539 
540  if (mFSTPlanes.size() <= planeId) {
541  LOG_WARN << "invalid VolumId -> out of bounds DetPlane, vid = " << planeId << endm;
542  return pOrig;
543  }
544 
545  // auto plane = mFSTPlanes[planeId];
546  auto plane = getFstPlane( static_cast<FwdHit*>(h) );
547 
548  measurement->setPlane(plane, planeId);
549  fitTrack.insertPoint(new genfit::TrackPoint(measurement, &fitTrack));
550 
551 
552  TVector3 hitXYZ( h->getX(), h->getY(), h->getZ() );
553  float phi = hitXYZ.Phi();
554  if ( phi < 0 ) phi = TMath::Pi() * 2 + phi;
555  double phi_slice = phi / (TMath::Pi() / 6.0); // 2pi/12
556  int phi_index = ((int)phi_slice);
557  double dz = (h->getZ() - plane->getO().Z());
558 
559  double r =sqrt( pow(hitXYZ.x(), 2) + pow(hitXYZ.y(), 2) );
560 
561  size_t idx = phi_index % 2;
562  auto planeCorr = mFSTPlanesInner[planeId + idx];
563  if ( r > 16 ){
564  planeCorr = mFSTPlanesOuter[planeId + idx];
565  }
566  double cdz = (h->getZ() - planeCorr->getO().Z());
567 
568  if (mGenHistograms){
569 
570  ((TH2*)mHist[ "FstDiffZVsR" ])->Fill( r, dz );
571 
572  if ( r < 16 ) {// inner
573  mHist["FstDiffZVsPhiSliceInner"]->Fill( phi_slice, dz );
574  mHist["CorrFstDiffZVsPhiSliceInner"]->Fill( phi_slice, cdz );
575  } else {
576  mHist["FstDiffZVsPhiSliceOuter"]->Fill( phi_slice, dz );
577  mHist["CorrFstDiffZVsPhiSliceOuter"]->Fill( phi_slice, cdz );
578  mHist["FstDiffZVsPhiOuter"]->Fill( phi, dz );
579  }
580  }
581  // mHist[ "FstDiffZVsPhiSliceInner" ]->Fill( sqrt( pow(hitXYZ.x(), 2), pow(hitXYZ.y(), 2) ), dz );
582 
583  }
584  // start at 0 if PV not included, 1 otherwise
585  for (size_t i = firstFTTIndex; i < trackPoints.size(); i++) {
586  // clone the track points into this track
587  fitTrack.insertPoint(new genfit::TrackPoint(trackPoints[i]->getRawMeasurement(), &fitTrack));
588  }
589 
590  try {
591  //Track RE-Fit with GENFIT2
592  // check consistency of all points
593  fitTrack.checkConsistency();
594 
595  // do the actual track fit
596  mFitter->processTrack(&fitTrack);
597 
598  fitTrack.checkConsistency();
599 
600  // this chooses the lowest chi2 fit result as cardinal
601  fitTrack.determineCardinalRep();
602 
603  } catch (genfit::Exception &e) {
604  // will be caught below by converge check
605  LOG_WARN << "Track fit exception : " << e.what() << endm;
606  }
607 
608  if (fitTrack.getFitStatus(fitTrack.getCardinalRep())->isFitConverged() == false) {
609  // Did not converge
610  return pOrig;
611  } else { // we did converge, return new momentum
612 
613  try {
614  // causes seg fault
615  auto cardinalRep = fitTrack.getCardinalRep();
616  auto cardinalStatus = fitTrack.getFitStatus(cardinalRep);
617  mFitStatus = *cardinalStatus; // save the status of last fit
618  } catch (genfit::Exception &e) {
619  }
620 
621  TVector3 p = fitTrack.getCardinalRep()->getMom(fitTrack.getFittedState(1, fitTrack.getCardinalRep()));
622  return p;
623  }
624  return pOrig;
625  } // refit with Si hits
626 
627  TVector3 refitTrackWithGBL( genfit::Track *originalTrack ) {
628  // mem leak, global track is overwritten without delete.
629  TVector3 pOrig = originalTrack->getCardinalRep()->getMom(originalTrack->getFittedState(1, originalTrack->getCardinalRep()));
630 
631  // auto cardinalStatus = originalTrack->getFitStatus(originalTrack->getCardinalRep());
632 
633  if (originalTrack->getFitStatus(originalTrack->getCardinalRep())->isFitConverged() == false) {
634  // in this case the original track did not converge so we should not refit.
635  // probably never get here due to previous checks
636  return pOrig;
637  }
638 
639  // Setup the Track Reps
640  auto trackRepPos = new genfit::RKTrackRep(mPdgPositron);
641  auto trackRepNeg = new genfit::RKTrackRep(mPdgElectron);
642 
643  // get the space points on the original track
644  auto trackPoints = originalTrack->getPointsWithMeasurement();
645 
646 
647  TVectorD rawCoords = trackPoints[0]->getRawMeasurement()->getRawHitCoords();
648  TVector3 seedPos(rawCoords(0), rawCoords(1), rawCoords(2));
649  TVector3 seedMom = pOrig;
650 
651  // Create the ref track using the seed state
652  auto pFitTrack = new genfit::Track(trackRepPos, seedPos, seedMom);
653  pFitTrack->addTrackRep(trackRepNeg);
654 
655  genfit::Track &fitTrack = *pFitTrack;
656 
657  for (size_t i = 0; i < trackPoints.size(); i++) {
658  // clone the track points into this track
659  fitTrack.insertPoint(new genfit::TrackPoint(trackPoints[i]->getRawMeasurement(), &fitTrack));
660  }
661 
662  auto gblFitter = std::unique_ptr<genfit::GblFitter>(new genfit::GblFitter());
663  try {
664  // check consistency of all points
665  fitTrack.checkConsistency();
666 
667  // do the actual track fit
668  mFitter->processTrack(&fitTrack);
669 
670  fitTrack.checkConsistency();
671 
672  // this chooses the lowest chi2 fit result as cardinal
673  fitTrack.determineCardinalRep();
674 
675  } catch (genfit::Exception &e) {
676  // will be caught below by converge check
677  LOG_WARN << "Track fit exception : " << e.what() << endm;
678  }
679 
680  if (fitTrack.getFitStatus(fitTrack.getCardinalRep())->isFitConverged() == false) {
681  LOG_WARN << "GBL fit did not converge" << endm;
682  delete pFitTrack;
683  return pOrig;
684  } else { // we did converge, return new momentum
685 
686  try {
687  // causes seg fault
688  auto cardinalRep = fitTrack.getCardinalRep();
689  auto cardinalStatus = fitTrack.getFitStatus(cardinalRep);
690  mFitStatus = *cardinalStatus; // save the status of last fit
691  } catch (genfit::Exception &e) {
692  LOG_WARN << "Failed to get cardinal status from converged fit" << endm;
693  }
694  auto mom = fitTrack.getCardinalRep()->getMom(fitTrack.getFittedState(1, fitTrack.getCardinalRep()));
695  delete pFitTrack;
696  return mom;
697  }
698  delete pFitTrack;
699  return pOrig;
700  } //refitwith GBL
701 
702 
703 
704  /* Generic method for fitting space points with GenFit
705  *
706  *
707  */
708  TVector3 fitSpacePoints( vector<genfit::SpacepointMeasurement*> spoints, TVector3 &seedPos, TVector3 &seedMom ){
709 
710  // setup track reps
711  auto trackRepPos = new genfit::RKTrackRep(mPdgPositron);
712  auto trackRepNeg = new genfit::RKTrackRep(mPdgElectron);
713 
714  // setup track for fit with positive and negative reps
715  auto mFitTrack = new genfit::Track(trackRepPos, seedPos, seedMom);
716  mFitTrack->addTrackRep(trackRepNeg);
717 
718  genfit::Track &fitTrack = *mFitTrack;
719 
720  // try adding the points to track and fitting
721  try {
722  for ( size_t i = 0; i < spoints.size(); i++ ){
723  fitTrack.insertPoint(new genfit::TrackPoint(spoints[i], &fitTrack));
724  }
725  // do the fit against the two possible fits
726  mFitter->processTrackWithRep(&fitTrack, trackRepPos);
727  mFitter->processTrackWithRep(&fitTrack, trackRepNeg);
728 
729  } catch (genfit::Exception &e) {
730  LOG_ERROR << "GenFit failed to fit track with: " << e.what() << endm;
731  }
732 
733  try {
734  fitTrack.checkConsistency();
735 
736  fitTrack.determineCardinalRep();
737  auto cardinalRep = fitTrack.getCardinalRep();
738 
739  TVector3 p = cardinalRep->getMom(fitTrack.getFittedState(1, cardinalRep));
740  // sucess, return momentum
741  return p;
742  } catch (genfit::Exception &e) {
743  LOG_ERROR << "GenFit failed to fit track with: " << e.what() << endm;
744  }
745  return TVector3(0, 0, 0);
746  }
747 
748  /* Fit a track
749  *
750  *
751  */
752  TVector3 fitTrack(Seed_t trackCand, double *Vertex = 0, TVector3 *McSeedMom = 0) {
753  long long itStart = FwdTrackerUtils::nowNanoSecond();
754  if (mGenHistograms) this->mHist["FitStatus"]->Fill("Total", 1);
755 
756  // The PV information, if we want to use it
757  TVectorD pv(3);
758 
760  if (0 == Vertex) { // randomized from simulation
761  pv[0] = mVertexPos[0] + rand.gauss(mVertexSigmaXY);
762  pv[1] = mVertexPos[1] + rand.gauss(mVertexSigmaXY);
763  pv[2] = mVertexPos[2] + rand.gauss(mVertexSigmaZ);
764  } else {
765  pv[0] = Vertex[0];
766  pv[1] = Vertex[1];
767  pv[2] = Vertex[2];
768  }
769 
770  // get the seed info from our hits
771  TVector3 seedMom, seedPos;
772  // returns track curvature if needed
773  seedState(trackCand, seedPos, seedMom);
774 
775  if (McSeedMom != nullptr) {
776  seedMom = *McSeedMom;
777  }
778 
779  // If we use the PV, use that as the start pos for the track
780  if (mIncludeVertexInFit) {
781  LOG_DEBUG << "Primary Vertex in fit (seed pos) @ " << TString::Format( "(%f, %f, %f)", pv[0], pv[1], pv[2] ).Data() << endm;
782  seedPos.SetXYZ(pv[0], pv[1], pv[2]);
783  }
784 
785  if (mFitTrack){
786  delete mFitTrack;
787  }
788 
789  // create the track representations
790  auto trackRepPos = new genfit::RKTrackRep(mPdgMuon);
791  auto trackRepNeg = new genfit::RKTrackRep(mPdgAntiMuon);
792 
793  // Create the track
794  mFitTrack = new genfit::Track(trackRepPos, seedPos, seedMom);
795  mFitTrack->addTrackRep(trackRepNeg);
796 
797 
798  LOG_DEBUG
799  << "seedPos : (" << seedPos.X() << ", " << seedPos.Y() << ", " << seedPos.Z() << " )"
800  << ", seedMom : (" << seedMom.X() << ", " << seedMom.Y() << ", " << seedMom.Z() << " )"
801  << ", seedMom : (" << seedMom.Pt() << ", " << seedMom.Eta() << ", " << seedMom.Phi() << " )"
802  << endm;
803 
804  genfit::Track &fitTrack = *mFitTrack;
805 
806  size_t planeId(0); // detector plane ID
807  int hitId(0); // hit ID
808 
809  // initialize the hit coords on plane
810  TVectorD hitCoords(2);
811  hitCoords[0] = 0;
812  hitCoords[1] = 0;
813 
814  /******************************************************************************************************************
815  * Include the Primary vertex if desired
816  ******************************************************************************************************************/
817  if (mIncludeVertexInFit) {
818 
819  TMatrixDSym hitCov3(3);
820  hitCov3(0, 0) = mVertexSigmaXY * mVertexSigmaXY;
821  hitCov3(1, 1) = mVertexSigmaXY * mVertexSigmaXY;
822  hitCov3(2, 2) = mVertexSigmaZ * mVertexSigmaZ;
823 
824  genfit::SpacepointMeasurement *measurement = new genfit::SpacepointMeasurement(pv, hitCov3, 0, ++hitId, nullptr);
825  fitTrack.insertPoint(new genfit::TrackPoint(measurement, &fitTrack));
826  }
827 
828  /******************************************************************************************************************
829  * loop over the hits, add them to the track
830  ******************************************************************************************************************/
831  for (auto h : trackCand) {
832 
833  hitCoords[0] = h->getX();
834  hitCoords[1] = h->getY();
835 
836  genfit::PlanarMeasurement *measurement = new genfit::PlanarMeasurement(hitCoords, CovMatPlane(h), h->getSector(), ++hitId, nullptr);
837 
838  planeId = h->getSector();
839 
840  if (mFTTPlanes.size() <= planeId) {
841  LOG_WARN << "invalid VolumId -> out of bounds DetPlane, vid = " << planeId << endm;
842  return TVector3(0, 0, 0);
843  }
844 
845  auto plane = mFTTPlanes[planeId];
846  measurement->setPlane(plane, planeId);
847  fitTrack.insertPoint(new genfit::TrackPoint(measurement, &fitTrack));
848 
849  if (abs(h->getZ() - plane->getO().Z()) > 0.05) {
850  LOG_WARN << "Z Mismatch h->z = " << h->getZ() << ", plane->z = "<< plane->getO().Z() <<", diff = " << abs(h->getZ() - plane->getO().Z()) << endm;
851  }
852  } // loop on trackCand
853 
854 
855  /******************************************************************************************************************
856  * Do the fit
857  ******************************************************************************************************************/
858  try {
859  // do the fit
860  mFitter->processTrackWithRep(&fitTrack, trackRepPos);
861  mFitter->processTrackWithRep(&fitTrack, trackRepNeg);
862 
863  } catch (genfit::Exception &e) {
864  if (mGenHistograms) mHist["FitStatus"]->Fill("Exception", 1);
865  }
866 
867  TVector3 p(0, 0, 0);
868 
869  /******************************************************************************************************************
870  * Now check the fit
871  ******************************************************************************************************************/
872  try {
873  //check
874  fitTrack.checkConsistency();
875 
876  // find track rep with smallest chi2
877  fitTrack.determineCardinalRep();
878  auto cardinalRep = fitTrack.getCardinalRep();
879  auto cardinalStatus = fitTrack.getFitStatus(cardinalRep);
880  mFitStatus = *cardinalStatus; // save the status of last fit
881 
882  // Delete any previous track rep
883  if (mTrackRep)
884  delete mTrackRep;
885 
886  // Clone the cardinal rep for persistency
887  mTrackRep = cardinalRep->clone(); // save the result of the fit
888  if (fitTrack.getFitStatus(cardinalRep)->isFitConverged() && mGenHistograms ) {
889  this->mHist["FitStatus"]->Fill("GoodCardinal", 1);
890  }
891 
892  if (fitTrack.getFitStatus(trackRepPos)->isFitConverged() == false &&
893  fitTrack.getFitStatus(trackRepNeg)->isFitConverged() == false) {
894 
895  LOG_WARN << "FWD Track GenFit Failed" << endm;
896 
897  p.SetXYZ(0, 0, 0);
898  long long duration = (FwdTrackerUtils::nowNanoSecond() - itStart) * 1e-6; // milliseconds
899  if (mGenHistograms) {
900  this->mHist["FitStatus"]->Fill("Fail", 1);
901  this->mHist["FailedFitDuration"]->Fill(duration);
902  }
903  return p;
904  } // neither track rep converged
905 
906  p = cardinalRep->getMom(fitTrack.getFittedState(1, cardinalRep));
907  mQ = cardinalRep->getCharge(fitTrack.getFittedState(1, cardinalRep));
908  mP = p;
909 
910  LOG_DEBUG << "track fit p = " << TString::Format( "(%f, %f, %f), q=%f", p.X(), p.Y(), p.Z(), mQ ).Data() << endm;
911 
912  } catch (genfit::Exception &e) {
913  LOG_WARN << "Exception on track fit: " << e.what() << endm;
914  p.SetXYZ(0, 0, 0);
915 
916  long long duration = (FwdTrackerUtils::nowNanoSecond() - itStart) * 1e-6; // milliseconds
917  if (mGenHistograms) {
918  this->mHist["FitStatus"]->Fill("Exception", 1);
919  this->mHist["FailedFitDuration"]->Fill(duration);
920  }
921 
922  return p;
923  } // try/catch
924 
925  long long duration = (FwdTrackerUtils::nowNanoSecond() - itStart) * 1e-6; // milliseconds
926  if (mGenHistograms) {
927  this->mHist["FitStatus"]->Fill("Pass", 1);
928  this->mHist["delta_fit_seed_pT"]->Fill(p.Pt() - seedMom.Pt());
929  this->mHist["delta_fit_seed_eta"]->Fill(p.Eta() - seedMom.Eta());
930  this->mHist["delta_fit_seed_phi"]->Fill(p.Phi() - seedMom.Phi());
931  this->mHist["FitDuration"]->Fill(duration);
932  }
933  return p;
934  }
935 
936  int getCharge() {
937  return (int)mQ;
938  }
939 
940 
941 
942  // Store the planes for FTT and FST
943  vector<genfit::SharedPlanePtr> mFTTPlanes;
944  vector<genfit::SharedPlanePtr> mFSTPlanes;
945  vector<genfit::SharedPlanePtr> mFSTPlanesInner;
946  vector<genfit::SharedPlanePtr> mFSTPlanesOuter;
947 
948  void SetIncludeVertex( bool vert ) { mIncludeVertexInFit = vert; }
949 
950  protected:
951  std::unique_ptr<genfit::AbsBField> mBField;
952 
953  FwdTrackerConfig mConfig; // main config object
954  TString mGeoCache;
955 
956  // optional histograms, off by default
957  std::map<std::string, TH1 *> mHist;
958  bool mGenHistograms = false;
959 
960  // Main GenFit fitter instance
961  std::unique_ptr<genfit::AbsKalmanFitter> mFitter = nullptr;
962 
963  // PDG codes for the default plc type for fits
964  const int mPdgPiPlus = 211;
965  const int mPdgPiMinus = -211;
966  const int mPdgPositron = 11;
967  const int mPdgElectron = -11;
968  const int mPdgMuon = 13;
969  const int mPdgAntiMuon = -13;
970 
971 
972  // det z locations loaded from geom or config
973  vector<double> mFSTZLocations, mFTTZLocations;
974 
975  // parameter ALIASED from mConfig wrt PV vertex
976  double mVertexSigmaXY = 1;
977  double mVertexSigmaZ = 30;
978  vector<double> mVertexPos;
979  bool mIncludeVertexInFit = false;
980 
981  // GenFit state
982  genfit::FitStatus mFitStatus;
983  genfit::AbsTrackRep *mTrackRep;
984  genfit::Track *mFitTrack;
985 
986  // Fit results
987  TVector3 mP;
988  double mQ;
989 };
990 
991 #endif
Double_t gauss(const Double_t sigma) const
Return a random number distributed according to a gaussian with specified sigma.
Definition: StarRandom.cxx:72
static StarRandom & Instance()
Obtain the single instance of the random number generator.
Definition: StarRandom.cxx:87
Definition: FwdHit.h:68
std::vector< T > getVector(std::string path, std::vector< T > dv) const
Get a Vector object from config.
A class for providing random number generation.
Definition: StarRandom.h:30
T get(std::string path, T dv) const
template function for getting any type that can be converted from string via stringstream ...