Skip to content

Commit

Permalink
Add homogeneous material generator
Browse files Browse the repository at this point in the history
  • Loading branch information
niermann999 committed Mar 19, 2024
1 parent c16486a commit 396404e
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 33 deletions.
2 changes: 1 addition & 1 deletion 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
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
201 changes: 201 additions & 0 deletions core/include/detray/builders/homogeneous_material_generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/** 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"

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;
using point3_t = typename detector_t::point3;
using vector3_t = typename detector_t::vector3;
using transform3_t = typename detector_t::transform3;

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};

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;
}
};

// 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;

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)};
}
}

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:
/// Portal 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
2 changes: 1 addition & 1 deletion tests/unit_tests/io/io_json_detector_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ GTEST_TEST(io, json_toy_detector_writer_new) {
// Toy detector
vecmem::host_memory_resource host_mr;
toy_config<scalar> toy_cfg{};
toy_cfg.n_brl_layers(4u).n_edc_layers(7u).use_material_maps(true);
toy_cfg.use_material_maps(false);
const auto [det, names] = build_toy_detector(host_mr, toy_cfg);

auto writer_cfg = io::detector_writer_config{}
Expand Down
51 changes: 23 additions & 28 deletions utils/include/detray/detectors/build_telescope_detector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "detray/builders/cuboid_portal_generator.hpp"
#include "detray/builders/detector_builder.hpp"
#include "detray/builders/homogeneous_material_builder.hpp"
#include "detray/builders/homogeneous_material_generator.hpp"
#include "detray/builders/homogeneous_volume_material_builder.hpp"
#include "detray/core/detector.hpp"
#include "detray/definitions/units.hpp"
Expand Down Expand Up @@ -43,17 +44,24 @@ struct tel_det_config {

/// Construct from existing mask
tel_det_config(const mask<mask_shape_t> &m, const trajectory_t &t = {})
: m_mask(m), m_trajectory(t) {}
: m_mask(m), m_trajectory(t) {
// Configure the material generation
m_material_config.sensitive_material(silicon_tml<scalar>())
.passive_material(vacuum<scalar>())
.portal_material(vacuum<scalar>())
.thickness(80.f * unit<scalar>::um);
}

/// Construct from from mask parameter vector
tel_det_config(std::vector<scalar> params, const trajectory_t &t = {})
: m_mask(std::move(params), 0u), m_trajectory(t) {}
: tel_det_config(mask<mask_shape_t>{std::move(params), 0u}, t) {}

/// Construct from mask parameters (except volume link, which is not needed)
template <
typename... Args,
std::enable_if_t<(std::is_same_v<Args, scalar> || ...), bool> = true>
tel_det_config(Args &&... args) : m_mask(0u, std::forward<Args>(args)...) {}
tel_det_config(Args &&... args)
: tel_det_config(mask<mask_shape_t>{0u, std::forward<Args>(args)...}) {}

/// Mask of the test surfaces
mask<mask_shape_t> m_mask;
Expand All @@ -63,12 +71,10 @@ struct tel_det_config {
scalar m_length{500.f * unit<scalar>::mm};
/// Concrete positions where to place the surfaces along the pilot track
std::vector<scalar> m_positions{};
/// Material for the test surfaces
material<scalar> m_material = silicon_tml<scalar>();
/// Configuration for the homogeneous material generator
hom_material_config<scalar> m_material_config{};
/// Material for volume
material<scalar> m_volume_material = vacuum<scalar>();
/// Thickness of the material
scalar m_thickness{80.f * unit<scalar>::um};
/// Pilot track along which to place the surfaces
trajectory_t m_trajectory{};
/// Safety envelope between the test surfaces and the portals
Expand Down Expand Up @@ -100,7 +106,7 @@ struct tel_det_config {
return *this;
}
constexpr tel_det_config &module_material(const material<scalar> &mat) {
m_material = mat;
m_material_config.sensitive_material(mat);
return *this;
}
constexpr tel_det_config &volume_material(const material<scalar> &mat) {
Expand All @@ -109,7 +115,7 @@ struct tel_det_config {
}
constexpr tel_det_config &mat_thickness(const scalar t) {
assert(t > 0.f && "Material thickness must be greater than zero");
m_thickness = t;
m_material_config.thickness(t);
return *this;
}
constexpr tel_det_config &pilot_track(const trajectory_t &traj) {
Expand All @@ -133,13 +139,17 @@ struct tel_det_config {
constexpr unsigned int n_surfaces() const { return m_n_surfaces; }
constexpr scalar length() const { return m_length; }
const std::vector<scalar> &positions() const { return m_positions; }
constexpr const auto &material_config() const { return m_material_config; }
constexpr auto &material_config() { return m_material_config; }
constexpr const material<scalar> &module_material() const {
return m_material;
return m_material_config.sensitive_material();
}
constexpr const material<scalar> &volume_material() const {
return m_volume_material;
}
constexpr scalar mat_thickness() const { return m_thickness; }
constexpr scalar mat_thickness() const {
return m_material_config.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; }
Expand Down Expand Up @@ -170,7 +180,6 @@ inline auto build_telescope_detector(
using builder_t =
detector_builder<telescope_metadata<mask_shape_t>, volume_builder>;
using detector_t = typename builder_t::detector_type;
using material_id = typename detector_t::materials::id;

// Detector and volume names
typename detector_t::name_map name_map = {{0u, "telescope_detector"},
Expand Down Expand Up @@ -217,22 +226,8 @@ inline auto build_telescope_detector(
v_builder);

auto tel_mat_generator =
std::make_shared<homogeneous_material_factory<detector_t>>(
std::move(tel_generator));

// Generate the material
std::vector<material_data<scalar>> sf_materials(
tel_mat_generator->size(),
material_data<scalar>{cfg.mat_thickness(), cfg.module_material()});

constexpr bool is_line{
std::is_same_v<mask_shape_t, detray::line_square> ||
std::is_same_v<mask_shape_t, detray::line_circular>};
constexpr auto mat_id{is_line ? material_id::e_rod
: material_id::e_slab};

// Add the material to the surface factory
tel_mat_generator->add_material(mat_id, std::move(sf_materials));
std::make_shared<homogeneous_material_generator<detector_t>>(
std::move(tel_generator), cfg.material_config());

module_generator = std::move(tel_mat_generator);

Expand Down
Loading

0 comments on commit 396404e

Please sign in to comment.