File indexing completed on 2026-10-17 08:32:08
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/containers.hpp"
0013 #include "detray/definitions/indexing.hpp"
0014 #include "detray/material/material.hpp"
0015 #include "detray/material/material_rod.hpp"
0016 #include "detray/material/material_slab.hpp"
0017
0018
0019 #include <algorithm>
0020 #include <cstddef>
0021 #include <functional>
0022 #include <optional>
0023 #include <unordered_map>
0024 #include <utility>
0025
0026
0027
0028
0029
0030
0031
0032
0033 namespace detray::detail {
0034
0035
0036
0037 template <concepts::scalar scalar_t>
0038 DETRAY_HOST constexpr bool is_identical(const material<scalar_t> &lhs,
0039 const material<scalar_t> &rhs) {
0040 return lhs == rhs && lhs.mass_density() == rhs.mass_density() &&
0041 lhs.molar_density() == rhs.molar_density() &&
0042 lhs.state() == rhs.state() &&
0043 lhs.has_density_effect_data() == rhs.has_density_effect_data() &&
0044 lhs.density_effect_data() == rhs.density_effect_data();
0045 }
0046
0047
0048 template <concepts::scalar scalar_t>
0049 DETRAY_HOST constexpr bool is_identical(const material_slab<scalar_t> &lhs,
0050 const material_slab<scalar_t> &rhs) {
0051 return is_identical(lhs.get_material(), rhs.get_material()) &&
0052 lhs.thickness() == rhs.thickness() &&
0053 lhs.thickness_in_X0() == rhs.thickness_in_X0() &&
0054 lhs.thickness_in_L0() == rhs.thickness_in_L0();
0055 }
0056
0057
0058 template <concepts::scalar scalar_t>
0059 DETRAY_HOST constexpr bool is_identical(const material_rod<scalar_t> &lhs,
0060 const material_rod<scalar_t> &rhs) {
0061
0062 return is_identical(lhs.get_material(), rhs.get_material()) &&
0063 lhs.radius() == rhs.radius();
0064 }
0065
0066
0067
0068 template <typename axis_lhs_t, typename axis_rhs_t>
0069 DETRAY_HOST bool is_identical_axis(const axis_lhs_t &lhs,
0070 const axis_rhs_t &rhs) {
0071 if (lhs.label() != rhs.label() || lhs.bounds() != rhs.bounds() ||
0072 lhs.binning() != rhs.binning() || lhs.nbins() != rhs.nbins() ||
0073 lhs.span() != rhs.span()) {
0074 return false;
0075 }
0076 const auto lhs_edges = lhs.bin_edges();
0077 const auto rhs_edges = rhs.bin_edges();
0078
0079 return std::ranges::equal(lhs_edges, rhs_edges);
0080 }
0081
0082
0083
0084
0085
0086
0087
0088 template <typename grid_lhs_t, typename grid_rhs_t>
0089 DETRAY_HOST bool is_identical_grid(const grid_lhs_t &lhs,
0090 const grid_rhs_t &rhs) {
0091 static_assert(grid_lhs_t::dim == grid_rhs_t::dim);
0092
0093 if (lhs.nbins() != rhs.nbins()) {
0094 return false;
0095 }
0096
0097
0098 const bool same_axes = [&]<std::size_t... I>(std::index_sequence<I...>) {
0099 return (is_identical_axis(lhs.template get_axis<I>(),
0100 rhs.template get_axis<I>()) &&
0101 ...);
0102 }(std::make_index_sequence<grid_lhs_t::dim>{});
0103
0104 if (!same_axes) {
0105 return false;
0106 }
0107
0108
0109 for (dindex gbin = 0u; gbin < lhs.nbins(); ++gbin) {
0110 const auto &lhs_bin = lhs.bin(gbin);
0111 const auto &rhs_bin = rhs.bin(gbin);
0112
0113 auto rhs_itr = rhs_bin.begin();
0114 for (const auto &lhs_entry : lhs_bin) {
0115 if (rhs_itr == rhs_bin.end() || !is_identical(lhs_entry, *rhs_itr)) {
0116 return false;
0117 }
0118 ++rhs_itr;
0119 }
0120 if (rhs_itr != rhs_bin.end()) {
0121 return false;
0122 }
0123 }
0124
0125 return true;
0126 }
0127
0128
0129
0130 template <typename material_entry_t>
0131 DETRAY_HOST std::size_t material_hash(const material_entry_t &entry) {
0132 using scalar_t = typename material_entry_t::scalar_type;
0133
0134 const auto &mat = entry.get_material();
0135 std::size_t seed{0u};
0136 for (const scalar_t v :
0137 {entry.thickness(), mat.X0(), mat.L0(), mat.Ar(), mat.Z()}) {
0138
0139 seed ^=
0140 std::hash<scalar_t>{}(v) + 0x9e3779b9u + (seed << 6u) + (seed >> 2u);
0141 }
0142 return seed;
0143 }
0144
0145
0146
0147
0148
0149
0150 template <typename collection_t>
0151 class homogeneous_material_lookup {
0152 using value_type = typename collection_t::value_type;
0153
0154 public:
0155
0156 DETRAY_HOST explicit homogeneous_material_lookup(collection_t &coll)
0157 : m_coll{coll} {
0158 for (dindex i = 0u; i < static_cast<dindex>(m_coll.size()); ++i) {
0159 m_index.emplace(material_hash(m_coll[i]), i);
0160 }
0161 }
0162
0163
0164
0165 DETRAY_HOST std::optional<dindex> find(const value_type &entry) const {
0166 auto [first, last] = m_index.equal_range(material_hash(entry));
0167 for (auto itr = first; itr != last; ++itr) {
0168 if (is_identical(m_coll[itr->second], entry)) {
0169 return itr->second;
0170 }
0171 }
0172 return std::nullopt;
0173 }
0174
0175
0176
0177 DETRAY_HOST dindex insert(const value_type &entry) {
0178 if (auto idx = find(entry); idx.has_value()) {
0179 return *idx;
0180 }
0181 const auto idx{static_cast<dindex>(m_coll.size())};
0182 m_coll.push_back(entry);
0183 m_index.emplace(material_hash(entry), idx);
0184
0185 return idx;
0186 }
0187
0188 private:
0189 collection_t &m_coll;
0190 std::unordered_multimap<std::size_t, dindex> m_index{};
0191 };
0192
0193 }