From 831b6f11b26339fb1c4002a1427f08cd4883181f Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Wed, 2 Oct 2024 18:05:13 +0200 Subject: [PATCH 1/5] get all changes from feature branch --- Examples/Detectors/CMakeLists.txt | 1 + .../ITkModuleSplitting/CMakeLists.txt | 7 + .../ITkModuleSplitting/ITkModuleSplitting.hpp | 147 ++++++++++++++++++ .../Detectors/TGeoDetector/CMakeLists.txt | 1 + .../src/TGeoITkModuleSplitter.cpp | 113 +++----------- Examples/Python/src/GeoModel.cpp | 66 +++++++- Plugins/GeoModel/CMakeLists.txt | 1 + .../GeoModel/GeoModelDetectorElement.hpp | 16 +- .../GeoModel/GeoModelDetectorElementITk.hpp | 87 +++++++++++ .../GeoModel/src/GeoModelDetectorElement.cpp | 6 + .../src/GeoModelDetectorElementITk.cpp | 131 ++++++++++++++++ .../src/GeoModelDetectorObjectFactory.cpp | 6 + .../UnitTests/Plugins/GeoModel/CMakeLists.txt | 2 + .../GeoModelDetectorElementITkTests.cpp | 90 +++++++++++ 14 files changed, 576 insertions(+), 98 deletions(-) create mode 100644 Examples/Detectors/ITkModuleSplitting/CMakeLists.txt create mode 100644 Examples/Detectors/ITkModuleSplitting/include/ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp create mode 100644 Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp create mode 100644 Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp create mode 100644 Tests/UnitTests/Plugins/GeoModel/GeoModelDetectorElementITkTests.cpp diff --git a/Examples/Detectors/CMakeLists.txt b/Examples/Detectors/CMakeLists.txt index a04112d572c..7e7aed5daed 100644 --- a/Examples/Detectors/CMakeLists.txt +++ b/Examples/Detectors/CMakeLists.txt @@ -4,5 +4,6 @@ add_subdirectory(GenericDetector) add_subdirectory_if(Geant4Detector ACTS_BUILD_EXAMPLES_GEANT4) add_subdirectory(MagneticField) add_subdirectory(TGeoDetector) +add_subdirectory(ITkModuleSplitting) add_subdirectory(TelescopeDetector) add_subdirectory_if(MuonSpectrometerMockupDetector ACTS_BUILD_EXAMPLES_GEANT4) diff --git a/Examples/Detectors/ITkModuleSplitting/CMakeLists.txt b/Examples/Detectors/ITkModuleSplitting/CMakeLists.txt new file mode 100644 index 00000000000..affd7146336 --- /dev/null +++ b/Examples/Detectors/ITkModuleSplitting/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(ActsExamplesITkModuleSplitting INTERFACE) +target_include_directories( + ActsExamplesITkModuleSplitting + INTERFACE $ +) + +install(DIRECTORY include/ActsExamples DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/Examples/Detectors/ITkModuleSplitting/include/ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp b/Examples/Detectors/ITkModuleSplitting/include/ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp new file mode 100644 index 00000000000..591671bffb7 --- /dev/null +++ b/Examples/Detectors/ITkModuleSplitting/include/ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp @@ -0,0 +1,147 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Definitions/Algebra.hpp" +#include "Acts/Surfaces/AnnulusBounds.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Surfaces/SurfaceBounds.hpp" + +#include +#include +#include +#include + +namespace ActsExamples::ITk { + +template +inline std::vector> splitBarrelModule( + const Acts::GeometryContext& gctx, + const std::shared_ptr& detElement, + unsigned int nSegments, const element_factory_t& factory, + const std::string& name, + const Acts::Logger& logger = Acts::getDummyLogger()) { + // Retrieve the surface + const Acts::Surface& surface = detElement->surface(); + const Acts::SurfaceBounds& bounds = surface.bounds(); + if (bounds.type() != Acts::SurfaceBounds::eRectangle || nSegments <= 1u) { + ACTS_WARNING("Invalid splitting config for barrel node: " + << name << "! Node will not be slpit."); + return {detElement}; + } + + // Output container for the submodules + std::vector> detElements = {}; + detElements.reserve(nSegments); + + // Get the geometric information + const Acts::Transform3& transform = surface.transform(gctx); + // Determine the new bounds + const std::vector boundsValues = bounds.values(); + + double lengthX = (boundsValues[Acts::RectangleBounds::eMaxX] - + boundsValues[Acts::RectangleBounds::eMinX]) / + nSegments; + double lengthY = boundsValues[Acts::RectangleBounds::eMaxY] - + boundsValues[Acts::RectangleBounds::eMinY]; + auto rectBounds = + std::make_shared(0.5 * lengthX, 0.5 * lengthY); + // Translation for every subelement + auto localTranslation = Acts::Vector2(-0.5 * lengthX * (nSegments - 1), 0.); + const auto step = Acts::Vector2(lengthX, 0.); + ACTS_DEBUG("Rectangle bounds for new node (half length): " + + std::to_string(rectBounds->halfLengthX()) + ", " + + std::to_string(rectBounds->halfLengthY())); + + for (std::size_t i = 0; i < nSegments; i++) { + Acts::Vector3 globalTranslation = + surface.localToGlobal(gctx, localTranslation, {}) - + transform.translation(); + auto elemTransform = + Acts::Transform3(transform).pretranslate(globalTranslation); + detElements.emplace_back(factory(elemTransform, rectBounds)); + + localTranslation += step; + } + return detElements; +} + +template +inline std::vector> splitDiscModule( + const Acts::GeometryContext& gctx, + const std::shared_ptr& detElement, + const std::vector>& splitRanges, + const element_factory_t& factory, const std::string& name, + const Acts::Logger& logger = Acts::getDummyLogger()) { + // Retrieve the surface + const Acts::Surface& surface = detElement->surface(); + const Acts::SurfaceBounds& bounds = surface.bounds(); + + // Check annulus bounds origin + auto printOrigin = [&](const Acts::Surface& sf) { + Acts::Vector3 discOrigin = + sf.localToGlobal(gctx, Acts::Vector2(0., 0.), Acts::Vector3::Zero()); + std::string out = + "Disc surface origin at: " + std::to_string(discOrigin[0]) + ", " + + std::to_string(discOrigin[1]) + ", " + std::to_string(discOrigin[2]); + return out; + }; + ACTS_DEBUG(printOrigin(surface)); + + if (bounds.type() != Acts::SurfaceBounds::eAnnulus || splitRanges.empty()) { + ACTS_WARNING("Invalid splitting config for disk node: " + << name << "! Node will not be slpit."); + return {detElement}; + } + + auto nSegments = splitRanges.size(); + + // Output container for the submodules + std::vector> detElements = {}; + detElements.reserve(nSegments); + + // Get the geometric information + const Acts::Transform3& transform = surface.transform(gctx); + const std::vector boundsValues = bounds.values(); + std::array values{}; + + std::copy_n(boundsValues.begin(), Acts::AnnulusBounds::eSize, values.begin()); + + for (std::size_t i = 0; i < nSegments; i++) { + if (boundsValues[Acts::AnnulusBounds::eMinR] > splitRanges[i].first || + boundsValues[Acts::AnnulusBounds::eMaxR] < splitRanges[i].second) { + ACTS_WARNING( + "Radius pattern not within the original bounds, node will not be " + "split!"); + return {detElement}; + } + + values[Acts::AnnulusBounds::eMinR] = splitRanges[i].first; + values[Acts::AnnulusBounds::eMaxR] = splitRanges[i].second; + auto annulusBounds = std::make_shared(values); + ACTS_DEBUG( + "New r bounds for node: " + std::to_string(annulusBounds->rMin()) + + ", " + std::to_string(annulusBounds->rMax())); + + auto element = factory(transform, annulusBounds); + detElements.push_back(std::move(element)); + } + return detElements; +} + +} // namespace ActsExamples::ITk diff --git a/Examples/Detectors/TGeoDetector/CMakeLists.txt b/Examples/Detectors/TGeoDetector/CMakeLists.txt index 04d065adaa5..3df36c62f15 100644 --- a/Examples/Detectors/TGeoDetector/CMakeLists.txt +++ b/Examples/Detectors/TGeoDetector/CMakeLists.txt @@ -17,6 +17,7 @@ target_link_libraries( ActsPluginJson ActsExamplesFramework ActsExamplesDetectorGeneric + ActsExamplesITkModuleSplitting ) install( diff --git a/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp b/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp index 0aafbe2d7d7..661bf536caa 100644 --- a/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp +++ b/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp @@ -14,12 +14,15 @@ #include "Acts/Surfaces/RectangleBounds.hpp" #include "Acts/Surfaces/Surface.hpp" #include "Acts/Surfaces/SurfaceBounds.hpp" +#include "ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp" #include #include #include #include +namespace {} + ActsExamples::TGeoITkModuleSplitter::TGeoITkModuleSplitter( const ActsExamples::TGeoITkModuleSplitter::Config& cfg, std::unique_ptr logger) @@ -86,55 +89,16 @@ ActsExamples::TGeoITkModuleSplitter::splitBarrelModule( const Acts::GeometryContext& gctx, const std::shared_ptr& detElement, unsigned int nSegments) const { - // Retrieve the surface - auto identifier = detElement->identifier(); - const Acts::Surface& surface = detElement->surface(); - const Acts::SurfaceBounds& bounds = surface.bounds(); - if (bounds.type() != Acts::SurfaceBounds::eRectangle || nSegments <= 1u) { - ACTS_WARNING("Invalid splitting config for barrel node: " + - std::string(detElement->tgeoNode().GetName()) + - "! Node will not be slpit."); - return {detElement}; - } - - // Output container for the submodules - std::vector> detElements = - {}; - detElements.reserve(nSegments); - - // Get the geometric information - double thickness = detElement->thickness(); - const Acts::Transform3& transform = surface.transform(gctx); - // Determine the new bounds - const std::vector boundsValues = bounds.values(); - double lengthX = (boundsValues[Acts::RectangleBounds::eMaxX] - - boundsValues[Acts::RectangleBounds::eMinX]) / - nSegments; - double lengthY = boundsValues[Acts::RectangleBounds::eMaxY] - - boundsValues[Acts::RectangleBounds::eMinY]; - auto rectBounds = - std::make_shared(0.5 * lengthX, 0.5 * lengthY); - // Translation for every subelement - auto localTranslation = Acts::Vector2(-0.5 * lengthX * (nSegments - 1), 0.); - const auto step = Acts::Vector2(lengthX, 0.); - ACTS_DEBUG("Rectangle bounds for new node (half length): " + - std::to_string(rectBounds->halfLengthX()) + ", " + - std::to_string(rectBounds->halfLengthY())); + auto name = detElement->tgeoNode().GetName(); - for (std::size_t i = 0; i < nSegments; i++) { - Acts::Vector3 globalTranslation = - surface.localToGlobal(gctx, localTranslation, {}) - - transform.translation(); - auto elemTransform = - Acts::Transform3(transform).pretranslate(globalTranslation); - auto element = std::make_shared( - identifier, detElement->tgeoNode(), elemTransform, rectBounds, - thickness); - detElements.push_back(std::move(element)); + auto factory = [&](const auto& trafo, const auto& bounds) { + return std::make_shared( + detElement->identifier(), detElement->tgeoNode(), trafo, bounds, + detElement->thickness()); + }; - localTranslation += step; - } - return detElements; + return ITk::splitBarrelModule(gctx, detElement, nSegments, factory, name, + logger()); } /// If applicable, returns a split detector element @@ -144,55 +108,14 @@ ActsExamples::TGeoITkModuleSplitter::splitDiscModule( const std::shared_ptr& detElement, const std::vector& splitRanges) const { - // Retrieve the surface - auto identifier = detElement->identifier(); - const Acts::Surface& surface = detElement->surface(); - const Acts::SurfaceBounds& bounds = surface.bounds(); + auto name = detElement->tgeoNode().GetName(); - // Check annulus bounds origin - auto printOrigin = [&](const Acts::Surface& sf) { - Acts::Vector3 discOrigin = - sf.localToGlobal(gctx, Acts::Vector2(0., 0.), Acts::Vector3::Zero()); - std::string out = - "Disc surface origin at: " + std::to_string(discOrigin[0]) + ", " + - std::to_string(discOrigin[1]) + ", " + std::to_string(discOrigin[2]); - return out; + auto factory = [&](const auto& trafo, const auto& bounds) { + return std::make_shared( + detElement->identifier(), detElement->tgeoNode(), trafo, bounds, + detElement->thickness()); }; - ACTS_DEBUG(printOrigin(surface)); - if (bounds.type() != Acts::SurfaceBounds::eAnnulus || splitRanges.empty()) { - ACTS_WARNING("Invalid splitting config for disk node: " + - std::string(detElement->tgeoNode().GetName()) + - "! Node will not be slpit."); - return {detElement}; - } - - auto nSegments = splitRanges.size(); - - // Output container for the submodules - std::vector> detElements = - {}; - detElements.reserve(nSegments); - - // Get the geometric information - double thickness = detElement->thickness(); - const Acts::Transform3& transform = surface.transform(gctx); - const std::vector boundsValues = bounds.values(); - std::array values{}; - std::copy_n(boundsValues.begin(), Acts::AnnulusBounds::eSize, values.begin()); - - for (std::size_t i = 0; i < nSegments; i++) { - values[Acts::AnnulusBounds::eMinR] = splitRanges[i].first; - values[Acts::AnnulusBounds::eMaxR] = splitRanges[i].second; - auto annulusBounds = std::make_shared(values); - ACTS_DEBUG( - "New r bounds for node: " + std::to_string(annulusBounds->rMin()) + - ", " + std::to_string(annulusBounds->rMax())); - - auto element = std::make_shared( - identifier, detElement->tgeoNode(), transform, annulusBounds, - thickness); - detElements.push_back(std::move(element)); - } - return detElements; + return ITk::splitDiscModule(gctx, detElement, splitRanges, factory, name, + logger()); } diff --git a/Examples/Python/src/GeoModel.cpp b/Examples/Python/src/GeoModel.cpp index 162062aa970..eb9b4406808 100644 --- a/Examples/Python/src/GeoModel.cpp +++ b/Examples/Python/src/GeoModel.cpp @@ -17,12 +17,17 @@ #include "Acts/Plugins/GeoModel/GeoModelBlueprintCreater.hpp" #include "Acts/Plugins/GeoModel/GeoModelConverters.hpp" #include "Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp" +#include "Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp" #include "Acts/Plugins/GeoModel/GeoModelDetectorObjectFactory.hpp" #include "Acts/Plugins/GeoModel/GeoModelReader.hpp" #include "Acts/Plugins/GeoModel/GeoModelTree.hpp" #include "Acts/Plugins/GeoModel/IGeoShapeConverter.hpp" #include "Acts/Plugins/Python/Utilities.hpp" -#include "Acts/Surfaces/Surface.hpp" +#include "Acts/Surfaces/AnnulusBounds.hpp" +#include "Acts/Surfaces/DiscSurface.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "ActsExamples/ITkModuleSplitting/ITkModuleSplitting.hpp" #include @@ -46,7 +51,13 @@ void addGeoModel(Context& ctx) { py::class_>( - gm, "GeoModelDetectorElement"); + gm, "GeoModelDetectorElement") + .def("logVolName", &Acts::GeoModelDetectorElement::logVolName) + .def("databaseEntryName", + &Acts::GeoModelDetectorElement::databaseEntryName) + .def("surface", [](Acts::GeoModelDetectorElement self) { + return self.surface().getSharedPtr(); + }); // Shape converters { @@ -184,5 +195,56 @@ void addGeoModel(Context& ctx) { .def_readwrite("table", &Acts::GeoModelBlueprintCreater::Options::table); } + + gm.def( + "splitBarrelModule", + [](const Acts::GeometryContext& gctx, + std::shared_ptr detElement, + unsigned nSegments, Acts::Logging::Level logLevel) { + auto logger = Acts::getDefaultLogger("ITkSlitBarrel", logLevel); + auto name = detElement->databaseEntryName(); + + auto factory = [&](const auto& trafo, const auto& bounds) { + return Acts::GeoModelDetectorElement::createDetectorElement< + Acts::PlaneSurface, Acts::RectangleBounds>( + detElement->physicalVolume(), bounds, trafo, + detElement->thickness()); + }; + + return ActsExamples::ITk::splitBarrelModule(gctx, detElement, nSegments, + factory, name, *logger); + }, + "gxtx"_a, "detElement"_a, "nSegments"_a, + "logLevel"_a = Acts::Logging::INFO); + + gm.def( + "splitDiscModule", + [](const Acts::GeometryContext& gctx, + std::shared_ptr detElement, + const std::vector>& patterns, + Acts::Logging::Level logLevel) { + auto logger = Acts::getDefaultLogger("ITkSlitBarrel", logLevel); + auto name = detElement->databaseEntryName(); + + auto factory = [&](const auto& trafo, const auto& bounds) { + return Acts::GeoModelDetectorElement::createDetectorElement< + Acts::DiscSurface, Acts::AnnulusBounds>( + detElement->physicalVolume(), bounds, trafo, + detElement->thickness()); + }; + + return ActsExamples::ITk::splitDiscModule(gctx, detElement, patterns, + factory, name, *logger); + }, + "gxtx"_a, "detElement"_a, "splitRanges"_a, + "logLevel"_a = Acts::Logging::INFO); + + py::class_>( + gm, "GeoModelDetectorElementITk") + .def("surface", [](Acts::GeoModelDetectorElementITk& self) { + return self.surface().getSharedPtr(); + }); + gm.def("convertToItk", &GeoModelDetectorElementITk::convertFromGeomodel); } } // namespace Acts::Python diff --git a/Plugins/GeoModel/CMakeLists.txt b/Plugins/GeoModel/CMakeLists.txt index 05c4c9e8148..90a672a012b 100644 --- a/Plugins/GeoModel/CMakeLists.txt +++ b/Plugins/GeoModel/CMakeLists.txt @@ -20,6 +20,7 @@ add_library( src/detail/GeoModelBinningHelper.cpp src/detail/GeoModelExtentHelper.cpp src/detail/GeoUnionDoubleTrdConverter.cpp + src/GeoModelDetectorElementITk.cpp ) target_include_directories( ActsPluginGeoModel diff --git a/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp index eed4d2f62a3..ab1cb025a4a 100644 --- a/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp +++ b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp @@ -87,7 +87,18 @@ class GeoModelDetectorElement : public DetectorElementBase { /// @return to the Geant4 physical volume PVConstLink physicalVolume() const; - private: + /// Get the name of the logical volume + const std::string& logVolName() const; + + /// Get the string identifier of the corresponding database entry + /// Note: This is not by defnitition a unique identifier, there can be + /// several detector elements created from a single database entry. + const std::string& databaseEntryName() const { return m_entryName; }; + + /// Set the corresponding database entry string + void setDatabaseEntryName(const std::string& n) { m_entryName = n; }; + + protected: /// Attach a surface /// /// @param surface The surface to attach @@ -95,6 +106,9 @@ class GeoModelDetectorElement : public DetectorElementBase { m_surface = std::move(surface); } + private: + std::string m_entryName; + /// The GeoModel full physical volume PVConstLink m_geoPhysVol{nullptr}; /// The surface diff --git a/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp new file mode 100644 index 00000000000..31cce3360e9 --- /dev/null +++ b/Plugins/GeoModel/include/Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp @@ -0,0 +1,87 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#pragma once + +#include "Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp" +#include "Acts/Utilities/MultiIndex.hpp" + +namespace Acts { + +class ITkIdentifier { + Acts::MultiIndex m_identifier{}; + + public: + ITkIdentifier(int hardware, int barrelEndcap, int layerWheel, int etaModule, + int phiModule, int side); + + /// Access the hardware specifier (pixel=0, strip=1) + int hardware() const; + + /// Access the barrel-endcap specifier (-2,0,2) + int barrelEndcap() const; + + /// Access the layer specifier + int layerWheel() const; + + /// Access the phi module specifier + int phiModule() const; + + /// Access the eta module specifier + int etaModule() const; + + /// Access the side (for double sided strip modules) + int side() const; + + /// A unique identifier that represents the combination of specifiers + std::size_t value() const; +}; + +std::ostream& operator<<(std::ostream& os, const ITkIdentifier& id); + +/// Specialization of the GeoModelDetectorElement for the ITk. This allows +/// mapping of Acts::GeometryIdentifiers to ITk modules in a straight-forward +/// way. +class GeoModelDetectorElementITk : public GeoModelDetectorElement { + public: + GeoModelDetectorElementITk(const PVConstLink& geoPhysVol, + std::shared_ptr surface, + const Transform3& sfTransform, + ActsScalar thickness, int hardware, + int barrelEndcap, int layerWheel, int etaModule, + int phiModule, int side) + : GeoModelDetectorElement(geoPhysVol, std::move(surface), sfTransform, + thickness), + m_identifier(hardware, barrelEndcap, layerWheel, etaModule, phiModule, + side) {} + + ITkIdentifier identifier() const { return m_identifier; } + + /// Convert a GeoModelDetectorElement to a GeoModelDetectorElementITk + /// A new surface is constructed. + /// @todo Remove redundancy in signature once plugin is refactored + static std::tuple, + std::shared_ptr> + convertFromGeomodel(std::shared_ptr detEl, + std::shared_ptr srf, const GeometryContext& gctx, + int hardware, int barrelEndcap, int layerWheel, + int etaModule, int phiModule, int side); + + private: + ITkIdentifier m_identifier; +}; + +} // namespace Acts diff --git a/Plugins/GeoModel/src/GeoModelDetectorElement.cpp b/Plugins/GeoModel/src/GeoModelDetectorElement.cpp index 81526fc7693..279a7b802b5 100644 --- a/Plugins/GeoModel/src/GeoModelDetectorElement.cpp +++ b/Plugins/GeoModel/src/GeoModelDetectorElement.cpp @@ -12,6 +12,8 @@ #include +#include + Acts::GeoModelDetectorElement::GeoModelDetectorElement( PVConstLink geoPhysVol, std::shared_ptr surface, const Transform3& sfTransform, ActsScalar thickness) @@ -40,3 +42,7 @@ Acts::ActsScalar Acts::GeoModelDetectorElement::thickness() const { PVConstLink Acts::GeoModelDetectorElement::physicalVolume() const { return m_geoPhysVol; } + +const std::string& Acts::GeoModelDetectorElement::logVolName() const { + return m_geoPhysVol->getLogVol()->getName(); +} diff --git a/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp b/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp new file mode 100644 index 00000000000..56fc20958a7 --- /dev/null +++ b/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp @@ -0,0 +1,131 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include "Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp" + +#include "Acts/Surfaces/AnnulusBounds.hpp" +#include "Acts/Surfaces/DiscSurface.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" + +#include + +namespace Acts { + +// Mapping between the barrel-endcap identifier and its unsigned representation +constexpr static std::array, 3> s_barrelEndcapMap{ + {{0, 0}, {1, 2}, {2, -2}}}; + +Acts::ITkIdentifier::ITkIdentifier(int hardware, int barrelEndcap, + int layerWheel, int etaModule, int phiModule, + int side) { + assert((hardware == 0) || (hardware == 1)); + assert((barrelEndcap == 2) || (barrelEndcap == -2) || (barrelEndcap == 0)); + assert(layerWheel >= 0); + assert(phiModule >= 0); + assert((side == 0) || (side == 1)); + + m_identifier.set(0, hardware); + + auto found = std::ranges::find(s_barrelEndcapMap, barrelEndcap, + &std::pair::second); + if (found == s_barrelEndcapMap.end()) { + throw std::invalid_argument("Invalid barrel-endcap specifier"); + } + m_identifier.set(1, found->first); + m_identifier.set(2, layerWheel); + m_identifier.set(3, etaModule < 0); + m_identifier.set(4, std::abs(etaModule)); + m_identifier.set(5, phiModule); + m_identifier.set(6, side); +} + +int Acts::ITkIdentifier::hardware() const { + return m_identifier.level(0); +} + +int Acts::ITkIdentifier::barrelEndcap() const { + auto found = std::ranges::find(s_barrelEndcapMap, m_identifier.level(1), + &std::pair::first); + if (found == s_barrelEndcapMap.end()) { + throw std::invalid_argument("Invalid barrel-endcap specifier"); + } + return found->second; +} + +int Acts::ITkIdentifier::layerWheel() const { + return m_identifier.level(2); +} + +int Acts::ITkIdentifier::etaModule() const { + int sign = (m_identifier.level(3) == 0) ? 1 : -1; + return sign * m_identifier.level(4); +} + +int Acts::ITkIdentifier::phiModule() const { + return m_identifier.level(5); +} + +int Acts::ITkIdentifier::side() const { + return m_identifier.level(6); +} + +std::size_t Acts::ITkIdentifier::value() const { + return m_identifier.value(); +} + +std::ostream &operator<<(std::ostream &os, const ITkIdentifier &id) { + os << "(hw: " << id.hardware() << ", be: " << id.barrelEndcap() + << ", lw: " << id.layerWheel() << ", em: " << id.etaModule() + << ", pm: " << id.phiModule() << ", sd: " << id.side() << ")"; + return os; +} + +std::tuple, + std::shared_ptr> +Acts::GeoModelDetectorElementITk::convertFromGeomodel( + std::shared_ptr detEl, + std::shared_ptr srf, const GeometryContext &gctx, int hardware, + int barrelEndcap, int layerWheel, int etaModule, int phiModule, int side) { + auto helper = [&]() { + auto bounds = std::make_shared( + dynamic_cast(srf->bounds())); + + auto itkEl = std::make_shared( + detEl->physicalVolume(), nullptr, detEl->transform(gctx), + detEl->thickness(), hardware, barrelEndcap, layerWheel, etaModule, + phiModule, side); + auto surface = Surface::makeShared(bounds, *itkEl.get()); + + itkEl->attachSurface(surface); + itkEl->setDatabaseEntryName(detEl->databaseEntryName()); + return std::pair{itkEl, surface}; + }; + + if (srf->type() == Acts::Surface::Plane && + srf->bounds().type() == Acts::SurfaceBounds::eRectangle) { + return helper.operator()(); + } + if (srf->type() == Acts::Surface::Disc && + srf->bounds().type() == Acts::SurfaceBounds::eAnnulus) { + return helper.operator()(); + } + + throw std::runtime_error( + "Only Plane+Rectangle and Disc+Annulus are converted for the ITk"); +} + +} // namespace Acts diff --git a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp index 91580a7bfda..fe1b2e84293 100644 --- a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp +++ b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp @@ -184,6 +184,12 @@ void Acts::GeoModelDetectorObjectFactory::convertFpv( const Transform3 &transform = fpv->getAbsoluteTransform(); convertSensitive(fpv, transform, cache.sensitiveSurfaces); } + + // Set the corresponding database entry name to all sensitive surfaces + for (auto i = prevSize; i < cache.sensitiveSurfaces.size(); ++i) { + auto &[detEl, _] = cache.sensitiveSurfaces[i]; + detEl->setDatabaseEntryName(name); + } } // function to determine if object fits query bool Acts::GeoModelDetectorObjectFactory::matches(const std::string &name, diff --git a/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt b/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt index 61711992918..25c3afd811b 100644 --- a/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt @@ -3,7 +3,9 @@ set(unittest_extra_libraries ActsPluginGeoModel) add_unittest(GeoModelDetectorElement GeoModelDetectorElementTests.cpp) add_unittest(GeoBoxConverter GeoBoxConverterTests.cpp) add_unittest(GeoTrdConverter GeoTrdConverterTests.cpp) +add_unittest(GeoModelModuleSplitter GeoModelModuleSplitterTests.cpp) add_unittest(GeoDetectorObjectTest GeoDetectorObjectTest.cpp) +add_unittest(GeoModelDetectorElementITk GeoModelDetectorElementITkTests.cpp) add_unittest(GeoPolyConverterTests GeoPolyConverterTests.cpp) add_unittest(GeoTrdToVolumeTest GeoTrdToVolumeTests.cpp) add_unittest(GeoBoxToVolumeTest GeoBoxToVolumeTest.cpp) diff --git a/Tests/UnitTests/Plugins/GeoModel/GeoModelDetectorElementITkTests.cpp b/Tests/UnitTests/Plugins/GeoModel/GeoModelDetectorElementITkTests.cpp new file mode 100644 index 00000000000..0c945ebb6dd --- /dev/null +++ b/Tests/UnitTests/Plugins/GeoModel/GeoModelDetectorElementITkTests.cpp @@ -0,0 +1,90 @@ +// This file is part of the ACTS project. +// +// Copyright (C) 2016 CERN for the benefit of the ACTS project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// This file is part of the Acts project. +// +// Copyright (C) 2024 CERN for the benefit of the Acts project +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include "Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp" +#include "Acts/Surfaces/PlaneSurface.hpp" +#include "Acts/Surfaces/RectangleBounds.hpp" +#include "Acts/Surfaces/Surface.hpp" + +#include +#include +#include +#include + +BOOST_AUTO_TEST_SUITE(GeoModelPlugin) + +BOOST_AUTO_TEST_CASE(ITkIdentifierTests) { + auto test = [](int hw, int bec, int lw, int em, int pm, int side) { + Acts::ITkIdentifier id(hw, bec, lw, em, pm, side); + BOOST_CHECK_EQUAL(id.hardware(), hw); + BOOST_CHECK_EQUAL(id.barrelEndcap(), bec); + BOOST_CHECK_EQUAL(id.layerWheel(), lw); + BOOST_CHECK_EQUAL(id.etaModule(), em); + BOOST_CHECK_EQUAL(id.phiModule(), pm); + BOOST_CHECK_EQUAL(id.side(), side); + }; + + for (int hw : {0, 1}) { + for (int bec : {-2, 0, 2}) { + for (int lw : {0, 10}) { + for (int em : {-10, 0, 10}) { + for (int pm : {10, 0}) { + for (int side : {0, 1}) { + test(hw, bec, lw, em, pm, side); + } + } + } + } + } + } +} + +BOOST_AUTO_TEST_CASE(GeoModelDetectorElementConstruction) { + Acts::GeometryContext gctx{}; + + auto material = GeoIntrusivePtr(new GeoMaterial("Material", 1.0)); + auto box = GeoIntrusivePtr(new GeoBox(100, 200, 2)); + auto log = GeoIntrusivePtr(new GeoLogVol("LogVolumeXY", box, material)); + auto fphys = GeoIntrusivePtr(new GeoFullPhysVol(log)); + auto rBounds = std::make_shared(100, 200); + + auto element = + Acts::GeoModelDetectorElement::createDetectorElement( + fphys, rBounds, Acts::Transform3::Identity(), 2.0); + + const int hardware = 0, barrelEndcap = -2, layerWheel = 100, phiModule = 200, + etaModule = 300, side = 1; + + auto [itkElement, _] = Acts::GeoModelDetectorElementITk::convertFromGeomodel( + element, element->surface().getSharedPtr(), gctx, hardware, barrelEndcap, + layerWheel, etaModule, phiModule, side); + + BOOST_CHECK_EQUAL(element->surface().type(), itkElement->surface().type()); + BOOST_CHECK_EQUAL(element->surface().bounds().type(), + itkElement->surface().bounds().type()); + BOOST_CHECK_NE(element->surface().associatedDetectorElement(), + itkElement->surface().associatedDetectorElement()); + BOOST_CHECK_EQUAL(itkElement->identifier().barrelEndcap(), barrelEndcap); + BOOST_CHECK_EQUAL(itkElement->identifier().hardware(), hardware); + BOOST_CHECK_EQUAL(itkElement->identifier().layerWheel(), layerWheel); + BOOST_CHECK_EQUAL(itkElement->identifier().phiModule(), phiModule); + BOOST_CHECK_EQUAL(itkElement->identifier().etaModule(), etaModule); + BOOST_CHECK_EQUAL(itkElement->identifier().side(), side); +} + +BOOST_AUTO_TEST_SUITE_END() From c8d15eeb237b127d08b5a001d1a055a950940f36 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Mon, 7 Oct 2024 14:31:14 +0200 Subject: [PATCH 2/5] add missing prevSize --- Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp index fe1b2e84293..d6f1d72d614 100644 --- a/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp +++ b/Plugins/GeoModel/src/GeoModelDetectorObjectFactory.cpp @@ -150,6 +150,7 @@ bool Acts::GeoModelDetectorObjectFactory::convertBox(std::string name) { void Acts::GeoModelDetectorObjectFactory::convertFpv( const std::string &name, GeoFullPhysVol *fpv, Cache &cache, const GeometryContext &gctx) { + const auto prevSize = cache.sensitiveSurfaces.size(); PVConstLink physVol{fpv}; // get children From c1b43eb6c44efa4691f62c0e8b99f13b05238075 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Mon, 7 Oct 2024 14:36:22 +0200 Subject: [PATCH 3/5] remove cmake for not exisisting test --- Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt b/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt index 25c3afd811b..a09476dae5b 100644 --- a/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt +++ b/Tests/UnitTests/Plugins/GeoModel/CMakeLists.txt @@ -3,7 +3,6 @@ set(unittest_extra_libraries ActsPluginGeoModel) add_unittest(GeoModelDetectorElement GeoModelDetectorElementTests.cpp) add_unittest(GeoBoxConverter GeoBoxConverterTests.cpp) add_unittest(GeoTrdConverter GeoTrdConverterTests.cpp) -add_unittest(GeoModelModuleSplitter GeoModelModuleSplitterTests.cpp) add_unittest(GeoDetectorObjectTest GeoDetectorObjectTest.cpp) add_unittest(GeoModelDetectorElementITk GeoModelDetectorElementITkTests.cpp) add_unittest(GeoPolyConverterTests GeoPolyConverterTests.cpp) From 070e350d573e854f7d4c24aff38415293b7dc0d2 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Mon, 7 Oct 2024 21:33:02 +0200 Subject: [PATCH 4/5] clang tidy --- Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp b/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp index 56fc20958a7..f671386dec6 100644 --- a/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp +++ b/Plugins/GeoModel/src/GeoModelDetectorElementITk.cpp @@ -47,7 +47,7 @@ Acts::ITkIdentifier::ITkIdentifier(int hardware, int barrelEndcap, } m_identifier.set(1, found->first); m_identifier.set(2, layerWheel); - m_identifier.set(3, etaModule < 0); + m_identifier.set(3, static_cast(etaModule < 0)); m_identifier.set(4, std::abs(etaModule)); m_identifier.set(5, phiModule); m_identifier.set(6, side); From eb65b03ae64836f4949b224bc45a05bf60db1c0b Mon Sep 17 00:00:00 2001 From: Benjamin Huth <37871400+benjaminhuth@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:32:50 +0200 Subject: [PATCH 5/5] Update Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp Co-authored-by: Paul Gessinger --- Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp b/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp index 661bf536caa..42bbbd9c882 100644 --- a/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp +++ b/Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp @@ -21,8 +21,6 @@ #include #include -namespace {} - ActsExamples::TGeoITkModuleSplitter::TGeoITkModuleSplitter( const ActsExamples::TGeoITkModuleSplitter::Config& cfg, std::unique_ptr logger)