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]").
31Acts::AtlasBetheHeitlerApprox::Data readBHParFile(const std::string& path) {
32 std::ifstream fin(path);
33 if (!fin) {
34 throw std::invalid_argument("Could not open BH par file: " + path);
35 }
36 std::size_t n_cmps = 0, degree = 0;
37 fin >> n_cmps >> degree;
38 if (!fin || n_cmps == 0 || degree == 0) {
39 throw std::invalid_argument("Bad header in BH par file: " + path);
40 }
41 Acts::AtlasBetheHeitlerApprox::Data data(n_cmps);
42 for (auto& cmp : data) {
43 cmp.weightCoeffs.resize(degree + 1);
44 cmp.meanCoeffs.resize(degree + 1);
45 cmp.varCoeffs.resize(degree + 1);
46 for (double& c : cmp.weightCoeffs) { fin >> c; }
47 for (double& c : cmp.meanCoeffs) { fin >> c; }
48 for (double& c : cmp.varCoeffs) { fin >> c; }
49 }
50 if (!fin) {
51 throw std::invalid_argument("Truncated data in BH par file: " + path);
52 }
53 return data;
54}
55} // anonymous namespace
56
57namespace ActsTrk {
58
60 ATH_MSG_DEBUG(name() << "::" << __FUNCTION__);
62 ATH_CHECK(m_ctxProvider.initialize());
63 ATH_CHECK(m_geometryConvTool.retrieve());
64 ATH_CHECK(m_ROTcreator.retrieve(EnableTool{!m_ROTcreator.empty()}));
65 m_logger = makeActsAthenaLogger(this, "Acts Gaussian Sum Refit");
66
67 auto field = std::make_shared<ATLASMagneticFieldWrapper>();
68
69 Acts::MultiEigenStepperLoop<> stepper(field);
70
71 // Use the GeantSim Bethe-Heitler parameterisation, which clamps at X/X0=0.20
72 // matching the behaviour in Trk::ElectronCombinedMaterialEffects. The files
73 // store coefficients in logit(z) space; transform=true applies sigmoid/exp to
74 // recover physical z in (0,1).
75 const std::string bhLow = PathResolver::find_file("GeantSim_LT01_cdf_nC6_O5.par", "DATAPATH");
76 const std::string bhHigh = PathResolver::find_file("GeantSim_GT01_cdf_nC6_O5.par", "DATAPATH");
77 ATH_MSG_INFO("ACTS GSF: loading GeantSim BH parameterisation (" << bhLow << ", " << bhHigh << ")");
78 auto bha = std::make_shared<Acts::AtlasBetheHeitlerApprox>(
79 readBHParFile(bhLow), readBHParFile(bhHigh),
80 /*lowTransform=*/true, /*highTransform=*/true,
81 /*lowLimit=*/0.1, /*highLimit=*/0.2, /*clampToRange=*/true,
82 /*noChangeLimit=*/0.0001, /*singleGaussianLimit=*/0.002);
83
84
86 // Direct Fitter
87 Acts::DirectNavigator directNavigator( logger().cloneWithSuffix("DirectNavigator") );
88 Acts::MultiEigenStepperLoop<> stepperDirect(field);
89 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::DirectNavigator> directPropagator(std::move(stepperDirect),
90 std::move(directNavigator),
91 logger().cloneWithSuffix("DirectPropagator"));
92 m_directFitter = std::make_unique<DirectFitter>(std::move(directPropagator), bha,
93 logger().cloneWithSuffix("DirectGaussianSumFitter"));
94
95 } else {
96 Acts::Navigator navigator(Acts::Navigator::Config{ m_trackingGeometrySvc->trackingGeometry() },
97 logger().cloneWithSuffix("Navigator") );
98 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::Navigator> propagator(std::move(stepper),
99 std::move(navigator),
100 logger().cloneWithSuffix("Prop"));
101 m_fitter = std::make_unique<Fitter>(std::move(propagator), bha,
102 logger().cloneWithSuffix("GaussianSumFitter"));
103 }
104
105 m_outlierFinder.StateChiSquaredPerNumberDoFCut = m_option_outlierChi2Cut;
106
107 FitterExtension_t gsfExtensionsTemplate;
108 gsfExtensionsTemplate.outlierFinder.connect<&ActsTrk::detail::FitterHelperFunctions::ATLASOutlierFinder::operator()<ActsTrk::MutableTrackStateBackend>>(&m_outlierFinder);
110 gsfExtensionsTemplate.mixtureReducer.connect<&Acts::reduceMixtureWithKLDistance>();
111
113 {
115
117 configureMe = gsfExtensionsTemplate;
118 //coverity has hard time matching arguments to these passed parameters
119 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
121 configureMe.surfaceAccessor.connect<&detail::TrkMeasSurfaceAccessor::operator()>(&m_trkSurfAcc);
122 }
124 {
127
129 configureMe = gsfExtensionsTemplate;
130 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
132 configureMe.surfaceAccessor.connect<&detail::TrkPrepRawDataSurfaceAcc::operator()>(&m_prdSurfAcc);
133 }
135 {
138
139 m_refitCalibrator = std::make_unique<detail::RefittingCalibrator>(m_geometryConvTool.get(), m_ROTcreator.get());
142
144 configureMe = gsfExtensionsTemplate;
145 configureMe.surfaceAccessor.connect<&detail::xAODUncalibMeasSurfAcc::operator()>(&m_unalibMeasSurfAcc);
146 configureMe.calibrator.connect<&detail::RefittingCalibrator::calibrate>(m_refitCalibrator.get());
147 }
148
149 if(m_option_componentMergeMethod == "Mean" ){
150 m_componentMergeMethod = Acts::ComponentMergeMethod::eMean;
151 }else if(m_option_componentMergeMethod == "MaxWeight"){
152 m_componentMergeMethod = Acts::ComponentMergeMethod::eMaxWeight;
153 }else{
154 throw std::runtime_error("Unknown option for ComponentMergeMethod: " + m_option_componentMergeMethod.value());
155 }
156
157 ATH_MSG_INFO("ACTS GSF direct nav " << m_useDirectNavigation.value());
158 ATH_MSG_INFO("ACTS GSF max cmps " << m_maxComponents.value());
159 ATH_MSG_INFO("ACTS GSF merge meth " << m_option_componentMergeMethod.value());
160 ATH_MSG_INFO("ACTS GSF weight ctf " << m_weightCutOff.value());
161 ATH_MSG_INFO("ACTS GSF outlier chi2 " << m_option_outlierChi2Cut.value());
162
163 return StatusCode::SUCCESS;
164}
165
167GaussianSumFitterTool::configureFit(const Acts::GeometryContext& tgContext,
168 const Acts::MagneticFieldContext& mfContext,
169 const Acts::CalibrationContext& calContext,
170 const Acts::PerigeeSurface& surface,
171 detail::SourceLinkType slType) const
172{
173 //slType can be 3
174 const auto& gsfExtensions = m_gsfExtensions.at(Acts::toUnderlying(slType));
175
176 Acts::PropagatorPlainOptions propagationOption(tgContext, mfContext);
177 propagationOption.maxSteps = m_option_maxPropagationStep;
178
179 FitterOptions_t gsfOptions(tgContext, mfContext, calContext);
180 gsfOptions.extensions=gsfExtensions;
181 gsfOptions.propagatorPlainOptions=std::move(propagationOption);
182 gsfOptions.referenceSurface = &surface;
183
184 // Set abortOnError to false, else the refitting crashes if no forward propagation is done. Here, we just skip the event and continue.
185 gsfOptions.abortOnError = false;
186 gsfOptions.maxComponents = m_maxComponents;
187 gsfOptions.weightCutoff = m_weightCutOff;
188 gsfOptions.componentMergeMethod = m_componentMergeMethod;
189
190 return gsfOptions;
191}
192
193// Acts track refit
194std::unique_ptr< ActsTrk::MutableTrackContainer >
196 const Acts::BoundTrackParameters& /*initialParams*/,
197 const Acts::GeometryContext& /*tgContext*/,
198 const Acts::MagneticFieldContext& /*mfContext*/,
199 const Acts::CalibrationContext& /*calContext*/,
200 const Acts::Surface& /*targetSurface*/) const
201{
202 ATH_MSG_VERBOSE("ACTS seed refit is not implemented in GaussianSumFitterTool");
203 return nullptr;
204}
205
206std::unique_ptr< ActsTrk::MutableTrackContainer >
207GaussianSumFitterTool::fit(const std::vector< const xAOD::UncalibratedMeasurement*> & /*clusterList*/,
208 const Acts::BoundTrackParameters& /*initialParams*/,
209 const Acts::GeometryContext& /*tgContext*/,
210 const Acts::MagneticFieldContext& /*mfContext*/,
211 const Acts::CalibrationContext& /*calContext*/,
212 const Acts::Surface* /*targetSurface*/) const
213{
214 ATH_MSG_VERBOSE("ACTS uncalib slink refit is not implemented in GaussianSumFitterTool");
215 return nullptr;
216}
217
218
220 const EventContext& ctx,
221 const ActsTrk::TrackContainer::ConstTrackProxy& track,
222 ActsTrk::MutableTrackContainer& trackContainer,
223 const Acts::PerigeeSurface& pSurface) const {
224 ATH_MSG_VERBOSE("GaussianSumFitterTool::fit(TrackProxy) called");
225
226 const Acts::BoundTrackParameters initialParams = track.createParametersAtReference();
227 std::vector<Acts::SourceLink> sourceLinks;
228
229 for (auto ts : track.trackStates()){
230 if (!ts.hasCalibrated()) {
231 continue;
232 }
233 if (ts.typeFlags().hasMeasurement()) {
234 sourceLinks.push_back(ts.getUncalibratedSourceLink());
235 }
236 }
237
238 if (sourceLinks.size() < 2) {
239 ATH_MSG_DEBUG("called to refit 0 or 1 sourceLink with too little information, reject fit");
240 return StatusCode::SUCCESS;
241 }
242
243 const Acts::GeometryContext tgContext{m_ctxProvider.getGeometryContext(ctx)};
244 const Acts::MagneticFieldContext mfContext{m_ctxProvider.getMagneticFieldContext(ctx)};
245 const Acts::CalibrationContext calContext{m_ctxProvider.getCalibrationContext(ctx)};
246
247 std::unique_ptr< ActsTrk::MutableTrackContainer > refittedTracks =
248 fit(sourceLinks, initialParams, tgContext, mfContext, calContext, &pSurface);
249
250 if (!refittedTracks) {
251 ATH_MSG_WARNING("Refit failed");
252 return StatusCode::SUCCESS;
253 }
254
256 trackContainer.ensureDynamicColumns(*refittedTracks);
257
258 for (auto trkProxy : *refittedTracks) {
260
261 auto destProxy = trackContainer.getTrack(trackContainer.addTrack());
262 destProxy.copyFrom(trkProxy);
263 }
264
265 return StatusCode::SUCCESS;
266}
267
269std::unique_ptr<MutableTrackContainer>
270GaussianSumFitterTool::fit(const std::vector<Acts::SourceLink>& sourceLinks,
271 const Acts::BoundTrackParameters& initialParams,
272 const Acts::GeometryContext& tgContext,
273 const Acts::MagneticFieldContext& mfContext,
274 const Acts::CalibrationContext& calContext,
275 const Acts::Surface* /*targetSurface*/ ) const {
276 if (sourceLinks.empty()) {
277 ATH_MSG_DEBUG("No measurements given. Nothing to do");
278 return nullptr;
279 }
280 // Construct a perigee surface as the target surface
281 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3::Zero());
282
284
285 FitterOptions_t gsfOptions = configureFit(tgContext, mfContext, calContext, *pSurface, slType);
286
287 ActsTrk::MutableTrackBackend trackContainerBackEnd;
288 ActsTrk::MutableTrackStateBackend multiTrajBackEnd;
289 auto tracks = std::make_unique<MutableTrackContainer>(std::move(trackContainerBackEnd),
290 std::move(multiTrajBackEnd));
291
292 bool fitSuccess = false;
294
295 std::vector<const Acts::Surface*> surfaces;
296 surfaces.reserve(sourceLinks.size());
297 switch (slType) {
299 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
300 surfaces.push_back(m_trkSurfAcc(sl));
301 });
302 break;
303 }
305 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
306 surfaces.push_back(m_prdSurfAcc(sl));
307 });
308 break;
309 }
311 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
312 surfaces.push_back(m_unalibMeasSurfAcc(sl));
313 });
314 break;
315 }
316 default:
317 ATH_MSG_ERROR("Unsupported source link type for KalmanFitterTool::fit");
318 return nullptr;
319 }
320 fitSuccess = m_directFitter->fit(sourceLinks.begin(), sourceLinks.end(),
321 initialParams, gsfOptions, surfaces, *tracks).ok();
322
323 } else {
324 fitSuccess = m_fitter->fit(sourceLinks.begin(), sourceLinks.end(),
325 initialParams, gsfOptions, *tracks).ok();
326 }
327
328 if (!fitSuccess) {
329 ATH_MSG_VERBOSE("Fitter has failed");
330 return nullptr;
331 }
332
334 for (auto trkProxy : *tracks) {
336 }
337 return tracks;
338}
339
341const Acts::Logger&
343{
344 return *m_logger;
345}
346
347}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::unique_ptr< const Acts::Logger > makeActsAthenaLogger(IMessageSvc *svc, const std::string &name, int level, std::optional< std::string > parent_name)
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