diff --git a/core/include/detray/builders/cuboid_portal_generator.hpp b/core/include/detray/builders/cuboid_portal_generator.hpp index 952c6806e0..82fea75cde 100644 --- a/core/include/detray/builders/cuboid_portal_generator.hpp +++ b/core/include/detray/builders/cuboid_portal_generator.hpp @@ -85,7 +85,7 @@ class cuboid_portal_generator final typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using point3_t = dpoint3D; using vector3_t = dvector3D; diff --git a/core/include/detray/builders/cylinder_portal_generator.hpp b/core/include/detray/builders/cylinder_portal_generator.hpp index bc62353ca1..972dd6189b 100644 --- a/core/include/detray/builders/cylinder_portal_generator.hpp +++ b/core/include/detray/builders/cylinder_portal_generator.hpp @@ -182,7 +182,7 @@ class cylinder_portal_generator final typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using aabb_t = axis_aligned_bounding_volume; diff --git a/core/include/detray/builders/homogeneous_material_factory.hpp b/core/include/detray/builders/homogeneous_material_factory.hpp index 267d11395a..033b03b2bf 100644 --- a/core/include/detray/builders/homogeneous_material_factory.hpp +++ b/core/include/detray/builders/homogeneous_material_factory.hpp @@ -39,21 +39,33 @@ class material_data { const std::size_t sf_idx = detail::invalid_value()) : m_sf_index{sf_idx} {} + /// Construct from a predefined material, without specific surface index. + /// Material will be appended to the surfaces at the end of the container + /// + /// @param mat predefined material, see + /// 'detray/materials/predefined_materials.hpp' + /// @param thickness of the material slab/rod + DETRAY_HOST + constexpr material_data(const scalar_t thickness, + const material &mat) + : material_data{detail::invalid_value(), thickness, mat} {} + /// Construct from a predefined material /// + /// @param sf_idx the volume-local index of the surface this material + /// belongs to /// @param mat predefined material, see /// 'detray/materials/predefined_materials.hpp' /// @param thickness of the material slab/rod - /// @param sf_idx the index of the surface this material belongs to, needs - /// to be passed only if a special oredering must be observed DETRAY_HOST - constexpr material_data( - const scalar_t thickness, const material &mat, - const std::size_t sf_idx = detail::invalid_value()) + constexpr material_data(const std::size_t sf_idx, const scalar_t thickness, + const material &mat) : m_sf_index{sf_idx}, m_mat{mat}, m_thickness{thickness} {} /// Construct from all parameters: /// + /// @param sf_idx the volume-local index of the surface this material + /// belongs to /// @param thickness of the material slab/rod /// @param material_paramters0 x0 is the radiation length /// @param material_paramters1 l0 is the nuclear interaction length @@ -61,14 +73,11 @@ class material_data { /// @param material_paramters3 z is the nuclear charge number /// @param material_paramters4 molarRho is the molar density /// @param state of the material (liquid, solid etc.) - /// @param sf_idx the index of the surface this material belongs to, needs - /// to be passed only if a special oredering must be observed DETRAY_HOST constexpr material_data( - const scalar_t thickness, + const std::size_t sf_idx, const scalar_t thickness, const std::vector &material_paramters, - const material_state state = material_state::e_solid, - const std::size_t sf_idx = detail::invalid_value()) + const material_state state = material_state::e_solid) : m_sf_index{sf_idx}, m_mat{material{material_paramters[0], material_paramters[1], material_paramters[2], material_paramters[3], @@ -172,7 +181,6 @@ class homogeneous_material_factory final // Need exactly one material per surface assert(m_indices.empty() || (m_indices.size() == n_surfaces)); - assert(m_links.size() == n_surfaces); assert(m_materials.size() == n_surfaces); assert(m_thickness.size() == n_surfaces); @@ -181,17 +189,20 @@ class homogeneous_material_factory final /// @returns the material links to the surfaces (counted for this volume) DETRAY_HOST - auto links() const -> const std::vector & { return m_links; } + auto links() const -> const std::map & { + return m_links; + } /// @returns the raw materials that are currently in the factory DETRAY_HOST - auto materials() const -> const std::vector> & { + auto materials() const + -> const std::map> & { return m_materials; } /// @returns the material thickness currently held by the factory DETRAY_HOST - auto thickness() const -> const std::vector & { + auto thickness() const -> const std::map & { return m_thickness; } @@ -208,10 +219,16 @@ class homogeneous_material_factory final assert(mat.size() == 1u); assert(thickness.size() == 1u); - m_links.push_back(std::make_pair(id, static_cast(index))); - m_indices.push_back(sf_index); - m_materials.push_back(mat[0]); - m_thickness.push_back(thickness[0]); + // Save the material data either at the surface index or append it for + // the next surface + const std::size_t i{detail::is_invalid_value(sf_index) + ? m_links.size() + : sf_index}; + + m_indices.push_back(i); + m_links.emplace(i, std::make_pair(id, static_cast(index))); + m_materials.emplace(i, mat[0]); + m_thickness.emplace(i, thickness[0]); } /// Add all necessary compontents to the factory for multiple material slabs @@ -238,6 +255,28 @@ class homogeneous_material_factory final m_thickness.clear(); } + /// Call the underlying surface factory and record the surface range that + /// was produced + /// + /// @param volume the volume the portals need to be added to. + /// @param surfaces the surface collection to wrap and to add the portals to + /// @param transforms the transforms of the surfaces. + /// @param masks the masks of the surfaces. + /// @param ctx the geometry context (not needed for portals). + DETRAY_HOST + auto operator()(typename detector_t::volume_type &volume, + typename detector_t::surface_lookup_container &surfaces, + typename detector_t::transform_container &transforms, + typename detector_t::mask_container &masks, + typename detector_t::geometry_context ctx = {}) + -> dvector override { + + m_surface_indices = + (*this->get_factory())(volume, surfaces, transforms, masks, ctx); + + return m_surface_indices; + } + /// @brief Add material to the containers of a volume builder. /// /// This assumes that the surfaces have already been added (e.g. by this @@ -265,10 +304,12 @@ class homogeneous_material_factory final // Check that the surfaces were set up correctly const std::size_t n_materials{this->n_materials()}; - assert(surfaces.size() >= n_materials); + assert(m_surface_indices.size() >= n_materials); + assert(surfaces.size() >= m_surface_indices.size()); // If no concrete surface ordering was passed, use index sequence // and add the materials to the trailing elements in the surfaces cont. + std::size_t sf_offset{0u}; if (m_indices.empty() || std::ranges::find(m_indices, detail::invalid_value()) != @@ -276,14 +317,30 @@ class homogeneous_material_factory final m_indices.resize(n_materials); std::iota(std::begin(m_indices), std::end(m_indices), surfaces.size() - n_materials); - } - // Correctly index the data in this factory - std::size_t sf_offset{*std::ranges::min_element(m_indices)}; + // Check that the underlying surface factory produced a contiguous + // range of surfaces. Otherwise the @c material_data has to be + // constructed with the matching surface indices + std::stringstream err_stream{ + "ERROR: Given material does not match the produced surfaces. " + "Use explicit surface with the material data."}; + if (m_indices.size() != m_surface_indices.size()) { + throw std::invalid_argument(err_stream.str()); + } + for (std::size_t j = 0u; j < m_surface_indices.size(); ++j) { + if (m_indices[j] != m_surface_indices[j]) { + throw std::invalid_argument(err_stream.str()); + } + } + + // Correctly index the data in this factory + sf_offset = *std::ranges::min_element(m_indices); + } // Add the material to the surfaces that the data links against - for (auto [i, sf] : detray::views::pick(surfaces, m_indices)) { - std::size_t sf_idx{i - sf_offset}; + for (const std::size_t i : m_indices) { + const auto sf_idx{i - sf_offset}; + const material &mat = m_materials.at(sf_idx); scalar_type t = m_thickness.at(sf_idx); @@ -292,8 +349,8 @@ class homogeneous_material_factory final auto &mat_coll = materials.template get(); material_slab mat_slab{mat, t}; - mat_idx = this->insert_in_container(mat_coll, mat_slab, - m_links.at(sf_idx).second); + mat_idx = this->insert_into_container( + mat_coll, mat_slab, m_links.at(sf_idx).second); } if constexpr (detector_t::materials::template is_defined< material_rod>()) { @@ -302,27 +359,29 @@ class homogeneous_material_factory final materials.template get(); material_rod mat_rod{mat, t}; - mat_idx = this->insert_in_container(mat_coll, mat_rod, - m_links[sf_idx].second); + mat_idx = this->insert_into_container( + mat_coll, mat_rod, m_links.at(sf_idx).second); } } // Set the initial surface material link (will be updated when // added to the detector) - surfaces.at(static_cast(i)).material() = - link_t{m_links[sf_idx].first, mat_idx}; + surfaces.at(static_cast(sf_idx)).material() = + link_t{m_links.at(sf_idx).first, mat_idx}; } } private: + /// Range of surface indices for which to generate material + dvector m_surface_indices{}; /// Material links of surfaces - std::vector> m_links{}; - /// Position of the material in the detector material collection + std::map> m_links{}; + /// Index of the surface the material belongs to (volume local) std::vector m_indices{}; /// Material thickness - std::vector m_thickness{}; + std::map m_thickness{}; /// The pre-computed material to be wrapped in a slab or rod - std::vector> m_materials{}; + std::map> m_materials{}; }; } // namespace detray diff --git a/core/include/detray/builders/homogeneous_material_generator.hpp b/core/include/detray/builders/homogeneous_material_generator.hpp index 9679f25a2e..048b5152f9 100644 --- a/core/include/detray/builders/homogeneous_material_generator.hpp +++ b/core/include/detray/builders/homogeneous_material_generator.hpp @@ -104,14 +104,12 @@ class homogeneous_material_generator final typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { - auto [lower, upper] = + m_surface_indices = (*this->get_factory())(volume, surfaces, transforms, masks, ctx); - m_surface_range = {lower, upper}; - - return {lower, upper}; + return m_surface_indices; } /// Create material slabs or rods for all surfaces that the undelying @@ -128,10 +126,12 @@ class homogeneous_material_generator final using material_id = typename detector_t::materials::id; using link_t = typename detector_t::surface_type::material_link; - assert(surfaces.size() >= (m_surface_range[1] - m_surface_range[0])); + // Make sure enough surfaces are present after surface factory ran + assert(surfaces.size() >= m_surface_indices.size()); // Add the material to the surfaces that the data links against - for (auto &sf : detray::ranges::subrange(surfaces, m_surface_range)) { + for (dindex sf_idx : m_surface_indices) { + auto &sf = surfaces.at(sf_idx); const material *mat_ptr{nullptr}; @@ -216,7 +216,7 @@ class homogeneous_material_generator final /// Material generator configuration hom_material_config m_cfg; /// Range of surface indices for which to generate material - dindex_range m_surface_range{}; + dvector m_surface_indices{}; }; } // namespace detray diff --git a/core/include/detray/builders/material_map_factory.hpp b/core/include/detray/builders/material_map_factory.hpp index cfd5013794..19785c210b 100644 --- a/core/include/detray/builders/material_map_factory.hpp +++ b/core/include/detray/builders/material_map_factory.hpp @@ -110,11 +110,13 @@ class material_map_factory final : public factory_decorator { auto [sf_index, mat, thickness] = std::move(mat_data).get_data(); - m_links[sf_index] = std::make_pair(id, std::move(indices)); - m_n_bins[sf_index] = std::move(n_bins); - m_axis_spans[sf_index] = std::move(axis_spans); - m_materials[sf_index] = std::move(mat); - m_thickness[sf_index] = std::move(thickness); + assert(!detail::is_invalid_value(sf_index)); + + m_links.emplace(sf_index, std::make_pair(id, std::move(indices))); + m_n_bins.emplace(sf_index, std::move(n_bins)); + m_axis_spans.emplace(sf_index, std::move(axis_spans)); + m_materials.emplace(sf_index, std::move(mat)); + m_thickness.emplace(sf_index, std::move(thickness)); } /// Clear old data @@ -163,12 +165,12 @@ class material_map_factory final : public factory_decorator { // Copy the number of bins to the builder assert(m_n_bins.at(sf_idx).size() == N); - n_bins[sf_idx] = {}; + n_bins.emplace(sf_idx, darray{}); std::ranges::copy_n(m_n_bins.at(sf_idx).begin(), N, n_bins.at(sf_idx).begin()); // Copy the axis spans to the builder (if present) - axis_spans[sf_idx] = darray, N>{}; + axis_spans.at(sf_idx) = darray, N>{}; for (std::size_t in = 0; in < N; ++in) { if (m_axis_spans.at(sf_idx).size() > in) { axis_spans.at(sf_idx).at(in) = @@ -187,14 +189,14 @@ class material_map_factory final : public factory_decorator { auto search = material_map.find(sf_idx); if (search == material_map.end()) { - material_map[sf_idx] = std::vector{data}; + material_map.emplace(sf_idx, std::vector{data}); } else { search->second.push_back(data); } } auto map_id{m_links.at(sf_idx).first}; - surfaces[sf_idx].material() = link_t{map_id, dindex_invalid}; + surfaces.at(sf_idx).material() = link_t{map_id, dindex_invalid}; } } diff --git a/core/include/detray/builders/material_map_generator.hpp b/core/include/detray/builders/material_map_generator.hpp index b39af926bc..dc67693a77 100644 --- a/core/include/detray/builders/material_map_generator.hpp +++ b/core/include/detray/builders/material_map_generator.hpp @@ -87,7 +87,7 @@ struct material_map_config { dindex map_id{dindex_invalid}; /// Number of bins for material maps darray n_bins{20u, 20u}; - /// Along which of the two axes to scale the material + /// Along which of the two axes to scale the material thickness std::size_t axis_index{0u}; /// Material to be filled into the maps material mapped_material{silicon_tml()}; @@ -172,14 +172,12 @@ class material_map_generator final : public factory_decorator { typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { - auto [lower, upper] = + m_surface_indices = (*this->get_factory())(volume, surfaces, transforms, masks, ctx); - m_surface_range = {lower, upper}; - - return {lower, upper}; + return m_surface_indices; } /// Create material maps for all surfaces that the undelying surface @@ -205,12 +203,12 @@ class material_map_generator final : public factory_decorator { using mask_id = typename detector_t::masks::id; using material_id = typename detector_t::materials::id; - assert(surfaces.size() >= (m_surface_range[1] - m_surface_range[0])); + // Make sure enough surfaces are present after surface factory ran + assert(surfaces.size() >= m_surface_indices.size()); // Add the material only to those surfaces that the data links against - for (const auto &[i, sf] : detray::views::enumerate( - detray::ranges::subrange(surfaces, m_surface_range))) { - const auto sf_idx{m_surface_range[0] + i}; + for (dindex sf_idx : m_surface_indices) { + auto &sf = surfaces.at(sf_idx); // Skip line surfaces, if any are defined if constexpr (detector_t::materials::template is_defined< @@ -231,12 +229,12 @@ class material_map_generator final : public factory_decorator { // Copy the number of bins to the builder assert(map_cfg.n_bins.size() == N); - n_bins[sf_idx] = {}; + n_bins.emplace(sf_idx, darray{}); std::ranges::copy_n(map_cfg.n_bins.begin(), N, n_bins.at(sf_idx).begin()); // Scale material thickness either over e.g. r- or z-bins - const std::size_t bins = map_cfg.n_bins[map_cfg.axis_index]; + const std::size_t bins = map_cfg.n_bins.at(map_cfg.axis_index); using sf_kernels = detail::surface_kernels; @@ -257,11 +255,12 @@ class material_map_generator final : public factory_decorator { bin_data_t data{ axis::multi_bin{bin0, bin1}, - material[(map_cfg.axis_index == 0u) ? bin0 : bin1]}; + material.at((map_cfg.axis_index == 0u) ? bin0 : bin1)}; auto search = material_map.find(sf_idx); if (search == material_map.end()) { - material_map[sf_idx] = std::vector{data}; + material_map.emplace(sf_idx, + std::vector{data}); } else { search->second.push_back(data); } @@ -270,8 +269,8 @@ class material_map_generator final : public factory_decorator { // Set the initial surface material link (will be updated when // added to the detector) - surfaces[sf_idx].material() = link_t{ - static_cast(map_cfg.map_id), dindex_invalid}; + sf.material() = link_t{static_cast(map_cfg.map_id), + dindex_invalid}; } } @@ -279,7 +278,7 @@ class material_map_generator final : public factory_decorator { /// Material generator configuration material_map_config m_cfg; /// Range of surface indices for which to generate material - dindex_range m_surface_range{}; + dvector m_surface_indices{}; }; } // namespace detray diff --git a/core/include/detray/builders/surface_factory.hpp b/core/include/detray/builders/surface_factory.hpp index 85dc9ff053..440b708f39 100644 --- a/core/include/detray/builders/surface_factory.hpp +++ b/core/include/detray/builders/surface_factory.hpp @@ -149,10 +149,13 @@ class surface_factory : public surface_factory_interface { [[maybe_unused]] typename detector_t::mask_container &masks, [[maybe_unused]] typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { // In case the surfaces container is prefilled with other surfaces const auto surfaces_offset{static_cast(surfaces.size())}; + // Save the indices of the generated surfaces for decorating factories + dvector surface_indices{}; + surface_indices.reserve(this->size()); // Nothing to construct if (size() == 0u) { @@ -186,8 +189,8 @@ class surface_factory : public surface_factory_interface { ? dindex_invalid : m_indices[idx]}; - // Add transform - const dindex trf_idx = this->insert_in_container( + // Add transform (same ordering as surfaces) + const dindex trf_idx = this->insert_into_container( transforms, m_transforms[idx], sf_idx, ctx); // Masks are simply appended, since they are distributed onto @@ -211,16 +214,19 @@ class surface_factory : public surface_factory_interface { material_link_t material_link{no_material, dindex_invalid}; // Add the surface descriptor at the position given by 'sf_idx' - this->insert_in_container( + const dindex final_idx = this->insert_into_container( surfaces, {surface_t{trf_idx, mask_link, material_link, volume.index(), m_types[idx]}, m_sources[idx]}, sf_idx); + + surface_indices.push_back(final_idx); } } + assert(!surface_indices.empty()); - return {surfaces_offset, static_cast(surfaces.size())}; + return surface_indices; } private: diff --git a/core/include/detray/builders/surface_factory_interface.hpp b/core/include/detray/builders/surface_factory_interface.hpp index 7122b896f4..30b484948e 100644 --- a/core/include/detray/builders/surface_factory_interface.hpp +++ b/core/include/detray/builders/surface_factory_interface.hpp @@ -122,7 +122,7 @@ class surface_factory_interface { typename detector_t::surface_lookup_container &surfaces, typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, - typename detector_t::geometry_context ctx = {}) -> dindex_range = 0; + typename detector_t::geometry_context ctx = {}) -> dvector = 0; protected: /// Insert a value in a container at a specific index @@ -134,7 +134,7 @@ class surface_factory_interface { /// /// @returns the position where the value has been copied. template - DETRAY_HOST dindex insert_in_container( + DETRAY_HOST dindex insert_into_container( container_t &cont, const typename container_t::value_type value, const dindex idx, Args &&... args) const { // If no valid position is given, perform push back @@ -203,7 +203,7 @@ class factory_decorator : public surface_factory_interface { typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { return (*m_factory)(volume, surfaces, transforms, masks, ctx); } /// @} diff --git a/io/include/detray/io/backend/detail/grid_reader.hpp b/io/include/detray/io/backend/detail/grid_reader.hpp index 1a2f8c83fe..9629066715 100644 --- a/io/include/detray/io/backend/detail/grid_reader.hpp +++ b/io/include/detray/io/backend/detail/grid_reader.hpp @@ -393,6 +393,7 @@ class grid_reader { } // For now assume surfaces ids as the only grid input + // TODO: Write bin content converter for (const auto c : bin_data.content) { if (detray::detail::is_invalid_value( static_cast(c))) { diff --git a/io/include/detray/io/backend/detail/grid_writer.hpp b/io/include/detray/io/backend/detail/grid_writer.hpp index 395384317c..ce7c793c01 100644 --- a/io/include/detray/io/backend/detail/grid_writer.hpp +++ b/io/include/detray/io/backend/detail/grid_writer.hpp @@ -145,7 +145,9 @@ class grid_writer { /// /// @param store the data store of grids (tuple of grid collections) /// @param grid_link type and index of the grid - /// @param owner_idx inder of the owner of the grid (e.g. volume index) + /// @param vol_idx type and index of volume the grid belongs to + /// @param owner_idx inder of the owner of the grid (can be identical to + /// vol_idx or volume-local surface index) /// @param grid_data the grid payload to be filled /// @param converter callable that can convert a grid bin entry into its /// respective IO payload (of type @tparam content_t) @@ -171,8 +173,8 @@ class grid_writer { inline void operator()( [[maybe_unused]] const grid_group_t& coll, [[maybe_unused]] const index_t& index, - [[maybe_unused]] std::size_t vol_link, - [[maybe_unused]] std::size_t owner_link, + [[maybe_unused]] std::size_t vol_idx, + [[maybe_unused]] std::size_t owner_idx, [[maybe_unused]] detector_grids_payload& grids_data, [[maybe_unused]] converter_t& converter) const { @@ -184,15 +186,15 @@ class grid_writer { using value_t = typename coll_value_t::value_type; auto gr_pyload = to_payload( - owner_link, io::detail::get_id(), index, + owner_idx, io::detail::get_id(), index, coll[index], converter); auto& grids_map = grids_data.grids; - auto search = grids_map.find(vol_link); + auto search = grids_map.find(vol_idx); if (search != grids_map.end()) { - grids_map.at(vol_link).push_back(std::move(gr_pyload)); + grids_map.at(vol_idx).push_back(std::move(gr_pyload)); } else { - grids_map[vol_link] = {std::move(gr_pyload)}; + grids_map[vol_idx] = {std::move(gr_pyload)}; } } } diff --git a/io/include/detray/io/backend/homogeneous_material_reader.hpp b/io/include/detray/io/backend/homogeneous_material_reader.hpp index 48161f159d..f5d22f374d 100644 --- a/io/include/detray/io/backend/homogeneous_material_reader.hpp +++ b/io/include/detray/io/backend/homogeneous_material_reader.hpp @@ -74,32 +74,24 @@ class homogeneous_material_reader { auto mat_factory = std::make_shared>(); - for (const auto& slab_data : mv_data.mat_slabs) { - assert(slab_data.type == io::material_id::slab); + for (const auto& mat_data : mv_data.surface_mat) { + // Determine the material type id + auto mat_type{mat_id::e_slab}; + if constexpr (detray::concepts::has_material_rods) { + mat_type = mat_data.type == io::material_id::slab + ? mat_id::e_slab + : mat_id::e_rod; + } else { + assert(mat_data.type == io::material_id::slab); + } - const auto sf_link{ - slab_data.index_in_coll.has_value() - ? slab_data.index_in_coll.value() + const auto mat_idx{ + mat_data.index_in_coll.has_value() + ? mat_data.index_in_coll.value() : detray::detail::invalid_value()}; mat_factory->add_material( - mat_id::e_slab, from_payload(slab_data), sf_link); - } - if constexpr (detray::concepts::has_material_rods) { - if (mv_data.mat_rods.has_value()) { - for (const auto& rod_data : *(mv_data.mat_rods)) { - assert(rod_data.type == io::material_id::rod); - - const auto sf_link{ - rod_data.index_in_coll.has_value() - ? rod_data.index_in_coll.value() - : detray::detail::invalid_value()}; - - mat_factory->add_material( - mat_id::e_rod, from_payload(rod_data), - sf_link); - } - } + mat_type, from_payload(mat_data), mat_idx); } // Add the material to the volume @@ -113,14 +105,14 @@ class homogeneous_material_reader { static material_data from_payload( const material_slab_payload& slab_data) { - return {static_cast(slab_data.thickness), - from_payload(slab_data.mat), - detail::basic_converter::from_payload(slab_data.surface)}; + return {detail::basic_converter::from_payload(slab_data.surface), + static_cast(slab_data.thickness), + from_payload(slab_data.mat)}; } /// @returns the material from its IO payload @param mat_data template - static auto from_payload(const material_payload& mat_data) { + static auto from_payload(const material_param_payload& mat_data) { return material{ static_cast(mat_data.params[0]), @@ -128,7 +120,7 @@ class homogeneous_material_reader { static_cast(mat_data.params[2]), static_cast(mat_data.params[3]), static_cast(mat_data.params[4]), - // The molar density is calculated on the fly + // The molar density (params[5]) is calculated on the fly static_cast(mat_data.params[6])}; } }; diff --git a/io/include/detray/io/backend/homogeneous_material_writer.hpp b/io/include/detray/io/backend/homogeneous_material_writer.hpp index e18a3fca88..c874b1c358 100644 --- a/io/include/detray/io/backend/homogeneous_material_writer.hpp +++ b/io/include/detray/io/backend/homogeneous_material_writer.hpp @@ -121,13 +121,10 @@ class homogeneous_material_writer { : material_slab_payload{}; mslp.type == material_type::slab) { mslp.index_in_coll = slab_idx++; - mv_data.mat_slabs.push_back(mslp); + mv_data.surface_mat.push_back(mslp); } else if (mslp.type == material_type::rod) { - if (!mv_data.mat_rods.has_value()) { - mv_data.mat_rods.emplace(); - } mslp.index_in_coll = rod_idx++; - mv_data.mat_rods->push_back(mslp); + mv_data.surface_mat.push_back(mslp); } else { /* material maps are handled by another writer */ } ++sf_idx; @@ -138,8 +135,8 @@ class homogeneous_material_writer { /// Convert surface material @param mat into its io payload template - static material_payload to_payload(const material& mat) { - material_payload mat_data; + static material_param_payload to_payload(const material& mat) { + material_param_payload mat_data; mat_data.params = {mat.X0(), mat.L0(), diff --git a/io/include/detray/io/backend/material_map_reader.hpp b/io/include/detray/io/backend/material_map_reader.hpp index b44fcfbde7..8420e2cf52 100644 --- a/io/include/detray/io/backend/material_map_reader.hpp +++ b/io/include/detray/io/backend/material_map_reader.hpp @@ -117,7 +117,7 @@ class material_map_reader { } loc_bins.push_back(std::move(mbin)); - // For now assume surfaces ids as the only grid input + // Add the material slab per bin for (const auto &slab_data : bin_data.content) { mat_data.append( material_reader_t::template from_payload( diff --git a/io/include/detray/io/frontend/payloads.hpp b/io/include/detray/io/frontend/payloads.hpp index d83ec9c02e..8f7635cbff 100644 --- a/io/include/detray/io/frontend/payloads.hpp +++ b/io/include/detray/io/frontend/payloads.hpp @@ -1,6 +1,6 @@ /** Detray library, part of the ACTS project (R&D line) * - * (c) 2022-2024 CERN for the benefit of the ACTS project + * (c) 2022-2025 CERN for the benefit of the ACTS project * * Mozilla Public License Version 2.0 */ @@ -29,31 +29,44 @@ /// Raw indices (std::size_t) denote links between data components in different /// files, while links used in detray detector objects are modelled as e.g. /// @c single_link_payload +/// +/// @note All indices are with respect to volume that the data belongs to, +/// starting at zero namespace detray::io { /// @brief a payload for common information struct common_header_payload { - std::string version{}, detector{}, tag{}, date{}; + /// Detray version number + std::string version{}; + /// Detector name + std::string detector{}; + /// Type of data the file contains (e.g. geometry vs material_maps) + std::string tag{}; + /// Date of file creation + std::string date{}; }; /// @brief a payload for common and extra information template struct header_payload { common_header_payload common{}; + /// Information that is specific to a tag, i.e. type of detector payload std::optional sub_header; }; -/// @brief A payload for a single object link +/// @brief A payload for a single object link (volume local) struct single_link_payload { std::size_t link{std::numeric_limits::max()}; }; -/// @brief A payload for a typed object link +/// @brief A payload for a typed object link (@c dtyped_index) template struct typed_link_payload { using type_id = type_id_t; + /// Type id of the object, e.g. @c shape_id type_id type{type_id::unknown}; + /// Index of the object within its volume std::size_t index{std::numeric_limits::max()}; }; @@ -62,7 +75,9 @@ struct typed_link_payload { /// @brief a payload for the geometry specific part of the file header struct geo_sub_header_payload { + /// Number of volumes in the detector std::size_t n_volumes{0ul}; + /// Total number of surfaces in the detector std::size_t n_surfaces{0ul}; }; @@ -77,8 +92,9 @@ using acc_links_payload = typed_link_payload; /// @brief A payload for an affine transformation in homogeneous coordinates struct transform_payload { + /// Translation std::array tr{}; - // Column major + // Column major rotaion matrix std::array rot{}; }; @@ -87,20 +103,28 @@ struct mask_payload { using mask_shape = io::shape_id; mask_shape shape{mask_shape::unknown}; + /// Sensitive/passive surface: Mother volume index, Portal: Volume the + /// portal leads into single_link_payload volume_link{}; + /// Boundary values accroding to @c boundaries enum of the shape in @c shape std::vector boundaries{}; }; /// @brief A payload for surfaces struct surface_payload { + /// Position of the surface in the volume surface container. + /// Optional, if no specific ordering std::optional index_in_coll; transform_payload transform{}; mask_payload mask{}; + /// Write the material link of the surface as additional information std::optional material; + /// Identifier of the source object (e.g. value of ACTS::GeometryIdentifier) std::uint64_t source{}; - // Write the surface barcode as an additional information + /// Write the surface barcode as an additional information std::optional barcode{ detray::detail::invalid_value()}; + /// Either sensitive, passive or portal detray::surface_id type{detray::surface_id::e_sensitive}; }; @@ -110,9 +134,9 @@ struct volume_payload { detray::volume_id type{detray::volume_id::e_cylinder}; transform_payload transform{}; std::vector surfaces{}; - // Index of the volume in the detector volume container + /// Index of the volume in the detector volume container single_link_payload index{}; - // Optional accelerator data structures + /// Optional accelerator data structures std::optional> acc_links{}; }; @@ -123,7 +147,9 @@ struct volume_payload { /// @brief a payload for the material specific part of the file header struct homogeneous_material_sub_header_payload { + /// Total number of material slabs in the detector std::size_t n_slabs{0ul}; + /// Total number of material rods (wire material) in the detector std::size_t n_rods{0ul}; }; @@ -132,7 +158,15 @@ using homogeneous_material_header_payload = header_payload; /// @brief A payload object for a material parametrization -struct material_payload { +struct material_param_payload { + /// Material parametrization + /// 0: X0 + /// 1: L0 + /// 2: Ar + /// 3: Z + /// 4: Mass density + /// 5: Molar densitty (unused) + /// 6: @c material_state enum (solid, liquid, gaseous) std::array params{}; }; @@ -140,18 +174,31 @@ struct material_payload { struct material_slab_payload { using mat_type = io::material_id; + /// Either 'slab' or 'rod' mat_type type{mat_type::unknown}; + /// Index of the material in the material container + /// Optional, if no specific sorting required std::optional index_in_coll; + /// Index of the surface in the volume the material belongs to single_link_payload surface{}; real_io thickness{std::numeric_limits::max()}; - material_payload mat{}; + material_param_payload mat{}; }; -/// @brief A payload object for the material contained in a volume +/// @brief A payload for the material of a volume +struct volume_material_payload { + // Not implemented +}; + +/// @brief A payload object for all of the [surface] material contained in a +/// volume struct material_volume_payload { + /// Volume index the payload belongs to single_link_payload volume_link{}; - std::vector mat_slabs{}; - std::optional> mat_rods; + /// Material of the volume + std::optional vol_mat; + /// Material slabs/rods of contained surfaces + std::vector surface_mat{}; }; /// @brief A payload for the homogeneous material description of a detector @@ -174,35 +221,46 @@ using grid_header_payload = header_payload; /// @brief axis definition and bin edges struct axis_payload { - /// axis lookup type + /// Axis binning type axis::binning binning{axis::binning::e_regular}; + /// Axis behaviour at final bin axis::bounds bounds{axis::bounds::e_closed}; + /// Label to retrieve the axis axis::label label{axis::label::e_r}; + /// Number of bins std::size_t bins{0u}; + /// Axis span for reg. binning or distinct bin edge values for irr. binning std::vector edges{}; }; -/// @brief A payload for a grid bin +/// @brief A payload for a single grid bin +/// @note The local indices and bin content container need to have the same +/// ordering for the data to be matched template struct grid_bin_payload { + /// Bin index per axis (global index is determined by serializer) std::vector loc_index{}; + /// Bin content for the bin (e.g. coll. of surface indices or material slab) std::vector content{}; }; /// @brief A payload for a grid definition +/// @tparam bin_content_t the value type of the grid, e.g. surface indices or +/// material_slab_payloads +/// @tparam grid_id_t grid type enum, e.g. @c accel_id or @c material_id template struct grid_payload { using grid_type = grid_id_t; - // Surface or volume index the grids belongs to + // volume-local surface or gloabl volume index the grids belongs to single_link_payload owner_link{}; - // Type and index of the grid + // Type and global index of the grid (index is optional only for debugging) typed_link_payload grid_link{}; + /// Must match the number of axis in the grid type indicated by @c grid_link std::vector axes{}; std::vector> bins{}; - std::optional transform; }; /// @brief A payload for the grid collections of a detector @@ -220,6 +278,7 @@ struct detector_grids_payload { /// @brief A payload for a detector geometry struct detector_payload { std::vector volumes = {}; + /// Volume acceleration structure std::optional> volume_grid; }; diff --git a/io/include/detray/io/json/detail/json_grids_io.hpp b/io/include/detray/io/json/detail/json_grids_io.hpp index e8870ba1b6..4d103c7077 100644 --- a/io/include/detray/io/json/detail/json_grids_io.hpp +++ b/io/include/detray/io/json/detail/json_grids_io.hpp @@ -87,10 +87,6 @@ inline void to_json(nlohmann::ordered_json& j, jbins.push_back(bin); } j["bins"] = jbins; - - if (g.transform.has_value()) { - j["transform"] = g.transform.value(); - } } template @@ -110,11 +106,6 @@ inline void from_json(const nlohmann::ordered_json& j, grid_bin_payload b = jbin; g.bins.push_back(std::move(b)); } - - if (j.find("transform") != j.end()) { - g.transform.emplace(); - g.transform = j["transform"]; - } } template diff --git a/io/include/detray/io/json/detail/json_material_io.hpp b/io/include/detray/io/json/detail/json_material_io.hpp index eddc8a6561..9685c24560 100644 --- a/io/include/detray/io/json/detail/json_material_io.hpp +++ b/io/include/detray/io/json/detail/json_material_io.hpp @@ -43,11 +43,13 @@ inline void from_json(const nlohmann::ordered_json& j, } } -inline void to_json(nlohmann::ordered_json& j, const material_payload& m) { +inline void to_json(nlohmann::ordered_json& j, + const material_param_payload& m) { j["params"] = m.params; } -inline void from_json(const nlohmann::ordered_json& j, material_payload& m) { +inline void from_json(const nlohmann::ordered_json& j, + material_param_payload& m) { m.params = j["params"].get>(); } @@ -76,19 +78,12 @@ inline void to_json(nlohmann::ordered_json& j, const material_volume_payload& mv) { j["volume_link"] = mv.volume_link; - if (!mv.mat_slabs.empty()) { + if (!mv.surface_mat.empty()) { nlohmann::ordered_json jmats; - for (const auto& m : mv.mat_slabs) { + for (const auto& m : mv.surface_mat) { jmats.push_back(m); } - j["material_slabs"] = jmats; - } - if (mv.mat_rods.has_value() && !mv.mat_rods->empty()) { - nlohmann::ordered_json jmats; - for (const auto& m : mv.mat_rods.value()) { - jmats.push_back(m); - } - j["material_rods"] = jmats; + j["surface_material"] = jmats; } } @@ -96,17 +91,10 @@ inline void from_json(const nlohmann::ordered_json& j, material_volume_payload& mv) { mv.volume_link = j["volume_link"]; - if (j.find("material_slabs") != j.end()) { - for (auto jmats : j["material_slabs"]) { - material_slab_payload mslp = jmats; - mv.mat_slabs.push_back(mslp); - } - } - if (j.find("material_rods") != j.end()) { - mv.mat_rods.emplace(); - for (auto jmats : j["material_rods"]) { + if (j.find("surface_material") != j.end()) { + for (auto jmats : j["surface_material"]) { material_slab_payload mslp = jmats; - mv.mat_rods->push_back(mslp); + mv.surface_mat.push_back(mslp); } } } diff --git a/tests/include/detray/test/common/factories/barrel_generator.hpp b/tests/include/detray/test/common/factories/barrel_generator.hpp index 98cbd95741..207ff72b83 100644 --- a/tests/include/detray/test/common/factories/barrel_generator.hpp +++ b/tests/include/detray/test/common/factories/barrel_generator.hpp @@ -147,7 +147,7 @@ class barrel_generator final : public surface_factory_interface { typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using surface_t = typename detector_t::surface_type; using nav_link_t = typename surface_t::navigation_link; diff --git a/tests/include/detray/test/common/factories/endcap_generator.hpp b/tests/include/detray/test/common/factories/endcap_generator.hpp index afbb5b7d7b..c7d40b5084 100644 --- a/tests/include/detray/test/common/factories/endcap_generator.hpp +++ b/tests/include/detray/test/common/factories/endcap_generator.hpp @@ -177,7 +177,7 @@ class endcap_generator final : public surface_factory_interface { typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using surface_t = typename detector_t::surface_type; using nav_link_t = typename surface_t::navigation_link; diff --git a/tests/include/detray/test/common/factories/telescope_generator.hpp b/tests/include/detray/test/common/factories/telescope_generator.hpp index b4f8969dae..71f4d9cf6d 100644 --- a/tests/include/detray/test/common/factories/telescope_generator.hpp +++ b/tests/include/detray/test/common/factories/telescope_generator.hpp @@ -107,7 +107,7 @@ class telescope_generator final : public surface_factory_interface { typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using surface_t = typename detector_t::surface_type; using nav_link_t = typename surface_t::navigation_link; diff --git a/tests/include/detray/test/common/factories/wire_layer_generator.hpp b/tests/include/detray/test/common/factories/wire_layer_generator.hpp index 233b9c471f..2e74a31b50 100644 --- a/tests/include/detray/test/common/factories/wire_layer_generator.hpp +++ b/tests/include/detray/test/common/factories/wire_layer_generator.hpp @@ -125,7 +125,7 @@ class wire_layer_generator final typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using surface_t = typename detector_t::surface_type; using nav_link_t = typename surface_t::navigation_link; diff --git a/tests/include/detray/test/utils/prefill_detector.hpp b/tests/include/detray/test/utils/prefill_detector.hpp index 61d60ab09a..9065fee266 100644 --- a/tests/include/detray/test/utils/prefill_detector.hpp +++ b/tests/include/detray/test/utils/prefill_detector.hpp @@ -58,7 +58,8 @@ void prefill_detector(detector_t& d, vol_link, std::vector{-3.f, 3.f}}); rectangle_factory->add_material( material_id::e_slab, - {3.f * unit::mm, detray::gold()}); + {0u, 3.f * unit::mm, detray::gold()}); + // Surface 1 auto annulus_factory = std::make_shared>( @@ -69,7 +70,7 @@ void prefill_detector(detector_t& d, vol_link, std::vector{1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f}}); annulus_factory->add_material( material_id::e_slab, - {12.f * unit::mm, detray::tungsten()}); + {1u, 12.f * unit::mm, detray::tungsten()}); // Surface 2 auto trapezoid_factory = @@ -81,7 +82,7 @@ void prefill_detector(detector_t& d, vol_link, std::vector{1.f, 2.f, 3.f, 1.f / 6.f}}); trapezoid_factory->add_material( material_id::e_rod, - {4.f * unit::mm, detray::aluminium()}); + {2u, 4.f * unit::mm, detray::aluminium()}); // Build the volume with three surfaces and homogenenous material v_mat_builder.add_surfaces(rectangle_factory, ctx); diff --git a/tests/unit_tests/cpu/builders/homogeneous_material_builder.cpp b/tests/unit_tests/cpu/builders/homogeneous_material_builder.cpp index a97aa696fc..1872e7ea76 100644 --- a/tests/unit_tests/cpu/builders/homogeneous_material_builder.cpp +++ b/tests/unit_tests/cpu/builders/homogeneous_material_builder.cpp @@ -65,36 +65,44 @@ TEST(detray_builders, homogeneous_material_factory) { EXPECT_TRUE(mat_factory->materials().empty()); EXPECT_TRUE(mat_factory->thickness().empty()); - // Add material for a few rectangle surfaces + // Add some rectangle surfaces mat_factory->push_back({surface_id::e_sensitive, transform3(point3{0.f, 0.f, -1.f}), 1u, std::vector{10.f, 8.f}}); - mat_factory->add_material(material_id::e_slab, - {1.f * unit::mm, silicon()}); mat_factory->push_back({surface_id::e_sensitive, transform3(point3{0.f, 0.f, 1.f}), 1u, std::vector{20.f, 16.f}}); - mat_factory->add_material(material_id::e_slab, - {10.f * unit::mm, tungsten()}); - // Pass the parameters for 'gold' mat_factory->push_back({surface_id::e_sensitive, - transform3(point3{0.f, 0.f, 1.f}), 1u, + transform3(point3{0.f, 0.f, 10.f}), 1u, + std::vector{20.f, 16.f}}); + mat_factory->push_back({surface_id::e_passive, + transform3(point3{0.f, 0.f, 20.f}), 1u, std::vector{20.f, 16.f}}); + mat_factory->push_back({surface_id::e_sensitive, + transform3(point3{0.f, 0.f, 50.f}), 1u, + std::vector{20.f, 16.f}}); + + // Add material for a few rectangle surfaces + mat_factory->add_material(material_id::e_slab, + {0u, 1.f * unit::mm, silicon()}); + mat_factory->add_material( + material_id::e_slab, {3u, 10.f * unit::mm, tungsten()}); + // Pass the parameters for 'gold' mat_factory->add_material( material_id::e_rod, - {0.1f * unit::mm, + {4u, 0.1f * unit::mm, std::vector{ 3.344f * unit::mm, 101.6f * unit::mm, 196.97f, 79, 19.32f * unit::g / (1.f * unit::cm3)}, material_state::e_solid}); - EXPECT_EQ(mat_factory->size(), 3u); + EXPECT_EQ(mat_factory->size(), 5u); // Test the material data - EXPECT_NEAR(mat_factory->thickness()[0], 1.f * unit::mm, tol); - EXPECT_NEAR(mat_factory->thickness()[1], 10.f * unit::mm, tol); - EXPECT_NEAR(mat_factory->thickness()[2], 0.1f * unit::mm, tol); - EXPECT_EQ(mat_factory->materials()[0], silicon()); - EXPECT_EQ(mat_factory->materials()[1], tungsten()); - EXPECT_EQ(mat_factory->materials()[2], gold()); + EXPECT_NEAR(mat_factory->thickness().at(0), 1.f * unit::mm, tol); + EXPECT_NEAR(mat_factory->thickness().at(3), 10.f * unit::mm, tol); + EXPECT_NEAR(mat_factory->thickness().at(4), 0.1f * unit::mm, tol); + EXPECT_EQ(mat_factory->materials().at(0), silicon()); + EXPECT_EQ(mat_factory->materials().at(3), tungsten()); + EXPECT_EQ(mat_factory->materials().at(4), gold()); } diff --git a/tutorials/include/detray/tutorial/square_surface_generator.hpp b/tutorials/include/detray/tutorial/square_surface_generator.hpp index f7e20890e1..f2bc3d6f00 100644 --- a/tutorials/include/detray/tutorial/square_surface_generator.hpp +++ b/tutorials/include/detray/tutorial/square_surface_generator.hpp @@ -67,7 +67,7 @@ class square_surface_generator final typename detector_t::transform_container &transforms, typename detector_t::mask_container &masks, typename detector_t::geometry_context ctx = {}) - -> dindex_range override { + -> dvector override { using surface_t = typename detector_t::surface_type; using mask_link_t = typename surface_t::mask_link; using material_link_t = typename surface_t::material_link;