ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
volume_builder.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s).
12#include "detray/builders/surface_factory_interface.hpp"
13#include "detray/builders/volume_builder_interface.hpp"
14#include "detray/definitions/geometry.hpp"
15#include "detray/geometry/surface.hpp"
16#include "detray/utils/concepts.hpp"
17#include "detray/utils/grid/concepts.hpp"
18#include "detray/utils/logging.hpp"
19
20// System include(s)
21#include <algorithm>
22#include <memory>
23#include <string>
24
25namespace detray {
26
27namespace detail {
28
31
32} // namespace detail
33
35template <typename detector_t>
36class volume_builder : public volume_builder_interface<detector_t> {
37 static_assert(concepts::detector<detector_t>);
38
39 public:
43 using volume_type = typename detector_t::volume_type;
45 using geo_obj_ids = typename detector_t::geo_obj_ids;
46
51 explicit volume_builder(const volume_id id, const dindex idx = 0)
52 : m_volume{id} {
53 m_volume.set_index(idx);
54 m_volume.set_material(volume_type::material_id::e_none, dindex_invalid);
55
56 // The first acceleration data structure in every volume is a brute
57 // force method that will at least contain the portals
58 m_volume.template set_accel_link<
59 static_cast<typename volume_type::object_id>(0)>(
60 detector_t::accel::id::e_surface_default, 0);
61
62 DETRAY_VERBOSE_HOST("Created builder for volume: " << idx);
63 };
64
66 DETRAY_HOST
67 auto vol_index() const -> dindex override { return m_volume.index(); }
68
71 DETRAY_HOST
72 void has_accel(bool toggle) override { m_has_accel = toggle; }
73
75 DETRAY_HOST
76 bool has_accel() const override { return m_has_accel; }
77
80 DETRAY_HOST void set_name(std::string volume_name) override {
81 m_volume_name = std::move(volume_name);
82 DETRAY_VERBOSE_HOST("Set volume name: " << m_volume_name);
83 }
84
86 DETRAY_HOST std::string_view name() override {
87 if (m_volume_name.empty()) {
88 // Consistent default after volume index is known
89 m_volume_name = "unknown(volume_" + std::to_string(vol_index()) + ")";
90 }
91 return m_volume_name;
92 }
93
96 DETRAY_HOST
97 auto operator()() const -> const typename detector_t::volume_type& override {
98 return m_volume;
99 }
100
103 DETRAY_HOST
104 auto operator()() -> typename detector_t::volume_type& override {
105 return m_volume;
106 }
107
114 DETRAY_HOST
115 auto build(detector_t& det, const volume_builder_options& opt,
116 typename detector_t::geometry_context ctx = {}) ->
117 typename detector_t::volume_type* override {
118 DETRAY_VERBOSE_HOST("Build surfaces...");
119
120 assert(!m_surfaces.empty());
121 assert(!m_transforms.empty());
122 assert(!m_masks.all_empty());
123
124 // Prepare volume data
125 m_volume.set_index(static_cast<dindex>(det.volumes().size()));
126
127 m_volume.set_transform(det.transform_store().size());
128 det._transforms.push_back(m_trf);
129
130 // Add all data from the builder to the detector containers
131 add_to_detector(opt, ctx, det);
132
133 // Reset after the data was added to the detector
134 m_surfaces.clear();
135 m_transforms.clear(ctx);
136 m_masks.clear_all();
137
138 DETRAY_VERBOSE_HOST("Successfully built "
139 << m_volume.n_surfaces()
140 << " surfaces for volume: " << this->name());
141
142 // Pass to decorator builders
143 return &(det._volumes.back());
144 }
145
147 DETRAY_HOST
149 const typename detector_t::transform3_type& trf = {}) override {
150 m_trf = trf;
151 }
152
155 DETRAY_HOST
157 const typename detector_t::point3_type& t) override {
158 m_trf = typename detector_t::transform3_type{t};
159 }
160
166 DETRAY_HOST
168 const typename detector_t::point3_type& t,
169 const typename detector_t::vector3_type& x,
170 const typename detector_t::vector3_type& z) override {
171 m_trf = typename detector_t::transform3_type{t, z, x};
172 }
173
177 DETRAY_HOST
179 std::shared_ptr<surface_factory_interface<detector_t>> sf_factory,
180 typename detector_t::geometry_context ctx = {}) override {
181 DETRAY_VERBOSE_HOST("Add surface factory:");
182
183 (*sf_factory)(m_volume, m_surfaces, m_transforms, m_masks, ctx);
184 }
185
186 protected:
188 typename detector_t::surface_lookup_container& surfaces() override {
189 return m_surfaces;
190 }
191
193 typename detector_t::transform_container& transforms() override {
194 return m_transforms;
195 }
196
198 typename detector_t::mask_container& masks() override { return m_masks; }
199
208 template <geo_obj_ids surface_id = static_cast<geo_obj_ids>(0)>
209 DETRAY_HOST auto add_to_detector(
210 const volume_builder_options& opt,
211 const typename detector_t::geometry_context ctx,
212 detector_t& det) noexcept(false) -> void {
213 if (opt.deduplicate()) {
214 DETRAY_WARN_HOST(m_volume_name
215 << ": Geometry data deduplication not yet implemented");
216 }
217
218 // Append transforms
219 const auto trf_offset = det.transform_store().size(ctx);
220 det._transforms.append(std::move(m_transforms), ctx);
221
222 // Surface index offset in the global detector container
223 auto sf_offset{static_cast<dindex>(det.surfaces().size())};
224
226 auto find_range = [&](auto sf_id) {
227 // Compare given id to surface identifier
228 auto is_sf_type = [sf_id](const auto& sf) { return sf.id() == sf_id; };
229
230 auto first = static_cast<dindex>(
231 math::abs(std::ranges::find_if(m_surfaces, is_sf_type) -
232 std::begin(m_surfaces)));
233
234 auto last = static_cast<dindex>(math::abs(
235 std::ranges::rend(m_surfaces) -
236 std::ranges::find_if(std::ranges::rbegin(m_surfaces),
237 std::ranges::rend(m_surfaces), is_sf_type)));
238
239 // Set correct empty range, otherwise shift by global surface offset
240 return (first >= last)
241 ? dindex_range{}
242 : dindex_range{first + sf_offset, last + sf_offset};
243 };
244
245 m_volume.template update_sf_link<surface_id::e_portal>(
246 find_range(surface_id::e_portal));
247
248 m_volume.template update_sf_link<surface_id::e_sensitive>(
249 find_range(surface_id::e_sensitive));
250
251 m_volume.template update_sf_link<surface_id::e_passive>(
252 find_range(surface_id::e_passive));
253
254 // Update mask and transform index of surfaces and set the
255 // correct index of the surface in container
256 std::size_t n_portals{0u};
257 for (auto& sf_desc : m_surfaces) {
258 det._masks.template visit<detail::mask_index_update>(sf_desc.mask(),
259 sf_desc);
260 sf_desc.set_volume(m_volume.index());
261 sf_desc.update_transform(trf_offset);
262 sf_desc.set_index(sf_offset++);
263
264 if (sf_desc.is_portal()) {
265 ++n_portals;
266 }
267
268 det._surfaces.insert(sf_desc);
269 }
270
271 // Place the appropriate surfaces in the brute force search method.
272 constexpr auto default_acc_id{detector_t::accel::id::e_surface_default};
273
274 // Strip the source link from the lookup data structure
275 typename detector_t::surface_container descriptors;
276 descriptors.reserve(m_surfaces.size());
277 std::ranges::transform(
278 m_surfaces, std::back_inserter(descriptors),
279 [](typename detector_t::surface_lookup_container::value_type& sf) {
280 return static_cast<
281 typename detector_t::surface_container::value_type>(sf);
282 });
283
284 // Add portals to brute force navigation method
285 if (m_has_accel) {
286 DETRAY_VERBOSE_HOST("-> Volume has acceleration structure:");
287
288 typename detector_t::surface_container portals{};
289 portals.reserve(n_portals);
290
291 std::ranges::copy_if(
292 descriptors, std::back_inserter(portals),
293 [](auto& sf_desc) { return !sf_desc.is_sensitive(); });
294
295 // Add only the portals to the brute force method
296 DETRAY_VERBOSE_HOST(
297 "-> Register only portals/passives with brute force "
298 "accelerator");
299
300 det._accelerators.template push_back<default_acc_id>(std::move(portals));
301 } else {
302 DETRAY_VERBOSE_HOST(
303 "-> Register all surfaces with brute force accelerator");
304
305 // Add all surfaces to the brute force method
306 det._accelerators.template push_back<default_acc_id>(
307 std::move(descriptors));
308 }
309
310 m_volume.template set_accel_link<surface_id>(
311 default_acc_id,
312 det.accelerator_store().template size<default_acc_id>() - 1u);
313
314 // Append masks
315 det._masks.append(std::move(m_masks));
316
317 // Finally, add the volume descriptor to the detector
318 det._volumes.push_back(m_volume);
319 }
320
321 private:
323 bool m_has_accel{false};
324
326 std::string m_volume_name{};
327
329 typename detector_t::volume_type m_volume{};
331 typename detector_t::transform3_type m_trf{};
332
335 typename detector_t::surface_lookup_container m_surfaces{};
336 typename detector_t::transform_container m_transforms{};
337 typename detector_t::mask_container m_masks{};
339};
340
341namespace detail {
342
348 template <typename group_t, typename index_t, typename surface_t>
349 DETRAY_HOST inline void operator()(const group_t& group,
350 const index_t& /*index*/,
351 surface_t& sf) const {
352 sf.update_mask(static_cast<dindex>(std::size(group)));
353 }
354};
355
356} // namespace detail
357
358} // namespace detray
How to generate surfaces with their corresponding masks and transforms.
Definition surface_factory_interface.hpp:120
Interface for volume builders (and volume builder decorators).
Definition volume_builder_interface.hpp:66
void add_surfaces(std::shared_ptr< surface_factory_interface< detector_t > > sf_factory, typename detector_t::geometry_context ctx={}) override
Add data for (a) new surface(s) to the builder.
Definition volume_builder.hpp:178
auto vol_index() const -> dindex override
Definition volume_builder.hpp:67
volume_builder(const volume_id id, const dindex idx=0)
Parametrized Constructor.
Definition volume_builder.hpp:51
void add_volume_placement(const typename detector_t::point3_type &t, const typename detector_t::vector3_type &x, const typename detector_t::vector3_type &z) override
Constructs a placement transform from axes x and z and the translation t for the volume.
Definition volume_builder.hpp:167
auto build(detector_t &det, const volume_builder_options &opt, typename detector_t::geometry_context ctx={}) -> typename detector_t::volume_type *override
Build the volume with internal surfaces and portals and add it to the detector instance det.
Definition volume_builder.hpp:115
detector_t::surface_lookup_container & surfaces() override
Definition volume_builder.hpp:188
detector_t::mask_container & masks() override
Definition volume_builder.hpp:198
bool has_accel() const override
Definition volume_builder.hpp:76
void add_volume_placement(const typename detector_t::transform3_type &trf={}) override
Adds a placement transform.
Definition volume_builder.hpp:148
typename detector_t::volume_type volume_type
Volume descriptor type produced by the builder.
Definition volume_builder.hpp:43
void set_name(std::string volume_name) override
Sets the name volume_name for the volume.
Definition volume_builder.hpp:80
dscalar< typename detector_t::algebra_type > scalar_t
Scalar type used by this detector's geometry.
Definition volume_builder.hpp:41
std::string_view name() override
Definition volume_builder.hpp:86
detector_t::transform_container & transforms() override
Definition volume_builder.hpp:193
typename detector_t::geo_obj_ids geo_obj_ids
Identifier enum for the detector's geometry object categories.
Definition volume_builder.hpp:45
auto add_to_detector(const volume_builder_options &opt, const typename detector_t::geometry_context ctx, detector_t &det) noexcept(false) -> void
Adds a new full set of volume components (e.g.
Definition volume_builder.hpp:209
auto operator()() -> typename detector_t::volume_type &override
Access to the volume under construction - non-const.
Definition volume_builder.hpp:104
auto operator()() const -> const typename detector_t::volume_type &override
Access to the volume under construction - const.
Definition volume_builder.hpp:97
void add_volume_placement(const typename detector_t::point3_type &t) override
Constructs a placement transform with identity rotation and translation.
Definition volume_builder.hpp:156
void has_accel(bool toggle) override
Toggles whether sensitive surfaces are added to the brute force method.
Definition volume_builder.hpp:72
Check if a type can be used as a detector.
Definition concepts.hpp:47
Detray include(s).
Definition array_operators.hpp:18
get_scalar_t< A, T > dscalar
Scalar type for algebra A and value type T.
Definition algebra.hpp:64
volume_id
Shape of a detector volume.
Definition geometry.hpp:27
detail::index_range< dindex > dindex_range
Index ranges and sequences.
Definition indexing.hpp:24
unsigned int dindex
Default index type.
Definition indexing.hpp:18
constexpr dindex dindex_invalid
Global invalid index definition.
Definition indexing.hpp:21
std::size_t n_portals(const detector_t &det)
Definition detector_statistics.hpp:24
A functor to update the mask index in surface objects.
Definition volume_builder.hpp:344
void operator()(const group_t &group, const index_t &, surface_t &sf) const
Update a surface's mask index after mask groups are appended.
Definition volume_builder.hpp:349
Options for the volume builder classes.
Definition volume_builder_interface.hpp:29
constexpr bool deduplicate() const
Getters.
Definition volume_builder_interface.hpp:40