LDMX Software
GeometryContainers.h
1// This file is part of the Acts project.
2//
3// Copyright (C) 2017-2020 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
9#pragma once
10
11#include <algorithm>
12#include <boost/container/flat_map.hpp>
13#include <boost/container/flat_set.hpp>
14#include <cassert>
15#include <cstddef>
16#include <iostream>
17#include <utility>
18
19#include "Acts/EventData/SourceLink.hpp"
20#include "Acts/Geometry/GeometryIdentifier.hpp"
21#include "Acts/Surfaces/Surface.hpp"
22#include "Tracking/Sim/GroupBy.h"
23#include "Tracking/Sim/Range.h"
24
25namespace ActsExamples {
26namespace detail {
27
28// extract the geometry identifier from a variety of types
30 // explicit geometry identifier are just forwarded
31 constexpr Acts::GeometryIdentifier operator()(
32 Acts::GeometryIdentifier geometryId) const {
33 return geometryId;
34 }
35 // encoded geometry ids are converted back to geometry identifiers.
36 constexpr Acts::GeometryIdentifier operator()(
37 Acts::GeometryIdentifier::Value encoded) const {
38 return Acts::GeometryIdentifier(encoded);
39 }
40 // support elements in map-like structures.
41 template <typename T>
42 constexpr Acts::GeometryIdentifier operator()(
43 const std::pair<Acts::GeometryIdentifier, T>& mapItem) const {
44 return mapItem.first;
45 }
46 // support elements that implement `.geometryId()`.
47 template <typename T>
48 inline auto operator()(const T& thing) const
49 -> decltype(thing.geometryId(), Acts::GeometryIdentifier()) {
50 return thing.geometryId();
51 }
52 // support reference_wrappers around such types as well
53 template <typename T>
54 inline auto operator()(std::reference_wrapper<T> thing) const
55 -> decltype(thing.get().geometryId(), Acts::GeometryIdentifier()) {
56 return thing.get().geometryId();
57 }
58};
59
61 // indicate that comparisons between keys and full objects are allowed.
62 using is_transparent = void;
63 // compare two elements using the automatic key extraction.
64 template <typename Left, typename Right>
65 constexpr bool operator()(Left&& lhs, Right&& rhs) const {
66 return GeometryIdGetter()(lhs) < GeometryIdGetter()(rhs);
67 }
68};
69
70} // namespace detail
71
82template <typename T>
83using GeometryIdMultiset =
84 boost::container::flat_multiset<T, detail::CompareGeometryId>;
85
99template <typename T>
100using GeometryIdMultimap =
101 GeometryIdMultiset<std::pair<Acts::GeometryIdentifier, T>>;
102
104template <typename T>
106 const GeometryIdMultiset<T>& container,
107 Acts::GeometryIdentifier::Value volume) {
108 auto cmp = Acts::GeometryIdentifier().setVolume(volume);
109 auto beg = std::lower_bound(container.begin(), container.end(), cmp,
111 // WARNING overflows to volume==0 if the input volume is the last one
112 cmp = Acts::GeometryIdentifier().setVolume(volume + 1u);
113 // optimize search by using the lower bound as start point. also handles
114 // volume overflows since the geo id would be located before the start of
115 // the upper edge search window.
116 auto end =
117 std::lower_bound(beg, container.end(), cmp, detail::CompareGeometryId{});
118 return makeRange(beg, end);
119}
120
122template <typename T>
123inline auto selectVolume(const GeometryIdMultiset<T>& container,
124 Acts::GeometryIdentifier id) {
125 return selectVolume(container, id.volume());
126}
127
129template <typename T>
130inline Range<typename GeometryIdMultiset<T>::const_iterator> selectLayer(
131 const GeometryIdMultiset<T>& container,
132 Acts::GeometryIdentifier::Value volume,
133 Acts::GeometryIdentifier::Value layer) {
134 auto cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer);
135 auto beg = std::lower_bound(container.begin(), container.end(), cmp,
136 detail::CompareGeometryId{});
137 // WARNING resets to layer==0 if the input layer is the last one
138 cmp = Acts::GeometryIdentifier().setVolume(volume).setLayer(layer + 1u);
139 // optimize search by using the lower bound as start point. also handles
140 // volume overflows since the geo id would be located before the start of
141 // the upper edge search window.
142 auto end =
143 std::lower_bound(beg, container.end(), cmp, detail::CompareGeometryId{});
144 return makeRange(beg, end);
145}
146
147// Select all elements within the given layer.
148template <typename T>
149inline auto selectLayer(const GeometryIdMultiset<T>& container,
150 Acts::GeometryIdentifier id) {
151 return selectLayer(container, id.volume(), id.layer());
152}
153
155template <typename T>
156inline Range<typename GeometryIdMultiset<T>::const_iterator> selectModule(
157 const GeometryIdMultiset<T>& container, Acts::GeometryIdentifier geoId) {
158 // module is the lowest level and defines a single geometry id value
159 return makeRange(container.equal_range(geoId));
160}
161
163template <typename T>
164inline auto selectModule(const GeometryIdMultiset<T>& container,
165 Acts::GeometryIdentifier::Value volume,
166 Acts::GeometryIdentifier::Value layer,
167 Acts::GeometryIdentifier::Value module) {
168 return selectModule(
169 container,
170 Acts::GeometryIdentifier().setVolume(volume).setLayer(layer).setSensitive(
171 module));
172}
173
190template <typename T>
191inline Range<typename GeometryIdMultiset<T>::const_iterator>
192selectLowestNonZeroGeometryObject(const GeometryIdMultiset<T>& container,
193 Acts::GeometryIdentifier geoId) {
194 assert((geoId.boundary() == 0u) and "Boundary component must be zero");
195 assert((geoId.approach() == 0u) and "Approach component must be zero");
196
197 if (geoId.sensitive() != 0u) {
198 return selectModule(container, geoId);
199 } else if (geoId.layer() != 0u) {
200 return selectLayer(container, geoId);
201 } else if (geoId.volume() != 0u) {
202 return selectVolume(container, geoId);
203 } else {
204 return makeRange(container.begin(), container.end());
205 }
206}
207
209template <typename T>
210inline GroupBy<typename GeometryIdMultiset<T>::const_iterator,
211 detail::GeometryIdGetter>
212groupByModule(const GeometryIdMultiset<T>& container) {
213 return makeGroupBy(container, detail::GeometryIdGetter());
214}
215
220template <typename T>
222 using Container = GeometryIdMultiset<T>;
223 using Key = Acts::GeometryIdentifier;
224 using Value = typename GeometryIdMultiset<T>::value_type;
225 using Iterator = typename GeometryIdMultiset<T>::const_iterator;
226
227 // pointer to the container
228 const Container* container = nullptr;
229};
230
231} // namespace ActsExamples
A wrapper around a pair of iterators to simplify range-based loops.
Definition Range.h:27
The accessor for the GeometryIdMultiset container.