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