File indexing completed on 2026-05-27 07:23:57
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/builders/surface_factory_interface.hpp"
0013 #include "detray/builders/volume_builder_interface.hpp"
0014 #include "detray/definitions/geometry.hpp"
0015 #include "detray/geometry/surface.hpp"
0016 #include "detray/utils/concepts.hpp"
0017 #include "detray/utils/grid/concepts.hpp"
0018 #include "detray/utils/logging.hpp"
0019
0020
0021 #include <algorithm>
0022 #include <memory>
0023 #include <string>
0024
0025 namespace detray {
0026
0027 namespace detail {
0028
0029
0030 struct mask_index_update;
0031
0032 }
0033
0034
0035 template <typename detector_t>
0036 class volume_builder : public volume_builder_interface<detector_t> {
0037 public:
0038 using scalar_t = dscalar<typename detector_t::algebra_type>;
0039 using volume_type = typename detector_t::volume_type;
0040 using geo_obj_ids = typename detector_t::geo_obj_ids;
0041
0042
0043
0044
0045
0046 explicit volume_builder(const volume_id id, const dindex idx = 0)
0047 : m_volume{id} {
0048 m_volume.set_index(idx);
0049 m_volume.set_material(volume_type::material_id::e_none, dindex_invalid);
0050
0051
0052
0053 m_volume.template set_accel_link<
0054 static_cast<typename volume_type::object_id>(0)>(
0055 detector_t::accel::id::e_surface_default, 0);
0056
0057 DETRAY_VERBOSE_HOST("Created builder for volume: " << idx);
0058 };
0059
0060
0061 DETRAY_HOST
0062 auto vol_index() const -> dindex override { return m_volume.index(); }
0063
0064
0065 DETRAY_HOST
0066 void has_accel(bool toggle) override { m_has_accel = toggle; }
0067
0068
0069 DETRAY_HOST
0070 bool has_accel() const override { return m_has_accel; }
0071
0072
0073 DETRAY_HOST void set_name(std::string volume_name) override {
0074 m_volume_name = std::move(volume_name);
0075 DETRAY_VERBOSE_HOST("Set volume name: " << m_volume_name);
0076 }
0077
0078
0079 DETRAY_HOST std::string_view name() override {
0080 if (m_volume_name.empty()) {
0081
0082 m_volume_name = "unknown(volume_" + std::to_string(vol_index()) + ")";
0083 }
0084 return m_volume_name;
0085 }
0086
0087
0088 DETRAY_HOST
0089 auto operator()() const -> const typename detector_t::volume_type& override {
0090 return m_volume;
0091 }
0092
0093
0094 DETRAY_HOST
0095 auto operator()() -> typename detector_t::volume_type& override {
0096 return m_volume;
0097 }
0098
0099
0100
0101 DETRAY_HOST
0102 auto build(detector_t& det, typename detector_t::geometry_context ctx = {}) ->
0103 typename detector_t::volume_type* override {
0104 DETRAY_VERBOSE_HOST("Build surfaces...");
0105
0106 assert(!m_surfaces.empty());
0107 assert(!m_transforms.empty());
0108 assert(!m_masks.all_empty());
0109
0110
0111 m_volume.set_index(static_cast<dindex>(det.volumes().size()));
0112
0113 m_volume.set_transform(det.transform_store().size());
0114 det._transforms.push_back(m_trf);
0115
0116
0117 add_to_detector(ctx, det);
0118
0119
0120 m_surfaces.clear();
0121 m_transforms.clear(ctx);
0122 m_masks.clear_all();
0123
0124 DETRAY_VERBOSE_HOST("Successfully built "
0125 << m_volume.n_surfaces()
0126 << " surfaces for volume: " << this->name());
0127
0128
0129 return &(det._volumes.back());
0130 }
0131
0132
0133 DETRAY_HOST
0134 void add_volume_placement(
0135 const typename detector_t::transform3_type& trf = {}) override {
0136 m_trf = trf;
0137 }
0138
0139
0140
0141 DETRAY_HOST
0142 void add_volume_placement(
0143 const typename detector_t::point3_type& t) override {
0144 m_trf = typename detector_t::transform3_type{t};
0145 }
0146
0147
0148
0149 DETRAY_HOST
0150 void add_volume_placement(
0151 const typename detector_t::point3_type& t,
0152 const typename detector_t::vector3_type& x,
0153 const typename detector_t::vector3_type& z) override {
0154 m_trf = typename detector_t::transform3_type{t, z, x};
0155 }
0156
0157
0158 DETRAY_HOST
0159 void add_surfaces(
0160 std::shared_ptr<surface_factory_interface<detector_t>> sf_factory,
0161 typename detector_t::geometry_context ctx = {}) override {
0162 DETRAY_VERBOSE_HOST("Add surface factory:");
0163
0164 (*sf_factory)(m_volume, m_surfaces, m_transforms, m_masks, ctx);
0165 }
0166
0167 protected:
0168
0169 typename detector_t::surface_lookup_container& surfaces() override {
0170 return m_surfaces;
0171 }
0172
0173
0174 typename detector_t::transform_container& transforms() override {
0175 return m_transforms;
0176 }
0177
0178
0179 typename detector_t::mask_container& masks() override { return m_masks; }
0180
0181
0182
0183
0184
0185
0186
0187
0188 template <geo_obj_ids surface_id = static_cast<geo_obj_ids>(0)>
0189 DETRAY_HOST auto add_to_detector(
0190 const typename detector_t::geometry_context ctx,
0191 detector_t& det) noexcept(false) -> void {
0192
0193 const auto trf_offset = det.transform_store().size(ctx);
0194 det._transforms.append(std::move(m_transforms), ctx);
0195
0196
0197 auto sf_offset{static_cast<dindex>(det.surfaces().size())};
0198
0199
0200 auto find_range = [&](auto sf_id) {
0201
0202 auto is_sf_type = [sf_id](const auto& sf) { return sf.id() == sf_id; };
0203
0204 auto first = static_cast<dindex>(
0205 math::abs(std::ranges::find_if(m_surfaces, is_sf_type) -
0206 std::begin(m_surfaces)));
0207
0208 auto last = static_cast<dindex>(math::abs(
0209 std::ranges::rend(m_surfaces) -
0210 std::ranges::find_if(std::ranges::rbegin(m_surfaces),
0211 std::ranges::rend(m_surfaces), is_sf_type)));
0212
0213
0214 return (first >= last)
0215 ? dindex_range{}
0216 : dindex_range{first + sf_offset, last + sf_offset};
0217 };
0218
0219 m_volume.template update_sf_link<surface_id::e_portal>(
0220 find_range(surface_id::e_portal));
0221
0222 m_volume.template update_sf_link<surface_id::e_sensitive>(
0223 find_range(surface_id::e_sensitive));
0224
0225 m_volume.template update_sf_link<surface_id::e_passive>(
0226 find_range(surface_id::e_passive));
0227
0228
0229
0230 std::size_t n_portals{0u};
0231 for (auto& sf_desc : m_surfaces) {
0232 det._masks.template visit<detail::mask_index_update>(sf_desc.mask(),
0233 sf_desc);
0234 sf_desc.set_volume(m_volume.index());
0235 sf_desc.update_transform(trf_offset);
0236 sf_desc.set_index(sf_offset++);
0237
0238 if (sf_desc.is_portal()) {
0239 ++n_portals;
0240 }
0241
0242 det._surfaces.insert(sf_desc);
0243 }
0244
0245
0246 constexpr auto default_acc_id{detector_t::accel::id::e_surface_default};
0247
0248
0249 typename detector_t::surface_container descriptors;
0250 descriptors.reserve(m_surfaces.size());
0251 std::ranges::transform(
0252 m_surfaces, std::back_inserter(descriptors),
0253 [](typename detector_t::surface_lookup_container::value_type& sf) {
0254 return static_cast<
0255 typename detector_t::surface_container::value_type>(sf);
0256 });
0257
0258
0259 if (m_has_accel) {
0260 DETRAY_VERBOSE_HOST("-> Volume has acceleration structure:");
0261
0262 typename detector_t::surface_container portals{};
0263 portals.reserve(n_portals);
0264
0265 std::ranges::copy_if(
0266 descriptors, std::back_inserter(portals),
0267 [](auto& sf_desc) { return !sf_desc.is_sensitive(); });
0268
0269
0270 DETRAY_VERBOSE_HOST(
0271 "-> Register only portals/passives with brute force "
0272 "accelerator");
0273
0274 det._accelerators.template push_back<default_acc_id>(std::move(portals));
0275 } else {
0276 DETRAY_VERBOSE_HOST(
0277 "-> Register all surfaces with brute force accelerator");
0278
0279
0280 det._accelerators.template push_back<default_acc_id>(
0281 std::move(descriptors));
0282 }
0283
0284 m_volume.template set_accel_link<surface_id>(
0285 default_acc_id,
0286 det.accelerator_store().template size<default_acc_id>() - 1u);
0287
0288
0289 det._masks.append(std::move(m_masks));
0290
0291
0292 det._volumes.push_back(m_volume);
0293 }
0294
0295 private:
0296
0297 bool m_has_accel{false};
0298
0299
0300 std::string m_volume_name{};
0301
0302
0303 typename detector_t::volume_type m_volume{};
0304
0305 typename detector_t::transform3_type m_trf{};
0306
0307
0308
0309 typename detector_t::surface_lookup_container m_surfaces{};
0310 typename detector_t::transform_container m_transforms{};
0311 typename detector_t::mask_container m_masks{};
0312
0313 };
0314
0315 namespace detail {
0316
0317
0318 struct mask_index_update {
0319 template <typename group_t, typename index_t, typename surface_t>
0320 DETRAY_HOST inline void operator()(const group_t& group,
0321 const index_t& ,
0322 surface_t& sf) const {
0323 sf.update_mask(static_cast<dindex>(std::size(group)));
0324 }
0325 };
0326
0327 }
0328
0329 }