Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-06 09:23:56

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Geometry/ApproachDescriptor.hpp"
0013 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0014 #include "Acts/Geometry/GeometryContext.hpp"
0015 #include "Acts/Geometry/GeometryIdentifier.hpp"
0016 #include "Acts/Geometry/Layer.hpp"
0017 #include "Acts/Geometry/TrackingGeometry.hpp"
0018 #include "Acts/Geometry/TrackingVolume.hpp"
0019 #include "Acts/Surfaces/Surface.hpp"
0020 #include "Acts/Surfaces/SurfaceArray.hpp"
0021 #include "Acts/Utilities/BinnedArray.hpp"
0022 
0023 #include <cstddef>
0024 #include <memory>
0025 #include <unordered_map>
0026 #include <vector>
0027 
0028 #include "TrackingVolumeCreation.hpp"
0029 
0030 using namespace Acts;
0031 using namespace Acts::UnitLiterals;
0032 
0033 namespace ActsTests {
0034 
0035 // Create a test context
0036 GeometryContext tgContext = GeometryContext();
0037 
0038 TrackingGeometry makeTrackingGeometry(const GeometryIdentifierHook& hook) {
0039   /// we test a two-level hierarchy
0040   /// every deeper level hierarchy is a derivate of this
0041   ///
0042   /// WorldVolume   with volumeID       == 1
0043   /// - InnerVolume with volumeID       == 2
0044   /// -- InnerInnerVolume with volumeID == 3
0045   /// -- InnerOuterVolume with volumeID == 4
0046   /// - OuterVolume with volumeID       == 5
0047 
0048   // sensitive surface definitions
0049   double surfaceHalfLengthZ = 50_mm;
0050   double surfaceRstagger = 5_mm;
0051   double surfaceZoverlap = 10_mm;
0052   double layerEnvelope = 0.5_mm;
0053   double volumeEnvelope = 10_mm;
0054 
0055   // inner inner volume definitions
0056   double iiv_surfaceR = 25_mm;
0057   double iiv_volumeR =
0058       iiv_surfaceR + 0.5 * surfaceRstagger + layerEnvelope + volumeEnvelope;
0059 
0060   ///  inner outer volume definitions
0061   double iov_surfaceR = 100_mm;
0062   double iov_volumeR =
0063       iov_surfaceR + 0.5 * surfaceRstagger + layerEnvelope + volumeEnvelope;
0064 
0065   ///  inner inner volume
0066   auto iiVolume = constructCylinderVolume(
0067       tgContext, surfaceHalfLengthZ, iiv_surfaceR, surfaceRstagger,
0068       surfaceZoverlap, layerEnvelope, volumeEnvelope, 0., iiv_volumeR,
0069       "InnerInnerVolume");
0070   ///  inner outer volume
0071   auto ioVolume = constructCylinderVolume(
0072       tgContext, surfaceHalfLengthZ, iov_surfaceR, surfaceRstagger,
0073       surfaceZoverlap, layerEnvelope, volumeEnvelope, iiv_volumeR, iov_volumeR,
0074       "InnerOuterVolume");
0075 
0076   // now create the Inner Container volume
0077   double volumeHalfZ =
0078       (4 * surfaceHalfLengthZ - surfaceZoverlap) + volumeEnvelope;
0079   /// the inner volume
0080   auto iVolume = constructContainerVolume(
0081       tgContext, iiVolume, ioVolume, iov_volumeR, volumeHalfZ, "InnerVolume");
0082 
0083   // outer volume definitions
0084   double ov_surfaceR = 150_mm;
0085   double ov_volumeR =
0086       ov_surfaceR + 0.5 * surfaceRstagger + layerEnvelope + volumeEnvelope;
0087 
0088   ///  inner outer volume
0089   auto oVolume = constructCylinderVolume(
0090       tgContext, surfaceHalfLengthZ, ov_surfaceR, surfaceRstagger,
0091       surfaceZoverlap, layerEnvelope, volumeEnvelope, iov_volumeR, ov_volumeR,
0092       "OuterVolume");
0093   /// the inner volume
0094   auto volume = constructContainerVolume(
0095       tgContext, iVolume, oVolume, ov_volumeR, volumeHalfZ, "WorldVolume");
0096 
0097   // creating a TrackingGeometry
0098   // -> close the geometry, this should set the GeometryIdentifier
0099   TrackingGeometry tGeometry(volume, nullptr, hook);
0100   return tGeometry;
0101 }
0102 
0103 BOOST_AUTO_TEST_SUITE(GeometrySuite)
0104 
0105 BOOST_AUTO_TEST_CASE(GeometryIdentifier_closeGeometry_test) {
0106   GeometryIdentifierHook hook{};
0107   TrackingGeometry tGeometry = makeTrackingGeometry(hook);
0108   auto world = tGeometry.highestTrackingVolume();
0109 
0110   // the lambda for checking
0111   auto check_vol = [](const TrackingVolume& vol,
0112                       GeometryIdentifier::Value geoid) {
0113     // check the geometry id of the volume
0114     BOOST_CHECK_EQUAL(geoid, vol.geometryId().volume());
0115     // check the geometry id of all boundary surfaces of the volume
0116     // - this is strictly only possible when glueing is OFF
0117     GeometryIdentifier::Value bsurface_id = 0;
0118     for (const auto& bSf : vol.boundarySurfaces()) {
0119       // check the bsurface volume id
0120       auto bs_vol_id = bSf->surfaceRepresentation().geometryId().volume();
0121       BOOST_CHECK_EQUAL(geoid, bs_vol_id);
0122       // check the bsurface boundary id
0123       auto bs_bsf_id = bSf->surfaceRepresentation().geometryId().boundary();
0124       auto bs_ext_id = bSf->surfaceRepresentation().geometryId().extra();
0125       BOOST_CHECK_EQUAL(++bsurface_id, bs_bsf_id);
0126       BOOST_CHECK_EQUAL(bs_ext_id, 0);
0127     }
0128     // testing the layer and its approach surfaces
0129     if (vol.confinedLayers() != nullptr) {
0130       // layers start are counted from 1 - n
0131       GeometryIdentifier::Value layer_id = 0;
0132       for (const auto& lay : vol.confinedLayers()->arrayObjects()) {
0133         // check the layer volume id and layer id
0134         auto lay_vol_id = lay->geometryId().volume();
0135         auto lay_lay_id = lay->geometryId().layer();
0136         BOOST_CHECK_EQUAL(++layer_id, lay_lay_id);
0137         BOOST_CHECK_EQUAL(geoid, lay_vol_id);
0138         // test the layer approach surfaces
0139         if (lay->approachDescriptor() != nullptr) {
0140           // approach surfaces are counted from 1 - n
0141           GeometryIdentifier::Value asurface_id = 0;
0142           for (const auto& asf :
0143                lay->approachDescriptor()->containedSurfaces()) {
0144             // check the approach volume id, approach layer id
0145             auto asf_vol_id = asf->geometryId().volume();
0146             auto asf_lay_id = asf->geometryId().layer();
0147             auto asf_asf_id = asf->geometryId().approach();
0148             auto ssf_ext_id = asf->geometryId().extra();
0149             BOOST_CHECK_EQUAL(layer_id, asf_lay_id);
0150             BOOST_CHECK_EQUAL(geoid, asf_vol_id);
0151             BOOST_CHECK_EQUAL(++asurface_id, asf_asf_id);
0152             BOOST_CHECK_EQUAL(0, ssf_ext_id);
0153           }
0154         }
0155         // test the sensitive surfaces
0156         if (lay->surfaceArray() != nullptr) {
0157           // sensitive surfaces are counted from 1 - n
0158           GeometryIdentifier::Value ssurface_id = 0;
0159           for (const auto& ssf : lay->surfaceArray()->surfaces()) {
0160             // check the approach volume id, approach layer id
0161             auto ssf_vol_id = ssf->geometryId().volume();
0162             auto ssf_lay_id = ssf->geometryId().layer();
0163             auto ssf_ssf_id = ssf->geometryId().sensitive();
0164             auto ssf_ext_id = ssf->geometryId().extra();
0165             BOOST_CHECK_EQUAL(layer_id, ssf_lay_id);
0166             BOOST_CHECK_EQUAL(geoid, ssf_vol_id);
0167             BOOST_CHECK_EQUAL(++ssurface_id, ssf_ssf_id);
0168             BOOST_CHECK_EQUAL(0, ssf_ext_id);
0169           }
0170         }
0171       }
0172     }
0173   };
0174 
0175   // get the two volumes the world is built of
0176   auto ioVolumes = world->confinedVolumes()->arrayObjects();
0177   // check the size - has to be two volumes
0178   BOOST_CHECK_EQUAL(2ul, ioVolumes.size());
0179   // get the innermost volumes
0180   auto iioVolumes = ioVolumes[0]->confinedVolumes()->arrayObjects();
0181   // check the size - has to be two volumes
0182   BOOST_CHECK_EQUAL(2ul, iioVolumes.size());
0183 
0184   // check the world
0185   check_vol(*world, 1);
0186   // - check InnerVolume
0187   check_vol(*ioVolumes[0], 2);
0188   // -- check the InnerInnerVolume
0189   check_vol(*iioVolumes[0], 3);
0190   // -- check the InenerOuterVolume
0191   check_vol(*iioVolumes[1], 4);
0192   // - check the OuterVolume
0193   check_vol(*ioVolumes[1], 5);
0194 }
0195 
0196 template <typename Callable>
0197 struct CallableHook : public GeometryIdentifierHook {
0198   Callable callable;
0199 
0200   explicit CallableHook(const Callable& c) : callable(c) {}
0201 
0202   GeometryIdentifier decorateIdentifier(GeometryIdentifier identifier,
0203                                         const Surface& surface) const override {
0204     return callable(identifier, surface);
0205   }
0206 };
0207 
0208 BOOST_AUTO_TEST_CASE(GeometryIdentifier_closeGeometry_test_extra) {
0209   std::size_t extra = 0;
0210   std::unordered_map<const Surface*, std::size_t> extraMap;
0211   auto hookImpl = [&](GeometryIdentifier orig, const Surface& srf) {
0212     ++extra;
0213     extraMap[&srf] = extra;
0214     return orig.withExtra(extra);
0215   };
0216   CallableHook<decltype(hookImpl)> hook{hookImpl};
0217 
0218   TrackingGeometry tGeometry = makeTrackingGeometry(hook);
0219   auto world = tGeometry.highestTrackingVolume();
0220 
0221   // the lambda for checking
0222   auto check_vol = [&extraMap](const TrackingVolume& vol,
0223                                GeometryIdentifier::Value geoid) {
0224     // check the geometry id of the volume
0225     BOOST_CHECK_EQUAL(geoid, vol.geometryId().volume());
0226     // check the geometry id of all boundary surfaces of the volume
0227     // - this is strictly only possible when glueing is OFF
0228     GeometryIdentifier::Value bsurface_id = 0;
0229     for (const auto& bSf : vol.boundarySurfaces()) {
0230       // check the bsurface volume id
0231       auto bs_vol_id = bSf->surfaceRepresentation().geometryId().volume();
0232       BOOST_CHECK_EQUAL(geoid, bs_vol_id);
0233       // check the bsurface boundary id
0234       auto bs_bsf_id = bSf->surfaceRepresentation().geometryId().boundary();
0235       auto bs_ext_id = bSf->surfaceRepresentation().geometryId().extra();
0236       BOOST_CHECK_EQUAL(++bsurface_id, bs_bsf_id);
0237       BOOST_CHECK_EQUAL(bs_ext_id, 0);
0238     }
0239     // testing the layer and its approach surfaces
0240     if (vol.confinedLayers() != nullptr) {
0241       // layers start are counted from 1 - n
0242       GeometryIdentifier::Value layer_id = 0;
0243       for (const auto& lay : vol.confinedLayers()->arrayObjects()) {
0244         // check the layer volume id and layer id
0245         auto lay_vol_id = lay->geometryId().volume();
0246         auto lay_lay_id = lay->geometryId().layer();
0247         BOOST_CHECK_EQUAL(++layer_id, lay_lay_id);
0248         BOOST_CHECK_EQUAL(geoid, lay_vol_id);
0249         // test the layer approach surfaces
0250         if (lay->approachDescriptor() != nullptr) {
0251           // approach surfaces are counted from 1 - n
0252           GeometryIdentifier::Value asurface_id = 0;
0253           for (const auto& asf :
0254                lay->approachDescriptor()->containedSurfaces()) {
0255             // check the approach volume id, approach layer id
0256             auto asf_vol_id = asf->geometryId().volume();
0257             auto asf_lay_id = asf->geometryId().layer();
0258             auto asf_asf_id = asf->geometryId().approach();
0259             auto ssf_ext_id = asf->geometryId().extra();
0260             BOOST_CHECK_EQUAL(layer_id, asf_lay_id);
0261             BOOST_CHECK_EQUAL(geoid, asf_vol_id);
0262             BOOST_CHECK_EQUAL(++asurface_id, asf_asf_id);
0263             BOOST_CHECK_EQUAL(0, ssf_ext_id);
0264           }
0265         }
0266         // test the sensitive surfaces
0267         if (lay->surfaceArray() != nullptr) {
0268           // sensitive surfaces are counted from 1 - n
0269           GeometryIdentifier::Value ssurface_id = 0;
0270           for (const auto& ssf : lay->surfaceArray()->surfaces()) {
0271             // check the approach volume id, approach layer id
0272             auto ssf_vol_id = ssf->geometryId().volume();
0273             auto ssf_lay_id = ssf->geometryId().layer();
0274             auto ssf_ssf_id = ssf->geometryId().sensitive();
0275             auto ssf_ext_id = ssf->geometryId().extra();
0276             BOOST_CHECK_EQUAL(layer_id, ssf_lay_id);
0277             BOOST_CHECK_EQUAL(geoid, ssf_vol_id);
0278             BOOST_CHECK_EQUAL(++ssurface_id, ssf_ssf_id);
0279             BOOST_CHECK_EQUAL(extraMap[ssf], ssf_ext_id);
0280           }
0281         }
0282       }
0283     }
0284   };
0285 
0286   // get the two volumes the world is built of
0287   auto ioVolumes = world->confinedVolumes()->arrayObjects();
0288   // check the size - has to be two volumes
0289   BOOST_CHECK_EQUAL(2ul, ioVolumes.size());
0290   // get the innermost volumes
0291   auto iioVolumes = ioVolumes[0]->confinedVolumes()->arrayObjects();
0292   // check the size - has to be two volumes
0293   BOOST_CHECK_EQUAL(2ul, iioVolumes.size());
0294 
0295   // check the world
0296   check_vol(*world, 1);
0297   // - check InnerVolume
0298   check_vol(*ioVolumes[0], 2);
0299   // -- check the InnerInnerVolume
0300   check_vol(*iioVolumes[0], 3);
0301   // -- check the InenerOuterVolume
0302   check_vol(*iioVolumes[1], 4);
0303   // - check the OuterVolume
0304   check_vol(*ioVolumes[1], 5);
0305 }
0306 
0307 BOOST_AUTO_TEST_CASE(TrackingGeometry_testVisitSurfaces) {
0308   GeometryIdentifierHook hook{};
0309   auto tGeometry = makeTrackingGeometry(hook);
0310 
0311   // Test visitSurfaces
0312   std::size_t nSurfaces = 0;
0313   tGeometry.visitSurfaces([&nSurfaces](const auto*) { nSurfaces++; });
0314   BOOST_CHECK_EQUAL(nSurfaces, 9u);
0315 
0316   // Test visitVolumes
0317   std::size_t nVolumes = 0;
0318   tGeometry.visitVolumes([&nVolumes](const auto*) { nVolumes++; });
0319   BOOST_CHECK_EQUAL(nVolumes,
0320                     5u);  // World + Inner + InnerInner + InnerOuter + Outer
0321 
0322   // Test apply with mutable visitor
0323   bool volumeCalled = false;
0324   tGeometry.apply([&](TrackingVolume& /*volume*/) { volumeCalled = true; });
0325   BOOST_CHECK(volumeCalled);
0326 
0327   // Test apply with const visitor
0328   bool constVolumeCalled = false;
0329   tGeometry.apply(
0330       [&](const TrackingVolume& /*volume*/) { constVolumeCalled = true; });
0331   BOOST_CHECK(constVolumeCalled);
0332 
0333   // Test apply with overloaded visitor
0334   bool surfaceCalled = false;
0335   bool portalCalled = false;
0336   tGeometry.apply(overloaded{
0337       [&](Surface& /*surface*/) { surfaceCalled = true; },
0338       [&](Portal& /*portal*/) { portalCalled = true; },
0339       [&](TrackingVolume& /*volume*/) {},
0340   });
0341   BOOST_CHECK(surfaceCalled);
0342   // Gen 1 geometry
0343   BOOST_CHECK(!portalCalled);
0344 
0345   // Test apply with lambda visitor
0346   bool lambdaVolumeCalled = false;
0347   tGeometry.apply([&](Volume& /*volume*/) { lambdaVolumeCalled = true; });
0348   BOOST_CHECK(lambdaVolumeCalled);
0349 }
0350 
0351 BOOST_AUTO_TEST_SUITE_END()
0352 
0353 }  // namespace ActsTests