ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
geometry_reader.hpp
1// This file is part of the ACTS project.
2//
3// Copyright (C) 2016 CERN for the benefit of the ACTS project
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#pragma once
10
11// Project include(s)
12#include "detray/builders/detector_builder.hpp"
13#include "detray/builders/surface_factory.hpp"
14#include "detray/builders/volume_builder.hpp"
15#include "detray/core/concepts.hpp"
16#include "detray/definitions/indexing.hpp"
17#include "detray/io/backend/detail/basic_converter.hpp"
18#include "detray/io/backend/detail/type_info.hpp"
19#include "detray/io/frontend/payloads.hpp"
20
21// System include(s)
22#include <algorithm>
23#include <cassert>
24#include <map>
25#include <stdexcept>
26#include <string_view>
27#include <utility>
28#include <vector>
29
30namespace std {
31
32// Specialize std::hash directly to the shape id type
33template <>
34struct hash<detray::io::shape_id> {
35 auto operator()(detray::io::shape_id m) const noexcept {
36 return std::hash<std::size_t>()(static_cast<std::size_t>(m));
37 }
38};
39
40} // namespace std
41
42namespace detray::io {
43
50 using io_shape_id = io::shape_id;
51
52 public:
54 static constexpr std::string_view tag = "geometry";
55
58
63 template <class detector_t>
64 static void from_payload(detector_builder<typename detector_t::metadata,
65 volume_builder>& det_builder,
66 const payload_type& det_data) {
67 DETRAY_VERBOSE_HOST("Reading payload object...");
68
69 // Can hold all types of surface fatory needed for the detector
70 using sf_factory_ptr_t =
71 std::shared_ptr<surface_factory_interface<detector_t>>;
72
73 // Map the io::shape_id in the payload to the shape types known by
74 // the detector under construction
75 using shape_registry_t = io::detail::filtered_shape_registry<detector_t>;
76 static_assert(
77 (!types::contains<shape_registry_t, io::detail::unknown_type> &&
78 types::size<shape_registry_t> > 0) ||
79 (types::contains<shape_registry_t, io::detail::unknown_type> &&
80 types::size<shape_registry_t> > 1));
81
82 DETRAY_DEBUG_HOST("Have " << det_data.volumes.size() << " input volumes");
83
84 // Convert the volumes one-by-one
85 for (const auto& vol_data : det_data.volumes) {
86 // Get a generic volume builder first and decorate it later
87 DETRAY_DEBUG_HOST("Configuring detector builder with new volume '"
88 << vol_data.name << "' of type " << vol_data.type);
89 auto vbuilder = det_builder.new_volume(vol_data.type);
90
91 // Set the volume name
92 vbuilder->set_name(vol_data.name);
93
94 DETRAY_DEBUG_HOST("Volume placement for " << vol_data.name << " is\n"
95 << vol_data.transform);
96 // Volume placement
97 vbuilder->add_volume_placement(
98 from_payload<detector_t>(vol_data.transform));
99
100 // Prepare the surface factories (one per shape and surface type)
101 std::map<io_shape_id, sf_factory_ptr_t> pt_factories;
102 std::map<io_shape_id, sf_factory_ptr_t> sf_factories;
103
104 // Add the surfaces to the factories
105 DETRAY_DEBUG_HOST("Discovered " << vol_data.surfaces.size()
106 << " surfaces in volume payload");
107 for (const auto& [sf_idx, sf_data] :
108 detray::views::enumerate(vol_data.surfaces)) {
109 const std::vector<mask_payload>& mask_data = sf_data.masks;
110
111 // Get a reference to the correct factory collection
112 auto& factories{sf_data.type == surface_id::e_portal ? pt_factories
113 : sf_factories};
114
115 // @TODO use portal cylinders until intersectors are fixed
116 auto shape_id{mask_data.front().shape == io_shape_id::cylinder2
117 ? io_shape_id::portal_cylinder2
118 : mask_data.front().shape};
119
120 if (shape_id == io_shape_id::unknown) {
121 std::string err_str{"Unknown mask shape id in geometry file!"};
122 DETRAY_FATAL_HOST(err_str);
123 throw std::invalid_argument(err_str);
124 }
125
126 // Check if a fitting factory already exists. If not, add it
127 // dynamically
128 const auto key{shape_id};
129 if (auto search = factories.find(key); search == factories.end()) {
130 DETRAY_DEBUG_HOST(
131 "Creating new surface factory for shape id: " << key);
132 factories[key] =
133 std::move(init_factory<shape_registry_t, detector_t>(shape_id));
134 }
135
136 DETRAY_DEBUG_HOST("-> Surface #" << sf_idx << " is " << sf_data.type);
137 DETRAY_DEBUG_HOST("--> shape = " << shape_id);
138 for ([[maybe_unused]] const auto& m_data : mask_data) {
139 DETRAY_DEBUG_HOST("--> boundaries = ["
140 << DETRAY_LOG_VECTOR(m_data.boundaries) << "]");
141 }
142 DETRAY_DEBUG_HOST("--> pos = ["
143 << DETRAY_LOG_VECTOR(sf_data.transform.tr) << "]");
144
145 // Add the data to the factory
146 factories.at(key)->push_back(from_payload<detector_t>(sf_data));
147 }
148
149 // Add all portals and surfaces to the volume
150 typename detector_t::geometry_context geo_ctx{};
151 for (const auto& [key, pt_factory] : pt_factories) {
152 DETRAY_DEBUG_HOST("Adding '" << key
153 << "' portal factory to volume builder");
154 vbuilder->add_surfaces(pt_factory, geo_ctx);
155 }
156
157 for (const auto& [key, sf_factory] : sf_factories) {
158 DETRAY_DEBUG_HOST("Adding '" << key
159 << "' surface factory to volume builder");
160 vbuilder->add_surfaces(sf_factory, geo_ctx);
161 }
162 }
163
164 // @TODO: Implement voume finder IO
165 }
166
168 template <class detector_t>
169 static typename detector_t::transform3_type from_payload(
170 const transform_payload& trf_data) {
171 using algebra_t = typename detector_t::algebra_type;
172 using scalar_t = dscalar<algebra_t>;
173 using vector3_t = dvector3D<algebra_t>;
174
175 vector3_t t{static_cast<scalar_t>(trf_data.tr[0]),
176 static_cast<scalar_t>(trf_data.tr[1]),
177 static_cast<scalar_t>(trf_data.tr[2])};
178 vector3_t x{static_cast<scalar_t>(trf_data.rot[0]),
179 static_cast<scalar_t>(trf_data.rot[1]),
180 static_cast<scalar_t>(trf_data.rot[2])};
181 vector3_t y{static_cast<scalar_t>(trf_data.rot[3]),
182 static_cast<scalar_t>(trf_data.rot[4]),
183 static_cast<scalar_t>(trf_data.rot[5])};
184 vector3_t z{static_cast<scalar_t>(trf_data.rot[6]),
185 static_cast<scalar_t>(trf_data.rot[7]),
186 static_cast<scalar_t>(trf_data.rot[8])};
187
188 return dtransform3D<algebra_t>{t, x, y, z};
189 }
190
195 template <class detector_t>
197 using nav_link_t = typename detector_t::surface_type::navigation_link;
199
200 // Transcribe mask boundaries onto correct vector type
201 std::vector<std::vector<scalar_t>> mask_boundaries{};
202 for (const auto& mask_data : sf_data.masks) {
203 std::vector<scalar_t>& boundaries = mask_boundaries.emplace_back();
204 std::ranges::copy(mask_data.boundaries, std::back_inserter(boundaries));
205 }
206
207 // If the concentric cylinder is shifted in z, discard the shift
208 // and put it in the mask boundaries instead. Everything else
209 // will be ignored
210 // @TODO: Remove this for cylinders again once 2 solution intersection
211 // work
212 auto trf = from_payload<detector_t>(sf_data.transform);
213 if (sf_data.masks.front().shape == io_shape_id::portal_cylinder2 ||
214 sf_data.masks.front().shape == io_shape_id::cylinder2) {
215 const auto z_shift{static_cast<scalar_t>(trf.translation()[2])};
216
217 for (auto& mask_boundary : mask_boundaries) {
218 mask_boundary[concentric_cylinder2D::e_lower_z] += z_shift;
219 mask_boundary[concentric_cylinder2D::e_upper_z] += z_shift;
220 }
221
222 // Set the transform to identity afterwards
223 trf = decltype(trf){};
224 }
225
226 const std::size_t sf_idx{
227 sf_data.index_in_coll.has_value()
228 ? *(sf_data.index_in_coll)
229 : detray::detail::invalid_value<std::size_t>()};
230
231 std::vector<nav_link_t> vol_links{};
232 vol_links.reserve(sf_data.masks.size());
233 for (const auto& mask_pl : sf_data.masks) {
234 vol_links.push_back(static_cast<nav_link_t>(
235 detail::basic_converter::from_payload(mask_pl.volume_link)));
236 }
237
238 assert(mask_boundaries.size() == vol_links.size());
239
240 return {sf_data.type,
241 trf,
242 std::move(vol_links),
243 std::move(mask_boundaries),
244 static_cast<dindex>(sf_idx),
245 sf_data.source};
246 }
247
248 private:
253 template <typename shape_registry_t, concepts::detector detector_t,
254 std::size_t I = 0u>
255 static std::shared_ptr<surface_factory_interface<detector_t>> init_factory(
256 const io_shape_id shape_id) {
257 // Get the next mask shape type
258 using shape_t = types::at<shape_registry_t, I>;
259
260 // Test whether this shape exists in detector
261 if constexpr (!std::is_same_v<shape_t, io::detail::unknown_type>) {
262 // Shape index of surface data found
263 if (shape_id == types::id<io::shape_registry, shape_t>) {
264 return std::make_shared<surface_factory<detector_t, shape_t>>();
265 }
266 }
267 // Test next shape id
268 if constexpr (I < types::size<shape_registry_t> - 1u) {
269 return init_factory<shape_registry_t, detector_t, I + 1>(shape_id);
270 } else {
271 std::string err_str{
272 "Given shape id could not be matched to a mask type: " +
273 std::to_string(static_cast<std::int64_t>(shape_id))};
274
275 DETRAY_FATAL_HOST(err_str);
276 throw std::invalid_argument(err_str);
277 }
278
279 // Cannot be reached
280 return {nullptr};
281 }
282};
283
284} // namespace detray::io
Provides functionality to build a detray detector volume by volume.
Definition detector_builder.hpp:40
Tracking geometry reader backend.
Definition geometry_reader.hpp:47
static void from_payload(detector_builder< typename detector_t::metadata, volume_builder > &det_builder, const payload_type &det_data)
Populate the detector builder from a serialized geometry payload.
Definition geometry_reader.hpp:64
detector_payload payload_type
Payload type that the reader processes.
Definition geometry_reader.hpp:57
static constexpr std::string_view tag
Tag the reader as "geometry".
Definition geometry_reader.hpp:54
static detector_t::transform3_type from_payload(const transform_payload &trf_data)
Definition geometry_reader.hpp:169
static surface_data< detector_t > from_payload(const surface_payload &sf_data)
Build surface-factory data from a serialized surface entry.
Definition geometry_reader.hpp:196
Bind transform and mask data together for surface building.
Definition surface_factory_interface.hpp:37
Provides basic functionality to build detector volumes.
Definition volume_builder.hpp:36
Check if a type can be used as a detector.
Definition concepts.hpp:47
constexpr double m
Meter.
Definition Units.hpp:97
The following enums are global for all detectors.
Definition concepts.hpp:18
shape_id
Enumerate the shape primitives globally.
Definition definitions.hpp:33
get_scalar_t< A, T > dscalar
Scalar type for algebra A and value type T.
Definition algebra.hpp:64
unsigned int dindex
Default index type.
Definition indexing.hpp:18
get_vector3D_t< A, T > dvector3D
Three-dimensional vector type for algebra A and value type T.
Definition algebra.hpp:80
get_transform3D_t< A, T > dtransform3D
Three-dimensional transform type for algebra A and value type T.
Definition algebra.hpp:84
A payload for a detector geometry.
Definition payloads.hpp:355
std::vector< volume_payload > volumes
Material payloads grouped by detector volume.
Definition payloads.hpp:357
A payload for surfaces.
Definition payloads.hpp:153
detray::surface_id type
Either sensitive, passive or portal.
Definition payloads.hpp:169
transform_payload transform
Placement transform of the surface.
Definition payloads.hpp:158
std::optional< std::size_t > index_in_coll
Position of the surface in the volume surface container.
Definition payloads.hpp:156
std::vector< mask_payload > masks
Mask definitions attached to the surface.
Definition payloads.hpp:160
std::uint64_t source
Identifier of the source object (e.g. value of ACTS::GeometryIdentifier).
Definition payloads.hpp:164
A payload for an affine transformation in homogeneous coordinates.
Definition payloads.hpp:100
std::array< io::scalar, 9u > rot
Column-major 3 by 3 rotation matrix.
Definition payloads.hpp:106
std::array< io::scalar, 3u > tr
Translation.
Definition payloads.hpp:102
Range adaptor that creates an enumerate view, optionally starting at a selected index.
Definition enumerate.hpp:266