Skip to content

Commit 396404e

Browse files
committed
Add homogeneous material generator
1 parent c16486a commit 396404e

File tree

6 files changed

+287
-33
lines changed

6 files changed

+287
-33
lines changed

core/include/detray/builders/cylinder_portal_generator.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class cylinder_portal_generator final
132132
upper_z{0.f};
133133
};
134134

135-
/// Use @param env as portal envelope
135+
/// Construct from configuration @param cfg
136136
DETRAY_HOST
137137
cylinder_portal_generator(const cylinder_portal_config<scalar_t> cfg)
138138
: m_cfg{cfg} {}

core/include/detray/builders/homogeneous_material_builder.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** Detray library, part of the ACTS project (R&D line)
22
*
3-
* (c) 2022-2023 CERN for the benefit of the ACTS project
3+
* (c) 2022-2024 CERN for the benefit of the ACTS project
44
*
55
* Mozilla Public License Version 2.0
66
*/
@@ -9,6 +9,7 @@
99

1010
// Project include(s).
1111
#include "detray/builders/homogeneous_material_factory.hpp"
12+
#include "detray/builders/homogeneous_material_generator.hpp"
1213
#include "detray/builders/volume_builder.hpp"
1314
#include "detray/builders/volume_builder_interface.hpp"
1415

