File indexing completed on 2026-05-27 07:23:56
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/builders/bin_fillers.hpp"
0013 #include "detray/builders/material_map_factory.hpp"
0014 #include "detray/builders/material_map_generator.hpp"
0015 #include "detray/builders/surface_factory_interface.hpp"
0016 #include "detray/builders/volume_builder_interface.hpp"
0017 #include "detray/geometry/concepts.hpp"
0018 #include "detray/geometry/surface.hpp"
0019 #include "detray/material/material_map.hpp"
0020
0021
0022 #include <cassert>
0023 #include <map>
0024 #include <memory>
0025 #include <stdexcept>
0026 #include <vector>
0027
0028 namespace detray {
0029
0030 namespace detail {
0031
0032 struct material_coll_size;
0033
0034 template <typename material_t>
0035 struct add_sf_material_map;
0036
0037 }
0038
0039
0040
0041
0042
0043 template <typename detector_t, std::size_t DIM = 2u,
0044 typename mat_map_factory_t =
0045 material_grid_factory<typename detector_t::algebra_type>>
0046 class material_map_builder final : public volume_decorator<detector_t> {
0047 using material_t = typename detector_t::material;
0048
0049 public:
0050 using scalar_type = dscalar<typename detector_t::algebra_type>;
0051 using detector_type = detector_t;
0052 using value_type = material_slab<scalar_type>;
0053 using bin_data_type =
0054 typename fill_by_bin::template bin_data<DIM, value_type>;
0055
0056
0057
0058 DETRAY_HOST
0059 explicit material_map_builder(
0060 std::unique_ptr<volume_builder_interface<detector_t>> vol_builder)
0061 : volume_decorator<detector_t>(std::move(vol_builder)) {
0062 DETRAY_VERBOSE_HOST("Add material map builder to volume: " << this->name());
0063 }
0064
0065
0066
0067 DETRAY_HOST
0068 auto data() const -> const std::map<dindex, std::vector<bin_data_type>>& {
0069 return m_bin_data;
0070 }
0071
0072
0073
0074 DETRAY_HOST
0075 void add_surfaces(
0076 std::shared_ptr<surface_factory_interface<detector_t>> sf_factory,
0077 typename detector_t::geometry_context ctx = {}) override {
0078 DETRAY_VERBOSE_HOST("Add [material] surface factory:");
0079
0080
0081 volume_decorator<detector_t>::add_surfaces(sf_factory, ctx);
0082
0083
0084 using sf_factory_t = material_map_factory<detector_t, axis::multi_bin<DIM>>;
0085 auto mat_factory = std::dynamic_pointer_cast<sf_factory_t>(sf_factory);
0086 if (mat_factory) {
0087 DETRAY_VERBOSE_HOST(
0088 "-> found decoration: " << DETRAY_TYPENAME(sf_factory_t));
0089 (*mat_factory)(this->surfaces(), m_bin_data, m_n_bins, m_axis_spans);
0090 }
0091 auto mat_generator =
0092 std::dynamic_pointer_cast<material_map_generator<detector_t>>(
0093 sf_factory);
0094 if (mat_generator) {
0095 DETRAY_VERBOSE_HOST("-> found decoration: " << DETRAY_TYPENAME(
0096 material_map_generator<detector_t>));
0097 (*mat_generator)(this->surfaces(), this->masks(), m_bin_data, m_n_bins);
0098 return;
0099 }
0100
0101 if (!mat_factory && !mat_generator) {
0102 DETRAY_VERBOSE_HOST("No material found in this surface factory");
0103 DETRAY_VERBOSE_HOST("-> Built non-material surfaces");
0104 }
0105 }
0106
0107
0108
0109 DETRAY_HOST
0110 auto build(detector_t& det, typename detector_t::geometry_context ctx = {}) ->
0111 typename detector_t::volume_type* override {
0112 DETRAY_VERBOSE_HOST("Build material maps...");
0113
0114
0115
0116 update_material_links(det);
0117
0118 DETRAY_DEBUG_HOST(
0119 "-> Let underlying builders construct the volume using correct "
0120 "material links...");
0121
0122 typename detector_t::volume_type* vol_ptr =
0123 volume_decorator<detector_t>::build(det, ctx);
0124 DETRAY_DEBUG_HOST("-> Back in material map building");
0125
0126
0127 dindex sf_idx = 0u;
0128 auto vol = tracking_volume{det, this->vol_index()};
0129 DETRAY_DEBUG_HOST("Build material maps for surfaces...");
0130 for (const auto& sf_desc : vol.surfaces()) {
0131 if (!surface_has_map(sf_idx)) {
0132 sf_idx++;
0133 continue;
0134 }
0135
0136 DETRAY_DEBUG_HOST("-> surface #" << sf_idx << " sf_desc = " << sf_desc);
0137
0138
0139 darray<std::vector<scalar_type>, DIM> axis_spans{};
0140 if (auto axis_spans_itr = m_axis_spans.find(sf_idx);
0141 axis_spans_itr != m_axis_spans.end()) {
0142 axis_spans = axis_spans_itr->second;
0143 }
0144
0145
0146 auto sf = geometry::surface{det, sf_desc};
0147 [[maybe_unused]] auto [mat_id, mat_idx] =
0148 sf.template visit_mask<detail::add_sf_material_map<material_t>>(
0149 m_factory, m_bin_data.at(sf_idx), m_n_bins.at(sf_idx), axis_spans,
0150 det._materials);
0151
0152
0153 std::stringstream err_msg;
0154 if (mat_id != sf_desc.material().id()) {
0155 err_msg << "-> material id mismatch for surface " << sf_idx
0156 << ": expected " << sf_desc.material().id() << ", got "
0157 << mat_id;
0158
0159 DETRAY_FATAL_HOST(err_msg.str());
0160 throw std::runtime_error(err_msg.str());
0161 }
0162 if (mat_idx != sf_desc.material().index()) {
0163 err_msg << "-> material index mismatch for "
0164 "surface "
0165 << sf_idx << ": expected " << sf_desc.material().index()
0166 << ", got " << mat_idx;
0167
0168 DETRAY_FATAL_HOST(err_msg.str());
0169 throw std::runtime_error(err_msg.str());
0170 }
0171 sf_idx++;
0172 }
0173
0174 DETRAY_VERBOSE_HOST(
0175 "Successfully built material maps for volume: " << this->name());
0176
0177
0178 return vol_ptr;
0179 }
0180
0181 private:
0182
0183
0184 bool surface_has_map(const dindex sf_idx) const {
0185 return m_bin_data.contains(sf_idx);
0186 }
0187
0188
0189 void update_material_links(const detector_t& det) {
0190 DETRAY_VERBOSE_HOST("Precompute material links...");
0191
0192
0193 const dindex n_surfaces{static_cast<dindex>(this->surfaces().size())};
0194
0195
0196 std::map<typename material_t::id, dindex> mat_type_count;
0197
0198 for (dindex sf_idx = 0u; sf_idx < n_surfaces; ++sf_idx) {
0199 if (!surface_has_map(sf_idx)) {
0200 continue;
0201 }
0202
0203 auto& sf_desc = this->surfaces().at(sf_idx);
0204 const auto id{sf_desc.material().id()};
0205
0206 DETRAY_DEBUG_HOST("-> surface #" << sf_idx << " (mat. id = " << id
0207 << ")");
0208
0209 if (!mat_type_count.contains(id)) {
0210 mat_type_count.emplace(id, 0u);
0211 } else {
0212 mat_type_count.at(id)++;
0213 }
0214
0215 DETRAY_DEBUG_HOST("--> set mat. index to: " << mat_type_count.at(id));
0216
0217 sf_desc.material().set_index(mat_type_count.at(id));
0218 }
0219
0220
0221 std::map<std::size_t, dindex> size_map;
0222 det._materials.template apply<detail::material_coll_size>(
0223 size_map, std::make_index_sequence<material_t::n_types>{});
0224
0225 DETRAY_DEBUG_HOST("Shift material indices by detector offset...");
0226 for (dindex sf_idx = 0u; sf_idx < n_surfaces; ++sf_idx) {
0227 if (!surface_has_map(sf_idx)) {
0228 continue;
0229 }
0230 auto& sf_desc = this->surfaces().at(sf_idx);
0231
0232 auto coll_idx{static_cast<std::size_t>(sf_desc.material().id())};
0233 sf_desc.material() += size_map.at(coll_idx);
0234
0235 DETRAY_DEBUG_HOST("(Shift = " << size_map.at(coll_idx)
0236 << "): material link = "
0237 << sf_desc.material());
0238 }
0239 }
0240
0241
0242 std::map<dindex, std::vector<bin_data_type>> m_bin_data;
0243
0244 std::map<dindex, darray<std::size_t, DIM>> m_n_bins{};
0245
0246 std::map<dindex, darray<std::vector<scalar_type>, DIM>> m_axis_spans{};
0247
0248 mat_map_factory_t m_factory{};
0249 };
0250
0251 namespace detail {
0252
0253
0254 struct material_coll_size {
0255 template <typename... coll_ts, std::size_t... I>
0256 DETRAY_HOST inline void operator()(std::map<std::size_t, dindex>& size_map,
0257 std::index_sequence<I...> ,
0258 const coll_ts&... coll) const {
0259 (size_map.emplace(I, static_cast<dindex>(std::size(coll))), ...);
0260 }
0261 };
0262
0263
0264 template <typename material_t>
0265 struct add_sf_material_map {
0266 template <typename mask_coll_t, typename index_range_t,
0267 typename mat_factory_t, typename bin_data_t, std::size_t DIM,
0268 typename material_store_t, concepts::scalar scalar_t>
0269 DETRAY_HOST inline std::pair<typename material_t::id, dindex> operator()(
0270 [[maybe_unused]] const mask_coll_t& mask_coll,
0271 [[maybe_unused]] const index_range_t& index,
0272 [[maybe_unused]] const mat_factory_t& mat_factory,
0273 [[maybe_unused]] std::vector<bin_data_t>& bin_data,
0274 [[maybe_unused]] const darray<std::size_t, DIM>& n_bins,
0275 [[maybe_unused]] const darray<std::vector<scalar_t>, DIM>& axis_spans,
0276 [[maybe_unused]] material_store_t& mat_store) const {
0277 using mask_t = typename mask_coll_t::value_type;
0278
0279
0280 if constexpr (!concepts::line_object<mask_t> && mask_t::shape::dim == DIM) {
0281
0282
0283 mask_t sf_mask = {};
0284 if constexpr (concepts::interval<index_range_t>) {
0285 using index_t = typename index_range_t::index_type;
0286
0287
0288 sf_mask = mask_coll.at(index.lower());
0289
0290 if (index.size() > 1u) {
0291 const index_range_t other_masks{
0292 index.lower() + 1u, static_cast<index_t>(index.size() - 1u)};
0293
0294
0295 for (const auto& sub_mask :
0296 detray::ranges::subrange(mask_coll, other_masks)) {
0297 sf_mask = sf_mask + sub_mask;
0298 }
0299 }
0300 } else {
0301 sf_mask = mask_coll.at(index);
0302 }
0303
0304 auto mat_grid = mat_factory.new_grid(sf_mask, n_bins, {}, {}, axis_spans);
0305
0306
0307 using non_owning_t = typename decltype(mat_grid)::template type<false>;
0308
0309
0310 if constexpr (types::contains<material_t, non_owning_t>) {
0311 DETRAY_VERBOSE_HOST("Filling material grid...");
0312
0313
0314 for (const auto& bin : bin_data) {
0315 mat_grid.template populate<replace<>>(bin.local_bin_idx,
0316 bin.single_element);
0317 }
0318
0319
0320 constexpr auto gid{types::id<material_t, non_owning_t>};
0321 mat_store.template push_back<gid>(mat_grid);
0322 DETRAY_VERBOSE_HOST("Built material grid:" << gid << ":\n"
0323 << mat_grid.axes());
0324
0325
0326 return {gid, static_cast<dindex>(mat_store.template size<gid>() - 1u)};
0327 } else {
0328 return {material_t::id::e_none, dindex_invalid};
0329 }
0330 } else {
0331 return {material_t::id::e_none, dindex_invalid};
0332 }
0333 }
0334 };
0335
0336 }
0337
0338 }