File indexing completed on 2025-08-05 08:09:48
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "ActsExamples/TrackFinding/MuonHoughSeeder.hpp"
0010
0011 #include "ActsExamples/EventData/MuonSimHit.hpp"
0012
0013 #include <algorithm>
0014 #include <cmath>
0015 #include <iterator>
0016 #include <ostream>
0017 #include <stdexcept>
0018 #include <variant>
0019
0020 #include "TBox.h"
0021 #include "TLatex.h"
0022 #include "TLegend.h"
0023
0024 namespace {
0025
0026 static const std::map<int, std::string> stationDict{
0027 {0, "BIL"}, {1, "BIS"}, {7, "BIR"}, {2, "BML"}, {3, "BMS"},
0028 {8, "BMF"}, {53, "BME"}, {54, "BMG"}, {52, "BIM"}, {4, "BOL"},
0029 {5, "BOS"}, {9, "BOF"}, {10, "BOG"}, {6, "BEE"}, {14, "EEL"},
0030 {15, "EES"}, {13, "EIL"}, {49, "EIS"}, {17, "EML"}, {18, "EMS"},
0031 {20, "EOL"}, {21, "EOS"}};
0032
0033 }
0034
0035 ActsExamples::MuonHoughSeeder::MuonHoughSeeder(
0036 ActsExamples::MuonHoughSeeder::Config cfg, Acts::Logging::Level lvl)
0037 : ActsExamples::IAlgorithm("MuonHoughSeeder", lvl),
0038 m_cfg(std::move(cfg)),
0039 m_logger(Acts::getDefaultLogger("MuonHoughSeeder", lvl)) {
0040 if (m_cfg.inDriftCircles.empty()) {
0041 throw std::invalid_argument(
0042 "MuonHoughSeeder: Missing drift circle collection");
0043 }
0044 if (m_cfg.inSimHits.empty()) {
0045 throw std::invalid_argument("MuonHoughSeeder: Missing sim hit collection");
0046 }
0047
0048 m_inputDriftCircles.initialize(m_cfg.inDriftCircles);
0049 m_inputSimHits.initialize(m_cfg.inSimHits);
0050 }
0051
0052 using PatternSeed = std::pair<double, double>;
0053
0054 ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::execute(
0055 const AlgorithmContext& ctx) const {
0056
0057 auto gotSH = m_inputSimHits(ctx);
0058 auto gotDC = m_inputDriftCircles(ctx);
0059
0060
0061 Acts::HoughTransformUtils::HoughPlaneConfig planeCfg;
0062 planeCfg.nBinsX = 1000;
0063 planeCfg.nBinsY = 1000;
0064
0065
0066 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMaxConfig peakFinderCfg;
0067 peakFinderCfg.fractionCutoff = 0.7;
0068 peakFinderCfg.threshold = 3.;
0069 peakFinderCfg.minSpacingBetweenPeaks = {0., 30.};
0070
0071
0072
0073 Acts::HoughTransformUtils::HoughAxisRanges axisRanges{-3., 3., -2000., 2000.};
0074
0075
0076
0077
0078
0079 auto houghParam_fromDC_left = [](double tanTheta, const DriftCircle& DC) {
0080 return DC.y() - tanTheta * DC.z() -
0081 DC.rDrift() / std::cos(std::atan(tanTheta));
0082 };
0083
0084 auto houghParam_fromDC_right = [](double tanTheta, const DriftCircle& DC) {
0085 return DC.y() - tanTheta * DC.z() +
0086 DC.rDrift() / std::cos(std::atan(tanTheta));
0087 };
0088
0089
0090 auto houghWidth_fromDC = [](double, const DriftCircle& DC) {
0091 return std::min(DC.rDriftError() * 3.,
0092 1.0);
0093
0094
0095 };
0096
0097
0098 std::vector<PatternSeed> truePatterns;
0099
0100
0101 Acts::HoughTransformUtils::HoughPlane<Acts::GeometryIdentifier::Value>
0102 houghPlane(planeCfg);
0103
0104 Acts::HoughTransformUtils::PeakFinders::IslandsAroundMax<
0105 Acts::GeometryIdentifier::Value>
0106 peakFinder(peakFinderCfg);
0107
0108
0109 for (auto& SH : gotSH) {
0110
0111 muonMdtIdentifierFields detailedInfo =
0112 ActsExamples::splitId(SH.geometryId().value());
0113
0114
0115 truePatterns.emplace_back(SH.direction().y() / SH.direction().z(),
0116 SH.fourPosition().y());
0117
0118 houghPlane.reset();
0119 int foundDC = 0;
0120
0121 for (DriftCircle& DC : gotDC) {
0122 if (DC.stationEta() == detailedInfo.stationEta &&
0123 DC.stationPhi() == detailedInfo.stationPhi &&
0124 DC.stationName() == detailedInfo.stationName) {
0125
0126 muonMdtIdentifierFields idf;
0127 idf.multilayer = DC.multilayer();
0128 idf.stationEta = DC.stationEta();
0129 idf.stationPhi = DC.stationPhi();
0130 idf.stationName = DC.stationName();
0131 idf.tubeLayer = DC.tubeLayer();
0132 idf.tube = DC.tube();
0133 auto identifier = compressId(idf);
0134 auto effectiveLayer = 3 * (DC.multilayer() - 1) + (DC.tubeLayer() - 1);
0135 ++foundDC;
0136
0137 houghPlane.fill<DriftCircle>(DC, axisRanges, houghParam_fromDC_left,
0138 houghWidth_fromDC, identifier,
0139 effectiveLayer, 1.0);
0140 houghPlane.fill<DriftCircle>(DC, axisRanges, houghParam_fromDC_right,
0141 houghWidth_fromDC, identifier,
0142 effectiveLayer, 1.0);
0143 }
0144 }
0145
0146 auto maxima = peakFinder.findPeaks(houghPlane, axisRanges);
0147
0148
0149
0150 TH2D houghHistoForPlot("houghHist", "HoughPlane;tan(#theta);z0 [mm]",
0151 houghPlane.nBinsX(), axisRanges.xMin,
0152 axisRanges.xMax, houghPlane.nBinsY(),
0153 axisRanges.yMin, axisRanges.yMax);
0154 for (int bx = 0; bx < houghHistoForPlot.GetNbinsX(); ++bx) {
0155 for (int by = 0; by < houghHistoForPlot.GetNbinsY(); ++by) {
0156 houghHistoForPlot.SetBinContent(bx + 1, by + 1,
0157 houghPlane.nHits(bx, by));
0158 }
0159 }
0160
0161 m_outCanvas->SetTitle(Form("Station %s, Eta %i, Phi %i",
0162 stationDict.at(detailedInfo.stationName).c_str(),
0163 (int)detailedInfo.stationEta,
0164 (int)detailedInfo.stationPhi));
0165 houghHistoForPlot.SetTitle(
0166 Form("Station %s, Eta %i, Phi %i",
0167 stationDict.at(detailedInfo.stationName).c_str(),
0168 (int)detailedInfo.stationEta, (int)detailedInfo.stationPhi));
0169 m_outCanvas->cd();
0170 int maxHitsAsInt = static_cast<int>(houghPlane.maxHits());
0171 houghHistoForPlot.SetContour(maxHitsAsInt + 1);
0172 for (int k = 0; k < maxHitsAsInt + 1; ++k) {
0173 houghHistoForPlot.SetContourLevel(k, k - 0.5);
0174 }
0175 std::vector<std::unique_ptr<TMarker>> markers;
0176 std::vector<std::unique_ptr<TBox>> boxes;
0177 houghHistoForPlot.SetContourLevel(maxHitsAsInt + 1,
0178 houghHistoForPlot.GetMaximum() + 0.5);
0179 houghHistoForPlot.Draw("COLZ");
0180
0181 auto trueMarker = std::make_unique<TMarker>(
0182 truePatterns.back().first, truePatterns.back().second, kOpenCrossX);
0183 trueMarker->SetMarkerSize(3);
0184 trueMarker->SetMarkerColor(kRed);
0185 trueMarker->Draw();
0186
0187
0188 for (auto& max : maxima) {
0189 markers.push_back(std::make_unique<TMarker>(max.x, max.y, kFullSquare));
0190 markers.back()->SetMarkerSize(1);
0191 markers.back()->SetMarkerColor(kBlue);
0192 markers.back()->Draw();
0193 boxes.push_back(std::make_unique<TBox>(max.x - max.wx, max.y - max.wy,
0194 max.x + max.wx, max.y + max.wy));
0195 boxes.back()->SetLineColor(kBlue);
0196 boxes.back()->SetFillStyle(1001);
0197 boxes.back()->SetFillColorAlpha(kBlue, 0.1);
0198 boxes.back()->SetLineWidth(0);
0199 boxes.back()->Draw();
0200 }
0201 TLegend legend(0.5, 0.7, 1. - gPad->GetRightMargin(),
0202 1. - gPad->GetTopMargin());
0203 legend.AddEntry(trueMarker.get(), "True coordinates");
0204 legend.SetBorderSize(0);
0205 legend.SetFillStyle(0);
0206 legend.Draw();
0207
0208 if (!boxes.empty()) {
0209 legend.AddEntry(markers.back().get(), "Hough maxima");
0210 legend.AddEntry(boxes.back().get(), "Hough uncertainties");
0211 }
0212 TLatex tl(gPad->GetLeftMargin() + 0.03, 1. - gPad->GetTopMargin() - 0.1,
0213 Form("%i drift circles on station", foundDC));
0214 tl.SetTextFont(43);
0215 tl.SetTextSize(24);
0216 tl.SetNDC();
0217 tl.Draw();
0218 m_outCanvas->SaveAs("HoughHistograms.pdf");
0219 }
0220
0221 ACTS_VERBOSE("SH: " << gotSH.size());
0222 ACTS_VERBOSE("DC: " << gotDC.size());
0223 return ActsExamples::ProcessCode::SUCCESS;
0224 }
0225
0226 ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::initialize() {
0227
0228 m_outCanvas = std::make_unique<TCanvas>("canvas", "", 800, 800);
0229 m_outCanvas->SaveAs("HoughHistograms.pdf[");
0230 m_outCanvas->SetRightMargin(0.12);
0231 m_outCanvas->SetLeftMargin(0.12);
0232 gStyle->SetPalette(kGreyScale);
0233 gStyle->SetOptStat(0);
0234 return ProcessCode::SUCCESS;
0235 }
0236 ActsExamples::ProcessCode ActsExamples::MuonHoughSeeder::finalize() {
0237 m_outCanvas->SaveAs("HoughHistograms.pdf]");
0238 return ProcessCode::SUCCESS;
0239 }