@@ -53,6 +54,13 @@ class homogeneous_material_builder final : public volume_decorator<detector_t> {
5354
sf_factory);
5455
if (mat_factory) {
5556
(*mat_factory)(this->surfaces(), m_materials);
57+
return;
58+
}
59+
auto mat_generator = std::dynamic_pointer_cast<
60+
homogeneous_material_generator<detector_t>>(sf_factory);
61+
if (mat_generator) {
62+
(*mat_generator)(this->surfaces(), m_materials);
63+
return;
5664
}
5765
}
5866
/// @}
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/** Detray library, part of the ACTS project (R&D line)
2+
*
3+
* (c) 2024 CERN for the benefit of the ACTS project
4+
*
5+
* Mozilla Public License Version 2.0
6+
*/
7+
8+
#pragma once
9+
10+
// Project include(s)
11+
#include "detray/builders/surface_factory_interface.hpp"
12+
#include "detray/definitions/detail/indexing.hpp"
13+
#include "detray/definitions/detail/qualifiers.hpp"
14+
#include "detray/materials/material.hpp"
15+
#include "detray/materials/predefined_materials.hpp"
16+
17+
namespace detray {
18+
19+
/// @brief Configuration for the homogeneous material generator
20+
template <typename scalar_t>
21+
struct hom_material_config {
22+
/// Type of material to put on the passive surfaces
23+
material<scalar_t> m_passive_material{silicon<scalar_t>{}};
24+
/// Type of material to put on the sensitive surfaces
25+
material<scalar_t> m_sensitive_material{silicon<scalar_t>{}};
26+
/// Type of material to put on the portal surfaces
27+
material<scalar_t> m_portal_material{vacuum<scalar_t>{}};
28+
/// Minimal envelope for the portals (used in autofitting)
29+
scalar_t m_thickness{1.5f * unit<scalar_t>::mm};
30+
31+
/// Setters
32+
/// @{
33+
constexpr hom_material_config &passive_material(
34+
const material<scalar_t> &m) {
35+
m_passive_material = m;
36+
return *this;
37+
}
38+
constexpr hom_material_config &sensitive_material(
39+
const material<scalar_t> &m) {
40+
m_sensitive_material = m;
41+
return *this;
42+
}
43+
constexpr hom_material_config &portal_material(
44+
const material<scalar_t> &m) {
45+
m_portal_material = m;
46+
return *this;
47+
}
48+
constexpr hom_material_config &thickness(const scalar_t t) {
49+
m_thickness = t;
50+
return *this;
51+
}
52+
/// @}
53+
54+
/// Getters
55+
/// @{
56+
constexpr const material<scalar_t> &passive_material() const {
57+
return m_passive_material;
58+
}
59+
constexpr const material<scalar_t> &sensitive_material() const {
60+
return m_sensitive_material;
61+
}
62+
constexpr const material<scalar_t> &portal_material() const {
63+
return m_portal_material;
64+
}
65+
constexpr scalar_t thickness() const { return m_thickness; }
66+
/// @}
67+
};
68+
69+
/// @brief Surface factory decorator that adds homogeneous material to surfaces
70+
///
71+
/// @tparam detector_t the type of detector the volume belongs to.
72+
template <typename detector_t>
73+
class homogeneous_material_generator final
74+
: public factory_decorator<detector_t> {
75+
76+
using scalar_t = typename detector_t::scalar_type;
77+
using point3_t = typename detector_t::point3;
78+
using vector3_t = typename detector_t::vector3;
79+
using transform3_t = typename detector_t::transform3;
80+
81+
public:
82+
/// Construct from configuration @param cfg
83+
DETRAY_HOST
84+
homogeneous_material_generator(
85+
std::unique_ptr<surface_factory_interface<detector_t>> factory,
86+
const hom_material_config<scalar_t> cfg)
87+
: factory_decorator<detector_t>(std::move(factory)), m_cfg{cfg} {}
88+
89+
/// Call the underlying surface factory and record the surface range that
90+
/// was produced
91+
///
92+
/// @param volume the volume the portals need to be added to.
93+
/// @param surfaces the surface collection to wrap and to add the portals to
94+
/// @param transforms the transforms of the surfaces.
95+
/// @param masks the masks of the surfaces.
96+
/// @param ctx the geometry context (not needed for portals).
97+
DETRAY_HOST
98+
auto operator()(typename detector_t::volume_type &volume,
99+
typename detector_t::surface_lookup_container &surfaces,
100+
typename detector_t::transform_container &transforms,
101+
typename detector_t::mask_container &masks,
102+
typename detector_t::geometry_context ctx = {})
103+
-> dindex_range override {
104+
105+
auto [sf_offset, n_surfaces] =
106+
(*this->m_factory)(volume, surfaces, transforms, masks, ctx);
107+
108+
m_surface_range = {sf_offset, sf_offset + n_surfaces};
109+
110+
return {sf_offset, n_surfaces};
111+
}
112+
113+
/// Create material slabs or rods for all surfaces that the undelying
114+
/// surface factory builds.
115+
///
116+
/// @param surfaces surface container of the volume builder that should get
117+
/// decorated with material.
118+
/// @param material material store of the volume builder that the new
119+
/// materials get added to.
120+
DETRAY_HOST
121+
auto operator()(typename detector_t::surface_lookup_container &surfaces,
122+
typename detector_t::material_container &materials) {
123+
124+
using material_id = typename detector_t::materials::id;
125+
using link_t = typename detector_t::surface_type::material_link;
126+
127+
// Add the material to the surfaces that the data links against
128+
for (auto &sf : detray::ranges::subrange(surfaces, m_surface_range)) {
129+
130+
const material<scalar_t> *mat_ptr{nullptr};
131+
132+
constexpr vacuum<scalar_t> vac{};
133+
switch (sf.id()) {
134+
case surface_id::e_passive: {
135+
const auto &mat = m_cfg.passive_material();
136+
mat_ptr = (mat != vac) ? &mat : nullptr;
137+
break;
138+
}
139+
case surface_id::e_sensitive: {
140+
const auto &mat = m_cfg.sensitive_material();
141+
mat_ptr = (mat != vac) ? &mat : nullptr;
142+
break;
143+
}
144+
case surface_id::e_portal: {
145+
const auto &mat = m_cfg.portal_material();
146+
mat_ptr = (mat != vac) ? &mat : nullptr;
147+
break;
148+
}
149+
};
150+
151+
// Found suitable material for this surface?
152+
if (mat_ptr == nullptr) {
153+
continue;
154+
}
155+
156+
// Handle line shaped surfaces differently
157+
bool is_line{false};
158+
link_t mat_link;
159+
160+
if constexpr (detector_t::materials::template is_defined<
161+
material_rod<scalar_t>>()) {
162+
163+
using mask_id = typename detector_t::masks::id;
164+
165+
const mask_id sf_mask_id = sf.mask().id();
166+
if (sf_mask_id == mask_id::e_straw_tube ||
167+
sf_mask_id == mask_id::e_drift_cell) {
168+
169+
is_line = true;
170+
171+
auto &mat_coll =
172+
materials.template get<material_id::e_rod>();
173+
mat_coll.emplace_back(*mat_ptr, m_cfg.thickness());
174+
175+
mat_link = {material_id::e_rod,
176+
static_cast<dindex>(mat_coll.size() - 1u)};
177+
}
178+
}
179+
180+
if (!is_line) {
181+
auto &mat_coll = materials.template get<material_id::e_slab>();
182+
mat_coll.emplace_back(*mat_ptr, m_cfg.thickness());
183+
184+
mat_link = {material_id::e_slab,
185+
static_cast<dindex>(mat_coll.size() - 1u)};
186+
}
187+
188+
// Set the initial surface material link (will be updated when
189+
// added to the detector)
190+
sf.material() = mat_link;
191+
}
192+
}
193+
194+
private:
195+
/// Portal generator configuration
196+
hom_material_config<scalar_t> m_cfg;
197+
/// Range of surface indices for which to generate material
198+
dindex_range m_surface_range{};
199+
};
200+
201+
} // namespace detray

