MyMarlinTPC  170316
RowBasedPadPulseRoadSearchProcessor.cc
Go to the documentation of this file.
1 // #ifdef USE_ROWPPRS
3 
5 
6 #include <iostream>
7 #include <string>
8 #include <ctime>
9 #include <cmath>
10 
11 //GEAR
12 #include <gear/TPCParameters.h>
13 #include <gear/BField.h>
14 #include <gearimpl/Vector3D.h>
15 
16 // include what you need from lcio
17 #include <EVENT/LCEvent.h>
18 #include <IMPL/LCCollectionVec.h>
19 #include <UTIL/BitField64.h>
20 #include <UTIL/ILDConf.h>
21 #include <IMPL/TrackerHitImpl.h>
22 #include <IMPL/TrackImpl.h>
23 #include <IMPL/LCFlagImpl.h>
24 #include <Exceptions.h>
25 
26 // the common flag word definitions in MarlinTPC
27 #include "FlagwordDefinitions.h"
28 
29 using namespace lcio;
30 using namespace marlin;
31 using namespace std;
32 using namespace gear;
33 
34 namespace marlintpc {
35 
36 static bool comparePadRow(pb_Pulse* one, pb_Pulse* two) {
37  return ((one->getRow()) < (two->getRow())); // increasing
38 }
39 
40 static bool comparePadCol(pb_Pulse* one, pb_Pulse* two) {
41  return ((one->getColumn()) < (two->getColumn())); // increasing
42 }
43 
44 static bool compareRelCharge(pb_Pulse* one, pb_Pulse* two) {
45  return ((one->getRelCharge()) > (two->getRelCharge())); // decreasing
46 }
47 
48 static bool compareCharge(pb_Pulse* one, pb_Pulse* two) {
49  return ((one->getCharge()) > (two->getCharge())); // decreasing
50 }
51 
53 
55 RowBasedPadPulseRoadSearchProcessor::RowBasedPadPulseRoadSearchProcessor() :
56  Processor("RowBasedPadPulseRoadSearchProcessor") {
57  // the processor description
58  _description = "RowBasedPadPulseRoadSearchProcessor is intended to simultaneously find TPC hits and tracks";
59 
60  registerInputCollection(LCIO::TRACKERPULSE, "InputTrackerPulses", "Name of the input TrackerPulses collection",
61  _inputTrackerPulsesColName, string("TPCPulses"));
62 
63  registerOutputCollection(LCIO::TRACKERHIT, "OutputTrackerHits", "Name of the output TrackerHits collection",
64  _outputTrackerHitsColName, string("TPCHits"));
65 
66  registerOutputCollection(LCIO::TRACK, "OutputTracks", "Name of the output Track Collection", _outputTrackColName,
67  string("TPCTracks"));
68 
69  registerOptionalParameter("BFieldScaleFactor", "Scales magnetic field (map), use 1.0 (default) for field ON or 0.0 for field OFF",
70  _bfieldScaleFactor, double(1.0));
71 
72  registerOptionalParameter("DriftVelocity", "Drift velocity", _driftVelocity, double(74.0));
73 
74  registerOptionalParameter("MaxColDiffNeighbourhood", "Maximal column difference to pulse in neighbourhood", _maxColDiff, int(1));
75 
76  registerOptionalParameter("MaxTimeDiff", "Maximum drift time difference in neighboorhood/hit", _dtMax, double(80.0));
77 
78  registerOptionalParameter("MaxSeedsInRow", "Maximum number of seeding pulses in row", _maxSeedsInRow, int(10));
79 
80  registerOptionalParameter("MinRowDiff", "Minimum row difference for pulse pair seeding road", _minRowDiff, int(5));
81 
82  registerOptionalParameter("MaxDxyRoad", "Maximum interpolation deviation in XY (road search)", _maxDxyRoad, double(2.0));
83 
84  registerOptionalParameter("MaxDzRoad", "Maximum interpolation deviation in Z (road search)", _maxDzRoad, double(3.0));
85 
86  registerOptionalParameter("MinRowNum", "Minimum number of rows for segment seed", _minRows, int(6));
87 
88  registerOptionalParameter("MinRowDensity", "Minimum row 'density' for segment seed", _rowDensityCut, double(0.8));
89 
90  registerOptionalParameter("MaxVarXY", "Maximum (average) XY variance (unweighted Chi2/ndf) for segment seed", _maxVarXY,
91  double(0.25));
92 
93  registerOptionalParameter("MaxOverlapFraction", "Maximum overlap fraction of segment seeds", _maxOverlapFraction, double(0.5));
94 
95  registerOptionalParameter("MaxColDiffHit", "Maximum distance of pad to seed in hit (if > 0)", _maxColDiffHit, int(0));
96 
97  registerOptionalParameter("MinNumPulses", "Minimum number of pulses in hit", _minNumPulses, int(2));
98 
99  registerOptionalParameter("MaxColGap", "Maximum column gap in hit", _maxColGap, int(1));
100 
101  registerProcessorParameter("OffsetCol", "sigma0^2 in column direction", _offsetCol, double(0.0085));
102 
103  registerProcessorParameter("SlopeCol", "diffusion in column direction", _slopeCol, double(0.00011));
104 
105  registerProcessorParameter("OffsetDrift", "sigma0^2 in drift direction", _offsetDrift, double(0.25));
106 
107  registerProcessorParameter("SlopeDrift", "diffusion term in drift direction", _slopeDrift, double(0.));
108 
109  registerProcessorParameter("OffsetRow", "sigma0^2 in row direction", _offsetRow, double(0.));
110 
111  registerProcessorParameter("SlopeRow", "diffusion in row direction", _slopeRow, double(0.));
112 
113  registerOptionalParameter("ChargeConversionFactor", "Optional: The charge conversion factor from ADC values to primary electrons",
114  _chargeConversionFactor, double(1.));
115 
116  registerOptionalParameter("SegmentMatchingChi2Cut", "Chi2/Ndf cut for segment matching (Ndf=4 for B off, 5 for B on)", _segCut,
117  double(30.0));
118 
119  registerOptionalParameter("ReferencePointAtPca", "Use PCA as reference point, else 1. hit", _refAtPCA, bool(false));
120 
121  registerOptionalParameter("SkipRoadSearch", "Skip road search, hit finding only", _skipRoadSearch, bool(false));
122 
123  registerOptionalParameter("SkipMultiplePulses", "Skip multiple pulse candidates as road search seeds", _skipMultiplePulses,
124  bool(true));
125 }
126 
129  streamlog_out(DEBUG) << " init() called " << endl;
130 
131  const gear::TPCParameters& tpcParameters = Global::GEAR->getTPCParameters();
132  bool cartesian = (tpcParameters.getCoordinateType() == PadRowLayout2D::CARTESIAN);
133  const std::vector<TPCModule*> moduleVector = tpcParameters.getModules();
134 
135  // get row offsets per module layer from module offset[0]
136  std::vector<double> xOffset;
137  for (std::vector<TPCModule*>::const_iterator itMod = moduleVector.begin(); itMod != moduleVector.end(); ++itMod) {
138  Vector2D offset = (*itMod)->getOffset();
139  xOffset.push_back(offset[0]);
140  }
141  sort(xOffset.begin(), xOffset.end());
142  // get list of (different) offsets
143  double eps = 0.1; // precision of offsets
144  std::vector<double> layerOffset;
145  layerOffset.push_back(xOffset.front());
146  for (std::vector<double>::iterator it = xOffset.begin() + 1; it != xOffset.end(); ++it)
147  if (abs(layerOffset.back() - (*it)) > eps) layerOffset.push_back(*it);
148  const int nLayer = layerOffset.size();
149  std::vector<int> layerRows(nLayer);
150  // get maximum number of rows per layer
151  for (std::vector<TPCModule*>::const_iterator itMod = moduleVector.begin(); itMod != moduleVector.end(); ++itMod) {
152  Vector2D offset = (*itMod)->getOffset();
153  int layer = 0;
154  while (abs(layerOffset[layer] - offset[0]) > eps)
155  layer++;
156  layerRows[layer] = max(layerRows[layer], (*itMod)->getNRows());
157  }
158 
159  streamlog_out(DEBUG) << " Number of modules: " << moduleVector.size() << endl;
160  for (std::vector<TPCModule*>::const_iterator itMod = moduleVector.begin(); itMod != moduleVector.end(); ++itMod) {
161  int module = (*itMod)->getModuleID();
162  Vector2D offset = (*itMod)->getOffset();
163  _moduleRowOffset[module] = 0;
164  int layer = 0;
165  while (abs(layerOffset[layer] - offset[0]) > eps) {
166  _moduleRowOffset[module] += layerRows[layer];
167  layer++;
168  }
169  streamlog_out(DEBUG) << " module " << module << " with " << (*itMod)->getNRows() << " rows, offset "
170  << _moduleRowOffset[module] << endl;
171  const std::vector<double> modExtend = (*itMod)->getLocalModuleExtent();
172 
173  Vector2D localOffset = (*itMod)->globalToLocal(offset[0], offset[1]);
174  for (std::vector<TPCModule*>::const_iterator itMod2 = itMod; itMod2 != moduleVector.end(); ++itMod2) {
175  if (areNeighbourModules(*itMod, *itMod2, cartesian)) {
176  _modNeighbours[module].push_back((*itMod2)->getModuleID());
177  streamlog_out(DEBUG) << " neighbour " << (*itMod2)->getModuleID() << endl;
178  }
179  }
180  }
181 
182  // TPC center
183  _Xcenter = tpcParameters.getDoubleVal("TPC_cylinder_centre_c0");
184  _Ycenter = tpcParameters.getDoubleVal("TPC_cylinder_centre_c1");
185 }
186 
188  // do something for each run
189 }
190 
193  std::clock_t start1 = std::clock();
194 
195  streamlog_out(DEBUG) << "Event Number: " << evt->getEventNumber() << endl;
196 
197  //get input collection
198  LCCollection* inputCol = 0;
199 
200  LCCollectionVec* outputHitCol = new LCCollectionVec(LCIO::TRACKERHIT);
201  //tpcHitCollection->setTransient(!_outputHitsPersistent);
202  // set the flags that cellID1 should be stored
203  LCFlagImpl hitFlag(0);
204  hitFlag.setBit(LCIO::RTHBIT_ID1);
205  outputHitCol->setFlag(hitFlag.getFlag());
206 
207  LCCollectionVec* outputTrackCol = new LCCollectionVec(LCIO::TRACK);
208  LCFlagImpl trkFlag(0);
209  trkFlag.setBit(LCIO::TRBIT_HITS);
210  outputTrackCol->setFlag(trkFlag.getFlag());
211 
212  // do a try / catch in case there is an empty event
213  try {
214  inputCol = evt->getCollection(_inputTrackerPulsesColName);
215  } catch (DataNotAvailableException &e) {
216  // no input data, just return and process the next event
217  return;
218  }
219 
220  Vector3D theTPCCenter(_Xcenter, _Ycenter, 0.);
221  Vector3D bfield = marlin::Global::GEAR->getBField().at(theTPCCenter);
222  const gear::TPCParameters& tpcParameters = Global::GEAR->getTPCParameters();
223 
224  const bool bOff(bfield.z() * _bfieldScaleFactor == 0.);
225  if (bOff) {
226  streamlog_out(DEBUG) << "BField(GEAR) is OFF" << std::endl;
227  } else {
228  streamlog_out(DEBUG) << "BField(GEAR) is ON" << std::endl;
229  }
230  // constant magnetic field (in z direction)
231  _Bzc = bfield.z() * _bfieldScaleFactor * 0.0002998; // Bz*c
232 
233  UTIL::BitField64 encoder(lcio::ILDCellID0::encoder_string);
234 
236  modPulseMapType pulseData;
237 
238  int nInput = inputCol->getNumberOfElements();
239  streamlog_out(DEBUG) << "Event " << evt->getEventNumber() << " in run " << evt->getRunNumber() << ", number of input pulses: "
240  << nInput << endl;
241 
242  double maxDriftLength = tpcParameters.getMaxDriftLength();
243  Vector2D globalPadCenter;
244  for (int iInput = 0; iInput < nInput; iInput++) {
245  TrackerPulse* aPulse = dynamic_cast<TrackerPulse*>(inputCol->getElementAt(iInput));
246  const int moduleID = aPulse->getCellID1();
247  const TPCModule& theModule = tpcParameters.getModule(moduleID);
248 
249  // coordinate system: z=0 at cathode, for large prototype the anode is in negative z-direction
250  // z-position is therefore: zAnode (max drift length, positive) - driftTime * driftVelocity
251  double zPosition = maxDriftLength - _driftVelocity * (aPulse->getTime()) / 1000.; // time is in [ns], drift velocity in [mm/mus]
252 
253  pb_Pulse* somePulse = new pb_Pulse(iInput, *aPulse, theModule, zPosition);
254  //somePulse->print();
255  pulseData[moduleID][somePulse->getRow()].push_back(somePulse);
256  }
257 
259  hitListType hitData;
260  int numHits = 0;
261  // map of modules with vectors of segments
262  modSegMapType segData;
263  for (modPulseMapType::iterator itMod = pulseData.begin(); itMod != pulseData.end(); ++itMod) {
264  const int moduleID = itMod->first;
265  streamlog_out(DEBUG) << " === Module " << moduleID << std::endl;
266  const TPCModule& theModule = tpcParameters.getModule(moduleID);
267  rowPulseMapType modData = itMod->second; // rows with pulses in module
268  pulseListType leadingPulses, trailingPulses, seedingPulses; // pulses in module
270  for (rowPulseMapType::iterator itRow = modData.begin(); itRow != modData.end(); ++itRow) {
271  //std::cout << " Row " << itRow->first << std::endl;
272  // sort row by column
273  sort(itRow->second.begin(), itRow->second.end(), comparePadCol);
274  for (pulseListType::iterator itP1 = itRow->second.begin(); itP1 != itRow->second.end() - 1; ++itP1) {
275  int col1 = (*itP1)->getColumn();
276  int colLast = col1; // last (neighbour) column
277  for (pulseListType::iterator itP2 = itP1 + 1; itP2 != itRow->second.end(); ++itP2) {
278  int col2 = (*itP2)->getColumn();
279  // out of neighbourhood?
280  if (col2 > col1 + _maxColDiff or col2 > colLast + 1) break;
281  // matching in time?
282  if (abs((*itP1)->getTime() - (*itP2)->getTime()) < _dtMax) {
283  colLast = col2;
284  (*itP1)->addNeighbour(*itP2);
285  (*itP2)->addNeighbour(*itP1);
286  }
287  }
288  }
289  // split into leading and trailing pulses, set index
290  const int numSeeding = seedingPulses.size();
291  for (pulseListType::iterator itP = itRow->second.begin(); itP != itRow->second.end(); ++itP) {
292  (*itP)->setIndex(itP - itRow->second.begin());
293  if ((*itP)->getRelCharge() > 1.0) {
294  leadingPulses.push_back(*itP);
295  if (pulseflag::isMultiplePulseCandidate((*itP)->getQuality()) and _skipMultiplePulses) continue; // skip for road seeding
296  if ((*itP)->isMaxPulse()) seedingPulses.push_back(*itP); // take largest pulse from neighbourhood
297  } else
298  trailingPulses.push_back(*itP);
299  }
300  // too many seeding pulses in row?
301  if (seedingPulses.size() > static_cast<unsigned int>(numSeeding + _maxSeedsInRow)) seedingPulses.resize(numSeeding); // skip row
302  }
303  if (_skipRoadSearch) seedingPulses.clear(); // only hit finding
304  streamlog_out(DEBUG) << " pulses (leading, seeding, trailing) " << leadingPulses.size() << " " << seedingPulses.size() << " "
305  << trailingPulses.size() << " " << std::endl;
306  // sort row by relative charge
307  sort(seedingPulses.begin(), seedingPulses.end(), compareRelCharge);
309  seedListType seedList;
310  pulseListType insidePulses; // (leading or trailing) pulses inside road
311  insidePulses.reserve(max(leadingPulses.size(), trailingPulses.size()));
312  // number of segment seeds
313  int numSegSeeds = 0;
314  // loop over pairs (of (unused) seeding pulses)
315  double pos1[3], pos2[3];
316  for (pulseListType::iterator itP1 = seedingPulses.begin(); itP1 != seedingPulses.end(); ++itP1) {
317  if ((*itP1)->inSeed()) continue;
318  const int row1 = (*itP1)->getRow();
319  (*itP1)->getPos(pos1);
320  //std::cout << " -seed pulse 1 " << row1 << " " << (*itP1)->getColumn() << " " << (*itP1)->getRelCharge() << std::endl;
321  for (pulseListType::iterator itP2 = itP1 + 1; itP2 != seedingPulses.end(); ++itP2) {
322  if ((*itP2)->inSeed()) continue;
323  const int row2 = (*itP2)->getRow();
324  if (abs(row1 - row2) >= _minRowDiff) {
325  // (straight line) road candidate
326  //std::cout << " seed pulse 2 " << row2 << " " << (*itP2)->getColumn() << " " << (*itP2)->getRelCharge() << std::endl;
327  (*itP2)->getPos(pos2);
328  const double dx(pos2[0] - pos1[0]), dy(pos2[1] - pos1[1]), dz(pos2[2] - pos1[2]), dist = sqrt(dx * dx + dy * dy);
329  const double ex(dx / dist), ey(dy / dist), dzds(dz / dist);
330  //std::cout << " par " << dist << " " << ex << " " << ey << " " << dzds << std::endl;
331  insidePulses.clear();
332  int numNearPulses = 0;
333  for (pulseListType::iterator itP = leadingPulses.begin(); itP != leadingPulses.end(); ++itP) {
334  (*itP)->getPos(pos2);
335  const double dx(pos2[0] - pos1[0]), dy(pos2[1] - pos1[1]), dxy(dy * ex - dx * ey);
336  const double ds(dx * ex + dy * ey), dz(pos2[2] - pos1[2] - ds * dzds);
337  //std::cout << " dist " << (*itP)->getRow() << " " << ds << " " << dxy << " " << dz << std::endl;
338  if (abs(dxy) < _maxDxyRoad and abs(dz) < _maxDzRoad)
339  insidePulses.push_back(*itP);
340  else if (abs(dxy) < 2. * _maxDxyRoad and abs(dz) < 2. * _maxDzRoad) numNearPulses++;
341  }
342  //std::cout << " inside " << insidePulses.size() << " near " << numNearPulses << std::endl;
343  // too few pulses found?
344  if (insidePulses.size() < static_cast<unsigned int>(_minRows)) continue;
345  // create seed from pulses
346  pb_Seed* someSeed = new pb_Seed(numSegSeeds, _Bzc, insidePulses, _minRows, _rowDensityCut, _maxVarXY);
347  if (!someSeed->getValid()) {
348  delete someSeed;
349  continue;
350  }
351  // iterate seed?
352  if (numNearPulses > 0) {
353  someSeed->roadSearch(leadingPulses, insidePulses, _maxDxyRoad, _maxDzRoad);
354  delete someSeed;
355  pb_Seed* iteratedSeed = new pb_Seed(numSegSeeds, _Bzc, insidePulses, _minRows, _rowDensityCut, _maxVarXY);
356  if (!iteratedSeed->getValid()) {
357  delete iteratedSeed;
358  continue;
359  }
360  // use iterated seed
361  someSeed = iteratedSeed;
362  }
363  // valid seed
364  someSeed->markPulses();
365  //std::cout << " --> accepted " << numSegSeeds << std::endl;
366  numSegSeeds++;
367  seedList.push_back(someSeed);
368  break;
369  }
370  }
371  }
372 
374  while (true) {
375  seedListType::iterator itWorst = seedList.end();
376  double worstFraction = _maxOverlapFraction;
377  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS) {
378  if (!(*itS)->getValid()) continue;
379  int numUnique = (*itS)->getNumUniqueSeedPulses();
380  int numAll = (*itS)->getNumSeedPulses();
381  if (numUnique < 4) numUnique = -1; // require minimum number of unique pulses
382  double fraction = double(numUnique) / double(numAll);
383  if (fraction < worstFraction) {
384  worstFraction = fraction;
385  itWorst = itS;
386  }
387  }
388  if (itWorst == seedList.end()) break;
389  // invalidate worst
390  //std::cout << " remove overlap seed " << itWorst - seedList.begin() << " " << worstFraction << std::endl;
391  (*itWorst)->freePulses();
392  (*itWorst)->setInvalid();
393  }
394 
396  // remove ambigous pulses from seeds
397  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS) {
398  if (!(*itS)->getValid()) continue;
399  int numUnique = (*itS)->getNumUniqueSeedPulses();
400  int numAll = (*itS)->getNumSeedPulses();
401  if (numUnique < numAll) {
402  const int seedId = (*itS)->getSeedId();
403  //std::cout << " remove ambigous hits " << seedId << std::endl;
404  pulseListType allPulses = (*itS)->getPulseList();
405  pulseListType uniquePulses;
406  for (pulseListType::iterator itP = allPulses.begin(); itP != allPulses.end(); ++itP) {
407  if ((*itP)->getNumSeeds() < 2) uniquePulses.push_back(*itP);
408  }
409  pb_Seed* uniqueSeed = new pb_Seed(seedId, _Bzc, uniquePulses);
410  //uniqueSeed->print();
411  // replace seed
412  delete *itS;
413  *itS = uniqueSeed;
414  }
415  }
416  // (re)attach ambigous pulses to nearest seed
417  double pos[3], refPoint[3], par[5], xyPos, zPos, sArc, phi, lambda;
418  int numAmbigousPulses = 0;
419  int numReattachedPulses = 0;
420  for (pulseListType::iterator itP = leadingPulses.begin(); itP != leadingPulses.end(); ++itP) {
421  if ((*itP)->getNumSeeds() < 2) continue;
422  // resolve by distance
423  numAmbigousPulses += 1;
424  (*itP)->getCOG(pos);
425  seedIdListType seedIds = (*itP)->getSeedIdList();
426  int bestId = -1;
427  double bestDist = _maxDxyRoad;
428  for (seedIdListType::iterator itId = seedIds.begin(); itId != seedIds.end(); ++itId) {
429  pb_Seed* aSeed = seedList[*itId];
430  // construct helix
431  aSeed->getRefPoint(refPoint);
432  aSeed->getPar(par);
433  simpleHelix hlx(par, refPoint, _Bzc);
434  if (hlx.getExpectedPlanePos(pos, (*itP)->getPhiMeas(), xyPos, zPos, sArc, phi, lambda)) {
435  //std::cout << " expected pos " << xyPos << " " << zPos << std::endl;
436  if (abs(xyPos) < bestDist) {
437  bestId = *itId;
438  bestDist = abs(xyPos);
439  }
440  }
441  }
442  // clear seeds
443  (*itP)->clearSeeds();
444  // reattach
445  //std::cout << " reattach " << bestId << " " << bestDist << std::endl;
446  if (bestId >= 0) {
447  numReattachedPulses += 1;
448  (*itP)->addSeed(bestId);
449  seedList[bestId]->addPulse(*itP);
450  }
451  }
452  // update seeds with additional pulses
453  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS) {
454  if (!(*itS)->getValid()) continue;
455  if ((*itS)->hasAddedPulses()) {
456  pb_Seed* uniqueSeed = new pb_Seed((*itS)->getSeedId(), _Bzc, (*itS)->getPulseList());
457  //uniqueSeed->print();
458  // replace seed
459  delete *itS;
460  *itS = uniqueSeed;
461  }
462  }
463 
465  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS) {
466  if (!(*itS)->getValid()) continue;
467  int seedId = (*itS)->getSeedId();
468  (*itS)->roadSearch(trailingPulses, insidePulses, _maxDxyRoad, _maxDzRoad * 2.);
469  // add associations to pulses
470  for (pulseListType::iterator itP = insidePulses.begin(); itP != insidePulses.end(); ++itP)
471  (*itP)->addSeed(seedId);
472  }
473 
475  for (pulseListType::iterator itP = trailingPulses.begin(); itP != trailingPulses.end(); ++itP) {
476  if ((*itP)->getNumSeeds() < 2) continue;
477  // resolve by distance
478  numAmbigousPulses += 1;
479  (*itP)->getCOG(pos);
480  seedIdListType seedIds = (*itP)->getSeedIdList();
481  int bestId = -1;
482  double bestDist = _maxDxyRoad;
483  for (seedIdListType::iterator itId = seedIds.begin(); itId != seedIds.end(); ++itId) {
484  pb_Seed* aSeed = seedList[*itId];
485  // construct helix
486  aSeed->getRefPoint(refPoint);
487  aSeed->getPar(par);
488  simpleHelix hlx(par, refPoint, _Bzc);
489  if (hlx.getExpectedPlanePos(pos, (*itP)->getPhiMeas(), xyPos, zPos, sArc, phi, lambda)) {
490  //std::cout << " expected pos " << xyPos << " " << zPos << std::endl;
491  if (abs(xyPos) < bestDist) {
492  bestId = *itId;
493  bestDist = abs(xyPos);
494  }
495  }
496  }
497  // clear seeds
498  (*itP)->clearSeeds();
499  // reattach
500  //std::cout << " reattach " << bestId << " " << bestDist << std::endl;
501  if (bestId >= 0) {
502  numReattachedPulses += 1;
503  (*itP)->addSeed(bestId);
504  }
505  }
506 
508  // similar to the RowBasedHitFinderProcessor
509  // loop ober rows
510  for (rowPulseMapType::iterator itRow = modData.begin(); itRow != modData.end(); ++itRow) {
511  const int row = itRow->first;
512  const pulseListType rowPulses = itRow->second;
513  const int numPulses = rowPulses.size();
514  const int firstCol = theModule.getPadNumber(theModule.getPadsInRow(row).front());
515  const int lastCol = theModule.getPadNumber(theModule.getPadsInRow(row).back());
516  const int maxColDiffHit = _maxColDiffHit > 0 ? _maxColDiffHit : lastCol - firstCol; // cut on column difference ?
517  //std::cout << " Make hits in row " << row << " " << numPulses << ", " << firstCol << ".." << lastCol << std::endl;
518  // use (only) leading pulses to seed hits
519  pulseListType seedingPulses;
520  for (pulseListType::const_iterator itP = rowPulses.begin(); itP != rowPulses.end(); ++itP)
521  if ((*itP)->getRelCharge() > 1.0) seedingPulses.push_back(*itP);
522  pulseListType hitPulses;
523  hitPulses.reserve(numPulses);
524  // sort by charge
525  sort(seedingPulses.begin(), seedingPulses.end(), compareCharge);
526  for (pulseListType::iterator itP = seedingPulses.begin(); itP != seedingPulses.end(); ++itP) {
527  //(*itP)->print();
528  if ((*itP)->inHit()) continue;
529  // start hit with this pulse
530  const double tSeed = (*itP)->getTime();
531  const int indSeed = (*itP)->getIndex();
532  const int colSeed = (*itP)->getColumn();
533  hitPulses.clear();
534  hitPulses.push_back(*itP);
535  int qualityFlag = 0;
536  // segment seed ID of hit seed
537  int segSeedId = (*itP)->getSeedId();
538  //std::cout << " hitSeed " << colSeed << " " << indSeed << " " << segSeedId << ", " << (*itP)->getPadId() << std::endl;
539  // check previous/next pulses/columns
540  for (int iDir = -1; iDir <= 1; iDir += 2) {
541  int ind = indSeed + iDir;
542  int colLast = colSeed;
543  double dtLast = 0.;
544  while (ind >= 0 and ind < numPulses) {
545  pb_Pulse* somePulse = rowPulses[ind];
546  ind += iDir;
547  if (somePulse->inHit()) continue; // skip used pulses
548  const int col = somePulse->getColumn();
549  const int colDiff = abs(col - colLast);
550  const int segId = somePulse->getSeedId();
551  const int maxGap = (segId >= 0) and (segId == segSeedId) ? _maxColGap : 0; // max. allowed column gap
552  if (colDiff > maxGap + 1) break; // empty (or dead?) pad (after last accepted pad)
553  if (abs(col - colSeed) > maxColDiffHit) break; // distance to seed too large
554  double dTime = abs(somePulse->getTime() - tSeed);
555  if (dTime > _dtMax) continue; // skip pulses not matching in time
556  if ((segId >= 0) and (segId != segSeedId)) {
558  continue; // skip pulses from different (segment) seed
559  }
560  // same column?
561  if (colDiff == 0) {
563  // take smaller time difference
564  if (dTime >= dtLast) continue; // skip new pulse
565  hitPulses.pop_back(); // remove last accepted pulse
566  } else {
567  // new column
568  if (colDiff > 1) hitflag::setDeadChannel(qualityFlag); // missing pad detected
569  // check charge for rerise, may indicate multiple hit
570  if (segId < 0)
571  if (somePulse->getCharge() > hitPulses.back()->getCharge()) hitflag::setMultipleHitCandidate(qualityFlag);
572  }
573  // accept pulse
574  hitPulses.push_back(somePulse);
575  colLast = col;
576  dtLast = dTime;
577  }
578  if (iDir < 0) {
579  if (colLast == firstCol) hitflag::setAtModuleBorder(qualityFlag); // at module border
580  // correct order
581  std::reverse(hitPulses.begin(), hitPulses.end());
582  } else if (colLast == lastCol) hitflag::setAtModuleBorder(qualityFlag); // at module border
583  }
584  //std::cout << " hit: " << colSeed << " " << hitPulses.front()->getColumn() << " " << hitPulses.back()->getColumn() << " " << hitPulses.size() << std::endl;
585  // to few pulses?
586  if (hitPulses.size() < static_cast<unsigned int>(_minNumPulses)) continue;
587  // hit accepted
588  (*itP)->setHitNum(numHits);
589  // calculate hit position
590  Vector2D localPadCenter;
591  double sumCharge = 0.;
592  double varCharge = 0.;
593  double sumChargePhiMeas = 0.;
594  double localPosition[2] = { 0., 0. };
595  for (pulseListType::iterator itHitP = hitPulses.begin(); itHitP != hitPulses.end(); ++itHitP) {
596  (*itHitP)->addToHit();
597  const double charge = (*itHitP)->getCharge();
598  localPadCenter = theModule.globalToLocal((*itHitP)->getX(), (*itHitP)->getY());
599  sumCharge += charge;
600  sumChargePhiMeas += charge * (*itHitP)->getPhiMeas();
601  localPosition[0] += charge * localPadCenter[0];
602  localPosition[1] += charge * localPadCenter[1];
603  }
604  Vector2D globalPosition2D = theModule.localToGlobal(localPosition[0] / sumCharge, localPosition[1] / sumCharge);
605  const double position[3] = { globalPosition2D[0], globalPosition2D[1], (*itP)->getZ() };
606  // calculate covariance matrix for hit position
607  float covMatrix[6] = { 0., 0., 0., 0., 0., 0. };
608  const double cosPhiMeas = cos(sumChargePhiMeas / sumCharge);
609  const double sinPhiMeas = sin(sumChargePhiMeas / sumCharge);
610  // variance in row direction
611  // Determine the covariance matrix according to the given resolution
612  const double zDrift = std::max(maxDriftLength - position[2], 0.);
613 
614  // Sigma squared along Z
615  const double zSigmaSquare = _offsetDrift + _slopeDrift * zDrift;
616  // Sigma squared in RPhi plane (azimuthal (Column) direction)
617  const double phiSigmaSquare = _offsetCol + _slopeCol * zDrift;
618  // Sigma squared in RPhi plane (radial (row) direction)
619  const double rSigmaSquare = _offsetRow + _slopeRow * zDrift;
620 
621  covMatrix[0] = pow(cosPhiMeas, 2) * phiSigmaSquare + pow(sinPhiMeas, 2) * rSigmaSquare;
622  covMatrix[1] = sinPhiMeas * cosPhiMeas * (phiSigmaSquare - rSigmaSquare);
623  covMatrix[2] = pow(sinPhiMeas, 2) * phiSigmaSquare + pow(cosPhiMeas, 2) * rSigmaSquare;
624  covMatrix[5] = float(zSigmaSquare);
625 
626  TrackerHitImpl* theHit = new TrackerHitImpl();
627  // theHit->setType(int type) ???
628  theHit->setPosition(position);
629  theHit->setCovMatrix(covMatrix);
630  //use the cellIDs of the seeding pad for the hit
631  theHit->setCellID1((*itP)->getPadId());
632  // encode CellID0
633  const int layer = row + _moduleRowOffset[moduleID];
634  encoder.reset();
635  encoder[ILDCellID0::subdet] = ILDDetID::TPC;
636  encoder[ILDCellID0::layer] = layer;
637  encoder[ILDCellID0::module] = moduleID;
638  theHit->setCellID0(encoder.lowWord());
639 
640  // add pulses
641  for (pulseListType::iterator itHitP = hitPulses.begin(); itHitP != hitPulses.end(); ++itHitP) {
642  TrackerPulse* aHitPulse = dynamic_cast<TrackerPulse*>(inputCol->getElementAt((*itHitP)->getPulseNum()));
643  theHit->rawHits().push_back(aHitPulse);
644 
645  // determine the quality bits from the pulses to let hit inherit them
646  int pulseQuality = aHitPulse->getQuality();
647  if (pulseflag::isSplit(pulseQuality)) hitflag::setSplitPulse(qualityFlag); // split pulse?
648  if (pulseflag::isOverflow(pulseQuality)) hitflag::setOverflowPulse(qualityFlag); // overflow
649  if (pulseflag::isAnomalousShape(pulseQuality)) hitflag::setAnomalousPulseShape(qualityFlag); // anomalous shape
650  if (pulseflag::isPlateauCutoff(pulseQuality)) hitflag::setPlateauCutoffPulse(qualityFlag); // anomalous shape
651  // variance of charge measurement
652  varCharge += aHitPulse->getCovMatrix()[0];
653  }
654  theHit->setQuality(qualityFlag);
655  // charge
656  theHit->setEDep(_chargeConversionFactor * sumCharge);
657  theHit->setEDepError(_chargeConversionFactor * sqrt(varCharge));
658 
659  // the time is inherited from the pulse with the largest charge
660  theHit->setTime((*itP)->getTime());
661 
662  // create row based hit
663  rb_Hit* someHit = new rb_Hit(numHits, moduleID, layer, *theHit);
664  hitData.push_back(someHit);
665 
666  outputHitCol->addElement(theHit);
667  numHits++;
668  }
669  }
671  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS) {
672  //(*itS)->print();
673  if (!(*itS)->getValid()) continue;
674  hitListType seedHits;
675  pulseListType seedPulses = (*itS)->getPulseList();
676  for (pulseListType::iterator itP = seedPulses.begin(); itP != seedPulses.end(); ++itP) {
677  const int iHit = (*itP)->getHitNum();
678  if (iHit >= 0) seedHits.push_back(hitData[iHit]);
679  }
680  rb_Segment* aSegment = new rb_Segment(_Bzc, seedHits, 1);
681  streamlog_out(DEBUG) << " segment " << seedHits.size() << " " << aSegment->getChi2() << " " << aSegment->getNdf()
682  << std::endl;
683  if (aSegment->getNdf() < 0)
684  delete aSegment;
685  else
686  segData[moduleID].push_back(aSegment);
687  }
688 
689  // cleanup seeds
690  for (seedListType::iterator itS = seedList.begin(); itS != seedList.end(); ++itS)
691  delete *itS;
692  }
693 
695  std::vector<std::pair<int, int> > segIndex;
696  simpleEquiClasses segEquiClass;
697  // create segment index
698  for (modSegMapType::iterator itMod = segData.begin(); itMod != segData.end(); ++itMod) {
699  //std::cout << " Segments in module " << itMod->first << std::endl;
700  segListType segments = itMod->second;
701  for (segListType::iterator itSeg = segments.begin(); itSeg != segments.end(); ++itSeg) {
702  (*itSeg)->setId(segIndex.size());
703  segIndex.push_back(make_pair(itMod->first, itSeg - segments.begin()));
704  segEquiClass.addIndex((*itSeg)->getId());
705  //std::cout << " " << (*itSeg)->getId() << " " << (*itSeg)->getFirstRow() << " " << (*itSeg)->getLastRow() << " " << (*itSeg)->getHitList().size() << std::endl;
706  }
707  }
708  // check segment matching with neighbour modules
709  segMatchListType segMatches;
710  for (modSegMapType::iterator itMod = segData.begin(); itMod != segData.end(); ++itMod) {
711  std::vector<int> neighbours = _modNeighbours[itMod->first];
712  segListType segments1 = itMod->second;
713  for (std::vector<int>::iterator itN = neighbours.begin(); itN != neighbours.end(); ++itN) {
714  segListType segments2 = segData[*itN];
715  for (segListType::iterator itSeg1 = segments1.begin(); itSeg1 != segments1.end(); ++itSeg1) {
716  for (segListType::iterator itSeg2 = segments2.begin(); itSeg2 != segments2.end(); ++itSeg2) {
717  // matching segments ?
718  if ((*itSeg1)->match(*itSeg2, _segCut, 0)) {
719  rb_SegmentMatch* someMatch = new rb_SegmentMatch(*itSeg1, *itSeg2);
720  //someMatch->print();
721  segMatches.push_back(someMatch);
722  }
723  }
724  }
725  }
726  }
727  // check for overlapping matches
728  segMatchMapType forwardMatches, backwardMatches;
729  for (segMatchListType::iterator itM = segMatches.begin(); itM != segMatches.end(); ++itM) {
730  forwardMatches[(*itM)->getSegId1()].push_back((*itM));
731  backwardMatches[(*itM)->getSegId2()].push_back((*itM));
732  }
733  // check forward matches
734  for (segMatchMapType::iterator itSid = forwardMatches.begin(); itSid != forwardMatches.end(); ++itSid) {
735  for (segMatchListType::iterator itM1 = itSid->second.begin(); itM1 != itSid->second.end() - 1; ++itM1) {
736  for (segMatchListType::iterator itM2 = itM1 + 1; itM2 != itSid->second.end(); ++itM2) {
737  if ((*itM1)->overlap(*itM2)) {
738  (*itM1)->setInvalid();
739  (*itM2)->setInvalid();
740  streamlog_out(DEBUG) << " overlap of forward matches " << (*itM1)->getSegId1() << " " << (*itM1)->getSegId2() << ", "
741  << (*itM2)->getSegId1() << " " << (*itM2)->getSegId2() << std::endl;
742  }
743  }
744  }
745  }
746  // check backward matches
747  for (segMatchMapType::iterator itSid = backwardMatches.begin(); itSid != backwardMatches.end(); ++itSid) {
748  for (segMatchListType::iterator itM1 = itSid->second.begin(); itM1 != itSid->second.end() - 1; ++itM1) {
749  for (segMatchListType::iterator itM2 = itM1 + 1; itM2 != itSid->second.end(); ++itM2) {
750  if ((*itM1)->overlap(*itM2)) {
751  (*itM1)->setInvalid();
752  (*itM2)->setInvalid();
753  streamlog_out(DEBUG) << " overlap of backward matches " << (*itM1)->getSegId1() << " " << (*itM1)->getSegId2() << ", "
754  << (*itM2)->getSegId1() << " " << (*itM2)->getSegId2() << std::endl;
755  }
756  }
757  }
758  }
759  // add valid matches
760  for (segMatchListType::iterator itM = segMatches.begin(); itM != segMatches.end(); ++itM)
761  if ((*itM)->getValid()) segEquiClass.addMatch(make_pair((*itM)->getSegId1(), (*itM)->getSegId2()));
762  // get classes with indices
763  std::map<int, std::vector<int> > segClasses = segEquiClass.getClasses();
764  segListType trackCandidates;
765  for (std::map<int, std::vector<int> >::iterator itC = segClasses.begin(); itC != segClasses.end(); ++itC) {
766  segListType matchingSegments;
767  for (std::vector<int>::iterator itInd = itC->second.begin(); itInd != itC->second.end(); ++itInd) {
768  std::pair<int, int> index = segIndex[*itInd];
769  matchingSegments.push_back(segData[index.first][index.second]);
770  }
771  trackCandidates.push_back(new rb_Segment(matchingSegments)); // save combined segments
772  }
773  streamlog_out(DEBUG) << " found " << numHits << " hits, " << trackCandidates.size() << " track candidates " << endl;
774 
776  for (segListType::iterator itSeg = trackCandidates.begin(); itSeg != trackCandidates.end(); ++itSeg) {
777  // new track
778  TrackImpl* theTrack = new TrackImpl();
779  // get hits
780  hitListType hits = (*itSeg)->getHitList();
781  // position of 1. hit
782  double posFirst[3];
783  hits.front()->getPos(posFirst);
784  // reference point, 1. hit or PCA (point of closest approach (to origin))
785  double refPos[] = { 0., 0., 0. };
786  if (!_refAtPCA) {
787  refPos[0] = posFirst[0];
788  refPos[1] = posFirst[1];
789  refPos[2] = posFirst[2];
790  }
791  float refPoint[3];
792  for (int i = 0; i < 3; ++i)
793  refPoint[i] = refPos[i];
794  // track parameters and covariance matrix
795  TVectorD parameters(5);
796  TMatrixDSym covariance(5);
797  (*itSeg)->getLCIOStateAtRefPoint(refPos, parameters, covariance); // ( d0, phi0, Omega, z0, tanLambda)
798 
799  theTrack->setOmega(parameters[2]);
800  theTrack->setTanLambda(parameters[4]);
801  theTrack->setPhi(parameters[1]);
802  theTrack->setD0(parameters[0]);
803  theTrack->setZ0(parameters[3]);
804  theTrack->setChi2((*itSeg)->getChi2());
805  theTrack->setNdf((*itSeg)->getNdf());
806  theTrack->setReferencePoint(refPoint);
807  /* prepare LCIO output; unknown parts:
808  *
809  * theTrack->setTypeBit (int index, bool val=true) // ?
810  * theTrack->setdEdx (float dEdx)
811  * theTrack->setdEdxError (float dEdxError) */
812  float rInner = sqrt(pow(posFirst[0], 2) + pow(posFirst[1], 2));
813  theTrack->setRadiusOfInnermostHit(rInner);
814  // compressed covariance matrix
815  float compressedCovariance[15];
816  int ind = 0;
817  for (int i = 0; i < 5; ++i)
818  for (int j = 0; j <= i; ++j)
819  compressedCovariance[ind++] = covariance[i][j];
820  theTrack->setCovMatrix(compressedCovariance);
821  // and finally add the hits to the track
822  for (hitListType::iterator itH = hits.begin(); itH != hits.end(); ++itH) {
823  TrackerHit* Hit = dynamic_cast<TrackerHit*>(outputHitCol->getElementAt((*itH)->getHitNum()));
824  theTrack->addHit(Hit);
825  }
826 
827  streamlog_out(DEBUG) << " +++ the found track has a chi^2 value of " << theTrack->getChi2() << " for ndf = "
828  << theTrack->getNdf() << " and the parameters [omega, tanLambda, phi0, d0, z0] = [" << theTrack->getOmega() << ","
829  << theTrack->getTanLambda() << "," << theTrack->getPhi() << "," << theTrack->getD0() << "," << theTrack->getZ0()
830  << "] at the reference position [" << refPoint[0] << "," << refPoint[1] << "," << refPoint[2] << "]." << endl;
831 
832  outputTrackCol->addElement(theTrack);
833  }
834 
835  streamlog_out(DEBUG) << "RowBasedPadPulseRoadSearch ... done!" << endl;
836 
837  outputHitCol->parameters().setValue("CellIDEncoding", ILDCellID0::encoder_string);
838  if (!outputHitCol->empty()) evt->addCollection(outputHitCol, _outputTrackerHitsColName);
839  if (!outputTrackCol->empty()) evt->addCollection(outputTrackCol, _outputTrackColName);
840 
841  streamlog_out(DEBUG) << ((std::clock() - start1) / (double) CLOCKS_PER_SEC) << " sec" << endl;
842 
843  // clean up
844  for (modPulseMapType::iterator itMod = pulseData.begin(); itMod != pulseData.end(); ++itMod) {
845  for (rowPulseMapType::iterator itRow = itMod->second.begin(); itRow != itMod->second.end(); ++itRow) {
846  for (pulseListType::iterator itP = itRow->second.begin(); itP != itRow->second.end(); ++itP) {
847  delete *itP;
848  }
849  }
850  }
851  pulseData.clear();
852  for (hitListType::iterator itH = hitData.begin(); itH != hitData.end(); ++itH)
853  delete *itH;
854  hitData.clear();
855  for (modSegMapType::iterator itMod = segData.begin(); itMod != segData.end(); ++itMod) {
856  for (segListType::iterator itSeg = itMod->second.begin(); itSeg != itMod->second.end(); ++itSeg) {
857  delete *itSeg;
858  }
859  }
860  segData.clear();
861  for (segMatchListType::iterator itM = segMatches.begin(); itM != segMatches.end(); ++itM)
862  delete *itM;
863  segMatches.clear();
864 }
865 
867  // check what is needed here
868 }
869 
871  // do something at the end of the processing, e.g. cleaning up
872 
873 }
874 
876 
882 bool RowBasedPadPulseRoadSearchProcessor::areNeighbourModules(gear::TPCModule* mod1, gear::TPCModule* mod2, bool cartesian) {
884  // are mod1 and mod2 neighbours?
885  if (mod1 == mod2) return false;
887  const std::vector<double> modExtend = mod1->getModuleExtent();
888  const double xm1 = 0.5 * (modExtend[1] + modExtend[0]), xs1 = 0.5 * (modExtend[1] - modExtend[0]);
889  const double ym1 = 0.5 * (modExtend[3] + modExtend[2]), ys1 = 0.5 * (modExtend[3] - modExtend[2]);
890  const std::vector<double> modExtend2 = mod2->getModuleExtent();
891  const double xm2 = 0.5 * (modExtend2[1] + modExtend2[0]), xs2 = 0.5 * (modExtend2[1] - modExtend2[0]);
892  const double ym2 = 0.5 * (modExtend2[3] + modExtend2[2]), ys2 = 0.5 * (modExtend2[3] - modExtend2[2]);
893  const double dx = xm2 - xm1, dy = ym2 - ym1;
894  return (pow(dx * dx + dy * dy, 2) / (pow((xs1 + xs2) * dx, 2) + pow((ys1 + ys2) * dy, 2)) < 2.);
895 }
896 
898 
904 pb_Pulse::pb_Pulse(const int iPulse, const EVENT::TrackerPulse& aPulse, const gear::TPCModule& aModule, const double zPos) :
905  _pulseNum(iPulse), _pulseModule(aPulse.getCellID1()), _pulsePadID(aPulse.getCellID0()), _pulseRow(
906  aModule.getRowNumber(_pulsePadID)), _pulseCol(aModule.getPadNumber(_pulsePadID)), _pulseQuality(aPulse.getQuality()), _pulseCharge(
907  aPulse.getCharge()), _pulseTime(aPulse.getTime()), _pulseX(aModule.getPadCenter(_pulsePadID)[0]), _pulseY(
908  aModule.getPadCenter(_pulsePadID)[1]), _pulseZ(zPos), _pulsePhiMeas(
909  (aModule.getLocalPadLayout().getCoordinateType() == gear::PadRowLayout2D::POLAR) ?
910  atan2((_pulseX - aModule.getOffset()[0]), (aModule.getOffset()[1] - _pulseY)) : aModule.getAngle()), _pulseDirX(
911  cos(_pulsePhiMeas)), _pulseDirY(sin(_pulsePhiMeas)), _firstCol(_pulseCol), _lastCol(_pulseCol), _maxCharge(0.), _sumCharge(
912  _pulseCharge), _sumChargeDist(0.), _seeds(), _inHit(false), _indexCol(-1), _hitNum(-1) {
913 }
914 
916 void pb_Pulse::print() const {
917  std::cout << " Pulse " << _pulseModule << " " << _pulseRow << " " << _pulseCol << " " << _pulseCharge << " " << _pulseTime
918  << std::endl;
919  std::cout << " " << _pulseX << " " << _pulseY << " " << _pulseZ << " " << _pulsePhiMeas << " " << _firstCol << " "
920  << _lastCol << " " << _sumCharge << " " << _sumChargeDist << std::endl;
921 }
922 
925  return _pulseNum;
926 }
927 
929 int pb_Pulse::getModule() const {
930  return _pulseModule;
931 }
932 
934 int pb_Pulse::getPadId() const {
935  return _pulsePadID;
936 }
937 
939 int pb_Pulse::getRow() const {
940  return _pulseRow;
941 }
942 
944 int pb_Pulse::getColumn() const {
945  return _pulseCol;
946 }
947 
949 int pb_Pulse::getQuality() const {
950  return _pulseQuality;
951 }
952 
954 double pb_Pulse::getCharge() const {
955  return _pulseCharge;
956 }
957 
959 double pb_Pulse::getRelCharge() const {
960  return (_lastCol + 1 - _firstCol) * _pulseCharge / _sumCharge;
961 }
962 
964 double pb_Pulse::getTime() const {
965  return _pulseTime;
966 }
967 
969 double pb_Pulse::getX() const {
970  return _pulseX;
971 }
972 
974 double pb_Pulse::getY() const {
975  return _pulseY;
976 }
977 
979 double pb_Pulse::getZ() const {
980  return _pulseZ;
981 }
982 
984 
987 void pb_Pulse::getPos(double* position) const {
988  position[0] = _pulseX;
989  position[1] = _pulseY;
990  position[2] = _pulseZ;
991 }
992 
994 
997 void pb_Pulse::getCOG(double* position) const {
998  position[0] = _pulseX + _pulseDirX * _sumChargeDist / _sumCharge;
999  position[1] = _pulseY + _pulseDirY * _sumChargeDist / _sumCharge;
1000  position[2] = _pulseZ;
1001 }
1002 
1004 double pb_Pulse::getPhiMeas() const {
1005  return _pulsePhiMeas;
1006 }
1007 
1009 
1012 void pb_Pulse::getMeasDir(double* direction) const {
1013  direction[0] = _pulseDirX;
1014  direction[1] = _pulseDirY;
1015 }
1016 
1018 
1022  _firstCol = min(_firstCol, aPulse->getColumn());
1023  _lastCol = max(_lastCol, aPulse->getColumn());
1024  _maxCharge = max(_maxCharge, aPulse->getCharge());
1025  _sumCharge += aPulse->getCharge();
1026  _sumChargeDist += aPulse->getCharge() * (_pulseDirX * (aPulse->getX() - _pulseX) + _pulseDirY * (aPulse->getY() - _pulseY));
1027 }
1028 
1030 bool pb_Pulse::isMaxPulse() const {
1031  return (_pulseCharge >= _maxCharge);
1032 }
1033 
1035 bool pb_Pulse::inSeed() const {
1036  return (_seeds.size() > 0);
1037 }
1038 
1041  return _seeds.size();
1042 }
1043 
1045 
1048 void pb_Pulse::addSeed(int s) {
1049  _seeds.push_back(s);
1050 }
1051 
1053 
1057  _seeds.remove(s);
1058 }
1059 
1062  _seeds.clear();
1063 }
1064 
1067  return _seeds;
1068 }
1069 
1071 int pb_Pulse::getSeedId() const {
1072  return _seeds.size() > 0 ? _seeds.front() : -1;
1073 }
1074 
1076 bool pb_Pulse::inHit() const {
1077  return _inHit;
1078 }
1079 
1082  _inHit = true;
1083 }
1084 
1086 int pb_Pulse::getIndex() const {
1087  return _indexCol;
1088 }
1089 
1091 
1094 void pb_Pulse::setIndex(int i) {
1095  _indexCol = i;
1096 }
1097 
1099 int pb_Pulse::getHitNum() const {
1100  return _hitNum;
1101 }
1102 
1104 
1107 void pb_Pulse::setHitNum(int i) {
1108  _hitNum = i;
1109 }
1110 
1112 
1120 pb_Seed::pb_Seed(const int seedId, const double Bzc, const pulseListType& pulses, const int minRows, const double rowDensityCut,
1121  const double maxVarXY) :
1122  _seedId(seedId), _bzc(Bzc), _checked(true), _numPulses(pulses.size()), _pulseList(pulses), _valid(false), _npar(
1123  (Bzc != 0.) ? 5 : 4), _parameters(_npar) {
1124  // count number of rows
1125  sort(_pulseList.begin(), _pulseList.end(), comparePadRow);
1126  int numRows = 1;
1127  int firstRow = _pulseList.front()->getRow();
1128  int lastRow = firstRow;
1129  for (pulseListType::iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1130  const int row = (*itP)->getRow();
1131  if (row > lastRow) {
1132  numRows++;
1133  lastRow = row;
1134  }
1135  }
1136  //std::cout << " pb_seed_checked " << _pulseList.size() << " " << numRows << " " << firstRow << " " << lastRow << std::endl;
1137  if (numRows < minRows or numRows < (lastRow + 1 - firstRow) * rowDensityCut) return;
1138  _fitSeed();
1139  // valid seed?
1140  _valid = (_varXY < maxVarXY);
1141 }
1142 
1144 
1149 pb_Seed::pb_Seed(const int seedId, const double Bzc, const pulseListType& pulses) :
1150  _seedId(seedId), _bzc(Bzc), _checked(false), _numPulses(pulses.size()), _pulseList(pulses), _valid(true), _npar(
1151  (Bzc != 0.) ? 5 : 4), _parameters(_npar) {
1152  // count number of rows
1153  sort(_pulseList.begin(), _pulseList.end(), comparePadRow);
1154  int numRows = 1;
1155  int firstRow = _pulseList.front()->getRow();
1156  int lastRow = firstRow;
1157  for (pulseListType::iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1158  const int row = (*itP)->getRow();
1159  if (row > lastRow) {
1160  numRows++;
1161  lastRow = row;
1162  }
1163  }
1164  //std::cout << " pb_seed_unchecked " << _pulseList.size() << " " << numRows << " " << firstRow << " " << lastRow << std::endl;
1165  _fitSeed();
1166 }
1167 
1169  // simple unweighted (sigma = 1.) fit with COG of largest pulses per row
1170  pulseListType fitPulses;
1171  pb_Pulse* largestPulse = _pulseList.front();
1172  for (pulseListType::iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1173  if ((*itP)->getRow() == largestPulse->getRow()) {
1174  if ((*itP)->getCharge() > largestPulse->getCharge()) largestPulse = *itP;
1175  } else {
1176  fitPulses.push_back(largestPulse);
1177  largestPulse = *itP;
1178  }
1179  }
1180  fitPulses.push_back(largestPulse);
1181  // reference point
1182  double pos1[3], pos2[3];
1183  fitPulses.front()->getPos(pos1);
1184  fitPulses.back()->getPos(pos2);
1185  _refX = 0.5 * (pos1[0] + pos2[0]);
1186  _refY = 0.5 * (pos1[1] + pos2[1]);
1187  _refZ = 0.5 * (pos1[2] + pos2[2]);
1188  double refPoint[] = { _refX, _refY, _refZ };
1189  int nParXY, nPointXY, nParZS, nPointZS;
1190  double pos[3], sArc, chi2XY, chi2ZS;
1191  double parameters[] = { 0., 0., 0., 0., 0. };
1192  // coarse unweighted xy fit
1193  simpleFitXY xyFit((_bzc != 0.), _refX, _refY);
1194  for (pulseListType::iterator itP = fitPulses.begin(); itP != fitPulses.end(); ++itP) {
1195  (*itP)->getCOG(pos);
1196  xyFit.addPoint(pos[0], pos[1], 1.0);
1197  }
1198  nParXY = xyFit.fit(chi2XY, nPointXY);
1199  //std::cout << " xyFit " << chi2XY << " " << nPointXY << " " << nParXY << std::endl;
1200  _varXY = chi2XY / (nPointXY - nParXY);
1201  _parameters.SetSub(0, xyFit.getPar());
1202  for (int i = 0; i < nParXY; ++i)
1203  parameters[3 - nParXY + i] = _parameters[i];
1204  // simple helix
1205  simpleHelix hlx(parameters, refPoint, _bzc);
1206  // coarse unweighted zs prefit
1207  simpleFitZS zsFit;
1208  for (pulseListType::iterator itP = fitPulses.begin(); itP != fitPulses.end(); ++itP) {
1209  (*itP)->getCOG(pos);
1210  sArc = hlx.getArcLengthXY(pos);
1211  zsFit.addPoint(sArc, pos[2] - _refZ, 1.0);
1212  }
1213  nParZS = zsFit.fit(chi2ZS, nPointZS);
1214  //std::cout << " zsFit " << chi2ZS << " " << nPointZS << std::endl;
1215  _varZS = chi2ZS / (nPointZS - nParZS);
1216  _parameters.SetSub(nParXY, zsFit.getPar());
1217 }
1218 
1220 void pb_Seed::print() const {
1221  std::cout << " seed " << _seedId << " " << _checked << ":" << _valid << " " << _pulseList.size() << " "
1222  << this->getNumUniqueSeedPulses() << " " << _pulseList.front()->getRow() << " " << _pulseList.front()->getColumn() << " "
1223  << _pulseList.back()->getRow() << " " << _pulseList.back()->getColumn() << " " << _varXY << " " << _varZS << std::endl;
1224 }
1225 
1227 int pb_Seed::getSeedId() const {
1228  return _seedId;
1229 }
1230 
1232 bool pb_Seed::getValid() const {
1233  return _valid;
1234 }
1235 
1238  _valid = false;
1239 }
1240 
1243  return _numPulses;
1244 }
1245 
1248  int num = 0;
1249  for (pulseListType::const_iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1250  if ((*itP)->getNumSeeds() < 2) num++;
1251  }
1252  return num;
1253 }
1254 
1257  return (_pulseList.size() > _numPulses);
1258 }
1259 
1261 
1265  _pulseList.push_back(aPulse);
1266 }
1267 
1269 
1272 void pb_Seed::getRefPoint(double* position) const {
1273  position[0] = _refX;
1274  position[1] = _refY;
1275  position[2] = _refZ;
1276 }
1277 
1279 
1282 void pb_Seed::getPar(double* par) const {
1283  par[0] = 0.;
1284  for (int i = 0; i < _npar; ++i)
1285  par[5 - _npar + i] = _parameters[i];
1286 }
1287 
1289 double pb_Seed::getVarXY() const {
1290  return _varXY;
1291 }
1292 
1295  for (pulseListType::iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1296  (*itP)->addSeed(_seedId);
1297  }
1298 }
1299 
1302  for (pulseListType::iterator itP = _pulseList.begin(); itP != _pulseList.end(); ++itP) {
1303  (*itP)->removeSeed(_seedId);
1304  }
1305 }
1306 
1309  return _pulseList;
1310 }
1311 
1313 
1319 void pb_Seed::roadSearch(pulseListType& pulses, pulseListType& insidePulses, const double maxDxy, const double maxDz) const {
1320  insidePulses.clear();
1321  if (!_valid) return;
1322  // construct helix
1323  double refPoint[3], par[5];
1324  this->getRefPoint(refPoint);
1325  this->getPar(par);
1326  simpleHelix hlx(par, refPoint, _bzc);
1327  // test pulses
1328  double pos[3], xyPos, zPos, sArc, phi, lambda;
1329  for (pulseListType::iterator itP = pulses.begin(); itP != pulses.end(); ++itP) {
1330  (*itP)->getCOG(pos);
1331  if (hlx.getExpectedPlanePos(pos, (*itP)->getPhiMeas(), xyPos, zPos, sArc, phi, lambda)) {
1332  //std::cout << " expected pos " << xyPos << " " << zPos << std::endl;
1333  if (abs(xyPos) < maxDxy and abs(zPos) < maxDz) insidePulses.push_back(*itP);
1334  }
1335  }
1336  //std::cout << " road search " << pulses.size() << " " << insidePulses.size() << std::endl;
1337 }
1338 
1340 
1344 rb_SegmentMatch::rb_SegmentMatch(const rb_Segment* segment1, const rb_Segment* segment2) :
1345  _segId1(segment1->getId()), _segId2(segment2->getId()), _firstRow1(segment1->getFirstRow()), _firstRow2(
1346  segment2->getFirstRow()), _lastRow1(segment1->getLastRow()), _lastRow2(segment2->getLastRow()), _valid(true) {
1347 }
1348 
1351  std::cout << " Segment match " << _segId1 << " " << _segId2 << ", " << _firstRow1 << " " << _firstRow2 << ", " << _lastRow1
1352  << " " << _lastRow2 << ", " << _valid << std::endl;
1353 }
1354 
1357  return _segId1;
1358 }
1359 
1362  return _segId2;
1363 }
1364 
1367  return _firstRow1;
1368 }
1369 
1372  return _firstRow2;
1373 }
1374 
1377  return _lastRow1;
1378 }
1379 
1382  return _lastRow2;
1383 }
1384 
1387  return _valid;
1388 }
1389 
1392  const int first1 = max(_firstRow1, aMatch->getFirstRow1());
1393  const int first2 = max(_firstRow2, aMatch->getFirstRow2());
1394  const int last1 = min(_lastRow1, aMatch->getLastRow1());
1395  const int last2 = min(_lastRow2, aMatch->getLastRow2());
1396  return first1 <= last1 and first2 <= last2;
1397 }
1398 
1401  _valid = false;
1402 }
1403 
1404 } // close namespace brackets
1405 
1406 // #endif //#ifdef USE_ROWPPRS
const int _firstRow1
first row of first segment
bool inHit() const
Is used by hit.
int fit(double &, int &)
Perform fit.
virtual void processEvent(EVENT::LCEvent *evt)
Process event.
const double _pulsePhiMeas
measurement direction in XY (tangential to row)
int getNdf() const
Get number of degrees of freedom (of segment fit).
double getY() const
Get Y coordinate.
std::vector< rb_SegmentMatch * > segMatchListType
const double _bzc
magnetic field strength (Bz*c)
int getLastRow2() const
Get last row of second segment.
int getNumSeeds() const
Get number of seeds.
double _slopeRow
measurement variance: diffusion term in row direction
std::map< int, std::vector< int > > _modNeighbours
neighbour modules
void getCOG(double *) const
Get (COG) )position.
double getRelCharge() const
Get relative charge.
int getSeedId() const
Get (unique) seedId.
void clearSeeds()
Clear (list of) seeds.
double _offsetRow
measurement variance: sigma0^2 in row direction (use rowHeight^2/12. if < 0.)
bool inSeed() const
Is used by seed.
std::map< int, pulseListType > rowPulseMapType
int getHitNum() const
Get hit number.
std::map< int, int > _moduleRowOffset
row offsets per module layer
std::vector< pb_Pulse * > pulseListType
const pulseListType & getPulseList() const
Get list of pulses.
int getFirstRow2() const
Get first row of second segment.
Simultaneous hit and track finding (pad row based).
void addSeed(int)
Add (segment) seed.
double getCharge() const
Get charge.
std::map< int, segListType > modSegMapType
void setMultipleHitCandidate(int &r)
void setPlateauCutoffPulse(int &t)
double getVarXY() const
Get XY variance (unweighted Chi2/ndf).
pulseListType _pulseList
pointers to pulses
double _offsetDrift
measurement variance: sigma0^2 in drift direction
const int _lastRow2
last row of second segment
int _maxColDiffHit
maximum distance of pad to seed in hit (if > 0)
const double _pulseX
X position (local)
bool areNeighbourModules(gear::TPCModule *, gear::TPCModule *, bool)
Check if modules are neighbours.
void setOverflowPulse(int &m)
int _maxColDiff
maximal column difference to pulse in neighbourhood
std::map< int, std::vector< int > > getClasses()
Get equivalence classes.
void getRefPoint(double *) const
Get reference point.
const int _pulseNum
input pulse collection index
bool getExpectedPlanePos(const double *, const double, double &, double &, double &, double &, double &) const
Get expected position (and direction) in plane.
void getMeasDir(double *) const
Get measurement direction.
int getSegId1() const
Get ID of first segment.
double _maxOverlapFraction
maximum overlap fraction of segment seeds
bool getValid() const
Get validity flag.
int getIndex() const
Get (column) index.
int getNumSeedPulses() const
Get number of seed pulses.
void addPoint(double, double, double)
Add point.
std::string _outputTrackerHitsColName
Name of the TPC hit output collection.
const unsigned int _numPulses
number of pulses
std::string _inputTrackerPulsesColName
Name of the TPc pulse input collection.
TVectorD _parameters
parameter vector
void markPulses()
Mark pulses as used.
double _dtMax
maximum drift time difference in neighboorhood/hit
double _rowDensityCut
minimum row &#39;density&#39; for segment seed
double _sumCharge
sum of charge in local neigbourhood
int _firstCol
start (column) of local neigbourhood
void addNeighbour(pb_Pulse *)
Add neighbour.
std::string _outputTrackColName
Name of the track output collection.
pb_Seed(const int seedID, const double Bzc, const pulseListType &pulses, const int minRows, const double rowDensityCut, const double maxVarXY)
Construct pad based seed with checks.
int fit(double &, int &)
Perform fit.
double getZ() const
Get Z coordinate.
double _varZS
chi2/ndf from (unweighted) ZS fit
rb_SegmentMatch(const rb_Segment *segment1, const rb_Segment *segment2)
Construct row based segment match.
const double _pulseY
Y position (local)
double _maxDxyRoad
maximum interpolation deviation in XY (road search)
void roadSearch(pulseListType &pulses, pulseListType &insidePulses, const double maxDxy, const double maxDz) const
Road search.
double _maxCharge
maximum charge in local neigbourhood
int _indexCol
index in list of pulses per row
int _maxSeedsInRow
maximum number of seeding pulses in row
const double _pulseDirY
measurement direction in Y
int _minRowDiff
minimum row difference for pulse pair seeding road
Pad based (track segment) seed.
double getX() const
Get X coordinate.
bool isMultiplePulseCandidate(int i)
std::vector< rb_Segment * > segListType
std::vector< rb_Hit * > hitListType
void setIndex(int)
Set (column) index.
const int _lastRow1
last row of first segment
TVectorD getPar() const
Get parameters vector.
double _varXY
chi2/ndf from (unweighted) XY fit
bool hasAddedPulses() const
Get flag for added pulses.
int getLastRow1() const
Get last row of first segment.
void addPoint(double, double, double)
Add point.
double _segCut
Chi2/Ndf cut for segment matching (Ndf=4 for B off, 5 for B on)
bool _inHit
flag for being part of a hit
int _lastCol
end (column) of local neigbourhood
double _maxVarXY
maximum (average) XY variance (unweighted Chi2/ndf) for segment seed
void getPos(double *) const
Get (pad) position.
seedIdListType _seeds
list of seeds (using pulse)
double _slopeCol
measurement variance: diffusion term in column direction
bool _refAtPCA
Use Pca as reference point (else 1. hit)
double _sumChargeDist
sum of charge*distance (to pulse) in local neigbourhood
int getPulseNum() const
Get pulse number.
bool isMaxPulse() const
Is pulse with maximal charge in neighbourhood.
const double _pulseDirX
measurement direction in X
const seedIdListType & getSeedIdList() const
Get list of seeds.
void removeSeed(int)
Remove (segment) seed.
int getFirstRow1() const
Get first row of first segment.
void addPulse(pb_Pulse *)
Add pulse.
double getArcLengthXY(const double *) const
Get (2D) arc length for given point.
double _refZ
Z of reference point.
double _refX
X of reference point.
int getNumUniqueSeedPulses() const
Get number of unique seed pulses.
std::map< int, segMatchListType > segMatchMapType
const int _firstRow2
first row of second segment
bool _skipMultiplePulses
skip multiple pulse candidates as road search seeds
void getPar(double *) const
Get (all five helix) parameters from segment fit.
double getChi2() const
Get chi2 from segment fit.
double _offsetCol
measurement variance: sigma0^2 in column direction
pb_Pulse(const int iPulse, const EVENT::TrackerPulse &aPulse, const gear::TPCModule &aModule, const double zPos)
Construct pad based Pulse.
RowBasedPadPulseRoadSearchProcessor aRowBasedPadPulseRoadSearchProcessor
std::vector< pb_Seed * > seedListType
TVectorD getPar() const
Get parameters vector.
std::map< int, rowPulseMapType > modPulseMapType
bool overlap(rb_SegmentMatch *) const
Check for (row) overlap.
double _slopeDrift
measurement variance: diffusion term in drift direction
void setAtModuleBorder(int &k)
int getSegId2() const
Get ID of second segment.
void setAnomalousPulseShape(int &p)
double _maxDzRoad
maximum interpolation deviation in Z (road search)
double _refY
Y of reference point.
double _chargeConversionFactor
charge conversion factor from ADC values to primary electrons
double getPhiMeas() const
Get measurement angle.
int _npar
number of parameters (5: helix, 4: line)
void addMatch(std::pair< int, int >)
Add match.
double _bfieldScaleFactor
scale factor for magnetic field (default: 1.0)