Skip to content

Commit

Permalink
feat: cylindrical detector from DD4hep (#2582)
Browse files Browse the repository at this point in the history
This PR introduces the possibility to build cylindrical detectors via a blue print definition from `DD4hep`.

It mainly adds two classes:
- `DD4hepBlueprint` which parses the DD4hep Detector Element tree and creates a blueprint
- `DD4hepDetectorStructure` which can turn this into a detector

Working with the Blueprint allows to get rid of the `DD4hepVolumeStructure` as this is part of the blueprint definition.

For debugging, is also refines the drawing of the `Blueprint` to `.dot` which is now decoupled from the class into a helper function.

It adds an extensive test on a simple detector,  and to make sure it does what it should do, I introduced a new 
- `DD4hepDiscLayerStructureTests` unit test.

![Screenshot 2023-10-25 at 17 00 06](https://github.com/acts-project/acts/assets/26623879/a69cf5e1-fcc4-4257-8c5a-179923c0a3c5)

The building seems to work, navigation is not tested yet on this one.

![Screenshot 2023-10-25 at 17 01 31](https://github.com/acts-project/acts/assets/26623879/6616b652-0b45-48f4-9889-8f081b963357)
  • Loading branch information
asalzburger authored Oct 30, 2023
1 parent 0547774 commit d4842c7
Show file tree
Hide file tree
Showing 24 changed files with 1,569 additions and 535 deletions.
66 changes: 4 additions & 62 deletions Core/include/Acts/Detector/Blueprint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Acts/Definitions/Common.hpp"
#include "Acts/Geometry/VolumeBounds.hpp"
#include "Acts/Utilities/BinningData.hpp"
#include "Acts/Utilities/StringHelpers.hpp"

#include <memory>
#include <string>
Expand Down Expand Up @@ -90,6 +91,9 @@ struct Node final {
/// Branch definition binning
std::vector<BinningValue> binning = {};

/// Auxiliary information
std::vector<std::string> auxiliary = {};

/// Builders and helper tools that can be attached
std::shared_ptr<const IRootVolumeFinderBuilder> rootVolumeFinderBuilder =
nullptr;
Expand All @@ -110,68 +114,6 @@ struct Node final {
c->parent = this;
children.push_back(std::move(c));
}

/// @brief Turn into a dot output
template <typename stream_type>
void dotStream(stream_type& ss,
const std::string& graphName = "blueprint") const {
if (isRoot()) {
ss << "digraph " << graphName << " {" << '\n';
ss << name
<< " [shape=\"circle\";style=\"filled\";fillcolor=\"darkorange\"];"
<< '\n';

} else if (isLeaf()) {
std::string color =
(internalsBuilder != nullptr) ? "darkolivegreen1" : "darkolivegreen3";

ss << name << " [shape=\"box\";style=\"filled\";fillcolor=\"";
ss << color << "\"];" << '\n';
} else {
ss << name << " [shape=\"diamond\"];" << '\n';
}

ss << name << " [label=\"" << name << "\"];" << '\n';
for (const auto& c : children) {
ss << name << " -> " << c->name << ";" << '\n';
c->dotStream(ss);
}
if (children.empty()) {
ss << name + "_shape"
<< " [shape=\"cylinder\";style=\"filled\";fillcolor=\"lightgrey\"];"
<< '\n';
ss << name << " -> " << name + "_shape"
<< ";" << '\n';
}

if (internalsBuilder != nullptr) {
ss << name + "_int"
<< " [shape=\"doubleoctagon\";style=\"filled\";fillcolor="
"\"cadetblue1\"];"
<< '\n';
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';
}
}
};

} // namespace Blueprint
Expand Down
69 changes: 69 additions & 0 deletions Core/include/Acts/Detector/detail/BlueprintDrawer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// This file is part of the Acts project.
//
// Copyright (C) 2023 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/Detector/Blueprint.hpp"

#include <ostream>
#include <string>

namespace Acts {

namespace Experimental {

namespace detail {
namespace BlueprintDrawer {

/// @brief Nested options struct for the drawer
struct Options {
struct Node {
/// ROOT node definitions
std::string shape = "circle";
std::string color = "darkorange";

/// Font properties
std::string face = "sans-serif";
int labelText = 12;
int infoText = 10;

/// Info properties
int precision = 1;
};

/// @brief The name of the graph
std::string graphName = "blueprint";

// Main node types to come
Node root = Node{};
Node branch = Node{"diamond", "white"};
Node leaf = Node{"box", "darkolivegreen1"};
Node gap = Node{"box", "darkolivegreen3"};

// Sub node types to come
Node shape = Node{"cylinder", "lightgrey"};
Node virtualShape = Node{"cylinder", "white"};
Node internals = Node{"doubleoctagon", "cadetblue1"};
Node geoID = Node{"box", "azure"};
Node roots = Node{"box", "darkkhaki"};
};

/// @brief Turn into a dot output by writing into a stream
///
/// @tparam the stream type to be used
///
/// @param ss the stream into which the dot output should be written
/// @param node the node to be drawn
/// @param options the options for the drawer
void dotStream(std::ostream& ss, const Blueprint::Node& node,
const Options& options = Options{});

} // namespace BlueprintDrawer
} // namespace detail
} // namespace Experimental
} // namespace Acts
3 changes: 3 additions & 0 deletions Core/include/Acts/Geometry/VolumeBounds.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class VolumeBounds {
eOther = 6
};

/// Static member to get the name of the BoundsType
static const std::vector<std::string> s_boundsTypeNames;

VolumeBounds() = default;

virtual ~VolumeBounds() = default;
Expand Down
19 changes: 19 additions & 0 deletions Core/include/Acts/Utilities/StringHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include "Acts/Definitions/Algebra.hpp"
#include "Acts/Utilities/Enumerate.hpp"

#include <iomanip>
#include <iostream>
Expand Down Expand Up @@ -103,4 +104,22 @@ inline std::string toString(const Acts::Transform3& transform,
return sout.str();
}

/// Print out a vector of ActsScalar
/// @param pVector The vector to print
/// @param precision Numeric output precision
inline std::string toString(const std::vector<ActsScalar>& pVector,
int precision = 4) {
std::ostringstream sout;
sout << std::setiosflags(std::ios::fixed) << std::setprecision(precision);
sout << "(";
for (const auto [i, val] : enumerate(pVector)) {
sout << val;
if (i != pVector.size() - 1) {
sout << ", ";
}
}
sout << ")";
return sout.str();
}

} // namespace Acts
1 change: 1 addition & 0 deletions Core/src/Detector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ target_sources(
ActsCore
PRIVATE
detail/BlueprintHelper.cpp
detail/BlueprintDrawer.cpp
detail/CylindricalDetectorHelper.cpp
detail/PortalHelper.cpp
detail/SupportHelper.cpp
Expand Down
115 changes: 115 additions & 0 deletions Core/src/Detector/detail/BlueprintDrawer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// This file is part of the Acts project.
//
// Copyright (C) 2023 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/Detector/detail/BlueprintDrawer.hpp"

#include <vector>

namespace {

/// @brief Generate the shape string
/// @param s the shape of the object
/// @param c the color of the object
/// @return a string with the shape and color
std::string shapeStr(
const Acts::Experimental::detail::BlueprintDrawer::Options::Node& node) {
return "[shape=\"" + node.shape + "\";style=\"filled\";fillcolor=\"" +
node.color + "\"];";
}

/// @brief Generate text output
///
/// @param node the node options
/// @param label the label text
/// @param info the info text
std::string labelStr(
const Acts::Experimental::detail::BlueprintDrawer::Options::Node& node,
const std::string& label, const std::vector<std::string>& info = {}) {
std::string lText = "[label=<<font face=\"";
lText += node.face;
lText += "\" point-size=\"";
lText += std::to_string(node.labelText);
lText += "\">" + label;
if (!info.empty()) {
lText += "</font><br/>";
lText += "<font face=\"";
lText += node.face;
lText += "\" point-size=\"";
lText += std::to_string(node.infoText);
lText += "\">";
for (const auto& i : info) {
lText += i;
lText += "<br/>";
}
}
lText += "</font>";
lText += ">];";
return lText;
}

} // namespace

void Acts::Experimental::detail::BlueprintDrawer::dotStream(
std::ostream& ss, const Acts::Experimental::Blueprint::Node& node,
const Options& options) {
// Root / leaf or branch
if (node.isRoot()) {
ss << "digraph " << options.graphName << " {" << '\n';
ss << node.name << " " << labelStr(options.root, node.name, node.auxiliary)
<< '\n';
ss << node.name << " " << shapeStr(options.root) << '\n';

} else if (node.isLeaf()) {
ss << node.name << " " << labelStr(options.leaf, node.name, node.auxiliary)
<< '\n';
ss << node.name << " "
<< ((node.internalsBuilder != nullptr) ? shapeStr(options.leaf)
: shapeStr(options.gap))
<< '\n';
} else {
ss << node.name << " "
<< labelStr(options.branch, node.name, node.auxiliary) << '\n';
ss << node.name << " " << shapeStr(options.branch) << '\n';
}
// Recursive for children
for (const auto& c : node.children) {
ss << node.name << " -> " << c->name << ";" << '\n';
dotStream(ss, *c, options);
}

// Shape
Options::Node shape = node.isLeaf() ? options.shape : options.virtualShape;
ss << node.name + "_shape " << shapeStr(shape) << '\n';
ss << node.name + "_shape "
<< labelStr(shape, VolumeBounds::s_boundsTypeNames[node.boundsType],
{"t = " + toString(node.transform.translation(), 1),
"b = " + toString(node.boundaryValues, 1)})
<< '\n';
ss << node.name << " -> " << node.name + "_shape [ arrowhead = \"none\" ];"
<< '\n';

// Sub node detection
if (node.internalsBuilder != nullptr) {
ss << node.name + "_int " << shapeStr(options.internals) << '\n';
ss << node.name << " -> " << node.name + "_int;" << '\n';
}

if (node.geoIdGenerator != nullptr) {
ss << node.name + "_geoID " << shapeStr(options.geoID) << '\n';
ss << node.name << " -> " << node.name + "_geoID;" << '\n';
}

if (node.rootVolumeFinderBuilder != nullptr) {
ss << node.name + "_roots " << shapeStr(options.roots) << '\n';
ss << node.name << " -> " << node.name + "_roots;" << '\n';
}

if (node.isRoot()) {
ss << "}" << '\n';
}
}
4 changes: 4 additions & 0 deletions Core/src/Geometry/VolumeBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

#include "Acts/Geometry/VolumeBounds.hpp"

const std::vector<std::string> Acts::VolumeBounds::s_boundsTypeNames = {
"Cone", "Cuboid", "CutoutCylinder", "Cylinder",
"GenericCuboid", "Trapezoid", "Other"};

/**Overload of << operator for std::ostream for debug output*/
std::ostream& Acts::operator<<(std::ostream& sl, const Acts::VolumeBounds& vb) {
return vb.toStream(sl);
Expand Down
5 changes: 3 additions & 2 deletions Plugins/DD4hep/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ include(FetchContent)
add_library(
ActsPluginDD4hep SHARED
src/ConvertDD4hepDetector.cpp
src/DD4hepBlueprint.cpp
src/DD4hepDetectorStructure.cpp
src/DD4hepMaterialHelpers.cpp
src/DD4hepDetectorElement.cpp
src/DD4hepDetectorSurfaceFactory.cpp
src/DD4hepLayerBuilder.cpp
src/DD4hepLayerStructure.cpp
src/DD4hepVolumeBuilder.cpp
src/DD4hepVolumeStructure.cpp)
src/DD4hepVolumeBuilder.cpp)
target_include_directories(
ActsPluginDD4hep
PUBLIC
Expand Down
Loading

0 comments on commit d4842c7

Please sign in to comment.