9#include "trg/cdc/NDFinder.h"
24#include "framework/logging/Logger.h"
31 m_ndFinderParams = ndFinderParameters;
34 const std::array<c3index, 3> shapeHough = {{m_nOmega, m_nPhi, m_nCot}};
35 m_houghSpace =
new c3array(shapeHough);
41 bool useDB = m_ndFinderParams.axialFile.empty() && m_ndFinderParams.stereoFile.empty();
42 std::vector<unsigned short> axialArray;
43 std::vector<unsigned short> stereoArray;
45 if (!m_LUTsConditionsDB) {
46 B2FATAL(
"CDCTriggerNDFinderLUTs payload not available and no LUT files provided");
48 const CDCTriggerNDFinderLUTs& luts = *m_LUTsConditionsDB;
49 axialArray = luts.axial;
50 stereoArray = luts.stereo;
52 axialArray = loadFromFile(m_ndFinderParams.axialFile);
53 stereoArray = loadFromFile(m_ndFinderParams.stereoFile);
55 fillCompressedHitReps(axialArray, m_compAxialBins, m_compAxialHitReps);
56 fillCompressedHitReps(stereoArray, m_compStereoBins, m_compStereoHitReps);
59 fillExpandedHitReps(m_compAxialBins, m_compAxialHitReps, m_expAxialHitReps);
60 fillExpandedHitReps(m_compStereoBins, m_compStereoHitReps, m_expStereoHitReps);
66 PeakFindingParameters peakFindingParams = {
67 ndFinderParameters.iterations,
68 ndFinderParameters.omegaTrim,
69 ndFinderParameters.phiTrim,
74 m_peakFinder = NDFinderPeakFinder(peakFindingParams);
78void NDFinder::addHit(
const HitInfo& hitInfo)
80 m_hitIDs.push_back(hitInfo.hitID);
81 m_hitSLIDs.push_back(hitInfo.hitSLID);
82 m_priorityWireTime.push_back(hitInfo.hitPrioTime);
87void NDFinder::initHitToSectorMap()
90 constexpr std::array<unsigned short, 9> nWires = {160, 160, 192, 224, 256, 288, 320, 352, 384};
92 std::vector<unsigned short> wiresPerSector;
94 std::vector<unsigned short> hitToSuperLayer;
96 std::vector<unsigned short> cumulativeWires = {0};
98 std::vector<unsigned short> cumulativeSectorWires = {0, 0};
99 for (
unsigned short superLayer = 0; superLayer < m_nSL; ++superLayer) {
100 wiresPerSector.push_back(nWires[superLayer] / m_phiGeo);
101 for (
unsigned short _ = 0; _ < nWires[superLayer]; ++_) {
102 hitToSuperLayer.push_back(superLayer);
104 cumulativeWires.push_back(cumulativeWires[superLayer] + nWires[superLayer]);
105 cumulativeSectorWires.push_back(cumulativeSectorWires[superLayer] + nWires[superLayer] / m_phiGeo);
107 for (
unsigned short hit = 0; hit < m_nTS; ++hit) {
108 unsigned short superLayer = hitToSuperLayer[hit];
109 bool isAxial = (superLayer % 2 == 0);
110 unsigned short wireIDinSL = hit - cumulativeWires[superLayer];
111 unsigned short wireIDinSector = wireIDinSL % wiresPerSector[superLayer];
112 unsigned short relativeWireIDinSector = cumulativeSectorWires[superLayer] + wireIDinSector;
113 unsigned short relativeSectorIDinSuperLayer =
static_cast<unsigned short>(floor(wireIDinSL / wiresPerSector[superLayer]));
114 m_hitToSectorIDs[hit][0] =
static_cast<unsigned short>(isAxial);
115 m_hitToSectorIDs[hit][1] = relativeWireIDinSector;
116 m_hitToSectorIDs[hit][2] = relativeSectorIDinSuperLayer;
121void NDFinder::fillCompressedHitReps(
const std::vector<unsigned short>& flatArray,
const SectorBinning& compBins,
122 c4array& compHitsToWeights)
const
124 size_t arrayIndex = 0;
125 for (c4index hitID = 0; hitID < compBins.nHitIDs; ++hitID) {
126 for (c4index omegaIdx = 0; omegaIdx < compBins.omega; ++omegaIdx) {
127 for (c4index phiIdx = 0; phiIdx < compBins.phi; ++phiIdx) {
128 for (c4index cotIdx = 0; cotIdx < compBins.cot; ++cotIdx) {
129 compHitsToWeights[hitID][omegaIdx][phiIdx][cotIdx] =
130 flatArray[arrayIndex++];
138std::vector<unsigned short> NDFinder::loadFromFile(
const std::string& fileName)
const
140 std::vector<unsigned short> flatArray;
141 std::ifstream arrayFile(fileName);
143 B2ERROR(
"Could not open file: " << fileName);
146 unsigned short value;
147 while (arrayFile >> value) {
148 flatArray.push_back(value);
154void NDFinder::fillExpandedHitReps(
const SectorBinning& compBins,
const c4array& compHitsToWeights, c4array& expHitsToWeights)
const
156 for (c4index hitID = 0; hitID < compBins.nHitIDs; ++hitID) {
157 for (c4index omegaIdx = 0; omegaIdx < compBins.omega; ++omegaIdx) {
158 for (c4index cotIdx = 0; cotIdx < compBins.cot; ++cotIdx) {
159 unsigned short phiStart = compHitsToWeights[hitID][omegaIdx][0][cotIdx];
160 unsigned short nPhiEntries = compHitsToWeights[hitID][omegaIdx][1][cotIdx];
161 for (c4index phiEntry = 0; phiEntry < nPhiEntries; ++phiEntry) {
162 unsigned short houghPhiIdx = (phiStart + phiEntry) % m_nPhi;
163 expHitsToWeights[hitID][omegaIdx][houghPhiIdx][cotIdx] =
164 compHitsToWeights[hitID][omegaIdx][phiEntry + 2][cotIdx];
165 if (compBins.cot == 1) {
166 for (c4index axialCotIdx = 1; axialCotIdx < m_nCot; ++axialCotIdx) {
167 expHitsToWeights[hitID][omegaIdx][houghPhiIdx][axialCotIdx] =
168 compHitsToWeights[hitID][omegaIdx][phiEntry + 2][cotIdx];
178void NDFinder::reset()
181 m_rawFinderTracks.clear();
187 m_priorityWireTime.clear();
191 std::array<c3index, 3> shapeHough = {{m_nOmega, m_nPhi, m_nCot}};
192 m_houghSpace =
new c3array(shapeHough);
196void NDFinder::findTracks()
199 for (
unsigned short hitIdx = 0; hitIdx < m_nHits; ++hitIdx) {
200 processHitForHoughSpace(hitIdx);
206void NDFinder::processHitForHoughSpace(
const unsigned short hitIdx)
208 unsigned short orientation = m_hitToSectorIDs[m_hitIDs[hitIdx]][0];
209 unsigned short relativeWireID = m_hitToSectorIDs[m_hitIDs[hitIdx]][1];
210 unsigned short relativeSectorID = m_hitToSectorIDs[m_hitIDs[hitIdx]][2];
211 unsigned short phiSectorStart = relativeSectorID * m_nPhiSector;
213 if (orientation == 1) {
214 writeHitToHoughSpace(relativeWireID, phiSectorStart, m_expAxialHitReps);
216 writeHitToHoughSpace(relativeWireID, phiSectorStart, m_expStereoHitReps);
221void NDFinder::writeHitToHoughSpace(
const unsigned short relativeWireID,
const unsigned short phiSectorStart,
222 const c4array& expHitsToWeights)
224 c3array& houghSpace = *m_houghSpace;
225 for (
unsigned short cotIdx = 0; cotIdx < m_nCot; ++cotIdx) {
226 for (
unsigned short omegaIdx = 0; omegaIdx < m_nOmega; ++omegaIdx) {
227 for (
unsigned short phiIdx = 0; phiIdx < m_nPhi; ++phiIdx) {
228 unsigned short houghPhiIdx = (phiIdx + phiSectorStart) % m_nPhi;
229 houghSpace[omegaIdx][houghPhiIdx][cotIdx] +=
230 expHitsToWeights[relativeWireID][omegaIdx][phiIdx][cotIdx];
237void NDFinder::runTrackFinding()
239 c3array& houghSpace = *m_houghSpace;
240 m_peakFinder.setNewPlane(houghSpace);
241 std::vector<HoughPeak> allPeaks = m_peakFinder.findPeaks();
242 std::vector<HoughPeak> validPeaks = relateHitsToPeaks(allPeaks);
244 for (HoughPeak& peak : validPeaks) {
245 cell_index peakCell = peak.cell;
246 std::array<double, 3> estimatedParameters = getTrackParameterEstimate(peakCell);
249 std::vector<uint8_t> readoutHoughSpace;
250 if (m_ndFinderParams.storeHoughSpace) {
251 readoutHoughSpace.reserve(m_nOmega * m_nPhi * m_nCot);
252 readoutHoughSpace.assign(houghSpace.data(), houghSpace.data() + houghSpace.num_elements());
255 m_rawFinderTracks.push_back(RawFinderTrack(estimatedParameters, std::move(peak), std::move(readoutHoughSpace)));
260std::vector<HoughPeak> NDFinder::relateHitsToPeaks(std::vector<HoughPeak>& peaks)
const
262 std::vector<std::vector<unsigned short>> hitsVsPeaks = getHitsVsPeaksTable(peaks);
263 std::vector<HoughPeak> goodPeaks;
264 if (hitsVsPeaks.empty())
return goodPeaks;
266 for (
unsigned short peakIdx = 0; peakIdx < hitsVsPeaks.size(); ++peakIdx) {
267 std::vector<ContributionInfo> contributionInfos = extractContributionInfos(hitsVsPeaks[peakIdx]);
268 std::vector<unsigned short> peakHits;
269 for (
unsigned short superLayer = 0; superLayer < 9; ++superLayer) {
270 int maximumHit = getMaximumHitInSuperLayer(contributionInfos, superLayer);
271 if (maximumHit >= 0) {
272 peakHits.push_back(
static_cast<unsigned short>(maximumHit));
275 peaks[peakIdx].hits = peakHits;
276 if (checkHitSuperLayers(peaks[peakIdx])) {
277 goodPeaks.push_back(peaks[peakIdx]);
284std::vector<std::vector<unsigned short>> NDFinder::getHitsVsPeaksTable(
const std::vector<HoughPeak>& peaks)
const
287 std::vector<unsigned short> hitElem(m_nHits, 0);
288 std::vector<std::vector<unsigned short>> hitsVsPeaks(peaks.size(), hitElem);
290 for (
unsigned short peakIdx = 0; peakIdx < peaks.size(); ++peakIdx) {
291 HoughPeak peak = peaks[peakIdx];
292 cell_index peakCell = peak.cell;
293 for (
unsigned short hitIdx = 0; hitIdx < m_hitIDs.size(); ++hitIdx) {
294 unsigned short contribution = getHitContribution(peakCell, hitIdx);
295 hitsVsPeaks[peakIdx][hitIdx] = contribution;
302unsigned short NDFinder::getHitContribution(
const cell_index& peakCell,
const unsigned short hitIdx)
const
304 unsigned short contribution = 0;
305 unsigned short omegaIdx = peakCell[0];
306 unsigned short houghPhiIdx = peakCell[1];
307 unsigned short cotIdx = peakCell[2];
309 unsigned short orientation = m_hitToSectorIDs[m_hitIDs[hitIdx]][0];
310 unsigned short relativeWireID = m_hitToSectorIDs[m_hitIDs[hitIdx]][1];
311 unsigned short relativeSectorID = m_hitToSectorIDs[m_hitIDs[hitIdx]][2];
312 unsigned short phiSectorStart = relativeSectorID * m_nPhiSector;
315 unsigned short phiIdx = (houghPhiIdx - phiSectorStart + m_nPhi) % m_nPhi;
317 if (orientation == 1) {
318 contribution = m_expAxialHitReps[relativeWireID][omegaIdx][phiIdx][cotIdx];
320 contribution = m_expStereoHitReps[relativeWireID][omegaIdx][phiIdx][cotIdx];
327std::vector<NDFinder::ContributionInfo> NDFinder::extractContributionInfos(
const std::vector<unsigned short>& peakHits)
const
329 std::vector<ContributionInfo> contributionInfos;
330 for (
unsigned short hitIdx = 0; hitIdx < m_hitIDs.size(); ++hitIdx) {
331 unsigned short contribution = peakHits[hitIdx];
332 if (contribution > 0) {
337 m_priorityWireTime[hitIdx]
339 contributionInfos.push_back(contributionInfo);
342 return contributionInfos;
346int NDFinder::getMaximumHitInSuperLayer(
const std::vector<ContributionInfo>& contributionInfos,
unsigned short superLayer)
const
348 std::vector<std::vector<int>> contributionsInSL;
350 if (contributionInfo.superLayer == superLayer) {
351 unsigned short hitIdx = contributionInfo.hitIndex;
352 unsigned short contribution = contributionInfo.contribution;
353 short priorityTime = contributionInfo.priorityTime;
354 contributionsInSL.push_back({hitIdx, contribution, priorityTime});
357 if (contributionsInSL.empty())
return -1;
359 std::sort(contributionsInSL.begin(), contributionsInSL.end(),
360 [](
const std::vector<int>& a,
const std::vector<int>& b) { return a[2] < b[2]; });
362 int maximumHit = contributionsInSL[0][0];
363 int maximumContribution = contributionsInSL[0][1];
364 for (
const auto& hit : contributionsInSL) {
365 if (hit[1] > maximumContribution) {
367 maximumContribution = hit[1];
374bool NDFinder::checkHitSuperLayers(
const HoughPeak& peak)
const
376 std::vector<unsigned short> peakHits = peak.hits;
377 std::set<unsigned short> uniqueSLNumbers;
379 for (
unsigned short hitIdx : peakHits) {
380 uniqueSLNumbers.insert(m_hitSLIDs[hitIdx]);
383 unsigned short nSL = uniqueSLNumbers.size();
384 uniqueSLNumbers.insert({0, 2, 4, 6, 8});
385 unsigned short withAxialSLs = uniqueSLNumbers.size();
386 unsigned short axialNumber = 5 - (withAxialSLs - nSL);
387 unsigned short stereoNumber = nSL - axialNumber;
389 bool isValid = axialNumber >= m_ndFinderParams.minSuperAxial && stereoNumber >= m_ndFinderParams.minSuperStereo;
394std::array<double, 3> NDFinder::getTrackParameterEstimate(
const cell_index& peakCell)
const
396 std::array<double, 3> estimatedParameters;
397 for (
unsigned short dimension = 0; dimension < 3; ++dimension) {
398 double trackParameter = m_acceptanceRanges[dimension][0] + (
static_cast<double>(peakCell[dimension]) + 0.5) * m_binSizes[dimension];
399 estimatedParameters[dimension] = trackParameter;
401 return transformTrackParameters(estimatedParameters);
405std::array<double, 3> NDFinder::transformTrackParameters(
const std::array<double, 3>& estimatedParameters)
const
407 std::array<double, 3> transformed;
409 if (estimatedParameters[0] == 0.) {
410 transformed[0] = estimatedParameters[0];
412 transformed[0] = -1 / getTrackRadius(1. / estimatedParameters[0]);
415 if (estimatedParameters[1] > 180) {
416 transformed[1] = (estimatedParameters[1] - 360) * TMath::DegToRad();
418 transformed[1] = (estimatedParameters[1]) * TMath::DegToRad();
421 transformed[2] = estimatedParameters[2];
bool isValid(EForwardBackward eForwardBackward)
Check whether the given enum instance is one of the valid values.
Abstract base class for different kinds of events.