Back to home page

sPhenix code displayed by LXR

 
 

    


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

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2018-2021 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/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Material/MaterialSlab.hpp"
0013 #include "Acts/Tests/CommonHelpers/PredefinedMaterials.hpp"
0014 #include "ActsFatras/EventData/Barcode.hpp"
0015 #include "ActsFatras/EventData/Particle.hpp"
0016 #include "ActsFatras/Kernel/InteractionList.hpp"
0017 
0018 #include <cstdint>
0019 #include <limits>
0020 #include <random>
0021 #include <utility>
0022 #include <vector>
0023 
0024 using namespace Acts::UnitLiterals;
0025 using namespace ActsFatras;
0026 
0027 using Acts::MaterialSlab;
0028 using Scalar = Particle::Scalar;
0029 
0030 namespace {
0031 
0032 /// Continuous process that does not trigger a break
0033 struct SterileContinuousProcess {
0034   template <typename generator_t>
0035   bool operator()(generator_t & /*generator*/, const MaterialSlab & /*slab*/,
0036                   Particle & /*particle*/,
0037                   std::vector<Particle> & /*generated*/) const {
0038     return false;
0039   }
0040 };
0041 
0042 static_assert(detail::IsContinuousProcess<SterileContinuousProcess>::value,
0043               "Is not a continuous process");
0044 static_assert(!detail::IsPointLikeProcess<SterileContinuousProcess>::value,
0045               "Is a point-like process");
0046 
0047 /// Continuous process that DOES trigger a break
0048 struct FatalContinuousProcess {
0049   template <typename generator_t>
0050   bool operator()(generator_t & /*generator*/, const MaterialSlab & /*slab*/,
0051                   Particle & /*particle*/,
0052                   std::vector<Particle> & /*generated*/) const {
0053     return true;
0054   }
0055 };
0056 static_assert(detail::IsContinuousProcess<FatalContinuousProcess>::value,
0057               "Is not a continuous process");
0058 static_assert(!detail::IsPointLikeProcess<FatalContinuousProcess>::value,
0059               "Is a point-like process");
0060 
0061 /// EM-like point-like process that triggers on X0 and keeps the particle alive.
0062 ///
0063 /// Each run call creates one descendant particle.
0064 struct X0PointLikeProcess {
0065   template <typename generator_t>
0066   std::pair<Scalar, Scalar> generatePathLimits(
0067       generator_t & /*generator*/, const Particle & /*particle*/) const {
0068     return {0.5, std::numeric_limits<Scalar>::infinity()};
0069   }
0070 
0071   template <typename generator_t>
0072   bool run(generator_t & /*generator*/, Particle &particle,
0073            std::vector<Particle> &generated) const {
0074     auto pid0 = particle.particleId().makeDescendant(0);
0075     generated.emplace_back(particle.withParticleId(pid0));
0076     return false;
0077   }
0078 };
0079 
0080 static_assert(!detail::IsContinuousProcess<X0PointLikeProcess>::value,
0081               "Is a continuous process");
0082 static_assert(detail::IsPointLikeProcess<X0PointLikeProcess>::value,
0083               "Is not a point-like process");
0084 
0085 /// Nuclear-like point-like process that triggers on L0 and kills the particle.
0086 ///
0087 /// Each run call creates two descendant particles.
0088 struct L0PointLikeProcess {
0089   template <typename generator_t>
0090   std::pair<Scalar, Scalar> generatePathLimits(
0091       generator_t & /*generator*/, const Particle & /*particle*/) const {
0092     return {std::numeric_limits<Scalar>::infinity(), 1.5};
0093   }
0094 
0095   template <typename generator_t>
0096   bool run(generator_t & /*generator*/, Particle &particle,
0097            std::vector<Particle> &generated) const {
0098     auto pid0 = particle.particleId().makeDescendant(0);
0099     auto pid1 = particle.particleId().makeDescendant(1);
0100     generated.emplace_back(particle.withParticleId(pid0));
0101     generated.emplace_back(particle.withParticleId(pid1));
0102     return true;
0103   }
0104 };
0105 
0106 static_assert(!detail::IsContinuousProcess<L0PointLikeProcess>::value,
0107               "Is a continuous process");
0108 static_assert(detail::IsPointLikeProcess<L0PointLikeProcess>::value,
0109               "Is not a point-like process");
0110 
0111 struct Fixture {
0112   std::ranlux48 rng{23};
0113   Acts::MaterialSlab slab =
0114       Acts::MaterialSlab(Acts::Test::makeBeryllium(), 1_mm);
0115   Particle incoming;
0116   std::vector<Particle> outgoing;
0117 };
0118 
0119 }  // namespace
0120 
0121 BOOST_AUTO_TEST_SUITE(FatrasInteractionList)
0122 
0123 BOOST_AUTO_TEST_CASE(Empty) {
0124   Fixture f;
0125   InteractionList<> l;
0126 
0127   // w/o processes the list should never abort
0128   BOOST_CHECK(!l.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0129 
0130   // w/o processes there should be no selection
0131   auto sel = l.armPointLike(f.rng, f.incoming);
0132   BOOST_CHECK_EQUAL(sel.x0Limit, std::numeric_limits<Scalar>::infinity());
0133   BOOST_CHECK_EQUAL(sel.l0Limit, std::numeric_limits<Scalar>::infinity());
0134   BOOST_CHECK_EQUAL(sel.x0Process, SIZE_MAX);
0135   BOOST_CHECK_EQUAL(sel.l0Process, SIZE_MAX);
0136 
0137   // running with an invalid process index should do nothing
0138   // interaction list is empty and 0 should already be invalid
0139   BOOST_CHECK(!l.runPointLike(f.rng, 0u, f.incoming, f.outgoing));
0140   BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0141   // SIZE_MAX should always be an invalid index
0142   BOOST_CHECK(!l.runPointLike(f.rng, SIZE_MAX, f.incoming, f.outgoing));
0143   BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0144 }
0145 
0146 BOOST_AUTO_TEST_CASE(ContinuousSterile) {
0147   Fixture f;
0148   InteractionList<SterileContinuousProcess> l;
0149 
0150   // sterile process should never abort
0151   BOOST_CHECK(!l.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0152 }
0153 
0154 BOOST_AUTO_TEST_CASE(ContinuousFatal) {
0155   Fixture f;
0156   InteractionList<FatalContinuousProcess> l;
0157 
0158   // fatal process must always abort
0159   BOOST_CHECK(l.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0160 }
0161 
0162 BOOST_AUTO_TEST_CASE(ContinuousSterileFatal) {
0163   Fixture f;
0164   InteractionList<SterileContinuousProcess, FatalContinuousProcess> physicsList;
0165 
0166   // the contained fatal process must always abort
0167   BOOST_CHECK(physicsList.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0168   // with the fatal process disabled, it should go through again
0169   physicsList.disable<FatalContinuousProcess>();
0170   BOOST_CHECK(
0171       !physicsList.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0172 }
0173 
0174 BOOST_AUTO_TEST_CASE(PointLikeX0) {
0175   Fixture f;
0176   InteractionList<X0PointLikeProcess> l;
0177 
0178   // w/o processes the list should never abort
0179   auto sel = l.armPointLike(f.rng, f.incoming);
0180   BOOST_CHECK_EQUAL(sel.x0Limit, 0.5);
0181   BOOST_CHECK_EQUAL(sel.l0Limit, std::numeric_limits<Scalar>::infinity());
0182   BOOST_CHECK_EQUAL(sel.x0Process, 0u);
0183   BOOST_CHECK_EQUAL(sel.l0Process, SIZE_MAX);
0184 
0185   // valid index, X0Process leaves the particle alive
0186   BOOST_CHECK(!l.runPointLike(f.rng, 0u, f.incoming, f.outgoing));
0187   BOOST_CHECK_EQUAL(f.outgoing.size(), 1u);
0188   // invalid index, should do nothing
0189   BOOST_CHECK(!l.runPointLike(f.rng, SIZE_MAX, f.incoming, f.outgoing));
0190   BOOST_CHECK_EQUAL(f.outgoing.size(), 1u);
0191 }
0192 
0193 BOOST_AUTO_TEST_CASE(PointLikeL0) {
0194   Fixture f;
0195   InteractionList<L0PointLikeProcess> l;
0196 
0197   // w/o processes the list should never abort
0198   auto sel = l.armPointLike(f.rng, f.incoming);
0199   BOOST_CHECK_EQUAL(sel.x0Limit, std::numeric_limits<Scalar>::infinity());
0200   BOOST_CHECK_EQUAL(sel.l0Limit, 1.5);
0201   BOOST_CHECK_EQUAL(sel.x0Process, SIZE_MAX);
0202   BOOST_CHECK_EQUAL(sel.l0Process, 0u);
0203 
0204   // valid index, L0Process kills the particles and creates 2 descendants
0205   BOOST_CHECK(l.runPointLike(f.rng, 0u, f.incoming, f.outgoing));
0206   BOOST_CHECK_EQUAL(f.outgoing.size(), 2u);
0207   // invalid index, should do nothing
0208   BOOST_CHECK(!l.runPointLike(f.rng, SIZE_MAX, f.incoming, f.outgoing));
0209   BOOST_CHECK_EQUAL(f.outgoing.size(), 2u);
0210 }
0211 
0212 BOOST_AUTO_TEST_CASE(PointLikeX0L0) {
0213   Fixture f;
0214   InteractionList<X0PointLikeProcess, L0PointLikeProcess> l;
0215 
0216   // w/o processes the list should never abort
0217   auto sel = l.armPointLike(f.rng, f.incoming);
0218   BOOST_CHECK_EQUAL(sel.x0Limit, 0.5);
0219   BOOST_CHECK_EQUAL(sel.l0Limit, 1.5);
0220   BOOST_CHECK_EQUAL(sel.x0Process, 0u);
0221   BOOST_CHECK_EQUAL(sel.l0Process, 1u);
0222 
0223   // valid index, X0Process leaves the particle alive
0224   BOOST_CHECK(!l.runPointLike(f.rng, 0u, f.incoming, f.outgoing));
0225   BOOST_CHECK_EQUAL(f.outgoing.size(), 1u);
0226   // valid index, L0Process kills the particles and creates 2 descendants
0227   BOOST_CHECK(l.runPointLike(f.rng, 1u, f.incoming, f.outgoing));
0228   BOOST_CHECK_EQUAL(f.outgoing.size(), 3u);
0229   // invalid index, should do nothing
0230   BOOST_CHECK(!l.runPointLike(f.rng, SIZE_MAX, f.incoming, f.outgoing));
0231   BOOST_CHECK_EQUAL(f.outgoing.size(), 3u);
0232 }
0233 
0234 // this tests both the disable functionality and an interaction list with both
0235 // continuous and point-like processes.
0236 BOOST_AUTO_TEST_CASE(Disable) {
0237   Fixture f;
0238   InteractionList<SterileContinuousProcess, FatalContinuousProcess,
0239                   X0PointLikeProcess, L0PointLikeProcess>
0240       l;
0241 
0242   // continuous should abort due to the fatal process
0243   BOOST_CHECK(l.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0244   // unless we disable it
0245   l.disable<FatalContinuousProcess>();
0246   BOOST_CHECK(!l.runContinuous(f.rng, f.slab, f.incoming, f.outgoing));
0247 
0248   // disabled X0Process should not participate in arming procedure
0249   l.disable<X0PointLikeProcess>();
0250   {
0251     auto sel = l.armPointLike(f.rng, f.incoming);
0252     BOOST_CHECK_EQUAL(sel.x0Limit, std::numeric_limits<Scalar>::infinity());
0253     BOOST_CHECK_EQUAL(sel.l0Limit, 1.5);
0254     BOOST_CHECK_EQUAL(sel.x0Process, SIZE_MAX);
0255     BOOST_CHECK_EQUAL(sel.l0Process, 3u);
0256 
0257     // index for X0Process, should do nothing since its disabled
0258     f.outgoing.clear();
0259     BOOST_CHECK(!l.runPointLike(f.rng, 2u, f.incoming, f.outgoing));
0260     BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0261     // index for L0Process, should run and generate a break condition
0262     BOOST_CHECK(l.runPointLike(f.rng, 3u, f.incoming, f.outgoing));
0263     BOOST_CHECK_EQUAL(f.outgoing.size(), 2u);
0264   }
0265 
0266   // disabling L0Process is equivalent to an empty list (for arming)
0267   l.disable<L0PointLikeProcess>();
0268   {
0269     auto sel = l.armPointLike(f.rng, f.incoming);
0270     BOOST_CHECK_EQUAL(sel.x0Limit, std::numeric_limits<Scalar>::infinity());
0271     BOOST_CHECK_EQUAL(sel.l0Limit, std::numeric_limits<Scalar>::infinity());
0272     BOOST_CHECK_EQUAL(sel.x0Process, SIZE_MAX);
0273     BOOST_CHECK_EQUAL(sel.l0Process, SIZE_MAX);
0274 
0275     // index for X0Process, should do nothing since its disabled
0276     f.outgoing.clear();
0277     BOOST_CHECK(!l.runPointLike(f.rng, 2u, f.incoming, f.outgoing));
0278     BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0279     // index for L0Process, should do nothing since its disabled
0280     BOOST_CHECK(!l.runPointLike(f.rng, 3u, f.incoming, f.outgoing));
0281     BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0282   }
0283 
0284   // invalid index, should do nothing
0285   f.outgoing.clear();
0286   BOOST_CHECK(!l.runPointLike(f.rng, SIZE_MAX, f.incoming, f.outgoing));
0287   BOOST_CHECK_EQUAL(f.outgoing.size(), 0u);
0288 }
0289 
0290 BOOST_AUTO_TEST_SUITE_END()