Belle II Software  release-06-02-00
CDCTriggerHoughETFModule.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/houghETF/CDCTriggerHoughETFModule.h>
10 
11 #include <cdc/geometry/CDCGeometryPar.h>
12 #include <framework/logging/Logger.h>
13 #include <framework/gearbox/Const.h>
14 
15 #include <cmath>
16 #include <algorithm>
17 #include <iterator>
18 
19 #include <root/TMatrix.h>
20 
21 /* defines */
22 #define CDC_SUPER_LAYERS 9
23 
24 using namespace std;
25 using namespace Belle2;
26 using namespace Belle2::CDC;
27 
28 //-----------------------------------------------------------------
29 // Register the Module
30 //-----------------------------------------------------------------
31 REG_MODULE(CDCTriggerHoughETF)
32 
33 //-----------------------------------------------------------------
34 // Implementation
35 //-----------------------------------------------------------------
36 
38 {
39  //Set module properties
40  setDescription("Hough tracking algorithm for CDC trigger.");
41  setPropertyFlags(c_ParallelProcessingCertified);
42 
43  // Define module parameters
44  // 2D ETF specified parameters
45  // ----- PARAMETERS : GRL t0 finder with fastest priority timing (current at 2020.2.7)-----
46  // t0CalcMethod = 0
47  // usePriorityPosition = true
48  // arrivalOrder = 0
49  //
50  addParam("outputEventTimeName", m_EventTimeName,
51  "Name of the output StoreObjPtr.",
52  string(""));
53  addParam("storeTracks", m_storeTracks,
54  "store tracks",
55  false);
56  addParam("usePriorityTiming", m_usePriorityTiming,
57  "Use priority timing instead of fastest timing.",
58  true);
59  addParam("useHighPassTimingList", m_useHighPassTimingList,
60  "Use associated fastest timings track-by-track",
61  true);
62  addParam("t0CalcMethod", m_t0CalcMethod,
63  "0: Nth fastest fastest time."
64  "1: median of all timings."
65  "2: median of timings in timing window.",
66  (unsigned)(0));
67  addParam("arrivalOrder", m_arrivalOrder,
68  "When t0CalcMethod == 0: Nth fastest ft is used as T0. (i.e. 0 is fastest)",
69  (unsigned)(0));
70  addParam("timeWindowBegin", m_timeWindowBegin,
71  "When t0CalcMethod == 2: start time of time window relative to median. (in ns)",
72  (short)(40));
73  addParam("timeWindowEnd", m_timeWindowEnd,
74  "When t0CalcMethod == 2: end time of time window relative to median. (in ns)",
75  (short)(0));
76 
77  //common as CDCTrigger2DFinderModule
78  addParam("hitCollectionName", m_hitCollectionName,
79  "Name of the input StoreArray of CDCTriggerSegmentHits.",
80  string(""));
81  addParam("outputCollectionName", m_outputCollectionName,
82  "Name of the StoreArray holding the tracks found in the Hough tracking.",
83  string("TRGCDCETFTracks"));
84  addParam("clusterCollectionName", m_clusterCollectionName,
85  "Name of the StoreArray holding the clusters formed in the Hough plane.",
86  string(""));
87  addParam("nCellsPhi", m_nCellsPhi,
88  "Number of Hough cells in phi (limits: [-180, 180]). Must be an even number.",
89  (unsigned)(160));
90  addParam("nCellsR", m_nCellsR,
91  "Number of Hough cells in 1/r. Must be an even number.",
92  (unsigned)(34));
93  addParam("minPt", m_minPt,
94  "Minimum Pt [GeV]. "
95  "Hough plane limits in 1/r are [-1/r(minPt), 1/r(minPt)]", (double)(0.3));
96  addParam("shiftPt", m_shiftPt,
97  "Shift the Hough plane by 1/4 cell size in 1/r to avoid "
98  "curvature 0 tracks (<0: shift in negative direction, "
99  "0: no shift, >0: shift in positive direction).", 0);
100 
101  addParam("minHits", m_minHits,
102  "Minimum hits from different super layers required in a peak cell.",
103  (unsigned)(4));
104  addParam("minHitsShort", m_minHitsShort,
105  "Minimum hits required required in a peak cell for a short track"
106  " (must be in the first minHitsShort super layers).",
107  (unsigned)(4));
108  addParam("minCells", m_minCells,
109  "Peaks with less than minCells connected cells are ignored.",
110  (unsigned)(2));
111  addParam("onlyLocalMax", m_onlyLocalMax,
112  "Switch to remove cells connected to a cell with higher super layer count.",
113  false);
114  addParam("connect", m_connect,
115  "Definition for connected cells. 4: direct (left/right/top/bottom), "
116  "6: direct + 2 diagonal (top right/bottom left), "
117  "8: direct + all diagonal (top right/top left/bottom right/bottom left)",
118  (unsigned)(6));
119  addParam("ignore2ndPriority", m_ignore2nd,
120  "Switch to skip second priority hits.", false);
121  addParam("usePriorityPosition", m_usePriority,
122  "If true, use wire position of priority cell in track segment, "
123  "otherwise use wire position of center cell.", true);
124  addParam("requireSL0", m_requireSL0,
125  "Switch to check separately for a hit in the innermost superlayer.", false);
126  addParam("storeHoughPlane", m_storePlane,
127  "Switch for saving Hough plane as TMatrix in DataStore. "
128  "0: don't store anything, 1: store only peaks, 2: store full plane "
129  "(will increase runtime).", (unsigned)(0));
130  addParam("clusterPattern", m_clusterPattern,
131  "use nested pattern algorithm to find clusters", true);
132  addParam("clusterSizeX", m_clusterSizeX,
133  "maximum number of 2 x 2 squares in cluster for pattern algorithm",
134  (unsigned)(3));
135  addParam("clusterSizeY", m_clusterSizeY,
136  "maximum number of 2 x 2 squares in cluster for pattern algorithm",
137  (unsigned)(3));
138  addParam("hitRelationsFromCorners", m_hitRelationsFromCorners,
139  "Switch for creating relations to hits in the pattern algorithm. "
140  "If true, create relations from cluster corners, otherwise "
141  "from estimated cluster center (might not have relations).", false);
142 
143  addParam("testFilename", m_testFilename,
144  "If not empty, a file with input (hits) and output (tracks) "
145  "for each event is written (for firmware debugging).", string(""));
146 
147  addParam("suppressClone", m_suppressClone,
148  "Switch to send only the first found track and suppress the "
149  "subsequent clones." , false);
150 }
151 
152 void
153 CDCTriggerHoughETFModule::initialize()
154 {
155  // register DataStore elements
156  m_eventTime.registerInDataStore(m_EventTimeName);
157  m_segmentHits.isRequired(m_hitCollectionName);
158 
159  if (m_storeTracks) {
160  m_tracks.registerInDataStore(m_outputCollectionName);
161  m_clusters.registerInDataStore(m_clusterCollectionName);
162 
163  m_tracks.registerRelationTo(m_segmentHits);
164  m_tracks.registerRelationTo(m_clusters);
165  }
166 
167  if (m_storePlane > 0) m_houghPlane.registerInDataStore("HoughPlane");
168 
169  const CDCGeometryPar& cdc = CDCGeometryPar::Instance();
170  int layerId = 3;
171  int nTS = 0;
172  for (int iSL = 0; iSL < 9; ++iSL) {
173  TSoffset[iSL] = nTS;
174  nTS += cdc.nWiresInLayer(layerId);
175  TSoffset[iSL + 1] = nTS;
176  for (int priority = 0; priority < 2; ++ priority) {
177  radius[iSL][priority] = cdc.senseWireR(layerId + priority);
178  }
179  layerId += (iSL > 0 ? 6 : 7);
180  }
181 
182  for (int sl = 1; sl < 9; sl++) {
183  NSecOffset[sl] = NSEC[sl - 1] + NSecOffset[sl - 1];
184  }
185 
186  if (m_testFilename != "") {
187  testFile.open(m_testFilename);
188  }
189 
190  if (m_suppressClone) {
191  B2INFO("2D finder will exit with the first track candidate in time.");
192  }
193 
194  if (m_t0CalcMethod != 0 && m_t0CalcMethod != 1) B2WARNING("t0CalcMethod is invalid. calculate as default.");
195 }
196 
197 void
198 CDCTriggerHoughETFModule::event()
199 {
200  /* Clean hits */
201  hitMap.clear();
202  houghCand.clear();
203  associatedTSHitsList.clear();
204 
205  if (!m_eventTime.isValid()) m_eventTime.create();
206  /* set default return value */
207  setReturnValue(true);
208 
209  if (m_testFilename != "") {
210  testFile << StoreObjPtr<EventMetaData>()->getEvent() << " "
211  << m_segmentHits.getEntries() << endl;
212  }
213 
214  if (m_segmentHits.getEntries() == 0) {
215  //B2WARNING("CDCTracking: tsHitsCollection is empty!");
216  return;
217  }
218 
219  /* get CDCHits coordinates in conformal space */
220  for (int iHit = 0; iHit < m_segmentHits.getEntries(); iHit++) {
221  unsigned short iSL = m_segmentHits[iHit]->getISuperLayer();
222  if (m_testFilename != "") {
223  testFile << iSL << " " << m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL] << " "
224  << m_segmentHits[iHit]->getPriorityPosition() << endl;
225  }
226  if (iSL % 2) continue;
227  if (m_ignore2nd && m_segmentHits[iHit]->getPriorityPosition() < 3) continue;
228  double phi = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
229  if (m_usePriority) {
230  phi += 0.5 * (((m_segmentHits[iHit]->getPriorityPosition() >> 1) & 1)
231  - (m_segmentHits[iHit]->getPriorityPosition() & 1));
232  }
233  phi = phi * 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
234  double r = radius[iSL][int(m_usePriority &&
235  m_segmentHits[iHit]->getPriorityPosition() < 3)];
236  TVector2 pos(cos(phi) / r, sin(phi) / r);
237  hitMap.insert(std::make_pair(iHit, std::make_pair(iSL, pos)));
238  }
239 
240  /* Extent the Hough plane such that the cell number is a power of 2 (same for x and y).
241  * This is for the fast peak finder, which divides the Hough plane in half in each step.
242  * Peaks found outside of the actual limits are ignored. */
243  maxIterations = ceil(log2(max(m_nCellsPhi, m_nCellsR))) - 1;
244  nCells = pow(2, maxIterations + 1);
245  /* limits in phi: [-pi, pi] + extra cells */
246  double rectX = M_PI * nCells / m_nCellsPhi;
247  /* limits in R: [-R(minPt), R(minPt)] + extra cells + shift */
248  maxR = 0.5 * Const::speedOfLight * 1.5e-4 / m_minPt;
249  double rectY = maxR * nCells / m_nCellsR;
250  shiftR = 0;
251  if (m_shiftPt < 0) {
252  shiftR = -maxR / 2. / m_nCellsR;
253  } else if (m_shiftPt > 0) {
254  shiftR = maxR / 2. / m_nCellsR;
255  }
256 
257  B2DEBUG(50, "extending Hough plane to " << maxIterations << " iterations, "
258  << nCells << " cells: phi in ["
259  << -rectX * 180. / M_PI << ", " << rectX * 180. / M_PI
260  << "] deg, 1/r in [" << -rectY + shiftR << ", " << rectY + shiftR << "] /cm");
261 
262  /* prepare matrix for storing the Hough plane */
263  if (m_storePlane > 0) {
264  m_houghPlane.create();
265  m_houghPlane->ResizeTo(m_nCellsPhi, m_nCellsR);
266  }
267 
268  // hit map containing only the early hits
269  cdcMap fastHitMap;
270  if (m_suppressClone && !hitMap.empty()) {
271  // find the first track candidates in Hough plane
272  // only for z0 resolution study with single-track events
273  // This will surely fail with multi-track ones,
274  // in which case we really need tick-by-tick simulation for all hits.
275 
277  typedef pair<int, cdcPair> cdcHitPair;
278  // sequential hit map, ordered by TS found time
279  typedef vector<cdcHitPair> cdcSeqMap;
280  cdcSeqMap seqHitMap;
281  // copy hit map to sequential hit map and sort it by TS found time
282  for (auto hit : hitMap) {
283  seqHitMap.push_back(hit);
284  }
285  sort(seqHitMap.begin(), seqHitMap.end(), [this](cdcHitPair i, cdcHitPair j) {
286  return m_segmentHits[i.first]->foundTime() < m_segmentHits[j.first]->foundTime();
287  });
288  auto seqHitItr = seqHitMap.begin();
289  /* layer filter */
290  vector<bool> layerHit(CDC_SUPER_LAYERS, false);
291  // data clock cycle in unit of 2ns
292  short period = 16;
293  short firstTick = m_segmentHits[(*seqHitMap.begin()).first]->foundTime() / period + 1;
294  short lastTick = m_segmentHits[(*(seqHitMap.end() - 1)).first]->foundTime() / period + 1;
295  // add TS hits in every clock cycle until a track candidate is found
296  for (auto tick = firstTick * period; tick < lastTick * period; tick += period) {
297  int nHitInCycle = 0;
298  for (auto itr = seqHitItr; itr < seqHitMap.end(); ++itr) {
299  cdcHitPair currentHit = *itr;
300  // start from the first hit over SL threshold
301  if (count(layerHit.begin(), layerHit.end(), true) >= m_minHits &&
302  m_segmentHits[currentHit.first]->foundTime() > tick) {
303  break;
304  }
305  nHitInCycle++;
306  layerHit[m_segmentHits[currentHit.first]->getISuperLayer()] = true;
307  }
308  copy_n(seqHitItr, nHitInCycle, inserter(fastHitMap, fastHitMap.end()));
309  fastInterceptFinder(fastHitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
310  B2DEBUG(20, "at tick " << tick << ", number of candidates: " << houghCand.size());
311  if (!houghCand.empty()) {
312  B2DEBUG(10, "found a track at clock " << tick << " with "
313  << fastHitMap.size() << "hits");
314  break;
315  }
316  advance(seqHitItr, nHitInCycle);
317  }
318  } else {
319  /* find track candidates in Hough plane using all TS hits */
320  fastInterceptFinder(hitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
321  if (!houghCand.empty()) {
322  B2DEBUG(10, "found a track with " << hitMap.size() << "hits");
323  }
324  }
325 
326  /* merge track candidates */
327  if (m_clusterPattern) {
328  if (patternClustering(fastHitMap))
329  m_eventTime->addBinnedEventT0(calcEventTiming(), Const::CDC);
330  } else {
331  connectedRegions();
332  }
333 
334  if (m_testFilename != "") {
335  testFile << m_tracks.getEntries() << endl;
336  for (int i = 0; i < m_tracks.getEntries(); ++i) {
337  float ix = (m_tracks[i]->getPhi0() - M_PI_4) * m_nCellsPhi / 2. / M_PI - 0.5;
338  float iy = (m_tracks[i]->getOmega() / 2. + maxR - shiftR) * m_nCellsR / 2. / maxR - 0.5;
339  testFile << round(2 * ix) / 2. << " " << round(2 * iy) / 2. << " "
340  << m_tracks[i]->getChargeSign() << endl;
342  m_tracks[i]->getRelationsTo<CDCTriggerSegmentHit>(m_hitCollectionName);
343  testFile << hits.size() << endl;
344  for (unsigned ihit = 0; ihit < hits.size(); ++ihit) {
345  unsigned short iSL = hits[ihit]->getISuperLayer();
346  testFile << iSL << " " << hits[ihit]->getSegmentID() - TSoffset[iSL] << " "
347  << hits[ihit]->getPriorityPosition() << " "
348  << hits.weight(ihit) << endl;
349  }
350  }
351  }
352 }
353 
354 void
355 CDCTriggerHoughETFModule::terminate()
356 {
357  if (m_testFilename != "") testFile.close();
358 }
Combination of several CDCHits to a track segment hit for the trigger.
The Class for CDC Geometry Parameters.
Base class for Modules.
Definition: Module.h:72
Class for type safe access to objects that are referred to in relations.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
std::map< int, cdcPair > cdcMap
Map of <counter, cdcPair>, for hits with indices.
Abstract base class for different kinds of events.