Skip to content

Commit

Permalink
Reimplement the telescope detector creation using the detector builde…
Browse files Browse the repository at this point in the history
…r tools.

 The creation of the telescope modules has been moved into a
dedicated surface factory and for the portals the cuboid_portal_generator is used.
  • Loading branch information
niermann999 committed Oct 19, 2023
1 parent 77a8f7c commit d9468fb
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 360 deletions.
43 changes: 21 additions & 22 deletions core/include/detray/surface_finders/brute_force_finder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class surface_t, typename container_t = host_container_types>
template <class value_t, typename container_t = host_container_types>
class brute_force_collection {

public:
Expand All @@ -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<const vector_type<surface_t>> {
: public detray::ranges::subrange<const vector_type<value_t>> {

using base = detray::ranges::subrange<const vector_type<surface_t>>;
using base = detray::ranges::subrange<const vector_type<value_t>>;

/// Default constructor
brute_forcer() = default;

/// Constructor from @param surface_range - move
DETRAY_HOST_DEVICE constexpr brute_forcer(
const vector_type<surface_t>& surfaces, const dindex_range& range)
const vector_type<value_t>& surfaces, const dindex_range& range)
: base(surfaces, range) {}

/// @returns the complete surface range of the search volume
Expand All @@ -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];
}

Expand All @@ -86,11 +86,11 @@ class brute_force_collection {
using value_type = brute_forcer;

using view_type =
dmulti_view<dvector_view<size_type>, dvector_view<surface_t>>;
using const_view_type = dmulti_view<dvector_view<const size_type>,
dvector_view<const surface_t>>;
dmulti_view<dvector_view<size_type>, dvector_view<value_t>>;
using const_view_type =
dmulti_view<dvector_view<const size_type>, dvector_view<const value_t>>;
using buffer_type =
dmulti_buffer<dvector_buffer<size_type>, dvector_buffer<surface_t>>;
dmulti_buffer<dvector_buffer<size_type>, dvector_buffer<value_t>>;

/// Default constructor
constexpr brute_force_collection() {
Expand Down Expand Up @@ -140,11 +140,11 @@ class brute_force_collection {

/// @return access to the surface container - const.
DETRAY_HOST_DEVICE
auto all() const -> const vector_type<surface_t>& { return m_surfaces; }
auto all() const -> const vector_type<value_t>& { return m_surfaces; }

/// @return access to the surface container - non-const.
DETRAY_HOST_DEVICE
auto all() -> vector_type<surface_t>& { return m_surfaces; }
auto all() -> vector_type<value_t>& { return m_surfaces; }

/// Create brute force surface finder from surface container - const
DETRAY_HOST_DEVICE
Expand All @@ -153,13 +153,12 @@ class brute_force_collection {
}

/// Add a new surface collection
template <
typename sf_container_t,
typename std::enable_if_t<detray::ranges::range_v<sf_container_t>,
bool> = true,
typename std::enable_if_t<
std::is_same_v<typename sf_container_t::value_type, surface_t>,
bool> = true>
template <typename sf_container_t,
typename std::enable_if_t<detray::ranges::range_v<sf_container_t>,
bool> = true,
typename std::enable_if_t<
std::is_same_v<typename sf_container_t::value_type, value_t>,
bool> = true>
DETRAY_HOST auto push_back(const sf_container_t& surfaces) noexcept(false)
-> void {
m_surfaces.reserve(m_surfaces.size() + surfaces.size());
Expand All @@ -170,7 +169,7 @@ class brute_force_collection {

/// Remove surface from collection
DETRAY_HOST auto erase(
typename vector_type<surface_t>::iterator pos) noexcept(false) {
typename vector_type<value_t>::iterator pos) noexcept(false) {
// Remove one element
auto next = m_surfaces.erase(pos);

Expand Down Expand Up @@ -203,7 +202,7 @@ class brute_force_collection {
/// Offsets for the respective volumes into the surface storage
vector_type<size_type> m_offsets{};
/// The storage for all surface handles
vector_type<surface_t> m_surfaces{};
vector_type<value_t> m_surfaces{};
};

} // namespace detray
9 changes: 8 additions & 1 deletion core/include/detray/tools/detector_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class detector_builder {

/// Put the volumes into a search data structure
template <typename... Args>
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;

Expand All @@ -114,9 +114,16 @@ class detector_builder {
n_axis::open<n_axis::label::e_z>, 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<std::unique_ptr<volume_builder_interface<detector_type>>>
Expand Down
8 changes: 6 additions & 2 deletions core/include/detray/tools/material_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class material_factory final : public factory_decorator<detector_t> {
/// @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<dindex>(m_links.size())};

Expand Down Expand Up @@ -194,8 +194,12 @@ class material_factory final : public factory_decorator<detector_t> {
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
Expand Down
211 changes: 211 additions & 0 deletions core/include/detray/tools/telescope_generator.hpp
Original file line number Diff line number Diff line change
@@ -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 <cassert>
#include <limits>

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 detector_t, typename mask_shape_t = rectangle2D<>,
typename trajectory_t = detail::ray<typename detector_t::transform3>>
class telescope_generator final : public surface_factory_interface<detector_t> {

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<scalar_t> positions,
std::array<scalar_t, mask_shape_t::boundaries::e_size> 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<scalar_t, mask_shape_t::boundaries::e_size> 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<scalar_t>(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<dindex>(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<detector_t> &&) override { /*Do nothing*/
}
DETRAY_HOST
auto push_back(std::vector<surface_data<detector_t>> &&)
-> 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<dindex>(surfaces.size())};

// The type id of the surface mask shape
constexpr auto mask_id{detector_t::mask_container::template get_id<
mask<mask_shape_t>>::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<nav_link_t>(volume_idx)};

// Surfaces with the linking into the local containers
mask_link_t mask_link{mask_id, masks.template size<mask_id>()};
material_link_t material_link{
no_material,
detail::invalid_value<typename material_link_t::index_type>()};

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<mask_id>(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<scalar_t>::max()};
unsigned int i{std::numeric_limits<uint>::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<dindex>(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_placement> module_positions(
const trajectory_t &traj, const std::vector<scalar_t> &steps) const {

// create and fill the module placements
std::vector<module_placement> 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<scalar_t> m_positions;
/// The boundary values for the surface mask
std::array<scalar_t, mask_shape_t::boundaries::e_size> m_boundaries;
};

} // namespace detray
1 change: 1 addition & 0 deletions tests/unit_tests/cpu/material_interaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
6 changes: 3 additions & 3 deletions tests/unit_tests/io/io_json_detector_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
Loading

0 comments on commit d9468fb

Please sign in to comment.