Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-14 08:12:34

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/Plugins/Geant4/Geant4DetectorSurfaceFactory.hpp"
0012 #include "Acts/Plugins/Geant4/Geant4PhysicalVolumeSelectors.hpp"
0013 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0014 #include "Acts/Visualization/GeometryView3D.hpp"
0015 #include "Acts/Visualization/ObjVisualization3D.hpp"
0016 
0017 #include <memory>
0018 #include <numbers>
0019 #include <string>
0020 
0021 #include "G4Box.hh"
0022 #include "G4LogicalVolume.hh"
0023 #include "G4PVPlacement.hh"
0024 #include "G4RotationMatrix.hh"
0025 #include "G4SystemOfUnits.hh"
0026 #include "G4ThreeVector.hh"
0027 #include "G4Transform3D.hh"
0028 #include "G4Tubs.hh"
0029 
0030 class G4VPhysicalVolume;
0031 
0032 BOOST_AUTO_TEST_SUITE(Geant4Plugin)
0033 
0034 BOOST_AUTO_TEST_CASE(Geant4DetecturSurfaceFactory_box) {
0035   G4Box* worldS = new G4Box("world", 100, 100, 100);
0036 
0037   G4LogicalVolume* worldLV = new G4LogicalVolume(worldS, nullptr, "World");
0038 
0039   G4Box* boxS = new G4Box("box", 10, 20, 20);
0040   G4LogicalVolume* boxLV = new G4LogicalVolume(boxS, nullptr, "World");
0041   G4VPhysicalVolume* boxPV = new G4PVPlacement(nullptr, G4ThreeVector(), boxLV,
0042                                                "Box", worldLV, false, 0, true);
0043 
0044   G4Transform3D nominal;
0045 
0046   // Get the box
0047   auto nameSelector =
0048       std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
0049           std::vector<std::string>{"ox"}, false);
0050 
0051   Acts::Geant4DetectorSurfaceFactory::Cache cache;
0052   Acts::Geant4DetectorSurfaceFactory::Options options;
0053   options.sensitiveSurfaceSelector = nameSelector;
0054 
0055   Acts::Geant4DetectorSurfaceFactory::Config factoryConfig;
0056   Acts::Geant4DetectorSurfaceFactory factory(factoryConfig);
0057 
0058   factory.construct(cache, nominal, *boxPV, options);
0059 
0060   BOOST_CHECK_EQUAL(cache.sensitiveSurfaces.size(), 1u);
0061   BOOST_CHECK_EQUAL(cache.passiveSurfaces.size(), 0u);
0062 
0063   auto [element, surface] = cache.sensitiveSurfaces.front();
0064   BOOST_CHECK_EQUAL(surface->type(), Acts::Surface::SurfaceType::Plane);
0065 }
0066 
0067 BOOST_AUTO_TEST_CASE(Geant4DetecturSurfaceFactory_Cylinder) {
0068   G4Box* worldS = new G4Box("world", 1000, 1000, 1000);
0069 
0070   G4LogicalVolume* worldLV = new G4LogicalVolume(worldS, nullptr, "World");
0071 
0072   G4Tubs* cylinderS =
0073       new G4Tubs("cylinder", 99, 100, 100, -std::numbers::pi * CLHEP::radian,
0074                  2 * std::numbers::pi * CLHEP::radian);
0075 
0076   G4LogicalVolume* cylinderLV =
0077       new G4LogicalVolume(cylinderS, nullptr, "World");
0078   G4VPhysicalVolume* cylinderPV =
0079       new G4PVPlacement(nullptr, G4ThreeVector(), cylinderLV, "Cylinder",
0080                         worldLV, false, 0, true);
0081 
0082   G4Transform3D nominal;
0083 
0084   // Get the box
0085   auto nameSelector =
0086       std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
0087           std::vector<std::string>{"yl"}, false);
0088 
0089   Acts::Geant4DetectorSurfaceFactory::Cache cache;
0090   Acts::Geant4DetectorSurfaceFactory::Options options;
0091   options.sensitiveSurfaceSelector = nameSelector;
0092 
0093   Acts::Geant4DetectorSurfaceFactory::Config factoryConfig;
0094   Acts::Geant4DetectorSurfaceFactory factory(factoryConfig);
0095   factory.construct(cache, nominal, *cylinderPV, options);
0096 
0097   BOOST_CHECK_EQUAL(cache.sensitiveSurfaces.size(), 1u);
0098   BOOST_CHECK_EQUAL(cache.passiveSurfaces.size(), 0u);
0099 
0100   auto [element, surface] = cache.sensitiveSurfaces.front();
0101   BOOST_CHECK_EQUAL(surface->type(), Acts::Surface::SurfaceType::Cylinder);
0102 }
0103 
0104 BOOST_AUTO_TEST_CASE(Geant4DetecturSurfaceFactory_Transforms) {
0105   Acts::GeometryContext gctx;
0106 
0107   G4Box* worldS = new G4Box("world", 1000, 1000, 1000);
0108   G4LogicalVolume* worldLV = new G4LogicalVolume(worldS, nullptr, "World");
0109   G4VPhysicalVolume* worldPV = new G4PVPlacement(
0110       nullptr, G4ThreeVector(), worldLV, "World", nullptr, false, 0, false);
0111 
0112   auto vol1S = new G4Box("volume1", 25, 10, 50);
0113   auto vol1L = new G4LogicalVolume(vol1S, nullptr, "Volume1");
0114 
0115   G4Transform3D transformVol1(CLHEP::HepRotationX(std::numbers::pi / 4.),
0116                               G4ThreeVector(20, 0, 0));
0117 
0118   [[maybe_unused]] auto vol1PV = new G4PVPlacement(
0119       transformVol1, vol1L, "Volume1", worldLV, false, 0, false);
0120 
0121   auto vol2S = new G4Box("volume2", 25, 10, 50);
0122   auto vol2L = new G4LogicalVolume(vol2S, nullptr, "Volume2");
0123 
0124   G4Transform3D transformVol2(CLHEP::HepRotationY(std::numbers::pi / 6.),
0125                               G4ThreeVector(0, 100, 20));
0126 
0127   [[maybe_unused]] auto vol2PV = new G4PVPlacement(
0128       transformVol2, vol2L, "Volume2", vol1L, false, 0, false);
0129 
0130   auto vol3S = new G4Box("volume3", 25, 10, 50);
0131   auto vol3L = new G4LogicalVolume(vol3S, nullptr, "Volume3");
0132 
0133   G4Transform3D transformVol3(CLHEP::HepRotationZ(std::numbers::pi / 12.),
0134                               G4ThreeVector(30, 100, 0));
0135 
0136   [[maybe_unused]] auto vol3PV = new G4PVPlacement(
0137       transformVol3, vol3L, "Volume3", vol2L, false, 0, false);
0138 
0139   // Get the lowest volume
0140   auto nameSelector =
0141       std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
0142           std::vector<std::string>{"olume"}, false);
0143 
0144   Acts::Geant4DetectorSurfaceFactory::Cache cache;
0145   Acts::Geant4DetectorSurfaceFactory::Options options;
0146   options.sensitiveSurfaceSelector = nameSelector;
0147 
0148   G4Transform3D nominal;
0149 
0150   Acts::Geant4DetectorSurfaceFactory::Config factoryConfig;
0151   Acts::Geant4DetectorSurfaceFactory factory(factoryConfig);
0152   factory.construct(cache, nominal, *worldPV, options);
0153 
0154   auto [element, surface] = cache.sensitiveSurfaces.front();
0155   BOOST_CHECK_EQUAL(surface->type(), Acts::Surface::SurfaceType::Plane);
0156 
0157   auto center = surface->center(gctx);
0158   auto normal = surface->normal(gctx, center, Acts::Vector3(1, 0, 0));
0159 
0160   // The following numbers represent the transforms above:
0161   //
0162   // 0.836516 -0.224144       0.5   45.9808
0163   //  0.524519  0.591506 -0.612372   137.886
0164   // -0.158494  0.774519  0.612372   144.957
0165   //       0         0         0         1
0166   // - check the translation
0167   CHECK_CLOSE_ABS(center.x(), 45.981, 1e-3);
0168   CHECK_CLOSE_ABS(center.y(), 137.886, 1e-3);
0169   CHECK_CLOSE_ABS(center.z(), 144.957, 1e-3);
0170   // - check the normal
0171   CHECK_CLOSE_ABS(normal.x(), 0.5, 1e-3);
0172   CHECK_CLOSE_ABS(normal.y(), -0.612372, 1e-3);
0173   CHECK_CLOSE_ABS(normal.z(), 0.612372, 1e-3);
0174 
0175   Acts::ObjVisualization3D obj;
0176   Acts::Vector3 origin(0, 0, 0);
0177   Acts::GeometryView3D::drawArrowForward(obj, origin, Acts::Vector3(100, 0, 0),
0178                                          1000, 10, {.color = {255, 0, 0}});
0179   Acts::GeometryView3D::drawArrowForward(obj, origin, Acts::Vector3(0, 100, 0),
0180                                          1000, 10, {.color = {0, 255, 0}});
0181   Acts::GeometryView3D::drawArrowForward(obj, origin, Acts::Vector3(0, 0, 100),
0182                                          1000, 10, {.color = {0, 0, 255}});
0183   Acts::GeometryView3D::drawArrowForward(obj, surface->center(gctx),
0184                                          surface->center(gctx) + 100 * normal,
0185                                          1000, 10, {.color = {0, 255, 0}});
0186   auto surfaces = cache.sensitiveSurfaces;
0187   for (const auto& [k, val] : Acts::enumerate(cache.sensitiveSurfaces)) {
0188     const auto& [el, surf] = val;
0189     Acts::ViewConfig vCfg;
0190     if (k == 0) {
0191       vCfg.color = {0, 255, 0};
0192     } else if (k == 1) {
0193       vCfg.color = {255, 0, 0};
0194     } else if (k == 2) {
0195       vCfg.color = {0, 255, 255};
0196     }
0197     Acts::GeometryView3D::drawSurface(obj, *surf, gctx,
0198                                       Acts::Transform3::Identity(), vCfg);
0199   }
0200 
0201   obj.write("RotatedSurface.obj");
0202 }
0203 
0204 BOOST_AUTO_TEST_CASE(Geant4DetecturSurfaceFactory_elemnet_overwrite) {
0205   // Usually one would use this to extend the Geant4DetectorElement
0206   // for a speicif alignment behavior and overwrite the transform() method.
0207   //
0208   // Here we demonstrate it with an override of the thickness() method
0209   class ExtendedGeant4DetectorElement : public Acts::Geant4DetectorElement {
0210    public:
0211     using Acts::Geant4DetectorElement::Geant4DetectorElement;
0212 
0213     double thickness() const final {
0214       // Overwrite the thickness to be 42
0215       return 42.0;
0216     }
0217   };
0218 
0219   // A factory method for the extended element
0220   auto extendedElementFactory =
0221       [](std::shared_ptr<Acts::Surface> surface,
0222          const G4VPhysicalVolume& g4physVol, const Acts::Transform3& toGlobal,
0223          double thickness) -> std::shared_ptr<Acts::Geant4DetectorElement> {
0224     return std::make_shared<ExtendedGeant4DetectorElement>(
0225         std::move(surface), g4physVol, toGlobal, thickness);
0226   };
0227 
0228   G4Box* worldS = new G4Box("world", 100, 100, 100);
0229   G4LogicalVolume* worldLV = new G4LogicalVolume(worldS, nullptr, "World");
0230 
0231   G4Box* boxS = new G4Box("box", 10, 20, 20);
0232   G4LogicalVolume* boxLV = new G4LogicalVolume(boxS, nullptr, "World");
0233   G4VPhysicalVolume* boxPV = new G4PVPlacement(nullptr, G4ThreeVector(), boxLV,
0234                                                "Box", worldLV, false, 0, true);
0235 
0236   G4Transform3D nominal;
0237 
0238   // Get the box
0239   auto nameSelector =
0240       std::make_shared<Acts::Geant4PhysicalVolumeSelectors::NameSelector>(
0241           std::vector<std::string>{"ox"}, false);
0242 
0243   Acts::Geant4DetectorSurfaceFactory::Cache cache;
0244   Acts::Geant4DetectorSurfaceFactory::Options options;
0245   options.sensitiveSurfaceSelector = nameSelector;
0246 
0247   Acts::Geant4DetectorSurfaceFactory::Config config;
0248   config.detectorElementFactory = extendedElementFactory;
0249   Acts::Geant4DetectorSurfaceFactory factory(config);
0250   factory.construct(cache, nominal, *boxPV, options);
0251 
0252   BOOST_CHECK_EQUAL(cache.sensitiveSurfaces.size(), 1u);
0253   BOOST_CHECK_EQUAL(cache.passiveSurfaces.size(), 0u);
0254 
0255   auto [element, surface] = cache.sensitiveSurfaces.front();
0256   BOOST_CHECK_EQUAL(surface->type(), Acts::Surface::SurfaceType::Plane);
0257 
0258   // Check that the thickness is 42
0259   CHECK_CLOSE_ABS(element->thickness(), 42.0, 1e-6);
0260 }
0261 
0262 BOOST_AUTO_TEST_SUITE_END()