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::AtlasBetheHeitlerApprox::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::AtlasBetheHeitlerApprox::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 auto bha = std::make_shared<Acts::AtlasBetheHeitlerApprox>(
84 readBHParFile(bhLow), readBHParFile(bhHigh),
85 /*lowTransform=*/true, /*highTransform=*/true,
86 /*lowLimit=*/0.1, /*highLimit=*/0.2, /*clampToRange=*/true,
87 /*noChangeLimit=*/0.0001, /*singleGaussianLimit=*/0.002);
88
89
91 // Direct Fitter
92 Acts::DirectNavigator directNavigator( logger().cloneWithSuffix("DirectNavigator") );
93 Acts::MultiEigenStepperLoop<> stepperDirect(field);
94 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::DirectNavigator> directPropagator(std::move(stepperDirect),
95 std::move(directNavigator),
96 logger().cloneWithSuffix("DirectPropagator"));
97 m_directFitter = std::make_unique<DirectFitter>(std::move(directPropagator), bha,
98 logger().cloneWithSuffix("DirectGaussianSumFitter"));
99
100 } else {
101 Acts::Navigator navigator(Acts::Navigator::Config{ m_trackingGeometrySvc->trackingGeometry() },
102 logger().cloneWithSuffix("Navigator") );
103 Acts::Propagator<Acts::MultiEigenStepperLoop<>, Acts::Navigator> propagator(std::move(stepper),
104 std::move(navigator),
105 logger().cloneWithSuffix("Prop"));
106 m_fitter = std::make_unique<Fitter>(std::move(propagator), bha,
107 logger().cloneWithSuffix("GaussianSumFitter"));
108 }
109
110 m_outlierFinder.StateChiSquaredPerNumberDoFCut = m_option_outlierChi2Cut;
111
112 FitterExtension_t gsfExtensionsTemplate;
113 gsfExtensionsTemplate.outlierFinder.connect<&ActsTrk::detail::FitterHelperFunctions::ATLASOutlierFinder::operator()<ActsTrk::MutableTrackStateBackend>>(&m_outlierFinder);
115 gsfExtensionsTemplate.mixtureReducer.connect<&Acts::reduceMixtureWithKLDistance>();
116
118 {
120
122 configureMe = gsfExtensionsTemplate;
123 //coverity has hard time matching arguments to these passed parameters
124 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
126 configureMe.surfaceAccessor.connect<&detail::TrkMeasSurfaceAccessor::operator()>(&m_trkSurfAcc);
127 }
129 {
132
134 configureMe = gsfExtensionsTemplate;
135 //coverity[RW.NO_MATCHING_FUNCTION:FALSE]
137 configureMe.surfaceAccessor.connect<&detail::TrkPrepRawDataSurfaceAcc::operator()>(&m_prdSurfAcc);
138 }
140 {
143
144 m_refitCalibrator = std::make_unique<detail::RefittingCalibrator>(m_geometryConvTool.get(), m_ROTcreator.get());
147
149 configureMe = gsfExtensionsTemplate;
150 configureMe.surfaceAccessor.connect<&detail::xAODUncalibMeasSurfAcc::operator()>(&m_unalibMeasSurfAcc);
151 configureMe.calibrator.connect<&detail::RefittingCalibrator::calibrate>(m_refitCalibrator.get());
152 }
153
154 if(m_option_componentMergeMethod == "Mean" ){
155 m_componentMergeMethod = Acts::ComponentMergeMethod::eMean;
156 }else if(m_option_componentMergeMethod == "MaxWeight"){
157 m_componentMergeMethod = Acts::ComponentMergeMethod::eMaxWeight;
158 }else{
159 throw std::runtime_error("Unknown option for ComponentMergeMethod: " + m_option_componentMergeMethod.value());
160 }
161
162 ATH_MSG_INFO("ACTS GSF direct nav " << m_useDirectNavigation.value());
163 ATH_MSG_INFO("ACTS GSF max cmps " << m_maxComponents.value());
164 ATH_MSG_INFO("ACTS GSF merge meth " << m_option_componentMergeMethod.value());
165 ATH_MSG_INFO("ACTS GSF weight ctf " << m_weightCutOff.value());
166 ATH_MSG_INFO("ACTS GSF outlier chi2 " << m_option_outlierChi2Cut.value());
167
168 return StatusCode::SUCCESS;
169}
170
172GaussianSumFitterTool::configureFit(const Acts::GeometryContext& tgContext,
173 const Acts::MagneticFieldContext& mfContext,
174 const Acts::CalibrationContext& calContext,
175 const Acts::PerigeeSurface& surface,
176 detail::SourceLinkType slType) const
177{
178 //slType can be 3
179 const auto& gsfExtensions = m_gsfExtensions.at(Acts::toUnderlying(slType));
180
181 Acts::PropagatorPlainOptions propagationOption(tgContext, mfContext);
182 propagationOption.maxSteps = m_option_maxPropagationStep;
183
184 FitterOptions_t gsfOptions(tgContext, mfContext, calContext);
185 gsfOptions.extensions=gsfExtensions;
186 gsfOptions.propagatorPlainOptions=std::move(propagationOption);
187 gsfOptions.referenceSurface = &surface;
188
189 // Set abortOnError to false, else the refitting crashes if no forward propagation is done. Here, we just skip the event and continue.
190 gsfOptions.abortOnError = false;
191 gsfOptions.maxComponents = m_maxComponents;
192 gsfOptions.weightCutoff = m_weightCutOff;
193 gsfOptions.componentMergeMethod = m_componentMergeMethod;
194
195 return gsfOptions;
196}
197
198// Acts track refit
199std::unique_ptr< ActsTrk::MutableTrackContainer >
201 const Acts::BoundTrackParameters& /*initialParams*/,
202 const Acts::GeometryContext& /*tgContext*/,
203 const Acts::MagneticFieldContext& /*mfContext*/,
204 const Acts::CalibrationContext& /*calContext*/,
205 const Acts::Surface& /*targetSurface*/) const
206{
207 ATH_MSG_VERBOSE("ACTS seed refit is not implemented in GaussianSumFitterTool");
208 return nullptr;
209}
210
211std::unique_ptr< ActsTrk::MutableTrackContainer >
212GaussianSumFitterTool::fit(const std::vector< const xAOD::UncalibratedMeasurement*> & /*clusterList*/,
213 const Acts::BoundTrackParameters& /*initialParams*/,
214 const Acts::GeometryContext& /*tgContext*/,
215 const Acts::MagneticFieldContext& /*mfContext*/,
216 const Acts::CalibrationContext& /*calContext*/,
217 const Acts::Surface* /*targetSurface*/) const
218{
219 ATH_MSG_VERBOSE("ACTS uncalib slink refit is not implemented in GaussianSumFitterTool");
220 return nullptr;
221}
222
223
225 const EventContext& ctx,
226 const ActsTrk::TrackContainer::ConstTrackProxy& track,
227 ActsTrk::MutableTrackContainer& trackContainer,
228 const Acts::PerigeeSurface& pSurface) const {
229 ATH_MSG_VERBOSE("GaussianSumFitterTool::fit(TrackProxy) called");
230
231 const Acts::BoundTrackParameters initialParams = track.createParametersAtReference();
232 std::vector<Acts::SourceLink> sourceLinks;
233
234 for (auto ts : track.trackStates()){
235 if (!ts.hasCalibrated()) {
236 continue;
237 }
238 if (ts.typeFlags().hasMeasurement()) {
239 sourceLinks.push_back(ts.getUncalibratedSourceLink());
240 }
241 }
242
243 if (sourceLinks.size() < 2) {
244 ATH_MSG_DEBUG("called to refit 0 or 1 sourceLink with too little information, reject fit");
245 return StatusCode::SUCCESS;
246 }
247
248 const Acts::GeometryContext tgContext{m_ctxProvider.getGeometryContext(ctx)};
249 const Acts::MagneticFieldContext mfContext{m_ctxProvider.getMagneticFieldContext(ctx)};
250 const Acts::CalibrationContext calContext{m_ctxProvider.getCalibrationContext(ctx)};
251
252 std::unique_ptr< ActsTrk::MutableTrackContainer > refittedTracks =
253 fit(sourceLinks, initialParams, tgContext, mfContext, calContext, &pSurface);
254
255 if (!refittedTracks) {
256 ATH_MSG_WARNING("Refit failed");
257 return StatusCode::SUCCESS;
258 }
259
261 trackContainer.ensureDynamicColumns(*refittedTracks);
262
263 for (auto trkProxy : *refittedTracks) {
265
266 auto destProxy = trackContainer.getTrack(trackContainer.addTrack());
267 destProxy.copyFrom(trkProxy);
268 }
269
270 return StatusCode::SUCCESS;
271}
272
274std::unique_ptr<MutableTrackContainer>
275GaussianSumFitterTool::fit(const std::vector<Acts::SourceLink>& sourceLinks,
276 const Acts::BoundTrackParameters& initialParams,
277 const Acts::GeometryContext& tgContext,
278 const Acts::MagneticFieldContext& mfContext,
279 const Acts::CalibrationContext& calContext,
280 const Acts::Surface* /*targetSurface*/ ) const {
281 if (sourceLinks.empty()) {
282 ATH_MSG_DEBUG("No measurements given. Nothing to do");
283 return nullptr;
284 }
285 // Construct a perigee surface as the target surface
286 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3::Zero());
287
289
290 FitterOptions_t gsfOptions = configureFit(tgContext, mfContext, calContext, *pSurface, slType);
291
292 ActsTrk::MutableTrackBackend trackContainerBackEnd;
293 ActsTrk::MutableTrackStateBackend multiTrajBackEnd;
294 auto tracks = std::make_unique<MutableTrackContainer>(std::move(trackContainerBackEnd),
295 std::move(multiTrajBackEnd));
296
297 bool fitSuccess = false;
299
300 std::vector<const Acts::Surface*> surfaces;
301 surfaces.reserve(sourceLinks.size());
302 switch (slType) {
304 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
305 surfaces.push_back(m_trkSurfAcc(sl));
306 });
307 break;
308 }
310 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
311 surfaces.push_back(m_prdSurfAcc(sl));
312 });
313 break;
314 }
316 std::ranges::for_each(sourceLinks, [this, &surfaces](const Acts::SourceLink& sl) {
317 surfaces.push_back(m_unalibMeasSurfAcc(sl));
318 });
319 break;
320 }
321 default:
322 ATH_MSG_ERROR("Unsupported source link type for KalmanFitterTool::fit");
323 return nullptr;
324 }
325 fitSuccess = m_directFitter->fit(sourceLinks.begin(), sourceLinks.end(),
326 initialParams, gsfOptions, surfaces, *tracks).ok();
327
328 } else {
329 fitSuccess = m_fitter->fit(sourceLinks.begin(), sourceLinks.end(),
330 initialParams, gsfOptions, *tracks).ok();
331 }
332
333 if (!fitSuccess) {
334 ATH_MSG_VERBOSE("Fitter has failed");
335 return nullptr;
336 }
337
339 for (auto trkProxy : *tracks) {
341 }
342 return tracks;
343}
344
346const Acts::Logger&
348{
349 return *m_logger;
350}
351
352}
#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)
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