EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GblFitter.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file GblFitter.cc
1 //-*-mode: C++; c-basic-offset: 2; -*-
2 /* Copyright 2013-2014
3  * Authors: Sergey Yashchenko and Tadeas Bilka
4  *
5  * This is an interface to General Broken Lines
6  *
7  * Version: 6 --------------------------------------------------------------
8  * - complete rewrite to GblFitter using GblFitterInfo and GblFitStatus
9  * - mathematics should be the same except for additional iterations
10  * (not possible before)
11  * - track is populated with scatterers + additional points with
12  * scatterers and no measurement (optional)
13  * - final track contains GblFitStatus and fitted states from GBL prediction
14  * - 1D/2D hits supported (pixel, single strip, combined strips(2D), wire)
15  * - At point: Only the very first raw measurement is used and from
16  * that, constructed MeasurementOnPlane with heighest weight
17  * Version: 5 --------------------------------------------------------------
18  * - several bug-fixes:
19  * - Scatterers at bad points
20  * - Jacobians at a point before they should be (code reorganized)
21  * - Change of sign of residuals
22  * Version: 4 --------------------------------------------------------------
23  * Fixed calculation of equvivalent scatterers (solution by C. Kleinwort)
24  * Now a scatterer is inserted at each measurement (except last) and
25  * between each two measurements.
26  * TrueHits/Clusters. Ghost (1D) hits ignored. With or
27  * without magnetic field.
28  * Version: 3 --------------------------------------------------------------
29  * This version now supports both TrueHits and Clusters for VXD.
30  * It can be used for arbitrary material distribution between
31  * measurements. Moments of scattering distribution are computed
32  * and translated into two equivalent thin GBL scatterers placed
33  * at computed positions between measurement points.
34  * Version: 2 ... never published -----------------------------------------
35  * Scatterer at each boundary (tooo many scatterers). TrueHits/Clusters.
36  * Without global der.&MP2 output.
37  * Version: 1 --------------------------------------------------------------
38  * Scatterers at measurement planes. TrueHits
39  * Version: 0 --------------------------------------------------------------
40  * Without scatterers. Genfit 1.
41  * -------------------------------------------------------------------------
42  *
43  * This file is part of GENFIT.
44  *
45  * GENFIT is free software: you can redistribute it and/or modify
46  * it under the terms of the GNU Lesser General Public License as published
47  * by the Free Software Foundation, either version 3 of the License, or
48  * (at your option) any later version.
49  *
50  * GENFIT is distributed in the hope that it will be useful,
51  * but WITHOUT ANY WARRANTY; without even the implied warranty of
52  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53  * GNU Lesser General Public License for more details.
54  *
55  * You should have received a copy of the GNU Lesser General Public License
56  * along with GENFIT. If not, see <http://www.gnu.org/licenses/>.
57  */
58 
59 #include "GblFitter.h"
60 #include "../include/GblFitStatus.h"
61 #include "GblFitterInfo.h"
62 #include "GblTrajectory.h"
63 #include "GblPoint.h"
65 
66 #include "Track.h"
67 #include <TFile.h>
68 #include <TH1F.h>
69 #include <TTree.h>
70 #include <string>
71 #include <list>
72 #include <FieldManager.h>
73 #include <HMatrixU.h>
74 #include <HMatrixV.h>
75 #include <Math/SMatrix.h>
76 #include <TMatrixD.h>
77 #include <TVectorDfwd.h>
78 #include <TMatrixT.h>
79 #include <TVector3.h>
80 
81 //#define DEBUG
82 
83 using namespace gbl;
84 using namespace std;
85 using namespace genfit;
86 
90 GblFitter::~GblFitter() {
91  if (m_segmentController) {
92  delete m_segmentController;
93  m_segmentController = nullptr;
94  }
95 }
96 
97 void GblFitter::setTrackSegmentController(GblTrackSegmentController* controler)
98 {
99  if (m_segmentController) {
100  delete m_segmentController;
101  m_segmentController = nullptr;
102  }
103  m_segmentController = controler;
104 }
105 
106 void GblFitter::processTrackWithRep(Track* trk, const AbsTrackRep* rep, bool resortHits)
107 {
108  cleanGblInfo(trk, rep);
109 
110  if (resortHits)
111  sortHits(trk, rep);
112 
113  // This flag enables/disables fitting of q/p parameter in GBL
114  // It is switched off automatically if no B-field at (0,0,0) is detected.
115  bool fitQoverP = true;
116  //TODO: Use clever way to determine zero B-field
117  double Bfield = genfit::FieldManager::getInstance()->getFieldVal(TVector3(0., 0., 0.)).Mag();
118  if (!(Bfield > 1.e-16))
119  fitQoverP = false;
120  // degrees of freedom after fit
121  int Ndf = 0;
122  // Chi2 after fit
123  double Chi2 = 0.;
124  //FIXME: d-w's not used so far...
125  double lostWeight = 0.;
126 
127  // Preparation of points (+add reference states) for GBL fit
128  // -----------------------------------------------------------------
130  trk->setFitStatus(gblfs, rep);
131  gblfs->setCurvature(fitQoverP);
132  //
133  // Propagate reference seed, create scattering points, calc Jacobians
134  // and store everything in fitter infos. (ready to collect points and fit)
135  //
136  //
137  gblfs->setTrackLen(
138  //
139  constructGblInfo(trk, rep)
140  //
141  );
142  //
143  //
144  gblfs->setIsFittedWithReferenceTrack(true);
145  gblfs->setNumIterations(0); //default value, still valid, No GBL iteration
146  if (m_externalIterations < 1)
147  return;
148  // -----------------------------------------------------------------
149 
150 
151  unsigned int nFailed = 0;
152  int fitRes = 0;
153  std::vector<std::string> gblIterations;
154  gblIterations.push_back(m_gblInternalIterations);
155 
156  // Iterations and updates of fitter infos and fit status
157  // -------------------------------------------------------------------
158  for (unsigned int iIter = 0; iIter < m_externalIterations; iIter++) {
159  // GBL refit (1st of reference, then refit of GBL trajectory itself)
160  int nscat = 0, nmeas = 0, ndummy = 0;
161  std::vector<gbl::GblPoint> points = collectGblPoints(trk, rep);
162  for(unsigned int ip = 0;ip<points.size(); ip++) {
163  GblPoint & p = points.at(ip);
164  if (p.hasScatterer())
165  nscat++;
166  if (p.hasMeasurement())
167  nmeas++;
168  if(!p.hasMeasurement()&&!p.hasScatterer())
169  ndummy++;
170  }
171  gbl::GblTrajectory traj(points, gblfs->hasCurvature());
172 
173  fitRes = traj.fit(Chi2, Ndf, lostWeight, (iIter == m_externalIterations - 1) ? m_gblInternalIterations : "");
174 
175  // Update fit results in fitterinfos
176  updateGblInfo(traj, trk, rep);
177 
178  // This repropagates to get new Jacobians,
179  // if planes changed, predictions are extrapolated to new planes
180  if (m_recalcJacobians > iIter) {
181  GblFitterInfo* prevFitterInfo = 0;
182  GblFitterInfo* currFitterInfo = 0;
183  for (unsigned int ip = 0; ip < trk->getNumPoints(); ip++) {
184  if (trk->getPoint(ip)->hasFitterInfo(rep) && (currFitterInfo = dynamic_cast<GblFitterInfo*>(trk->getPoint(ip)->getFitterInfo(rep)))) {
185 
186  currFitterInfo->recalculateJacobian(prevFitterInfo);
187  prevFitterInfo = currFitterInfo;
188  }
189  }
190  }
191 
192  gblfs->setIsFitted(true);
193  gblfs->setIsFitConvergedPartially(fitRes == 0);
194  nFailed = trk->getNumPointsWithMeasurement() - nmeas;
195  gblfs->setNFailedPoints(nFailed);
196  gblfs->setIsFitConvergedFully(fitRes == 0 && nFailed == 0);
197  gblfs->setNumIterations(iIter + 1);
198  gblfs->setChi2(Chi2);
199  gblfs->setNdf(Ndf);
200  gblfs->setCharge(trk->getFittedState().getCharge());
201 
202  #ifdef DEBUG
203  int npoints_meas = trk->getNumPointsWithMeasurement();
204  int npoints_all = trk->getNumPoints();
205 
206  cout << "-------------------------------------------------------" << endl;
207  cout << " GBL processed genfit::Track " << endl;
208  cout << "-------------------------------------------------------" << endl;
209  cout << " # Track Points : " << npoints_all << endl;
210  cout << " # Meas. Points : " << npoints_meas << endl;
211  cout << " # GBL points all : " << traj.getNumPoints();
212  if (ndummy)
213  cout << " (" << ndummy << " dummy) ";
214  cout << endl;
215  cout << " # GBL points meas : " << nmeas << endl;
216  cout << " # GBL points scat : " << nscat << endl;
217  cout << "-------------- GBL Fit Results ----------- Iteration " << iIter+1 << " " << ((iIter < gblIterations.size()) ? gblIterations[iIter] : "") << endl;
218  cout << " Fit q/p parameter : " << (gblfs->hasCurvature() ? ("True") : ("False")) << endl;
219  cout << " Valid trajectory : " << ((traj.isValid()) ? ("True") : ("False")) << endl;
220  cout << " Fit result : " << fitRes << " (0 for success)" << endl;
221  cout << " GBL track NDF : " << Ndf << " (-1 for failure)" << endl;
222  cout << " GBL track Chi2 : " << Chi2 << endl;
223  cout << " GBL track P-value : " << TMath::Prob(Chi2, Ndf) << endl;
224  cout << "-------------------------------------------------------" << endl;
225  #endif
226 
227  }
228  // -------------------------------------------------------------------
229 
230 }
231 
232 void GblFitter::cleanGblInfo(Track* trk, const AbsTrackRep* rep) const {
233 
234  for (int ip = trk->getNumPoints() - 1; ip >=0; ip--) {
235  trk->getPoint(ip)->setScatterer(nullptr);
236  trk->getPoint(ip)->deleteFitterInfo(rep);
237  //TODO
238  if (!trk->getPoint(ip)->hasRawMeasurements())
239  trk->deletePoint(ip);
240  }
241 }
242 
243 void GblFitter::sortHits(Track* trk, const AbsTrackRep* rep) const {
244  // All measurement points in ref. track
245  int npoints_meas = trk->getNumPointsWithMeasurement();
246  // Prepare state for extrapolation of track seed
247  StateOnPlane reference(rep);
248  rep->setTime(reference, trk->getTimeSeed());
249  rep->setPosMom(reference, trk->getStateSeed());
250  // Take the state to first plane
251  SharedPlanePtr firstPlane(trk->getPointWithMeasurement(0)->getRawMeasurement(0)->constructPlane(reference));
252  reference.extrapolateToPlane(firstPlane);
253  //1st point is at arc-len=0
254  double arcLenPos = 0;
255 
256  // Loop only between meas. points
257  for (int ipoint_meas = 0; ipoint_meas < npoints_meas - 1; ipoint_meas++) {
258  // current measurement point
259  TrackPoint* point_meas = trk->getPointWithMeasurement(ipoint_meas);
260  // Current detector plane
261  SharedPlanePtr plane = point_meas->getRawMeasurement(0)->constructPlane(reference);
262  // Get the next plane
263  SharedPlanePtr nextPlane(trk->getPointWithMeasurement(ipoint_meas + 1)->getRawMeasurement(0)->constructPlane(reference));
264 
265  point_meas->setSortingParameter(arcLenPos);
266  arcLenPos += reference.extrapolateToPlane(nextPlane);
267 
268  } // end of loop over track points with measurement
269  trk->getPointWithMeasurement(npoints_meas - 1)->setSortingParameter(arcLenPos);
270  trk->sort();
271 }
272 
273 std::vector<gbl::GblPoint> GblFitter::collectGblPoints(genfit::Track* trk, const genfit::AbsTrackRep* rep) {
274  //TODO store collected points in in fit status? need streamer for GblPoint (or something like that)
275  std::vector<gbl::GblPoint> thePoints;
276  thePoints.clear();
277 
278  // Collect points from track and fitterInfo(rep)
279  for (unsigned int ip = 0; ip < trk->getNumPoints(); ip++) {
280  GblFitterInfo * gblfi = dynamic_cast<GblFitterInfo*>(trk->getPoint(ip)->getFitterInfo(rep));
281  if (!gblfi)
282  continue;
283  thePoints.push_back(gblfi->constructGblPoint());
284  }
285  return thePoints;
286 }
287 
288 void GblFitter::updateGblInfo(gbl::GblTrajectory& traj, genfit::Track* trk, const genfit::AbsTrackRep* rep) {
289  //FIXME
290  if (!traj.isValid())
291  return;
292 
293  // Update points in track and fitterInfo(rep)
294  int igblfi = -1;
295  for (unsigned int ip = 0; ip < trk->getNumPoints(); ip++) {
296  GblFitterInfo * gblfi = dynamic_cast<GblFitterInfo*>(trk->getPoint(ip)->getFitterInfo(rep));
297  if (!gblfi)
298  continue;
299  igblfi++;
300 
301  // The point will calculate its position on the track
302  // (counting fitter infos) which hopefully
303  gblfi->updateFitResults(traj);
304 
305  // This is agains logic. User can do this if he wants and it is recommended usually
306  // so that following fit could reuse the updated seed
307  //if (igblfi == 0) {
308  // trk->setStateSeed( gblfi->getFittedState(true).getPos(), gblfi->getFittedState(true).getMom() );
309  // trk->setCovSeed( gblfi->getFittedState(true).get6DCov() );
310  //}
311  }
312 }
313 
315  double& theta, double& s, double& ds,
316  const double p, const double mass, const double charge,
317  const std::vector<genfit::MatStep>& steps) const {
318  theta = 0.; s = 0.; ds = 0.; length = 0;
319  if (steps.empty()) return;
320 
321  // sum of step lengths
322  double len = 0.;
323  // normalization
324  double sumxx = 0.;
325  // first moment (non-normalized)
326  double sumx2x2 = 0.;
327  // (part of) second moment / variance (non-normalized)
328  double sumx3x3 = 0.;
329 
330  double xmin = 0.;
331  double xmax = 0.;
332 
333  for (unsigned int i = 0; i < steps.size(); i++) {
334  const MatStep step = steps.at(i);
335  // inverse of material radiation length ... (in 1/cm) ... "density of scattering"
336  double rho = 1. / step.material_.radiationLength;
337  len += fabs(step.stepSize_);
338  xmin = xmax;
339  xmax = xmin + fabs(step.stepSize_);
340  // Compute integrals
341 
342  // integral of rho(x)
343  sumxx += rho * (xmax - xmin);
344  // integral of x*rho(x)
345  sumx2x2 += rho * (xmax * xmax - xmin * xmin) / 2.;
346  // integral of x*x*rho(x)
347  sumx3x3 += rho * (xmax * xmax * xmax - xmin * xmin * xmin) / 3.;
348  }
349  // This ensures PDG formula still gives positive results (but sumxx should be > 1e-4 for it to hold)
350  if (sumxx < 1.0e-10) return;
351  // Calculate theta from total sum of radiation length
352  // instead of summimg squares of individual deflection angle variances
353  // PDG formula:
354  double beta = p / sqrt(p * p + mass * mass);
355  theta = (0.0136 / p / beta) * fabs(charge) * sqrt(sumxx) * (1. + 0.038 * log(sumxx));
356  //theta = (0.015 / p / beta) * fabs(charge) * sqrt(sumxx);
357 
358  // track length
359  length = len;
360  // Normalization factor
361  double N = 1. / sumxx;
362  // First moment
363  s = N * sumx2x2;
364  // Square of second moment (variance)
365  // integral of (x - s)*(x - s)*rho(x)
366  double ds_2 = N * (sumx3x3 - 2. * sumx2x2 * s + sumxx * s * s);
367  ds = sqrt(ds_2);
368 
369  #ifdef DEBUG
370 
371  #endif
372 }
373 
374 double GblFitter::constructGblInfo(Track* trk, const AbsTrackRep* rep)
375 {
376  // All measurement points in ref. track
377  int npoints_meas = trk->getNumPointsWithMeasurement();
378  // Dimesion of representation/state
379  int dim = rep->getDim();
380  // Jacobian for point with measurement = how to propagate from previous point (scat/meas)
381  TMatrixD jacPointToPoint(dim, dim);
382  jacPointToPoint.UnitMatrix();
383 
384  // Prepare state for extrapolation of track seed
385  // Take the state to first plane
386  StateOnPlane reference(rep);
387  rep->setTime(reference, trk->getTimeSeed());
388  rep->setPosMom(reference, trk->getStateSeed());
389 
390  SharedPlanePtr firstPlane(trk->getPointWithMeasurement(0)->getRawMeasurement(0)->constructPlane(reference));
391  reference.extrapolateToPlane(firstPlane);
392 
393  double sumTrackLen = 0;
394  // NOT used but useful
395  TMatrixDSym noise; TVectorD deltaState;
396 
397  // Loop only between meas. points
398  for (int ipoint_meas = 0; ipoint_meas < npoints_meas; ipoint_meas++) {
399  // current measurement point
400  TrackPoint* point_meas = trk->getPointWithMeasurement(ipoint_meas);
401  // Current detector plane
402  SharedPlanePtr plane = point_meas->getRawMeasurement(0)->constructPlane(reference);
403  // track direction at plane (in global coords)
404  TVector3 trackDir = rep->getDir(reference);
405  // track momentum direction vector at plane (in global coords)
406  double trackMomMag = rep->getMomMag(reference);
407  // charge of particle
408  double particleCharge = rep->getCharge(reference);
409  // mass of particle
410  double particleMass = rep->getMass(reference);
411  // Parameters of a thick scatterer between measurements
412  double trackLen = 0., scatTheta = 0., scatSMean = 0., scatDeltaS = 0.;
413  // Parameters of two equivalent thin scatterers
414  double theta1 = 0., theta2 = 0., s1 = 0., s2 = 0.;
415  // jacobian from s1=0 to s2
416  TMatrixD jacMeas2Scat(dim, dim);
417  jacMeas2Scat.UnitMatrix();
418 
419  // Stop here if we are at last point (do not add scatterers to last point),
420  // just the fitter info
421  if (ipoint_meas >= npoints_meas - 1) {
422 
423  // Construction last measurement (no scatterer)
424  // --------------------------------------------
425  // Just add the fitter info of last plane
426  GblFitterInfo* gblfimeas(new GblFitterInfo(point_meas, rep, reference));
427  gblfimeas->setJacobian(jacPointToPoint);
428  point_meas->setFitterInfo(gblfimeas);
429  // --------------------------------------------
430 
431  break;
432  }
433  // Extrapolate to next measurement to get material distribution
434  // Use a temp copy of the StateOnPlane to propage between measurements
435  StateOnPlane refCopy(reference);
436  // Get the next plane
437  SharedPlanePtr nextPlane(trk->getPointWithMeasurement(ipoint_meas + 1)->getRawMeasurement(0)->constructPlane(reference));
438 
439  // Extrapolation for multiple scattering calculation
440  // Extrap to point + 1, do NOT stop at boundary
441  TVector3 segmentEntry = refCopy.getPos();
442  rep->extrapolateToPlane(refCopy, nextPlane, false, false);
443  TVector3 segmentExit = refCopy.getPos();
444 
445  getScattererFromMatList(trackLen,
446  scatTheta,
447  scatSMean,
448  scatDeltaS,
449  trackMomMag,
450  particleMass,
451  particleCharge,
452  rep->getSteps());
453  // Now calculate positions and scattering variance for equivalent scatterers
454  // (Solution from Claus Kleinwort (DESY))
455  s1 = 0.; s2 = scatSMean + scatDeltaS * scatDeltaS / (scatSMean - s1);
456  theta1 = sqrt(scatTheta * scatTheta * scatDeltaS * scatDeltaS / (scatDeltaS * scatDeltaS + (scatSMean - s1) * (scatSMean - s1)));
457  theta2 = sqrt(scatTheta * scatTheta * (scatSMean - s1) * (scatSMean - s1) / (scatDeltaS * scatDeltaS + (scatSMean - s1) * (scatSMean - s1)));
458 
459  // Call segment controller to set MS options:
460  if (m_segmentController)
461  m_segmentController->controlTrackSegment(segmentEntry, segmentExit, scatTheta, this);
462 
463  // Scattering options: OFF / THIN / THICK
464  if (m_enableScatterers && !m_enableIntermediateScatterer) {
465  theta1 = scatTheta;
466  theta2 = 0;
467  } else if (!m_enableScatterers) {
468  theta1 = 0.;
469  theta2 = 0.;
470  }
471 
472  // Construction of measurement (with scatterer)
473  // --------------------------------------------
474 
475  if (theta1 > scatEpsilon)
476  point_meas->setScatterer(new ThinScatterer(plane, Material(theta1, 0., 0., 0., 0.)));
477 
478  GblFitterInfo* gblfimeas(new GblFitterInfo(point_meas, rep, reference));
479  gblfimeas->setJacobian(jacPointToPoint);
480  point_meas->setFitterInfo(gblfimeas);
481  // --------------------------------------------
482 
483 
484  // If not last measurement, extrapolate and get jacobians for scattering points between this and next measurement
485  if (theta2 > scatEpsilon) {
486  // First scatterer has been placed at current measurement point (see above)
487  // theta2 > 0 ... we want second scatterer:
488  // Extrapolate to s2 (we have s1 = 0)
489  rep->extrapolateBy(reference, s2, false, true);
490  rep->getForwardJacobianAndNoise(jacMeas2Scat, noise, deltaState);
491 
492  // Construction of intermediate scatterer
493  // --------------------------------------
494  TrackPoint* scattp = new TrackPoint(trk);
495  scattp->setSortingParameter(point_meas->getSortingParameter() + s2);
496  scattp->setScatterer(new ThinScatterer(reference.getPlane(), Material(theta2, 0., 0., 0., 0.)));
497  // Add point to track before next point
498  int pointIndex = 0;
499  //TODO Deduce this rather than looping over all points
500  for (unsigned int itp = 0; itp < trk->getNumPoints(); itp++) {
501  if (trk->getPoint(itp) == point_meas) {
502  pointIndex = itp;
503  break;
504  }
505  }
506  trk->insertPoint(scattp, pointIndex + 1);
507  // Create and store fitter info
508  GblFitterInfo * gblfiscat(new GblFitterInfo(scattp, rep, reference));
509  gblfiscat->setJacobian(jacMeas2Scat);
510  scattp->setFitterInfo(gblfiscat);
511  // ---------------------------------------
512 
513  // Finish extrapolation to next measurement
514  double nextStep = rep->extrapolateToPlane(reference, nextPlane, false, true);
515  rep->getForwardJacobianAndNoise(jacPointToPoint, noise, deltaState);
516 
517  if (0. > nextStep) {
518  cout << " ERROR: The extrapolation to measurement point " << (ipoint_meas + 2) << " stepped back by " << nextStep << "cm !!! Track will be cut before this point." << endl;
519  // stop trajectory construction here
520  break;
521  }
522 
523  } else {
524  // No scattering: extrapolate whole distance between measurements
525  double nextStep = rep->extrapolateToPlane(reference, nextPlane, false, true);
526  rep->getForwardJacobianAndNoise(jacPointToPoint, noise, deltaState);
527 
528  if (0. > nextStep) {
529  cout << " ERROR: The extrapolation to measurement point " << (ipoint_meas + 2) << " stepped back by " << nextStep << "cm !!! Track will be cut before this point." << endl;
530  // stop trajectory construction here
531  break;
532  }
533  }
534  // Track length up to next point
535  sumTrackLen += trackLen;
536 
537  } // end of loop over track points with measurement
538  return sumTrackLen;
539 }