4#ifndef MUONTRACKFINDINGTOOLS_FITTER_H
5#define MUONTRACKFINDINGTOOLS_FITTER_H
7#include "Acts/Definitions/Algebra.hpp"
8#include "Acts/Definitions/Common.hpp"
9#include "Acts/EventData/MeasurementHelpers.hpp"
10#include "Acts/EventData/MultiTrajectory.hpp"
11#include "Acts/EventData/SourceLink.hpp"
12#include "Acts/EventData/TrackProxyConcept.hpp"
13#include "Acts/EventData/Types.hpp"
14#include "Acts/EventData/VectorMultiTrajectory.hpp"
15#include "Acts/EventData/VectorTrackContainer.hpp"
16#include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
17#include "Acts/Geometry/GeometryContext.hpp"
18#include "Acts/Geometry/TrackingVolume.hpp"
19#include "Acts/MagneticField/MagneticFieldContext.hpp"
20#include "Acts/Material/Interactions.hpp"
21#include "Acts/Propagator/DirectNavigator.hpp"
22#include "Acts/Propagator/PropagatorOptions.hpp"
23#include "Acts/Propagator/StandardAborters.hpp"
24#include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
25#include "Acts/TrackFitting/GlobalChiSquareFitterError.hpp"
26#include "Acts/TrackFitting/detail/VoidFitterComponents.hpp"
27#include "Acts/Utilities/CalibrationContext.hpp"
28#include "Acts/Utilities/Delegate.hpp"
29#include "Acts/Utilities/Logger.hpp"
30#include "Acts/Utilities/Result.hpp"
31#include "Acts/Utilities/TrackHelpers.hpp"
37#include <unordered_map>
52 TrackStatePropMask::Jacobian |
53 TrackStatePropMask::Calibrated;
88 :
m_isValid{std::min(energy, sigma) > Acts::s_epsilon},
94 if (&other !=
this && other.isValid()) {
112 const CalibrationContext& calibContext,
113 const Vector3& pos,
const Vector3& dir,
114 const Surface& matSurface);
139 if (&other !=
this && other.isValid()) {
172 constexpr std::size_t
nDim()
const {
174 (
m_eloss.isValid() ? 1ul : 0ul);
198 const std::size_t firstParamIdx,
199 const Logger&
logger)
const;
202 const std::size_t firstParamIdx);
227template <
typename traj_t>
233 typename MultiTrajectory<traj_t>::ConstTrackStateProxy;
239 Delegate<void(
const GeometryContext&,
const CalibrationContext&,
254 const GeometryContext& geoContext,
const CalibrationContext& calibContext,
255 const Vector3& pos,
const Vector3& dir,
const Surface& matSurf)>;
278 calibrator.template connect<&Acts::detail::voidFitterCalibrator<traj_t>>();
279 outlierFinder.template connect<&Acts::detail::voidOutlierFinder<traj_t>>();
289template <
typename traj_t>
305 const MagneticFieldContext& mctx,
306 std::reference_wrapper<const CalibrationContext> cctx,
308 const PropagatorPlainOptions& pOptions)
362template <
typename traj_t>
369 std::unordered_map<GeometryIdentifier, Gx2fMaterialProperties>
materialMap{};
473 std::size_t ndfSystem = 0;
524 const std::vector<BoundMatrix>& jacobianFromStart,
525 const std::vector<std::size_t>& materialIndices,
526 const std::vector<double>& qOverPderiv,
527 const Eigen::MatrixXd& covarianceMeasurement,
const BoundVector& predicted,
528 const Eigen::VectorXd& measurement,
const Eigen::MatrixXd& projector,
544template <std::
size_t kMeasDim,
typename track_state_t>
546 const std::vector<BoundMatrix>& jacobianFromStart,
547 const std::vector<std::size_t>& materialIndices,
548 const std::vector<double>& qOverPderiv,
549 const track_state_t& trackState,
551 const SquareMatrix<kMeasDim> covarianceMeasurement =
552 trackState.template calibratedCovariance<kMeasDim>();
554 const BoundVector predicted = trackState.smoothed();
556 const Vector<kMeasDim> measurement =
557 trackState.template calibrated<kMeasDim>();
560 trackState.template projectorSubspaceHelper<kMeasDim>().projector();
563 extendedSystem, jacobianFromStart, materialIndices, qOverPderiv,
564 covarianceMeasurement, predicted, measurement, projector,
logger);
581template <TrackProxyConcept track_proxy_t>
583 const track_proxy_t track,
Gx2fSystem& extendedSystem,
584 const std::unordered_map<GeometryIdentifier, Gx2fMaterialProperties>&
586 const std::vector<std::size_t>& materialParamIndices,
587 std::vector<GeometryIdentifier>& geoIdVector,
const Logger&
logger) {
588 std::vector<BoundMatrix> jacobianFromStart;
589 jacobianFromStart.emplace_back(BoundMatrix::Identity());
590 geoIdVector.reserve(track.nTrackStates());
591 std::vector<double> qOverPderiv;
593 bool foundELoss{
false};
594 for (
const auto& trackState : track.trackStates()) {
596 const GeometryIdentifier geoId = trackState.referenceSurface().geometryId();
597 ACTS_DEBUG(
"Start to investigate trackState on surface " << geoId);
598 const auto typeFlags = trackState.typeFlags();
601 for (
auto& jac : jacobianFromStart) {
602 jac = trackState.jacobian() * jac;
606 if (!typeFlags.hasMeasurement() && !typeFlags.hasMaterial()) {
607 ACTS_DEBUG(
" Skip state.");
612 if (typeFlags.hasMeasurement()) {
613 ACTS_DEBUG(
" Handle measurement. ");
615 const auto measDim = trackState.calibratedSize();
617 if (measDim < 1 || 6 < measDim) {
618 ACTS_ERROR(
"Can not process state with measurement with "
619 << measDim <<
" dimensions.");
620 throw std::domain_error(
621 "Found measurement with less than 1 or more than 6 dimension(s).");
624 extendedSystem.
ndf() += measDim;
626 visit_measurement(measDim, [&](
auto N) {
628 materialParamIndices, qOverPderiv,
634 if (typeFlags.hasMaterial()) {
635 ACTS_DEBUG(
" Handle material");
636 const auto materialMapId = materialMap.find(geoId);
637 if (materialMapId == materialMap.end()) {
638 ACTS_ERROR(
"No material properties found for surface " << geoId);
639 throw std::runtime_error(
"No material properties found for surface.");
642 if (materialMapId->second.nDim() == 0ul) {
645 if (materialMapId->second.energyLoss().isValid()) {
646 ACTS_VERBOSE(
"The material surface carries energy loss");
649 const std::size_t deltaPosition =
650 materialParamIndices.at(geoIdVector.size());
651 geoIdVector.push_back(geoId);
653 materialMapId->second.contributionToGx2fSums(
654 extendedSystem, trackState.smoothed()[eBoundTheta], deltaPosition,
660 ACTS_DEBUG(
" Update Jacobian for q/p after material surface "
661 << geoId <<
" with ratio " << materialMapId->second.qOverPratio());
662 jacobianFromStart.front().row(eBoundQOverP) *=
663 materialMapId->second.qOverPratio();
666 jacobianFromStart.emplace_back(BoundMatrix::Identity());
667 qOverPderiv.push_back(materialMapId->second.qOverPderiv());
690 BoundTrackParameters& params,
const Eigen::VectorXd& deltaParamsExtended,
691 std::unordered_map<GeometryIdentifier, Gx2fMaterialProperties>& materialMap,
692 const std::vector<GeometryIdentifier>& geoIdVector);
705 Gx2fSystem& extendedSystem);
712template <
typename propagator_t,
typename traj_t>
717 static constexpr auto kInvalid = kTrackIndexInvalid;
729 std::unique_ptr<const Logger> log =
730 getDefaultLogger(
"Gx2Fitter", Logging::INFO))
740 m_logger->cloneWithSuffix(
"Actor")};
742 m_logger->cloneWithSuffix(
"AddToSum")};
804 template <
typename propagator_state_t,
typename stepper_t,
805 typename navigator_t>
808 const Logger& )
const {
809 assert(result.fittedStates &&
"No MultiTrajectory set");
813 ACTS_DEBUG(
"Actor: finish: All measurements have been found.");
814 result.finished =
true;
815 }
else if (state.navigation.navigationBreak) {
816 ACTS_DEBUG(
"Actor: finish: navigationBreak.");
817 result.finished =
true;
821 if (result.finished) {
823 if (result.measurementStates > 0) {
824 result.missedActiveSurfaces.resize(result.measurementHoles);
832 const Surface* surface = navigator.currentSurface(state.navigation);
833 if (surface ==
nullptr) {
837 ++result.surfaceCount;
838 const GeometryIdentifier geoId = surface->geometryId();
839 ACTS_DEBUG(
"Surface "
840 << geoId <<
", " << surface->bounds() <<
" detected. "
841 <<
"Sensitive: " << (surface->isSensitive() ?
"yes" :
"no")
842 <<
", has material: "
843 << (surface->hasMaterial() ?
"yes" :
"no"));
845 auto matFillResult =
fillMaterialMap(state, stepper, navigator, result);
846 if (!matFillResult.ok()) {
847 return matFillResult.error();
850 auto trackStateResult =
makeTrackState(state, stepper, navigator, result);
851 if (!trackStateResult.ok()) {
852 return trackStateResult.error();
858 ++result.processedMeasurements;
860 result.lastMeasurementIndex = result.lastTrackIndex;
864 ++result.measurementStates;
867 ++result.processedStates;
871 result.measurementHoles = result.missedActiveSurfaces.size();
876 ACTS_DEBUG(
" The surface contains no measurement/material/hole.");
880 template <
typename propagator_state_t,
typename stepper_t,
881 typename navigator_t>
883 const stepper_t& stepper,
884 const navigator_t& navigator,
886 const Surface* surface = navigator.currentSurface(state.navigation);
888 const GeometryIdentifier geoId = surface->geometryId();
891 auto materialItr = result.materialMap.find(geoId);
892 const bool isSensitive =
894 const bool hasMaterial = surface->hasMaterial() &&
895 materialItr != result.materialMap.end() &&
896 materialItr->second.materialIsValid();
898 if (!isSensitive && !hasMaterial) {
902 auto& fittedStates = *result.fittedStates;
909 result.lastTrackIndex = trackStateProxy.index();
911 auto typeFlags = trackStateProxy.typeFlags();
912 typeFlags.setHasParameters();
915 auto transportRes = stepper.transportToBound(
917 if (!transportRes.ok()) {
918 return transportRes.error();
923 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
926 auto res = stepper.boundParameters(state.stepping, *surface);
931 auto& boundParams = *
res;
933 trackStateProxy.smoothedCovariance() = stepper.covariance(state.stepping).value();
934 trackStateProxy.jacobian() = *transportRes;
935 trackStateProxy.pathLength() = stepper.pathLength(state.stepping);
939 typeFlags.setHasMaterial();
942 ACTS_DEBUG(
" Update parameters with material effects.");
943 ACTS_VERBOSE(
" boundParams before the update: "
944 << boundParams.parameters().transpose());
946 materialItr->second.updateTrackParameters(boundParams);
947 ACTS_VERBOSE(
" boundParams after the update: "
948 << boundParams.parameters().transpose());
950 stepper.update(state.stepping,
951 transformBoundToFreeParameters(
952 trackStateProxy.referenceSurface(), state.geoContext,
953 boundParams.parameters()),
954 boundParams.parameters(),
955 trackStateProxy.smoothedCovariance(), *surface);
959 trackStateProxy.smoothed() = boundParams.parameters();
965 typeFlags.setIsHole();
968 typeFlags.setIsMeasurement();
973 sourceLinkIt->second, trackStateProxy);
987 template <
typename propagator_state_t,
typename stepper_t,
988 typename navigator_t>
990 const stepper_t& stepper,
991 const navigator_t& navigator,
997 <<
"Multiple scattering and energy loss are disabled. Returning");
1000 const Surface* surface = navigator.currentSurface(state.navigation);
1001 if (!surface->hasMaterial()) {
1007 ACTS_DEBUG(
" The surface contains material ...");
1009 const GeometryIdentifier geoId = surface->geometryId();
1010 auto materialMapId = result.materialMap.find(geoId);
1013 if (materialMapId != result.materialMap.end()) {
1014 ACTS_VERBOSE(
" .... entry is already in the material map.");
1015 if (materialMapId->second.nDim() == 0ul) {
1016 ACTS_VERBOSE(
" Material surface "
1018 <<
" has zero dimension - do not keep the index.");
1021 result.materialParamIndices.push_back(
1022 result.materialParamIndices.back() + materialMapId->second.nDim());
1026 ACTS_DEBUG(
" ... create entry in material map.");
1029 Acts::detail::evaluateMaterialSlab(
1030 state, stepper, *surface,
1031 Acts::detail::determineMaterialUpdateMode(
1032 state, navigator, MaterialUpdateMode::FullUpdate));
1033 if (!slabResult.ok()) {
1034 ACTS_DEBUG(__func__ <<
" | "
1035 <<
"Failed to evaluate material slab: "
1036 << slabResult.error());
1039 const MaterialSlab& slab = *slabResult;
1040 const bool goodSlab = !slab.isVacuum();
1045 ELossAtSurface eLoss{};
1046 ScatteringAtSurface scatterer{};
1051 const double sigma =
1052 static_cast<double>(Acts::computeMultipleScatteringTheta0(
1053 slab, particle.absolutePdg(), particle.mass(),
1055 particle.absoluteCharge()));
1056 ACTS_VERBOSE(
" The Highland formula gives sigma = " << sigma);
1058 scatterer = ScatteringAtSurface{sigma};
1061 ACTS_VERBOSE(
" Material slab is not valid.");
1067 stepper.position(state.stepping), stepper.direction(state.stepping),
1071 if (!eLoss.isValid() && goodSlab) {
1074 const double qOverP = stepper.qOverP(state.stepping);
1075 ACTS_VERBOSE(
"The particle has momentum "
1076 << (1. / qOverP) * particle.absoluteCharge()
1077 <<
" and charge " << particle.absoluteCharge());
1079 eLoss = ELossAtSurface{
1080 computeEnergyLossMean(slab, particle.absolutePdg(),
1081 particle.mass(), qOverP,
1082 particle.absoluteCharge()),
1084 static_cast<double>(Acts::computeEnergyLossLandauSigma(
1085 slab, particle.mass(),
static_cast<float>(qOverP),
1086 particle.absoluteCharge()))};
1088 ACTS_VERBOSE(
" The Bethe-Bloch formula gives energy loss "
1089 << eLoss.lostEnergy() <<
" with uncertainty "
1090 << eLoss.lostSigma());
1095 scatterer += result.accScatterer;
1096 eLoss += result.accEloss;
1098 result.accScatterer = std::move(scatterer);
1099 scatterer = ScatteringAtSurface{};
1101 result.accScatterer = ScatteringAtSurface{};
1105 result.accEloss = std::move(eLoss);
1106 eLoss = ELossAtSurface{};
1108 result.accEloss = ELossAtSurface{};
1110 ACTS_DEBUG(
" ... add entry in material map with scattering "
1111 << scatterer.sigma() <<
" and energy loss "
1112 << eLoss.lostEnergy());
1118 if (materialMapId->second.nDim() == 0ul) {
1119 ACTS_VERBOSE(
" Material surface "
1121 <<
" has zero dimension - do not keep the index.");
1124 result.materialParamIndices.push_back(result.materialParamIndices.back() +
1125 materialMapId->second.nDim());
1130 template <
typename propagator_state_t,
typename stepper_t,
1131 typename navigator_t,
typename result_t>
1133 const navigator_t& ,
const result_t& result,
1134 const Logger& )
const {
1135 return result.finished;
1156 template <
typename source_link_iterator_t,
1157 TrackContainerFrontend track_container_t>
1159 source_link_iterator_t it, source_link_iterator_t end,
1160 const BoundTrackParameters& sParameters,
1162 track_container_t& trackContainer)
const
1163 requires(!std::is_same_v<Gx2fNavigator, DirectNavigator>)
1168 ACTS_VERBOSE(
"Preparing " << std::distance(it, end)
1169 <<
" input measurements");
1170 std::unordered_map<const Surface*, SourceLink> inputMeasurements{};
1172 for (; it != end; ++it) {
1173 inputMeasurements.try_emplace(gx2fOptions.extensions.surfaceAccessor(*it),
1178 using Actors = Acts::ActorList<GX2FActor>;
1180 using PropagatorOptions =
typename propagator_t::template
Options<Actors>;
1182 BoundTrackParameters params = sParameters;
1183 params.covariance() = BoundMatrix::Identity();
1186 double oldChi2sum = std::numeric_limits<double>::max();
1192 typename track_container_t::TrackContainerBackend trackContainerTempBackend;
1193 traj_t trajectoryTempBackend;
1194 TrackContainer trackContainerTemp{trackContainerTempBackend,
1195 trajectoryTempBackend};
1204 std::unordered_map<GeometryIdentifier, Gx2fMaterialProperties> materialMap;
1208 BoundMatrix fullCovariancePredicted = BoundMatrix::Identity();
1210 ACTS_VERBOSE(
"Initial parameters: " << params.parameters().transpose());
1213 ACTS_DEBUG(
"Start to iterate");
1218 std::size_t nUpdate = 0;
1219 for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; ++nUpdate) {
1220 ACTS_DEBUG(
"nUpdate = " << nUpdate + 1 <<
"/" << gx2fOptions.nUpdateMax);
1223 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1227 for (
const auto& [surface, _] : inputMeasurements) {
1228 propagatorOptions.navigation.registerMeasurementSurface(*surface);
1231 auto& gx2fActor = propagatorOptions.actorList.template
get<GX2FActor>();
1232 gx2fActor.inputMeasurements = &inputMeasurements;
1233 if (gx2fOptions.includeMaterialInIter) {
1234 gx2fActor.doMultipleScattering = gx2fOptions.doMultipleScattering;
1235 gx2fActor.doEnergyLoss = gx2fOptions.doEnergyLoss;
1236 gx2fActor.scatteringCutOff = gx2fOptions.scatteringCutOff;
1237 gx2fActor.elossCutOff = gx2fOptions.elossCutOff;
1239 gx2fActor.extensions = gx2fOptions.extensions;
1240 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1242 gx2fActor.startParameters = ¶ms;
1244 auto propagatorState =
m_propagator.makeState(propagatorOptions);
1246 auto propagatorInitResult =
1247 m_propagator.initialize(propagatorState, params,
nullptr);
1248 if (!propagatorInitResult.ok()) {
1249 ACTS_DEBUG(
"Propagation initialization failed: "
1250 << propagatorInitResult.error());
1251 return propagatorInitResult.error();
1255 r.fittedStates = &trajectoryTempBackend;
1256 r.materialMap = std::move(materialMap);
1260 trackContainerTemp.clear();
1263 auto propagationResult =
m_propagator.propagate(propagatorState);
1266 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1267 propagatorOptions,
false);
1270 ACTS_DEBUG(
"Propagation failed: " << result.error());
1271 return result.error();
1276 auto& propRes = *result;
1277 GX2FResult gx2fResult = std::move(propRes.template
get<GX2FResult>());
1279 materialMap = std::move(gx2fResult.materialMap);
1281 auto track = trackContainerTemp.makeTrack();
1282 tipIndex = gx2fResult.lastMeasurementIndex;
1288 ACTS_INFO(
"Did not find any measurements in nUpdate "
1289 << nUpdate + 1 <<
"/" << gx2fOptions.nUpdateMax);
1290 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1293 track.tipIndex() = tipIndex;
1294 track.linkForward();
1298 Gx2fSystem extendedSystem{gx2fResult.materialParamIndices.back()};
1304 std::vector<GeometryIdentifier> geoIdVector;
1307 gx2fResult.materialParamIndices, geoIdVector,
1310 chi2sum = extendedSystem.
chi2();
1325 ACTS_INFO(
"Not enough measurements. Require "
1327 << extendedSystem.
ndf() <<
" could be used.");
1328 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1331 Eigen::VectorXd deltaParamsExtended =
1334 ACTS_VERBOSE(
"aMatrix:\n"
1335 << extendedSystem.
aMatrix() <<
"\n"
1337 << extendedSystem.
bVector() <<
"\n"
1338 <<
"deltaParamsExtended:\n"
1339 << deltaParamsExtended <<
"\n"
1340 <<
"oldChi2sum = " << oldChi2sum <<
"\n"
1341 <<
"chi2sum = " << extendedSystem.
chi2());
1343 if ((gx2fOptions.relChi2changeCutOff != 0) && (nUpdate > 0) &&
1344 (std::abs(extendedSystem.
chi2() / oldChi2sum - 1) <
1345 gx2fOptions.relChi2changeCutOff)) {
1346 ACTS_DEBUG(
"Abort with relChi2changeCutOff after "
1347 << nUpdate + 1 <<
"/" << gx2fOptions.nUpdateMax
1353 if (extendedSystem.
chi2() > oldChi2sum + 1e-5) {
1354 ACTS_DEBUG(
"chi2 not converging monotonically in update " << nUpdate);
1359 if (nUpdate == gx2fOptions.nUpdateMax - 1) {
1365 if (gx2fOptions.nUpdateMax > 5) {
1366 ACTS_INFO(
"Did not converge in " << gx2fOptions.nUpdateMax
1368 return Experimental::GlobalChiSquareFitterError::DidNotConverge;
1376 ACTS_VERBOSE(
"Updated parameters: " << params.parameters().transpose());
1378 oldChi2sum = extendedSystem.
chi2();
1380 ACTS_DEBUG(
"Iterations finished");
1381 ACTS_VERBOSE(
"Final parameters: " << params.parameters().transpose());
1382 ACTS_VERBOSE(
"Final scattering angles and energy loss:");
1383 for (
const auto& [key, value] : materialMap) {
1384 if (!value.materialIsValid()) {
1387 ACTS_VERBOSE(
" ( " << value.deltaTheta() <<
" | " << value.deltaPhi()
1388 <<
"|" << value.lostEnergy() <<
" )");
1393 if (!gx2fOptions.includeMaterialInIter &&
1394 (gx2fOptions.doEnergyLoss || gx2fOptions.doMultipleScattering)) {
1395 ACTS_DEBUG(
"Start to evaluate material");
1398 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1402 for (
const auto& [surface, _] : inputMeasurements) {
1403 propagatorOptions.navigation.registerMeasurementSurface(*surface);
1406 auto& gx2fActor = propagatorOptions.actorList.template
get<GX2FActor>();
1407 gx2fActor.inputMeasurements = &inputMeasurements;
1408 gx2fActor.doMultipleScattering = gx2fOptions.doMultipleScattering;
1409 gx2fActor.doEnergyLoss = gx2fOptions.doEnergyLoss;
1410 gx2fActor.extensions = gx2fOptions.extensions;
1411 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1413 gx2fActor.startParameters = ¶ms;
1414 gx2fActor.scatteringCutOff = gx2fOptions.scatteringCutOff;
1415 gx2fActor.elossCutOff = gx2fOptions.elossCutOff;
1417 auto propagatorState =
m_propagator.makeState(propagatorOptions);
1419 auto propagatorInitResult =
1420 m_propagator.initialize(propagatorState, params,
nullptr);
1421 if (!propagatorInitResult.ok()) {
1422 ACTS_DEBUG(
"Propagation initialization failed: "
1423 << propagatorInitResult.error());
1424 return propagatorInitResult.error();
1428 r.fittedStates = &trajectoryTempBackend;
1429 r.materialMap = std::move(materialMap);
1433 trackContainerTemp.clear();
1436 auto propagationResult =
m_propagator.propagate(propagatorState);
1439 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1440 propagatorOptions,
false);
1443 ACTS_DEBUG(
"Propagation failed: " << result.error());
1444 return result.error();
1449 auto& propRes = *result;
1450 GX2FResult gx2fResult = std::move(propRes.template
get<GX2FResult>());
1451 materialMap = std::move(gx2fResult.materialMap);
1452 auto track = trackContainerTemp.makeTrack();
1453 tipIndex = gx2fResult.lastMeasurementIndex;
1459 ACTS_INFO(
"Did not find any measurements in material fit.");
1460 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1463 track.tipIndex() = tipIndex;
1464 track.linkForward();
1468 Gx2fSystem extendedSystem{gx2fResult.materialParamIndices.back()};
1474 std::vector<GeometryIdentifier> geoIdVector;
1477 gx2fResult.materialParamIndices, geoIdVector,
1480 chi2sum = extendedSystem.
chi2();
1492 ACTS_INFO(
"Not enough measurements. Require "
1494 << extendedSystem.
ndf() <<
" could be used.");
1495 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1498 Eigen::VectorXd deltaParamsExtended =
1501 ACTS_VERBOSE(
"aMatrix:\n"
1502 << extendedSystem.
aMatrix() <<
"\n"
1504 << extendedSystem.
bVector() <<
"\n"
1505 <<
"deltaParamsExtended:\n"
1506 << deltaParamsExtended <<
"\n"
1507 <<
"oldChi2sum = " << oldChi2sum <<
"\n"
1508 <<
"chi2sum = " << extendedSystem.
chi2());
1510 chi2sum = extendedSystem.
chi2();
1513 ACTS_VERBOSE(
"Updated parameters: " << params.parameters().transpose());
1517 ACTS_DEBUG(
"Finished to evaluate material");
1518 ACTS_VERBOSE(
"Final parameters after material: "
1519 << params.parameters().transpose());
1523 ACTS_VERBOSE(
"Final scattering angles and energy loss:");
1524 for (
const auto& [key, value] : materialMap) {
1525 if (!value.materialIsValid()) {
1528 ACTS_VERBOSE(
" ( " << value.deltaTheta() <<
" | " << value.deltaPhi()
1529 <<
"|" << value.lostEnergy() <<
" )");
1532 ACTS_VERBOSE(
"Final covariance:\n" << fullCovariancePredicted);
1539 if (
false && gx2fOptions.nUpdateMax > 0) {
1540 ACTS_VERBOSE(
"Propagate with the final covariance.");
1542 params.covariance() = fullCovariancePredicted;
1545 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1546 auto& gx2fActor = propagatorOptions.actorList.template
get<GX2FActor>();
1547 gx2fActor.inputMeasurements = &inputMeasurements;
1548 gx2fActor.doMultipleScattering = gx2fOptions.doMultipleScattering;
1549 gx2fActor.doEnergyLoss = gx2fOptions.doEnergyLoss;
1550 gx2fActor.extensions = gx2fOptions.extensions;
1551 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1553 gx2fActor.startParameters = ¶ms;
1555 auto propagatorState =
m_propagator.makeState(propagatorOptions);
1557 auto propagatorInitResult =
1558 m_propagator.initialize(propagatorState, params,
nullptr);
1559 if (!propagatorInitResult.ok()) {
1560 ACTS_DEBUG(
"Propagation initialization failed: "
1561 << propagatorInitResult.error());
1562 return propagatorInitResult.error();
1566 r.fittedStates = &trackContainer.trackStateContainer();
1567 r.materialMap = std::move(materialMap);
1570 auto propagationResult =
m_propagator.propagate(propagatorState);
1573 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1574 propagatorOptions,
false);
1577 ACTS_DEBUG(
"Propagation failed: " << result.error());
1578 return result.error();
1581 auto& propRes = *result;
1582 GX2FResult gx2fResult = std::move(propRes.template
get<GX2FResult>());
1583 materialMap = std::move(gx2fResult.materialMap);
1585 if (tipIndex != gx2fResult.lastMeasurementIndex) {
1586 ACTS_INFO(
"Final fit used unreachable measurements.");
1587 tipIndex = gx2fResult.lastMeasurementIndex;
1592 ACTS_INFO(
"Did not find any measurements in final propagation.");
1593 return Experimental::GlobalChiSquareFitterError::
1594 NotEnoughMeasurements;
1599 if (!trackContainer.hasColumn(
1601 trackContainer.template addColumn<std::uint32_t>(
"Gx2fnUpdateColumn");
1605 auto track = trackContainer.makeTrack();
1606 track.tipIndex() = tipIndex;
1607 track.parameters() = params.parameters();
1608 track.covariance() = fullCovariancePredicted;
1609 track.setReferenceSurface(params.referenceSurface().getSharedPtr());
1611 if (trackContainer.hasColumn(
1613 ACTS_DEBUG(
"Add nUpdate to track");
1614 track.template component<std::uint32_t>(
"Gx2fnUpdateColumn") =
1615 static_cast<std::uint32_t
>(nUpdate);
1619 calculateTrackQuantities(track);
1623 track.chi2() = chi2sum;
1625 track.linkForward();
Scalar theta() const
theta method
bool isValid() const
Test to see if the link can be dereferenced.
std::pair< std::vector< unsigned int >, bool > res
Propagator Actor plugin for the GX2F.
const CalibrationContext * calibrationContext
Calibration context for the fit.
double elossCutOff
Cutoff value on the energy loss to fine tune the number of energy loss parameters in the fit.
const BoundTrackParameters * startParameters
Start parameters of the track fit.
bool checkAbort(propagator_state_t &, const stepper_t &, const navigator_t &, const result_t &result, const Logger &) const
Result< void > act(propagator_state_t &state, const stepper_t &stepper, const navigator_t &navigator, result_type &result, const Logger &) const
Gx2f actor operation.
Result< void > fillMaterialMap(propagator_state_t &state, const stepper_t &stepper, const navigator_t &navigator, result_type &result) const
FreeToBoundCorrection freeToBoundCorrection
Whether to include non-linear correction during global to local transformation.
const Logger * actorLogger
The logger instance.
const Logger & logger() const
Logger helper.
Gx2FitterExtensions< traj_t > extensions
Gx2FitterResult< traj_t > result_type
Broadcast the result_type.
Result< void > makeTrackState(propagator_state_t &state, const stepper_t &stepper, const navigator_t &navigator, result_type &result) const
typename traj_t::TrackStateProxy TrackStateProxy_t
const std::unordered_map< const Surface *, SourceLink > * inputMeasurements
Allows retrieving measurements for a surface.
bool doMultipleScattering
Whether to consider multiple scattering.
bool doEnergyLoss
Whether to consider energy loss.
const Logger & logger() const
std::unique_ptr< const Logger > m_actorLogger
typename propagator_t::Navigator Gx2fNavigator
The navigator type.
std::unique_ptr< const Logger > m_addToSumLogger
StraightPropagator_t m_propagator
Result< typename track_container_t::TrackProxy > fit(source_link_iterator_t it, source_link_iterator_t end, const BoundTrackParameters &sParameters, const Gx2FitterOptions< traj_t > &gx2fOptions, track_container_t &trackContainer) const
Fit implementation.
Gx2Fitter(const propagator_t &pPropagator, std::unique_ptr< const Logger > log=getDefaultLogger("Gx2Fitter", Logging::INFO))
Constructor for the Global Chi-Square Fitter.
static constexpr auto kInvalid
std::unique_ptr< const Logger > m_logger
void updateGx2fParams(BoundTrackParameters ¶ms, const Eigen::VectorXd &deltaParamsExtended, std::unordered_map< GeometryIdentifier, Gx2fMaterialProperties > &materialMap, const std::vector< GeometryIdentifier > &geoIdVector)
Update parameters (and scattering angles if applicable).
Eigen::VectorXd computeGx2fDeltaParams(const Gx2fSystem &extendedSystem)
Solve the gx2f system to get the delta parameters for the update.
void addMeasurementToGx2fSums(Gx2fSystem &extendedSystem, const std::vector< BoundMatrix > &jacobianFromStart, const std::vector< std::size_t > &materialIndices, const std::vector< double > &qOverPderiv, const track_state_t &trackState, const Logger &logger)
Process measurements and fill the aMatrix and bVector.
void addMeasurementToGx2fSumsBackend(Gx2fSystem &extendedSystem, const std::vector< BoundMatrix > &jacobianFromStart, const std::vector< std::size_t > &materialIndices, const std::vector< double > &qOverPderiv, const Eigen::MatrixXd &covarianceMeasurement, const BoundVector &predicted, const Eigen::VectorXd &measurement, const Eigen::MatrixXd &projector, const Logger &logger)
Adds a measurement to the GX2F equation system in a modular backend function.
void updateGx2fCovarianceParams(BoundMatrix &fullCovariancePredicted, Gx2fSystem &extendedSystem)
Calculate and update the covariance of the fitted parameters.
void fillGx2fSystem(const track_proxy_t track, Gx2fSystem &extendedSystem, const std::unordered_map< GeometryIdentifier, Gx2fMaterialProperties > &materialMap, const std::vector< std::size_t > &materialParamIndices, std::vector< GeometryIdentifier > &geoIdVector, const Logger &logger)
Fill the GX2F system with data from a track.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
static Root::TMsgLogger logger("iLumiCalc")
This class is not to needed in AthSimulation.
constexpr std::string_view gx2fnUpdateColumn
constexpr TrackStatePropMask trackStateMask
Extension struct which holds delegates to customise the GX2F behaviour.
typename MultiTrajectory< traj_t >::ConstTrackStateProxy ConstTrackStateProxy
Type alias for const track state proxy from multi-trajectory.
Delegate< void(const GeometryContext &, const CalibrationContext &, const SourceLink &, TrackStateProxy)> Calibrator
Type alias for calibrator delegate to process measurements.
OutlierFinder outlierFinder
typename TrackStateProxy::Parameters Parameters
Type alias for track parameters from track state proxy.
Delegate< Gx2fMaterialProperties::ELossAtSurface( const GeometryContext &geoContext, const CalibrationContext &calibContext, const Vector3 &pos, const Vector3 &dir, const Surface &matSurf)> ELossAccumulator
Type alias of a delegate to retrieve the measured energy loss at a given surface e....
SourceLinkSurfaceAccessor surfaceAccessor
Delegate< bool(ConstTrackStateProxy)> OutlierFinder
Type alias for outlier finder delegate to identify measurement outliers.
typename MultiTrajectory< traj_t >::TrackStateProxy TrackStateProxy
Type alias for mutable track state proxy from multi-trajectory.
Gx2FitterExtensions()
Default constructor which connects the default void components.
ELossAccumulator elossAccumulator
Combined options for the Global-Chi-Square fitter.
Gx2FitterOptions(const GeometryContext &gctx, const MagneticFieldContext &mctx, std::reference_wrapper< const CalibrationContext > cctx, Gx2FitterExtensions< traj_t > extensions_, const PropagatorPlainOptions &pOptions)
PropagatorOptions with context.
bool includeMaterialInIter
PropagatorPlainOptions propagatorPlainOptions
double relChi2changeCutOff
FreeToBoundCorrection freeToBoundCorrection
Gx2FitterExtensions< ActsTrk::MutableTrackStateBackend > extensions
std::reference_wrapper< const CalibrationContext > calibrationContext
std::reference_wrapper< const MagneticFieldContext > magFieldContext
std::reference_wrapper< const GeometryContext > geoContext
bool doMultipleScattering
Result container for a global chi-square fit.
std::vector< std::size_t > materialParamIndices
Index of the next material parameter.
std::unordered_map< GeometryIdentifier, Gx2fMaterialProperties > materialMap
The materialMap stores for each visited surface their scattering properties.
std::size_t surfaceCount
Count how many surfaces have been hit.
Gx2fMaterialProperties::ScatteringAtSurface accScatterer
Accumulated scattering.
bool finished
Indicator if track fitting has been done.
Gx2fMaterialProperties::ELossAtSurface accEloss
Accumulated energy loss to cache the energy loss which is below the threshold.
std::size_t processedStates
Counter for handled states.
std::size_t lastTrackIndex
This is the index of the 'tip' of the states stored in multitrajectory.
std::size_t lastMeasurementIndex
This is the index of the 'tip' of the track stored in multitrajectory.
std::vector< const Surface * > missedActiveSurfaces
Measurement surfaces without hits.
traj_t * fittedStates
Fitted states that the actor has handled.
std::size_t measurementHoles
Counter for measurements holes A hole correspond to a surface with an associated detector element wit...
std::size_t processedMeasurements
Counter for handled measurements.
std::size_t measurementStates
Counter for states with non-outlier measurements.
Auxiliary struct to include the measured energy loss at a surface.
constexpr double lostSigma() const
The uncertainty on the energy loss.
ELossAtSurface & operator+=(const ELossAtSurface &other) noexcept
Absorb the energy loss from another object.
constexpr double lostEnergy() const
The amount of lost energy (Bethe bloch / measurement).
ELossAtSurface(const double energy, const double sigma) noexcept
Constructor taking the measured energy loss and its uncertainty.
double m_lostEnergy
The amount of lost energy at a given surface.
double m_lossSigma
The uncertainty on the lost energy.
constexpr bool isValid() const
Is the measured energy loss valid.
bool m_isValid
Flag toggling whether the parameters are valid.
ELossAtSurface()=default
Default constructor to construct an invalid energy loss.
static ELossAtSurface invalidELoss(const GeometryContext &geoContext, const CalibrationContext &calibContext, const Vector3 &pos, const Vector3 &dir, const Surface &matSurface)
Function that satisfies the eLossAccumulator delegate pattern and the produces an invalid energy loss...
Auxiliary struct to describe the material scattering at a surface.
bool m_isValid
Flag toggling whether the scatterer is valid.
ScatteringAtSurface()=default
Default constructor to construct an invalid scatterer.
constexpr double sigma() const
Uncertainty on the scattering angle.
double m_sigma
The inverse uncertainty on the scattering angles calculated using e.g.
ScatteringAtSurface & operator+=(const ScatteringAtSurface &other)
ScatteringAtSurface(const double sigma)
Constructor taking the width of the scatterer.
constexpr bool isValid() const
Is the scattering uncertainty valid.
A container to store material properties for each material surface.
double m_scatPhi
Fitted delta phi scattering.
constexpr double qOverPderiv() const
ELossAtSurface m_eloss
Description of the energy loss.
void updateParameters(const Eigen::VectorXd &deltaParamsExtended, const std::size_t firstParamIdx)
const ScatteringAtSurface & scatterer() const
constexpr std::size_t nDim() const
Number of dimensions from the material scatterer.
double m_lostEnergy
Fitted parameters.
constexpr bool materialIsValid() const
Accessor for the material validity flag.
double m_scatTheta
Fitted delta theta scattering.
constexpr double lostEnergy() const
double m_qOverPderiv
qOverP derivative with respect to eloss
void contributionToGx2fSums(Gx2fSystem &extendedSystem, const double theta, const std::size_t firstParamIdx, const Logger &logger) const
ScatteringAtSurface m_scatterer
Description of the scattering angles.
const ELossAtSurface & energyLoss() const
constexpr double deltaPhi() const
constexpr double deltaTheta() const
constexpr double qOverPratio() const
void updateTrackParameters(BoundTrackParameters &trackPars)
Update the track parameters with the scattering angles and.
Gx2fMaterialProperties(ScatteringAtSurface &&scatterer, ELossAtSurface &&eLoss)
Constructor to initialize material properties.
A container to manage all properties of a gx2f system.
std::size_t m_ndf
Number of degrees of freedom of the system.
bool isWellDefined()
Checks if the system has sufficient degrees of freedom for fitting.
double & chi2()
Accessor for the accumulated chi-squared value (mutable version).
std::size_t m_nDims
Number of dimensions of the (extended) system.
Eigen::VectorXd & bVector()
Accessor for the extended system vector (mutable version).
double chi2() const
Accessor for the accumulated chi-squared value (const version).
std::size_t findRequiredNdf()
Determines the minimum number of degrees of freedom required for the fit.
std::size_t & ndf()
Accessor for the number of degrees of freedom (mutable version).
Gx2fSystem(std::size_t nDims)
Constructor to initialize matrices and vectors to zero based on specified dimensions.
std::size_t nDims() const
Accessor for the number of dimensions of the extended system.
std::size_t ndf() const
Accessor for the number of degrees of freedom (const version).
const Eigen::VectorXd & bVector() const
Accessor for the extended system vector (const version).
const Eigen::MatrixXd & aMatrix() const
Accessor for the extended system matrix (const version).
Eigen::MatrixXd & aMatrix()
Accessor for the extended system matrix (mutable version).
Eigen::VectorXd m_bVector
Extended vector for accumulation.
double m_chi2
Sum of chi-squared values.
Eigen::MatrixXd m_aMatrix
Extended matrix for accumulation.