ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
material_map_generator.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/definitions/algebra.hpp"
14#include "detray/definitions/detail/qualifiers.hpp"
15#include "detray/definitions/indexing.hpp"
16#include "detray/geometry/detail/surface_kernels.hpp"
17#include "detray/geometry/shapes/cylinder2D.hpp"
18#include "detray/geometry/shapes/ring2D.hpp"
19#include "detray/material/material.hpp"
20#include "detray/material/material_rod.hpp"
21#include "detray/material/material_slab.hpp"
22#include "detray/material/predefined_materials.hpp"
23#include "detray/utils/grid/axis.hpp"
24#include "detray/utils/logging.hpp"
25#include "detray/utils/ranges.hpp"
26
27// System include(s)
28#include <functional>
29#include <map>
30#include <memory>
31#include <vector>
32
33namespace detray {
34
35namespace detail {
36
38template <concepts::scalar scalar_t>
39inline std::vector<material_slab<scalar_t>> generate_cyl_mat(
40 const dvector<dvector<scalar_t>> &bounds_vec, const std::size_t nbins,
41 material<scalar_t> mat, const scalar_t t, const scalar_t scalor) {
42 std::vector<material_slab<scalar_t>> ts;
43 ts.reserve(nbins);
44
45 // Find the surface bounds from the masks
46 scalar_t z_lower{detail::invalid_value<scalar_t>()};
47 scalar_t z_upper{-detail::invalid_value<scalar_t>()};
48 for (const auto &bounds : bounds_vec) {
49 z_lower = math::min(z_lower, bounds.at(cylinder2D::e_lower_z));
50 z_upper = math::max(z_upper, bounds.at(cylinder2D::e_upper_z));
51 }
52
53 // Generate material steps (quadratic with distance to origin)
54 const scalar_t length{math::fabs(z_upper - z_lower)};
55 scalar_t z{z_lower};
56 const scalar_t z_step{length / static_cast<scalar_t>(nbins - 1u)};
57 for (std::size_t n = 0u; n < nbins; ++n) {
58 ts.emplace_back(mat, static_cast<scalar_t>(scalor * z * z) + t);
59 z += z_step;
60 }
61
62 return ts;
63}
64
66template <concepts::scalar scalar_t>
67inline std::vector<material_slab<scalar_t>> generate_disc_mat(
68 const dvector<dvector<scalar_t>> &bounds_vec, const std::size_t nbins,
69 material<scalar_t> mat, const scalar_t t, const scalar_t scalor) {
70 std::vector<material_slab<scalar_t>> ts;
71 ts.reserve(nbins);
72
73 // Find the surface bounds from the masks
74 scalar_t r_inner{detail::invalid_value<scalar_t>()};
75 scalar_t r_outer{0.f};
76 for (const auto &bounds : bounds_vec) {
77 r_inner = math::min(r_inner, bounds.at(ring2D::e_inner_r));
78 r_outer = math::max(r_outer, bounds.at(ring2D::e_outer_r));
79 }
80
81 scalar_t r{r_inner};
82 const scalar_t r_step{(r_outer - r_inner) /
83 static_cast<scalar_t>(nbins - 1u)};
84 for (std::size_t n = 0u; n < nbins; ++n) {
85 ts.emplace_back(mat, static_cast<scalar_t>(scalor * r) + t);
86 r += r_step;
87 }
88
89 return ts;
90}
91
92} // namespace detail
93
95template <concepts::scalar scalar_t>
98 struct map_config {
104 std::size_t axis_index{0u};
108 scalar_t thickness{0.15f * unit<scalar_t>::mm};
110 scalar_t scalor{1.f};
112 std::function<std::vector<material_slab<scalar_t>>(
113 const dvector<dvector<scalar_t>> &, const std::size_t,
114 material<scalar_t>, const scalar_t, const scalar_t)>
115 mat_generator{detray::detail::generate_cyl_mat<scalar_t>};
116 };
117
120 std::map<std::pair<unsigned int, surface_id>, map_config> m_map_configs;
121
129 template <typename mask_id_t>
130 constexpr material_map_config &set_map_config(mask_id_t map_type,
131 surface_id sf_type,
132 const map_config &cfg) {
133 const auto key =
134 std::make_pair(static_cast<unsigned int>(map_type), sf_type);
135 if (!m_map_configs.contains(key)) {
136 m_map_configs.emplace(key, cfg);
137 } else {
138 m_map_configs.at(key) = cfg;
139 }
140 return *this;
141 }
142
143
150 template <typename mask_id_t>
151 bool has_config(mask_id_t map_type, surface_id sf_type) const {
152 const auto key =
153 std::make_pair(static_cast<unsigned int>(map_type), sf_type);
154 return m_map_configs.contains(key);
155 }
156
160 template <typename mask_id_t>
161 const auto &get_map_config(mask_id_t map_type, surface_id sf_type) const {
162 const auto key =
163 std::make_pair(static_cast<unsigned int>(map_type), sf_type);
164 return m_map_configs.at(key);
165 }
166
170 template <typename mask_id_t>
171 auto &get_map_config(mask_id_t map_type, surface_id sf_type) {
172 const auto key =
173 std::make_pair(static_cast<unsigned int>(map_type), sf_type);
174 return m_map_configs.at(key);
175 }
176
177};
178
182template <concepts::detector detector_t>
183class material_map_generator final : public factory_decorator<detector_t> {
185
186 public:
190 DETRAY_HOST
192 std::unique_ptr<surface_factory_interface<detector_t>> factory,
194 : factory_decorator<detector_t>(std::move(factory)), m_cfg{cfg} {}
195
205 DETRAY_HOST
206 auto operator()(typename detector_t::volume_type &volume,
207 typename detector_t::surface_lookup_container &surfaces,
208 typename detector_t::transform_container &transforms,
209 typename detector_t::mask_container &masks,
210 typename detector_t::geometry_context ctx = {})
211 -> dindex_range override {
212 const dindex_range idx_range =
213 (*this->get_factory())(volume, surfaces, transforms, masks, ctx);
214
215 m_surface_range = idx_range;
216
217 return idx_range;
218 }
219
231 template <typename bin_data_t, std::size_t N>
232 DETRAY_HOST auto operator()(
233 typename detector_t::surface_lookup_container &surfaces,
234 const typename detector_t::mask_container &masks,
235 std::map<dindex, std::vector<bin_data_t>> &material_map,
236 std::map<dindex, darray<std::size_t, N>> &n_bins) {
237 DETRAY_DEBUG_HOST("Generate material maps...");
238
239 static_assert(N == 2u, "This generator only supports 2D material maps");
240
241 using link_t = typename detector_t::surface_type::material_link;
242 using mask_id = typename detector_t::masks::id;
243 using material_id = typename detector_t::material::id;
244
245 assert(surfaces.size() >= (m_surface_range[1] - m_surface_range[0]));
246
247 // Add the material only to those surfaces that the data links against
248 unsigned int i{0u};
249 for (auto &sf : detray::ranges::subrange(surfaces, m_surface_range)) {
250 const auto sf_idx{m_surface_range[0] + i};
251
252 // Skip line surfaces, if any are defined
253 if constexpr (types::contains<typename detector_t::material,
255 const mask_id sf_mask_id = sf.mask().id();
256 if (sf_mask_id == mask_id::e_straw_tube ||
257 sf_mask_id == mask_id::e_drift_cell) {
258 continue;
259 }
260 }
261
262 // Get the correct configuration for this surface
263 if (!m_cfg.has_config(sf.mask().id(), sf.id())) {
264 continue;
265 }
266 const auto &map_cfg = m_cfg.get_map_config(sf.mask().id(), sf.id());
267
268 // Copy the number of bins to the builder
269 assert(map_cfg.n_bins.size() == N);
270 n_bins.emplace(sf_idx, darray<std::size_t, N>{});
271 std::ranges::copy_n(map_cfg.n_bins.begin(), N, n_bins.at(sf_idx).begin());
272
273 // Scale material thickness either over e.g. r- or z-bins
274 const std::size_t bins = map_cfg.n_bins.at(map_cfg.axis_index);
275
276 using sf_kernels =
277 detail::surface_kernels<typename detector_t::algebra_type>;
278
279 const auto bounds_vec =
280 masks.template visit<typename sf_kernels::get_mask_values>(sf.mask());
281
282 // Generate the raw material
283 const auto material{
284 map_cfg.mat_generator(bounds_vec, bins, map_cfg.mapped_material,
285 map_cfg.thickness, map_cfg.scalor)};
286
287 // Add the material slabs with their local bin indices to the
288 // volume builder
289 for (dindex bin0 = 0u; bin0 < map_cfg.n_bins.at(0); ++bin0) {
290 for (dindex bin1 = 0u; bin1 < map_cfg.n_bins.at(1); ++bin1) {
291 bin_data_t data{
292 axis::multi_bin<N>{bin0, bin1},
293 material.at((map_cfg.axis_index == 0u) ? bin0 : bin1)};
294
295 auto search = material_map.find(sf_idx);
296 if (search == material_map.end()) {
297 material_map.emplace(sf_idx, std::vector<bin_data_t>{data});
298 } else {
299 search->second.push_back(data);
300 }
301 }
302 }
303
304 // Set the initial surface material link (will be updated when
305 // added to the detector)
306 sf.material() =
307 link_t{static_cast<material_id>(map_cfg.map_id), dindex_invalid};
308 i++;
309 }
310 }
311
312 private:
316 dindex_range m_surface_range{};
317};
318
319} // namespace detray
const surface_factory_interface< detector_t > * get_factory() const
Definition surface_factory_interface.hpp:215
factory_decorator(std::unique_ptr< surface_factory_interface< detector_t > > factory)
Wrap a concrete surface factory and forward interface calls to it.
Definition surface_factory_interface.hpp:203
auto operator()(typename detector_t::volume_type &volume, typename detector_t::surface_lookup_container &surfaces, typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx={}) -> dindex_range override
Call the underlying surface factory and record the surface range that was produced.
Definition material_map_generator.hpp:206
material_map_generator(std::unique_ptr< surface_factory_interface< detector_t > > factory, const material_map_config< scalar_t > &cfg)
Construct from configuration cfg.
Definition material_map_generator.hpp:191
auto operator()(typename detector_t::surface_lookup_container &surfaces, const typename detector_t::mask_container &masks, std::map< dindex, std::vector< bin_data_t > > &material_map, std::map< dindex, darray< std::size_t, N > > &n_bins)
Create material maps for all surfaces that the underlying surface factory builds.
Definition material_map_generator.hpp:232
How to generate surfaces with their corresponding masks and transforms.
Definition surface_factory_interface.hpp:120
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
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
grid< algebra_t, axes< shape_t >, bins::single< material_slab< dscalar< algebra_t > > >, simple_serializer, container_t, owning > material_map
Definition of binned material.
Definition material_map.hpp:29
unsigned int dindex
Default index type.
Definition indexing.hpp:18
constexpr dindex dindex_invalid
Global invalid index definition.
Definition indexing.hpp:21
surface_id
surface type, resolved during navigation.
Definition geometry.hpp:41
std::array< value_t, kDIM > darray
Fixed-size array container.
Definition containers.hpp:30
Multi-bin: contains bin indices from multiple axes.
Definition axis.hpp:36
How to configure the generation for a specific type of material map.
Definition material_map_generator.hpp:98
darray< std::size_t, 2 > n_bins
Number of bins for material maps.
Definition material_map_generator.hpp:102
scalar_t thickness
Minimal thickness of the material slabs in the material maps.
Definition material_map_generator.hpp:108
scalar_t scalor
Scale factor for the material thickness calculation.
Definition material_map_generator.hpp:110
std::function< std::vector< material_slab< scalar_t > >(const dvector< dvector< scalar_t > > &, const std::size_t, material< scalar_t >, const scalar_t, const scalar_t)> mat_generator
How to vary the material thickness along the bins.
Definition material_map_generator.hpp:115
dindex map_id
Type id value of the material map in a given detector.
Definition material_map_generator.hpp:100
std::size_t axis_index
Along which of the two axes to scale the material thickness.
Definition material_map_generator.hpp:104
material< scalar_t > mapped_material
Material to be filled into the maps.
Definition material_map_generator.hpp:106
Configuration for the material map generator.
Definition material_map_generator.hpp:96
std::map< std::pair< unsigned int, surface_id >, map_config > m_map_configs
Configuration for different types of material maps: The key consists of the mask type id and the surf...
Definition material_map_generator.hpp:120
constexpr material_map_config & set_map_config(mask_id_t map_type, surface_id sf_type, const map_config &cfg)
SettersStore the configuration for one mask and surface category.
Definition material_map_generator.hpp:130
const auto & get_map_config(mask_id_t map_type, surface_id sf_type) const
Get the configuration for a mask and surface category.
Definition material_map_generator.hpp:161
auto & get_map_config(mask_id_t map_type, surface_id sf_type)
Get the mutable configuration for a mask and surface category.
Definition material_map_generator.hpp:171
bool has_config(mask_id_t map_type, surface_id sf_type) const
GettersCheck whether a configuration exists for a mask and surface category.
Definition material_map_generator.hpp:151
Rod structure to be mapped on the line mask.
Definition material_rod.hpp:26
Material composition properties and density data used by interactions.
Definition material.hpp:36
interface type to construct a subrange_view with CTAD
Definition subrange.hpp:90
Predefined silicon material using TrackML bulk properties.
Definition predefined_materials.hpp:212
static constexpr scalar_t mm
Native length unit, the millimetre.
Definition units.hpp:27