Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-24 07:35:22

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/EventData/TransformationHelpers.hpp"
0013 #include "Acts/Surfaces/Surface.hpp"
0014 #include "Acts/Surfaces/SurfacePlacementBase.hpp"
0015 #include "Acts/Utilities/Result.hpp"
0016 #include "ActsFatras/Digitization/DigitizationError.hpp"
0017 #include "ActsFatras/EventData/Hit.hpp"
0018 
0019 #include <array>
0020 #include <functional>
0021 #include <utility>
0022 
0023 namespace ActsFatras {
0024 
0025 /// Smearing function definition for single track parameters.
0026 ///
0027 /// The function takes the unsmeared parameter and returns the smeared value and
0028 /// a standard deviation.
0029 ///
0030 /// @tparam generator_t The type of the random generator.
0031 template <typename generator_t>
0032 using SingleParameterSmearFunction =
0033     std::function<Acts::Result<std::pair<double, double>>(double,
0034                                                           generator_t&)>;
0035 
0036 /// Uncorrelated smearing algorithm for fast digitisation of bound parameters.
0037 ///
0038 /// @tparam generator_t Random number generator type
0039 /// @tparam kSize Number of smeared parameters
0040 ///
0041 /// The smearer takes a single simulated `Hit` and generates a smeared parameter
0042 /// vector and associated covariance matrix.
0043 template <typename generator_t, std::size_t kSize>
0044 struct BoundParametersSmearer {
0045   /// Type alias for parameter vector of dimension kSize
0046   using ParametersVector = Acts::Vector<kSize>;
0047   /// Type alias for covariance matrix of dimension kSize x kSize
0048   using CovarianceMatrix = Acts::SquareMatrix<kSize>;
0049   /// Type alias for smearing result containing parameters and covariance
0050   using Result = Acts::Result<std::pair<ParametersVector, CovarianceMatrix>>;
0051 
0052   /// Parameter indices that will be used to create the smeared measurements.
0053   std::array<Acts::BoundIndices, kSize> indices{};
0054   /// Array of smearing functions for each measurement parameter
0055   std::array<SingleParameterSmearFunction<generator_t>, kSize> smearFunctions{};
0056   /// Array of flags to force positive values after smearing
0057   std::array<bool, kSize> forcePositive = {};
0058   /// Maximum number of retries for generating positive values when forced
0059   std::size_t maxRetries = 0;
0060 
0061   /// Get the number of bound parameters that will be smeared
0062   /// @return Number of bound parameters (kSize)
0063   static constexpr std::size_t size() { return kSize; }
0064 
0065   /// Generate smeared measured for configured parameters.
0066   ///
0067   /// @param rng Random number generator
0068   /// @param hit Simulated hit
0069   /// @param surface Local surface on which the hit is smeared
0070   /// @param geoCtx Geometry context
0071   /// @retval Smeared parameters vector and associated covariance on success
0072   /// @retval Error code for failure
0073   Result operator()(generator_t& rng, const Hit& hit,
0074                     const Acts::Surface& surface,
0075                     const Acts::GeometryContext& geoCtx) const {
0076     // We use the thickness of the detector element as tolerance, because Geant4
0077     // treats the Surfaces as volumes and thus it is not ensured, that each hit
0078     // lies exactly on the Acts::Surface
0079     const auto tolerance = surface.isSensitive() ? surface.thickness()
0080                                                  : Acts::s_onSurfaceTolerance;
0081 
0082     // construct full bound parameters. they are probably not all needed, but it
0083     // is easier to just create them all and then select the requested ones.
0084     Acts::Result<Acts::BoundVector> boundParamsRes =
0085         Acts::transformFreeToBoundParameters(hit.position(), hit.time(),
0086                                              hit.direction(), 0, surface,
0087                                              geoCtx, tolerance);
0088 
0089     if (!boundParamsRes.ok()) {
0090       return boundParamsRes.error();
0091     }
0092 
0093     const auto& boundParams = *boundParamsRes;
0094     Acts::BoundVector smearedBoundParams = boundParams;
0095 
0096     for (std::size_t k = 0; k < maxRetries + 1; ++k) {
0097       ParametersVector par = ParametersVector::Zero();
0098       CovarianceMatrix cov = CovarianceMatrix::Zero();
0099       for (std::size_t i = 0; i < kSize; ++i) {
0100         auto res = smearFunctions[i](boundParams[indices[i]], rng);
0101         if (!res.ok()) {
0102           return Result::failure(res.error());
0103         }
0104         auto [value, stddev] = res.value();
0105         par[i] = value;
0106         if (forcePositive[i]) {
0107           par[i] = std::abs(value);
0108         }
0109         smearedBoundParams[indices[i]] = par[i];
0110         cov(i, i) = stddev * stddev;
0111       }
0112 
0113       if (!surface.insideBounds(smearedBoundParams.head<2>())) {
0114         continue;
0115       }
0116 
0117       return Result::success(std::make_pair(par, cov));
0118     }
0119 
0120     return Result::failure(DigitizationError::MaximumRetriesExceeded);
0121   }
0122 };
0123 
0124 /// Uncorrelated smearing algorithm for fast digitisation of free parameters.
0125 ///
0126 /// @tparam generator_t Random number generator type
0127 /// @tparam kSize Number of smeared parameters
0128 ///
0129 /// The smearer takes a single simulated `Hit` and generates a smeared parameter
0130 /// vector and associated covariance matrix.
0131 ///
0132 /// @note Uncorrelated smearing of the direction using each components
0133 ///   individually is not recommended
0134 template <typename generator_t, std::size_t kSize>
0135 struct FreeParametersSmearer {
0136   /// Type alias for parameter vector of dimension kSize
0137   using ParametersVector = Acts::Vector<kSize>;
0138   /// Type alias for covariance matrix of dimension kSize x kSize
0139   using CovarianceMatrix = Acts::SquareMatrix<kSize>;
0140   /// Type alias for smearing result containing parameters and covariance
0141   using Result = Acts::Result<std::pair<ParametersVector, CovarianceMatrix>>;
0142 
0143   /// Parameter indices that will be used to create the smeared measurements.
0144   std::array<Acts::FreeIndices, kSize> indices{};
0145   /// Array of smearing functions for each free parameter
0146   std::array<SingleParameterSmearFunction<generator_t>, kSize> smearFunctions;
0147 
0148   /// Get the number of free parameters that will be smeared
0149   /// @return Number of free parameters (kSize)
0150   static constexpr std::size_t size() { return kSize; }
0151 
0152   /// Generate smeared measured for configured parameters.
0153   ///
0154   /// @param rng Random number generator
0155   /// @param hit Simulated hit
0156   /// @return Smeared free parameter set wrapped in a Result<...> object
0157   /// @retval Smeared parameters vector and associated covariance on success
0158   /// @retval Error code for failure
0159   Result operator()(generator_t& rng, const Hit& hit) const {
0160     // construct full free parameters. they are probably not all needed, but it
0161     // is easier to just create them all and then select the requested ones.
0162     Acts::FreeVector freeParams;
0163     freeParams.segment<3>(Acts::eFreePos0) = hit.position();
0164     freeParams[Acts::eFreeTime] = hit.time();
0165     freeParams.segment<3>(Acts::eFreeDir0) = hit.direction();
0166     freeParams[Acts::eFreeQOverP] = 0;
0167 
0168     ParametersVector par = ParametersVector::Zero();
0169     CovarianceMatrix cov = CovarianceMatrix::Zero();
0170     for (std::size_t i = 0; i < kSize; ++i) {
0171       auto res = smearFunctions[i](freeParams[indices[i]], rng);
0172       if (!res.ok()) {
0173         return Result::failure(res.error());
0174       }
0175       auto [value, stddev] = res.value();
0176       par[i] = value;
0177       cov(i, i) = stddev * stddev;
0178     }
0179 
0180     return Result::success(std::make_pair(par, cov));
0181   }
0182 };
0183 
0184 }  // namespace ActsFatras