Belle II Software release-09-00-00
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 45
19
20using namespace std;
21using namespace Belle2;
22
23unsigned short
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
34bool
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*/
56int
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 //bool layerHit[CDC_SUPER_LAYERS*5] = {false}; /* For layer filter */
116 int iit = 0;
117 for (auto it = hits.begin(); it != hits.end(); ++it) {
118 iHit = it->first;
119 hp = it->second;
120 iSL = hp.first;
121 m = hp.second.X();
122 a = hp.second.Y();
123 //std::cout << "checking bin content" << iit << " " << iSL << " " << m << " " << a << std::endl;
124 iit++;
125 // calculate Hough curve with slightly enlarged limits to avoid errors due to rounding
126 y1 = m * sin(x1_d - 1e-10) - a * cos(x1_d - 1e-10);
127 y2 = m * sin(x2_d + 1e-10) - a * cos(x2_d + 1e-10);
128 // skip decreasing half of the sine (corresponds to curl back half of the track)
129 if (iterations == maxIterations && y1 > y2) continue;
130 if (!((y1 > y2_d && y2 > y2_d) || (y1 < y1_d && y2 < y1_d))) {
131 if (iterations == maxIterations) {
132 idx_list.push_back(iHit);
133 }
134 layerHit[iSL] = true; /* layer filter */
135 }
136 }
137 unsigned short nSL = countSL(layerHit);
138 B2DEBUG(150, indent << "i " << i << " j " << j
139 << " layerHit " << int(layerHit[0]) << int(layerHit[2])
140 << int(layerHit[4]) << int(layerHit[6]) << int(layerHit[8])
141 << " nSL " << nSL);
142 //std::cout << indent << "i " << i << " j " << j
143 // << " layerHit " << int(layerHit[0]) << int(layerHit[2])
144 // << int(layerHit[4]) << int(layerHit[6]) << int(layerHit[8])
145 // << " nSL " << nSL << std::endl;
146 if (nSL >= m_minHits || shortTrack(layerHit)) {
147 if (iterations != maxIterations) {
148 fastInterceptFinder(hits, x1_d, x2_d, y1_d, y2_d, iterations + 1, ix, iy);
149 } else {
150 ROOT::Math::XYVector v1(x1_d, y1_d);
151 ROOT::Math::XYVector v2(x2_d, y2_d);
152 houghCand.push_back(CDCTriggerHoughCand(idx_list, make_pair(v1, v2),
153 nSL, houghCand.size()));
154 if (m_storePlane > 0) {
155 (*m_houghPlane)[ix - (nCells - m_nCellsPhi) / 2][iy - (nCells - m_nCellsR) / 2] = nSL;
156 }
157 }
158 } else if (m_storePlane > 1) {
159 // to store the full Hough plane, we need to continue the iteration
160 // to minimal cell size everywhere
161 for (unsigned min = m_minHits - 1; min > 0; --min) {
162 if (nSL >= min) {
163 if (iterations != maxIterations) {
164 fastInterceptFinder(hits, x1_d, x2_d, y1_d, y2_d, iterations + 1, ix, iy);
165 } else {
166 (*m_houghPlane)[ix - (nCells - m_nCellsPhi) / 2][iy - (nCells - m_nCellsR) / 2] = nSL;
167 }
168 break;
169 }
170 }
171 }
172 }
173 }
174
175 return 0;
176}
177
178/*
179* Peak finding method: connected regions & center of gravity
180*/
181void
183{
184 vector<vector<CDCTriggerHoughCand>> regions;
185 vector<CDCTriggerHoughCand> cpyCand = houghCand;
186
187 // debug: print candidate list
188 B2DEBUG(50, "houghCand number " << cpyCand.size());
189 for (unsigned icand = 0; icand < houghCand.size(); ++icand) {
190 coord2dPair coord = houghCand[icand].getCoord();
191 B2DEBUG(100, houghCand[icand].getID()
192 << " nSL " << houghCand[icand].getSLcount()
193 << " x1 " << coord.first.X() << " x2 " << coord.second.X()
194 << " y1 " << coord.first.Y() << " y2 " << coord.second.Y());
195 }
196
197 // combine connected cells to regions
198 while (cpyCand.size() > 0) {
199 B2DEBUG(100, "make new region");
200 vector<CDCTriggerHoughCand> region;
201 vector<CDCTriggerHoughCand> rejected;
202 CDCTriggerHoughCand start = cpyCand[0];
203 cpyCand.erase(cpyCand.begin());
204 region.push_back(start);
205 addNeighbors(start, cpyCand, region, rejected, start.getSLcount());
206 regions.push_back(region);
207 for (auto cand = cpyCand.begin(); cand != cpyCand.end();) {
208 if (inList(*cand, region) || inList(*cand, rejected))
209 cpyCand.erase(cand);
210 else
211 ++cand;
212 }
213 }
214
215 // find center of gravity for each region
216 for (unsigned ir = 0; ir < regions.size(); ++ir) {
217 B2DEBUG(50, "region " << ir << " (" << regions[ir].size() << " cells).");
218 // skip regions with size below cut
219 if (regions[ir].size() < m_minCells) {
220 B2DEBUG(50, "Skipping region with " << regions[ir].size() << " cells.");
221 continue;
222 }
223 double xfirst = regions[ir][0].getCoord().first.X();
224 double x = 0;
225 double y = 0;
226 int n = 0;
227 vector<unsigned> mergedList;
228 int xmin = m_nCellsPhi;
229 int xmax = 0;
230 int ymin = m_nCellsR;
231 int ymax = 0;
232 vector<ROOT::Math::XYVector> cellIds = {};
233 for (unsigned ir2 = 0; ir2 < regions[ir].size(); ++ir2) {
234 coord2dPair hc = regions[ir][ir2].getCoord();
235 B2DEBUG(100, " " << regions[ir][ir2].getID()
236 << " nSL " << regions[ir][ir2].getSLcount()
237 << " x1 " << hc.first.X() << " x2 " << hc.second.X()
238 << " y1 " << hc.first.Y() << " y2 " << hc.second.Y());
239 int ix = floor((hc.first.X() + M_PI) / 2. / M_PI * m_nCellsPhi + 0.5);
240 int iy = floor((hc.first.Y() + maxR - shiftR) / 2. / maxR * m_nCellsR + 0.5);
241 x += (hc.first.X() + hc.second.X());
242 if (xfirst - hc.first.X() > M_PI) {
243 x += 4 * M_PI;
244 ix += m_nCellsPhi;
245 } else if (hc.first.X() - xfirst > M_PI) {
246 x -= 4 * M_PI;
247 ix -= m_nCellsPhi;
248 }
249 y += (hc.first.Y() + hc.second.Y());
250 n += 1;
251 vector<unsigned> idList = regions[ir][ir2].getIdList();
252 mergeIdList(mergedList, mergedList, idList);
253 xmin = min(xmin, ix);
254 xmax = max(xmax, ix);
255 ymin = min(ymin, iy);
256 ymax = max(ymax, iy);
257 cellIds.push_back(ROOT::Math::XYVector(ix, iy));
258 }
259 x *= 0.5 / n;
260 if (x > M_PI)
261 x -= 2 * M_PI;
262 else if (x <= -M_PI)
263 x += 2 * M_PI;
264 y *= 0.5 / n;
265 B2DEBUG(50, "x " << x << " y " << y);
266
267 // select 1 hit per super layer
268 vector<unsigned> selectedList = {};
269 vector<unsigned> unselectedList = {};
270 selectHits(mergedList, selectedList, unselectedList);
271
272 // save track
273 const CDCTriggerTrack* track =
274 m_tracks.appendNew(x, 2. * y, 0.);
275 // relations to selected hits
276 for (unsigned i = 0; i < selectedList.size(); ++i) {
277 unsigned its = selectedList[i];
278 track->addRelationTo(m_segmentHits[its]);
279 }
280 // relations to additional hits get a negative weight
281 for (unsigned i = 0; i < unselectedList.size(); ++i) {
282 unsigned its = unselectedList[i];
283 track->addRelationTo(m_segmentHits[its], -1.);
284 }
285 // save detail information about the cluster
286 const CDCTriggerHoughCluster* cluster =
287 m_clusters.appendNew(xmin, xmax, ymin, ymax, cellIds);
288 track->addRelationTo(cluster);
289 }
290}
291
292void
294 const vector<CDCTriggerHoughCand>& candidates,
295 vector<CDCTriggerHoughCand>& merged,
296 vector<CDCTriggerHoughCand>& rejected,
297 unsigned short nSLmax) const
298{
299 for (unsigned icand = 0; icand < candidates.size(); ++icand) {
300 B2DEBUG(120, "compare center " << center.getID()
301 << " to " << candidates[icand].getID());
302 if (inList(candidates[icand], merged) || inList(candidates[icand], rejected)) {
303 B2DEBUG(120, " " << candidates[icand].getID() << " already in list");
304 continue;
305 }
306 bool reject = inList(center, rejected);
307 if (connected(center, candidates[icand])) {
308 if (m_onlyLocalMax && candidates[icand].getSLcount() < nSLmax) {
309 B2DEBUG(100, " lower than highest SLcount, rejected");
310 rejected.push_back(candidates[icand]);
311 } else if (m_onlyLocalMax && !reject && candidates[icand].getSLcount() > nSLmax) {
312 B2DEBUG(100, " new highest SLcount, clearing list");
313 nSLmax = candidates[icand].getSLcount();
314 for (unsigned imerged = 0; imerged < merged.size(); ++imerged) {
315 rejected.push_back(merged[imerged]);
316 }
317 merged.clear();
318 merged.push_back(candidates[icand]);
319 } else if (m_onlyLocalMax && candidates[icand].getSLcount() > center.getSLcount()) {
320 B2DEBUG(100, " connected to rejected cell, skip");
321 continue;
322 } else if (m_onlyLocalMax && reject) {
323 B2DEBUG(100, " connected to rejected cell, rejected");
324 rejected.push_back(candidates[icand]);
325 } else {
326 B2DEBUG(100, " connected");
327 merged.push_back(candidates[icand]);
328 }
329 vector<CDCTriggerHoughCand> cpyCand = candidates;
330 cpyCand.erase(cpyCand.begin() + icand);
331 addNeighbors(candidates[icand], cpyCand, merged, rejected, nSLmax);
332 }
333 }
334}
335
336bool
338 const vector<CDCTriggerHoughCand>& list) const
339{
340 for (unsigned i = 0; i < list.size(); ++i) {
341 if (a == list[i]) return true;
342 }
343 return false;
344}
345
346bool
348 const CDCTriggerHoughCand& b) const
349{
350 double ax1 = a.getCoord().first.X();
351 double ax2 = a.getCoord().second.X();
352 double ay1 = a.getCoord().first.Y();
353 double ay2 = a.getCoord().second.Y();
354 double bx1 = b.getCoord().first.X();
355 double bx2 = b.getCoord().second.X();
356 double by1 = b.getCoord().first.Y();
357 double by2 = b.getCoord().second.Y();
358 // direct neighbors
359 bool direct = ((ax2 == bx1 && ay1 == by1) || // right
360 (ax1 == bx2 && ay1 == by1) || // left
361 (ax1 == bx1 && ay2 == by1) || // above
362 (ax1 == bx1 && ay1 == by2) || // below
363 (ax1 + 2. * M_PI == bx2 && ay1 == by1) ||
364 (ax2 == bx1 + 2. * M_PI && ay1 == by1));
365 // diagonal connections
366 bool diagRise = ((ax2 == bx1 && ay2 == by1) || // right above
367 (ax1 == bx2 && ay1 == by2) || // left below
368 (ax1 + 2. * M_PI == bx2 && ay1 == by2) ||
369 (ax2 == bx1 + 2. * M_PI && ay2 == by1));
370 bool diagFall = ((ax1 == bx2 && ay2 == by1) || // left above
371 (ax2 == bx1 && ay1 == by2) || // right below
372 (ax2 == bx1 + 2. * M_PI && ay1 == by2) ||
373 (ax1 + 2. * M_PI == bx2 && ay2 == by1));
374 if (m_connect == 4) return direct;
375 else if (m_connect == 6) return (direct || diagRise);
376 else if (m_connect == 8) return (direct || diagRise || diagFall);
377 else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
378 return (direct || diagRise);
379}
380
381/*
382* Merge Id lists.
383*/
384void
385CDCTrigger2DFinderModule::mergeIdList(std::vector<unsigned>& merged,
386 std::vector<unsigned>& a,
387 std::vector<unsigned>& b)
388{
389 bool found;
390
391 for (auto it = a.begin(); it != a.end(); ++it) {
392 found = false;
393 for (auto it_in = merged.begin(); it_in != merged.end(); ++it_in) {
394 if (*it_in == *it) {
395 found = true;
396 break;
397 }
398 }
399 if (!found) {
400 merged.push_back(*it);
401 }
402 }
403
404 for (auto it = b.begin(); it != b.end(); ++it) {
405 found = false;
406 for (auto it_in = merged.begin(); it_in != merged.end(); ++it_in) {
407 if (*it_in == *it) {
408 found = true;
409 break;
410 }
411 }
412 if (!found) {
413 merged.push_back(*it);
414 }
415 }
416}
417
418void
420 double x1, double x2,
421 double y1, double y2,
422 const cdcMap& inputMap)
423{
424 double m, a, y1_h, y2_h;
425 for (int iHit = 0; iHit < m_segmentHits.getEntries(); iHit++) {
426 unsigned short iSL = m_segmentHits[iHit]->getISuperLayer();
427 if (iSL % 2) continue;
428 // associate only the hits actually used to form the cluster
429 if (m_suppressClone && inputMap.find(iHit) == inputMap.end()) continue;
430 //TODO: add options: center cell / active priority cell / all priority cells
431 vector<double> phi = {0, 0, 0};
432 phi[0] = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
433 phi[1] = phi[0] + 0.5;
434 phi[2] = phi[0] - 0.5;
435 vector<double> r = {radius[iSL][0], radius[iSL][1], radius[iSL][1]};
436 for (unsigned i = 0; i < 3; ++i) {
437 phi[i] *= 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
438 m = cos(phi[i]) / r[i];
439 a = sin(phi[i]) / r[i];
440 // calculate Hough curve with slightly enlarged limits to avoid errors due to rounding
441 y1_h = m * sin(x1 - 1e-10) - a * cos(x1 - 1e-10);
442 y2_h = m * sin(x2 + 1e-10) - a * cos(x2 + 1e-10);
443 // skip decreasing half of the sine (corresponds to curl back half of the track)
444 if (y1_h > y2_h) continue;
445 if (!((y1_h > y2 && y2_h > y2) || (y1_h < y1 && y2_h < y1))) {
446 list.push_back(iHit);
447 break;
448 }
449 }
450 }
451}
452
453/*
454 * Select one hit per super layer
455 */
456void
457CDCTrigger2DFinderModule::selectHits(std::vector<unsigned>& list,
458 std::vector<unsigned>& selected,
459 std::vector<unsigned>& unselected)
460{
461 std::vector<int> bestPerSL(5, -1);
462 for (unsigned i = 0; i < list.size(); ++i) {
463 unsigned iax = m_segmentHits[list[i]]->getISuperLayer() / 2;
464 bool firstPriority = (m_segmentHits[list[i]]->getPriorityPosition() == 3);
465 if (bestPerSL[iax] < 0) {
466 bestPerSL[iax] = i;
467 } else {
468 unsigned itsBest = list[bestPerSL[iax]];
469 bool firstBest = (m_segmentHits[itsBest]->getPriorityPosition() == 3);
470 // selection rules:
471 // first priority, higher ID
472 if ((firstPriority && !firstBest) ||
473 (firstPriority == firstBest &&
474 m_segmentHits[list[i]]->getSegmentID() > m_segmentHits[itsBest]->getSegmentID())) {
475 bestPerSL[iax] = i;
476 }
477 }
478 }
479
480 for (unsigned i = 0; i < list.size(); ++i) {
481 unsigned iax = m_segmentHits[list[i]]->getISuperLayer() / 2;
482 if (int(i) == bestPerSL[iax]) selected.push_back(list[i]);
483 else unselected.push_back(list[i]);
484 }
485}
486
487/*
488* Alternative peak finding with nested patterns
489*/
490void
492{
493 // fill a matrix of 2 x 2 squares
494 TMatrix plane2(m_nCellsPhi / 2, m_nCellsR / 2);
495 TMatrix planeIcand(m_nCellsPhi, m_nCellsR);
496 for (unsigned icand = 0; icand < houghCand.size(); ++icand) {
497 double x = (houghCand[icand].getCoord().first.X() +
498 houghCand[icand].getCoord().second.X()) / 2.;
499 unsigned ix = floor((x + M_PI) / 2. / M_PI * m_nCellsPhi);
500 double y = (houghCand[icand].getCoord().first.Y() +
501 houghCand[icand].getCoord().second.Y()) / 2.;
502 unsigned iy = floor((y + maxR - shiftR) / 2. / maxR * m_nCellsR);
503 plane2[ix / 2][iy / 2] += 1 << ((ix % 2) + 2 * (iy % 2));
504 planeIcand[ix][iy] = icand;
505 B2DEBUG(100, "candidate " << icand << " at ix " << ix << " iy " << iy);
506 }
507 // look for clusters of 2 x 2 squares in a (rX x rY) region
508 unsigned nX = m_nCellsPhi / 2;
509 unsigned nY = m_nCellsR / 2;
510 unsigned rX = m_clusterSizeX;
511 unsigned rY = m_clusterSizeY;
512 for (unsigned ix = 0; ix < nX; ++ix) {
513 for (unsigned iy = 0; iy < nY; ++iy) {
514 if (!plane2[ix][iy]) continue;
515 // check if we are in a lower left corner
516 unsigned ileft = (ix - 1 + nX) % nX;
517 B2DEBUG(100, "ix " << ix << " iy " << iy);
518 if (connectedLR(plane2[ileft][iy], plane2[ix][iy]) ||
519 (iy > 0 && connectedUD(plane2[ix][iy - 1], plane2[ix][iy])) ||
520 (iy > 0 && connectedDiag(plane2[ileft][iy - 1], plane2[ix][iy]))) {
521 B2DEBUG(100, "skip connected square");
522 continue;
523 }
524 // form cluster
525 vector<unsigned> pattern(rX * rY, 0);
526 pattern[0] = plane2[ix][iy];
527 vector<ROOT::Math::XYVector> cellIds = {ROOT::Math::XYVector(2 * ix, 2 * iy)};
528 for (unsigned ix2 = 0; ix2 < rX; ++ix2) {
529 for (unsigned iy2 = 0; iy2 < rY; ++iy2) {
530 if (iy + iy2 >= nY) continue;
531 unsigned ip = ix2 + rX * iy2;
532 unsigned iright = (ix + ix2 + nX) % nX;
533 ileft = (iright - 1 + nX) % nX;
534 B2DEBUG(100, "ix2 " << ix2 << " ileft " << ileft << " iright " << iright);
535 if ((ix2 > 0 && // check left/right connection
536 pattern[ip - 1] &&
537 connectedLR(plane2[ileft][iy + iy2], plane2[iright][iy + iy2])) ||
538 (iy2 > 0 && // check up/down connection
539 pattern[ip - rX] &&
540 connectedUD(plane2[iright][iy + iy2 - 1], plane2[iright][iy + iy2])) ||
541 (ix2 > 0 && iy2 > 0 && // check diagonal connection
542 pattern[ip - rX - 1] &&
543 connectedDiag(plane2[ileft][iy + iy2 - 1], plane2[iright][iy + iy2]))) {
544 pattern[ip] = plane2[iright][iy + iy2];
545 B2DEBUG(100, "connect cell " << iright << " " << iy + iy2);
546 cellIds.push_back(ROOT::Math::XYVector(2 * (ix + ix2), 2 * (iy + iy2)));
547 }
548 }
549 }
550 B2DEBUG(100, "cluster starting at " << ix << " " << iy);
551 // check if cluster continues beyond defined area
552 bool overflowRight = false;
553 bool overflowTop = false;
554 for (unsigned iy2 = 0; iy2 < rY; ++iy2) {
555 unsigned ip = rX - 1 + rX * iy2;
556 if (!pattern[ip]) continue;
557 unsigned iright = (ix + rX + nX) % nX;
558 ileft = (iright - 1 + nX) % nX;
559 if (connectedLR(plane2[ileft][iy + iy2], plane2[iright][iy + iy2]) ||
560 ((iy + iy2 + 1 < nY) &&
561 connectedDiag(plane2[ileft][iy + iy2], plane2[iright][iy + iy2 + 1]))) {
562 setReturnValue(false);
563 overflowRight = true;
564 }
565 }
566 if (iy + rY < nY) {
567 for (unsigned ix2 = 0; ix2 < rX; ++ix2) {
568 unsigned ip = ix2 + rX * (rY - 1);
569 if (!pattern[ip]) continue;
570 unsigned iright = (ix + ix2 + 1 + nX) % nX;
571 ileft = (iright - 1 + nX) % nX;
572 if (connectedUD(plane2[ileft][iy + rY - 1], plane2[ileft][iy + rY]) ||
573 connectedDiag(plane2[ileft][iy + rY - 1], plane2[iright][iy + rY])) {
574 setReturnValue(false);
575 overflowTop = true;
576 }
577 }
578 }
579 if (overflowRight && !overflowTop) {
580 B2DEBUG(100, "cluster extends right of " << rX << " x " << rY << " area");
581 } else if (overflowTop && !overflowRight) {
582 B2DEBUG(100, "cluster extends above " << rX << " x " << rY << " area");
583 } else if (overflowRight && overflowTop) {
584 B2DEBUG(100, "cluster extends right and above " << rX << " x " << rY << " area");
585 }
586 // find corners of cluster
587 unsigned topRight2 = topRightSquare(pattern);
588 unsigned topRight = topRightCorner(pattern[topRight2]);
589 unsigned bottomLeft = bottomLeftCorner(pattern[0]);
590 B2DEBUG(100, "topRight2 " << topRight2 << " topRight " << topRight << " bottomLeft " << bottomLeft);
591 // average over corners to find cluster center
592 unsigned ixTR = 2 * (topRight2 % m_clusterSizeX) + (topRight % 2);
593 unsigned ixBL = bottomLeft % 2;
594 unsigned iyTR = 2 * (topRight2 / m_clusterSizeX) + (topRight / 2);
595 unsigned iyBL = bottomLeft / 2;
596 B2DEBUG(100, "ixTR " << ixTR << " ixBL " << ixBL << " iyTR " << iyTR << " iyBL " << iyBL);
597 // skip size 1 clusters
598 if (m_minCells > 1 && ixTR == ixBL && iyTR == iyBL) {
599 B2DEBUG(100, "skipping cluster of size 1");
600 continue;
601 }
602 float centerX = 2 * ix + (ixTR + ixBL) / 2.;
603 if (centerX >= m_nCellsPhi) centerX -= m_nCellsPhi;
604 float centerY = 2 * iy + (iyTR + iyBL) / 2.;
605 B2DEBUG(100, "center at cell (" << centerX << ", " << centerY << ")");
606 // convert to coordinates
607 double x = -M_PI + (centerX + 0.5) * 2. * M_PI / m_nCellsPhi;
608 double y = -maxR + shiftR + (centerY + 0.5) * 2. * maxR / m_nCellsR;
609 B2DEBUG(100, "center coordinates (" << x << ", " << y << ")");
610 // get list of related hits
611 vector <unsigned> idList = {};
613 unsigned icandTR = planeIcand[(ixTR + 2 * ix) % m_nCellsPhi][iyTR + 2 * iy];
614 unsigned icandBL = planeIcand[ixBL + 2 * ix][iyBL + 2 * iy];
615 vector<unsigned> candIdListTR = houghCand[icandTR].getIdList();
616 vector<unsigned> candIdListBL = houghCand[icandBL].getIdList();
617 mergeIdList(idList, candIdListTR, candIdListBL);
618 B2DEBUG(100, "merge id lists from candidates " << icandTR << " and " << icandBL);
619 } else {
620 double dx = M_PI / m_nCellsPhi;
621 double dy = maxR / m_nCellsR;
622 double x1 = (round(centerX) == centerX) ? x - dx : x - 2 * dx;
623 double x2 = (round(centerX) == centerX) ? x + dx : x + 2 * dx;
624 double y1 = (round(centerY) == centerY) ? y - dy : y - 2 * dy;
625 double y2 = (round(centerY) == centerY) ? y + dy : y + 2 * dy;
626 findAllCrossingHits(idList, x1, x2, y1, y2, inputMap);
627 }
628 if (idList.size() == 0) {
629 setReturnValue(false);
630 B2DEBUG(100, "id list empty");
631 }
632
633 // select 1 hit per super layer
634 vector<unsigned> selectedList = {};
635 vector<unsigned> unselectedList = {};
636 selectHits(idList, selectedList, unselectedList);
637
638 // save track
639 const CDCTriggerTrack* track =
640 m_tracks.appendNew(x, 2. * y, 0.);
641 // relations to selected hits
642 for (unsigned i = 0; i < selectedList.size(); ++i) {
643 unsigned its = selectedList[i];
644 track->addRelationTo(m_segmentHits[its]);
645 }
646 // relations to additional hits get a negative weight
647 for (unsigned i = 0; i < unselectedList.size(); ++i) {
648 unsigned its = unselectedList[i];
649 track->addRelationTo(m_segmentHits[its], -1.);
650 }
651 // save detail information about the cluster
652 const CDCTriggerHoughCluster* cluster =
653 m_clusters.appendNew(2 * ix, 2 * (ix + m_clusterSizeX) - 1,
654 2 * iy, 2 * (iy + m_clusterSizeY) - 1,
655 cellIds);
656 track->addRelationTo(cluster);
657 }
658 }
659}
660
661/*
662* connection definitions for 2 x 2 squares
663*/
664bool
665CDCTrigger2DFinderModule::connectedLR(unsigned patternL, unsigned patternR)
666{
667 // connected if
668 // . x | x . or . . | . .
669 // . . | . . . x | x .
670 bool connectDirect = (((patternL >> 3) & 1) && ((patternR >> 2) & 1)) ||
671 (((patternL >> 1) & 1) && ((patternR >> 0) & 1));
672 // connected if
673 // . . | x .
674 // . x | . .
675 bool connectRise = ((patternL >> 1) & 1) && ((patternR >> 2) & 1);
676 // connected if
677 // . x | . .
678 // . . | x .
679 bool connectFall = ((patternL >> 3) & 1) && ((patternR >> 0) & 1);
680
681 if (m_connect == 4) return connectDirect;
682 else if (m_connect == 6) return (connectDirect || connectRise);
683 else if (m_connect == 8) return (connectDirect || connectRise || connectFall);
684 else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
685 return (connectDirect || connectRise);
686}
687
688bool
689CDCTrigger2DFinderModule::connectedUD(unsigned patternD, unsigned patternU)
690{
691 // connected if
692 // . . . .
693 // x . . x
694 // --- or ---
695 // x . . x
696 // . . . .
697 bool connectDirect = (((patternU >> 0) & 1) && ((patternD >> 2) & 1)) ||
698 (((patternU >> 1) & 1) && ((patternD >> 3) & 1));
699 // connected if
700 // . .
701 // . x
702 // ---
703 // x .
704 // . .
705 bool connectRise = ((patternU >> 1) & 1) && ((patternD >> 2) & 1);
706 // connected if
707 // . .
708 // x .
709 // ---
710 // . x
711 // . .
712 bool connectFall = ((patternU >> 0) & 1) && ((patternD >> 3) & 1);
713
714 if (m_connect == 4) return connectDirect;
715 else if (m_connect == 6) return (connectDirect || connectRise);
716 else if (m_connect == 8) return (connectDirect || connectRise || connectFall);
717 else B2WARNING("Unknown option for connect " << m_connect << ", using default.");
718 return (connectDirect || connectRise);
719}
720
721bool
722CDCTrigger2DFinderModule::connectedDiag(unsigned patternLD, unsigned patternRU)
723{
724 if (m_connect == 4) return false;
725
726 // connected if
727 // . .
728 // x .
729 // . x
730 // . .
731 return (((patternRU >> 0) & 1) && ((patternLD >> 3) & 1));
732}
733
734unsigned
736{
737 // scan from top right corner until an active square is found
738 for (unsigned index = pattern.size() - 1; index > 0; --index) {
739 if (!pattern[index]) continue;
740 // check for ambiguity
741 unsigned ix = index % m_clusterSizeX;
742 unsigned iy = index / m_clusterSizeX;
743 if (ix < m_clusterSizeX - 1 && iy > 0) {
744 bool unique = true;
745 for (unsigned index2 = index - 1; index2 > 0; --index2) {
746 if (!pattern[index2]) continue;
747 unsigned ix2 = index2 % m_clusterSizeX;
748 unsigned iy2 = index2 / m_clusterSizeX;
749 if (iy2 < iy && ix2 > ix) {
750 unique = false;
751 break;
752 }
753 }
754 if (!unique) {
755 setReturnValue(false);
756 B2DEBUG(100, "topRightSquare not unique");
757 }
758 }
759 return index;
760 }
761 return 0;
762}
763
764unsigned
766{
767 // scan pattern from right to left:
768 // 2 3
769 // 0 1
770 if ((pattern >> 3) & 1) return 3;
771 if ((pattern >> 1) & 1) {
772 if ((pattern >> 2) & 1) {
773 setReturnValue(false);
774 B2DEBUG(100, "topRightCorner not unique");
775 }
776 return 1;
777 }
778 if ((pattern >> 2) & 1) return 2;
779 return 0;
780}
781
782unsigned
784{
785 // scan pattern from left to right:
786 // 2 3
787 // 0 1
788 if (pattern & 1) return 0;
789 if ((pattern >> 2) & 1) {
790 if ((pattern >> 1) & 1) {
791 setReturnValue(false);
792 B2DEBUG(100, "bottomLeftCorner not unique");
793 }
794 return 2;
795 }
796 if ((pattern >> 1) & 1) return 1;
797 return 3;
798}
std::vector< CDCTriggerHoughCand > houghCand
Hough Candidates.
bool connectedLR(unsigned patternL, unsigned patternR)
Check for left/right connection of patterns in 2 x 2 squares.
unsigned topRightCorner(unsigned pattern)
Find the top right corner within 2 x 2 square.
int fastInterceptFinder(cdcMap &hits, double x1_s, double x2_s, double y1_s, double y2_s, unsigned iterations, unsigned ix_s, unsigned iy_s)
Fast intercept finder Divide Hough plane recursively to find cells with enough crossing lines.
unsigned m_minCells
minimum number of cells in a cluster to form a track
bool connectedUD(unsigned patternD, unsigned patternU)
Check for up/down connection of patterns in 2 x 2 squares.
unsigned maxIterations
number of iterations for the fast peak finder, smallest n such that 2^(n+1) > max(nCellsPhi,...
unsigned m_minHitsShort
short tracks require hits in the first minHitsShort super layers to form a candidate
unsigned m_nCellsR
number of Hough cells in 1/r
StoreArray< CDCTriggerSegmentHit > m_segmentHits
list of track segment hits
unsigned m_nCellsPhi
number of Hough cells in phi
unsigned short countSL(bool *superLayers)
count the number of super layers with hits
double maxR
Hough plane limit in 1/r [1/cm].
bool m_hitRelationsFromCorners
switch for creating relations to hits in the pattern clustering algorithm.
unsigned m_storePlane
switch to save the Hough plane in DataStore (0: don't save, 1: save only peaks, 2: save full plane)
bool inList(const CDCTriggerHoughCand &a, const std::vector< CDCTriggerHoughCand > &list) const
Check if candidate is in list.
void patternClustering(const cdcMap &inputMap)
Combine Hough candidates to tracks by a fixed pattern algorithm.
unsigned m_connect
number of neighbors to check for connection (4: direct, 6: direct + upper right and lower left corner...
double shiftR
Hough plane shift in 1/r [1/cm].
void findAllCrossingHits(std::vector< unsigned > &list, double x1, double x2, double y1, double y2, const cdcMap &inputMap)
Find all hits in inputMap whose Hough curve crosses the rectangle with corners (x1,...
unsigned nCells
number of cells for the fast peak finder: 2^(maxIterations + 1).
void selectHits(std::vector< unsigned > &list, std::vector< unsigned > &selected, std::vector< unsigned > &unselected)
Select one hit per super layer.
bool m_suppressClone
switch to send only the first found track and suppress the subsequent clones
StoreArray< CDCTriggerTrack > m_tracks
list of found tracks
unsigned m_clusterSizeX
maximum cluster size for pattern algorithm
void mergeIdList(std::vector< unsigned > &merged, std::vector< unsigned > &a, std::vector< unsigned > &b)
Merge lists a and b and put the result in merged.
bool connected(const CDCTriggerHoughCand &a, const CDCTriggerHoughCand &b) const
Check if candidates are connected.
unsigned bottomLeftCorner(unsigned pattern)
Find the bottom left corner within 2 x 2 square.
bool m_requireSL0
switch to check separately for a hit in the innermost super layer
unsigned m_minHits
minimum number of hits from different super layers in a Hough cell to form a candidate
StoreArray< CDCTriggerHoughCluster > m_clusters
list of clusters in the Hough map
void addNeighbors(const CDCTriggerHoughCand &center, const std::vector< CDCTriggerHoughCand > &candidates, std::vector< CDCTriggerHoughCand > &merged, std::vector< CDCTriggerHoughCand > &rejected, unsigned short nSLmax) const
Recursive function to add combine connected cells.
bool shortTrack(bool *superLayers)
check the short track condition (= hits in the inner super layers rather than any super layers)
bool connectedDiag(unsigned patternLD, unsigned patternRU)
Check for diagonal connected of patterns in 2 x 2 squares.
unsigned topRightSquare(std::vector< unsigned > &pattern)
Find the top right square within a cluster of 2 x 2 squares In case of ambiguity, top is favored over...
unsigned TSoffset[10]
Number of track segments up to super layer.
double radius[9][5]
Radius of the CDC layers with priority wires (2 per super layer).
bool m_onlyLocalMax
switch to ignore candidates connected to cells with higher super layer count
unsigned m_clusterSizeY
maximum cluster size for pattern algorithm
void connectedRegions()
Combine Hough candidates to tracks by merging connected cells.
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.
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition: Module.cc:220
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
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< ROOT::Math::XYVector, ROOT::Math::XYVector > coord2dPair
Hough Tuples.
std::pair< unsigned short, ROOT::Math::XYVector > cdcPair
Pair of <iSuperLayer, (x, y)>, for hits in conformal space.
Abstract base class for different kinds of events.
STL namespace.