Skip to content

Commit

Permalink
feat: Add homogeneous material to new toy detector and switch the tes…
Browse files Browse the repository at this point in the history
…elscope detector to new material generation (#703)

Adds a homogeneous material generator that adds a predefined type of material to passive, sensitive or portals surfaces, depending on the configuration. This is used to add material to the new toy detector and is also used now in the telescope geometry instead of the homogeneous material factory.
  • Loading branch information
niermann999 authored Mar 20, 2024
1 parent 5e606c3 commit bda3817
Show file tree
Hide file tree
Showing 12 changed files with 457 additions and 130 deletions.
22 changes: 13 additions & 9 deletions core/include/detray/builders/cylinder_portal_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class cylinder_portal_generator final
upper_z{0.f};
};

/// Use @param env as portal envelope
/// Construct from configuration @param cfg
DETRAY_HOST
cylinder_portal_generator(const cylinder_portal_config<scalar_t> cfg)
: m_cfg{cfg} {}
Expand Down Expand Up @@ -258,9 +258,9 @@ class cylinder_portal_generator final

using surface_type = typename detector_t::surface_type;
using mask_id = typename detector_t::masks::id;
using mask_link_type = typename surface_type::mask_link;
using mask_link_t = typename surface_type::mask_link;
using material_id = typename detector_t::materials::id;
using material_link_type = typename surface_type::material_link;
using material_link_t = typename surface_type::material_link;

constexpr auto invalid_src_link{detail::invalid_value<std::uint64_t>()};

Expand All @@ -276,10 +276,12 @@ class cylinder_portal_generator final
empty_context{}, vol_link, r, min_z, max_z);

