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"
22#include "trg/cdc/NDFinder.h"
62 if (hitInfo.hitPrioPos > 0) {
75 const std::array<c2index, 2> shapeHitToSectorIDs = {{
m_nTS,
m_nPrio}};
84 m_compStereoHitReps =
new c5array(shapeCompStereoHitReps);
86 m_expStereoHitReps =
new c5array(shapeExpStereoHitReps);
94 constexpr std::array<unsigned short, 9> nWires = {160, 160, 192, 224, 256, 288, 320, 352, 384};
96 std::vector<unsigned short> wiresPerSector;
98 std::vector<unsigned short> hitToSuperLayer;
100 std::vector<unsigned short> cumulativeWires = {0};
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);
108 cumulativeWires.push_back(cumulativeWires[superLayer] + nWires[superLayer]);
109 cumulativeSectorWires.push_back(cumulativeSectorWires[superLayer] + nWires[superLayer] /
m_phiGeo);
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]));
119 hitToSectorIDs[hit][0] =
static_cast<unsigned short>(isAxial);
120 hitToSectorIDs[hit][1] = relativeWireIDinSector;
121 hitToSectorIDs[hit][2] = relativeSectorIDinSuperLayer;
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);
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);
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];
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;
169 expHitsToWeights[hitID][priorityWire][omegaIdx][houghPhiIdx][cotIdx] =
170 compHitsToWeights[hitID][priorityWire][omegaIdx][phiEntry + 2][cotIdx];
171 if (compBins.cot == 1) {
172 for (
c5index axialCotIdx = 1; axialCotIdx <
m_nCot; ++axialCotIdx) {
173 expHitsToWeights[hitID][priorityWire][omegaIdx][houghPhiIdx][axialCotIdx] =
174 compHitsToWeights[hitID][priorityWire][omegaIdx][phiEntry + 2][cotIdx];
207 for (
unsigned short hitIdx = 0; hitIdx <
m_nHits; ++hitIdx) {
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;
223 WireInfo wireInfo = {relativeWireID, phiSectorStart, priorityWire};
224 if (orientation == 1) {
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];
251 std::vector<SimpleCluster> allClusters =
m_clusterer.makeClusters();
259 std::vector<ROOT::Math::XYZVector> readoutHoughSpace;
260 std::vector<ROOT::Math::XYZVector> readoutCluster;
267 unsigned short element = houghSpace[omegaIdx][phiIdx][cotIdx];
268 readoutHoughSpace.push_back(ROOT::Math::XYZVector(element, 0, 0));
273 unsigned int peakWeight = cluster.getPeakWeight();
274 readoutCluster.push_back(ROOT::Math::XYZVector(peakWeight, 0, 0));
276 unsigned short nCells = cluster.getCells().size();
277 readoutCluster.push_back(ROOT::Math::XYZVector(nCells, 0, 0));
279 readoutCluster.push_back(ROOT::Math::XYZVector(centerOfGravity[0], centerOfGravity[1], centerOfGravity[2]));
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));
286 for (
const cell_index& cellIdx : cluster.getCells()) {
287 readoutCluster.push_back(ROOT::Math::XYZVector(cellIdx[0], cellIdx[1], cellIdx[2]));
291 std::move(cluster), std::move(readoutHoughSpace), std::move(readoutCluster)));
299 std::vector<SimpleCluster> goodClusters;
300 if (hitsVsClusters.empty())
return goodClusters;
302 for (
unsigned short clusterIdx = 0; clusterIdx < hitsVsClusters.size(); ++clusterIdx) {
304 for (
unsigned short superLayer = 0; superLayer < 9; ++superLayer) {
306 if (maximumHit >= 0) {
307 clusters[clusterIdx].addHitToCluster(
static_cast<unsigned short>(maximumHit));
311 goodClusters.push_back(clusters[clusterIdx]);
321 std::vector<unsigned short> hitElem(
m_nHits, 0);
322 std::vector<std::vector<unsigned short>> hitsVsClusters(clusters.size(), hitElem);
324 for (
unsigned short clusterIdx = 0; clusterIdx < clusters.size(); ++clusterIdx) {
327 for (
unsigned short hitIdx = 0; hitIdx <
m_hitIDs.size(); ++hitIdx) {
329 hitsVsClusters[clusterIdx][hitIdx] = contribution;
332 return hitsVsClusters;
338 unsigned short contribution = 0;
339 unsigned short omegaIdx = peakCell[0];
340 unsigned short houghPhiIdx = peakCell[1];
341 unsigned short cotIdx = peakCell[2];
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;
351 unsigned short phiIdx = (houghPhiIdx - phiSectorStart +
m_nPhi) %
m_nPhi;
353 if (orientation == 1) {
354 contribution = (*m_expAxialHitReps)[relativeWireID][priorityWire][omegaIdx][phiIdx][cotIdx];
356 contribution = (*m_expStereoHitReps)[relativeWireID][priorityWire][omegaIdx][phiIdx][cotIdx];
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) {
375 contributionInfos.push_back(contributionInfo);
378 return contributionInfos;
384 std::vector<std::vector<int>> contributionsInSL;
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});
393 if (contributionsInSL.empty())
return -1;
395 std::sort(contributionsInSL.begin(), contributionsInSL.end(),
396 [](
const std::vector<int>& a,
const std::vector<int>& b) { return a[2] < b[2]; });
398 int maximumHit = contributionsInSL[0][0];
399 int maximumContribution = contributionsInSL[0][1];
400 for (
const auto& hit : contributionsInSL) {
401 if (hit[1] > maximumContribution) {
403 maximumContribution = hit[1];
412 std::vector<unsigned short> clusterHits = cluster.getClusterHits();
413 std::set<unsigned short> uniqueSLNumbers;
415 for (
unsigned short hitIdx : clusterHits) {
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;
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;
443 int phi = cellIdx[1];
444 int delta = phi - peakPhi;
448 }
else if (delta < -
m_nPhi / 2) {
451 double unwrappedPhi = peakPhi + delta;
452 weightedSumPhi += unwrappedPhi * cellWeight;
453 weightSum += cellWeight;
455 weightedSumOmega /= weightSum;
456 weightedSumCot /= weightSum;
457 weightedSumPhi /= weightSum;
459 if (weightedSumPhi < 0) weightedSumPhi +=
m_nPhi;
460 std::array<double, 3> centerOfGravity = {weightedSumOmega, weightedSumPhi, weightedSumCot};
461 return centerOfGravity;
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;
478 std::array<double, 3> transformed;
480 if (estimatedParameters[0] == 0.) {
481 transformed[0] = estimatedParameters[0];
483 transformed[0] = -1 /
getTrackRadius(1. / estimatedParameters[0]);
486 if (estimatedParameters[1] > 180) {
487 transformed[1] = (estimatedParameters[1] - 360) * TMath::DegToRad();
489 transformed[1] = (estimatedParameters[1]) * TMath::DegToRad();
492 transformed[2] = estimatedParameters[2];
Class for a found NDFinder track.
static constexpr unsigned short m_nPhi
Bins in the omega dimension.
std::vector< short > m_priorityWireTime
Drift time of the priority wire.
static constexpr unsigned short m_nPhiComp
Bins of compressed phi: phi_start, phi_width, phi_0, ..., phi_12.
c5array * m_compAxialHitReps
m_compAxialHitReps/m_compStereoHitReps (~ Compressed in phi (width, start, values)) 5D array mapping:
std::vector< std::vector< unsigned short > > getHitsVsClustersTable(const std::vector< SimpleCluster > &clusters)
Create hits to clusters confusion matrix.
static constexpr unsigned short m_nSL
Number of super layers.
std::vector< unsigned short > m_hitIDs
TS-IDs of the hits in the current event: Elements = [0,2335] for 2336 TS in total.
std::array< double, 3 > transformTrackParameters(const std::array< double, 3 > &estimatedParameters)
Transform to physical units.
void initLookUpArrays()
Initialize the arrays LUT arrays.
std::vector< unsigned short > m_priorityWirePos
Priority positon within the TS. Elements basf2: [0,3] first, left, right, no hit.
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...
std::vector< NDFinderTrack > m_ndFinderTracks
Result: Vector of the found tracks.
static constexpr unsigned short m_nOmega
Bins in the phi dimension.
Clusterizend m_clusterer
Clustering module.
int getMaximumHitInSuperLayer(const std::vector< ContributionInfo > &contributionInfos, unsigned short superLayer)
Find the hit with the maximum contribution in a given super layer.
void init(const NDFinderParameters &ndFinderParameters)
Initialization of the NDFinder (parameters and lookup tables)
void initHitToSectorMap()
Fills the m_hitToSectorIDs (see below) array with the hit to orientation/sectorWire/sectorID relation...
bool checkHitSuperLayers(const SimpleCluster &cluster)
Cut on the number of hit axial/stereo super layers.
static constexpr unsigned short m_nTS
Number of track segments.
unsigned short m_nHits
Counter for the number of hits in the current event.
c3array * m_houghSpace
The complete Hough space with the size [m_nOmega, m_nPhi, m_nCot].
static constexpr unsigned short m_phiGeo
Repetition of the wire pattern.
void fillExpandedHitReps(const SectorBinning &compBins, const c5array &compHitsToWeights, c5array &expHitsToWeights)
Fills the m_expAxialHitReps/m_expStereoHitReps (see below) arrays with the expanded hit representatio...
static double getTrackRadius(double transverseMomentum)
Transverse momentum (which is 1/omega, in GeV/c) to radius (in cm)
static constexpr unsigned short m_nStereo
Number of unique stereo track segments.
NDFinderParameters m_ndFinderParams
Configuration parameters of the 3DFinder.
static constexpr unsigned short m_nPrio
Number of priority wires.
static constexpr unsigned short m_nAxial
Number of unique axial track segments.
c2array * m_hitToSectorIDs
m_hitToSectorIDs: 2D array mapping TS-ID ([0, 2335]) to:
void processHitForHoughSpace(const unsigned short hitIdx)
Process a single axial or stereo hit for the Hough space.
static constexpr unsigned short m_nPhiSector
Bins of one phi sector (12)
std::array< double, 3 > calculateCenterOfGravity(const SimpleCluster &cluster)
Calculate the center of gravity (weighted mean) for the track parameters.
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.
std::vector< unsigned short > m_hitSLIDs
SL-IDs of the hits in the current event: Elements = Super layer number in [0,1,......
static constexpr SectorBinning m_compAxialBins
40, 15, 1, 41, 3
void reset()
Reset the NDFinder data structure to process next event.
void findTracks()
Main function for track finding.
void addHit(const HitInfo &hitInfo)
Add the hit info of a single track segment to the NDFinder.
static constexpr SectorBinning m_compStereoBins
40, 15, 9, 32, 3
static constexpr unsigned short m_nCot
Bins in the cot dimension.
c5array * m_expAxialHitReps
m_expAxialHitReps/m_expStereoHitReps (~ expansion of the compressed representations) 5D array mapping...
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)
std::vector< ContributionInfo > extractContributionInfos(const std::vector< unsigned short > &clusterHits)
Extract relevant hit information (hitIdx, contribution, super layer, drift time)
std::array< double, 3 > getTrackParameterEstimate(const std::array< double, 3 > ¢erOfGravity)
Transform the center of gravity (cells) into the estimated track parameters.
void writeHitToHoughSpace(const WireInfo &hitInfo, const c5array &expHitsToWeights)
Write (add) a single hit (Hough curve) to the Hough space.
void runTrackFinding()
Core track finding logic in the constructed Hough space.
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)
Struct of NDFinder parameters.
unsigned short phiTrim
Clustering: Number of deleted cells in each phi direction from the maximum.
unsigned short omegaTrim
Clustering: Number of deleted cells in each omega direction from the maximum.
unsigned short iterations
Clustering: Number of iterations for the cluster search in each Hough space quadrant.
Collection of the hit contribution information needed for the hit to cluster relations.
Data type to collect a binning.
Collection of the hit information needed for the hit representations.