diff --git a/Tracking/TrkFitter/TrkGaussianSumFilter/TrkGaussianSumFilter/GsfExtrapolator.h b/Tracking/TrkFitter/TrkGaussianSumFilter/TrkGaussianSumFilter/GsfExtrapolator.h index bea460322c29b2395b69baff67d747ef89de60e8..2d4a5d3815ac750f832016445e712ef5ef48d109 100755 --- a/Tracking/TrkFitter/TrkGaussianSumFilter/TrkGaussianSumFilter/GsfExtrapolator.h +++ b/Tracking/TrkFitter/TrkGaussianSumFilter/TrkGaussianSumFilter/GsfExtrapolator.h @@ -1,382 +1,388 @@ -/* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -*/ - -/********************************************************************************* - GsfExtrapolator.h - description - ------------------------------------------ -begin : Tuesday 25th January 2005 -author : atkinson -email : Tom.Atkinson@cern.ch -decription : Extrapolation of MultiComponentState class based on - Andi's single component state extrapolator. It is an - AlgTool inheriting from the IMultiStateExtrapolator class -*********************************************************************************/ - -#ifndef TrkGsfExtrapolator_H -#define TrkGsfExtrapolator_H - -#include "TrkExInterfaces/IEnergyLossUpdator.h" -#include "TrkExInterfaces/IMultipleScatteringUpdator.h" -#include "TrkGaussianSumFilter/IMultiComponentStateCombiner.h" -#include "TrkGaussianSumFilter/IMultiStateExtrapolator.h" - -#include "AthenaBaseComps/AthAlgTool.h" -#include "GaudiKernel/ToolHandle.h" -#include "GaudiKernel/ServiceHandle.h" -#include "GaudiKernel/IChronoStatSvc.h" -#include "TrkParameters/TrackParameters.h" -#include "TrkMaterialOnTrack/MaterialEffectsOnTrack.h" - -#include "GeoPrimitives/GeoPrimitives.h" - -#include "TrkGeometry/MagneticFieldProperties.h" - -#include <map> -#include <vector> -#include <string> - -namespace Trk{ - -class Layer; -class Surface; -class INavigator; -class TrackingVolume; -class TrackingGeometry; -class TrackStateOnSurface; -class MaterialProperties; -class IMultiComponentStateMerger; -class IMaterialMixtureConvolution; - - -/** @struct StateAtBoundarySurface - - Structure to contain information about a state at the interface between tracking volumes -*/ - -struct StateAtBoundarySurface { - - /** Data members */ - mutable const MultiComponentState* stateAtBoundary; - mutable const TrackParameters* navigationParameters; - mutable const TrackingVolume* trackingVolume; - - /** Default constructor */ - StateAtBoundarySurface() - : - stateAtBoundary(0), - navigationParameters(0), - trackingVolume(0) - {} - - /** Update State at Boundary Surface Information */ - void updateBoundaryInformation( const MultiComponentState* boundaryState, - const TrackParameters* navParameters, - const TrackingVolume* nextVolume ) - { - stateAtBoundary = boundaryState; - navigationParameters = navParameters; - trackingVolume = nextVolume; - } - - /** Reset boundary information by clearing cashed parameters */ - void resetBoundaryInformation() - { - stateAtBoundary = 0; - navigationParameters = 0; - trackingVolume = 0; - } - -}; - -/** @class GsfExtrapolator */ - -class GsfExtrapolator : public AthAlgTool, virtual public IMultiStateExtrapolator { - - public: - - /** Constructor with AlgTool parameters */ - GsfExtrapolator(const std::string&, const std::string&, const IInterface*); - - /** Destructor */ - ~GsfExtrapolator(); - - /** AlgTool initialise method */ - StatusCode initialize(); - - /** AlgTool finalise method */ - StatusCode finalize(); - - /** Extrapolation of a MutiComponentState to a destination surface (1) */ - virtual const MultiComponentState* extrapolate ( const IPropagator&, - const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** - Extrapolation of a MultiComponentState to destination surface without material effects (2) */ - virtual const MultiComponentState* extrapolateDirectly ( const IPropagator&, - const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Configured AlgTool extrapolation method (1) */ - virtual const MultiComponentState* extrapolate ( const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Configured AlgTool extrapolation without material effects method (2) */ - virtual const MultiComponentState* extrapolateDirectly ( const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - - - virtual const std::vector<const Trk::TrackStateOnSurface*>* extrapolateM(const MultiComponentState&, - const Surface& sf, - PropDirection dir, - BoundaryCheck bcheck, - ParticleHypothesis particle) const; - - - private: - - /** Two primary private extrapolation methods - - extrapolateToVolumeBoundary - extrapolates to the exit of the destination tracking volume - - Exit layer surface will be hit in this method. - - extrapolateInsideVolume - extrapolates to the destination surface in the final tracking volume - */ - - void extrapolateToVolumeBoundary ( const IPropagator&, - const MultiComponentState&, - const Layer*, - const TrackingVolume&, - PropDirection direction = anyDirection, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - const MultiComponentState* extrapolateInsideVolume ( const IPropagator&, - const MultiComponentState&, - const Surface&, - const Layer*, - const TrackingVolume&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Additional private extrapolation methods */ - - /** Layer stepping, stopping at the last layer before destination */ - const MultiComponentState* extrapolateFromLayerToLayer( const IPropagator&, - const MultiComponentState&, - const TrackingVolume&, - const Layer* startLayer, - const Layer* destinationLayer = 0, - PropDirection direction = anyDirection, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Single extrapolation step to an intermediate layer */ - const MultiComponentState* extrapolateToIntermediateLayer ( const IPropagator&, - const MultiComponentState&, - const Layer&, - const TrackingVolume&, - PropDirection direction = anyDirection, - ParticleHypothesis particleHypothesis = nonInteracting, - bool perpendicularCheck = true) const; - - /** Final extrapolation step to a destination layer */ - const MultiComponentState* extrapolateToDestinationLayer ( const IPropagator&, - const MultiComponentState&, - const Surface&, - const Layer&, - //const TrackingVolume&, - const Layer*, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Extrapolation to consider material effects assuming all material on active sensor elements - CTB method */ - const MultiComponentState* extrapolateSurfaceBasedMaterialEffects ( const IPropagator&, - const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** GSF Method to propagate a number of components simultaneously */ - const MultiComponentState* multiStatePropagate ( const IPropagator&, - const MultiComponentState&, - const Surface&, - PropDirection direction = anyDirection, - BoundaryCheck boundaryCheck = true, - ParticleHypothesis particleHypothesis = nonInteracting ) const; - - /** Method to choose propagator type */ - unsigned int propagatorType ( const TrackingVolume& trackingVolume ) const; - - /** Method to initialise navigation parameters including starting state, layer and volume, and destination volume */ - void initialiseNavigation ( const IPropagator& propagator, - const MultiComponentState& initialState, - const Surface& surface, - const Layer*& associatedLayer, - const TrackingVolume*& currentVolume, - const TrackingVolume*& destinationVolume, - const TrackParameters*& referenceParameters, - PropDirection direction ) const; - - /** Method to print details of the state at a point in extrapolation */ - void printState( const std::string&, const TrackParameters& ) const; - - /** Method to set the recall information */ - void setRecallInformation( const Surface&, const Layer&, const TrackingVolume& ) const; - - /** Method to reset the recall information */ - void resetRecallInformation() const; - - /** Private method to throw a multi-component state into the garbage bin */ - void throwIntoGarbageBin( const MultiComponentState* ) const; - - /** Private method to throw a set of track parameters into the garbage bin */ - void throwIntoGarbageBin( const TrackParameters* ) const; - - /** Private method to empty garbage bins */ - void emptyGarbageBins() const; - - /** Private method to reset the garbage bins */ - void resetGarbageBins() const; - - /** Add material to vector*/ - void addMaterialtoVector(const Trk::Layer* nextLayer, - const Trk::TrackParameters* nextPar, - PropDirection direction = anyDirection, - ParticleHypothesis particleHypothesis = nonInteracting) const; - - - std::string layerRZoutput(const Trk::Layer * lay) const; - - std::string positionOutput(const Amg::Vector3D& pos) const; - - - int radialDirection(const Trk::MultiComponentState& pars, PropDirection dir) const; - - bool radialDirectionCheck(const IPropagator& prop, - const MultiComponentState& startParm, - const MultiComponentState& parsOnLayer, - const TrackingVolume& tvol, - PropDirection dir, - ParticleHypothesis particle) const; - - private: - - ToolHandleArray< IPropagator > m_propagators; //!< Propagators to be retrieved from the ToolSvc - bool m_propagatorStickyConfiguration; //!< Switch between simple and full configured propagators - unsigned int m_propagatorConfigurationLevel; //!< Configuration level of the propagator - unsigned int m_propagatorSearchLevel; //!< Search level of the propagator - - ToolHandle<INavigator> m_navigator; //!< Navigator - - ToolHandle<IMaterialMixtureConvolution> m_materialUpdator; //!< (Multi-component) material effects updator - - ToolHandle<IMultiComponentStateMerger> m_merger; //!< Multi-component state reduction - - PublicToolHandle<IMultiComponentStateCombiner> m_stateCombiner - {this,"MultiComponentStateCombiner","Trk::MultiComponentStateCombiner/GsfExtrapolatorCombiner",""}; //!< Multi-component State combiner - - PublicToolHandle< IMultipleScatteringUpdator > m_msupdators - {this,"MultipleScatteringUpdator","Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator",""}; //!< Array of MultipleScattering Updators - PublicToolHandle< IEnergyLossUpdator > m_elossupdators - {this,"EnergyLossUpdator","Trk::EnergyLossUpdator/AtlasEnergyLossUpdator",""}; //!< Array of EnergyLoss Updators - - bool m_surfaceBasedMaterialEffects; //!< Switch to turn on/off surface based material effects - - mutable bool m_recall; //!< Flag the recall solution - mutable const Surface* m_recallSurface; //!< Surface for recall - mutable const Layer* m_recallLayer; //!< Layer for recall - mutable const TrackingVolume* m_recallTrackingVolume; //!< Tracking volume for recall - - mutable StateAtBoundarySurface m_stateAtBoundarySurface; //!< Instance of structure describing the state at a boundary of tracking volumes - - mutable int m_extrapolateCalls; //!< Statistics: Number of calls to the main extrapolate method - mutable int m_extrapolateDirectlyCalls; //!< Statistics: Number of calls to the extrapolate directly method - mutable int m_extrapolateDirectlyFallbacks; //!< Statistics: Number of calls to the extrapolate directly fallback - mutable int m_navigationDistanceIncreaseBreaks; //!< Statistics: Number of times navigation stepping fails to go the right way - mutable int m_oscillationBreaks; //!< Statistics: Number of times a tracking volume oscillation is detected - mutable int m_missedVolumeBoundary; //!< Statistics: Number of times the volume boundary is missed - - ServiceHandle<IChronoStatSvc> m_chronoSvc; //!< Timing: The Gaudi time auditing service - - mutable std::map< const MultiComponentState*, bool > m_mcsGarbageBin; //!< Garbage bin for MultiComponentState objects - mutable std::map< const TrackParameters*, bool > m_tpGarbageBin; //!< Garbage bin for TrackParameter objects - - mutable std::vector<const Trk::TrackStateOnSurface*>* m_matstates; - - - bool m_fastField; - Trk::MagneticFieldProperties m_fieldProperties; -}; - -} // end namespace Trk - -inline void Trk::GsfExtrapolator::setRecallInformation( const Trk::Surface& recallSurface, const Trk::Layer& recallLayer, const Trk::TrackingVolume& recallTrackingVolume ) const -{ - - m_recall = true; - m_recallSurface = &recallSurface; - m_recallLayer = &recallLayer; - m_recallTrackingVolume = &recallTrackingVolume; - -} - -inline void Trk::GsfExtrapolator::resetRecallInformation() const -{ - - m_recall = false; - m_recallSurface = 0; - m_recallLayer = 0; - m_recallTrackingVolume = 0; - -} - -inline void Trk::GsfExtrapolator::throwIntoGarbageBin( const Trk::MultiComponentState* garbage ) const -{ if (garbage) m_mcsGarbageBin[garbage] = true; } - -inline void Trk::GsfExtrapolator::throwIntoGarbageBin( const Trk::TrackParameters* garbage ) const -{ if (garbage) m_tpGarbageBin[garbage] = true; } - -inline void Trk::GsfExtrapolator::emptyGarbageBins() const -{ - - // Reset the boundary information - m_stateAtBoundarySurface.resetBoundaryInformation(); - - // Loop over both garbage collections and delete - std::map< const Trk::MultiComponentState*, bool >::iterator mcsGarbage = m_mcsGarbageBin.begin(); - - for ( ; mcsGarbage != m_mcsGarbageBin.end() ; ++mcsGarbage ) - delete mcsGarbage->first; - - m_mcsGarbageBin.clear(); - - std::map< const Trk::TrackParameters*, bool >::iterator tpGarbage = m_tpGarbageBin.begin(); - - for ( ; tpGarbage != m_tpGarbageBin.end() ; ++tpGarbage ) - delete tpGarbage->first; - - m_tpGarbageBin.clear(); - -} - -inline void Trk::GsfExtrapolator::resetGarbageBins() const -{ - - m_mcsGarbageBin.clear(); - m_tpGarbageBin.clear(); - -} - -#endif +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + */ + +/********************************************************************************* + GsfExtrapolator.h - description +------------------------------------------ +begin : Tuesday 25th January 2005 +author : atkinson +email : Tom.Atkinson@cern.ch +decription : Extrapolation of MultiComponentState class based on +Andi's single component state extrapolator. It is an +AlgTool inheriting from the IMultiStateExtrapolator class +*********************************************************************************/ + +#ifndef TrkGsfExtrapolator_H +#define TrkGsfExtrapolator_H + +#include "GaudiKernel/Counters.h" + +#include "TrkExInterfaces/IEnergyLossUpdator.h" +#include "TrkExInterfaces/IMultipleScatteringUpdator.h" +#include "TrkGaussianSumFilter/IMultiComponentStateCombiner.h" +#include "TrkGaussianSumFilter/IMultiStateExtrapolator.h" + +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/IChronoStatSvc.h" +#include "TrkParameters/TrackParameters.h" +#include "TrkMaterialOnTrack/MaterialEffectsOnTrack.h" + +#include "GeoPrimitives/GeoPrimitives.h" + +#include "TrkGeometry/MagneticFieldProperties.h" +#include <map> +#include <vector> +#include <string> +#include <memory> + +namespace Trk{ + +class Layer; +class Surface; +class INavigator; +class TrackingVolume; +class TrackingGeometry; +class TrackStateOnSurface; +class MaterialProperties; +class IMultiComponentStateMerger; +class IMaterialMixtureConvolution; + + +/** @struct StateAtBoundarySurface + - Structure to contain information about a state at the interface between tracking volumes + */ + +struct StateAtBoundarySurface { + + /** Data members */ + const MultiComponentState* stateAtBoundary; + const TrackParameters* navigationParameters; + const TrackingVolume* trackingVolume; + + /** Default constructor */ + StateAtBoundarySurface() + : + stateAtBoundary(0), + navigationParameters(0), + trackingVolume(0) + {} + + /** Update State at Boundary Surface Information */ + void updateBoundaryInformation( const MultiComponentState* boundaryState, + const TrackParameters* navParameters, + const TrackingVolume* nextVolume ) + { + stateAtBoundary = boundaryState; + navigationParameters = navParameters; + trackingVolume = nextVolume; + } +}; + +/** @class GsfExtrapolator */ + +class GsfExtrapolator : public AthAlgTool, virtual public IMultiStateExtrapolator { + +public: + + /** Constructor with AlgTool parameters */ + GsfExtrapolator(const std::string&, const std::string&, const IInterface*); + + /** Destructor */ + ~GsfExtrapolator(); + + /** AlgTool initialise method */ + StatusCode initialize(); + + /** AlgTool finalise method */ + StatusCode finalize(); + + /** Extrapolation of a MutiComponentState to a destination surface (1) */ + virtual const MultiComponentState* extrapolate ( const IPropagator&, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const override; + + /** - Extrapolation of a MultiComponentState to destination surface without material effects (2) */ + virtual const MultiComponentState* extrapolateDirectly ( const IPropagator&, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const override; + + /** Configured AlgTool extrapolation method (1) */ + virtual const MultiComponentState* extrapolate ( const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const override; + + /** Configured AlgTool extrapolation without material effects method (2) */ + virtual const MultiComponentState* extrapolateDirectly ( const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const override; + + + + virtual const std::vector<const Trk::TrackStateOnSurface*>* extrapolateM(const MultiComponentState&, + const Surface& sf, + PropDirection dir, + BoundaryCheck bcheck, + ParticleHypothesis particle) const override; + + +private: + struct Cache { + bool m_recall; //!< Flag the recall solution + const Surface* m_recallSurface; //!< Surface for recall + const Layer* m_recallLayer; //!< Layer for recall + const TrackingVolume* m_recallTrackingVolume; //!< Tracking volume for recall + StateAtBoundarySurface m_stateAtBoundarySurface; //!< Instance of structure describing the state at a boundary of tracking volumes + std::unique_ptr< std::vector<const Trk::TrackStateOnSurface*> > m_matstates; + std::vector< std::unique_ptr< const MultiComponentState> > m_mcsGarbageBin; //!< Garbage bin for MultiComponentState objects + std::vector< std::unique_ptr< const TrackParameters> > m_tpGarbageBin; //!< Garbage bin for TrackParameter objects + + Cache(): m_recall(false), + m_recallSurface(nullptr), + m_recallLayer(nullptr), + m_recallTrackingVolume(nullptr), + m_stateAtBoundarySurface(), + m_matstates(nullptr), + m_mcsGarbageBin(), + m_tpGarbageBin(){ + } + }; + + /** These are the methods that do the actual heavy lifting when extrapolating with a cache */ + const MultiComponentState* extrapolateImpl (Cache& cache, + const IPropagator&, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + const MultiComponentState* extrapolateImpl ( Cache& cache, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + + + /** Two primary private extrapolation methods + - extrapolateToVolumeBoundary - extrapolates to the exit of the destination tracking volume + - Exit layer surface will be hit in this method. + - extrapolateInsideVolume - extrapolates to the destination surface in the final tracking volume + */ + + void extrapolateToVolumeBoundary ( Cache& cache, + const IPropagator&, + const MultiComponentState&, + const Layer*, + const TrackingVolume&, + PropDirection direction = anyDirection, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + const MultiComponentState* extrapolateInsideVolume ( Cache& cache, + const IPropagator&, + const MultiComponentState&, + const Surface&, + const Layer*, + const TrackingVolume&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + /** Additional private extrapolation methods */ + + /** Layer stepping, stopping at the last layer before destination */ + const MultiComponentState* extrapolateFromLayerToLayer( Cache& cache, + const IPropagator&, + const MultiComponentState&, + const TrackingVolume&, + const Layer* startLayer, + const Layer* destinationLayer = 0, + PropDirection direction = anyDirection, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + /** Single extrapolation step to an intermediate layer */ + const MultiComponentState* extrapolateToIntermediateLayer ( Cache& cache, + const IPropagator&, + const MultiComponentState&, + const Layer&, + const TrackingVolume&, + PropDirection direction = anyDirection, + ParticleHypothesis particleHypothesis = nonInteracting, + bool perpendicularCheck = true) const; + + /** Final extrapolation step to a destination layer */ + const MultiComponentState* extrapolateToDestinationLayer ( Cache& cache, + const IPropagator&, + const MultiComponentState&, + const Surface&, + const Layer&, + const Layer*, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + /** Extrapolation to consider material effects assuming all material on active sensor elements - CTB method */ + const MultiComponentState* extrapolateSurfaceBasedMaterialEffects ( const IPropagator&, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + /** GSF Method to propagate a number of components simultaneously */ + const MultiComponentState* multiStatePropagate ( const IPropagator&, + const MultiComponentState&, + const Surface&, + PropDirection direction = anyDirection, + BoundaryCheck boundaryCheck = true, + ParticleHypothesis particleHypothesis = nonInteracting ) const; + + /** Method to choose propagator type */ + unsigned int propagatorType ( const TrackingVolume& trackingVolume ) const; + + /** Method to initialise navigation parameters including starting state, layer and volume, and destination volume */ + void initialiseNavigation ( Cache& cache, + const IPropagator& propagator, + const MultiComponentState& initialState, + const Surface& surface, + const Layer*& associatedLayer, + const TrackingVolume*& currentVolume, + const TrackingVolume*& destinationVolume, + const TrackParameters*& referenceParameters, + PropDirection direction ) const; + + /** Method to set the recall information */ + void setRecallInformation( Cache& cache, const Surface&, const Layer&, const TrackingVolume& ) const; + + /** Method to reset the recall information */ + void resetRecallInformation(Cache& cache) const; + + /** Private method to throw a multi-component state into the garbage bin */ + void throwIntoGarbageBin( Cache& cache , const MultiComponentState* ) const; + + /** Private method to throw a set of track parameters into the garbage bin */ + void throwIntoGarbageBin( Cache& cache, const TrackParameters* ) const; + + /** Private method to empty garbage bins */ + void emptyGarbageBins(Cache& cache) const; + /** Add material to vector*/ + void addMaterialtoVector(Cache& cache, + const Trk::Layer* nextLayer, + const Trk::TrackParameters* nextPar, + PropDirection direction = anyDirection, + ParticleHypothesis particleHypothesis = nonInteracting) const; + + /** Method to print details of the state at a point in extrapolation */ + void printState( const std::string&, const TrackParameters& ) const; + + + std::string layerRZoutput(const Trk::Layer * lay) const; + + std::string positionOutput(const Amg::Vector3D& pos) const; + + int radialDirection(const Trk::MultiComponentState& pars, PropDirection dir) const; + + bool radialDirectionCheck(const IPropagator& prop, + const MultiComponentState& startParm, + const MultiComponentState& parsOnLayer, + const TrackingVolume& tvol, + PropDirection dir, + ParticleHypothesis particle) const; + + ToolHandleArray< IPropagator > m_propagators; //!< Propagators to be retrieved from the ToolSvc + ToolHandle<INavigator> m_navigator; //!< Navigator + ToolHandle<IMaterialMixtureConvolution> m_materialUpdator; //!< (Multi-component) material effects updator + ToolHandle<IMultiComponentStateMerger> m_merger; //!< Multi-component state reduction + PublicToolHandle<IMultiComponentStateCombiner> m_stateCombiner + {this,"MultiComponentStateCombiner","Trk::MultiComponentStateCombiner/GsfExtrapolatorCombiner",""}; //!< Multi-component State combiner + PublicToolHandle< IMultipleScatteringUpdator > m_msupdators + {this,"MultipleScatteringUpdator","Trk::MultipleScatteringUpdator/AtlasMultipleScatteringUpdator",""}; //!< Array of MultipleScattering Updators + PublicToolHandle< IEnergyLossUpdator > m_elossupdators + {this,"EnergyLossUpdator","Trk::EnergyLossUpdator/AtlasEnergyLossUpdator",""}; //!< Array of EnergyLoss Updators + + bool m_propagatorStickyConfiguration; //!< Switch between simple and full configured propagators + bool m_surfaceBasedMaterialEffects; //!< Switch to turn on/off surface based material effects + bool m_fastField; + unsigned int m_propagatorConfigurationLevel; //!< Configuration level of the propagator + unsigned int m_propagatorSearchLevel; //!< Search level of the propagator + Trk::MagneticFieldProperties m_fieldProperties; + + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_extrapolateCalls; //!< Statistics: Number of calls to the main extrapolate method + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_extrapolateDirectlyCalls; //!< Statistics: Number of calls to the extrapolate directly method + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_extrapolateDirectlyFallbacks; //!< Statistics: Number of calls to the extrapolate directly fallback + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_navigationDistanceIncreaseBreaks; //!< Statistics: Number of times navigation stepping fails to go the right way + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_oscillationBreaks; //!< Statistics: Number of times a tracking volume oscillation is detected + mutable Gaudi::Accumulators::Counter<int, Gaudi::Accumulators::atomicity::full> + m_missedVolumeBoundary; //!< Statistics: Number of times the volume boundary is missed + + +}; + +} // end namespace Trk + +inline void Trk::GsfExtrapolator::setRecallInformation( Cache& cache, + const Trk::Surface& recallSurface, + const Trk::Layer& recallLayer, + const Trk::TrackingVolume& recallTrackingVolume ) const +{ + cache.m_recall = true; + cache.m_recallSurface = &recallSurface; + cache.m_recallLayer = &recallLayer; + cache.m_recallTrackingVolume = &recallTrackingVolume; +} + +inline void Trk::GsfExtrapolator::resetRecallInformation(Cache& cache) const +{ + cache.m_recall = false; + cache.m_recallSurface = 0; + cache.m_recallLayer = 0; + cache.m_recallTrackingVolume = 0; +} + +inline void Trk::GsfExtrapolator::throwIntoGarbageBin( Cache& cache, const Trk::MultiComponentState* garbage ) const +{ + if (garbage){ + std::unique_ptr<const Trk::MultiComponentState> sink(garbage); + cache.m_mcsGarbageBin.push_back(std::move(sink)); + } +} + +inline void Trk::GsfExtrapolator::throwIntoGarbageBin(Cache& cache, const Trk::TrackParameters* garbage ) const +{ + if (garbage){ + std::unique_ptr<const Trk::TrackParameters> sink(garbage); + cache.m_tpGarbageBin.push_back(std::move(sink)); + } +} + +inline void Trk::GsfExtrapolator::emptyGarbageBins(Cache& cache) const +{ + // Reset the boundary information + StateAtBoundarySurface freshState; + cache.m_stateAtBoundarySurface=freshState; + cache.m_mcsGarbageBin.clear(); + cache.m_tpGarbageBin.clear(); + cache.m_matstates.reset(nullptr); +} + + +#endif diff --git a/Tracking/TrkFitter/TrkGaussianSumFilter/src/GsfExtrapolator.cxx b/Tracking/TrkFitter/TrkGaussianSumFilter/src/GsfExtrapolator.cxx index ca0af99552ca8cbab749f8e78b9f90317e060661..a3a8b022abd88e3e8438b4c6de0cc50d3331f1c5 100644 --- a/Tracking/TrkFitter/TrkGaussianSumFilter/src/GsfExtrapolator.cxx +++ b/Tracking/TrkFitter/TrkGaussianSumFilter/src/GsfExtrapolator.cxx @@ -1,1924 +1,1784 @@ -/* - Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration -*/ - -/********************************************************************************* - GsfExtrapolator.cxx - description - ----------------------------------- -begin : Tuesday 25th January 2005 -author : amorley -email : amorley@cern.ch -decription : Implementation code for GsfExtrapolator class -*********************************************************************************/ - -#include "TrkGaussianSumFilter/GsfExtrapolator.h" - -#include "TrkGaussianSumFilter/IMaterialMixtureConvolution.h" -#include "TrkGaussianSumFilter/IMultiComponentStateMerger.h" - -#include "TrkExInterfaces/IPropagator.h" -#include "TrkExInterfaces/INavigator.h" - - -#include "TrkGeometry/MaterialProperties.h" -#include "TrkGeometry/TrackingVolume.h" -#include "TrkGeometry/Layer.h" - -#include "TrkSurfaces/Surface.h" -#include "TrkParameters/TrackParameters.h" -#include "TrkTrack/TrackStateOnSurface.h" -#include "TrkMaterialOnTrack/ScatteringAngles.h" -#include "TrkMaterialOnTrack/EnergyLoss.h" -#include "TrkExUtils/MaterialUpdateMode.h" - -#include "TrkGeometry/MagneticFieldProperties.h" - -#include "GaudiKernel/Chrono.h" - -bool useBoundaryMaterialUpdate(true); - -Trk::GsfExtrapolator::GsfExtrapolator(const std::string& type, const std::string& name, const IInterface* parent) - : - AthAlgTool(type, name, parent), - m_propagators(), - m_propagatorStickyConfiguration(true), - m_propagatorConfigurationLevel(10), - m_propagatorSearchLevel(10), - m_navigator("Trk::Navigator/Navigator"), - m_materialUpdator("Trk::GsfMaterialMixtureConvolution/GsfMaterialMixtureConvolution"), - m_merger("Trk::CloseComponentsMultiStateMerger/CloseComponentsMultiStateMerger"), - m_surfaceBasedMaterialEffects(false), - m_recall(false), - m_recallSurface(0), - m_recallLayer(0), - m_recallTrackingVolume(0), - m_extrapolateCalls(0), - m_extrapolateDirectlyCalls(0), - m_extrapolateDirectlyFallbacks(0), - m_navigationDistanceIncreaseBreaks(0), - m_oscillationBreaks(0), - m_missedVolumeBoundary(0), - m_chronoSvc("ChronoStatSvc", name), - m_matstates(0), - m_fastField(false) -{ - - declareInterface<IMultiStateExtrapolator>(this); - - declareProperty("Propagators", m_propagators ); - - declareProperty("SearchLevelClosestParameters", m_propagatorSearchLevel ); - - declareProperty("StickyConfiguration", m_propagatorStickyConfiguration ); - - declareProperty("Navigator", m_navigator ); - - declareProperty("GsfMaterialConvolution", m_materialUpdator ); - - declareProperty("ComponentMerger", m_merger ); - - declareProperty("SurfaceBasedMaterialEffects", m_surfaceBasedMaterialEffects ); - - declareProperty("MagneticFieldProperties", m_fastField); - -} - -Trk::GsfExtrapolator::~GsfExtrapolator() -{} - -/* ========================================================================================================================================= - B - ========================================================================================================================================= - Initialisation and finalisation - ========================================================================================================================================= - ========================================================================================================================================= */ - -StatusCode Trk::GsfExtrapolator::initialize() -{ - - // Request the Chrono Service - ATH_CHECK( m_chronoSvc.retrieve() ); - - // Request the Propagator AlgTools - if ( not m_propagators.empty() ){ - ATH_MSG_INFO( "Attempting to retrieve propagator tool.... " ); - ATH_CHECK( m_propagators.retrieve() ); - ATH_MSG_INFO( "Retrieved tools " << m_propagators ); - unsigned int retrievedPropagators = m_propagators.size(); - if (!retrievedPropagators){ - ATH_MSG_WARNING( "None of the specified propagators could be retrieved! Extrapolators will operate in unconfigured mode."); - m_propagatorConfigurationLevel = 10; - } else { - // Set the configuration level for the retrieved propagators - m_propagatorConfigurationLevel = m_propagators.size() - 1; - } - ATH_MSG_INFO( "Propagator configuration level: " << m_propagatorConfigurationLevel ); - - } else { - ATH_MSG_WARNING( "List of propagators to retrieve is empty. Extrapolators will work in unconfigured mode" ); - } - - - // Request the Navigation AlgTool - ATH_CHECK( m_navigator.retrieve() ); - - // Request the Material Effects Updator AlgTool - ATH_CHECK( m_materialUpdator.retrieve() ); - - // Retrieve an instance of the component merger - ATH_CHECK( m_merger.retrieve() ); - - // Retrieve an instance of the multi-component state combiner tool - ATH_CHECK( m_stateCombiner.retrieve() ); - - - ATH_CHECK( m_elossupdators.retrieve() ); - - - ATH_CHECK( m_msupdators.retrieve() ); - - m_fieldProperties = m_fastField ? Trk::MagneticFieldProperties(Trk::FastField) : Trk::MagneticFieldProperties(Trk::FullField); - - - ATH_MSG_INFO( "Initialisation of " << name() << " was successful" ); - return StatusCode::SUCCESS; -} - -StatusCode Trk::GsfExtrapolator::finalize() -{ - - ATH_MSG_INFO( "*** Extrapolator " << name() << " performance statistics ***********" ); - ATH_MSG_INFO( " * - Number of extrapolate() calls: " << m_extrapolateCalls ); - ATH_MSG_INFO( " * - Number of extrapolateDirectly() calls: " << m_extrapolateDirectlyCalls ); - ATH_MSG_INFO( " * - Number of extrapolateDirectly() fallbacks: " << m_extrapolateDirectlyFallbacks ); - ATH_MSG_INFO( " * - Number of navigation distance check breaks: " << m_navigationDistanceIncreaseBreaks ); - ATH_MSG_INFO( " * - Number of volume boundary search failures: " << m_missedVolumeBoundary ); - ATH_MSG_INFO( " * - Number of tracking volume oscillation breaks: " << m_oscillationBreaks ); - ATH_MSG_INFO( "*****************************************************************************************************************" ); - - ATH_MSG_INFO( "Finalisation of " << name() << " was successful" ); - return StatusCode::SUCCESS; -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - Extrapolation methods without configured propagator - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolate( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolate() in non-configured mode: " << multiComponentState.size() ); - - // If the extrapolation is to be without material effects simply revert to the extrapolateDirectly method - if ( particleHypothesis == Trk::nonInteracting ) - return extrapolateDirectly( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); - - // Surface based material effects (assumes all material is on active sensor elements) - if ( m_surfaceBasedMaterialEffects ) - return extrapolateSurfaceBasedMaterialEffects( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); - - // statistics - ++m_extrapolateCalls; - - // Start the timer - //Chrono chrono( &(*m_chronoSvc), "extrapolate()" ); - - const Trk::Layer* associatedLayer = 0; - const Trk::TrackingVolume* startVolume = 0; - const Trk::TrackingVolume* destinationVolume = 0; - const Trk::TrackParameters* referenceParameters = 0; - - initialiseNavigation( propagator, multiComponentState, surface, associatedLayer, startVolume, destinationVolume, referenceParameters, direction ); - - // Bail to direct extrapolation if the direction cannot be determined - if ( direction == Trk::anyDirection ) - return extrapolateDirectly( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); - - const Trk::TrackParameters* combinedState = multiComponentState.begin()->first; - - const Trk::MultiComponentState* currentState = &multiComponentState; - - /* Define the initial distance between destination and current position. Destination should be determined from either - - reference parameters (prefered if they exist) or - - destination surface - */ - - Amg::Vector3D globalSeparation = referenceParameters ? referenceParameters->position() - combinedState->position() : surface.globalReferencePoint() - combinedState->position(); - double initialDistance = globalSeparation.mag(); - if (referenceParameters) printState("Intial Ref Parameters at next surface ", *referenceParameters); - else ATH_MSG_DEBUG( "No reference parameters?? Gobal sep (r,z): (" <<globalSeparation.perp() << ",\t" <<globalSeparation.z() <<")" ); - - - // =============== - // Debug print-out - // =============== - if (msgLvl(MSG::DEBUG)){ - ATH_MSG_VERBOSE( "extrapolate() with configuration ++++++++++++++++++++++++++++++++++++++++++++" ); - ATH_MSG_VERBOSE( " -> Combined state: " << *combinedState ); - ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); - ATH_MSG_VERBOSE( " -> Destination surface: " << surface ); - ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); - ATH_MSG_VERBOSE( " -> Starting volume from navigator: " << startVolume->volumeName() ); - ATH_MSG_VERBOSE( " -> Destination volume from navigator: " << destinationVolume->volumeName() ); - ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); - ATH_MSG_VERBOSE( " -> Configuration (direction/boundaryCheck/particleHypothesis): " << direction << " / " << boundaryCheck << " / " << particleHypothesis ); - ATH_MSG_VERBOSE( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" ); - } - - ATH_MSG_DEBUG( "Running extrapolation direction " << direction << " from: " - << startVolume->volumeName() << " to " << destinationVolume->volumeName() << " and surface centre (" - << surface.center().x() << ", " << surface.center().y() << ", " << surface.center().z() << ")" ); - - this->printState( "Extrapolation starting with", *combinedState ); - - // Clean up memory from combiner. It is no longer needed - combinedState = 0; - - /* There are two parts to the extrapolation: - - Extrapolate from start point to volume boundary - - Extrapolate from volume boundary to destination surface - */ - - const Trk::IPropagator* currentPropagator = 0; - - /* ================================================================= - Extrapolation to destination volume boundary - ================================================================= */ - - bool foundFinalBoundary(true); - - int fallbackOscillationCounter(0); - - const Trk::TrackingVolume* currentVolume = startVolume; - const Trk::TrackingVolume* previousVolume = 0; - - while ( currentVolume && currentVolume != destinationVolume && currentState ){ - - // Configure propagator based on the current tracking volume - currentPropagator = m_propagatorStickyConfiguration ? &propagator : &(*m_propagators[ this->propagatorType( *currentVolume ) ]); - - if (referenceParameters) printState("Old Ref Parameters at next surface ", *referenceParameters); - - // Extrapolate to volume boundary - extrapolateToVolumeBoundary( *currentPropagator, - *currentState, - associatedLayer, - *currentVolume, - direction, - particleHypothesis ); - - // New current state is the state extrapolated to the tracking volume boundary. - currentState = m_stateAtBoundarySurface.stateAtBoundary; - - // The volume that the extrapolation is about to enter into is called the nextVolume - const Trk::TrackingVolume* nextVolume = m_stateAtBoundarySurface.trackingVolume; - - // Break the loop if the next tracking volume is the same as the current one - if ( !nextVolume || nextVolume == currentVolume ){ - ATH_MSG_DEBUG( "Navigation break: No next volume found" ); - ++m_missedVolumeBoundary; - foundFinalBoundary = false; - break; - } - - // New reference parameters are the navigation parameters at the boundary surface - referenceParameters = m_stateAtBoundarySurface.navigationParameters; - //coverity 111522: null check is redundant here since referenceParameters is dereferenced later anyway. - //if (referenceParameters) printState("New Ref Parameters at next surface ", *referenceParameters); - printState("New Ref Parameters at next surface ", *referenceParameters); - - // Break the lop if an oscillation is detected - if ( previousVolume == nextVolume ) - ++fallbackOscillationCounter; - - if ( fallbackOscillationCounter > 10 ){ - ATH_MSG_DEBUG( "Navigation break: Oscillation" ); - ++m_oscillationBreaks; - foundFinalBoundary = false; - break; - } - - // Break the loop if the distance between the surface and the track parameters has increased - combinedState = currentState->begin()->first; - - const TrackParameters* parametersAtDestination = currentPropagator->propagateParameters( *combinedState, surface, direction, false, m_fieldProperties, Trk::electron ); - Amg::Vector3D newDestination; - if (parametersAtDestination){ - printState("Parameters at next surface ", *parametersAtDestination); - newDestination = parametersAtDestination->position(); - delete parametersAtDestination; - } else { - ATH_MSG_DEBUG( "Distance check propagation Failed. Using surface center" ); - newDestination = surface.center(); - } - - double revisedDistance = ( referenceParameters->position() - newDestination ).mag(); - - double distanceChange = fabs( revisedDistance - initialDistance ); - - if ( revisedDistance > initialDistance && distanceChange > 0.01 ){ - ATH_MSG_DEBUG( "Navigation break. Initial separation: " << initialDistance << " Current Sepatation: " << revisedDistance ); - ATH_MSG_DEBUG( ".... Volume " << nextVolume->volumeName()<< " from " <<currentVolume->volumeName() ); - foundFinalBoundary = false; - ++m_navigationDistanceIncreaseBreaks; - break; - } - - combinedState = 0; - - ATH_MSG_DEBUG( "Switching tracking volume look for Material: " << nextVolume->volumeName() ); - - // Initialise the oscillation checker - previousVolume = currentVolume; - - // As the extrapolation is moving into the next volume, the next volume -> current volume - currentVolume = nextVolume; - - // Associated layer now needs to be reset - //if(!entryLayerFound) - associatedLayer = 0; - - } // end while loop - - // Look to catch failures now - if ( !currentState ){ - ATH_MSG_DEBUG( "No current state at boundary... Falling back to original state" ); - currentState = &multiComponentState; - foundFinalBoundary = false; - } - - if ( currentVolume != destinationVolume ){ - ATH_MSG_DEBUG( "Trk::GsfExtrapolator::extrapolate failed to reach destination volume... " ); - currentState = &multiComponentState; - foundFinalBoundary = false; - } - - if ( !foundFinalBoundary ){ - ATH_MSG_DEBUG( "Could not find final boundary switch to direct EXTRAPOLATION" ); - -/* const Trk::MultiComponentState* bailOutState = extrapolateDirectly( propagator, - *currentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); -*/ - - const Trk::MultiComponentState* bailOutState = multiStatePropagate( propagator, - *currentState, - surface, - Trk::anyDirection, - boundaryCheck, - particleHypothesis ); - - if ( !bailOutState ){ - ATH_MSG_DEBUG( "Fallback to propagation failed... Returning 0" ); - return 0; - } - - emptyGarbageBins(); - - return bailOutState; - - } - - // =============== - // Debug print-out - // =============== - - if (msgLvl(MSG::DEBUG)){ - combinedState = m_stateCombiner->combine( *currentState ); - - if ( !combinedState ){ - ATH_MSG_ERROR( "State combination failed... exiting" ); - return 0; - } - - this->printState( "Reached final volume boundary " + currentVolume->volumeName() + " with", *combinedState ); - - delete combinedState; - combinedState = 0; - } - - /* ================================================================= - Extrapolation from volume boundary to surface - ================================================================= */ - - // Configure propagator based on the current tracking volume - currentPropagator = m_propagatorStickyConfiguration ? &propagator : &(*m_propagators[ this->propagatorType( *currentVolume ) ]); - - // extrapolate inside destination volume - const Trk::MultiComponentState* destinationState = extrapolateInsideVolume( *currentPropagator, - *currentState, - surface, - associatedLayer, - *currentVolume, - direction, - boundaryCheck, - particleHypothesis ); - - // FALLBACK POINT: Crisis if extrapolation fails here... As per extrapolation to volume boundary, in emergency revert to extrapolateDirectly - if ( destinationState == currentState ){ - destinationState = 0; - } - - - if ( destinationState && &((*(destinationState->begin())).first->associatedSurface()) != &surface ){ - ATH_MSG_DEBUG( "Failed to reach destination surface ... reached some other surface"); - if( destinationState != currentState) - delete destinationState; - destinationState = 0; - } - - if ( !destinationState ){ - - ATH_MSG_DEBUG( "extrapolateInsideVolume() failed... falling back to direct propagation" ); - - destinationState = multiStatePropagate( propagator, - *currentState, - surface, - Trk::anyDirection, - boundaryCheck, - particleHypothesis ); - - // statistics - ++m_extrapolateDirectlyFallbacks; - - } - - emptyGarbageBins(); - - if ( !destinationState ){ - ATH_MSG_DEBUG( "Extrapolation inside volume failed... returning 0" ); - return 0; - } - - // =============== - // Debug print-out - // =============== - if (msgLvl(MSG::DEBUG)){ - - combinedState = m_stateCombiner->combine( *destinationState ); - - if ( !combinedState ){ - ATH_MSG_ERROR( "State combination failed... exiting" ); - return 0; - } - - this->printState( "Extrapolation completed with", *combinedState ); - ATH_MSG_DEBUG( "With "<< destinationState->size() << " components" ); - ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); - - delete combinedState; - combinedState = 0; - } - // =============================================== - // After successful extrapolation return the state - // =============================================== - - return destinationState; - -} - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateDirectly( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolateDirectly() in non-configured mode: " <<multiComponentState.size() ); - - // statistics - ++m_extrapolateDirectlyCalls; - - resetRecallInformation(); - - const Trk::TrackingVolume* currentVolume = m_navigator->highestVolume(); - - if ( !currentVolume ){ - ATH_MSG_WARNING( "Current tracking volume could not be determined... returning 0" ); - return 0; - } - - // Propagate all components - const Trk::MultiComponentState* returnState = multiStatePropagate( propagator, - multiComponentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - - if ( !returnState ){ - ATH_MSG_DEBUG( "Trk::GsfExtrapolator::extrapolateDirectly() failed... returning 0" ); - return 0; - } - - return returnState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - Configured AlgTool methods - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* -Trk::GsfExtrapolator::extrapolate( const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolate() in configured mode" ); - - if ( multiComponentState.empty() ){ - ATH_MSG_DEBUG( "MultiComponentState is empty... returning 0" ); - return 0; - } - - if (m_propagatorConfigurationLevel < 10){ - - // Set the propagator to that one corresponding to the configuration level - const Trk::IPropagator* currentPropagator = &(*m_propagators[m_propagatorConfigurationLevel]); - - const Trk::MultiComponentState* extrapolatedState = this->extrapolate( *currentPropagator, - multiComponentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - - return extrapolatedState; - - } - - ATH_MSG_ERROR( "No default propagator is selected in 'extrapolate'. Check job options!" ); - return 0; - -} - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateDirectly( const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolateDirectly() in configured mode" ); - - if (m_propagatorConfigurationLevel < 10){ - - // Set the propagator to that one corresponding to the configuration level - const Trk::IPropagator* currentPropagator = &(*m_propagators[m_propagatorConfigurationLevel]); - - if ( !currentPropagator) { - ATH_MSG_ERROR( "No current propagator is defined... Exiting" ); - return 0; - } - - return this->extrapolateDirectly( *currentPropagator, - multiComponentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - } - - ATH_MSG_ERROR( "No default propagator is selected in 'extrapolateDirectly'. Check job options!" ); - - return 0; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate to Volume Boundary! - - ========================================================================================================================================= - ========================================================================================================================================= */ - -void Trk::GsfExtrapolator::extrapolateToVolumeBoundary ( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Layer* layer, - const Trk::TrackingVolume& trackingVolume, - Trk::PropDirection direction, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_DEBUG( "GSF extrapolateToVolumeBoundary() to tracking volume: " << trackingVolume.volumeName() ); - - // Start the timer - //Chrono chrono( &(*m_chronoSvc), "extrapolateToVolumeBoundary()" ); - - // MultiComponentState propagation and material effects - const Trk::MultiComponentState* currentState = &multiComponentState; - - // Determine the current layer - the state combiner is required - - if(!currentState){ - ATH_MSG_WARNING( "extrapolateToVolumeBoundary: Trying to extrapolate nothing?? - return" ); - return; - } - - const Trk::TrackParameters* combinedState = currentState->begin()->first; //m_stateCombiner->combine( multiComponentState ); - - const Trk::Layer* associatedLayer = layer; - - if ( !associatedLayer ) - { - ATH_MSG_DEBUG( "No associated layer passed with volume.... lets get one" ); - // Get entry layer but do not use it as it should have already be hit if it was desired - associatedLayer = trackingVolume.associatedLayer( combinedState->position() ); - associatedLayer = associatedLayer ? associatedLayer : trackingVolume.nextLayer( combinedState->position(), direction * combinedState->momentum().unit(), associatedLayer ); - - ATH_MSG_DEBUG( "Found layer in Volume " << layerRZoutput(associatedLayer) ); - - } - // Only loop over layers if they can be found within the tracking volume - else if ( trackingVolume.confinedLayers() && associatedLayer->layerMaterialProperties() ) - { - //const TrackParameters* paranetersAtDestination = currentPropagator->propagateParameters( *combinedState, associatedLayer->surfaceRepresentation(), direction, false, trackingVolume ); - //if(paranetersAtDestination) - - const Trk::MultiComponentState* updatedState = m_materialUpdator->postUpdate( *currentState, - *layer, - direction, - particleHypothesis ); - - // Memory clean-up - if ( updatedState && updatedState != currentState && currentState != &multiComponentState ) - delete currentState; - - // Refresh updated state pointer - updatedState = updatedState ? updatedState : currentState; - - if (updatedState != currentState ) - addMaterialtoVector( layer, currentState->begin()->first ); - - //---------------------------------------- - // Component reduction - //---------------------------------------- - - const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState); - - // Memory clean-up - if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) - delete updatedState; - - // Refresh current state pointer - currentState = reducedState ? reducedState : updatedState; - - - } - - // Clean up memory used by the combiner - combinedState = 0; - - const Trk::MultiComponentState* nextState = 0; - - // If an associated surface can be found, extrapolation within the tracking volume is mandatory - // This will take extrapolate to the last layer in the volume - if ( associatedLayer ){ - nextState = extrapolateFromLayerToLayer( propagator, - *currentState, - trackingVolume, - associatedLayer, - 0, - direction, - particleHypothesis ); - - // Make sure reduced state is added to the list of garbage to be collected - if ( nextState && nextState != currentState && currentState != &multiComponentState ) - delete currentState; - - // Refresh the current state pointer - currentState = nextState ? nextState : currentState; - - } - - - - - /* ============================================= - Find the boundary surface using the navigator - ============================================= */ - - Trk::NavigationCell nextNavigationCell(0,0); - - combinedState = currentState->begin()->first->clone(); //m_stateCombiner->combine( *currentState ); - - const Trk::TrackingVolume* nextVolume = 0; - const Trk::TrackParameters* navigationParameters = m_stateAtBoundarySurface.navigationParameters ? m_stateAtBoundarySurface.navigationParameters : combinedState; - - unsigned int navigationPropagatorIndex = 0; - - if ( m_propagatorConfigurationLevel < 10 ) { - - // Not the default - while ( navigationPropagatorIndex <= m_propagatorConfigurationLevel ) { - - const Trk::IPropagator* navigationPropagator = &(*m_propagators[navigationPropagatorIndex]); - - if ( !navigationPropagator ){ - ATH_MSG_WARNING( "Navigation propagator cannot be retrieved... Continuing" ); - continue; - } - - nextNavigationCell = m_navigator->nextTrackingVolume( *navigationPropagator, *navigationParameters, direction, trackingVolume ); - nextVolume = nextNavigationCell.nextVolume; - if (navigationPropagatorIndex >= 1) - delete navigationParameters; - navigationParameters = nextNavigationCell.parametersOnBoundary; - - ++navigationPropagatorIndex; - - // If the next tracking volume is found then no need to continue looping - if ( nextVolume ) break; - - } - - } - - else { - - // The Default - nextNavigationCell = m_navigator->nextTrackingVolume( propagator, *navigationParameters, direction, trackingVolume ); - nextVolume = nextNavigationCell.nextVolume; - navigationParameters = nextNavigationCell.parametersOnBoundary; - - } - - // Clean up memory allocated by the combiner - if ( navigationParameters != combinedState ) - delete combinedState; - - if ( !nextVolume ){ - ATH_MSG_DEBUG( "Cannot find next TrackingVolume from initial tracking volume: " << trackingVolume.volumeName() ); - - // Reset the layer recall - resetRecallInformation(); - - } - - // !< TODO check the material on the boundary - if (useBoundaryMaterialUpdate) { - - //Check for two things: - // 1. If the next volume was found - // 2. If there is material associated with the boundary layer. - // If so, apply material effects update. - - //Get layer associated with boundary surface. - const Trk::TrackParameters *paramsAtBoundary = nextNavigationCell.parametersOnBoundary; - const Trk::Layer *layerAtBoundary = (paramsAtBoundary) ? (paramsAtBoundary->associatedSurface()).materialLayer() : 0; - const Trk::TrackParameters *matUpdatedParameters = 0; - const Trk::MultiComponentState *matUpdatedState = 0; - - if (nextVolume && layerAtBoundary) { - - if (layerAtBoundary->layerMaterialProperties()) { - ATH_MSG_DEBUG( "Boundary surface has material - updating properties" ); - assert (currentState); - matUpdatedState = m_materialUpdator->postUpdate(*currentState, - *layerAtBoundary, - direction, - particleHypothesis ); - } - } - - //If state has changed due to boundary material, modify state, parameters accordingly. - if ( matUpdatedState && matUpdatedState != currentState ) { - - ATH_MSG_DEBUG( "Performing state update" ); - - //Clean out memory, update state. - delete currentState; - currentState = matUpdatedState; - - //Update navigation parameters (?). - matUpdatedParameters = currentState->begin()->first->clone(); - if (matUpdatedParameters != navigationParameters) { - delete navigationParameters; - navigationParameters = matUpdatedParameters; - } - - //Add to material vector. - addMaterialtoVector(layerAtBoundary, currentState->begin()->first ); - - } - } - - // Update the boundary information - m_stateAtBoundarySurface.updateBoundaryInformation( currentState, navigationParameters, nextVolume ); - - // Make sure navigation parameters and current state are added to the list of garbage to be collected - throwIntoGarbageBin( navigationParameters ); - if ( currentState != &multiComponentState ) throwIntoGarbageBin( currentState ); - - if (msgLvl(MSG::DEBUG)){ - combinedState = m_stateCombiner->combine( *currentState ); - - printState( "State at boundary surface", *combinedState ); - - delete combinedState; - } - - return; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate inside volume to destination surface! - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateInsideVolume ( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - const Trk::Layer* layer, - const Trk::TrackingVolume& trackingVolume, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_DEBUG( "GSF extrapolateInsideVolume() in tracking volume: " << trackingVolume.volumeName() ); - - // Start the timer - //Chrono chrono( &(*m_chronoSvc), "extrapolateInsideVolume()" ); - - const Trk::MultiComponentState* currentState = &multiComponentState; - - /* ================================================== - Retrieve the destination layer - ================================================== */ - - // 1. Association - const Trk::Layer* destinationLayer = surface.associatedLayer(); - - // 2. Recall and Global Search - if ( !destinationLayer ){ - ATH_MSG_DEBUG( "No associated later to surface" ); - destinationLayer = ( &surface == m_recallSurface ) ? m_recallLayer : trackingVolume.associatedLayer( surface.globalReferencePoint() ); - } - // If there is still no destination layer, flag a warning - if ( !destinationLayer ) - ATH_MSG_DEBUG( "No destination layer could be found inside tracking volume: " << trackingVolume.volumeName() ); - - - ATH_MSG_DEBUG( "Current layer " << layerRZoutput(layer) ); - ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); - - - /* ================================================== - Retrieve the current layer - ================================================== */ - - // Produce a combined state - const Trk::TrackParameters* combinedState = currentState->begin()->first; - - const Trk::Layer* associatedLayer = layer; - - if ( !associatedLayer ){ - - - ATH_MSG_DEBUG( "No assoicated layer passed with volume.... lets get one" ); - // Get entry layer but do not use it as it should have already be hit if it was desired - associatedLayer = trackingVolume.associatedLayer( combinedState->position() ); - associatedLayer = associatedLayer ? associatedLayer : trackingVolume.nextLayer( combinedState->position(), direction * combinedState->momentum().unit(), associatedLayer ); - - - ATH_MSG_DEBUG( "Found layer in Volume " << layerRZoutput(associatedLayer) ); - - } - - else if ( associatedLayer != destinationLayer && trackingVolume.confinedLayers() && associatedLayer->layerMaterialProperties() ){ - - const Trk::MultiComponentState* updatedState = m_materialUpdator->postUpdate( *currentState, - *associatedLayer, - direction, - particleHypothesis ); - - // Memory clean-up - if ( updatedState && updatedState != currentState && currentState != &multiComponentState ) - delete currentState; - - // Refresh the updated state pointer - updatedState = updatedState ? updatedState : currentState; - - - if(updatedState != currentState ) - addMaterialtoVector( associatedLayer, currentState->begin()->first ); - - /* ---------------------------------------- - Component reduction - ---------------------------------------- */ - - const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState ); - - // Memory clean-up - if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) - delete updatedState; - - // Refresh the current state pointer - currentState = reducedState ? reducedState : updatedState; - - } - - // Memory clean-up - combinedState = 0; - - if ( destinationLayer ){ - - // If there are intermediate layers then additional extrapolations need to be done - if ( associatedLayer && associatedLayer != destinationLayer ){ - - const Trk::MultiComponentState* nextState = extrapolateFromLayerToLayer( propagator, - *currentState, - trackingVolume, - associatedLayer, - destinationLayer, - direction, - particleHypothesis ); - - // Memory clean-up - if ( nextState && nextState != currentState && currentState != &multiComponentState ) - delete currentState; - - // Refresh the current state pointer - currentState = nextState ? nextState : currentState; - - } - - // Final extrapolation to destination surface - const Trk::MultiComponentState* returnState = extrapolateToDestinationLayer( propagator, - *currentState, - surface, - *destinationLayer, - //trackingVolume, - associatedLayer, - direction, - boundaryCheck, - particleHypothesis ); - - // Memory clean-up - if ( returnState && returnState != currentState && currentState != &multiComponentState ) - delete currentState; - - returnState = returnState ? returnState : currentState; - - // Set the information for the current layer, surface, tracking volume - setRecallInformation( surface, *destinationLayer, trackingVolume ); - - ATH_MSG_VERBOSE( "Successfully extrapolated inside volume " << returnState->size() ); - - return returnState; - - } - - // FALLBACK POINT: If no destination layer is found fall-back and extrapolate directly - ATH_MSG_DEBUG( "extrapolateInsideVolume() could not find the destination layer... propagating directly to surface" ); - - const Trk::MultiComponentState* returnState = multiStatePropagate( propagator, - *currentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - - // Memory clean-up - if ( returnState && returnState != currentState && currentState != &multiComponentState ) - delete currentState; - - // No destination layer exists so layer recall method cannot be used and should be reset - resetRecallInformation(); - - return returnState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate from Layer to Layer - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateFromLayerToLayer( const IPropagator& propagator, - const MultiComponentState& multiComponentState, - const TrackingVolume& trackingVolume, - const Layer* startLayer, - const Layer* destinationLayer, - PropDirection direction, - ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_DEBUG( "Starting extrapolateFromLayerToLayer()" ); - - - const Trk::Layer* currentLayer = startLayer; - const Trk::MultiComponentState* currentState = &multiComponentState; - - // Find the combined state to find the next layer - if (!currentState){ - ATH_MSG_WARNING( "extrapolateFromLayerToLayer: Trying to extrapolate nothing?? - return" ); - return 0; - } - const Trk::TrackParameters* combinedState = currentState->begin()->first; - - // No need to extrapolate to start layer, find the next one - const Trk::Layer* nextLayer = currentLayer->nextLayer( combinedState->position(), direction * combinedState->momentum().unit() ); - - ATH_MSG_DEBUG( "Current layer " << layerRZoutput(startLayer) ); - ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); - ATH_MSG_DEBUG( "Next layer " << layerRZoutput(nextLayer) ); - - // Clean up memory - combinedState =0; - - // Begin while loop over all intermediate layers - while ( nextLayer && nextLayer != destinationLayer ){ - ATH_MSG_DEBUG( "NextLayer, walking next step." ); - - const Trk::MultiComponentState* nextState = 0; - - // Only extrapolate to an intermediate layer if it requires material update... otherwise step over it - if ( nextLayer && nextLayer->layerMaterialProperties() ){ - ATH_MSG_DEBUG( "NextLayer, has material extrapolate to it" ); - - nextState = extrapolateToIntermediateLayer( propagator, - *currentState, - *nextLayer, - trackingVolume, - direction, - particleHypothesis ); - - // Memory clean-up - if ( nextState && nextState != currentState && currentState != &multiComponentState ) - delete currentState; - - // Refresh current state pointer - currentState = nextState ? nextState : currentState; - - } - - // Find the next layer - combinedState = currentState->begin()->first; //m_stateCombiner->combine( *currentState ); - - currentLayer = nextLayer; - nextLayer = currentLayer->nextLayer( combinedState->position(), direction * combinedState->momentum().unit() ); - } - - if (destinationLayer && nextLayer != destinationLayer && currentState != &multiComponentState){ - ATH_MSG_DEBUG( "extrapolateFromLayerToLayer failed to reach destination layer.. return 0" ); - ATH_MSG_DEBUG( "Current layer " << layerRZoutput(currentLayer) ); - ATH_MSG_DEBUG( "NextLayer layer " << layerRZoutput(nextLayer) ); - ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); - delete currentState; - currentState = 0; - } - - return currentState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate to Intermediate Layer - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateToIntermediateLayer( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Layer& layer, - const Trk::TrackingVolume& trackingVolume, - Trk::PropDirection direction, - Trk::ParticleHypothesis particleHypothesis, - bool doPerpCheck ) const -{ - - const Trk::TrackParameters* combinedState = 0; - if (msgLvl(MSG::DEBUG)){ - combinedState = m_stateCombiner->combine( multiComponentState ); - - ATH_MSG_VERBOSE( "GSF extrapolateToIntermediateLayer()" ); - ATH_MSG_VERBOSE( "Starting track parameters (combined state): " << *combinedState ); - ATH_MSG_VERBOSE( "Destination layer (surface representation): " << layer.surfaceRepresentation() ); - - ATH_MSG_VERBOSE( "-----------------------------------------------------------------------------------------------------------" ); - - delete combinedState; - } - - printState( "extrapolateToIntermediateLayer(). Starting with ", *(multiComponentState.begin()->first) ); - - - const Trk::Surface* startSurface = &(multiComponentState.begin()->first->associatedSurface()); - if (startSurface){ - const Trk::Layer* startLayer = startSurface->associatedLayer(); - ATH_MSG_DEBUG( "Starting Layer: " << layerRZoutput(startLayer) ); - } else { - ATH_MSG_DEBUG( "Initial parameters have no surafce associated to them" ); - } - ATH_MSG_DEBUG( "Destination Layer: " << layerRZoutput(&layer) ); - - - const Trk::MultiComponentState* initialState = &multiComponentState; - - // Propagate over all components - const Trk::MultiComponentState* destinationState = multiStatePropagate( propagator, - *initialState, - layer.surfaceRepresentation(), - direction, - true, - particleHypothesis ); - - if ( !destinationState ){ - ATH_MSG_DEBUG( "Multi-state propagation failed... Returning 0!" ); - ATH_MSG_VERBOSE( "Failed to reach layer" << layer.surfaceRepresentation() ); - return 0; - } - - // the layer has been intersected ------------------------------------------------------------------------ - // check for radial direction change --------------------------------------------------------------------- - int rDirection = radialDirection(multiComponentState,direction); - int newrDirection = radialDirection(*destinationState,direction); - if (newrDirection != rDirection && doPerpCheck){ - // it is unfortunate that the cancelling could invalidate the material collection - ATH_MSG_DEBUG( " [!] Perpendicular direction of track has changed -- checking" ); - // reset the nextParameters if the radial change is not allowed - // resetting is ok - since the parameters are in the garbage bin already - if (!radialDirectionCheck(propagator, multiComponentState, *destinationState,trackingVolume,direction,particleHypothesis)){ - ATH_MSG_DEBUG( " [+] Perpendicular direction check cancelled this layer intersection." ); - delete destinationState; - return 0; - } - } - - - if ( destinationState != initialState && initialState != &multiComponentState ) - delete initialState; - - if (msgLvl(MSG::DEBUG)){ - combinedState = m_stateCombiner->combine( *destinationState ); - - this->printState( "Propagation to intermediate completed with", *combinedState ); - - delete combinedState; - } - /* ------------------------------------- - Material effects - ------------------------------------- */ - - const Trk::MultiComponentState* updatedState = 0; - - - - updatedState = m_materialUpdator->update( *destinationState, layer, direction, particleHypothesis ); - - // Memory clean-up - if ( updatedState && updatedState != destinationState && destinationState != &multiComponentState ) - delete destinationState; - - updatedState = updatedState ? updatedState : destinationState; - - if(updatedState!=destinationState) - addMaterialtoVector( &layer, updatedState->begin()->first, direction, particleHypothesis ); - - - /* ------------------------------------- - Component reduction - ------------------------------------- */ - - const Trk::MultiComponentState* reducedState = m_merger->merge( *updatedState ); - - if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) - delete updatedState; - - reducedState = reducedState ? reducedState : updatedState; - - - - if (msgLvl(MSG::DEBUG)){ - - combinedState = m_stateCombiner->combine( *reducedState ); - - this->printState( "Material update at intermediate completed with", *combinedState ); - ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); - - delete combinedState; - } - - return reducedState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate to Destination Layer - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateToDestinationLayer ( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - const Trk::Layer& layer, - //const Trk::TrackingVolume& trackingVolume, - const Trk::Layer* startLayer, - Trk::PropDirection direction, - Trk::BoundaryCheck boundaryCheck, - Trk::ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolateToDestinationLayer()" ); - - const Trk::MultiComponentState* initialState = &multiComponentState; - - const Trk::TrackParameters* combinedState = 0; - - if (msgLvl(MSG::DEBUG)){ - - combinedState = m_stateCombiner->combine( *initialState ); - - ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); - this->printState( "Starting extrapolation to destination with", *combinedState ); - - delete combinedState; - } - - // Propagate over all components - const Trk::MultiComponentState* destinationState = multiStatePropagate( propagator, - multiComponentState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - - // Require a fall-back if the initial state is close to the destination surface then a fall-back solution is required - - if ( !destinationState ){ - - combinedState = initialState->begin()->first; - - if ( surface.isOnSurface( combinedState->position(), true, 0.5 * layer.thickness() ) ){ - - ATH_MSG_DEBUG( "Initiating fall-back from failed propagation" ); - - destinationState = multiStatePropagate( propagator, - *initialState, - surface, - Trk::anyDirection, - boundaryCheck, - particleHypothesis ); - - } - - // Memory clean-up - combinedState = 0; - - if ( !destinationState ){ - ATH_MSG_DEBUG( "Propagated state is empty... returning 0" ); - return 0; - } - - } - - ATH_MSG_VERBOSE( "DestinationState state has " << destinationState->size() << " components " ); - - - if (msgLvl(MSG::DEBUG)){ - - combinedState = m_stateCombiner->combine( *destinationState ); - - this->printState( "Propagation to destination completed with", *combinedState ); - - delete combinedState; - - } - - /* ---------------------------------------- - Material effects - ---------------------------------------- */ - - //std::cout << "CALLING PREUPDATE " <<std::endl; - - const Trk::MultiComponentState* updatedState = ( startLayer != &layer ) ? m_materialUpdator->preUpdate( *destinationState, - layer, - direction, - particleHypothesis ) : destinationState; - - if ( updatedState && updatedState != destinationState && destinationState != &multiComponentState ) - delete destinationState; - - updatedState = updatedState ? updatedState : destinationState; - - ATH_MSG_VERBOSE( "Updated state has " << updatedState->size() << " components " ); - - - if(updatedState != destinationState) - addMaterialtoVector( &layer, updatedState->begin()->first, direction, particleHypothesis ); - - /* ---------------------------------------- - Component reduction - ---------------------------------------- */ - - const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState); - - if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) - delete updatedState; - - reducedState = reducedState ? reducedState : updatedState; - - ATH_MSG_VERBOSE( "Reduced state has " << reducedState->size() << " components " ); - - - - if (msgLvl(MSG::DEBUG)){ - ATH_MSG_VERBOSE( "Successfully completed extrapolation to destination: " ); - - combinedState = m_stateCombiner->combine( *reducedState ); - - this->printState( "Material update at destination completed with", *combinedState ); - ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); - - delete combinedState; - } - - return reducedState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate based on material on active surfaces - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateSurfaceBasedMaterialEffects ( const IPropagator& propagator, - const MultiComponentState& multiComponentState, - const Surface& surface, - PropDirection direction, - BoundaryCheck boundaryCheck, - ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_VERBOSE( "GSF extrapolateSurfaceBasedMaterialEffects()" ); - - /* ------------------------------------- - Preliminary checks - ------------------------------------- */ - - // Check the multi-component state is populated - if ( multiComponentState.empty() ){ - ATH_MSG_WARNING( "Multi component state passed to extrapolateInsideVolume is not populated... returning 0" ); - return 0; - } - - //const Trk::TrackingVolume* currentVolume = m_navigator->highestVolume(); - - const Trk::MultiComponentState* lastState = &multiComponentState; - const Trk::MultiComponentState* nextState = 0; - - // Propagate over all components - nextState = multiStatePropagate( propagator, - *lastState, - surface, - direction, - boundaryCheck, - particleHypothesis ); - - - // Clean up memory after the propagation. Reset pointers - if ( lastState != &multiComponentState && lastState != nextState ) - delete lastState; - - if ( !nextState ){ - ATH_MSG_DEBUG( "Propagated state is empty... returning 0" ); - return 0; - } - - /* ---------------------------------------- - Material effects - ---------------------------------------- */ - - lastState = nextState; - nextState = 0; - - nextState = m_materialUpdator->simpliedMaterialUpdate( *lastState, direction, particleHypothesis ); - - if ( nextState != lastState && lastState != &multiComponentState ) - delete lastState; - - /* ---------------------------------------- - Component reduction - ---------------------------------------- */ - - lastState = nextState; - nextState = 0; - - nextState = m_merger->merge(*lastState); - - if ( lastState != nextState && lastState != &multiComponentState ) - delete lastState; - - return nextState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Multi-component state propagate - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const Trk::MultiComponentState* Trk::GsfExtrapolator::multiStatePropagate ( const IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Surface& surface, - PropDirection direction, - BoundaryCheck boundaryCheck, - ParticleHypothesis particleHypothesis ) const -{ - - ATH_MSG_DEBUG( "GSF multiStatePropagate() propagating " << multiComponentState.size() << " components\n" << - "\t\t\t\t\t...Propagating to surface [r,z] [" << surface.center().perp() << ",\t" << surface.center().z() << ']' ); - const Trk::Layer* layer = surface.associatedLayer(); - ATH_MSG_DEBUG( "...associated layer to surface " << layerRZoutput(layer) ); - - - // Start the timer - //Chrono chrono( &(*m_chronoSvc), "multiStatePropagate()" ); - - Trk::MultiComponentState* propagatedState = new Trk::MultiComponentState(); - - Trk::MultiComponentState::const_iterator component = multiComponentState.begin(); - - double sumw(0); //HACK variable to avoid propagation errors - for ( ; component != multiComponentState.end(); ++component ){ - - const Trk::TrackParameters* currentParameters = component->first; - const Trk::TrackParameters* propagatedParameters = 0; - - if ( !currentParameters ){ - ATH_MSG_DEBUG( "Component parameters not defined... component will not be propagated... continuing" ); - continue; - } - - propagatedParameters = propagator.propagate( *currentParameters, surface, direction, boundaryCheck, m_fieldProperties, particleHypothesis ); - - if ( !propagatedParameters ){ - ATH_MSG_DEBUG( "Propagation of component failed... continuing" ); - continue; - } - - sumw+=component->second; - // Propagation does not affect the weightings of the states - const Trk::ComponentParameters propagatedComponent( propagatedParameters, component->second ); - propagatedState->push_back( propagatedComponent ); - - } - - ATH_MSG_DEBUG( "GSF multiStatePropagate() propagated " << propagatedState->size() << "components" ); - - // Protect against empty propagation - if ( propagatedState->empty() || sumw<0.1 ){ - ATH_MSG_DEBUG( "multiStatePropagate failed... returning 0" ); - delete propagatedState; - return 0; - } - - return propagatedState; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - PropagatorType - - ========================================================================================================================================= - ========================================================================================================================================= */ - -unsigned int Trk::GsfExtrapolator::propagatorType ( const Trk::TrackingVolume& trackingVolume ) const -{ - if (m_propagatorStickyConfiguration) { - if (m_propagators.size()>m_propagatorConfigurationLevel) return m_propagatorConfigurationLevel; - ATH_MSG_WARNING( "Misconfigured propagator type, set to "<<m_propagatorConfigurationLevel<<"->0" ); - return 0; - } - - // Determine what sort of magnetic field is present - unsigned int magneticFieldMode = m_fieldProperties.magneticFieldMode(); - - // Chose between runge-kutta and step propagators depending on field magnetic field and material properties - // ST : the following check may fail as the dEdX is often dummy for dense volumes - switch to rho or zOverAtimesRho ? - unsigned int propagatorMode = ( magneticFieldMode > 1 && fabs( trackingVolume.dEdX ) < 10e-2 ) ? 2 : 3; - - unsigned int returnType = (propagatorMode > m_propagatorConfigurationLevel) ? m_propagatorConfigurationLevel : propagatorMode; - - if ( m_propagators.size()> returnType ) return returnType; - ATH_MSG_WARNING( "Misconfigured propagator type, set to "<< returnType <<"->0" ); - return 0; -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Initialise Navigation - - ========================================================================================================================================= - ========================================================================================================================================= */ - -void Trk::GsfExtrapolator::initialiseNavigation ( const Trk::IPropagator& propagator, - const Trk::MultiComponentState& multiComponentState, - const Trk::Surface& surface, - const Trk::Layer*& currentLayer, - const Trk::TrackingVolume*& currentVolume, - const Trk::TrackingVolume*& destinationVolume, - const Trk::TrackParameters*& referenceParameters, - Trk::PropDirection direction ) const -{ - - // Start the timer - //Chrono chrono( &(*m_chronoSvc), "initialiseNavigation()" ); - ATH_MSG_DEBUG( "initialiseNavigation !!!" ); - // Empty the garbage bin - emptyGarbageBins(); - ATH_MSG_DEBUG( "Destination to surface [r,z] [" << surface.center().perp() << ",\t" << surface.center().z() << ']' ); - - - const Trk::TrackParameters* combinedState = multiComponentState.begin()->first; //m_stateCombiner->combine( multiComponentState ); - - /* ============================================= - Look for current volume - ============================================= */ - - // 1. See if the current layer is associated with a tracking volume - - const Trk::Surface* associatedSurface = &(combinedState->associatedSurface()); - - currentLayer = associatedSurface ? associatedSurface->associatedLayer() : currentLayer; - currentVolume = currentLayer ? currentLayer->enclosingTrackingVolume() : currentVolume; - - // If the association method failed then try the recall method - - if ( !currentVolume && associatedSurface == m_recallSurface ){ - currentVolume = m_recallTrackingVolume; - currentLayer = m_recallLayer; - } - - // Global search method if this fails - - else if ( !currentVolume ) { - // If the recall method fails then the cashed information needs to be reset - resetRecallInformation(); - currentVolume = m_navigator->volume( combinedState->position() ); - currentLayer = (currentVolume) ? currentVolume->associatedLayer(combinedState->position()) : nullptr; - - } - - /* ============================================= - Determine the resolved direction - ============================================= */ - if ( currentVolume && direction == Trk::anyDirection ){ - - - } - - - if ( direction == Trk::anyDirection ){ - - if (!currentVolume) ATH_MSG_DEBUG( "Initliasation Current No Volume WTF" ); - else ATH_MSG_DEBUG( "Any direction initliation WTF" ); - - referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties ) : 0; - - // These parameters will need to be deleted later. Add to list of garbage to be collected - throwIntoGarbageBin( referenceParameters ); - - if ( referenceParameters ){ - Amg::Vector3D surfaceDirection( referenceParameters->position() - combinedState->position() ); - direction = ( surfaceDirection.dot( combinedState->momentum() ) > 0. ) ? Trk::alongMomentum : Trk::oppositeMomentum; - } - - } - - /* ============================================= - Look for destination volume - ============================================= */ - - // 1. See if the destination layer is associated with a tracking volume - destinationVolume = surface.associatedLayer() ? surface.associatedLayer()->enclosingTrackingVolume() : 0; - if (!surface.associatedLayer()) - ATH_MSG_DEBUG( "No layer associated to the surface" ); - - - - // 2. See if there is a cashed recall surface - if ( !destinationVolume && &surface == m_recallSurface ){ - destinationVolume = m_recallTrackingVolume; - // If no reference parameters are defined, then determine them - if ( !referenceParameters ){ - - referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties ) : 0; - - // These parameters will need to be deleted later. Add to list of garbage to be collected - throwIntoGarbageBin( referenceParameters ); - } - - // 3. Global search - } else { - - // If no reference parameters are defined, then determine them - if ( !referenceParameters ){ - - referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties) : 0; - - // These parameters will need to be deleted later. Add to list of garbage to be collected - throwIntoGarbageBin( referenceParameters ); - } - - // Global search of tracking geometry to find the destination volume - if ( referenceParameters ){ - destinationVolume = m_navigator->volume( referenceParameters->position() ); - } - // If destination volume is still not found then global search based on surface position - else { - destinationVolume = m_navigator->volume( surface.globalReferencePoint() ); - } - } - - return; - -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - PrintState - - ========================================================================================================================================= - ========================================================================================================================================= */ - -void Trk::GsfExtrapolator::printState( const std::string& description, const Trk::TrackParameters& trackParameters ) const -{ - - std::string label = description + " (r,phi,z), (phi, theta, q/p):\t("; - - ATH_MSG_DEBUG( label - << trackParameters.position().perp() << ", " << trackParameters.position().phi() << ", " << trackParameters.position().z() << "), (" - << trackParameters.parameters()[Trk::phi] << ", " << trackParameters.parameters()[Trk::theta] << ", " << trackParameters.parameters()[Trk::qOverP] << ")" ); - - return; - -} - - - - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolate M - - ========================================================================================================================================= - ========================================================================================================================================= */ - -const std::vector<const Trk::TrackStateOnSurface*>* Trk::GsfExtrapolator::extrapolateM( const Trk::MultiComponentState& mcsparameters, - const Surface& sf, - PropDirection dir, - BoundaryCheck bcheck, - ParticleHypothesis particle) const -{ - ATH_MSG_DEBUG( "C extrapolateM()" ); - // create a new vector for the material to be collected - - - - //const Trk::TrackParameters* combinedState = mcsparameters.begin()->first; //m_stateCombiner->combine( multiComponentState ); - - /* ============================================= - Look for current volume - ============================================= */ - - - //const Amg::Vector3D destinationPosition = combinedState->position(); - - m_matstates = new std::vector<const Trk::TrackStateOnSurface*>; - // collect the material - const MultiComponentState* parameterAtDestination = extrapolate(mcsparameters,sf,dir,bcheck,particle); - // there are no parameters - if (!parameterAtDestination ){ - ATH_MSG_VERBOSE( " [!] Destination surface for extrapolateM has not been hit (required through configuration). Return 0" ); - // loop over and clean up - for (const Trk::TrackStateOnSurface *ptr : *m_matstates) { delete ptr; } - delete m_matstates; m_matstates = 0; - // bail out - emptyGarbageBins(); - return 0; - } - else { - ATH_MSG_VERBOSE( " [+] Adding the destination surface to the TSOS vector in extrapolateM() " ); - m_matstates->push_back(new TrackStateOnSurface(0,parameterAtDestination->begin()->first->clone(),0,0)); - delete parameterAtDestination; - } - - // assign the temporary states - std::vector<const Trk::TrackStateOnSurface*> *tmpMatStates = m_matstates; - m_matstates=0; - emptyGarbageBins(); - // return the material states - return tmpMatStates; -} - -/* ========================================================================================================================================= - ========================================================================================================================================= - - Extrapolte M - - ========================================================================================================================================= - ========================================================================================================================================= */ -/*const std::vector<const Trk::TrackParameters*>* Trk::GsfExtrapolator::extrapolateM(const TrackParameters& , - const Surface& , - PropDirection , - BoundaryCheck , - std::vector<MaterialEffectsOnTrack>& , - std::vector<Trk::TransportJacobian*>& , - ParticleHypothesis ) const -{ - ATH_MSG_DEBUG( "C-[" << ++m_methodSequence << "] extrapolateM(..) with jacobian collection - Not implemented yet." ); - return 0; -}*/ - - -/* ========================================================================================================================================= - ========================================================================================================================================= - - addMaterialtoVector - - ========================================================================================================================================= - ========================================================================================================================================= */ - -void Trk::GsfExtrapolator::addMaterialtoVector(const Trk::Layer* nextLayer, - const Trk::TrackParameters* nextPar, - PropDirection dir, - ParticleHypothesis particle) const - - -{ - ATH_MSG_DEBUG( "GSF inside addMaterialVector " ); - - if (!m_matstates || !nextLayer || !nextPar) return; - - - - // Extract the material properties from the layer - const Trk::MaterialProperties* materialProperties(0); - double pathcorr(0.); - - - // Get the surface associated with the parameters - const Trk::Surface* surface = &(nextPar->associatedSurface()); - - // Only utilise the reference material if an associated detector element exists - if ( surface && surface->associatedDetectorElement() ){ - - // Get the layer material properties - const Trk::LayerMaterialProperties* layerMaterial = nextLayer->layerMaterialProperties(); - - // Assign the material properties - materialProperties = layerMaterial ? layerMaterial->fullMaterial( nextPar->position() ) : 0; - - // Determine the pathCorrection if the material properties exist - pathcorr = materialProperties ? 1. / fabs( surface->normal().dot( nextPar->momentum().unit() ) ) : 0.; - - } - - - // Check that the material properties have been defined - if not define them from the layer information - materialProperties = materialProperties ? materialProperties : nextLayer->fullUpdateMaterialProperties( *nextPar ); - - - - if(!materialProperties){ - ATH_MSG_DEBUG( "addMaterialVector: layer has no MaterialProperties!! " ); - return; - } - - - //std::cout << "0PL, PC, X0 :" << thick << '\t' << pathcorr<< '\t' <<thick / lx0 <<'\t'<< materialProperties->thickness() <<std::endl; - - - if (m_matstates) { - pathcorr = pathcorr > 0. ? pathcorr : nextLayer->surfaceRepresentation().pathCorrection(nextPar->position(),nextPar->momentum()); - double thick = pathcorr * materialProperties->thickness(); - double dInX0 = thick / materialProperties->x0(); - double absP=1/fabs(nextPar->parameters()[Trk::qOverP]); - double scatsigma=sqrt(m_msupdators->sigmaSquare(*materialProperties,absP,pathcorr,particle)); - Trk::ScatteringAngles *newsa=new Trk::ScatteringAngles(0,0,scatsigma/sin(nextPar->parameters()[Trk::theta]),scatsigma); - //energy loss - Trk::EnergyLoss* eloss = m_elossupdators->energyLoss(*materialProperties,absP,pathcorr, - dir,particle,Trk::addNoise); - - - // use curvilinear TPs to simplify retrieval by fitters - Trk::CurvilinearParameters* cvlTP = new Trk::CurvilinearParameters(nextPar->position(),nextPar->momentum(),nextPar->charge()); - Trk::MaterialEffectsOnTrack* mefot = new Trk::MaterialEffectsOnTrack(dInX0,newsa,eloss,cvlTP->associatedSurface()); - m_matstates->push_back(new TrackStateOnSurface(0,cvlTP,0,mefot)); - ATH_MSG_DEBUG( "addMaterialVector: from layer:"<< layerRZoutput(nextLayer) <<". Size is now " << m_matstates->size() ); - - } - -} - - - -std::string -Trk::GsfExtrapolator::layerRZoutput(const Trk::Layer* lay) const { - std::string result("NULL"); - if (not lay) return result; - result = "[r,z] = [ " + std::to_string(lay->surfaceRepresentation().bounds().r() ) - + ", " + std::to_string( lay->surfaceRepresentation().center().z()) + " ] - Index "; - result+= std::to_string( lay->layerIndex().value()); - return result; - -} - -std::string Trk::GsfExtrapolator::positionOutput(const Amg::Vector3D& pos) const -{ - std::stringstream outStream; - outStream << "[r,phi,z] = [ " << pos.perp() << ", " << pos.phi() << ", " << pos.z() << " ]"; - return outStream.str(); -} - - - -int Trk::GsfExtrapolator::radialDirection(const Trk::MultiComponentState& pars, PropDirection dir) const -{ - // safe inbound/outbound estimation - double prePositionR = pars.begin()->first->position().perp(); - return (prePositionR > (pars.begin()->first->position() + dir*0.5*prePositionR*pars.begin()->first->momentum().unit()).perp()) ? -1 : 1; -} - -bool Trk::GsfExtrapolator::radialDirectionCheck(const IPropagator& prop, - const MultiComponentState& startParm, - const MultiComponentState& parsOnLayer, - const TrackingVolume& tvol, - PropDirection dir, - ParticleHypothesis particle) const -{ - const Amg::Vector3D& startPosition = startParm.begin()->first->position(); - const Amg::Vector3D& onLayerPosition = parsOnLayer.begin()->first->position(); - - // the 3D distance to the layer intersection - double distToLayer = (startPosition-onLayerPosition).mag(); - // get the innermost contained surface for crosscheck - const std::vector< SharedObject<const BoundarySurface<TrackingVolume> > >& boundarySurfaces = tvol.boundarySurfaces(); - // only for tubes the crossing makes sense to check for validity - if (boundarySurfaces.size()==4) { - // propagate to the inside surface and compare the distance: - // it can be either the next layer from the initial point, or the inner tube boundary surface - const Trk::Surface& insideSurface = (boundarySurfaces[Trk::tubeInnerCover].getPtr())->surfaceRepresentation(); - const Trk::TrackParameters* parsOnInsideSurface = prop.propagateParameters(*(startParm.begin()->first), - insideSurface,dir,true,m_fieldProperties,particle); - double distToInsideSurface = parsOnInsideSurface ? (startPosition-(parsOnInsideSurface->position())).mag() : 10e10; - - ATH_MSG_DEBUG( " Radial direction check start - at " << positionOutput(startPosition) ); - ATH_MSG_DEBUG( " Radial direction check layer - at " << positionOutput(onLayerPosition) ); - if (parsOnInsideSurface) - ATH_MSG_DEBUG( " Radial direction check inner - at " << positionOutput(parsOnInsideSurface->position()) ); - - // memory cleanup (no garbage bin, this is faster) - delete parsOnInsideSurface; - ATH_MSG_DEBUG( " Check radial direction: distance layer / boundary = " << distToLayer << " / " << distToInsideSurface ); - // the intersection with the original layer is valid if it is before the inside surface - return (distToLayer < distToInsideSurface) ? true : false; - } - return true; -} - - - +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + */ + +/********************************************************************************* + GsfExtrapolator.cxx - description + ----------------------------------- +begin : Tuesday 25th January 2005 +author : amorley +email : amorley@cern.ch +decription : Implementation code for GsfExtrapolator class +*********************************************************************************/ + +#include "TrkGaussianSumFilter/GsfExtrapolator.h" + +#include "TrkGaussianSumFilter/IMaterialMixtureConvolution.h" +#include "TrkGaussianSumFilter/IMultiComponentStateMerger.h" + +#include "TrkExInterfaces/IPropagator.h" +#include "TrkExInterfaces/INavigator.h" + + +#include "TrkGeometry/MaterialProperties.h" +#include "TrkGeometry/TrackingVolume.h" +#include "TrkGeometry/Layer.h" + +#include "TrkSurfaces/Surface.h" +#include "TrkParameters/TrackParameters.h" +#include "TrkTrack/TrackStateOnSurface.h" +#include "TrkMaterialOnTrack/ScatteringAngles.h" +#include "TrkMaterialOnTrack/EnergyLoss.h" +#include "TrkExUtils/MaterialUpdateMode.h" + +#include "TrkGeometry/MagneticFieldProperties.h" + +namespace{ +const bool useBoundaryMaterialUpdate(true); +} + +Trk::GsfExtrapolator::GsfExtrapolator(const std::string& type, const std::string& name, const IInterface* parent) + : + AthAlgTool(type, name, parent), + m_propagators(), + m_navigator("Trk::Navigator/Navigator"), + m_materialUpdator("Trk::GsfMaterialMixtureConvolution/GsfMaterialMixtureConvolution"), + m_merger("Trk::CloseComponentsMultiStateMerger/CloseComponentsMultiStateMerger"), + m_propagatorStickyConfiguration(true), + m_surfaceBasedMaterialEffects(false), + m_fastField(false), + m_propagatorConfigurationLevel(10), + m_propagatorSearchLevel(10), + m_extrapolateCalls{}, + m_extrapolateDirectlyCalls{}, + m_extrapolateDirectlyFallbacks{}, + m_navigationDistanceIncreaseBreaks{}, + m_oscillationBreaks{}, + m_missedVolumeBoundary{} +{ + + declareInterface<IMultiStateExtrapolator>(this); + + declareProperty("Propagators", m_propagators ); + + declareProperty("SearchLevelClosestParameters", m_propagatorSearchLevel ); + + declareProperty("StickyConfiguration", m_propagatorStickyConfiguration ); + + declareProperty("Navigator", m_navigator ); + + declareProperty("GsfMaterialConvolution", m_materialUpdator ); + + declareProperty("ComponentMerger", m_merger ); + + declareProperty("SurfaceBasedMaterialEffects", m_surfaceBasedMaterialEffects ); + + declareProperty("MagneticFieldProperties", m_fastField); + +} + +Trk::GsfExtrapolator::~GsfExtrapolator() +{} + +/* + * Initialisation and finalisation + */ + +StatusCode Trk::GsfExtrapolator::initialize() +{ + + + // Request the Propagator AlgTools + if ( not m_propagators.empty() ){ + ATH_MSG_INFO( "Attempting to retrieve propagator tool.... " ); + ATH_CHECK( m_propagators.retrieve() ); + ATH_MSG_INFO( "Retrieved tools " << m_propagators ); + unsigned int retrievedPropagators = m_propagators.size(); + if (!retrievedPropagators){ + ATH_MSG_WARNING( "None of the specified propagators could be retrieved! Extrapolators will operate in unconfigured mode."); + m_propagatorConfigurationLevel = 10; + } else { + // Set the configuration level for the retrieved propagators + m_propagatorConfigurationLevel = m_propagators.size() - 1; + } + ATH_MSG_INFO( "Propagator configuration level: " << m_propagatorConfigurationLevel ); + + } else { + ATH_MSG_WARNING( "List of propagators to retrieve is empty. Extrapolators will work in unconfigured mode" ); + } + + + // Request the Navigation AlgTool + ATH_CHECK( m_navigator.retrieve() ); + + // Request the Material Effects Updator AlgTool + ATH_CHECK( m_materialUpdator.retrieve() ); + + // Retrieve an instance of the component merger + ATH_CHECK( m_merger.retrieve() ); + + // Retrieve an instance of the multi-component state combiner tool + ATH_CHECK( m_stateCombiner.retrieve() ); + + + ATH_CHECK( m_elossupdators.retrieve() ); + + + ATH_CHECK( m_msupdators.retrieve() ); + + m_fieldProperties = m_fastField ? Trk::MagneticFieldProperties(Trk::FastField) : Trk::MagneticFieldProperties(Trk::FullField); + + + ATH_MSG_INFO( "Initialisation of " << name() << " was successful" ); + return StatusCode::SUCCESS; +} + +StatusCode Trk::GsfExtrapolator::finalize() +{ + + ATH_MSG_INFO( "*** Extrapolator " << name() << " performance statistics ***********" ); + ATH_MSG_INFO( " * - Number of extrapolate() calls: " << m_extrapolateCalls ); + ATH_MSG_INFO( " * - Number of extrapolateDirectly() fallbacks: " << m_extrapolateDirectlyFallbacks ); + ATH_MSG_INFO( " * - Number of navigation distance check breaks: " << m_navigationDistanceIncreaseBreaks ); + ATH_MSG_INFO( " * - Number of volume boundary search failures: " << m_missedVolumeBoundary ); + ATH_MSG_INFO( " * - Number of tracking volume oscillation breaks: " << m_oscillationBreaks ); + ATH_MSG_INFO( "*****************************************************************************************************************" ); + + ATH_MSG_INFO( "Finalisation of " << name() << " was successful" ); + return StatusCode::SUCCESS; +} + +/* + * This is the actual (non-direct) extrapolation method + * The other one will end up calling this one passing the internal cache + */ +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateImpl(Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + auto buff_extrapolateCalls=m_extrapolateCalls.buffer(); + ATH_MSG_VERBOSE( "GSF extrapolate() in non-configured mode: " << multiComponentState.size() ); + + // If the extrapolation is to be without material effects simply revert to the extrapolateDirectly method + if ( particleHypothesis == Trk::nonInteracting ){ + return extrapolateDirectly( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); + } + // Surface based material effects (assumes all material is on active sensor elements) + if ( m_surfaceBasedMaterialEffects ){ + return extrapolateSurfaceBasedMaterialEffects( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); + } + // statistics + ++buff_extrapolateCalls; + + const Trk::Layer* associatedLayer = 0; + const Trk::TrackingVolume* startVolume = 0; + const Trk::TrackingVolume* destinationVolume = 0; + const Trk::TrackParameters* referenceParameters = 0; + + initialiseNavigation( cache, + propagator, + multiComponentState, + surface, associatedLayer, + startVolume, + destinationVolume, + referenceParameters, + direction ); + + // Bail to direct extrapolation if the direction cannot be determined + if ( direction == Trk::anyDirection ) + return extrapolateDirectly( propagator, multiComponentState, surface, direction, boundaryCheck, particleHypothesis ); + + const Trk::TrackParameters* combinedState = multiComponentState.begin()->first; + + const Trk::MultiComponentState* currentState = &multiComponentState; + + /* Define the initial distance between destination and current position. Destination should be determined from either + - reference parameters (prefered if they exist) or + - destination surface + */ + + Amg::Vector3D globalSeparation = referenceParameters ? referenceParameters->position() - combinedState->position() : surface.globalReferencePoint() - combinedState->position(); + double initialDistance = globalSeparation.mag(); + if (referenceParameters) printState("Intial Ref Parameters at next surface ", *referenceParameters); + else ATH_MSG_DEBUG( "No reference parameters?? Gobal sep (r,z): (" <<globalSeparation.perp() << ",\t" <<globalSeparation.z() <<")" ); + + + // =============== + // Debug print-out + // =============== + if (msgLvl(MSG::DEBUG)){ + ATH_MSG_VERBOSE( "extrapolate() with configuration ++++++++++++++++++++++++++++++++++++++++++++" ); + ATH_MSG_VERBOSE( " -> Combined state: " << *combinedState ); + ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); + ATH_MSG_VERBOSE( " -> Destination surface: " << surface ); + ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); + ATH_MSG_VERBOSE( " -> Starting volume from navigator: " << startVolume->volumeName() ); + ATH_MSG_VERBOSE( " -> Destination volume from navigator: " << destinationVolume->volumeName() ); + ATH_MSG_VERBOSE( " --------------------------------------------------------------------------------------------" ); + ATH_MSG_VERBOSE( " -> Configuration (direction/boundaryCheck/particleHypothesis): " << direction << " / " << boundaryCheck << " / " << particleHypothesis ); + ATH_MSG_VERBOSE( "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" ); + } + + ATH_MSG_DEBUG( "Running extrapolation direction " << direction << " from: " + << startVolume->volumeName() << " to " << destinationVolume->volumeName() << " and surface centre (" + << surface.center().x() << ", " << surface.center().y() << ", " << surface.center().z() << ")" ); + + this->printState( "Extrapolation starting with", *combinedState ); + + // Clean up memory from combiner. It is no longer needed + combinedState = 0; + + /* There are two parts to the extrapolation: + - Extrapolate from start point to volume boundary + - Extrapolate from volume boundary to destination surface + */ + + const Trk::IPropagator* currentPropagator = 0; + + /* + * Extrapolation to destination volume boundary + */ + + bool foundFinalBoundary(true); + int fallbackOscillationCounter(0); + const Trk::TrackingVolume* currentVolume = startVolume; + const Trk::TrackingVolume* previousVolume = 0; + auto buff_missedVolumeBoundary= m_missedVolumeBoundary.buffer(); + auto buff_oscillationBreaks = m_oscillationBreaks.buffer(); + auto buff_navigationDistanceIncreaseBreaks= m_navigationDistanceIncreaseBreaks.buffer(); + + while ( currentVolume && currentVolume != destinationVolume && currentState ){ + // Configure propagator based on the current tracking volume + currentPropagator = m_propagatorStickyConfiguration ? &propagator : &(*m_propagators[ this->propagatorType( *currentVolume ) ]); + + if (referenceParameters) printState("Old Ref Parameters at next surface ", *referenceParameters); + + // Extrapolate to volume boundary + extrapolateToVolumeBoundary( cache, + *currentPropagator, + *currentState, + associatedLayer, + *currentVolume, + direction, + particleHypothesis ); + + // New current state is the state extrapolated to the tracking volume boundary. + currentState = cache.m_stateAtBoundarySurface.stateAtBoundary; + + // The volume that the extrapolation is about to enter into is called the nextVolume + const Trk::TrackingVolume* nextVolume = cache.m_stateAtBoundarySurface.trackingVolume; + + // Break the loop if the next tracking volume is the same as the current one + if ( !nextVolume || nextVolume == currentVolume ){ + ATH_MSG_DEBUG( "Navigation break: No next volume found" ); + ++buff_missedVolumeBoundary; + foundFinalBoundary = false; + break; + } + + // New reference parameters are the navigation parameters at the boundary surface + referenceParameters = cache.m_stateAtBoundarySurface.navigationParameters; + //coverity 111522: null check is redundant here since referenceParameters is dereferenced later anyway. + //if (referenceParameters) printState("New Ref Parameters at next surface ", *referenceParameters); + printState("New Ref Parameters at next surface ", *referenceParameters); + + // Break the lop if an oscillation is detected + if ( previousVolume == nextVolume ) + ++fallbackOscillationCounter; + + if ( fallbackOscillationCounter > 10 ){ + ATH_MSG_DEBUG( "Navigation break: Oscillation" ); + ++buff_oscillationBreaks; + foundFinalBoundary = false; + break; + } + + // Break the loop if the distance between the surface and the track parameters has increased + combinedState = currentState->begin()->first; + + const TrackParameters* parametersAtDestination = currentPropagator->propagateParameters( *combinedState, + surface, + direction, + false, + m_fieldProperties, Trk::electron ); + Amg::Vector3D newDestination; + if (parametersAtDestination){ + printState("Parameters at next surface ", *parametersAtDestination); + newDestination = parametersAtDestination->position(); + delete parametersAtDestination; + } else { + ATH_MSG_DEBUG( "Distance check propagation Failed. Using surface center" ); + newDestination = surface.center(); + } + + double revisedDistance = ( referenceParameters->position() - newDestination ).mag(); + + double distanceChange = fabs( revisedDistance - initialDistance ); + + if ( revisedDistance > initialDistance && distanceChange > 0.01 ){ + ATH_MSG_DEBUG( "Navigation break. Initial separation: " << initialDistance << " Current Sepatation: " << revisedDistance ); + ATH_MSG_DEBUG( ".... Volume " << nextVolume->volumeName()<< " from " <<currentVolume->volumeName() ); + foundFinalBoundary = false; + ++buff_navigationDistanceIncreaseBreaks; + break; + } + + combinedState = 0; + ATH_MSG_DEBUG( "Switching tracking volume look for Material: " << nextVolume->volumeName() ); + // Initialise the oscillation checker + previousVolume = currentVolume; + // As the extrapolation is moving into the next volume, the next volume -> current volume + currentVolume = nextVolume; + // Associated layer now needs to be reset + //if(!entryLayerFound) + associatedLayer = 0; + } // end while loop + + // Look to catch failures now + if ( !currentState ){ + ATH_MSG_DEBUG( "No current state at boundary... Falling back to original state" ); + currentState = &multiComponentState; + foundFinalBoundary = false; + } + + if ( currentVolume != destinationVolume ){ + ATH_MSG_DEBUG( "Trk::GsfExtrapolator::extrapolate failed to reach destination volume... " ); + currentState = &multiComponentState; + foundFinalBoundary = false; + } + + if ( !foundFinalBoundary ){ + ATH_MSG_DEBUG( "Could not find final boundary switch to direct EXTRAPOLATION" ); + + const Trk::MultiComponentState* bailOutState = multiStatePropagate( propagator, + *currentState, + surface, + Trk::anyDirection, + boundaryCheck, + particleHypothesis ); + + if ( !bailOutState ){ + ATH_MSG_DEBUG( "Fallback to propagation failed... Returning 0" ); + return 0; + } + emptyGarbageBins(cache); + return bailOutState; + } + + // =============== + // Debug print-out + // =============== + + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( *currentState ); + if ( !combinedState ){ + ATH_MSG_ERROR( "State combination failed... exiting" ); + return 0; + } + this->printState( "Reached final volume boundary " + currentVolume->volumeName() + " with", *combinedState ); + delete combinedState; + combinedState = 0; + } + + /* + * Extrapolation from volume boundary to surface + */ + + // Configure propagator based on the current tracking volume + currentPropagator = m_propagatorStickyConfiguration ? &propagator : &(*m_propagators[ this->propagatorType( *currentVolume ) ]); + + // extrapolate inside destination volume + const Trk::MultiComponentState* destinationState = extrapolateInsideVolume( cache, + *currentPropagator, + *currentState, + surface, + associatedLayer, + *currentVolume, + direction, + boundaryCheck, + particleHypothesis ); + + // FALLBACK POINT: Crisis if extrapolation fails here... As per extrapolation to volume boundary, in emergency revert to extrapolateDirectly + + auto buff_extrapolateDirectlyFallbacks=m_extrapolateDirectlyFallbacks.buffer(); + if ( destinationState == currentState ){ + destinationState = 0; + } + + if ( destinationState && &((*(destinationState->begin())).first->associatedSurface()) != &surface ){ + ATH_MSG_DEBUG( "Failed to reach destination surface ... reached some other surface"); + if( destinationState != currentState) + delete destinationState; + destinationState = 0; + } + + if ( !destinationState ){ + ATH_MSG_DEBUG( "extrapolateInsideVolume() failed... falling back to direct propagation" ); + destinationState = multiStatePropagate( propagator, + *currentState, + surface, + Trk::anyDirection, + boundaryCheck, + particleHypothesis ); + + // statistics + ++buff_extrapolateDirectlyFallbacks; + } + emptyGarbageBins(cache); + if ( !destinationState ){ + ATH_MSG_DEBUG( "Extrapolation inside volume failed... returning 0" ); + return 0; + } + // =============== + // Debug print-out + // =============== + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( *destinationState ); + if ( !combinedState ){ + ATH_MSG_ERROR( "State combination failed... exiting" ); + return 0; + } + + this->printState( "Extrapolation completed with", *combinedState ); + ATH_MSG_DEBUG( "With "<< destinationState->size() << " components" ); + ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); + delete combinedState; + combinedState = 0; + } + // After successful extrapolation return the state + return destinationState; +} + +/* + * When the propagator is configured + * We can go through this overload + */ +const Trk::MultiComponentState* +Trk::GsfExtrapolator::extrapolateImpl(Cache& cache, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_VERBOSE( "GSF extrapolate() in configured mode" ); + + if ( multiComponentState.empty() ){ + ATH_MSG_DEBUG( "MultiComponentState is empty... returning 0" ); + return 0; + } + + if (m_propagatorConfigurationLevel < 10){ + + // Set the propagator to that one corresponding to the configuration level + const Trk::IPropagator* currentPropagator = &(*m_propagators[m_propagatorConfigurationLevel]); + return extrapolateImpl( cache, + *currentPropagator, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + } + ATH_MSG_ERROR( "No default propagator is selected in 'extrapolate'. Check job options!" ); + return 0; +} + +/************************************************************/ +/* + * Done with the internal actual implementation methods here + * Implement the public ones + */ +/************************************************************/ + +/* + * Extrapolation methods without configured propagator + */ +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolate(const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + Cache cache{}; + return extrapolateImpl(cache, + propagator, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + +} + +/* + * Direct method + * does not uses a cache + */ +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateDirectly( const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_VERBOSE( "GSF extrapolateDirectly() in non-configured mode: " <<multiComponentState.size() ); + auto buff_extrapolateDirectlyCalls= m_extrapolateDirectlyCalls.buffer(); + // statistics + ++buff_extrapolateDirectlyCalls; + const Trk::TrackingVolume* currentVolume = m_navigator->highestVolume(); + if ( !currentVolume ){ + ATH_MSG_WARNING( "Current tracking volume could not be determined... returning 0" ); + return 0; + } + // Propagate all components + const Trk::MultiComponentState* returnState = multiStatePropagate( propagator, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + + if ( !returnState ){ + ATH_MSG_DEBUG( "Trk::GsfExtrapolator::extrapolateDirectly() failed... returning 0" ); + return 0; + } + return returnState; +} + +/* + * Methods that can use a configured propagator + */ +const Trk::MultiComponentState* +Trk::GsfExtrapolator::extrapolate( const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + Cache cache{}; + return extrapolateImpl( cache, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); +} + +/* + * Direct method does not uses a cache + */ +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateDirectly( const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_VERBOSE( "GSF extrapolateDirectly() in configured mode" ); + if (m_propagatorConfigurationLevel < 10){ + // Set the propagator to that one corresponding to the configuration level + const Trk::IPropagator* currentPropagator = &(*m_propagators[m_propagatorConfigurationLevel]); + if ( !currentPropagator) { + ATH_MSG_ERROR( "No current propagator is defined... Exiting" ); + return 0; + } + + return this->extrapolateDirectly( *currentPropagator, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + } + ATH_MSG_ERROR( "No default propagator is selected in 'extrapolateDirectly'. Check job options!" ); + return 0; +} + +/* + * Extrapolate M + */ + +const std::vector<const Trk::TrackStateOnSurface*>* Trk::GsfExtrapolator::extrapolateM( const Trk::MultiComponentState& mcsparameters, + const Surface& sf, + PropDirection dir, + BoundaryCheck bcheck, + ParticleHypothesis particle) const +{ + ATH_MSG_DEBUG( "C extrapolateM()" ); + // create a new vector for the material to be collected + + /* ============================================= + Look for current volume + ============================================= */ + + Cache cache{}; + cache.m_matstates.reset(new std::vector<const Trk::TrackStateOnSurface*>); + // collect the material + const MultiComponentState* parameterAtDestination = extrapolateImpl(cache,mcsparameters,sf,dir,bcheck,particle); + // there are no parameters + if (!parameterAtDestination ){ + ATH_MSG_VERBOSE( " [!] Destination surface for extrapolateM has not been hit (required through configuration). Return 0" ); + // loop over and clean up + for (const Trk::TrackStateOnSurface *ptr : *cache.m_matstates) { delete ptr; } + emptyGarbageBins(cache); + return 0; + } + else { + ATH_MSG_VERBOSE( " [+] Adding the destination surface to the TSOS vector in extrapolateM() " ); + cache.m_matstates->push_back(new TrackStateOnSurface(0,parameterAtDestination->begin()->first->clone(),0,0)); + delete parameterAtDestination; + } + // assign the temporary states + std::vector<const Trk::TrackStateOnSurface*> *tmpMatStates = cache.m_matstates.release(); + emptyGarbageBins(cache); + // return the material states + return tmpMatStates; +} + +/************************************************************/ +/* + * Now the implementation of all the internal methods + * that perform actual calculations + */ +/************************************************************/ + +/* + * Extrapolate to Volume Boundary! + */ +void Trk::GsfExtrapolator::extrapolateToVolumeBoundary ( Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Layer* layer, + const Trk::TrackingVolume& trackingVolume, + Trk::PropDirection direction, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_DEBUG( "GSF extrapolateToVolumeBoundary() to tracking volume: " << trackingVolume.volumeName() ); + + + // MultiComponentState propagation and material effects + const Trk::MultiComponentState* currentState = &multiComponentState; + + // Determine the current layer - the state combiner is required + + if(!currentState){ + ATH_MSG_WARNING( "extrapolateToVolumeBoundary: Trying to extrapolate nothing?? - return" ); + return; + } + + const Trk::TrackParameters* combinedState = currentState->begin()->first; //m_stateCombiner->combine( multiComponentState ); + + const Trk::Layer* associatedLayer = layer; + + if ( !associatedLayer ) + { + ATH_MSG_DEBUG( "No associated layer passed with volume.... lets get one" ); + // Get entry layer but do not use it as it should have already be hit if it was desired + associatedLayer = trackingVolume.associatedLayer( combinedState->position() ); + associatedLayer = associatedLayer ? associatedLayer : trackingVolume.nextLayer( combinedState->position(), direction * combinedState->momentum().unit(), associatedLayer ); + + ATH_MSG_DEBUG( "Found layer in Volume " << layerRZoutput(associatedLayer) ); + + } + // Only loop over layers if they can be found within the tracking volume + else if ( trackingVolume.confinedLayers() && associatedLayer->layerMaterialProperties() ) + { + //const TrackParameters* paranetersAtDestination = currentPropagator->propagateParameters( *combinedState, associatedLayer->surfaceRepresentation(), direction, false, trackingVolume ); + //if(paranetersAtDestination) + + const Trk::MultiComponentState* updatedState = m_materialUpdator->postUpdate( *currentState, + *layer, + direction, + particleHypothesis ); + + // Memory clean-up + if ( updatedState && updatedState != currentState && currentState != &multiComponentState ){ + delete currentState; + } + + // Refresh updated state pointer + updatedState = updatedState ? updatedState : currentState; + + if (updatedState != currentState ){ + addMaterialtoVector( cache, layer, currentState->begin()->first ); + } + //---------------------------------------- + // Component reduction + //---------------------------------------- + + const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState); + + // Memory clean-up + if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) + delete updatedState; + + // Refresh current state pointer + currentState = reducedState ? reducedState : updatedState; + + + } + + // Clean up memory used by the combiner + combinedState = 0; + + const Trk::MultiComponentState* nextState = 0; + + // If an associated surface can be found, extrapolation within the tracking volume is mandatory + // This will take extrapolate to the last layer in the volume + if ( associatedLayer ){ + nextState = extrapolateFromLayerToLayer( cache, + propagator, + *currentState, + trackingVolume, + associatedLayer, + 0, + direction, + particleHypothesis ); + + // Make sure reduced state is added to the list of garbage to be collected + if ( nextState && nextState != currentState && currentState != &multiComponentState ) + delete currentState; + + // Refresh the current state pointer + currentState = nextState ? nextState : currentState; + + } + + /* ============================================= + Find the boundary surface using the navigator + ============================================= */ + + Trk::NavigationCell nextNavigationCell(0,0); + + combinedState = currentState->begin()->first->clone(); //m_stateCombiner->combine( *currentState ); + + const Trk::TrackingVolume* nextVolume = 0; + const Trk::TrackParameters* navigationParameters = cache.m_stateAtBoundarySurface.navigationParameters + ? cache.m_stateAtBoundarySurface.navigationParameters : combinedState; + + unsigned int navigationPropagatorIndex = 0; + + if ( m_propagatorConfigurationLevel < 10 ) { + + // Not the default + while ( navigationPropagatorIndex <= m_propagatorConfigurationLevel ) { + + const Trk::IPropagator* navigationPropagator = &(*m_propagators[navigationPropagatorIndex]); + + if ( !navigationPropagator ){ + ATH_MSG_WARNING( "Navigation propagator cannot be retrieved... Continuing" ); + continue; + } + + nextNavigationCell = m_navigator->nextTrackingVolume( *navigationPropagator, *navigationParameters, direction, trackingVolume ); + nextVolume = nextNavigationCell.nextVolume; + if (navigationPropagatorIndex >= 1) + delete navigationParameters; + navigationParameters = nextNavigationCell.parametersOnBoundary; + + ++navigationPropagatorIndex; + + // If the next tracking volume is found then no need to continue looping + if ( nextVolume ) break; + + } + + } + + else { + + // The Default + nextNavigationCell = m_navigator->nextTrackingVolume( propagator, *navigationParameters, direction, trackingVolume ); + nextVolume = nextNavigationCell.nextVolume; + navigationParameters = nextNavigationCell.parametersOnBoundary; + + } + + // Clean up memory allocated by the combiner + if ( navigationParameters != combinedState ) + delete combinedState; + + if ( !nextVolume ){ + ATH_MSG_DEBUG( "Cannot find next TrackingVolume from initial tracking volume: " << trackingVolume.volumeName() ); + + // Reset the layer recall + resetRecallInformation(cache); + + } + + // !< TODO check the material on the boundary + if (useBoundaryMaterialUpdate) { + + //Check for two things: + // 1. If the next volume was found + // 2. If there is material associated with the boundary layer. + // If so, apply material effects update. + + //Get layer associated with boundary surface. + const Trk::TrackParameters *paramsAtBoundary = nextNavigationCell.parametersOnBoundary; + const Trk::Layer *layerAtBoundary = (paramsAtBoundary) ? (paramsAtBoundary->associatedSurface()).materialLayer() : 0; + const Trk::TrackParameters *matUpdatedParameters = 0; + const Trk::MultiComponentState *matUpdatedState = 0; + + if (nextVolume && layerAtBoundary) { + + if (layerAtBoundary->layerMaterialProperties()) { + ATH_MSG_DEBUG( "Boundary surface has material - updating properties" ); + assert (currentState); + matUpdatedState = m_materialUpdator->postUpdate(*currentState, + *layerAtBoundary, + direction, + particleHypothesis ); + } + } + + //If state has changed due to boundary material, modify state, parameters accordingly. + if ( matUpdatedState && matUpdatedState != currentState ) { + + ATH_MSG_DEBUG( "Performing state update" ); + + //Clean out memory, update state. + delete currentState; + currentState = matUpdatedState; + + //Update navigation parameters (?). + matUpdatedParameters = currentState->begin()->first->clone(); + if (matUpdatedParameters != navigationParameters) { + delete navigationParameters; + navigationParameters = matUpdatedParameters; + } + + //Add to material vector. + addMaterialtoVector(cache,layerAtBoundary, currentState->begin()->first ); + + } + } + + // Update the boundary information + cache.m_stateAtBoundarySurface.updateBoundaryInformation( currentState, navigationParameters, nextVolume ); + + // Make sure navigation parameters and current state are added to the list of garbage to be collected + throwIntoGarbageBin( cache,navigationParameters ); + if ( currentState != &multiComponentState ) { + throwIntoGarbageBin( cache, currentState ); + } + + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( *currentState ); + + printState( "State at boundary surface", *combinedState ); + + delete combinedState; + } + + return; + +} + +/* + * Extrapolate inside volume to destination surface! + */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateInsideVolume ( Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + const Trk::Layer* layer, + const Trk::TrackingVolume& trackingVolume, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_DEBUG( "GSF extrapolateInsideVolume() in tracking volume: " << trackingVolume.volumeName() ); + + + const Trk::MultiComponentState* currentState = &multiComponentState; + + /* ================================================== + Retrieve the destination layer + ================================================== */ + + // 1. Association + const Trk::Layer* destinationLayer = surface.associatedLayer(); + + // 2. Recall and Global Search + if ( !destinationLayer ){ + ATH_MSG_DEBUG( "No associated later to surface" ); + destinationLayer = ( &surface == cache.m_recallSurface ) ? + cache.m_recallLayer : trackingVolume.associatedLayer( surface.globalReferencePoint() ); + } + // If there is still no destination layer, flag a warning + if ( !destinationLayer ) + ATH_MSG_DEBUG( "No destination layer could be found inside tracking volume: " << trackingVolume.volumeName() ); + + ATH_MSG_DEBUG( "Current layer " << layerRZoutput(layer) ); + ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); + + + /* ================================================== + Retrieve the current layer + ================================================== */ + + // Produce a combined state + const Trk::TrackParameters* combinedState = currentState->begin()->first; + + const Trk::Layer* associatedLayer = layer; + + if ( !associatedLayer ){ + + ATH_MSG_DEBUG( "No assoicated layer passed with volume.... lets get one" ); + // Get entry layer but do not use it as it should have already be hit if it was desired + associatedLayer = trackingVolume.associatedLayer( combinedState->position() ); + associatedLayer = associatedLayer ? associatedLayer : trackingVolume.nextLayer( combinedState->position(), direction * combinedState->momentum().unit(), associatedLayer ); + ATH_MSG_DEBUG( "Found layer in Volume " << layerRZoutput(associatedLayer) ); + } + + else if ( associatedLayer != destinationLayer && trackingVolume.confinedLayers() && associatedLayer->layerMaterialProperties() ){ + const Trk::MultiComponentState* updatedState = m_materialUpdator->postUpdate( *currentState, + *associatedLayer, + direction, + particleHypothesis ); + + // Memory clean-up + if ( updatedState && updatedState != currentState && currentState != &multiComponentState ) + delete currentState; + + // Refresh the updated state pointer + updatedState = updatedState ? updatedState : currentState; + + if(updatedState != currentState ) + addMaterialtoVector( cache,associatedLayer, currentState->begin()->first ); + + /* ---------------------------------------- + Component reduction + ---------------------------------------- */ + + const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState ); + + // Memory clean-up + if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ){ + delete updatedState; + } + + // Refresh the current state pointer + currentState = reducedState ? reducedState : updatedState; + } + + // Memory clean-up + combinedState = 0; + + if ( destinationLayer ){ + // If there are intermediate layers then additional extrapolations need to be done + if ( associatedLayer && associatedLayer != destinationLayer ){ + const Trk::MultiComponentState* nextState = extrapolateFromLayerToLayer( cache, + propagator, + *currentState, + trackingVolume, + associatedLayer, + destinationLayer, + direction, + particleHypothesis ); + + // Memory clean-up + if ( nextState && nextState != currentState && currentState != &multiComponentState ) + delete currentState; + + // Refresh the current state pointer + currentState = nextState ? nextState : currentState; + + } + + // Final extrapolation to destination surface + const Trk::MultiComponentState* returnState = extrapolateToDestinationLayer( cache, + propagator, + *currentState, + surface, + *destinationLayer, + //trackingVolume, + associatedLayer, + direction, + boundaryCheck, + particleHypothesis ); + + // Memory clean-up + if ( returnState && returnState != currentState && currentState != &multiComponentState ) + delete currentState; + + returnState = returnState ? returnState : currentState; + + // Set the information for the current layer, surface, tracking volume + setRecallInformation( cache,surface, *destinationLayer, trackingVolume ); + + ATH_MSG_VERBOSE( "Successfully extrapolated inside volume " << returnState->size() ); + + return returnState; + + } + + // FALLBACK POINT: If no destination layer is found fall-back and extrapolate directly + ATH_MSG_DEBUG( "extrapolateInsideVolume() could not find the destination layer... propagating directly to surface" ); + + const Trk::MultiComponentState* returnState = multiStatePropagate( propagator, + *currentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + + // Memory clean-up + if ( returnState && returnState != currentState && currentState != &multiComponentState ) + delete currentState; + + // No destination layer exists so layer recall method cannot be used and should be reset + resetRecallInformation(cache); + + return returnState; + +} + +/* + * Extrapolate from Layer to Layer + */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateFromLayerToLayer( Cache& cache, + const IPropagator& propagator, + const MultiComponentState& multiComponentState, + const TrackingVolume& trackingVolume, + const Layer* startLayer, + const Layer* destinationLayer, + PropDirection direction, + ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_DEBUG( "Starting extrapolateFromLayerToLayer()" ); + + + const Trk::Layer* currentLayer = startLayer; + const Trk::MultiComponentState* currentState = &multiComponentState; + + // Find the combined state to find the next layer + if (!currentState){ + ATH_MSG_WARNING( "extrapolateFromLayerToLayer: Trying to extrapolate nothing?? - return" ); + return 0; + } + const Trk::TrackParameters* combinedState = currentState->begin()->first; + + // No need to extrapolate to start layer, find the next one + const Trk::Layer* nextLayer = currentLayer->nextLayer( combinedState->position(), direction * combinedState->momentum().unit() ); + + ATH_MSG_DEBUG( "Current layer " << layerRZoutput(startLayer) ); + ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); + ATH_MSG_DEBUG( "Next layer " << layerRZoutput(nextLayer) ); + + // Clean up memory + combinedState =0; + + // Begin while loop over all intermediate layers + while ( nextLayer && nextLayer != destinationLayer ){ + ATH_MSG_DEBUG( "NextLayer, walking next step." ); + + const Trk::MultiComponentState* nextState = 0; + + // Only extrapolate to an intermediate layer if it requires material update... otherwise step over it + if ( nextLayer && nextLayer->layerMaterialProperties() ){ + ATH_MSG_DEBUG( "NextLayer, has material extrapolate to it" ); + + nextState = extrapolateToIntermediateLayer( cache, + propagator, + *currentState, + *nextLayer, + trackingVolume, + direction, + particleHypothesis ); + + // Memory clean-up + if ( nextState && nextState != currentState && currentState != &multiComponentState ) + delete currentState; + + // Refresh current state pointer + currentState = nextState ? nextState : currentState; + + } + + // Find the next layer + combinedState = currentState->begin()->first; //m_stateCombiner->combine( *currentState ); + + currentLayer = nextLayer; + nextLayer = currentLayer->nextLayer( combinedState->position(), direction * combinedState->momentum().unit() ); + } + + if (destinationLayer && nextLayer != destinationLayer && currentState != &multiComponentState){ + ATH_MSG_DEBUG( "extrapolateFromLayerToLayer failed to reach destination layer.. return 0" ); + ATH_MSG_DEBUG( "Current layer " << layerRZoutput(currentLayer) ); + ATH_MSG_DEBUG( "NextLayer layer " << layerRZoutput(nextLayer) ); + ATH_MSG_DEBUG( "Destination layer " << layerRZoutput(destinationLayer) ); + delete currentState; + currentState = 0; + } + + return currentState; + +} + +/* + * Extrapolate to Intermediate Layer + */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateToIntermediateLayer( Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Layer& layer, + const Trk::TrackingVolume& trackingVolume, + Trk::PropDirection direction, + Trk::ParticleHypothesis particleHypothesis, + bool doPerpCheck ) const +{ + + const Trk::TrackParameters* combinedState = 0; + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( multiComponentState ); + + ATH_MSG_VERBOSE( "GSF extrapolateToIntermediateLayer()" ); + ATH_MSG_VERBOSE( "Starting track parameters (combined state): " << *combinedState ); + ATH_MSG_VERBOSE( "Destination layer (surface representation): " << layer.surfaceRepresentation() ); + + ATH_MSG_VERBOSE( "-----------------------------------------------------------------------------------------------------------" ); + + delete combinedState; + } + + printState( "extrapolateToIntermediateLayer(). Starting with ", *(multiComponentState.begin()->first) ); + + + const Trk::Surface* startSurface = &(multiComponentState.begin()->first->associatedSurface()); + if (startSurface){ + const Trk::Layer* startLayer = startSurface->associatedLayer(); + ATH_MSG_DEBUG( "Starting Layer: " << layerRZoutput(startLayer) ); + } else { + ATH_MSG_DEBUG( "Initial parameters have no surafce associated to them" ); + } + ATH_MSG_DEBUG( "Destination Layer: " << layerRZoutput(&layer) ); + + + const Trk::MultiComponentState* initialState = &multiComponentState; + + // Propagate over all components + const Trk::MultiComponentState* destinationState = multiStatePropagate( propagator, + *initialState, + layer.surfaceRepresentation(), + direction, + true, + particleHypothesis ); + + if ( !destinationState ){ + ATH_MSG_DEBUG( "Multi-state propagation failed... Returning 0!" ); + ATH_MSG_VERBOSE( "Failed to reach layer" << layer.surfaceRepresentation() ); + return 0; + } + + // the layer has been intersected ------------------------------------------------------------------------ + // check for radial direction change --------------------------------------------------------------------- + int rDirection = radialDirection(multiComponentState,direction); + int newrDirection = radialDirection(*destinationState,direction); + if (newrDirection != rDirection && doPerpCheck){ + // it is unfortunate that the cancelling could invalidate the material collection + ATH_MSG_DEBUG( " [!] Perpendicular direction of track has changed -- checking" ); + // reset the nextParameters if the radial change is not allowed + // resetting is ok - since the parameters are in the garbage bin already + if (!radialDirectionCheck(propagator, multiComponentState, *destinationState,trackingVolume,direction,particleHypothesis)){ + ATH_MSG_DEBUG( " [+] Perpendicular direction check cancelled this layer intersection." ); + delete destinationState; + return 0; + } + } + + + if ( destinationState != initialState && initialState != &multiComponentState ) + delete initialState; + + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( *destinationState ); + + this->printState( "Propagation to intermediate completed with", *combinedState ); + + delete combinedState; + } + /* ------------------------------------- + Material effects + ------------------------------------- */ + + const Trk::MultiComponentState* updatedState = 0; + + + + updatedState = m_materialUpdator->update( *destinationState, layer, direction, particleHypothesis ); + + // Memory clean-up + if ( updatedState && updatedState != destinationState && destinationState != &multiComponentState ) + delete destinationState; + + updatedState = updatedState ? updatedState : destinationState; + + if(updatedState!=destinationState) + addMaterialtoVector( cache,&layer, updatedState->begin()->first, direction, particleHypothesis ); + + /* ------------------------------------- + Component reduction + ------------------------------------- */ + const Trk::MultiComponentState* reducedState = m_merger->merge( *updatedState ); + + if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ){ + delete updatedState; + } + + reducedState = reducedState ? reducedState : updatedState; + + if (msgLvl(MSG::DEBUG)){ + + combinedState = m_stateCombiner->combine( *reducedState ); + + this->printState( "Material update at intermediate completed with", *combinedState ); + ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); + + delete combinedState; + } + + return reducedState; + +} + +/* ========================================================================================================================================= + ========================================================================================================================================= + + Extrapolate to Destination Layer + + ========================================================================================================================================= + ========================================================================================================================================= */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateToDestinationLayer ( Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + const Trk::Layer& layer, + //const Trk::TrackingVolume& trackingVolume, + const Trk::Layer* startLayer, + Trk::PropDirection direction, + Trk::BoundaryCheck boundaryCheck, + Trk::ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_VERBOSE( "GSF extrapolateToDestinationLayer()" ); + + const Trk::MultiComponentState* initialState = &multiComponentState; + + const Trk::TrackParameters* combinedState = 0; + + if (msgLvl(MSG::DEBUG)){ + + combinedState = m_stateCombiner->combine( *initialState ); + + ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); + this->printState( "Starting extrapolation to destination with", *combinedState ); + + delete combinedState; + } + + // Propagate over all components + const Trk::MultiComponentState* destinationState = multiStatePropagate( propagator, + multiComponentState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + + // Require a fall-back if the initial state is close to the destination surface then a fall-back solution is required + + if ( !destinationState ){ + + combinedState = initialState->begin()->first; + + if ( surface.isOnSurface( combinedState->position(), true, 0.5 * layer.thickness() ) ){ + + ATH_MSG_DEBUG( "Initiating fall-back from failed propagation" ); + + destinationState = multiStatePropagate( propagator, + *initialState, + surface, + Trk::anyDirection, + boundaryCheck, + particleHypothesis ); + + } + // Memory clean-up + combinedState = 0; + if ( !destinationState ){ + ATH_MSG_DEBUG( "Propagated state is empty... returning 0" ); + return 0; + } + } + + ATH_MSG_VERBOSE( "DestinationState state has " << destinationState->size() << " components " ); + + if (msgLvl(MSG::DEBUG)){ + combinedState = m_stateCombiner->combine( *destinationState ); + this->printState( "Propagation to destination completed with", *combinedState ); + delete combinedState; + } + + /* ---------------------------------------- + Material effects + ---------------------------------------- */ + + + const Trk::MultiComponentState* updatedState = ( startLayer != &layer ) ? m_materialUpdator->preUpdate( *destinationState, + layer, + direction, + particleHypothesis ) : destinationState; + + if ( updatedState && updatedState != destinationState && destinationState != &multiComponentState ) + delete destinationState; + + updatedState = updatedState ? updatedState : destinationState; + + ATH_MSG_VERBOSE( "Updated state has " << updatedState->size() << " components " ); + + + if(updatedState != destinationState) + addMaterialtoVector( cache,&layer, updatedState->begin()->first, direction, particleHypothesis ); + + /* ---------------------------------------- + Component reduction + ---------------------------------------- */ + + const Trk::MultiComponentState* reducedState = m_merger->merge(*updatedState); + + if ( reducedState && reducedState != updatedState && updatedState != &multiComponentState ) + delete updatedState; + + reducedState = reducedState ? reducedState : updatedState; + + ATH_MSG_VERBOSE( "Reduced state has " << reducedState->size() << " components " ); + + if (msgLvl(MSG::DEBUG)){ + ATH_MSG_VERBOSE( "Successfully completed extrapolation to destination: " ); + combinedState = m_stateCombiner->combine( *reducedState ); + this->printState( "Material update at destination completed with", *combinedState ); + ATH_MSG_DEBUG( "-----------------------------------------------------------------------------------------------------------" ); + delete combinedState; + } + return reducedState; +} + +/* + * Extrapolate based on material on active surfaces + */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::extrapolateSurfaceBasedMaterialEffects ( const IPropagator& propagator, + const MultiComponentState& multiComponentState, + const Surface& surface, + PropDirection direction, + BoundaryCheck boundaryCheck, + ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_VERBOSE( "GSF extrapolateSurfaceBasedMaterialEffects()" ); + + /* ------------------------------------- + Preliminary checks + ------------------------------------- */ + + // Check the multi-component state is populated + if ( multiComponentState.empty() ){ + ATH_MSG_WARNING( "Multi component state passed to extrapolateInsideVolume is not populated... returning 0" ); + return 0; + } + + //const Trk::TrackingVolume* currentVolume = m_navigator->highestVolume(); + + const Trk::MultiComponentState* lastState = &multiComponentState; + const Trk::MultiComponentState* nextState = 0; + + // Propagate over all components + nextState = multiStatePropagate( propagator, + *lastState, + surface, + direction, + boundaryCheck, + particleHypothesis ); + + + // Clean up memory after the propagation. Reset pointers + if ( lastState != &multiComponentState && lastState != nextState ) + delete lastState; + + if ( !nextState ){ + ATH_MSG_DEBUG( "Propagated state is empty... returning 0" ); + return 0; + } + + /* ---------------------------------------- + Material effects + ---------------------------------------- */ + + lastState = nextState; + nextState = 0; + + nextState = m_materialUpdator->simpliedMaterialUpdate( *lastState, direction, particleHypothesis ); + + if ( nextState != lastState && lastState != &multiComponentState ) + delete lastState; + + /* ---------------------------------------- + Component reduction + ---------------------------------------- */ + + lastState = nextState; + nextState = 0; + + nextState = m_merger->merge(*lastState); + + if ( lastState != nextState && lastState != &multiComponentState ) + delete lastState; + + return nextState; + +} + +/* + * Multi-component state propagate + */ + +const Trk::MultiComponentState* Trk::GsfExtrapolator::multiStatePropagate ( const IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Surface& surface, + PropDirection direction, + BoundaryCheck boundaryCheck, + ParticleHypothesis particleHypothesis ) const +{ + + ATH_MSG_DEBUG( "GSF multiStatePropagate() propagating " << multiComponentState.size() << " components\n" << + "\t\t\t\t\t...Propagating to surface [r,z] [" << surface.center().perp() << ",\t" << surface.center().z() << ']' ); + const Trk::Layer* layer = surface.associatedLayer(); + ATH_MSG_DEBUG( "...associated layer to surface " << layerRZoutput(layer) ); + + + + Trk::MultiComponentState* propagatedState = new Trk::MultiComponentState(); + + Trk::MultiComponentState::const_iterator component = multiComponentState.begin(); + + double sumw(0); //HACK variable to avoid propagation errors + for ( ; component != multiComponentState.end(); ++component ){ + + const Trk::TrackParameters* currentParameters = component->first; + const Trk::TrackParameters* propagatedParameters = 0; + + if ( !currentParameters ){ + ATH_MSG_DEBUG( "Component parameters not defined... component will not be propagated... continuing" ); + continue; + } + + propagatedParameters = propagator.propagate( *currentParameters, surface, direction, boundaryCheck, m_fieldProperties, particleHypothesis ); + + if ( !propagatedParameters ){ + ATH_MSG_DEBUG( "Propagation of component failed... continuing" ); + continue; + } + + sumw+=component->second; + // Propagation does not affect the weightings of the states + const Trk::ComponentParameters propagatedComponent( propagatedParameters, component->second ); + propagatedState->push_back( propagatedComponent ); + + } + + ATH_MSG_DEBUG( "GSF multiStatePropagate() propagated " << propagatedState->size() << "components" ); + + // Protect against empty propagation + if ( propagatedState->empty() || sumw<0.1 ){ + ATH_MSG_DEBUG( "multiStatePropagate failed... returning 0" ); + delete propagatedState; + return 0; + } + return propagatedState; +} + +/* + * PropagatorType + */ + +unsigned int Trk::GsfExtrapolator::propagatorType ( const Trk::TrackingVolume& trackingVolume ) const +{ + if (m_propagatorStickyConfiguration) { + if (m_propagators.size()>m_propagatorConfigurationLevel) return m_propagatorConfigurationLevel; + ATH_MSG_WARNING( "Misconfigured propagator type, set to "<<m_propagatorConfigurationLevel<<"->0" ); + return 0; + } + + // Determine what sort of magnetic field is present + unsigned int magneticFieldMode = m_fieldProperties.magneticFieldMode(); + + // Chose between runge-kutta and step propagators depending on field magnetic field and material properties + // ST : the following check may fail as the dEdX is often dummy for dense volumes - switch to rho or zOverAtimesRho ? + unsigned int propagatorMode = ( magneticFieldMode > 1 && fabs( trackingVolume.dEdX ) < 10e-2 ) ? 2 : 3; + + unsigned int returnType = (propagatorMode > m_propagatorConfigurationLevel) ? m_propagatorConfigurationLevel : propagatorMode; + + if ( m_propagators.size()> returnType ) return returnType; + ATH_MSG_WARNING( "Misconfigured propagator type, set to "<< returnType <<"->0" ); + return 0; +} + +/* + * Initialise Navigation + */ + +void Trk::GsfExtrapolator::initialiseNavigation ( Cache& cache, + const Trk::IPropagator& propagator, + const Trk::MultiComponentState& multiComponentState, + const Trk::Surface& surface, + const Trk::Layer*& currentLayer, + const Trk::TrackingVolume*& currentVolume, + const Trk::TrackingVolume*& destinationVolume, + const Trk::TrackParameters*& referenceParameters, + Trk::PropDirection direction ) const +{ + + ATH_MSG_DEBUG( "initialiseNavigation !!!" ); + // Empty the garbage bin + ATH_MSG_DEBUG( "Destination to surface [r,z] [" << surface.center().perp() << ",\t" << surface.center().z() << ']' ); + emptyGarbageBins(cache); + const Trk::TrackParameters* combinedState = multiComponentState.begin()->first; //m_stateCombiner->combine( multiComponentState ); + /* ============================================= + Look for current volume + ============================================= */ + // 1. See if the current layer is associated with a tracking volume + + const Trk::Surface* associatedSurface = &(combinedState->associatedSurface()); + currentLayer = associatedSurface ? associatedSurface->associatedLayer() : currentLayer; + currentVolume = currentLayer ? currentLayer->enclosingTrackingVolume() : currentVolume; + + // If the association method failed then try the recall method + + if ( !currentVolume && associatedSurface == cache.m_recallSurface ){ + currentVolume = cache.m_recallTrackingVolume; + currentLayer = cache.m_recallLayer; + } + // Global search method if this fails + + else if ( !currentVolume ) { + // If the recall method fails then the cashed information needs to be reset + resetRecallInformation(cache); + currentVolume = m_navigator->volume( combinedState->position() ); + currentLayer = (currentVolume) ? currentVolume->associatedLayer(combinedState->position()) : nullptr; + + } + /* ============================================= + Determine the resolved direction + ============================================= */ + if ( direction == Trk::anyDirection ){ + if (!currentVolume) { + ATH_MSG_DEBUG( "Initialisation Current No Volume" ); + } + else { + ATH_MSG_DEBUG( "Any direction initialisation" ); + } + referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties ) : 0; + // These parameters will need to be deleted later. Add to list of garbage to be collected + throwIntoGarbageBin( cache,referenceParameters ); + if ( referenceParameters ){ + Amg::Vector3D surfaceDirection( referenceParameters->position() - combinedState->position() ); + direction = ( surfaceDirection.dot( combinedState->momentum() ) > 0. ) ? Trk::alongMomentum : Trk::oppositeMomentum; + } + } + + /* ============================================= + Look for destination volume + ============================================= */ + + // 1. See if the destination layer is associated with a tracking volume + destinationVolume = surface.associatedLayer() ? surface.associatedLayer()->enclosingTrackingVolume() : 0; + if (!surface.associatedLayer()) + ATH_MSG_DEBUG( "No layer associated to the surface" ); + + // 2. See if there is a cashed recall surface + if ( !destinationVolume && &surface == cache.m_recallSurface ){ + destinationVolume = cache.m_recallTrackingVolume; + // If no reference parameters are defined, then determine them + if ( !referenceParameters ){ + referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties ) : 0; + // These parameters will need to be deleted later. Add to list of garbage to be collected + throwIntoGarbageBin( cache,referenceParameters ); + } + + // 3. Global search + } else { + // If no reference parameters are defined, then determine them + if ( !referenceParameters ){ + referenceParameters = currentVolume ? propagator.propagateParameters( *combinedState, surface, direction, false, m_fieldProperties) : 0; + // These parameters will need to be deleted later. Add to list of garbage to be collected + throwIntoGarbageBin( cache,referenceParameters ); + } + // Global search of tracking geometry to find the destination volume + if ( referenceParameters ){ + destinationVolume = m_navigator->volume( referenceParameters->position() ); + } + // If destination volume is still not found then global search based on surface position + else { + destinationVolume = m_navigator->volume( surface.globalReferencePoint() ); + } + } + return; +} + + +void Trk::GsfExtrapolator::printState( const std::string& description, const Trk::TrackParameters& trackParameters ) const +{ + std::string label = description + " (r,phi,z), (phi, theta, q/p):\t("; + ATH_MSG_DEBUG( label + << trackParameters.position().perp() << ", " << trackParameters.position().phi() + << ", " << trackParameters.position().z() << "), ("<< trackParameters.parameters()[Trk::phi] + << ", " << trackParameters.parameters()[Trk::theta] << ", " << trackParameters.parameters()[Trk::qOverP] << ")" ); + return; +} + +/* + * addMaterialtoVector + */ + +void Trk::GsfExtrapolator::addMaterialtoVector(Cache& cache, + const Trk::Layer* nextLayer, + const Trk::TrackParameters* nextPar, + PropDirection dir, + ParticleHypothesis particle) const + + +{ + ATH_MSG_DEBUG( "GSF inside addMaterialVector " ); + + if (!cache.m_matstates || !nextLayer || !nextPar) { + return; + } + + // Extract the material properties from the layer + const Trk::MaterialProperties* materialProperties(0); + double pathcorr(0.); + + // Get the surface associated with the parameters + const Trk::Surface* surface = &(nextPar->associatedSurface()); + + // Only utilise the reference material if an associated detector element exists + if ( surface && surface->associatedDetectorElement() ){ + + // Get the layer material properties + const Trk::LayerMaterialProperties* layerMaterial = nextLayer->layerMaterialProperties(); + + // Assign the material properties + materialProperties = layerMaterial ? layerMaterial->fullMaterial( nextPar->position() ) : 0; + + // Determine the pathCorrection if the material properties exist + pathcorr = materialProperties ? 1. / fabs( surface->normal().dot( nextPar->momentum().unit() ) ) : 0.; + } + + // Check that the material properties have been defined - if not define them from the layer information + materialProperties = materialProperties ? materialProperties : nextLayer->fullUpdateMaterialProperties( *nextPar ); + + if(!materialProperties){ + ATH_MSG_DEBUG( "addMaterialVector: layer has no MaterialProperties!! " ); + return; + } + + if (cache.m_matstates) { + pathcorr = pathcorr > 0. ? pathcorr : nextLayer->surfaceRepresentation().pathCorrection(nextPar->position(),nextPar->momentum()); + double thick = pathcorr * materialProperties->thickness(); + double dInX0 = thick / materialProperties->x0(); + double absP=1/fabs(nextPar->parameters()[Trk::qOverP]); + double scatsigma=sqrt(m_msupdators->sigmaSquare(*materialProperties,absP,pathcorr,particle)); + Trk::ScatteringAngles *newsa=new Trk::ScatteringAngles(0,0,scatsigma/sin(nextPar->parameters()[Trk::theta]),scatsigma); + //energy loss + Trk::EnergyLoss* eloss = m_elossupdators->energyLoss(*materialProperties,absP,pathcorr, + dir,particle,Trk::addNoise); + + + // use curvilinear TPs to simplify retrieval by fitters + Trk::CurvilinearParameters* cvlTP = new Trk::CurvilinearParameters(nextPar->position(),nextPar->momentum(),nextPar->charge()); + Trk::MaterialEffectsOnTrack* mefot = new Trk::MaterialEffectsOnTrack(dInX0,newsa,eloss,cvlTP->associatedSurface()); + cache.m_matstates->push_back(new TrackStateOnSurface(0,cvlTP,0,mefot)); + ATH_MSG_DEBUG( "addMaterialVector: from layer:"<< layerRZoutput(nextLayer) <<". Size is now " << cache.m_matstates->size() ); + } +} + +std::string +Trk::GsfExtrapolator::layerRZoutput(const Trk::Layer* lay) const { + std::string result("NULL"); + if (not lay) return result; + result = "[r,z] = [ " + std::to_string(lay->surfaceRepresentation().bounds().r() ) + + ", " + std::to_string( lay->surfaceRepresentation().center().z()) + " ] - Index "; + result+= std::to_string( lay->layerIndex().value()); + return result; + +} + +std::string Trk::GsfExtrapolator::positionOutput(const Amg::Vector3D& pos) const +{ + std::stringstream outStream; + outStream << "[r,phi,z] = [ " << pos.perp() << ", " << pos.phi() << ", " << pos.z() << " ]"; + return outStream.str(); +} + + + +int Trk::GsfExtrapolator::radialDirection(const Trk::MultiComponentState& pars, PropDirection dir) const +{ + // safe inbound/outbound estimation + double prePositionR = pars.begin()->first->position().perp(); + return (prePositionR > (pars.begin()->first->position() + dir*0.5*prePositionR*pars.begin()->first->momentum().unit()).perp()) ? -1 : 1; +} + +bool Trk::GsfExtrapolator::radialDirectionCheck(const IPropagator& prop, + const MultiComponentState& startParm, + const MultiComponentState& parsOnLayer, + const TrackingVolume& tvol, + PropDirection dir, + ParticleHypothesis particle) const +{ + const Amg::Vector3D& startPosition = startParm.begin()->first->position(); + const Amg::Vector3D& onLayerPosition = parsOnLayer.begin()->first->position(); + + // the 3D distance to the layer intersection + double distToLayer = (startPosition-onLayerPosition).mag(); + // get the innermost contained surface for crosscheck + const std::vector< SharedObject<const BoundarySurface<TrackingVolume> > >& boundarySurfaces = tvol.boundarySurfaces(); + // only for tubes the crossing makes sense to check for validity + if (boundarySurfaces.size()==4) { + // propagate to the inside surface and compare the distance: + // it can be either the next layer from the initial point, or the inner tube boundary surface + const Trk::Surface& insideSurface = (boundarySurfaces[Trk::tubeInnerCover].getPtr())->surfaceRepresentation(); + const Trk::TrackParameters* parsOnInsideSurface = prop.propagateParameters(*(startParm.begin()->first), + insideSurface,dir,true,m_fieldProperties,particle); + double distToInsideSurface = parsOnInsideSurface ? (startPosition-(parsOnInsideSurface->position())).mag() : 10e10; + + ATH_MSG_DEBUG( " Radial direction check start - at " << positionOutput(startPosition) ); + ATH_MSG_DEBUG( " Radial direction check layer - at " << positionOutput(onLayerPosition) ); + if (parsOnInsideSurface) + ATH_MSG_DEBUG( " Radial direction check inner - at " << positionOutput(parsOnInsideSurface->position()) ); + + // memory cleanup (no garbage bin, this is faster) + delete parsOnInsideSurface; + ATH_MSG_DEBUG( " Check radial direction: distance layer / boundary = " << distToLayer << " / " << distToInsideSurface ); + // the intersection with the original layer is valid if it is before the inside surface + return (distToLayer < distToInsideSurface) ? true : false; + } + return true; +} +