// Add surface links
mask_link_type mask_link{
mask_link_t mask_link{
mask_id::e_portal_cylinder2,
masks.template size<mask_id::e_portal_cylinder2>() - 1u};
material_link_type material_link{material_id::e_none, dindex_invalid};
material_link_t material_link{
material_id::e_none,
detail::invalid_value<typename material_link_t::index_type>()};

surfaces.push_back(
{static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
Expand All @@ -298,9 +300,9 @@ class cylinder_portal_generator final

using surface_type = typename detector_t::surface_type;
using mask_id = typename detector_t::masks::id;
using mask_link_type = typename surface_type::mask_link;
using mask_link_t = typename surface_type::mask_link;
using material_id = typename detector_t::materials::id;
using material_link_type = typename surface_type::material_link;
using material_link_t = typename surface_type::material_link;

constexpr auto invalid_src_link{detail::invalid_value<std::uint64_t>()};

Expand All @@ -316,10 +318,12 @@ class cylinder_portal_generator final
empty_context{}, vol_link, min_r, max_r);

// Add surface links
mask_link_type mask_link{
mask_link_t mask_link{
mask_id::e_portal_ring2,
masks.template size<mask_id::e_portal_ring2>() - 1u};
material_link_type material_link{material_id::e_none, dindex_invalid};
material_link_t material_link{
material_id::e_none,
detail::invalid_value<typename material_link_t::index_type>()};

surfaces.push_back(
{static_cast<dindex>(transforms.size(ctx) - 1u), mask_link,
Expand Down
10 changes: 9 additions & 1 deletion core/include/detray/builders/homogeneous_material_builder.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** Detray library, part of the ACTS project (R&D line)
*
* (c) 2022-2023 CERN for the benefit of the ACTS project
* (c) 2022-2024 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/
Expand All @@ -9,6 +9,7 @@

// Project include(s).
#include "detray/builders/homogeneous_material_factory.hpp"
#include "detray/builders/homogeneous_material_generator.hpp"
#include "detray/builders/volume_builder.hpp"
#include "detray/builders/volume_builder_interface.hpp"

Expand Down Expand Up @@ -53,6 +54,13 @@ class homogeneous_material_builder final : public volume_decorator<detector_t> {
sf_factory);
if (mat_factory) {
(*mat_factory)(this->surfaces(), m_materials);
return;
}
auto mat_generator = std::dynamic_pointer_cast<
homogeneous_material_generator<detector_t>>(sf_factory);
if (mat_generator) {
(*mat_generator)(this->surfaces(), m_materials);
return;
}
}
/// @}
Expand Down
210 changes: 210 additions & 0 deletions core/include/detray/builders/homogeneous_material_generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/** Detray library, part of the ACTS project (R&D line)
*
* (c) 2024 CERN for the benefit of the ACTS project
*
* Mozilla Public License Version 2.0
*/

#pragma once

// Project include(s)
#include "detray/builders/surface_factory_interface.hpp"
#include "detray/definitions/detail/indexing.hpp"
#include "detray/definitions/detail/qualifiers.hpp"
#include "detray/materials/material.hpp"
#include "detray/materials/predefined_materials.hpp"

// System include(s)
#include <stdexcept>

namespace detray {

/// @brief Configuration for the homogeneous material generator
template <typename scalar_t>
struct hom_material_config {
/// Type of material to put on the passive surfaces
material<scalar_t> m_passive_material{silicon<scalar_t>{}};
/// Type of material to put on the sensitive surfaces
material<scalar_t> m_sensitive_material{silicon<scalar_t>{}};
/// Type of material to put on the portal surfaces
material<scalar_t> m_portal_material{vacuum<scalar_t>{}};
/// Minimal envelope for the portals (used in autofitting)
scalar_t m_thickness{1.5f * unit<scalar_t>::mm};

/// Setters
/// @{
constexpr hom_material_config &passive_material(
const material<scalar_t> &m) {
m_passive_material = m;
return *this;
}
constexpr hom_material_config &sensitive_material(
const material<scalar_t> &m) {
m_sensitive_material = m;
return *this;
}
constexpr hom_material_config &portal_material(
const material<scalar_t> &m) {
m_portal_material = m;
return *this;
}
constexpr hom_material_config &thickness(const scalar_t t) {
m_thickness = t;
return *this;
}
/// @}

/// Getters
/// @{
constexpr const material<scalar_t> &passive_material() const {
return m_passive_material;
}
constexpr const material<scalar_t> &sensitive_material() const {
return m_sensitive_material;
}
constexpr const material<scalar_t> &portal_material() const {
return m_portal_material;
}
constexpr scalar_t thickness() const { return m_thickness; }
/// @}
};

/// @brief Surface factory decorator that adds homogeneous material to surfaces
///
/// @tparam detector_t the type of detector the volume belongs to.
template <typename detector_t>
class homogeneous_material_generator final
: public factory_decorator<detector_t> {

using scalar_t = typename detector_t::scalar_type;

public:
/// Construct from configuration @param cfg
DETRAY_HOST
homogeneous_material_generator(
std::unique_ptr<surface_factory_interface<detector_t>> factory,
const hom_material_config<scalar_t> cfg)
: factory_decorator<detector_t>(std::move(factory)), m_cfg{cfg} {}

/// Call the underlying surface factory and record the surface range that
/// was produced
///
/// @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_lookup_container &surfaces,
typename detector_t::transform_container &transforms,
typename detector_t::mask_container &masks,
typename detector_t::geometry_context ctx = {})
-> dindex_range override {

auto [sf_offset, n_surfaces] =
(*this->m_factory)(volume, surfaces, transforms, masks, ctx);

m_surface_range = {sf_offset, sf_offset + n_surfaces};

return {sf_offset, n_surfaces};
}

/// Create material slabs or rods for all surfaces that the undelying
/// surface factory builds.
///
/// @param surfaces surface container of the volume builder that should get
/// decorated with material.
/// @param material material store of the volume builder that the new
/// materials get added to.
DETRAY_HOST
auto operator()(typename detector_t::surface_lookup_container &surfaces,
typename detector_t::material_container &materials) {

using material_id = typename detector_t::materials::id;
using link_t = typename detector_t::surface_type::material_link;

// Add the material to the surfaces that the data links against
for (auto &sf : detray::ranges::subrange(surfaces, m_surface_range)) {

const material<scalar_t> *mat_ptr{nullptr};

// Get the correct material for this surface type
constexpr vacuum<scalar_t> vac{};
switch (sf.id()) {
case surface_id::e_passive: {
const auto &mat = m_cfg.passive_material();
mat_ptr = (mat != vac) ? &mat : nullptr;
break;
}
case surface_id::e_sensitive: {
const auto &mat = m_cfg.sensitive_material();
mat_ptr = (mat != vac) ? &mat : nullptr;
break;
}
case surface_id::e_portal: {
const auto &mat = m_cfg.portal_material();
mat_ptr = (mat != vac) ? &mat : nullptr;
break;
}
case surface_id::e_unknown: {
throw std::runtime_error(
"Encountered surface of unknown type during material "
"generation");
break;
}
};

// Found suitable material for this surface?
if (mat_ptr == nullptr) {
continue;
}

// Handle line shaped surfaces differently
bool is_line{false};
link_t mat_link;

if constexpr (detector_t::materials::template is_defined<
material_rod<scalar_t>>()) {

using mask_id = typename detector_t::masks::id;

// If the current surface is a line, generate a material rod
const mask_id sf_mask_id = sf.mask().id();
if (sf_mask_id == mask_id::e_straw_tube ||
sf_mask_id == mask_id::e_drift_cell) {

is_line = true;

auto &mat_coll =
materials.template get<material_id::e_rod>();
mat_coll.emplace_back(*mat_ptr, m_cfg.thickness());

mat_link = {material_id::e_rod,
static_cast<dindex>(mat_coll.size() - 1u)};
}
}

// For all surfaces that are not lines, generate a material slab
if (!is_line) {
auto &mat_coll = materials.template get<material_id::e_slab>();
mat_coll.emplace_back(*mat_ptr, m_cfg.thickness());

mat_link = {material_id::e_slab,
static_cast<dindex>(mat_coll.size() - 1u)};
}

// Set the initial surface material link (will be updated when
// added to the detector)
sf.material() = mat_link;
}
}

private:
/// Material generator configuration
hom_material_config<scalar_t> m_cfg;
/// Range of surface indices for which to generate material
dindex_range m_surface_range{};
};

} // namespace detray
4 changes: 3 additions & 1 deletion core/include/detray/builders/surface_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ class surface_factory : public surface_factory_interface<detector_t> {
mask_link_t mask_link{mask_id,
masks.template size<mask_id>() - 1u};
// If material is present, it is added in a later step
material_link_t material_link{no_material, 0};
material_link_t material_link{
no_material, detail::invalid_value<
typename material_link_t::index_type>()};

// Add the surface descriptor at the position given by 'sf_idx'
this->insert_in_container(
Expand Down
8 changes: 5 additions & 3 deletions core/include/detray/builders/volume_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ struct mask_index_update;
template <typename detector_t>
class volume_builder : public volume_builder_interface<detector_t> {

using material_link_t = typename detector_t::surface_type::material_link;

public:
using scalar_type = typename detector_t::scalar_type;
template <typename T, std::size_t N>
using array_type = typename detector_t::template array_type<T, N>;
using volume_type = typename detector_t::volume_type;
using geo_obj_ids = typename detector_t::geo_obj_ids;

Expand All @@ -45,7 +45,9 @@ class volume_builder : public volume_builder_interface<detector_t> {
: m_has_accel{false}, m_volume{id} {

m_volume.set_index(idx);
m_volume.set_material(volume_type::material_id::e_none, 0u);
m_volume.set_material(
volume_type::material_id::e_none,
detail::invalid_value<typename material_link_t::index_type>());

// The first acceleration data structure in every volume is a brute
// force method that will at least contain the portals
Expand Down
Loading

0 comments on commit bda3817

Please sign in to comment.