Belle II Software development
NDFinder.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 <string>
10#include <vector>
11#include <array>
12#include <utility>
13#include <string>
14#include <fstream>
15#include <set>
16#include <cmath>
17#include "framework/logging/Logger.h"
18#include "boost/iostreams/filter/gzip.hpp"
19#include "boost/iostreams/filtering_streambuf.hpp"
20#include "boost/iostreams/filtering_stream.hpp"
21#include "TMath.h"
22#include "trg/cdc/NDFinder.h"
23
24using namespace Belle2;
25
26// Run the necessary initialization of the NDFinder
27void NDFinder::init(const NDFinderParameters& ndFinderParameters)
28{
29 m_ndFinderParams = ndFinderParameters;
30
31 // Initialization of the pointer arrays, fills hit to sector LUT
34
35 // Load the axial and stereo track to hit relations from file.
37 loadCompressedHitReps(m_ndFinderParams.stereoFile, m_compStereoBins, *m_compStereoHitReps);
38
39 // Fills the expanded hit representations (from compressed hits to weights)
41 fillExpandedHitReps(m_compStereoBins, *m_compStereoHitReps, *m_expStereoHitReps);
42
43 // Reset the NDFinder data structure to process next event
44 reset();
45
46 // Parameters necessary for the clustering algorithm
47 ClustererParameters clustererParams = {
48 ndFinderParameters.iterations,
49 ndFinderParameters.omegaTrim,
50 ndFinderParameters.phiTrim,
52 m_nPhi,
53 m_nCot
54 };
55 m_clusterer = Clusterizend(clustererParams);
56}
57
58// Add the hit info of a single track segment to the NDFinder
59void NDFinder::addHit(const HitInfo& hitInfo)
60{
61 // Priority position from the track segment finder: 0 = no hit, 3 = 1st priority, 1 = 2nd right, 2 = 2nd left
62 if (hitInfo.hitPrioPos > 0) { // Skip "no hit" case
63 m_hitIDs.push_back(hitInfo.hitID);
64 m_hitSLIDs.push_back(hitInfo.hitSLID);
65 m_priorityWirePos.push_back(3 - hitInfo.hitPrioPos); // 0 = 1st priority, 1 = 2nd left, 2 = 2nd right
66 m_priorityWireTime.push_back(hitInfo.hitPrioTime);
67 ++m_nHits;
68 }
69}
70
71// Initialization of the LUT arrays
73{
74 // Shapes of the arrays holding the hit patterns
75 const std::array<c2index, 2> shapeHitToSectorIDs = {{m_nTS, m_nPrio}};
76 const std::array<c5index, 5> shapeCompAxialHitReps = {{m_nAxial, m_nPrio, m_nOmega, m_nPhiComp, 1}};
77 const std::array<c5index, 5> shapeCompStereoHitReps = {{m_nStereo, m_nPrio, m_nOmega, m_nPhiComp, m_nCot}};
78 const std::array<c5index, 5> shapeExpAxialHitReps = {{m_nAxial, m_nPrio, m_nOmega, m_nPhi, m_nCot}};
79 const std::array<c5index, 5> shapeExpStereoHitReps = {{m_nStereo, m_nPrio, m_nOmega, m_nPhi, m_nCot}};
80 const std::array<c3index, 3> shapeHough = {{m_nOmega, m_nPhi, m_nCot}};
81
82 m_hitToSectorIDs = new c2array(shapeHitToSectorIDs);
83 m_compAxialHitReps = new c5array(shapeCompAxialHitReps);
84 m_compStereoHitReps = new c5array(shapeCompStereoHitReps);
85 m_expAxialHitReps = new c5array(shapeExpAxialHitReps);
86 m_expStereoHitReps = new c5array(shapeExpStereoHitReps);
87 m_houghSpace = new c3array(shapeHough);
88}
89
90// Fills the m_hitToSectorIDs array
92{
93 // Number of first priority wires in each super layer (TS per SL)
94 constexpr std::array<unsigned short, 9> nWires = {160, 160, 192, 224, 256, 288, 320, 352, 384};
95 // Number of priority wires (= number of TS) per SL in a single (1/32) phi sector
96 std::vector<unsigned short> wiresPerSector;
97 // Lookup table: Maps the TS id to the SL number
98 std::vector<unsigned short> hitToSuperLayer;
99 // Integrated number of priority wires for each SL
100 std::vector<unsigned short> cumulativeWires = {0};
101 // Integrated number of sector priority wires for each SL (Axial even, Stereo odd)
102 std::vector<unsigned short> cumulativeSectorWires = {0, 0};
103 for (unsigned short superLayer = 0; superLayer < m_nSL; ++superLayer) {
104 wiresPerSector.push_back(nWires[superLayer] / m_phiGeo);
105 for (unsigned short _ = 0; _ < nWires[superLayer]; ++_) {
106 hitToSuperLayer.push_back(superLayer);
107 }
108 cumulativeWires.push_back(cumulativeWires[superLayer] + nWires[superLayer]);
109 cumulativeSectorWires.push_back(cumulativeSectorWires[superLayer] + nWires[superLayer] / m_phiGeo);
110 }
111 for (unsigned short hit = 0; hit < m_nTS; ++hit) {
112 unsigned short superLayer = hitToSuperLayer[hit];
113 bool isAxial = (superLayer % 2 == 0);
114 unsigned short wireIDinSL = hit - cumulativeWires[superLayer];
115 unsigned short wireIDinSector = wireIDinSL % wiresPerSector[superLayer];
116 unsigned short relativeWireIDinSector = cumulativeSectorWires[superLayer] + wireIDinSector;
117 unsigned short relativeSectorIDinSuperLayer = static_cast<unsigned short>(floor(wireIDinSL / wiresPerSector[superLayer]));
118 c2array& hitToSectorIDs = *m_hitToSectorIDs;
119 hitToSectorIDs[hit][0] = static_cast<unsigned short>(isAxial);
120 hitToSectorIDs[hit][1] = relativeWireIDinSector;
121 hitToSectorIDs[hit][2] = relativeSectorIDinSuperLayer;
122 }
123}
124
125// Fills the m_compAxialHitReps/m_compStereoHitReps arrays
126void NDFinder::loadCompressedHitReps(const std::string& fileName, const SectorBinning& compBins, c5array& compHitsToWeights)
127{
128 // Array of the entries in trg/cdc/data/ndFinderArray*Comp.txt.gz
129 std::vector<unsigned short> flatArray;
130 std::ifstream arrayFileGZ(fileName, std::ios_base::in | std::ios_base::binary);
131 if (!arrayFileGZ.is_open()) {
132 B2ERROR("Could not open array file: " << fileName);
133 return;
134 }
135 boost::iostreams::filtering_istream arrayStream;
136 arrayStream.push(boost::iostreams::gzip_decompressor());
137 arrayStream.push(arrayFileGZ);
138 unsigned short uline;
139 while (arrayStream >> uline) {
140 flatArray.push_back(uline);
141 }
142 arrayFileGZ.close();
143 unsigned long arrayIndex = 0;
144 for (c5index hitID = 0; hitID < compBins.nHitIDs; ++hitID) {
145 for (c5index priorityWire = 0; priorityWire < compBins.nPriorityWires; ++priorityWire) {
146 for (c5index omegaIdx = 0; omegaIdx < compBins.omega; ++omegaIdx) {
147 for (c5index phiIdx = 0; phiIdx < compBins.phi; ++phiIdx) {
148 for (c5index cotIdx = 0; cotIdx < compBins.cot; ++cotIdx) {
149 compHitsToWeights[hitID][priorityWire][omegaIdx][phiIdx][cotIdx] = flatArray[arrayIndex];
150 ++arrayIndex;
151 }
152 }
153 }
154 }
155 }
156}
157
158// Fills the m_expAxialHitReps/m_expStereoHitReps arrays
159void NDFinder::fillExpandedHitReps(const SectorBinning& compBins, const c5array& compHitsToWeights, c5array& expHitsToWeights)
160{
161 for (c5index hitID = 0; hitID < compBins.nHitIDs; ++hitID) {
162 for (c5index priorityWire = 0; priorityWire < compBins.nPriorityWires; ++priorityWire) {
163 for (c5index omegaIdx = 0; omegaIdx < compBins.omega; ++omegaIdx) {
164 for (c5index cotIdx = 0; cotIdx < compBins.cot; ++cotIdx) {
165 unsigned short phiStart = compHitsToWeights[hitID][priorityWire][omegaIdx][0][cotIdx];
166 unsigned short nPhiEntries = compHitsToWeights[hitID][priorityWire][omegaIdx][1][cotIdx];
167 for (c5index phiEntry = 0; phiEntry < nPhiEntries; ++phiEntry) {
168 unsigned short houghPhiIdx = (phiStart + phiEntry) % m_nPhi; // houghPhiIdx goes now over the complete Hough space
169 expHitsToWeights[hitID][priorityWire][omegaIdx][houghPhiIdx][cotIdx] =
170 compHitsToWeights[hitID][priorityWire][omegaIdx][phiEntry + 2][cotIdx];
171 if (compBins.cot == 1) { // Axial case: expand the same curve in all cot bins
172 for (c5index axialCotIdx = 1; axialCotIdx < m_nCot; ++axialCotIdx) {
173 expHitsToWeights[hitID][priorityWire][omegaIdx][houghPhiIdx][axialCotIdx] =
174 compHitsToWeights[hitID][priorityWire][omegaIdx][phiEntry + 2][cotIdx];
175 }
176 }
177 }
178 }
179 }
180 }
181 }
182}
183
184// Reset the NDFinder data structure to process next event
186{
187 // Clear the vector of the found tracks
188 m_ndFinderTracks.clear();
189
190 // Clear the hit informations
191 m_hitIDs.clear();
192 m_hitSLIDs.clear();
193 m_nHits = 0;
194 m_priorityWirePos.clear();
195 m_priorityWireTime.clear();
196
197 // Create a new Hough space
198 delete m_houghSpace;
199 std::array<c3index, 3> shapeHough = {{m_nOmega, m_nPhi, m_nCot}};
200 m_houghSpace = new c3array(shapeHough);
201}
202
203// Public: Adds the hits to the Hough space and finds the tracks
205{
206 // Build the Hough plane by summing up all single hit contributions
207 for (unsigned short hitIdx = 0; hitIdx < m_nHits; ++hitIdx) {
209 }
211}
212
213// Process a single axial or stereo hit
214void NDFinder::processHitForHoughSpace(const unsigned short hitIdx)
215{
216 const c2array& hitToSectorIDs = *m_hitToSectorIDs;
217 unsigned short orientation = hitToSectorIDs[m_hitIDs[hitIdx]][0];
218 unsigned short relativeWireID = hitToSectorIDs[m_hitIDs[hitIdx]][1];
219 unsigned short relativeSectorID = hitToSectorIDs[m_hitIDs[hitIdx]][2];
220 unsigned short phiSectorStart = relativeSectorID * m_nPhiSector;
221 unsigned short priorityWire = m_priorityWirePos[hitIdx];
222
223 WireInfo wireInfo = {relativeWireID, phiSectorStart, priorityWire};
224 if (orientation == 1) {
226 } else {
227 writeHitToHoughSpace(wireInfo, *m_expStereoHitReps);
228 }
229}
230
231// Write (add) a single hit (Hough curve) to the Hough space
232void NDFinder::writeHitToHoughSpace(const WireInfo& wireInfo, const c5array& expHitsToWeights)
233{
234 c3array& houghSpace = *m_houghSpace;
235 for (unsigned short cotIdx = 0; cotIdx < m_nCot; ++cotIdx) {
236 for (unsigned short omegaIdx = 0; omegaIdx < m_nOmega; ++omegaIdx) {
237 for (unsigned short phiIdx = 0; phiIdx < m_nPhi; ++phiIdx) {
238 unsigned short houghPhiIdx = (phiIdx + wireInfo.phiSectorStart) % m_nPhi;
239 houghSpace[omegaIdx][houghPhiIdx][cotIdx] +=
240 expHitsToWeights[wireInfo.relativeWireID][wireInfo.priorityWire][omegaIdx][phiIdx][cotIdx];
241 }
242 }
243 }
244}
245
246// Core track finding logic in the constructed Hough space
248{
249 c3array& houghSpace = *m_houghSpace;
250 m_clusterer.setNewPlane(houghSpace);
251 std::vector<SimpleCluster> allClusters = m_clusterer.makeClusters();
252 std::vector<SimpleCluster> validClusters = relateHitsToClusters(allClusters);
253
254 for (SimpleCluster& cluster : validClusters) {
255 std::array<double, 3> centerOfGravity = calculateCenterOfGravity(cluster);
256 std::array<double, 3> estimatedParameters = getTrackParameterEstimate(centerOfGravity);
257
258 // Readouts for the 3DFinderInfo class for analysis (Hough space + cluster info)
259 std::vector<ROOT::Math::XYZVector> readoutHoughSpace;
260 std::vector<ROOT::Math::XYZVector> readoutCluster;
261
262 if (m_ndFinderParams.storeAdditionalReadout) {
263 // Readout of the complete Hough space
264 for (c3index omegaIdx = 0; omegaIdx < m_nOmega; ++omegaIdx) {
265 for (c3index phiIdx = 0; phiIdx < m_nPhi; ++phiIdx) {
266 for (c3index cotIdx = 0; cotIdx < m_nCot; ++cotIdx) {
267 unsigned short element = houghSpace[omegaIdx][phiIdx][cotIdx];
268 readoutHoughSpace.push_back(ROOT::Math::XYZVector(element, 0, 0));
269 }
270 }
271 }
272 // Readout of the peak cluster weight
273 unsigned int peakWeight = cluster.getPeakWeight();
274 readoutCluster.push_back(ROOT::Math::XYZVector(peakWeight, 0, 0));
275 // Readout of the number of cluster cells
276 unsigned short nCells = cluster.getCells().size();
277 readoutCluster.push_back(ROOT::Math::XYZVector(nCells, 0, 0));
278 // Readout of the cluster center of gravity
279 readoutCluster.push_back(ROOT::Math::XYZVector(centerOfGravity[0], centerOfGravity[1], centerOfGravity[2]));
280 // Readout of the cluster weights
281 for (const cell_index& cellIdx : cluster.getCells()) {
282 unsigned short element = houghSpace[cellIdx[0]][cellIdx[1]][cellIdx[2]];
283 readoutCluster.push_back(ROOT::Math::XYZVector(element, 0, 0));
284 }
285 // Readout of the cluster cell indices
286 for (const cell_index& cellIdx : cluster.getCells()) {
287 readoutCluster.push_back(ROOT::Math::XYZVector(cellIdx[0], cellIdx[1], cellIdx[2]));
288 }
289 }
290 m_ndFinderTracks.push_back(NDFinderTrack(estimatedParameters,
291 std::move(cluster), std::move(readoutHoughSpace), std::move(readoutCluster)));
292 }
293}
294
295// Relate the hits in the peak cell of the cluster to the cluster. Applies a cut on the clusters.
296std::vector<SimpleCluster> NDFinder::relateHitsToClusters(std::vector<SimpleCluster>& clusters)
297{
298 std::vector<std::vector<unsigned short>> hitsVsClusters = getHitsVsClustersTable(clusters);
299 std::vector<SimpleCluster> goodClusters;
300 if (hitsVsClusters.empty()) return goodClusters;
301
302 for (unsigned short clusterIdx = 0; clusterIdx < hitsVsClusters.size(); ++clusterIdx) {
303 std::vector<ContributionInfo> contributionInfos = extractContributionInfos(hitsVsClusters[clusterIdx]);
304 for (unsigned short superLayer = 0; superLayer < 9; ++superLayer) {
305 int maximumHit = getMaximumHitInSuperLayer(contributionInfos, superLayer);
306 if (maximumHit >= 0) { // there exists a hit
307 clusters[clusterIdx].addHitToCluster(static_cast<unsigned short>(maximumHit));
308 }
309 }
310 if (checkHitSuperLayers(clusters[clusterIdx])) {
311 goodClusters.push_back(clusters[clusterIdx]);
312 }
313 }
314 return goodClusters;
315}
316
317// Create hits to clusters confusion matrix
318std::vector<std::vector<unsigned short>> NDFinder::getHitsVsClustersTable(const std::vector<SimpleCluster>& clusters)
319{
320 // Creates a (Number Clusters)x(Number Hits) matrix
321 std::vector<unsigned short> hitElem(m_nHits, 0);
322 std::vector<std::vector<unsigned short>> hitsVsClusters(clusters.size(), hitElem);
323 // Fill the matrix with all the hit contributions
324 for (unsigned short clusterIdx = 0; clusterIdx < clusters.size(); ++clusterIdx) {
325 SimpleCluster cluster = clusters[clusterIdx];
326 cell_index peakCell = cluster.getPeakCell();
327 for (unsigned short hitIdx = 0; hitIdx < m_hitIDs.size(); ++hitIdx) {
328 unsigned short contribution = getHitContribution(peakCell, hitIdx);
329 hitsVsClusters[clusterIdx][hitIdx] = contribution;
330 }
331 }
332 return hitsVsClusters;
333}
334
335// Returns the hit contribution of a TS at a certain maximum cell
336unsigned short NDFinder::getHitContribution(const cell_index& peakCell, const unsigned short hitIdx)
337{
338 unsigned short contribution = 0;
339 unsigned short omegaIdx = peakCell[0];
340 unsigned short houghPhiIdx = peakCell[1];
341 unsigned short cotIdx = peakCell[2];
342
343 const c2array& hitToSectorIDs = *m_hitToSectorIDs;
344 unsigned short orientation = hitToSectorIDs[m_hitIDs[hitIdx]][0];
345 unsigned short relativeWireID = hitToSectorIDs[m_hitIDs[hitIdx]][1];
346 unsigned short relativeSectorID = hitToSectorIDs[m_hitIDs[hitIdx]][2];
347 unsigned short phiSectorStart = relativeSectorID * m_nPhiSector;
348 unsigned short priorityWire = m_priorityWirePos[hitIdx];
349
350 // Inverse Hough transformation (inverse of writeHitToHoughSpace method)
351 unsigned short phiIdx = (houghPhiIdx - phiSectorStart + m_nPhi) % m_nPhi;
352
353 if (orientation == 1) { // Axial TS
354 contribution = (*m_expAxialHitReps)[relativeWireID][priorityWire][omegaIdx][phiIdx][cotIdx];
355 } else { // Stereo TS
356 contribution = (*m_expStereoHitReps)[relativeWireID][priorityWire][omegaIdx][phiIdx][cotIdx];
357 }
358
359 return contribution;
360}
361
362// Extract relevant hit information (hitIdx, contribution, super layer, drift time)
363std::vector<NDFinder::ContributionInfo> NDFinder::extractContributionInfos(const std::vector<unsigned short>& clusterHits)
364{
365 std::vector<ContributionInfo> contributionInfos;
366 for (unsigned short hitIdx = 0; hitIdx < m_hitIDs.size(); ++hitIdx) {
367 unsigned short contribution = clusterHits[hitIdx];
368 if (contribution > 0) {
369 ContributionInfo contributionInfo = {
370 hitIdx,
371 contribution,
372 m_hitSLIDs[hitIdx],
373 m_priorityWireTime[hitIdx]
374 };
375 contributionInfos.push_back(contributionInfo);
376 }
377 }
378 return contributionInfos;
379}
380
381// Find the hit with the maximum contribution in a given super layer
382int NDFinder::getMaximumHitInSuperLayer(const std::vector<ContributionInfo>& contributionInfos, unsigned short superLayer)
383{
384 std::vector<std::vector<int>> contributionsInSL;
385 for (const ContributionInfo& contributionInfo : contributionInfos) {
386 if (contributionInfo.superLayer == superLayer) {
387 unsigned short hitIdx = contributionInfo.hitIndex;
388 unsigned short contribution = contributionInfo.contribution;
389 short priorityTime = contributionInfo.priorityTime;
390 contributionsInSL.push_back({hitIdx, contribution, priorityTime});
391 }
392 }
393 if (contributionsInSL.empty()) return -1;
394 // Sort by drift time
395 std::sort(contributionsInSL.begin(), contributionsInSL.end(),
396 [](const std::vector<int>& a, const std::vector<int>& b) { return a[2] < b[2]; });
397 // Find max contribution
398 int maximumHit = contributionsInSL[0][0];
399 int maximumContribution = contributionsInSL[0][1];
400 for (const auto& hit : contributionsInSL) {
401 if (hit[1] > maximumContribution) {
402 maximumHit = hit[0];
403 maximumContribution = hit[1];
404 }
405 }
406 return maximumHit;
407}
408
409// Cut on the number of hit axial/stereo super layers
411{
412 std::vector<unsigned short> clusterHits = cluster.getClusterHits();
413 std::set<unsigned short> uniqueSLNumbers;
414 // Add all hit super layers
415 for (unsigned short hitIdx : clusterHits) {
416 uniqueSLNumbers.insert(m_hitSLIDs[hitIdx]);
417 }
418 // Calculate the number of hit axial and stereo super layers
419 unsigned short nSL = uniqueSLNumbers.size();
420 uniqueSLNumbers.insert({0, 2, 4, 6, 8});
421 unsigned short withAxialSLs = uniqueSLNumbers.size();
422 unsigned short axialNumber = 5 - (withAxialSLs - nSL);
423 unsigned short stereoNumber = nSL - axialNumber;
424 // Cut away all clusters that do have enough hit super layers
425 bool isValid = axialNumber >= m_ndFinderParams.minSuperAxial && stereoNumber >= m_ndFinderParams.minSuperStereo;
426 return isValid;
427}
428
429// Calculate the center of gravity for the track parameters
430std::array<double, 3> NDFinder::calculateCenterOfGravity(const SimpleCluster& cluster)
431{
432 double weightedSumOmega = 0.;
433 double weightedSumPhi = 0.;
434 double weightedSumCot = 0.;
435 unsigned int weightSum = 0;
436 std::vector<cell_index> clusterCells = cluster.getCells();
437 const int peakPhi = clusterCells.front()[1];
438 for (const cell_index& cellIdx : clusterCells) {
439 const unsigned short cellWeight = (*m_houghSpace)[cellIdx[0]][cellIdx[1]][cellIdx[2]];
440 weightedSumOmega += cellIdx[0] * cellWeight;
441 weightedSumCot += cellIdx[2] * cellWeight;
442 // Calculate relative phi position to peak
443 int phi = cellIdx[1];
444 int delta = phi - peakPhi;
445 // Wrap-around correction to stay within [-m_nPhi/2, +m_nPhi/2]
446 if (delta > m_nPhi / 2) {
447 delta -= m_nPhi;
448 } else if (delta < -m_nPhi / 2) {
449 delta += m_nPhi;
450 }
451 double unwrappedPhi = peakPhi + delta;
452 weightedSumPhi += unwrappedPhi * cellWeight;
453 weightSum += cellWeight;
454 }
455 weightedSumOmega /= weightSum;
456 weightedSumCot /= weightSum;
457 weightedSumPhi /= weightSum;
458 if (weightedSumPhi >= m_nPhi) weightedSumPhi -= m_nPhi;
459 if (weightedSumPhi < 0) weightedSumPhi += m_nPhi;
460 std::array<double, 3> centerOfGravity = {weightedSumOmega, weightedSumPhi, weightedSumCot};
461 return centerOfGravity;
462}
463
464// Transform the center of gravity (of cells) into the estimated track parameters
465std::array<double, 3> NDFinder::getTrackParameterEstimate(const std::array<double, 3>& centerOfGravity)
466{
467 std::array<double, 3> estimatedParameters;
468 for (unsigned short dimension = 0; dimension < 3; ++dimension) {
469 double trackParameter = m_acceptanceRanges[dimension][0] + (centerOfGravity[dimension] + 0.5) * m_binSizes[dimension];
470 estimatedParameters[dimension] = trackParameter;
471 }
472 return transformTrackParameters(estimatedParameters);
473}
474
475// Transform to physical units
476std::array<double, 3> NDFinder::transformTrackParameters(const std::array<double, 3>& estimatedParameters)
477{
478 std::array<double, 3> transformed;
479 // Omega
480 if (estimatedParameters[0] == 0.) {
481 transformed[0] = estimatedParameters[0];
482 } else { // omega = sign(q)/r, r in cm
483 transformed[0] = -1 / getTrackRadius(1. / estimatedParameters[0]);
484 }
485 // Phi
486 if (estimatedParameters[1] > 180) {
487 transformed[1] = (estimatedParameters[1] - 360) * TMath::DegToRad();
488 } else {
489 transformed[1] = (estimatedParameters[1]) * TMath::DegToRad();
490 }
491 // Cot
492 transformed[2] = estimatedParameters[2];
493 return transformed;
494}
Clustering module.
Class for a found NDFinder track.
Definition NDFinder.h:53
static constexpr unsigned short m_nPhi
Bins in the omega dimension.
Definition NDFinder.h:222
std::vector< short > m_priorityWireTime
Drift time of the priority wire.
Definition NDFinder.h:198
static constexpr unsigned short m_nPhiComp
Bins of compressed phi: phi_start, phi_width, phi_0, ..., phi_12.
Definition NDFinder.h:232
c5array * m_compAxialHitReps
m_compAxialHitReps/m_compStereoHitReps (~ Compressed in phi (width, start, values)) 5D array mapping:
Definition NDFinder.h:267
std::vector< std::vector< unsigned short > > getHitsVsClustersTable(const std::vector< SimpleCluster > &clusters)
Create hits to clusters confusion matrix.
Definition NDFinder.cc:318
static constexpr unsigned short m_nSL
Number of super layers.
Definition NDFinder.h:215
std::vector< unsigned short > m_hitIDs
TS-IDs of the hits in the current event: Elements = [0,2335] for 2336 TS in total.
Definition NDFinder.h:192
std::array< double, 3 > transformTrackParameters(const std::array< double, 3 > &estimatedParameters)
Transform to physical units.
Definition NDFinder.cc:476
void initLookUpArrays()
Initialize the arrays LUT arrays.
Definition NDFinder.cc:72
std::vector< unsigned short > m_priorityWirePos
Priority positon within the TS. Elements basf2: [0,3] first, left, right, no hit.
Definition NDFinder.h:196
void loadCompressedHitReps(const std::string &fileName, const SectorBinning &compBins, c5array &compHitsToWeights)
Fills the m_compAxialHitReps/m_compStereoHitReps (see below) arrays with the hit representations (hit...
Definition NDFinder.cc:126
std::vector< NDFinderTrack > m_ndFinderTracks
Result: Vector of the found tracks.
Definition NDFinder.h:190
static constexpr unsigned short m_nOmega
Bins in the phi dimension.
Definition NDFinder.h:221
Clusterizend m_clusterer
Clustering module.
Definition NDFinder.h:204
int getMaximumHitInSuperLayer(const std::vector< ContributionInfo > &contributionInfos, unsigned short superLayer)
Find the hit with the maximum contribution in a given super layer.
Definition NDFinder.cc:382
void init(const NDFinderParameters &ndFinderParameters)
Initialization of the NDFinder (parameters and lookup tables)
Definition NDFinder.cc:27
void initHitToSectorMap()
Fills the m_hitToSectorIDs (see below) array with the hit to orientation/sectorWire/sectorID relation...
Definition NDFinder.cc:91
bool checkHitSuperLayers(const SimpleCluster &cluster)
Cut on the number of hit axial/stereo super layers.
Definition NDFinder.cc:410
static constexpr unsigned short m_nTS
Number of track segments.
Definition NDFinder.h:214
unsigned short m_nHits
Counter for the number of hits in the current event.
Definition NDFinder.h:200
c3array * m_houghSpace
The complete Hough space with the size [m_nOmega, m_nPhi, m_nCot].
Definition NDFinder.h:283
static constexpr unsigned short m_phiGeo
Repetition of the wire pattern.
Definition NDFinder.h:226
void fillExpandedHitReps(const SectorBinning &compBins, const c5array &compHitsToWeights, c5array &expHitsToWeights)
Fills the m_expAxialHitReps/m_expStereoHitReps (see below) arrays with the expanded hit representatio...
Definition NDFinder.cc:159
static double getTrackRadius(double transverseMomentum)
Transverse momentum (which is 1/omega, in GeV/c) to radius (in cm)
Definition NDFinder.h:185
static constexpr unsigned short m_nStereo
Number of unique stereo track segments.
Definition NDFinder.h:217
NDFinderParameters m_ndFinderParams
Configuration parameters of the 3DFinder.
Definition NDFinder.h:202
static constexpr unsigned short m_nPrio
Number of priority wires.
Definition NDFinder.h:218
static constexpr unsigned short m_nAxial
Number of unique axial track segments.
Definition NDFinder.h:216
c2array * m_hitToSectorIDs
m_hitToSectorIDs: 2D array mapping TS-ID ([0, 2335]) to:
Definition NDFinder.h:255
void processHitForHoughSpace(const unsigned short hitIdx)
Process a single axial or stereo hit for the Hough space.
Definition NDFinder.cc:214
static constexpr unsigned short m_nPhiSector
Bins of one phi sector (12)
Definition NDFinder.h:229
std::array< double, 3 > calculateCenterOfGravity(const SimpleCluster &cluster)
Calculate the center of gravity (weighted mean) for the track parameters.
Definition NDFinder.cc:430
std::vector< SimpleCluster > relateHitsToClusters(std::vector< SimpleCluster > &clusters)
Relate the hits in the peak of the cluster to the cluster. Applies a cut on the clusters.
Definition NDFinder.cc:296
std::vector< unsigned short > m_hitSLIDs
SL-IDs of the hits in the current event: Elements = Super layer number in [0,1,......
Definition NDFinder.h:194
static constexpr SectorBinning m_compAxialBins
40, 15, 1, 41, 3
Definition NDFinder.h:233
void reset()
Reset the NDFinder data structure to process next event.
Definition NDFinder.cc:185
void findTracks()
Main function for track finding.
Definition NDFinder.cc:204
void addHit(const HitInfo &hitInfo)
Add the hit info of a single track segment to the NDFinder.
Definition NDFinder.cc:59
static constexpr SectorBinning m_compStereoBins
40, 15, 9, 32, 3
Definition NDFinder.h:234
static constexpr unsigned short m_nCot
Bins in the cot dimension.
Definition NDFinder.h:223
c5array * m_expAxialHitReps
m_expAxialHitReps/m_expStereoHitReps (~ expansion of the compressed representations) 5D array mapping...
Definition NDFinder.h:280
unsigned short getHitContribution(const cell_index &peakCell, const unsigned short hitIdx)
Returns the hit contribution of a TS at a certain cluster cell (= peak/maximum cell)
Definition NDFinder.cc:336
std::vector< ContributionInfo > extractContributionInfos(const std::vector< unsigned short > &clusterHits)
Extract relevant hit information (hitIdx, contribution, super layer, drift time)
Definition NDFinder.cc:363
std::array< double, 3 > getTrackParameterEstimate(const std::array< double, 3 > &centerOfGravity)
Transform the center of gravity (cells) into the estimated track parameters.
Definition NDFinder.cc:465
void writeHitToHoughSpace(const WireInfo &hitInfo, const c5array &expHitsToWeights)
Write (add) a single hit (Hough curve) to the Hough space.
Definition NDFinder.cc:232
void runTrackFinding()
Core track finding logic in the constructed Hough space.
Definition NDFinder.cc:247
Type for found clusters.
c5array::index c5index
index of store hit pattern 5D array
boost::multi_array< unsigned short, 2 > c2array
TS-ID to 1/32 phi-sector mapping is stored in a 2D array.
boost::multi_array< unsigned short, 5 > c5array
Store hit patterns in a 5D array (hitid, prio, omega, phi, cot)
c3array::index c3index
index of Hough space 3D array
boost::multi_array< unsigned short, 3 > c3array
The Hough space is a 3D array (omega, phi, cot)
std::array< c3index, 3 > cell_index
The cell index of one Hough space bin.
Abstract base class for different kinds of events.
Struct containing the parameters for the clustering.
Struct containing the track segment (hit) information from the Track Segment Finder (TSF)
Definition NDFinder.h:45
Struct of NDFinder parameters.
Definition NDFinder.h:26
unsigned short phiTrim
Clustering: Number of deleted cells in each phi direction from the maximum.
Definition NDFinder.h:36
unsigned short omegaTrim
Clustering: Number of deleted cells in each omega direction from the maximum.
Definition NDFinder.h:34
unsigned short iterations
Clustering: Number of iterations for the cluster search in each Hough space quadrant.
Definition NDFinder.h:32
Collection of the hit contribution information needed for the hit to cluster relations.
Definition NDFinder.h:118
Data type to collect a binning.
Definition NDFinder.h:102
Collection of the hit information needed for the hit representations.
Definition NDFinder.h:111