tests/unit_tests/io/io_json_detector_writer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ GTEST_TEST(io, json_toy_detector_writer_new) {
131131
// Toy detector
132132
vecmem::host_memory_resource host_mr;
133133
toy_config<scalar> toy_cfg{};
134-
toy_cfg.n_brl_layers(4u).n_edc_layers(7u).use_material_maps(true);
134+
toy_cfg.use_material_maps(false);
135135
const auto [det, names] = build_toy_detector(host_mr, toy_cfg);
136136

137137
auto writer_cfg = io::detector_writer_config{}

utils/include/detray/detectors/build_telescope_detector.hpp

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "detray/builders/cuboid_portal_generator.hpp"
1212
#include "detray/builders/detector_builder.hpp"
1313
#include "detray/builders/homogeneous_material_builder.hpp"
14+
#include "detray/builders/homogeneous_material_generator.hpp"
1415
#include "detray/builders/homogeneous_volume_material_builder.hpp"
1516
#include "detray/core/detector.hpp"
1617
#include "detray/definitions/units.hpp"
@@ -43,17 +44,24 @@ struct tel_det_config {
4344

4445
/// Construct from existing mask
4546
tel_det_config(const mask<mask_shape_t> &m, const trajectory_t &t = {})
46-
: m_mask(m), m_trajectory(t) {}
47+
: m_mask(m), m_trajectory(t) {
48+
// Configure the material generation
49+
m_material_config.sensitive_material(silicon_tml<scalar>())
50+
.passive_material(vacuum<scalar>())
51+
.portal_material(vacuum<scalar>())
52+
.thickness(80.f * unit<scalar>::um);
53+
}
4754

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

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

5866
/// Mask of the test surfaces
5967
mask<mask_shape_t> m_mask;
@@ -63,12 +71,10 @@ struct tel_det_config {
6371
scalar m_length{500.f * unit<scalar>::mm};
6472
/// Concrete positions where to place the surfaces along the pilot track
6573
std::vector<scalar> m_positions{};
66-
/// Material for the test surfaces
67-
material<scalar> m_material = silicon_tml<scalar>();
74+
/// Configuration for the homogeneous material generator
75+
hom_material_config<scalar> m_material_config{};
6876
/// Material for volume
6977
material<scalar> m_volume_material = vacuum<scalar>();
70-
/// Thickness of the material
71-
scalar m_thickness{80.f * unit<scalar>::um};
7278
/// Pilot track along which to place the surfaces
7379
trajectory_t m_trajectory{};
7480
/// Safety envelope between the test surfaces and the portals
@@ -100,7 +106,7 @@ struct tel_det_config {
100106
return *this;
101107
}
102108
constexpr tel_det_config &module_material(const material<scalar> &mat) {
103-
m_material = mat;
109+
m_material_config.sensitive_material(mat);
104110
return *this;
105111
}
106112
constexpr tel_det_config &volume_material(const material<scalar> &mat) {
@@ -109,7 +115,7 @@ struct tel_det_config {
109115
}
110116
constexpr tel_det_config &mat_thickness(const scalar t) {
111117
assert(t > 0.f && "Material thickness must be greater than zero");
112-
m_thickness = t;
118+
m_material_config.thickness(t);
113119
return *this;
114120
}
115121
constexpr tel_det_config &pilot_track(const trajectory_t &traj) {
@@ -133,13 +139,17 @@ struct tel_det_config {
133139
constexpr unsigned int n_surfaces() const { return m_n_surfaces; }
134140
constexpr scalar length() const { return m_length; }
135141
const std::vector<scalar> &positions() const { return m_positions; }
142+
constexpr const auto &material_config() const { return m_material_config; }
143+
constexpr auto &material_config() { return m_material_config; }
136144
constexpr const material<scalar> &module_material() const {
137-
return m_material;
145+
return m_material_config.sensitive_material();
138146
}
139147
constexpr const material<scalar> &volume_material() const {
140148
return m_volume_material;
141149
}
142-
constexpr scalar mat_thickness() const { return m_thickness; }
150+
constexpr scalar mat_thickness() const {
151+
return m_material_config.thickness();
152+
}
143153
const trajectory_t &pilot_track() const { return m_trajectory; }
144154
constexpr scalar envelope() const { return m_envelope; }
145155
bool do_check() const { return m_do_check; }
@@ -170,7 +180,6 @@ inline auto build_telescope_detector(
170180
using builder_t =
171181
detector_builder<telescope_metadata<mask_shape_t>, volume_builder>;
172182
using detector_t = typename builder_t::detector_type;
173-
using material_id = typename detector_t::materials::id;
174183

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

219228
auto tel_mat_generator =
220-
std::make_shared<homogeneous_material_factory<detector_t>>(
221-
std::move(tel_generator));
222-
223-
// Generate the material
224-
std::vector<material_data<scalar>> sf_materials(
225-
tel_mat_generator->size(),
226-
material_data<scalar>{cfg.mat_thickness(), cfg.module_material()});
227-
228-
constexpr bool is_line{
229-
std::is_same_v<mask_shape_t, detray::line_square> ||
230-
std::is_same_v<mask_shape_t, detray::line_circular>};
231-
constexpr auto mat_id{is_line ? material_id::e_rod
232-
: material_id::e_slab};
233-
234-
// Add the material to the surface factory
235-
tel_mat_generator->add_material(mat_id, std::move(sf_materials));
229+
std::make_shared<homogeneous_material_generator<detector_t>>(
230+
std::move(tel_generator), cfg.material_config());
236231

237232
module_generator = std::move(tel_mat_generator);
238233

0 commit comments

Comments
 (0)