Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:30

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2023 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011 
0012 #include "Acts/EventData/MultiTrajectory.hpp"
0013 #include "Acts/EventData/TrackContainer.hpp"
0014 #include "Acts/EventData/TrackStateType.hpp"
0015 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0016 #include "Acts/EventData/VectorTrackContainer.hpp"
0017 #include "Acts/Geometry/GeometryIdentifier.hpp"
0018 #include "Acts/Surfaces/PerigeeSurface.hpp"
0019 #include "Acts/Surfaces/PlaneSurface.hpp"
0020 #include "Acts/TrackFinding/TrackSelector.hpp"
0021 
0022 #include <limits>
0023 
0024 using namespace Acts;
0025 namespace bdata = boost::unit_test::data;
0026 
0027 struct MockTrack {
0028   double m_theta;
0029   double m_phi;
0030   double m_pt;
0031   double m_loc0;
0032   double m_loc1;
0033   double m_time;
0034   std::size_t m_nMeasurements;
0035   std::size_t m_nHoles;
0036   std::size_t m_nOutliers;
0037   std::size_t m_nSharedHits;
0038   float m_chi2;
0039 
0040   bool hasReferenceSurface() const { return true; }
0041   double theta() const { return m_theta; }
0042   double phi() const { return m_phi; }
0043   double transverseMomentum() const { return m_pt; }
0044   double loc0() const { return m_loc0; }
0045   double loc1() const { return m_loc1; }
0046   double time() const { return m_time; }
0047   std::size_t nMeasurements() const { return m_nMeasurements; }
0048   std::size_t nHoles() const { return m_nHoles; }
0049   std::size_t nOutliers() const { return m_nOutliers; }
0050   std::size_t nSharedHits() const { return m_nSharedHits; }
0051   float chi2() const { return m_chi2; }
0052 
0053   // To comply with concept, not actually used
0054  private:
0055   struct MockTrackState {
0056     const Surface& referenceSurface() const {
0057       static const auto srf =
0058           Surface::makeShared<PlaneSurface>(Vector3::Zero(), Vector3::UnitZ());
0059       return *srf;
0060     }
0061 
0062     ConstTrackStateType typeFlags() const {
0063       static const ConstTrackStateType::raw_type raw{0};
0064       return {raw};
0065     }
0066   };
0067 
0068   struct TrackStateRange {
0069     auto begin() const { return m_trackStates.begin(); }
0070     auto end() const { return m_trackStates.end(); }
0071 
0072    private:
0073     std::vector<MockTrackState> m_trackStates;
0074   };
0075 
0076  public:
0077   TrackStateRange trackStatesReversed() const { return {}; }
0078 };
0079 
0080 double thetaFromEta(double eta) {
0081   return 2 * std::atan(std::exp(-eta));
0082 }
0083 
0084 BOOST_AUTO_TEST_SUITE(TrackSelectorTests)
0085 
0086 std::vector<double> etaValues{-5.0, -4.5, -4.0, -3.5, -3.0, -2.5, -2.0, -1.5,
0087                               -1.0, -0.5, 0.0,  0.5,  1.0,  1.5,  2.0,  2.5,
0088                               3.0,  3.5,  4.0,  4.5,  5.0,  1.0};
0089 
0090 BOOST_DATA_TEST_CASE(TestSingleBinCase, bdata::make(etaValues), eta) {
0091   TrackSelector::EtaBinnedConfig cfgBase;
0092 
0093   MockTrack baseTrack{};
0094   baseTrack.m_theta = thetaFromEta(eta);
0095   baseTrack.m_phi = 0.5;
0096   baseTrack.m_pt = 0.5;
0097   baseTrack.m_loc0 = 0.5;
0098   baseTrack.m_loc1 = 0.5;
0099   baseTrack.m_time = 0.5;
0100   baseTrack.m_nMeasurements = 1;
0101   baseTrack.m_nHoles = 0;
0102   baseTrack.m_nOutliers = 0;
0103   baseTrack.m_nSharedHits = 0;
0104   baseTrack.m_chi2 = 0.0;
0105 
0106   {
0107     TrackSelector selector{cfgBase};
0108     // should select anything
0109     BOOST_CHECK(selector.isValidTrack(baseTrack));
0110   }
0111 
0112   auto check = [&](const auto& var, const auto& minPtr, const auto& maxPtr,
0113                    const auto& propPtr) {
0114     BOOST_TEST_INFO_SCOPE("Testing " << var);
0115     MockTrack track = baseTrack;
0116 
0117     auto cfgMinOnly = cfgBase;
0118     auto cfgMaxOnly = cfgBase;
0119     auto cfgMinMax = cfgBase;
0120 
0121     cfgMinOnly.cutSets.at(0).*minPtr = -1;
0122     cfgMinMax.cutSets.at(0).*minPtr = -1;
0123     cfgMaxOnly.cutSets.at(0).*maxPtr = 1;
0124     cfgMinMax.cutSets.at(0).*maxPtr = 1;
0125 
0126     TrackSelector minOnly{cfgMinOnly};
0127     TrackSelector maxOnly{cfgMaxOnly};
0128     TrackSelector minMax{cfgMinMax};
0129 
0130     BOOST_CHECK(minOnly.isValidTrack(track));
0131     BOOST_CHECK(maxOnly.isValidTrack(track));
0132     BOOST_CHECK(minMax.isValidTrack(track));
0133 
0134     // push track outside of minimum
0135     track.*propPtr = -1.1;
0136 
0137     BOOST_CHECK(!minOnly.isValidTrack(track));
0138     BOOST_CHECK(maxOnly.isValidTrack(track));
0139     BOOST_CHECK(!minMax.isValidTrack(track));
0140 
0141     // push track outside of maximum
0142     track.*propPtr = 1.1;
0143 
0144     BOOST_CHECK(minOnly.isValidTrack(track));
0145     BOOST_CHECK(!maxOnly.isValidTrack(track));
0146     BOOST_CHECK(!minMax.isValidTrack(track));
0147   };
0148 
0149   check("loc0", &TrackSelector::Config::loc0Min,
0150         &TrackSelector::Config::loc0Max, &MockTrack::m_loc0);
0151 
0152   check("loc1", &TrackSelector::Config::loc1Min,
0153         &TrackSelector::Config::loc1Max, &MockTrack::m_loc1);
0154 
0155   check("phi", &TrackSelector::Config::phiMin, &TrackSelector::Config::phiMax,
0156         &MockTrack::m_phi);
0157 
0158   check("time", &TrackSelector::Config::timeMin,
0159         &TrackSelector::Config::timeMax, &MockTrack::m_time);
0160 
0161   {
0162     BOOST_TEST_INFO_SCOPE("pt min");
0163     auto cfg = cfgBase;
0164     cfg.cutSets.at(0).ptMin = {0.2};
0165     TrackSelector selector{cfg};
0166     MockTrack track = baseTrack;
0167     BOOST_CHECK(selector.isValidTrack(track));
0168     track.m_pt = 0.1;
0169     BOOST_CHECK(!selector.isValidTrack(track));
0170   }
0171 
0172   {
0173     BOOST_TEST_INFO_SCOPE("pt max");
0174     auto cfg = cfgBase;
0175     cfg.cutSets.at(0).ptMax = {1.0};
0176     TrackSelector selector{cfg};
0177     MockTrack track = baseTrack;
0178     BOOST_CHECK(selector.isValidTrack(track));
0179     track.m_pt = 1.1;
0180     BOOST_CHECK(!selector.isValidTrack(track));
0181   }
0182 
0183   {
0184     BOOST_TEST_INFO_SCOPE("pt min max");
0185     auto cfg = cfgBase;
0186     cfg.cutSets.at(0).ptMin = {0.2};
0187     cfg.cutSets.at(0).ptMax = {1.0};
0188     TrackSelector selector{cfg};
0189     MockTrack track = baseTrack;
0190     BOOST_CHECK(selector.isValidTrack(track));
0191     track.m_pt = 0.1;
0192     BOOST_CHECK(!selector.isValidTrack(track));
0193     track.m_pt = 1.1;
0194     BOOST_CHECK(!selector.isValidTrack(track));
0195   }
0196 
0197   {
0198     BOOST_TEST_INFO_SCOPE("eta min");
0199     auto cfg = cfgBase;
0200     cfg.cutSets.at(0).etaMin = {-1.0};
0201     TrackSelector selector{cfg};
0202     MockTrack track = baseTrack;
0203     track.m_theta = thetaFromEta(0.5);
0204     BOOST_CHECK(selector.isValidTrack(track));
0205     track.m_theta = thetaFromEta(-1.1);
0206     BOOST_CHECK(!selector.isValidTrack(track));
0207   }
0208 
0209   {
0210     BOOST_TEST_INFO_SCOPE("eta max");
0211     auto cfg = cfgBase;
0212     cfg.cutSets.at(0).etaMax = {1.0};
0213     TrackSelector selector{cfg};
0214     MockTrack track = baseTrack;
0215     track.m_theta = thetaFromEta(0.5);
0216     BOOST_CHECK(selector.isValidTrack(track));
0217     track.m_theta = thetaFromEta(1.1);
0218     BOOST_CHECK(!selector.isValidTrack(track));
0219   }
0220 
0221   {
0222     BOOST_TEST_INFO_SCOPE("eta min max");
0223     auto cfg = cfgBase;
0224     cfg.cutSets.at(0).etaMin = {-1.0};
0225     cfg.cutSets.at(0).etaMax = {1.0};
0226     TrackSelector selector{cfg};
0227     MockTrack track = baseTrack;
0228     track.m_theta = thetaFromEta(0.5);
0229     BOOST_CHECK(selector.isValidTrack(track));
0230     track.m_theta = thetaFromEta(-1.1);
0231     BOOST_CHECK(!selector.isValidTrack(track));
0232     track.m_theta = thetaFromEta(1.1);
0233     BOOST_CHECK(!selector.isValidTrack(track));
0234   }
0235 
0236   {
0237     BOOST_TEST_INFO_SCOPE("abs eta min");
0238     auto cfg = cfgBase;
0239     cfg.cutSets.at(0).absEtaMin = {0.2};
0240     TrackSelector selector{cfg};
0241     MockTrack track = baseTrack;
0242     track.m_theta = thetaFromEta(0.5);
0243     BOOST_CHECK(selector.isValidTrack(track));
0244     track.m_theta = thetaFromEta(-0.5);
0245     BOOST_CHECK(selector.isValidTrack(track));
0246 
0247     track.m_theta = thetaFromEta(0.1);
0248     BOOST_CHECK(!selector.isValidTrack(track));
0249     track.m_theta = thetaFromEta(-0.1);
0250     BOOST_CHECK(!selector.isValidTrack(track));
0251   }
0252 
0253   {
0254     BOOST_TEST_INFO_SCOPE("abs eta max");
0255     auto cfg = cfgBase;
0256     cfg.cutSets.at(0).absEtaMax = {1.0};
0257     TrackSelector selector{cfg};
0258     MockTrack track = baseTrack;
0259     track.m_theta = thetaFromEta(0.5);
0260     BOOST_CHECK(selector.isValidTrack(track));
0261     track.m_theta = thetaFromEta(-0.5);
0262     BOOST_CHECK(selector.isValidTrack(track));
0263 
0264     track.m_theta = thetaFromEta(1.1);
0265     BOOST_CHECK(!selector.isValidTrack(track));
0266     track.m_theta = thetaFromEta(-1.1);
0267     BOOST_CHECK(!selector.isValidTrack(track));
0268   }
0269 
0270   {
0271     BOOST_TEST_INFO_SCOPE("abs eta min max");
0272     auto cfg = cfgBase;
0273     cfg.cutSets.at(0).absEtaMin = {0.2};
0274     cfg.cutSets.at(0).absEtaMax = {1.0};
0275     TrackSelector selector{cfg};
0276     MockTrack track = baseTrack;
0277     track.m_theta = thetaFromEta(0.5);
0278     BOOST_CHECK(selector.isValidTrack(track));
0279     track.m_theta = thetaFromEta(-0.5);
0280     BOOST_CHECK(selector.isValidTrack(track));
0281 
0282     track.m_theta = thetaFromEta(0.1);
0283     BOOST_CHECK(!selector.isValidTrack(track));
0284     track.m_theta = thetaFromEta(-0.1);
0285     BOOST_CHECK(!selector.isValidTrack(track));
0286 
0287     track.m_theta = thetaFromEta(1.1);
0288     BOOST_CHECK(!selector.isValidTrack(track));
0289     track.m_theta = thetaFromEta(-1.1);
0290     BOOST_CHECK(!selector.isValidTrack(track));
0291   }
0292 
0293   {
0294     BOOST_TEST_INFO_SCOPE("nMeas min");
0295     auto cfg = cfgBase;
0296     cfg.cutSets.at(0).minMeasurements = {1};
0297     TrackSelector selector{cfg};
0298     MockTrack track = baseTrack;
0299     track.m_nMeasurements = {2};
0300     BOOST_CHECK(selector.isValidTrack(track));
0301     track.m_nMeasurements = {1};
0302     BOOST_CHECK(selector.isValidTrack(track));
0303     track.m_nMeasurements = {0};
0304     BOOST_CHECK(!selector.isValidTrack(track));
0305   }
0306 
0307   {
0308     BOOST_TEST_INFO_SCOPE("nHoles max");
0309     auto cfg = cfgBase;
0310     cfg.cutSets.at(0).maxHoles = {3};
0311     TrackSelector selector{cfg};
0312     MockTrack track = baseTrack;
0313     track.m_nHoles = {2};
0314     BOOST_CHECK(selector.isValidTrack(track));
0315     track.m_nHoles = {3};
0316     BOOST_CHECK(selector.isValidTrack(track));
0317     track.m_nHoles = {4};
0318     BOOST_CHECK(!selector.isValidTrack(track));
0319   }
0320 
0321   {
0322     BOOST_TEST_INFO_SCOPE("nOutliers max");
0323     auto cfg = cfgBase;
0324     cfg.cutSets.at(0).maxOutliers = {3};
0325     TrackSelector selector{cfg};
0326     MockTrack track = baseTrack;
0327     track.m_nOutliers = {2};
0328     BOOST_CHECK(selector.isValidTrack(track));
0329     track.m_nOutliers = {3};
0330     BOOST_CHECK(selector.isValidTrack(track));
0331     track.m_nOutliers = {4};
0332     BOOST_CHECK(!selector.isValidTrack(track));
0333   }
0334 
0335   {
0336     BOOST_TEST_INFO_SCOPE("nSharedHits max");
0337     auto cfg = cfgBase;
0338     cfg.cutSets.at(0).maxSharedHits = {3};
0339     TrackSelector selector{cfg};
0340     MockTrack track = baseTrack;
0341     track.m_nSharedHits = {2};
0342     BOOST_CHECK(selector.isValidTrack(track));
0343     track.m_nSharedHits = {3};
0344     BOOST_CHECK(selector.isValidTrack(track));
0345     track.m_nSharedHits = {4};
0346     BOOST_CHECK(!selector.isValidTrack(track));
0347   }
0348 
0349   {
0350     BOOST_TEST_INFO_SCOPE("nSharedHits max");
0351     auto cfg = cfgBase;
0352     cfg.cutSets.at(0).maxChi2 = {3};
0353     TrackSelector selector{cfg};
0354     MockTrack track = baseTrack;
0355     track.m_chi2 = {2};
0356     BOOST_CHECK(selector.isValidTrack(track));
0357     track.m_chi2 = {3};
0358     BOOST_CHECK(selector.isValidTrack(track));
0359     track.m_chi2 = {4};
0360     BOOST_CHECK(!selector.isValidTrack(track));
0361   }
0362 }
0363 
0364 BOOST_AUTO_TEST_CASE(TestSingleBinEtaCutByBinEdge) {
0365   TrackSelector selector{TrackSelector::EtaBinnedConfig(1.0).addCuts(2.0)};
0366 
0367   BOOST_TEST_INFO_SCOPE(selector.config());
0368 
0369   MockTrack track{};
0370   track.m_theta = thetaFromEta(0.0);
0371   BOOST_CHECK(!selector.isValidTrack(track));
0372 
0373   track.m_theta = thetaFromEta(0.5);
0374   BOOST_CHECK(!selector.isValidTrack(track));
0375 
0376   // cannot easily check on-edge behavior because of floating point arithmetic
0377   // (it won't be exactly 1.0 in selector)
0378   track.m_theta = thetaFromEta(1.01);
0379   BOOST_CHECK(selector.isValidTrack(track));
0380 
0381   track.m_theta = thetaFromEta(1.5);
0382   BOOST_CHECK(selector.isValidTrack(track));
0383 
0384   track.m_theta = thetaFromEta(2.0);
0385   BOOST_CHECK(!selector.isValidTrack(track));
0386 }
0387 
0388 BOOST_AUTO_TEST_CASE(TestMultiBinCuts) {
0389   MockTrack baseTrack{};
0390   baseTrack.m_theta = thetaFromEta(1.0);
0391   baseTrack.m_phi = 0.5;
0392   baseTrack.m_pt = 0.5;
0393   baseTrack.m_loc0 = 0.5;
0394   baseTrack.m_loc1 = 0.5;
0395   baseTrack.m_time = 0.5;
0396   baseTrack.m_nMeasurements = 1;
0397   baseTrack.m_nHoles = 0;
0398   baseTrack.m_nOutliers = 0;
0399   baseTrack.m_nSharedHits = 0;
0400   baseTrack.m_chi2 = 0.0;
0401 
0402   using Config = TrackSelector::Config;
0403 
0404   using factory_ptr_t = Config& (Config::*)(double, double);
0405   using prop_ptr_t = double MockTrack::*;
0406 
0407   auto check = [&](const char* name, const factory_ptr_t& factory,
0408                    const prop_ptr_t& prop) {
0409     BOOST_TEST_CONTEXT(name) {
0410       auto cfg = TrackSelector::EtaBinnedConfig{0.0};
0411 
0412       cfg.addCuts(2.0, [&](auto& c) { (c.*factory)(-1.0, 1.0); })
0413           .addCuts([&](auto& c) { (c.*factory)(-2.0, 2.0); });
0414 
0415       TrackSelector selector{cfg};
0416 
0417       BOOST_TEST_INFO_SCOPE(cfg);
0418 
0419       {
0420         // exactly at zero
0421         MockTrack track = baseTrack;
0422         track.m_theta = thetaFromEta(0.0);
0423 
0424         BOOST_CHECK(selector.isValidTrack(track));
0425 
0426         track.*prop = -1.1;
0427         BOOST_CHECK(!selector.isValidTrack(track));
0428 
0429         track.*prop = 1.1;
0430         BOOST_CHECK(!selector.isValidTrack(track));
0431       }
0432 
0433       {
0434         // first bin
0435         MockTrack track = baseTrack;
0436         track.m_theta = thetaFromEta(1.0);
0437 
0438         BOOST_CHECK(selector.isValidTrack(track));
0439 
0440         track.*prop = -1.1;
0441         BOOST_CHECK(!selector.isValidTrack(track));
0442 
0443         track.*prop = 1.1;
0444         BOOST_CHECK(!selector.isValidTrack(track));
0445       }
0446 
0447       {
0448         // first bin edge
0449         MockTrack track = baseTrack;
0450         track.m_theta =
0451             thetaFromEta(2.0 - std::numeric_limits<double>::epsilon());
0452 
0453         BOOST_CHECK(selector.isValidTrack(track));
0454 
0455         track.*prop = -1.1;
0456         BOOST_CHECK(!selector.isValidTrack(track));
0457 
0458         track.*prop = 1.1;
0459         BOOST_CHECK(!selector.isValidTrack(track));
0460       }
0461 
0462       {
0463         // second bin lower edge
0464         MockTrack track = baseTrack;
0465         track.m_theta = thetaFromEta(2.0);
0466 
0467         BOOST_CHECK(selector.isValidTrack(track));
0468 
0469         track.*prop = -1.1;
0470         BOOST_CHECK(selector.isValidTrack(track));
0471 
0472         track.*prop = 1.1;
0473         BOOST_CHECK(selector.isValidTrack(track));
0474 
0475         track.*prop = -2.1;
0476         BOOST_CHECK(!selector.isValidTrack(track));
0477 
0478         track.*prop = 2.1;
0479         BOOST_CHECK(!selector.isValidTrack(track));
0480       }
0481 
0482       {
0483         // second bin
0484         MockTrack track = baseTrack;
0485         track.m_theta = thetaFromEta(666.0);
0486 
0487         track.*prop = -1.1;
0488         BOOST_CHECK(selector.isValidTrack(track));
0489 
0490         track.*prop = 1.1;
0491         BOOST_CHECK(selector.isValidTrack(track));
0492 
0493         track.*prop = -2.1;
0494         BOOST_CHECK(!selector.isValidTrack(track));
0495 
0496         track.*prop = 2.1;
0497         BOOST_CHECK(!selector.isValidTrack(track));
0498       }
0499     }
0500   };
0501 
0502   check("loc0", &Config::loc0, &MockTrack::m_loc0);
0503   check("loc1", &Config::loc1, &MockTrack::m_loc1);
0504   check("time", &Config::time, &MockTrack::m_time);
0505   check("phi", &Config::phi, &MockTrack::m_phi);
0506   check("pt", &Config::pt, &MockTrack::m_pt);
0507 }
0508 
0509 BOOST_AUTO_TEST_CASE(TestBinSelection) {
0510   using EtaBinnedConfig = TrackSelector::EtaBinnedConfig;
0511   constexpr double inf = std::numeric_limits<double>::infinity();
0512 
0513   {
0514     EtaBinnedConfig cfg{std::vector<double>{0, inf}};
0515     for (int i = -1; i <= 1; i = i + 2) {
0516       BOOST_CHECK_EQUAL(cfg.binIndex(i * 0.0), 0);
0517       BOOST_CHECK_EQUAL(cfg.binIndex(i * 1.0), 0);
0518       BOOST_CHECK_EQUAL(cfg.binIndex(i * 2.0), 0);
0519       BOOST_CHECK_EQUAL(cfg.binIndex(i * 3.0), 0);
0520       BOOST_CHECK_EQUAL(cfg.binIndex(i * 10.0), 0);
0521       BOOST_CHECK_EQUAL(cfg.binIndex(i * 1000.0), 0);
0522     }
0523   }
0524 
0525   {
0526     EtaBinnedConfig cfg{std::vector<double>{0, 0.5, 1.5, 2.5, 3.0, inf}};
0527     for (int i = -1; i <= 1; i = i + 2) {
0528       BOOST_CHECK_EQUAL(cfg.binIndex(i * 0.0), 0);
0529       BOOST_CHECK_EQUAL(cfg.binIndex(i * 1.0), 1);
0530       BOOST_CHECK_EQUAL(cfg.binIndex(i * 2.0), 2);
0531       BOOST_CHECK_EQUAL(cfg.binIndex(i * 3.0), 4);
0532       BOOST_CHECK_EQUAL(cfg.binIndex(i * 10.0), 4);
0533       BOOST_CHECK_EQUAL(cfg.binIndex(i * 1000.0), 4);
0534     }
0535   }
0536 
0537   {
0538     EtaBinnedConfig cfg{std::vector<double>{0, 1, 2}};
0539     for (int i = -1; i <= 1; i = i + 2) {
0540       BOOST_CHECK_EQUAL(cfg.binIndex(i * 0.0), 0);
0541       BOOST_CHECK_EQUAL(cfg.binIndex(i * 1.0), 1);
0542       BOOST_CHECK_EQUAL(
0543           cfg.binIndex(i * (2.0 - std::numeric_limits<double>::epsilon())), 1);
0544       BOOST_CHECK_THROW(cfg.binIndex(i * 2.0), std::invalid_argument);
0545     }
0546   }
0547 }
0548 
0549 BOOST_AUTO_TEST_CASE(TestConstructor) {
0550   // valid multi bin construction
0551   {
0552     TrackSelector::EtaBinnedConfig cfg{std::vector<double>{0, 1, 4}};
0553     cfg.cutSets.at(0).ptMin = 0.9;
0554     cfg.cutSets.at(1).ptMin = 0.4;
0555     TrackSelector{cfg};
0556   }
0557 
0558   {
0559     // Track selector config with 2 eta bins
0560     TrackSelector::EtaBinnedConfig cfg{std::vector<double>{0, 1, 4}};
0561 
0562     // just the right amount!
0563     TrackSelector{cfg};
0564 
0565     // not enough cut cets
0566     cfg.cutSets.resize(1);
0567     BOOST_CHECK_THROW(TrackSelector{cfg}, std::invalid_argument);
0568 
0569     // too many cut sets
0570     cfg.cutSets.resize(3);
0571     BOOST_CHECK_THROW(TrackSelector{cfg}, std::invalid_argument);
0572   }
0573 
0574   // Constructor straight from cut config
0575   TrackSelector::Config cuts;
0576   TrackSelector selector{cuts};
0577   BOOST_CHECK_EQUAL(selector.config().absEtaEdges.size(), 2);
0578 
0579   {
0580     // Invalid sequence of chained construction
0581     auto cfg = TrackSelector::EtaBinnedConfig(0);
0582     cfg.addCuts(2.0, [](auto& c) { c.loc0(-1.0, 1.0); });
0583     BOOST_CHECK_THROW(cfg.addCuts(1.0), std::invalid_argument);
0584     BOOST_CHECK_THROW(TrackSelector::EtaBinnedConfig(0).addCuts(-2.0),
0585                       std::invalid_argument);
0586   }
0587 
0588   {
0589     auto cfg = TrackSelector::EtaBinnedConfig(1.0);
0590 
0591     cfg.addCuts(2.0, [](auto& c) { c.loc0(-1.0, 1.0); });
0592     BOOST_CHECK_EQUAL(cfg.nEtaBins(), 1);
0593     BOOST_CHECK_EQUAL(cfg.getCuts(1.5).loc0Min, -1.0);
0594     BOOST_CHECK_EQUAL(cfg.getCuts(1.5).loc0Max, 1.0);
0595 
0596     cfg.addCuts(3.0, [](auto& c) { c.loc0(-2.0, 2.0); });
0597     BOOST_CHECK_EQUAL(cfg.nEtaBins(), 2);
0598     BOOST_CHECK_EQUAL(cfg.getCuts(2.5).loc0Min, -2.0);
0599     BOOST_CHECK_EQUAL(cfg.getCuts(2.5).loc0Max, 2.0);
0600 
0601     cfg.addCuts(4.0, [](auto& c) { c.loc0(-3.0, 3.0); });
0602     BOOST_CHECK_EQUAL(cfg.nEtaBins(), 3);
0603     BOOST_CHECK_EQUAL(cfg.getCuts(3.5).loc0Min, -3.0);
0604     BOOST_CHECK_EQUAL(cfg.getCuts(3.5).loc0Max, 3.0);
0605   }
0606 }
0607 
0608 BOOST_AUTO_TEST_CASE(SubsetHitCountCut) {
0609   auto makeSurface = [](GeometryIdentifier id) {
0610     auto srf =
0611         Surface::makeShared<PlaneSurface>(Vector3::Zero(), Vector3::UnitZ());
0612 
0613     srf->assignGeometryId(id);
0614     return srf;
0615   };
0616 
0617   auto addTrackState = [](auto& track, const auto& surface,
0618                           TrackStateFlag flag) {
0619     auto ts = track.appendTrackState();
0620     ts.setReferenceSurface(surface);
0621     ts.typeFlags().set(flag);
0622     return ts;
0623   };
0624 
0625   auto addMeasurement = [&](auto& track, const auto& surface) {
0626     return addTrackState(track, surface, TrackStateFlag::MeasurementFlag);
0627   };
0628 
0629   auto addMaterial = [&](auto& track, const auto& surface) {
0630     return addTrackState(track, surface, TrackStateFlag::MaterialFlag);
0631   };
0632 
0633   TrackContainer tc{VectorTrackContainer{}, VectorMultiTrajectory{}};
0634 
0635   auto makeTrack = [&]() {
0636     auto track = tc.makeTrack();
0637 
0638     using namespace Acts::UnitLiterals;
0639     track.parameters() << 0, 0, M_PI / 2, M_PI / 2, 1 / 1_GeV, 0;
0640     auto perigee = Surface::makeShared<PerigeeSurface>(Vector3::Zero());
0641     track.setReferenceSurface(perigee);
0642     return track;
0643   };
0644 
0645   auto vol7_lay3_sen2 = makeSurface(
0646       GeometryIdentifier{}.setVolume(7).setLayer(3).setSensitive(2));
0647   auto vol7_lay4 = makeSurface(GeometryIdentifier{}.setVolume(7).setLayer(4));
0648   auto vol7_lay3_sen8 = makeSurface(
0649       GeometryIdentifier{}.setVolume(7).setLayer(3).setSensitive(8));
0650   auto vol7_lay5_sen11 = makeSurface(
0651       GeometryIdentifier{}.setVolume(7).setLayer(5).setSensitive(11));
0652   auto vol7_lay5_sen12 = makeSurface(
0653       GeometryIdentifier{}.setVolume(7).setLayer(5).setSensitive(12));
0654   auto vol7_lay6_sen3 = makeSurface(
0655       GeometryIdentifier{}.setVolume(7).setLayer(6).setSensitive(3));
0656 
0657   auto vol8_lay8_sen1 = makeSurface(
0658       GeometryIdentifier{}.setVolume(8).setLayer(8).setSensitive(1));
0659   auto vol8_lay8_sen2 = makeSurface(
0660       GeometryIdentifier{}.setVolume(8).setLayer(8).setSensitive(2));
0661   auto vol8_lay9_sen1 = makeSurface(
0662       GeometryIdentifier{}.setVolume(8).setLayer(9).setSensitive(1));
0663 
0664   TrackSelector::Config cfgVol7;
0665   cfgVol7.measurementCounter.addCounter({GeometryIdentifier{}.setVolume(7)}, 3);
0666   TrackSelector selectorVol7{cfgVol7};
0667 
0668   auto trackVol7 = makeTrack();
0669 
0670   BOOST_CHECK(!selectorVol7.isValidTrack(trackVol7));
0671 
0672   // 1 hit in vol7
0673   addMeasurement(trackVol7, vol7_lay3_sen2);
0674   addMaterial(trackVol7, vol7_lay4);
0675 
0676   BOOST_CHECK(!selectorVol7.isValidTrack(trackVol7));
0677   addMeasurement(trackVol7, vol7_lay5_sen11);
0678   BOOST_CHECK(!selectorVol7.isValidTrack(trackVol7));
0679 
0680   // Now we should have enough hits
0681   addMeasurement(trackVol7, vol7_lay6_sen3);
0682   BOOST_CHECK(selectorVol7.isValidTrack(trackVol7));
0683 
0684   TrackSelector::Config cfgVol8;
0685   cfgVol8.measurementCounter.addCounter({GeometryIdentifier{}.setVolume(8)}, 2);
0686   TrackSelector selectorVol8{cfgVol8};
0687 
0688   // Previous trackVol7 has no measurements in volume 8
0689   BOOST_CHECK(!selectorVol8.isValidTrack(trackVol7));
0690 
0691   auto trackVol8 = makeTrack();
0692   BOOST_CHECK(!selectorVol8.isValidTrack(trackVol8));
0693 
0694   addMeasurement(trackVol8, vol8_lay8_sen1);
0695   BOOST_CHECK(!selectorVol8.isValidTrack(trackVol8));
0696   addMeasurement(trackVol8, vol8_lay8_sen2);
0697   BOOST_CHECK(selectorVol8.isValidTrack(trackVol8));
0698   addMeasurement(trackVol8, vol8_lay9_sen1);
0699   BOOST_CHECK(selectorVol8.isValidTrack(trackVol8));
0700 
0701   TrackSelector::Config cfgVol7Lay5;
0702   cfgVol7Lay5.measurementCounter.addCounter(
0703       {GeometryIdentifier{}.setVolume(7).setLayer(5)}, 2);
0704   TrackSelector selectorVol7Lay5{cfgVol7Lay5};
0705 
0706   // Only one hit on volume 7 layer 5
0707   BOOST_CHECK(!selectorVol7Lay5.isValidTrack(trackVol7));
0708   addMeasurement(trackVol7, vol7_lay5_sen12);
0709   BOOST_CHECK(selectorVol7Lay5.isValidTrack(trackVol7));
0710 
0711   // Check requirement on volume 7 OR 8
0712   TrackSelector::Config cfgVol7Or8;
0713   cfgVol7Or8.measurementCounter.addCounter(
0714       {GeometryIdentifier{}.setVolume(7), GeometryIdentifier{}.setVolume(8)},
0715       4);
0716   TrackSelector selectorVol7Or8{cfgVol7Or8};
0717 
0718   // threshold is 4
0719   // this track has enough hits in volume 7 only
0720   BOOST_CHECK(selectorVol7Or8.isValidTrack(trackVol7));
0721   // this track does not have enough hits in volume 8 only
0722   BOOST_CHECK(!selectorVol7Or8.isValidTrack(trackVol8));
0723 
0724   // add 1 hit in volume 7 to push it over the threshold
0725   addMeasurement(trackVol8, vol7_lay3_sen8);
0726   // now it passes
0727   BOOST_CHECK(selectorVol7Or8.isValidTrack(trackVol8));
0728 
0729   TrackSelector::Config cfgVol7And8;
0730   cfgVol7And8.measurementCounter.addCounter({GeometryIdentifier{}.setVolume(7)},
0731                                             4);
0732   cfgVol7And8.measurementCounter.addCounter({GeometryIdentifier{}.setVolume(8)},
0733                                             2);
0734   TrackSelector selectorVol7And8{cfgVol7And8};
0735 
0736   // this track has enough hits in vol 7 but not enough in vol 8
0737   BOOST_CHECK(!selectorVol7And8.isValidTrack(trackVol7));
0738 
0739   addMeasurement(trackVol7, vol8_lay8_sen1);
0740   addMeasurement(trackVol7, vol8_lay8_sen2);
0741 
0742   BOOST_CHECK(selectorVol7And8.isValidTrack(trackVol7));
0743 }
0744 
0745 BOOST_AUTO_TEST_SUITE_END()