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"
31template <concepts::scalar scalar_t>
154template <concepts::detector detector_t>
156 :
public surface_factory_interface<detector_t> {
157 using algebra_t =
typename detector_t::algebra_type;
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;
170 struct bounding_box_creator {
173 template <
typename mask_group_t,
typename idx_range_t>
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 {
180 aabb_t box{
mask, boxes.size(), envelope};
183 boxes.push_back(box.transform(trf));
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 = {})
245 DETRAY_VERBOSE_HOST(
"Generate cylinder portals...");
250 assert(volume.id() == volume_id::e_cylinder);
251 const dindex vol_idx{volume.index()};
253 const std::size_t n_surfaces{surfaces.size()};
255 if (!m_cfg.do_autofit()) {
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);
262 assert(n_surfaces != 0u);
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()};
270 if (m_cfg.do_autofit()) {
272 std::vector<aabb_t> boxes;
273 boxes.reserve(n_surfaces);
275 for (
const auto &sf : surfaces) {
276 masks.template visit<bounding_box_creator>(
277 sf.mask(), m_cfg.envelope(), transforms.at(sf.transform(), ctx),
282 aabb_t world_box{boxes, boxes.size(), m_cfg.envelope()};
284 const point3_t center = world_box.template center<point3_t>();
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>();
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])};
296 const scalar_t outer_r_min{math::max(h_x, h_y)};
297 const scalar_t mean_radius{get_mean_radius(surfaces, transforms)};
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);
306 if (m_cfg.fixed_inner_radius() > 0.f) {
307 inner_r = m_cfg.fixed_inner_radius();
309 if (m_cfg.fixed_outer_radius() > 0.f) {
310 outer_r = m_cfg.fixed_outer_radius();
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();
317 m_boundaries = {inner_r, outer_r, lower_z, upper_z};
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);
324 add_cylinder_portal(surfaces, transforms, masks, ctx, vol_idx,
325 m_cfg.link_north(), outer_r, lower_z, upper_z);
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);
332 return {
static_cast<dindex>(n_surfaces),
333 static_cast<dindex>(surfaces.size())};
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>()};
347 const scalar_t min_z{math::min(lower_z, upper_z)};
348 const scalar_t max_z{math::max(lower_z, upper_z)};
351 const point3_t tsl{0.f, 0.f, 0.f};
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);
359 mask_link_t mask_link{};
360 const auto mask_idx{
static_cast<dindex>(
362 set_mask_link(mask_link, mask_id::e_concentric_cylinder2D, mask_idx);
364 material_link_t material_link{material_id::e_none,
dindex_invalid};
367 {
static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
368 material_link, vol_idx, surface_id::e_portal},
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>()};
381 const scalar_t min_r{math::min(inner_r, outer_r)};
382 const scalar_t max_r{math::max(inner_r, outer_r)};
385 point3_t tsl{
static_cast<scalar_t
>(0),
static_cast<scalar_t
>(0), z};
388 transforms.emplace_back(ctx, tsl);
389 masks.template emplace_back<mask_id::e_ring2D>(empty_context{}, vol_link,
393 mask_link_t mask_link{};
396 set_mask_link(mask_link, mask_id::e_ring2D, mask_idx);
398 material_link_t material_link{material_id::e_none,
dindex_invalid};
401 {
static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
402 material_link, vol_idx, surface_id::e_portal},
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 {
412 for (
const auto &sf_desc : surfaces) {
413 const auto &trf = transforms.at(sf_desc.transform());
414 mean += vector::perp(trf.translation());
417 return static_cast<scalar_t
>(mean /
static_cast<double>(surfaces.size()));
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});
427 mask_link.set_index(lower_idx);
432 cylinder_portal_config<scalar_t> m_cfg;
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