ATLAS Offline Software
Loading...
Searching...
No Matches
GaussianSumFitterTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7// ACTS
8#include "Acts/MagneticField/MagneticFieldContext.hpp"
9#include "Acts/Surfaces/PerigeeSurface.hpp"
10#include "Acts/Surfaces/Surface.hpp"
11#include "Acts/TrackFitting/GsfMixtureReduction.hpp"
12#include "Acts/EventData/BoundTrackParameters.hpp"
15
16// PACKAGE
19#include "ActsInterop/Logger.h"
20#include "Acts/Propagator/DirectNavigator.hpp"
22// STL
23#include <vector>
24#include <type_traits>
25#include <fstream>
26
28
29namespace {
30 // Read an ATLAS Bethe-Heitler .par file (format: "n_cmps degree\n[data]").
31 //see, for example:
32 //athena/Tracking/TrkFitter/TrkGaussianSumFilter/Data/BetheHeitler_cdfmom_nC6_O5.par
33 //try to indicate a sane maximum value for degree
34 constexpr std::size_t MAXDEGREE = 30;
35 //
36 Acts::PolynomialBetheHeitlerApprox::Data readBHParFile(const std::string& path) {
37 std::ifstream fin(path);
38 if (!fin) {
39 throw std::invalid_argument("Could not open BH par file: " + path);
40 }
41 std::size_t n_cmps = 0, degree = 0;
42 fin >> n_cmps >> degree;
43 if (!fin || n_cmps == 0 || degree == 0 || degree > MAXDEGREE) {
44 throw std::invalid_argument("Bad header in BH par file: " + path);
45 }
46 Acts::PolynomialBetheHeitlerApprox::Data data(n_cmps);
47 for (auto& cmp : data) {
48 cmp.weightCoeffs.resize(degree + 1);
49 cmp.meanCoeffs.resize(degree + 1);
50 cmp.varCoeffs.resize(degree + 1);
51 for (double& c : cmp.weightCoeffs) { fin >> c; }
52 for (double& c : cmp.meanCoeffs) { fin >> c; }
53 for (double& c : cmp.varCoeffs) { fin >> c; }
54 }
55 if (!fin) {
56 throw std::invalid_argument("Truncated data in BH par file: " + path);
57 }
58 return data;
59 }
60} // anonymous namespace
61
62namespace ActsTrk {
63
65 ATH_MSG_DEBUG(name() << "::" << __FUNCTION__);
67 ATH_CHECK(m_ctxProvider.initialize());
68 ATH_CHECK(m_geometryConvTool.retrieve());
69 ATH_CHECK(m_ROTcreator.retrieve(EnableTool{!m_ROTcreator.empty()}));
70 m_logger = makeActsAthenaLogger(this, "Acts Gaussian Sum Refit");
71
72 auto field = std::make_shared<ATLASMagneticFieldWrapper>();
73
74 Acts::MultiEigenStepperLoop<> stepper(field);
75
76 // Use the GeantSim Bethe-Heitler parameterisation, which clamps at X/X0=0.20
77 // matching the behaviour in Trk::ElectronCombinedMaterialEffects. The files
78 // store coefficients in logit(z) space; transform=true applies sigmoid/exp to
79 // recover physical z in (0,1).
80 const std::string bhLow = PathResolver::find_file("GeantSim_LT01_cdf_nC6_O5.par", "DATAPATH");
81 const std::string bhHigh = PathResolver::find_file("GeantSim_GT01_cdf_nC6_O5.par", "DATAPATH");
82 ATH_MSG_INFO("ACTS GSF: loading GeantSim BH parameterisation (" << bhLow << ", " << bhHigh << ")");
83 std::vector<Acts::PolynomialBetheHeitlerApprox::RangeData> bhRanges;
84 bhRanges.emplace_back(0.0, 0.1, readBHParFile(bhLow), /*transform=*/true);
85 bhRanges.emplace_back(0.1, 0.2, readBHParFile(bhHigh), /*transform=*/true);
86 auto bha = std::make_shared<Acts::PolynomialBetheHeitlerApprox>(
87 std::move(bhRanges), /*clampToRange=*/true,
88 /*noChangeLimit=*/0.0001, /*singleGaussianLimit=*/0.002);
89
90
92 // Direct Fitter
93 Acts::DirectNavigator directNavigator( logger().cloneWithSuffix("DirectNavigator") );
94 Acts::MultiEigenStepperLoop<> stepperDirect(field);
95 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::DirectNavigator> directPropagator(std::move(stepperDirect),
96 std::move(directNavigator),
97 logger().cloneWithSuffix("DirectPropagator"));
98 m_directFitter = std::make_unique<DirectFitter>(std::move(directPropagator), bha,
99 logger().cloneWithSuffix("DirectGaussianSumFitter"));
100
101 } else {
102 Acts::Navigator navigator(Acts::Navigator::Config{ m_trackingGeometrySvc->trackingGeometry() },
103 logger().cloneWithSuffix("Navigator") );
104 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::Navigator> propagator(std::move(stepper),
105 std::move(navigator),
106 logger().cloneWithSuffix("Prop"));
107 m_fitter = std::make_unique<Fitter>(std::move(propagator), bha,
108 logger().cloneWithSuffix("GaussianSumFitter"));
109 }
110
111 m_outlierFinder.StateChiSquaredPerNumberDoFCut = m_option_outlierChi2Cut;
112
113 FitterExtension_t gsfExtensionsTemplate;
114 gsfExtensionsTemplate.outlierFinder.connect<&ActsTrk::detail::FitterHelperFunctions::ATLASOutlierFinder::operator()<ActsTrk::MutableTrackStateBackend>>(&m_outlierFinder);
116 gsfExtensionsTemplate.mixtureReducer.connect<&Acts::reduceMixtureWithKLDistance>();
117
119 {
121
123 configureMe = gsfExtensionsTemplate;
124 //coverity has hard time matching arguments to these passed parameters
125 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
127 configureMe.surfaceAccessor.connect<&detail::TrkMeasSurfaceAccessor::operator()>(&m_trkSurfAcc);
128 }
130 {
133
135 configureMe = gsfExtensionsTemplate;
136 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
138 configureMe.surfaceAccessor.connect<&detail::TrkPrepRawDataSurfaceAcc::operator()>(&m_prdSurfAcc);
139 }
141 {
144
145 m_refitCalibrator = std::make_unique<detail::RefittingCalibrator>(m_geometryConvTool.get(), m_ROTcreator.get());
148
150 configureMe = gsfExtensionsTemplate;
151 configureMe.surfaceAccessor.connect<&detail::xAODUncalibMeasSurfAcc::operator()>(&m_unalibMeasSurfAcc);
152 configureMe.calibrator.connect<&detail::RefittingCalibrator::calibrate>(m_refitCalibrator.get());
153 }
154
155 if(m_option_componentMergeMethod == "Mean" ){
156 m_componentMergeMethod = Acts::ComponentMergeMethod::eMean;
157 }else if(m_option_componentMergeMethod == "MaxWeight"){
158 m_componentMergeMethod = Acts::ComponentMergeMethod::eMaxWeight;
159 }else{
160 throw std::runtime_error("Unknown option for ComponentMergeMethod: " + m_option_componentMergeMethod.value());
161 }
162
163 ATH_MSG_INFO("ACTS GSF direct nav " << m_useDirectNavigation.value());
164 ATH_MSG_INFO("ACTS GSF max cmps " << m_maxComponents.value());
165 ATH_MSG_INFO("ACTS GSF merge meth " << m_option_componentMergeMethod.value());
166 ATH_MSG_INFO("ACTS GSF weight ctf " << m_weightCutOff.value());
167 ATH_MSG_INFO("ACTS GSF outlier chi2 " << m_option_outlierChi2Cut.value());
168
169 return StatusCode::SUCCESS;
170}
171
173GaussianSumFitterTool::configureFit(const Acts::GeometryContext& tgContext,
174 const Acts::MagneticFieldContext& mfContext,
175 const Acts::CalibrationContext& calContext,
176 const Acts::PerigeeSurface& surface,
177 detail::SourceLinkType slType) const
178{
179 //slType can be 3
180 const auto& gsfExtensions = m_gsfExtensions.at(Acts::toUnderlying(slType));
181
182 Acts::PropagatorPlainOptions propagationOption(tgContext, mfContext);
183 propagationOption.maxSteps = m_option_maxPropagationStep;
184
185 FitterOptions_t gsfOptions(tgContext, mfContext, calContext);
186 gsfOptions.extensions=gsfExtensions;
187 gsfOptions.propagatorPlainOptions=std::move(propagationOption);
188 gsfOptions.referenceSurface = &surface;
189
190 // Set abortOnError to false, else the refitting crashes if no forward propagation is done. Here, we just skip the event and continue.
191 gsfOptions.abortOnError = false;
192 gsfOptions.maxComponents = m_maxComponents;
193 gsfOptions.weightCutoff = m_weightCutOff;
194 gsfOptions.componentMergeMethod = m_componentMergeMethod;
195
196 return gsfOptions;
197}
198
199// Acts track refit
200std::unique_ptr< ActsTrk::MutableTrackContainer >
202 const Acts::BoundTrackParameters& /*initialParams*/,
203 const Acts::GeometryContext& /*tgContext*/,
204 const Acts::MagneticFieldContext& /*mfContext*/,
205 const Acts::CalibrationContext& /*calContext*/,
206 const Acts::Surface& /*targetSurface*/) const
207{
208 ATH_MSG_VERBOSE("ACTS seed refit is not implemented in GaussianSumFitterTool");
209 return nullptr;
210}
211
212std::unique_ptr< ActsTrk::MutableTrackContainer >
213GaussianSumFitterTool::fit(const std::vector< const xAOD::UncalibratedMeasurement*> & /*clusterList*/,
214 const Acts::BoundTrackParameters& /*initialParams*/,
215 const Acts::GeometryContext& /*tgContext*/,
216 const Acts::MagneticFieldContext& /*mfContext*/,
217 const Acts::CalibrationContext& /*calContext*/,
218 const Acts::Surface* /*targetSurface*/) const
219{
220 ATH_MSG_VERBOSE("ACTS uncalib slink refit is not implemented in GaussianSumFitterTool");
221 return nullptr;
222}
223
224
226 const EventContext& ctx,
227 const ActsTrk::TrackContainer::ConstTrackProxy& track,
228 ActsTrk::MutableTrackContainer& trackContainer,
229 const Acts::PerigeeSurface& pSurface) const {
230 ATH_MSG_VERBOSE("GaussianSumFitterTool::fit(TrackProxy) called");
231
232 const Acts::BoundTrackParameters initialParams = track.createParametersAtReference();
233 std::vector<Acts::SourceLink> sourceLinks;
234
235 for (auto ts : track.trackStates()){
236 if (!ts.hasCalibrated()) {
237 continue;
238 }
239 if (ts.typeFlags().hasMeasurement()) {
240 sourceLinks.push_back(ts.getUncalibratedSourceLink());
241 }
242 }
243
244 if (sourceLinks.size() < 2) {
245 ATH_MSG_DEBUG("called to refit 0 or 1 sourceLink with too little information, reject fit");
246 return StatusCode::SUCCESS;
247 }
248
249 const Acts::GeometryContext tgContext{m_ctxProvider.getGeometryContext(ctx)};
250 const Acts::MagneticFieldContext mfContext{m_ctxProvider.getMagneticFieldContext(ctx)};
251 const Acts::CalibrationContext calContext{m_ctxProvider.getCalibrationContext(ctx)};
252
253 std::unique_ptr< ActsTrk::MutableTrackContainer > refittedTracks =
254 fit(sourceLinks, initialParams, tgContext, mfContext, calContext, &pSurface);
255
256 if (!refittedTracks) {
257 ATH_MSG_WARNING("Refit failed");
258 return StatusCode::SUCCESS;
259 }
260
262 trackContainer.ensureDynamicColumns(*refittedTracks);
263
264 for (auto trkProxy : *refittedTracks) {
266
267 auto destProxy = trackContainer.getTrack(trackContainer.addTrack());
268 destProxy.copyFrom(trkProxy);
269 }
270
271 return StatusCode::SUCCESS;
272}
273
275std::unique_ptr<MutableTrackContainer>
276GaussianSumFitterTool::fit(const std::vector<Acts::SourceLink>& sourceLinks,
277 const Acts::BoundTrackParameters& initialParams,
278 const Acts::GeometryContext& tgContext,
279 const Acts::MagneticFieldContext& mfContext,
280 const Acts::CalibrationContext& calContext,
281 const Acts::Surface* /*targetSurface*/ ) const {
282 if (sourceLinks.empty()) {
283 ATH_MSG_DEBUG("No measurements given. Nothing to do");
284 return nullptr;
285 }
286 // Construct a perigee surface as the target surface
287 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3::Zero());
288
290
291 FitterOptions_t gsfOptions = configureFit(tgContext, mfContext, calContext, *pSurface, slType);
292
293 ActsTrk::MutableTrackBackend trackContainerBackEnd;
294 ActsTrk::MutableTrackStateBackend multiTrajBackEnd;
295 auto tracks = std::make_unique<MutableTrackContainer>(std::move(trackContainerBackEnd),
296 std::move(multiTrajBackEnd));
297
298 bool fitSuccess = false;
300
301 std::vector<const Acts::Surface*> surfaces;
302 surfaces.reserve(sourceLinks.size());
303 switch (slType) {
305 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
306 surfaces.push_back(m_trkSurfAcc(sl));
307 });
308 break;
309 }
311 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
312 surfaces.push_back(m_prdSurfAcc(sl));
313 });
314 break;
315 }
317 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
318 surfaces.push_back(m_unalibMeasSurfAcc(sl));
319 });
320 break;
321 }
322 default:
323 ATH_MSG_ERROR("Unsupported source link type for KalmanFitterTool::fit");
324 return nullptr;
325 }
326 fitSuccess = m_directFitter->fit(sourceLinks.begin(), sourceLinks.end(),
327 initialParams, gsfOptions, surfaces, *tracks).ok();
328
329 } else {
330 fitSuccess = m_fitter->fit(sourceLinks.begin(), sourceLinks.end(),
331 initialParams, gsfOptions, *tracks).ok();
332 }
333
334 if (!fitSuccess) {
335 ATH_MSG_VERBOSE("Fitter has failed");
336 return nullptr;
337 }
338
340 for (auto trkProxy : *tracks) {
342 }
343 return tracks;
344}
345
347const Acts::Logger&
349{
350 return *m_logger;
351}
352
353}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(x,...)
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
Definition Logger.cxx:64
const Acts::Logger & logger() const
Private access to the logger.
Gaudi::Property< std::string > m_option_componentMergeMethod
std::unique_ptr< detail::RefittingCalibrator > m_refitCalibrator
ToolHandle< Trk::IRIO_OnTrackCreator > m_ROTcreator
Gaudi::Property< double > m_weightCutOff
Gaudi::Property< int > m_option_maxPropagationStep
virtual StatusCode initialize() override
virtual std::unique_ptr< ActsTrk::MutableTrackContainer > fit(const ActsTrk::Seed &seed, const Acts::BoundTrackParameters &initialParams, const Acts::GeometryContext &tgContext, const Acts::MagneticFieldContext &mfContext, const Acts::CalibrationContext &calContext, const Acts::Surface &targetSurface) const override
Acts seed fit.
PublicToolHandle< IGeometryRealmConvTool > m_geometryConvTool
detail::TrkMeasurementCalibrator m_trkCalibrator
Calibrator for the Trk::MeasurementBase track states (legacy EDM).
Acts::ComponentMergeMethod m_componentMergeMethod
detail::TrkPrepRawDataSurfaceAcc m_prdSurfAcc
Surface accessor for the Trk::PrepRawData track states (legacy EDM).
ServiceHandle< ActsTrk::ITrackingGeometrySvc > m_trackingGeometrySvc
Gaudi::Property< double > m_option_outlierChi2Cut
FitterOptions_t configureFit(const Acts::GeometryContext &tgContext, const Acts::MagneticFieldContext &mfContext, const Acts::CalibrationContext &calContext, const Acts::PerigeeSurface &surface, detail::SourceLinkType slType) const
Gaudi::Property< bool > m_useDirectNavigation
Acts::GsfExtensions< ActsTrk::MutableTrackStateBackend > FitterExtension_t
std::unique_ptr< Fitter > m_fitter
std::array< FitterExtension_t, s_nExtensions > m_gsfExtensions
std::unique_ptr< const Acts::Logger > m_logger
logging instance
detail::TrkPrepRawDataCalibrator m_prdCalibrator
Calibrator for the Trk::PrepRawData track states (legacy EDM).
ContextUtility m_ctxProvider
Utility to fetch the geometry, magnetic field and calibration context in the event.
std::unique_ptr< DirectFitter > m_directFitter
detail::xAODUncalibMeasSurfAcc m_unalibMeasSurfAcc
Accessor to fetch surfaces from the xAOD::UncalibratedMeasurements (Phase-II EDM).
Acts::GsfOptions< ActsTrk::MutableTrackStateBackend > FitterOptions_t
ActsTrk::detail::FitterHelperFunctions::ATLASOutlierFinder m_outlierFinder
detail::TrkMeasSurfaceAccessor m_trkSurfAcc
Accessor to fetch surfaces from the Trk::MeasurementBase track states (legacy EDM).
static SourceLinkType getType(const Acts::SourceLink &sl)
Returns the enumeration corresponding to the object type cached within the Acts::SourceLink.
void calibrate(const Acts::GeometryContext &geoctx, const Acts::CalibrationContext &cctx, const Acts::SourceLink &link, TrackStateProxy state) const
static OnTrackCalibrator NoCalibration(const ActsTrk::ITrackingGeometrySvc *trackGeoSvc)
void calibrate(const Acts::GeometryContext &gctx, const Acts::CalibrationContext &cctx, const Acts::SourceLink &sourceLink, MutableTrackStateProxy trackState) const
Helper class to access the Acts::Surface for a given Acts::SourceLink which is poiniting to a Trk::Me...
void calibrate(const Acts::GeometryContext &gctx, const Acts::CalibrationContext &cctx, const Acts::SourceLink &sl, proxy_t trackState) const
Calibrator delegate implementation to calibrate the ActsTrk fit from Trk::MeasurementBase objects.
Class to calibrate the Acts track states with uncalibrated Trk::PrepRaw data objects.
void calibrate(const Acts::GeometryContext &gctx, const Acts::CalibrationContext &cctx, const Acts::SourceLink &sl, proxy_t trackState) const
Calibrator delegate implementation to calibrate the ActsTrk fit from Trk::PrepRawData objects.
Helper class to access the Acts::surface associated with a Trk::PrepRawData measurement.
Helper class to access the Acts::surface associated with an Uncalibrated xAOD measurement.
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
int ts
Definition globals.cxx:24
Acts::Result< void > gainMatrixUpdate(const Acts::GeometryContext &gctx, typename trajectory_t::TrackStateProxy trackState, const Acts::Logger &logger)
SourceLinkType
Enumeration to distinguish between the ATLAS EDM -> Acts::SourceLink variants.
@ xAODUnCalibMeas
UnCalibrated Trk::PrepRawData objects.
@ TrkPrepRawData
Calibrated Trk::MeasurementBase objects.
The AlignStoreProviderAlg loads the rigid alignment corrections and pipes them through the readout ge...
Acts::VectorMultiTrajectory MutableTrackStateBackend
Acts::TrackContainer< MutableTrackBackend, MutableTrackStateBackend, Acts::detail::ValueHolder > MutableTrackContainer
Acts::VectorTrackContainer MutableTrackBackend
cmp(x, y)
Definition EI_Lib.py:6
@ GaussianSumFilter
Tracks from Gaussian Sum Filter.
static void addFitterTypeProperty(track_container_t &tracksContainer)
add fitter column to the track container
static void setFitterType(trackproxy_t &trackProxy, xAOD::TrackFitter fitterType)
set fitter type of a track