Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-21 08:04:48

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