File indexing completed on 2026-05-27 07:23:59
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/detail/qualifiers.hpp"
0013 #include "detray/definitions/geometry.hpp"
0014 #include "detray/definitions/indexing.hpp"
0015 #include "detray/definitions/math.hpp"
0016 #include "detray/geometry/detail/surface_kernels.hpp"
0017 #include "detray/geometry/identifier.hpp"
0018 #include "detray/material/material.hpp"
0019 #include "detray/utils/ranges/ranges.hpp"
0020
0021
0022 #include <ostream>
0023 #include <type_traits>
0024
0025 namespace detray::geometry {
0026
0027
0028
0029
0030
0031
0032
0033
0034 template <typename det_t>
0035 class surface {
0036
0037 using detector_t = std::add_const_t<det_t>;
0038
0039 using descr_t = typename detector_t::surface_type;
0040
0041 using kernels = detail::surface_kernels<typename detector_t::algebra_type>;
0042
0043 public:
0044 using algebra_type = typename detector_t::algebra_type;
0045 using scalar_type = dscalar<algebra_type>;
0046 using point2_type = dpoint2D<algebra_type>;
0047 using point3_type = dpoint3D<algebra_type>;
0048 using vector3_type = dvector3D<algebra_type>;
0049 using transform3_type = dtransform3D<algebra_type>;
0050 using context = typename detector_t::geometry_context;
0051
0052
0053 surface() = delete;
0054
0055
0056
0057 DETRAY_HOST_DEVICE
0058 constexpr surface(const detector_t &det, const descr_t &desc)
0059 : m_detector{det}, m_desc{desc} {
0060 assert(!m_desc.identifier().is_invalid());
0061 assert(m_desc.index() < det.surfaces().size());
0062 assert(m_desc.transform() < det.transform_store().size());
0063 }
0064
0065
0066
0067 DETRAY_HOST_DEVICE
0068 constexpr surface(const detector_t &det, const geometry::identifier geo_id)
0069 : surface(det, det.surface(geo_id)) {}
0070
0071
0072 DETRAY_HOST_DEVICE
0073 constexpr surface(const detector_t &det, const dindex sf_idx)
0074 : surface(det, det.surface(sf_idx)) {}
0075
0076
0077
0078 template <typename detector_type = detector_t>
0079 requires(!std::is_const_v<detector_type>)
0080
0081 DETRAY_HOST_DEVICE constexpr operator surface<const detector_type>() const {
0082 return surface<const detector_type>{this->m_detector, this->m_desc};
0083 }
0084
0085
0086
0087
0088 DETRAY_HOST_DEVICE
0089 constexpr auto operator==(const surface &rhs) const -> bool {
0090 return (&m_detector == &(rhs.m_detector) && m_desc == rhs.m_desc);
0091 }
0092
0093
0094 DETRAY_HOST_DEVICE
0095 constexpr auto identifier() const -> geometry::identifier {
0096 assert(!m_desc.identifier().is_invalid());
0097 return m_desc.identifier();
0098 }
0099
0100
0101 DETRAY_HOST_DEVICE
0102 constexpr auto volume() const -> dindex {
0103 assert(identifier().volume() < m_detector.volumes().size());
0104 return identifier().volume();
0105 }
0106
0107
0108 DETRAY_HOST_DEVICE
0109 constexpr auto index() const -> dindex {
0110 assert(identifier().index() < m_detector.surfaces().size());
0111 return identifier().index();
0112 }
0113
0114
0115 DETRAY_HOST_DEVICE
0116 constexpr auto id() const -> surface_id {
0117 assert(identifier().id() != surface_id::e_unknown);
0118 return identifier().id();
0119 }
0120
0121
0122 DETRAY_HOST_DEVICE
0123 constexpr auto extra() const -> dindex { return identifier().extra(); }
0124
0125
0126 DETRAY_HOST_DEVICE
0127 constexpr auto shape_id() const { return m_desc.mask().id(); }
0128
0129
0130 DETRAY_HOST_DEVICE
0131 constexpr auto source() const {
0132 return m_detector.surface(identifier()).source;
0133 }
0134
0135
0136 DETRAY_HOST_DEVICE
0137 constexpr auto is_sensitive() const -> bool {
0138 return identifier().id() == surface_id::e_sensitive;
0139 }
0140
0141
0142 DETRAY_HOST_DEVICE
0143 constexpr auto is_portal() const -> bool {
0144 return identifier().id() == surface_id::e_portal;
0145 }
0146
0147
0148 DETRAY_HOST_DEVICE
0149 constexpr auto is_passive() const -> bool {
0150 return identifier().id() == surface_id::e_passive;
0151 }
0152
0153
0154 DETRAY_HOST_DEVICE
0155 constexpr bool has_material() const { return m_desc.has_material(); }
0156
0157
0158 DETRAY_HOST_DEVICE
0159 constexpr auto volume_links() const {
0160 return visit_mask<typename kernels::get_volume_links>();
0161 }
0162
0163
0164 DETRAY_HOST
0165 std::string shape_name() const {
0166 return visit_mask<typename kernels::get_shape_name>();
0167 }
0168
0169
0170 DETRAY_HOST_DEVICE
0171 std::size_t n_masks() const {
0172 if constexpr (concepts::interval<decltype(m_desc.mask().index())>) {
0173 return m_desc.mask().index().size();
0174 } else {
0175 return 1u;
0176 }
0177 }
0178
0179
0180 DETRAY_HOST_DEVICE
0181 constexpr auto transform(const context &ctx) const
0182 -> const transform3_type & {
0183 assert(m_desc.transform() < m_detector.transform_store().size());
0184 return m_detector.transform_store().at(m_desc.transform(), ctx);
0185 }
0186
0187
0188 template <concepts::point point_t = point2_type>
0189 DETRAY_HOST_DEVICE constexpr bool is_inside(const point_t &loc_p,
0190 const scalar_type tol) const {
0191 return visit_mask<typename kernels::is_inside>(loc_p, tol);
0192 }
0193
0194
0195 DETRAY_HOST_DEVICE
0196 constexpr auto boundary(std::size_t index) const {
0197 return visit_mask<typename kernels::get_mask_value>(index);
0198 }
0199
0200
0201 DETRAY_HOST_DEVICE
0202 constexpr auto centroid() const -> point3_type {
0203 return visit_mask<typename kernels::centroid>();
0204 }
0205
0206
0207
0208
0209 DETRAY_HOST_DEVICE
0210 constexpr auto center(const context &ctx) const -> point3_type {
0211 return transform(ctx).translation();
0212 }
0213
0214
0215
0216 template <concepts::point point_t = point2_type>
0217 DETRAY_HOST_DEVICE constexpr auto normal(const context &ctx,
0218 const point_t &p) const
0219 -> vector3_type {
0220 return visit_mask<typename kernels::normal>(transform(ctx), p);
0221 }
0222
0223
0224
0225 DETRAY_HOST_DEVICE constexpr const material<scalar_type> *material_parameters(
0226 const point2_type &loc_p) const {
0227 return visit_material<typename kernels::get_material_params>(loc_p);
0228 }
0229
0230
0231
0232 DETRAY_HOST_DEVICE
0233 constexpr point3_type global_to_local(const context &ctx,
0234 const point3_type &global,
0235 const vector3_type &dir) const {
0236 return visit_mask<typename kernels::global_to_local>(transform(ctx), global,
0237 dir);
0238 }
0239
0240
0241
0242 DETRAY_HOST_DEVICE
0243 constexpr point2_type global_to_bound(const context &ctx,
0244 const point3_type &global,
0245 const vector3_type &dir) const {
0246 const point3_type local{global_to_local(ctx, global, dir)};
0247
0248 return {local[0], local[1]};
0249 }
0250
0251
0252
0253 template <concepts::point point_t = point2_type>
0254 DETRAY_HOST_DEVICE constexpr point3_type local_to_global(
0255 const context &ctx, const point_t &local, const vector3_type &dir) const {
0256 return visit_mask<typename kernels::local_to_global>(transform(ctx), local,
0257 dir);
0258 }
0259
0260
0261
0262
0263
0264 template <typename functor_t, typename... Args>
0265 DETRAY_HOST_DEVICE constexpr auto visit_mask(Args &&...args) const {
0266 assert(!m_desc.mask().is_invalid());
0267 const auto &masks = m_detector.mask_store();
0268 return masks.template visit<functor_t>(m_desc.mask(),
0269 std::forward<Args>(args)...);
0270 }
0271
0272
0273
0274
0275
0276 template <typename functor_t, typename... Args>
0277 DETRAY_HOST_DEVICE constexpr auto visit_material(Args &&...args) const {
0278 assert(has_material());
0279 const auto &materials = m_detector.material_store();
0280 return materials.template visit<functor_t>(m_desc.material(),
0281 std::forward<Args>(args)...);
0282 }
0283
0284
0285
0286
0287
0288
0289 DETRAY_HOST bool self_check(std::ostream &os) const {
0290 if (identifier().is_invalid()) {
0291 os << "DETRAY ERROR (HOST): Invalid identifier for surface:\n"
0292 << *this << std::endl;
0293 return false;
0294 }
0295 if (index() >= m_detector.surfaces().size()) {
0296 os << "DETRAY ERROR (HOST): Surface index out of bounds for "
0297 "surface:\n"
0298 << *this << std::endl;
0299 return false;
0300 }
0301 if (volume() >= m_detector.volumes().size()) {
0302 os << "DETRAY ERROR (HOST): Surface volume index out of bounds for "
0303 "surface:\n"
0304 << *this << std::endl;
0305 return false;
0306 }
0307 if (detail::is_invalid_value(m_desc.transform())) {
0308 os << "DETRAY ERROR (HOST): Surface transform undefined for "
0309 "surface:\n"
0310 << *this << std::endl;
0311 return false;
0312 }
0313 if (m_desc.transform() >= m_detector.transform_store().size()) {
0314 os << "DETRAY ERROR (HOST): Surface transform index out of bounds "
0315 "for surface:\n"
0316 << *this << std::endl;
0317 return false;
0318 }
0319 if (detail::is_invalid_value(m_desc.mask())) {
0320 os << "DETRAY ERROR (HOST): Surface does not have a valid mask "
0321 "link:\n"
0322 << *this << std::endl;
0323 return false;
0324 }
0325
0326 if (!m_detector.material_store().all_empty() && has_material() &&
0327 m_desc.material().is_invalid_index()) {
0328 os << "DETRAY ERROR (HOST): Surface does not have valid material "
0329 "link:\n"
0330 << *this << std::endl;
0331 return false;
0332 }
0333
0334 if (!visit_mask<typename kernels::mask_self_check>(os)) {
0335 os << "\nSurface: " << *this << std::endl;
0336 return false;
0337 }
0338
0339
0340 const auto vol_links = visit_mask<typename kernels::get_volume_links>();
0341 for (const auto vol_link : vol_links) {
0342 if (is_portal()) {
0343 if (vol_link == volume()) {
0344 os << "DETRAY ERROR (HOST): Portal surface links to mother "
0345 "volume:\n"
0346 << *this << std::endl;
0347 return false;
0348 }
0349 } else if (vol_link != volume()) {
0350 os << "DETRAY ERROR (HOST): Passive/sensitive surface does not "
0351 "link to mother volume: Mask volume link : "
0352 << vol_link << "\n"
0353 << *this << std::endl;
0354 return false;
0355 }
0356 }
0357
0358 return true;
0359 }
0360
0361 protected:
0362
0363 DETRAY_HOST
0364 friend std::ostream &operator<<(std::ostream &os, const surface &sf) {
0365 os << sf.m_desc;
0366 return os;
0367 }
0368
0369
0370 DETRAY_HOST_DEVICE
0371 const detector_t &detector() const { return m_detector; }
0372
0373
0374 DETRAY_HOST_DEVICE
0375 descr_t descriptor() const { return m_desc; }
0376
0377 private:
0378
0379 const detector_t &m_detector;
0380
0381 const descr_t m_desc;
0382 };
0383
0384 template <typename detector_t, typename descr_t>
0385 DETRAY_HOST_DEVICE surface(const detector_t &, const descr_t &)
0386 -> surface<detector_t>;
0387
0388 template <typename detector_t>
0389 DETRAY_HOST_DEVICE surface(const detector_t &, const geometry::identifier)
0390 -> surface<detector_t>;
0391
0392 }