Belle II Software  release-08-01-10
CDCTriggerHoughtrafo.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <trg/cdc/modules/houghtracking/CDCTrigger2DFinderModule.h>
10 
11 #include <framework/logging/Logger.h>
12 
13 #include <cmath>
14 
15 #include <root/TMatrix.h>
16 
17 /* defines */
18 #define CDC_SUPER_LAYERS 9
19 
20 using namespace std;
21 using namespace Belle2;
22 
23 unsigned short
24 CDCTrigger2DFinderModule::countSL(bool* layer)
25 {
26  if (m_requireSL0 && !layer[0]) return 0;
27  unsigned short lcnt = 0;
28  for (int i = 0; i < CDC_SUPER_LAYERS; ++i) {
29  if (layer[i] == true) ++lcnt;
30  }
31  return lcnt;
32 }
33 
34 bool
35 CDCTrigger2DFinderModule::shortTrack(bool* layer)
36 {
37  unsigned short lcnt = 0;
38  // check axial super layers (even layer number),
39  // break at first layer without hit
40  for (int i = 0; i < CDC_SUPER_LAYERS; i += 2) {
41  if (layer[i] == true) ++lcnt;
42  else break;
43  }
44  return (lcnt >= m_minHitsShort);
45 }
46 
47 /*
48 * Find the intercept in hough space.
49 * In each iteration the Hough plane is divided in quarters.
50 * For each quarter containing enough hits, the process is repeated
51 * until the quarters correspond to single Hough cells.
52 * Return zero on success.
53 * x = m
54 * y = a
55 */
56 int
57 CDCTrigger2DFinderModule::fastInterceptFinder(cdcMap& hits,
58  double x1_s, double x2_s,
59  double y1_s, double y2_s,
60  unsigned iterations,
61  unsigned ix_s, unsigned iy_s)
62 {
63  string indent = "";
64  for (unsigned i = 0; i < iterations; ++i) indent += " ";
65  B2DEBUG(150, indent << "intercept finder iteration " << iterations
66  << " x1 " << x1_s * 180 / M_PI << " x2 " << x2_s * 180 / M_PI
67  << " y1 " << y1_s << " y2 " << y2_s
68  << " ix " << ix_s << " iy " << iy_s);
69 
70  int i, j, iHit;
71  double unitx, unity;
72  double y1, y2;
73  double m, a;
74  cdcPair hp;
75  unsigned short iSL;
76  // list of hit indices crossing the current rectangle
77  vector<unsigned> idx_list;
78 
79  // limits of divided rectangles
80  double x1_d, x2_d, y1_d, y2_d;
81 
82  // cell indices in full plane
83  unsigned ix, iy;
84 
85  unitx = ((x2_s - x1_s) / 2.0);
86  unity = ((y2_s - y1_s) / 2.0);
87 
88  // divide x axis in half
89  for (i = 0; i < 2 ; ++i) {
90  // divide y axis in half
91  for (j = 0; j < 2; ++j) {
92  x1_d = x1_s + i * unitx;
93  x2_d = x1_s + (i + 1) * unitx;
94  y1_d = y1_s + j * unity;
95  y2_d = y1_s + (j + 1) * unity;
96 
97  ix = 2 * ix_s + i;
98  iy = 2 * iy_s + j;
99 
100  // skip extra cells outside of the Hough plane
101  if (x2_d <= -M_PI || x1_d >= M_PI || y2_d <= -maxR + shiftR || y1_d >= maxR + shiftR) {
102  B2DEBUG(150, indent << "skip Hough cell outside of plane limits");
103  continue;
104  }
105 
106  // if the cell size in phi is too large, the hit calculation is not reliable
107  // -> continue to next iteration without hit check
108  if (iterations != maxIterations && unitx > M_PI / 2.) {
109  fastInterceptFinder(hits, x1_d, x2_d, y1_d, y2_d, iterations + 1, ix, iy);
110  continue;
111  }
112 
113  idx_list.clear();
114  bool layerHit[CDC_SUPER_LAYERS] = {false}; /* For layer filter */
115  for (auto it = hits.begin(); it != hits.end(); ++it) {
116  iHit = it->first;
117  hp = it->second;
118  iSL = hp.first;
119  m = hp.second.X();
120  a = hp.second.Y();
121  // calculate Hough curve with slightly enlarged limits to avoid errors due to rounding
122  y1 = m * sin(x1_d - 1e-10) - a * cos(x1_d - 1e-10);
123  y2 = m * sin(x2_d + 1e-10) - a * cos(x2_d + 1e-10);
124  // skip decreasing half of the sine (corresponds to curl back half of the track)
125  if (iterations == maxIterations && y1 > y2) continue;
126  if (!((y1 > y2_d && y2 > y2_d) || (y1 < y1_d && y2 < y1_d))) {
127  if (iterations == maxIterations) {
128  idx_list.push_back(iHit);
129  }
130  layerHit[iSL] = true; /* layer filter */
131  }
132  }
133  unsigned short nSL = countSL(layerHit);
134  B2DEBUG(150, indent << "i " << i << " j " << j
135  << " layerHit " << int(layerHit[0]) << int(layerHit[2])
136  << int(layerHit[4]) << int(layerHit[6]) << int(layerHit[8])
137  << " nSL " << nSL);
138  if (nSL >= m_minHits || shortTrack(layerHit)) {
139  if (iterations != maxIterations) {
140  fastInterceptFinder(hits, x1_d, x2_d, y1_d, y2_d, iterations + 1, ix, iy);
141  } else {
142  TVector2 v1(x1_d, y1_d);
143  TVector2 v2(x2_d, y2_d);
144  houghCand.push_back(CDCTriggerHoughCand(idx_list, make_pair(v1, v2),
145  nSL, houghCand.size()));
146  if (m_storePlane > 0) {
147  (*m_houghPlane)[ix - (nCells - m_nCellsPhi) / 2][iy - (nCells - m_nCellsR) / 2] = nSL;
148  }
149  }
150  } else if (m_storePlane > 1) {
151  // to store the full Hough plane, we need to continue the iteration
152  // to minimal cell size everywhere
153  for (unsigned min = m_minHits - 1; min > 0; --min) {
154  if (nSL >= min) {
155  if (iterations != maxIterations) {
156  fastInterceptFinder(hits, x1_d, x2_d, y1_d, y2_d, iterations + 1, ix, iy);
157  } else {
158  (*m_houghPlane)[ix - (nCells - m_nCellsPhi) / 2][iy - (nCells - m_nCellsR) / 2] = nSL;
159  }
160  break;
161  }
162  }
163  }
164  }
165  }
166 
167  return 0;
168 }
169 
170 /*
171 * Peak finding method: connected regions & center of gravity
172 */
173 void
174 CDCTrigger2DFinderModule::connectedRegions()
175 {
176  vector<vector<CDCTriggerHoughCand>> regions;
177  vector<CDCTriggerHoughCand> cpyCand = houghCand;
178 
179  // debug: print candidate list
180  B2DEBUG(50, "houghCand number " << cpyCand.size());
181  for (unsigned icand = 0; icand < houghCand.size(); ++icand) {
182  coord2dPair coord = houghCand[icand].getCoord();
183  B2DEBUG(100, houghCand[icand].getID()
184  << " nSL " << houghCand[icand].getSLcount()
185  << " x1 " << coord.first.X() << " x2 " << coord.second.X()
186  << " y1 " << coord.first.Y() << " y2 " << coord.second.Y());
187  }
188 
189  // combine connected cells to regions
190  while (cpyCand.size() > 0) {
191  B2DEBUG(100, "make new region");
192  vector<CDCTriggerHoughCand> region;
193  vector<CDCTriggerHoughCand> rejected;
194  CDCTriggerHoughCand start = cpyCand[0];
195  cpyCand.erase(cpyCand.begin());
196  region.push_back(start);
197  addNeighbors(start, cpyCand, region, rejected, start.getSLcount());
198  regions.push_back(region);
199  for (auto cand = cpyCand.begin(); cand != cpyCand.end();) {
200  if (inList(*cand, region) || inList(*cand, rejected))
201  cpyCand.erase(cand);
202  else
203  ++cand;
204  }
205  }
206 
207  // find center of gravity for each region
208  for (unsigned ir = 0; ir < regions.size(); ++ir) {
209  B2DEBUG(50, "region " << ir << " (" << regions[ir].size() << " cells).");
210  // skip regions with size below cut
211  if (regions[ir].size() < m_minCells) {
212  B2DEBUG(50, "Skipping region with " << regions[ir].size() << " cells.");
213  continue;
214  }
215  double xfirst = regions[ir][0].getCoord().first.X();
216  double x = 0;
217  double y = 0;
218  int n = 0;
219  vector<unsigned> mergedList;
220  int xmin = m_nCellsPhi;
221  int xmax = 0;
222  int ymin = m_nCellsR;
223  int ymax = 0;
224  vector<TVector2> cellIds = {};
225  for (unsigned ir2 = 0; ir2 < regions[ir].size(); ++ir2) {
226  coord2dPair hc = regions[ir][ir2].getCoord();
227  B2DEBUG(100, " " << regions[ir][ir2].getID()
228  << " nSL " << regions[ir][ir2].getSLcount()
229  << " x1 " << hc.first.X() << " x2 " << hc.second.X()
230  << " y1 " << hc.first.Y() << " y2 " << hc.second.Y());
231  int ix = floor((hc.first.X() + M_PI) / 2. / M_PI * m_nCellsPhi + 0.5);
232  int iy = floor((hc.first.Y() + maxR - shiftR) / 2. / maxR * m_nCellsR + 0.5);
233  x += (hc.first.X() + hc.second.X());
234  if (xfirst - hc.first.X() > M_PI) {
235  x += 4 * M_PI;
236  ix += m_nCellsPhi;
237  } else if (hc.first.X() - xfirst > M_PI) {
238  x -= 4 * M_PI;
239  ix -= m_nCellsPhi;
240  }
241  y += (hc.first.Y() + hc.second.Y());
242  n += 1;
243  vector<unsigned> idList = regions[ir][ir2].getIdList();
244  mergeIdList(mergedList, mergedList, idList);
245  xmin = min(xmin, ix);
246  xmax = max(xmax, ix);
247  ymin = min(ymin, iy);
248  ymax = max(ymax, iy);
249  cellIds.push_back(TVector2(ix, iy));
250  }
251  x *= 0.5 / n;
252  if (x > M_PI)
253  x -= 2 * M_PI;
254  else if (x <= -M_PI)
255  x += 2 * M_PI;
256  y *= 0.5 / n;
257  B2DEBUG(50, "x " << x << " y " << y);
258 
259  // select 1 hit per super layer
260  vector<unsigned> selectedList = {};
261  vector<unsigned> unselectedList = {};
262  selectHits(mergedList, selectedList, unselectedList);
263 
264  // save track
265  const CDCTriggerTrack* track =
266  m_tracks.appendNew(x, 2. * y, 0.);
267  // relations to selected hits
268  for (unsigned i = 0; i < selectedList.size(); ++i) {
269  unsigned its = selectedList[i];
270  track->addRelationTo(m_segmentHits[its]);
271  }
272  // relations to additional hits get a negative weight
273  for (unsigned i = 0; i < unselectedList.size(); ++i) {
274  unsigned its = unselectedList[i];
275  track->addRelationTo(m_segmentHits[its], -1.);
276  }
277  // save detail information about the cluster
278  const CDCTriggerHoughCluster* cluster =
279  m_clusters.appendNew(xmin, xmax, ymin, ymax, cellIds);
280  track->addRelationTo(cluster);
281  }
282 }
283 
284 void
285 CDCTrigger2DFinderModule::addNeighbors(const CDCTriggerHoughCand& center,
286  const vector<CDCTriggerHoughCand>& candidates,
287  vector<CDCTriggerHoughCand>& merged,
288  vector<CDCTriggerHoughCand>& rejected,
289  unsigned short nSLmax) const
290 {
291  for (unsigned icand = 0; icand < candidates.size(); ++icand) {
292  B2DEBUG(120, "compare center " << center.getID()
293  << " to " << candidates[icand].getID());
294  if (inList(candidates[icand], merged) || inList(candidates[icand], rejected)) {
295  B2DEBUG(120, " " << candidates[icand].getID() << " already in list");
296  continue;
297  }
298  bool reject = inList(center, rejected);
299  if (connected(center, candidates[icand])) {
300  if (m_onlyLocalMax && candidates[icand].getSLcount() < nSLmax) {
301  B2DEBUG(100, " lower than highest SLcount, rejected");
302  rejected.push_back(candidates[icand]);
303  } else if (m_onlyLocalMax && !reject && candidates[icand].getSLcount() > nSLmax) {
304  B2DEBUG(100, " new highest SLcount, clearing list");
305  nSLmax = candidates[icand].getSLcount();
306  for (unsigned imerged = 0; imerged < merged.size(); ++imerged) {
307  rejected.push_back(merged[imerged]);
308  }
309  merged.clear();
310  merged.push_back(candidates[icand]);
311  } else if (m_onlyLocalMax && candidates[icand].getSLcount() > center.getSLcount()) {
312  B2DEBUG(100, " connected to rejected cell, skip");
313  continue;
314  } else if (m_onlyLocalMax && reject) {
315  B2DEBUG(100, " connected to rejected cell, rejected");
316  rejected.push_back(candidates[icand]);
317  } else {
318  B2DEBUG(100, " connected");
319  merged.push_back(candidates[icand]);
320  }
321  vector<CDCTriggerHoughCand> cpyCand = candidates;
322  cpyCand.erase(cpyCand.begin() + icand);
323  addNeighbors(candidates[icand], cpyCand, merged, rejected, nSLmax);
324  }
325  }
326 }
327 
328 bool
329 CDCTrigger2DFinderModule::inList(const CDCTriggerHoughCand& a,
330  const vector<CDCTriggerHoughCand>& list) const
331 {
332  for (unsigned i = 0; i < list.size(); ++i) {
333  if (a == list[i]) return true;
334  }
335  return false;
336 }
337 
338 bool
339 CDCTrigger2DFinderModule::connected(const CDCTriggerHoughCand& a,
340  const CDCTriggerHoughCand& b) const
341 {
342  double ax1 = a.getCoord().first.X();
343  double ax2 = a.getCoord().second.X();
344  double ay1 = a.getCoord().first.Y();
345  double ay2 = a.getCoord().second.Y();
346  double bx1 = b.getCoord().first.X();
347  double bx2 = b.getCoord().second.X();
348  double by1 = b.getCoord().first.Y();
349  double by2 = b.getCoord().second.Y();
350  // direct neighbors
351  bool direct = ((ax2 == bx1 && ay1 == by1) || // right
352  (ax1 == bx2 && ay1 == by1) || // left
353  (ax1 == bx1 && ay2 == by1) || // above
354  (ax1 == bx1 && ay1 == by2) || // below
355  (ax1 + 2. * M_PI == bx2 && ay1 == by1) ||
356  (ax2 == bx1 + 2. * M_PI && ay1 == by1));
357  // diagonal connections
358  bool diagRise = ((ax2 == bx1 && ay2 == by1) || // right above
359  (ax1 == bx2 && ay1 == by2) || // left below
360  (ax1 + 2. * M_PI == bx2 && ay1 == by2) ||
361  (ax2 == bx1 + 2. * M_PI && ay2 == by1));
362  bool diagFall = ((ax1 == bx2 && ay2 == by1) || // left above
363  (ax2 == bx1 && ay1 == by2) || // right below
364  (ax2 == bx1 + 2. * M_PI && ay1 == by2) ||
365  (ax1 + 2. * M_PI == bx2 && ay2 == by1));
366  if (m_connect == 4) return direct;
367  else if (m_connect == 6) return (direct || diagRise);
368  else if (m_connect == 8) return (direct || diagRise || diagFall);
369  else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
370  return (direct || diagRise);
371 }
372 
373 /*
374 * Merge Id lists.
375 */
376 void
377 CDCTrigger2DFinderModule::mergeIdList(std::vector<unsigned>& merged,
378  std::vector<unsigned>& a,
379  std::vector<unsigned>& b)
380 {
381  bool found;
382 
383  for (auto it = a.begin(); it != a.end(); ++it) {
384  found = false;
385  for (auto it_in = merged.begin(); it_in != merged.end(); ++it_in) {
386  if (*it_in == *it) {
387  found = true;
388  break;
389  }
390  }
391  if (!found) {
392  merged.push_back(*it);
393  }
394  }
395 
396  for (auto it = b.begin(); it != b.end(); ++it) {
397  found = false;
398  for (auto it_in = merged.begin(); it_in != merged.end(); ++it_in) {
399  if (*it_in == *it) {
400  found = true;
401  break;
402  }
403  }
404  if (!found) {
405  merged.push_back(*it);
406  }
407  }
408 }
409 
410 void
411 CDCTrigger2DFinderModule::findAllCrossingHits(std::vector<unsigned>& list,
412  double x1, double x2,
413  double y1, double y2,
414  const cdcMap& inputMap)
415 {
416  double m, a, y1_h, y2_h;
417  for (int iHit = 0; iHit < m_segmentHits.getEntries(); iHit++) {
418  unsigned short iSL = m_segmentHits[iHit]->getISuperLayer();
419  if (iSL % 2) continue;
420  // associate only the hits actually used to form the cluster
421  if (m_suppressClone && inputMap.find(iHit) == inputMap.end()) continue;
422  //TODO: add options: center cell / active priority cell / all priority cells
423  vector<double> phi = {0, 0, 0};
424  phi[0] = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
425  phi[1] = phi[0] + 0.5;
426  phi[2] = phi[0] - 0.5;
427  vector<double> r = {radius[iSL][0], radius[iSL][1], radius[iSL][1]};
428  for (unsigned i = 0; i < 3; ++i) {
429  phi[i] *= 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
430  m = cos(phi[i]) / r[i];
431  a = sin(phi[i]) / r[i];
432  // calculate Hough curve with slightly enlarged limits to avoid errors due to rounding
433  y1_h = m * sin(x1 - 1e-10) - a * cos(x1 - 1e-10);
434  y2_h = m * sin(x2 + 1e-10) - a * cos(x2 + 1e-10);
435  // skip decreasing half of the sine (corresponds to curl back half of the track)
436  if (y1_h > y2_h) continue;
437  if (!((y1_h > y2 && y2_h > y2) || (y1_h < y1 && y2_h < y1))) {
438  list.push_back(iHit);
439  break;
440  }
441  }
442  }
443 }
444 
445 /*
446  * Select one hit per super layer
447  */
448 void
449 CDCTrigger2DFinderModule::selectHits(std::vector<unsigned>& list,
450  std::vector<unsigned>& selected,
451  std::vector<unsigned>& unselected)
452 {
453  std::vector<int> bestPerSL(5, -1);
454  for (unsigned i = 0; i < list.size(); ++i) {
455  unsigned iax = m_segmentHits[list[i]]->getISuperLayer() / 2;
456  bool firstPriority = (m_segmentHits[list[i]]->getPriorityPosition() == 3);
457  if (bestPerSL[iax] < 0) {
458  bestPerSL[iax] = i;
459  } else {
460  unsigned itsBest = list[bestPerSL[iax]];
461  bool firstBest = (m_segmentHits[itsBest]->getPriorityPosition() == 3);
462  // selection rules:
463  // first priority, higher ID
464  if ((firstPriority && !firstBest) ||
465  (firstPriority == firstBest &&
466  m_segmentHits[list[i]]->getSegmentID() > m_segmentHits[itsBest]->getSegmentID())) {
467  bestPerSL[iax] = i;
468  }
469  }
470  }
471 
472  for (unsigned i = 0; i < list.size(); ++i) {
473  unsigned iax = m_segmentHits[list[i]]->getISuperLayer() / 2;
474  if (int(i) == bestPerSL[iax]) selected.push_back(list[i]);
475  else unselected.push_back(list[i]);
476  }
477 }
478 
479 /*
480 * Alternative peak finding with nested patterns
481 */
482 void
483 CDCTrigger2DFinderModule::patternClustering(const cdcMap& inputMap)
484 {
485  // fill a matrix of 2 x 2 squares
486  TMatrix plane2(m_nCellsPhi / 2, m_nCellsR / 2);
487  TMatrix planeIcand(m_nCellsPhi, m_nCellsR);
488  for (unsigned icand = 0; icand < houghCand.size(); ++icand) {
489  double x = (houghCand[icand].getCoord().first.X() +
490  houghCand[icand].getCoord().second.X()) / 2.;
491  unsigned ix = floor((x + M_PI) / 2. / M_PI * m_nCellsPhi);
492  double y = (houghCand[icand].getCoord().first.Y() +
493  houghCand[icand].getCoord().second.Y()) / 2.;
494  unsigned iy = floor((y + maxR - shiftR) / 2. / maxR * m_nCellsR);
495  plane2[ix / 2][iy / 2] += 1 << ((ix % 2) + 2 * (iy % 2));
496  planeIcand[ix][iy] = icand;
497  B2DEBUG(100, "candidate " << icand << " at ix " << ix << " iy " << iy);
498  }
499  // look for clusters of 2 x 2 squares in a (rX x rY) region
500  unsigned nX = m_nCellsPhi / 2;
501  unsigned nY = m_nCellsR / 2;
502  unsigned rX = m_clusterSizeX;
503  unsigned rY = m_clusterSizeY;
504  for (unsigned ix = 0; ix < nX; ++ix) {
505  for (unsigned iy = 0; iy < nY; ++iy) {
506  if (!plane2[ix][iy]) continue;
507  // check if we are in a lower left corner
508  unsigned ileft = (ix - 1 + nX) % nX;
509  B2DEBUG(100, "ix " << ix << " iy " << iy);
510  if (connectedLR(plane2[ileft][iy], plane2[ix][iy]) ||
511  (iy > 0 && connectedUD(plane2[ix][iy - 1], plane2[ix][iy])) ||
512  (iy > 0 && connectedDiag(plane2[ileft][iy - 1], plane2[ix][iy]))) {
513  B2DEBUG(100, "skip connected square");
514  continue;
515  }
516  // form cluster
517  vector<unsigned> pattern(rX * rY, 0);
518  pattern[0] = plane2[ix][iy];
519  vector<TVector2> cellIds = {TVector2(2 * ix, 2 * iy)};
520  for (unsigned ix2 = 0; ix2 < rX; ++ix2) {
521  for (unsigned iy2 = 0; iy2 < rY; ++iy2) {
522  if (iy + iy2 >= nY) continue;
523  unsigned ip = ix2 + rX * iy2;
524  unsigned iright = (ix + ix2 + nX) % nX;
525  ileft = (iright - 1 + nX) % nX;
526  B2DEBUG(100, "ix2 " << ix2 << " ileft " << ileft << " iright " << iright);
527  if ((ix2 > 0 && // check left/right connection
528  pattern[ip - 1] &&
529  connectedLR(plane2[ileft][iy + iy2], plane2[iright][iy + iy2])) ||
530  (iy2 > 0 && // check up/down connection
531  pattern[ip - rX] &&
532  connectedUD(plane2[iright][iy + iy2 - 1], plane2[iright][iy + iy2])) ||
533  (ix2 > 0 && iy2 > 0 && // check diagonal connection
534  pattern[ip - rX - 1] &&
535  connectedDiag(plane2[ileft][iy + iy2 - 1], plane2[iright][iy + iy2]))) {
536  pattern[ip] = plane2[iright][iy + iy2];
537  B2DEBUG(100, "connect cell " << iright << " " << iy + iy2);
538  cellIds.push_back(TVector2(2 * (ix + ix2), 2 * (iy + iy2)));
539  }
540  }
541  }
542  B2DEBUG(100, "cluster starting at " << ix << " " << iy);
543  // check if cluster continues beyond defined area
544  bool overflowRight = false;
545  bool overflowTop = false;
546  for (unsigned iy2 = 0; iy2 < rY; ++iy2) {
547  unsigned ip = rX - 1 + rX * iy2;
548  if (!pattern[ip]) continue;
549  unsigned iright = (ix + rX + nX) % nX;
550  ileft = (iright - 1 + nX) % nX;
551  if (connectedLR(plane2[ileft][iy + iy2], plane2[iright][iy + iy2]) ||
552  ((iy + iy2 + 1 < nY) &&
553  connectedDiag(plane2[ileft][iy + iy2], plane2[iright][iy + iy2 + 1]))) {
554  setReturnValue(false);
555  overflowRight = true;
556  }
557  }
558  if (iy + rY < nY) {
559  for (unsigned ix2 = 0; ix2 < rX; ++ix2) {
560  unsigned ip = ix2 + rX * (rY - 1);
561  if (!pattern[ip]) continue;
562  unsigned iright = (ix + ix2 + 1 + nX) % nX;
563  ileft = (iright - 1 + nX) % nX;
564  if (connectedUD(plane2[ileft][iy + rY - 1], plane2[ileft][iy + rY]) ||
565  connectedDiag(plane2[ileft][iy + rY - 1], plane2[iright][iy + rY])) {
566  setReturnValue(false);
567  overflowTop = true;
568  }
569  }
570  }
571  if (overflowRight && !overflowTop) {
572  B2DEBUG(100, "cluster extends right of " << rX << " x " << rY << " area");
573  } else if (overflowTop && !overflowRight) {
574  B2DEBUG(100, "cluster extends above " << rX << " x " << rY << " area");
575  } else if (overflowRight && overflowTop) {
576  B2DEBUG(100, "cluster extends right and above " << rX << " x " << rY << " area");
577  }
578  // find corners of cluster
579  unsigned topRight2 = topRightSquare(pattern);
580  unsigned topRight = topRightCorner(pattern[topRight2]);
581  unsigned bottomLeft = bottomLeftCorner(pattern[0]);
582  B2DEBUG(100, "topRight2 " << topRight2 << " topRight " << topRight << " bottomLeft " << bottomLeft);
583  // average over corners to find cluster center
584  unsigned ixTR = 2 * (topRight2 % m_clusterSizeX) + (topRight % 2);
585  unsigned ixBL = bottomLeft % 2;
586  unsigned iyTR = 2 * (topRight2 / m_clusterSizeX) + (topRight / 2);
587  unsigned iyBL = bottomLeft / 2;
588  B2DEBUG(100, "ixTR " << ixTR << " ixBL " << ixBL << " iyTR " << iyTR << " iyBL " << iyBL);
589  // skip size 1 clusters
590  if (m_minCells > 1 && ixTR == ixBL && iyTR == iyBL) {
591  B2DEBUG(100, "skipping cluster of size 1");
592  continue;
593  }
594  float centerX = 2 * ix + (ixTR + ixBL) / 2.;
595  if (centerX >= m_nCellsPhi) centerX -= m_nCellsPhi;
596  float centerY = 2 * iy + (iyTR + iyBL) / 2.;
597  B2DEBUG(100, "center at cell (" << centerX << ", " << centerY << ")");
598  // convert to coordinates
599  double x = -M_PI + (centerX + 0.5) * 2. * M_PI / m_nCellsPhi;
600  double y = -maxR + shiftR + (centerY + 0.5) * 2. * maxR / m_nCellsR;
601  B2DEBUG(100, "center coordinates (" << x << ", " << y << ")");
602  // get list of related hits
603  vector <unsigned> idList = {};
604  if (m_hitRelationsFromCorners) {
605  unsigned icandTR = planeIcand[(ixTR + 2 * ix) % m_nCellsPhi][iyTR + 2 * iy];
606  unsigned icandBL = planeIcand[ixBL + 2 * ix][iyBL + 2 * iy];
607  vector<unsigned> candIdListTR = houghCand[icandTR].getIdList();
608  vector<unsigned> candIdListBL = houghCand[icandBL].getIdList();
609  mergeIdList(idList, candIdListTR, candIdListBL);
610  B2DEBUG(100, "merge id lists from candidates " << icandTR << " and " << icandBL);
611  } else {
612  double dx = M_PI / m_nCellsPhi;
613  double dy = maxR / m_nCellsR;
614  double x1 = (round(centerX) == centerX) ? x - dx : x - 2 * dx;
615  double x2 = (round(centerX) == centerX) ? x + dx : x + 2 * dx;
616  double y1 = (round(centerY) == centerY) ? y - dy : y - 2 * dy;
617  double y2 = (round(centerY) == centerY) ? y + dy : y + 2 * dy;
618  findAllCrossingHits(idList, x1, x2, y1, y2, inputMap);
619  }
620  if (idList.size() == 0) {
621  setReturnValue(false);
622  B2DEBUG(100, "id list empty");
623  }
624 
625  // select 1 hit per super layer
626  vector<unsigned> selectedList = {};
627  vector<unsigned> unselectedList = {};
628  selectHits(idList, selectedList, unselectedList);
629 
630  // save track
631  const CDCTriggerTrack* track =
632  m_tracks.appendNew(x, 2. * y, 0.);
633  // relations to selected hits
634  for (unsigned i = 0; i < selectedList.size(); ++i) {
635  unsigned its = selectedList[i];
636  track->addRelationTo(m_segmentHits[its]);
637  }
638  // relations to additional hits get a negative weight
639  for (unsigned i = 0; i < unselectedList.size(); ++i) {
640  unsigned its = unselectedList[i];
641  track->addRelationTo(m_segmentHits[its], -1.);
642  }
643  // save detail information about the cluster
644  const CDCTriggerHoughCluster* cluster =
645  m_clusters.appendNew(2 * ix, 2 * (ix + m_clusterSizeX) - 1,
646  2 * iy, 2 * (iy + m_clusterSizeY) - 1,
647  cellIds);
648  track->addRelationTo(cluster);
649  }
650  }
651 }
652 
653 /*
654 * connection definitions for 2 x 2 squares
655 */
656 bool
657 CDCTrigger2DFinderModule::connectedLR(unsigned patternL, unsigned patternR)
658 {
659  // connected if
660  // . x | x . or . . | . .
661  // . . | . . . x | x .
662  bool connectDirect = (((patternL >> 3) & 1) && ((patternR >> 2) & 1)) ||
663  (((patternL >> 1) & 1) && ((patternR >> 0) & 1));
664  // connected if
665  // . . | x .
666  // . x | . .
667  bool connectRise = ((patternL >> 1) & 1) && ((patternR >> 2) & 1);
668  // connected if
669  // . x | . .
670  // . . | x .
671  bool connectFall = ((patternL >> 3) & 1) && ((patternR >> 0) & 1);
672 
673  if (m_connect == 4) return connectDirect;
674  else if (m_connect == 6) return (connectDirect || connectRise);
675  else if (m_connect == 8) return (connectDirect || connectRise || connectFall);
676  else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
677  return (connectDirect || connectRise);
678 }
679 
680 bool
681 CDCTrigger2DFinderModule::connectedUD(unsigned patternD, unsigned patternU)
682 {
683  // connected if
684  // . . . .
685  // x . . x
686  // --- or ---
687  // x . . x
688  // . . . .
689  bool connectDirect = (((patternU >> 0) & 1) && ((patternD >> 2) & 1)) ||
690  (((patternU >> 1) & 1) && ((patternD >> 3) & 1));
691  // connected if
692  // . .
693  // . x
694  // ---
695  // x .
696  // . .
697  bool connectRise = ((patternU >> 1) & 1) && ((patternD >> 2) & 1);
698  // connected if
699  // . .
700  // x .
701  // ---
702  // . x
703  // . .
704  bool connectFall = ((patternU >> 0) & 1) && ((patternD >> 3) & 1);
705 
706  if (m_connect == 4) return connectDirect;
707  else if (m_connect == 6) return (connectDirect || connectRise);
708  else if (m_connect == 8) return (connectDirect || connectRise || connectFall);
709  else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
710  return (connectDirect || connectRise);
711 }
712 
713 bool
714 CDCTrigger2DFinderModule::connectedDiag(unsigned patternLD, unsigned patternRU)
715 {
716  if (m_connect == 4) return false;
717 
718  // connected if
719  // . .
720  // x .
721  // . x
722  // . .
723  return (((patternRU >> 0) & 1) && ((patternLD >> 3) & 1));
724 }
725 
726 unsigned
727 CDCTrigger2DFinderModule::topRightSquare(vector<unsigned>& pattern)
728 {
729  // scan from top right corner until an active square is found
730  for (unsigned index = pattern.size() - 1; index > 0; --index) {
731  if (!pattern[index]) continue;
732  // check for ambiguity
733  unsigned ix = index % m_clusterSizeX;
734  unsigned iy = index / m_clusterSizeX;
735  if (ix < m_clusterSizeX - 1 && iy > 0) {
736  bool unique = true;
737  for (unsigned index2 = index - 1; index2 > 0; --index2) {
738  if (!pattern[index2]) continue;
739  unsigned ix2 = index2 % m_clusterSizeX;
740  unsigned iy2 = index2 / m_clusterSizeX;
741  if (iy2 < iy && ix2 > ix) {
742  unique = false;
743  break;
744  }
745  }
746  if (!unique) {
747  setReturnValue(false);
748  B2DEBUG(100, "topRightSquare not unique");
749  }
750  }
751  return index;
752  }
753  return 0;
754 }
755 
756 unsigned
757 CDCTrigger2DFinderModule::topRightCorner(unsigned pattern)
758 {
759  // scan pattern from right to left:
760  // 2 3
761  // 0 1
762  if ((pattern >> 3) & 1) return 3;
763  if ((pattern >> 1) & 1) {
764  if ((pattern >> 2) & 1) {
765  setReturnValue(false);
766  B2DEBUG(100, "topRightCorner not unique");
767  }
768  return 1;
769  }
770  if ((pattern >> 2) & 1) return 2;
771  return 0;
772 }
773 
774 unsigned
775 CDCTrigger2DFinderModule::bottomLeftCorner(unsigned pattern)
776 {
777  // scan pattern from left to right:
778  // 2 3
779  // 0 1
780  if (pattern & 1) return 0;
781  if ((pattern >> 2) & 1) {
782  if ((pattern >> 1) & 1) {
783  setReturnValue(false);
784  B2DEBUG(100, "bottomLeftCorner not unique");
785  }
786  return 2;
787  }
788  if ((pattern >> 1) & 1) return 1;
789  return 3;
790 }
unsigned getID() const
Get candidate number.
unsigned short getSLcount() const
Get super layer count.
Cluster created by the Hough finder of the CDC trigger.
Track created by the CDC trigger.
int getID(const std::vector< double > &breaks, double t)
get id of the time point t
Definition: calibTools.h:60
std::map< int, cdcPair > cdcMap
Map of <counter, cdcPair>, for hits with indices.
std::pair< unsigned short, TVector2 > cdcPair
Pair of <iSuperLayer, (x, y)>, for hits in conformal space.
std::pair< TVector2, TVector2 > coord2dPair
Hough Tuples.
Abstract base class for different kinds of events.