File indexing completed on 2025-10-21 08:04:48
0001
0002
0003
0004
0005
0006
0007
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
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
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
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
0166
0167
0168
0169
0170
0171
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
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
0210
0211
0212
0213 class ExtendedGeant4DetectorElement : public Geant4DetectorElement {
0214 public:
0215 using Geant4DetectorElement::Geant4DetectorElement;
0216
0217 double thickness() const final {
0218
0219 return 42.0;
0220 }
0221 };
0222
0223
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
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
0263 CHECK_CLOSE_ABS(element->thickness(), 42.0, 1e-6);
0264 }
0265
0266 BOOST_AUTO_TEST_SUITE_END()
0267
0268 }