Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:51:17

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