MyMarlinTPC  170316
StepWiseHelixGeneralBrokenLineInterfaceProcessor.cc
Go to the documentation of this file.
1 #ifdef USE_GBL
2 
4 
5 #include <iostream>
6 #include <string>
7 
8 // include what you need from lcio
9 #include <EVENT/LCEvent.h>
10 #include <IMPL/LCCollectionVec.h>
11 #include <EVENT/Track.h>
12 #include <EVENT/TrackerHit.h>
13 #include "IMPL/TrackImpl.h"
14 #include "IMPL/LCFlagImpl.h"
15 #include <Exceptions.h>
16 #include <UTIL/BitField64.h>
17 #include <UTIL/ILDConf.h>
18 
19 #include "marlin/Global.h"
20 
21 // GEAR
22 #include "GEAR.h"
23 #include <gear/TPCParameters.h>
24 #include <gear/TPCModule.h>
25 #include <gear/BField.h>
26 #include <gearimpl/Vector3D.h>
27 
28 // the gbl includes
29 #include "GblPoint.h"
30 
31 //#include "TMath.h"
32 
33 using namespace lcio;
34 using namespace marlin;
35 using namespace std;
36 using namespace gear;
37 
38 namespace marlintpc {
39 static bool compare(indexArcPair one, indexArcPair two) {
40  return ((one.second) < (two.second));
41 }
42 
43 using namespace gbl;
44 
46 
47 StepWiseHelixGeneralBrokenLineInterfaceProcessor::StepWiseHelixGeneralBrokenLineInterfaceProcessor() :
48  Processor("StepWiseHelixGeneralBrokenLineInterfaceProcessor") {
49  // the processor description
50  _description =
51  "StepWiseHelixGeneralBrokenLineInterfaceProcessor is the interface between MarlinTPC and the General Broken Lines track (re-)fitting package.";
52 
53  registerInputCollection(LCIO::TRACK, "InputSeedTracks",
54  "The name of the input collection of track candidates (default: TPCSeedTracks)", _inputCollectionName,
55  std::string("TPCSeedTracks"));
56 
57  registerOutputCollection(LCIO::TRACK, "OutputTracks",
58  "The name of the output collection with the fitted tracks(default: TPCTracks)", _outputTrackCollectionName,
59  std::string("TPCTracks"));
60 
61  registerProcessorParameter("WriteOutputToStorage", "If true the output collection is written to file", _outputIsPersistent, true);
62 
63  registerOptionalParameter("BFieldScaleFactor", "Scales magnetic field (map), use 1.0 (default) for field ON or 0.0 for field OFF",
64  _bfieldScaleFactor, double(1.0));
65 
66  registerOptionalParameter("FitOptions",
67  "Set wether multiple passes with h huber, t tukey or c cauchy downweighting should be performed", _fitOptions,
68  std::string(""));
69 
70  registerOptionalParameter("WriteMillepedeBinary", "Set to true if you want a Millepede binary file (default:false)",
71  _writeMillepedeOut, false);
72 
73  registerOptionalParameter("MillePedeCalcMethod",
74  "Defines which parameters should be calculates for Millepede: 0: module alignment, 1: track distortions, 2: hit charge dependence (has yet to be implemented) (default:0)",
75  _milleCalcMethod, 0);
76 
77  registerOptionalParameter("MillePedeMinHits", "Minimum number of hits on track for output to Millepede binary file (default: 42)",
78  _milleMinHits, 42);
79 
80  registerOptionalParameter("MillepedeFilename", "Set the name of the Millepede binary file ", _fileNameMillepedeFile,
81  std::string(""));
82  registerOptionalParameter("EncodedModuleID", "Module ID encoded in CellID0", _encodedModuleID, bool(true));
83 
84  registerOptionalParameter("MaxStep", "Maximal step size (with constant magnetic field)", _maxStep, double(10.0));
85 
86  registerProcessorParameter("X0PerUnitLength", "X0 per unit length (TPC gas as homogeneous scatterer)", _x0PerUnitLength,
87  double(0.0));
88 
89  registerProcessorParameter("ThickScatterer", "Selects thick (otherwise thin) scatterers for multiple scattering", _thickScatterer,
90  bool(false));
91 
92  registerProcessorParameter("DefaultMomentum", "Default momentum for multiple scattering (for Bfield off)", _defaultMomentum,
93  double(10.0));
94 }
95 
98  printParameters();
99  if (_writeMillepedeOut) {
100  _milleBinary = new MilleBinary(_fileNameMillepedeFile.c_str());
101  }
102 
103  const gear::TPCParameters& tpcParameters = Global::GEAR->getTPCParameters();
104  // TPC center
105  _Xcenter = tpcParameters.getDoubleVal("TPC_cylinder_centre_c0");
106  _Ycenter = tpcParameters.getDoubleVal("TPC_cylinder_centre_c1");
107 }
108 
110 }
111 
114  // use an LCCollectionVec instead of LCCollection so we can use iterators later
115  LCCollectionVec* seedTrackCollectionVector = NULL;
116 
117  // do a try / catch in case there is an empty event
118  try {
119  seedTrackCollectionVector = dynamic_cast<LCCollectionVec *>(evt->getCollection(_inputCollectionName));
120  } catch (DataNotAvailableException &e) {
121  // no input data, just return and process the next event
122  return;
123  }
124 
125  streamlog_out(DEBUG) << "in event " << evt->getEventNumber() << " there are " << seedTrackCollectionVector->size() << " tracks. "
126  << endl;
127 
128  Vector3D theTPCCenter(_Xcenter, _Ycenter, 0.);
129  Vector3D bfield = marlin::Global::GEAR->getBField().at(theTPCCenter);
130 
131  const bool bOff(bfield.z() * _bfieldScaleFactor == 0.);
132  if (bOff) {
133  streamlog_out(DEBUG) << "BField(GEAR) is OFF" << std::endl;
134  } else {
135  streamlog_out(DEBUG) << "BField(GEAR) is ON" << std::endl;
136  }
137  // magnetic field (in z direction) at TPC center
138  double Bz = bfield.z() * _bfieldScaleFactor; // rho component is accessible with field.rho()
139 
140  // output collection for the fitted tracks
141  IMPL::LCCollectionVec* outputTrackCollection = new IMPL::LCCollectionVec(EVENT::LCIO::TRACK);
142 
143  // hits are to be stored with the track -- set the according flag
144  LCFlagImpl trkFlag(0);
145  trkFlag.setBit(LCIO::TRBIT_HITS);
146  outputTrackCollection->setFlag(trkFlag.getFlag());
147 
148  // loop over the seed tracks
149  for (LCCollectionVec::iterator inputIter = seedTrackCollectionVector->begin(), endIter = seedTrackCollectionVector->end();
150  inputIter < endIter; ++inputIter) {
151  // dynamic cast to lcio::track
152  Track* seedTrack = dynamic_cast<Track *>(*inputIter);
153 
154  double seedD0 = seedTrack->getD0();
155  double seedPhi = seedTrack->getPhi();
156  double seedOmega = seedTrack->getOmega();
157  double seedZ0 = seedTrack->getZ0();
158  double seedTanLambda = seedTrack->getTanLambda();
159  vector<TrackerHit*> hitList = seedTrack->getTrackerHits();
160  //CHK track parameters are defined at (distance of closest approach to) reference point !?
161  const float* refPoint = seedTrack->getReferencePoint();
162  const double refPos[] = { refPoint[0], refPoint[1], refPoint[2] };
163  //CHK arc-length is measured from reference point
164  float rInner = seedTrack->getRadiusOfInnermostHit();
165 
166  streamlog_out(DEBUG) << " ++ track number " << endIter - inputIter << " with " << seedTrack->getTrackerHits().size()
167  << " hits on the track has the parameters: [omega, tanLambda, phi0, d0, z0] = [" << seedOmega << "," << seedTanLambda << ","
168  << seedPhi << "," << seedD0 << "," << seedZ0 << "]." << endl;
169 
170  if (bOff) {
171  _curvature = false;
172  // current Clupatra fits curved tracks independent of magnetic field
173  // calculate new seed from straight line defined by (radially) first and last hit
174  if (seedOmega != 0.) calcLineSeed(hitList, refPos, seedOmega, seedPhi, seedD0, seedTanLambda, seedZ0);
175  } else {
176  _curvature = true;
177  }
178 
179  const double seedLambda = atan(seedTanLambda);
180 
181  //CHK reference helix
182  double seedPar[] = { -seedOmega, seedPhi, -seedD0, seedTanLambda, seedZ0 };
183  // use local helix
184  localHelix lHelix(seedPar, refPos, _bfieldScaleFactor);
185  simpleHelix hlx = lHelix.getSimpleHelix();
186  // lHelix.dump();
187 
189  vector<indexArcPair> hitWithArcList;
190  for (unsigned int i = 0; i < hitList.size(); ++i) {
191  double sArc = hlx.getArcLengthXY(hitList[i]->getPosition());
192  hitWithArcList.push_back(make_pair(i, sArc));
193  }
194  // find smallest arc-length
195  indexArcPair closest(hitWithArcList.front()), first(closest), last(closest);
196  for (vector<indexArcPair>::const_iterator thePair = hitWithArcList.begin() + 1; thePair < hitWithArcList.end(); ++thePair) {
197  if (abs(thePair->second) < abs(closest.second)) closest = *thePair;
198  if (thePair->second < first.second) first = *thePair;
199  if (thePair->second > last.second) last = *thePair;
200  }
201  // add reference point if not at a hit (or close by)
202  const double averageStep = (last.second - first.second) / (hitWithArcList.size() - 1);
203  if (abs(closest.second / averageStep) > 1.0E-5) {
204  closest = make_pair(-1, 0.);
205  hitWithArcList.push_back(closest);
206  }
207  sort(hitWithArcList.begin(), hitWithArcList.end(), compare);
208 
210  // list of scatterers between measurements (relative arc-length and variance)
211  vector<arcVarPair> arcWithVarList;
212  if (_x0PerUnitLength > 0.) {
213  double ptot = _defaultMomentum;
214  if (!bOff) ptot = Bz * 0.0002998 / (seedOmega * cos(seedLambda));
215  double XbyX0 = _x0PerUnitLength * (last.second - first.second) / cos(seedLambda); // total material on track
216  // Highland formula, variance per unit (arc-)length in XY
217  double MultScatVar = pow(0.0136 / ptot * (1. + 0.038 * std::log(XbyX0)), 2) * _x0PerUnitLength / cos(seedLambda);
218  if (_thickScatterer) { // use two equivalent thin scatterers
219  arcWithVarList.push_back(make_pair(0.21132, 0.5 * MultScatVar)); // at 0.5-1/sqrt(12.)
220  arcWithVarList.push_back(make_pair(0.78868, 0.5 * MultScatVar)); // at 0.5+1/sqrt(12.)
221  } else
222  arcWithVarList.push_back(make_pair(0.5, MultScatVar)); // at 0.5
223 
224  }
225 
227  vector<GblPoint> theListOfPoints;
228  // number of valid hits (with measurement)
229  unsigned int numValid = 0;
230  // point 2 point jacobian in local curvilinear parameters
231  TMatrixD point2pointJacobian(5, 5);
232  point2pointJacobian.UnitMatrix();
233  bool makeScatterers = false; // in active volume, between first and last hit?
234  // Energy loss estimators.
235  vector<double> eLossEstimators;
236  // number of hits lost (due to threshold)
237  unsigned int numLow = 0;
238  for (vector<indexArcPair>::const_iterator thePair = hitWithArcList.begin(); thePair < hitWithArcList.end(); ++thePair) {
239  // cout << " sArc " << thePair->first << ", " << thePair->second << endl;
240  int index = thePair->first;
241  double phiTrack = seedPhi - seedOmega * thePair->second;
242  // propagate to position
243  const double* position = index >= 0 ? hitList[index]->getPosition() : refPos;
244 
245  // insert scatterers
246  if (makeScatterers) {
247  // simple helix (at last point)
248  simpleHelix hlx = lHelix.getSimpleHelix();
249  // distance (to this point)
250  double step = hlx.getArcLengthXY(position);
251  double scatPos[3];
252  for (vector<arcVarPair>::const_iterator theScat = arcWithVarList.begin(); theScat < arcWithVarList.end(); ++theScat) {
253  // get position of scatterer
254  hlx.getPosAtArcLength(theScat->first * step, scatPos);
255  point2pointJacobian = lHelix.propagateTo(scatPos, _maxStep) * point2pointJacobian;
256  // create a point from the jacobian
257  GblPoint point(point2pointJacobian);
258  // reset (integrated) jacobian
259  point2pointJacobian.UnitMatrix();
260  // add scatterer
261  TVectorD scat(2);
262  scat.Zero();
263  TVectorD scatPrec(2);
264  scatPrec[0] = scatPrec[1] = 1.0 / (theScat->second * step);
265  point.addScatterer(scat, scatPrec);
266  // store the point in the list that will be handed to the trajectory
267  theListOfPoints.push_back(point);
268  }
269  }
270  if (_x0PerUnitLength > 0.) {
271  if (index == first.first) makeScatterers = true; // reached first hit
272  if (index == last.first) makeScatterers = false; // reached last hit
273  }
274 
275  point2pointJacobian = lHelix.propagateTo(position, _maxStep) * point2pointJacobian;
276 
277  gblHelperHit aHit =
278  index >= 0 ?
280  phiTrack) :
281  gblHelperHit(seedPhi);
282  if (aHit.isValid()) {
283  numValid++;
284  // create a point from the jacobian
285  GblPoint point(point2pointJacobian);
286  // reset (integrated) jacobian
287  point2pointJacobian.UnitMatrix();
288  // now add the measurement point
289  if (aHit.isMeasurement()) {
290  point.addMeasurement(aHit.getLocalToMeasurementProjection(), aHit.getResiduals(), aHit.getPrecision());
291  if (aHit.getNumGlobals() > 0) point.addGlobals(aHit.getGlobalLabels(), aHit.getGlobalDerivatives());
292  if (aHit.getEScaled() > 0.)
293  eLossEstimators.push_back(1. / sqrt(aHit.getEScaled()));
294  else
295  numLow++;
296  }
297  // store the point in the list that will be handed to the trajectory
298  theListOfPoints.push_back(point);
299  // is reference point?
300  if (index == closest.first) _refPointIndex = theListOfPoints.size();
301  } else
302  streamlog_out(DEBUG) << " invalid hit: " << thePair->first << ", " << thePair->second << endl;
303  }
304  if (numValid < 3) {
305  streamlog_out(DEBUG) << " ++ track number " << endIter - inputIter << " skipped - too few valid hits " << endl;
306  continue;
307  }
309  _trajectory = new GblTrajectory(theListOfPoints, _curvature);
310 
313  if (_writeMillepedeOut) {
314  trackerAlcaSelector sel(*seedTrack, _milleMinHits);
315  if (sel.isSelected()) _trajectory->milleOut(*_milleBinary);
316  }
317  TVectorD trackparameters(5);
318  TMatrixDSym trackcovariance(5);
319  if (_ndf > 0) // check if the fit was successful
320  {
321  // get the results at a given label in local cl track parameters
322  // the track parameters are corrections to the curvilinear track parameters
323  _trajectory->getResults(_refPointIndex, trackparameters, trackcovariance);
324  // the results need to be transformed to the LCIO perigee representation ( d0, phi0, Omega, z0, tanLambda)
325  TMatrixD jacCL2LCIO = hlx.perigeeToLCIOJacobian() * hlx.curvilinearToPerigeeJacobian();
326  TVectorD correctionVec = jacCL2LCIO * trackparameters;
327  TMatrixDSym covarianceMatrix = trackcovariance.Similarity(jacCL2LCIO);
328  /* prepare LCIO output; unknown parts first:
329  *
330  * theTrack->setTypeBit (int index, bool val=true) // ?
331  *
332  */
333 
334  TrackImpl* theTrack = new TrackImpl();
335  theTrack->setOmega(seedOmega + correctionVec[2]);
336  theTrack->setTanLambda(seedTanLambda + correctionVec[4]);
337  theTrack->setPhi(seedPhi + correctionVec[1]);
338  theTrack->setD0(seedD0 + correctionVec[0]);
339  theTrack->setZ0(seedZ0 + correctionVec[3]);
340  theTrack->setReferencePoint(refPoint);
341  theTrack->setRadiusOfInnermostHit(rInner);
342  // compressed covariance matrix
343  float compressedCovariance[15];
344  int ind = 0;
345  for (int i = 0; i < 5; ++i)
346  for (int j = 0; j <= i; ++j)
347  compressedCovariance[ind++] = covarianceMatrix[i][j];
348  theTrack->setCovMatrix(compressedCovariance);
349 
350  theTrack->setChi2(_chisquare);
351  theTrack->setNdf(_ndf);
352 
353  // simple dEdx from median(1/sqrt(EScaled))
354  const unsigned int numEstimators = eLossEstimators.size();
355  if (numEstimators > numLow) {
356  sort(eLossEstimators.begin(), eLossEstimators.end());
357  const int nTot = numEstimators + numLow;
358  const int indMed = nTot / 2;
359  const double eMed =
360  (nTot % 2 == 0) ? 0.5 * (eLossEstimators[indMed - 1] + eLossEstimators[indMed]) : eLossEstimators[indMed]; // median
361  vector<double> absDev;
362  for (unsigned int i = 0; i < numEstimators; ++i)
363  absDev.push_back(abs(eLossEstimators[i] - eMed));
364  sort(absDev.begin(), absDev.end());
365  const double eMAD = (nTot % 2 == 0) ? 0.5 * (absDev[indMed - 1] + absDev[indMed]) : absDev[indMed]; // median of absolute deviations, sigma(gauss) = 1.4826 * MAD
366  const float ndEdx = nTot;
367  const float dEdx = 1.0 / (eMed * eMed);
368  const float dEdxError = 2. * 1.4826 * eMAD * dEdx / eMed / sqrt(ndEdx);
369  streamlog_out(DEBUG) << " dEdx " << ndEdx << " " << dEdx << " " << dEdxError << endl;
370  theTrack->setdEdx(dEdx);
371  theTrack->setdEdxError(dEdxError);
372  }
373  // and finally add the hits to the track
374  for (vector<TrackerHit*>::const_iterator theHit = seedTrack->getTrackerHits().begin(), hitEnd =
375  seedTrack->getTrackerHits().end(); theHit < hitEnd; ++theHit)
376  theTrack->addHit(*theHit);
377 
378  streamlog_out(DEBUG) << " +++ the fitted track has a chi^2 value of " << _chisquare << " for ndf = " << _ndf
379  << " and the parameters [omega, tanLambda, phi0, d0, z0] = [" << theTrack->getOmega() << "," << theTrack->getTanLambda()
380  << "," << theTrack->getPhi() << "," << theTrack->getD0() << "," << theTrack->getZ0() << "]." << endl;
382  outputTrackCollection->addElement(theTrack);
383  }
384  }
385  // cleanup
386  if (_trajectory) delete _trajectory;
387  }
388  // final storage to the event
389  if (_outputIsPersistent) evt->addCollection(outputTrackCollection, _outputTrackCollectionName);
390 }
391 
393 }
394 
396  // close Millepede-II binary file
397  if (_milleBinary) delete _milleBinary;
398 }
399 
401 
412 void StepWiseHelixGeneralBrokenLineInterfaceProcessor::calcLineSeed(const std::vector<TrackerHit*> hitList, const double* refPos,
413  double& omega, double& phi, double& d0, double& tanLambda, double& z0) const {
414  //
415  TMatrixD xyzr(2, 4);
416  for (vector<TrackerHit*>::const_iterator theHit = hitList.begin(), hitEnd = hitList.end(); theHit < hitEnd; ++theHit) {
417  const EVENT::TrackerHit& aHit = **theHit;
418  const double x = aHit.getPosition()[0];
419  const double y = aHit.getPosition()[1];
420  const double z = aHit.getPosition()[2];
421  const double r = sqrt(pow(x, 2) + pow(y, 2));
422  if (xyzr[0][3] == 0.) // for first hit
423  {
424  xyzr[0][0] = x;
425  xyzr[0][1] = y;
426  xyzr[0][2] = z;
427  xyzr[0][3] = r;
428  xyzr[1][0] = x;
429  xyzr[1][1] = y;
430  xyzr[1][2] = z;
431  xyzr[1][3] = r;
432  }
433  if (r < xyzr[0][3]) // new innermost hit
434  {
435  xyzr[0][0] = x;
436  xyzr[0][1] = y;
437  xyzr[0][2] = z;
438  xyzr[0][3] = r;
439  }
440  if (r > xyzr[1][3]) // new outermost hit
441  {
442  xyzr[1][0] = x;
443  xyzr[1][1] = y;
444  xyzr[1][2] = z;
445  xyzr[1][3] = r;
446  }
447  }
448  const double dx = xyzr[1][0] - xyzr[0][0];
449  const double dy = xyzr[1][1] - xyzr[0][1];
450  const double dz = xyzr[1][2] - xyzr[0][2];
451  const double dr = sqrt(pow(dx, 2) + pow(dy, 2));
452  const double x1 = xyzr[0][0] - refPos[0];
453  const double y1 = xyzr[0][1] - refPos[1];
454  const double z1 = xyzr[0][2] - refPos[2];
455  // new track parameters
456  omega = 0.;
457  phi = atan2(dy, dx);
458  d0 = y1 * cos(phi) - x1 * sin(phi);
459  tanLambda = dz / dr;
460  z0 = z1 - tanLambda * (x1 * cos(phi) + y1 * sin(phi));
461  //cout << " new seed " << phi << ", " << d0 << ", " << tanLambda << ", " << z0 << endl;
462 }
463 
464 } // close namespace brackets
465 #endif // conditional compilation if GBL program package is available on the system
TVectorD getResiduals() const
Get residuals.
simpleHelix getSimpleHelix() const
Get simple helix.
TMatrixD propagateTo(const double *, const double)
Propagate stepwise (close) to point.
const bool isSelected() const
Get selection flag.
unsigned int getNumGlobals() const
Get number of global derivatives.
bool isMeasurement() const
Get measurement flag.
int _milleMinHits
defines minimum number of hits on track for output to Millepede binary file
TMatrixD perigeeToLCIOJacobian() const
Get transformation from helix to LCIO track parameters (at reference point)
bool isValid() const
Get flag for valid prediction.
bool _thickScatterer
selects thick (otherwise thin) scatterers for multiple scattering (default: false) ...
TMatrixDSym getPrecision() const
Get precision.
void getPosAtArcLength(const double, double *) const
Get position (on helix) at arc length.
std::string _fitOptions
list of iterations with &#39;h&#39; Huber, &#39;t&#39; Tukey or &#39;c&#39; Cauchy down-weighting
void calcLineSeed(const std::vector< TrackerHit *>, const double *, double &, double &, double &, double &, double &) const
Simple seed for straight line.
bool _outputIsPersistent
whether the output is to be stored or not (default: true)
double _defaultMomentum
default momentum for multiple scattering (for Bfield off, GeV) (default: 10.)
TMatrixD curvilinearToPerigeeJacobian() const
Get transformation from curivilinear to perigee track parameters (at reference point) ...
User defined class to select tracks for Millepede-II.
int _milleCalcMethod
defines which parameter should be calculated for Millepede-II binary file
double getEScaled() const
Get scaled Edep.
std::vector< int > getGlobalLabels() const
Get labels for global derivatives.
std::string _inputCollectionName
Name of the input collection – track seeds.
TMatrixD getLocalToMeasurementProjection() const
Get projection from local to measurement system.
const TMatrixD & getGlobalDerivatives() const
Get global derivatives.
StepWiseHelixGeneralBrokenLineInterfaceProcessor aStepWiseHelixGeneralBrokenLineInterfaceProcessor
double getArcLengthXY(const double *) const
Get (2D) arc length for given point.
double _x0PerUnitLength
X0 per unit length (TPC gas as homogeneous scatterer) (default: 0.)