Skip to content

Commit

Permalink
change module splitter to be unified with ITk module splitter
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Huth committed Sep 2, 2024
1 parent 1764173 commit 60b5903
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 365 deletions.
1 change: 1 addition & 0 deletions Examples/Detectors/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
7 changes: 7 additions & 0 deletions Examples/Detectors/ITkModuleSplitting/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_library(ActsExamplesITkModuleSplitting INTERFACE)
target_include_directories(
ActsExamplesITkModuleSplitting
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)

install(DIRECTORY include/ActsExamples DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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 <algorithm>
#include <array>
#include <cstddef>
#include <sstream>

namespace ActsExamples::ITk {

template <typename detector_element_t, typename element_factory_t>
inline std::vector<std::shared_ptr<const detector_element_t>> splitBarrelModule(
const Acts::GeometryContext& gctx,
const std::shared_ptr<const detector_element_t>& 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<std::shared_ptr<const detector_element_t>> detElements = {};
detElements.reserve(nSegments);

// Get the geometric information
const Acts::Transform3& transform = surface.transform(gctx);
// Determine the new bounds
const std::vector<double> 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<Acts::RectangleBounds>(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 <typename detector_element_t, typename element_factory_t>
inline std::vector<std::shared_ptr<detector_element_t>> splitDiscModule(
const Acts::GeometryContext& gctx,
const std::shared_ptr<detector_element_t>& detElement,
const std::vector<std::pair<double, double>>& 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<std::shared_ptr<const Acts::TGeoDetectorElement>> detElements =
{};
detElements.reserve(nSegments);

// Get the geometric information
double thickness = detElement->thickness();
const Acts::Transform3& transform = surface.transform(gctx);
const std::vector<double> boundsValues = bounds.values();
std::array<double, Acts::AnnulusBounds::eSize> 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<Acts::AnnulusBounds>(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
1 change: 1 addition & 0 deletions Examples/Detectors/TGeoDetector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target_link_libraries(
ActsPluginJson
ActsExamplesFramework
ActsExamplesDetectorGeneric
ActsExamplesITkModuleSplitting
)

install(
Expand Down
113 changes: 18 additions & 95 deletions Examples/Detectors/TGeoDetector/src/TGeoITkModuleSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <algorithm>
#include <array>
#include <cstddef>
#include <sstream>

namespace {}

ActsExamples::TGeoITkModuleSplitter::TGeoITkModuleSplitter(
const ActsExamples::TGeoITkModuleSplitter::Config& cfg,
std::unique_ptr<const Acts::Logger> logger)
Expand Down Expand Up @@ -88,55 +91,16 @@ ActsExamples::TGeoITkModuleSplitter::splitBarrelModule(
const Acts::GeometryContext& gctx,
const std::shared_ptr<const Acts::TGeoDetectorElement>& 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<std::shared_ptr<const Acts::TGeoDetectorElement>> 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<double> 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<Acts::RectangleBounds>(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<const Acts::TGeoDetectorElement>(
identifier, detElement->tgeoNode(), elemTransform, rectBounds,
thickness);
detElements.push_back(std::move(element));
auto factory = [&](const auto& trafo, const auto& bounds) {
return std::make_shared<const Acts::TGeoDetectorElement>(
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
Expand All @@ -146,55 +110,14 @@ ActsExamples::TGeoITkModuleSplitter::splitDiscModule(
const std::shared_ptr<const Acts::TGeoDetectorElement>& detElement,
const std::vector<ActsExamples::TGeoITkModuleSplitter::SplitRange>&
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<const Acts::TGeoDetectorElement>(
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<std::shared_ptr<const Acts::TGeoDetectorElement>> detElements =
{};
detElements.reserve(nSegments);

// Get the geometric information
double thickness = detElement->thickness();
const Acts::Transform3& transform = surface.transform(gctx);
const std::vector<double> boundsValues = bounds.values();
std::array<double, Acts::AnnulusBounds::eSize> 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<Acts::AnnulusBounds>(values);
ACTS_DEBUG(
"New r bounds for node: " + std::to_string(annulusBounds->rMin()) +
", " + std::to_string(annulusBounds->rMax()));

auto element = std::make_shared<const Acts::TGeoDetectorElement>(
identifier, detElement->tgeoNode(), transform, annulusBounds,
thickness);
detElements.push_back(std::move(element));
}
return detElements;
return ITk::splitDiscModule(gctx, detElement, splitRanges, factory, name,
logger());
}
5 changes: 4 additions & 1 deletion Examples/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ else()
endif()

if(ACTS_BUILD_PLUGIN_GEOMODEL)
target_link_libraries(ActsPythonBindings PUBLIC ActsPluginGeoModel)
target_link_libraries(
ActsPythonBindings
PUBLIC ActsPluginGeoModel ActsExamplesITkModuleSplitting
)
target_sources(ActsPythonBindings PRIVATE src/GeoModel.cpp)
else()
target_sources(ActsPythonBindings PRIVATE src/GeoModelStub.cpp)
Expand Down
55 changes: 47 additions & 8 deletions Examples/Python/src/GeoModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
#include "Acts/Plugins/GeoModel/GeoModelDetectorElement.hpp"
#include "Acts/Plugins/GeoModel/GeoModelDetectorElementITk.hpp"
#include "Acts/Plugins/GeoModel/GeoModelDetectorObjectFactory.hpp"
#include "Acts/Plugins/GeoModel/GeoModelModuleSplitter.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 <string>

Expand Down Expand Up @@ -190,12 +193,48 @@ void addGeoModel(Context& ctx) {
&Acts::GeoModelBlueprintCreater::Options::table);
}

py::class_<Acts::GeoModelModuleSplitter>(gm, "GeoModelModuleSplitter")
.def(py::init<std::map<std::string, std::vector<double>>, double,
Acts::Logging::Level>(),
"self"_a, "designs"_a, "tolerance", "level"_a)
.def("split", &Acts::GeoModelModuleSplitter::split, "detElement"_a,
"gctx"_a);
gm.def(
"splitBarrelModule",
[](const Acts::GeometryContext& gctx,
std::shared_ptr<const GeoModelDetectorElement> 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<const GeoModelDetectorElement> detElement,
const std::vector<std::pair<double, double>>& 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_<Acts::GeoModelDetectorElementITk,
std::shared_ptr<Acts::GeoModelDetectorElementITk>>(
Expand Down
Loading

0 comments on commit 60b5903

Please sign in to comment.