Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylindricalContainerBuilder.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylindricalContainerBuilder.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2023 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
18 
19 #include <algorithm>
20 #include <ostream>
21 #include <stdexcept>
22 #include <utility>
23 
24 namespace Acts {
25 namespace Experimental {
26 class DetectorVolume;
27 } // namespace Experimental
28 } // namespace Acts
29 
30 namespace {
31 
44 template <typename object_collection>
46  const Acts::GeometryContext& gctx, object_collection& objects,
47  const std::vector<Acts::BinningValue>& binning,
49  // Return container object
51  if (binning.size() == 1u) {
52  Acts::BinningValue bv = binning.front();
53  // 1-dimensional binning options
54  switch (bv) {
55  case Acts::binR: {
56  rContainer =
58  gctx, objects, {}, logLevel);
59  } break;
60  case Acts::binZ: {
61  rContainer =
63  gctx, objects, {}, logLevel);
64  } break;
65  case Acts::binPhi: {
66  rContainer =
68  gctx, objects, {}, logLevel);
69  } break;
70  default:
71  break;
72  }
73  } else if (binning ==
74  std::vector<Acts::BinningValue>{Acts::binZ, Acts::binR} and
75  objects.size() == 2u) {
76  rContainer =
78  gctx, objects, logLevel);
79  }
80  return rContainer;
81 }
82 } // namespace
83 
86  std::unique_ptr<const Acts::Logger> logger)
87  : IDetectorComponentBuilder(), m_cfg(cfg), m_logger(std::move(logger)) {
88  // Check if builders are present
89  if (m_cfg.builders.empty()) {
90  throw std::invalid_argument(
91  "CylindricalContainerBuilder: no sub builders provided.");
92  }
93  // Check if binning value is correctly chosen
94  if (m_cfg.binning.size() == 1u) {
95  // 1-dimensional case
96  auto b = m_cfg.binning.front();
97  if (b != Acts::binR and b != Acts::binZ and b != Acts::binPhi) {
98  throw std::invalid_argument(
99  "CylindricalContainerBuilder: 1D binning only supported in z, r, or "
100  "phi");
101  }
102  } else if (m_cfg.binning.size() == 2u) {
103  // 2-dimensional case, this is for wrapping
104  if (m_cfg.binning !=
105  std::vector<Acts::BinningValue>{Acts::binZ, Acts::binR}) {
106  throw std::invalid_argument(
107  "CylindricalContainerBuilder: 2D binning only supports wrapping in "
108  "z-r.");
109  } else if (m_cfg.builders.size() != 2u) {
110  // Wrapping needs exactly one inner (volume or container) and one outer
111  // volume
112  throw std::invalid_argument(
113  "CylindricalContainerBuilder: 2D wrapping in z-r requires exactly "
114  "two builders.");
115  }
116  }
117 }
118 
121  Acts::Logging::Level logLevel)
123  m_logger(getDefaultLogger(bpNode.name + "_cont", logLevel)) {
124  if (bpNode.boundsType != VolumeBounds::BoundsType::eCylinder) {
125  throw std::invalid_argument(
126  "CylindricalContainerBuilder: boundary type must be cylinder - for "
127  "building from a blueprint node.");
128  }
129 
130  std::vector<std::shared_ptr<const IDetectorComponentBuilder>> builders;
131  for (const auto& child : bpNode.children) {
132  if (child->isLeaf()) {
133  // Volume structure
135  vsCfg.transform = child->transform;
136  vsCfg.boundsType = child->boundsType;
137  vsCfg.boundValues = child->boundaryValues;
138  vsCfg.auxiliary = "*** acts auto-generated shape builder ***";
139  auto vsBuilder = std::make_shared<VolumeStructureBuilder>(
140  vsCfg, getDefaultLogger(child->name + "_shape", logLevel));
141  // Detector volume builder
143  dvCfg.name = child->name;
144  dvCfg.externalsBuilder = vsBuilder;
145  dvCfg.internalsBuilder = child->internalsBuilder;
146  dvCfg.auxiliary = "*** acts auto-generated volume builder ***";
147  // Add the builder
148  m_cfg.builders.push_back(std::make_shared<DetectorVolumeBuilder>(
149  dvCfg, getDefaultLogger(child->name, logLevel)));
150  } else {
151  // This evokes the recursive stepping down the tree
152  m_cfg.builders.push_back(
153  std::make_shared<CylindricalContainerBuilder>(*child, logLevel));
154  }
155  }
156 
157  m_cfg.binning = bpNode.binning;
158  m_cfg.auxiliary = "*** acts auto-generated from proxy ***";
161 }
162 
165  const GeometryContext& gctx) const {
166  // Return container object
168  bool atNavigationLevel = true;
169 
170  // Create the indivudal components, collect for both outcomes
171  std::vector<DetectorComponent> components;
172  ACTS_DEBUG("Building container from " << m_cfg.builders.size()
173  << " components.");
174  // Check through the component volumes - if every builder only
175  // built exactly one volume, you are at pure navigation level
176  // Collect the volumes
177  std::vector<std::shared_ptr<DetectorVolume>> volumes;
178  std::vector<DetectorComponent::PortalContainer> containers;
179  std::vector<std::shared_ptr<DetectorVolume>> rootVolumes;
180  // Run through the builders
181  std::for_each(
182  m_cfg.builders.begin(), m_cfg.builders.end(), [&](const auto& builder) {
183  auto [cVolumes, cContainer, cRoots] = builder->construct(gctx);
184  atNavigationLevel = (atNavigationLevel and cVolumes.size() == 1u);
185  // Collect individual components, volumes, containers, roots
186  volumes.insert(volumes.end(), cVolumes.begin(), cVolumes.end());
187  containers.push_back(cContainer);
188  rootVolumes.insert(rootVolumes.end(), cRoots.volumes.begin(),
189  cRoots.volumes.end());
190  });
191  // Navigation level detected, connect volumes (cleaner and faster than
192  // connect containers)
193  if (atNavigationLevel) {
194  ACTS_VERBOSE(
195  "Component volumes are at navigation level: connecting volumes.");
196  // Connect volumes
197  rContainer = connect(gctx, volumes, m_cfg.binning, logger().level());
198  } else {
199  ACTS_VERBOSE("Components contain sub containers: connect containers.");
200  // Connect containers
201  rContainer = connect(gctx, containers, m_cfg.binning, logger().level());
202  }
203  ACTS_VERBOSE("Number of root volumes: " << rootVolumes.size());
204 
205  // Check if a root volume finder is provided
206  if (m_cfg.rootVolumeFinderBuilder) {
207  // Return the container
209  {},
210  rContainer,
212  rootVolumes,
213  m_cfg.rootVolumeFinderBuilder->construct(gctx, rootVolumes)}};
214  }
215 
216  // Geometry Id generation
217  if (m_cfg.geoIdGenerator != nullptr) {
218  ACTS_DEBUG("Assigning geometry ids to the detector");
219  auto cache = m_cfg.geoIdGenerator->generateCache();
220  if (m_cfg.geoIdReverseGen) {
221  std::for_each(rootVolumes.rbegin(), rootVolumes.rend(), [&](auto& v) {
222  m_cfg.geoIdGenerator->assignGeometryId(cache, *v);
223  });
224  } else {
225  std::for_each(rootVolumes.begin(), rootVolumes.end(), [&](auto& v) {
226  m_cfg.geoIdGenerator->assignGeometryId(cache, *v);
227  });
228  }
229  }
230 
231  // Return the container
233  {}, rContainer, RootDetectorVolumes{rootVolumes, tryRootVolumes()}};
234 }