diff --git a/Core/include/Acts/Fitter/KalmanFitter.hpp b/Core/include/Acts/Fitter/KalmanFitter.hpp index ec82ff4b9957c077f147883d448c0e49939ab8de..ec3a9cebd941a0740cff2ab8f562bef083fd07d2 100644 --- a/Core/include/Acts/Fitter/KalmanFitter.hpp +++ b/Core/include/Acts/Fitter/KalmanFitter.hpp @@ -40,12 +40,20 @@ namespace Acts { /// @brief Options struct how the Fitter is called /// -/// It contains the context of the fitter call, the optional +/// It contains the context of the fitter call, the outlier finder, the optional /// surface where to express the fit result and configurations for material /// effects and smoothing options /// +/// /// @note the context objects must be provided +template <typename outlier_finder_t = VoidOutlierFinder> struct KalmanFitterOptions { + // Broadcast the outlier finder type + using OutlierFinderType = outlier_finder_t; + + // Broadcast the outlier finder config type + using OutlierFinderConfigType = typename OutlierFinderType::Config; + /// Deleted default constructor KalmanFitterOptions() = delete; @@ -54,6 +62,7 @@ struct KalmanFitterOptions { /// @param gctx The goemetry context for this fit /// @param mctx The magnetic context for this fit /// @param cctx The calibration context for this fit + /// @param olCfg The config for the outlier finder /// @param rSurface The reference surface for the fit to be expressed at /// @param mScattering Whether to include multiple scattering /// @param eLoss Whether to include energy loss @@ -61,12 +70,14 @@ struct KalmanFitterOptions { KalmanFitterOptions(std::reference_wrapper<const GeometryContext> gctx, std::reference_wrapper<const MagneticFieldContext> mctx, std::reference_wrapper<const CalibrationContext> cctx, + const OutlierFinderConfigType& ofCfg, const Surface* rSurface = nullptr, bool mScattering = true, bool eLoss = true, bool bwdFiltering = false) : geoContext(gctx), magFieldContext(mctx), calibrationContext(cctx), + outlierFinderConfig(ofCfg), referenceSurface(rSurface), multipleScattering(mScattering), energyLoss(eLoss), @@ -79,6 +90,9 @@ struct KalmanFitterOptions { /// context object for the calibration std::reference_wrapper<const CalibrationContext> calibrationContext; + /// The config for the outlier finder + OutlierFinderConfigType outlierFinderConfig; + /// The reference Surface const Surface* referenceSurface = nullptr; @@ -136,6 +150,7 @@ struct KalmanFitterResult { /// @tparam propagator_t Type of the propagation class /// @tparam updater_t Type of the kalman updater class /// @tparam smoother_t Type of the kalman smoother class +/// @tparam outlier_finder_t Type of the outlier finder class /// @tparam calibrator_t Type of the calibrator class /// @tparam input_converter_t Type of the input converter class /// @tparam output_converter_t Type of the output converter class @@ -499,7 +514,6 @@ class KalmanFitter { // Get and set the type flags auto& typeFlags = trackStateProxy.typeFlags(); typeFlags.set(TrackStateFlag::MaterialFlag); - typeFlags.set(TrackStateFlag::MeasurementFlag); typeFlags.set(TrackStateFlag::ParameterFlag); // If the update is successful, set covariance and @@ -509,6 +523,8 @@ class KalmanFitter { return updateRes.error(); } else { if (not m_outlierFinder(trackStateProxy)) { + // Set the measurement type flag + typeFlags.set(TrackStateFlag::MeasurementFlag); // Update the stepping state with filtered parameters ACTS_VERBOSE( "Filtering step successful, updated parameters are : \n" @@ -888,6 +904,7 @@ class KalmanFitter { /// @tparam source_link_t Source link type identifying uncalibrated input /// measurements. /// @tparam start_parameters_t Type of the initial parameters + /// @tparam kalman_fitter_options_t Type of the kalman fitter options /// @tparam parameters_t Type of parameters used for local parameters /// /// @param sourcelinks The fittable uncalibrated measurements @@ -899,15 +916,23 @@ class KalmanFitter { /// /// @return the output as an output track template <typename source_link_t, typename start_parameters_t, + typename kalman_fitter_options_t, typename parameters_t = BoundParameters, typename result_t = Result<KalmanFitterResult<source_link_t>>> auto fit(const std::vector<source_link_t>& sourcelinks, const start_parameters_t& sParameters, - const KalmanFitterOptions& kfOptions) const + const kalman_fitter_options_t& kfOptions) const -> std::enable_if_t<!isDirectNavigator, result_t> { static_assert(SourceLinkConcept<source_link_t>, "Source link does not fulfill SourceLinkConcept"); + static_assert( + std::is_same< + outlier_finder_t, + typename kalman_fitter_options_t::OutlierFinderType>::value, + "Inconsistent type of outlier finder between kalman fitter and " + "kalman fitter options"); + // To be able to find measurements later, we put them into a map // We need to copy input SourceLinks anyways, so the map can own them. ACTS_VERBOSE("Preparing " << sourcelinks.size() << " input measurements"); @@ -937,6 +962,9 @@ class KalmanFitter { kalmanActor.energyLoss = kfOptions.energyLoss; kalmanActor.backwardFiltering = kfOptions.backwardFiltering; + // Set config for outlier finder + kalmanActor.m_outlierFinder.m_config = kfOptions.outlierFinderConfig; + // also set logger on updater and smoother kalmanActor.m_updater.m_logger = m_logger; kalmanActor.m_smoother.m_logger = m_logger; @@ -974,6 +1002,7 @@ class KalmanFitter { /// @tparam source_link_t Source link type identifying uncalibrated input /// measurements. /// @tparam start_parameters_t Type of the initial parameters + /// @tparam kalman_fitter_options_t Type of the kalman fitter options /// @tparam parameters_t Type of parameters used for local parameters /// /// @param sourcelinks The fittable uncalibrated measurements @@ -986,16 +1015,24 @@ class KalmanFitter { /// /// @return the output as an output track template <typename source_link_t, typename start_parameters_t, + typename kalman_fitter_options_t, typename parameters_t = BoundParameters, typename result_t = Result<KalmanFitterResult<source_link_t>>> auto fit(const std::vector<source_link_t>& sourcelinks, const start_parameters_t& sParameters, - const KalmanFitterOptions& kfOptions, + const kalman_fitter_options_t& kfOptions, const std::vector<const Surface*>& sSequence) const -> std::enable_if_t<isDirectNavigator, result_t> { static_assert(SourceLinkConcept<source_link_t>, "Source link does not fulfill SourceLinkConcept"); + static_assert( + std::is_same< + outlier_finder_t, + typename kalman_fitter_options_t::OutlierFinderType>::value, + "Inconsistent type of outlier finder between kalman fitter and " + "kalman fitter options"); + // To be able to find measurements later, we put them into a map // We need to copy input SourceLinks anyways, so the map can own them. ACTS_VERBOSE("Preparing " << sourcelinks.size() << " input measurements"); @@ -1025,6 +1062,9 @@ class KalmanFitter { kalmanActor.energyLoss = kfOptions.energyLoss; kalmanActor.backwardFiltering = kfOptions.backwardFiltering; + // Set config for outlier finder + kalmanActor.m_outlierFinder.m_config = kfOptions.outlierFinderConfig; + // also set logger on updater and smoother kalmanActor.m_updater.m_logger = m_logger; kalmanActor.m_smoother.m_logger = m_logger; diff --git a/Core/include/Acts/Fitter/detail/VoidKalmanComponents.hpp b/Core/include/Acts/Fitter/detail/VoidKalmanComponents.hpp index 3098b39195795e7cb82bd2de0f56f10ba2399158..c89b661cbad736cb0af2ca72f705429246d8460d 100644 --- a/Core/include/Acts/Fitter/detail/VoidKalmanComponents.hpp +++ b/Core/include/Acts/Fitter/detail/VoidKalmanComponents.hpp @@ -112,6 +112,12 @@ struct VoidKalmanSmoother { /// @brief void outlier finder struct VoidOutlierFinder { + /// @brief nested config struct + /// + struct Config { + // Allowed maximum chi2 + double maxChi2 = std::numeric_limits<double>::max(); + }; /// @brief Public call mimicking an outlier finder /// /// @tparam track_state_t Type of the track state @@ -121,8 +127,14 @@ struct VoidOutlierFinder { /// @return Whether it's outlier or not template <typename track_state_t> bool operator()(const track_state_t& trackState) const { + if (trackState.chi2 > m_config.maxChi2) { + return true; + } return false; } + + /// The config + Config m_config; }; } // namespace Acts diff --git a/Tests/UnitTests/Core/Fitter/KalmanFitterTests.cpp b/Tests/UnitTests/Core/Fitter/KalmanFitterTests.cpp index d70200945c2201a3c38144fd8dfe8c9c4ba37967..7572f5566cd7241576400d2ec3f31707c3d1236f 100644 --- a/Tests/UnitTests/Core/Fitter/KalmanFitterTests.cpp +++ b/Tests/UnitTests/Core/Fitter/KalmanFitterTests.cpp @@ -221,11 +221,15 @@ struct MaterialScattering { }; struct MinimalOutlierFinder { - /// The measurement significance criteria - double measurementSignificance = 0.05; + /// @brief nested config struct + /// + struct Config { + /// The measurement significance criteria + double measurementSignificance = 0; - /// The chi2 round-off error - double chi2Tolerance = 10e-5; + /// The chi2 round-off error + double chi2Tolerance = 10e-5; + }; /// @brief Public call mimicking an outlier finder /// @@ -237,7 +241,7 @@ struct MinimalOutlierFinder { template <typename track_state_t> bool operator()(const track_state_t& trackState) const { double chi2 = trackState.chi2(); - if (std::abs(chi2) < chi2Tolerance) { + if (std::abs(chi2) < m_config.chi2Tolerance) { return false; } // The measurement dimension @@ -247,8 +251,11 @@ struct MinimalOutlierFinder { // The p-Value double pValue = 1 - boost::math::cdf(chiDist, chi2); // If pValue is NOT significant enough => outlier - return pValue > measurementSignificance ? false : true; + return pValue > m_config.measurementSignificance ? false : true; } + + /// The config + Config m_config; }; /// @@ -366,10 +373,15 @@ BOOST_AUTO_TEST_CASE(kalman_fitter_zero_field) { using KalmanFitter = KalmanFitter<RecoPropagator, Updater, Smoother, MinimalOutlierFinder>; + using OutlierFinderConfig = typename MinimalOutlierFinder::Config; + OutlierFinderConfig ofConfig; + ofConfig.measurementSignificance = 0.05; + KalmanFitter kFitter(rPropagator, getDefaultLogger("KalmanFilter", Logging::VERBOSE)); - KalmanFitterOptions kfOptions(tgContext, mfContext, calContext, rSurface); + KalmanFitterOptions<MinimalOutlierFinder> kfOptions( + tgContext, mfContext, calContext, ofConfig, rSurface); // Fit the track auto fitRes = kFitter.fit(sourcelinks, rStart, kfOptions);