ATLAS Offline Software
Loading...
Searching...
No Matches
Trk::GlobalChi2Fitter Class Reference

#include <GlobalChi2Fitter.h>

Inheritance diagram for Trk::GlobalChi2Fitter:
Collaboration diagram for Trk::GlobalChi2Fitter:

Classes

struct  Cache
struct  PropagationResult
struct  TrackHoleCount

Public Member Functions

 GlobalChi2Fitter (const std::string &, const std::string &, const IInterface *)
virtual ~GlobalChi2Fitter ()
virtual StatusCode initialize () override
virtual StatusCode finalize () override
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const PrepRawDataSet &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const Track &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const MeasurementSet &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const Track &, const PrepRawDataSet &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const Track &, const Track &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual std::unique_ptr< Trackfit (const EventContext &ctx, const Track &, const MeasurementSet &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
virtual TrackalignmentFit (AlignmentCache &, const Track &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=Trk::nonInteracting) const override

Private Types

enum  FitterStatusType {
  S_FITS , S_SUCCESSFUL_FITS , S_MAT_INV_FAIL , S_NOT_ENOUGH_MEAS ,
  S_PROPAGATION_FAIL , S_INVALID_ANGLES , S_NOT_CONVERGENT , S_HIGH_CHI2 ,
  S_LOW_MOMENTUM , S_MAX_VALUE
}

Private Member Functions

TrackfitIm (const EventContext &ctx, Cache &cache, const Track &inputTrack, const RunOutlierRemoval runOutlier, const ParticleHypothesis matEffects) const
Trackmyfit (const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const
Trackmyfit_helper (Cache &, GXFTrajectory &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const
TrackmainCombinationStrategy (const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
TrackbackupCombinationStrategy (const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
void makeProtoState (Cache &, GXFTrajectory &, const TrackStateOnSurface *, int index=-1) const
void makeProtoStateFromMeasurement (Cache &, GXFTrajectory &, const MeasurementBase *, const TrackParameters *trackpar=nullptr, bool isoutlier=false, int index=-1) const
bool processTrkVolume (Cache &, const Trk::TrackingVolume *tvol) const
void addMaterialUpdateTrajectory (Cache &cache, GXFTrajectory &track, int offset, std::vector< std::pair< const Layer *, const Layer * > > &layers, const TrackParameters *ref1, const TrackParameters *ref2, ParticleHypothesis mat) const
 Given layer information, probe those layers for scatterers and add them to a track.
void addIDMaterialFast (const EventContext &ctx, Cache &cache, GXFTrajectory &track, const TrackParameters *parameters, ParticleHypothesis part) const
 A faster strategy for adding scatter material to tracks, works only for inner detector tracks.
void addMaterial (const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters *, ParticleHypothesis) const
std::vector< std::unique_ptr< TrackParameters > > holesearchExtrapolation (const EventContext &ctx, const TrackParameters &src, const GXFTrackState &dst, PropDirection propdir) const
 Helper method which performs an extrapolation with additional logic for hole search.
std::unique_ptr< const TrackParametersmakePerigee (Cache &, const TrackParameters &, const ParticleHypothesis) const
std::unique_ptr< const TrackParametersmakeTrackFindPerigeeParameters (const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
std::unique_ptr< GXFTrackStatemakeTrackFindPerigee (const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
std::unique_ptr< TrackmakeTrack (const EventContext &ctx, Cache &, GXFTrajectory &, const ParticleHypothesis) const
void fillResidualsAndErrors (const EventContext &ctx, const Cache &cache, GXFTrajectory &trajectory, const int it, Amg::VectorX &b, int &bremno_maxbrempull, GXFTrackState *&state_maxbrempull) const
void tryToConverge (const Cache &cache, GXFTrajectory &trajectory, const int it) const
void updateSystemWithMaxBremPull (GXFTrajectory &trajectory, const int bremno_maxbrempull, GXFTrackState *state_maxbrempull, Amg::SymMatrixX &a) const
void fillDerivatives (GXFTrajectory &traj) const
FitterStatusCode runIteration (const EventContext &ctx, Cache &cache, GXFTrajectory &trajectory, const int it, Amg::SymMatrixX &a, Amg::VectorX &b, Amg::SymMatrixX &lu, bool &doDeriv) const
FitterStatusCode updateFitParameters (GXFTrajectory &, const Amg::VectorX &, const Amg::SymMatrixX &) const
 Method to update peregee parameters, scattering angles, and brems.
void updatePixelROTs (GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, const EventContext &evtctx) const
 Update the Pixel ROT using the current trajectory/local track parameters.
GXFTrajectoryrunTrackCleanerSilicon (const EventContext &ctx, Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::SymMatrixX &, Amg::VectorX &, bool) const
void runTrackCleanerTRT (Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, Amg::SymMatrixX &, bool, bool, int, const EventContext &ctx) const
PropagationResult calculateTrackParametersPropagateHelper (const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
 Helper method that encapsulates calls to the propagator tool in the calculateTrackParameters() method.
PropagationResult calculateTrackParametersPropagate (const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
 Propagate onto a track state, collecting new track parameters, and optionally the Jacobian and possible holes.
std::vector< std::reference_wrapper< GXFTrackState > > holeSearchStates (GXFTrajectory &trajectory) const
 Extracts a collection of track states which are important for hole search.
std::optional< GlobalChi2Fitter::TrackHoleCountholeSearchProcess (const EventContext &ctx, const std::vector< std::reference_wrapper< GXFTrackState > > &states) const
 Conduct a hole search between a list of states, possibly reusing existing information.
void holeSearchHelper (const std::vector< std::unique_ptr< TrackParameters > > &hc, std::set< Identifier > &id_set, std::set< Identifier > &sct_set, TrackHoleCount &rv, bool count_holes, bool count_dead) const
 Helper method for the hole search that does the actual counting of holes and dead modules.
FitterStatusCode calculateTrackParameters (const EventContext &ctx, GXFTrajectory &, bool) const
std::variant< std::unique_ptr< const TrackParameters >, FitterStatusCodeupdateEnergyLoss (const Surface &, const GXFMaterialEffects &, const TrackParameters &, double, int) const
void calculateTrackErrors (GXFTrajectory &, Amg::SymMatrixX &, bool) const
std::optional< TransportJacobiannumericalDerivatives (const EventContext &ctx, const TrackParameters *, const Surface &, PropDirection, const MagneticFieldProperties &) const
virtual int iterationsOfLastFit () const
virtual void setMinIterations (int)
bool isMuonTrack (const Track &) const
void initFieldCache (const EventContext &ctx, Cache &cache) const
 Initialize a field cache inside a fit cache object.
void throwFailedToGetTrackingGeomtry () const
bool ensureValidEntranceCalo (const EventContext &ctx, Cache &cache) const
bool ensureValidEntranceMuonSpectrometer (const EventContext &ctx, Cache &cache) const
const TrackingGeometrytrackingGeometry (Cache &cache, const EventContext &ctx) const
const TrackingGeometryretrieveTrackingGeometry (const EventContext &ctx) const

Static Private Member Functions

static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionDisc (Cache &cache, const DiscSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
 Find the intersection of a set of track parameters onto a disc surface.
static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionCyl (Cache &cache, const CylinderSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
 Find the intersection of a set of track parameters onto a cylindrical surface.
static void addMaterialGetLayers (Cache &cache, std::vector< std::pair< const Layer *, const Layer * > > &layers, std::vector< std::pair< const Layer *, const Layer * > > &uplayers, const std::vector< std::unique_ptr< GXFTrackState > > &states, GXFTrackState &first, GXFTrackState &last, const TrackParameters *refpar, bool hasmat)
 Collect all possible layers that a given track could have passed through.
static void makeTrackFillDerivativeMatrix (Cache &, GXFTrajectory &)
static void fillFirstLastMeasurement (Cache &cache, GXFTrajectory &trajectory)
static void fillBfromMeasurements (const Cache &cache, GXFTrajectory &trajectory, Amg::VectorX &b)
static void fillAfromMeasurements (const Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
static void fillAfromScatterers (GXFTrajectory &trajectory, Amg::SymMatrixX &a)
static bool tryToWeightAfromMaterial (Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a, const bool doDeriv, const int it, const double oldRedChi2, const double newRedChi2)
static void compensatePhiWeights (Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
static void calculateDerivatives (GXFTrajectory &)
static bool correctAngles (double &, double &)

Private Attributes

ToolHandle< IRIO_OnTrackCreatorm_ROTcreator {this, "RotCreatorTool", "", ""}
ToolHandle< IRIO_OnTrackCreatorm_broadROTcreator {this, "BroadRotCreatorTool", "", ""}
ToolHandle< IUpdatorm_updator {this, "MeasurementUpdateTool", "", ""}
ToolHandle< IExtrapolatorm_extrapolator {this, "ExtrapolationTool", "Trk::Extrapolator/CosmicsExtrapolator", ""}
ToolHandle< IMultipleScatteringUpdatorm_scattool {this, "MultipleScatteringTool", "Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator", ""}
ToolHandle< IEnergyLossUpdatorm_elosstool {this, "EnergyLossTool", "Trk::EnergyLossUpdator/AtlasEnergyLossUpdator", ""}
ToolHandle< IMaterialEffectsUpdatorm_matupdator {this, "MaterialUpdateTool", "", ""}
ToolHandle< IPropagatorm_propagator {this, "PropagatorTool", "", ""}
ToolHandle< INavigatorm_navigator {this, "NavigatorTool", "Trk::Navigator/CosmicsNavigator", ""}
ToolHandle< IResidualPullCalculatorm_residualPullCalculator {this, "ResidualPullCalculatorTool", "Trk::ResidualPullCalculator/ResidualPullCalculator", ""}
ToolHandle< Trk::ITrkMaterialProviderToolm_caloMaterialProvider {this, "CaloMaterialProvider", "Trk::TrkMaterialProviderTool/TrkMaterialProviderTool", ""}
ToolHandle< IMaterialEffectsOnTrackProviderm_calotool {this, "MuidTool", "Rec::MuidMaterialEffectsOnTrackProvider/MuidMaterialEffectsOnTrackProvider", ""}
ToolHandle< IMaterialEffectsOnTrackProviderm_calotoolparam {this, "MuidToolParam", "", ""}
ToolHandle< IBoundaryCheckToolm_boundaryCheckTool {this, "BoundaryCheckTool", "", "Boundary checking tool for detector sensitivities" }
SG::ReadCondHandleKey< TrackingGeometrym_trackingGeometryReadKey
SG::ReadCondHandleKey< AtlasFieldCacheCondObjm_field_cache_key
const AtlasDetectorIDm_DetID = nullptr
Gaudi::Property< bool > m_signedradius {this, "SignedDriftRadius", true}
Gaudi::Property< bool > m_calomat {this, "MuidMat", false}
Gaudi::Property< bool > m_extmat {this, "ExtrapolatorMaterial", true}
Gaudi::Property< bool > m_fillderivmatrix {this, "FillDerivativeMatrix", false}
Gaudi::Property< bool > m_straightlineprop {this, "StraightLine", true}
Gaudi::Property< bool > m_extensioncuts {this, "TRTExtensionCuts", true}
Gaudi::Property< bool > m_sirecal {this, "RecalibrateSilicon", false}
Gaudi::Property< bool > m_trtrecal {this, "RecalibrateTRT", false}
Gaudi::Property< bool > m_kinkfinding {this, "KinkFinding", false}
Gaudi::Property< bool > m_decomposesegments {this, "DecomposeSegments", true}
Gaudi::Property< bool > m_getmaterialfromtrack {this, "GetMaterialFromTrack", true}
Gaudi::Property< bool > m_domeastrackpar {this, "MeasuredTrackParameters", true}
Gaudi::Property< bool > m_storemat {this, "StoreMaterialOnTrack", true}
Gaudi::Property< bool > m_redoderivs {this, "RecalculateDerivatives", false}
Gaudi::Property< bool > m_reintoutl {this, "ReintegrateOutliers", false}
Gaudi::Property< bool > m_acceleration {this, "Acceleration", false}
Gaudi::Property< bool > m_numderiv {this, "NumericalDerivs", false}
Gaudi::Property< bool > m_fiteloss {this, "FitEnergyLoss", false}
Gaudi::Property< bool > m_asymeloss {this, "AsymmetricEnergyLoss", true}
Gaudi::Property< bool > m_useCaloTG {this, "UseCaloTG", false}
Gaudi::Property< bool > m_rejectLargeNScat {this, "RejectLargeNScat", false}
Gaudi::Property< bool > m_createSummary {this, "CreateTrackSummary", true}
Gaudi::Property< bool > m_holeSearch {this, "DoHoleSearch", false}
Gaudi::Property< double > m_outlcut {this, "OutlierCut", 5.0}
Gaudi::Property< double > m_p {this, "Momentum", 0.0}
Gaudi::Property< double > m_chi2cut {this, "TrackChi2PerNDFCut", 1.e15}
Gaudi::Property< double > m_scalefactor {this, "TRTTubeHitCut", 2.5}
Gaudi::Property< double > m_minphfcut {this, "MinPHFCut", 0.}
Gaudi::Property< int > m_maxoutliers {this, "MaxOutliers", 10}
Gaudi::Property< int > m_maxit {this, "MaxIterations", 30}
Gaudi::Property< int > m_miniter {this, "MinimumIterations", 1}
Gaudi::Property< int > m_fixbrem {this, "FixBrem", -1}
Gaudi::Property< int > m_maxitPixelROT {this, "IterationsToRebuildPixelRots", 0}
SG::ReadHandleKey< Trk::ClusterSplitProbabilityContainerm_clusterSplitProbContainer {this, "ClusterSplitProbabilityName", "",""}
Trk::Volume m_idVolume
std::array< std::atomic< unsigned int >, S_MAX_VALUE > m_fit_status ATLAS_THREAD_SAFE = {}

Detailed Description

Definition at line 156 of file GlobalChi2Fitter.h.

Member Enumeration Documentation

◆ FitterStatusType

Enumerator
S_FITS 
S_SUCCESSFUL_FITS 
S_MAT_INV_FAIL 
S_NOT_ENOUGH_MEAS 
S_PROPAGATION_FAIL 
S_INVALID_ANGLES 
S_NOT_CONVERGENT 
S_HIGH_CHI2 
S_LOW_MOMENTUM 
S_MAX_VALUE 

Definition at line 176 of file GlobalChi2Fitter.h.

Constructor & Destructor Documentation

◆ GlobalChi2Fitter()

Trk::GlobalChi2Fitter::GlobalChi2Fitter ( const std::string & t,
const std::string & n,
const IInterface * p )

Definition at line 200 of file GlobalChi2Fitter.cxx.

204 :
205 base_class(t, n, p),
206 m_idVolume(nullptr, std::make_shared<Trk::CylinderVolumeBounds>(560, 2750))
207 {
208 }

◆ ~GlobalChi2Fitter()

Trk::GlobalChi2Fitter::~GlobalChi2Fitter ( )
virtualdefault

Member Function Documentation

◆ addIDMaterialFast()

void Trk::GlobalChi2Fitter::addIDMaterialFast ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & track,
const TrackParameters * parameters,
ParticleHypothesis part ) const
private

A faster strategy for adding scatter material to tracks, works only for inner detector tracks.

For every track, we need to add its scatterers. That is to say, we need to determine which bits of non-active material the particle in question may have passed through and add them to the track. This is generally an expensive operation, but we can cut some corners if the track only consists of inner detector hits. Specifically, we can exploit the layer structure of the detector to find possible material hits more quickly and efficiently than using the standard material adding algorithm, which is addMaterial.

Parameters
[in,out]cacheGeneral cache object, as used everywhere.
[in,out]trajectoryThe current state of the track, respresented in the fitter's internal track representation. States may be added to this.
[in]parametersStarting parameters for the material addition step.
[in]partStandard representation of particle type, used to determine the behaviour of the particle as it traverses materials.

Definition at line 3465 of file GlobalChi2Fitter.cxx.

3471 {
3472 /*
3473 * Ensure that the cache contains a valid tracking geometry that we can
3474 * use.
3475 */
3476 const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3477 if (!caloEntranceIsValid) {
3478 return;
3479 }
3480
3481 /*
3482 * If we have not yet set the discs on either side of the detector as well
3483 * as the barrel layers, do so now.
3484 */
3485 if (
3486 cache.m_negdiscs.empty() &&
3487 cache.m_posdiscs.empty() &&
3488 cache.m_barrelcylinders.empty()
3489 ) {
3490 /*
3491 * Attempt to add the layer information to the cache using the previously
3492 * selected tracking volume.
3493 */
3494 const bool ok = processTrkVolume(cache, cache.m_caloEntrance);
3495
3496 /*
3497 * If this process somehow fails, we cannot use the fast material adding
3498 * algorithm and we must fall back to the slow version. As far as I know
3499 * this doesn't really happen.
3500 */
3501 if (!ok) {
3502 ATH_MSG_DEBUG("Falling back to slow material collection");
3503 cache.m_fastmat = false;
3504 addMaterial(ctx, cache, trajectory, refpar2, matEffects);
3505 return;
3506 }
3507
3508 /*
3509 * Sort the discs and barrel layers such that they are in the right
3510 * order. What the right order is in this case is defined a bit above
3511 * this code, in the GXF::LayerSort2 class. Should be in increasing order
3512 * of distance from the detector center.
3513 */
3514 std::stable_sort(cache.m_negdiscs.begin(), cache.m_negdiscs.end(), GXF::LayerSort2());
3515 std::stable_sort(cache.m_posdiscs.begin(), cache.m_posdiscs.end(), GXF::LayerSort2());
3516 std::stable_sort(cache.m_barrelcylinders.begin(), cache.m_barrelcylinders.end(), GXF::LayerSort2());
3517 }
3518
3519 const TrackParameters *refpar = refpar2;
3520 bool hasmat = false;
3521 int indexoffset = 0;
3522 int lastmatindex = 0;
3523 std::vector<std::unique_ptr<GXFTrackState>> & oldstates = trajectory.trackStates();
3524
3525 GXFTrackState *firstsistate = nullptr;
3526 GXFTrackState *lastsistate = nullptr;
3527
3528 /*
3529 * This loop serves several purposes in one, because it's very efficient:
3530 *
3531 * 1. It detects whether there are already any materials on this track, and
3532 * if so where they are.
3533 * 2. It determines what the first and last silicon hits are.
3534 * 3. It calculates trackparameters for any states that might not have them
3535 * for whatever reason.
3536 */
3537 for (int i = 0; i < (int) oldstates.size(); i++) {
3538 if (oldstates[i]->materialEffects() != nullptr) {
3539 hasmat = true;
3540 lastmatindex = i;
3541 }
3542
3543 if (
3544 oldstates[i]->measurementType() == TrackState::Pixel ||
3545 oldstates[i]->measurementType() == TrackState::SCT
3546 ) {
3547 if (firstsistate == nullptr) {
3548 if (oldstates[i]->trackParameters() == nullptr) {
3549 std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3550 ctx,
3551 *refpar,
3552 oldstates[i]->associatedSurface(),
3554 false,
3555 trajectory.m_fieldprop,
3557 ));
3558
3559 if (tmppar == nullptr) return;
3560
3561 oldstates[i]->setTrackParameters(std::move(tmppar));
3562 }
3563 firstsistate = oldstates[i].get();
3564 }
3565 lastsistate = oldstates[i].get();
3566 }
3567 }
3568
3569 /*
3570 * Only happens when there are no tracks, and that shouldn't happen in the
3571 * first place.
3572 */
3573 if (lastsistate == nullptr) {
3574 throw std::logic_error("No track state");
3575 }
3576
3577 /*
3578 * Also try to generate a set of track parameters for the last silicon hit
3579 * if it doesn't have any. I don't really know when that would happen, but
3580 * I suppose it's possible. Anything is possible, if you believe hard
3581 * enough.
3582 */
3583 if (lastsistate->trackParameters() == nullptr) {
3584 std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
3585 ctx,
3586 *refpar,
3587 lastsistate->associatedSurface(),
3588 alongMomentum, false,
3589 trajectory.m_fieldprop,
3591 ));
3592
3593 if (tmppar == nullptr) return;
3594
3595 lastsistate->setTrackParameters(std::move(tmppar));
3596 }
3597
3598 /*
3599 * If we have found any materials on the track, we've presumably already
3600 * done a fit for that part of the track, so the reference parameters are
3601 * either the first or last silicon state's parameters.
3602 */
3603 if (hasmat) {
3604 refpar = lastsistate->trackParameters();
3605 indexoffset = lastmatindex;
3606 } else {
3607 refpar = firstsistate->trackParameters();
3608 }
3609
3610 /*
3611 * These vectors will hold the layers. The types here are a little bit
3612 * strange, but the idea is that the right member is a disc surface and the
3613 * left member is a cylindrical surface. Could be more elegantly done using
3614 * polymorphism.
3615 *
3616 * The upstream layers may already be filled due to previous fits.
3617 *
3618 * TODO: Use polymorphism to get rid of these strange types.
3619 */
3620 std::vector<std::pair<const Layer *, const Layer *>> layers;
3621 std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = trajectory.upstreamMaterialLayers();
3622
3623 /*
3624 * Fill the aforementioned layer vectors with layers.
3625 */
3626 addMaterialGetLayers(cache, layers, upstreamlayers, oldstates, *firstsistate, *lastsistate, refpar, hasmat);
3627
3628 /*
3629 * Finally, use that layer information to actually add states to the track.
3630 */
3631 addMaterialUpdateTrajectory(cache, trajectory, indexoffset, layers, refpar, refpar2, matEffects);
3632 }
#define ATH_MSG_DEBUG(x)
bool processTrkVolume(Cache &, const Trk::TrackingVolume *tvol) const
ToolHandle< IPropagator > m_propagator
void addMaterial(const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters *, ParticleHypothesis) const
bool ensureValidEntranceCalo(const EventContext &ctx, Cache &cache) const
static void addMaterialGetLayers(Cache &cache, std::vector< std::pair< const Layer *, const Layer * > > &layers, std::vector< std::pair< const Layer *, const Layer * > > &uplayers, const std::vector< std::unique_ptr< GXFTrackState > > &states, GXFTrackState &first, GXFTrackState &last, const TrackParameters *refpar, bool hasmat)
Collect all possible layers that a given track could have passed through.
void addMaterialUpdateTrajectory(Cache &cache, GXFTrajectory &track, int offset, std::vector< std::pair< const Layer *, const Layer * > > &layers, const TrackParameters *ref1, const TrackParameters *ref2, ParticleHypothesis mat) const
Given layer information, probe those layers for scatterers and add them to a track.
layers(flags, cells_name, *args, **kw)
Here we define wrapper functions to set up all of the standard corrections.
@ alongMomentum
ParametersBase< TrackParametersDim, Charged > TrackParameters
void stable_sort(DataModel_detail::iterator< DVL > beg, DataModel_detail::iterator< DVL > end)
Specialization of stable_sort for DataVector/List.

◆ addMaterial()

void Trk::GlobalChi2Fitter::addMaterial ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & trajectory,
const TrackParameters * refpar2,
ParticleHypothesis matEffects ) const
private

Definition at line 3634 of file GlobalChi2Fitter.cxx.

3640 {
3641 if (refpar2 == nullptr) {
3642 return;
3643 }
3644 const MeasurementBase *firstmuonhit = nullptr;
3645 const MeasurementBase *lastmuonhit = nullptr;
3646 const MeasurementBase *firstidhit =
3647 nullptr;
3648 const MeasurementBase *lastidhit = nullptr;
3649 const MeasurementBase *firsthit = nullptr;
3650 const MeasurementBase *lasthit = nullptr;
3651 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
3652 std::vector<std::unique_ptr<GXFTrackState>> matstates;
3653 std::unique_ptr< const std::vector < const TrackStateOnSurface *>,
3654 void (*)(const std::vector<const TrackStateOnSurface *> *) >
3656 bool matvec_used=false;
3657 std::unique_ptr<TrackParameters> startmatpar1;
3658 std::unique_ptr<TrackParameters> startmatpar2;
3659 const TrackParameters *firstidpar = nullptr;
3660 const TrackParameters *lastidpar = nullptr;
3661 const TrackParameters *firstsiliconpar = nullptr;
3662 const TrackParameters *lastsiliconpar = nullptr;
3663 const TrackParameters *firstmatpar = nullptr;
3664 const TrackParameters *firstcalopar = nullptr;
3665 const TrackParameters *lastcalopar = nullptr;
3666 const TrackParameters *firstmuonpar = nullptr;
3667 const TrackParameters *lastmuonpar = nullptr;
3668
3669 int npseudomuon1 = 0;
3670 int npseudomuon2 = 0;
3671
3672 for (auto & state : states) {
3673 TrackState::MeasurementType const meastype = state->measurementType();
3674 const TrackParameters *tp = state->trackParameters();
3675 GXFMaterialEffects *meff = state->materialEffects();
3676
3677 if (meastype == TrackState::Pseudo) {
3678 if (firstidhit == nullptr) {
3679 npseudomuon1++;
3680 } else {
3681 npseudomuon2++;
3682 }
3683 continue;
3684 }
3685
3686 if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
3687 if (firsthit == nullptr) {
3688 firsthit = state->measurement();
3689 if (cache.m_acceleration) {
3690 if (tp == nullptr) {
3691 tp = m_extrapolator->extrapolate(
3692 ctx,
3693 *refpar2,
3694 state->associatedSurface(),
3696 false,
3697 matEffects
3698 ).release();
3699
3700 if (tp == nullptr) {
3701 return;
3702 }
3703
3704 state->setTrackParameters(std::unique_ptr<const TrackParameters>(tp));
3705 }
3706 // When acceleration is enabled, material collection starts from first hit
3707 refpar2 = tp;
3708 }
3709 }
3710 lasthit = state->measurement();
3711 if (
3712 meastype == TrackState::Pixel ||
3713 meastype == TrackState::SCT ||
3714 meastype == TrackState::TRT
3715 ) {
3716 if (firstidhit == nullptr) {
3717 firstidhit = state->measurement();
3718 }
3719
3720 if ((firstidpar == nullptr) && (tp != nullptr)) {
3721 firstidpar = tp;
3722 }
3723
3724 lastidhit = state->measurement();
3725 if (tp != nullptr) {
3726 lastidpar = tp;
3727 }
3728
3729 if ((tp != nullptr) && meastype != TrackState::TRT) {
3730 if (firstsiliconpar == nullptr) {
3731 firstsiliconpar = tp;
3732 }
3733 lastsiliconpar = tp;
3734 }
3735 }
3736
3737 if (
3738 meastype == TrackState::RPC ||
3739 meastype == TrackState::CSC ||
3740 meastype == TrackState::TGC ||
3741 meastype == TrackState::MDT ||
3742 meastype == TrackState::MM ||
3743 meastype == TrackState::STGC
3744 ) {
3745 if (firstmuonhit == nullptr) {
3746 firstmuonhit = state->measurement();
3747 if (tp != nullptr) {
3748 firstmuonpar = tp;
3749 }
3750 }
3751 lastmuonhit = state->measurement();
3752 if (tp != nullptr) {
3753 lastmuonpar = tp;
3754 }
3755 }
3756 }
3757 if (state->getStateType(TrackStateOnSurface::Scatterer) || state->getStateType(TrackStateOnSurface::BremPoint)) {
3758 if (meff->deltaE() == 0) {
3759 if (firstcalopar == nullptr) {
3760 firstcalopar = state->trackParameters();
3761 }
3762 lastcalopar = state->trackParameters();
3763 }
3764 if (firstmatpar == nullptr) {
3765 firstmatpar = state->trackParameters();
3766 }
3767 }
3768 }
3769
3770 std::unique_ptr<TrackParameters> refpar;
3771 AmgVector(5) newpars = refpar2->parameters();
3772
3773 if (trajectory.m_straightline && m_p != 0) {
3774 newpars[Trk::qOverP] = 1 / m_p;
3775 }
3776
3777 refpar = refpar2->associatedSurface().createUniqueTrackParameters(
3778 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3779 );
3780
3781 if (firstmatpar != nullptr) {
3782 startmatpar1 = unique_clone(firstsiliconpar);
3783 startmatpar2 = unique_clone(lastsiliconpar);
3784 }
3785
3786 if ((startmatpar1 == nullptr) || ((firstidhit != nullptr) && (firstmuonhit != nullptr))) {
3787 startmatpar1 = unique_clone(refpar);
3788 startmatpar2 = unique_clone(refpar);
3789
3790 const double mass = trajectory.mass();
3791 if (mass > 200 * MeV) {
3792 const AmgVector(5) & newpars = startmatpar2->parameters();
3793 const double oldp = std::abs(1 / newpars[Trk::qOverP]);
3794 const double sign = (newpars[Trk::qOverP] < 0) ? -1 : 1;
3795
3796 startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3797 newpars[0], newpars[1], newpars[2], newpars[3],
3798 sign / std::sqrt(oldp * oldp + 2 * 100 * MeV * std::sqrt(oldp * oldp + mass * mass) + 100 * MeV * 100 * MeV),
3799 std::nullopt
3800 );
3801 }
3802 } else if (trajectory.m_straightline && m_p != 0) {
3803 AmgVector(5) newpars = startmatpar1->parameters();
3804 newpars[Trk::qOverP] = 1 / m_p;
3805
3806 startmatpar1 = startmatpar1->associatedSurface().createUniqueTrackParameters(
3807 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3808 );
3809
3810 newpars = startmatpar2->parameters();
3811 newpars[Trk::qOverP] = 1 / m_p;
3812
3813 startmatpar2 = startmatpar2->associatedSurface().createUniqueTrackParameters(
3814 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
3815 );
3816 }
3817
3818 if ((firstidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3819
3820 const DistanceSolution distsol = firstidhit->associatedSurface().straightLineDistanceEstimate(
3821 refpar->position(),
3822 refpar->momentum().unit()
3823 );
3824
3825 const double distance = getDistance(distsol);
3826
3827 if (distance < 0 && distsol.numberOfSolutions() > 0 && !cache.m_acceleration) {
3828 ATH_MSG_DEBUG("Obtaining upstream layers from Extrapolator");
3829
3830 const Surface *destsurf = &firstidhit->associatedSurface();
3831 std::unique_ptr<const TrackParameters> tmppar;
3832
3833 if (firstmuonhit != nullptr) {
3834 const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3835 if (caloEntranceIsValid) {
3836 tmppar = m_extrapolator->extrapolateToVolume(ctx,
3837 *startmatpar1,
3838 *cache.m_caloEntrance,
3839 oppositeMomentum,
3840 Trk::nonInteracting);
3841
3842 if (tmppar != nullptr) {
3843 destsurf = &tmppar->associatedSurface();
3844 }
3845 }
3846 }
3847
3848 if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3849 matvec.reset( m_extrapolator->extrapolateM(ctx,
3850 *startmatpar1,
3851 *destsurf,
3853 false, matEffects) );
3854 matvec_used=false;
3855
3856 if (matvec && !matvec->empty()) {
3857 for (int i = (int)matvec->size() - 1; i > -1; i--) {
3858 const MaterialEffectsBase *meb = (*matvec)[i]->materialEffectsOnTrack();
3859 if (meb) {
3860 if (meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) {
3861 const MaterialEffectsOnTrack *meot = static_cast < const MaterialEffectsOnTrack * >(meb);
3862 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3863 const TrackParameters * newpars = (*matvec)[i]->trackParameters() != nullptr ? (*matvec)[i]->trackParameters()->clone() : nullptr;
3864 meff->setSigmaDeltaE(0);
3865 matstates.push_back(std::make_unique<GXFTrackState>(
3866 std::move(meff),
3867 std::unique_ptr<const TrackParameters>(newpars)
3868 ));
3869 matvec_used=true;
3870 }
3871 }
3872 }
3873 }
3874 }
3875 }
3876
3877 if ((lastidhit != nullptr) && trajectory.numberOfSiliconHits() > 0 && cache.m_idmat) {
3878 const DistanceSolution distsol = lastidhit->associatedSurface().straightLineDistanceEstimate(
3879 refpar->position(),
3880 refpar->momentum().unit()
3881 );
3882
3883 const double distance = getDistance(distsol);
3884
3885 if (distance > 0 && distsol.numberOfSolutions() > 0) {
3886 ATH_MSG_DEBUG("Obtaining downstream ID layers from Extrapolator");
3887 const Surface *destsurf = &lastidhit->associatedSurface();
3888 std::unique_ptr<const TrackParameters> tmppar;
3889 std::unique_ptr<Surface> calosurf;
3890 if (firstmuonhit != nullptr) {
3891 const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
3892 if (caloEntranceIsValid) {
3893 tmppar = m_extrapolator->extrapolateToVolume(ctx,
3894 *startmatpar2,
3895 *cache.m_caloEntrance,
3898 }
3899
3900 if (tmppar != nullptr) {
3901 const CylinderSurface *cylcalosurf = nullptr;
3902
3903 if (tmppar->associatedSurface().type() == Trk::SurfaceType::Cylinder)
3904 cylcalosurf = static_cast<const CylinderSurface *>(&tmppar->associatedSurface());
3905
3906 const DiscSurface *disccalosurf = nullptr;
3907
3908 if (tmppar->associatedSurface().type() == Trk::SurfaceType::Disc)
3909 disccalosurf = static_cast<const DiscSurface *>(&tmppar->associatedSurface());
3910
3911 if (cylcalosurf != nullptr) {
3912 Amg::Transform3D const trans = Amg::Transform3D(cylcalosurf->transform());
3913 const CylinderBounds & cylbounds = cylcalosurf->bounds();
3914 const double radius = cylbounds.r();
3915 const double hlength = cylbounds.halflengthZ();
3916 calosurf = std::make_unique<CylinderSurface>(trans, radius - 1, hlength);
3917 } else if (disccalosurf != nullptr) {
3918 const double newz = (
3919 disccalosurf->center().z() > 0 ?
3920 disccalosurf->center().z() - 1 :
3921 disccalosurf->center().z() + 1
3922 );
3923
3924 const Amg::Vector3D newpos(
3925 disccalosurf->center().x(),
3926 disccalosurf->center().y(),
3927 newz
3928 );
3929
3930 Amg::Transform3D trans = (disccalosurf->transform());
3931 trans.translation() << newpos;
3932
3933 const DiscBounds *discbounds = static_cast<const DiscBounds *>(&disccalosurf->bounds());
3934 const double rmin = discbounds->rMin();
3935 const double rmax = discbounds->rMax();
3936 calosurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
3937 }
3938 destsurf = calosurf.release();
3939 }
3940 }
3941
3942 if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
3943 matvec.reset(m_extrapolator->extrapolateM(
3944 ctx, *startmatpar2, *destsurf, alongMomentum, false, matEffects));
3945 matvec_used = false;
3946
3947 if (matvec && !matvec->empty()) {
3948 for (const auto & i : *matvec) {
3949 const Trk::MaterialEffectsBase * meb = i->materialEffectsOnTrack();
3950
3951 if (meb) {
3953 const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
3954 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
3955 if (cache.m_fiteloss && (meot->energyLoss() != nullptr)) {
3956 meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
3957 }
3958
3959 if (matEffects == electron && cache.m_asymeloss) {
3960 meff->setDeltaE(-5);
3961
3962 if (trajectory.numberOfTRTHits() == 0) {
3963 meff->setScatteringSigmas(0, 0);
3964 }
3965
3966 meff->setSigmaDeltaE(50);
3967 }
3968
3969 const TrackParameters * newparams = i->trackParameters() != nullptr ? i->trackParameters()->clone() : nullptr;
3970
3971 matstates.push_back(std::make_unique<GXFTrackState>(
3972 std::move(meff),
3973 std::unique_ptr<const TrackParameters>(newparams)
3974 ));
3975 matvec_used=true;
3976 }
3977 }
3978 }
3979 } else {
3980 ATH_MSG_WARNING("No material layers collected from Extrapolator");
3981 }
3982 }
3983 }
3984
3985 if (cache.m_calomat && (firstmuonhit != nullptr) && (firstidhit != nullptr)) {
3986 const IPropagator *prop = &*m_propagator;
3987
3988 std::vector<MaterialEffectsOnTrack> calomeots = m_calotool->extrapolationSurfacesAndEffects(
3989 *m_navigator->highestVolume(ctx),
3990 *prop,
3991 *lastidpar,
3992 firstmuonhit->associatedSurface(),
3994 muon
3995 );
3996
3997 if (calomeots.empty()) {
3998 ATH_MSG_WARNING("No material layers collected in calorimeter");
3999 return;
4000 }
4001
4002 std::unique_ptr<const TrackParameters> prevtrackpars = unique_clone(lastidpar);
4003 if (lasthit == lastmuonhit) {
4004 for (int i = 0; i < (int) calomeots.size(); i++) {
4005 const PropDirection propdir = alongMomentum;
4006
4007 std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4008 ctx,
4009 *prevtrackpars,
4010 calomeots[i].associatedSurface(),
4011 propdir,
4012 false,
4013 trajectory.m_fieldprop,
4015 ));
4016
4017 if (layerpar == nullptr) {
4018 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4019 return;
4020 }
4021
4022 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4023
4024 if (i == 2) {
4025 lastcalopar = layerpar.get();
4026 }
4027
4028 if (i == 1) {
4029 const double qoverp = layerpar->parameters()[Trk::qOverP];
4030 double qoverpbrem = 0;
4031
4032 if (
4033 npseudomuon2 < 2 &&
4034 (firstmuonpar != nullptr) &&
4035 std::abs(firstmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4036 ) {
4037 qoverpbrem = firstmuonpar->parameters()[Trk::qOverP];
4038 } else {
4039 const double sign = (qoverp > 0) ? 1 : -1;
4040 qoverpbrem = sign / (1 / std::abs(qoverp) - std::abs(calomeots[i].energyLoss()->deltaE()));
4041 }
4042
4043 const AmgVector(5) & newpar = layerpar->parameters();
4044
4045 layerpar = layerpar->associatedSurface().createUniqueTrackParameters(
4046 newpar[0], newpar[1], newpar[2], newpar[3], qoverpbrem, std::nullopt
4047 );
4048 meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4049 }
4050
4051 matstates.push_back(std::make_unique<GXFTrackState>(
4052 std::move(meff),
4053 std::unique_ptr<const TrackParameters>(layerpar != nullptr ? layerpar->clone() : nullptr)
4054 ));
4055 prevtrackpars = std::move(layerpar);
4056 }
4057 }
4058
4059 if (
4060 firsthit == firstmuonhit &&
4061 (!cache.m_getmaterialfromtrack || lasthit == lastidhit)
4062 ) {
4063 prevtrackpars = unique_clone(firstidpar);
4064 for (int i = 0; i < (int) calomeots.size(); i++) {
4065 const PropDirection propdir = oppositeMomentum;
4066 std::unique_ptr<const TrackParameters> layerpar(m_propagator->propagateParameters(
4067 ctx,
4068 *prevtrackpars,
4069 calomeots[i].associatedSurface(),
4070 propdir,
4071 false,
4072 trajectory.m_fieldprop,
4074 ));
4075
4076 if (layerpar == nullptr) {
4077 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4078 return;
4079 }
4080
4081 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(calomeots[i]);
4082
4083 if (i == 2) {
4084 firstcalopar = unique_clone(layerpar.get()).release();
4085 }
4086
4087 prevtrackpars = unique_clone(layerpar.get());
4088
4089 if (i == 1) {
4090 const double qoverpbrem = layerpar->parameters()[Trk::qOverP];
4091 double qoverp = 0;
4092
4093 if (
4094 npseudomuon1 < 2 &&
4095 (lastmuonpar != nullptr) &&
4096 std::abs(lastmuonpar->parameters()[Trk::qOverP]) > 1.e-9
4097 ) {
4098 qoverp = lastmuonpar->parameters()[Trk::qOverP];
4099 } else {
4100 const double sign = (qoverpbrem > 0) ? 1 : -1;
4101 qoverp = sign / (1 / std::abs(qoverpbrem) + std::abs(calomeots[i].energyLoss()->deltaE()));
4102 }
4103
4104 meff->setdelta_p(1000 * (qoverpbrem - qoverp));
4105 const AmgVector(5) & newpar = layerpar->parameters();
4106
4107 prevtrackpars = layerpar->associatedSurface().createUniqueTrackParameters(
4108 newpar[0], newpar[1], newpar[2], newpar[3], qoverp, std::nullopt
4109 );
4110 }
4111
4112 matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(std::move(meff), std::move(layerpar)));
4113 }
4114 }
4115 }
4116
4117 if (lasthit == lastmuonhit && cache.m_extmat) {
4118 std::unique_ptr<const Trk::TrackParameters> muonpar1;
4119
4120 if (lastcalopar != nullptr) {
4121 const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4122 if (msEntranceIsValid) {
4123 if (cache.m_msEntrance->inside(lastcalopar->position())) {
4124 muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4125 *lastcalopar,
4126 *cache.m_msEntrance,
4129
4130 if (muonpar1 != nullptr) {
4131 const Amg::Vector3D trackdir = muonpar1->momentum().unit();
4132 const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4133 const Amg::Vector3D curvU = curvZcrossT.unit();
4134 const Amg::Vector3D curvV = trackdir.cross(curvU);
4135 Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4136 rot.col(0) = curvU;
4137 rot.col(1) = curvV;
4138 rot.col(2) = trackdir;
4139 Amg::Transform3D trans;
4140 trans.linear().matrix() << rot;
4141 trans.translation() << muonpar1->position() - .1 * trackdir;
4142 PlaneSurface const curvlinsurf(trans);
4143
4144 std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4145 ctx,
4146 *muonpar1,
4147 curvlinsurf,
4150 ));
4151
4152 if (curvlinpar != nullptr) {
4153 muonpar1 = std::move(curvlinpar);
4154 }
4155 }
4156 } else {
4157 muonpar1 = std::unique_ptr<TrackParameters>(lastcalopar->clone());
4158 }
4159 }
4160 } else {
4161 muonpar1 = std::unique_ptr<TrackParameters>(refpar->clone());
4162 }
4163
4164 DistanceSolution distsol;
4165
4166 if (muonpar1 != nullptr) {
4167 distsol = lastmuonhit->associatedSurface().straightLineDistanceEstimate(
4168 muonpar1->position(),
4169 muonpar1->momentum().unit()
4170 );
4171 }
4172
4173 double distance = getDistance(distsol);
4174
4175 if ((distance > 0) and(distsol.numberOfSolutions() >
4176 0) and (firstmuonhit != nullptr)) {
4177 distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4178 muonpar1->position(),
4179 muonpar1->momentum().unit()
4180 );
4181
4182 distance = 0;
4183
4184 if (distsol.numberOfSolutions() == 1) {
4185 distance = distsol.first();
4186 } else if (distsol.numberOfSolutions() == 2) {
4187 distance = (
4188 std::abs(distsol.first()) < std::abs(distsol.second()) ?
4189 distsol.first() :
4190 distsol.second()
4191 );
4192 }
4193
4194 if (distance < 0 && distsol.numberOfSolutions() > 0 && (firstidhit == nullptr)) {
4195 if (firstmuonpar != nullptr) {
4196 AmgVector(5) newpars = firstmuonpar->parameters();
4197
4198 if (trajectory.m_straightline && m_p != 0) {
4199 newpars[Trk::qOverP] = 1 / m_p;
4200 }
4201
4202 muonpar1 = firstmuonpar->associatedSurface().createUniqueTrackParameters(
4203 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4204 );
4205 } else {
4206 std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4207 ctx,
4208 *muonpar1,
4209 firstmuonhit->associatedSurface(),
4211 false,
4212 trajectory.m_fieldprop,
4214 ));
4215
4216 if (tmppar != nullptr) {
4217 muonpar1 = std::move(tmppar);
4218 }
4219 }
4220 }
4221
4222 const TrackParameters *prevtp = muonpar1.get();
4223 ATH_MSG_DEBUG("Obtaining downstream layers from Extrapolator");
4224 if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4225 matvec.reset(m_extrapolator->extrapolateM(ctx,
4226 *prevtp,
4227 states.back()->associatedSurface(),
4229 false,
4231 matvec_used = false;
4232
4233 if (matvec && matvec->size() > 1000 && m_rejectLargeNScat) {
4234 ATH_MSG_DEBUG("too many scatterers: " << matvec->size());
4235 return;
4236 }
4237
4238 if (matvec && !matvec->empty()) {
4239 for (int j = 0; j < (int) matvec->size(); j++) {
4240 const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4241
4242 if (meb) {
4243 if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) and (j < (int) matvec->size() - 1)) {
4244 const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4245 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4246
4247 if (
4248 !trajectory.m_straightline &&
4249 (meot->energyLoss() != nullptr) &&
4250 std::abs(meff->deltaE()) > 25 &&
4251 std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4252 ) {
4253 meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4254 }
4255
4256 const TrackParameters * newparams = (*matvec)[j]->trackParameters() != nullptr ? (*matvec)[j]->trackParameters()->clone() : nullptr;
4257
4258 matstates.push_back(std::make_unique<GXFTrackState>(
4259 std::move(meff),
4260 std::unique_ptr<const TrackParameters>(newparams)
4261 ));
4262 matvec_used=true;
4263 }
4264 }
4265 }
4266 }
4267 }
4268 }
4269
4270 if (firsthit == firstmuonhit && cache.m_extmat && (firstcalopar != nullptr)) {
4271 std::unique_ptr<const Trk::TrackParameters> muonpar1;
4272
4273 const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
4274 if (msEntranceIsValid) {
4275 if (cache.m_msEntrance->inside(firstcalopar->position())) {
4276 muonpar1 = m_extrapolator->extrapolateToVolume(ctx,
4277 *firstcalopar,
4278 *cache.m_msEntrance,
4281
4282 if (muonpar1 != nullptr) {
4283 const Amg::Vector3D trackdir = muonpar1->momentum().unit();
4284 const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
4285 const Amg::Vector3D curvU = curvZcrossT.unit();
4286 const Amg::Vector3D curvV = trackdir.cross(curvU);
4287 Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
4288 rot.col(0) = curvU;
4289 rot.col(1) = curvV;
4290 rot.col(2) = trackdir;
4291 Amg::Transform3D trans;
4292 trans.linear().matrix() << rot;
4293 trans.translation() << muonpar1->position() - .1 * trackdir;
4294 const PlaneSurface curvlinsurf(trans);
4295
4296 std::unique_ptr<const TrackParameters> curvlinpar(m_extrapolator->extrapolateDirectly(
4297 ctx,
4298 *muonpar1,
4299 curvlinsurf,
4302 ));
4303
4304 if (curvlinpar != nullptr) {
4305 muonpar1 = std::move(curvlinpar);
4306 }
4307 }
4308 } else {
4309 muonpar1 = std::unique_ptr<const TrackParameters>(firstcalopar->clone());
4310 }
4311 }
4312
4313 DistanceSolution distsol;
4314
4315 if (muonpar1 != nullptr) {
4316 distsol = firstmuonhit->associatedSurface().straightLineDistanceEstimate(
4317 muonpar1->position(),
4318 muonpar1->momentum().unit()
4319 );
4320 }
4321
4322 const double distance = getDistance(distsol);
4323
4324 if (distance < 0 && distsol.numberOfSolutions() > 0) {
4325 const TrackParameters *prevtp = muonpar1.get();
4326 ATH_MSG_DEBUG("Collecting upstream muon material from extrapolator");
4327 if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4328 matvec.reset(m_extrapolator->extrapolateM(ctx,
4329 *prevtp,
4330 states[0]->associatedSurface(),
4332 false,
4334 matvec_used = false;
4335
4336 if (matvec && !matvec->empty()) {
4337 ATH_MSG_DEBUG("Retrieved " << matvec->size() << " material states");
4338
4339 for (int j = 0; j < (int) matvec->size(); j++) {
4340 const MaterialEffectsBase *meb = (*matvec)[j]->materialEffectsOnTrack();
4341
4342 if (meb != nullptr) {
4343
4344
4345 if ((meb->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK) && j < (int) matvec->size() - 1) {
4346 const MaterialEffectsOnTrack *meot = static_cast<const MaterialEffectsOnTrack *>(meb);
4347 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>(*meot);
4348
4349 if (
4350 !trajectory.m_straightline &&
4351 (meot->energyLoss() != nullptr) &&
4352 std::abs(meff->deltaE()) > 25 &&
4353 std::abs((*matvec)[j]->trackParameters()->position().z()) < 13000
4354 ) {
4355 meff->setSigmaDeltaE(meot->energyLoss()->sigmaDeltaE());
4356 }
4357
4358 const TrackParameters* tmpparams =
4359 (*matvec)[j]->trackParameters() != nullptr
4360 ? (*matvec)[j]->trackParameters()->clone()
4361 : nullptr;
4362
4363 matstates.insert(matstates.begin(), std::make_unique<GXFTrackState>(
4364 std::move(meff),
4365 std::unique_ptr<const TrackParameters>(tmpparams)
4366 ));
4367 matvec_used=true;
4368 }
4369 }
4370 }
4371 }
4372 }
4373 }
4374
4375 ATH_MSG_DEBUG("Number of layers: " << matstates.size());
4376
4377 // Now insert the material states into the trajectory
4378 std::vector<std::unique_ptr<GXFTrackState>> & newstates = states;
4379 std::vector<std::unique_ptr<GXFTrackState>> oldstates = std::move(newstates);
4380
4381 newstates.clear();
4382 newstates.reserve(oldstates.size() + matstates.size());
4383
4384 int layerno = 0;
4385 int firstlayerno = -1;
4386
4387 if (cache.m_acceleration) {
4388 trajectory.addBasicState(std::move(oldstates[0]));
4389 }
4390
4391 const double cosphi = std::cos(refpar->parameters()[Trk::phi0]);
4392 const double sinphi = std::sin(refpar->parameters()[Trk::phi0]);
4393
4394 for (int i = cache.m_acceleration ? 1 : 0; i < (int) oldstates.size(); i++) {
4395 bool addlayer = true;
4396
4397 while (addlayer && layerno < (int) matstates.size()) {
4398 addlayer = false;
4399 const TrackParameters *layerpar = matstates[layerno]->trackParameters();
4400
4401 const DistanceSolution distsol = oldstates[i]->associatedSurface().straightLineDistanceEstimate(
4402 layerpar->position(),
4403 layerpar->momentum().unit()
4404 );
4405
4406 const double distance = getDistance(distsol);
4407
4408 if (distance > 0 && distsol.numberOfSolutions() > 0) {
4409 addlayer = true;
4410 }
4411
4412 if (layerpar->associatedSurface().type() == Trk::SurfaceType::Cylinder) {
4413 const double cylinderradius = layerpar->associatedSurface().bounds().r();
4414 const double trackimpact = std::abs(-refpar->position().x() * sinphi + refpar->position().y() * cosphi);
4415
4416 if (trackimpact > cylinderradius - 5 * mm) {
4417 layerno++;
4418 continue;
4419 }
4420 }
4421
4422 if (i == (int) oldstates.size() - 1) {
4423 addlayer = true;
4424 }
4425
4426 if (addlayer) {
4427 GXFMaterialEffects *meff = matstates[layerno]->materialEffects();
4428
4429 if (meff->sigmaDeltaPhi() > .4 || (meff->sigmaDeltaPhi() == 0 && meff->sigmaDeltaE() <= 0)) {
4430 if (meff->sigmaDeltaPhi() > .4) {
4431 ATH_MSG_DEBUG("Material state with excessive scattering, skipping it");
4432 }
4433
4434 if (meff->sigmaDeltaPhi() == 0) {
4435 ATH_MSG_WARNING("Material state with zero scattering, skipping it");
4436 }
4437
4438 layerno++;
4439 continue;
4440 }
4441
4442 if (firstlayerno < 0) {
4443 firstlayerno = layerno;
4444 }
4445
4446 trajectory.addMaterialState(std::move(matstates[layerno]));
4447
4448 if ((layerpar != nullptr) && matEffects != pion && matEffects != muon) {
4449 const TrackingVolume *tvol = m_navigator->volume(ctx,layerpar->position());
4450 const Layer *lay = nullptr;
4451
4452 if (tvol != nullptr) {
4453 lay = (tvol->closestMaterialLayer(layerpar->position(),layerpar->momentum().normalized())).object;
4454 }
4455
4456 const MaterialProperties *matprop = lay != nullptr ? lay->fullUpdateMaterialProperties(*layerpar) : nullptr;
4457 meff->setMaterialProperties(matprop);
4458 }
4459
4460 layerno++;
4461 }
4462 }
4463 trajectory.addBasicState(std::move(oldstates[i]));
4464 }
4465
4466 ATH_MSG_DEBUG("Total X0: " << trajectory.totalX0() << " total eloss: " << trajectory.totalEnergyLoss());
4467
4468 if (matvec_used) cache.m_matTempStore.push_back( std::move(matvec) );
4469 }
#define ATH_MSG_WARNING(x)
#define AmgVector(rows)
if(febId1==febId2)
int sign(int a)
Gaudi::Property< double > m_p
Gaudi::Property< bool > m_rejectLargeNScat
ToolHandle< INavigator > m_navigator
ToolHandle< IExtrapolator > m_extrapolator
bool ensureValidEntranceMuonSpectrometer(const EventContext &ctx, Cache &cache) const
ToolHandle< IMaterialEffectsOnTrackProvider > m_calotool
virtual MaterialEffectsDerivedType derivedType() const =0
Returns the concrete derived type.
virtual ParametersBase< DIM, T > * clone() const override=0
clone method for polymorphic deep copy
@ Measurement
This is a measurement, and will at least contain a Trk::MeasurementBase.
@ BremPoint
This represents a brem point on the track, and so will contain TrackParameters and MaterialEffectsBas...
@ Outlier
This TSoS contains an outlier, that is, it contains a MeasurementBase/RIO_OnTrack which was not used ...
@ Scatterer
This represents a scattering point on the track, and so will contain TrackParameters and MaterialEffe...
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Eigen::Affine3d Transform3D
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Eigen::Matrix< double, 3, 1 > Vector3D
double getDistance(const xAOD::Vertex *vtx1, const xAOD::Vertex *vtx2)
MeasurementType
enum describing the flavour of MeasurementBase
PropDirection
PropDirection, enum for direction of the propagation.
@ oppositeMomentum
std::unique_ptr< T > unique_clone(const T *v)
Definition unique_clone.h:8
@ z
global position (cartesian)
Definition ParamDefs.h:57
@ u
Enums for curvilinear frames.
Definition ParamDefs.h:77
@ phi0
Definition ParamDefs.h:65
@ qOverP
perigee
Definition ParamDefs.h:67
@ nonInteractingMuon
static void objVectorDeleter(const std::vector< const T * > *ptr)

◆ addMaterialFindIntersectionCyl()

std::optional< std::pair< Amg::Vector3D, double > > Trk::GlobalChi2Fitter::addMaterialFindIntersectionCyl ( Cache & cache,
const CylinderSurface & surface,
const TrackParameters & param1,
const TrackParameters & param2,
const ParticleHypothesis mat )
staticprivate

Find the intersection of a set of track parameters onto a cylindrical surface.

See addMaterialFindIntersectionDisc for more information.

Note
This method can probably be replaced entirely by the straight line intersection method of the appropriate Surface subclass.

Definition at line 2995 of file GlobalChi2Fitter.cxx.

3001 {
3002 /*
3003 * I hope you like trigonometry!
3004 *
3005 * For more information, please find a source elsewhere on finding
3006 * intersections with cylinders.
3007 */
3008 double field[3];
3009 const double * pos = parforextrap.position().data();
3010 const double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
3011 cache.m_field_cache.getFieldZR(pos, field);
3012 const double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
3013 const double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
3014 const double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
3015 const double costheta = std::cos(parforextrap.parameters()[Trk::theta]);
3016 const double tantheta = std::tan(parforextrap.parameters()[Trk::theta]);
3017 const double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
3018 const double xc = parforextrap.position().x() - r * sinphi;
3019 const double yc = parforextrap.position().y() + r * cosphi;
3020 const double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
3021 const double z0 = parforextrap.position().z();
3022 const double d = xc * xc + yc * yc;
3023 const double rcyl = surf.bounds().r();
3024 double mysqrt = ((r + rcyl) * (r + rcyl) - d) * (d - (r - rcyl) * (r - rcyl));
3025
3026 if (mysqrt < 0) {
3027 return {};
3028 }
3029
3030 mysqrt = std::sqrt(mysqrt);
3031 double firstterm = xc / 2 + (xc * (rcyl * rcyl - r * r)) / (2 * d);
3032 double secondterm = (mysqrt * yc) / (2 * d);
3033 const double x1 = firstterm + secondterm;
3034 const double x2 = firstterm - secondterm;
3035 firstterm = yc / 2 + (yc * (rcyl * rcyl - r * r)) / (2 * d);
3036 secondterm = (mysqrt * xc) / (2 * d);
3037 const double y1 = firstterm - secondterm;
3038 const double y2 = firstterm + secondterm;
3039 double x = parforextrap.position().x();
3040 double y = parforextrap.position().y();
3041 const double dist1 = (x - x1) * (x - x1) + (y - y1) * (y - y1);
3042 const double dist2 = (x - x2) * (x - x2) + (y - y2) * (y - y2);
3043
3044 if (dist1 < dist2) {
3045 x = x1;
3046 y = y1;
3047 } else {
3048 x = x2;
3049 y = y2;
3050 }
3051
3052 const double phi1 = std::atan2(y - yc, x - xc);
3053 const double deltaphi = xAOD::P4Helpers::deltaPhi(phi1, phi0);
3054
3055 const double delta_z = r * deltaphi / tantheta;
3056 const double z = z0 + delta_z;
3057
3059
3060 if (std::abs(z - surf.center().z()) > surf.bounds().halflengthZ()) {
3061 return {};
3062 }
3063
3064 const Amg::Vector3D normal(x, y, 0);
3065 const double phidir = xAOD::P4Helpers::deltaPhi(parforextrap.parameters()[Trk::phi], -deltaphi);
3066
3067 const Amg::Vector3D trackdir(cos(phidir) * sintheta, std::sin(phidir) * sintheta, costheta);
3068
3069 const double costracksurf = std::abs(normal.unit().dot(trackdir));
3070
3071 return std::make_pair(intersect, costracksurf);
3072 }
int r
Definition globals.cxx:22
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
@ x
Definition ParamDefs.h:55
@ theta
Definition ParamDefs.h:66
@ y
Definition ParamDefs.h:56
@ phi
Definition ParamDefs.h:75
@ z0
Definition ParamDefs.h:64
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[

◆ addMaterialFindIntersectionDisc()

std::optional< std::pair< Amg::Vector3D, double > > Trk::GlobalChi2Fitter::addMaterialFindIntersectionDisc ( Cache & cache,
const DiscSurface & surface,
const TrackParameters & param1,
const TrackParameters & param2,
const ParticleHypothesis mat )
staticprivate

Find the intersection of a set of track parameters onto a disc surface.

Calculates the intersection from a point and momentum in space onto a disc surface which represents a disc-shaped layer in the detector. The position of the intersection can be used to find materials in that layer at that position.

Parameters
[in]cacheThe standard GX2F cache.
[in]surfaceThe surface to intersect with.
[in]param1The main track parameters to calculate the intersection from.
[in]param2A secondary set of parameters used for electrons. The purpose of this is not known to us at this time.
[in]matA particle hypothesis describing the behaviour of the particle.
Returns
Nothing if the intersection failed (i.e. there was no intersection), otherwise both an intersection positition as well as the angle of inflection.
Note
This method can probably be replaced entirely by the straight line intersection method of the appropriate Surface subclass.

Definition at line 2950 of file GlobalChi2Fitter.cxx.

2956 {
2957 /*
2958 * Please refer to external sources on how to find the intersection between
2959 * a line and a disc.
2960 */
2961 double field[3];
2962 const double * pos = parforextrap.position().data();
2963 const double currentqoverp = (matEffects != Trk::electron) ? parforextrap.parameters()[Trk::qOverP] : refpar2.parameters()[Trk::qOverP];
2964 cache.m_field_cache.getFieldZR(pos, field);
2965 const double sinphi = std::sin(parforextrap.parameters()[Trk::phi0]);
2966 const double cosphi = std::cos(parforextrap.parameters()[Trk::phi0]);
2967 const double sintheta = std::sin(parforextrap.parameters()[Trk::theta]);
2968 const double costheta = std::cos(parforextrap.parameters()[Trk::theta]);
2969 //magnetic field deviation from straight line
2970 //https://cds.cern.ch/record/1281363/files/ATLAS-CONF-2010-072.pdf, equation 1
2971 //converted to MeV and kT
2972 const double r = (std::abs(currentqoverp) > 1e-10) ? -sintheta / (currentqoverp * 300. * field[2]) : 1e6;
2973 const double xc = parforextrap.position().x() - r * sinphi;
2974 const double yc = parforextrap.position().y() + r * cosphi;
2975 const double phi0 = std::atan2(parforextrap.position().y() - yc, parforextrap.position().x() - xc);
2976 const double z0 = parforextrap.position().z();
2977 const double delta_s = (surf.center().z() - z0) / costheta;
2978 const double delta_phi = delta_s * sintheta / r;
2979 const double x = xc + std::abs(r) * std::cos(phi0 + delta_phi);
2980 const double y = yc + std::abs(r) * std::sin(phi0 + delta_phi);
2981 const Amg::Vector3D intersect = Amg::Vector3D(x, y, surf.center().z());
2982 const double perp = intersect.perp();
2983 const DiscBounds *discbounds = static_cast<const DiscBounds *> (&surf.bounds());
2984
2985 if (perp > discbounds->rMax() || perp < discbounds->rMin()) {
2986 return {};
2987 }
2988
2989 const double costracksurf = std::abs(costheta);
2990
2991 return std::make_pair(intersect, costracksurf);
2992 }
Scalar perp() const
perp method - perpendicular length
delta_phi(phi1, phi2)
Definition eFEXNTuple.py:14

◆ addMaterialGetLayers()

void Trk::GlobalChi2Fitter::addMaterialGetLayers ( Cache & cache,
std::vector< std::pair< const Layer *, const Layer * > > & layers,
std::vector< std::pair< const Layer *, const Layer * > > & uplayers,
const std::vector< std::unique_ptr< GXFTrackState > > & states,
GXFTrackState & first,
GXFTrackState & last,
const TrackParameters * refpar,
bool hasmat )
staticprivate

Collect all possible layers that a given track could have passed through.

If we are to use layer information to determine possible scatterer hits, we must first gather those layers. That's what this method does. It looks for disc and barrel cylinder layers that the given track might have crossed and collects them into output vectors. One contains layers between states on the track, and the upstream layers lie before the first state of the track.

Parameters
[in,out]cacheGeneral cache object.
[out]layersOutput vector for layers.
[out]uplayersOutput vector for upstream layers, which lie before the first hit in the track.
[in]statesA list of track states on the track.
[in]firstThe first track state.
[in]lastThe last track state.
[in]refparReference parameters from which to extrapolate.
[in]hasmatAre there any existing materials on this track?

Definition at line 3285 of file GlobalChi2Fitter.cxx.

3294 {
3295 /*
3296 * Reserve some arbitrary number of layers in the output vectors.
3297 */
3298 upstreamlayers.reserve(5);
3299 layers.reserve(30);
3300
3301 /*
3302 * Gather a bunch of numbers from the parameters. Someties we need to grab
3303 * them from the first silicon state, sometimes from the last.
3304 */
3305 const double firstz = firstsistate.trackParameters()->position().z();
3306 const double firstr = firstsistate.trackParameters()->position().perp();
3307 const double firstz2 = hasmat ? lastsistate.trackParameters()->position().z() : firstsistate.trackParameters()->position().z();
3308 const double firstr2 = hasmat ? lastsistate.trackParameters()->position().perp() : firstsistate.trackParameters()->position().perp();
3309
3310 GXFTrackState *firststate = oldstates.front().get();
3311 GXFTrackState *laststate = oldstates.back().get();
3312
3313 /*
3314 * This number is particularly interesting, as it determines which side we
3315 * need to look at in regards to the disc layers.
3316 */
3317 const double lastz = laststate->position().z();
3318 const double lastr = laststate->position().perp();
3319
3320 const Layer *startlayer = firststate->associatedSurface().associatedLayer();
3321 const Layer *startlayer2 = hasmat ? lastsistate.associatedSurface().associatedLayer() : nullptr;
3322 const Layer *endlayer = laststate->associatedSurface().associatedLayer();
3323
3324 const double tantheta = std::tan(refpar->parameters()[Trk::theta]);
3325 const double slope = (tantheta != 0) ? 1 / tantheta : 0; // (lastz-firstz)/(lastr-firstr);
3326
3327 /*
3328 * First, we will grab our disc layers.
3329 */
3330 if (slope != 0) {
3331 std::vector < const Layer *>::const_iterator it;
3332 std::vector < const Layer *>::const_iterator itend;
3333
3334 /*
3335 * If we're on the positive z-side of the detector, we will iterate over
3336 * the positive discs. Otherwise, we will need to iterate over the
3337 * negative discs.
3338 */
3339 if (lastz > 0) {
3340 it = cache.m_posdiscs.begin();
3341 itend = cache.m_posdiscs.end();
3342 } else {
3343 it = cache.m_negdiscs.begin();
3344 itend = cache.m_negdiscs.end();
3345 }
3346
3347 /*
3348 * Iterate over our disc layers.
3349 */
3350 for (; it != itend; ++it) {
3351 /*
3352 * If we've overshot the last hit in our track, we don't need to look
3353 * at any further layers. We're done!
3354 */
3355 if (std::abs((*it)->surfaceRepresentation().center().z()) > std::abs(lastz)) {
3356 break;
3357 }
3358
3359 /*
3360 * Grab the bounds from the layer, which is a more useful kind of
3361 * object that allows us to do some geometric calculations.
3362 */
3363 const DiscBounds *discbounds = static_cast<const DiscBounds *> (&(*it)->surfaceRepresentation().bounds());
3364
3365 /*
3366 * Ensure that we've actually hit the layer!
3367 */
3368 if (discbounds->rMax() < firstr || discbounds->rMin() > lastr) {
3369 continue;
3370 }
3371
3372 const double rintersect = firstr + ((*it)->surfaceRepresentation().center().z() - firstz) / slope;
3373
3374 if (
3375 rintersect < discbounds->rMin() - 50 ||
3376 rintersect > discbounds->rMax() + 50
3377 ) {
3378 continue;
3379 }
3380
3381 /*
3382 * We also do not need to consider the last layer. If all goes well,
3383 * the next loop will immediately break because it will be an
3384 * overshoot.
3385 */
3386 if ((*it) == endlayer) {
3387 continue;
3388 }
3389
3390 /*
3391 * If this layer lies before the first hit, it's an upstream hit and we
3392 * add it to the upstream layer vector.
3393 *
3394 * Notice how we add this layer on the right side of the pair, that's
3395 * the convention. Discs to right, cylinders go left.
3396 */
3397 if (
3398 std::abs((*it)->surfaceRepresentation().center().z()) < std::abs(firstz) ||
3399 (*it) == startlayer
3400 ) {
3401 upstreamlayers.emplace_back((Layer *) nullptr, (*it));
3402 }
3403
3404 /*
3405 * Otherwise, it's a normal layer. Add it.
3406 */
3407 if (
3408 (*it) != startlayer &&
3409 (std::abs((*it)->surfaceRepresentation().center().z()) > std::abs(firstz2) ||
3410 (*it) == startlayer2)
3411 ) {
3412 layers.emplace_back((Layer *) nullptr, (*it));
3413 }
3414 }
3415 }
3416
3417 /*
3418 * Now, we add the barrel cylinder layers.
3419 */
3420 for (const auto *barrelcylinder : cache.m_barrelcylinders) {
3421 /*
3422 * Check for overshoots and reject them.
3423 */
3424 if (barrelcylinder->surfaceRepresentation().bounds().r() > lastr) {
3425 break;
3426 }
3427
3428 /*
3429 * Confirm intersection with the layer.
3430 */
3431 const double zintersect = firstz + (barrelcylinder->surfaceRepresentation().bounds().r() - firstr) * slope;
3432
3433 if (std::abs(zintersect - barrelcylinder->surfaceRepresentation().center().z()) >
3434 ((const CylinderSurface*)(&barrelcylinder->surfaceRepresentation()))->bounds().halflengthZ() + 50) {
3435 continue;
3436 }
3437
3438 if (barrelcylinder == endlayer) {
3439 continue;
3440 }
3441
3442 /*
3443 * Same as with the discs, add the layers to the output vectors.
3444 */
3445 if (barrelcylinder->surfaceRepresentation().bounds().r() < firstr ||
3446 barrelcylinder == startlayer) {
3447 upstreamlayers.emplace_back(barrelcylinder, (Layer*)nullptr);
3448 }
3449
3450 if (barrelcylinder != startlayer &&
3451 (barrelcylinder->surfaceRepresentation().bounds().r() > firstr2 ||
3452 barrelcylinder == startlayer2)) {
3453 layers.emplace_back(barrelcylinder, (Layer*)nullptr);
3454 }
3455 }
3456
3457 /*
3458 * Sort the layers such that they are in the right order, from close to far
3459 * in respect to the experiment center.
3460 */
3461 std::sort(layers.begin(), layers.end(), GXF::LayerSort());
3462 std::sort(upstreamlayers.begin(), upstreamlayers.end(), GXF::LayerSort());
3463 }
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.

◆ addMaterialUpdateTrajectory()

void Trk::GlobalChi2Fitter::addMaterialUpdateTrajectory ( Cache & cache,
GXFTrajectory & track,
int offset,
std::vector< std::pair< const Layer *, const Layer * > > & layers,
const TrackParameters * ref1,
const TrackParameters * ref2,
ParticleHypothesis mat ) const
private

Given layer information, probe those layers for scatterers and add them to a track.

This is the meat of the pudding, if you will. Given the information that we have about layers, go through them all and find any possible material hits that we need to add to the track.

Parameters
[in,out]cacheGeneral cache object.
[in,out]trackThe track object as it exists now in IR.
[in]offsetThe first state after any existing materials.
[in]layersThe list of layers.
[in]ref1The first set of reference parameters.
[in]ref2The second set of reference parameters.
[in]matThe particle hypothesis describing the track behaviour.
Note
Attentive readers may wonder why we pass this function a vector of layers, but not a vector of upstream layers. The reason for this is that the vector of upstream layers is also a member of the cache object.

Definition at line 3074 of file GlobalChi2Fitter.cxx.

3082 {
3083 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
3084 std::vector<std::unique_ptr<GXFTrackState>> oldstates = std::move(states);
3085
3086 states.clear();
3087 states.reserve(oldstates.size() + layers.size());
3088
3089 int layerindex = 0;
3090
3091 /*
3092 * First, simply copy any upstream states. We do not need to anything with
3093 * them as they are presumably already fit.
3094 */
3095 for (int i = 0; i <= indexoffset; i++) {
3096 trajectory.addBasicState(std::move(oldstates[i]));
3097 }
3098
3099 const TrackParameters *parforextrap = refpar;
3100
3101 /*
3102 * For non-upstream layers, that is to say layers after the last existing
3103 * material, the logic is not so simple.
3104 */
3105 for (int i = indexoffset + 1; i < (int) oldstates.size(); i++) {
3106 const double rmeas = oldstates[i]->position().perp();
3107 const double zmeas = oldstates[i]->position().z();
3108
3109 /*
3110 * Iterate over layers. Note that this is shared between different track
3111 * states! This makes sense, because the track states are sorted and so
3112 * are the layers. If that sorting is consistent between the two, which
3113 * it should be, this works.
3114 */
3115 while (layerindex < (int) layers.size()) {
3117 double costracksurf = 0.0;
3118 const Layer *layer = nullptr;
3119
3120 /*
3121 * Remember how we distinguish between disc and cylinder surfaces: if
3122 * the first element of the pair is not null, then it points to a
3123 * cylinder. If the second element of the pais is not null, then it's a
3124 * disc surface. That is the logic being applied here. Separate
3125 * handling of cylinders and discs.
3126 */
3127 if (layers[layerindex].first != nullptr) {
3128 /*
3129 * First, convert the pointer to a real CylinderSurface pointer.
3130 */
3131 layer = layers[layerindex].first;
3132 const CylinderSurface *cylsurf = static_cast<const CylinderSurface *> (&layer->surfaceRepresentation());
3133
3134 /*
3135 * Check if we have a different set of parameters that make more
3136 * sense. If not, reuse the ones we already had.
3137 */
3138 if (oldstates[i]->trackParameters() != nullptr) {
3139 const double rlayer = cylsurf->bounds().r();
3140 if (std::abs(rmeas - rlayer) < std::abs(parforextrap->position().perp() - rlayer)) {
3141 parforextrap = oldstates[i]->trackParameters();
3142 }
3143 }
3144
3145 /*
3146 * Check if we have an intersection with this layer. If so, break out
3147 * of this loop, we have what we need. Otherwise, go to the next
3148 * layer and try again.
3149 */
3150 if (auto res = addMaterialFindIntersectionCyl(cache, *cylsurf, *parforextrap, *refpar2, matEffects)) {
3151 std::tie(intersect, costracksurf) = res.value();
3152 } else {
3153 layerindex++;
3154 continue;
3155 }
3156
3157 if (cylsurf->bounds().r() > rmeas) break;
3158 } else if (layers[layerindex].second != nullptr) {
3159 /*
3160 * The logic for disc surfaces is essentially identical to the logic
3161 * for cylinder surfaces. You'll find comments for that just a dozen
3162 * lines up.
3163 */
3164 layer = layers[layerindex].second;
3165 const DiscSurface *discsurf = static_cast<const DiscSurface *> (&layer->surfaceRepresentation());
3166
3167 if (oldstates[i]->trackParameters() != nullptr) {
3168 const double zlayer = discsurf->center().z();
3169 if (std::abs(zmeas - zlayer) < std::abs(parforextrap->position().z() - zlayer)) {
3170 parforextrap = oldstates[i]->trackParameters();
3171 }
3172 }
3173
3174 if (auto res = addMaterialFindIntersectionDisc(cache, *discsurf, *parforextrap, *refpar2, matEffects)) {
3175 std::tie(intersect, costracksurf) = res.value();
3176 } else {
3177 layerindex++;
3178 continue;
3179 }
3180
3181 if (std::abs(discsurf->center().z()) > std::abs(zmeas)) break;
3182 } else {
3183 throw std::logic_error("Unhandled surface.");
3184 }
3185
3186 /*
3187 * Grab the material properties from our layer. If there are none, just
3188 * go to the next layer.
3189 */
3190 const MaterialProperties *matprop = layer->layerMaterialProperties()->fullMaterial(intersect);
3191 if (matprop == nullptr) {
3192 layerindex++;
3193 continue;
3194 }
3195
3196 /*
3197 * Convert the material properties into the internal representation of
3198 * material effects.
3199 */
3200 const double X0 = matprop->thicknessInX0();
3201 const double currentqoverp = (matEffects != Trk::electron)
3202 ? parforextrap->parameters()[Trk::qOverP]
3203 : refpar2->parameters()[Trk::qOverP];
3204 const double actualx0 = X0 / costracksurf;
3205 const double de = -std::abs(
3206 (matprop->thickness() / costracksurf) *
3207 m_elosstool->dEdX(
3208 *matprop,
3209 (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3210 matEffects));
3211 const double sintheta = std::sin(parforextrap->parameters()[Trk::theta]);
3212 const double sigmascat = std::sqrt(m_scattool->sigmaSquare(
3213 *matprop,
3214 (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3215 1. / costracksurf,
3216 matEffects));
3217
3218 std::unique_ptr<GXFMaterialEffects> meff = std::make_unique<GXFMaterialEffects>();
3219 meff->setDeltaE(de);
3220 meff->setScatteringSigmas(sigmascat / sintheta, sigmascat);
3221 meff->setX0(actualx0);
3222 meff->setSurface(&layer->surfaceRepresentation());
3223 meff->setMaterialProperties(matprop);
3224
3225 /*
3226 * If we have an electron, or if so configured, calculate energy loss
3227 * as well.
3228 */
3229 std::unique_ptr<EnergyLoss> eloss;
3230
3231 if (cache.m_fiteloss || (matEffects == electron && cache.m_asymeloss)) {
3232 eloss = std::make_unique<EnergyLoss>(m_elosstool->energyLoss(
3233 *matprop,
3234 (m_p != 0.0 ? std::abs(m_p) : std::abs(1. / currentqoverp)),
3235 1. / costracksurf,
3237 matEffects
3238 ));
3239 if (eloss != nullptr) {
3240 meff->setSigmaDeltaE(eloss->sigmaDeltaE());
3241 }
3242 }
3243
3244 if (matEffects == electron && cache.m_asymeloss) {
3245 meff->setDeltaE(-5);
3246 if (trajectory.numberOfTRTHits() == 0) {
3247 meff->setScatteringSigmas(0, 0);
3248 }
3249
3250 meff->setSigmaDeltaE(50);
3251 if (eloss != nullptr) {
3252 meff->setSigmaDeltaEPos(eloss->sigmaPlusDeltaE());
3253 meff->setSigmaDeltaENeg(eloss->sigmaMinusDeltaE());
3254 }
3255 }
3256
3258 "X0: " << meff->x0() << " qoverp: " << currentqoverp <<
3259 " sigmascat " << meff->sigmaDeltaTheta() <<" eloss: " << meff->deltaE() <<
3260 " sigma eloss: " << meff->sigmaDeltaE()
3261 );
3262
3263 /*
3264 * Create a new track state in the internal representation and load it
3265 * with any and all information we might have.
3266 */
3267 std::unique_ptr<GXFTrackState> matstate = std::make_unique<GXFTrackState>(
3268 std::move(meff),
3269 std::unique_ptr<const TrackParameters>()
3270 );
3271 matstate->setPosition(intersect);
3272 trajectory.addMaterialState(std::move(matstate));
3273
3274 /*
3275 * We're done on this layer, so the next state will go to the next
3276 * layer.
3277 */
3278 layerindex++;
3279 }
3280
3281 trajectory.addBasicState(std::move(oldstates[i]));
3282 }
3283 }
std::pair< std::vector< unsigned int >, bool > res
static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionDisc(Cache &cache, const DiscSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
Find the intersection of a set of track parameters onto a disc surface.
static std::optional< std::pair< Amg::Vector3D, double > > addMaterialFindIntersectionCyl(Cache &cache, const CylinderSurface &surface, const TrackParameters &param1, const TrackParameters &param2, const ParticleHypothesis mat)
Find the intersection of a set of track parameters onto a cylindrical surface.
ToolHandle< IEnergyLossUpdator > m_elosstool
ToolHandle< IMultipleScatteringUpdator > m_scattool
@ layer
Definition HitInfo.h:79

◆ alignmentFit()

Track * Trk::GlobalChi2Fitter::alignmentFit ( AlignmentCache & alignCache,
const Track & inputTrack,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = Trk::nonInteracting ) const
overridevirtual

Definition at line 1819 of file GlobalChi2Fitter.cxx.

1822 {
1823
1824
1825 const EventContext& ctx = Gaudi::Hive::currentContext();
1826 Cache cache(this);
1827 initFieldCache(ctx, cache);
1828
1829 delete alignCache.m_derivMatrix;
1830 alignCache.m_derivMatrix = nullptr;
1831
1832 delete alignCache.m_fullCovarianceMatrix;
1833 alignCache.m_fullCovarianceMatrix = nullptr;
1834 alignCache.m_iterationsOfLastFit = 0;
1835
1836 Trk::Track* newTrack =
1837 fitIm(ctx, cache, inputTrack, runOutlier, matEffects);
1838 if(newTrack != nullptr){
1839 if(cache.m_derivmat.size() != 0)
1840 alignCache.m_derivMatrix = new Amg::MatrixX(cache.m_derivmat);
1841 if(cache.m_fullcovmat.size() != 0)
1842 alignCache.m_fullCovarianceMatrix = new Amg::MatrixX(cache.m_fullcovmat);
1843 alignCache.m_iterationsOfLastFit = cache.m_lastiter;
1844 }
1845 return newTrack;
1846 }
Track * fitIm(const EventContext &ctx, Cache &cache, const Track &inputTrack, const RunOutlierRemoval runOutlier, const ParticleHypothesis matEffects) const
void initFieldCache(const EventContext &ctx, Cache &cache) const
Initialize a field cache inside a fit cache object.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.

◆ backupCombinationStrategy()

Track * Trk::GlobalChi2Fitter::backupCombinationStrategy ( const EventContext & ctx,
Cache & cache,
const Track & intrk1,
const Track & intrk2,
GXFTrajectory & trajectory,
std::vector< MaterialEffectsOnTrack > & calomeots ) const
private

Definition at line 1242 of file GlobalChi2Fitter.cxx.

1249 {
1250 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::backupCombinationStrategy");
1251
1252 const bool firstismuon = isMuonTrack(intrk1);
1253 const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
1254
1255 const Trk::TrackStates::const_iterator beginStates = intrk1.trackStateOnSurfaces()->begin();
1256 Trk::TrackStates::const_iterator itStates = beginStates;
1257 const Trk::TrackStates::const_iterator endState = intrk1.trackStateOnSurfaces()->end();
1258 const Trk::TrackStates::const_iterator beginStates2 = intrk2.trackStateOnSurfaces()->begin();
1259 Trk::TrackStates::const_iterator itStates2 = beginStates2;
1260 const Trk::TrackStates::const_iterator endState2 = intrk2.trackStateOnSurfaces()->end();
1261
1262 const TrackParameters *firstidpar = nullptr;
1263 const auto *const pParametersVector = indettrack->trackParameters();
1264 // Dont understand why the second track parameters are taken
1265 // Is it assumed the ID track is slimmed?
1266 if (pParametersVector->size() > 1)
1267 firstidpar = (*pParametersVector)[1];
1268 else
1269 firstidpar = pParametersVector->back();
1270
1271 std::unique_ptr<const TrackParameters> lastidpar = nullptr;
1272 if ((firstidpar != nullptr) && (cache.m_caloEntrance != nullptr))
1273 lastidpar = m_extrapolator->extrapolateToVolume(
1274 ctx, *firstidpar, *cache.m_caloEntrance, alongMomentum, Trk::muon);
1275
1276 if (lastidpar == nullptr) {
1277 lastidpar.reset(pParametersVector->back()->clone());
1278 }
1279
1280 std::unique_ptr < const TrackParameters > firstscatpar;
1281 std::unique_ptr < const TrackParameters > lastscatpar;
1282 std::unique_ptr < const TrackParameters > elosspar;
1283
1284 const double charge = (lastidpar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1285
1286 Perigee startper(
1287 lastidpar->position(),
1288 lastidpar->momentum(),
1289 charge,
1290 lastidpar->position()
1291 );
1292
1293 if (!firstismuon) {
1294 firstscatpar = m_propagator->propagateParameters(
1295 ctx,
1296 *lastidpar,
1297 calomeots[0].associatedSurface(),
1299 false,
1300 trajectory.m_fieldprop,
1302
1303 if (!firstscatpar) {
1304 return nullptr;
1305 }
1306
1307 const std::unique_ptr<const TrackParameters> tmppar(
1308 m_propagator->propagateParameters(
1309 ctx,
1310 *firstscatpar,
1311 calomeots[1].associatedSurface(),
1313 false,
1314 trajectory.m_fieldprop,
1316
1317 if (!tmppar) {
1318 return nullptr;
1319 }
1320
1321 const double sign = (tmppar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1322 const double mass = Trk::ParticleMasses::mass[muon];
1323
1324 const double oldp = std::abs(1 / tmppar->parameters()[Trk::qOverP]);
1325 const double de = std::abs(calomeots[1].energyLoss()->deltaE());
1326
1327 double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
1328
1329 if (newp2 < 4.e6) {
1330 newp2 = 4.e6;
1331 }
1332
1333 const double newqoverp = sign / std::sqrt(newp2);
1334
1335 const AmgVector(5) & pars = tmppar->parameters();
1336
1337 elosspar=
1338 tmppar->associatedSurface().createUniqueTrackParameters(
1339 pars[0], pars[1], pars[2], pars[3], newqoverp, std::nullopt
1340 );
1341
1342 lastscatpar = m_propagator->propagateParameters(
1343 ctx,
1344 *elosspar,
1345 calomeots[2].associatedSurface(),
1347 false,
1348 trajectory.m_fieldprop,
1350
1351 if (!lastscatpar) {
1352 return nullptr;
1353 }
1354 } else {
1355 lastscatpar = m_propagator->propagateParameters(
1356 ctx,
1357 *firstidpar,
1358 calomeots[2].associatedSurface(),
1360 false,
1361 trajectory.m_fieldprop,
1363 );
1364
1365 if (!lastscatpar) {
1366 return nullptr;
1367 }
1368
1369 elosspar= m_propagator->propagateParameters(
1370 ctx,
1371 *lastscatpar,
1372 calomeots[1].associatedSurface(),
1374 false,
1375 trajectory.m_fieldprop,
1377 );
1378
1379 if (!elosspar) {
1380 return nullptr;
1381 }
1382
1383 const double sign = (elosspar->parameters()[Trk::qOverP] < 0) ? -1 : 1;
1384 const double newqoverp = sign /
1385 (1. / std::abs(elosspar->parameters()[Trk::qOverP]) +
1386 std::abs(calomeots[1].energyLoss()->deltaE()));
1387
1388 const AmgVector(5) & pars = elosspar->parameters();
1389
1390 std::unique_ptr<const TrackParameters>const tmppar(
1391 elosspar->associatedSurface().createUniqueTrackParameters(
1392 pars[0], pars[1], pars[2], pars[3], newqoverp, std::nullopt
1393 )
1394 );
1395
1396 firstscatpar = m_propagator->propagateParameters(
1397 ctx,
1398 *tmppar,
1399 calomeots[0].associatedSurface(),
1401 false,
1402 trajectory.m_fieldprop,
1404 );
1405
1406 if (!firstscatpar) {
1407 return nullptr;
1408 }
1409 }
1410
1411 for (; itStates != endState; ++itStates) {
1412 if (
1413 firstismuon &&
1414 (*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)
1415 ) {
1416 continue;
1417 }
1418
1419 if ((*itStates)->materialEffectsOnTrack() != nullptr) {
1420 if (!firstismuon) {
1421 cache.m_idmat = false;
1422 } else {
1423 continue;
1424 }
1425 }
1426
1427 if (firstismuon) {
1428 makeProtoState(cache, trajectory, *itStates);
1429 }
1430 }
1431
1432 std::unique_ptr<GXFMaterialEffects> firstscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[0]);
1433 std::unique_ptr<GXFMaterialEffects> elossmeff = std::make_unique<GXFMaterialEffects>(calomeots[1]);
1434 std::unique_ptr<GXFMaterialEffects> secondscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[2]);
1435
1436 double dp = 0;
1437 double sigmadp = 0;
1438 sigmadp = calomeots[1].energyLoss()->sigmaDeltaE();
1439 elossmeff->setSigmaDeltaE(sigmadp);
1440
1441 dp = 1000 * (lastscatpar->parameters()[Trk::qOverP] - firstscatpar->parameters()[Trk::qOverP]);
1442 elossmeff->setdelta_p(dp);
1443
1444 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(firstscatmeff), std::move(firstscatpar)), -1);
1445 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(elossmeff), std::move(elosspar)), -1);
1446 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(secondscatmeff), std::move(lastscatpar)), -1);
1447
1448 GXFTrackState *secondscatstate = trajectory.trackStates().back().get();
1449 const Surface *triggersurf1 = nullptr;
1450 const Surface *triggersurf2 = nullptr;
1451 Amg::Vector3D triggerpos1(0, 0, 0);
1452 Amg::Vector3D triggerpos2(0, 0, 0);
1453
1454 bool seenmdt = false;
1455 bool mdtbetweenphihits = false;
1456 int nphi = 0;
1457
1458 for (
1459 itStates2 = (!firstismuon ? beginStates2 : endState - 1);
1460 itStates2 != (!firstismuon ? endState2 : beginStates - 1);
1461 (!firstismuon ? ++itStates2 : --itStates2)
1462 ) {
1463 if (
1464 ((*itStates2)->measurementOnTrack() == nullptr) ||
1465 (*itStates2)->type(TrackStateOnSurface::Outlier)
1466 ) {
1467 continue;
1468 }
1469 const auto *const pMeasurement = (*itStates2)->measurementOnTrack();
1470 const Surface *surf = &pMeasurement->associatedSurface();
1471 const bool isCompetingRIOsOnTrack = pMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
1472 const RIO_OnTrack *rot = nullptr;
1473
1474 if (isCompetingRIOsOnTrack) {
1475 const auto *const crot = static_cast<const CompetingRIOsOnTrack *>(pMeasurement);
1476 rot = &crot->rioOnTrack(0);
1477 } else {
1478 if (pMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
1479 rot = static_cast<const RIO_OnTrack *>(pMeasurement);
1480 }
1481 }
1482 if ((rot != nullptr) && m_DetID->is_mdt(rot->identify()) && (triggersurf1 != nullptr)) {
1483 seenmdt = true;
1484 }
1485 if (
1486 (rot != nullptr) && (
1487 m_DetID->is_tgc(rot->identify()) ||
1488 m_DetID->is_rpc(rot->identify()) ||
1489 m_DetID->is_stgc(rot->identify())
1490 )
1491 ) {
1492 const Amg::Vector3D measdir = surf->transform().rotation().col(0);
1493 const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1494 const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
1495
1496 const bool measphi = std::abs(dotprod1) <= .5 && std::abs(dotprod2) <= .5;
1497 if (measphi) {
1498 nphi++;
1499 const Amg::Vector3D thispos =
1500 (*itStates2)->trackParameters() != nullptr ?
1501 (*itStates2)->trackParameters()->position() :
1502 rot->globalPosition();
1503 if (triggersurf1 != nullptr) {
1504 triggerpos2 = thispos;
1505 triggersurf2 = surf;
1506 if (seenmdt) {
1507 mdtbetweenphihits = true;
1508 }
1509 } else {
1510 triggerpos1 = thispos;
1511 triggersurf1 = surf;
1512 }
1513 }
1514 }
1515 }
1516
1517 double mdttrig1 = 999999;
1518 double mdttrig2 = 999999;
1519 const Surface *mdtsurf1 = nullptr;
1520 const Surface *mdtsurf2 = nullptr;
1521
1522 for (
1523 itStates2 = (!firstismuon ? beginStates2 : endState - 1);
1524 itStates2 != (!firstismuon ? endState2 : beginStates - 1);
1525 (!firstismuon ? ++itStates2 : --itStates2)
1526 ) {
1527 const Surface *surf = nullptr;
1528 if (
1529 ((*itStates2)->measurementOnTrack() != nullptr) &&
1530 !(*itStates2)->type(TrackStateOnSurface::Outlier)
1531 ) {
1532 surf = &(*itStates2)->measurementOnTrack()->associatedSurface();
1533 }
1534
1535 if (surf == nullptr) {
1536 continue;
1537 }
1538 const auto *const pThisMeasurement = (*itStates2)->measurementOnTrack();
1539 const bool isCompetingRioOnTrack = pThisMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
1540 const RIO_OnTrack *rot = nullptr;
1541
1542 if (isCompetingRioOnTrack) {
1543 const auto *crot = static_cast<const CompetingRIOsOnTrack *>(pThisMeasurement);
1544 rot = &crot->rioOnTrack(0);
1545 } else {
1546 if (pThisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
1547 rot = static_cast<const RIO_OnTrack *>(pThisMeasurement);
1548 }
1549 }
1550 const bool thisismdt = rot and m_DetID->is_mdt(rot->identify());
1551 if (thisismdt) {
1552 const Amg::Vector3D globpos =
1553 (*itStates2)->trackParameters() != nullptr ?
1554 (*itStates2)->trackParameters()->position() :
1555 pThisMeasurement->globalPosition();
1556 if (triggerpos1.mag() > 1 && (globpos - triggerpos1).mag() < mdttrig1) {
1557 mdttrig1 = (globpos - triggerpos1).mag();
1558 mdtsurf1 = surf;
1559 }
1560 if (triggerpos2.mag() > 1 && (globpos - triggerpos2).mag() < mdttrig2) {
1561 mdttrig2 = (globpos - triggerpos2).mag();
1562 mdtsurf2 = surf;
1563 }
1564 }
1565 }
1566
1567 GXFTrackState * firstpseudostate = nullptr;
1568 std::vector<GXFTrackState *> outlierstates;
1569 std::vector<GXFTrackState *> outlierstates2;
1570
1571 outlierstates.reserve(10);
1572 outlierstates2.reserve(10);
1573
1574 std::unique_ptr<PseudoMeasurementOnTrack> newpseudo;
1575
1576 for (itStates2 = beginStates2; itStates2 != endState2; ++itStates2) {
1577 const auto *const pMeasurement{(*itStates2)->measurementOnTrack()};
1578 const bool isPseudo = pMeasurement->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack);
1579 const bool isStraightLine =
1580 pMeasurement != nullptr ?
1581 pMeasurement->associatedSurface().type() == Trk::SurfaceType::Line :
1582 false;
1583
1584 if (
1585 isStraightLine &&
1586 !firstismuon &&
1587 (newpseudo == nullptr) && (
1588 (itStates2 == beginStates2 || itStates2 == beginStates2 + 1) &&
1589 std::abs(pMeasurement->globalPosition().z()) < 10000
1590 )
1591 ) {
1592 std::unique_ptr<const TrackParameters> par2;
1593 if (((*itStates2)->trackParameters() != nullptr) && nphi > 99) {
1594 par2.reset((*itStates2)->trackParameters()->clone());
1595 } else {
1596 par2 = m_propagator->propagateParameters(
1597 ctx,
1598 *secondscatstate->trackParameters(),
1599 pMeasurement->associatedSurface(),
1601 false,
1602 trajectory.m_fieldprop,
1604 );
1605 }
1606 if (par2 == nullptr) {
1607 continue;
1608 }
1609 Amg::MatrixX covMatrix(1, 1);
1610 covMatrix(0, 0) = 100;
1611
1612 newpseudo = std::make_unique<PseudoMeasurementOnTrack>(
1613 LocalParameters(DefinedParameter(par2->parameters()[Trk::locY], Trk::locY)),
1614 std::move(covMatrix),
1615 par2->associatedSurface()
1616 );
1617
1618 std::unique_ptr<GXFTrackState> firstpseudo = std::make_unique<GXFTrackState>(std::move(newpseudo), std::move(par2));
1619 firstpseudo->setMeasurementType(TrackState::Pseudo);
1620
1621 double errors[5];
1622 errors[0] = errors[2] = errors[3] = errors[4] = -1;
1623 errors[1] = 10;
1624
1625 firstpseudo->setMeasurementErrors(errors);
1626 firstpseudostate = firstpseudo.get();
1627 trajectory.addMeasurementState(std::move(firstpseudo));
1628 ATH_MSG_DEBUG("Adding PseudoMeasurement");
1629 continue;
1630 }
1631
1632 if (isPseudo && !firstismuon) {
1633 continue;
1634 }
1635
1636 if ((**itStates2).materialEffectsOnTrack() != nullptr) {
1637 if (firstismuon) {
1638 cache.m_idmat = false;
1639 } else {
1640 continue;
1641 }
1642 }
1643
1644 if (!firstismuon) {
1645 if (
1646 ((**itStates2).measurementOnTrack() != nullptr) &&
1647 &(**itStates2).measurementOnTrack()->associatedSurface() == triggersurf1 &&
1648 (mdtsurf1 != nullptr)
1649 ) {
1650 std::unique_ptr<Amg::Transform3D> transf = std::make_unique<Amg::Transform3D>(mdtsurf1->transform());
1651
1652 transf->translation() << triggerpos1;
1653 StraightLineSurface const slsurf(*transf);
1654 Amg::MatrixX covMatrix(1, 1);
1655 covMatrix(0, 0) = 100;
1656
1657 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1658 LocalParameters(DefinedParameter(0, Trk::locY)), std::move(covMatrix), slsurf
1659 );
1660
1661 std::unique_ptr<GXFTrackState> pseudostate1 = std::make_unique<GXFTrackState>(std::move(newpseudo), nullptr);
1662 pseudostate1->setMeasurementType(TrackState::Pseudo);
1663
1664 double errors[5];
1665 errors[0] = errors[2] = errors[3] = errors[4] = -1;
1666 errors[1] = 10;
1667
1668 pseudostate1->setMeasurementErrors(errors);
1669 outlierstates2.push_back(pseudostate1.get());
1670 trajectory.addMeasurementState(std::move(pseudostate1));
1671 }
1672
1673 if (
1674 ((**itStates2).measurementOnTrack() != nullptr) &&
1675 &(**itStates2).measurementOnTrack()->associatedSurface() == triggersurf2 &&
1676 mdtbetweenphihits &&
1677 (mdtsurf2 != nullptr)
1678 ) {
1679 std::unique_ptr<Amg::Transform3D> transf = std::make_unique<Amg::Transform3D>(mdtsurf2->transform());
1680 transf->translation() << triggerpos2;
1681 StraightLineSurface const slsurf(*transf);
1682 Amg::MatrixX covMatrix(1, 1);
1683 covMatrix(0, 0) = 100;
1684
1685 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1686 LocalParameters(DefinedParameter(0, Trk::locY)), std::move(covMatrix), slsurf
1687 );
1688
1689 std::unique_ptr<GXFTrackState> pseudostate2 = std::make_unique<GXFTrackState>(std::move(newpseudo), nullptr);
1690 pseudostate2->setMeasurementType(TrackState::Pseudo);
1691
1692 double errors[5];
1693 errors[0] = errors[2] = errors[3] = errors[4] = -1;
1694 errors[1] = 10;
1695
1696 pseudostate2->setMeasurementErrors(errors);
1697 // cppcheck-suppress invalidLifetime; false positive
1698 outlierstates2.push_back(pseudostate2.get());
1699 trajectory.addMeasurementState(std::move(pseudostate2));
1700 }
1701
1702 makeProtoState(cache, trajectory, *itStates2);
1703
1704 if (
1705 (
1706 trajectory.trackStates().back()->measurementType() == TrackState::TGC ||
1707 (
1708 trajectory.trackStates().back()->measurementType() == TrackState::RPC &&
1709 trajectory.trackStates().back()->measuresPhi()
1710 )
1711 ) &&
1712 trajectory.trackStates().back()->getStateType(TrackStateOnSurface::Measurement)
1713 ) {
1714 outlierstates.push_back(trajectory.trackStates().back().get());
1715 trajectory.setOutlier((int) trajectory.trackStates().size() - 1, true);
1716 }
1717 }
1718 }
1719
1720 trajectory.setNumberOfPerigeeParameters(0);
1721
1722 Track *track = nullptr;
1723
1724 trajectory.setPrefit(2);
1725 const TrackParameters *startpar2 = &startper;
1726 cache.m_matfilled = true;
1727 const bool tmpacc = cache.m_acceleration;
1728 cache.m_acceleration = false;
1729 // @TODO eventually track created but not used why ?
1730 const std::unique_ptr<Trk::Track> tmp_track(
1731 myfit(ctx, cache, trajectory, *startpar2, false, muon));
1732 cache.m_acceleration = tmpacc;
1733
1734 cache.m_matfilled = false;
1735 if (
1736 !firstismuon &&
1737 trajectory.converged() &&
1738 std::abs(trajectory.residuals().tail<1>()(0) / trajectory.errors().tail<1>()(0)) > 10
1739 ) {
1740 return nullptr;
1741 }
1742
1743 if (trajectory.converged()) {
1744 if (firstpseudostate != nullptr) {
1745 const TrackParameters *par2 = firstpseudostate->trackParameters();
1746 Amg::MatrixX covMatrix(1, 1);
1747 covMatrix(0, 0) = 100;
1748
1749 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1750 LocalParameters(DefinedParameter(par2->parameters()[Trk::locY], Trk::locY)),
1751 std::move(covMatrix),
1752 par2->associatedSurface()
1753 );
1754 firstpseudostate->setMeasurement(std::move(newpseudo));
1755 firstpseudostate->setRecalibrated(false);
1756 }
1757
1758 for (int j = 0; j < (int) trajectory.trackStates().size(); j++) {
1759 for (const auto & i : outlierstates2) {
1760 if (trajectory.trackStates()[j].get() == i) {
1761 trajectory.setOutlier(j, true);
1762 }
1763 }
1764
1765 for (const auto & i : outlierstates) {
1766 if (trajectory.trackStates()[j].get() == i) {
1767 trajectory.setOutlier(j, false);
1768 }
1769 }
1770 }
1771
1772 for (
1773 itStates = (firstismuon ? beginStates2 : endState - 1);
1774 itStates != (firstismuon ? endState2 : beginStates - 1);
1775 (firstismuon ? ++itStates : --itStates)
1776 ) {
1777 if ((*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
1778 continue;
1779 }
1780
1781 makeProtoState(cache, trajectory, *itStates, (firstismuon ? -1 : 0));
1782 }
1783
1784 trajectory.reset();
1785 trajectory.setPrefit(0);
1786 trajectory.setNumberOfPerigeeParameters(5);
1787 track = myfit(ctx, cache, trajectory, *firstidpar, false, muon);
1788 cache.m_matfilled = false;
1789 }
1790
1791 return track;
1792 }
Scalar mag() const
mag method
double charge(const T &p)
Definition AtlasPID.h:997
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
Identifier identify() const
return the identifier -extends MeasurementBase
virtual const Amg::Vector3D & globalPosition() const override=0
Interface method to get the global Position.
void makeProtoState(Cache &, GXFTrajectory &, const TrackStateOnSurface *, int index=-1) const
Track * myfit(const EventContext &ctx, Cache &, GXFTrajectory &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const
bool isMuonTrack(const Track &) const
const AtlasDetectorID * m_DetID
constexpr double mass[PARTICLEHYPOTHESES]
the array of masses
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ locY
local cartesian
Definition ParamDefs.h:38
std::pair< double, ParamDefs > DefinedParameter
Typedef to of a std::pair<double, ParamDefs> to identify a passed-through double as a specific type o...

◆ calculateDerivatives()

void Trk::GlobalChi2Fitter::calculateDerivatives ( GXFTrajectory & trajectory)
staticprivate

Definition at line 8002 of file GlobalChi2Fitter.cxx.

8002 {
8003 const int nstatesupstream = trajectory.numberOfUpstreamStates();
8004 const int nscatupstream = trajectory.numberOfUpstreamScatterers();
8005 const int nbremupstream = trajectory.numberOfUpstreamBrems();
8006 const int nscats = trajectory.numberOfScatterers();
8007 const int nperpars = trajectory.numberOfPerigeeParameters();
8008 const int nfitpars = trajectory.numberOfFitParameters();
8009
8010 using Matrix55 = Eigen::Matrix<double, 5, 5>;
8011
8012 Matrix55 initialjac;
8013 initialjac.setZero();
8014 initialjac(4, 4) = 1;
8015
8016 Matrix55 jacvertex(initialjac);
8017
8018 std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacscat(trajectory.numberOfScatterers(), initialjac);
8019 std::vector<Matrix55, Eigen::aligned_allocator<Matrix55>> jacbrem(trajectory.numberOfBrems(), initialjac);
8020
8021 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8022 GXFTrackState *prevstate = nullptr;
8023 GXFTrackState *state = nullptr;
8024
8025 int hit_begin = 0;
8026 int hit_end = 0;
8027 int scatno = 0;
8028 int bremno = 0;
8029
8030 for (const bool forward : {false, true}) {
8031 if (forward) {
8032 hit_begin = nstatesupstream;
8033 hit_end = (int) states.size();
8034 scatno = nscatupstream;
8035 bremno = nbremupstream;
8036 } else {
8037 hit_begin = nstatesupstream - 1;
8038 hit_end = 0;
8039 scatno = trajectory.numberOfUpstreamScatterers() - 1;
8040 bremno = trajectory.numberOfUpstreamBrems() - 1;
8041 }
8042
8043 for (
8044 int hitno = hit_begin;
8045 forward ? (hitno < hit_end) : (hitno >= hit_end);
8046 hitno += (forward ? 1 : -1)
8047 ) {
8048
8049 state = states[hitno].get();
8050
8051 const bool fillderivmat = (!state->getStateType(TrackStateOnSurface::Scatterer) && !state->getStateType(TrackStateOnSurface::BremPoint));
8052
8053 if (fillderivmat && state->derivatives().cols() != nfitpars) {
8054 state->derivatives().resize(5, nfitpars);
8055 state->derivatives().setZero();
8056 }
8057
8058 int jminscat = 0;
8059 int jmaxscat = 4;
8060 int jminbrem = 0;
8061 const int jmaxbrem = 4;
8062
8063 if (hitno == (forward ? hit_end - 1 : 0)) {
8064 if (!fillderivmat) {
8065 break;
8066 }
8067 jminscat = 2;
8068 jmaxscat = 3;
8069 jminbrem = 4;
8070 }
8071
8072 Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8073
8074 if (hitno == nstatesupstream + (forward ? 0 : -1)) {
8075 jacvertex.block<4, 5>(0, 0) = jac.block<4, 5>(0, 0);
8076 jacvertex(4, 4) = jac(4, 4);
8077 } else {
8078 int jmin = 0;
8079 int jmax = 0;
8080 int jcnt = 0;
8081 int lp_bgn = 0;
8082 int lp_end = 0;
8083
8084 jmin = jminscat;
8085 jmax = jmaxscat;
8086 jcnt = jmax - jmin + 1;
8087
8088 lp_bgn = forward ? nscatupstream : nscatupstream - 1;
8089 lp_end = scatno;
8090
8091 for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8092 if (
8093 i == scatno + (forward ? -1 : 1) &&
8094 prevstate != nullptr &&
8095 prevstate->getStateType(TrackStateOnSurface::Scatterer) &&
8096 (!trajectory.prefit() || prevstate->materialEffects()->deltaE() == 0)
8097 ) {
8098 jacscat[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8099 jacscat[i](4, 4) = jac(4, 4);
8100 } else {
8101 calculateJac(jac, jacscat[i], jmin, jmax);
8102 }
8103
8104 if (fillderivmat) {
8105 Eigen::MatrixXd & derivmat = state->derivatives();
8106 const int scatterPos = nperpars + 2 * i;
8107
8108 derivmat.block<4, 2>(0, scatterPos) = (forward ? 1 : -1) * jacscat[i].block<4, 2>(0, 2);
8109 }
8110 }
8111
8112 jmin = jminbrem;
8113 jmax = jmaxbrem;
8114 jcnt = jmax - jmin + 1;
8115
8116 lp_bgn = forward ? nbremupstream : nbremupstream - 1;
8117 lp_end = bremno;
8118
8119 for (int i = lp_bgn; forward ? (i < lp_end) : (i > lp_end); i += (forward ? 1 : -1)) {
8120 if (
8121 i == bremno + (forward ? -1 : 1) &&
8122 prevstate &&
8123 prevstate->materialEffects() &&
8124 prevstate->materialEffects()->sigmaDeltaE() > 0
8125 ) {
8126 jacbrem[i].block(0, jmin, 4, jcnt) = jac.block(0, jmin, 4, jcnt);
8127 jacbrem[i](4, 4) = jac(4, 4);
8128 } else {
8129 calculateJac(jac, jacbrem[i], jmin, jmax);
8130 }
8131
8132 if (fillderivmat) {
8133 Eigen::MatrixXd & derivmat = state->derivatives();
8134 const int scatterPos = nperpars + 2 * nscats + i;
8135
8136 derivmat.block<5, 1>(0, scatterPos) = (forward ? .001 : -.001) * jacbrem[i].block<5, 1>(0, 4);
8137 }
8138 }
8139
8140 calculateJac(jac, jacvertex, 0, 4);
8141 }
8142
8143 if (fillderivmat) {
8144 Eigen::MatrixXd & derivmat = state->derivatives();
8145 derivmat.block(0, 0, 4, nperpars) = jacvertex.block(0, 0, 4, nperpars);
8146
8147 if (nperpars == 5) {
8148 derivmat.col(4).segment(0, 4) *= .001;
8149 derivmat(4, 4) = .001 * jacvertex(4, 4);
8150 }
8151 }
8152
8153 if (
8154 state->getStateType(TrackStateOnSurface::Scatterer) &&
8155 (!trajectory.prefit() || states[hitno]->materialEffects()->deltaE() == 0)
8156 ) {
8157 scatno += (forward ? 1 : -1);
8158 }
8159
8160 if (
8161 states[hitno]->materialEffects() &&
8162 states[hitno]->materialEffects()->sigmaDeltaE() > 0
8163 ) {
8164 bremno += (forward ? 1 : -1);
8165 }
8166
8167 prevstate = states[hitno].get();
8168 }
8169 }
8170 }

◆ calculateTrackErrors()

void Trk::GlobalChi2Fitter::calculateTrackErrors ( GXFTrajectory & trajectory,
Amg::SymMatrixX & fullcovmat,
bool onlylocal ) const
private

Definition at line 8174 of file GlobalChi2Fitter.cxx.

8176 {
8177 //
8178 // Calculate track errors at each state, except scatterers and brems
8179 //
8180 ATH_MSG_DEBUG("CalculateTrackErrors");
8181
8182 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
8183 const int nstatesupstream = trajectory.numberOfUpstreamStates();
8184 std::vector < int >indices(states.size());
8185 GXFTrackState *prevstate = nullptr;
8186 int i = nstatesupstream;
8187 for (int j = 0; j < (int) states.size(); j++) {
8188 if (j < nstatesupstream) {
8189 i--;
8190 indices[j] = i;
8191 } else {
8192 indices[j] = j;
8193 }
8194 }
8195 for (int stateno = 0; stateno < (int) states.size(); stateno++) {
8196 if (stateno == 0 || stateno == nstatesupstream) {
8197 prevstate = nullptr;
8198 }
8199 const int index = indices[stateno];
8200 std::unique_ptr<GXFTrackState> & state = states[index];
8201 if (state->materialEffects() != nullptr) {
8202 prevstate = state.get();
8203 continue;
8204 }
8205
8206 if (!state->hasTrackCovariance()) {
8207 state->zeroTrackCovariance();
8208 }
8209 AmgMatrix(5, 5) & trackerrmat = state->trackCovariance();
8210
8211 if ((prevstate != nullptr) &&
8212 (prevstate->getStateType(TrackStateOnSurface::Measurement) ||
8213 prevstate->getStateType(TrackStateOnSurface::Outlier))
8214 && !onlylocal) {
8215 Eigen::Matrix<double, 5, 5> & jac = state->jacobian();
8216 const AmgMatrix(5, 5)& prevcov = states[indices[stateno - 1]]->trackCovariance();
8217
8218 trackerrmat = jac * prevcov * jac.transpose();
8219 } else {
8220 Amg::MatrixX & derivatives = state->derivatives();
8221
8222 trackerrmat = derivatives * fullcovmat * derivatives.transpose();
8223 }
8224
8225 if (!onlylocal) {
8226 const MeasurementBase *measurement = state->measurement();
8227 const Amg::MatrixX & meascov = measurement->localCovariance();
8228 int j = 0;
8229 int indices[5] = {
8230 -1, -1, -1, -1, -1
8231 };
8232 bool errorok = true;
8233 for (int i = 0; i < 5; i++) {
8234 if (measurement->localParameters().contains(Trk::ParamDefsAccessor::pardef[i])) {
8235 if (state->getStateType(TrackStateOnSurface::Measurement)
8236 && trackerrmat(i, i) > meascov(j, j)) {
8237 errorok = false;
8238 const double scale = std::sqrt(meascov(j, j) / trackerrmat(i, i));
8239 trackerrmat(i, i) = meascov(j, j);
8240 for (int k = 0; k < 5; k++) {
8241 if (k != i) {
8242 trackerrmat(k, i) *= scale;
8243 }
8244 }
8245 indices[i] = j;
8246 }
8247 j++;
8248 }
8249 }
8250 for (int i = 0; i < 5; i++) {
8251 if (indices[i] == -1) {
8252 continue;
8253 }
8254 for (int j = 0; j < 5; j++) {
8255 if (indices[j] == -1) {
8256 continue;
8257 }
8258 trackerrmat(i, j) = meascov(indices[i], indices[j]);
8259 }
8260 }
8261 if (trajectory.m_straightline) {
8262 trackerrmat(4, 4) = 1e-20;
8263 }
8264
8265 const TrackParameters *tmptrackpar =
8266 state->trackParameters();
8267
8268 std::optional<AmgMatrix(5, 5)> trkerrmat;
8269
8270 if (state->hasTrackCovariance()) {
8271 trkerrmat = (state->trackCovariance());
8272 } else {
8273 trkerrmat = std::nullopt;
8274 }
8275
8276 const AmgVector(5) & tpars = tmptrackpar->parameters();
8277 std::unique_ptr<const TrackParameters> trackpar(
8278 tmptrackpar->associatedSurface().createUniqueTrackParameters(tpars[0],
8279 tpars[1],
8280 tpars[2],
8281 tpars[3],
8282 tpars[4],
8283 std::move(trkerrmat))
8284 );
8285 state->setTrackParameters(std::move(trackpar));
8286 FitQualityOnSurface fitQual{};
8287 if (state->getStateType(TrackStateOnSurface::Measurement)) {
8288 if (errorok && trajectory.nDOF() > 0) {
8289 fitQual = m_updator->fullStateFitQuality(
8290 *state->trackParameters(),
8291 measurement->localParameters(),
8292 measurement->localCovariance()
8293 );
8294 } else {
8295 fitQual = FitQualityOnSurface(0, state->numberOfMeasuredParameters());
8296 }
8297 }
8298 state->setFitQuality(fitQual);
8299 }
8300 prevstate = state.get();
8301 }
8302 }
#define AmgMatrix(rows, cols)
ToolHandle< IUpdator > m_updator
str index
Definition DeMoScan.py:362
std::pair< long int, long int > indices
static constexpr std::array< ParamDefs, 6 > pardef
Constructor.
Definition ParamDefs.h:94

◆ calculateTrackParameters()

FitterStatusCode Trk::GlobalChi2Fitter::calculateTrackParameters ( const EventContext & ctx,
GXFTrajectory & trajectory,
bool calcderiv ) const
private

Definition at line 7778 of file GlobalChi2Fitter.cxx.

7782 {
7783 // Loop over states, calculate track parameters and (optionally) jacobian at each state
7784 ATH_MSG_DEBUG("CalculateTrackParameters");
7785
7786 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
7787 const int nstatesupstream = trajectory.numberOfUpstreamStates();
7788 const TrackParameters *prevtrackpar = trajectory.referenceParameters();
7789 std::unique_ptr<const TrackParameters> tmptrackpar;
7790
7791 for (int hitno = nstatesupstream - 1; hitno >= 0; hitno--) {
7792 const Surface &surf1 = states[hitno]->associatedSurface();
7794
7795 const DistanceSolution distsol = surf1.straightLineDistanceEstimate(
7796 prevtrackpar->position(), prevtrackpar->momentum().unit()
7797 );
7798
7799 const double distance = getDistance(distsol);
7800
7801 if (
7802 distance > 0 &&
7803 distsol.numberOfSolutions() > 0 &&
7804 prevtrackpar != trajectory.referenceParameters()
7805 ) {
7806 propdir = Trk::alongMomentum;
7807 }
7808
7809 GlobalChi2Fitter::PropagationResult rv = calculateTrackParametersPropagate(
7810 ctx,
7811 *prevtrackpar,
7812 *states[hitno],
7813 propdir,
7814 trajectory.m_fieldprop,
7815 calcderiv,
7816 false
7817 );
7818
7819 if (
7820 propdir == Trk::alongMomentum &&
7821 (rv.m_parameters != nullptr) &&
7822 (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7823 ) {
7824 ATH_MSG_DEBUG("Propagation in wrong direction");
7825
7826 }
7827
7828 if (rv.m_parameters == nullptr) {
7829 ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7830 " pos: " << prevtrackpar->position() << " destination surface: " << surf1);
7832 }
7833
7834 states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7835 const TrackParameters *currenttrackpar = states[hitno]->trackParameters();
7836 const Surface &surf = states[hitno]->associatedSurface();
7837
7838 if (rv.m_jacobian != std::nullopt) {
7839 if (
7840 states[hitno]->materialEffects() != nullptr &&
7841 states[hitno]->materialEffects()->deltaE() != 0 &&
7842 states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7843 !trajectory.m_straightline
7844 ) {
7845 const double p = 1. / std::abs(currenttrackpar->parameters()[Trk::qOverP]);
7846 const double de = std::abs(states[hitno]->materialEffects()->deltaE());
7847 const double mass = trajectory.mass();
7848 const double newp = std::sqrt(p * p + 2 * de * std::sqrt(mass * mass + p * p) + de * de);
7849 (*rv.m_jacobian) (4, 4) = ((p + p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7850 }
7851
7852 states[hitno]->setJacobian(*rv.m_jacobian);
7853 } else if (calcderiv) {
7854 ATH_MSG_WARNING("Jacobian is null");
7856 }
7857
7858 GXFMaterialEffects *meff = states[hitno]->materialEffects();
7859
7860 if (meff != nullptr && hitno != 0) {
7861 std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7862 surf, *meff, *states[hitno]->trackParameters(), trajectory.mass(), -1
7863 );
7864
7865 if (std::holds_alternative<FitterStatusCode>(r)) {
7866 return std::get<FitterStatusCode>(r);
7867 }
7868
7869 tmptrackpar = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7870 prevtrackpar = tmptrackpar.get();
7871 } else {
7872 prevtrackpar = currenttrackpar;
7873 }
7874 }
7875
7876 prevtrackpar = trajectory.referenceParameters();
7877
7878 for (int hitno = nstatesupstream; hitno < (int) states.size(); hitno++) {
7879 const Surface &surf = states[hitno]->associatedSurface();
7881 const DistanceSolution distsol = surf.straightLineDistanceEstimate(prevtrackpar->position(), prevtrackpar->momentum().unit());
7882
7883 const double distance = getDistance(distsol);
7884
7885 if (distance < 0 && distsol.numberOfSolutions() > 0 && prevtrackpar != trajectory.referenceParameters()) {
7886 propdir = Trk::oppositeMomentum;
7887 }
7888
7889 GlobalChi2Fitter::PropagationResult rv = calculateTrackParametersPropagate(
7890 ctx,
7891 *prevtrackpar,
7892 *states[hitno],
7893 propdir,
7894 trajectory.m_fieldprop,
7895 calcderiv,
7896 false
7897 );
7898
7899 if (
7900 (rv.m_parameters != nullptr) &&
7901 propdir == Trk::oppositeMomentum &&
7902 (prevtrackpar->position() - rv.m_parameters->position()).mag() > 5 * mm
7903 ) {
7904 ATH_MSG_DEBUG("Propagation in wrong direction");
7905 }
7906
7907 if (rv.m_parameters == nullptr) {
7908 ATH_MSG_DEBUG("propagation failed, prev par: " << *prevtrackpar <<
7909 " pos: " << prevtrackpar->
7910 position() << " destination surface: " << surf);
7912 }
7913
7914 if (rv.m_jacobian != std::nullopt) {
7915 if (
7916 states[hitno]->materialEffects() != nullptr &&
7917 states[hitno]->materialEffects()->deltaE() != 0 &&
7918 states[hitno]->materialEffects()->sigmaDeltaE() <= 0 &&
7919 !trajectory.m_straightline
7920 ) {
7921 const double p = 1 / std::abs(rv.m_parameters->parameters()[Trk::qOverP]);
7922 const double de = std::abs(states[hitno]->materialEffects()->deltaE());
7923 const double mass = trajectory.mass();
7924 double newp = p * p - 2 * de * std::sqrt(mass * mass + p * p) + de * de;
7925
7926 if (newp > 0) {
7927 newp = std::sqrt(newp);
7928 }
7929
7930 (*rv.m_jacobian) (4, 4) = ((p - p * de / std::sqrt(p * p + mass * mass)) / newp) * p * p / (newp * newp);
7931 }
7932
7933 states[hitno]->setJacobian(*rv.m_jacobian);
7934 } else if (calcderiv) {
7935 ATH_MSG_WARNING("Jacobian is null");
7937 }
7938
7939 GXFMaterialEffects *meff = states[hitno]->materialEffects();
7940
7941 if (meff != nullptr) {
7942 std::variant<std::unique_ptr<const TrackParameters>, FitterStatusCode> r = updateEnergyLoss(
7943 surf, *meff, *rv.m_parameters, trajectory.mass(), +1
7944 );
7945
7946 if (std::holds_alternative<FitterStatusCode>(r)) {
7947 return std::get<FitterStatusCode>(r);
7948 }
7949
7950 rv.m_parameters = std::move(std::get<std::unique_ptr<const TrackParameters>>(r));
7951 }
7952
7953 states[hitno]->setTrackParameters(std::move(rv.m_parameters));
7954 prevtrackpar = states[hitno]->trackParameters();
7955 }
7956
7958 }
@ ExtrapolationFailure
extrapolation failed
@ Success
fit successfull
std::variant< std::unique_ptr< const TrackParameters >, FitterStatusCode > updateEnergyLoss(const Surface &, const GXFMaterialEffects &, const TrackParameters &, double, int) const
PropagationResult calculateTrackParametersPropagate(const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
Propagate onto a track state, collecting new track parameters, and optionally the Jacobian and possib...

◆ calculateTrackParametersPropagate()

GlobalChi2Fitter::PropagationResult Trk::GlobalChi2Fitter::calculateTrackParametersPropagate ( const EventContext & ctx,
const TrackParameters & prev,
const GXFTrackState & ts,
PropDirection propdir,
const MagneticFieldProperties & bf,
bool calcderiv,
bool holesearch ) const
private

Propagate onto a track state, collecting new track parameters, and optionally the Jacobian and possible holes.

This is a helper function for the calculateTrackParameters() method. Its purpose is to propagate from a set of track parameters onto a surface, finding the new track parameters at that surface and optionally the Jacobian and a list of possible holes.

This method uses another helper function, aptly called calculateTrackParametersPropagateHelper(), which wraps the actual propagator calls. What calculateTrackParametersPropagate() is call this method once and check the result. If the result is invalid, that is to say we didn't manage to extract a correct set of track parameters, we try again but with the propagation direction flipped.

If the calcderiv argument is set, this method will attempt to calculate the Jacobian as well as the new set of track parameters. This involves non-trivial logic which is abstracted away in the underlying helper function.

Parameters
[in]ctxAn event context.
[in]prevThe origin track parameters to start the propagation.
[in]tsThe destination track state (in GX2F internal form).
[in]propdirThe propagation direction.
[in]bfThe magnetic field properties.
[in]calcderivIf set, calculate the derivative.
[in]holesearchIf set, search for holes.
Returns
An instance of PropagationResult, which is a struct with three members. Firstly, it contains a unique pointer to a set of track parameters, which are the track parameters at the destination track state following propagation. If these parameters are a nullpointer, that indicates a failure state. Secondly, if requested, the Jacobian is stored in this struct. This may be a nullptr if it was not requested or if the calculation of the Jacobian failed. Thirdly, it contains a vector of possible holes found between the start and end of the propagation. Since these hole states are not always necessary, they are wrapped in a std::optional type.

Definition at line 7752 of file GlobalChi2Fitter.cxx.

7760 {
7762
7764 ctx, prev, ts, propdir, bf, calcderiv, holesearch
7765 );
7766
7767 if (rv.m_parameters == nullptr) {
7768 propdir = invertPropdir(propdir);
7769
7771 ctx, prev, ts, propdir, bf, calcderiv, holesearch
7772 );
7773 }
7774
7775 return rv;
7776 }
PropagationResult calculateTrackParametersPropagateHelper(const EventContext &, const TrackParameters &, const GXFTrackState &, PropDirection, const MagneticFieldProperties &, bool, bool) const
Helper method that encapsulates calls to the propagator tool in the calculateTrackParameters() method...
int ts
Definition globals.cxx:24

◆ calculateTrackParametersPropagateHelper()

GlobalChi2Fitter::PropagationResult Trk::GlobalChi2Fitter::calculateTrackParametersPropagateHelper ( const EventContext & ctx,
const TrackParameters & prev,
const GXFTrackState & ts,
PropDirection propdir,
const MagneticFieldProperties & bf,
bool calcderiv,
bool holesearch ) const
private

Helper method that encapsulates calls to the propagator tool in the calculateTrackParameters() method.

This method encapsulates some of the logic relating to passing or not passing a Jacobian matrix to make the calculateTrackParameters() a lot more readable.

For information about parameters see the IPropagator::propagateParameters() method, which this method almost directly wraps.

Definition at line 7713 of file GlobalChi2Fitter.cxx.

7721 {
7722 std::unique_ptr<const TrackParameters> rv;
7723 std::optional<TransportJacobian> jac{};
7724
7725 if (calcderiv && !m_numderiv) {
7726 rv = m_propagator->propagateParameters(
7727 ctx, prev, ts.associatedSurface(), propdir, false, bf, jac, Trk::nonInteracting, false
7728 );
7729 } else {
7730 rv = m_propagator->propagateParameters(
7731 ctx, prev, ts.associatedSurface(), propdir, false, bf, Trk::nonInteracting, false
7732 );
7733
7734 if (rv != nullptr && calcderiv) {
7735 jac = numericalDerivatives(ctx, &prev, ts.associatedSurface(), propdir, bf);
7736 }
7737 }
7738
7739 std::optional<std::vector<std::unique_ptr<TrackParameters>>> extrapolation;
7740
7741 if (holesearch) {
7742 extrapolation = holesearchExtrapolation(ctx, prev, ts, propdir);
7743 }
7744
7745 return PropagationResult {
7746 std::move(rv),
7747 std::move(jac),
7748 std::move(extrapolation)
7749 };
7750 }
std::optional< TransportJacobian > numericalDerivatives(const EventContext &ctx, const TrackParameters *, const Surface &, PropDirection, const MagneticFieldProperties &) const
std::vector< std::unique_ptr< TrackParameters > > holesearchExtrapolation(const EventContext &ctx, const TrackParameters &src, const GXFTrackState &dst, PropDirection propdir) const
Helper method which performs an extrapolation with additional logic for hole search.
Gaudi::Property< bool > m_numderiv

◆ compensatePhiWeights()

void Trk::GlobalChi2Fitter::compensatePhiWeights ( Cache & cache,
GXFTrajectory & trajectory,
Amg::SymMatrixX & a )
staticprivate

Definition at line 5953 of file GlobalChi2Fitter.cxx.

5957 {
5958 const int nPerPars = trajectory.numberOfPerigeeParameters();
5959 std::size_t scatno = 0;
5960
5961 for (auto & state : trajectory.trackStates()) {
5962 const GXFMaterialEffects *meff = state->materialEffects();
5963
5964 if (meff == nullptr || meff->sigmaDeltaPhi() == 0) {
5965 continue;
5966 }
5967
5968 if (scatno >= cache.m_phiweight.size()) {
5969 std::stringstream message;
5970 message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5971 throw std::range_error(message.str());
5972 }
5973
5974 const bool isValidPlaneSurface =
5975 state->associatedSurface().type() == Trk::SurfaceType::Plane &&
5976 static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5977
5978 if (meff->deltaE() == 0 || isValidPlaneSurface) {
5979 const int scatNoIndex = 2 * scatno + nPerPars;
5980 a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5981 cache.m_phiweight[scatno] = 1;
5982 }
5983
5984 /*
5985 * NOTE: We already check for this in the beginning of the loop. Is
5986 * there any way, this can change?
5987 */
5988 if (meff->sigmaDeltaPhi() != 0) {
5989 scatno++;
5990 }
5991 }
5992 }
static Double_t a

◆ correctAngles()

bool Trk::GlobalChi2Fitter::correctAngles ( double & phi,
double & theta )
staticprivate

Definition at line 8452 of file GlobalChi2Fitter.cxx.

8452 {
8453 if (theta > M_PI) {
8454 theta = M_PI - theta;
8455 phi += M_PI;
8456 }
8457 if (theta < 0) {
8458 theta = -theta;
8459 phi += M_PI;
8460 }
8461
8462 phi = -std::remainder(-phi, 2 * M_PI);
8463
8464 return theta >= 0 && theta <= M_PI && phi >= -M_PI && phi <= M_PI;
8465 }
#define M_PI

◆ ensureValidEntranceCalo()

bool Trk::GlobalChi2Fitter::ensureValidEntranceCalo ( const EventContext & ctx,
Cache & cache ) const
private

Definition at line 8534 of file GlobalChi2Fitter.cxx.

8534 {
8535 if (cache.m_caloEntrance == nullptr) {
8536 const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8537
8538 if (geometry != nullptr) {
8539 cache.m_caloEntrance = geometry->trackingVolume("InDet::Containers::InnerDetector");
8540 } else {
8541 ATH_MSG_ERROR("Tracking Geometry not available");
8542 }
8543
8544 /*
8545 * Check, if we managed to find an entrance.
8546 */
8547 if (cache.m_caloEntrance == nullptr) {
8548 ATH_MSG_ERROR("calo entrance not available");
8549 }
8550 }
8551
8552 return cache.m_caloEntrance != nullptr;
8553 }
#define ATH_MSG_ERROR(x)
const TrackingGeometry * trackingGeometry(Cache &cache, const EventContext &ctx) const

◆ ensureValidEntranceMuonSpectrometer()

bool Trk::GlobalChi2Fitter::ensureValidEntranceMuonSpectrometer ( const EventContext & ctx,
Cache & cache ) const
private

Definition at line 8555 of file GlobalChi2Fitter.cxx.

8555 {
8556 if (cache.m_msEntrance == nullptr) {
8557 const TrackingGeometry *geometry = trackingGeometry(cache, ctx);
8558
8559 if (geometry != nullptr) {
8560 cache.m_msEntrance = geometry->trackingVolume("MuonSpectrometerEntrance");
8561 } else {
8562 ATH_MSG_ERROR("Tracking Geometry not available");
8563 }
8564
8565 /*
8566 * Check, if we managed to find an entrance.
8567 */
8568 if (cache.m_msEntrance == nullptr) {
8569 ATH_MSG_ERROR("MS entrance not available");
8570 }
8571 }
8572
8573 return cache.m_msEntrance != nullptr;
8574 }

◆ fillAfromMeasurements()

void Trk::GlobalChi2Fitter::fillAfromMeasurements ( const Cache & cache,
GXFTrajectory & trajectory,
Amg::SymMatrixX & a )
staticprivate

Definition at line 5750 of file GlobalChi2Fitter.cxx.

5754 {
5755 const int nFitPars = trajectory.numberOfFitParameters();
5756 const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5757
5758 for (int k = 0; k < nFitPars; k++) {
5759 for (int l = k; l < nFitPars; l++) {
5760 const int minMeas = std::max(cache.m_firstmeasurement[k], cache.m_firstmeasurement[l]);
5761 const int maxMeas = std::min(cache.m_lastmeasurement[k], cache.m_lastmeasurement[l]);
5762
5763 double a_kl = 0;
5764 for (int measno = minMeas; measno < maxMeas; measno++) {
5765 a_kl += weightDeriv(measno, k) * weightDeriv(measno, l);
5766 }
5767
5768 a.fillSymmetric(l, k, a_kl);
5769 }
5770 }
5771 }
l
Printing final latex table to .tex output file.

◆ fillAfromScatterers()

void Trk::GlobalChi2Fitter::fillAfromScatterers ( GXFTrajectory & trajectory,
Amg::SymMatrixX & a )
staticprivate

Definition at line 5773 of file GlobalChi2Fitter.cxx.

5776 {
5777 const int nFitPars = trajectory.numberOfFitParameters();
5778 const int nPerPars = trajectory.numberOfPerigeeParameters();
5779 const int nScatPars = 2 * trajectory.numberOfScatterers();
5780 const int nBrem = trajectory.numberOfBrems();
5781 const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5782
5783 const Amg::VectorX & res = trajectory.residuals();
5784 const auto & scatSigmas = trajectory.scatteringSigmas();
5785
5786 const int nMeas = (int) res.size();
5787
5788 int scatno = 0;
5789
5790 /*
5791 * Direct contribution on the diagonal from the scatterer itself.
5792 */
5793 for (int k = nPerPars; k < nPerPars + nScatPars; k += 2) {
5794 a(k, k) += 1. / std::pow(scatSigmas[scatno].first, 2);
5795 a(k + 1, k + 1) += 1. / std::pow(scatSigmas[scatno].second, 2);
5796
5797 scatno++;
5798 }
5799
5800 /*
5801 * Indirect contribution on the qOverP and brems derivatives.
5802 */
5803 for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5804 for (int k = 4; k < nFitPars; k++) {
5805 if (k == 5) {
5806 k = nPerPars + nScatPars;
5807 }
5808
5809 for (int l = k; l < nFitPars; l++) {
5810 if (l == 5) {
5811 l = nPerPars + nScatPars;
5812 }
5813
5814 const double a_kl = a(l, k) + weightDeriv(measno, k) * weightDeriv(measno, l);
5815 a.fillSymmetric(l, k, a_kl);
5816 }
5817 }
5818 }
5819 }
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorX
Dynamic Vector - dynamic allocation.

◆ fillBfromMeasurements()

void Trk::GlobalChi2Fitter::fillBfromMeasurements ( const Cache & cache,
GXFTrajectory & trajectory,
Amg::VectorX & b )
staticprivate

Definition at line 5706 of file GlobalChi2Fitter.cxx.

5710 {
5711 const int nFitPars = trajectory.numberOfFitParameters();
5712 const int nPerPars = trajectory.numberOfPerigeeParameters();
5713 const int nScatPars = 2 * trajectory.numberOfScatterers();
5714 const int nBrem = trajectory.numberOfBrems();
5715 const Amg::MatrixX & weightDeriv = trajectory.weightedResidualDerivatives();
5716
5717 const Amg::VectorX & res = trajectory.residuals();
5718 const Amg::VectorX & error = trajectory.errors();
5719
5720 const int nMeas = (int) res.size();
5721
5722 for (int k = 0; k < nFitPars; k++) {
5723 const int minMeasK = cache.m_firstmeasurement[k];
5724 const int maxMeasK = cache.m_lastmeasurement[k];
5725
5726 /*
5727 * NOTE: It is necessary to do r * invError * weight instead of doing
5728 * r / error * w. Otherwise, the implementation tests fail do to
5729 * numerical reasons.
5730 */
5731 for (int measno = minMeasK; measno < maxMeasK; measno++) {
5732 b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5733 }
5734
5735 /*
5736 * For qOverP and brems, we also have a contribution to brems elements.
5737 *
5738 * NOTE: It is necessary to do r * invError * weight instead of doing
5739 * r / error * w. Otherwise, the implementation tests fail do to
5740 * numerical reasons.
5741 */
5742 if (k == 4 || k >= nPerPars + nScatPars) {
5743 for (int measno = nMeas - nBrem; measno < nMeas; measno++) {
5744 b[k] += res[measno] * (1. / error[measno]) * weightDeriv(measno, k);
5745 }
5746 }
5747 }
5748 }

◆ fillDerivatives()

void Trk::GlobalChi2Fitter::fillDerivatives ( GXFTrajectory & traj) const
private

Definition at line 5497 of file GlobalChi2Fitter.cxx.

5499 {
5500 ATH_MSG_DEBUG("fillDerivatives");
5501
5502 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5503 int scatno = 0;
5504 int bremno = 0;
5505 int measno = 0;
5506 const int nscatupstream = trajectory.numberOfUpstreamScatterers();
5507 const int nbremupstream = trajectory.numberOfUpstreamBrems();
5508 const int nscat = trajectory.numberOfScatterers();
5509 const int nbrem = trajectory.numberOfBrems();
5510 const int nperparams = trajectory.numberOfPerigeeParameters();
5511
5512 Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5513 Amg::VectorX & error = trajectory.errors();
5514
5515 const int nmeas = (int) weightderiv.rows();
5516
5517 for (std::unique_ptr<GXFTrackState> & state : states) {
5518 if (state->getStateType(TrackStateOnSurface::Measurement)) {
5519 TrackState::MeasurementType const hittype = state->measurementType();
5520 const MeasurementBase *measbase = state->measurement();
5521 const auto [scatmin, scatmax] = std::minmax(scatno, nscatupstream);
5522 const auto [bremmin, bremmax] = std::minmax(bremno, nbremupstream);
5523
5524 Amg::MatrixX & derivatives = state->derivatives();
5525
5526 /*
5527 * Get the stereo angles for SCT and TGC.
5528 */
5529 const double sinStereo =
5530 hittype == TrackState::SCT || hittype == TrackState::TGC ?
5531 state->sinStereo() :
5532 0;
5533 const double cosStereo =
5534 sinStereo != 0 ?
5535 std::sqrt(1 - std::pow(sinStereo, 2)) :
5536 1.;
5537
5538 /*
5539 * For SCT and TGC we need modified derivatives, taking into account
5540 * the orientation.This lambda chooses the correct accessor and rotates
5541 * the derivative accordingly.
5542 */
5543 auto getThisDeriv = [sinStereo, cosStereo, &derivatives](int i, int j) -> double {
5544 if (i == 0 && sinStereo != 0) {
5545 return derivatives(0, j) * cosStereo + sinStereo * derivatives(1, j);
5546 } else {
5547 return derivatives(i, j);
5548 }
5549 };
5550
5551 for (int i = 0; i < 5; i++) {
5552 if (!measbase->localParameters().contains(Trk::ParamDefsAccessor::pardef[i])) {
5553 continue;
5554 }
5555
5556 /*
5557 * SCT and TGC have all information stored in the first parameter.
5558 */
5559 if ((hittype == TrackState::SCT || hittype == TrackState::TGC) && i > 0) {
5560 break;
5561 }
5562
5563 if (trajectory.numberOfPerigeeParameters() > 0) {
5564 const int cols = trajectory.m_straightline ? 4 : 5;
5565
5566 if (i == 0 && sinStereo != 0) {
5567 weightderiv.row(measno).head(cols) =
5568 (derivatives.row(0).head(cols) * cosStereo +
5569 sinStereo * derivatives.row(1).head(cols)) /
5570 error[measno];
5571 } else {
5572 weightderiv.row(measno).head(cols) = derivatives.row(i).head(cols) / error[measno];
5573 }
5574 }
5575
5576 for (int j = scatmin; j < scatmax; j++) {
5577 if (trajectory.prefit() == 1) {
5578 const int index = nperparams + j;
5579 weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5580 } else {
5581 const int index = nperparams + 2 * j;
5582 weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5583 weightderiv(measno, index + 1) = getThisDeriv(i, index + 1) / error[measno];
5584 }
5585 }
5586
5587 for (int j = bremmin; j < bremmax; j++) {
5588 const int index = j + nperparams + 2 * nscat;
5589 weightderiv(measno, index) = getThisDeriv(i, index) / error[measno];
5590 }
5591
5592 measno++;
5593 }
5594 } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5595 double *errors = state->measurementErrors();
5596 for (int i = 0; i < 5; i++) {
5597 if (errors[i] > 0) {
5598 measno++;
5599 }
5600 }
5601 } else if (
5602 state->getStateType(TrackStateOnSurface::Scatterer) &&
5603 ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5604 ) {
5605 scatno++;
5606 }
5607
5608 if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5609 //limit values to avoid FPE overflow or div by zero
5610 const double qoverpbrem = limitInversePValue(1000 * state->trackParameters()->parameters()[Trk::qOverP]);
5611 const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5612
5613 const double mass = .001 * trajectory.mass();
5614
5615 const auto thisMeasurementIdx{nmeas - nbrem + bremno};
5616 //references (courtesy of Christos Anastopoulos):
5617 //https://inspirehep.net/files/a810ad0047a22af32fbff587c6c98ce5
5618 //https://its.cern.ch/jira/browse/ATLASRECTS-6213
5619 auto multiplier = [] (double mass, double qOverP){
5620 return std::copysign(1./(qOverP * qOverP * std::sqrt(1. + mass * mass * qOverP * qOverP)), qOverP);
5621 };
5622 const auto qoverpTerm {multiplier(mass, qoverp) / error[thisMeasurementIdx]};
5623 const auto qoverpBremTerm {multiplier(mass, qoverpbrem) / error[thisMeasurementIdx]};
5624
5625 if (trajectory.numberOfPerigeeParameters() > 0) {
5626 weightderiv(thisMeasurementIdx, 4) = qoverpBremTerm - qoverpTerm;
5627 }
5628 //
5629 const auto bremNoBase = nperparams + 2 * nscat;
5630 if (bremno < nbremupstream) {
5631 weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpTerm;
5632 for (int bremno2 = bremno + 1; bremno2 < nbremupstream; bremno2++) {
5633 weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpTerm - qoverpBremTerm;
5634 }
5635 } else {
5636 weightderiv(thisMeasurementIdx, bremNoBase + bremno) = qoverpBremTerm;
5637 for (int bremno2 = nbremupstream; bremno2 < bremno; bremno2++) {
5638 weightderiv(thisMeasurementIdx, bremNoBase + bremno2) = qoverpBremTerm - qoverpTerm;
5639 }
5640 }
5641 bremno++;
5642 }
5643 }
5644 }
std::string head(std::string s, const std::string &pattern)
head of a string

◆ fillFirstLastMeasurement()

void Trk::GlobalChi2Fitter::fillFirstLastMeasurement ( Cache & cache,
GXFTrajectory & trajectory )
staticprivate

Definition at line 5646 of file GlobalChi2Fitter.cxx.

5649 {
5650 const int nFitPars = trajectory.numberOfFitParameters();
5651 const int nPerPars = trajectory.numberOfPerigeeParameters();
5652 const int nScatPars = 2 * trajectory.numberOfScatterers();
5653 const int nBrem = trajectory.numberOfBrems();
5654 const int nUpstreamStates = trajectory.numberOfUpstreamStates();
5655
5656 const Amg::VectorX & res = trajectory.residuals();
5657 const int nMeas = (int) res.size();
5658
5659 cache.m_firstmeasurement.resize(nFitPars);
5660 cache.m_lastmeasurement.resize(nFitPars);
5661
5662 for (int i = 0; i < nPerPars; i++) {
5663 cache.m_firstmeasurement[i] = 0;
5664 cache.m_lastmeasurement[i] = nMeas - nBrem;
5665 }
5666
5667 int measno = 0;
5668 int scatno = 0;
5669 int bremno = 0;
5670 for (int i = 0; i < (int) trajectory.trackStates().size(); i++) {
5671 const std::unique_ptr<GXFTrackState> & state = trajectory.trackStates()[i];
5672 const GXFMaterialEffects *meff = state->materialEffects();
5673
5674 if (meff == nullptr) {
5675 measno += state->numberOfMeasuredParameters();
5676 continue;
5677 }
5678
5679 const int firstMeasurement = i < nUpstreamStates ? 0 : measno;
5680 const int lastMeasurement = i < nUpstreamStates ? measno : nMeas - nBrem;
5681
5682 if (meff->sigmaDeltaTheta() != 0
5683 && (trajectory.prefit() == 0 || meff->deltaE() == 0)) {
5684 const int scatterPos = nPerPars + 2 * scatno;
5685
5686 cache.m_firstmeasurement[scatterPos] = firstMeasurement;
5687 cache.m_lastmeasurement[scatterPos] = lastMeasurement;
5688
5689 cache.m_firstmeasurement[scatterPos + 1] = firstMeasurement;
5690 cache.m_lastmeasurement[scatterPos + 1] = lastMeasurement;
5691
5692 scatno++;
5693 }
5694
5695 if (meff->sigmaDeltaE() > 0) {
5696 const int bremPos = nPerPars + nScatPars + bremno;
5697
5698 cache.m_firstmeasurement[bremPos] = firstMeasurement;
5699 cache.m_lastmeasurement[bremPos] = lastMeasurement;
5700
5701 bremno++;
5702 }
5703 }
5704 }

◆ fillResidualsAndErrors()

void Trk::GlobalChi2Fitter::fillResidualsAndErrors ( const EventContext & ctx,
const Cache & cache,
GXFTrajectory & trajectory,
const int it,
Amg::VectorX & b,
int & bremno_maxbrempull,
GXFTrackState *& state_maxbrempull ) const
private

Definition at line 5073 of file GlobalChi2Fitter.cxx.

5081 {
5082 ATH_MSG_DEBUG("fillResidualsAndErrors");
5083
5084 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
5085
5086 /*
5087 * The residual and error vectors, we want to fill in this function.
5088 */
5089 Amg::VectorX & res = trajectory.residuals();
5090 Amg::VectorX & error = trajectory.errors();
5091
5092 /*
5093 * These variables are used inside the preprocessing loop for counting and
5094 * managing some quantities.
5095 */
5096 int scatno = 0;
5097 int bremno = 0;
5098 int measno = 0;
5099
5100 /*
5101 * Total number of measurements, and brems and perigee parameters. This is
5102 * used later to fill the residual and error vector to find the offsets.
5103 */
5104 const int nmeas = (int) res.size();
5105 const int nbrem = trajectory.numberOfBrems();
5106 const int nperpars = trajectory.numberOfPerigeeParameters();
5107
5108 /*
5109 * Under certain circumstances, we create new pseudo measurements. Here are
5110 * the static conditions. Later, we have also for each state a more
5111 * confining check.
5112 */
5113 const int nidhits = trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits();
5114 const int nDOF = trajectory.nDOF();
5115 const bool doNewPseudoMeasurements = (
5116 1 < it &&
5117 it <= 100 &&
5118 nDOF != 0 &&
5119 std::abs((trajectory.prevchi2() - trajectory.chi2()) / nDOF) < 15 &&
5120 nidhits < trajectory.numberOfHits() &&
5121 (nperpars == 0 || nidhits > 0)
5122 );
5123
5124 /*
5125 * Temporary quantities.
5126 * - chi2 will be used later to set the new chi2.
5127 * - maxbrempull collects the elosspull for the kink with the largest
5128 * brems. It is initised to -0.2 to consider only definitely negative
5129 * pulls.
5130 */
5131 double chi2 = 0;
5132 double maxbrempull = -0.2;
5133
5134 /*
5135 * Loop over all hits and do some preprocessing. In this step, we do:
5136 * - Get residuals
5137 * - Get errors
5138 * - Get scattering angles
5139 * - Fill b-vector and chi2 with scattering effects (others fill later)
5140 */
5141 for (int hitno = 0; hitno < (int) states.size(); hitno++) {
5142 std::unique_ptr<GXFTrackState> & state = states[hitno];
5143 const TrackParameters *currenttrackpar = state->trackParameters();
5144 TrackState::MeasurementType const hittype = state->measurementType();
5145 const MeasurementBase *measbase = state->measurement();
5146
5147 /*
5148 * Measurements and outliers.
5149 */
5150 if (state->getStateType(TrackStateOnSurface::Measurement)) {
5151 /*
5152 * Create new pseudo measurements when the static check (evaluated
5153 * outside the loop) and the dynamic checks both pass
5154 */
5155 if (
5156 doNewPseudoMeasurements &&
5157 hittype == TrackState::Pseudo &&
5158 !state->associatedSurface().isFree() &&
5159 !state->isRecalibrated()
5160 ) {
5161 Amg::MatrixX covMatrix(1, 1);
5162 covMatrix(0, 0) = 100;
5163
5164 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
5165 LocalParameters(DefinedParameter(currenttrackpar->parameters()[Trk::locY], Trk::locY)),
5166 std::move(covMatrix),
5167 currenttrackpar->associatedSurface()
5168 );
5169
5170 state->setMeasurement(std::move(newpseudo));
5171 measbase = state->measurement();
5172 }
5173
5174 /*
5175 * Separate all parameters in the residuals and errors. We will handle
5176 * them separately, asuming them uncorrelated.
5177 */
5178 double *errors = state->measurementErrors();
5179 std::array<double,5> residuals = m_residualPullCalculator->residuals(measbase, currenttrackpar, ResidualPull::Biased, hittype);
5180 for (int i = 0; i < 5; i++) {
5181 /*
5182 * Skip the parameter, if there is no accessor for it.
5183 */
5184 if (!measbase->localParameters().contains(Trk::ParamDefsAccessor::pardef[i])) {
5185 continue;
5186 }
5187
5188 /*
5189 * SCT and TGC are 1-dimensional, so we can skip the other parameters.
5190 */
5191 if (i > 0 && (hittype == TrackState::SCT || hittype == TrackState::TGC)) {
5192 continue;
5193 }
5194
5195 error[measno] =
5196 (trajectory.prefit() > 0 && (hittype == TrackState::MDT || (hittype == TrackState::CSC && !state->measuresPhi()))) ?
5197 2 :
5198 errors[i];
5199
5200 res[measno] = residuals[i];
5201
5202 /*
5203 * Ensure, that the phi-residual is mapped into the correct period.
5204 */
5205 if (i == 2) {
5206 res[measno] = -std::remainder(-res[measno], 2 * M_PI);
5207 }
5208
5209 measno++;
5210 }
5211 } else if (state->getStateType(TrackStateOnSurface::Outlier)) {
5212 /*
5213 * NOTE: It seems the residuals are not set in this step. Why?
5214 */
5215 double *errors = state->measurementErrors();
5216 for (int i = 0; i < 5; i++) {
5217 if (errors[i] > 0) {
5218 error[measno] = errors[i];
5219 measno++;
5220 }
5221 }
5222 }
5223
5224 /*
5225 * Scattering angles contribute to the b-vector and the chi2.
5226 */
5227 if (
5228 state->getStateType(TrackStateOnSurface::Scatterer) &&
5229 ((trajectory.prefit() == 0) || state->materialEffects()->deltaE() == 0)
5230 ) {
5231 const double deltaPhi = state->materialEffects()->deltaPhi();
5232 const double measDeltaPhi = state->materialEffects()->measuredDeltaPhi();
5233 const double sigma2deltaPhi = std::pow(state->materialEffects()->sigmaDeltaPhi(), 2);
5234 const double deltaTheta = state->materialEffects()->deltaTheta();
5235 const double sigma2deltaTheta = std::pow(state->materialEffects()->sigmaDeltaTheta(), 2);
5236
5237 if (trajectory.prefit() != 1) {
5238 b[nperpars + 2 * scatno] -= (deltaPhi - measDeltaPhi) / sigma2deltaPhi;
5239 b[nperpars + 2 * scatno + 1] -= deltaTheta / sigma2deltaTheta;
5240 } else {
5241 b[nperpars + scatno] -= deltaTheta / sigma2deltaTheta;
5242 }
5243
5244 chi2 += (
5245 deltaPhi * deltaPhi / sigma2deltaPhi +
5246 deltaTheta * deltaTheta / sigma2deltaTheta
5247 );
5248
5249 scatno++;
5250 }
5251
5252 /*
5253 * Energy loss will be considered in the form of a kink.
5254 */
5255 if ((state->materialEffects() != nullptr) && state->materialEffects()->sigmaDeltaE() > 0) {
5256 double averagenergyloss = std::abs(state->materialEffects()->deltaE());
5257 const double qoverpbrem = limitInversePValue(1000 * states[hitno]->trackParameters()->parameters()[Trk::qOverP]);
5258 const double qoverp = limitInversePValue(qoverpbrem - state->materialEffects()->delta_p());
5259 const double pbrem = 1. / std::abs(qoverpbrem);
5260 const double p = 1. / std::abs(qoverp);
5261 const double mass = .001 * trajectory.mass();
5262 const double energy = std::sqrt(p * p + mass * mass);
5263 const double bremEnergy = std::sqrt(pbrem * pbrem + mass * mass);
5264
5265 const double resMaterial = .001 * averagenergyloss - energy + bremEnergy;
5266 res[nmeas - nbrem + bremno] = resMaterial;
5267
5268 const double sigde = state->materialEffects()->sigmaDeltaE();
5269 const double sigdepos = state->materialEffects()->sigmaDeltaEPos();
5270 const double sigdeneg = state->materialEffects()->sigmaDeltaENeg();
5271
5272 double errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5273 error[nmeas - nbrem + bremno] = errorMaterial;
5274
5275 /*
5276 * There is already a kink in the trajectory. No need to look for more.
5277 * - Set the maxbrempull to a small value, so no future candidate can
5278 * be found.
5279 * - Reset the pointer to the state, in case we have set one before.
5280 *
5281 * NOTE: I think, the new value of maxbrempull should be -inf since it
5282 * allows for some edge case pulls. Not sure if bug or feature.
5283 */
5284 if (state->materialEffects()->isKink()) {
5285 maxbrempull = -999999999;
5286 state_maxbrempull = nullptr;
5287 }
5288
5289 if (
5290 cache.m_asymeloss &&
5291 it > 0 &&
5292 trajectory.prefit() == 0 &&
5293 sigde > 0 &&
5294 sigde != sigdepos &&
5295 sigde != sigdeneg
5296 ) {
5297 const double elosspull = resMaterial / errorMaterial;
5298
5299 if (trajectory.mass() > 100) {
5300 /*
5301 * If the absolute energy loss pull is too large, update the
5302 * sigmaDeltaE of the state and also update the error/
5303 */
5304 if (std::abs(elosspull) > 1) {
5305 if (elosspull < -1) {
5306 state->materialEffects()->setSigmaDeltaE(sigdepos);
5307 } else {
5308 state->materialEffects()->setSigmaDeltaE(sigdeneg);
5309 }
5310
5311 errorMaterial = .001 * state->materialEffects()->sigmaDeltaE();
5312 error[nmeas - nbrem + bremno] = errorMaterial;
5313 }
5314 } else if ((trajectory.numberOfTRTHits() == 0) || it >= 3) {
5315 /*
5316 * In case the state is not yet marked as a kink, we might want to
5317 * do so later. For this, we propose a maxbrempull state if either
5318 * - we did not provide an external kink with Gaudi and we want a
5319 * definitely negative elosspull.
5320 * or
5321 * - an external kink is given with Gaudi and we are on it now.
5322 */
5323 if (
5324 !state->materialEffects()->isKink() && (
5325 (m_fixbrem == -1 && elosspull < maxbrempull) ||
5326 (m_fixbrem >= 0 && bremno == m_fixbrem)
5327 )
5328 ) {
5329 bremno_maxbrempull = bremno;
5330 state_maxbrempull = state.get();
5331 maxbrempull = elosspull;
5332 }
5333 }
5334 }
5335
5336 if (
5337 it > 0 &&
5338 hitno >= 2 &&
5339 !m_calotoolparam.empty() &&
5340 trajectory.prefit() == 0 &&
5341 state->materialEffects()->sigmaDeltaPhi() == 0 &&
5342 state->materialEffects()->isMeasuredEloss() &&
5343 resMaterial / (.001 * state->materialEffects()->sigmaDeltaEAve()) > 2.5
5344 ) {
5345 const TrackParameters* parforcalo = states[hitno - 2]->trackParameters();
5346 const IPropagator* prop = &*m_propagator;
5347
5348 std::vector<MaterialEffectsOnTrack> calomeots =
5349 m_calotoolparam->extrapolationSurfacesAndEffects(
5350 *m_navigator->highestVolume(ctx),
5351 *prop,
5352 *parforcalo,
5353 parforcalo->associatedSurface(),
5355 Trk::muon);
5356
5357 /*
5358 * Update energyLoss, sigma, residual, and error if the parametrised
5359 * energy loss results in a absolute smaller pull.
5360 */
5361 if (calomeots.size() == 3) {
5362 averagenergyloss = std::abs(calomeots[1].energyLoss()->deltaE());
5363 const double newres = .001 * averagenergyloss - energy + bremEnergy;
5364 const double newerr = .001 * calomeots[1].energyLoss()->sigmaDeltaE();
5365
5366 const double oldPull = resMaterial / errorMaterial;
5367 const double newPull = newres / newerr;
5368
5369 if (std::abs(newPull) < std::abs(oldPull)) {
5370 ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
5371
5372 state->materialEffects()->setEloss(std::unique_ptr<EnergyLoss>(calomeots[1].energyLoss()->clone()));
5373 state->materialEffects()->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
5374 res[nmeas - nbrem + bremno] = newres;
5375 error[nmeas - nbrem + bremno] = newerr;
5376 }
5377 }
5378
5379 state->materialEffects()->setMeasuredEloss(false);
5380 }
5381
5382 bremno++;
5383 }
5384 }
5385
5386 /*
5387 * Sum up the chi2 contributions from all measurements.
5388 */
5389 for (int imeas = 0; imeas < nmeas; imeas++) {
5390 if (error[imeas] == 0) {
5391 continue;
5392 }
5393
5394 chi2 += std::pow(res[imeas] / error[imeas], 2);
5395 }
5396
5397 /*
5398 * Update trajectory with previous and current chi2
5399 */
5400 trajectory.setPrevChi2(trajectory.chi2());
5401 trajectory.setChi2(chi2);
5402 }
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
Gaudi::Property< int > m_fixbrem
ToolHandle< IMaterialEffectsOnTrackProvider > m_calotoolparam
ToolHandle< IResidualPullCalculator > m_residualPullCalculator
@ Biased
RP with track state including the hit.
double chi2(TH1 *h0, TH1 *h1)
@ anyDirection

◆ finalize()

StatusCode Trk::GlobalChi2Fitter::finalize ( )
overridevirtual

Definition at line 289 of file GlobalChi2Fitter.cxx.

289 {
290
291 ATH_MSG_INFO(m_fit_status[S_FITS] << " attempted track fits");
292 if (m_fit_status[S_FITS] > 0) {
293 ATH_MSG_INFO(m_fit_status[S_SUCCESSFUL_FITS] << " successful track fits");
294 ATH_MSG_INFO(m_fit_status[S_MAT_INV_FAIL]
295 << " track fits failed because of a matrix inversion failure");
296 ATH_MSG_INFO(m_fit_status[S_NOT_ENOUGH_MEAS]
297 << " tracks were rejected by the outlier logic");
298 ATH_MSG_INFO(m_fit_status[S_PROPAGATION_FAIL]
299 << " track fits failed because of a propagation failure");
300 ATH_MSG_INFO(m_fit_status[S_INVALID_ANGLES]
301 << " track fits failed because of an invalid angle (theta/phi)");
302 ATH_MSG_INFO(m_fit_status[S_NOT_CONVERGENT]
303 << " track fits failed because the fit did not converge");
304 ATH_MSG_INFO(m_fit_status[S_HIGH_CHI2]
305 << " tracks did not pass the chi^2 cut");
306 ATH_MSG_INFO(m_fit_status[S_LOW_MOMENTUM]
307 << " tracks were killed by the energy loss update");
308 }
309
310 return StatusCode::SUCCESS;
311 }
#define ATH_MSG_INFO(x)

◆ fit() [1/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const MeasurementSet & rots,
const TrackParameters & param,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 2401 of file GlobalChi2Fitter.cxx.

2407 {
2408 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Meas'BaseSet,,)");
2409
2410 Cache cache(this);
2411 initFieldCache(ctx,cache);
2412
2413 GXFTrajectory trajectory;
2414
2415 if (!m_straightlineprop) {
2416 trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
2417 }
2418
2419 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
2420
2421 for (const auto *itSet : rots) {
2422 if (itSet == nullptr) {
2423 ATH_MSG_WARNING("There is an empty MeasurementBase object in the track! Skip this object..");
2424 } else {
2425 makeProtoStateFromMeasurement(cache, trajectory, itSet);
2426 }
2427 }
2428
2429 std::unique_ptr<const TrackParameters> startpar(param.clone());
2430
2431 if (
2432 matEffects == muon &&
2433 trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0
2434 ) {
2435 cache.m_matfilled = true;
2436 trajectory.setPrefit(2);
2437
2438 myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects);
2439
2440 cache.m_matfilled = false;
2441
2442 if (!trajectory.converged()) {
2443 return nullptr;
2444 }
2445
2446 trajectory.setConverged(false);
2447 const TrackParameters *firstpar = trajectory.trackStates()[0]->trackParameters();
2448 const TrackParameters *lastpar = trajectory.trackStates().back()->trackParameters();
2449
2450 PerigeeSurface const persurf(firstpar->position() - 10 * firstpar->momentum().unit());
2451
2452 if (trajectory.trackStates().front()->measurementType() == TrackState::Pseudo) {
2453 Amg::MatrixX covMatrix(1, 1);
2454 covMatrix(0, 0) = 100;
2455
2456 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2457 LocalParameters(DefinedParameter(firstpar->parameters()[Trk::locY], Trk::locY)),
2458 std::move(covMatrix),
2459 firstpar->associatedSurface()
2460 );
2461
2462 trajectory.trackStates().front()->setMeasurement(std::move(newpseudo));
2463 }
2464
2465 if (trajectory.trackStates().back()->measurementType() == TrackState::Pseudo) {
2466 Amg::MatrixX covMatrix(1, 1);
2467 covMatrix(0, 0) = 100;
2468
2469 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2470 LocalParameters(DefinedParameter(lastpar->parameters()[Trk::locY], Trk::locY)),
2471 std::move(covMatrix),
2472 lastpar->associatedSurface()
2473 );
2474
2475 trajectory.trackStates().back()->setMeasurement(std::move(newpseudo));
2476 }
2477
2478 if (!trajectory.m_straightline) {
2479 trajectory.setPrefit(3);
2480 const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2481 startpar = trajectory.referenceParameters()->associatedSurface().createUniqueTrackParameters(
2482 refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2483 );
2484
2485 trajectory.reset();
2486
2487 myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects);
2488
2489 cache.m_matfilled = true;
2490
2491 if (!trajectory.converged()) {
2492 return nullptr;
2493 }
2494 }
2495
2496 const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2497 startpar = trajectory.referenceParameters()->associatedSurface().createUniqueTrackParameters(
2498 refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2499 );
2500
2501 trajectory.reset();
2502 trajectory.setPrefit(0);
2503
2504 if (trajectory.trackStates().front()->measurementType() == TrackState::Pseudo) {
2505 firstpar = trajectory.trackStates().front()->trackParameters();
2506
2507 Amg::MatrixX covMatrix(1, 1);
2508 covMatrix(0, 0) = 100;
2509
2510 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2511 LocalParameters(DefinedParameter(firstpar->parameters()[Trk::locY], Trk::locY)),
2512 std::move(covMatrix),
2513 firstpar->associatedSurface()
2514 );
2515
2516 trajectory.trackStates().front()->setMeasurement(std::move(newpseudo));
2517 double errors[5];
2518 errors[0] = errors[2] = errors[3] = errors[4] = -1;
2519 errors[1] = 10;
2520 trajectory.trackStates().front()->setMeasurementErrors(errors);
2521 }
2522
2523 if (trajectory.trackStates().back()->measurementType() == TrackState::Pseudo) {
2524 lastpar = trajectory.trackStates().back()->trackParameters();
2525
2526 Amg::MatrixX covMatrix(1, 1);
2527 covMatrix(0, 0) = 100;
2528
2529 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2530 LocalParameters(DefinedParameter(lastpar->parameters()[Trk::locY], Trk::locY)),
2531 std::move(covMatrix),
2532 lastpar->associatedSurface()
2533 );
2534
2535 trajectory.trackStates().back()->setMeasurement(std::move(newpseudo));
2536 double errors[5];
2537 errors[0] = errors[2] = errors[3] = errors[4] = -1;
2538 errors[1] = 10;
2539 trajectory.trackStates().back()->setMeasurementErrors(errors);
2540 }
2541 }
2542
2543 std::unique_ptr<Track> track;
2544
2545 if (startpar != nullptr) {
2546 track.reset(myfit(ctx,cache, trajectory, *startpar, runOutlier, matEffects));
2547 }
2548
2549 if (track != nullptr) {
2550 cache.incrementFitStatus(S_SUCCESSFUL_FITS);
2551 }
2552 cache.m_matfilled = false;
2553
2554 return track;
2555 }
Gaudi::Property< bool > m_straightlineprop
void makeProtoStateFromMeasurement(Cache &, GXFTrajectory &, const MeasurementBase *, const TrackParameters *trackpar=nullptr, bool isoutlier=false, int index=-1) const
@ NoField
Field is set to 0., 0., 0.,.
@ FullField
Field is set to be realistic, but within a given Volume.

◆ fit() [2/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const PrepRawDataSet & prds,
const TrackParameters & param,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 2180 of file GlobalChi2Fitter.cxx.

2186 {
2187 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(PRDS,TP,)");
2188 MeasurementSet rots;
2189
2190 for (const auto *prd : prds) {
2191 const Surface & prdsurf = (*prd).detectorElement()->surface((*prd).identify());
2192 const RIO_OnTrack *rot = nullptr;
2193 const PlaneSurface *plsurf = nullptr;
2194
2195 if (prdsurf.type() == Trk::SurfaceType::Plane)
2196 plsurf = static_cast < const PlaneSurface *>(&prdsurf);
2197
2198 const StraightLineSurface *slsurf = nullptr;
2199
2200 if (prdsurf.type() == Trk::SurfaceType::Line)
2201 slsurf = static_cast < const StraightLineSurface *>(&prdsurf);
2202
2203 if ((slsurf == nullptr) && (plsurf == nullptr)) {
2204 ATH_MSG_ERROR("Surface is neither PlaneSurface nor StraightLineSurface!");
2205 }
2206
2207 if (!m_broadROTcreator.empty() && (slsurf != nullptr)) {
2208 rot = m_broadROTcreator->correct(*prd, param, ctx);
2209 } else if (slsurf != nullptr) {
2210 AtaStraightLine const atasl(
2211 slsurf->center(),
2212 param.parameters()[Trk::phi],
2213 param.parameters()[Trk::theta],
2214 param.parameters()[Trk::qOverP],
2215 *slsurf
2216 );
2217 rot = m_ROTcreator->correct(*prd, atasl, ctx);
2218 } else if (plsurf != nullptr) {
2219 if (param.covariance() != nullptr) {
2220 AtaPlane const atapl(
2221 plsurf->center(),
2222 param.parameters()[Trk::phi],
2223 param.parameters()[Trk::theta],
2224 param.parameters()[Trk::qOverP],
2225 *plsurf,
2226 AmgSymMatrix(5)(*param.covariance())
2227 );
2228 rot = m_ROTcreator->correct(*prd, atapl, ctx);
2229 } else {
2230 AtaPlane const atapl(
2231 plsurf->center(),
2232 param.parameters()[Trk::phi],
2233 param.parameters()[Trk::theta],
2234 param.parameters()[Trk::qOverP],
2235 *plsurf
2236 );
2237 rot = m_ROTcreator->correct(*prd, atapl, ctx);
2238 }
2239 }
2240
2241 if (rot != nullptr) {
2242 rots.push_back(rot);
2243 }
2244 }
2245
2246 std::unique_ptr<Track> track =
2247 fit(ctx, rots, param, runOutlier, matEffects);
2248
2249 for (const auto *rot : rots) {
2250 delete rot;
2251 }
2252
2253 return track;
2254 }
#define AmgSymMatrix(dim)
ToolHandle< IRIO_OnTrackCreator > m_broadROTcreator
ToolHandle< IRIO_OnTrackCreator > m_ROTcreator
virtual std::unique_ptr< Track > fit(const EventContext &ctx, const PrepRawDataSet &, const TrackParameters &, const RunOutlierRemoval runOutlier=false, const ParticleHypothesis matEffects=nonInteracting) const override final
std::vector< const MeasurementBase * > MeasurementSet
vector of fittable measurements
Definition FitterTypes.h:30
ParametersT< TrackParametersDim, Charged, StraightLineSurface > AtaStraightLine
ParametersT< TrackParametersDim, Charged, PlaneSurface > AtaPlane

◆ fit() [3/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const Track & inputTrack,
const MeasurementSet & addMeasColl,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 2257 of file GlobalChi2Fitter.cxx.

2263 {
2264 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,Meas'BaseSet,,)");
2265
2266 Cache cache(this);
2267 initFieldCache(ctx,cache);
2268
2269 GXFTrajectory trajectory;
2270
2271 if (!m_straightlineprop) {
2272 trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
2273 }
2274
2275 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
2276
2277 const TrackParameters *minpar = inputTrack.perigeeParameters();
2278
2279 if (minpar == nullptr) {
2280 minpar = *(inputTrack.trackParameters()->begin());
2281 }
2282
2283 MeasurementSet const hitColl;
2284
2285 // collect MBs from Track (speed: assume this method is used for extending track at end)
2286 Trk::TrackStates::const_iterator itStates = inputTrack.trackStateOnSurfaces()->begin();
2287 const Trk::TrackStates::const_iterator endState = inputTrack.trackStateOnSurfaces()->end();
2288
2289 const bool old_reintoutl = cache.m_reintoutl;
2290 cache.m_reintoutl = false;
2291 const bool tmpasymeloss = cache.m_asymeloss;
2292
2293 if (matEffects == electron) {
2294 cache.m_asymeloss = true;
2295 }
2296
2297 for (; itStates != endState; ++itStates) {
2298 makeProtoState(cache, trajectory, *itStates);
2299 if (
2300 matEffects == electron &&
2301 !trajectory.trackStates().empty() &&
2302 (trajectory.trackStates().back()->materialEffects() != nullptr) &&
2303 trajectory.trackStates().back()->materialEffects()->sigmaDeltaE() > 50.001
2304 ) {
2305 trajectory.trackStates().back()->materialEffects()->setKink(true);
2306 }
2307 }
2308
2309 cache.m_reintoutl = old_reintoutl;
2310
2311 for (const auto & measBase : addMeasColl) {
2312 if (measBase == nullptr) {
2313 ATH_MSG_WARNING("There is an empty MeasurementBase object in the track! Skip this object..");
2314 continue;
2315 }
2316
2317 makeProtoStateFromMeasurement(cache, trajectory, measBase);
2318 }
2319
2320 // fit set of MeasurementBase using main method, start with first TrkParameter in inputTrack
2321 std::unique_ptr<Track> track(myfit(ctx, cache, trajectory, *minpar, runOutlier, matEffects));
2322 cache.m_asymeloss = tmpasymeloss;
2323
2324 if (track != nullptr) {
2325 const double oldqual =
2326 inputTrack.fitQuality()->numberDoF() != 0 ?
2327 inputTrack.fitQuality()->chiSquared() / inputTrack.fitQuality()->numberDoF() :
2328 -999;
2329
2330 const double newqual =
2331 track->fitQuality()->numberDoF() != 0 ?
2332 track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() :
2333 -999;
2334
2335 if (m_extensioncuts && runOutlier && newqual > 2 && newqual > 2 * oldqual) {
2336 ATH_MSG_DEBUG("Extension rejected");
2337
2338 cache.incrementFitStatus(S_HIGH_CHI2);
2339 track.reset(nullptr);
2340 }
2341 }
2342
2343 if (track != nullptr) {
2344 cache.incrementFitStatus(S_SUCCESSFUL_FITS);
2345 }
2346
2347 return track;
2348 }
Gaudi::Property< bool > m_extensioncuts

◆ fit() [4/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const Track & intrk,
const PrepRawDataSet & prds,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 2353 of file GlobalChi2Fitter.cxx.

2359 {
2360 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,PRDS,)");
2361 MeasurementSet rots;
2362 const TrackParameters *hitparam = intrk.trackParameters()->back();
2363
2364 for (const auto *prd : prds) {
2365 const Surface & prdsurf = (*prd).detectorElement()->surface((*prd).identify());
2366
2367 Amg::VectorX parameterVector = hitparam->parameters();
2368 std::unique_ptr<const TrackParameters>const trackparForCorrect(
2369 hitparam->associatedSurface().createUniqueTrackParameters(
2370 parameterVector[Trk::loc1],
2371 parameterVector[Trk::loc2],
2372 parameterVector[Trk::phi],
2373 parameterVector[Trk::theta],
2374 parameterVector[Trk::qOverP],
2375 AmgSymMatrix(5)(*hitparam->covariance())
2376 )
2377 );
2378
2379 const RIO_OnTrack *rot = nullptr;
2380
2381 if (!m_broadROTcreator.empty() && prdsurf.type() == Trk::SurfaceType::Line) {
2382 rot = m_broadROTcreator->correct(*prd, *hitparam, ctx);
2383 } else {
2384 rot = m_ROTcreator->correct(*prd, *trackparForCorrect, ctx);
2385 }
2386
2387 if (rot != nullptr) {
2388 rots.push_back(rot);
2389 }
2390 }
2391
2392 std::unique_ptr<Track> track = fit(ctx,intrk, rots, runOutlier, matEffects);
2393
2394 for (const auto *rot : rots) {
2395 delete rot;
2396 }
2397
2398 return track;
2399 }
@ loc2
generic first and second local coordinate
Definition ParamDefs.h:35
@ loc1
Definition ParamDefs.h:34

◆ fit() [5/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const Track & inputTrack,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 1795 of file GlobalChi2Fitter.cxx.

1800 {
1801 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,)");
1802
1803 Cache cache(this);
1804 initFieldCache(ctx,cache);
1805
1806 GXFTrajectory trajectory;
1807
1808 if (!m_straightlineprop) {
1809 trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
1810 }
1811
1812 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
1813
1814 return std::unique_ptr<Track>(
1815 fitIm(ctx, cache, inputTrack, runOutlier, matEffects));
1816 }

◆ fit() [6/6]

std::unique_ptr< Track > Trk::GlobalChi2Fitter::fit ( const EventContext & ctx,
const Track & intrk1,
const Track & intrk2,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
finaloverridevirtual

Definition at line 316 of file GlobalChi2Fitter.cxx.

322 {
323 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,Track,)");
324
325 Cache cache(this);
326 initFieldCache(ctx,cache);
327
328 GXFTrajectory trajectory;
329 if (!m_straightlineprop) {
330 trajectory.m_straightline = (
331 !cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn()
332 );
333 }
334
335 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
336
337 const bool firstismuon = isMuonTrack(intrk1);
338 const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
339 const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
340 const bool muonisstraight = muontrack->info().trackProperties(TrackInfo::StraightTrack);
341 bool measphi = false;
342
343 for (const auto *i : *(muontrack->measurementsOnTrack())) {
344 const RIO_OnTrack *rot = nullptr;
345
347 const auto *const crot = static_cast<const CompetingRIOsOnTrack *>(i);
348 rot = &crot->rioOnTrack(0);
349 } else {
351 rot =static_cast<const RIO_OnTrack *>(i);
352 }
353 }
354 if ((rot != nullptr) && !m_DetID->is_mdt(rot->identify())) {
355 const Surface *surf = &rot->associatedSurface();
356 const Amg::Vector3D measdir = surf->transform().rotation().col(0);
357 const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
358 const double dotprod2 = measdir.dot(
359 Amg::Vector3D(surf->center().x(), surf->center().y(), 0) /
360 surf->center().perp());
361 if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
362 measphi = true;
363 break;
364 }
365 }
366 }
367
368 const IPropagator *prop = &*m_propagator;
369 auto [firstidpar, lastidpar] = getFirstLastIdPar(*indettrack);
370
371 if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
372 return nullptr;
373 }
374
375 std::unique_ptr<const TrackParameters> parforcalo = unique_clone(firstismuon ? firstidpar : lastidpar);
376
377 if (!cache.m_field_cache.solenoidOn()) {
378 const AmgVector(5) & newpars = parforcalo->parameters();
379
380 parforcalo=parforcalo->associatedSurface().createUniqueTrackParameters(
381 newpars[0], newpars[1], newpars[2], newpars[3], 1 / 5000., std::nullopt
382 );
383 }
384
385 std::vector < MaterialEffectsOnTrack > calomeots;
386 if (!m_useCaloTG) {
387 if (!m_calotool.empty()) {
388 calomeots = m_calotool->extrapolationSurfacesAndEffects(
389 *m_navigator->highestVolume(ctx),
390 *prop,
391 *parforcalo,
392 parforcalo->associatedSurface(),
395 );
396 }
397 } else {
398 m_caloMaterialProvider->getCaloMEOT(*indettrack, *muontrack, calomeots);
399 }
400
401 if (firstismuon) {
402 std::reverse(calomeots.begin(), calomeots.end());
403 }
404
405 if (calomeots.empty()) {
406 ATH_MSG_WARNING("No calorimeter material collected, failing fit");
407 return nullptr;
408 }
409
410 std::unique_ptr<Track> track;
411
412 const bool tmp = m_calomat;
413 cache.m_calomat = false;
414 const bool tmp2 = cache.m_extmat;
415 const bool tmp4 = cache.m_idmat;
416
417 const TrackParameters *measperid = indettrack->perigeeParameters();
418 const TrackParameters *measpermuon = muontrack->perigeeParameters();
419
420 const double qoverpid = measperid != nullptr ? measperid->parameters()[Trk::qOverP] : 0;
421 const double qoverpmuon = measpermuon != nullptr ? measpermuon->parameters()[Trk::qOverP] : 0;
422
423 const AmgSymMatrix(5) * errmatid = measperid != nullptr ? measperid->covariance() : nullptr;
424 const AmgSymMatrix(5) * errmatmuon = measpermuon != nullptr ? measpermuon->covariance() : nullptr;
425
426 if (
427 !firstismuon &&
428 (errmatid != nullptr) &&
429 (errmatmuon != nullptr) &&
430 qoverpmuon != 0 &&
431 !m_calotoolparam.empty() &&
433 ) {
434 const double piderror = std::sqrt((*errmatid) (4, 4)) / (qoverpid * qoverpid);
435 const double pmuonerror = std::sqrt((*errmatmuon) (4, 4)) / (qoverpmuon * qoverpmuon);
436 const double energyerror = std::sqrt(
437 calomeots[1].energyLoss()->sigmaDeltaE() *
438 calomeots[1].energyLoss()->sigmaDeltaE() + piderror * piderror +
439 pmuonerror * pmuonerror
440 );
441
442 if (
443 (std::abs(calomeots[1].energyLoss()->deltaE()) -
444 std::abs(1 / qoverpid) + std::abs(1 / qoverpmuon)
445 ) / energyerror > 5
446 ) {
447 ATH_MSG_DEBUG("Changing from measured to parametrized energy loss");
448 calomeots = m_calotoolparam->extrapolationSurfacesAndEffects(
449 *m_navigator->highestVolume(ctx),
450 *prop,
451 *parforcalo,
452 parforcalo->associatedSurface(),
455 );
456
457 if (calomeots.empty()) {
458 ATH_MSG_WARNING("No calorimeter material collected, failing fit");
459 return nullptr;
460 }
461 }
462 }
463
464 const int nfits = cache.m_fit_status[S_FITS];
465 bool firstfitwasattempted = false;
466
467 const bool caloEntranceIsValid = ensureValidEntranceCalo(ctx, cache);
468 if (!caloEntranceIsValid) {
469 return nullptr;
470 }
471
472 if (
473 (!cache.m_field_cache.toroidOn() && !cache.m_field_cache.solenoidOn()) ||
474 (
475 cache.m_getmaterialfromtrack &&
476 !muonisstraight &&
477 measphi &&
478 muontrack->info().trackFitter() != Trk::TrackInfo::Unknown &&
479 qoverpid * qoverpmuon > 0
480 )
481 ) {
482 track.reset(mainCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
483
484 if (cache.m_fit_status[S_FITS] == (unsigned int) (nfits + 1)) {
485 firstfitwasattempted = true;
486 }
487 }
488
489 if (
490 (track == nullptr) &&
491 !firstfitwasattempted &&
492 (cache.m_field_cache.toroidOn() || cache.m_field_cache.solenoidOn())
493 ) {
494 // Reset the trajectory
495 GXFTrajectory trajectory2;
496 trajectory2.m_straightline = trajectory.m_straightline;
497 trajectory2.m_fieldprop = trajectory.m_fieldprop;
498 trajectory = trajectory2;
499 track.reset(backupCombinationStrategy(ctx,cache, intrk1, intrk2, trajectory, calomeots));
500 }
501
502 bool pseudoupdated = false;
503
504 if (track != nullptr) {
505 for (std::unique_ptr<GXFTrackState> & pseudostate : trajectory.trackStates()) {
506 if (pseudostate == nullptr) {
507 continue;
508 }
509
510 if (
511 pseudostate->measurementType() != TrackState::Pseudo ||
512 !pseudostate->getStateType(TrackStateOnSurface::Measurement)
513 ) {
514 continue;
515 }
516
517 if ((pseudostate == nullptr) || pseudostate->fitQuality().chiSquared() < 10) {
518 continue;
519 }
520
521 const TrackParameters *pseudopar = pseudostate->trackParameters();
522 const std::unique_ptr<const TrackParameters> updpar(m_updator->removeFromState(
523 *pseudopar,
524 pseudostate->measurement()->localParameters(),
525 pseudostate->measurement()->localCovariance()
526 ));
527
528 if (updpar == nullptr) {
529 continue;
530 }
531
533 covMatrix(0, 0) = 100;
534
535 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
536 LocalParameters(
537 DefinedParameter(updpar->parameters()[Trk::locY], Trk::locY)
538 ),
539 std::move(covMatrix),
540 pseudopar->associatedSurface()
541 );
542
543 pseudostate->setMeasurement(std::move(newpseudo));
544 double errors[5];
545 errors[0] = errors[2] = errors[3] = errors[4] = -1;
546 errors[1] = 10;
547 pseudostate->setMeasurementErrors(errors);
548 pseudoupdated = true;
549 }
550
551 if (pseudoupdated) {
552 trajectory.setConverged(false);
553 cache.m_matfilled = true;
554
555 track.reset(myfit(
556 ctx,
557 cache,
558 trajectory,
559 *track->perigeeParameters(),
560 false,
561 (cache.m_field_cache.toroidOn() || cache.m_field_cache.solenoidOn()) ? muon : nonInteracting
562 ));
563
564 cache.m_matfilled = false;
565 }
566 }
567
568 cache.m_fit_status[S_FITS] = nfits + 1;
569
570 if (track != nullptr) {
571 track->info().addPatternReco(intrk1.info());
572 track->info().addPatternReco(intrk2.info());
573 cache.incrementFitStatus(S_SUCCESSFUL_FITS);
574 }
575
576 cache.m_calomat = tmp;
577 cache.m_extmat = tmp2;
578 cache.m_idmat = tmp4;
579 return track;
580 }
virtual const Surface & associatedSurface() const override=0
returns the surface for the local to global transformation
ToolHandle< Trk::ITrkMaterialProviderTool > m_caloMaterialProvider
Track * backupCombinationStrategy(const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
Track * mainCombinationStrategy(const EventContext &ctx, Cache &, const Track &, const Track &, GXFTrajectory &, std::vector< MaterialEffectsOnTrack > &) const
Gaudi::Property< bool > m_calomat
Gaudi::Property< bool > m_useCaloTG
void reverse(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of reverse for DataVector/List.

◆ fitIm()

Track * Trk::GlobalChi2Fitter::fitIm ( const EventContext & ctx,
Cache & cache,
const Track & inputTrack,
const RunOutlierRemoval runOutlier,
const ParticleHypothesis matEffects ) const
private

Definition at line 1849 of file GlobalChi2Fitter.cxx.

1855 {
1856
1857 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::fit(Track,,)");
1858
1859 GXFTrajectory trajectory;
1860
1861 if (!m_straightlineprop) {
1862 trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
1863 }
1864
1865 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
1866
1867 if (inputTrack.trackStateOnSurfaces()->empty()) {
1868 ATH_MSG_WARNING("Track with zero track states, cannot perform fit");
1869 return nullptr;
1870 }
1871
1872 if (inputTrack.trackParameters()->empty()) {
1873 ATH_MSG_WARNING("Track without track parameters, cannot perform fit");
1874 return nullptr;
1875 }
1876
1877 std::unique_ptr<const TrackParameters> minpar = unique_clone(inputTrack.perigeeParameters());
1878 const TrackParameters *firstidpar = nullptr;
1879 const TrackParameters *lastidpar = nullptr;
1880
1881 if (minpar == nullptr) {
1882 minpar = unique_clone(*(inputTrack.trackParameters()->begin()));
1883 }
1884
1885 const bool tmpgetmat = cache.m_getmaterialfromtrack;
1886
1887 if (
1888 matEffects == Trk::nonInteracting ||
1889 inputTrack.info().trackFitter() == TrackInfo::Unknown
1890 ) {
1891 cache.m_getmaterialfromtrack = false;
1892 }
1893
1894 Trk::TrackStates::const_iterator itStates = inputTrack.trackStateOnSurfaces()->begin();
1895 const Trk::TrackStates::const_iterator endState = inputTrack.trackStateOnSurfaces()->end();
1896
1897 trajectory.trackStates().reserve(inputTrack.trackStateOnSurfaces()->size());
1898
1899 const Surface *firsthitsurf = nullptr;
1900 const Surface *lasthitsurf = nullptr;
1901 bool hasid = false;
1902 bool hasmuon = false;
1903 bool iscombined = false;
1904 bool seenphimeas = false;
1905 bool phiem = false;
1906 bool phibo = false;
1907
1908 for (; itStates != endState; ++itStates) {
1909 const auto *const pMeasurement = (**itStates).measurementOnTrack();
1910 if (
1911 (pMeasurement == nullptr) &&
1912 ((**itStates).materialEffectsOnTrack() != nullptr) &&
1913 matEffects != inputTrack.info().particleHypothesis()
1914 ) {
1915 continue;
1916 }
1917
1918 if (pMeasurement != nullptr) {
1919 const Surface *surf = &pMeasurement->associatedSurface();
1920 Identifier hitid = surf->associatedDetectorElementIdentifier();
1921 if (!hitid.is_valid()) {
1922 if (pMeasurement->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack)) {
1923 const CompetingRIOsOnTrack *crot = static_cast<const CompetingRIOsOnTrack *>(pMeasurement);
1924 hitid = crot->rioOnTrack(0).identify();
1925 }
1926 }
1927 if (hitid.is_valid()) {
1928 if (firsthitsurf == nullptr) {
1929 firsthitsurf = surf;
1930 }
1931 lasthitsurf = surf;
1932 if (m_DetID->is_indet(hitid)) {
1933 hasid = true;
1934 if (hasmuon) {
1935 iscombined = true;
1936 }
1937 if ((**itStates).trackParameters() != nullptr) {
1938 lastidpar = (**itStates).trackParameters();
1939 if (firstidpar == nullptr) {
1940 firstidpar = lastidpar;
1941 }
1942 }
1943 } else {
1944 if (!(**itStates).type(TrackStateOnSurface::Outlier)) {
1945 const Amg::Vector3D measdir = surf->transform().rotation().col(0);
1946 const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
1947 const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
1948 if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
1949 seenphimeas = true;
1950 if (std::abs(surf->center().z()) > 13000) {
1951 phiem = true;
1952 }
1953 if (surf->center().perp() > 9000 && std::abs(surf->center().z()) < 13000) {
1954 phibo = true;
1955 }
1956 }
1957 }
1958 hasmuon = true;
1959 if (hasid) {
1960 iscombined = true;
1961 }
1962 }
1963 }
1964
1965 if (iscombined && seenphimeas && (phiem || phibo)) {
1967 continue;
1968 }
1969 }
1970 }
1971 makeProtoState(cache, trajectory, *itStates);
1972 }
1973
1974 if (
1975 cache.m_getmaterialfromtrack && trajectory.numberOfScatterers() != 0 &&
1976 (hasmuon || cache.m_acceleration)
1977 ) {
1978 cache.m_matfilled = true;
1979 }
1980
1981 if (firstidpar == lastidpar) {
1982 firstidpar = lastidpar = nullptr;
1983 }
1984
1985 if (
1986 iscombined &&
1987 !cache.m_matfilled &&
1988 (
1989 m_DetID->is_indet(firsthitsurf->associatedDetectorElementIdentifier()) !=
1990 m_DetID->is_indet(lasthitsurf->associatedDetectorElementIdentifier())
1991 ) &&
1992 (firstidpar != nullptr)
1993 ) {
1994 if (m_DetID->is_indet(firsthitsurf->associatedDetectorElementIdentifier())) {
1995 minpar = unique_clone(lastidpar);
1996 } else {
1997 minpar = unique_clone(firstidpar);
1998 }
1999 }
2000
2001 const bool tmpacc = cache.m_acceleration;
2002 const bool tmpfiteloss = m_fiteloss;
2003 const bool tmpsirecal = cache.m_sirecal;
2004 std::unique_ptr<Track> tmptrack = nullptr;
2005
2006 if (matEffects == Trk::proton || matEffects == Trk::kaon || matEffects == Trk::electron) {
2007 ATH_MSG_DEBUG("call myfit(GXFTrajectory,TP,,)");
2008 cache.m_fiteloss = true;
2009 cache.m_sirecal = false;
2010
2011 if (matEffects == Trk::electron) {
2012 cache.m_asymeloss = true;
2013 }
2014
2015 tmptrack.reset(myfit(ctx, cache, trajectory, *minpar, false, matEffects));
2016 cache.m_sirecal = tmpsirecal;
2017
2018 if (tmptrack == nullptr) {
2019 cache.m_matfilled = false;
2020 cache.m_getmaterialfromtrack = tmpgetmat;
2021 cache.m_acceleration = tmpacc;
2022 cache.m_fiteloss = tmpfiteloss;
2023 return nullptr;
2024 }
2025
2026 int nscats = 0;
2027 bool isbrem = false;
2028 double bremdp = 0;
2029 unsigned int n_brem=0;
2030
2031 for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
2032 GXFMaterialEffects *meff = state->materialEffects();
2033
2034 if (meff != nullptr) {
2035 nscats++;
2036
2037 const TrackParameters *layerpars = state->trackParameters();
2038 const MaterialProperties *matprop = meff->materialProperties();
2039
2040 const double p = 1. / std::abs(layerpars->parameters()[Trk::qOverP] - .0005 * meff->delta_p());
2041
2042 std::optional<Amg::Vector2D> locpos(state->associatedSurface().globalToLocal(layerpars->position()));
2043 const Amg::Vector3D layerNormal(state->associatedSurface().normal(*locpos));
2044 double costracksurf = 1.;
2045
2046 costracksurf = std::abs(layerNormal.dot(layerpars->momentum().unit()));
2047
2048 const double oldde = meff->deltaE();
2049
2050 std::unique_ptr<EnergyLoss> eloss;
2051 double sigmascat = 0;
2052
2053 if (matprop != nullptr) {
2054 eloss = std::make_unique<EnergyLoss>(
2055 m_elosstool->energyLoss(*matprop, p, 1. / costracksurf,
2056 Trk::alongMomentum, matEffects));
2057 sigmascat = std::sqrt(m_scattool->sigmaSquare(*matprop, p, 1. / costracksurf, matEffects));
2058
2059 if (eloss != nullptr) {
2060 meff->setDeltaE(eloss->deltaE());
2061 }
2062 } else {
2063 MaterialProperties const tmpprop(1., meff->x0(), 0., 0., 0., 0.);
2064 sigmascat = std::sqrt(m_scattool->sigmaSquare(tmpprop, p, 1. / costracksurf, matEffects));
2065 }
2066
2067 meff->setScatteringSigmas(
2068 sigmascat / std::sin(layerpars->parameters()[Trk::theta]),
2069 sigmascat
2070 );
2071
2072
2073 if (matEffects == electron) {
2074 state->resetStateType(TrackStateOnSurface::Scatterer);
2075 meff->setDeltaE(oldde);
2076 if (!meff->isKink()) {
2077 meff->setSigmaDeltaE(0);
2078 } else {
2079 isbrem = true;
2080 bremdp = meff->delta_p();
2081 }
2082 } else if (eloss != nullptr) {
2083 meff->setSigmaDeltaE(eloss->sigmaDeltaE());
2084 }
2085 if (meff->sigmaDeltaE() > 0) {
2086 ++n_brem;
2087 }
2088 }
2089 }
2090
2091 const AmgVector(5) & refpars = trajectory.referenceParameters()->parameters();
2092 minpar=trajectory.referenceParameters()->associatedSurface().createUniqueTrackParameters(
2093 refpars[0], refpars[1], refpars[2], refpars[3], refpars[4], std::nullopt
2094 );
2095
2096 trajectory.reset();
2097 cache.m_matfilled = true;
2098
2099 if (matEffects == Trk::electron) {
2100 if (!isbrem) {
2101 trajectory.brems().clear();
2102 } else {
2103 trajectory.brems().resize(1);
2104 trajectory.brems()[0] = bremdp;
2105 }
2106
2107 cache.m_asymeloss = false;
2108 trajectory.setNumberOfScatterers(nscats);
2109 // @TODO fillResiduals assumes that numberOfBrems == number of states with material effects and sigmaDeltaE() > 0
2110 // not clear whether fillResiduals has to be adjusted for electrons rather than this
2111 trajectory.setNumberOfBrems(n_brem);
2112 }
2113 }
2114
2115 std::unique_ptr<Track> track(myfit(ctx, cache, trajectory, *minpar, runOutlier, matEffects));
2116
2117 bool pseudoupdated = false;
2118
2119 if ((track != nullptr) && hasid && hasmuon) {
2120 for (std::unique_ptr<GXFTrackState> & pseudostate : trajectory.trackStates()) {
2121 if (
2122 (pseudostate == nullptr) ||
2123 pseudostate->measurementType() != TrackState::Pseudo ||
2124 pseudostate->fitQuality().chiSquared() < 10
2125 ) {
2126 continue;
2127 }
2128
2129 const TrackParameters *pseudopar = pseudostate->trackParameters();
2130 const std::unique_ptr<const TrackParameters> updpar(m_updator->removeFromState(
2131 *pseudopar,
2132 pseudostate->measurement()->localParameters(),
2133 pseudostate->measurement()->localCovariance()
2134 ));
2135
2136 if (updpar == nullptr) {
2137 continue;
2138 }
2139
2140 Amg::MatrixX covMatrix(1, 1);
2141 covMatrix(0, 0) = 100;
2142
2143 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
2144 LocalParameters(DefinedParameter(updpar->parameters()[Trk::locY], Trk::locY)),
2145 std::move(covMatrix),
2146 pseudopar->associatedSurface()
2147 );
2148
2149 pseudostate->setMeasurement(std::move(newpseudo));
2150 double errors[5];
2151 errors[0] = errors[2] = errors[3] = errors[4] = -1;
2152 errors[1] = 10;
2153 pseudostate->setMeasurementErrors(errors);
2154 pseudoupdated = true;
2155 }
2156
2157 if (pseudoupdated) {
2158 trajectory.setConverged(false);
2159 cache.m_matfilled = true;
2160 track.reset(myfit(ctx, cache, trajectory, *track->perigeeParameters(), false, muon));
2161 cache.m_matfilled = false;
2162 }
2163 }
2164
2165 cache.m_matfilled = false;
2166 cache.m_getmaterialfromtrack = tmpgetmat;
2167 cache.m_acceleration = tmpacc;
2168 cache.m_fiteloss = tmpfiteloss;
2169
2170 if (track != nullptr) {
2171 cache.incrementFitStatus(S_SUCCESSFUL_FITS);
2172 const TrackInfo& old_info = inputTrack.info();
2173 track->info().addPatternReco(old_info);
2174 }
2175
2176 return track.release();
2177 }
bool is_valid() const
Check if id is in a valid state.
Gaudi::Property< bool > m_fiteloss

◆ holesearchExtrapolation()

std::vector< std::unique_ptr< TrackParameters > > Trk::GlobalChi2Fitter::holesearchExtrapolation ( const EventContext & ctx,
const TrackParameters & src,
const GXFTrackState & dst,
PropDirection propdir ) const
private

Helper method which performs an extrapolation with additional logic for hole search.

This method is a wrapper around extrapolateStepwise from the extrapolator interface, with the added functionality that it will null any returned track parameters which are on the start and end surface.

Parameters
[in]ctxAn event context for extrapolation.
[in]srcThe track parameters to start extrapolating from.
[in]dstThe track state to extrapolate to.
[in]propdirThe propagation direction.
Returns
A vector of track states, just like normal extrapolation.

Definition at line 7662 of file GlobalChi2Fitter.cxx.

7667 {
7668 /*
7669 * First, we conduct a bog standard stepwise extrapolation. This will
7670 * yield some unwanted results, but we will filter those later.
7671 */
7672 std::vector<std::unique_ptr<TrackParameters>> rv = m_extrapolator->extrapolateStepwise(
7673 ctx, src, dst.associatedSurface(), propdir, false
7674 );
7675
7676 /*
7677 * It is possible for the first returned track parameter to be on the same
7678 * surface as we started on. That's probably due to some rounding errors.
7679 * We check for this possibility, and set the pointer to null if it
7680 * occurs. Note that this leaves some null pointers in the returned vector
7681 * but this is more performant compared to removing them properly.
7682 */
7683 if (
7684 !rv.empty() && (
7685 &rv.front()->associatedSurface() == &dst.associatedSurface() ||
7686 &rv.front()->associatedSurface() == &src.associatedSurface() ||
7687 trackParametersClose(*rv.front(), src, 0.001) ||
7688 trackParametersClose(*rv.front(), *dst.trackParameters(), 0.001)
7689 )
7690 ) {
7691 rv.front().reset(nullptr);
7692 }
7693
7694 /*
7695 * Same logic, but for the last returned element. In that case, we get a
7696 * set of parameters on the destination surface, which we also do not
7697 * want.
7698 */
7699 if (
7700 rv.size() > 1 && (
7701 &rv.back()->associatedSurface() == &dst.associatedSurface() ||
7702 &rv.back()->associatedSurface() == &src.associatedSurface() ||
7703 trackParametersClose(*rv.back(), src, 0.001) ||
7704 trackParametersClose(*rv.back(), *dst.trackParameters(), 0.001)
7705 )
7706 ) {
7707 rv.back().reset(nullptr);
7708 }
7709
7710 return rv;
7711 }

◆ holeSearchHelper()

void Trk::GlobalChi2Fitter::holeSearchHelper ( const std::vector< std::unique_ptr< TrackParameters > > & hc,
std::set< Identifier > & id_set,
std::set< Identifier > & sct_set,
TrackHoleCount & rv,
bool count_holes,
bool count_dead ) const
private

Helper method for the hole search that does the actual counting of holes and dead modules.

This is a helper function that does a lot of esoteric and weird things that you most likely won't need to know about. The gist of it is that you pass it a vector of track parameters and a counting object, and it will update those counters according to its analysis of the track parameters.

Unfortunately, due to the design of this method, it requires quite a lot of persistent state between invocations for the same track. That's bad design of course, but it is how it is for now. This means that there are quite a few state parameters.

Parameters
[in]hcA list of candidate hole track parameters to analyse.
[in,out]id_setA set of identifiers found to be holes or dead.
[in,out]sct_setA set of identifiers of SCT holes.
[in,out]rvThe hole count container to update.
[in]count_holesHoles are counted only if this is enabled.
[in]count_deadDead modules are counted only if this is enabled.

Definition at line 7205 of file GlobalChi2Fitter.cxx.

7212 {
7213 /*
7214 * Our input is a list of track states, which we are iterating over. We
7215 * need to examine each one and update the values in our track hole count
7216 * accordingly.
7217 */
7218 for (const std::unique_ptr<TrackParameters> & tp : hc) {
7219 /*
7220 * It is possible, expected even, for some of these pointers to be null.
7221 * In those cases, it would be dangerous to continue, so we need to make
7222 * sure we skip them.
7223 */
7224 if (tp == nullptr) {
7225 continue;
7226 }
7227
7228 /*
7229 * Extract the detector element of the track parameter surface for
7230 * examination. If for whatever reason there is none (i.e. the surface
7231 * is not a detector at all), we can skip it and continue.
7232 */
7233 const TrkDetElementBase * de = tp->associatedSurface().associatedDetectorElement();
7234
7235 if (de == nullptr) {
7236 continue;
7237 }
7238
7239 Identifier const id = de->identify();
7240
7241 /*
7242 * If, for whatever reason, we have already visited this detector, we do
7243 * not want to visit it again. Otherwise we might end up with modules
7244 * counted twice, and that would be very bad.
7245 */
7246 if (id_set.find(id) != id_set.end()) {
7247 continue;
7248 }
7249
7250 /*
7251 * This is the meat of the pudding, we use the boundary checking tool
7252 * to see whether this set of parameters is a hole candidate, a dead
7253 * module, or not a hole at all.
7254 */
7255 BoundaryCheckResult const bc = m_boundaryCheckTool->boundaryCheck(*tp);
7256
7257 if (bc == BoundaryCheckResult::DeadElement && count_dead) {
7258 /*
7259 * If the module is dead, our job is very simple. We just check
7260 * whether it is a Pixel or an SCT and increment the appropriate
7261 * counter. We also insert the module into our set of visited elements.
7262 */
7263 if (m_DetID->is_pixel(id)) {
7264 ++rv.m_pixel_dead;
7265 } else if (m_DetID->is_sct(id)) {
7266 ++rv.m_sct_dead;
7267 }
7268 id_set.insert(id);
7269 } else if (bc == BoundaryCheckResult::Candidate && count_holes) {
7270 /*
7271 * If the module is a candidate, it's much the same, but we also need
7272 * to handle double SCT holes.
7273 */
7274 if (m_DetID->is_pixel(id)) {
7275 ++rv.m_pixel_hole;
7276 } else if (m_DetID->is_sct(id)) {
7277 ++rv.m_sct_hole;
7278
7279 /*
7280 * To check for SCT double holes, we need to first fetch the other
7281 * side of the current SCT. Thankfully, the detector description
7282 * makes this very easy.
7283 */
7284 const InDetDD::SiDetectorElement* e = dynamic_cast<const InDetDD::SiDetectorElement *>(de);
7285 const Identifier os = e->otherSide()->identify();
7286
7287 /*
7288 * We keep a special set containing only SCT hole IDs. We simply
7289 * check whether the ID of the other side of the SCT is in this set
7290 * to confirm that we have a double hole. Note that the first side
7291 * in a double hole will be counted as a SCT hole only, and the
7292 * second side will count as another hole as well as a double hole,
7293 * which is exactly the behaviour we would expect to see.
7294 */
7295 if (sct_set.find(os) != sct_set.end()) {
7296 ++rv.m_sct_double_hole;
7297 }
7298
7299 /*
7300 * We need to add our SCT to the SCT identifier set if it is a
7301 * candidate hit, otherwise known as a hole in this context.
7302 */
7303 sct_set.insert(id);
7304 }
7305
7306 /*
7307 * SCTs are also added to the set of all identifiers to avoid double
7308 * counting them.
7309 */
7310 id_set.insert(id);
7311 }
7312 }
7313 }
ToolHandle< IBoundaryCheckTool > m_boundaryCheckTool
@ DeadElement
outside the element

◆ holeSearchProcess()

std::optional< GlobalChi2Fitter::TrackHoleCount > Trk::GlobalChi2Fitter::holeSearchProcess ( const EventContext & ctx,
const std::vector< std::reference_wrapper< GXFTrackState > > & states ) const
private

Conduct a hole search between a list of states, possibly reusing existing information.

Given a collection of state references, this method will conduct a hole search between consecutive pairs of states, possibly reusing existing information stored in the state data types. The method will check whether the state contains any previous hole search data and use it. If there is no data, it will run additional extrapolations to gather that data. It will then use a helper method to count holes and dead modules and return a total count.

In some cases, this method may error. Should this occur, it will return a non-extant value.

Parameters
[in]ctxAn event context used for extrapolation.
[in]statesA list of states to operate on, using consecutive states as extrapolation regions.
Returns
A list of hole counts if the process succeeded, or a non-extant value in case of an error.

Definition at line 7390 of file GlobalChi2Fitter.cxx.

7393 {
7394 /*
7395 * Firstly, we need to guard against tracks having too few measurement
7396 * states to perform a good hole search. This is a mechanism that we
7397 * inherit from the reference hole search. If we have too few states, we
7398 * return a non-extant result to indicate an error state.
7399 *
7400 * TODO: The minimum value of 3 is also borrowed from the reference
7401 * implementation. It's hardcoded for now, but could be a parameter in the
7402 * future.
7403 */
7404 constexpr uint min_meas = 3;
7405 if (std::count_if(states.begin(), states.end(), [](const GXFTrackState & s){ return s.getStateType(TrackStateOnSurface::Measurement); }) < min_meas) {
7406 return {};
7407 }
7408
7409 bool seen_meas = false;
7411 std::set<Identifier> id_set;
7412 std::set<Identifier> sct_set;
7413
7414 /*
7415 * Using an old-school integer-based for loop because we need to iterate
7416 * over successive pairs of states to do an extrapolation between.
7417 */
7418 for (std::size_t i = 0; i < states.size() - 1; i++) {
7419 /*
7420 * Gather references to the state at the beginning of the extrapolation,
7421 * named beg, and the end, named end.
7422 */
7423 GXFTrackState & beg = states[i];
7424 GXFTrackState const& end = states[i + 1];
7425
7426 /*
7427 * Update the boolean keeping track of whether we have seen a measurement
7428 * or outlier yet. Once we see one, this will remain true forever, but
7429 * it helps us make sure we don't collect holes before the first
7430 * measurement.
7431 */
7432 seen_meas |= beg.getStateType(TrackStateOnSurface::Measurement) || beg.getStateType(TrackStateOnSurface::Outlier);
7433
7434 /*
7435 * Calculate the distance between the position of the starting parameters
7436 * and the end parameters. If this distance is sufficiently small, there
7437 * can be no elements between them (for example, between two SCTs), and
7438 * we don't need to do an extrapolation. This can easily save us a few
7439 * microseconds.
7440 */
7441 const double dist = (beg.trackParameters()->position() - end.trackParameters()->position()).norm();
7442
7443 const bool zStartValid = std::abs(beg.trackParameters()->position().z())<10000.;
7444 if(!zStartValid){
7445 ATH_MSG_DEBUG("Pathological track parameter well outside of detector");
7446 ATH_MSG_DEBUG("Propagator might have issue with this, skipping");
7447 ATH_MSG_VERBOSE("dumping track parameters " << *(beg.trackParameters()));
7448 }
7449
7450 /*
7451 * Only proceed to count holes if we have seen a measurement before (this
7452 * may include the starting track state, if it is a measurement) and the
7453 * distance between start and end is at least 2.5 millimeters
7454 * and the z position is valid
7455 */
7456 if (seen_meas && dist >= 2.5 && zStartValid) {
7457 /*
7458 * First, we retrieve the hole data stored in the beginning state. Note
7459 * that this may very well be non-extant, but it is possible for the
7460 * fitter to have deposited some hole information into the track state
7461 * earlier on in the fitting process.
7462 */
7463 std::optional<std::vector<std::unique_ptr<TrackParameters>>> & hc = beg.getHoles();
7464 std::vector<std::unique_ptr<TrackParameters>> states;
7465
7466 /*
7467 * Gather the track states between the start and end of the
7468 * extrapolation. If the track state contained hole search information,
7469 * we simply move that out and use it. If there was no information, we
7470 * do a fresh extrapolation. This can be a CPU hog!
7471 */
7472 if (hc.has_value()) {
7473 states = std::move(*hc);
7474 } else {
7475 states = holesearchExtrapolation(ctx, *beg.trackParameters(), end, alongMomentum);
7476 }
7477
7478 /*
7479 * Finally, we process the collected hole candidate states, checking
7480 * them for liveness and other properties. This helper function will
7481 * increment the values in rv accordingly.
7482 */
7483 holeSearchHelper(states, id_set, sct_set, rv, true, true);
7484 }
7485 }
7486
7487 /*
7488 * Once we are done processing our measurements, we also need to do a
7489 * final blind extrapolation to collect and dead modules (but not holes)
7490 * behind the last measurement. For this, we do a blind extrapolation
7491 * from the final state.
7492 */
7493 GXFTrackState const& last = states.back();
7494
7495 /*
7496 * To do the blind extrapolation, we need to have a set of track parameters
7497 * for our last measurement state. We also check whether the position of
7498 * the last measurement is still inside the inner detector. If it is not,
7499 * we don't need to blindly extrapolate because we're only interested in
7500 * collecting inner detector dead modules. This check saves us a few tens
7501 * of microseconds.
7502 */
7503 if (
7504 last.trackParameters() != nullptr &&
7505 m_idVolume.inside(last.trackParameters()->position())
7506 ) {
7507 /*
7508 * Simply conduct the blind extrapolation, and then use the helper tool
7509 * to ensure that the hole counts are updated.
7510 */
7511 std::vector<std::unique_ptr<Trk::TrackParameters>> const bl = m_extrapolator->extrapolateBlindly(
7512 ctx,
7513 *last.trackParameters(),
7515 false,
7516 Trk::pion,
7517 &m_idVolume
7518 );
7519
7520 /*
7521 * Note that we have flipped one of the boolean parameters of the helper
7522 * method here to make sure it only collects dead modules, not hole
7523 * candidates.
7524 */
7525 holeSearchHelper(bl, id_set, sct_set, rv, false, true);
7526 }
7527
7528 return rv;
7529 }
#define ATH_MSG_VERBOSE(x)
unsigned int uint
void holeSearchHelper(const std::vector< std::unique_ptr< TrackParameters > > &hc, std::set< Identifier > &id_set, std::set< Identifier > &sct_set, TrackHoleCount &rv, bool count_holes, bool count_dead) const
Helper method for the hole search that does the actual counting of holes and dead modules.

◆ holeSearchStates()

std::vector< std::reference_wrapper< GXFTrackState > > Trk::GlobalChi2Fitter::holeSearchStates ( GXFTrajectory & trajectory) const
private

Extracts a collection of track states which are important for hole search.

This method helps extract the measurement (and outlier) states from a track. These are the states between which we want to do a hole search, so the result of calling this method can be used as a source of truth for conducting a hole search on the track.

This method only returns states between the first and last measurements on the track, which is the region in which we are interested in doing a hole search.

As an example, if we denote scatterers as S, and measurements as M, this method would reduce the following track with numbered states:

1 2 3 4 5 6 7 8 9 M S S M M S M S S

Into a list of references [1, 4, 5, 7].

This method ensures that each pair of consecutive states in the return value list is a target for a hole search extrapolation.

Parameters
[in]trajectoryThe trajectory from which to extract states.
Returns
A vector of state references as described above.

Definition at line 7315 of file GlobalChi2Fitter.cxx.

7317 {
7318 /*
7319 * Firstly, we will need to find the last measurement state on our track.
7320 * This will allow us to break the main loop later once we are done with
7321 * our work.
7322 */
7323 GXFTrackState * lastmeas = nullptr;
7324
7325 for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7326 if (s->getStateType(TrackStateOnSurface::Measurement)) {
7327 lastmeas = s.get();
7328 }
7329 }
7330
7331 /*
7332 * We create a vector of reference wrappers and reserve at least enough
7333 * space to contain the entire trajectory. This is perhaps a little
7334 * wasteful since we will never need this much space, but it may be more
7335 * efficient than taking the resizing pentalty on the chin.
7336 */
7337 std::vector<std::reference_wrapper<GXFTrackState>> rv;
7338 rv.reserve(trajectory.trackStates().size());
7339
7340 /*
7341 * The main body of our method now. We iterate over all track states in
7342 * the track, at least until we find the last measurement state as found
7343 * above.
7344 */
7345 for (const std::unique_ptr<GXFTrackState> & s : trajectory.trackStates()) {
7346 /*
7347 * We are only interested in collecting measurements, perigees, and any
7348 * outlier states.
7349 */
7350 if (
7351 s->getStateType(TrackStateOnSurface::Measurement) ||
7352 s->getStateType(TrackStateOnSurface::Perigee) ||
7353 s->getStateType(TrackStateOnSurface::Outlier)
7354 ) {
7355 /*
7356 * We store a reference to the current track state in our return value
7357 * vector.
7358 */
7359 rv.emplace_back(*s);
7360
7361 /*
7362 * We want to make sure we do not collect any TRT results or other
7363 * non-SCT and non-Pixel detector types. For that, we need to access
7364 * the details of the detector element and determine the detector type.
7365 */
7366 const TrkDetElementBase * de = s->trackParameters()->associatedSurface().associatedDetectorElement();
7367
7368 if (de != nullptr) {
7369 Identifier const id = de->identify();
7370
7371 if (!m_DetID->is_pixel(id) && !m_DetID->is_sct(id)) {
7372 break;
7373 }
7374 }
7375
7376 /*
7377 * We also have no interest in going past the final measurement, so we
7378 * break out of the loop if we find it.
7379 */
7380 //cppcheck-suppress iterators3
7381 if (s.get() == lastmeas) {
7382 break;
7383 }
7384 }
7385 }
7386
7387 return rv;
7388 }
@ Perigee
This represents a perigee, and so will contain a Perigee object only.

◆ initFieldCache()

void Trk::GlobalChi2Fitter::initFieldCache ( const EventContext & ctx,
Cache & cache ) const
private

Initialize a field cache inside a fit cache object.

Following the shift from old-style magnetic field services to the new cached implementation for thread safety, we need some additional logic to create a magnetic field cache object and insert it into our fitting cache object for access.

Parameters
[in]cacheThe GX2F cache objects in which to load the magnetic field cache.

Definition at line 8510 of file GlobalChi2Fitter.cxx.

8512 {
8513 SG::ReadCondHandle<AtlasFieldCacheCondObj> rh(
8515 ctx
8516 );
8517
8518 const AtlasFieldCacheCondObj * cond_obj(*rh);
8519
8520 if (cond_obj == nullptr) {
8521 ATH_MSG_ERROR("Failed to create AtlasFieldCacheCondObj!");
8522 return;
8523 }
8524
8525 cond_obj->getInitializedCache(cache.m_field_cache);
8526 }
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_field_cache_key

◆ initialize()

StatusCode Trk::GlobalChi2Fitter::initialize ( )
overridevirtual

Definition at line 210 of file GlobalChi2Fitter.cxx.

210 {
211 ATH_CHECK(m_field_cache_key.initialize());
212
213 if (!m_ROTcreator.name().empty()) {
214 ATH_CHECK(m_ROTcreator.retrieve());
215 }
216
217 if (!m_broadROTcreator.name().empty()) {
218 ATH_CHECK(m_broadROTcreator.retrieve());
219 }
220
221 ATH_CHECK(m_updator.retrieve());
222 ATH_CHECK(m_extrapolator.retrieve());
223 ATH_CHECK(m_navigator.retrieve());
225 ATH_CHECK(m_propagator.retrieve());
226
227 if (!m_boundaryCheckTool.name().empty()) {
228 ATH_CHECK(m_boundaryCheckTool.retrieve());
229 } else if (m_holeSearch.value()) {
230 ATH_MSG_ERROR("Hole search requested but no boundary check tool provided.");
231 return StatusCode::FAILURE;
232 }
233
234 if (m_calomat) {
235 ATH_CHECK(m_calotool.retrieve());
236
237 if (!m_calotoolparam.empty()) {
238 ATH_CHECK(m_calotoolparam.retrieve());
239 }
240 } else{
241 m_calotool.disable();
242 m_calotoolparam.disable();
243 }
244
245 ATH_CHECK(m_scattool.retrieve());
246 ATH_CHECK(m_elosstool.retrieve());
247
248 if (!m_matupdator.name().empty()) {
249 ATH_CHECK(m_matupdator.retrieve());
250 }
251
252 // need an Atlas id-helper to identify sub-detectors, take the one from detStore
253 ATH_CHECK(detStore()->retrieve(m_DetID, "AtlasID"));
254
256 ATH_MSG_WARNING("FillDerivativeMatrix option selected, switching off acceleration!");
257 m_acceleration = false;
258 }
259
260 if (!m_trackingGeometryReadKey.key().empty()){
262 }
263 if (m_useCaloTG) {
265 ATH_MSG_INFO(m_caloMaterialProvider << " retrieved ");
266 }
267 else{
268 m_caloMaterialProvider.disable();
269 }
270
272
273 /*
274 * Doing a hole search only makes sense if we are also creating a track
275 * summary, because the track summary is the only way for us to export the
276 * hole search information out of the fitter. For this reason, we disable
277 * the hole search in the case that track summaries are disabled.
278 */
279 if (m_holeSearch.value() && !m_createSummary.value()) {
280 ATH_MSG_ERROR("Hole search requested but track summaries are disabled.");
281 return StatusCode::FAILURE;
282 }
283
284 ATH_MSG_INFO("fixed momentum: " << m_p);
285
286 return StatusCode::SUCCESS;
287 }
#define ATH_CHECK
Evaluate an expression and check for errors.
SG::ReadHandleKey< Trk::ClusterSplitProbabilityContainer > m_clusterSplitProbContainer
Gaudi::Property< bool > m_fillderivmatrix
ToolHandle< IMaterialEffectsUpdator > m_matupdator
SG::ReadCondHandleKey< TrackingGeometry > m_trackingGeometryReadKey
Gaudi::Property< bool > m_acceleration
Gaudi::Property< bool > m_holeSearch
Gaudi::Property< bool > m_createSummary
retrieve(aClass, aKey=None)
Definition PyKernel.py:110

◆ isMuonTrack()

bool Trk::GlobalChi2Fitter::isMuonTrack ( const Track & intrk1) const
private

Definition at line 8468 of file GlobalChi2Fitter.cxx.

8468 {
8469 const auto *pDataVector = intrk1.measurementsOnTrack();
8470 auto nmeas1 = pDataVector->size();
8471 const auto *pLastValue = (*pDataVector)[nmeas1 - 1];
8472 //
8473 const bool lastMeasIsRIO = pLastValue->type(Trk::MeasurementBaseType::RIO_OnTrack);
8474 const bool lastMeasIsCompetingRIO = pLastValue->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8475 //we only need the RIO on track pointer to be valid to identify
8476 const RIO_OnTrack *testrot{};
8477 //
8478 if (lastMeasIsRIO){
8479 testrot = static_cast<const RIO_OnTrack *>(pLastValue);
8480 } else {
8481 if (lastMeasIsCompetingRIO){
8482 const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pLastValue);
8483 testrot = &testcrot->rioOnTrack(0);
8484 }
8485 }
8486 //still undefined, so try penultimate measurement as well
8487 if (testrot == nullptr) {
8488 const auto *pPenultimate = (*pDataVector)[nmeas1 - 2];
8489 const bool penultimateIsRIO = pPenultimate->type(Trk::MeasurementBaseType::RIO_OnTrack);
8490 const bool penultimateIsCompetingRIO = pPenultimate->type(Trk::MeasurementBaseType::CompetingRIOsOnTrack);
8491 if(penultimateIsRIO){
8492 testrot = static_cast<const RIO_OnTrack *>(pPenultimate);
8493 } else {
8494 if (penultimateIsCompetingRIO){
8495 const auto *testcrot = static_cast<const CompetingRIOsOnTrack*>(pPenultimate);
8496 testrot = &testcrot->rioOnTrack(0);
8497 }
8498 }
8499 }
8500 //check: we've successfully got a valid RIO on track; it's not the inner detector;
8501 //it's really the muon detector (question: doesn't that make the previous check redundant?)
8502 return (
8503 (testrot != nullptr) &&
8504 !m_DetID->is_indet(testrot->identify()) &&
8505 m_DetID->is_muon(testrot->identify())
8506 );
8507 }

◆ iterationsOfLastFit()

int Trk::GlobalChi2Fitter::iterationsOfLastFit ( ) const
privatevirtual

Definition at line 8443 of file GlobalChi2Fitter.cxx.

8443 {
8444 return 0;
8445 } void

◆ mainCombinationStrategy()

Track * Trk::GlobalChi2Fitter::mainCombinationStrategy ( const EventContext & ctx,
Cache & cache,
const Track & intrk1,
const Track & intrk2,
GXFTrajectory & trajectory,
std::vector< MaterialEffectsOnTrack > & calomeots ) const
private

Definition at line 582 of file GlobalChi2Fitter.cxx.

589 {
590 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::mainCombinationStrategy");
591
592 const double mass = Trk::ParticleMasses::mass[muon];
593
594 const bool firstismuon = isMuonTrack(intrk1);
595 const Track *indettrack = firstismuon ? &intrk2 : &intrk1;
596 const Track *muontrack = firstismuon ? &intrk1 : &intrk2;
597
598 auto [tmpfirstidpar, tmplastidpar] = getFirstLastIdPar(*indettrack);
599 std::unique_ptr<const TrackParameters> firstidpar = unique_clone(tmpfirstidpar);
600 std::unique_ptr<const TrackParameters> lastidpar = unique_clone(tmplastidpar);
601
602 if ((firstidpar == nullptr) || (lastidpar == nullptr)) {
603 return nullptr;
604 }
605
606 if (muontrack->trackStateOnSurfaces()->empty()) {
607 return nullptr;
608 }
609
611 firstismuon ?
612 muontrack->trackStateOnSurfaces()->end() - 1 :
613 muontrack->trackStateOnSurfaces()->begin();
614
615 const MeasurementBase *closestmuonmeas = nullptr;
616 std::unique_ptr<const TrackParameters> tp_closestmuon = nullptr;
617
618 while (closestmuonmeas == nullptr) {
619 closestmuonmeas = nullptr;
620 const TrackParameters *thispar = (**tsosit).trackParameters();
621
622 if ((**tsosit).measurementOnTrack() != nullptr) {
623 closestmuonmeas = (**tsosit).measurementOnTrack();
624
625 if (thispar != nullptr) {
626 const AmgVector(5) & parvec = thispar->parameters();
627 tp_closestmuon=thispar->associatedSurface().createUniqueTrackParameters(
628 parvec[0], parvec[1], parvec[2], parvec[3], parvec[4], std::nullopt
629 );
630 }
631 break;
632 }
633
634 if (firstismuon) {
635 --tsosit;
636 } else {
637 ++tsosit;
638 }
639 }
640
641 PropDirection propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
642 std::unique_ptr<const TrackParameters> tmppar;
643
644 const bool msEntranceIsValid = ensureValidEntranceMuonSpectrometer(ctx, cache);
645 if ((tp_closestmuon != nullptr) && msEntranceIsValid) {
646 tmppar = m_extrapolator->extrapolateToVolume(
647 ctx, *tp_closestmuon, *cache.m_msEntrance, propdir, nonInteracting);
648 }
649
650 std::unique_ptr<const std::vector<const TrackStateOnSurface *>> matvec;
651
652 if (tmppar != nullptr) {
653 const Surface & associatedSurface = tmppar->associatedSurface();
654 std::unique_ptr<Surface> muonsurf = nullptr;
655
656 if (associatedSurface.type() == Trk::SurfaceType::Cylinder) {
657 if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Cylinder) {
658 const CylinderBounds *cylbounds = static_cast <const CylinderBounds * >(&associatedSurface.bounds());
659 Amg::Transform3D const trans = Amg::Transform3D(associatedSurface.transform());
660 const double radius = cylbounds->r();
661 const double hlength = cylbounds->halflengthZ();
662 muonsurf = std::make_unique<CylinderSurface>(trans, radius + 1, hlength);
663 }
664 } else if (associatedSurface.type() == Trk::SurfaceType::Disc) {
665 if (associatedSurface.bounds().type() == Trk::SurfaceBounds::Disc) {
666 const double newz = (
667 associatedSurface.center().z() > 0 ?
668 associatedSurface.center().z() + 1 :
669 associatedSurface.center().z() - 1
670 );
671
672 const Amg::Vector3D newpos(
673 associatedSurface.center().x(),
674 associatedSurface.center().y(),
675 newz
676 );
677 Amg::Transform3D trans = associatedSurface.transform();
678 trans.translation() << newpos;
679
680 const DiscBounds *discbounds = static_cast<const DiscBounds *>(&associatedSurface.bounds());
681 const double rmin = discbounds->rMin();
682 const double rmax = discbounds->rMax();
683 muonsurf = std::make_unique<DiscSurface>(trans, rmin, rmax);
684 }
685 }
686
687 if (muonsurf != nullptr) {
688 matvec.reset(m_extrapolator->extrapolateM(
689 ctx,
690 *tp_closestmuon,
691 *muonsurf,
692 propdir,
693 false,
694 muon
695 ));
696 }
697 }
698
699 std::vector<const TrackStateOnSurface *> tmp_matvec;
700
701 if ((matvec != nullptr) && !matvec->empty()) {
702 tmp_matvec = *matvec;
703 delete tmp_matvec.back();
704 tmp_matvec.pop_back();
705
706 for (auto & i : tmp_matvec) {
707 propdir = firstismuon ? Trk::alongMomentum : oppositeMomentum;
708 if (i->materialEffectsOnTrack()->derivedType() != MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK){
709 continue;
710 }
711 const MaterialEffectsOnTrack *meff = static_cast<const MaterialEffectsOnTrack *>(i->materialEffectsOnTrack());
712
713 const Surface *matsurf = &meff->associatedSurface();
714 tmppar = m_propagator->propagateParameters(
715 ctx,
716 *tp_closestmuon,
717 *matsurf,
718 propdir,
719 false,
720 trajectory.m_fieldprop,
722 );
723
724
725 if (tmppar == nullptr) {
726 propdir = !firstismuon ? Trk::alongMomentum : oppositeMomentum;
727 tmppar=m_propagator->propagateParameters(
728 ctx,
729 *tp_closestmuon,
730 *matsurf,
731 propdir,
732 false,
733 trajectory.m_fieldprop,
735 );
736
737 }
738
739 if (tmppar == nullptr) {
740 return nullptr;
741 }
742
743 AmgVector(5) newpars = tmppar->parameters();
744
745 if (newpars[Trk::qOverP] != 0) {
746 const double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
747 const double de = std::abs(meff->energyLoss()->deltaE());
748 const double oldp = std::abs(1 / newpars[Trk::qOverP]);
749 const double newp2 = oldp * oldp + (!firstismuon ? 2 : -2) * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
750
751 if (newp2 > 0) {
752 newpars[Trk::qOverP] = sign / std::sqrt(newp2);
753 }
754 }
755
756 tp_closestmuon=tmppar->associatedSurface().createUniqueTrackParameters(
757 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
758 );
759 }
760
761 if (!firstismuon) {
762 std::reverse(tmp_matvec.begin(), tmp_matvec.end());
763 }
764 }
765
766 const Trk::TrackStates::const_iterator beginStates = intrk1.trackStateOnSurfaces()->begin();
767 Trk::TrackStates::const_iterator itStates = beginStates;
768 const Trk::TrackStates::const_iterator endState = firstismuon ? tsosit + 1 : intrk1.trackStateOnSurfaces()->end();
769 const Trk::TrackStates::const_iterator beginStates2 = !firstismuon ? tsosit : intrk2.trackStateOnSurfaces()->begin();
770 Trk::TrackStates::const_iterator itStates2 = beginStates2;
771 const Trk::TrackStates::const_iterator endState2 = intrk2.trackStateOnSurfaces()->end();
772
773 for (; itStates != endState; ++itStates) {
774 if (firstismuon && (*itStates)->measurementOnTrack()->type(Trk::MeasurementBaseType::PseudoMeasurementOnTrack)) {
775 continue;
776 }
777
778 const bool tmpgetmat = cache.m_getmaterialfromtrack;
779
780 if ((*itStates)->materialEffectsOnTrack() != nullptr) {
781 if (firstismuon) {
782 cache.m_extmat = false;
783 } else {
784 cache.m_idmat = false;
785 }
786
787 const auto *const pBaseMEOT = (*itStates)->materialEffectsOnTrack();
788 const bool itsAnMEOT = (pBaseMEOT->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK);
789
790 if (itsAnMEOT ){
791 const auto *const pMEOT =static_cast<const MaterialEffectsOnTrack *>((*itStates)->materialEffectsOnTrack());
792 if ((pMEOT->scatteringAngles() == nullptr) or (pMEOT->energyLoss() == nullptr)) {
793 cache.m_getmaterialfromtrack = true; // always take calorimeter layers
794 }
795 }
796 }
797
798 makeProtoState(cache, trajectory, *itStates);
799 cache.m_getmaterialfromtrack = tmpgetmat;
800 }
801
802 if (
803 !firstismuon &&
804 intrk1.info().trackProperties(TrackInfo::SlimmedTrack)
805 ) {
806 trajectory.trackStates().back()->setTrackParameters(nullptr);
807 }
808
809 std::unique_ptr<const TrackParameters> firstscatpar;
810 std::unique_ptr<const TrackParameters> lastscatpar;
811 const TrackParameters *origlastidpar = unique_clone(lastidpar).release();
812
813 double newqoverpid = 0;
814
815 if (!firstismuon) {
816 const double de = std::abs(calomeots[1].energyLoss()->deltaE());
817 const double sigmade = std::abs(calomeots[1].energyLoss()->sigmaDeltaE());
818
819 const double pbefore = std::abs(1 / firstidpar->parameters()[Trk::qOverP]);
820 const double pafter = std::abs(1 / tp_closestmuon->parameters()[Trk::qOverP]);
821 const double elosspull = (pbefore - pafter - de) / sigmade;
822
823 if (std::abs(elosspull) > 10) {
824 if (elosspull > 10) {
825 newqoverpid = 1 / (de + pafter + 10 * sigmade);
826 } else {
827 newqoverpid = 1 / (de + pafter - 10 * sigmade);
828 }
829
830 if (tp_closestmuon->parameters()[Trk::qOverP] * newqoverpid < 0) {
831 newqoverpid *= -1;
832 }
833
834 const AmgVector(5) & newpar = firstidpar->parameters();
835 firstidpar=firstidpar->associatedSurface().createUniqueTrackParameters(
836 newpar[0], newpar[1], newpar[2], newpar[3], newqoverpid, std::nullopt
837 );
838 }
839
840 lastidpar = m_extrapolator->extrapolateToVolume(
841 ctx, *firstidpar, *cache.m_caloEntrance, alongMomentum, Trk::muon);
842 }
843
844 if (lastidpar == nullptr) {
845 lastidpar = unique_clone(origlastidpar);
846 }
847
848 firstscatpar= m_propagator->propagateParameters(
849 ctx,
850 *(firstismuon ? tp_closestmuon.get() : lastidpar.get()),
851 calomeots[0].associatedSurface(),
853 false,
854 trajectory.m_fieldprop,
856 );
857
858 if (firstscatpar == nullptr) {
859 return nullptr;
860 }
861
862 lastscatpar = m_propagator->propagateParameters(
863 ctx,
864 *(firstismuon ? firstidpar : tp_closestmuon),
865 calomeots[2].associatedSurface(),
867 false,
868 trajectory.m_fieldprop,
870 );
871
872 if (lastscatpar == nullptr) {
873 return nullptr;
874 }
875
876 std::optional<TransportJacobian> jac1;
877 std::optional<TransportJacobian> jac2;
878 std::unique_ptr<const TrackParameters> elosspar;
879
880 double firstscatphi = 0;
881 double secondscatphi = 0;
882 double firstscattheta = 0;
883 double secondscattheta = 0;
884 double muonscatphi = 0;
885 double muonscattheta = 0;
886
887 const TrackParameters *idscatpar = !firstismuon ? firstscatpar.get() : lastscatpar.get();
888 const TrackParameters *muonscatpar = firstismuon ? firstscatpar.get() : lastscatpar.get();
889
890 newqoverpid = idscatpar->parameters()[Trk::qOverP];
891
892 const Amg::Vector3D calosegment = lastscatpar->position() - firstscatpar->position();
893 muonscatphi = xAOD::P4Helpers::deltaPhi(calosegment.phi(), muonscatpar->parameters()[Trk::phi]);
894
895 muonscattheta = calosegment.theta() - muonscatpar->parameters()[Trk::theta];
896 std::unique_ptr<const TrackParameters> startPar = unique_clone(cache.m_idmat ? lastidpar.get() : indettrack->perigeeParameters());
897
898 for (int i = 0; i < 2; i++) {
899 std::unique_ptr<const TrackParameters> tmpelosspar;
900 AmgVector(5) params1 = muonscatpar->parameters();
901 params1[Trk::phi] += muonscatphi;
902 params1[Trk::theta] += muonscattheta;
903
904 if (!correctAngles(params1[Trk::phi], params1[Trk::theta])) {
905 return nullptr;
906 }
907
908 const std::unique_ptr<const TrackParameters> tmppar1(muonscatpar->associatedSurface().createUniqueTrackParameters(
909 params1[0], params1[1], params1[2], params1[3], params1[4], std::nullopt
910 ));
911
912 const PropDirection propdir = !firstismuon ? oppositeMomentum : alongMomentum;
913
914 tmpelosspar = m_propagator->propagateParameters(
915 ctx,
916 *tmppar1,
917 calomeots[1].
918 associatedSurface(),
919 propdir,
920 false,
921 trajectory.m_fieldprop,
922 jac1,
924 );
925
926 if (m_numderiv) {
928 ctx,
929 firstscatpar.get(),
930 calomeots[1].associatedSurface(),
931 propdir,
932 trajectory.m_fieldprop
933 );
934 }
935
936 if ((tmpelosspar == nullptr) || (jac1 == std::nullopt)) {
937 // @TODO
938 // according to coverity elosspar cannot be non NULL here
939 // because elosspar is initially NULL and only set in the last loop iteration (i==1)
940 // is this intended ?
941 // delete elosspar;
942 return nullptr;
943 }
944
945 const AmgVector(5) & newpars = tmpelosspar->parameters();
946 const std::unique_ptr<const TrackParameters> elosspar2(tmpelosspar->associatedSurface().createUniqueTrackParameters(
947 newpars[0], newpars[1], newpars[2], newpars[3], newqoverpid, std::nullopt
948 ));
949
950 if (i == 1) {
951 elosspar = std::move(tmpelosspar);
952 }
953
954 std::unique_ptr<const TrackParameters> scat2(m_propagator->propagateParameters(
955 ctx,
956 *elosspar2,
957 !firstismuon ?
958 calomeots[0].associatedSurface() :
959 calomeots[2].associatedSurface(),
960 propdir,
961 false,
962 trajectory.m_fieldprop,
963 jac2,
965 ));
966
967 if (m_numderiv) {
969 ctx,
970 elosspar2.get(),
971 !firstismuon ?
972 calomeots[0].associatedSurface() :
973 calomeots[2].associatedSurface(),
974 !firstismuon ?
977 trajectory.m_fieldprop
978 );
979 }
980
981 if ((scat2 == nullptr) || (jac2 == std::nullopt)) {
982 return nullptr;
983 }
984
985 double jac3[5][5];
986 for (int j = 0; j < 5; j++) {
987 for (int k = 0; k < 5; k++) {
988 jac3[j][k] = 0;
989 for (int l = 0; l < 5; l++) {
990 jac3[j][k] += (*jac2) (j, l) * (*jac1) (l, k);
991 }
992 }
993 }
994
995 jac1.reset();
996 jac2.reset();
997 Amg::MatrixX jac4(2, 2);
998
999 jac4(0, 0) = jac3[0][2];
1000 jac4(1, 1) = jac3[1][3];
1001 jac4(0, 1) = jac3[0][3];
1002 jac4(1, 0) = jac3[1][2];
1003
1004 jac4 = jac4.inverse();
1005
1006 double dloc1 = idscatpar->parameters()[Trk::loc1] - scat2->parameters()[Trk::loc1];
1007 double dloc2 = idscatpar->parameters()[Trk::loc2] - scat2->parameters()[Trk::loc2];
1008 const Trk::CylinderSurface * cylsurf = nullptr;
1009
1010 if (scat2->associatedSurface().type() == Trk::SurfaceType::Cylinder)
1011 cylsurf = static_cast<const Trk::CylinderSurface *>(&scat2->associatedSurface());
1012
1013 const Trk::DiscSurface * discsurf = nullptr;
1014
1015 if (scat2->associatedSurface().type() == Trk::SurfaceType::Cylinder)
1016 discsurf = static_cast<const Trk::DiscSurface *>(&scat2->associatedSurface());
1017
1018 if (cylsurf != nullptr) {
1019 dloc1 = -std::remainder(-dloc1, 2 * M_PI * cylsurf->bounds().r());
1020 }
1021
1022 if (discsurf != nullptr) {
1023 dloc2 = -std::remainder(-dloc2, 2 * M_PI);
1024 }
1025
1026 double dphi = jac4(0, 0) * dloc1 + jac4(0, 1) * dloc2;
1027 double dtheta = jac4(1, 0) * dloc1 + jac4(1, 1) * dloc2;
1028
1029 if (i == 1) {
1030 dphi = dtheta = 0;
1031 }
1032
1033 muonscatphi += dphi;
1034 muonscattheta += dtheta;
1035
1036 const double idscatphi = xAOD::P4Helpers::deltaPhi(idscatpar->parameters()[Trk::phi], scat2->parameters()[Trk::phi] + dphi);
1037 const double idscattheta = idscatpar->parameters()[Trk::theta] - (scat2->parameters()[Trk::theta] + dtheta);
1038
1039 if (firstismuon) {
1040 firstscatphi = muonscatphi;
1041 secondscatphi = idscatphi;
1042 firstscattheta = muonscattheta;
1043 secondscattheta = idscattheta;
1044 } else {
1045 firstscatphi = -idscatphi;
1046 secondscatphi = -muonscatphi;
1047 firstscattheta = -idscattheta;
1048 secondscattheta = -muonscattheta;
1049 }
1050
1051 if (i == 1 && cache.m_field_cache.toroidOn() && !firstismuon) {
1052 AmgVector(5) params2 = scat2->parameters();
1053 params2[Trk::phi] += idscatphi;
1054 params2[Trk::theta] += idscattheta;
1055
1056 if (!correctAngles(params2[Trk::phi], params2[Trk::theta])) {
1057 return nullptr;
1058 }
1059
1060 firstscatpar=scat2->associatedSurface().createUniqueTrackParameters(
1061 params2[0], params2[1], params2[2], params2[3], params2[4], std::nullopt
1062 );
1063 idscatpar = firstscatpar.get();
1064
1065 startPar = m_extrapolator->extrapolateToVolume(ctx,
1066 *idscatpar,
1067 *cache.m_caloEntrance,
1070
1071 if (startPar != nullptr) {
1072 const Amg::Vector3D trackdir = startPar->momentum().unit();
1073 const Amg::Vector3D curvZcrossT = -(trackdir.cross(Amg::Vector3D(0, 0, 1)));
1074 const Amg::Vector3D curvU = curvZcrossT.unit();
1075 const Amg::Vector3D curvV = trackdir.cross(curvU);
1076 Amg::RotationMatrix3D rot = Amg::RotationMatrix3D::Identity();
1077
1078 rot.col(0) = curvU;
1079 rot.col(1) = curvV;
1080 rot.col(2) = trackdir;
1081
1082 Amg::Transform3D trans;
1083 trans.linear().matrix() << rot;
1084 trans.translation() << startPar->position() - .1 * trackdir;
1085 PlaneSurface const curvlinsurf(trans);
1086
1087 const TrackParameters *curvlinpar = m_extrapolator->extrapolateDirectly(
1088 ctx,
1089 *startPar,
1090 curvlinsurf,
1093 ).release();
1094
1095 if (curvlinpar != nullptr) {
1096 startPar.reset(curvlinpar);
1097 }
1098 }
1099
1100 firstscatpar = std::move(scat2);
1101 }
1102 }
1103
1104 std::unique_ptr<GXFMaterialEffects> firstscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[0]);
1105 std::unique_ptr<GXFMaterialEffects> elossmeff = std::make_unique<GXFMaterialEffects>(calomeots[1]);
1106 std::unique_ptr<GXFMaterialEffects> secondscatmeff = std::make_unique<GXFMaterialEffects>(calomeots[2]);
1107
1108 const double pull1 = std::abs(firstscatphi / firstscatmeff->sigmaDeltaPhi());
1109 const double pull2 = std::abs(secondscatphi / secondscatmeff->sigmaDeltaPhi());
1110
1111 if (firstismuon) {
1112 for (auto & i : tmp_matvec) {
1113 makeProtoState(cache, trajectory, i, -1);
1114 }
1115 }
1116
1117 firstscatmeff->setScatteringAngles(firstscatphi, firstscattheta);
1118 secondscatmeff->setScatteringAngles(secondscatphi, secondscattheta);
1119
1120 if (!firstismuon) {
1121 elossmeff->setdelta_p(1000 * (lastscatpar->parameters()[Trk::qOverP] - newqoverpid));
1122 } else {
1123 elossmeff->setdelta_p(1000 * (newqoverpid - firstscatpar->parameters()[Trk::qOverP]));
1124 }
1125
1126 elossmeff->setSigmaDeltaE(calomeots[1].energyLoss()->sigmaDeltaE());
1127
1128 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(firstscatmeff), std::move(firstscatpar)), -1);
1129 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(elossmeff), std::move(elosspar)), -1);
1130 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(secondscatmeff), std::move(lastscatpar)), -1);
1131
1132 if (!firstismuon) {
1133 for (auto & i : tmp_matvec) {
1134 makeProtoState(cache, trajectory, i, -1);
1135 }
1136 }
1137
1138 ATH_MSG_DEBUG("pull1: " << pull1 << " pull2: " << pull2);
1139
1140 if (startPar == nullptr) {
1141 return nullptr;
1142 }
1143
1144 if (
1145 (pull1 > 5 || pull2 > 5) &&
1146 (pull1 > 25 || pull2 > 25 || closestmuonmeas->associatedSurface().type() == Trk::SurfaceType::Line)
1147 ) {
1148 return nullptr;
1149 }
1150
1151 bool largegap = false;
1152 double previousz = 0;
1153
1154 for (itStates2 = beginStates2; itStates2 != endState2; ++itStates2) {
1155 const MaterialEffectsBase *meff = (*itStates2)->materialEffectsOnTrack();
1156 const TrackParameters *tpar = (*itStates2)->trackParameters();
1157 const MeasurementBase *meas = (*itStates2)->measurementOnTrack();
1158
1159 if (meff != nullptr) {
1160 if (!firstismuon) {
1161 const MaterialEffectsOnTrack *mefot{};
1162 if (meff->derivedType() == MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK){
1163 mefot = static_cast<const MaterialEffectsOnTrack *>(meff);
1164 }
1165 if ( mefot and mefot->energyLoss() and
1166 std::abs(mefot->energyLoss()->deltaE()) > 250 &&
1167 mefot->energyLoss()->sigmaDeltaE() < 1.e-9
1168 ) {
1169 return nullptr;
1170 }
1171
1172 cache.m_extmat = false;
1173 } else {
1174 cache.m_idmat = false;
1175 }
1176 }
1178 if (
1179 ispseudo &&
1180 !(itStates2 == beginStates2 || itStates2 == beginStates2 + 1) &&
1181 !largegap
1182 ) {
1183 continue;
1184 }
1185
1186 makeProtoState(cache, trajectory, *itStates2);
1187
1188 if (
1189 itStates2 == endState2 - 1 &&
1190 tpar->associatedSurface().type() == Trk::SurfaceType::Line &&
1191 tpar->position().perp() > 9000 &&
1192 std::abs(tpar->position().z()) < 13000
1193 ) {
1194 std::unique_ptr<const TrackParameters> pseudopar(tpar->clone());
1195 Amg::MatrixX covMatrix(1, 1);
1196 covMatrix(0, 0) = 100;
1197
1198 std::unique_ptr<const PseudoMeasurementOnTrack> newpseudo = std::make_unique<const PseudoMeasurementOnTrack>(
1199 LocalParameters(DefinedParameter(pseudopar->parameters()[Trk::locY], Trk::locY)),
1200 std::move(covMatrix),
1201 pseudopar->associatedSurface()
1202 );
1203
1204 std::unique_ptr<GXFTrackState> pseudostate = std::make_unique<GXFTrackState>(std::move(newpseudo), std::move(pseudopar));
1205 pseudostate->setMeasurementType(TrackState::Pseudo);
1206
1207 double errors[5];
1208 errors[0] = errors[2] = errors[3] = errors[4] = -1;
1209 errors[1] = 10;
1210
1211 pseudostate->setMeasurementErrors(errors);
1212 trajectory.addMeasurementState(std::move(pseudostate));
1213 ispseudo = true;
1214 ATH_MSG_DEBUG("Adding pseudomeasurement");
1215 }
1216
1217 if (
1218 std::abs(trajectory.trackStates().back()->position().z()) > 20000 &&
1219 std::abs(previousz) < 12000
1220 ) {
1221 largegap = true;
1222 }
1223
1224 if (trajectory.trackStates().back()->getStateType(TrackStateOnSurface::Measurement)) {
1225 previousz = trajectory.trackStates().back()->position().z();
1226 }
1227 }
1228
1229 Track *track = myfit(
1230 ctx,
1231 cache,
1232 trajectory,
1233 *startPar,
1234 false,
1235 (cache.m_field_cache.toroidOn() || cache.m_field_cache.solenoidOn()) ? muon : nonInteracting
1236 );
1237
1238 return track;
1239 }
virtual double r() const override final
This method returns the radius.
virtual const CylinderBounds & bounds() const override final
This method returns the CylinderBounds by reference (NoBounds is not possible for cylinder)
static bool correctAngles(double &, double &)
virtual constexpr ParametersType type() const override=0
Return the ParametersType enum.

◆ makePerigee()

std::unique_ptr< const TrackParameters > Trk::GlobalChi2Fitter::makePerigee ( Cache & cache,
const TrackParameters & param,
const ParticleHypothesis matEffects ) const
private

Definition at line 4471 of file GlobalChi2Fitter.cxx.

4475 {
4476 const PerigeeSurface *persurf = nullptr;
4477
4478 if (param.associatedSurface().type() == Trk::SurfaceType::Perigee)
4479 persurf = static_cast<const PerigeeSurface *>(&param.associatedSurface());
4480
4481 if ((persurf != nullptr) && (!cache.m_acceleration || persurf->center().perp() > 5)) {
4482 const AmgVector(5) & pars = param.parameters();
4483 return param.associatedSurface().createUniqueTrackParameters(
4484 pars[0], pars[1], pars[2], pars[3], pars[4], std::nullopt
4485 );
4486 }
4487
4488 if (cache.m_acceleration) {
4489 return nullptr;
4490 }
4491
4492 PerigeeSurface const tmppersf;
4493 std::unique_ptr<const TrackParameters> per(m_extrapolator->extrapolate(
4494 Gaudi::Hive::currentContext(),param, tmppersf, oppositeMomentum, false, matEffects));
4495
4496 if (per == nullptr) {
4497 ATH_MSG_DEBUG("Cannot make Perigee with starting parameters");
4498 return nullptr;
4499 }
4500
4501 if(std::abs(per->position().z())>5000.) {
4502 ATH_MSG_WARNING("Pathological perigee well outside of tracking detector!! Returning nullptr");
4503 return nullptr;
4504 }
4505
4506 return per;
4507 }

◆ makeProtoState()

void Trk::GlobalChi2Fitter::makeProtoState ( Cache & cache,
GXFTrajectory & trajectory,
const TrackStateOnSurface * tsos,
int index = -1 ) const
private

Definition at line 2557 of file GlobalChi2Fitter.cxx.

2562 {
2563 if (
2564 (
2565 tsos->type(TrackStateOnSurface::Scatterer) ||
2566 tsos->type(TrackStateOnSurface::BremPoint) ||
2569 ) && cache.m_getmaterialfromtrack
2570 ) {
2571 if (cache.m_acceleration && trajectory.numberOfHits() == 0) {
2572 return;
2573 }
2574 if (tsos->materialEffectsOnTrack()->derivedType() != MaterialEffectsBase::MATERIAL_EFFECTS_ON_TRACK){
2575 return;
2576 }
2577 const MaterialEffectsOnTrack *meff = static_cast<const MaterialEffectsOnTrack *>(tsos->materialEffectsOnTrack());
2578
2579 std::unique_ptr<GXFMaterialEffects> newmeff;
2580
2581 if (
2582 meff->scatteringAngles() or
2583 meff->energyLoss() or
2584 !tsos->type(TrackStateOnSurface::Scatterer) or
2585 (tsos->trackParameters() == nullptr)
2586 ) {
2587 newmeff = std::make_unique<GXFMaterialEffects>(*meff);
2588 } else {
2589 Trk::MaterialProperties const matprop(meff->thicknessInX0(), 1., 0., 0., 0., 0.);
2590
2591 const double sigmascat = std::sqrt(m_scattool->sigmaSquare(
2592 matprop,
2593 std::abs(1. / tsos->trackParameters()->parameters()[Trk::qOverP]),
2594 1.,
2595 Trk::muon)
2596 );
2597
2598 auto newsa = Trk::ScatteringAngles(
2599 0,
2600 0,
2601 sigmascat / std::sin(tsos->trackParameters()->parameters()[Trk::theta]),
2602 sigmascat
2603 );
2604
2605 Trk::MaterialEffectsOnTrack const newmeot(
2606 meff->thicknessInX0(),
2607 newsa,
2608 nullptr,
2609 tsos->surface()
2610 );
2611
2612 newmeff = std::make_unique<GXFMaterialEffects>(newmeot);
2613 }
2614
2615 if (
2616 (meff->energyLoss() != nullptr) &&
2617 meff->energyLoss()->sigmaDeltaE() > 0 &&
2618 (
2619 (tsos->type(TrackStateOnSurface::BremPoint) && (meff->scatteringAngles() != nullptr)) ||
2620 ((meff->scatteringAngles() == nullptr) || meff->thicknessInX0() == 0)
2621 )
2622 ) {
2623 newmeff->setSigmaDeltaE(meff->energyLoss()->sigmaDeltaE());
2624
2625 if (
2626 (tsos->trackParameters() != nullptr) &&
2627 !trajectory.trackStates().empty() &&
2628 ((**trajectory.trackStates().rbegin()).trackParameters() != nullptr)
2629 ) {
2630 const double delta_p = 1000 * (
2631 tsos->trackParameters()->parameters()[Trk::qOverP] -
2632 (**trajectory.trackStates().rbegin()).trackParameters()->
2634 );
2635
2636 newmeff->setdelta_p(delta_p);
2637 }
2638 }
2639
2640 trajectory.addMaterialState(std::make_unique<GXFTrackState>(std::move(newmeff), unique_clone(tsos->trackParameters())), index);
2641 }
2642
2643 if (
2646 ) {
2647 const bool isoutlier = tsos->type(TrackStateOnSurface::Outlier) && !cache.m_reintoutl;
2648
2650 cache,
2651 trajectory,
2652 tsos->measurementOnTrack(),
2653 tsos->trackParameters(),
2654 isoutlier,
2655 index
2656 );
2657 }
2658 }
@ InertMaterial
This represents inert material, and so will contain MaterialEffectsBase.
@ CaloDeposit
This TSOS contains a CaloEnergy object.

◆ makeProtoStateFromMeasurement()

void Trk::GlobalChi2Fitter::makeProtoStateFromMeasurement ( Cache & cache,
GXFTrajectory & trajectory,
const MeasurementBase * measbase,
const TrackParameters * trackpar = nullptr,
bool isoutlier = false,
int index = -1 ) const
private

Definition at line 2660 of file GlobalChi2Fitter.cxx.

2667 {
2668 const Segment *seg = nullptr;
2669
2670 if (!measbase->associatedSurface().associatedDetectorElementIdentifier().is_valid()) {
2671 if (measbase->type(Trk::MeasurementBaseType::Segment)){
2672 seg = static_cast<const Segment *>(measbase);
2673 }
2674 }
2675
2676 int imax = 1;
2677
2678 if ((seg != nullptr) && m_decomposesegments) {
2679 imax = (int) seg->numberOfMeasurementBases();
2680 }
2681
2682 for (int i = 0; i < imax; i++) {
2683 const MeasurementBase *measbase2 = ((seg != nullptr) && m_decomposesegments) ? seg->measurement(i) : measbase;
2684 const TrackParameters *newtrackpar = ((seg != nullptr) && m_decomposesegments) ? nullptr : trackpar;
2685 std::unique_ptr<GXFTrackState> ptsos = std::make_unique<GXFTrackState>(
2686 std::unique_ptr<const MeasurementBase>(measbase2->clone()),
2687 std::unique_ptr<const TrackParameters>(newtrackpar != nullptr ? newtrackpar->clone() : nullptr)
2688 );
2689 const Amg::MatrixX & covmat = measbase2->localCovariance();
2690 double sinstereo = 0;
2691 double errors[5];
2692 errors[0] = errors[1] = errors[2] = errors[3] = errors[4] = -1;
2694 Identifier hitid = measbase2->associatedSurface().associatedDetectorElementIdentifier();
2695 //const CompetingRIOsOnTrack *crot = nullptr;
2696 if (!hitid.is_valid()) {
2698 const CompetingRIOsOnTrack *crot = static_cast<const CompetingRIOsOnTrack *>(measbase2);
2699 hitid = crot->rioOnTrack(0).identify();
2700 }
2701 }
2702
2703 bool measphi = false;
2704
2705 if (hitid.is_valid() && measbase2->localParameters().contains(Trk::locX)) {
2706 bool rotated = false;
2707
2708 if (m_DetID->is_indet(hitid) && !m_DetID->is_muon(hitid)) {
2709 if (m_DetID->is_pixel(hitid)) {
2710 hittype = TrackState::Pixel;
2711 } else if (m_DetID->is_sct(hitid)) {
2712 if (covmat.cols() != 1 && covmat(1, 0) != 0) {
2713 rotated = true;
2714 }
2715 hittype = TrackState::SCT;
2716 } else if (m_DetID->is_trt(hitid)) {
2717 hittype = TrackState::TRT;
2718 }
2719 } else { // Muon hit
2720 if (m_DetID->is_rpc(hitid)) {
2721 hittype = TrackState::RPC;
2722 if (measbase->localParameters().parameterKey() != 1) {
2723 ATH_MSG_WARNING("Corrupt RPC hit, skipping it");
2724 continue;
2725 }
2726 } else if (m_DetID->is_mdt(hitid)) {
2727 hittype = TrackState::MDT;
2728 } else if (m_DetID->is_tgc(hitid)) {
2729 if (measbase2->associatedSurface().bounds().type() == Trk::SurfaceBounds::Trapezoid) {
2730 rotated = true;
2731 }
2732 hittype = TrackState::TGC;
2733 } else if (m_DetID->is_csc(hitid)) {
2734 hittype = TrackState::CSC;
2735 } else if (m_DetID->is_mm(hitid)) {
2736 hittype = TrackState::MM;
2737 } else if (m_DetID->is_stgc(hitid)) {
2738 hittype = TrackState::STGC;
2739 }
2740 }
2741
2742 if (rotated) {
2743 const auto [covEigenValueSmall, covStereoAngle] = principalComponentAnalysis2x2(covmat);
2744 errors[0] = std::sqrt(covEigenValueSmall);
2745 sinstereo = std::sin(covStereoAngle);
2746 } else {
2747 errors[0] = std::sqrt(covmat(0, 0));
2748 if (hittype == TrackState::Pixel) {
2749 errors[1] = std::sqrt(covmat(1, 1));
2750 }
2751 }
2752 if (
2753 hittype == TrackState::RPC ||
2754 hittype == TrackState::TGC ||
2755 hittype == TrackState::CSC ||
2756 hittype == TrackState::STGC
2757 ) {
2758 const Surface *surf = &measbase2->associatedSurface();
2759 const Amg::Vector3D measdir = surf->transform().rotation().col(0);
2760 const double dotprod1 = measdir.dot(Amg::Vector3D(0, 0, 1));
2761 const double dotprod2 = measdir.dot(Amg::Vector3D(surf->center().x(), surf->center().y(), 0) / surf->center().perp());
2762 if (std::abs(dotprod1) < .5 && std::abs(dotprod2) < .5) {
2763 measphi = true;
2764 }
2765 }
2766 } else {
2767 const Trk::LocalParameters & psmpar = measbase2->localParameters();
2768 // @TODO coverity complains about index shadowing the method argument index
2769 // this is solved by renaming index in this block by param_index
2770 int param_index = 0;
2771 if (psmpar.contains(Trk::locRPhi)) {
2772 errors[0] = std::sqrt(covmat(0, 0));
2773 param_index++;
2774 }
2775
2776 if (psmpar.contains(Trk::locZ)) {
2777 errors[1] = std::sqrt(covmat(param_index, param_index));
2778 param_index++;
2779 }
2780
2781 if (psmpar.contains(Trk::phi)) {
2782 errors[2] = std::sqrt(covmat(param_index, param_index));
2783 param_index++;
2784 }
2785
2786 if (psmpar.contains(Trk::theta)) {
2787 errors[3] = std::sqrt(covmat(param_index, param_index));
2788 param_index++;
2789 }
2790
2791 if (psmpar.contains(Trk::qOverP)) {
2792 errors[4] = std::sqrt(covmat(param_index, param_index));
2793 param_index++;
2794 }
2796 hittype = TrackState::Pseudo;
2797 ATH_MSG_DEBUG("PseudoMeasurement, pos=" << measbase2->globalPosition());
2798 } else if (measbase2->type(Trk::MeasurementBaseType::VertexOnTrack )) {
2799 hittype = TrackState::Vertex;
2800 ATH_MSG_DEBUG("VertexOnTrack, pos=" << measbase2->globalPosition()); // print out the hit type
2801 } else if (measbase2->type(Trk::MeasurementBaseType::Segment )) {
2802 hittype = TrackState::Segment;
2803 ATH_MSG_DEBUG("Segment, pos=" << measbase2->globalPosition()); // print out the hit type
2804 }
2805 }
2806 if (
2807 errors[0] > 0 ||
2808 errors[1] > 0 ||
2809 errors[2] > 0 ||
2810 errors[3] > 0 ||
2811 errors[4] > 0
2812 ) {
2813 ptsos->setMeasurementErrors(errors);
2814 ptsos->setSinStereo(sinstereo);
2815 ptsos->setMeasurementType(hittype);
2816 ptsos->setMeasuresPhi(measphi);
2817
2818 if (isoutlier && !cache.m_reintoutl) {
2819 ptsos->resetStateType(TrackStateOnSurface::Outlier);
2820 }
2821
2822 // @TODO here index really is supposed to refer to the method argument index ?
2823 const bool ok = trajectory.addMeasurementState(std::move(ptsos), index);
2824 if (!ok) {
2825 ATH_MSG_WARNING("Duplicate hit on track");
2826 }
2827 } else {
2828 ATH_MSG_WARNING("Measurement error is zero or negative, drop hit");
2829 }
2830 }
2831 }
int imax(int i, int j)
Gaudi::Property< bool > m_decomposesegments
bool contains(ParamDefs par) const
The simple check for the clients whether the parameter is contained.
@ locX
Definition ParamDefs.h:37
@ locRPhi
Definition ParamDefs.h:40
@ locZ
local cylindrical
Definition ParamDefs.h:42

◆ makeTrack()

std::unique_ptr< Track > Trk::GlobalChi2Fitter::makeTrack ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & oldtrajectory,
const ParticleHypothesis matEffects ) const
private

Definition at line 7531 of file GlobalChi2Fitter.cxx.

7536 {
7537 // Convert internal trajectory into track
7538 auto trajectory = std::make_unique<Trk::TrackStates>();
7539
7540 if (m_fillderivmatrix) {
7541 makeTrackFillDerivativeMatrix(cache, oldtrajectory);
7542 }
7543
7544 GXFTrajectory tmptrajectory(oldtrajectory);
7545
7546 std::unique_ptr<GXFTrackState> perigee_ts = makeTrackFindPerigee(ctx, cache, oldtrajectory, matEffects);
7547
7548 if (perigee_ts == nullptr) {
7549 return nullptr;
7550 }
7551
7552 tmptrajectory.addBasicState(std::move(perigee_ts), cache.m_acceleration ? 0 : tmptrajectory.numberOfUpstreamStates());
7553 //reserve the ouput size
7554 trajectory->reserve(tmptrajectory.trackStates().size());
7555 for (auto & hit : tmptrajectory.trackStates()) {
7556 if (
7557 hit->measurementType() == TrackState::Pseudo &&
7558 hit->getStateType(TrackStateOnSurface::Outlier)
7559 ) {
7560 hit->resetTrackCovariance();
7561 continue;
7562 }
7563
7564 if (!Trk::consistentSurfaces (hit->trackParameters(),
7565 hit->measurement(),
7566 hit->materialEffects()))
7567 {
7568 return nullptr;
7569 }
7570
7571 //should check hit->isSane() here with better equality check(other than ptr comparison)
7572 auto trackState = hit->trackStateOnSurface();
7573 hit->resetTrackCovariance();
7574 trajectory->emplace_back(trackState.release());
7575 }
7576
7577 auto qual = std::make_unique<FitQuality>(tmptrajectory.chi2(), tmptrajectory.nDOF());
7578
7579
7580 TrackInfo info;
7581
7582 if (matEffects != electron) {
7583 info = TrackInfo(TrackInfo::GlobalChi2Fitter, matEffects);
7584 } else {
7586 info.setTrackProperties(TrackInfo::BremFit);
7587
7588 if (matEffects == electron && tmptrajectory.hasKink()) {
7589 info.setTrackProperties(TrackInfo::BremFitSuccessful);
7590 }
7591 }
7592
7593 if (tmptrajectory.m_straightline) {
7594 info.setTrackProperties(TrackInfo::StraightTrack);
7595 }
7596
7597 std::unique_ptr<Track> rv = std::make_unique<Track>(info, std::move(trajectory), std::move(qual));
7598
7599 /*
7600 * Here, we create a track summary and attach it to our newly created
7601 * track. Note that this code only runs if the m_createSummary Gaudi
7602 * property is set. In cases where having a track summary on the track is
7603 * not desired, such as for compatibility with other tools, this can be
7604 * turned off.
7605 */
7606 if (m_createSummary.value()) {
7607 std::unique_ptr<TrackSummary> ts = std::make_unique<TrackSummary>();
7608
7609 /*
7610 * This segment determines the hole search behaviour of the track fitter.
7611 * It is only invoked if the DoHoleSearch parameter is set, but it can
7612 * take a significant amount of CPU time, since the hole search is rather
7613 * expensive. Beware of that!
7614 */
7615 if (m_holeSearch.value()) {
7616 std::optional<TrackHoleCount> hole_count;
7617
7618 /*
7619 * First, we collect a list of states that will act as our hole search
7620 * extrapolation states. This will serve as our source of truth in
7621 * regards to which track states we need to extrapolate between.
7622 */
7623 std::vector<std::reference_wrapper<GXFTrackState>> const states = holeSearchStates(tmptrajectory);
7624
7625 /*
7626 * Then, collect the actual hole search infomation using our state list
7627 * from before. This is the expensive operation, as it will invoke a
7628 * series of extrapolations if not all states have existing hole
7629 * information! It will also check all the hole candidates to see if
7630 * they are actually holes or not.
7631 */
7632 hole_count = holeSearchProcess(ctx, states);
7633
7634 /*
7635 * Note that the hole search is not guaranteed to return a useful set
7636 * of values. It can, for example, reach an error state if the number
7637 * of measurements on a track is below a certain threshold. In that
7638 * case, a non-extant result will be returned, which we must guard
7639 * against. In that case, the hole counts will remain unset.
7640 */
7641 if (hole_count.has_value()) {
7642 /*
7643 * If the hole search did return good results, we can proceed to
7644 * simply copy the numerical values in the track summary.
7645 */
7646 ts->update(Trk::numberOfPixelHoles, hole_count->m_pixel_hole);
7647 ts->update(Trk::numberOfSCTHoles, hole_count->m_sct_hole);
7648 ts->update(Trk::numberOfSCTDoubleHoles, hole_count->m_sct_double_hole);
7649 ts->update(Trk::numberOfPixelDeadSensors, hole_count->m_pixel_dead);
7650 ts->update(Trk::numberOfSCTDeadSensors, hole_count->m_sct_dead);
7651 }
7652 }
7653
7654 rv->setTrackSummary(std::move(ts));
7655 }
7656
7657 return rv;
7658 }
std::optional< GlobalChi2Fitter::TrackHoleCount > holeSearchProcess(const EventContext &ctx, const std::vector< std::reference_wrapper< GXFTrackState > > &states) const
Conduct a hole search between a list of states, possibly reusing existing information.
std::unique_ptr< GXFTrackState > makeTrackFindPerigee(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const
std::vector< std::reference_wrapper< GXFTrackState > > holeSearchStates(GXFTrajectory &trajectory) const
Extracts a collection of track states which are important for hole search.
static void makeTrackFillDerivativeMatrix(Cache &, GXFTrajectory &)
@ GlobalChi2Fitter
Track's from Thijs' global chi^2 fitter.
@ BremFit
A brem fit was performed on this track.
@ BremFitSuccessful
A brem fit was performed on this track and this fit was successful.
bool consistentSurfaces(U)
@ numberOfSCTHoles
number of Holes in both sides of a SCT module
@ numberOfPixelHoles
number of pixels which have a ganged ambiguity.
@ numberOfPixelDeadSensors
number of pixel hits with broad errors (width/sqrt(12))

◆ makeTrackFillDerivativeMatrix()

void Trk::GlobalChi2Fitter::makeTrackFillDerivativeMatrix ( Cache & cache,
GXFTrajectory & oldtrajectory )
staticprivate

Definition at line 6990 of file GlobalChi2Fitter.cxx.

6993 {
6994 Amg::MatrixX & derivs = oldtrajectory.weightedResidualDerivatives();
6995 Amg::VectorX & errors = oldtrajectory.errors();
6996 int nrealmeas = 0;
6997
6998 for (auto & hit : oldtrajectory.trackStates()) {
6999 if (const auto *pMeas{hit->measurement()};
7000 hit->getStateType(TrackStateOnSurface::Measurement) and (
7003 )
7004 ) {
7005 nrealmeas += hit->numberOfMeasuredParameters();
7006 }
7007 }
7008 cache.m_derivmat.resize(nrealmeas, oldtrajectory.numberOfFitParameters());
7009 cache.m_derivmat.setZero();
7010 int measindex = 0;
7011 int measindex2 = 0;
7012 const int nperpars = oldtrajectory.numberOfPerigeeParameters();
7013 const int nscat = oldtrajectory.numberOfScatterers();
7014 for (auto & hit : oldtrajectory.trackStates()) {
7015 if (const auto *pMeas{hit->measurement()};
7016 hit->getStateType(TrackStateOnSurface::Measurement) and (
7019 )
7020 ) {
7021 for (int i = measindex; i < measindex + hit->numberOfMeasuredParameters(); i++) {
7022 for (int j = 0; j < oldtrajectory.numberOfFitParameters(); j++) {
7023 cache.m_derivmat(i, j) = derivs(measindex2, j) * errors[measindex2];
7024 if ((j == 4 && !oldtrajectory.m_straightline) || j >= nperpars + 2 * nscat) {
7025 cache.m_derivmat(i, j) *= 1000;
7026 }
7027 }
7028
7029 measindex2++;
7030 }
7031
7032 measindex += hit->numberOfMeasuredParameters();
7033 } else if (hit->materialEffects() == nullptr) {
7034 measindex2 += hit->numberOfMeasuredParameters();
7035 }
7036 }
7037 }

◆ makeTrackFindPerigee()

std::unique_ptr< GXFTrackState > Trk::GlobalChi2Fitter::makeTrackFindPerigee ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & oldtrajectory,
const ParticleHypothesis matEffects ) const
private

Definition at line 7188 of file GlobalChi2Fitter.cxx.

7193 {
7194 std::unique_ptr<const TrackParameters> per = makeTrackFindPerigeeParameters(ctx, cache, oldtrajectory, matEffects);
7195
7196 if (per == nullptr) {
7197 return nullptr;
7198 }
7199
7200 ATH_MSG_DEBUG("Final perigee: " << *per << " pos: " << per->position() << " pT: " << per->pT());
7201
7202 return std::make_unique<GXFTrackState>(std::move(per), TrackStateOnSurface::Perigee);
7203 }
std::unique_ptr< const TrackParameters > makeTrackFindPerigeeParameters(const EventContext &, Cache &, GXFTrajectory &, const ParticleHypothesis) const

◆ makeTrackFindPerigeeParameters()

std::unique_ptr< const TrackParameters > Trk::GlobalChi2Fitter::makeTrackFindPerigeeParameters ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & oldtrajectory,
const ParticleHypothesis matEffects ) const
private

Definition at line 7039 of file GlobalChi2Fitter.cxx.

7044 {
7045 GXFTrackState *firstmeasstate = nullptr;
7046 GXFTrackState *lastmeasstate = nullptr;
7047 std::tie(firstmeasstate, lastmeasstate) = oldtrajectory.findFirstLastMeasurement();
7048 std::unique_ptr<const TrackParameters> per(nullptr);
7049
7050 if (cache.m_acceleration && !m_matupdator.empty()) {
7051 std::unique_ptr<const TrackParameters> prevpar(
7052 firstmeasstate->trackParameters() != nullptr ?
7053 firstmeasstate->trackParameters()->clone() :
7054 nullptr
7055 );
7056 std::vector<std::pair<const Layer *, const Layer *>> & upstreamlayers = oldtrajectory.upstreamMaterialLayers();
7057 bool first = true;
7058
7059 for (const auto & [layer1, layer2] : upstreamlayers | std::views::reverse) {
7060 if (prevpar == nullptr) {
7061 break;
7062 }
7063
7065 const Layer *layer = layer1 != nullptr ? layer1 : layer2;
7066
7067 const DistanceSolution distsol = layer->surfaceRepresentation().straightLineDistanceEstimate(
7068 prevpar->position(), prevpar->momentum().unit()
7069 );
7070 const double distance = getDistance(distsol);
7071
7072 if (distsol.numberOfSolutions() == 2) {
7073 if (std::abs(distance) < 0.01) {
7074 continue;
7075 }
7076
7077 if (distsol.first() * distsol.second() < 0 && !first) {
7078 continue;
7079 }
7080 }
7081
7082 if (first && distance > 0) {
7083 propdir = alongMomentum;
7084 }
7085
7086 std::unique_ptr<const TrackParameters> layerpar(
7087 m_propagator->propagate(
7088 ctx,
7089 *prevpar,
7090 layer->surfaceRepresentation(),
7091 propdir,
7092 true,
7093 oldtrajectory.m_fieldprop,
7095 )
7096 );
7097
7098 if (layerpar == nullptr) {
7099 continue;
7100 }
7101
7102 if (layer->surfaceRepresentation().bounds().inside(layerpar->localPosition())) {
7103 layerpar = m_matupdator->update(layerpar.get(), *layer, oppositeMomentum, matEffects);
7104 }
7105
7106 prevpar = std::move(layerpar);
7107 first = false;
7108 }
7109
7110 const Layer *startlayer = firstmeasstate->trackParameters()->associatedSurface().associatedLayer();
7111
7112 if ((startlayer != nullptr) && (startlayer->layerMaterialProperties() != nullptr)) {
7113 double startfactor = startlayer->layerMaterialProperties()->alongPostFactor();
7114 const Surface & discsurf = startlayer->surfaceRepresentation();
7115
7116 if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7117 startfactor = startlayer->layerMaterialProperties()->oppositePostFactor();
7118 }
7119 if (startfactor > 0.5) {
7120 std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7121 firstmeasstate->trackParameters(), *startlayer, oppositeMomentum, matEffects
7122 );
7123
7124 if (updatedpar != nullptr) {
7125 firstmeasstate->setTrackParameters(std::move(updatedpar));
7126 }
7127 }
7128 }
7129
7130 // @TODO Coverity complains about a possible NULL pointer dereferencing in lastmeasstate->...
7131 // Now an exception is thrown if there is no firstmeastate. Thus if the code here is
7132 // reached then there should be a firstmeasstate and a lastmeasstate
7133
7134 const Layer *endlayer = lastmeasstate->trackParameters()->associatedSurface().associatedLayer();
7135
7136 if ((endlayer != nullptr) && (endlayer->layerMaterialProperties() != nullptr)) {
7137 double endfactor = endlayer->layerMaterialProperties()->alongPreFactor();
7138 const Surface & discsurf = endlayer->surfaceRepresentation();
7139
7140 if (discsurf.type() == Trk::SurfaceType::Disc && discsurf.center().z() * discsurf.normal().z() < 0) {
7141 endfactor = endlayer->layerMaterialProperties()->oppositePreFactor();
7142 }
7143
7144 if (endfactor > 0.5) {
7145 std::unique_ptr<const TrackParameters> updatedpar = m_matupdator->update(
7146 lastmeasstate->trackParameters(), *endlayer, alongMomentum, matEffects
7147 );
7148
7149 if (updatedpar != nullptr) {
7150 lastmeasstate->setTrackParameters(std::move(updatedpar));
7151 }
7152 }
7153 }
7154
7155 if (prevpar != nullptr) {
7156 per = m_propagator->propagate(
7157 ctx,
7158 *prevpar,
7159 PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7161 false,
7162 oldtrajectory.m_fieldprop,
7164 );
7165 }
7166
7167 if (per == nullptr) {
7168 ATH_MSG_DEBUG("Failed to extrapolate to perigee, returning 0");
7169 cache.incrementFitStatus(S_PROPAGATION_FAIL);
7170 cache.m_fittercode = FitterStatusCode::ExtrapolationFailure;
7171 return nullptr;
7172 }
7173 } else if (cache.m_acceleration && (firstmeasstate->trackParameters() != nullptr)) {
7174 per = m_extrapolator->extrapolate(ctx,
7175 *firstmeasstate->trackParameters(),
7176 PerigeeSurface(Amg::Vector3D(0, 0, 0)),
7178 false,
7179 matEffects);
7180 } else {
7181 per.reset(oldtrajectory.referenceParameters()->clone());
7182 }
7183
7184 return per;
7185 }
bool first
Definition DeMoScan.py:534

◆ myfit()

Track * Trk::GlobalChi2Fitter::myfit ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & trajectory,
const TrackParameters & param,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
private

Definition at line 4509 of file GlobalChi2Fitter.cxx.

4516 {
4517 ATH_MSG_DEBUG("--> entering GlobalChi2Fitter::myfit_helper");
4518 cache.m_fittercode = FitterStatusCode::Success;
4519 trajectory.m_straightline = m_straightlineprop;
4520
4521 if (!trajectory.m_straightline) {
4522 if (trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
4523 trajectory.m_straightline = !cache.m_field_cache.solenoidOn();
4524 } else if ((trajectory.prefit() == 0) && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == 0) {
4525 trajectory.m_straightline = !cache.m_field_cache.toroidOn();
4526 } else {
4527 trajectory.m_straightline = (!cache.m_field_cache.solenoidOn() && !cache.m_field_cache.toroidOn());
4528 }
4529 }
4530
4531 trajectory.m_fieldprop = trajectory.m_straightline ? Trk::NoField : Trk::FullField;
4532 cache.m_lastiter = 0;
4533
4534 Amg::SymMatrixX lu;
4535
4536 if (trajectory.numberOfPerigeeParameters() == -1) {
4537 cache.incrementFitStatus(S_FITS);
4538 if (trajectory.m_straightline) {
4539 trajectory.setNumberOfPerigeeParameters(4);
4540 } else {
4541 trajectory.setNumberOfPerigeeParameters(5);
4542 }
4543 }
4544
4545 if (trajectory.nDOF() < 0) {
4546 ATH_MSG_DEBUG("Not enough measurements, reject track");
4547 return nullptr;
4548 }
4549
4550 cache.m_phiweight.clear();
4551 cache.m_firstmeasurement.clear();
4552 cache.m_lastmeasurement.clear();
4553
4554 if (matEffects != nonInteracting && param.parameters()[Trk::qOverP] == 0 && m_p == 0) {
4555 ATH_MSG_WARNING("Attempt to apply material corrections with q/p=0, reject track");
4556 return nullptr;
4557 }
4558
4559 if (matEffects == Trk::electron && trajectory.m_straightline) {
4560 ATH_MSG_WARNING("Electron fit requires helix track model");
4561 return nullptr;
4562 }
4563
4564 const double mass = Trk::ParticleMasses::mass[matEffects];
4565 trajectory.setMass(mass);
4566
4567 ATH_MSG_DEBUG("start param: " << param << " pos: " << param.position() << " pt: " << param.pT());
4568
4569 std::unique_ptr<const TrackParameters> per = makePerigee(cache, param, matEffects);
4570
4571 if (!cache.m_acceleration && (per == nullptr)) {
4572 cache.m_fittercode = FitterStatusCode::ExtrapolationFailure;
4573 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4574 ATH_MSG_DEBUG("Propagation to perigee failed 1");
4575 return nullptr;
4576 }
4577
4578 if (matEffects != Trk::nonInteracting && !cache.m_matfilled) {
4579 if (
4580 cache.m_fastmat &&
4581 cache.m_acceleration &&
4582 trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits() &&
4583 (m_matupdator.empty() || (m_trackingGeometryReadKey.key().empty()))
4584 ) {
4585 ATH_MSG_WARNING("Tracking Geometry Service and/or Material Updator Tool not configured");
4586 ATH_MSG_WARNING("Falling back to slow material collection");
4587
4588 cache.m_fastmat = false;
4589 }
4590
4591 if (
4592 !cache.m_fastmat ||
4593 !cache.m_acceleration ||
4594 trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() != trajectory.numberOfHits()
4595 ) {
4596 addMaterial(ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4597 } else {
4599 ctx, cache, trajectory, per != nullptr ? per.get() : &param, matEffects);
4600 }
4601 }
4602
4603 if (cache.m_acceleration && (trajectory.referenceParameters() == nullptr) && (per == nullptr)) {
4605
4606 if (trajectory.numberOfScatterers() >= 2) {
4607 GXFTrackState *scatstate = nullptr;
4608 GXFTrackState *scatstate2 = nullptr;
4609 int scatindex = 0;
4610
4611 for (const auto & state : trajectory.trackStates()) {
4612 if (state->getStateType(TrackStateOnSurface::Scatterer)) {
4613 if (
4614 scatindex == trajectory.numberOfScatterers() / 2 ||
4615 state->materialEffects()->deltaE() == 0
4616 ) {
4617 scatstate2 = state.get();
4618 break;
4619 }
4620
4621 scatindex++;
4622 scatstate = state.get();
4623 }
4624 }
4625
4626 // @TODO coverity complains about a possible null pointer dereferencing in scatstate->... or scatstate2->...
4627 // it seems to me that if (**it).materialEffects()->deltaE()==0 of the first scatterer
4628 // than scatstate will be NULL.
4629 if ((scatstate == nullptr) || (scatstate2 == nullptr)) {
4630 throw std::logic_error("Invalid scatterer");
4631 }
4632
4633 vertex = .49 * (scatstate->position() + scatstate2->position());
4634 } else {
4635 const int nstates = (int) trajectory.trackStates().size();
4636 vertex = .49 * (
4637 trajectory.trackStates()[nstates / 2 - 1]->position() +
4638 trajectory.trackStates()[nstates / 2]->position()
4639 );
4640 }
4641
4642 PerigeeSurface const persurf(vertex);
4643 std::unique_ptr<const TrackParameters> nearestpar;
4644 double mindist = 99999;
4645 std::vector < GXFTrackState * >mymatvec;
4646
4647 for (auto & it : trajectory.trackStates()) {
4648 if ((*it).trackParameters() == nullptr) {
4649 continue;
4650 }
4651
4652 const double distance = persurf
4653 .straightLineDistanceEstimate(
4654 (*it).trackParameters()->position(),
4655 (*it).trackParameters()->momentum().unit())
4656 .first();
4657
4658 const bool insideid = (
4659 (cache.m_caloEntrance == nullptr) ||
4660 cache.m_caloEntrance->inside((*it).trackParameters()->position())
4661 );
4662
4663 if (
4664 (((*it).measurement() != nullptr) && insideid) || (
4665 ((*it).materialEffects() != nullptr) &&
4666 distance > 0 && (
4667 (*it).materialEffects()->deltaE() == 0 ||
4668 ((*it).materialEffects()->sigmaDeltaPhi() == 0 &&
4669 !insideid) ||
4670 (*it).materialEffects()->deltaPhi() != 0
4671 )
4672 )
4673 ) {
4674 const double dist = ((*it).trackParameters()->position() - vertex).perp();
4675 if (dist < mindist) {
4676 mindist = dist;
4677 nearestpar = unique_clone((*it).trackParameters());
4678 mymatvec.clear();
4679 continue;
4680 }
4681 }
4682
4683 if (((*it).materialEffects() != nullptr) && distance > 0) {
4684 mymatvec.push_back(it.get());
4685 }
4686 }
4687
4688 if (nearestpar == nullptr) {
4689 nearestpar = unique_clone(&param);
4690 }
4691
4692 for (auto & state : mymatvec) {
4694 const Surface &matsurf = state->associatedSurface();
4695 const DistanceSolution distsol = matsurf.straightLineDistanceEstimate(
4696 nearestpar->position(), nearestpar->momentum().unit());
4697
4698 const double distance = getDistance(distsol);
4699
4700 if (distance < 0 && distsol.numberOfSolutions() > 0) {
4701 propdir = oppositeMomentum;
4702 }
4703
4704 std::unique_ptr<const TrackParameters> tmppar(m_propagator->propagateParameters(
4705 ctx,
4706 *nearestpar,
4707 matsurf,
4708 propdir,
4709 false,
4710 trajectory.m_fieldprop,
4712 ));
4713
4714 if (tmppar == nullptr) {
4715 propdir = (propdir == oppositeMomentum) ? alongMomentum : oppositeMomentum;
4716 tmppar = m_propagator->propagateParameters(
4717 ctx,
4718 *nearestpar,
4719 matsurf,
4720 propdir,
4721 false,
4722 trajectory.m_fieldprop,
4724 );
4725
4726 if (tmppar == nullptr) {
4727 cache.m_fittercode = FitterStatusCode::ExtrapolationFailure;
4728 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4729
4730 ATH_MSG_DEBUG("Propagation to perigee failed 2");
4731
4732 return nullptr;
4733 }
4734 }
4735
4736 AmgVector(5) newpars = tmppar->parameters();
4737
4738 if (state->materialEffects()->sigmaDeltaE() > 0) {
4739 newpars[Trk::qOverP] += .001 * state->materialEffects()->delta_p();
4740 } else if (newpars[Trk::qOverP] != 0) {
4741 const double sign = (newpars[Trk::qOverP] > 0) ? 1 : -1;
4742 const double de = std::abs(state->materialEffects()->deltaE());
4743 const double oldp = std::abs(1 / newpars[Trk::qOverP]);
4744 const double newp2 = oldp * oldp - 2 * de * std::sqrt(mass * mass + oldp * oldp) + de * de;
4745 if (newp2 > 0) {
4746 newpars[Trk::qOverP] = sign / std::sqrt(newp2);
4747 }
4748 }
4749
4750 nearestpar = tmppar->associatedSurface().createUniqueTrackParameters(
4751 newpars[0], newpars[1], newpars[2], newpars[3], newpars[4], std::nullopt
4752 );
4753 }
4754
4755 std::unique_ptr<Trk::TrackParameters> tmpPars(m_propagator->propagateParameters(
4756 ctx,
4757 *nearestpar,
4758 persurf,
4760 false,
4761 trajectory.m_fieldprop,
4763 ));
4764
4765 // Parameters are at a Perigee surface so they are perigee parameters
4766 if (tmpPars != nullptr) {
4767 per.reset(static_cast < const Perigee *>(tmpPars.release()));
4768 }
4769
4770 if ((per != nullptr) && (matEffects == Trk::proton || matEffects == Trk::kaon)) {
4771 const double sign = (per->parameters()[Trk::qOverP] < 0) ? -1. : 1.;
4772 const double oldp = 1. / std::abs(per->parameters()[Trk::qOverP]);
4773 const double toteloss = std::abs(trajectory.totalEnergyLoss());
4774 const double newp = std::sqrt(oldp * oldp + 2 * toteloss * std::sqrt(oldp * oldp + mass * mass) + toteloss * toteloss);
4775 AmgVector(5) params = per->parameters();
4776 params[Trk::qOverP] = sign / newp;
4777
4778 per = per->associatedSurface().createUniqueTrackParameters(
4779 params[0], params[1], params[2], params[3], params[4], std::nullopt
4780 );
4781 }
4782
4783 if (per == nullptr) {
4784 cache.m_fittercode = FitterStatusCode::ExtrapolationFailure;
4785 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4786 ATH_MSG_DEBUG("Propagation to perigee failed 3");
4787
4788 return nullptr;
4789 }
4790
4791 PerigeeSurface const persurf2(per->position());
4792 per = persurf2.createUniqueTrackParameters(
4793 0,
4794 0,
4795 per->parameters()[Trk::phi],
4796 per->parameters()[Trk::theta],
4797 per->parameters()[Trk::qOverP],
4798 std::nullopt
4799 );
4800 } else if (per == nullptr) {
4801 per = makePerigee(cache, param, matEffects);
4802 }
4803
4804 if ((per == nullptr) && (trajectory.referenceParameters() == nullptr)) {
4805 cache.m_fittercode = FitterStatusCode::ExtrapolationFailure;
4806 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4807 ATH_MSG_DEBUG("Propagation to perigee failed 4");
4808
4809 return nullptr;
4810 }
4811
4812 if (trajectory.m_straightline && (per != nullptr)) {
4813 if (trajectory.numberOfPerigeeParameters() == -1) {
4814 trajectory.setNumberOfPerigeeParameters(4);
4815 }
4816
4817 const AmgVector(5) & pars = per->parameters();
4818 per = per->associatedSurface().createUniqueTrackParameters(
4819 pars[0], pars[1], pars[2], pars[3], 0, std::nullopt
4820 );
4821 } else if (trajectory.numberOfPerigeeParameters() == -1) {
4822 trajectory.setNumberOfPerigeeParameters(5);
4823 }
4824
4825 if (per != nullptr) {
4826 trajectory.setReferenceParameters(std::move(per));
4827 }
4828
4829 const int nfitpar = trajectory.numberOfFitParameters();
4830 const int nperpars = trajectory.numberOfPerigeeParameters();
4831 const int nscat = trajectory.numberOfScatterers();
4832 const int nbrem = trajectory.numberOfBrems();
4833
4834 Eigen::MatrixXd a;
4835 Eigen::MatrixXd a_inv;
4836 a.resize(nfitpar, nfitpar);
4837
4838 Amg::VectorX b(nfitpar);
4839
4840 Amg::MatrixX derivPool(5, nfitpar);
4841 derivPool.setZero();
4842
4843 for (std::unique_ptr<GXFTrackState> & state : trajectory.trackStates()) {
4844 if (state->materialEffects() != nullptr) {
4845 continue;
4846 }
4847 state->setDerivatives(derivPool);
4848 }
4849
4850 bool doderiv = true;
4851 const int tmpminiter = cache.m_miniter;
4852
4853 for (int it = 0; it < m_maxit; ++it) {
4854 cache.m_lastiter = it;
4855
4856 if (it >= m_maxit - 1) {
4857 ATH_MSG_DEBUG("Fit did not converge");
4858 cache.m_fittercode = FitterStatusCode::NoConvergence;
4859 cache.incrementFitStatus(S_NOT_CONVERGENT);
4860 cache.m_miniter = tmpminiter;
4861 return nullptr;
4862 }
4863
4864 if (!trajectory.converged()) {
4865 cache.m_fittercode =
4866 runIteration(ctx, cache, trajectory, it, a, b, lu, doderiv);
4867 if (cache.m_fittercode != FitterStatusCode::Success) {
4868 if (cache.m_fittercode == FitterStatusCode::ExtrapolationFailure) {
4869 cache.incrementFitStatus(S_PROPAGATION_FAIL);
4870 } else if (cache.m_fittercode == FitterStatusCode::InvalidAngles) {
4871 cache.incrementFitStatus(S_INVALID_ANGLES);
4872 } else if (cache.m_fittercode == FitterStatusCode::ExtrapolationFailureDueToSmallMomentum) {
4873 cache.incrementFitStatus(S_LOW_MOMENTUM);
4874 }
4875 cache.m_miniter = tmpminiter;
4876 return nullptr;
4877 }
4878
4879 const int nhits = trajectory.numberOfHits();
4880 const int ntrthits = trajectory.numberOfTRTHits();
4881 const int nsihits = trajectory.numberOfSiliconHits();
4882 const double redchi2 = (trajectory.nDOF() > 0) ? trajectory.chi2() / trajectory.nDOF() : 0;
4883 const double prevredchi2 = (trajectory.nDOF() > 0) ? trajectory.prevchi2() / trajectory.nDOF() : 0;
4884
4885
4886 if( nsihits > 0 && it > 0 && it < m_maxitPixelROT )
4887 updatePixelROTs( trajectory, a, b, ctx);
4888
4889 if (
4890 it > 0 &&
4891 it < 4 && (
4892 (redchi2 < prevredchi2 &&
4893 (redchi2 > prevredchi2 - 1 || redchi2 < 2)) ||
4894 nsihits + ntrthits == nhits
4895 ) &&
4896 (runOutlier || m_trtrecal) &&
4897 ntrthits > 0
4898 ) {
4899 if (it != 1 || nsihits != 0 || trajectory.nDOF() <= 0 || trajectory.chi2() / trajectory.nDOF() <= 3) {
4900 ATH_MSG_DEBUG("Running TRT cleaner");
4901 runTrackCleanerTRT(cache, trajectory, a, b, lu, runOutlier, m_trtrecal, it, ctx);
4902 if (cache.m_fittercode != FitterStatusCode::Success) {
4903 ATH_MSG_DEBUG("TRT cleaner failed, returning null...");
4904 cache.m_miniter = tmpminiter;
4905 return nullptr;
4906 }
4907 }
4908 }
4909
4910 // PHF cut at iteration 3 (to save CPU time)
4911 const int ntrtprechits = trajectory.numberOfTRTPrecHits();
4912 const int ntrttubehits = trajectory.numberOfTRTTubeHits();
4913 float phf = 1.;
4914 if (ntrtprechits+ntrttubehits) {
4915 phf = float(ntrtprechits)/float(ntrtprechits+ntrttubehits);
4916 }
4917 if (phf<m_minphfcut && it>=3) {
4918 if ((ntrtprechits+ntrttubehits)>=15) {
4919 return nullptr;
4920 }
4921 }
4922 ATH_MSG_DEBUG("Iter = " << it << " | nTRTStates = " << ntrthits
4923 << " | nTRTPrecHits = " << ntrtprechits
4924 << " | nTRTTubeHits = " << ntrttubehits
4925 << " | nOutliers = "
4926 << trajectory.numberOfOutliers());
4927
4928 if (!trajectory.converged()) {
4929 cache.m_fittercode = updateFitParameters(trajectory, b, lu);
4930 if (cache.m_fittercode != FitterStatusCode::Success) {
4931 if (cache.m_fittercode == FitterStatusCode::InvalidAngles) {
4932 cache.incrementFitStatus(S_INVALID_ANGLES);
4933 }
4934 cache.m_miniter = tmpminiter;
4935 return nullptr;
4936 }
4937 }
4938 } else {
4939 break;
4940 }
4941 }
4942
4943 cache.m_miniter = tmpminiter;
4944
4945 if (trajectory.prefit() == 0) {
4946 // Solve assuming the matrix is SPD.
4947 // Cholesky Decomposition is used -- could use LDLT
4948
4949 Eigen::LLT < Eigen::MatrixXd > const lltOfW(a);
4950 if (lltOfW.info() == Eigen::Success) {
4951 // Solve for x where Wx = I
4952 // this is cheaper than invert as invert makes no assumptions about the
4953 // matrix being symmetric
4954 const int ncols = a.cols();
4955 Amg::MatrixX const weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
4956 a_inv = lltOfW.solve(weightInvAMG);
4957 } else {
4958 ATH_MSG_DEBUG("matrix inversion failed!");
4959 cache.incrementFitStatus(S_MAT_INV_FAIL);
4960 cache.m_fittercode = FitterStatusCode::MatrixInversionFailure;
4961 return nullptr;
4962 }
4963 }
4964
4965 GXFTrajectory *finaltrajectory = &trajectory;
4966 if (
4967 (runOutlier || cache.m_sirecal) &&
4968 trajectory.numberOfSiliconHits() == trajectory.numberOfHits()
4969 ) {
4970 calculateTrackErrors(trajectory, a_inv, true);
4971 GXFTrajectory* traj = runTrackCleanerSilicon(ctx,cache, trajectory, a, a_inv, b, runOutlier);
4972
4973 if (cache.m_fittercode != FitterStatusCode::Success) {
4974 ATH_MSG_DEBUG("Silicon cleaner failed, returning null...");
4975 if (traj != &trajectory) {
4976 delete traj;
4977 }
4978 return nullptr;
4979 }
4980 finaltrajectory = traj;
4981 }
4982
4983 if (m_domeastrackpar && (finaltrajectory->prefit() == 0)) {
4984 calculateTrackErrors(*finaltrajectory, a_inv, false);
4985 }
4986
4987 if (!cache.m_acceleration && (finaltrajectory->prefit() == 0)) {
4988 if (nperpars == 5) {
4989 for (int i = 0; i < a.cols(); i++) {
4990 a_inv(4, i) *= .001;
4991 a_inv(i, 4) *= .001;
4992 }
4993 }
4994
4995 int scatterPos = nperpars + 2 * nscat;
4996 for (int bremno = 0; bremno < nbrem; bremno++, scatterPos++) {
4997 for (int i = 0; i < a.cols(); i++) {
4998 a_inv(scatterPos, i) *= .001;
4999 a_inv(i, scatterPos) *= .001;
5000 }
5001 }
5002
5003 AmgSymMatrix(5) errmat;
5004 errmat.setZero();
5005 const int nperparams = finaltrajectory->numberOfPerigeeParameters();
5006 for (int i = 0; i < nperparams; i++) {
5007 for (int j = 0; j < nperparams; j++) {
5008 (errmat) (j, i) = a_inv(j, i);
5009 }
5010 }
5011
5012 if (trajectory.m_straightline) {
5013 (errmat) (4, 4) = 1e-20;
5014 }
5015
5016 const AmgVector(5) & perpars = finaltrajectory->referenceParameters()->parameters();
5017 std::unique_ptr<const TrackParameters> measper(
5018 finaltrajectory->referenceParameters()->associatedSurface().createUniqueTrackParameters(
5019 perpars[0], perpars[1], perpars[2], perpars[3], perpars[4], std::move(errmat)
5020 )
5021 );
5022
5023 finaltrajectory->setReferenceParameters(std::move(measper));
5024 if (m_fillderivmatrix) {
5025 cache.m_fullcovmat = a_inv;
5026 }
5027 }
5028
5029 std::unique_ptr<Track> track = nullptr;
5030
5031 if (finaltrajectory->prefit() > 0) {
5032 if (finaltrajectory != &trajectory) {
5033 // cppcheck-suppress autovarInvalidDeallocation; false positive
5034 delete finaltrajectory;
5035 }
5036 return nullptr;
5037 }
5038
5039 if (finaltrajectory->numberOfOutliers() <= m_maxoutliers || !runOutlier) {
5040 track = makeTrack(ctx,cache, *finaltrajectory, matEffects);
5041 } else {
5042 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
5043 cache.m_fittercode = FitterStatusCode::OutlierLogicFailure;
5044 }
5045
5046 const double cut = (finaltrajectory->numberOfSiliconHits() ==
5047 finaltrajectory->numberOfHits())
5048 ? 999.0
5049 : m_chi2cut.value();
5050
5051 if (
5052 runOutlier &&
5053 (track != nullptr) && (
5054 track->fitQuality()->numberDoF() != 0 &&
5055 track->fitQuality()->chiSquared() / track->fitQuality()->numberDoF() > cut
5056 )
5057 ) {
5058 track.reset(nullptr);
5059 cache.incrementFitStatus(S_HIGH_CHI2);
5060 }
5061
5062 if (track == nullptr) {
5063 ATH_MSG_DEBUG("Track rejected");
5064 }
5065
5066 if (finaltrajectory != &trajectory) {
5067 delete finaltrajectory;
5068 }
5069
5070 return track.release();
5071 }
@ ExtrapolationFailureDueToSmallMomentum
extrapolation failed due to small momentum
@ OutlierLogicFailure
outlier logic failed
Gaudi::Property< int > m_maxoutliers
std::unique_ptr< Track > makeTrack(const EventContext &ctx, Cache &, GXFTrajectory &, const ParticleHypothesis) const
Gaudi::Property< bool > m_trtrecal
FitterStatusCode updateFitParameters(GXFTrajectory &, const Amg::VectorX &, const Amg::SymMatrixX &) const
Method to update peregee parameters, scattering angles, and brems.
Gaudi::Property< bool > m_domeastrackpar
Gaudi::Property< int > m_maxit
void addIDMaterialFast(const EventContext &ctx, Cache &cache, GXFTrajectory &track, const TrackParameters *parameters, ParticleHypothesis part) const
A faster strategy for adding scatter material to tracks, works only for inner detector tracks.
void updatePixelROTs(GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, const EventContext &evtctx) const
Update the Pixel ROT using the current trajectory/local track parameters.
GXFTrajectory * runTrackCleanerSilicon(const EventContext &ctx, Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::SymMatrixX &, Amg::VectorX &, bool) const
std::unique_ptr< const TrackParameters > makePerigee(Cache &, const TrackParameters &, const ParticleHypothesis) const
Gaudi::Property< double > m_chi2cut
void runTrackCleanerTRT(Cache &, GXFTrajectory &, Amg::SymMatrixX &, Amg::VectorX &, Amg::SymMatrixX &, bool, bool, int, const EventContext &ctx) const
void calculateTrackErrors(GXFTrajectory &, Amg::SymMatrixX &, bool) const
Gaudi::Property< int > m_maxitPixelROT
FitterStatusCode runIteration(const EventContext &ctx, Cache &cache, GXFTrajectory &trajectory, const int it, Amg::SymMatrixX &a, Amg::VectorX &b, Amg::SymMatrixX &lu, bool &doDeriv) const
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > SymMatrixX
cut
This script demonstrates how to call a C++ class from Python Also how to use PyROOT is shown.

◆ myfit_helper()

Track * Trk::GlobalChi2Fitter::myfit_helper ( Cache & ,
GXFTrajectory & ,
const TrackParameters & ,
const RunOutlierRemoval runOutlier = false,
const ParticleHypothesis matEffects = nonInteracting ) const
private

◆ numericalDerivatives()

std::optional< TransportJacobian > Trk::GlobalChi2Fitter::numericalDerivatives ( const EventContext & ctx,
const TrackParameters * prevpar,
const Surface & surf,
PropDirection propdir,
const MagneticFieldProperties & fieldprop ) const
private

Definition at line 8305 of file GlobalChi2Fitter.cxx.

8311 {
8312 double J[25] = {
8313 1, 0, 0, 0, 0,
8314 0, 1, 0, 0, 0,
8315 0, 0, 1, 0, 0,
8316 0, 0, 0, 1, 0,
8317 0, 0, 0, 0, 1
8318 };
8319 std::optional<TransportJacobian> jac = std::make_optional<TransportJacobian>(J);
8320 const TrackParameters *tmpprevpar = prevpar;
8321 double eps[5] = {
8322 0.01, 0.01, 0.00001, 0.00001, 0.000000001
8323 };
8324
8325 const AmgVector(5) & vec = tmpprevpar->parameters();
8326
8327 const bool cylsurf = surf.type() == Trk::SurfaceType::Cylinder;
8328 const bool discsurf = surf.type() == Trk::SurfaceType::Disc;
8329 const Surface & previousSurface = tmpprevpar->associatedSurface();
8330 const bool thiscylsurf = previousSurface.type() == Trk::SurfaceType::Cylinder;
8331 const bool thisdiscsurf = previousSurface.type() == Trk::SurfaceType::Disc;
8332
8333 for (int i = 0; i < 5; i++) {
8334 AmgVector(5) vecpluseps = vec, vecminuseps = vec;
8335
8336 if (thisdiscsurf && i == 1) {
8337 eps[i] /= vec[0];
8338 }
8339
8340 vecpluseps[Trk::ParamDefsAccessor::pardef[i]] += eps[i];
8341 vecminuseps[Trk::ParamDefsAccessor::pardef[i]] -= eps[i];
8342 if (i == 0 && thiscylsurf) {
8343 vecminuseps[i] = -std::remainder(-vecminuseps[i], 2 * M_PI * previousSurface.bounds().r());
8344 } else if (i == 1 && thisdiscsurf) {
8345 vecpluseps[i] = -std::remainder(-vecpluseps[i], 2 * M_PI);
8346 }
8347 correctAngles(vecminuseps[Trk::phi], vecminuseps[Trk::theta]);
8348 correctAngles(vecpluseps[Trk::phi], vecpluseps[Trk::theta]);
8349
8350 std::unique_ptr<const TrackParameters> parpluseps(
8351 tmpprevpar->associatedSurface().createUniqueTrackParameters(
8352 vecpluseps[0],
8353 vecpluseps[1],
8354 vecpluseps[2],
8355 vecpluseps[3],
8356 vecpluseps[4],
8357 std::nullopt
8358 )
8359 );
8360 const std::unique_ptr<const TrackParameters> parminuseps(
8361 tmpprevpar->associatedSurface().createUniqueTrackParameters(
8362 vecminuseps[0],
8363 vecminuseps[1],
8364 vecminuseps[2],
8365 vecminuseps[3],
8366 vecminuseps[4],
8367 std::nullopt
8368 )
8369 );
8370
8371 std::unique_ptr<const TrackParameters> newparpluseps(
8372 m_propagator->propagateParameters(
8373 ctx,
8374 *parpluseps,
8375 surf,
8376 propdir,
8377 false,
8378 fieldprop,
8380 )
8381 );
8382 std::unique_ptr<const TrackParameters> newparminuseps(
8383 m_propagator->propagateParameters(
8384 ctx,
8385 *parminuseps,
8386 surf,
8387 propdir,
8388 false,
8389 fieldprop,
8391 )
8392 );
8393
8394 const PropDirection propdir2 =
8395 (propdir ==
8397 if (newparpluseps == nullptr) {
8398 newparpluseps =
8399 m_propagator->propagateParameters(
8400 ctx,
8401 *parpluseps,
8402 surf,
8403 propdir2,
8404 false,
8405 fieldprop,
8407 );
8408 }
8409 if (newparminuseps == nullptr) {
8410 newparminuseps =
8411 m_propagator->propagateParameters(
8412 ctx,
8413 *parminuseps,
8414 surf,
8415 propdir2,
8416 false,
8417 fieldprop,
8419 );
8420 }
8421 if ((newparpluseps == nullptr) || (newparminuseps == nullptr)) {
8422 return nullptr;
8423 }
8424
8425 for (int j = 0; j < 5; j++) {
8426 double diff = newparpluseps->parameters()[Trk::ParamDefsAccessor::pardef[j]] -
8427 newparminuseps->parameters()[Trk::ParamDefsAccessor::pardef[j]];
8428
8429 if (j == 0 && cylsurf) {
8430 diff = -std::remainder(-diff, 2 * M_PI * surf.bounds().r());
8431 } else if (j == 1 && discsurf) {
8432 diff = -std::remainder(-diff, 2 * M_PI);
8433 }
8434
8435 (*jac) (j, i) = diff / (2 * eps[i]);
8436 }
8437
8438 }
8439 return jac;
8440 }
std::vector< size_t > vec
void diff(const Jet &rJet1, const Jet &rJet2, std::map< std::string, double > varDiff)
Difference between jets - Non-Class function required by trigger.
Definition Jet.cxx:631

◆ processTrkVolume()

bool Trk::GlobalChi2Fitter::processTrkVolume ( Cache & cache,
const Trk::TrackingVolume * tvol ) const
private

Definition at line 2833 of file GlobalChi2Fitter.cxx.

2836 {
2837 if (tvol == nullptr) {
2838 return false;
2839 }
2840
2841 const Trk::BinnedArray < Trk::Layer > *confinedLayers = tvol->confinedLayers();
2842
2843 // loop over confined layers
2844 if (confinedLayers != nullptr) {
2845 // loop over layers
2846 for (const auto & layer : confinedLayers->arrayObjects()) {
2847 // push_back the layer
2848 if (layer != nullptr) {
2849 // get the layerIndex
2850 const Trk::LayerIndex & layIndex = layer->layerIndex();
2851 // skip navigaion layers for the moment
2852
2853 if ((layIndex.value() == 0) || (layer->layerMaterialProperties() == nullptr)) {
2854 continue;
2855 }
2856
2857 const CylinderLayer *cyllay = nullptr;
2858 if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Cylinder) {
2859 cyllay = static_cast<const CylinderLayer *>(layer);
2860 }
2861
2862 const DiscLayer *disclay = nullptr;
2863 if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Disc) {
2864 disclay = static_cast<const DiscLayer *>(layer);
2865 }
2866
2867 if (disclay != nullptr) {
2868 if (disclay->center().z() < 0) {
2869 cache.m_negdiscs.push_back(disclay);
2870 } else {
2871 cache.m_posdiscs.push_back(disclay);
2872 }
2873 } else if (cyllay != nullptr) {
2874 cache.m_barrelcylinders.push_back(cyllay);
2875 } else {
2876 return false;
2877 }
2878 }
2879 }
2880 }
2881
2882 const auto & bsurf = tvol->boundarySurfaces();
2883
2884 for (size_t ib = 0 ; ib < bsurf.size(); ++ib) {
2885 const Layer *layer = bsurf[ib]->surfaceRepresentation().materialLayer();
2886
2887 if (layer == nullptr) continue;
2888
2889 const Trk::LayerIndex & layIndex = layer->layerIndex();
2890
2891 if ((layIndex.value() == 0) || (layer->layerMaterialProperties() == nullptr)) {
2892 continue;
2893 }
2894
2895 const CylinderSurface *cylsurf = nullptr;
2896
2897 if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Cylinder)
2898 cylsurf = static_cast<const CylinderSurface *>(&layer->surfaceRepresentation());
2899
2900 const DiscSurface *discsurf = nullptr;
2901
2902 if (layer->surfaceRepresentation().type() == Trk::SurfaceType::Disc)
2903 discsurf = static_cast<const DiscSurface *>(&layer->surfaceRepresentation());
2904
2905 if (discsurf != nullptr) {
2906 if (
2907 discsurf->center().z() < 0 &&
2908 std::find(cache.m_negdiscs.begin(), cache.m_negdiscs.end(), layer) == cache.m_negdiscs.end()
2909 ) {
2910 cache.m_negdiscs.push_back(layer);
2911 } else if (
2912 discsurf->center().z() > 0 &&
2913 std::find(cache.m_posdiscs.begin(), cache.m_posdiscs.end(), layer) == cache.m_posdiscs.end()
2914 ) {
2915 cache.m_posdiscs.push_back(layer);
2916 }
2917 } else if (
2918 (cylsurf != nullptr) &&
2919 std::find(cache.m_barrelcylinders.begin(), cache.m_barrelcylinders.end(), layer) == cache.m_barrelcylinders.end()
2920 ) {
2921 cache.m_barrelcylinders.push_back(layer);
2922 }
2923
2924 if ((cylsurf == nullptr) && (discsurf == nullptr)) {
2925 return false;
2926 }
2927 }
2928
2929 const TrackingVolumeArray* confinedVolumes = tvol->confinedVolumes();
2930 // get the confined volumes and loop over it -> call recursively
2931 if (confinedVolumes != nullptr) {
2932 for (const auto & volume : confinedVolumes->arrayObjects()) {
2933 if (volume != nullptr) {
2934 const bool ok = processTrkVolume(cache, volume);
2935 if (!ok) {
2936 return false;
2937 }
2938 }
2939 }
2940 }
2941
2942 return true;
2943 }
virtual std::span< T *const > arrayObjects()=0
Return all objects of the Array non-const we can still modify the T.
int value() const
layerIndex expressed in an integer
Definition LayerIndex.h:71
const LayerArray * confinedLayers() const
Return the subLayer array.
const TrackingVolumeArray * confinedVolumes() const
Return the subLayer array.
std::vector< std::shared_ptr< BoundarySurface< TrackingVolume > > > & boundarySurfaces()
Method to return the BoundarySurfaces.
BinnedArray< TrackingVolume > TrackingVolumeArray
simply for the eye

◆ retrieveTrackingGeometry()

const TrackingGeometry * Trk::GlobalChi2Fitter::retrieveTrackingGeometry ( const EventContext & ctx) const
inlineprivate

Definition at line 1139 of file GlobalChi2Fitter.h.

1141 {
1142 SG::ReadCondHandle<TrackingGeometry> handle(m_trackingGeometryReadKey,
1143 ctx);
1144 if (!handle.isValid()) {
1146 }
1147 return handle.cptr();
1148 }
void throwFailedToGetTrackingGeomtry() const

◆ runIteration()

FitterStatusCode Trk::GlobalChi2Fitter::runIteration ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & trajectory,
const int it,
Amg::SymMatrixX & a,
Amg::VectorX & b,
Amg::SymMatrixX & lu,
bool & doDeriv ) const
private

Definition at line 5994 of file GlobalChi2Fitter.cxx.

6003 {
6004 const int nDOFold = trajectory.nDOF();
6005 const double oldChi2 = trajectory.chi2();
6006 const double oldRedChi2 = nDOFold > 0 ? oldChi2 / nDOFold : 0;
6007
6008 if (cache.m_phiweight.empty()) {
6009 cache.m_phiweight.assign(trajectory.trackStates().size(), 1);
6010 }
6011
6012 FitterStatusCode fsc = calculateTrackParameters(ctx, trajectory, doDeriv);
6013
6014 if (fsc != FitterStatusCode::Success) {
6015 return fsc;
6016 }
6017
6018 /*
6019 * Reset the b-vector. We want to add to the components later.
6020 */
6021 b.setZero();
6022
6023 /*
6024 * Here we store the information on where to find the maxbrempull, in case
6025 * we find any large ones during the residual calculation. We might need it
6026 * later to update our errors.
6027 */
6028 int bremno_maxbrempull = 0;
6029 GXFTrackState* state_maxbrempull = nullptr;
6030
6031 fillResidualsAndErrors(ctx, cache, trajectory, it, b, bremno_maxbrempull, state_maxbrempull);
6032
6033 /*
6034 * Check if we hit any convergence conditions.
6035 */
6036 tryToConverge(cache, trajectory, it);
6037
6038 /*
6039 * In case we converged but have a state with maxbrempull (a kink) we want
6040 * to do more iterations. Therefore, reset the convergence flag and inflate
6041 * the chi2. Then update the error estimates using the state with the
6042 * maxbrempull.
6043 */
6044 if ((state_maxbrempull != nullptr) && trajectory.converged()) {
6045 trajectory.setConverged(false);
6046 trajectory.setChi2(1e15);
6047 doDeriv = true;
6048
6049 updateSystemWithMaxBremPull(trajectory, bremno_maxbrempull, state_maxbrempull, a);
6050 lu = a;
6051 }
6052
6053 const int nDOFnew = trajectory.nDOF();
6054 const double newChi2 = trajectory.chi2();
6055 const double newRedChi2 = nDOFnew > 0 ? newChi2 / nDOFnew : 0;
6056
6057 ATH_MSG_DEBUG("old chi2: " << oldChi2 << "/" << nDOFold << "=" << oldRedChi2 <<
6058 ", new chi2: " << newChi2 << "/" << nDOFnew << "=" << newRedChi2);
6059
6060 if (trajectory.prefit() > 0 && trajectory.converged()) {
6062 }
6063
6064 if (doDeriv) {
6065 calculateDerivatives(trajectory);
6066 fillDerivatives(trajectory);
6067 }
6068
6069 if (cache.m_firstmeasurement.empty()) {
6070 fillFirstLastMeasurement(cache, trajectory);
6071 }
6072
6073 if (a.cols() != trajectory.numberOfFitParameters()) {
6074 ATH_MSG_ERROR("Your assumption is wrong!!!!");
6075 }
6076
6077 fillBfromMeasurements(cache, trajectory, b);
6078
6079 /*
6080 * The [a]-matrix does not depend on the residuals. We only need to change
6081 * it, if the derivatives have changed.
6082 */
6083 if (doDeriv) {
6084 fillAfromMeasurements(cache, trajectory, a);
6085 fillAfromScatterers(trajectory, a);
6086 }
6087
6088 const bool weightChanged = tryToWeightAfromMaterial(cache, trajectory, a, doDeriv, it, oldRedChi2, newRedChi2);
6089
6090 /*
6091 * Update the [lu]-matrix if we modified the [a]-matrix.
6092 */
6093 if (doDeriv || weightChanged) {
6094 lu = a;
6095 }
6096
6097 /*
6098 * Special handling for prefit == 0:
6099 * - If we already converged, but there are hits apart from Si and TRT or
6100 * the numbers don't match, the applied phi weights need to be reset.
6101 * - If we got in an early iteration to a low reduced chi2 or converged
6102 * with the reduced chi2, we don't need to redo derivatives.
6103 */
6104 if (trajectory.prefit() == 0) {
6105 if (trajectory.converged()) {
6106 const int nSiHits = trajectory.numberOfSiliconHits();
6107 const int nTrtHits = trajectory.numberOfTRTHits();
6108 const int nHits = trajectory.numberOfHits();
6109
6110 if (nSiHits + nTrtHits != nHits) {
6111 compensatePhiWeights(cache, trajectory, a);
6112 lu = a;
6113 }
6114 } else if (
6115 !m_redoderivs &&
6116 it < 5 &&
6117 (newRedChi2 < 2 || (newRedChi2 < oldRedChi2 && newRedChi2 > oldRedChi2 - .5))
6118 ) {
6119 doDeriv = false;
6120 }
6121 }
6122
6124 }
static const uint32_t nHits
void tryToConverge(const Cache &cache, GXFTrajectory &trajectory, const int it) const
FitterStatusCode calculateTrackParameters(const EventContext &ctx, GXFTrajectory &, bool) const
void fillResidualsAndErrors(const EventContext &ctx, const Cache &cache, GXFTrajectory &trajectory, const int it, Amg::VectorX &b, int &bremno_maxbrempull, GXFTrackState *&state_maxbrempull) const
void updateSystemWithMaxBremPull(GXFTrajectory &trajectory, const int bremno_maxbrempull, GXFTrackState *state_maxbrempull, Amg::SymMatrixX &a) const
static void fillFirstLastMeasurement(Cache &cache, GXFTrajectory &trajectory)
static void fillBfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::VectorX &b)
static void compensatePhiWeights(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
static void fillAfromScatterers(GXFTrajectory &trajectory, Amg::SymMatrixX &a)
static void calculateDerivatives(GXFTrajectory &)
Gaudi::Property< bool > m_redoderivs
void fillDerivatives(GXFTrajectory &traj) const
static bool tryToWeightAfromMaterial(Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a, const bool doDeriv, const int it, const double oldRedChi2, const double newRedChi2)
static void fillAfromMeasurements(const Cache &cache, GXFTrajectory &trajectory, Amg::SymMatrixX &a)
float nSiHits(const U &p)

◆ runTrackCleanerSilicon()

GXFTrajectory * Trk::GlobalChi2Fitter::runTrackCleanerSilicon ( const EventContext & ctx,
Cache & cache,
GXFTrajectory & trajectory,
Amg::SymMatrixX & a,
Amg::SymMatrixX & fullcov,
Amg::VectorX & b,
bool runoutlier ) const
private
Warning
This method has some unclear memory ownership mechanics that might not correspond fully with the model described at the beginning of the file. Be aware!

Definition at line 6511 of file GlobalChi2Fitter.cxx.

6519 {
6520 bool trackok = false;
6521 GXFTrajectory *oldtrajectory = &trajectory;
6522 std::unique_ptr < GXFTrajectory > cleanup_oldtrajectory;
6523 GXFTrajectory *newtrajectory = nullptr;
6524 std::unique_ptr < GXFTrajectory > cleanup_newtrajectory;
6525
6526 // the oldtrajectory will be returned, so in case newtrajectory==oldtrajectory
6527 // the cleanup_newtrajectory == NULL and cleanup_oldtrajectory = oldtrajectory, otherwise
6528 // cleanup_newtrajectory will destroy the object oldtrajectory is pointing to.
6529
6530 while (!trackok && oldtrajectory->nDOF() > 0) {
6531 trackok = true;
6532 std::vector<std::unique_ptr<GXFTrackState>> & states = oldtrajectory->trackStates();
6533 Amg::VectorX & res = oldtrajectory->residuals();
6534 Amg::VectorX & err = oldtrajectory->errors();
6535 Amg::MatrixX & weightderiv = oldtrajectory->weightedResidualDerivatives();
6536 const int nfitpars = oldtrajectory->numberOfFitParameters();
6537 const int nhits = oldtrajectory->numberOfHits();
6538 const int nsihits = oldtrajectory->numberOfSiliconHits();
6539
6540 if (nhits != nsihits) {
6541 return &trajectory;
6542 }
6543
6544 double maxsipull = -1;
6545 int hitno = 0;
6546 int hitno_maxsipull = -1;
6547 int measno_maxsipull = -1;
6548 int stateno_maxsipull = 0;
6549 GXFTrackState *state_maxsipull = nullptr;
6550 int measno = 0;
6551 int n3sigma = 0;
6552 const double cut = m_outlcut;
6553 double cut2 = m_outlcut - 1.;
6554 const int noutl = oldtrajectory->numberOfOutliers();
6555
6556 if (noutl > 0) {
6557 cut2 = cut - 1.25;
6558 }
6559
6560 for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6561 std::unique_ptr<GXFTrackState> & state = states[stateno];
6562
6563 if (state->getStateType(TrackStateOnSurface::Measurement)) {
6564 TrackState::MeasurementType const hittype = state->measurementType();
6565
6566 if ((hittype == TrackState::Pixel || hittype == TrackState::SCT) && state->hasTrackCovariance()) {
6567 double *errors = state->measurementErrors();
6568 AmgSymMatrix(5) & trackcov = state->trackCovariance();
6569 const Amg::MatrixX & hitcov = state->measurement()->localCovariance();
6570 const double sinstereo = state->sinStereo();
6571 const double cosstereo = (sinstereo == 0) ? 1 : std::sqrt(1 - sinstereo * sinstereo);
6572 double weight1 = -1;
6573
6574 if (hitcov(0, 0) > trackcov(0, 0)) {
6575 if (sinstereo == 0) {
6576 weight1 = errors[0] * errors[0] - trackcov(0, 0);
6577 } else {
6578 weight1 = errors[0] * errors[0] - (
6579 trackcov(0, 0) * cosstereo * cosstereo + 2 *
6580 trackcov(1, 0) * cosstereo * sinstereo + trackcov(1, 1) * sinstereo * sinstereo
6581 );
6582 }
6583 }
6584
6585 const double weight2 = (
6586 hittype == TrackState::Pixel && hitcov(1, 1) > trackcov(1, 1) ?
6587 errors[1] * errors[1] - trackcov(1, 1) :
6588 -1
6589 );
6590
6591 double sipull1 = weight1 > 0 ? std::abs(res[measno] / std::sqrt(weight1)) : -1;
6592 const double sipull2 = (
6593 hittype == TrackState::Pixel && weight2 > 0 ?
6594 std::abs(res[measno + 1] / std::sqrt(weight2)) :
6595 -1
6596 );
6597 sipull1 = std::max(sipull1, sipull2);
6598
6599 if (sipull1 > maxsipull) {
6600 maxsipull = sipull1;
6601 measno_maxsipull = measno;
6602 state_maxsipull = state.get();
6603 stateno_maxsipull = stateno;
6604 hitno_maxsipull = hitno;
6605 }
6606
6607 if (hittype == TrackState::Pixel && sipull1 > cut2) {
6608 n3sigma++;
6609 }
6610 }
6611 }
6612
6613 if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6614 hitno++;
6615 measno += state->numberOfMeasuredParameters();
6616 }
6617 }
6618
6619 const double maxpull = maxsipull;
6620
6621 ATH_MSG_DEBUG(" maxsipull: " << maxsipull << " hitno_maxsipull: " <<
6622 hitno_maxsipull << " n3sigma: " << n3sigma << " cut: " << cut << " cut2: " << cut2);
6623
6624 Amg::SymMatrixX * newap = &a;
6625 Amg::VectorX * newbp = &b;
6626 Amg::SymMatrixX newa(nfitpars, nfitpars);
6627 Amg::VectorX newb(nfitpars);
6628
6629 if (
6630 maxpull > 2 &&
6631 oldtrajectory->chi2() / oldtrajectory->nDOF() > .25 * m_chi2cut
6632 ) {
6633 state_maxsipull = oldtrajectory->trackStates()[stateno_maxsipull].get();
6634 const PrepRawData *prd{};
6635 if (const auto *const pMeas = state_maxsipull->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6636 const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6637 prd = rot->prepRawData();
6638 }
6639 std::unique_ptr < const RIO_OnTrack > broadrot;
6640 double *olderror = state_maxsipull->measurementErrors();
6641 TrackState::MeasurementType const hittype_maxsipull = state_maxsipull->measurementType();
6642 const TrackParameters *trackpar_maxsipull = state_maxsipull->trackParameters();
6643
6644 Amg::VectorX parameterVector = trackpar_maxsipull->parameters();
6645 const std::unique_ptr<const TrackParameters> trackparForCorrect(
6646 trackpar_maxsipull->associatedSurface().createUniqueTrackParameters(
6647 parameterVector[Trk::loc1],
6648 parameterVector[Trk::loc2],
6649 parameterVector[Trk::phi],
6650 parameterVector[Trk::theta],
6651 parameterVector[Trk::qOverP],
6652 state_maxsipull->hasTrackCovariance()
6653 ? std::optional<AmgSymMatrix(5)>(
6654 state_maxsipull->trackCovariance())
6655 : std::nullopt));
6656
6657 double newerror[5];
6658 newerror[0] = newerror[1] = newerror[2] = newerror[3] = newerror[4] = -1;
6659 double newpull = -1;
6660 double newpull1 = -1;
6661 double newpull2 = -1;
6662 double newres1 = -1;
6663 double newres2 = -1;
6664 double newsinstereo = 0;
6665
6666 if (
6667 (prd != nullptr) &&
6668 !state_maxsipull->isRecalibrated() &&
6669 maxpull > 2.5 &&
6670 oldtrajectory->chi2() / trajectory.nDOF() > .3 * m_chi2cut &&
6671 cache.m_sirecal
6672 ) {
6673 broadrot.reset(m_broadROTcreator->correct(*prd, *trackparForCorrect, ctx));
6674 }
6675
6676 if (broadrot) {
6677 const Amg::MatrixX & covmat = broadrot->localCovariance();
6678
6679 if (state_maxsipull->sinStereo() != 0) {
6680 const auto [covEigenValueSmall, covStereoAngle] = principalComponentAnalysis2x2(covmat);
6681 newerror[0] = std::sqrt(covEigenValueSmall);
6682 newsinstereo = std::sin(covStereoAngle);
6683 } else {
6684 newerror[0] = std::sqrt(covmat(0, 0));
6685 }
6686
6687 const double cosstereo = (newsinstereo == 0) ? 1. : std::sqrt(1 - newsinstereo * newsinstereo);
6688
6689 if (cosstereo != 1.) {
6690 newres1 = (
6691 cosstereo * (broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX]) +
6692 newsinstereo * (broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY])
6693 );
6694 } else {
6695 newres1 = broadrot->localParameters()[Trk::locX] - trackpar_maxsipull->parameters()[Trk::locX];
6696 }
6697
6698 if (newerror[0] == 0.0) {
6699 ATH_MSG_WARNING("Measurement error is zero or negative, treating as outlier");
6700 newpull1 = 9999.;
6701 } else {
6702 newpull1 = std::abs(newres1 / newerror[0]);
6703 }
6704
6705 if (hittype_maxsipull == TrackState::Pixel) {
6706 newerror[1] = std::sqrt(covmat(1, 1));
6707 newres2 = broadrot->localParameters()[Trk::locY] - trackpar_maxsipull->parameters()[Trk::locY];
6708 newpull2 = std::abs(newres2 / newerror[1]);
6709 }
6710
6711 newpull = std::max(newpull1, newpull2);
6712 }
6713
6714 if (
6715 broadrot &&
6716 newpull < m_outlcut &&
6717 (newerror[0] > 1.5 * olderror[0] || newerror[1] > 1.5 * std::abs(olderror[1]))
6718 ) {
6719 if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6720 throw std::runtime_error(
6721 "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6722 );
6723 }
6724
6725 trackok = false;
6726 newtrajectory = oldtrajectory;
6727
6728 if (a.cols() != nfitpars) {
6729 ATH_MSG_ERROR("Your assumption is wrong!!!!");
6730 }
6731
6732 const double oldres1 = res[measno_maxsipull];
6733 res[measno_maxsipull] = newres1;
6734 err[measno_maxsipull] = newerror[0];
6735
6736 for (int i = 0; i < nfitpars; i++) {
6737 if (weightderiv(measno_maxsipull, i) == 0) {
6738 continue;
6739 }
6740
6741 b[i] -= weightderiv(measno_maxsipull, i) * (oldres1 / olderror[0] - (newres1 * olderror[0]) / (newerror[0] * newerror[0]));
6742
6743 for (int j = i; j < nfitpars; j++) {
6744 a.fillSymmetric(
6745 i, j,
6746 a(i, j) + (
6747 weightderiv(measno_maxsipull, i) *
6748 weightderiv(measno_maxsipull, j) *
6749 ((olderror[0] * olderror[0]) / (newerror[0] * newerror[0]) - 1)
6750 )
6751 );
6752 }
6753 weightderiv(measno_maxsipull, i) *= olderror[0] / newerror[0];
6754 }
6755
6756 if (hittype_maxsipull == TrackState::Pixel) {
6757 const double oldres2 = res[measno_maxsipull + 1];
6758 res[measno_maxsipull + 1] = newres2;
6759 err[measno_maxsipull + 1] = newerror[1];
6760
6761 for (int i = 0; i < nfitpars; i++) {
6762 if (weightderiv(measno_maxsipull + 1, i) == 0) {
6763 continue;
6764 }
6765
6766 b[i] -= weightderiv(measno_maxsipull + 1, i) * (oldres2 / olderror[1] - (newres2 * olderror[1]) / (newerror[1] * newerror[1]));
6767
6768 for (int j = i; j < nfitpars; j++) {
6769 a.fillSymmetric(
6770 i, j,
6771 a(i, j) + (
6772 weightderiv(measno_maxsipull + 1, i) *
6773 weightderiv(measno_maxsipull + 1, j) *
6774 ((olderror[1] * olderror[1]) / (newerror[1] * newerror[1]) - 1)
6775 )
6776 );
6777 }
6778
6779 weightderiv(measno_maxsipull + 1, i) *= olderror[1] / newerror[1];
6780 }
6781 }
6782
6784 "Recovering outlier, hitno=" << hitno_maxsipull << " measno=" <<
6785 measno_maxsipull << " pull=" << maxsipull << " olderror_0=" <<
6786 olderror[0] << " newerror_0=" << newerror[0] << " olderror_1=" <<
6787 olderror[1] << " newerror_1=" << newerror[1]
6788 );
6789
6790 state_maxsipull->setMeasurement(std::move(broadrot));
6791 state_maxsipull->setSinStereo(newsinstereo);
6792 state_maxsipull->setMeasurementErrors(newerror);
6793 } else if (
6794 (
6795 (
6796 ((n3sigma < 2 && maxsipull > cut2 && maxsipull < cut) || n3sigma > 1) &&
6797 (oldtrajectory->chi2() / oldtrajectory->nDOF() > .3 * m_chi2cut || noutl > 1)
6798 ) ||
6799 maxsipull > cut
6800 ) &&
6801 (oldtrajectory->nDOF() > 1 || hittype_maxsipull == TrackState::SCT) &&
6802 runoutlier
6803 ) {
6804 trackok = false;
6806 "Removing outlier, hitno=" << hitno_maxsipull << ", measno=" <<
6807 measno_maxsipull << " pull=" << maxsipull
6808 );
6809
6810 newa = a;
6811 newb = b;
6812 newap = &newa;
6813 newbp = &newb;
6814 cleanup_newtrajectory = std::make_unique<GXFTrajectory>(*oldtrajectory);
6815 newtrajectory = cleanup_newtrajectory.get();
6816
6817 if (newa.cols() != nfitpars) {
6818 ATH_MSG_ERROR("Your assumption is wrong!!!!");
6819 }
6820
6821 Amg::VectorX & newres = newtrajectory->residuals();
6822 Amg::MatrixX & newweightderiv = newtrajectory->weightedResidualDerivatives();
6823 if ((measno_maxsipull < 0) or(measno_maxsipull >= (int) res.size())) {
6824 throw std::runtime_error(
6825 "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6826 );
6827 }
6828
6829 const double oldres1 = res[measno_maxsipull];
6830 newres[measno_maxsipull] = 0;
6831
6832 for (int i = 0; i < nfitpars; i++) {
6833 if (weightderiv(measno_maxsipull, i) == 0) {
6834 continue;
6835 }
6836
6837 newb[i] -= weightderiv(measno_maxsipull, i) * oldres1 / olderror[0];
6838
6839 for (int j = i; j < nfitpars; j++) {
6840 newa.fillSymmetric(
6841 i, j,
6842 newa(i, j) - (
6843 weightderiv(measno_maxsipull, i) *
6844 weightderiv(measno_maxsipull, j)
6845 )
6846 );
6847 }
6848 newweightderiv(measno_maxsipull, i) = 0;
6849 }
6850
6851 if (hittype_maxsipull == TrackState::Pixel) {
6852 const double oldres2 = res[measno_maxsipull + 1];
6853 newres[measno_maxsipull + 1] = 0;
6854
6855 for (int i = 0; i < nfitpars; i++) {
6856 if (weightderiv(measno_maxsipull + 1, i) == 0) {
6857 continue;
6858 }
6859
6860 newb[i] -= weightderiv(measno_maxsipull + 1, i) * oldres2 / olderror[1];
6861
6862 for (int j = i; j < nfitpars; j++) {
6863 if (weightderiv(measno_maxsipull + 1, j) == 0) {
6864 continue;
6865 }
6866
6867 newa.fillSymmetric(
6868 i, j,
6869 newa(i, j) - (
6870 weightderiv(measno_maxsipull + 1, i) *
6871 weightderiv(measno_maxsipull + 1, j)
6872 )
6873 );
6874 }
6875 newweightderiv(measno_maxsipull + 1, i) = 0;
6876 }
6877 }
6878
6879 newtrajectory->setOutlier(stateno_maxsipull);
6880 }
6881 }
6882
6883 if (!trackok) {
6884 Amg::SymMatrixX lu_m = *newap;
6885 newtrajectory->setConverged(false);
6886 bool doderiv = m_redoderivs;
6887 cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6888 if (cache.m_fittercode != FitterStatusCode::Success) {
6889 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6890 return nullptr;
6891 }
6892
6893 for (int it = 0; it < m_maxit; ++it) {
6894 if (it == m_maxit - 1) {
6895 ATH_MSG_DEBUG("Fit did not converge");
6896 cache.m_fittercode = FitterStatusCode::NoConvergence;
6897 cache.incrementFitStatus(S_NOT_CONVERGENT);
6898 return nullptr;
6899 }
6900
6901 if (!newtrajectory->converged()) {
6902 cache.m_fittercode = runIteration(
6903 ctx, cache, *newtrajectory, it, *newap, *newbp, lu_m, doderiv);
6904
6905 if (cache.m_fittercode != FitterStatusCode::Success) {
6906 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6907 return nullptr;
6908 }
6909
6910 if (!newtrajectory->converged()) {
6911 cache.m_fittercode = updateFitParameters(*newtrajectory, *newbp, lu_m);
6912 if (cache.m_fittercode != FitterStatusCode::Success) {
6913 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6914
6915 return nullptr;
6916 }
6917 }
6918 } else {
6919 const double oldchi2 = oldtrajectory->chi2() / oldtrajectory->nDOF();
6920 const double newchi2 = (newtrajectory->nDOF() > 0) ? newtrajectory->chi2() / newtrajectory->nDOF() : 0;
6921 double mindiff = 0;
6922
6923 if (newtrajectory->nDOF() != oldtrajectory->nDOF() && maxsipull > cut2) {
6924 mindiff = (oldchi2 > .33 * m_chi2cut || noutl > 0) ? .8 : 1.;
6925
6926 if (noutl == 0 && maxsipull < cut - .5 && oldchi2 < .5 * m_chi2cut) {
6927 mindiff = 2.;
6928 }
6929 }
6930
6931 if (newchi2 > oldchi2 || (newchi2 > oldchi2 - mindiff && newchi2 > .33 * oldchi2)) {
6932 ATH_MSG_DEBUG("Outlier not confirmed, keeping old trajectory");
6933
6934 if (oldchi2 > m_chi2cut) {
6935 cache.m_fittercode = FitterStatusCode::OutlierLogicFailure;
6936 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6937 return nullptr;
6938 }
6939
6940 (void)cleanup_oldtrajectory.release();
6941 return oldtrajectory;
6942 }
6943 if (oldtrajectory != newtrajectory) {
6944 cleanup_oldtrajectory = std::move(cleanup_newtrajectory);
6945 oldtrajectory = newtrajectory;
6946 a = newa;
6947 b = newb;
6948 }
6949
6950 // Solve assuming the matrix is SPD.
6951 // Cholesky Decomposition is used
6952 Eigen::LLT < Eigen::MatrixXd > const lltOfW(a);
6953 if (lltOfW.info() == Eigen::Success) {
6954 // Solve for x where Wx = I
6955 // this is cheaper than invert as invert makes no assumptions about the
6956 // matrix being symmetric
6957 const int ncols = a.cols();
6958 Amg::MatrixX const weightInvAMG = Amg::MatrixX::Identity(ncols, ncols);
6959 fullcov = lltOfW.solve(weightInvAMG);
6960 } else {
6961 ATH_MSG_DEBUG("matrix inversion failed!");
6962 cache.incrementFitStatus(S_MAT_INV_FAIL);
6963 cache.m_fittercode = FitterStatusCode::MatrixInversionFailure;
6964 return nullptr;
6965 }
6966 break;
6967 }
6968 }
6969 }
6970
6971 if (!trackok) {
6972 calculateTrackErrors(*oldtrajectory, fullcov, true);
6973 }
6974 }
6975
6976 if (
6977 oldtrajectory->nDOF() > 0 &&
6978 oldtrajectory->chi2() / oldtrajectory->nDOF() > m_chi2cut &&
6979 runoutlier
6980 ) {
6981 cache.m_fittercode = FitterStatusCode::OutlierLogicFailure;
6982 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6983 return nullptr;
6984 }
6985
6986 (void)cleanup_oldtrajectory.release();
6987 return oldtrajectory;
6988 }
Gaudi::Property< double > m_outlcut

◆ runTrackCleanerTRT()

void Trk::GlobalChi2Fitter::runTrackCleanerTRT ( Cache & cache,
GXFTrajectory & trajectory,
Amg::SymMatrixX & a,
Amg::VectorX & b,
Amg::SymMatrixX & lu_m,
bool runOutlier,
bool trtrecal,
int it,
const EventContext & ctx ) const
private

Definition at line 6341 of file GlobalChi2Fitter.cxx.

6351 {
6352 double scalefactor = m_scalefactor;
6353
6354 if (it == 1 && trajectory.numberOfSiliconHits() + trajectory.numberOfTRTHits() == trajectory.numberOfHits()) {
6355 scalefactor *= 2;
6356 }
6357
6358 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6359 Amg::VectorX & res = trajectory.residuals();
6360 Amg::VectorX & err = trajectory.errors();
6361 Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6362 const int nfitpars = trajectory.numberOfFitParameters();
6363
6364 if (a.cols() != nfitpars) {
6365 ATH_MSG_ERROR("Your assumption is wrong!!!!");
6366 }
6367
6368 const int nperpars = trajectory.numberOfPerigeeParameters();
6369 const int nscats = trajectory.numberOfScatterers();
6370 int hitno = 0;
6371 int measno = 0;
6372 bool outlierremoved = false;
6373 bool hitrecalibrated = false;
6374
6375 for (int stateno = 0; stateno < (int) states.size(); stateno++) {
6376 std::unique_ptr<GXFTrackState> & state = states[stateno];
6377
6378 if (state->getStateType(TrackStateOnSurface::Measurement)) { // Hit is not (yet) an outlier
6379 TrackState::MeasurementType const hittype = state->measurementType();
6380
6381 if (hittype == TrackState::TRT) {
6382 if (
6383 runOutlier &&
6384 std::abs(state->trackParameters()->parameters()[Trk::driftRadius]) > 1.05 * state->associatedSurface().bounds().r()
6385 ) {
6386 ATH_MSG_DEBUG("Removing TRT hit #" << hitno);
6387
6388 trajectory.setOutlier(stateno);
6389 outlierremoved = true;
6390
6391 double *errors = state->measurementErrors();
6392 const double olderror = errors[0];
6393
6394 trajectory.updateTRTHitCount(stateno, olderror);
6395
6396 for (int i = 0; i < nfitpars; i++) {
6397 if (weightderiv(measno, i) == 0) {
6398 continue;
6399 }
6400
6401 b[i] -= res[measno] * weightderiv(measno, i) / olderror;
6402
6403 for (int j = i; j < nfitpars; j++) {
6404 a.fillSymmetric(
6405 i, j,
6406 a(i, j) - weightderiv(measno, i) * weightderiv(measno, j)
6407 );
6408 }
6409 weightderiv(measno, i) = 0;
6410 }
6411
6412 res[measno] = 0;
6413 } else if (trtrecal) {
6414 double *errors = state->measurementErrors();
6415 const double olderror = errors[0];
6416 const Trk::RIO_OnTrack * oldrot{};
6417 const auto *const thisMeasurement{state->measurement()};
6418 if ( not thisMeasurement->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6419 continue;
6420 }
6421 oldrot = static_cast<const Trk::RIO_OnTrack *>(thisMeasurement);
6422 const double oldradius = oldrot->localParameters()[Trk::driftRadius];
6423 if (oldrot->prepRawData() != nullptr) {
6424 const double dcradius = oldrot->prepRawData()->localPosition()[Trk::driftRadius];
6425 const double dcerror = std::sqrt(oldrot->prepRawData()->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6426 const double trackradius = state->trackParameters()->parameters()[Trk::driftRadius];
6427
6428 std::unique_ptr<const Trk::RIO_OnTrack> newrot = nullptr;
6429 const double distance = std::abs(std::abs(trackradius) - dcradius);
6430
6431 if (distance < scalefactor * dcerror && (olderror > 1. || trackradius * oldradius < 0)) {
6432 newrot.reset(m_ROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6433 } else if (distance > scalefactor * dcerror && olderror < 1.) {
6434 newrot.reset(m_broadROTcreator->correct(*oldrot->prepRawData(), *state->trackParameters(), ctx));
6435 }
6436
6437 if (newrot != nullptr) {
6438 ATH_MSG_DEBUG("Recalibrating TRT hit #" << hitno);
6439 hitrecalibrated = true;
6440 const double newradius = newrot->localParameters()[Trk::driftRadius];
6441 const double newerror = std::sqrt(newrot->localCovariance()(Trk::driftRadius, Trk::driftRadius));
6442
6443 if ((measno < 0) or (measno >= (int) res.size())) {
6444 throw std::runtime_error(
6445 "'res' array index out of range in TrkGlobalChi2Fitter/src/GlobalChi2Fitter.cxx:" + std::to_string(__LINE__)
6446 );
6447 }
6448
6449 const double oldres = res[measno];
6450 const double newres = newradius - state->trackParameters()->parameters()[Trk::driftRadius];
6451 errors[0] = newerror;
6452 state->setMeasurement(std::move(newrot));
6453
6454 trajectory.updateTRTHitCount(stateno, olderror);
6455
6456 for (int i = 0; i < nfitpars; i++) {
6457 if (weightderiv(measno, i) == 0) {
6458 continue;
6459 }
6460
6461 b[i] -= weightderiv(measno, i) * (oldres / olderror - (newres * olderror) / (newerror * newerror));
6462
6463 for (int j = i; j < nfitpars; j++) {
6464 double weight = 1;
6465
6466 if (
6467 !cache.m_phiweight.empty() &&
6468 i == j &&
6469 i >= nperpars &&
6470 i < nperpars + 2 * nscats &&
6471 (i - nperpars) % 2 == 0
6472 ) {
6473 weight = cache.m_phiweight[(i - nperpars) / 2];
6474 }
6475
6476 a.fillSymmetric(
6477 i, j,
6478 a(i, j) + weightderiv(measno, i) * weightderiv(measno, j) * ((olderror * olderror) / (newerror * newerror) - 1) * weight
6479 );
6480 }
6481 weightderiv(measno, i) *= olderror / newerror;
6482 }
6483
6484 res[measno] = newres;
6485 err[measno] = newerror;
6486 }
6487 }
6488 }
6489 }
6490 }
6491
6492 if (state->getStateType(TrackStateOnSurface::Measurement) || state->getStateType(TrackStateOnSurface::Outlier)) {
6493 hitno++;
6494 measno += state->numberOfMeasuredParameters();
6495 }
6496 }
6497
6498 if (trajectory.nDOF() < 0) {
6499 cache.m_fittercode = FitterStatusCode::OutlierLogicFailure;
6500 cache.incrementFitStatus(S_NOT_ENOUGH_MEAS);
6501 }
6502
6503 if (outlierremoved || hitrecalibrated) {
6504 lu_m = a;
6505 trajectory.setConverged(false);
6506
6507 cache.m_miniter = it + 2;
6508 }
6509 }
Gaudi::Property< double > m_scalefactor
const LocalParameters & localParameters() const
Interface method to get the LocalParameters.
const Amg::Vector2D & localPosition() const
return the local position reference
const Amg::MatrixX & localCovariance() const
return const ref to the error matrix
virtual const Trk::PrepRawData * prepRawData() const =0
returns the PrepRawData (also known as RIO) object to which this RIO_OnTrack is associated.
@ driftRadius
trt, straws
Definition ParamDefs.h:53

◆ setMinIterations()

void Trk::GlobalChi2Fitter::setMinIterations ( int )
privatevirtual

Definition at line 8446 of file GlobalChi2Fitter.cxx.

8446 {
8448 ("Configure the minimum number of Iterations via jobOptions");
8449 }

◆ throwFailedToGetTrackingGeomtry()

void Trk::GlobalChi2Fitter::throwFailedToGetTrackingGeomtry ( ) const
private

Definition at line 8528 of file GlobalChi2Fitter.cxx.

8528 {
8529 std::stringstream msg;
8530 msg << "Failed to get conditions data " << m_trackingGeometryReadKey.key() << ".";
8531 throw std::runtime_error(msg.str());
8532 }
MsgStream & msg
Definition testRead.cxx:32

◆ trackingGeometry()

const TrackingGeometry * Trk::GlobalChi2Fitter::trackingGeometry ( Cache & cache,
const EventContext & ctx ) const
inlineprivate

Definition at line 1132 of file GlobalChi2Fitter.h.

1134 {
1135 if (!cache.m_trackingGeometry)
1136 cache.m_trackingGeometry = retrieveTrackingGeometry(ctx);
1137 return cache.m_trackingGeometry;
1138 }
const TrackingGeometry * retrieveTrackingGeometry(const EventContext &ctx) const

◆ tryToConverge()

void Trk::GlobalChi2Fitter::tryToConverge ( const Cache & cache,
GXFTrajectory & trajectory,
const int it ) const
private

Definition at line 5404 of file GlobalChi2Fitter.cxx.

5408 {
5409 ATH_MSG_DEBUG("tryToConverge");
5410
5411 const double oldChi2 = trajectory.prevchi2();
5412 const double newChi2 = trajectory.chi2();
5413
5414 /*
5415 * First convergence check
5416 */
5417 const double nDOF = trajectory.nDOF();
5418 const double oldRedChi2 = (nDOF > 0) ? oldChi2 / nDOF : 0;
5419 const double newRedChi2 = (nDOF > 0) ? newChi2 / nDOF : 0;
5420
5421 if (
5422 trajectory.prefit() > 0 && (
5423 (newRedChi2 < 2 && it != 0) ||
5424 (newRedChi2 < oldRedChi2 + .1 && std::abs(newRedChi2 - oldRedChi2) < 1 && it != 1)
5425 )
5426 ) {
5427 trajectory.setConverged(true);
5428 }
5429
5430 /*
5431 * Second convergence check
5432 */
5433 const int nsihits = trajectory.numberOfSiliconHits();
5434 const int ntrthits = trajectory.numberOfTRTHits();
5435 const int nhits = trajectory.numberOfHits();
5436
5437 int miniter = (nsihits != 0 && nsihits + ntrthits == nhits) ? 1 : 2;
5438 miniter = std::max(miniter, cache.m_miniter);
5439
5440 if (it >= miniter && std::abs(oldChi2 - newChi2) < 1) {
5441 trajectory.setConverged(true);
5442 }
5443 }

◆ tryToWeightAfromMaterial()

bool Trk::GlobalChi2Fitter::tryToWeightAfromMaterial ( Cache & cache,
GXFTrajectory & trajectory,
Amg::SymMatrixX & a,
const bool doDeriv,
const int it,
const double oldRedChi2,
const double newRedChi2 )
staticprivate

Definition at line 5821 of file GlobalChi2Fitter.cxx.

5829 {
5830 const int nPerPars = trajectory.numberOfPerigeeParameters();
5831
5832 /*
5833 * The return value collects, if any weights changed while looping over all
5834 * material states.
5835 */
5836 bool weightChanged = false;
5837
5838 /*
5839 * The weights for the diagonal material components in the [a]-matrix
5840 * depend on how far we are in the iteration process (iteration number or
5841 * chi2 convergence).
5842 */
5843 double newPhiWeight = 1.1;
5844 double newThetaWeight = 1.001;
5845 if (trajectory.prefit() == 0) {
5846 /*
5847 * We do not consider theta at all in the prefit 0 case. Therefore, we do
5848 * not need to adjust the theta weights.
5849 */
5850 if (it == 0) {
5851 newPhiWeight = 1.00000001;
5852 } else if (it == 1) {
5853 newPhiWeight = 1.0000001;
5854 } else if (it <= 3) {
5855 newPhiWeight = 1.0001;
5856 } else if (it <= 6) {
5857 newPhiWeight = 1.01;
5858 }
5859 } else {
5860 if (newRedChi2 > oldRedChi2 - 1 && newRedChi2 < oldRedChi2) {
5861 newPhiWeight = 1.0001;
5862 newThetaWeight = 1.0001;
5863 } else if (newRedChi2 > oldRedChi2 - 25 && newRedChi2 < oldRedChi2) {
5864 newPhiWeight = 1.001;
5865 newThetaWeight = 1.0001;
5866 }
5867 }
5868
5869 /*
5870 * Counter for the scattering states. We cannot directly loop over them.
5871 */
5872 std::size_t scatno = 0;
5873
5874 /*
5875 * Loop over all track states. Skip states without material effects.
5876 */
5877 for (const auto & state : trajectory.trackStates()) {
5878 const GXFMaterialEffects *meff = state->materialEffects();
5879
5880 if (meff == nullptr) {
5881 continue;
5882 }
5883
5884 const bool isValidPlaneSurface =
5885 state->associatedSurface().type() == Trk::SurfaceType::Plane &&
5886 static_cast<const PlaneSurface *>(&state->associatedSurface()) != nullptr;
5887
5888 /*
5889 * Modify the diagonal material elements in the [a]-matrix.
5890 */
5891 if (meff->deltaE() == 0 || (trajectory.prefit() == 0 && isValidPlaneSurface)) {
5892 weightChanged = true;
5893
5894 const int scatNoIndex = 2 * scatno + nPerPars;
5895
5896 if (trajectory.prefit() == 0 && meff->sigmaDeltaPhi() != 0) {
5897 if (scatno >= cache.m_phiweight.size()) {
5898 std::stringstream message;
5899 message << "scatno is out of range " << scatno << " !< " << cache.m_phiweight.size();
5900 throw std::range_error(message.str());
5901 }
5902
5903 /*
5904 * In case, no derivative is necessary, the weight will be
5905 * effectively replaced by the relative weight change
5906 */
5907 if (!doDeriv) {
5908 a(scatNoIndex, scatNoIndex) /= cache.m_phiweight[scatno];
5909 }
5910
5911 cache.m_phiweight[scatno] = newPhiWeight;
5912 a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5913 } else if (trajectory.prefit() >= 2) {
5914 a(scatNoIndex, scatNoIndex) *= newPhiWeight;
5915 a(scatNoIndex + 1, scatNoIndex + 1) *= newThetaWeight;
5916 }
5917 }
5918
5919 /*
5920 * The state is a valid scatterer even, if not considered in the
5921 * modification of the weights before. Therefore increment the count.
5922 *
5923 * NOTE: It is not clear, why this check is not at the beginning of the
5924 * loop. This way, a mismatch in the state counting could happen.
5925 */
5926 if (
5927 meff->sigmaDeltaPhi() != 0 &&
5928 (trajectory.prefit() == 0 || meff->deltaE() == 0)
5929 ) {
5930 scatno++;
5931 }
5932 }
5933
5934 /*
5935 * Add a weight to the qOverP component of the [a]-matrix if a set of
5936 * pre-conditions are met and the reduced chi2 either
5937 * - converges very fast (e.g. at the beginning of the fit)
5938 * OR
5939 * - gets larger (e.g. moving away from minimum or overshooting by a lot)
5940 */
5941 if (
5942 trajectory.prefit() == 2 &&
5943 doDeriv &&
5944 trajectory.numberOfBrems() > 0 &&
5945 (newRedChi2 < oldRedChi2 - 25 || newRedChi2 > oldRedChi2)
5946 ) {
5947 a(4, 4) *= 1.001;
5948 }
5949
5950 return weightChanged;
5951 }

◆ updateEnergyLoss()

std::variant< std::unique_ptr< const TrackParameters >, FitterStatusCode > Trk::GlobalChi2Fitter::updateEnergyLoss ( const Surface & surf,
const GXFMaterialEffects & meff,
const TrackParameters & param,
double mass,
int sign ) const
private

Definition at line 7960 of file GlobalChi2Fitter.cxx.

7966 {
7967 const AmgVector(5) & old = param.parameters();
7968
7969 double newphi = old[Trk::phi0] + sign * meff.deltaPhi();
7970 double newtheta = old[Trk::theta] + sign * meff.deltaTheta();
7971
7972 if (!correctAngles(newphi, newtheta)) {
7973 ATH_MSG_DEBUG("Angles out of range, phi: " << newphi << " theta: " << newtheta);
7975 }
7976
7977 double newqoverp = 0;
7978
7979 if (meff.sigmaDeltaE() <= 0) {
7980 if (std::abs(old[Trk::qOverP]) < 1.e-12) {
7981 newqoverp = 0.;
7982 } else {
7983 const double oldp = std::abs(1 / old[Trk::qOverP]);
7984 const double newp2 = oldp * oldp - sign * 2 * std::abs(meff.deltaE()) * std::sqrt(mass * mass + oldp * oldp) + meff.deltaE() * meff.deltaE();
7985
7986 if (newp2 < 0) {
7987 ATH_MSG_DEBUG("Track killed by energy loss update");
7989 }
7990
7991 newqoverp = std::copysign(1 / std::sqrt(newp2), old[Trk::qOverP]);
7992 }
7993 } else {
7994 newqoverp = old[Trk::qOverP] + sign * .001 * meff.delta_p();
7995 }
7996
7997 return surf.createUniqueTrackParameters(
7998 old[0], old[1], newphi, newtheta, newqoverp, std::nullopt
7999 );
8000 }

◆ updateFitParameters()

FitterStatusCode Trk::GlobalChi2Fitter::updateFitParameters ( GXFTrajectory & trajectory,
const Amg::VectorX & b,
const Amg::SymMatrixX & lu_m ) const
private

Method to update peregee parameters, scattering angles, and brems.

Tries to solve the system [A] * deltaParameters = b and then update in the trajectory all parameters used for the fit. Returns also a status.

Definition at line 6126 of file GlobalChi2Fitter.cxx.

6130 {
6131 ATH_MSG_DEBUG("UpdateFitParameters");
6132
6133 /*
6134 * Compute the parameter update from [llt] * deltaParameters = b.
6135 * In case we cannot do a Cholesky decomposition, we do not update and
6136 * use an early return.
6137 * TODO: Investigate, if it is really Success, if we do not update.
6138 */
6139 Eigen::LLT<Eigen::MatrixXd> const llt(lu_m);
6140
6141 if (llt.info() != Eigen::Success) {
6143 }
6144
6145 const Amg::VectorX deltaParameters = llt.solve(b);
6146
6147 /*
6148 * Collect the number of each parameter type for the offsets in the
6149 * deltaParameters vector.
6150 */
6151 const int nscat = trajectory.numberOfScatterers();
6152 const int nbrem = trajectory.numberOfBrems();
6153 const int nperparams = trajectory.numberOfPerigeeParameters();
6154
6155 /*
6156 * Update the perigee parameters.
6157 * The parameters are not modified in place. In case the angles are pushed
6158 * too far and cannot be corrected anymore, the parameters should not be
6159 * updated and the fit should fail.
6160 *
6161 * NOTE: It is not clear if the fit should fail for fitter reasons or
6162 * because the angle correction is not stable enough.
6163 */
6164 const TrackParameters *refpar = trajectory.referenceParameters();
6165 double d0 = refpar->parameters()[Trk::d0];
6166 double z0 = refpar->parameters()[Trk::z0];
6167 double phi = refpar->parameters()[Trk::phi0];
6168 double theta = refpar->parameters()[Trk::theta];
6169 double qoverp = refpar->parameters()[Trk::qOverP];
6170
6171 if (nperparams > 0) {
6172 d0 += deltaParameters[0];
6173 z0 += deltaParameters[1];
6174 phi += deltaParameters[2];
6175 theta += deltaParameters[3];
6176 qoverp = (trajectory.m_straightline) ? 0 : .001 * deltaParameters[4] + qoverp;
6177 }
6178
6179 if (!correctAngles(phi, theta)) {
6180 ATH_MSG_DEBUG("angles out of range: " << theta << " " << phi);
6181 ATH_MSG_DEBUG("Fit failed");
6183 }
6184
6185 /*
6186 * Update the scattering angles.
6187 */
6188 std::vector < std::pair < double, double >>&scatangles = trajectory.scatteringAngles();
6189 for (int i = 0; i < nscat; i++) {
6190 scatangles[i].first += deltaParameters[2 * i + nperparams];
6191 scatangles[i].second += deltaParameters[2 * i + nperparams + 1];
6192 }
6193
6194 /*
6195 * Update the brems.
6196 */
6197 std::vector < double >&delta_ps = trajectory.brems();
6198 for (int i = 0; i < nbrem; i++) {
6199 delta_ps[i] += deltaParameters[nperparams + 2 * nscat + i];
6200 }
6201
6202 /*
6203 * Create new peregee parameters from the updated ones.
6204 */
6205 std::unique_ptr<const TrackParameters> newper(
6206 trajectory.referenceParameters()->associatedSurface().createUniqueTrackParameters(
6207 d0, z0, phi, theta, qoverp, std::nullopt
6208 )
6209 );
6210
6211 /*
6212 * Apply all changes.
6213 */
6214 trajectory.setReferenceParameters(std::move(newper));
6215 trajectory.setScatteringAngles(scatangles);
6216 trajectory.setBrems(delta_ps);
6217
6219 }
@ d0
Definition ParamDefs.h:63

◆ updatePixelROTs()

void Trk::GlobalChi2Fitter::updatePixelROTs ( GXFTrajectory & trajectory,
Amg::SymMatrixX & a,
Amg::VectorX & b,
const EventContext & evtctx ) const
private

Update the Pixel ROT using the current trajectory/local track parameters.

Definition at line 6221 of file GlobalChi2Fitter.cxx.

6226 {
6227 if ( trajectory.numberOfSiliconHits() == 0) {
6228 return;
6229 }
6230
6231 if ( m_clusterSplitProbContainer.empty() ){
6232 return;
6233 }
6234
6235 SG::ReadHandle<Trk::ClusterSplitProbabilityContainer> splitProbContainer(m_clusterSplitProbContainer, evtctx);
6236 if (!splitProbContainer.isValid()) {
6237 ATH_MSG_FATAL("Failed to get cluster splitting probability container " << m_clusterSplitProbContainer);
6238 }
6239
6240 std::vector<std::unique_ptr<GXFTrackState>> & states = trajectory.trackStates();
6241 Amg::VectorX & res = trajectory.residuals();
6242 Amg::VectorX & err = trajectory.errors();
6243 Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
6244 const int nfitpars = trajectory.numberOfFitParameters();
6245
6246 int measno = 0;
6247 for (size_t stateno = 0; stateno < states.size(); stateno++) {
6248
6249 // Increment the measurement counter everytime we have crossed a measurement/outlier surface
6250 if ( stateno > 0 && ( states[stateno-1]->getStateType(TrackStateOnSurface::Measurement) ||
6251 states[stateno-1]->getStateType(TrackStateOnSurface::Outlier) ) ) {
6252 measno += states[stateno-1]->numberOfMeasuredParameters();
6253 }
6254
6255 std::unique_ptr<GXFTrackState> & state = states[stateno];
6256 if (!state->getStateType(TrackStateOnSurface::Measurement)) {
6257 continue;
6258 }
6259
6260 TrackState::MeasurementType const hittype = state->measurementType();
6261 if (hittype != TrackState::Pixel) {
6262 continue;
6263 }
6264
6265 const PrepRawData *prd{};
6266 if (const auto *const pMeas = state->measurement(); pMeas->type(Trk::MeasurementBaseType::RIO_OnTrack)){
6267 const auto *const rot = static_cast<const RIO_OnTrack *>(pMeas);
6268 prd = rot->prepRawData();
6269 }
6270
6271 if(!prd)
6272 continue;
6273
6274 if(!prd->type(Trk::PrepRawDataType::PixelCluster)){
6275 continue;
6276 }
6277 const InDet::PixelCluster* pixelCluster = static_cast<const InDet::PixelCluster*> ( prd );
6278 const auto &splitProb = splitProbContainer->splitProbability(pixelCluster);
6279 if (!splitProb.isSplit()) {
6280 ATH_MSG_DEBUG( "Pixel cluster is not split so no need to update" );
6281 continue;
6282 }
6283
6284 std::unique_ptr < const RIO_OnTrack > newrot;
6285 double *olderror = state->measurementErrors();
6286 const TrackParameters *trackpars = state->trackParameters();
6287
6288 double newerror[5] = {-1,-1,-1,-1,-1};
6289 double newres[2] = {-1,-1};
6290
6291 newrot.reset(m_ROTcreator->correct(*prd, *trackpars, evtctx));
6292
6293 if(!newrot)
6294 continue;
6295
6296 const Amg::MatrixX & covmat = newrot->localCovariance();
6297
6298 newerror[0] = std::sqrt(covmat(0, 0));
6299 newres[0] = newrot->localParameters()[Trk::locX] - trackpars->parameters()[Trk::locX];
6300 newerror[1] = std::sqrt(covmat(1, 1));
6301 newres[1] = newrot->localParameters()[Trk::locY] - trackpars->parameters()[Trk::locY];
6302
6303 if (a.cols() != nfitpars) {
6304 ATH_MSG_ERROR("Your assumption is wrong!!!!");
6305 }
6306
6307 //loop over both measurements -- treated as uncorrelated
6308 for( int k =0; k<2; k++ ){
6309 const double oldres = res[measno+k];
6310 res[measno+k] = newres[k];
6311 err[measno+k] = newerror[k];
6312
6313 for (int i = 0; i < nfitpars; i++) {
6314 if (weightderiv(measno+k, i) == 0) {
6315 continue;
6316 }
6317
6318 b[i] -= weightderiv(measno+k, i) * (oldres / olderror[k] - (newres[k] * olderror[k]) / (newerror[k] * newerror[k]));
6319
6320 for (int j = i; j < nfitpars; j++) {
6321 a.fillSymmetric(
6322 i, j,
6323 a(i, j) + (
6324 weightderiv(measno+k, i) *
6325 weightderiv(measno+k, j) *
6326 ((olderror[k] * olderror[k]) / (newerror[k] * newerror[k]) - 1)
6327 )
6328 );
6329 }
6330 weightderiv(measno+k, i) *= olderror[k] / newerror[k];
6331 }
6332 }
6333
6334 state->setMeasurement(std::move(newrot));
6335 state->setMeasurementErrors(newerror);
6336
6337 }// end for
6338 }
#define ATH_MSG_FATAL(x)
@ pixelCluster

◆ updateSystemWithMaxBremPull()

void Trk::GlobalChi2Fitter::updateSystemWithMaxBremPull ( GXFTrajectory & trajectory,
const int bremno_maxbrempull,
GXFTrackState * state_maxbrempull,
Amg::SymMatrixX & a ) const
private

Definition at line 5445 of file GlobalChi2Fitter.cxx.

5450 {
5451 ATH_MSG_DEBUG("updateSystemWithMaxBremPull");
5452
5453 if (state_maxbrempull == nullptr) {
5454 return;
5455 }
5456
5457 state_maxbrempull->materialEffects()->setSigmaDeltaE(
5458 10 * state_maxbrempull->materialEffects()->sigmaDeltaEPos()
5459 );
5460
5461 state_maxbrempull->materialEffects()->setKink(true);
5462
5463 const int nbrem = trajectory.numberOfBrems();
5464 const Amg::VectorX & res = trajectory.residuals();
5465 const int nmeas = (int) res.size();
5466
5467 Amg::VectorX & error = trajectory.errors();
5468 const double oldError = error[nmeas - nbrem + bremno_maxbrempull];
5469 const double newError = .001 * state_maxbrempull->materialEffects()->sigmaDeltaE();
5470 error[nmeas - nbrem + bremno_maxbrempull] = newError;
5471
5472 const int nFitPars = trajectory.numberOfFitParameters();
5473 if (a.cols() != nFitPars) {
5474 ATH_MSG_ERROR("Your assumption is wrong!!!!");
5475 }
5476
5477 const double errorRatio = oldError / newError;
5478 const double errorReductionRatio = 1 - std::pow(errorRatio, 2);
5479
5480 Amg::MatrixX & weightderiv = trajectory.weightedResidualDerivatives();
5481 for (int i = 0; i < nFitPars; i++) {
5482 if (weightderiv(nmeas - nbrem + bremno_maxbrempull, i) == 0) {
5483 continue;
5484 }
5485
5486 for (int j = i; j < nFitPars; j++) {
5487 const double newaij = a(i, j) - errorReductionRatio *
5488 weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *
5489 weightderiv(nmeas - nbrem + bremno_maxbrempull, j);
5490
5491 a.fillSymmetric(i, j, newaij);
5492 }
5493 weightderiv(nmeas - nbrem + bremno_maxbrempull, i) *= errorRatio;
5494 }
5495 }

Member Data Documentation

◆ ATLAS_THREAD_SAFE

std::array<std::atomic<unsigned int>, S_MAX_VALUE> m_fit_status Trk::GlobalChi2Fitter::ATLAS_THREAD_SAFE = {}
mutableprivate

Definition at line 1219 of file GlobalChi2Fitter.h.

1219{};

◆ m_acceleration

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_acceleration {this, "Acceleration", false}
private

Definition at line 1181 of file GlobalChi2Fitter.h.

1181{this, "Acceleration", false};

◆ m_asymeloss

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_asymeloss {this, "AsymmetricEnergyLoss", true}
private

Definition at line 1184 of file GlobalChi2Fitter.h.

1184{this, "AsymmetricEnergyLoss", true};

◆ m_boundaryCheckTool

ToolHandle<IBoundaryCheckTool> Trk::GlobalChi2Fitter::m_boundaryCheckTool {this, "BoundaryCheckTool", "", "Boundary checking tool for detector sensitivities" }
private

Definition at line 1100 of file GlobalChi2Fitter.h.

1100{this, "BoundaryCheckTool", "", "Boundary checking tool for detector sensitivities" };

◆ m_broadROTcreator

ToolHandle<IRIO_OnTrackCreator> Trk::GlobalChi2Fitter::m_broadROTcreator {this, "BroadRotCreatorTool", "", ""}
private

Definition at line 1088 of file GlobalChi2Fitter.h.

1088{this, "BroadRotCreatorTool", "", ""};

◆ m_calomat

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_calomat {this, "MuidMat", false}
private

Definition at line 1167 of file GlobalChi2Fitter.h.

1167{this, "MuidMat", false};

◆ m_caloMaterialProvider

ToolHandle<Trk::ITrkMaterialProviderTool> Trk::GlobalChi2Fitter::m_caloMaterialProvider {this, "CaloMaterialProvider", "Trk::TrkMaterialProviderTool/TrkMaterialProviderTool", ""}
private

Definition at line 1097 of file GlobalChi2Fitter.h.

1097{this, "CaloMaterialProvider", "Trk::TrkMaterialProviderTool/TrkMaterialProviderTool", ""};

◆ m_calotool

ToolHandle<IMaterialEffectsOnTrackProvider> Trk::GlobalChi2Fitter::m_calotool {this, "MuidTool", "Rec::MuidMaterialEffectsOnTrackProvider/MuidMaterialEffectsOnTrackProvider", ""}
private

Definition at line 1098 of file GlobalChi2Fitter.h.

1098{this, "MuidTool", "Rec::MuidMaterialEffectsOnTrackProvider/MuidMaterialEffectsOnTrackProvider", ""};

◆ m_calotoolparam

ToolHandle<IMaterialEffectsOnTrackProvider> Trk::GlobalChi2Fitter::m_calotoolparam {this, "MuidToolParam", "", ""}
private

Definition at line 1099 of file GlobalChi2Fitter.h.

1099{this, "MuidToolParam", "", ""};

◆ m_chi2cut

Gaudi::Property<double> Trk::GlobalChi2Fitter::m_chi2cut {this, "TrackChi2PerNDFCut", 1.e15}
private

Definition at line 1192 of file GlobalChi2Fitter.h.

1192{this, "TrackChi2PerNDFCut", 1.e15};

◆ m_clusterSplitProbContainer

SG::ReadHandleKey<Trk::ClusterSplitProbabilityContainer> Trk::GlobalChi2Fitter::m_clusterSplitProbContainer {this, "ClusterSplitProbabilityName", "",""}
private

Definition at line 1202 of file GlobalChi2Fitter.h.

1202{this, "ClusterSplitProbabilityName", "",""};

◆ m_createSummary

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_createSummary {this, "CreateTrackSummary", true}
private

Definition at line 1187 of file GlobalChi2Fitter.h.

1187{this, "CreateTrackSummary", true};

◆ m_decomposesegments

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_decomposesegments {this, "DecomposeSegments", true}
private

Definition at line 1175 of file GlobalChi2Fitter.h.

1175{this, "DecomposeSegments", true};

◆ m_DetID

const AtlasDetectorID* Trk::GlobalChi2Fitter::m_DetID = nullptr
private

Definition at line 1164 of file GlobalChi2Fitter.h.

◆ m_domeastrackpar

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_domeastrackpar {this, "MeasuredTrackParameters", true}
private

Definition at line 1177 of file GlobalChi2Fitter.h.

1177{this, "MeasuredTrackParameters", true};

◆ m_elosstool

ToolHandle<IEnergyLossUpdator> Trk::GlobalChi2Fitter::m_elosstool {this, "EnergyLossTool", "Trk::EnergyLossUpdator/AtlasEnergyLossUpdator", ""}
private

Definition at line 1092 of file GlobalChi2Fitter.h.

1092{this, "EnergyLossTool", "Trk::EnergyLossUpdator/AtlasEnergyLossUpdator", ""};

◆ m_extensioncuts

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_extensioncuts {this, "TRTExtensionCuts", true}
private

Definition at line 1171 of file GlobalChi2Fitter.h.

1171{this, "TRTExtensionCuts", true};

◆ m_extmat

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_extmat {this, "ExtrapolatorMaterial", true}
private

Definition at line 1168 of file GlobalChi2Fitter.h.

1168{this, "ExtrapolatorMaterial", true};

◆ m_extrapolator

ToolHandle<IExtrapolator> Trk::GlobalChi2Fitter::m_extrapolator {this, "ExtrapolationTool", "Trk::Extrapolator/CosmicsExtrapolator", ""}
private

Definition at line 1090 of file GlobalChi2Fitter.h.

1090{this, "ExtrapolationTool", "Trk::Extrapolator/CosmicsExtrapolator", ""};

◆ m_field_cache_key

SG::ReadCondHandleKey<AtlasFieldCacheCondObj> Trk::GlobalChi2Fitter::m_field_cache_key
private
Initial value:
{
this,
"AtlasFieldCacheCondObj",
"fieldCondObj",
"Trk::GlobalChi2Fitter field conditions object key"
}

Definition at line 1157 of file GlobalChi2Fitter.h.

1157 {
1158 this,
1159 "AtlasFieldCacheCondObj",
1160 "fieldCondObj",
1161 "Trk::GlobalChi2Fitter field conditions object key"
1162 };

◆ m_fillderivmatrix

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_fillderivmatrix {this, "FillDerivativeMatrix", false}
private

Definition at line 1169 of file GlobalChi2Fitter.h.

1169{this, "FillDerivativeMatrix", false};

◆ m_fiteloss

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_fiteloss {this, "FitEnergyLoss", false}
private

Definition at line 1183 of file GlobalChi2Fitter.h.

1183{this, "FitEnergyLoss", false};

◆ m_fixbrem

Gaudi::Property<int> Trk::GlobalChi2Fitter::m_fixbrem {this, "FixBrem", -1}
private

Definition at line 1199 of file GlobalChi2Fitter.h.

1199{this, "FixBrem", -1};

◆ m_getmaterialfromtrack

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_getmaterialfromtrack {this, "GetMaterialFromTrack", true}
private

Definition at line 1176 of file GlobalChi2Fitter.h.

1176{this, "GetMaterialFromTrack", true};

◆ m_holeSearch

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_holeSearch {this, "DoHoleSearch", false}
private

Definition at line 1188 of file GlobalChi2Fitter.h.

1188{this, "DoHoleSearch", false};

◆ m_idVolume

Trk::Volume Trk::GlobalChi2Fitter::m_idVolume
private

Definition at line 1210 of file GlobalChi2Fitter.h.

◆ m_kinkfinding

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_kinkfinding {this, "KinkFinding", false}
private

Definition at line 1174 of file GlobalChi2Fitter.h.

1174{this, "KinkFinding", false};

◆ m_matupdator

ToolHandle<IMaterialEffectsUpdator> Trk::GlobalChi2Fitter::m_matupdator {this, "MaterialUpdateTool", "", ""}
private

Definition at line 1093 of file GlobalChi2Fitter.h.

1093{this, "MaterialUpdateTool", "", ""};

◆ m_maxit

Gaudi::Property<int> Trk::GlobalChi2Fitter::m_maxit {this, "MaxIterations", 30}
private

Definition at line 1197 of file GlobalChi2Fitter.h.

1197{this, "MaxIterations", 30};

◆ m_maxitPixelROT

Gaudi::Property<int> Trk::GlobalChi2Fitter::m_maxitPixelROT {this, "IterationsToRebuildPixelRots", 0}
private

Definition at line 1200 of file GlobalChi2Fitter.h.

1200{this, "IterationsToRebuildPixelRots", 0};

◆ m_maxoutliers

Gaudi::Property<int> Trk::GlobalChi2Fitter::m_maxoutliers {this, "MaxOutliers", 10}
private

Definition at line 1196 of file GlobalChi2Fitter.h.

1196{this, "MaxOutliers", 10};

◆ m_miniter

Gaudi::Property<int> Trk::GlobalChi2Fitter::m_miniter {this, "MinimumIterations", 1}
private

Definition at line 1198 of file GlobalChi2Fitter.h.

1198{this, "MinimumIterations", 1};

◆ m_minphfcut

Gaudi::Property<double> Trk::GlobalChi2Fitter::m_minphfcut {this, "MinPHFCut", 0.}
private

Definition at line 1194 of file GlobalChi2Fitter.h.

1194{this, "MinPHFCut", 0.};

◆ m_navigator

ToolHandle<INavigator> Trk::GlobalChi2Fitter::m_navigator {this, "NavigatorTool", "Trk::Navigator/CosmicsNavigator", ""}
private

Definition at line 1095 of file GlobalChi2Fitter.h.

1095{this, "NavigatorTool", "Trk::Navigator/CosmicsNavigator", ""};

◆ m_numderiv

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_numderiv {this, "NumericalDerivs", false}
private

Definition at line 1182 of file GlobalChi2Fitter.h.

1182{this, "NumericalDerivs", false};

◆ m_outlcut

Gaudi::Property<double> Trk::GlobalChi2Fitter::m_outlcut {this, "OutlierCut", 5.0}
private

Definition at line 1190 of file GlobalChi2Fitter.h.

1190{this, "OutlierCut", 5.0};

◆ m_p

Gaudi::Property<double> Trk::GlobalChi2Fitter::m_p {this, "Momentum", 0.0}
private

Definition at line 1191 of file GlobalChi2Fitter.h.

1191{this, "Momentum", 0.0};

◆ m_propagator

ToolHandle<IPropagator> Trk::GlobalChi2Fitter::m_propagator {this, "PropagatorTool", "", ""}
private

Definition at line 1094 of file GlobalChi2Fitter.h.

1094{this, "PropagatorTool", "", ""};

◆ m_redoderivs

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_redoderivs {this, "RecalculateDerivatives", false}
private

Definition at line 1179 of file GlobalChi2Fitter.h.

1179{this, "RecalculateDerivatives", false};

◆ m_reintoutl

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_reintoutl {this, "ReintegrateOutliers", false}
private

Definition at line 1180 of file GlobalChi2Fitter.h.

1180{this, "ReintegrateOutliers", false};

◆ m_rejectLargeNScat

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_rejectLargeNScat {this, "RejectLargeNScat", false}
private

Definition at line 1186 of file GlobalChi2Fitter.h.

1186{this, "RejectLargeNScat", false};

◆ m_residualPullCalculator

ToolHandle<IResidualPullCalculator> Trk::GlobalChi2Fitter::m_residualPullCalculator {this, "ResidualPullCalculatorTool", "Trk::ResidualPullCalculator/ResidualPullCalculator", ""}
private

Definition at line 1096 of file GlobalChi2Fitter.h.

1096{this, "ResidualPullCalculatorTool", "Trk::ResidualPullCalculator/ResidualPullCalculator", ""};

◆ m_ROTcreator

ToolHandle<IRIO_OnTrackCreator> Trk::GlobalChi2Fitter::m_ROTcreator {this, "RotCreatorTool", "", ""}
private

Definition at line 1087 of file GlobalChi2Fitter.h.

1087{this, "RotCreatorTool", "", ""};

◆ m_scalefactor

Gaudi::Property<double> Trk::GlobalChi2Fitter::m_scalefactor {this, "TRTTubeHitCut", 2.5}
private

Definition at line 1193 of file GlobalChi2Fitter.h.

1193{this, "TRTTubeHitCut", 2.5};

◆ m_scattool

ToolHandle<IMultipleScatteringUpdator> Trk::GlobalChi2Fitter::m_scattool {this, "MultipleScatteringTool", "Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator", ""}
private

Definition at line 1091 of file GlobalChi2Fitter.h.

1091{this, "MultipleScatteringTool", "Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator", ""};

◆ m_signedradius

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_signedradius {this, "SignedDriftRadius", true}
private

Definition at line 1166 of file GlobalChi2Fitter.h.

1166{this, "SignedDriftRadius", true};

◆ m_sirecal

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_sirecal {this, "RecalibrateSilicon", false}
private

Definition at line 1172 of file GlobalChi2Fitter.h.

1172{this, "RecalibrateSilicon", false};

◆ m_storemat

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_storemat {this, "StoreMaterialOnTrack", true}
private

Definition at line 1178 of file GlobalChi2Fitter.h.

1178{this, "StoreMaterialOnTrack", true};

◆ m_straightlineprop

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_straightlineprop {this, "StraightLine", true}
private

Definition at line 1170 of file GlobalChi2Fitter.h.

1170{this, "StraightLine", true};

◆ m_trackingGeometryReadKey

SG::ReadCondHandleKey<TrackingGeometry> Trk::GlobalChi2Fitter::m_trackingGeometryReadKey
private
Initial value:
{
this,
"TrackingGeometryReadKey",
"AtlasTrackingGeometry",
"Key of the TrackingGeometry conditions data."
}

Definition at line 1150 of file GlobalChi2Fitter.h.

1150 {
1151 this,
1152 "TrackingGeometryReadKey",
1153 "AtlasTrackingGeometry",
1154 "Key of the TrackingGeometry conditions data."
1155 };

◆ m_trtrecal

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_trtrecal {this, "RecalibrateTRT", false}
private

Definition at line 1173 of file GlobalChi2Fitter.h.

1173{this, "RecalibrateTRT", false};

◆ m_updator

ToolHandle<IUpdator> Trk::GlobalChi2Fitter::m_updator {this, "MeasurementUpdateTool", "", ""}
private

Definition at line 1089 of file GlobalChi2Fitter.h.

1089{this, "MeasurementUpdateTool", "", ""};

◆ m_useCaloTG

Gaudi::Property<bool> Trk::GlobalChi2Fitter::m_useCaloTG {this, "UseCaloTG", false}
private

Definition at line 1185 of file GlobalChi2Fitter.h.

1185{this, "UseCaloTG", false};

The documentation for this class was generated from the following files: