Skip to content

Commit

Permalink
feat: use blueprint to generate cylindrical detector (#2557)
Browse files Browse the repository at this point in the history
This PR follows #2550 and introduces an automated conversion from blueprint to a cylindrical detector builder.

- it adds the auto-translation of blueprint to cylindrical container builder 
- plus unit test (yes, it's boiler plate blueprint building, but the code for detector building is now really concise)
- it adds the graphical representation of `root volume finder builder` and `geo id generator`:

<img width="750" alt="Screenshot 2023-10-20 at 16 55 51" src="https://github.com/acts-project/acts/assets/26623879/5ee546db-9581-47be-82fe-32212a08cb9b">
  • Loading branch information
asalzburger committed Oct 25, 2023
1 parent 6df0704 commit 33e36ea
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 11 deletions.
24 changes: 24 additions & 0 deletions Core/include/Acts/Detector/Blueprint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
namespace Acts {
namespace Experimental {

class IGeometryIdGenerator;
class IInternalStructureBuilder;
class IRootVolumeFinderBuilder;

/// A Blueprint is an instruction tree that allows you to defina a tree sequence
/// of volume building using the provided tools.
Expand Down Expand Up @@ -87,6 +89,12 @@ struct Node final {
std::vector<std::unique_ptr<Node>> children = {};
/// Branch definition binning
std::vector<BinningValue> binning = {};

/// Builders and helper tools that can be attached
std::shared_ptr<const IRootVolumeFinderBuilder> rootVolumeFinderBuilder =
nullptr;
/// Geometry id generator
std::shared_ptr<const IGeometryIdGenerator> geoIdGenerator = nullptr;
/// Internal structure builder - for leaf nodes
std::shared_ptr<const IInternalStructureBuilder> internalsBuilder = nullptr;

Expand Down Expand Up @@ -144,6 +152,22 @@ struct Node final {
ss << name << " -> " << name + "_int"
<< ";" << '\n';
}

if (geoIdGenerator != nullptr) {
ss << name + "_geoID"
<< " [shape=\"note\";style=\"filled\";fillcolor=\"azure\"];" << '\n';
ss << name << " -> " << name + "_geoID"
<< ";" << '\n';
}

if (rootVolumeFinderBuilder != nullptr) {
ss << name + "_roots"
<< " [shape=\"Msquare\";style=\"filled\";fillcolor=\"darkkhaki\"];"
<< '\n';
ss << name << " -> " << name + "_roots"
<< ";" << '\n';
}

if (isRoot()) {
ss << "}" << '\n';
}
Expand Down
28 changes: 26 additions & 2 deletions Core/include/Acts/Detector/CylindricalContainerBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include "Acts/Detector/Blueprint.hpp"
#include "Acts/Detector/DetectorComponents.hpp"
#include "Acts/Detector/interface/IDetectorComponentBuilder.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
Expand All @@ -30,6 +31,10 @@ class IGeometryIdGenerator;
/// and allows for DetectorVolume attachment in z/r/phi, such as wrapping
/// of bevelled cylinder objects in z/r
///
/// There exists an option to create this container builder (recursively)
/// from a blueprint tree, which attempts to fill in the gap volumes
/// accordingly.
///
/// @note the builder expects a fully consistent set of sub volume builders
/// that will be executed in a chain
///
Expand All @@ -45,7 +50,8 @@ class CylindricalContainerBuilder : public IDetectorComponentBuilder {
/// Binning prescription of attachment
std::vector<BinningValue> binning = {};
/// The root volume finder
std::shared_ptr<IRootVolumeFinderBuilder> rootVolumeFinderBuilder = nullptr;
std::shared_ptr<const IRootVolumeFinderBuilder> rootVolumeFinderBuilder =
nullptr;
/// The geometry id generator
std::shared_ptr<const IGeometryIdGenerator> geoIdGenerator = nullptr;
/// An eventual reverse geometry id generation
Expand All @@ -54,7 +60,7 @@ class CylindricalContainerBuilder : public IDetectorComponentBuilder {
std::string auxiliary = "";
};

/// Constructor with configuration arguments
/// Constructor with configuration struct
///
/// @param cfg is the configuration struct
/// @param logger logging instance for screen output
Expand All @@ -63,6 +69,24 @@ class CylindricalContainerBuilder : public IDetectorComponentBuilder {
std::unique_ptr<const Logger> logger =
getDefaultLogger("CylindricalContainerBuilder", Logging::INFO));

/// Constructor from blueprint and logging level
///
/// It will create recursively the builders of sub volumes
///
/// @param bpNode is the entry blue print node
/// @param logLevel is the logging output level for the builder tools
///
/// @note no checking is being done on consistency of the blueprint,
/// it is assumed it has passed first through gap filling via the
/// blueprint helper.
///
/// @note that the naming of the builders is taken from the bluprint nodes
///
/// @return a cylindrical container builder representing this blueprint
CylindricalContainerBuilder(
const Acts::Experimental::Blueprint::Node& bpNode,
Acts::Logging::Level logLevel = Acts::Logging::INFO);

/// The final implementation of the cylindrical container builder
///
/// @param gctx The geometry context for this call
Expand Down
2 changes: 0 additions & 2 deletions Core/include/Acts/Detector/DetectorVolumeBuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@

#include "Acts/Detector/DetectorComponents.hpp"
#include "Acts/Detector/interface/IDetectorComponentBuilder.hpp"
#include "Acts/Detector/interface/IExternalStructureBuilder.hpp"
#include "Acts/Detector/interface/IInternalStructureBuilder.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Utilities/Logger.hpp"

Expand Down
46 changes: 46 additions & 0 deletions Core/src/Detector/CylindricalContainerBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "Acts/Detector/CylindricalContainerBuilder.hpp"

#include "Acts/Detector/DetectorComponents.hpp"
#include "Acts/Detector/DetectorVolumeBuilder.hpp"
#include "Acts/Detector/VolumeStructureBuilder.hpp"
#include "Acts/Detector/detail/CylindricalDetectorHelper.hpp"
#include "Acts/Detector/interface/IGeometryIdGenerator.hpp"
#include "Acts/Detector/interface/IRootVolumeFinderBuilder.hpp"
Expand Down Expand Up @@ -114,6 +116,50 @@ Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
}
}

Acts::Experimental::CylindricalContainerBuilder::CylindricalContainerBuilder(
const Acts::Experimental::Blueprint::Node& bpNode,
Acts::Logging::Level logLevel)
: IDetectorComponentBuilder(),
m_logger(getDefaultLogger(bpNode.name + "_cont", logLevel)) {
if (bpNode.boundsType != VolumeBounds::BoundsType::eCylinder) {
throw std::invalid_argument(
"CylindricalContainerBuilder: boundary type must be cylinder - for "
"building from a blueprint node.");
}

std::vector<std::shared_ptr<const IDetectorComponentBuilder>> builders;
for (const auto& child : bpNode.children) {
if (child->isLeaf()) {
// Volume structure
VolumeStructureBuilder::Config vsCfg;
vsCfg.transform = child->transform;
vsCfg.boundsType = child->boundsType;
vsCfg.boundValues = child->boundaryValues;
vsCfg.auxiliary = "*** acts auto-generated shape builder ***";
auto vsBuilder = std::make_shared<VolumeStructureBuilder>(
vsCfg, getDefaultLogger(child->name + "_shape", logLevel));
// Detector volume builder
DetectorVolumeBuilder::Config dvCfg;
dvCfg.name = child->name;
dvCfg.externalsBuilder = vsBuilder;
dvCfg.internalsBuilder = child->internalsBuilder;
dvCfg.auxiliary = "*** acts auto-generated volume builder ***";
// Add the builder
m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
dvCfg, getDefaultLogger(child->name, logLevel)));
} else {
// This evokes the recursive stepping down the tree
m_cfg.builders.push_back(
std::make_shared<CylindricalContainerBuilder>(*child, logLevel));
}
}

m_cfg.binning = bpNode.binning;
m_cfg.auxiliary = "*** acts auto-generated from proxy ***";
m_cfg.geoIdGenerator = bpNode.geoIdGenerator;
m_cfg.rootVolumeFinderBuilder = bpNode.rootVolumeFinderBuilder;
}

Acts::Experimental::DetectorComponent
Acts::Experimental::CylindricalContainerBuilder::construct(
const GeometryContext& gctx) const {
Expand Down
2 changes: 1 addition & 1 deletion Core/src/Detector/DetectorVolumeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Acts::Experimental::DetectorVolumeBuilder::construct(
if (not m_cfg.auxiliary.empty()) {
ACTS_DEBUG(m_cfg.auxiliary);
}
ACTS_DEBUG("Building a volume with name " << m_cfg.name);
ACTS_DEBUG("Building a volume with name '" << m_cfg.name << "'.");

// Get transform and bounds from the volume
auto [transform, bounds, portalGenerator] =
Expand Down
15 changes: 13 additions & 2 deletions Core/src/Detector/VolumeStructureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Acts/Geometry/TrapezoidVolumeBounds.hpp"
#include "Acts/Utilities/Enumerate.hpp"
#include "Acts/Utilities/Helpers.hpp"
#include "Acts/Utilities/StringHelpers.hpp"

Acts::Experimental::VolumeStructureBuilder::VolumeStructureBuilder(
const Acts::Experimental::VolumeStructureBuilder::Config& cfg,
Expand Down Expand Up @@ -140,6 +141,10 @@ Acts::Experimental::VolumeStructureBuilder::construct(
boundValues.push_back(M_PI);
boundValues.push_back(0.);
}
ACTS_VERBOSE(" - cylindrical shape with [iR, oR, hZ, sPhi, mPhi] = "
<< boundValues[0] << ", " << boundValues[1] << ", "
<< boundValues[2] << ", " << boundValues[3] << ", "
<< boundValues[4]);
auto bArray =
to_array<CylinderVolumeBounds::BoundValues::eSize>(boundValues);
volumeBounds = std::make_unique<CylinderVolumeBounds>(bArray);
Expand Down Expand Up @@ -175,8 +180,14 @@ Acts::Experimental::VolumeStructureBuilder::construct(
default:
break;
}

Transform3 fTransform = m_cfg.transform * eTransform;
ACTS_VERBOSE(" - translation: " << Acts::toString(fTransform.translation()));
if (not fTransform.rotation().isApprox(
Acts::Transform3::Identity().rotation())) {
ACTS_VERBOSE(" - rotation: " << Acts::toString(fTransform.rotation()));
}
// Return the transform, the volume bounds, and some default portal
// generators
return {Transform3(m_cfg.transform * eTransform), std::move(volumeBounds),
defaultPortalGenerator()};
return {fTransform, std::move(volumeBounds), defaultPortalGenerator()};
}
10 changes: 6 additions & 4 deletions Core/src/Detector/detail/BlueprintHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,31 +97,33 @@ void Acts::Experimental::detail::BlueprintHelper::fillGaps(
unsigned int igap = 0;
for (auto& child : node.children) {
auto [neg, pos] = cylEndpointsZ(*child);
if ((neg - negC).norm() > s_onSurfaceTolerance) {
ActsScalar gapSpan = (neg - negC).norm();
if (gapSpan > s_onSurfaceTolerance) {
// Fill a gap node
auto gapName = node.name + "_gap_" + std::to_string(igap);
auto gapTransform = Transform3::Identity();
gapTransform.rotate(node.transform.rotation());
gapTransform.translate(0.5 * (neg + negC));
auto gap = std::make_unique<Blueprint::Node>(
gapName, gapTransform, VolumeBounds::eCylinder,
std::vector<ActsScalar>{cInnerR, cOuterR, negC.z() - neg.z()});
std::vector<ActsScalar>{cInnerR, cOuterR, 0.5 * gapSpan});
gaps.push_back(std::move(gap));
++igap;
}
// Set to new current negative value
negC = pos;
}
// Check if a last one needs to be filled
if ((negC - posC).norm() > s_onSurfaceTolerance) {
ActsScalar gapSpan = (negC - posC).norm();
if (gapSpan > s_onSurfaceTolerance) {
// Fill a gap node
auto gapName = node.name + "_gap_" + std::to_string(igap);
auto gapTransform = Transform3::Identity();
gapTransform.rotate(node.transform.rotation());
gapTransform.translate(0.5 * (negC + posC));
auto gap = std::make_unique<Blueprint::Node>(
gapName, gapTransform, VolumeBounds::eCylinder,
std::vector<ActsScalar>{cInnerR, cOuterR, posC.z() - negC.z()});
std::vector<ActsScalar>{cInnerR, cOuterR, 0.5 * gapSpan});
gaps.push_back(std::move(gap));
}

Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/Core/Detector/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_unittest(Blueprint BlueprintTests.cpp)
add_unittest(BlueprintHelper BlueprintHelperTests.cpp)
add_unittest(CylindricalContainerBuilder CylindricalContainerBuilderTests.cpp)
add_unittest(CylindricalDetectorFromBlueprint CylindricalDetectorFromBlueprintTests.cpp)
add_unittest(CylindricalDetectorHelper CylindricalDetectorHelperTests.cpp)
add_unittest(GridAxisGenerators GridAxisGeneratorsTests.cpp)
add_unittest(Detector DetectorTests.cpp)
Expand Down

0 comments on commit 33e36ea

Please sign in to comment.