ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
cylinder_portal_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/builders/volume_builder.hpp"
14#include "detray/core/concepts.hpp"
15#include "detray/core/detail/data_context.hpp"
16#include "detray/definitions/algebra.hpp"
17#include "detray/definitions/detail/qualifiers.hpp"
18#include "detray/definitions/geometry.hpp"
19#include "detray/definitions/indexing.hpp"
20#include "detray/geometry/shapes/cuboid3D.hpp"
21#include "detray/utils/bounding_volume.hpp"
22#include "detray/utils/logging.hpp"
23
24// System include(s)
25#include <cassert>
26#include <limits>
27
28namespace detray {
29
31template <concepts::scalar scalar_t>
35 bool m_build_inner{true};
37 bool m_do_autofit{true};
39 scalar_t m_envelope{100.f * unit<scalar_t>::um};
41 scalar_t m_fixed_inner_r{0.f};
43 scalar_t m_fixed_outer_r{0.f};
45 scalar_t m_fixed_z{0.f};
49
55 constexpr cylinder_portal_config &build_inner(const bool b) {
56 m_build_inner = b;
57 return *this;
58 }
59
62 constexpr cylinder_portal_config &do_autofit(const bool b) {
63 m_do_autofit = b;
64 return *this;
65 }
66
69 constexpr cylinder_portal_config &envelope(const scalar_t e) {
70 m_envelope = e;
71 return *this;
72 }
73
76 constexpr cylinder_portal_config &fixed_inner_radius(const scalar_t r) {
78 return *this;
79 }
80
83 constexpr cylinder_portal_config &fixed_outer_radius(const scalar_t r) {
85 return *this;
86 }
87
90 constexpr cylinder_portal_config &fixed_half_length(const scalar_t z) {
91 m_fixed_z = z;
92 return *this;
93 }
94
98 m_volume_links[0] = l;
99 return *this;
100 }
101
105 m_volume_links[1] = l;
106 return *this;
107 }
108
112 m_volume_links[2] = l;
113 return *this;
114 }
115
119 m_volume_links[3] = l;
120 return *this;
121 }
122
123
127 constexpr bool build_inner() const { return m_build_inner; }
129 constexpr bool do_autofit() const { return m_do_autofit; }
131 constexpr scalar_t envelope() const { return m_envelope; }
133 constexpr scalar_t fixed_inner_radius() const { return m_fixed_inner_r; }
135 constexpr scalar_t fixed_outer_radius() const { return m_fixed_outer_r; }
137 constexpr scalar_t fixed_half_length() const { return m_fixed_z; }
139 constexpr const auto &volume_links() const { return m_volume_links; }
141 constexpr const auto &link_north() const { return m_volume_links[0]; }
143 constexpr const auto &link_south() const { return m_volume_links[1]; }
145 constexpr const auto &link_east() const { return m_volume_links[2]; }
147 constexpr const auto &link_west() const { return m_volume_links[3]; }
149};
150
154template <concepts::detector detector_t>
156 : public surface_factory_interface<detector_t> {
157 using algebra_t = typename detector_t::algebra_type;
158 using scalar_t = dscalar<algebra_t>;
159 using point3_t = dpoint3D<algebra_t>;
160 using vector3_t = dvector3D<algebra_t>;
161 using transform3_t = dtransform3D<algebra_t>;
162
163 using surface_type = typename detector_t::surface_type;
164 using mask_id = typename detector_t::masks::id;
165 using mask_link_t = typename surface_type::mask_link;
166 using material_id = typename detector_t::material::id;
167 using material_link_t = typename surface_type::material_link;
168
170 struct bounding_box_creator {
172
173 template <typename mask_group_t, typename idx_range_t>
174 DETRAY_HOST_DEVICE inline void operator()(
175 const mask_group_t &mask_group, const idx_range_t &idx_range,
176 const scalar_t envelope, const transform3_t &trf,
177 std::vector<aabb_t> &boxes) const {
178 for (const auto &mask : detray::ranges::subrange(mask_group, idx_range)) {
179 // Local minimum bounding box
180 aabb_t box{mask, boxes.size(), envelope};
181 // Bounding box in global coordinates (might no longer be
182 // minimum)
183 boxes.push_back(box.transform(trf));
184 }
185 }
186 };
187
188 public:
190 struct boundaries {
192 scalar_t inner_radius{0.f};
194 scalar_t outer_radius{0.f};
196 scalar_t lower_z{0.f};
198 scalar_t upper_z{0.f};
199 };
200
203 DETRAY_HOST
206 : m_cfg{cfg} {}
207
209 DETRAY_HOST
210 auto size() const -> dindex override { return 4u; }
211
212 DETRAY_HOST
213 void clear() override { /*Do nothing*/ };
214
215 DETRAY_HOST
217 surface_data<detector_t> && /*unused*/) override { /*Do nothing*/ }
218
220 DETRAY_HOST
221 auto push_back(std::vector<surface_data<detector_t>> && /*unused*/)
222 -> void override { /*Do nothing*/ }
223
226 const boundaries &volume_boundaries() const { return m_boundaries; }
227
238 DETRAY_HOST
239 auto operator()(typename detector_t::volume_type &volume,
240 typename detector_t::surface_lookup_container &surfaces,
241 typename detector_t::transform_container &transforms,
242 typename detector_t::mask_container &masks,
243 typename detector_t::geometry_context ctx = {})
244 -> dindex_range override {
245 DETRAY_VERBOSE_HOST("Generate cylinder portals...");
246
248
249 // Only build portals for cylinder volumes
250 assert(volume.id() == volume_id::e_cylinder);
251 const dindex vol_idx{volume.index()};
252
253 const std::size_t n_surfaces{surfaces.size()};
254
255 if (!m_cfg.do_autofit()) {
256 // Without autofit, the portal bounds have to be given explicitly
257 assert(!(m_cfg.fixed_inner_radius() == 0.f &&
258 m_cfg.fixed_outer_radius() == 0.f) ||
259 m_cfg.fixed_half_length() != 0.f);
260 } else {
261 // Need surfaces in volume to do autofit
262 assert(n_surfaces != 0u);
263 }
264
265 scalar_t inner_r{m_cfg.fixed_inner_radius()};
266 scalar_t outer_r{m_cfg.fixed_outer_radius()};
267 scalar_t lower_z{-m_cfg.fixed_half_length()};
268 scalar_t upper_z{m_cfg.fixed_half_length()};
269
270 if (m_cfg.do_autofit()) {
271 // The bounding boxes around the module surfaces
272 std::vector<aabb_t> boxes;
273 boxes.reserve(n_surfaces);
274
275 for (const auto &sf : surfaces) {
276 masks.template visit<bounding_box_creator>(
277 sf.mask(), m_cfg.envelope(), transforms.at(sf.transform(), ctx),
278 boxes);
279 }
280
281 // Build an aabb in the global space around the surface aabbs
282 aabb_t world_box{boxes, boxes.size(), m_cfg.envelope()};
283 // translation
284 const point3_t center = world_box.template center<point3_t>();
285
286 // The world box local frame is the global coordinate frame
287 const point3_t box_min = world_box.template loc_min<point3_t>();
288 const point3_t box_max = world_box.template loc_max<point3_t>();
289
290 // Get the half lengths for the cylinder height and disc translation
291 const point3_t h_lengths = 0.5f * (box_max - box_min);
292 const scalar_t h_x{math::fabs(h_lengths[0])};
293 const scalar_t h_y{math::fabs(h_lengths[1])};
294 const scalar_t h_z{math::fabs(h_lengths[2])};
295
296 const scalar_t outer_r_min{math::max(h_x, h_y)};
297 const scalar_t mean_radius{get_mean_radius(surfaces, transforms)};
298
299 outer_r = outer_r_min;
300 inner_r = mean_radius - (outer_r - mean_radius);
301 lower_z = math::min(center[2] - h_z, center[2] + h_z);
302 upper_z = math::max(center[2] - h_z, center[2] + h_z);
303 }
304
305 // Observe boundary conditions
306 if (m_cfg.fixed_inner_radius() > 0.f) {
307 inner_r = m_cfg.fixed_inner_radius();
308 }
309 if (m_cfg.fixed_outer_radius() > 0.f) {
310 outer_r = m_cfg.fixed_outer_radius();
311 }
312 if (m_cfg.fixed_half_length() > 0.f) {
313 lower_z = -m_cfg.fixed_half_length();
314 upper_z = m_cfg.fixed_half_length();
315 }
316
317 m_boundaries = {inner_r, outer_r, lower_z, upper_z};
318
319 // If inner radius is 0, skip adding the inner cylinder
320 if (m_cfg.build_inner()) {
321 add_cylinder_portal(surfaces, transforms, masks, ctx, vol_idx,
322 m_cfg.link_south(), inner_r, lower_z, upper_z);
323 }
324 add_cylinder_portal(surfaces, transforms, masks, ctx, vol_idx,
325 m_cfg.link_north(), outer_r, lower_z, upper_z);
326
327 add_disc_portal(surfaces, transforms, masks, ctx, vol_idx,
328 m_cfg.link_west(), inner_r, outer_r, lower_z);
329 add_disc_portal(surfaces, transforms, masks, ctx, vol_idx,
330 m_cfg.link_east(), inner_r, outer_r, upper_z);
331
332 return {static_cast<dindex>(n_surfaces),
333 static_cast<dindex>(surfaces.size())};
334 }
335
336 private:
338 void add_cylinder_portal(
339 typename detector_t::surface_lookup_container &surfaces,
340 typename detector_t::transform_container &transforms,
341 typename detector_t::mask_container &masks,
342 typename detector_t::geometry_context ctx, dindex vol_idx,
343 dindex vol_link, const scalar_t r, const scalar_t lower_z,
344 const scalar_t upper_z) const {
345 constexpr auto invalid_src_link{detail::invalid_value<std::uint64_t>()};
346
347 const scalar_t min_z{math::min(lower_z, upper_z)};
348 const scalar_t max_z{math::max(lower_z, upper_z)};
349
350 // translation
351 const point3_t tsl{0.f, 0.f, 0.f};
352
353 // Add transform and mask data
354 transforms.emplace_back(ctx, tsl);
355 masks.template emplace_back<mask_id::e_concentric_cylinder2D>(
356 empty_context{}, vol_link, r, min_z, max_z);
357
358 // Add surface links
359 mask_link_t mask_link{};
360 const auto mask_idx{static_cast<dindex>(
361 masks.template size<mask_id::e_concentric_cylinder2D>() - 1u)};
362 set_mask_link(mask_link, mask_id::e_concentric_cylinder2D, mask_idx);
363
364 material_link_t material_link{material_id::e_none, dindex_invalid};
365
366 surfaces.push_back(
367 {static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
368 material_link, vol_idx, surface_id::e_portal},
369 invalid_src_link);
370 }
371
373 void add_disc_portal(typename detector_t::surface_lookup_container &surfaces,
374 typename detector_t::transform_container &transforms,
375 typename detector_t::mask_container &masks,
376 typename detector_t::geometry_context ctx,
377 dindex vol_idx, dindex vol_link, const scalar_t inner_r,
378 const scalar_t outer_r, const scalar_t z) const {
379 constexpr auto invalid_src_link{detail::invalid_value<std::uint64_t>()};
380
381 const scalar_t min_r{math::min(inner_r, outer_r)};
382 const scalar_t max_r{math::max(inner_r, outer_r)};
383
384 // translation
385 point3_t tsl{static_cast<scalar_t>(0), static_cast<scalar_t>(0), z};
386
387 // Add transform and mask data
388 transforms.emplace_back(ctx, tsl);
389 masks.template emplace_back<mask_id::e_ring2D>(empty_context{}, vol_link,
390 min_r, max_r);
391
392 // Add surface links
393 mask_link_t mask_link{};
394 const auto mask_idx{
395 static_cast<dindex>(masks.template size<mask_id::e_ring2D>() - 1u)};
396 set_mask_link(mask_link, mask_id::e_ring2D, mask_idx);
397
398 material_link_t material_link{material_id::e_none, dindex_invalid};
399
400 surfaces.push_back(
401 {static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
402 material_link, vol_idx, surface_id::e_portal},
403 invalid_src_link);
404 }
405
407 template <typename surface_container_t, typename transform_container_t>
408 scalar_t get_mean_radius(const surface_container_t &surfaces,
409 const transform_container_t &transforms) const {
410 double mean{0.};
411
412 for (const auto &sf_desc : surfaces) {
413 const auto &trf = transforms.at(sf_desc.transform());
414 mean += vector::perp(trf.translation());
415 }
416
417 return static_cast<scalar_t>(mean / static_cast<double>(surfaces.size()));
418 }
419
421 void set_mask_link(mask_link_t &mask_link, const mask_id id,
422 const dindex lower_idx) const {
423 mask_link.set_id(id);
424 if constexpr (concepts::interval<typename mask_link_t::index_type>) {
425 mask_link.set_index({lower_idx, 1u});
426 } else {
427 mask_link.set_index(lower_idx);
428 }
429 }
430
432 cylinder_portal_config<scalar_t> m_cfg;
434 boundaries m_boundaries{};
435};
436
437} // namespace detray
An axis aligned bounding box of a given.
Definition bounding_volume.hpp:32
cylinder_portal_generator(const cylinder_portal_config< scalar_t > &cfg)
Construct from configuration cfg.
Definition cylinder_portal_generator.hpp:204
void clear() override
Clear all data in the factory.
Definition cylinder_portal_generator.hpp:213
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
Create minimum aabbs around all surfaces that are passed and then construct cylinder and disc portals...
Definition cylinder_portal_generator.hpp:239
const boundaries & volume_boundaries() const
Access the volume boundaries after fitting.
Definition cylinder_portal_generator.hpp:226
auto size() const -> dindex override
Definition cylinder_portal_generator.hpp:210
void push_back(surface_data< detector_t > &&) override
Add data to the factory.
Definition cylinder_portal_generator.hpp:216
auto push_back(std::vector< surface_data< detector_t > > &&) -> void override
Ignore inserted surface records; portal geometry is derived from the existing volume surfaces when th...
Definition cylinder_portal_generator.hpp:221
Mask a region on a surface and link it to a volume.
Definition mask.hpp:46
Bind transform and mask data together for surface building.
Definition surface_factory_interface.hpp:37
virtual dindex size() const =0
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
unsigned int dindex
Default index type.
Definition indexing.hpp:18
constexpr dindex dindex_invalid
Global invalid index definition.
Definition indexing.hpp:21
get_vector3D_t< A, T > dvector3D
Three-dimensional vector type for algebra A and value type T.
Definition algebra.hpp:80
get_transform3D_t< A, T > dtransform3D
Three-dimensional transform type for algebra A and value type T.
Definition algebra.hpp:84
get_point3D_t< A, T > dpoint3D
Three-dimensional point type for algebra A and value type T.
Definition algebra.hpp:72
configuration for the cylinder portal generator
Definition cylinder_portal_generator.hpp:32
std::vector< dindex > m_volume_links
The portal volumes links (north, south, east, west).
Definition cylinder_portal_generator.hpp:47
constexpr cylinder_portal_config & link_north(const dindex l)
Set the volume adjacent to the north endcap.
Definition cylinder_portal_generator.hpp:97
constexpr cylinder_portal_config & link_east(const dindex l)
Set the volume adjacent to the outer cylindrical surface.
Definition cylinder_portal_generator.hpp:111
bool m_do_autofit
Autofit the lower/upper z extend and inner/outer radii.
Definition cylinder_portal_generator.hpp:37
constexpr cylinder_portal_config & fixed_half_length(const scalar_t z)
Set the half-length used when autofitting is disabled.
Definition cylinder_portal_generator.hpp:90
scalar_t m_fixed_outer_r
Fixed outer radius during autofit.
Definition cylinder_portal_generator.hpp:43
constexpr cylinder_portal_config & fixed_inner_radius(const scalar_t r)
Set the inner radius used when autofitting is disabled.
Definition cylinder_portal_generator.hpp:76
constexpr const auto & link_south() const
Definition cylinder_portal_generator.hpp:143
constexpr bool do_autofit() const
Definition cylinder_portal_generator.hpp:129
constexpr const auto & link_north() const
Definition cylinder_portal_generator.hpp:141
constexpr scalar_t fixed_inner_radius() const
Definition cylinder_portal_generator.hpp:133
scalar_t m_envelope
Minimal envelope for the portals (used in autofitting).
Definition cylinder_portal_generator.hpp:39
constexpr cylinder_portal_config & build_inner(const bool b)
SettersSet whether to create an inner cylindrical portal.
Definition cylinder_portal_generator.hpp:55
constexpr scalar_t envelope() const
Definition cylinder_portal_generator.hpp:131
constexpr const auto & volume_links() const
Definition cylinder_portal_generator.hpp:139
constexpr bool build_inner() const
Getters.
Definition cylinder_portal_generator.hpp:127
constexpr cylinder_portal_config & envelope(const scalar_t e)
Set the gap between fitted portals and the contained surfaces.
Definition cylinder_portal_generator.hpp:69
bool m_build_inner
Build inner cylinder portal (will use the same distance to the layer that was found for the outer cyl...
Definition cylinder_portal_generator.hpp:35
constexpr scalar_t fixed_outer_radius() const
Definition cylinder_portal_generator.hpp:135
constexpr cylinder_portal_config & do_autofit(const bool b)
Set whether portal bounds are fitted from the contained surfaces.
Definition cylinder_portal_generator.hpp:62
constexpr cylinder_portal_config & link_west(const dindex l)
Set the volume adjacent to the inner cylindrical surface.
Definition cylinder_portal_generator.hpp:118
constexpr cylinder_portal_config & fixed_outer_radius(const scalar_t r)
Set the outer radius used when autofitting is disabled.
Definition cylinder_portal_generator.hpp:83
scalar_t m_fixed_z
Fixed length of the cylinder.
Definition cylinder_portal_generator.hpp:45
scalar_t m_fixed_inner_r
Fixed inner radius during autofit.
Definition cylinder_portal_generator.hpp:41
constexpr scalar_t fixed_half_length() const
Definition cylinder_portal_generator.hpp:137
constexpr const auto & link_east() const
Definition cylinder_portal_generator.hpp:145
constexpr cylinder_portal_config & link_south(const dindex l)
Set the volume adjacent to the south endcap.
Definition cylinder_portal_generator.hpp:104
constexpr const auto & link_west() const
Definition cylinder_portal_generator.hpp:147
Save the boundaries of the cylinder after autofitting the portals.
Definition cylinder_portal_generator.hpp:190
scalar_t outer_radius
Outer radius of the fitted cylinder.
Definition cylinder_portal_generator.hpp:194
scalar_t upper_z
Upper axial coordinate of the fitted cylinder.
Definition cylinder_portal_generator.hpp:198
scalar_t lower_z
Lower axial coordinate of the fitted cylinder.
Definition cylinder_portal_generator.hpp:196
scalar_t inner_radius
Inner radius of the fitted cylinder.
Definition cylinder_portal_generator.hpp:192
interface type to construct a subrange_view with CTAD
Definition subrange.hpp:90
static constexpr scalar_t um
Length, native unit mm.
Definition units.hpp:25