ATLAS Offline Software
Loading...
Searching...
No Matches
NeutralParticleParameterCalculator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
5/*********************************************************************
6 NeutralParticleParameterCalculator.cxx - Description in header file
7*********************************************************************/
8
14
17
18
19// #define IMPACTPOINT3DESTIMATOR_DEBUG
20
21namespace Trk
22{
23
24 NeutralParticleParameterCalculator::NeutralParticleParameterCalculator(const std::string& t, const std::string& n, const IInterface* p) :
25 AthAlgTool(t,n,p),
26 m_LinearizedTrackFactory("Trk::FullLinearizedTrackFactory/FullLinearizedTrackFactory"),
28 {
29 declareProperty("LinearizedTrackFactory",m_LinearizedTrackFactory);
30 declareInterface<INeutralParticleParameterCalculator>(this);
31 }
32
34
36 {
37 ATH_CHECK(m_LinearizedTrackFactory.retrieve( DisableTool{ m_LinearizedTrackFactory.empty() } ));
39
40 return StatusCode::SUCCESS;
41 }
42
43
45 (const xAOD::Vertex & myVertex) const
46 {
47
48 if (myVertex.nTrackParticles()!=2)
49 {
50 msg(MSG::WARNING) << " More or less than 2 tracks in Vertex. No Neutral Perigee could be created" << endmsg;
51 return nullptr;
52 }
53
54 if ( !myVertex.trackParticleLinks()[0].isValid() || !myVertex.trackParticleLinks()[1].isValid() )
55 {
56 msg(MSG::WARNING) << " Track Particle Element link is not valid" << endmsg;
57 return nullptr;
58
59 }
60 const xAOD::TrackParticle * myFirstTrack= myVertex.trackParticle( 0 );
61 const xAOD::TrackParticle * mySecondTrack=myVertex.trackParticle( 1 );
62
63 const Trk::Perigee& myFirstPerigee = myFirstTrack->perigeeParameters();
64 const Trk::Perigee& mySecondPerigee = mySecondTrack->perigeeParameters();
65
66 const AmgMatrix(3,3)& vrt_cov = myVertex.covariancePosition();
67 AmgMatrix(3,3) vrt_weight = myVertex.covariancePosition().inverse().eval();
68
69 //need to recalculate the refitted covariance matrix of the tracks (yes, we don't have it yet)
70 std::pair<AmgMatrix(3,3),AmgMatrix(3,3)> PosMomAndMomCovFirstTrack;
71 std::pair<AmgMatrix(3,3),AmgMatrix(3,3)> PosMomAndMomCovSecondTrack;
72
73
74 //check if the linearizedTrackFactory is available...
76 msg(MSG::ERROR) << " No LinearizedTrackFactory is defined and no ExtendedVxCandidate is provided. Cannot obtain covariance matrix of neutral particle. Failed... " << endmsg;
77 return nullptr;
78 }
79
80
82
83 const Trk::LinearizedTrack * myFirstLinearizedTrack = m_LinearizedTrackFactory->linearizedTrack(&myFirstPerigee, myVertex.position() );
84 const Trk::LinearizedTrack * mySecondLinearizedTrack= m_LinearizedTrackFactory->linearizedTrack(&mySecondPerigee, myVertex.position() );
85
86 if (myFirstLinearizedTrack==nullptr||mySecondLinearizedTrack==nullptr)
87 {
88 msg(MSG::WARNING) << " Could not find one of the linearized tracks. No Neutral Perigee could be created" << endmsg;
89 if (myFirstLinearizedTrack) delete myFirstLinearizedTrack;
90 if (mySecondLinearizedTrack) delete mySecondLinearizedTrack;
91 return nullptr;
92 }
93
94 PosMomAndMomCovFirstTrack=getPosMomentumAndMomentumCovMatrix(myFirstLinearizedTrack,
95 vrt_cov,
96 vrt_weight);
97
98 PosMomAndMomCovSecondTrack=getPosMomentumAndMomentumCovMatrix(mySecondLinearizedTrack,
99 vrt_cov,
100 vrt_weight);
101
102 delete myFirstLinearizedTrack;
103 delete mySecondLinearizedTrack;
104 } else {
105 msg(MSG::WARNING) << " getPosMomentumAndMomentumCovMatrix method failed " << endmsg;
106 return nullptr;
107 }
108
109 const AmgVector(5) & myFirstPerigeeParameters=myFirstPerigee.parameters();
110 const AmgVector(5) & mySecondPerigeeParameters=mySecondPerigee.parameters();
111
112 AmgMatrix(3,3) FirstJacobianToPxPyPz=getPhiThetaQOverPToPxPyPzJacobian(myFirstPerigeeParameters[Trk::qOverP],
113 myFirstPerigeeParameters[Trk::theta],
114 myFirstPerigeeParameters[Trk::phi0]);
115
116 AmgMatrix(3,3) SecondJacobianToPxPyPz=getPhiThetaQOverPToPxPyPzJacobian(mySecondPerigeeParameters[Trk::qOverP],
117 mySecondPerigeeParameters[Trk::theta],
118 mySecondPerigeeParameters[Trk::phi0]);
119
120
121
122 AmgMatrix(3,3) posMomentumCovFirst=PosMomAndMomCovFirstTrack.first*FirstJacobianToPxPyPz.transpose();
123 AmgMatrix(3,3) posMomentumCovSecond=PosMomAndMomCovSecondTrack.first*SecondJacobianToPxPyPz.transpose();
124
125 AmgMatrix(3,3) momentumCovFirst=PosMomAndMomCovFirstTrack.second.similarity(FirstJacobianToPxPyPz);
126 AmgMatrix(3,3) momentumCovSecond=PosMomAndMomCovSecondTrack.second.similarity(SecondJacobianToPxPyPz);
127
128
129 //P1 P2 covariance matrix
130 AmgMatrix(3,3) covP1P2; covP1P2.setZero();
131
132
133 covP1P2=posMomentumCovFirst.transpose()*vrt_weight*posMomentumCovSecond;
134
135 // no distinction between symmetric and non-symmetric square matrices in new EDM, drop checks.
136 // AmgMatrix(3,3) nonSymCovNewP = momentumCovFirst+momentumCovSecond+covP1P2+covP1P2.transpose();
137 AmgMatrix(3,3) covNewP = momentumCovFirst+momentumCovSecond+covP1P2+covP1P2.transpose();
138
139 AmgMatrix(3,3) covNewXP=posMomentumCovFirst+posMomentumCovSecond;
140
141 //now covNewP and covNewXP are the new covariance matrices with the new momentum
142 //calculate also new momentum
143 Amg::Vector3D newMomentum=myFirstPerigee.momentum()+mySecondPerigee.momentum();
144
145 ATH_MSG_VERBOSE(" new momentum " << newMomentum << " new cov Momentum " << covNewP);
146 ATH_MSG_VERBOSE(" position " << myVertex.position() << " cov Pos - Momentum " << covNewXP);
147 ATH_MSG_VERBOSE(" old cov position " << vrt_cov);
148
149 //Now you need to create the new neutral tracks
150 //NOT trivial, since no global representation exists...
151 //now you need first to go back with the momentum (px,py,pz -> phi,theta,q/p)
152
153 Trk::JacobianPxyzToPhiThetaQoverPspherical JacobianToPhiThetaQOverP(newMomentum.phi(),
154 newMomentum.theta(),
155 1./newMomentum.mag());
156
157 AmgMatrix(3,3) finalCovNewP=covNewP.similarity(JacobianToPhiThetaQOverP);
158 AmgMatrix(3,3) finalCovNewXP=covNewXP*JacobianToPhiThetaQOverP.transpose();
159
160 double phi=newMomentum.phi();
161 double theta=newMomentum.theta();
162 double qOverP=1./newMomentum.mag();
163
164 ATH_MSG_VERBOSE(" new phi: " << phi << " +/- " << sqrt(finalCovNewP(0,0)));
165 ATH_MSG_VERBOSE(" new theta: " << theta << " +/- " << sqrt(finalCovNewP(1,1)));
166 ATH_MSG_VERBOSE(" new P: " << 1./qOverP << " +/- " << 1./qOverP/qOverP*sqrt(finalCovNewP(2,2)));
167
168 //now you still have 6 parameters! need to reduce them to 5!
169 //
170 //create the jacobian for a neutral particle
171
172 double sin_phi_v=sin(phi);
173 double cos_phi_v=cos(phi);
174 double tan_th=tan(theta);
175
176 //jacobian elements
177 AmgMatrix(5,6) globalNeutralJacobian; globalNeutralJacobian.setZero();
178 globalNeutralJacobian(0,0) = -sin_phi_v;
179 globalNeutralJacobian(0,1) = +cos_phi_v;
180 globalNeutralJacobian(1,0) = -cos_phi_v/tan_th;
181 globalNeutralJacobian(1,1) = -sin_phi_v/tan_th;
182 globalNeutralJacobian(1,2) = 1.;
183 globalNeutralJacobian(2,3) = 1.;
184 globalNeutralJacobian(3,4) = 1.;
185 globalNeutralJacobian(4,5) = 1.;
186
187 AmgMatrix(6,6) fullTrkCov; fullTrkCov.setZero();
188 fullTrkCov.block<3,3>(0,3) = finalCovNewXP; // was .sub(1,4, finalCovNewXP);
189 fullTrkCov.block<3,3>(3,0) = finalCovNewXP.transpose(); // was .sub(4,1, finalCovNewXP.T());
190 fullTrkCov.block<3,3>(0,0) = vrt_cov; // was .sub(1,1, vrt_cov);
191 fullTrkCov.block<3,3>(3,3) = finalCovNewP; // was .sub(4,4, finalCovNewP);
192
193 // no mechanism in new EDM: CLHEP::HepSymMatrix symFullTrkCov;
194 // no mechanism in new EDM: symFullTrkCov.assign(fullTrkCov);
195
196 Trk::PerigeeSurface perSurface(myVertex.position());
197 AmgSymMatrix(5) covNeutral = AmgSymMatrix(5)(globalNeutralJacobian*fullTrkCov*globalNeutralJacobian.transpose());
198
199 return new Trk::NeutralPerigee(0,0,phi,theta,qOverP,perSurface,std::move(covNeutral));
200 }
201
202
203
204
206 (const Trk::LinearizedTrack* linTrack,
207 const AmgMatrix(3,3) & vrt_cov,
208 const AmgMatrix(3,3) & vrt_weight) const
209 {
210
211 const AmgMatrix(5,3) & A = linTrack->positionJacobian();
212 const AmgMatrix(5,3) & B = linTrack->momentumJacobian();
213 const AmgSymMatrix(5) & trkParametersWeight = linTrack->expectedWeightAtPCA();
214
215 AmgSymMatrix(3) Sm = B.transpose()*(trkParametersWeight*B);
216 // same maths, but doesn't compile: AmgSymMatrix(3) Sm = trkParametersWeight.similarityT(B);
217 if (Sm.determinant() == 0.0) {
218 ATH_MSG_WARNING("S matrix can not be inverted, new type of check as part of Eigen, please monitor."
219 << endmsg << "Matrix Sm = " << Sm);
220 ATH_MSG_WARNING("This track is returned not refitted");
221 // throw std::string("Inversion of S matrix fails in track parameters refit");
222 }
223 Sm = Sm.inverse().eval();
224 AmgMatrix(3,3) posMomentumCovariance = -vrt_cov * A.transpose() * trkParametersWeight * B *Sm;
225 AmgMatrix(3,3) momentumCovariance = Sm + vrt_weight.similarityT(posMomentumCovariance);
226
227 return std::pair<AmgMatrix(3,3),AmgMatrix(3,3)>(posMomentumCovariance,momentumCovariance);
228 }
229
230
231 AmgMatrix(3,3) NeutralParticleParameterCalculator::getPhiThetaQOverPToPxPyPzJacobian
232 (double qOverP,double theta,double phi) {
233 AmgMatrix(3,3) transform; transform.setZero();
234 transform(0,0)=-1./fabs(qOverP)*sin(theta)*sin(phi);
235 transform(0,1)=1./fabs(qOverP)*sin(theta)*cos(phi);
236 transform(0,2)=0.;
237 transform(1,0)=1./fabs(qOverP)*cos(theta)*cos(phi);
238 transform(1,1)=1./fabs(qOverP)*cos(theta)*sin(phi);
239 transform(1,2)=-1./fabs(qOverP)*sin(theta);
240 transform(2,0)=-1./qOverP/fabs(qOverP)*sin(theta)*cos(phi);
241 transform(2,1)=-1./qOverP/fabs(qOverP)*sin(theta)*sin(phi);
242 transform(2,2)=-1./qOverP/fabs(qOverP)*cos(theta);
243 return transform.transpose().eval();
244 }
245
246}
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define AmgSymMatrix(dim)
#define AmgVector(rows)
#define AmgMatrix(rows, cols)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
MsgStream & msg() const
Jacobian in spherical coordinates for the transformation of momentum in Cartesian coordinates to mom...
Tool taking a two-track vertex and creating a neutral track from it.
ToolHandle< Trk::IVertexLinearizedTrackFactory > m_LinearizedTrackFactory
std::pair< AmgMatrix(3, 3), AmgMatrix(3, 3)> getPosMomentumAndMomentumCovMatrix(const Trk::LinearizedTrack *linTrack, const AmgMatrix(3, 3) &vrt_cov, const AmgMatrix(3, 3) &vrt_weight) const
NeutralParticleParameterCalculator(const std::string &t, const std::string &n, const IInterface *p)
Default constructor due to Athena interface.
virtual NeutralPerigee * createNeutralTrackFromVertex(const xAOD::Vertex &) const override
method that makes the parameters of a V0 or photon before decay to two tracks
const Amg::Vector3D & momentum() const
Access method for the momentum.
Class describing the Line to which the Perigee refers to.
const Trk::Perigee & perigeeParameters() const
Returns the Trk::MeasuredPerigee track parameters.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticleLinks_t & trackParticleLinks() const
Get all the particles associated with the vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
const Amg::Vector3D & position() const
Returns the 3-pos.
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
ParametersT< NeutralParametersDim, Neutral, PerigeeSurface > NeutralPerigee
@ phi0
Definition ParamDefs.h:65
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ phi
Definition ParamDefs.h:75
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
hold the test vectors and ease the comparison