File indexing completed on 2025-12-14 09:23:08
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include <set>
0012
0013 #include "StrawHitGeneratorHelper.hpp"
0014 #include "TFile.h"
0015 #include "TTree.h"
0016
0017 constexpr auto logLvl = Acts::Logging::Level::INFO;
0018 constexpr std::size_t nEvents = 5;
0019
0020 ACTS_LOCAL_LOGGER(getDefaultLogger("StrawLineSeederTest", logLvl));
0021
0022 #define DECLARE_BRANCH(dTYPE, NAME) \
0023 dTYPE NAME{}; \
0024 outTree->Branch(#NAME, &NAME);
0025
0026 namespace ActsTests {
0027
0028 void testSeeder(RandomEngine& engine, TFile& outFile) {
0029 auto outTree = std::make_unique<TTree>("StrawSeederTree", "StrawSeederTree");
0030
0031 DECLARE_BRANCH(double, trueY0);
0032 DECLARE_BRANCH(double, trueTheta);
0033 DECLARE_BRANCH(std::size_t, nTruthStraws);
0034 DECLARE_BRANCH(std::size_t, nTruthStrips);
0035 DECLARE_BRANCH(std::vector<double>, recoY0);
0036 DECLARE_BRANCH(std::vector<double>, recoTheta);
0037 DECLARE_BRANCH(std::vector<std::size_t>, nStraws);
0038 DECLARE_BRANCH(std::vector<std::size_t>, nStrips);
0039 DECLARE_BRANCH(std::size_t, nSeeds);
0040
0041 using GenCfg_t = MeasurementGenerator::Config;
0042 GenCfg_t genCfg{};
0043 genCfg.twinStraw = false;
0044 genCfg.createStrips = true;
0045
0046 CompositeSpacePointLineSeeder::Config seederCfg{};
0047 seederCfg.busyLayerLimit = 20;
0048 const CompositeSpacePointLineSeeder seeder{
0049 seederCfg, getDefaultLogger("StrawLineSeederTest", logLvl)};
0050
0051 for (std::size_t evt = 0; evt < nEvents; ++evt) {
0052 if (evt % 100 == 0) {
0053 ACTS_INFO("Generating event " << evt);
0054 }
0055 const auto line = generateLine(engine, logger());
0056 auto linePars = line.parameters();
0057 trueY0 = linePars[toUnderlying(FitParIndex::y0)];
0058 trueTheta = linePars[toUnderlying(FitParIndex::theta)];
0059 auto testTubes =
0060 MeasurementGenerator::spawn(line, 0._ns, engine, genCfg, logger());
0061 nTruthStraws = static_cast<std::size_t>(std::ranges::count_if(
0062 testTubes, [](const auto& testSp) { return testSp->isStraw(); }));
0063 nTruthStrips = static_cast<std::size_t>(std::ranges::count_if(
0064 testTubes, [](const auto& testSp) { return !testSp->isStraw(); }));
0065 auto calibrator = std::make_unique<SpCalibrator>();
0066
0067 using SeedState_t =
0068 CompositeSpacePointLineSeeder::SeedingState<Container_t, Container_t,
0069 SpSorter>;
0070 SeedState_t seedOpts{testTubes, calibrator.get()};
0071 seedOpts.strawRadius = 15._mm;
0072 ACTS_DEBUG(seedOpts);
0073 nSeeds = 0;
0074 CalibrationContext cctx{};
0075 while (auto seed = seeder.nextSeed(cctx, seedOpts)) {
0076 ACTS_DEBUG("Seed finder loop " << seedOpts);
0077 if (seed == std::nullopt) {
0078 break;
0079 }
0080 recoTheta.push_back(seed->parameters[toUnderlying(FitParIndex::theta)]);
0081 recoY0.push_back(seed->parameters[toUnderlying(FitParIndex::y0)]);
0082
0083 const auto seedStraws = static_cast<std::size_t>(std::ranges::count_if(
0084 seed->hits, [](const auto& testMe) { return testMe->isStraw(); }));
0085 const auto seedStrips = seed->hits.size() - seedStraws;
0086 nStraws.push_back(seedStraws);
0087 nStrips.push_back(seedStrips);
0088 ++nSeeds;
0089 }
0090 ACTS_DEBUG("======Event " << evt << " found " << nSeeds << " seeds.");
0091
0092 outTree->Fill();
0093 recoY0.clear();
0094 recoTheta.clear();
0095 nStraws.clear();
0096 nStrips.clear();
0097 }
0098 outFile.WriteObject(outTree.get(), outTree->GetName());
0099 }
0100
0101 using GenCfg_t = MeasurementGenerator::Config;
0102
0103 BOOST_AUTO_TEST_SUITE(SeedingSuite)
0104 BOOST_AUTO_TEST_CASE(SeederTest) {
0105 RandomEngine engine{1602};
0106 std::unique_ptr<TFile> outFile{
0107 TFile::Open("StrawLineSeedTest.root", "RECREATE")};
0108
0109 BOOST_CHECK_EQUAL(outFile->IsZombie(), false);
0110
0111 testSeeder(engine, *outFile);
0112 }
0113 BOOST_AUTO_TEST_CASE(SeedTangents) {
0114 RandomEngine engine{117};
0115 constexpr double tolerance = 1.e-3;
0116
0117 using Seeder = CompositeSpacePointLineSeeder;
0118 using SeedAux = CompSpacePointAuxiliaries;
0119 using enum Seeder::TangentAmbi;
0120 GenCfg_t genCfg{};
0121 genCfg.createStrips = false;
0122 genCfg.createStraws = true;
0123 genCfg.smearRadius = false;
0124 for (std::size_t evt = 0; evt < nEvents; ++evt) {
0125 const auto line = generateLine(engine, logger());
0126 auto testTubes =
0127 MeasurementGenerator::spawn(line, 0._ns, engine, genCfg, logger());
0128
0129 const double lineTanBeta = line.direction().y() / line.direction().z();
0130 const double lineY0 = line.position().y();
0131
0132 for (std::size_t m1 = testTubes.size() - 1; m1 > testTubes.size() / 2;
0133 --m1) {
0134 for (std::size_t m2 = 0; m2 < m1; ++m2) {
0135 const auto& bottomTube = *testTubes[m2];
0136 const auto& topTube = *testTubes[m1];
0137
0138 const int signTop = SeedAux::strawSign(line, topTube);
0139 const int signBot = SeedAux::strawSign(line, bottomTube);
0140 const auto trueAmbi = Seeder::encodeAmbiguity(signTop, signBot);
0141
0142 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - "
0143 << std::format("bottom tube @ {:}, r: {:.3f}({:})",
0144 toString(bottomTube.localPosition()),
0145 (signBot * bottomTube.driftRadius()),
0146 signBot > 0 ? "R" : "L")
0147 << ", "
0148 << std::format("top tube @ {:}, r: {:.3f} ({:})",
0149 toString(topTube.localPosition()),
0150 (signTop * topTube.driftRadius()),
0151 signTop > 0 ? "R" : "L"));
0152
0153 bool seenTruePars{false};
0154 std::set<std::pair<double, double>> fourSeedPars{};
0155 for (const auto ambi : {LL, RL, LR, RR}) {
0156 const auto pars =
0157 Seeder::constructTangentLine(topTube, bottomTube, ambi);
0158
0159 const bool isTruePars =
0160 Acts::abs(std::tan(pars.theta) - lineTanBeta) < tolerance &&
0161 Acts::abs(lineY0 - pars.y0) < tolerance;
0162 seenTruePars |= isTruePars;
0163 ACTS_VERBOSE(__func__
0164 << "() " << __LINE__ << " - Test ambiguity "
0165 << CompositeSpacePointLineSeeder::toString(ambi)
0166 << " -> "
0167 << std::format("theta: {:.3f}, ", pars.theta / 1._degree)
0168 << std::format("tanTheta: {:.3f}, ",
0169 std::tan(pars.theta))
0170 << std::format("y0: {:.3f}", pars.y0)
0171 << (!isTruePars ? (ambi == trueAmbi ? " xxxxxx" : "")
0172 : " <-------"));
0173 const Vector3 seedPos = pars.y0 * Vector3::UnitY();
0174 const Vector3 seedDir =
0175 makeDirectionFromAxisTangents(0., std::tan(pars.theta));
0176
0177 const double chi2Top = SeedAux::chi2Term(seedPos, seedDir, topTube);
0178 const double chi2Bot =
0179 SeedAux::chi2Term(seedPos, seedDir, bottomTube);
0180 ACTS_VERBOSE(__func__ << "() " << __LINE__
0181 << " - Resulting chi2 top: " << chi2Top
0182 << ", bottom: " << chi2Bot);
0183 BOOST_CHECK_LE(chi2Top, 1.e-17);
0184 BOOST_CHECK_LE(chi2Bot, 1.e-17);
0185 BOOST_CHECK_EQUAL(
0186 fourSeedPars.insert(std::make_pair(pars.theta, pars.y0)).second,
0187 true);
0188 }
0189 BOOST_CHECK_EQUAL(seenTruePars, true);
0190 BOOST_CHECK_EQUAL(fourSeedPars.size(), 4);
0191 const auto seedPars =
0192 Seeder::constructTangentLine(topTube, bottomTube, trueAmbi);
0193
0194 ACTS_DEBUG(__func__
0195 << "() " << __LINE__ << " - Line tan theta: " << lineTanBeta
0196 << ", reconstructed tan theta: " << std::tan(seedPars.theta)
0197 << ", line y0: " << lineY0
0198 << ", reconstructed y0: " << seedPars.y0);
0199 BOOST_CHECK_CLOSE(std::tan(seedPars.theta), lineTanBeta, tolerance);
0200 BOOST_CHECK_CLOSE(seedPars.y0, lineY0, tolerance);
0201 }
0202 }
0203 }
0204 }
0205 }
0206 BOOST_AUTO_TEST_SUITE_END()