ACTS
Experiment-independent tracking
Loading...
Searching...
No Matches
material_validation_utils.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/core/concepts.hpp"
13#include "detray/definitions/algebra.hpp"
14#include "detray/material/concepts.hpp"
15#include "detray/material/detail/material_accessor.hpp"
16#include "detray/navigation/caching_navigator.hpp"
17#include "detray/navigation/detail/print_state.hpp"
18#include "detray/propagator/actors.hpp"
19#include "detray/propagator/line_stepper.hpp"
20#include "detray/propagator/propagator.hpp"
21#include "detray/utils/logging.hpp"
22#include "detray/utils/type_list.hpp"
23
24// Detray IO include(s)
25#include "detray/io/utils/create_path.hpp"
26#include "detray/io/utils/file_handle.hpp"
27
28// Test include(s)
29#include "detray/test/utils/data_record.hpp"
30
31// Vecmem include(s)
32#include <vecmem/memory/memory_resource.hpp>
33
34// System include(s)
35#include <filesystem>
36
37namespace detray::material_validator {
38
43 double phi{detail::invalid_value<double>()};
45 double eta{detail::invalid_value<double>()};
48 double sX0{0.f};
50 double tX0{0.f};
52 double sL0{0.f};
54 double tL0{0.f};
55};
56
66 template <typename mat_group_t, typename index_t, concepts::point2D point2_t,
67 concepts::scalar scalar_t>
68 DETRAY_HOST_DEVICE auto operator()(
69 [[maybe_unused]] const mat_group_t &mat_group,
70 [[maybe_unused]] const index_t &index,
71 [[maybe_unused]] const point2_t &loc,
72 [[maybe_unused]] const scalar_t cos_inc_angle) const {
73 using material_t = typename mat_group_t::value_type;
74
75 constexpr auto inv{detail::invalid_value<double>()};
76 constexpr geometry::identifier inv_sf{};
77
78 // Access homogeneous surface material or material maps
80 // Slab or rod
81 const auto mat = detail::material_accessor::get(mat_group, index, loc);
82
83 // Empty material can occur in material maps, skip it
84 if (!mat) {
85 // Set the pathlength and thickness to zero so that they are not counted
86 return material_record{inv_sf, 0.f, 0.f, inv, inv};
87 }
88
89 const double seg{mat.path_segment(cos_inc_angle, loc[0])};
90 const double t{mat.thickness()};
91 const double mat_X0{mat.get_material().X0()};
92 const double mat_L0{mat.get_material().L0()};
93
94 return material_record{inv_sf, seg, t, mat_X0, mat_L0};
95 } else {
96 return material_record{inv_sf, 0., 0., inv, inv};
97 }
98 }
99};
100
106template <template <typename...> class vector_t>
112
114 struct state {
115 friend struct material_tracer;
116
119 DETRAY_HOST
120 explicit state(vecmem::memory_resource &resource)
121 : m_mat_steps(&resource) {}
122
125 DETRAY_HOST_DEVICE
126 explicit state(vector_t<material_record_type> &&steps)
127 : m_mat_steps(std::move(steps)) {}
128
131 DETRAY_HOST_DEVICE
132 const auto &get_track_material() const { return m_track_material; }
133
136 DETRAY_HOST
137 auto &&release_track_material() && { return std::move(m_track_material); }
138
141 DETRAY_HOST_DEVICE
142 const auto &get_material_steps() const { return m_mat_steps; }
143
146 DETRAY_HOST_DEVICE
147 auto &&release_material_steps() && { return std::move(m_mat_steps); }
148
149 private:
151 track_material_type m_track_material{};
152
154 vector_t<material_record_type> m_mat_steps{};
155 };
156
161 template <typename propagator_state_t, concepts::algebra algebra_t>
162 DETRAY_HOST_DEVICE void operator()(
163 state &tracer, const propagator_state_t &prop_state,
165 record_track_dir(tracer, prop_state);
166
167 // Only count material if navigator encountered it
168 const auto &navigation = prop_state.navigation();
169 if (!navigation.encountered_sf_material()) {
170 return;
171 }
172
173 // For now use default context
174 typename propagator_state_t::detector_type::geometry_context gctx{};
175
176 const auto &track_param = res.destination_params();
177 dpoint2D<algebra_t> loc_pos = track_param.bound_local();
178
179 record_mat_step(tracer, gctx, navigation.current_surface(), loc_pos,
180 track_param.dir());
181 }
182
186 template <typename propagator_state_t>
187 DETRAY_HOST_DEVICE void operator()(
188 state &tracer, const propagator_state_t &prop_state) const {
189 using algebra_t = typename propagator_state_t::detector_type::algebra_type;
190
191 record_track_dir(tracer, prop_state);
192
193 // Only count material if navigator encountered it
194 const auto &navigation = prop_state.navigation();
195 if (!navigation.encountered_sf_material()) {
196 return;
197 }
198
199 // For now use default context
200 typename propagator_state_t::detector_type::geometry_context gctx{};
201
202 // Current surface
203 const auto sf = navigation.current_surface();
204
205 const auto &track_param = prop_state.stepping()();
206 dvector3D<algebra_t> glob_dir = track_param.dir();
207 dpoint2D<algebra_t> loc_pos =
208 sf.global_to_bound(gctx, track_param.pos(), glob_dir);
209
210 record_mat_step(tracer, gctx, sf, loc_pos, glob_dir);
211 }
212
213 private:
215 template <typename propagator_state_t>
216 DETRAY_HOST_DEVICE inline auto record_track_dir(
217 state &tracer, const propagator_state_t &prop_state) const {
218 using algebra_t = typename propagator_state_t::detector_type::algebra_type;
219 using vector3_t = dvector3D<algebra_t>;
220
221 // Record the initial track direction
222 vector3_t glob_dir = prop_state.stepping()().dir();
223 if (detray::detail::is_invalid_value(tracer.m_track_material.eta) &&
224 detray::detail::is_invalid_value(tracer.m_track_material.phi)) {
225 tracer.m_track_material.eta = vector::eta(glob_dir);
226 tracer.m_track_material.phi = vector::phi(glob_dir);
227 }
228 }
229
231 template <concepts::detector detector_t>
232 DETRAY_HOST_DEVICE inline auto record_mat_step(
233 state &tracer, const typename detector_t::geometry_context &gctx,
236 const dvector3D<typename detector_t::algebra_type> &glob_dir) const {
237 // Fetch the material parameters and pathlength through the material
238 const auto mat_params = sf.template visit_material<get_material_record>(
239 loc_pos, cos_angle(gctx, sf, glob_dir, loc_pos));
240
241 const double seg{mat_params.path};
242 const double t{mat_params.thickness};
243 const double mx0{mat_params.mat_X0};
244 const double ml0{mat_params.mat_L0};
245
246 // Fill the material record
247 if (mx0 > 0.) {
248 tracer.m_track_material.sX0 += seg / mx0;
249 tracer.m_track_material.tX0 += t / mx0;
250 }
251 if (ml0 > 0.) {
252 tracer.m_track_material.sL0 += seg / ml0;
253 tracer.m_track_material.tL0 += t / ml0;
254 }
255 if (t > 0.) {
256 tracer.m_mat_steps.push_back({sf.identifier(), seg, t, mx0, ml0});
257 }
258 }
259};
260
262template <concepts::detector detector_t>
263inline auto record_material(
264 const typename detector_t::geometry_context /*gctx*/,
265 vecmem::memory_resource *host_mr, const detector_t &det,
266 const propagation::config &cfg,
268 using algebra_t = typename detector_t::algebra_type;
269 using scalar_t = dscalar<algebra_t>;
270
271 using stepper_t = line_stepper<algebra_t>;
272 using navigator_t = caching_navigator<detector_t>;
273
274 // Propagator with pathlimit aborter
275 using material_tracer_t = material_validator::material_tracer<vecmem::vector>;
276 using pathlimit_aborter_t = actor::pathlimit_aborter<scalar_t>;
277 using parameter_updater_t =
278 actor::parameter_updater<algebra_t,
279 actor::pointwise_material_interactor<algebra_t>,
280 material_tracer_t>;
281 using actor_chain_t = actor_chain<pathlimit_aborter_t, parameter_updater_t>;
282 using propagator_t = propagator<stepper_t, navigator_t, actor_chain_t>;
283
284 // Propagator
285 propagator_t prop{cfg};
286
287 // Build actor and propagator states
288 typename pathlimit_aborter_t::state pathlimit_aborter_state{
289 cfg.stepping.path_limit};
290 actor::parameter_updater_state<algebra_t> updater_state{cfg, track};
291 typename actor::pointwise_material_interactor<algebra_t>::state
292 interactor_state{};
293 typename material_tracer_t::state mat_tracer_state{*host_mr};
294
295 auto actor_states = detray::tie(pathlimit_aborter_state, updater_state,
296 interactor_state, mat_tracer_state);
297
298 typename propagator_t::state propagation{track, det, cfg.context};
299
300 // Run the propagation
301 bool success = prop.propagate(propagation, actor_states);
302
303 return std::make_tuple(success,
304 std::move(mat_tracer_state).release_track_material(),
305 std::move(mat_tracer_state).release_material_steps());
306}
307
320inline auto compare_traces(
321 const dvector<material_record> &reference, const track_material &ref_record,
322 const dvector<material_record> &mat_trace, const track_material &mat_record,
323 std::size_t trk_i = detail::invalid_value<std::size_t>(),
324 const double rel_tol = 0.01, const bool verbose = true) {
325 // Material traces contain records of different surfaces/material
326 bool is_bad_comp{reference.size() != mat_trace.size()};
327 // Overall recorded material is different (in case small errors accumulate)
328 bool is_diff_mat{false};
329
330 std::stringstream debug_msg{};
331 debug_msg << "Track No. " << trk_i << ":\n----------------" << std::endl;
332
333 if (is_bad_comp) {
334 debug_msg << "-> Different no. of surfaces: " << mat_trace.size()
335 << " (ref.: " << reference.size() << ")\n"
336 << std::endl;
337 } else {
338 for (std::size_t j = 0u; j < math::min(reference.size(), mat_trace.size());
339 ++j) {
340 if (reference[j].geo_id != mat_trace[j].geo_id) {
341 is_bad_comp = true;
342 debug_msg << "-> Surfaces don't match: " << mat_trace[j].geo_id
343 << " (ref.: " << reference[j].geo_id << ")" << std::endl;
344 continue;
345 }
346
347 // TODO: Use approx_equal from algebra-plugins
348 // Compare thickness of the surface material
349 if ((reference[j].thickness - mat_trace[j].thickness) /
350 reference[j].thickness >
351 rel_tol) {
352 is_bad_comp = true;
353 debug_msg << "-> On surface: " << reference[j].geo_id << ":"
354 << std::endl;
355 debug_msg << "-> thickness: " << mat_trace[j].thickness
356 << ", thickness ref.: " << reference[j].thickness
357 << std::endl;
358 }
359
360 // Compare radiation length of the surface material
361 if ((reference[j].mat_X0 - mat_trace[j].mat_X0) / reference[j].mat_X0 >
362 rel_tol) {
363 is_bad_comp = true;
364 debug_msg << "-> On surface: " << reference[j].geo_id << ":"
365 << std::endl;
366 debug_msg << "-> X0: " << mat_trace[j].mat_X0
367 << ", X0 ref.: " << reference[j].mat_X0 << std::endl;
368 }
369
370 // Compare interaction length of the surface material
371 if ((reference[j].mat_L0 - mat_trace[j].mat_L0) / reference[j].mat_L0 >
372 rel_tol) {
373 is_bad_comp = true;
374 debug_msg << "-> On surface: " << reference[j].geo_id << ":"
375 << std::endl;
376 debug_msg << "-> L0: " << mat_trace[j].mat_L0
377 << ", L0 ref.: " << reference[j].mat_L0 << std::endl;
378 }
379
380 // Compare path of the track through the surface material
381 if ((reference[j].path - mat_trace[j].path) / reference[j].path >
382 rel_tol) {
383 is_bad_comp = true;
384 debug_msg << "-> On surface: " << reference[j].geo_id << ":"
385 << std::endl;
386 debug_msg << "-> Mat. path: " << mat_trace[j].path / unit<double>::mm
387 << " mm, mat. path ref.: "
388 << reference[j].path / unit<double>::mm << " mm" << std::endl;
389 }
390 }
391 }
392
393 // Compare the total accumulated material along the track
394 const double rel_error{(ref_record.sX0 - mat_record.sX0) / ref_record.sX0};
395 const bool small_mat{ref_record.sX0 < rel_tol && mat_record.sX0 < rel_tol};
396
397 // If almost no material was collected, the relative error can be
398 // large, but also has little consequence for tracking
399 if (!(small_mat || (rel_error <= rel_tol))) {
400 // Already know that material cannot add up: Only flag the additional
401 // cases here
402 if (!is_bad_comp) {
403 is_diff_mat = true;
404 }
405 debug_msg << "\nTotal material discrepancy of " << 100. * rel_error << "%\n"
406 << std::endl;
407 }
408
409 if (verbose && (is_bad_comp || is_diff_mat)) {
410 DETRAY_INFO_HOST(debug_msg.str());
411 }
412
413 return std::make_tuple(is_bad_comp, is_diff_mat);
414}
415
418inline auto write_material(const std::string &mat_file_name,
419 const dvector<track_material> &mat_records) {
420 const auto file_path = std::filesystem::path{mat_file_name};
421 assert(file_path.extension() == ".csv");
422
423 // Make sure path to file exists
424 io::create_path(file_path.parent_path());
425
426 detray::io::file_handle outfile{
427 mat_file_name, std::ios::out | std::ios::binary | std::ios::trunc};
428 *outfile << "eta,phi,mat_sX0,mat_sL0,mat_tX0,mat_tL0" << std::endl;
429
430 for (const auto &rec : mat_records) {
431 *outfile << rec.eta << "," << rec.phi << "," << rec.sX0 << "," << rec.sL0
432 << "," << rec.tX0 << "," << rec.tL0 << std::endl;
433 }
434}
435
436} // namespace detray::material_validator
Unique identifier for geometry objects, based on the ACTS GeometryIdentifier.
Definition identifier.hpp:36
Definition concepts.hpp:74
Scalar concept: Elements of vectors/matrices (can be simd vectors).
Definition concepts.hpp:40
Material that can used for surfaces.
Definition concepts.hpp:111
auto create_path(const std::string &outdir)
Check if a given file path exists and generate it if not.
Definition create_path.hpp:79
get_scalar_t< A, T > dscalar
Scalar type for algebra A and value type T.
Definition algebra.hpp:64
vecmem::vector< value_t > dvector
Vector container backed by vecmem.
Definition containers.hpp:34
constexpr dscalar< typename detector_t::algebra_type > cos_angle(const typename detector_t::geometry_context &ctx, geometry::surface< detector_t > sf, const dvector3D< typename detector_t::algebra_type > &dir, const point_t &loc)
Helper to get the incidence angle of a direction vector on a surface.
Definition geometry_utils.hpp:29
get_vector3D_t< A, T > dvector3D
Three-dimensional vector type for algebra A and value type T.
Definition algebra.hpp:80
constexpr detray::tuple< Ts &... > tie(Ts &...args)
Create a tuple of references to the supplied objects.
Definition tuple.hpp:211
tracking_surface(const detector_t &, const descr_t &) -> tracking_surface< detector_t >
Deduce the detector type from a detector and surface descriptor pair.
get_point2D_t< A, T > dpoint2D
Two-dimensional point type for algebra A and value type T.
Definition algebra.hpp:68
free_parameters_vector< algebra_t > free_track_parameters
The free track parameters consist only of the parameter vector.
Definition free_track_parameters.hpp:249
Result of the param. transporter: bound track parameters at dest. sf.
Definition parameter_updater.hpp:210
constexpr const bound_track_parameters< algebra_t > & destination_params() const
Definition parameter_updater.hpp:236
Base class actor implementation.
Definition base_actor.hpp:20
Contains the material parameters and the pathlength.
Definition data_record.hpp:303
Functor to retrieve the material parameters for a given local position.
Definition material_validation_utils.hpp:59
auto operator()(const mat_group_t &mat_group, const index_t &index, const point2_t &loc, const scalar_t cos_inc_angle) const
Retrieve the material record at a local position.
Definition material_validation_utils.hpp:68
State used to collect material during propagation.
Definition material_validation_utils.hpp:114
state(vecmem::memory_resource &resource)
Construct the vector containers with a given resource.
Definition material_validation_utils.hpp:120
const auto & get_material_steps() const
Access to the recorded material steps along the track - const.
Definition material_validation_utils.hpp:142
auto && release_track_material() &&
Move the total recorded material out of the actor.
Definition material_validation_utils.hpp:137
state(vector_t< material_record_type > &&steps)
Construct from externally provided vector for the steps.
Definition material_validation_utils.hpp:126
const auto & get_track_material() const
Access to the total recorded material along the track - const.
Definition material_validation_utils.hpp:132
auto && release_material_steps() &&
Move the recorded material steps pout of the actor.
Definition material_validation_utils.hpp:147
Actor that collects all material encountered by a track during navigation.
Definition material_validation_utils.hpp:107
material_record material_record_type
Type storing one material step.
Definition material_validation_utils.hpp:111
track_material track_material_type
Type storing accumulated track material.
Definition material_validation_utils.hpp:109
void operator()(state &tracer, const propagator_state_t &prop_state) const
Run in a propagation chain without covariance transport.
Definition material_validation_utils.hpp:187
void operator()(state &tracer, const propagator_state_t &prop_state, const detray::actor::parameter_transporter_result< algebra_t > &res) const
Run as observer to the parameter transporter (covariance transport).
Definition material_validation_utils.hpp:162
Record the total material budget per track.
Definition material_validation_utils.hpp:40
double sX0
Accumulated radiation length per pathlength through the material.
Definition material_validation_utils.hpp:48
double tL0
Accumulated interaction length per thickness.
Definition material_validation_utils.hpp:54
double sL0
Accumulated interaction length per pathlength through the material.
Definition material_validation_utils.hpp:52
double eta
Eta of the track.
Definition material_validation_utils.hpp:45
double tX0
Accumulated radiation length per thickness.
Definition material_validation_utils.hpp:50
double phi
Phi and eta values of the track for which the material was recorded.
Definition material_validation_utils.hpp:43
static constexpr scalar_t mm
Native length unit, the millimetre.
Definition units.hpp:27