Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:52

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2019-2024 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 http://mozilla.org/MPL/2.0/.
0008 
0009 namespace Acts {
0010 
0011 template <typename traj_t>
0012 Result<
0013     std::pair<typename std::vector<typename traj_t::TrackStateProxy>::iterator,
0014               typename std::vector<typename traj_t::TrackStateProxy>::iterator>>
0015 MeasurementSelector::select(
0016     std::vector<typename traj_t::TrackStateProxy>& candidates, bool& isOutlier,
0017     const Logger& logger) const {
0018   using Result = Result<std::pair<
0019       typename std::vector<typename traj_t::TrackStateProxy>::iterator,
0020       typename std::vector<typename traj_t::TrackStateProxy>::iterator>>;
0021 
0022   ACTS_VERBOSE("Invoked MeasurementSelector");
0023 
0024   // Return error if no measurement
0025   if (candidates.empty()) {
0026     return CombinatorialKalmanFilterError::MeasurementSelectionFailed;
0027   }
0028 
0029   // Get geoID of this surface
0030   auto geoID = candidates.front().referenceSurface().geometryId();
0031   // Find the appropriate cuts
0032   auto cuts = m_config.find(geoID);
0033   if (cuts == m_config.end()) {
0034     // for now we consider missing cuts an unrecoverable error
0035     // TODO consider other options e.g. do not add measurements at all (not
0036     // even as outliers)
0037     return CombinatorialKalmanFilterError::MeasurementSelectionFailed;
0038   }
0039 
0040   assert(!cuts->chi2CutOff.empty());
0041   const std::vector<double>& chi2CutOff = cuts->chi2CutOff;
0042   const double maxChi2Cut =
0043       std::min(*std::max_element(chi2CutOff.begin(), chi2CutOff.end()),
0044                getCut<traj_t>(candidates.front(), cuts, chi2CutOff, logger));
0045   const std::size_t numMeasurementsCut = getCut<traj_t>(
0046       candidates.front(), cuts, cuts->numMeasurementsCutOff, logger);
0047 
0048   if (numMeasurementsCut == 0ul) {
0049     return CombinatorialKalmanFilterError::MeasurementSelectionFailed;
0050   }
0051 
0052   double minChi2 = std::numeric_limits<double>::max();
0053   std::size_t minIndex = std::numeric_limits<std::size_t>::max();
0054 
0055   isOutlier = false;
0056 
0057   // Loop over all measurements to select the compatible measurements
0058   // Sort track states which do not satisfy the chi2 cut to the end.
0059   // When done trackStateIterEnd will point to the first element that
0060   // does not satisfy the chi2 cut.
0061   std::size_t passedCandidates = 0ul;
0062   for (std::size_t i(0ul); i < candidates.size(); ++i) {
0063     auto& trackState = candidates[i];
0064 
0065     // This abuses an incorrectly sized vector / matrix to access the
0066     // data pointer! This works (don't use the matrix as is!), but be
0067     // careful!
0068     double chi2 = calculateChi2(
0069         trackState
0070             .template calibrated<MultiTrajectoryTraits::MeasurementSizeMax>()
0071             .data(),
0072         trackState
0073             .template calibratedCovariance<
0074                 MultiTrajectoryTraits::MeasurementSizeMax>()
0075             .data(),
0076         trackState.predicted(), trackState.predictedCovariance(),
0077         trackState.projector(), trackState.calibratedSize());
0078     trackState.chi2() = chi2;
0079 
0080     if (chi2 < minChi2) {
0081       minChi2 = chi2;
0082       minIndex = i;
0083     }
0084 
0085     // only consider track states which pass the chi2 cut
0086     if (chi2 >= maxChi2Cut) {
0087       continue;
0088     }
0089 
0090     if (passedCandidates != i) {
0091       std::swap(candidates[passedCandidates], candidates[i]);
0092       if (minIndex == i) {
0093         minIndex = passedCandidates;
0094       }
0095     }
0096     ++passedCandidates;
0097   }
0098 
0099   // If there are no measurements below the chi2 cut off, return the
0100   // measurement with the best chi2 and tag it as an outlier
0101   if (passedCandidates == 0ul) {
0102     ACTS_VERBOSE("No measurement candidate. Return an outlier measurement chi2="
0103                  << minChi2);
0104     isOutlier = true;
0105   }
0106 
0107   if (passedCandidates <= 1ul || numMeasurementsCut == 1ul) {
0108     // return single item range, no sorting necessary
0109     ACTS_VERBOSE("Returning only 1 element");
0110     return Result::success(std::make_pair(candidates.begin() + minIndex,
0111                                           candidates.begin() + minIndex + 1));
0112   }
0113 
0114   std::sort(
0115       candidates.begin(), candidates.begin() + passedCandidates,
0116       [](const auto& tsa, const auto& tsb) { return tsa.chi2() < tsb.chi2(); });
0117 
0118   if (passedCandidates <= numMeasurementsCut) {
0119     ACTS_VERBOSE("Number of selected measurements: "
0120                  << passedCandidates << ", max: " << numMeasurementsCut);
0121     return Result::success(std::make_pair(
0122         candidates.begin(), candidates.begin() + passedCandidates));
0123   }
0124 
0125   ACTS_VERBOSE("Number of selected measurements: "
0126                << numMeasurementsCut << ", max: " << numMeasurementsCut);
0127 
0128   return Result::success(std::make_pair(
0129       candidates.begin(), candidates.begin() + numMeasurementsCut));
0130 }
0131 
0132 template <typename traj_t, typename cut_value_t>
0133 cut_value_t MeasurementSelector::getCut(
0134     const typename traj_t::TrackStateProxy& trackState,
0135     const Acts::MeasurementSelector::Config::Iterator selector,
0136     const std::vector<cut_value_t>& cuts, const Logger& logger) {
0137   const auto& etaBins = selector->etaBins;
0138   if (etaBins.empty()) {
0139     return cuts[0];  // shortcut if no etaBins
0140   }
0141   const auto eta = std::atanh(std::cos(trackState.predicted()[eBoundTheta]));
0142   const auto abseta = std::abs(eta);
0143   std::size_t bin = 0;
0144   for (auto etaBin : etaBins) {
0145     if (etaBin >= abseta) {
0146       break;
0147     }
0148     bin++;
0149   }
0150   if (bin >= cuts.size()) {
0151     bin = cuts.size() - 1;
0152   }
0153   ACTS_VERBOSE("Get cut for eta=" << eta << ": " << cuts[bin]);
0154   return cuts[bin];
0155 }
0156 
0157 }  // namespace Acts