diff --git a/core/include/detray/surface_finders/brute_force_finder.hpp b/core/include/detray/surface_finders/brute_force_finder.hpp index 2fda8b1920..9d448f6e14 100644 --- a/core/include/detray/surface_finders/brute_force_finder.hpp +++ b/core/include/detray/surface_finders/brute_force_finder.hpp @@ -28,9 +28,9 @@ namespace detray { /// /// This class fulfills all criteria to be used in the detector @c multi_store . /// -/// @tparam surface_t the type of surface data handles in a detector. +/// @tparam value_t the entry type in the collection (e.g. surface descriptors). /// @tparam container_t the types of underlying containers to be used. -template +template class brute_force_collection { public: @@ -42,16 +42,16 @@ class brute_force_collection { /// force). This type will be returned when the surface collection is /// queried for the surfaces of a particular volume. struct brute_forcer - : public detray::ranges::subrange> { + : public detray::ranges::subrange> { - using base = detray::ranges::subrange>; + using base = detray::ranges::subrange>; /// Default constructor brute_forcer() = default; /// Constructor from @param surface_range - move DETRAY_HOST_DEVICE constexpr brute_forcer( - const vector_type& surfaces, const dindex_range& range) + const vector_type& surfaces, const dindex_range& range) : base(surfaces, range) {} /// @returns the complete surface range of the search volume @@ -64,11 +64,11 @@ class brute_force_collection { } /// @returns the surface at a given index @param i - const - DETRAY_HOST_DEVICE constexpr surface_t at(const dindex i) const { + DETRAY_HOST_DEVICE constexpr value_t at(const dindex i) const { return (*this)[i]; } /// @returns the surface at a given index @param i - non-const - DETRAY_HOST_DEVICE constexpr surface_t& at(const dindex i) { + DETRAY_HOST_DEVICE constexpr value_t& at(const dindex i) { return (*this)[i]; } @@ -86,11 +86,11 @@ class brute_force_collection { using value_type = brute_forcer; using view_type = - dmulti_view, dvector_view>; - using const_view_type = dmulti_view, - dvector_view>; + dmulti_view, dvector_view>; + using const_view_type = + dmulti_view, dvector_view>; using buffer_type = - dmulti_buffer, dvector_buffer>; + dmulti_buffer, dvector_buffer>; /// Default constructor constexpr brute_force_collection() { @@ -140,11 +140,11 @@ class brute_force_collection { /// @return access to the surface container - const. DETRAY_HOST_DEVICE - auto all() const -> const vector_type& { return m_surfaces; } + auto all() const -> const vector_type& { return m_surfaces; } /// @return access to the surface container - non-const. DETRAY_HOST_DEVICE - auto all() -> vector_type& { return m_surfaces; } + auto all() -> vector_type& { return m_surfaces; } /// Create brute force surface finder from surface container - const DETRAY_HOST_DEVICE @@ -153,13 +153,12 @@ class brute_force_collection { } /// Add a new surface collection - template < - typename sf_container_t, - typename std::enable_if_t, - bool> = true, - typename std::enable_if_t< - std::is_same_v, - bool> = true> + template , + bool> = true, + typename std::enable_if_t< + std::is_same_v, + bool> = true> DETRAY_HOST auto push_back(const sf_container_t& surfaces) noexcept(false) -> void { m_surfaces.reserve(m_surfaces.size() + surfaces.size()); @@ -170,7 +169,7 @@ class brute_force_collection { /// Remove surface from collection DETRAY_HOST auto erase( - typename vector_type::iterator pos) noexcept(false) { + typename vector_type::iterator pos) noexcept(false) { // Remove one element auto next = m_surfaces.erase(pos); @@ -203,7 +202,7 @@ class brute_force_collection { /// Offsets for the respective volumes into the surface storage vector_type m_offsets{}; /// The storage for all surface handles - vector_type m_surfaces{}; + vector_type m_surfaces{}; }; } // namespace detray diff --git a/core/include/detray/tools/detector_builder.hpp b/core/include/detray/tools/detector_builder.hpp index 57b0339215..6e21a863c0 100644 --- a/core/include/detray/tools/detector_builder.hpp +++ b/core/include/detray/tools/detector_builder.hpp @@ -94,7 +94,7 @@ class detector_builder { /// Put the volumes into a search data structure template - DETRAY_HOST void set_volume_finder(Args&&... /*args*/) { + DETRAY_HOST void set_volume_finder([[maybe_unused]] Args&&... args) { using vol_finder_t = typename detector_type::volume_finder; @@ -114,9 +114,16 @@ class detector_builder { n_axis::open, n_axis::irregular<>, n_axis::regular<>, n_axis::irregular<>>(vgrid_dims, n_vgrid_bins); + } else { + m_vol_finder = vol_finder_t{args...}; } } + /// @returns access to the volume finder + DETRAY_HOST typename detector_type::volume_finder& volume_finder() { + return m_vol_finder; + } + protected: /// Data structure that holds a volume builder for every detector volume volume_data_t>> diff --git a/core/include/detray/tools/material_factory.hpp b/core/include/detray/tools/material_factory.hpp index f4f22bbc31..fd22811775 100644 --- a/core/include/detray/tools/material_factory.hpp +++ b/core/include/detray/tools/material_factory.hpp @@ -111,7 +111,7 @@ class material_factory final : public factory_decorator { /// @returns the number of material instances that will be built by the /// factory DETRAY_HOST - auto size() const -> dindex { + auto n_materials() const -> dindex { const dindex n_surfaces{static_cast(m_links.size())}; @@ -194,8 +194,12 @@ class material_factory final : public factory_decorator { using mat_types = typename detector_t::material_container::value_types; using link_t = typename detector_t::surface_type::material_link; + if (m_materials.empty()) { + return; + } + // Check that the surfaces were set up correctly - const std::size_t n_materials{this->size()}; + const std::size_t n_materials{this->n_materials()}; assert(surfaces.size() >= n_materials); // If no concrete surface ordering was passed, use index sequence diff --git a/core/include/detray/tools/telescope_generator.hpp b/core/include/detray/tools/telescope_generator.hpp new file mode 100644 index 0000000000..d421c9e39a --- /dev/null +++ b/core/include/detray/tools/telescope_generator.hpp @@ -0,0 +1,211 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +#pragma once + +// Project include(s) +#include "detray/core/detail/data_context.hpp" +#include "detray/definitions/geometry.hpp" +#include "detray/definitions/indexing.hpp" +#include "detray/definitions/qualifiers.hpp" +#include "detray/masks/masks.hpp" +#include "detray/masks/rectangle2D.hpp" +#include "detray/tools/surface_factory_interface.hpp" + +// System include(s) +#include +#include + +namespace detray { + +/// @brief Generates a number of surfaces along a given direction +/// +/// @tparam detector_t the type of detector the volume belongs to. +template , + typename trajectory_t = detail::ray> +class telescope_generator final : public surface_factory_interface { + + using scalar_t = typename detector_t::scalar_type; + using transform3_t = typename detector_t::transform3; + using point3_t = typename detector_t::point3; + using vector3_t = typename detector_t::vector3; + + public: + /// Build a surface at with extent given in @param boundaries at every + /// position in @param positions along the pilot-track @param traj. + DETRAY_HOST + telescope_generator( + std::vector positions, + std::array boundaries, + trajectory_t traj) + : m_traj{traj}, m_positions{positions}, m_boundaries{boundaries} {} + + /// Infer the sensitive surface placement from the telescope @param length + /// if no concrete positions were given. + /// @param n_surfaces number of surfaces to be generated + /// @param boundaries mask boundaries of the surfaces + /// @param traj pilot track along which to build the telescope + DETRAY_HOST + telescope_generator( + scalar_t length, std::size_t n_surfaces, + std::array boundaries, + trajectory_t traj) + : m_traj{traj}, m_positions{}, m_boundaries{boundaries} { + scalar_t pos{0.f}; + scalar_t dist{n_surfaces > 1u + ? length / static_cast(n_surfaces - 1u) + : 0.f}; + for (std::size_t i = 0u; i < n_surfaces; ++i) { + m_positions.push_back(pos); + pos += dist; + } + } + + /// @returns the number of surfaces this factory will produce + DETRAY_HOST + auto size() const -> dindex override { + return static_cast(m_positions.size()); + } + + /// Clear the positions and boundaries of the surfaces. + DETRAY_HOST + void clear() override { + m_positions.clear(); + m_boundaries = {}; + }; + + /// This is a surface generator, no external surface data needed + /// @{ + DETRAY_HOST + void push_back(surface_data &&) override { /*Do nothing*/ + } + DETRAY_HOST + auto push_back(std::vector> &&) + -> void override { /*Do nothing*/ + } + /// @} + + /// Create a surface telescope. + /// + /// @param volume the volume the portals need to be added to. + /// @param surfaces the surface collection to wrap and to add the portals to + /// @param transforms the transforms of the surfaces. + /// @param masks the masks of the surfaces. + /// @param ctx the geometry context (not needed for portals). + DETRAY_HOST + auto operator()(typename detector_t::volume_type &volume, + typename detector_t::surface_container_t &surfaces, + typename detector_t::transform_container &transforms, + typename detector_t::mask_container &masks, + typename detector_t::geometry_context ctx = {}) const + -> dindex_range override { + + using surface_t = typename detector_t::surface_type; + using nav_link_t = typename surface_t::navigation_link; + using mask_link_t = typename surface_t::mask_link; + using material_link_t = typename surface_t::material_link; + + const dindex surfaces_offset{static_cast(surfaces.size())}; + + // The type id of the surface mask shape + constexpr auto mask_id{detector_t::mask_container::template get_id< + mask>::value}; + + // The material will be added in a later step + constexpr auto no_material{surface_t::material_id::e_none}; + + auto volume_idx{volume.index()}; + + // Create the module centers + const auto mod_placements = module_positions(m_traj, m_positions); + + // Create geometry data + for (const auto &mod_placement : mod_placements) { + + auto mask_volume_link{static_cast(volume_idx)}; + + // Surfaces with the linking into the local containers + mask_link_t mask_link{mask_id, masks.template size()}; + material_link_t material_link{ + no_material, + detail::invalid_value()}; + + const auto trf_index = transforms.size(ctx); + surfaces.emplace_back(trf_index, mask_link, material_link, + volume_idx, dindex_invalid, + surface_id::e_sensitive); + + // The rectangle bounds for this module + masks.template emplace_back(empty_context{}, m_boundaries, + mask_volume_link); + + // Build the transform + // Local z axis is the global normal vector + vector3_t m_local_z = algebra::vector::normalize(mod_placement.dir); + + // Project onto the weakest direction component of the normal vector + vector3_t e_i{0.f, 0.f, 0.f}; + scalar_t min{std::numeric_limits::max()}; + unsigned int i{std::numeric_limits::max()}; + for (unsigned int k = 0u; k < 3u; ++k) { + if (m_local_z[k] < min) { + min = m_local_z[k]; + i = k; + } + } + e_i[i] = 1.f; + vector3_t proj = algebra::vector::dot(m_local_z, e_i) * m_local_z; + // Local x axis is the normal to local y,z + vector3_t m_local_x = algebra::vector::normalize(e_i - proj); + + // Create the global-to-local transform of the module + transforms.emplace_back(ctx, mod_placement.pos, m_local_z, + m_local_x); + } + + return {surfaces_offset, static_cast(surfaces.size())}; + } + + private: + /// Where and how to place the telescope modules. + struct module_placement { + /// Module position + point3_t pos; + /// Module normal + vector3_t dir; + }; + + /// Helper method for positioning the surfaces. + /// + /// @param traj pilot trajectory along which the modules should be placed. + /// @param steps lengths along the trajectory where surfaces should be + /// placed. + /// + /// @return a vector of the @c module_placements along the trajectory. + inline std::vector module_positions( + const trajectory_t &traj, const std::vector &steps) const { + + // create and fill the module placements + std::vector placements; + placements.reserve(steps.size()); + + for (const auto s : steps) { + placements.push_back({traj.pos(s), traj.dir(s)}); + } + + return placements; + } + + /// "pilot-track" along which to place the surfaces + trajectory_t m_traj; + /// Positions of the surfaces in the telescope along the pilot track + std::vector m_positions; + /// The boundary values for the surface mask + std::array m_boundaries; +}; + +} // namespace detray diff --git a/tests/unit_tests/cpu/material_interaction.cpp b/tests/unit_tests/cpu/material_interaction.cpp index bd3c711ffa..8626c575c6 100644 --- a/tests/unit_tests/cpu/material_interaction.cpp +++ b/tests/unit_tests/cpu/material_interaction.cpp @@ -20,6 +20,7 @@ #include "detray/propagator/actors/parameter_resetter.hpp" #include "detray/propagator/actors/parameter_transporter.hpp" #include "detray/propagator/actors/pointwise_material_interactor.hpp" +#include "detray/propagator/line_stepper.hpp" #include "detray/propagator/navigator.hpp" #include "detray/propagator/propagator.hpp" #include "detray/propagator/rk_stepper.hpp" diff --git a/tests/unit_tests/io/io_json_detector_reader.cpp b/tests/unit_tests/io/io_json_detector_reader.cpp index eb953c7175..25510f901c 100644 --- a/tests/unit_tests/io/io_json_detector_reader.cpp +++ b/tests/unit_tests/io/io_json_detector_reader.cpp @@ -119,9 +119,9 @@ TEST(io, json_telescope_detector_reader) { writer_cfg.replace_files(false); io::write_detector(det, names, writer_cfg); - // Not equal due to missing data deduplication in IO - /*EXPECT_TRUE(compare_files("telescope_detector_geometry.json", - * "telescope_detector_geometry_2.json"));*/ + // Compare writing round-trip + EXPECT_TRUE(compare_files("telescope_detector_geometry.json", + "telescope_detector_geometry_2.json")); EXPECT_TRUE( compare_files("telescope_detector_homogeneous_material.json", "telescope_detector_homogeneous_material_2.json")); diff --git a/utils/include/detray/detectors/create_telescope_detector.hpp b/utils/include/detray/detectors/create_telescope_detector.hpp index 76f824011b..09a0602918 100644 --- a/utils/include/detray/detectors/create_telescope_detector.hpp +++ b/utils/include/detray/detectors/create_telescope_detector.hpp @@ -13,18 +13,20 @@ #include "detray/detectors/telescope_metadata.hpp" #include "detray/masks/masks.hpp" #include "detray/materials/predefined_materials.hpp" -#include "detray/propagator/line_stepper.hpp" -#include "detray/tools/bounding_volume.hpp" +#include "detray/tools/cuboid_portal_generator.hpp" +#include "detray/tools/detector_builder.hpp" +#include "detray/tools/material_builder.hpp" +#include "detray/tools/telescope_generator.hpp" +#include "detray/utils/consistency_checker.hpp" // Vecmem include(s) #include // System include(s) #include -#include #include -#include -#include +#include +#include namespace detray { @@ -63,6 +65,8 @@ struct tel_det_config { trajectory_t m_trajectory{}; /// Safety envelope between the test surfaces and the portals scalar m_envelope{0.1f * unit::mm}; + /// Run detector consistency check after reading + bool m_do_check{true}; /// Setters /// @{ @@ -105,6 +109,10 @@ struct tel_det_config { m_envelope = e; return *this; } + tel_det_config &do_check(const bool check) { + m_do_check = check; + return *this; + } /// @} /// Getters @@ -119,289 +127,10 @@ struct tel_det_config { constexpr scalar mat_thickness() const { return m_thickness; } const trajectory_t &pilot_track() const { return m_trajectory; } constexpr scalar envelope() const { return m_envelope; } + bool do_check() const { return m_do_check; } /// @} }; -/// Where and how to place the telescope modules. -struct module_placement { - - // @Note: These type definitions should be removed at some point - using point3 = __plugin::point3; - using vector3 = __plugin::vector3; - - /// Module position - point3 _pos; - /// Module normal - vector3 _dir; - - bool operator==(const module_placement &other) const { - bool is_same = true; - is_same &= (_pos == other._pos); - is_same &= (_dir == other._dir); - return is_same; - } -}; - -/// Helper method for positioning the plane surfaces. -/// -/// @param traj pilot trajectory along which the modules should be placed. -/// @param steps lengths along the trajectory where surfaces should be placed. -/// -/// @return a vector of the @c module_placements along the trajectory. -template -inline std::vector module_positions( - const trajectory_t &traj, const std::vector &steps) { - - // create and fill the module placements - std::vector placements; - placements.reserve(steps.size()); - - for (const auto s : steps) { - placements.push_back({traj.pos(s), traj.dir(s)}); - } - - return placements; -} - -/// Helper function to create minimum aabbs around all module surfaces in the -/// telescope and then construct world portals from the global bounding box. -/// This assumes that the module surfaces are already built inside the -/// argument containers. -/// -/// @param ctx geometry context. -/// @param pt_envelope envelope around the module surfaces for the portals. -/// @param volume the single cuboid volume that the portals will be added to. -/// @param surfaces the module surface descriptors. -/// @param masks the module masks. -/// @param materials the materials (only needed to add the portal materials). -/// @param transforms the module surface transforms. -template -inline void create_cuboid_portals(context_t &ctx, const scalar pt_envelope, - volume_t &volume, - surface_container_t &surfaces, - mask_container_t &masks, - material_container_t &materials, - transform_container_t &transforms) { - // @Note: These type definitions should be removed at some point - using point3 = __plugin::point3; - using vector3 = __plugin::vector3; - - using surface_t = typename surface_container_t::value_type; - using nav_link_t = typename surface_t::navigation_link; - using mask_link_t = typename surface_t::mask_link; - using material_link_t = typename surface_t::material_link; - - using aabb_t = axis_aligned_bounding_volume>; - - constexpr auto rectangle_id{mask_container_t::ids::e_portal_rectangle2}; - constexpr auto slab_id{material_container_t::ids::e_slab}; - - // Envelope for the module surface minimum aabb - constexpr scalar envelope{10.f * std::numeric_limits::epsilon()}; - // Max distance in case of infinite bounds - constexpr scalar max_shift{0.01f * std::numeric_limits::max()}; - - // The bounding boxes around the module surfaces - std::vector boxes; - boxes.reserve(surfaces.size()); - - const auto &mask_collection = masks.template get(); - - for (const auto &sf : surfaces) { - // Local minimum bounding box - aabb_t box{mask_collection[sf.mask().index()], boxes.size(), envelope}; - // Minimum bounding box in global coordinates - boxes.push_back(box.transform(transforms[sf.transform()])); - } - // Build an aabb in the global space around the surface aabbs - aabb_t world_box{boxes, boxes.size(), pt_envelope}; - - // translation - const point3 center = world_box.template center(); - - // The world box local frame is the global coordinate frame - const point3 box_min = world_box.template loc_min(); - const point3 box_max = world_box.template loc_max(); - - // Get the half lengths for the rectangle sides and translation - const point3 h_lengths = 0.5f * (box_max - box_min); - const scalar h_x{math_ns::abs(h_lengths[0])}; - const scalar h_y{math_ns::abs(h_lengths[1])}; - const scalar h_z{math_ns::abs(h_lengths[2])}; - - // Volume links for the portal descriptors and the masks - const dindex volume_idx{volume.index()}; - const nav_link_t volume_link{detail::invalid_value()}; - - // Construct portals in the... - - // - // ... x-y plane - // - // Only one rectangle needed for both surfaces - mask_link_t mask_link{rectangle_id, masks.template size()}; - masks.template emplace_back(empty_context{}, volume_link, h_x, - h_y); - - // No rotation, but shift in z for both faces - vector3 shift{0.f, 0.f, std::isinf(h_z) ? max_shift : h_z}; - transforms.emplace_back(ctx, static_cast(center + shift)); - transforms.emplace_back(ctx, static_cast(center - shift)); - - // Add material slab (no material on the portals) - material_link_t material_link{slab_id, materials.template size()}; - materials.template emplace_back(empty_context{}, vacuum{}, - 0.f); - - // Build the portal surfaces - dindex trf_idx{transforms.size(ctx) - 2}; - surfaces.emplace_back(trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); - - surfaces.emplace_back(++trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); - - // - // ... x-z plane - // - ++mask_link; - masks.template emplace_back(empty_context{}, volume_link, h_x, - h_z); - - // Rotate by 90deg around x-axis, plus shift in y - shift = {0.f, std::isinf(h_y) ? max_shift : h_y, 0.f}; - vector3 new_x{1.f, 0.f, 0.f}; - vector3 new_z{0.f, -1.f, 0.f}; - transforms.emplace_back(ctx, static_cast(center + shift), new_z, - new_x); - transforms.emplace_back(ctx, static_cast(center - shift), new_z, - new_x); - - ++material_link; - materials.template emplace_back(empty_context{}, vacuum{}, - 0.f); - - surfaces.emplace_back(++trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); - - surfaces.emplace_back(++trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); - - // - // ... y-z plane - // - ++mask_link; - masks.template emplace_back(empty_context{}, volume_link, h_z, - h_y); - - // Rotate by 90deg around y-axis, plus shift in x - shift = {std::isinf(h_x) ? max_shift : h_x, 0.f, 0.f}; - new_x = {0.f, 0.f, -1.f}; - new_z = {1.f, 0.f, 0.f}; - transforms.emplace_back(ctx, static_cast(center + shift), new_z, - new_x); - transforms.emplace_back(ctx, static_cast(center - shift), new_z, - new_x); - - ++material_link; - materials.template emplace_back(empty_context{}, vacuum{}, - 0.f); - - surfaces.emplace_back(++trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); - - surfaces.emplace_back(++trf_idx, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_portal); -} - -/// Helper function that creates the telescope surfaces. -/// -/// @param ctx geometric context -/// @param traj pilot trajectory along which the modules should be placed -/// @param volume volume the planes should be added to -/// @param surfaces container to add new surface to -/// @param masks container to add new cylinder mask to -/// @param transforms container to add new transform to -/// @param cfg config struct for module creation -template -inline void create_telescope(context_t &ctx, volume_t &volume, - surface_container_t &surfaces, - mask_container_t &masks, - material_container_t &materials, - transform_container_t &transforms, - const config_t &cfg, - const std::vector &positions) { - // @Note: These type definitions should be removed at some point - using vector3 = __plugin::vector3; - - using surface_type = typename surface_container_t::value_type; - using nav_link_t = typename surface_type::navigation_link; - using mask_link_t = typename surface_type::mask_link; - using material_link_t = typename surface_type::material_link; - - auto volume_idx = volume.index(); - constexpr auto slab_id = material_link_t::id_type::e_slab; - - // Create the module centers - const std::vector m_placements = - module_positions(cfg.pilot_track(), positions); - - // Create geometry data - for (const auto &m_placement : m_placements) { - - auto mask_volume_link{static_cast(volume_idx)}; - - // Surfaces with the linking into the local containers - mask_link_t mask_link{mask_id, masks.template size()}; - material_link_t material_link{slab_id, - materials.template size()}; - const auto trf_index = transforms.size(ctx); - surfaces.emplace_back(trf_index, mask_link, material_link, volume_idx, - dindex_invalid, surface_id::e_sensitive); - - // The rectangle bounds for this module - masks.template emplace_back( - empty_context{}, cfg.module_mask().values(), mask_volume_link); - - // Lines need different material - using mask_t = typename mask_container_t::template get_type; - if (mask_t::shape::name == "line") { - materials.template emplace_back( - empty_context{}, cfg.module_material(), cfg.mat_thickness()); - } else { - materials.template emplace_back( - empty_context{}, cfg.module_material(), cfg.mat_thickness()); - } - - // Build the transform - // Local z axis is the global normal vector - vector3 m_local_z = algebra::vector::normalize(m_placement._dir); - - // Project onto the weakest direction component of the normal vector - vector3 e_i{0.f, 0.f, 0.f}; - scalar min = std::numeric_limits::infinity(); - unsigned int i{std::numeric_limits::max()}; - for (unsigned int k = 0u; k < 3u; ++k) { - if (m_local_z[k] < min) { - min = m_local_z[k]; - i = k; - } - } - e_i[i] = 1.f; - vector3 proj = algebra::vector::dot(m_local_z, e_i) * m_local_z; - // Local x axis is the normal to local y,z - vector3 m_local_x = algebra::vector::normalize(e_i - proj); - - // Create the global-to-local transform of the module - transforms.emplace_back(ctx, m_placement._pos, m_local_z, m_local_x); - } -} - } // namespace /// Builds a detray geometry that contains only one volume with one type of @@ -414,6 +143,7 @@ inline void create_telescope(context_t &ctx, volume_t &volume, /// @tparam trajectory_t the type of the pilot trajectory /// /// @param resource the memory resource for the detector containers +/// @param cfg configuration struct of the telescope detector /// /// @returns a complete detector object template , @@ -423,64 +153,74 @@ inline auto create_telescope_detector( const tel_det_config &cfg = { 20.f * unit::mm, 20.f * unit::mm}) { - // detector type - using detector_t = - detector, host_container_types>; + detector_builder, volume_builder> + det_builder; + + using detector_t = typename decltype(det_builder)::detector_type; // Detector and volume names typename detector_t::name_map name_map = {{0u, "telescope_detector"}, {1u, "telescope_world_0"}}; - // Infer the snesitive surface placement from the telescope length if no - // concrete positions were given - std::vector positions; - if (cfg.positions().empty()) { - scalar pos{0.f}; - scalar dist{cfg.n_surfaces() > 1u - ? cfg.length() / - static_cast(cfg.n_surfaces() - 1u) - : 0.f}; - for (std::size_t i = 0u; i < cfg.n_surfaces(); ++i) { - positions.push_back(pos); - pos += dist; - } - } else { - std::copy(cfg.positions().begin(), cfg.positions().end(), - std::back_inserter(positions)); - } + // Create an empty cuboid volume with homogeneous material description + auto v_builder = det_builder.new_volume(volume_id::e_cuboid); + const dindex vol_idx{v_builder->vol_index()}; + auto vm_builder = + det_builder.template decorate>(vol_idx); + + // Identity transform + vm_builder->add_volume_placement(); + + // Add module surfaces to volume + using telescope_factory = + telescope_generator; + auto tel_generator = + cfg.positions().empty() + ? std::make_unique( + cfg.length(), cfg.n_surfaces(), cfg.module_mask().values(), + cfg.pilot_track()) + : std::make_unique(cfg.positions(), + cfg.module_mask().values(), + cfg.pilot_track()); // @todo: Temporal restriction due to missing local navigation - assert((positions.size() < 20u) && + assert((tel_generator->size() < 20u) && "Due to WIP, please choose less than 20 surfaces for now"); - // create empty detector - detector_t det(resource); + std::vector> sf_materials( + tel_generator->size(), + material_data{cfg.mat_thickness(), cfg.module_material()}); - typename detector_t::geometry_context ctx{}; + using material_id = typename detector_t::materials::id; + const auto mat_id = (mask_shape_t::name == "line") ? material_id::e_rod + : material_id::e_slab; - // The telescope detector has only one volume with default placement - auto &vol = det.new_volume(volume_id::e_cuboid, - {detector_t::sf_finders::id::e_default, 0u}); - vol.set_transform(det.transform_store().size()); - det.transform_store().emplace_back(); + auto tel_mat_generator = std::make_shared>( + std::move(tel_generator)); + tel_mat_generator->add_material(mat_id, std::move(sf_materials)); - // Add module surfaces to volume - typename detector_t::surface_container_t surfaces(&resource); - typename detector_t::mask_container masks(resource); - typename detector_t::material_container materials(resource); - typename detector_t::transform_container transforms(resource); - - constexpr auto mask_id{ - detector_t::mask_container::template get_id>::value}; - - create_telescope(ctx, vol, surfaces, masks, materials, transforms, - cfg, positions); - // Add portals to volume - create_cuboid_portals(ctx, cfg.envelope(), vol, surfaces, masks, - materials, transforms); - // Add volme to the detector - det.add_objects_per_volume(ctx, vol, surfaces, masks, transforms, - materials); + // Add a portal box around the cuboid volume + auto portal_generator = std::make_shared>( + std::make_unique>(cfg.envelope())); + + // @TODO: Put no material instead of 'vacuum' + std::vector> pt_materials( + portal_generator->size(), material_data{0.f, vacuum{}}); + portal_generator->add_material(detector_t::materials::id::e_slab, + std::move(pt_materials)); + + vm_builder->add_surfaces(tel_mat_generator); + vm_builder->add_surfaces(portal_generator); + + det_builder.set_volume_finder(resource); + det_builder.volume_finder().push_back(std::vector{vol_idx}); + + // Build and return the detector + auto det = det_builder.build(resource); + + if (cfg.do_check()) { + detray::detail::check_consistency(det); + } return std::make_pair(std::move(det), std::move(name_map)); } diff --git a/utils/include/detray/detectors/telescope_metadata.hpp b/utils/include/detray/detectors/telescope_metadata.hpp index c761842735..c06eb3d376 100644 --- a/utils/include/detray/detectors/telescope_metadata.hpp +++ b/utils/include/detray/detectors/telescope_metadata.hpp @@ -132,7 +132,7 @@ struct telescope_metadata { /// Volume search (only one volume exists) template - using volume_finder = brute_force_collection; + using volume_finder = brute_force_collection; }; } // namespace detray