ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
volume_graph.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/definitions/indexing.hpp"
14#include "detray/definitions/math.hpp"
15#include "detray/geometry/tracking_volume.hpp"
16#include "detray/utils/ranges.hpp"
17#include "detray/utils/type_traits.hpp"
18
19// System include(s)
20#include <algorithm>
21#include <cstddef>
22#include <iterator>
23#include <queue>
24#include <sstream>
25#include <string>
26#include <utility>
27
28namespace detray {
29
32template <typename node_t>
36 bool operator()(const node_t & /*n*/) const { return true; }
37};
38
40template <typename node_t>
41struct void_actor {
43 void operator()(const node_t & /*n*/,
44 const dindex_range & /*edge_range*/) const {
45 /*Do nothing*/
46 }
47};
48
57template <concepts::detector detector_t,
58 typename node_inspector =
59 void_node_inspector<typename detector_t::volume_type>,
60 template <typename...> class vector_t = dvector>
62 public:
64 using geo_obj_ids = typename detector_t::geo_obj_ids;
66 using volume_container_t = vector_t<typename detector_t::volume_type>;
68 using mask_container_t = typename detector_t::mask_container;
69
77 : public detray::ranges::view_interface<node_generator> {
79 struct node_builder {
83 inline void operator()(
84 const typename detector_t::surface_type &sf,
85 vector_t<typename detector_t::surface_type::mask_link> &half_edges)
86 const {
87 half_edges.push_back(sf.mask());
88 }
89 };
90
94 struct node {
97 explicit node(const tracking_volume<detector_t> &volume)
98 : m_idx(volume.index()) {
99 // @TODO: Remove duplicates from multiple placements of surfaces
100 volume.template visit_surfaces<surface_id::e_all, node_builder>(
102 }
103
105 dindex index() const { return m_idx; }
106
108 const auto &half_edges() const { return m_half_edges; }
109
113 vector_t<typename detector_t::surface_type::mask_link> m_half_edges;
114 };
115
117 struct iterator {
118 // Iterator type defs
120 using volume_iter = detray::ranges::const_iterator_t<volume_container_t>;
121
123 using difference_type = std::iter_difference_t<volume_iter>;
127 using pointer = typename std::iterator_traits<volume_iter>::pointer;
129 using reference = std::iter_reference_t<volume_iter>;
132 typename std::iterator_traits<volume_iter>::iterator_category;
133
135 iterator() = delete;
136
141 iterator(volume_iter &&vol_itr, const detector_t &det)
142 : m_vol_itr(std::move(vol_itr)), m_det(det) {}
143
147 bool operator==(const iterator &rhs) const {
148 return m_vol_itr == rhs.m_vol_itr;
149 }
150
152 node operator*() { return node({m_det, m_vol_itr->index()}); }
153
157 ++m_vol_itr;
158 return *this;
159 }
160
164 --m_vol_itr;
165 return *this;
166 }
167
171 constexpr auto operator+=(const difference_type j) -> iterator & {
172 m_vol_itr += j;
173 return *this;
174 }
175
179 constexpr auto operator-=(const difference_type j) -> iterator & {
180 return *this += -j;
181 }
182
183 protected:
185 friend constexpr auto operator+(const difference_type j,
186 const iterator &itr) -> iterator {
187 return {itr.m_vol_itr + j, itr.m_det};
188 }
189
191 friend constexpr auto operator-(const difference_type j,
192 const iterator &itr) -> iterator {
193 return itr + -j;
194 }
195
197 friend constexpr auto operator-(const iterator &lhs, const iterator &rhs)
198 -> difference_type {
199 return lhs.m_vol_itr - rhs.m_vol_itr;
200 }
201
202 private:
204 volume_iter m_vol_itr;
206 const detector_t &m_det;
207 };
208
211
213 node_generator() = delete;
214
218 node_generator(const volume_container_t &volumes, const detector_t &det)
219 : m_volumes(volumes), m_det(det) {}
220
222 iterator begin() const { return iterator(m_volumes.begin(), m_det); }
223
225 iterator end() const { return iterator(m_volumes.end(), m_det); }
226
228 dindex size() const { return static_cast<dindex>(m_volumes.size()); }
229
233 const detector_t &m_det;
234 };
235
242 : public detray::ranges::view_interface<edge_generator> {
244 using mask_edge_t = typename detector_t::surface_type::navigation_link;
246 using mask_link_t = typename detector_t::surface_type::mask_link;
247
250 struct edge {
254 edge(const dindex volume_id, const dindex link)
255 : _from(volume_id), _to(link) {}
256
258 dindex from() const { return _from; }
260 dindex to() const { return _to; }
261
266 };
267
286 template <typename mask_group_t, typename mask_range_t>
287 inline vector_t<edge> operator()(const mask_group_t &mask_group,
288 const mask_range_t &mask_range,
289 const dindex volume_id) {
290 vector_t<edge> edges{};
291 for (const auto &mask :
292 detray::ranges::subrange(mask_group, mask_range)) {
293 edges.emplace_back(volume_id, mask.volume_link());
294 }
295 return edges;
296 }
297 };
298
300 edge_generator() = delete;
301
306 explicit edge_generator(const typename detector_t::mask_container &masks,
307 const dindex volume_id = 0,
308 const mask_link_t mask_link = {})
309 : _masks(masks), _volume_id(volume_id), _mask_link{mask_link} {
310 _edges = _masks.template visit<edges_builder>(_mask_link, _volume_id);
311 }
312
314 auto begin() { return _edges.begin(); }
315
317 auto end() { return _edges.end(); }
318
325 _mask_link = mask_link;
326 _edges.clear();
327 _edges = _masks.template visit<edges_builder>(_mask_link, _volume_id);
328
329 return *this;
330 }
331
335 vector_t<edge> _edges;
340 };
341
342 // Graph nodes
345 // Graph edges
348
350 volume_graph() = delete;
351
358 explicit volume_graph(const detector_t &det)
359 : _nodes(det.volumes(), det), _edges(det.mask_store()), _adj_matrix{0} {
360 build();
361 }
362
364 ~volume_graph() = default;
365
367 dindex n_nodes() const { return static_cast<dindex>(_nodes.size()); }
368
370 const auto &nodes() const { return _nodes; }
371
375 const node_type n = _nodes[volume_id];
376 // Number of half_edges is equal to number of edges for volume
377 return static_cast<dindex>(n.half_edges().size());
378 }
379
381 const auto &edges() const { return _edges; }
382
384 const auto &adjacency_matrix() const { return _adj_matrix; }
385
387 /*template <typename action_t = void_actor<node_type>>
388 void bfs(action_t actor = {}) const {
389 // Do node inspection
390 const auto inspector = node_inspector();
391
392 node_type const *current = nullptr;
393 vector_t<bool> visited(_nodes.size(), false);
394
395 // Nodes to be visited. Start at first node
396 std::queue<node_type const *> node_queue;
397 node first_node = _nodes.front();
398 node_queue.push(&(first_node));
399
400 // Visit adjacent nodes and check current one
401 while (!node_queue.empty()) {
402 // Inspect
403 current = node_queue.front();
404 if (visited[current->index()]) {
405 node_queue.pop();
406 continue;
407 }
408 inspector(*current);
409
410 // Visit neighbors and perform action
411 actor(*current, current->template
412 range<static_cast<geo_obj_ids>(0)>());
413
414 // Add neighbors to queue
415 for (const auto &edg_link : current->edges()) {
416 for (const auto &edg :
417 edge_generator::iterator(current->index(), edg_link, _edges)) { dindex nbr
418 = edg.to();
419 // If not leaving world and if not visited, enqueue the node
420 if ((nbr != dindex_invalid && nbr > 0) && not
421 visited[nbr]) { node_queue.push(&(_nodes[nbr]));
422 }
423 }
424 }
425
426 // This node has been visited
427 visited[current->index()] = true;
428 node_queue.pop();
429 }
430 }*/
431
433 inline std::string to_string() const {
434 std::stringstream stream;
435 dindex dim = n_nodes() + 1u;
436 for (const auto &n : _nodes) {
437 stream << "[>>] Node with index " << n.index() << std::endl;
438 stream << " -> edges: " << std::endl;
439 for (unsigned int i = 0u; i < dim; ++i) {
440 const dindex degr = _adj_matrix[dim * n.index() + i];
441 if (degr == 0) {
442 continue;
443 }
444 std::string n_occur =
445 degr > 1 ? "\t\t\t\t(" + std::to_string(degr) + "x)" : "";
446
447 // Edge that leads out of the detector world
448 if (i == dim - 1u && degr != 0u) {
449 stream << " -> leaving world " + n_occur << std::endl;
450 } else {
451 stream << " -> " << std::to_string(i) + "\t" + n_occur
452 << std::endl;
453 }
454 }
455 }
456 return stream.str();
457 }
458
460 inline std::string to_dot_string() const {
461 std::stringstream stream;
462 dindex dim = n_nodes() + 1u;
463
464 stream << "strict graph {" << std::endl;
465 stream << " layout=neato;" << std::endl;
466 stream << " node [margin=0,shape=circle,style=filled];" << std::endl;
467 stream << " overlap=scale;" << std::endl;
468 stream << " splines=true;" << std::endl;
469 stream << " mode=KK;" << std::endl;
470 stream << std::endl;
471 stream << R"( exit [label="OOB",fillcolor="firebrick1"];)" << std::endl;
472
473 for (const auto &n : _nodes) {
474 stream << " v" << n.index() << ";" << std::endl;
475 }
476
477 stream << std::endl;
478
479 for (const auto &n : _nodes) {
480 for (unsigned int i = 0u; i < dim; ++i) {
481 const dindex degr = _adj_matrix[dim * n.index() + i];
482 if (degr == 0) {
483 continue;
484 }
485
486 bool to_oob = i == dim - 1u;
487 bool to_self = n.index() == i;
488
489 std::string label = degr > 1 ? std::to_string(degr) : "";
490 std::string dest = to_oob ? "exit" : ("v" + std::to_string(i));
491 std::string dir = (to_oob || to_self) ? "forward" : "both";
492
493 stream << " v" << n.index() << " -- " << dest << " [label=\""
494 << label << "\", dir=" << dir << "];" << std::endl;
495 }
496 }
497
498 stream << "}" << std::endl;
499
500 return stream.str();
501 }
502
503 private:
507 void build() {
508 // Leave space for the world volume (links to dindex_invalid)
509 const dindex dim{n_nodes() + 1u};
510 _adj_matrix.resize(dim * dim);
511
512 for (const auto &n : _nodes) {
513 // Only works for non batched geometries
514 for (const auto &edg_link : n.half_edges()) {
515 // Build an edge
516 for (const auto edg : _edges(n.index(), edg_link)) {
517 const dindex elem =
518 edg.to() < detail::invalid_value<
520 ? dim * n.index() + edg.to()
521 : dim * n.index() + dim - 1u;
522 _adj_matrix[elem]++;
523 }
524 }
525 }
526 }
527
529 node_generator _nodes;
530
532 edge_generator _edges;
533
535 vector_t<dindex> _adj_matrix;
536};
537
538} // namespace detray
Mask a region on a surface and link it to a volume.
Definition mask.hpp:46
auto volume_link() const -> const links_type &
Definition mask.hpp:255
Defines a detray 'view'.
Definition ranges.hpp:190
Facade for a detray detector volume.
Definition tracking_volume.hpp:44
std::string to_dot_string() const
Definition volume_graph.hpp:460
typename node_generator::node node_type
Type representing a volume graph node.
Definition volume_graph.hpp:344
const auto & nodes() const
Definition volume_graph.hpp:370
const auto & edges() const
Definition volume_graph.hpp:381
typename edge_generator::edge edge_type
Type representing a volume graph edge.
Definition volume_graph.hpp:347
typename detector_t::mask_container mask_container_t
Detector mask container type.
Definition volume_graph.hpp:68
typename detector_t::geo_obj_ids geo_obj_ids
Geometry object identifier type provided by the detector.
Definition volume_graph.hpp:64
~volume_graph()=default
Default destructor: we don't own anything.
dindex n_edges(dindex volume_id) const
Definition volume_graph.hpp:374
volume_graph()=delete
Default constructor.
const auto & adjacency_matrix() const
Definition volume_graph.hpp:384
std::string to_string() const
Walks breadth first through the geometry objects.
Definition volume_graph.hpp:433
vector_t< typename detector_t::volume_type > volume_container_t
Container type used to access detector volumes.
Definition volume_graph.hpp:66
volume_graph(const detector_t &det)
Build from existing nodes and edges, which are provide by the detector.
Definition volume_graph.hpp:358
dindex n_nodes() const
Definition volume_graph.hpp:367
Detray include(s).
Definition array_operators.hpp:18
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
vecmem::vector< value_t > dvector
Vector container backed by vecmem.
Definition containers.hpp:34
unsigned int dindex
Default index type.
Definition indexing.hpp:18
interface type to construct a subrange_view with CTAD
Definition subrange.hpp:90
Placeholder struct for an action while walking through the graph.
Definition volume_graph.hpp:41
void operator()(const node_t &, const dindex_range &) const
Ignore a visited node and its edge range.
Definition volume_graph.hpp:43
Placeholder struct for the implementation of an inspection function that will be executed,...
Definition volume_graph.hpp:33
bool operator()(const node_t &) const
Accept a node without performing an inspection.
Definition volume_graph.hpp:36
An edge in the graph connects two nodes (volumes).
Definition volume_graph.hpp:250
dindex from() const
Definition volume_graph.hpp:258
edge(const dindex volume_id, const dindex link)
Construct an edge between two volume indices.
Definition volume_graph.hpp:254
dindex _to
Destination volume index.
Definition volume_graph.hpp:265
dindex _from
Source volume index.
Definition volume_graph.hpp:263
dindex to() const
Definition volume_graph.hpp:260
Nested functor that fills the edges from a mask container.
Definition volume_graph.hpp:269
vector_t< edge > operator()(const mask_group_t &mask_group, const mask_range_t &mask_range, const dindex volume_id)
Builds the collection of graph edges for a given node.
Definition volume_graph.hpp:287
Builds graph edges from the detector mask collection on the fly.
Definition volume_graph.hpp:242
edge_generator & operator()(dindex volume_id, const mask_link_t mask_link)
Rebuild edges for a new volume and mask link.
Definition volume_graph.hpp:323
typename detector_t::surface_type::mask_link mask_link_t
The link to the surfaces mask.
Definition volume_graph.hpp:246
edge_generator(const typename detector_t::mask_container &masks, const dindex volume_id=0, const mask_link_t mask_link={})
Constructor from the detector masks store.
Definition volume_graph.hpp:306
typename detector_t::surface_type::navigation_link mask_edge_t
The link to the next volume.
Definition volume_graph.hpp:244
mask_link_t _mask_link
Link identifying the mask range used to generate edges.
Definition volume_graph.hpp:339
auto begin()
Definition volume_graph.hpp:314
dindex _volume_id
Current source volume index.
Definition volume_graph.hpp:337
vector_t< edge > _edges
Edges generated for the current volume and mask link.
Definition volume_graph.hpp:335
edge_generator()=delete
No default constructor (holds member reference).
auto end()
Definition volume_graph.hpp:317
const mask_container_t & _masks
Referenced detector mask container.
Definition volume_graph.hpp:333
Iterator over the graph nodes.
Definition volume_graph.hpp:117
std::iter_reference_t< volume_iter > reference
Reference type of the underlying volume iterator.
Definition volume_graph.hpp:129
iterator()=delete
No default construction because of reference member.
bool operator==(const iterator &rhs) const
Equality operator.
Definition volume_graph.hpp:147
typename std::iterator_traits< volume_iter >::iterator_category iterator_category
Category of the underlying volume iterator.
Definition volume_graph.hpp:131
std::iter_difference_t< volume_iter > difference_type
Difference type of the underlying volume iterator.
Definition volume_graph.hpp:123
constexpr auto operator+=(const difference_type j) -> iterator &
Advances iterator by j.
Definition volume_graph.hpp:171
friend constexpr auto operator+(const difference_type j, const iterator &itr) -> iterator
Definition volume_graph.hpp:185
friend constexpr auto operator-(const difference_type j, const iterator &itr) -> iterator
Definition volume_graph.hpp:191
iterator(volume_iter &&vol_itr, const detector_t &det)
Constructor from an iterator on the detector volume container and a reference to its surface containe...
Definition volume_graph.hpp:141
node value_type
Value type produced by dereferencing this iterator.
Definition volume_graph.hpp:125
typename std::iterator_traits< volume_iter >::pointer pointer
Pointer type of the underlying volume iterator.
Definition volume_graph.hpp:127
constexpr auto operator-=(const difference_type j) -> iterator &
Advances iterator by - j.
Definition volume_graph.hpp:179
iterator & operator++()
Prefix increment.
Definition volume_graph.hpp:156
friend constexpr auto operator-(const iterator &lhs, const iterator &rhs) -> difference_type
Definition volume_graph.hpp:197
node operator*()
Dereference operator.
Definition volume_graph.hpp:152
detray::ranges::const_iterator_t< volume_container_t > volume_iter
Iterator type used to traverse the detector's volumes.
Definition volume_graph.hpp:120
iterator & operator--()
Prefix decrement.
Definition volume_graph.hpp:163
A functor to retrieve the half-edges of a node.
Definition volume_graph.hpp:79
void operator()(const typename detector_t::surface_type &sf, vector_t< typename detector_t::surface_type::mask_link > &half_edges) const
Append a surface's mask link to the node's half-edge collection.
Definition volume_graph.hpp:83
A node in the graph has an index (volume index) and a collection of edges that belong to it (mask lin...
Definition volume_graph.hpp:94
dindex m_idx
Node(volume) index.
Definition volume_graph.hpp:111
node(const tracking_volume< detector_t > &volume)
Constructor from a detectors volume and surface collections.
Definition volume_graph.hpp:97
vector_t< typename detector_t::surface_type::mask_link > m_half_edges
Vector of half edges towards other volumes.
Definition volume_graph.hpp:113
const auto & half_edges() const
Definition volume_graph.hpp:108
dindex index() const
Definition volume_graph.hpp:105
Builds a graph node from the detector collections on the fly.
Definition volume_graph.hpp:77
iterator begin() const
Definition volume_graph.hpp:222
const detector_t & m_det
Detector used to access volume surfaces.
Definition volume_graph.hpp:233
iterator end() const
Definition volume_graph.hpp:225
const volume_container_t & m_volumes
Referenced detector volumes.
Definition volume_graph.hpp:231
iterator iterator_t
Node iterator type.
Definition volume_graph.hpp:210
node_generator()=delete
No default constructor (holds member reference).
dindex size() const
Definition volume_graph.hpp:228
node_generator(const volume_container_t &volumes, const detector_t &det)
Constructor from a detector containers.
Definition volume_graph.hpp:218