Belle II Software development
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
24using namespace std;
25using namespace Belle2;
26using namespace Belle2::CDC;
27
28//-----------------------------------------------------------------
29// Register the Module
30//-----------------------------------------------------------------
31REG_MODULE(CDCTriggerHoughETF);
32
33//-----------------------------------------------------------------
34// Implementation
35//-----------------------------------------------------------------
36
38{
39 //Set module properties
40 setDescription("Hough tracking algorithm for CDC trigger.");
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 addParam("offset", m_offset,
152 "Set certain time offset for ETFHough simulation"
153 "Default as -10", -10);
154}
155
156void
158{
159 // register DataStore elements
162
163 if (m_storeTracks) {
165 m_clusters.registerInDataStore(m_clusterCollectionName);
166
169 }
170
171 if (m_storePlane > 0) m_houghPlane.registerInDataStore("HoughPlane");
172
174 int layerId = 3;
175 int nTS = 0;
176 for (int iSL = 0; iSL < 9; ++iSL) {
177 TSoffset[iSL] = nTS;
178 nTS += cdc.nWiresInLayer(layerId);
179 TSoffset[iSL + 1] = nTS;
180 for (int priority = 0; priority < 2; ++ priority) {
181 radius[iSL][priority] = cdc.senseWireR(layerId + priority);
182 }
183 layerId += (iSL > 0 ? 6 : 7);
184 }
185
186 for (int sl = 1; sl < 9; sl++) {
187 NSecOffset[sl] = NSEC[sl - 1] + NSecOffset[sl - 1];
188 }
189
190 if (m_testFilename != "") {
192 }
193
194 if (m_suppressClone) {
195 B2INFO("2D finder will exit with the first track candidate in time.");
196 }
197
198 if (m_t0CalcMethod != 0 && m_t0CalcMethod != 1) B2WARNING("t0CalcMethod is invalid. calculate as default.");
199}
200
201void
203{
204 /* Clean hits */
205 hitMap.clear();
206 houghCand.clear();
207 associatedTSHitsList.clear();
208
210 /* set default return value */
211 setReturnValue(true);
212
213 if (m_testFilename != "") {
214 testFile << StoreObjPtr<EventMetaData>()->getEvent() << " "
215 << m_segmentHits.getEntries() << endl;
216 }
217
218 if (m_segmentHits.getEntries() == 0) {
219 //B2WARNING("CDCTracking: tsHitsCollection is empty!");
220 return;
221 }
222
223 /* get CDCHits coordinates in conformal space */
224 for (int iHit = 0; iHit < m_segmentHits.getEntries(); iHit++) {
225 unsigned short iSL = m_segmentHits[iHit]->getISuperLayer();
226 if (m_testFilename != "") {
227 testFile << iSL << " " << m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL] << " "
228 << m_segmentHits[iHit]->getPriorityPosition() << endl;
229 }
230 if (iSL % 2) continue;
231 if (m_ignore2nd && m_segmentHits[iHit]->getPriorityPosition() < 3) continue;
232 double phi = m_segmentHits[iHit]->getSegmentID() - TSoffset[iSL];
233 if (m_usePriority) {
234 phi += 0.5 * (((m_segmentHits[iHit]->getPriorityPosition() >> 1) & 1)
235 - (m_segmentHits[iHit]->getPriorityPosition() & 1));
236 }
237 phi = phi * 2. * M_PI / (TSoffset[iSL + 1] - TSoffset[iSL]);
238 double r = radius[iSL][int(m_usePriority &&
239 m_segmentHits[iHit]->getPriorityPosition() < 3)];
240 ROOT::Math::XYVector pos(cos(phi) / r, sin(phi) / r);
241 hitMap.insert(std::make_pair(iHit, std::make_pair(iSL, pos)));
242 }
243
244 /* Extent the Hough plane such that the cell number is a power of 2 (same for x and y).
245 * This is for the fast peak finder, which divides the Hough plane in half in each step.
246 * Peaks found outside of the actual limits are ignored. */
247 maxIterations = ceil(log2(max(m_nCellsPhi, m_nCellsR))) - 1;
248 nCells = pow(2, maxIterations + 1);
249 /* limits in phi: [-pi, pi] + extra cells */
250 double rectX = M_PI * nCells / m_nCellsPhi;
251 /* limits in R: [-R(minPt), R(minPt)] + extra cells + shift */
252 maxR = 0.5 * Const::speedOfLight * 1.5e-4 / m_minPt;
253 double rectY = maxR * nCells / m_nCellsR;
254 shiftR = 0;
255 if (m_shiftPt < 0) {
256 shiftR = -maxR / 2. / m_nCellsR;
257 } else if (m_shiftPt > 0) {
258 shiftR = maxR / 2. / m_nCellsR;
259 }
260
261 B2DEBUG(50, "extending Hough plane to " << maxIterations << " iterations, "
262 << nCells << " cells: phi in ["
263 << -rectX * 180. / M_PI << ", " << rectX * 180. / M_PI
264 << "] deg, 1/r in [" << -rectY + shiftR << ", " << rectY + shiftR << "] /cm");
265
266 /* prepare matrix for storing the Hough plane */
267 if (m_storePlane > 0) {
270 }
271
272 // hit map containing only the early hits
273 cdcMap fastHitMap;
274 if (m_suppressClone && !hitMap.empty()) {
275 // find the first track candidates in Hough plane
276 // only for z0 resolution study with single-track events
277 // This will surely fail with multi-track ones,
278 // in which case we really need tick-by-tick simulation for all hits.
279
281 typedef pair<int, cdcPair> cdcHitPair;
282 // sequential hit map, ordered by TS found time
283 typedef vector<cdcHitPair> cdcSeqMap;
284 cdcSeqMap seqHitMap;
285 // copy hit map to sequential hit map and sort it by TS found time
286 for (auto hit : hitMap) {
287 seqHitMap.push_back(hit);
288 }
289 sort(seqHitMap.begin(), seqHitMap.end(), [this](cdcHitPair i, cdcHitPair j) {
290 return m_segmentHits[i.first]->foundTime() < m_segmentHits[j.first]->foundTime();
291 });
292 auto seqHitItr = seqHitMap.begin();
293 /* layer filter */
294 vector<bool> layerHit(CDC_SUPER_LAYERS, false);
295 // data clock cycle in unit of 2ns
296 short period = 16;
297 short firstTick = m_segmentHits[(*seqHitMap.begin()).first]->foundTime() / period + 1;
298 short lastTick = m_segmentHits[(*(seqHitMap.end() - 1)).first]->foundTime() / period + 1;
299 // add TS hits in every clock cycle until a track candidate is found
300 for (auto tick = firstTick * period; tick < lastTick * period; tick += period) {
301 int nHitInCycle = 0;
302 for (auto itr = seqHitItr; itr < seqHitMap.end(); ++itr) {
303 cdcHitPair currentHit = *itr;
304 // start from the first hit over SL threshold
305 if (count(layerHit.begin(), layerHit.end(), true) >= m_minHits &&
306 m_segmentHits[currentHit.first]->foundTime() > tick) {
307 break;
308 }
309 nHitInCycle++;
310 layerHit[m_segmentHits[currentHit.first]->getISuperLayer()] = true;
311 }
312 copy_n(seqHitItr, nHitInCycle, inserter(fastHitMap, fastHitMap.end()));
313 fastInterceptFinder(fastHitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
314 B2DEBUG(20, "at tick " << tick << ", number of candidates: " << houghCand.size());
315 if (!houghCand.empty()) {
316 B2DEBUG(10, "found a track at clock " << tick << " with "
317 << fastHitMap.size() << "hits");
318 break;
319 }
320 advance(seqHitItr, nHitInCycle);
321 }
322 } else {
323 /* find track candidates in Hough plane using all TS hits */
324 fastInterceptFinder(hitMap, -rectX, rectX, -rectY + shiftR, rectY + shiftR, 0, 0, 0);
325 if (!houghCand.empty()) {
326 B2DEBUG(10, "found a track with " << hitMap.size() << "hits");
327 }
328 }
329
330 /* merge track candidates */
331 if (m_clusterPattern) {
332 if (patternClustering(fastHitMap))
333 m_eventTime->addBinnedEventT0(calcEventTiming() + m_offset, Const::CDC);
334 } else {
336 }
337
338 if (m_testFilename != "") {
339 testFile << m_tracks.getEntries() << endl;
340 for (int i = 0; i < m_tracks.getEntries(); ++i) {
341 float ix = (m_tracks[i]->getPhi0() - M_PI_4) * m_nCellsPhi / 2. / M_PI - 0.5;
342 float iy = (m_tracks[i]->getOmega() / 2. + maxR - shiftR) * m_nCellsR / 2. / maxR - 0.5;
343 testFile << round(2 * ix) / 2. << " " << round(2 * iy) / 2. << " "
344 << m_tracks[i]->getChargeSign() << endl;
347 testFile << hits.size() << endl;
348 for (unsigned ihit = 0; ihit < hits.size(); ++ihit) {
349 unsigned short iSL = hits[ihit]->getISuperLayer();
350 testFile << iSL << " " << hits[ihit]->getSegmentID() - TSoffset[iSL] << " "
351 << hits[ihit]->getPriorityPosition() << " "
352 << hits.weight(ihit) << endl;
353 }
354 }
355 }
356}
357
358void
360{
361 if (m_testFilename != "") testFile.close();
362}
void addBinnedEventT0(int eventT0, Const::EDetector detector)
Store a binned event t0 for the given detector replacing any other hypothesis for this detector.
std::string m_EventTimeName
Name of the StoreObject containing the trigger event time.
int NSecOffset[9]
Number of sector offset of each super layer.
std::vector< CDCTriggerHoughCand > houghCand
Hough Candidates.
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.
bool m_useHighPassTimingList
Use associated fastest timings track-by-track.
unsigned m_minCells
minimum number of cells in a cluster to form a track
std::ofstream testFile
filestream for test output for firmware debugging
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
short m_timeWindowEnd
End time of time window relative to median.
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.
std::vector< std::vector< CDCTriggerSegmentHit * > > associatedTSHitsList
list of fastest timing of TS associated with Track
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
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
unsigned m_t0CalcMethod
Switch method to determine the event timing.
double radius[9][2]
Radius of the CDC layers with priority wires (2 per super layer).
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...
int m_offset
offset for ETF simulation
unsigned m_arrivalOrder
arrival order of fastest timing used as t0 (effective when t0CalcMEthod == 0)
unsigned m_clusterSizeX
maximum cluster size for pattern algorithm
double m_minPt
Hough plane limit in Pt [GeV].
const int NSEC[9]
Number of sector in each super layer.
bool m_requireSL0
switch to check separately for a hit in the innermost super layer
short m_timeWindowBegin
Start time of time window relative to median.
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
StoreObjPtr< BinnedEventT0 > m_eventTime
StoreObjPtr holding the event time.
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.
bool m_storeTracks
Switch to save the 2D Hough track reconstructed in this module.
std::string m_hitCollectionName
Name of the StoreArray containing the input track segment hits.
bool patternClustering(const cdcMap &inputMap)
Combine Hough candidates to tracks by a fixed pattern algorithm.
bool m_onlyLocalMax
switch to ignore candidates connected to cells with higher super layer count
bool m_usePriorityTiming
Switch to use priority timing instead of fastest timing.
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
Base class for Modules.
Definition: Module.h:72
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
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.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool create(bool replace=false)
Create a default object in the data store.
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:111
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:560
#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.
STL namespace.