Belle II Software development
CDCTrigger2DFinderModule.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 <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/* defines */
20#define CDC_SUPER_LAYERS 9
21
22using namespace std;
23using namespace Belle2;
24using namespace Belle2::CDC;
25
26//-----------------------------------------------------------------
27// Register the Module
28//-----------------------------------------------------------------
29REG_MODULE(CDCTrigger2DFinder);
30
31//-----------------------------------------------------------------
32// Implementation
33//-----------------------------------------------------------------
34
36{
37 //Set module properties
38 setDescription("Hough tracking algorithm for CDC trigger.");
40
41 // Define module parameters
42 addParam("hitCollectionName", m_hitCollectionName,
43 "Name of the input StoreArray of CDCTriggerSegmentHits.",
44 string(""));
45 addParam("outputCollectionName", m_outputCollectionName,
46 "Name of the StoreArray holding the tracks found in the Hough tracking.",
47 string("TRGCDC2DFinderTracks"));
48 addParam("clusterCollectionName", m_clusterCollectionName,
49 "Name of the StoreArray holding the clusters formed in the Hough plane.",
50 string(""));
51 addParam("nCellsPhi", m_nCellsPhi,
52 "Number of Hough cells in phi (limits: [-180, 180]). Must be an even number.",
53 (unsigned)(160));
54 addParam("nCellsR", m_nCellsR,
55 "Number of Hough cells in 1/r. Must be an even number.",
56 (unsigned)(34));
57 addParam("minPt", m_minPt,
58 "Minimum Pt [GeV]. "
59 "Hough plane limits in 1/r are [-1/r(minPt), 1/r(minPt)]", (double)(0.3));
60 addParam("shiftPt", m_shiftPt,
61 "Shift the Hough plane by 1/4 cell size in 1/r to avoid "
62 "curvature 0 tracks (<0: shift in negative direction, "
63 "0: no shift, >0: shift in positive direction).", 0);
64
65 addParam("minHits", m_minHits,
66 "Minimum hits from different super layers required in a peak cell.",
67 (unsigned)(4));
68 addParam("minHitsShort", m_minHitsShort,
69 "Minimum hits required required in a peak cell for a short track"
70 " (must be in the first minHitsShort super layers).",
71 (unsigned)(4));
72 addParam("minCells", m_minCells,
73 "Peaks with less than minCells connected cells are ignored.",
74 (unsigned)(2));
75 addParam("onlyLocalMax", m_onlyLocalMax,
76 "Switch to remove cells connected to a cell with higher super layer count.",
77 false);
78 addParam("connect", m_connect,
79 "Definition for connected cells. 4: direct (left/right/top/bottom), "
80 "6: direct + 2 diagonal (top right/bottom left), "
81 "8: direct + all diagonal (top right/top left/bottom right/bottom left)",
82 (unsigned)(6));
83 addParam("ignore2ndPriority", m_ignore2nd,
84 "Switch to skip second priority hits.", false);
85 addParam("usePriorityPosition", m_usePriority,
86 "If true, use wire position of priority cell in track segment, "
87 "otherwise use wire position of center cell.", true);
88 addParam("requireSL0", m_requireSL0,
89 "Switch to check separately for a hit in the innermost superlayer.", false);
90 addParam("storeHoughPlane", m_storePlane,
91 "Switch for saving Hough plane as TMatrix in DataStore. "
92 "0: don't store anything, 1: store only peaks, 2: store full plane "
93 "(will increase runtime).", (unsigned)(0));
94 addParam("clusterPattern", m_clusterPattern,
95 "use nested pattern algorithm to find clusters", true);
96 addParam("clusterSizeX", m_clusterSizeX,
97 "maximum number of 2 x 2 squares in cluster for pattern algorithm",
98 (unsigned)(3));
99 addParam("clusterSizeY", m_clusterSizeY,
100 "maximum number of 2 x 2 squares in cluster for pattern algorithm",
101 (unsigned)(3));
102 addParam("hitRelationsFromCorners", m_hitRelationsFromCorners,
103 "Switch for creating relations to hits in the pattern algorithm. "
104 "If true, create relations from cluster corners, otherwise "
105 "from estimated cluster center (might not have relations).", false);
106
107 addParam("testFilename", m_testFilename,
108 "If not empty, a file with input (hits) and output (tracks) "
109 "for each event is written (for firmware debugging).", string(""));
110
111 addParam("suppressClone", m_suppressClone,
112 "Switch to send only the first found track and suppress the "
113 "subsequent clones.", false);
114
115 addParam("usehitpattern", m_usehitpattern,
116 "Switch to use hit pattern inside TSF ", false);
117
118 addParam("useadc", m_useadc,
119 "Switch to use ADC. Can be used with usehitpattern enabled. ", false);
120
121 addParam("useDB", m_useDB,
122 "Switch to use database to load run dependent parameters. ", true);
123}
124
125void
127{
129 m_tracks.registerInDataStore(m_outputCollectionName);
130 m_clusters.registerInDataStore(m_clusterCollectionName);
131
132 m_tracks.registerRelationTo(m_segmentHits);
133 m_tracks.registerRelationTo(m_clusters);
134
135 if (m_storePlane > 0) m_houghPlane.registerInDataStore("HoughPlane");
136
137 if (m_testFilename != "") {
139 }
140
141 if (m_suppressClone) {
142 B2INFO("2D finder will exit with the first track candidate in time.");
143 }
144}
145
146void
148{
149 if (m_useDB) {
150 if (not m_cdctrg2d_DB.isValid()) {
151 StoreObjPtr<EventMetaData> evtMetaData;
152 B2FATAL("No database for CDCTRG 2D parameter. exp " << evtMetaData->getExperiment() << " run "
153 << evtMetaData->getRun());
154 } else {
155 m_usehitpattern = m_cdctrg2d_DB->getfullhit();
156 m_useadc = m_cdctrg2d_DB->getADC();
157 m_minHits = m_cdctrg2d_DB->gethitthreshold();
158 m_minHitsShort = m_cdctrg2d_DB->gethitthreshold();
159 }
160 }
161
163 int layerId = 3;
164 int nTS = 0;
165 for (int iSL = 0; iSL < 9; ++iSL) {
166 TSoffset[iSL] = nTS;
167 nTS += cdc.nWiresInLayer(layerId);
168 TSoffset[iSL + 1] = nTS;
169 if (!m_usehitpattern) {
170 for (int priority = 0; priority < 2; ++ priority) {
171 radius[iSL][priority] = cdc.senseWireR(layerId + priority);
172 }
173 } else {
174 for (int priority = 0; priority < 5; ++ priority) {
175 if (iSL == 0) radius[iSL][priority] = cdc.senseWireR(layerId + priority);
176 else radius[iSL][priority] = cdc.senseWireR(layerId + priority - 2);
177 }
178 }
179 layerId += (iSL > 0 ? 6 : 7);
180 }
181}
182
183void
185{
186 /* Clean hits */
187 hitMap.clear();
188 houghCand.clear();
189
190 /* set default return value */
191 setReturnValue(true);
192
193 if (m_testFilename != "") {
194 testFile << StoreObjPtr<EventMetaData>()->getEvent() << " "
195 << m_segmentHits.getEntries() << endl;
196 }
197
198 if (m_segmentHits.getEntries() == 0) {
199 //B2WARNING("CDCTracking: tsHitsCollection is empty!");
200 return;
201 }
202
203 /* get CDCHits coordinates in conformal space */
204 for (int iHit = 0; iHit < m_segmentHits.getEntries(); iHit++) {
205 unsigned short iSL = m_segmentHits[iHit]->getISuperLayer();
206 if (m_testFilename != "") {
207 testFile << iSL << " " << m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL] << " "
208 << m_segmentHits[iHit]->getPriorityPosition() << endl;
209 }
210 if (iSL % 2) continue;
211 if (m_ignore2nd && m_segmentHits[iHit]->getPriorityPosition() < 3) continue;
212
213 if (m_usehitpattern) {
214 unsigned hitpattern;
215 if (m_useadc) hitpattern = m_segmentHits[iHit]->getadcpattern();
216 else hitpattern = m_segmentHits[iHit]->gethitpattern();
217 int nhitpattern = 0;
218 if (iSL == 0)nhitpattern = 15;
219 else nhitpattern = 11;
220 for (int i = 0; i < nhitpattern; i++) {
221 if ((hitpattern & (1 << i)) != 0) {
222 double phi = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
223 if (iSL != 0 && i == 0) phi = phi - 1;
224 else if (iSL != 0 && i == 1) phi = phi + 0;
225 else if (iSL != 0 && i == 2) phi = phi + 1;
226 else if (iSL != 0 && i == 3) phi = phi - 0.5;
227 else if (iSL != 0 && i == 4) phi = phi + 0.5;
228 else if (iSL != 0 && i == 5) phi = phi + 0;
229 else if (iSL != 0 && i == 6) phi = phi - 0.5;
230 else if (iSL != 0 && i == 7) phi = phi + 0.5;
231 else if (iSL != 0 && i == 8) phi = phi - 1;
232 else if (iSL != 0 && i == 9) phi = phi + 0;
233 else if (iSL != 0 && i == 10) phi = phi + 1;
234 else if (iSL == 0 && i == 0) phi = phi + 0;
235 else if (iSL == 0 && i == 1) phi = phi - 0.5;
236 else if (iSL == 0 && i == 2) phi = phi + 0.5;
237 else if (iSL == 0 && i == 3) phi = phi - 1;
238 else if (iSL == 0 && i == 4) phi = phi + 0;
239 else if (iSL == 0 && i == 5) phi = phi + 1;
240 else if (iSL == 0 && i == 6) phi = phi - 1.5;
241 else if (iSL == 0 && i == 7) phi = phi - 0.5;
242 else if (iSL == 0 && i == 8) phi = phi + 0.5;
243 else if (iSL == 0 && i == 9) phi = phi + 1.5;
244 else if (iSL == 0 && i == 10) phi = phi - 2;
245 else if (iSL == 0 && i == 11) phi = phi - 1;
246 else if (iSL == 0 && i == 12) phi = phi + 0;
247 else if (iSL == 0 && i == 13) phi = phi + 1;
248 else if (iSL == 0 && i == 14) phi = phi + 2;
249 phi = phi * 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
250 int iLayer = 0;
251 if (iSL != 0 && i == 0) iLayer = 0;
252 else if (iSL != 0 && i == 1) iLayer = 0;
253 else if (iSL != 0 && i == 2) iLayer = 0;
254 else if (iSL != 0 && i == 3) iLayer = 1;
255 else if (iSL != 0 && i == 4) iLayer = 1;
256 else if (iSL != 0 && i == 5) iLayer = 2;
257 else if (iSL != 0 && i == 6) iLayer = 3;
258 else if (iSL != 0 && i == 7) iLayer = 3;
259 else if (iSL != 0 && i == 8) iLayer = 4;
260 else if (iSL != 0 && i == 9) iLayer = 4;
261 else if (iSL != 0 && i == 10) iLayer = 4;
262 else if (iSL == 0 && i == 0) iLayer = 0;
263 else if (iSL == 0 && i == 1) iLayer = 1;
264 else if (iSL == 0 && i == 2) iLayer = 1;
265 else if (iSL == 0 && i == 3) iLayer = 2;
266 else if (iSL == 0 && i == 4) iLayer = 2;
267 else if (iSL == 0 && i == 5) iLayer = 2;
268 else if (iSL == 0 && i == 6) iLayer = 3;
269 else if (iSL == 0 && i == 7) iLayer = 3;
270 else if (iSL == 0 && i == 8) iLayer = 3;
271 else if (iSL == 0 && i == 9) iLayer = 3;
272 else if (iSL == 0 && i == 10) iLayer = 4;
273 else if (iSL == 0 && i == 11) iLayer = 4;
274 else if (iSL == 0 && i == 12) iLayer = 4;
275 else if (iSL == 0 && i == 13) iLayer = 4;
276 else if (iSL == 0 && i == 14) iLayer = 4;
277
278 double r = radius[iSL][iLayer];
279 ROOT::Math::XYVector pos(cos(phi) / r, sin(phi) / r);
280 hitMap.insert(std::make_pair(iHit * 15 + i, std::make_pair(iSL * 5 + iLayer, pos)));
281 }
282 }
283 } else {
284 double phi = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
285 if (m_usePriority) {
286 phi += 0.5 * (((m_segmentHits[iHit]->getPriorityPosition() >> 1) & 1)
287 - (m_segmentHits[iHit]->getPriorityPosition() & 1));
288 }
289 phi = phi * 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
290 double r = radius[iSL][int(m_usePriority &&
291 m_segmentHits[iHit]->getPriorityPosition() < 3)];
292 ROOT::Math::XYVector pos(cos(phi) / r, sin(phi) / r);
293 hitMap.insert(std::make_pair(iHit, std::make_pair(iSL, pos)));
294 }
295 }
296
297 /* Extent the Hough plane such that the cell number is a power of 2 (same for x and y).
298 * This is for the fast peak finder, which divides the Hough plane in half in each step.
299 * Peaks found outside of the actual limits are ignored. */
300 maxIterations = ceil(log2(max(m_nCellsPhi, m_nCellsR))) - 1;
301 nCells = pow(2, maxIterations + 1);
302 /* limits in phi: [-pi, pi] + extra cells */
303 double rectX = M_PI * nCells / m_nCellsPhi;
304 /* limits in R: [-R(minPt), R(minPt)] + extra cells + shift */
305 maxR = 0.5 * Const::speedOfLight * 1.5e-4 / m_minPt;
306 double rectY = maxR * nCells / m_nCellsR;
307 shiftR = 0;
308 if (m_shiftPt < 0) {
309 shiftR = -maxR / 2. / m_nCellsR;
310 } else if (m_shiftPt > 0) {
311 shiftR = maxR / 2. / m_nCellsR;
312 }
313
314 B2DEBUG(50, "extending Hough plane to " << maxIterations << " iterations, "
315 << nCells << " cells: phi in ["
316 << -rectX * 180. / M_PI << ", " << rectX * 180. / M_PI
317 << "] deg, 1/r in [" << -rectY + shiftR << ", " << rectY + shiftR << "] /cm");
318
319 /* prepare matrix for storing the Hough plane */
320 if (m_storePlane > 0) {
321 m_houghPlane.create();
323 }
324
325 // hit map containing only the early hits
326 cdcMap fastHitMap;
327 if (m_suppressClone && !hitMap.empty()) {
328 // find the first track candidates in Hough plane
329 // only for z0 resolution study with single-track events
330 // This will surely fail with multi-track ones,
331 // in which case we really need tick-by-tick simulation for all hits.
332
334 typedef pair<int, cdcPair> cdcHitPair;
335 // sequential hit map, ordered by TS found time
336 typedef vector<cdcHitPair> cdcSeqMap;
337 cdcSeqMap seqHitMap;
338 // copy hit map to sequential hit map and sort it by TS found time
339 for (auto hit : hitMap) {
340 seqHitMap.push_back(hit);
341 }
342 sort(seqHitMap.begin(), seqHitMap.end(), [this](cdcHitPair i, cdcHitPair j) {
343 return m_segmentHits[i.first]->foundTime() < m_segmentHits[j.first]->foundTime();
344 });
345 auto seqHitItr = seqHitMap.begin();
346 /* layer filter */
347 vector<bool> layerHit(CDC_SUPER_LAYERS, false);
348 // data clock cycle in unit of 2ns
349 short period = 16;
350 short firstTick = m_segmentHits[(*seqHitMap.begin()).first]->foundTime() / period + 1;
351 short lastTick = m_segmentHits[(*(seqHitMap.end() - 1)).first]->foundTime() / period + 1;
352 // add TS hits in every clock cycle until a track candidate is found
353 for (auto tick = firstTick * period; tick < lastTick * period; tick += period) {
354 int nHitInCycle = 0;
355 for (auto itr = seqHitItr; itr < seqHitMap.end(); ++itr) {
356 cdcHitPair currentHit = *itr;
357 // start from the first hit over SL threshold
358 if (count(layerHit.begin(), layerHit.end(), true) >= m_minHits &&
359 m_segmentHits[currentHit.first]->foundTime() > tick) {
360 break;
361 }
362 nHitInCycle++;
363 layerHit[m_segmentHits[currentHit.first]->getISuperLayer()] = true;
364 }
365 copy_n(seqHitItr, nHitInCycle, inserter(fastHitMap, fastHitMap.end()));
366 fastInterceptFinder(fastHitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
367 B2DEBUG(20, "at tick " << tick << ", number of candidates: " << houghCand.size());
368 if (!houghCand.empty()) {
369 B2DEBUG(10, "found a track at clock " << tick << " with "
370 << fastHitMap.size() << "hits");
371 break;
372 }
373 advance(seqHitItr, nHitInCycle);
374 }
375 } else {
376 /* find track candidates in Hough plane using all TS hits */
377 fastInterceptFinder(hitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
378 if (!houghCand.empty()) {
379 B2DEBUG(10, "found a track with " << hitMap.size() << "hits");
380 }
381 }
382
383 /* merge track candidates */
385 patternClustering(fastHitMap);
386 else
388
389 if (m_testFilename != "") {
390 testFile << m_tracks.getEntries() << endl;
391 for (int i = 0; i < m_tracks.getEntries(); ++i) {
392 float ix = (m_tracks[i]->getPhi0() - M_PI_4) * m_nCellsPhi / 2. / M_PI - 0.5;
393 float iy = (m_tracks[i]->getOmega() / 2. + maxR - shiftR) * m_nCellsR / 2. / maxR - 0.5;
394 testFile << round(2 * ix) / 2. << " " << round(2 * iy) / 2. << " "
395 << m_tracks[i]->getChargeSign() << endl;
398 testFile << hits.size() << endl;
399 for (unsigned ihit = 0; ihit < hits.size(); ++ihit) {
400 unsigned short iSL = hits[ihit]->getISuperLayer();
401 testFile << iSL << " " << hits[ihit]->getSegmentID() - TSoffset[iSL] << " "
402 << hits[ihit]->getPriorityPosition() << " "
403 << hits.weight(ihit) << endl;
404 }
405 }
406 }
407}
408
409void
std::vector< CDCTriggerHoughCand > houghCand
Hough Candidates.
bool m_usehitpattern
switch to use hit pattern inside TSF
std::string m_testFilename
filename for test output for firmware debugging
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
std::ofstream testFile
filestream for test output for firmware debugging
bool m_useadc
switch to use hit pattern inside TSF with ADC cut
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
virtual void initialize() override
Initialize the module and check module parameters.
unsigned m_nCellsR
number of Hough cells in 1/r
int m_shiftPt
shift the Hough plane in 1/r to avoid curvature 0 tracks < 0: shift in negative direction (negative h...
virtual void event() override
Run tracking.
StoreArray< CDCTriggerSegmentHit > m_segmentHits
list of track segment hits
std::string m_outputCollectionName
Name of the StoreArray containing the tracks found by the Hough tracking.
unsigned m_nCellsPhi
number of Hough cells in phi
bool m_usePriority
switch between priority position and center position of track segment
bool m_clusterPattern
switch for clustering algorithm (if true use nested patterns)
double maxR
Hough plane limit in 1/r [1/cm].
virtual void terminate() override
Clean up.
bool m_hitRelationsFromCorners
switch for creating relations to hits in the pattern clustering algorithm.
StoreObjPtr< TMatrix > m_houghPlane
matrix containing the Hough plane
unsigned m_storePlane
switch to save the Hough plane in DataStore (0: don't save, 1: save only peaks, 2: save full plane)
bool m_ignore2nd
switch to skip second priority hits
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].
unsigned nCells
number of cells for the fast peak finder: 2^(maxIterations + 1).
bool m_suppressClone
switch to send only the first found track and suppress the subsequent clones
virtual void beginRun() override
Register run-dependent DataStore arrays.
StoreArray< CDCTriggerTrack > m_tracks
list of found tracks
cdcMap hitMap
map of TS hits containing <iHit, <iSL, (x, y)>> with iHit: hit index in StoreArray iSL: super layer i...
unsigned m_clusterSizeX
maximum cluster size for pattern algorithm
double m_minPt
Hough plane limit in Pt [GeV].
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
unsigned TSoffset[10]
Number of track segments up to super layer.
std::string m_clusterCollectionName
Name of the StoreArray containing the clusters formed in the Hough plane.
std::string m_hitCollectionName
Name of the StoreArray containing the input track segment hits.
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
bool m_useDB
switch to use database to load run dependent parameter
DBObjPtr< CDCTrigger2DConfig > m_cdctrg2d_DB
run dependent parameter database of 2D
unsigned m_clusterSizeY
maximum cluster size for pattern algorithm
void connectedRegions()
Combine Hough candidates to tracks by merging connected cells.
Combination of several CDCHits to a track segment hit for the trigger.
The Class for CDC Geometry Parameters.
static CDCGeometryPar & Instance(const CDCGeometry *=nullptr)
Static method to get a reference to the CDCGeometryPar instance.
static const double speedOfLight
[cm/ns]
Definition Const.h:695
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition Module.cc:220
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
Class for type safe access to objects that are referred to in relations.
Type-safe access to single objects in the data store.
Definition StoreObjPtr.h:96
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
std::map< int, cdcPair > cdcMap
Map of <counter, cdcPair>, for hits with indices.
Abstract base class for different kinds of events.
STL namespace.