ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
tracking_volume.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/core/concepts.hpp"
13#include "detray/core/name_map.hpp"
14#include "detray/definitions/containers.hpp"
15#include "detray/definitions/detail/qualifiers.hpp"
16#include "detray/definitions/geometry.hpp"
17#include "detray/definitions/indexing.hpp"
18#include "detray/geometry/detail/volume_kernels.hpp"
19#include "detray/material/material.hpp"
20#include "detray/navigation/accelerators/search_window.hpp"
21#include "detray/utils/logging.hpp"
22#include "detray/utils/ranges.hpp"
23
24// System include(s)
25#include <algorithm>
26#include <iostream>
27#include <sstream>
28
29namespace detray {
30
43template <concepts::detector detector_t> // @TODO: This needs a concept
46 using algebra_type = typename detector_t::algebra_type;
47 using scalar_type = dscalar<algebra_type>;
48 using point3_type = dpoint3D<algebra_type>;
49
51 using descr_t = typename detector_t::volume_type;
52 using context_t = typename detector_t::geometry_context;
53
54 public:
58 using object_id = descr_t::object_id;
59
61 tracking_volume() = delete;
62
66 constexpr tracking_volume(const detector_t &det, const descr_t &desc)
67 : m_detector{det}, m_desc{desc} {
68 assert(m_desc.index() < det.volumes().size());
69 assert(m_desc.id() != volume_id::e_unknown);
70 }
71
74 constexpr tracking_volume(const detector_t &det, const dindex vol_idx)
75 : tracking_volume(det, det.volume(vol_idx)) {}
76
78 DETRAY_HOST_DEVICE
79 auto detector() const -> const detector_t & { return m_detector; }
80
85 DETRAY_HOST_DEVICE
86 constexpr auto operator==(const tracking_volume &rhs) const -> bool {
87 return (&m_detector == &(rhs.m_detector) && m_desc == rhs.m_desc);
88 }
89
91 DETRAY_HOST_DEVICE
92 constexpr auto id() const -> volume_id { return m_desc.id(); }
93
95 DETRAY_HOST_DEVICE
96 constexpr auto index() const -> dindex { return m_desc.index(); }
97
100 DETRAY_HOST_DEVICE
101 constexpr auto transform() const -> const
102 typename detector_t::transform3_type & {
103 return m_detector.transform_store().at(m_desc.transform());
104 }
105
107 DETRAY_HOST_DEVICE
108 constexpr auto center() const -> point3_type {
109 return transform().translation();
110 }
111
114 DETRAY_HOST_DEVICE constexpr auto material_parameters(
115 const point3_type &loc_p) const -> const detray::material<scalar_type> * {
117 }
118
120 DETRAY_HOST_DEVICE
121 constexpr bool has_material() const { return m_desc.has_material(); }
122
124 template <surface_id sf_type = surface_id::e_all>
125 DETRAY_HOST_DEVICE constexpr decltype(auto) surfaces() const {
126 if constexpr (sf_type == surface_id::e_all) {
127 return detray::ranges::subrange{m_detector.surfaces(),
128 m_desc.full_sf_range()};
129 } else {
130 return detray::ranges::subrange{m_detector.surfaces(),
131 m_desc.template sf_link<sf_type>()};
132 }
133 }
134
136 DETRAY_HOST_DEVICE constexpr decltype(auto) portals() const {
138 }
139
141 DETRAY_HOST_DEVICE constexpr dindex n_portals() const {
142 const auto pt_idx_range = m_desc.template sf_link<surface_id::e_portal>();
143
144 assert(pt_idx_range[1] > pt_idx_range[0]);
145 return pt_idx_range[1] - pt_idx_range[0];
146 }
147
149 DETRAY_HOST_DEVICE constexpr dindex n_sensitives() const {
150 const auto sens_idx_range =
151 m_desc.template sf_link<surface_id::e_sensitive>();
152
153 assert(sens_idx_range[1] >= sens_idx_range[0]);
154 return sens_idx_range[1] - sens_idx_range[0];
155 }
156
158 DETRAY_HOST_DEVICE constexpr dindex n_passives() const {
159 const auto ps_idx_range = m_desc.template sf_link<surface_id::e_passive>();
160
161 assert(ps_idx_range[1] >= ps_idx_range[0]);
162 return ps_idx_range[1] - ps_idx_range[0];
163 }
164
172 template <object_id I, typename functor_t, typename... Args>
173 DETRAY_HOST_DEVICE constexpr void visit_accelerator(Args &&...args) const {
174 static_assert(I < object_id::e_all);
175
176 if (const auto &link{m_desc.template accel_link<I>()}; !link.is_invalid()) {
177 // Run over the surfaces in a single acceleration data structure
178 // and apply the functor to the resulting neighborhood
179 m_detector.accelerator_store().template visit<functor_t>(
180 link, std::forward<Args>(args)...);
181 }
182 }
183
190 template <typename functor_t, int I = static_cast<int>(object_id::e_all) - 1,
191 typename... Args>
192 DETRAY_HOST_DEVICE constexpr void visit_accelerators(Args &&...args) const {
193 // Get the acceleration data structures for this volume and only visit,
194 // if object type is contained in volume
195 for (std::size_t id = 0u; id < static_cast<std::size_t>(object_id::e_size);
196 ++id) {
197 if (const auto &link{m_desc.accel_link()[id]}; !link.is_invalid()) {
198 // Run over the surfaces in a single acceleration data structure
199 // and apply the functor to the resulting neighborhood
200 m_detector.accelerator_store().template visit<functor_t>(
201 link, std::forward<Args>(args)...);
202 }
203 }
204 }
205
214 template <surface_id I, typename functor_t, typename... Args>
215 DETRAY_HOST_DEVICE constexpr void visit_surfaces(Args &&...args) const {
216 using surface_getter_t = detail::apply_to_surfaces<functor_t>;
217
218 // Dispatch to the correct acceleration structure
219 if constexpr (I == surface_id::e_portal) {
221 std::forward<Args>(args)...);
222 } else if constexpr (I == surface_id::e_sensitive) {
224 std::forward<Args>(args)...);
225 } else if constexpr (I == surface_id::e_passive) {
227 std::forward<Args>(args)...);
228 } else {
229 // Visit all surface types, but not other geometric objects
230 // (e.g. daughter volumes)
232 std::forward<Args>(args)...);
233 if constexpr (object_id::e_portal != object_id::e_passive) {
235 std::forward<Args>(args)...);
236 }
238 std::forward<Args>(args)...);
239 }
240 }
241
247 template <typename functor_t, typename... Args>
248 DETRAY_HOST_DEVICE constexpr void visit_daughter_volumes(
249 Args &&...args) const {
250 using volume_getter_t = detail::apply_to_volumes<functor_t>;
251
253 std::forward<Args>(args)...);
254 }
255
271 template <object_id I, typename functor_t, typename track_t,
272 concepts::arithmetic window_size_t, typename... Args>
273 DETRAY_HOST_DEVICE constexpr void visit_neighborhood(
274 const track_t &track, const search_window<window_size_t, 2> &win_size,
275 const context_t &ctx, Args &&...args) const {
276 if constexpr (I == object_id::e_all) {
278 m_detector, m_desc, track, win_size, ctx,
279 std::forward<Args>(args)...);
280 } else {
282 m_detector, m_desc, track, win_size, ctx,
283 std::forward<Args>(args)...);
284 }
285 }
286
293 template <typename functor_t, typename... Args>
294 DETRAY_HOST_DEVICE constexpr auto visit_material(Args &&...args) const {
295 assert(has_material());
296 const auto &materials = m_detector.material_store();
297 return materials.template visit<functor_t>(m_desc.material(),
298 std::forward<Args>(args)...);
299 }
300
306 DETRAY_HOST bool self_check(std::ostream &os) const {
307 if (id() == volume_id::e_unknown) {
308 os << "DETRAY ERROR (HOST): Unknown volume shape type in volume:\n"
309 << *this << std::endl;
310 return false;
311 }
312 if (detail::is_invalid_value(index())) {
313 os << "DETRAY ERROR (HOST): Volume index undefined in volume:\n"
314 << *this << std::endl;
315 return false;
316 }
317 if (index() >= m_detector.volumes().size()) {
318 os << "DETRAY ERROR (HOST): Volume index out of bounds in volume:\n"
319 << *this << std::endl;
320 return false;
321 }
322 if (detail::is_invalid_value(m_desc.transform())) {
323 os << "DETRAY ERROR (HOST): Volume transform undefined in volume:\n"
324 << *this << std::endl;
325 return false;
326 }
327 if (m_desc.transform() >= m_detector.transform_store().size()) {
328 os << "DETRAY ERROR (HOST): Volume transform index out of bounds "
329 "in volume:\n"
330 << *this << std::endl;
331 return false;
332 }
333 // Only check, if there is material in the detector
334 if (!m_detector.material_store().all_empty() && has_material() &&
335 m_desc.material().is_invalid_index()) {
336 os << "DETRAY ERROR (HOST): Volume does not have valid material "
337 "link:\n"
338 << *this << std::endl;
339 return false;
340 }
341 const auto &acc_link = m_desc.accel_link();
342 if (detail::is_invalid_value(acc_link[0])) {
343 os << "DETRAY ERROR (HOST): Link to portal lookup broken: " << acc_link[0]
344 << "\n in volume: " << *this << std::endl;
345 return false;
346 }
347 if (const auto &pt_link = m_desc.template sf_link<surface_id::e_portal>();
348 detail::is_invalid_value(pt_link)) {
349 os << "DETRAY ERROR (HOST): Link to portal surfaces broken: " << pt_link
350 << "\n in volume: " << *this << std::endl;
351 return false;
352 }
353 // Check consistency of surface ranges
354 std::vector<dindex_range> sf_ranges = {
355 m_desc.template sf_link<surface_id::e_portal>()};
356
357 // Only add the other ranges in case they are not empty
358 if (const auto &sens_range =
359 m_desc.template sf_link<surface_id::e_sensitive>();
360 sens_range[0] != sens_range[1]) {
361 sf_ranges.push_back(sens_range);
362 }
363 if (const auto &psv_range =
364 m_desc.template sf_link<surface_id::e_passive>();
365 psv_range[0] != psv_range[1]) {
366 sf_ranges.push_back(psv_range);
367 }
368
369 // Sort and check that the ranges are contiguous
370 auto compare_ranges = [](const dindex_range &rg1, const dindex_range &rg2) {
371 return rg1[0] < rg2[0];
372 };
373
374 std::ranges::sort(sf_ranges, compare_ranges);
375
376 if ((sf_ranges.size() > 1 && sf_ranges[0][1] != sf_ranges[1][0]) ||
377 (sf_ranges.size() > 2 && sf_ranges[1][1] != sf_ranges[2][0])) {
378 os << "DETRAY ERROR (HOST): Surface index ranges not contiguous: "
379 << m_desc.sf_link() << "\n in volume: " << *this << std::endl;
380 return false;
381 }
382
383 // Warnings
384 bool suspicious_links = false;
385 std::stringstream warnings{};
386 for (std::size_t i = 1u; i < acc_link.size(); ++i) {
387 // An acceleration data structure link was set, but is invalid
388 if (!acc_link[i].is_invalid_id() && acc_link[i].is_invalid_index()) {
389 suspicious_links = true;
390 warnings << "Link to acceleration data structure "
391 << static_cast<int>(acc_link[i].id()) << " is invalid"
392 << std::endl;
393 }
394 }
395 if (suspicious_links) {
396 DETRAY_WARN_HOST(warnings.str() << " in volume: " << *this);
397 }
398
399 return true;
400 }
401
404 DETRAY_HOST_DEVICE
405 auto name(const name_map &names) const -> std::string {
406 return names.empty() ? "volume " + std::to_string(m_desc.index())
407 : names.at(m_desc.index());
408 }
409
411 DETRAY_HOST
412 friend std::ostream &operator<<(std::ostream &os, const tracking_volume &v) {
413 os << v.m_desc;
414 return os;
415 }
416
417 private:
419 const detector_t &m_detector;
421 const descr_t &m_desc;
422};
423
424} // namespace detray
constexpr auto material_parameters(const point3_type &loc_p) const -> const detray::material< scalar_type > *
Definition tracking_volume.hpp:114
friend std::ostream & operator<<(std::ostream &os, const tracking_volume &v)
Definition tracking_volume.hpp:412
constexpr void visit_accelerators(Args &&...args) const
Apply a functor to all acceleration structures of this volume.
Definition tracking_volume.hpp:192
constexpr dindex n_sensitives() const
Definition tracking_volume.hpp:149
constexpr void visit_surfaces(Args &&...args) const
Apply a functor to all surfaces of a given surface id (portal, passive, sensitive) in the volume.
Definition tracking_volume.hpp:215
constexpr void visit_accelerator(Args &&...args) const
Apply a functor to all surfaces in one of the volume's acceleration structures.
Definition tracking_volume.hpp:173
constexpr decltype(auto) surfaces() const
Definition tracking_volume.hpp:125
constexpr auto operator==(const tracking_volume &rhs) const -> bool
Equality operator.
Definition tracking_volume.hpp:86
constexpr dindex n_portals() const
Definition tracking_volume.hpp:141
constexpr bool has_material() const
Definition tracking_volume.hpp:121
bool self_check(std::ostream &os) const
Do a consistency check on the volume after building the detector.
Definition tracking_volume.hpp:306
constexpr decltype(auto) portals() const
Definition tracking_volume.hpp:136
constexpr auto id() const -> volume_id
Definition tracking_volume.hpp:92
descr_t::object_id object_id
Object identifier enum used by the volume descriptor's accelerator links.
Definition tracking_volume.hpp:58
constexpr tracking_volume(const detector_t &det, const descr_t &desc)
Construct a volume facade from its detector and descriptor.
Definition tracking_volume.hpp:66
detray::name_map name_map
In case the geometry needs to be printed.
Definition tracking_volume.hpp:56
auto name(const name_map &names) const -> std::string
Definition tracking_volume.hpp:405
constexpr void visit_daughter_volumes(Args &&...args) const
Apply a functor to all daughter volumes.
Definition tracking_volume.hpp:248
constexpr tracking_volume(const detector_t &det, const dindex vol_idx)
Constructor from detector.
Definition tracking_volume.hpp:74
auto detector() const -> const detector_t &
Definition tracking_volume.hpp:79
constexpr auto visit_material(Args &&...args) const
Call a functor on the volume material with additional arguments.
Definition tracking_volume.hpp:294
constexpr auto index() const -> dindex
Definition tracking_volume.hpp:96
constexpr auto center() const -> point3_type
Definition tracking_volume.hpp:108
constexpr auto transform() const -> const typename detector_t::transform3_type &
Definition tracking_volume.hpp:101
constexpr void visit_neighborhood(const track_t &track, const search_window< window_size_t, 2 > &win_size, const context_t &ctx, Args &&...args) const
Apply a functor to a neighborhood of geometric objects around a track position in the volume.
Definition tracking_volume.hpp:273
constexpr dindex n_passives() const
Definition tracking_volume.hpp:158
tracking_volume()=delete
Not allowed: always needs a detector and a descriptor.
Arithmetic types.
Definition concepts.hpp:21
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
surface_id
surface type, resolved during navigation.
Definition geometry.hpp:41
darray< window_size_t, DIM > search_window
Size around a query point for which to do the search in an acceleration structure.
Definition search_window.hpp:24
get_point3D_t< A, T > dpoint3D
Three-dimensional point type for algebra A and value type T.
Definition algebra.hpp:72
Material composition properties and density data used by interactions.
Definition material.hpp:36
Map volume indices to volume names and vice versa.
Definition name_map.hpp:23
interface type to construct a subrange_view with CTAD
Definition subrange.hpp:90