19 #include "CLHEP/GenericFunctions/CumulativeChiSquare.hh" 
   22 #include "CLHEP/Vector/LorentzVector.h" 
   29     declareInterface<V0Tools>(
this);
 
   32   V0Tools::~V0Tools() = 
default;
 
   37     return StatusCode::SUCCESS;
 
   40   double V0Tools::invariantMass(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass)
 const 
   42     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
   44     return invariantMass(vxCandidate,
masses);
 
   49   double V0Tools::invariantMass(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
   51     double px = 0., 
py = 0., 
pz = 0., 
e = 0.;
 
   53     if (
masses.size() != NTrk) {
 
   54       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
   57     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
   60         px += lorentz_trk.Px();
 
   61         py += lorentz_trk.Py();
 
   62         pz += lorentz_trk.Pz();
 
   67     return (msq>0.) ? sqrt(msq) : 0.;
 
   70   double V0Tools::invariantMassError(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass)
 const 
   72     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
   74     return invariantMassError(vxCandidate,
masses);
 
   77   double V0Tools::invariantMassError(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
   80     if (
masses.size() != NTrk) {
 
   81       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
   84     double error = -999999.;
 
   85     auto fullCov = convertCovMatrix(vxCandidate);
 
   86     if (fullCov.size() == 0) {
 
   87       ATH_MSG_DEBUG(
"0 pointer for full covariance. Making-up one from the vertex and tracks covariances");
 
   90       unsigned int ndim = fullCov.rows();
 
   92         if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
   94         } 
else if (ndim == 3*NTrk+3) {
 
  102   double V0Tools::massErrorV0Fitter(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass)
 const 
  104     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
  106     return massErrorV0Fitter(vxCandidate,
masses);
 
  109   double V0Tools::massErrorV0Fitter(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
  112     if (
masses.size() != NTrk) {
 
  113       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
  116     auto fullCov = convertCovMatrix(vxCandidate);
 
  117     if (fullCov.size() == 0) 
return -999999.;
 
  118     unsigned int ndim = fullCov.rows();
 
  119     double E=0., Px=0., Py=0., Pz=0.;
 
  121     std::vector<double>dm2dphi(NTrk), dm2dtheta(NTrk), dm2dqOverP(NTrk);
 
  122     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  125         double trkCharge = 1.;
 
  126         if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
  132         double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  140     double msq = 
E*
E - Px*Px - Py*Py - Pz*Pz;
 
  141     double mass = (msq>0.) ? sqrt(msq) : 0.;
 
  143     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  152     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  153       D_vec(5*
it+0,0)  = 0.;
 
  154       D_vec(5*
it+1,0)  = 0.;
 
  155       D_vec(5*
it+2,0)  = dm2dphi[
it];
 
  156       D_vec(5*
it+3,0)  = dm2dtheta[
it];
 
  157       D_vec(5*
it+4,0)  = dm2dqOverP[
it];
 
  159     Amg::MatrixX V0_merr = D_vec.transpose() * fullCov.block(0,0,ndim-3,ndim-3) * D_vec;
 
  161     double massVarsq = V0_merr(0,0);
 
  162     if (massVarsq <= 0.) 
ATH_MSG_DEBUG(
"massError: negative sqrt massVarsq " << massVarsq);
 
  163     double massVar = (massVarsq>0.) ? sqrt(massVarsq) : 0.;
 
  164     double massErr = massVar/(2.*
mass);
 
  168   double V0Tools::massErrorVKalVrt(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass)
 const 
  170     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
  171     return massErrorVKalVrt(vxCandidate,
masses);
 
  174   double V0Tools::massErrorVKalVrt(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
  177     if (
masses.size() != NTrk) {
 
  178       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
  181     std::vector<xAOD::TrackParticle::FourMom_t> particleMom(NTrk);
 
  182     std::vector<
AmgMatrix(3,3)> particleDeriv(NTrk);
 
  184     AmgMatrix(3,3) tmpDeriv; tmpDeriv.setZero();
 
  185     auto fullCov = convertCovMatrix(vxCandidate);
 
  186     if (fullCov.
size() == 0) return -999999.;
 
  188     for( 
unsigned int it=0; 
it<NTrk; 
it++){
 
  198         double e = (esq>0.) ? sqrt(esq) : 0.;
 
  201         particleMom[
it] = 
tmp;
 
  205         tmpDeriv(0,0) = - 
tmp.Py();
 
  206         tmpDeriv(1,0) =   
tmp.Px();
 
  210         tmpDeriv(2,1) = - 
sin(
theta)/fabs(invP);
 
  211         tmpDeriv(0,2) = - 
tmp.Px()/invP;
 
  212         tmpDeriv(1,2) = - 
tmp.Py()/invP;
 
  213         tmpDeriv(2,2) = - 
tmp.Pz()/invP;
 
  214         particleDeriv[
it] = tmpDeriv;
 
  218     std::vector<double> Deriv(3*NTrk+3, 0.);
 
  219     for(
unsigned int it=0; 
it<NTrk; 
it++){
 
  221         double dMdPx = ( totalMom.E() * particleMom[
it].Px()/particleMom[
it].E() - totalMom.Px() ) / totalMom.M();
 
  222         double dMdPy = ( totalMom.E() * particleMom[
it].Py()/particleMom[
it].E() - totalMom.Py() ) / totalMom.M();
 
  223         double dMdPz = ( totalMom.E() * particleMom[
it].Pz()/particleMom[
it].E() - totalMom.Pz() ) / totalMom.M();
 
  225         double dMdPhi   = dMdPx*particleDeriv[
it](0,0) + dMdPy*particleDeriv[
it](1,0) + dMdPz*particleDeriv[
it](2,0);
 
  226         double dMdTheta = dMdPx*particleDeriv[
it](0,1) + dMdPy*particleDeriv[
it](1,1) + dMdPz*particleDeriv[
it](2,1);
 
  227         double dMdInvP  = dMdPx*particleDeriv[
it](0,2) + dMdPy*particleDeriv[
it](1,2) + dMdPz*particleDeriv[
it](2,2);
 
  229         Deriv[3*
it + 3 + 0] = dMdPhi;    Deriv[3*
it + 3 + 1] = dMdTheta; Deriv[3*
it + 3 + 2] = dMdInvP;
 
  234     for(
unsigned int i=0; 
i<3*NTrk+3; 
i++){
 
  235       for(
unsigned int j=0; j<3*NTrk+3; j++){
 
  236         err += Deriv[
i]*( fullCov)(
i,j)*Deriv[j];
 
  240     return (
err>0.) ? sqrt(
err) : 0.;
 
  243   double V0Tools::massErrorVxCandidate(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass)
 const 
  245     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
  247     return massErrorVxCandidate(vxCandidate,
masses);
 
  250   double V0Tools::massErrorVxCandidate(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
  253     if (
masses.size() != NTrk) {
 
  254       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
  257     double E=0., Px=0., Py=0., Pz=0.;
 
  259     std::vector<double>dm2dphi(NTrk), dm2dtheta(NTrk), dm2dqOverP(NTrk);
 
  261     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  265         V0_cor(5*
it+2,5*
it+2) = (*cov_tmp)(2,2);
 
  266         V0_cor(5*
it+2,5*
it+3) = (*cov_tmp)(2,3);
 
  267         V0_cor(5*
it+2,5*
it+4) = (*cov_tmp)(2,4);
 
  268         V0_cor(5*
it+3,5*
it+3) = (*cov_tmp)(3,3);
 
  269         V0_cor(5*
it+3,5*
it+4) = (*cov_tmp)(3,4);
 
  270         V0_cor(5*
it+4,5*
it+4) = (*cov_tmp)(4,4);
 
  271         V0_cor(5*
it+3,5*
it+2) = (*cov_tmp)(2,3);
 
  272         V0_cor(5*
it+4,5*
it+2) = (*cov_tmp)(2,4);
 
  273         V0_cor(5*
it+4,5*
it+3) = (*cov_tmp)(3,4);
 
  274         double trkCharge = 1.;
 
  275         if (bPer->parameters()(
Trk::qOverP) < 0.) trkCharge = -1.;
 
  281         double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  289     double msq = 
E*
E - Px*Px - Py*Py - Pz*Pz;
 
  290     double mass = (msq>0.) ? sqrt(msq) : 0.;
 
  292     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  301     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  302       D_vec(5*
it+0,0)  = 0.;
 
  303       D_vec(5*
it+1,0)  = 0.;
 
  304       D_vec(5*
it+2,0)  = dm2dphi[
it];
 
  305       D_vec(5*
it+3,0)  = dm2dtheta[
it];
 
  306       D_vec(5*
it+4,0)  = dm2dqOverP[
it];
 
  309     Amg::MatrixX V0_merr = D_vec.transpose() * V0_cor * D_vec;
 
  311     double massVarsq = V0_merr(0,0);
 
  312     if (massVarsq <= 0.) 
ATH_MSG_DEBUG(
"massError: negative sqrt massVarsq " << massVarsq);
 
  313     double massVar = (massVarsq>0.) ? sqrt(massVarsq) : 0.;
 
  314     double massErr = massVar/(2.*
mass);
 
  318   double V0Tools::invariantMassProbability(
const xAOD::Vertex * vxCandidate, 
double V0Mass, 
double posTrackMass, 
double negTrackMass)
 const 
  320     std::array<double, 2> 
masses = {posTrackMass , negTrackMass};
 
  322     return invariantMassProbability(vxCandidate,V0Mass,
masses);
 
  325   double V0Tools::invariantMassProbability(
const xAOD::Vertex * vxCandidate, 
double V0Mass, std::span<const double> 
masses)
 const 
  327     double mass = invariantMass(vxCandidate, 
masses);
 
  328     double massErr = invariantMassError(vxCandidate, 
masses);
 
  333       Genfun::CumulativeChiSquare myCumulativeChiSquare(
ndf);
 
  335         double achi2prob = 1.-myCumulativeChiSquare(
chi2);
 
  347   double V0Tools::massProbability(
double V0Mass, 
double mass, 
double massErr)
 const 
  351       double chi2 = (V0Mass - 
mass)*(V0Mass - 
mass)/(massErr*massErr);
 
  353       Genfun::CumulativeChiSquare myCumulativeChiSquare(
ndf);
 
  355         double achi2prob = 1.-myCumulativeChiSquare(
chi2);
 
  377     if (NTrk != 2) 
return mom;
 
  378     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  389     if (NTrk != 2) 
return mom;
 
  390     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  401     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  412     double e = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  422     double e = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  432     double e = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  441     double e = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
  457   double V0Tools::vertexProbability(
const xAOD::Vertex * vxCandidate)
 const 
  459     float dof = 
ndof(vxCandidate);
 
  461       Genfun::CumulativeChiSquare myCumulativeChiSquare(dof);
 
  462       float chi = chisq(vxCandidate);
 
  464         double chi2prob = 1.-myCumulativeChiSquare(chi);
 
  484     return vxCandidate->
position().perp();
 
  500     double rxy = (rxysq>0.) ? sqrt(rxysq) : 0.;
 
  501     double drdx = 
dx/rxy;
 
  502     double drdy = 
dy/rxy;
 
  506     Amg::
MatrixX rxy_err = D_vec.transpose() * 
cov.block(0,0,2,2) * D_vec;
 
  507     double rxyVar = rxy_err(0,0);
 
  514     double dx = vxCandidate->position().x();
 
  515     double dy = vxCandidate->position().y();
 
  516     double rxyVar = rxy_var(
dx,
dy,
cov);
 
  517     if (rxyVar <= 0.) 
ATH_MSG_DEBUG(
"rxyError: negative sqrt rxyVar " << rxyVar);
 
  518     return (rxyVar>0.) ? sqrt(rxyVar) : 0.;
 
  525     double dx = vert.x();
 
  526     double dy = vert.y();
 
  528     if (rxyVar <= 0.) 
ATH_MSG_DEBUG(
"rxyError: negative sqrt rxyVar " << rxyVar);
 
  529     return (rxyVar>0.) ? sqrt(rxyVar) : 0.;
 
  536     double dx = vert.x();
 
  537     double dy = vert.y();
 
  539     if (rxyVar <= 0.) 
ATH_MSG_DEBUG(
"rxyError: negative sqrt rxyVar " << rxyVar);
 
  540     return (rxyVar>0.) ? sqrt(rxyVar) : 0.;
 
  545     return V0Momentum(vxCandidate).perp();
 
  552     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
  553     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
  554     std::vector<double>dPTdqOverP(NTrk), dPTdtheta(NTrk), dPTdphi(NTrk);
 
  556     auto fullCov = convertCovMatrix(vxCandidate);
 
  557     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  559       double trkCharge = 1.;
 
  560       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
  573     double PTsq = Px*Px+Py*Py;
 
  574     double PT = (PTsq>0.) ? sqrt(PTsq) : 0.;
 
  576     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  577       dPTdqOverP[
it]  = (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
  578       dPTdtheta[
it]   = (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
  579       dPTdphi[
it]     = (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
  582     unsigned int ndim = 0;
 
  583     if (fullCov.size() == 0) {
 
  586       ndim = fullCov.rows();
 
  590     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
  592       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  593         D_vec(5*
it+0,0)  = 0.;
 
  594         D_vec(5*
it+1,0)  = 0.;
 
  595         D_vec(5*
it+2,0)  = dPTdphi[
it];
 
  596         D_vec(5*
it+3,0)  = dPTdtheta[
it];
 
  597         D_vec(5*
it+4,0)  = dPTdqOverP[
it];
 
  599       if (fullCov.size() == 0) {
 
  601         PtErrSq = D_vec.transpose() * V0_cov * D_vec;
 
  603         PtErrSq = D_vec.transpose() * fullCov.block(0,0,5*NTrk-1,5*NTrk-1) * D_vec;
 
  605     } 
else if (ndim == 3*NTrk+3) {
 
  607       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  608         D_vec(3*
it+0,0)  = dPTdphi[
it];
 
  609         D_vec(3*
it+1,0)  = dPTdtheta[
it];
 
  610         D_vec(3*
it+2,0)  = dPTdqOverP[
it];
 
  612       PtErrSq = D_vec.transpose() * fullCov.block(3,3,ndim-3,ndim-3) * D_vec;
 
  615     double PtErrsq = PtErrSq(0,0);
 
  616     if (PtErrsq <= 0.) 
ATH_MSG_DEBUG(
"ptError: negative sqrt PtErrsq " << PtErrsq);
 
  617     return (PtErrsq>0.) ? sqrt(PtErrsq) : 0.;
 
  622     assert(vxCandidate!=0);
 
  623     if(
nullptr == vxCandidate) {
 
  630     double p2 = 
P.mag2();
 
  631     double pdr = 
P.dot((
sv - 
pv));
 
  632     return sv - 
P*pdr/
p2;
 
  637     const Amg::MatrixX& 
cov = (vxCandidate->covariancePosition() + 
vertex->covariancePosition()).inverse().eval();
 
  644     double sepVarsq = sepVarsqMat(0,0);
 
  645     if (sepVarsq <= 0.) 
ATH_MSG_DEBUG(
"separation: negative sqrt sepVarsq " << sepVarsq);
 
  646     double sepVar = (sepVarsq>0.) ? sqrt(sepVarsq) : 0.;
 
  659     double sepVarsq = sepVarsqMat(0,0);
 
  660     if (sepVarsq <= 0.) 
ATH_MSG_DEBUG(
"separation: negative sqrt sepVarsq " << sepVarsq);
 
  661     double sepVar = (sepVarsq>0.) ? sqrt(sepVarsq) : 0.;
 
  667     double cosineTheta_xy = cosTheta_xy(vxCandidate,
vertex);
 
  668     double sinTheta_xy = ((1.-cosineTheta_xy*cosineTheta_xy)>0.) ? sqrt((1.-cosineTheta_xy*cosineTheta_xy)) : 0.;
 
  669     return (vtx(vxCandidate)-
vertex->position()).perp() * sinTheta_xy;
 
  683     double cosineTheta = cosTheta(vxCandidate,
vertex);
 
  684     double sinTheta = ((1.-cosineTheta*cosineTheta)>0.) ? sqrt((1.-cosineTheta*cosineTheta)) : 0.;
 
  685     return (vtx(vxCandidate)-
vertex->position()).mag() * sinTheta;
 
  693     double dx = vert.x();
 
  694     double dy = vert.y();
 
  695     double dz = vert.z();
 
  696     double Px=0., Py=0., Pz=0.;
 
  697     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
  698     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
  699     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk);
 
  700     std::vector<double>da0dqOverP(NTrk), da0dtheta(NTrk), da0dphi(NTrk);
 
  702     auto fullCov = convertCovMatrix(vxCandidate);
 
  703     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  705       double trkCharge = 1.;
 
  706       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
  722     double P2 = Px*Px+Py*Py+Pz*Pz;
 
  723     double B = Px*
dx+Py*
dy+Pz*dz;
 
  725     double da0dx  = (Px*Pz)/P2;
 
  726     double da0dy  = (Py*Pz)/P2;
 
  727     double da0dz  = (Pz*Pz)/P2 - 1.;
 
  728     double da0dx0 = -da0dx;
 
  729     double da0dy0 = -da0dy;
 
  730     double da0dz0 = -da0dz;
 
  731     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  732       double dP2dqOverP = 2.*(Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it]);
 
  733       double dP2dtheta  = 2.*(Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it]);
 
  734       double dP2dphi    = 2.*(Px*dpxdphi[
it]+Py*dpydphi[
it]);
 
  735       da0dqOverP[
it] =  (B*(P2*dpzdqOverP[
it]-Pz*dP2dqOverP) +
 
  736                          Pz*P2*(
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it]+dz*dpzdqOverP[
it]))/(P2*P2);
 
  737       da0dtheta[
it]  =  (B*(P2*dpzdtheta[
it]-Pz*dP2dtheta) +
 
  738                          Pz*P2*(
dx*dpxdtheta[
it]+
dy*dpydtheta[
it]+dz*dpzdtheta[
it]))/(P2*P2);
 
  739       da0dphi[
it]    = -(B*Pz*dP2dphi -
 
  740                          Pz*P2*(
dx*dpxdphi[
it]+
dy*dpydphi[
it]))/(P2*P2);
 
  743     unsigned int ndim = 0;
 
  744     if (fullCov.size() != 0) {
 
  745       ndim = fullCov.rows();
 
  751     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
  753       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  756         D_vec(5*
it+2)  = da0dphi[
it];
 
  757         D_vec(5*
it+3)  = da0dtheta[
it];
 
  758         D_vec(5*
it+4)  = da0dqOverP[
it];
 
  760       D_vec(5*NTrk+0) = da0dx;
 
  761       D_vec(5*NTrk+1) = da0dy;
 
  762       D_vec(5*NTrk+2) = da0dz;
 
  763       D_vec(5*NTrk+3) = da0dx0;
 
  764       D_vec(5*NTrk+4) = da0dy0;
 
  765       D_vec(5*NTrk+5) = da0dz0;
 
  768       if (fullCov.size() != 0) {
 
  769         W_mat.block(0,0,ndim,ndim) = fullCov;
 
  772         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
  773         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
  775       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) =  
vertex->covariancePosition();
 
  776       V0_err = D_vec.transpose() * W_mat * D_vec;
 
  777     } 
else if (ndim == 3*NTrk+3) {
 
  782       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  783         D_vec(3*
it+3)  = da0dphi[
it];
 
  784         D_vec(3*
it+4)  = da0dtheta[
it];
 
  785         D_vec(3*
it+5)  = da0dqOverP[
it];
 
  787       D_vec(3*NTrk+3) = da0dx0;
 
  788       D_vec(3*NTrk+4) = da0dy0;
 
  789       D_vec(3*NTrk+5) = da0dz0;
 
  792       W_mat.block(0,0,ndim,ndim) = fullCov;
 
  793       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) =  
vertex->covariancePosition();
 
  794       V0_err = D_vec.transpose() * W_mat * D_vec;
 
  797     double a0Errsq = V0_err(0,0);
 
  798     if (a0Errsq <= 0.) 
ATH_MSG_DEBUG(
"a0Error: negative sqrt a0Errsq " << a0Errsq);
 
  799     double a0Err = (a0Errsq>0.) ? sqrt(a0Errsq) : 0.;
 
  805     return a0Error(vxCandidate, 
vertex, 
false);
 
  812     double dx = vert.x();
 
  813     double dy = vert.y();
 
  814     double dz = vert.z();
 
  815     double Px=0., Py=0., Pz=0.;
 
  816     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
  817     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
  818     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk);
 
  819     std::vector<double>da0dqOverP(NTrk), da0dtheta(NTrk), da0dphi(NTrk);
 
  821     auto fullCov = convertCovMatrix(vxCandidate);
 
  822     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  824       double trkCharge = 1.;
 
  825       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
  846       cosineTheta = cosTheta(vxCandidate,
vertex);
 
  849       cosineTheta = cosTheta_xy(vxCandidate,
vertex);
 
  850       a0val = a0xy(vxCandidate,
vertex);
 
  854     double P = sqrt(Px*Px+Py*Py+Pz*Pz);
 
  857     double da0dx  = (Px/
P*
r*cosineTheta - 
dx)/a0val;
 
  858     double da0dy  = (Py/
P*
r*cosineTheta - 
dy)/a0val;
 
  859     double da0dz  = (Pz/
P*
r*cosineTheta - dz)/a0val;
 
  860     double da0dx0 = -da0dx;
 
  861     double da0dy0 = -da0dy;
 
  862     double da0dz0 = -da0dz;
 
  863     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  864       da0dqOverP[
it] = -(
r*cosineTheta/
P)*(da0dx*dpxdqOverP[
it]+da0dy*dpydqOverP[
it]+da0dz*dpzdqOverP[
it]);
 
  865       da0dtheta[
it]  = -(
r*cosineTheta/
P)*(da0dx*dpxdtheta[
it]+da0dy*dpydtheta[
it]+da0dz*dpzdtheta[
it]);
 
  866       da0dphi[
it]    = -(
r*cosineTheta/
P)*(da0dx*dpxdphi[
it]+da0dy*dpydphi[
it]);
 
  869     unsigned int ndim = 0;
 
  870     if (fullCov.size() != 0) {
 
  871       ndim = fullCov.rows();
 
  877     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
  879       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  882         D_vec(5*
it+2)  = da0dphi[
it];
 
  883         D_vec(5*
it+3)  = da0dtheta[
it];
 
  884         D_vec(5*
it+4)  = da0dqOverP[
it];
 
  886       D_vec(5*NTrk+0) = da0dx;
 
  887       D_vec(5*NTrk+1) = da0dy;
 
  888       D_vec(5*NTrk+2) = da0dz;
 
  889       D_vec(5*NTrk+3) = da0dx0;
 
  890       D_vec(5*NTrk+4) = da0dy0;
 
  891       D_vec(5*NTrk+5) = da0dz0;
 
  894       if (fullCov.size() != 0) {
 
  895         W_mat.block(0,0,ndim,ndim) = fullCov;
 
  898         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
  899         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
  901       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
  902       V0_err = D_vec.transpose() * W_mat * D_vec;
 
  903     } 
else if (ndim == 3*NTrk+3) {
 
  908       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  909         D_vec(3*
it+3)  = da0dphi[
it];
 
  910         D_vec(3*
it+4)  = da0dtheta[
it];
 
  911         D_vec(3*
it+5)  = da0dqOverP[
it];
 
  913       D_vec(3*NTrk+3) = da0dx0;
 
  914       D_vec(3*NTrk+4) = da0dy0;
 
  915       D_vec(3*NTrk+5) = da0dz0;
 
  918       W_mat.block(0,0,ndim,ndim) = fullCov;
 
  919       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) =  
vertex->covariancePosition();
 
  920       V0_err = D_vec.transpose() * W_mat * D_vec;
 
  923     double a0Errsq = V0_err(0,0);
 
  924     if (a0Errsq <= 0.) 
ATH_MSG_DEBUG(
"a0Error: negative sqrt a0Errsq " << a0Errsq);
 
  925     double a0Err = (a0Errsq>0.) ? sqrt(a0Errsq) : 0.;
 
  932     double dx = vert.x();
 
  933     double dy = vert.y();
 
  942     double dx = vert.x();
 
  943     double dy = vert.y();
 
  946     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
  947     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
  948     std::vector<double>dLxydqOverP(NTrk), dLxydtheta(NTrk), dLxydphi(NTrk);
 
  950     auto fullCov = convertCovMatrix(vxCandidate);
 
  951     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  953       double trkCharge = 1.;
 
  954       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
  967     double PTsq = Px*Px+Py*Py;
 
  968     double PT = (PTsq>0.) ? sqrt(PTsq) : 0.;
 
  969     double LXYoverPT = (Px*
dx+Py*
dy)/PTsq;
 
  971     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  972       double dPTdqOverP  = (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
  973       double dPTdtheta   = (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
  974       double dPTdphi     = (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
  975       dLxydqOverP[
it] = (
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it])/
PT-LXYoverPT*dPTdqOverP;
 
  976       dLxydtheta[
it]  = (
dx*dpxdtheta[
it]+
dy*dpydtheta[
it])/
PT-LXYoverPT*dPTdtheta;
 
  977       dLxydphi[
it]    = (
dx*dpxdphi[
it]+
dy*dpydphi[
it])/
PT-LXYoverPT*dPTdphi;
 
  979     double dLxydx = Px/
PT;
 
  980     double dLxydy = Py/
PT;
 
  981     double dLxydx0 = -dLxydx;
 
  982     double dLxydy0 = -dLxydy;
 
  984     unsigned int ndim = 0;
 
  985     if (fullCov.size() != 0) {
 
  986       ndim = fullCov.rows();
 
  992     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
  994       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
  997         D_vec(5*
it+2)  = dLxydphi[
it];
 
  998         D_vec(5*
it+3)  = dLxydtheta[
it];
 
  999         D_vec(5*
it+4)  = dLxydqOverP[
it];
 
 1001       D_vec(5*NTrk+0) = dLxydx;
 
 1002       D_vec(5*NTrk+1) = dLxydy;
 
 1003       D_vec(5*NTrk+2) = 0.;
 
 1004       D_vec(5*NTrk+3) = dLxydx0;
 
 1005       D_vec(5*NTrk+4) = dLxydy0;
 
 1006       D_vec(5*NTrk+5) = 0.;
 
 1008       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1009       if (fullCov.size() != 0) {
 
 1010         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1013         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1014         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 1016       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1017       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1018     } 
else if (ndim == 3*NTrk+3) {
 
 1023       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1024         D_vec(3*
it+3) = dLxydphi[
it];
 
 1025         D_vec(3*
it+4) = dLxydtheta[
it];
 
 1026         D_vec(3*
it+5) = dLxydqOverP[
it];
 
 1028       D_vec(3*NTrk+3) = dLxydx0;
 
 1029       D_vec(3*NTrk+4) = dLxydy0;
 
 1030       D_vec(3*NTrk+5) = 0.;
 
 1032       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1033       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1034       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1035       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1038     double LxyErrsq = V0_err(0,0);
 
 1039     if (LxyErrsq <= 0.) 
ATH_MSG_DEBUG(
"lxyError: negative sqrt LxyErrsq " << LxyErrsq);
 
 1040     return (LxyErrsq>0.) ? sqrt(LxyErrsq) : 0.;
 
 1046     double dx = vert.x();
 
 1047     double dy = vert.y();
 
 1048     double dz = vert.z();
 
 1057     double dx = vert.x();
 
 1058     double dy = vert.y();
 
 1059     double dz = vert.z();
 
 1061     double Px=0., Py=0., Pz=0.;
 
 1062     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 1063     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 1064     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk);
 
 1065     std::vector<double>dLxyzdqOverP(NTrk), dLxyzdtheta(NTrk), dLxyzdphi(NTrk);
 
 1067     auto fullCov = convertCovMatrix(vxCandidate);
 
 1068     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1070       double trkCharge = 1.;
 
 1071       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 1087     double Psq = Px*Px+Py*Py+Pz*Pz;
 
 1088     double P = (Psq>0.) ? sqrt(Psq) : 0.;
 
 1089     double LXYZoverP = (Px*
dx+Py*
dy+Pz*dz)/Psq;
 
 1091     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1092       double dPdqOverP  = (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it])/
P;
 
 1093       double dPdtheta   = (Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/
P;
 
 1094       double dPdphi     = (Px*dpxdphi[
it]+Py*dpydphi[
it])/
P;
 
 1095       dLxyzdqOverP[
it] = (
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it]+dz*dpzdqOverP[
it])/
P-LXYZoverP*dPdqOverP;
 
 1096       dLxyzdtheta[
it]  = (
dx*dpxdtheta[
it]+
dy*dpydtheta[
it]+dz*dpzdtheta[
it])/
P-LXYZoverP*dPdtheta;
 
 1097       dLxyzdphi[
it]    = (
dx*dpxdphi[
it]+
dy*dpydphi[
it])/
P-LXYZoverP*dPdphi;
 
 1099     double dLxyzdx = Px/
P;
 
 1100     double dLxyzdy = Py/
P;
 
 1101     double dLxyzdz = Pz/
P;
 
 1102     double dLxyzdx0 = -dLxyzdx;
 
 1103     double dLxyzdy0 = -dLxyzdy;
 
 1104     double dLxyzdz0 = -dLxyzdz;
 
 1106     unsigned int ndim = 0;
 
 1107     if (fullCov.size() != 0) {
 
 1108       ndim = fullCov.rows();
 
 1114     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 1116       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1119         D_vec(5*
it+2)  = dLxyzdphi[
it];
 
 1120         D_vec(5*
it+3)  = dLxyzdtheta[
it];
 
 1121         D_vec(5*
it+4)  = dLxyzdqOverP[
it];
 
 1123       D_vec(5*NTrk+0) = dLxyzdx;
 
 1124       D_vec(5*NTrk+1) = dLxyzdy;
 
 1125       D_vec(5*NTrk+2) = dLxyzdz;
 
 1126       D_vec(5*NTrk+3) = dLxyzdx0;
 
 1127       D_vec(5*NTrk+4) = dLxyzdy0;
 
 1128       D_vec(5*NTrk+5) = dLxyzdz0;
 
 1130       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1131       if (fullCov.size() != 0) {
 
 1132         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1135         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1136         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 1138       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1139       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1140     } 
else if (ndim == 3*NTrk+3) {
 
 1145       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1146         D_vec(3*
it+3) = dLxyzdphi[
it];
 
 1147         D_vec(3*
it+4) = dLxyzdtheta[
it];
 
 1148         D_vec(3*
it+5) = dLxyzdqOverP[
it];
 
 1150       D_vec(3*NTrk+3) = dLxyzdx0;
 
 1151       D_vec(3*NTrk+4) = dLxyzdy0;
 
 1152       D_vec(3*NTrk+5) = dLxyzdz0;
 
 1154       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1155       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1156       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1157       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1160     double LxyzErrsq = V0_err(0,0);
 
 1161     if (LxyzErrsq <= 0.) 
ATH_MSG_DEBUG(
"lxyzError: negative sqrt LxyzErrsq " << LxyzErrsq);
 
 1162     return (LxyzErrsq>0.) ? sqrt(LxyzErrsq) : 0.;
 
 1167     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
 1175     if (
masses.size() != NTrk) {
 
 1176       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1180     double CONST = 1000./299.792;
 
 1181     double M = invariantMass(vxCandidate, 
masses);
 
 1182     double LXY = lxy(vxCandidate,
vertex);
 
 1183     double PT = V0Momentum(vxCandidate).perp();
 
 1189     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
 1197     if (
masses.size() != NTrk) {
 
 1198       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1203     double mass = invariantMass(vxCandidate,
masses);
 
 1207     double deltaTau = -(massV0-
mass)*cov_i12/cov_i11;
 
 1208     return Tau + deltaTau;
 
 1214     double CONST = 1000./299.792;
 
 1215     double LXY = lxy(vxCandidate,
vertex);
 
 1216     double PT = V0Momentum(vxCandidate).perp();
 
 1223     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
 1232     if (
masses.size() != NTrk) {
 
 1233       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1237     double CONST = 1000./299.792;
 
 1238     double PT = V0Momentum(vxCandidate).perp();
 
 1240     double dx = vert.x();
 
 1241     double dy = vert.y();
 
 1242     double M = invariantMass(vxCandidate, 
masses);
 
 1243     double E=0., Px=0., Py=0., Pz=0.;
 
 1244     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 1245     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 1246     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk), dedqOverP(NTrk);
 
 1247     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 1249     auto fullCov = convertCovMatrix(vxCandidate);
 
 1250     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1252       double trkCharge = 1.;
 
 1253       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 1258       double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 1273     double LXY = Px*
dx+Py*
dy;
 
 1275     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1276       double dMdqOverP   = -(Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it]-
E*dedqOverP[
it])/M;
 
 1277       double dMdtheta    = -(Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/M;
 
 1278       double dMdphi      = -(Px*dpxdphi[
it]+Py*dpydphi[
it])/M;
 
 1279       double dPTdqOverP  =  (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
 1280       double dPTdtheta   =  (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
 1281       double dPTdphi     =  (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
 1282       double dLXYdqOverP =  
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it];
 
 1283       double dLXYdtheta  =  
dx*dpxdtheta[
it]+
dy*dpydtheta[
it];
 
 1284       double dLXYdphi    =  
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 1285       dTaudqOverP[
it] =  (LXY*dMdqOverP+M*dLXYdqOverP)/(
PT*
PT)-(2.*LXY*M*dPTdqOverP)/(
PT*
PT*
PT);
 
 1286       dTaudtheta[
it]  =  (LXY*dMdtheta+M*dLXYdtheta)/(
PT*
PT)-(2.*LXY*M*dPTdtheta)/(
PT*
PT*
PT);
 
 1287       dTaudphi[
it]    =  (LXY*dMdphi+M*dLXYdphi)/(
PT*
PT)-(2.*LXY*M*dPTdphi)/(
PT*
PT*
PT);
 
 1289     double dTaudx = (M*Px)/(
PT*
PT);
 
 1290     double dTaudy = (M*Py)/(
PT*
PT);
 
 1291     double dTaudx0 = -dTaudx;
 
 1292     double dTaudy0 = -dTaudy;
 
 1294     unsigned int ndim = 0;
 
 1295     if (fullCov.size() != 0) {
 
 1296       ndim = fullCov.rows();
 
 1302     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 1304       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1307         D_vec(5*
it+2)  = dTaudphi[
it];
 
 1308         D_vec(5*
it+3)  = dTaudtheta[
it];
 
 1309         D_vec(5*
it+4)  = dTaudqOverP[
it];
 
 1311       D_vec(5*NTrk+0) = dTaudx;
 
 1312       D_vec(5*NTrk+1) = dTaudy;
 
 1313       D_vec(5*NTrk+2) = 0.;
 
 1314       D_vec(5*NTrk+3) = dTaudx0;
 
 1315       D_vec(5*NTrk+4) = dTaudy0;
 
 1316       D_vec(5*NTrk+5) = 0.;
 
 1318       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1319       if (fullCov.size() != 0) {
 
 1320         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1323         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1324         W_mat.block(5*NTrk,5*NTrk,3,3) =  vxCandidate->covariancePosition();
 
 1326       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1327       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1328     } 
else if (ndim == 3*NTrk+3) {
 
 1333       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1334         D_vec(3*
it+3)  = dTaudphi[
it];
 
 1335         D_vec(3*
it+4)  = dTaudtheta[
it];
 
 1336         D_vec(3*
it+5)  = dTaudqOverP[
it];
 
 1338       D_vec(3*NTrk+3) = dTaudx0;
 
 1339       D_vec(3*NTrk+4) = dTaudy0;
 
 1340       D_vec(3*NTrk+5) = 0.;
 
 1342       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1343       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1344       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) =  
vertex->covariancePosition();
 
 1345       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1348     double tauErrsq = V0_err(0,0);
 
 1349     if (tauErrsq <= 0.) 
ATH_MSG_DEBUG(
"tauError: negative sqrt tauErrsq " << tauErrsq);
 
 1350     double tauErr = (tauErrsq>0.) ? sqrt(tauErrsq) : 0.;
 
 1351     return CONST*tauErr;
 
 1354   double V0Tools::tauError(
const xAOD::Vertex * vxCandidate, 
const xAOD::Vertex* 
vertex, 
double posTrackMass, 
double negTrackMass, 
double massV0)
 const 
 1356     std::array<double, 2> 
masses = {posTrackMass, negTrackMass};
 
 1364     if (
masses.size() != NTrk) {
 
 1365       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1368     double error = -999999.;
 
 1372     if (cov_i11 > 0.) 
error = 1./sqrt(cov_i11);
 
 1380     double CONST = 1000./299.792;
 
 1381     double PT = V0Momentum(vxCandidate).perp();
 
 1383     double dx = vecsub.x();
 
 1384     double dy = vecsub.y();
 
 1386     double Px=0., Py=0.;
 
 1387     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 1388     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 1389     std::vector<double>dPTdtheta(NTrk), dPTdphi(NTrk);
 
 1390     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 1392     auto fullCov = convertCovMatrix(vxCandidate);
 
 1393     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1395       double trkCharge = 1.;
 
 1396       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 1409     double LXY = Px*
dx+Py*
dy;
 
 1411     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1412       double dPTdqOverP  = (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
 1413       double dPTdtheta   = (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
 1414       double dPTdphi     = (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
 1415       double dLXYdqOverP = 
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it];
 
 1416       double dLXYdtheta  = 
dx*dpxdtheta[
it]+
dy*dpydtheta[
it];
 
 1417       double dLXYdphi = 
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 1418       dTaudqOverP[
it] = M*dLXYdqOverP/(
PT*
PT)-(2.*LXY*M*dPTdqOverP)/(
PT*
PT*
PT);
 
 1419       dTaudtheta[
it]  = M*dLXYdtheta/(
PT*
PT)-(2.*LXY*M*dPTdtheta)/(
PT*
PT*
PT);
 
 1420       dTaudphi[
it]    = M*dLXYdphi/(
PT*
PT)-(2.*LXY*M*dPTdphi)/(
PT*
PT*
PT);
 
 1422     double dTaudx = (M*Px)/(
PT*
PT);
 
 1423     double dTaudy = (M*Py)/(
PT*
PT);
 
 1424     double dTaudx0 = -dTaudx;
 
 1425     double dTaudy0 = -dTaudy;
 
 1427     unsigned int ndim = 0;
 
 1428     if (fullCov.size() != 0) {
 
 1429       ndim = fullCov.rows();
 
 1435     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 1437       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1440         D_vec(5*
it+2) = dTaudphi[
it];
 
 1441         D_vec(5*
it+3) = dTaudtheta[
it];
 
 1442         D_vec(5*
it+4) = dTaudqOverP[
it];
 
 1444       D_vec(5*NTrk+0) = dTaudx;
 
 1445       D_vec(5*NTrk+1) = dTaudy;
 
 1446       D_vec(5*NTrk+2) = 0.;
 
 1447       D_vec(5*NTrk+3) = dTaudx0;
 
 1448       D_vec(5*NTrk+4) = dTaudy0;
 
 1449       D_vec(5*NTrk+5) = 0.;
 
 1451       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1452       if (fullCov.size() != 0) {
 
 1453         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1456         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1457         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 1459       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1460       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1461     } 
else if (ndim == 3*NTrk+3) {
 
 1466       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1467         D_vec(3*
it+3)  = dTaudphi[
it];
 
 1468         D_vec(3*
it+4)  = dTaudtheta[
it];
 
 1469         D_vec(3*
it+5)  = dTaudqOverP[
it];
 
 1471       D_vec(3*NTrk+3) = dTaudx0;
 
 1472       D_vec(3*NTrk+4) = dTaudy0;
 
 1473       D_vec(3*NTrk+5) = 0.;
 
 1475       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1476       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1477       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1478       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1481     double tauErrsq = V0_err(0,0);
 
 1482     if (tauErrsq <= 0.) 
ATH_MSG_DEBUG(
"tauError: negative sqrt tauErrsq " << tauErrsq);
 
 1483     double tauErr = (tauErrsq>0.) ? sqrt(tauErrsq) : 0.;
 
 1484     return CONST*tauErr;
 
 1490     if (
masses.size() != NTrk) {
 
 1491       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1495     double CONST = 1000./299.792;
 
 1496     double M = invariantMass(vxCandidate, 
masses);
 
 1497     double LXYZ = lxyz(vxCandidate,
vertex);
 
 1498     double P = V0Momentum(vxCandidate).mag();
 
 1505     double CONST = 1000./299.792;
 
 1506     double LXYZ = lxyz(vxCandidate,
vertex);
 
 1507     double P = V0Momentum(vxCandidate).mag();
 
 1515     if (
masses.size() != NTrk) {
 
 1516       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 1520     double CONST = 1000./299.792;
 
 1521     double P = V0Momentum(vxCandidate).mag();
 
 1523     double dx = vert.x();
 
 1524     double dy = vert.y();
 
 1525     double dz = vert.z();
 
 1526     double M = invariantMass(vxCandidate, 
masses);
 
 1527     double E=0., Px=0., Py=0., Pz=0.;
 
 1528     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 1529     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 1530     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk), dedqOverP(NTrk);
 
 1531     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 1533     auto fullCov = convertCovMatrix(vxCandidate);
 
 1534     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1536       double trkCharge = 1.;
 
 1537       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 1542       double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 1557     double LXYZ = Px*
dx+Py*
dy+Pz*dz;
 
 1559     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1560       double dMdqOverP    = -(Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it]-
E*dedqOverP[
it])/M;
 
 1561       double dMdtheta     = -(Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/M;
 
 1562       double dMdphi       = -(Px*dpxdphi[
it]+Py*dpydphi[
it])/M;
 
 1563       double dPdqOverP    =  (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it])/
P;
 
 1564       double dPdtheta     =  (Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/
P;
 
 1565       double dPdphi       =  (Px*dpxdphi[
it]+Py*dpydphi[
it])/
P;
 
 1566       double dLXYZdqOverP =  
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it]+dz*dpzdqOverP[
it];
 
 1567       double dLXYZdtheta  =  
dx*dpxdtheta[
it]+
dy*dpydtheta[
it]+dz*dpzdtheta[
it];
 
 1568       double dLXYZdphi    =  
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 1569       dTaudqOverP[
it]  =  (LXYZ*dMdqOverP+M*dLXYZdqOverP)/(
P*
P)-(2.*LXYZ*M*dPdqOverP)/(
P*
P*
P);
 
 1570       dTaudtheta[
it]   =  (LXYZ*dMdtheta+M*dLXYZdtheta)/(
P*
P)-(2.*LXYZ*M*dPdtheta)/(
P*
P*
P);
 
 1571       dTaudphi[
it]     =  (LXYZ*dMdphi+M*dLXYZdphi)/(
P*
P)-(2.*LXYZ*M*dPdphi)/(
P*
P*
P);
 
 1573     double dTaudx = (M*Px)/(
P*
P);
 
 1574     double dTaudy = (M*Py)/(
P*
P);
 
 1575     double dTaudz = (M*Pz)/(
P*
P);
 
 1576     double dTaudx0 = -dTaudx;
 
 1577     double dTaudy0 = -dTaudy;
 
 1578     double dTaudz0 = -dTaudz;
 
 1580     unsigned int ndim = 0;
 
 1581     if (fullCov.size() != 0) {
 
 1582       ndim = fullCov.rows();
 
 1588     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 1590       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1593         D_vec(5*
it+2) = dTaudphi[
it];
 
 1594         D_vec(5*
it+3) = dTaudtheta[
it];
 
 1595         D_vec(5*
it+4) = dTaudqOverP[
it];
 
 1597       D_vec(5*NTrk+0) = dTaudx;
 
 1598       D_vec(5*NTrk+1) = dTaudy;
 
 1599       D_vec(5*NTrk+2) = dTaudz;
 
 1600       D_vec(5*NTrk+3) = dTaudx0;
 
 1601       D_vec(5*NTrk+4) = dTaudy0;
 
 1602       D_vec(5*NTrk+5) = dTaudz0;
 
 1604       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1605       if (fullCov.size() != 0) {
 
 1606         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1609         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1610         W_mat.block(5*NTrk,5*NTrk,3,3) =  vxCandidate->covariancePosition();
 
 1612       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1613       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1614     } 
else if (ndim == 3*NTrk+3) {
 
 1619       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1620         D_vec(3*
it+3) = dTaudphi[
it];
 
 1621         D_vec(3*
it+4) = dTaudtheta[
it];
 
 1622         D_vec(3*
it+5) = dTaudqOverP[
it];
 
 1624       D_vec(3*NTrk+3) = dTaudx0;
 
 1625       D_vec(3*NTrk+4) = dTaudy0;
 
 1626       D_vec(3*NTrk+5) = dTaudz0;
 
 1628       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1629       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1630       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) =  
vertex->covariancePosition();
 
 1631       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1634     double tauErrsq = V0_err(0,0);
 
 1635     if (tauErrsq <= 0.) 
ATH_MSG_DEBUG(
"tauError: negative sqrt tauErrsq " << tauErrsq);
 
 1636     double tauErr = (tauErrsq>0.) ? sqrt(tauErrsq) : 0.;
 
 1637     return CONST*tauErr;
 
 1644     double CONST = 1000./299.792;
 
 1645     double P = V0Momentum(vxCandidate).mag();
 
 1647     double dx = vecsub.x();
 
 1648     double dy = vecsub.y();
 
 1649     double dz = vecsub.z();
 
 1651     double Px=0., Py=0., Pz=0.;
 
 1652     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 1653     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 1654     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk);
 
 1655     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 1657     auto fullCov = convertCovMatrix(vxCandidate);
 
 1658     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1660       double trkCharge = 1.;
 
 1661       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 1677     double LXYZ = Px*
dx+Py*
dy+Pz*dz;
 
 1679     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1680       double dPdqOverP    = (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it])/
P;
 
 1681       double dPdtheta     = (Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/
P;
 
 1682       double dPdphi       = (Px*dpxdphi[
it]+Py*dpydphi[
it])/
P;
 
 1683       double dLXYZdqOverP = 
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it]+dz*dpzdqOverP[
it];
 
 1684       double dLXYZdtheta  = 
dx*dpxdtheta[
it]+
dy*dpydtheta[
it]+dz*dpzdtheta[
it];
 
 1685       double dLXYZdphi    = 
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 1686       dTaudqOverP[
it]  = M*dLXYZdqOverP/(
P*
P)-(2.*LXYZ*M*dPdqOverP)/(
P*
P*
P);
 
 1687       dTaudtheta[
it]   = M*dLXYZdtheta/(
P*
P)-(2.*LXYZ*M*dPdtheta)/(
P*
P*
P);
 
 1688       dTaudphi[
it]     = M*dLXYZdphi/(
P*
P)-(2.*LXYZ*M*dPdphi)/(
P*
P*
P);
 
 1690     double dTaudx = (M*Px)/(
P*
P);
 
 1691     double dTaudy = (M*Py)/(
P*
P);
 
 1692     double dTaudz = (M*Pz)/(
P*
P);
 
 1693     double dTaudx0 = -dTaudx;
 
 1694     double dTaudy0 = -dTaudy;
 
 1695     double dTaudz0 = -dTaudz;
 
 1697     unsigned int ndim = 0;
 
 1698     if (fullCov.size() != 0) {
 
 1699       ndim = fullCov.rows();
 
 1705     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 1707       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1710         D_vec(5*
it+2) = dTaudphi[
it];
 
 1711         D_vec(5*
it+3) = dTaudtheta[
it];
 
 1712         D_vec(5*
it+4) = dTaudqOverP[
it];
 
 1714       D_vec(5*NTrk+0) = dTaudx;
 
 1715       D_vec(5*NTrk+1) = dTaudy;
 
 1716       D_vec(5*NTrk+2) = dTaudz;
 
 1717       D_vec(5*NTrk+3) = dTaudx0;
 
 1718       D_vec(5*NTrk+4) = dTaudy0;
 
 1719       D_vec(5*NTrk+5) = dTaudz0;
 
 1721       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 1722       if (fullCov.size() != 0) {
 
 1723         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1726         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 1727         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 1729       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1730       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1731     } 
else if (ndim == 3*NTrk+3) {
 
 1736       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1737         D_vec(3*
it+3) = dTaudphi[
it];
 
 1738         D_vec(3*
it+4) = dTaudtheta[
it];
 
 1739         D_vec(3*
it+5) = dTaudqOverP[
it];
 
 1741       D_vec(3*NTrk+3) = dTaudx0;
 
 1742       D_vec(3*NTrk+4) = dTaudy0;
 
 1743       D_vec(3*NTrk+5) = dTaudz0;
 
 1745       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 1746       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 1747       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 1748       V0_err = D_vec.transpose() * W_mat * D_vec;
 
 1751     double tauErrsq = V0_err(0,0);
 
 1752     if (tauErrsq <= 0.) 
ATH_MSG_DEBUG(
"tauError: negative sqrt tauErrsq " << tauErrsq);
 
 1753     double tauErr = (tauErrsq>0.) ? sqrt(tauErrsq) : 0.;
 
 1754     return CONST*tauErr;
 
 1757   double V0Tools::thetaStar(
const xAOD::Vertex * vxCandidate, 
double mass1, 
double mass2) 
 
 1762     CLHEP::HepLorentzVector v1(
V1.Px(),
V1.Py(),
V1.Pz(),
V1.E());
 
 1763     CLHEP::HepLorentzVector 
v2(V2.Px(),V2.Py(),V2.Pz(),V2.E());
 
 1764     CLHEP::HepLorentzVector 
v0 = v1 + 
v2;
 
 1765     CLHEP::Hep3Vector boost_v0 = 
v0.boostVector();
 
 1767     v1.boost( boost_v0 );
 
 1768     v2.boost( boost_v0 );
 
 1769     theta = 
v0.angle( v1.vect() );
 
 1773   double V0Tools::cosThetaStar(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass) 
 
 1777     CLHEP::HepLorentzVector posMom(PosMom.Px(),PosMom.Py(),PosMom.Pz(),PosMom.E());
 
 1778     CLHEP::HepLorentzVector negMom(NegMom.Px(),NegMom.Py(),NegMom.Pz(),NegMom.E());
 
 1779     return cosThetaStar(posMom, negMom);
 
 1782   double V0Tools::cosThetaStar(
const CLHEP::HepLorentzVector & posTrack, 
const CLHEP::HepLorentzVector & negTrack)
 
 1784     CLHEP::HepLorentzVector 
v0(posTrack + negTrack);
 
 1785     double Mv0   = 
v0.m();
 
 1786     double Mplus = posTrack.m();
 
 1787     double Mminus= negTrack.m();
 
 1789     double pssq = (Mv0*Mv0-(Mplus+Mminus)*(Mplus+Mminus))*(Mv0*Mv0-(Mplus-Mminus)*(Mplus-Mminus));
 
 1790     double ps = (pssq>0.) ? sqrt(pssq) : 0.;
 
 1792     double pp = 
v0.px()*posTrack.px() + 
v0.py()*posTrack.py() + 
v0.pz()*posTrack.pz();
 
 1793     return ( 
v0.e()*pp - Pv0*Pv0*posTrack.e())/( Mv0*
ps*Pv0);
 
 1797   double V0Tools::phiStar(
const xAOD::Vertex * vxCandidate, 
double posTrackMass, 
double negTrackMass) 
 
 1801     CLHEP::HepLorentzVector v_pos(V_pos.Px(),V_pos.Py(),V_pos.Pz(),V_pos.E());
 
 1802     CLHEP::HepLorentzVector v_neg(V_neg.Px(),V_neg.Py(),V_neg.Pz(),V_neg.E());
 
 1803     return phiStar(v_pos+v_neg,v_pos);
 
 1806   double V0Tools::phiStar(
const CLHEP::HepLorentzVector & 
v0, 
const CLHEP::HepLorentzVector & 
track)
 
 1808     double phiStar = -999999.;
 
 1809     CLHEP::Hep3Vector V0 = 
v0.getV();
 
 1810     CLHEP::Hep3Vector trk = 
track.getV();
 
 1812     trk.rotateZ(-V0.phi());
 
 1813     trk.rotateY(-V0.theta());
 
 1820     phiStar = atan2(trk.y(),trk.x());
 
 1826     auto mom = V0Momentum(vxCandidate);
 
 1827     auto vtx1 = vtx(vxCandidate);
 
 1829     return (
mom.dot(vtx1))/(
mom.mag()*(vtx1).
mag());
 
 1834     auto mom = V0Momentum(vxCandidate);
 
 1835     auto vtx1 = vtx(vxCandidate);
 
 1836     vtx1 -= 
vertex->position();
 
 1837     return (
mom.dot((vtx1)))/(
mom.mag()*(vtx1).
mag());
 
 1842     auto mom = V0Momentum(vxCandidate);
 
 1843     auto vtx1 = vtx(vxCandidate);
 
 1845     double pT = 
mom.perp();
 
 1846     return (
mom.x()*vtx1.x()+
mom.y()*vtx1.y())/(
pT*vtx1.perp());
 
 1851     auto mom = V0Momentum(vxCandidate);
 
 1852     auto vtx1 = vtx(vxCandidate);
 
 1853     vtx1 -= 
vertex->position();
 
 1854     double pT = 
mom.perp();
 
 1855     return (
mom.x()*vtx1.x()+
mom.y()*vtx1.y())/(
pT*vtx1.perp());
 
 1862     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1881     if (NTrk != 2) 
return origTrk;
 
 1882     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 1892     if (NTrk != 2) 
return origTrk;
 
 1893     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2140   double V0Tools::invariantMassBeforeFitIP(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
 2142     double px = 0., 
py = 0., 
pz = 0., 
e = 0.;
 
 2144     if (
masses.size() != NTrk) {
 
 2145       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2148     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2151         if (TP == 
nullptr) 
return -999999.;
 
 2152         TLorentzVector Tp4 = TP->
p4();
 
 2157         double pe = (pesq>0.) ? sqrt(pesq) : 0.;
 
 2162     return (msq>0.) ? sqrt(msq) : 0.;
 
 2165   double V0Tools::invariantMassBeforeFit(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses, 
const EventContext& ctx, 
const Trk::IExtrapolator* extrapolator)
 const 
 2168     double px = 0., 
py = 0., 
pz = 0., 
e = 0.;
 
 2170     if (
masses.size() != NTrk) {
 
 2171       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2174     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2177         if (TP == 
nullptr) 
return -999999.;
 
 2178         std::unique_ptr<const Trk::TrackParameters> extrPer =
 
 2180         if (extrPer == 
nullptr)
 
 2186         double pe = (pesq>0.) ? sqrt(pesq) : 0.;
 
 2191     return (msq>0.) ? sqrt(msq) : 0.;
 
 2194   double V0Tools::invariantMassBeforeFit(
const xAOD::Vertex * vxCandidate, 
 
 2198     double px = 0., 
py = 0., 
pz = 0., 
e = 0.;
 
 2201       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2204     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2207         if (TP == 
nullptr) 
return -999999.;
 
 2208         std::unique_ptr<const Trk::TrackParameters> extrPer =
 
 2210         if (extrPer == 
nullptr)
 
 2216         double pe = (pesq>0.) ? sqrt(pesq) : 0.;
 
 2221     return (msq>0.) ? sqrt(msq) : 0.;
 
 2224   double V0Tools::invariantMassErrorBeforeFitIP(
const xAOD::Vertex * vxCandidate, std::span<const double> 
masses)
 const 
 2227     if (
masses.size() != NTrk) {
 
 2228       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2231     double mass = invariantMassBeforeFitIP(vxCandidate, 
masses);
 
 2232     double E=0., Px=0., Py=0., Pz=0.;
 
 2234     std::vector<double>dm2dphi(NTrk), dm2dtheta(NTrk), dm2dqOverP(NTrk);
 
 2236     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2239         if (TP == 
nullptr) 
return -999999.;
 
 2241         V0_cor(5*
it+2,5*
it+2) = cov_tmp(2,2);
 
 2242         V0_cor(5*
it+2,5*
it+3) = cov_tmp(2,3);
 
 2243         V0_cor(5*
it+2,5*
it+4) = cov_tmp(2,4);
 
 2244         V0_cor(5*
it+3,5*
it+3) = cov_tmp(3,3);
 
 2245         V0_cor(5*
it+3,5*
it+4) = cov_tmp(3,4);
 
 2246         V0_cor(5*
it+4,5*
it+4) = cov_tmp(4,4);
 
 2247         V0_cor(5*
it+3,5*
it+2) = cov_tmp(2,3);
 
 2248         V0_cor(5*
it+4,5*
it+2) = cov_tmp(2,4);
 
 2249         V0_cor(5*
it+4,5*
it+3) = cov_tmp(3,4);
 
 2255         double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 2258         TLorentzVector p4 = TP->
p4();
 
 2265     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2274     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2275       D_vec(5*
it+0,0)  = 0.;
 
 2276       D_vec(5*
it+1,0)  = 0.;
 
 2277       D_vec(5*
it+2,0)  = dm2dphi[
it];
 
 2278       D_vec(5*
it+3,0)  = dm2dtheta[
it];
 
 2279       D_vec(5*
it+4,0)  = dm2dqOverP[
it];
 
 2281     Amg::MatrixX V0_merr = D_vec.transpose() * V0_cor * D_vec;
 
 2283     double massVarsq = V0_merr(0,0);
 
 2284     if (massVarsq <= 0.) 
ATH_MSG_DEBUG(
"massError: negative sqrt massVarsq " << massVarsq);
 
 2285     double massVar = (massVarsq>0.) ? sqrt(massVarsq) : 0.;
 
 2286     double massErr = massVar/(2.*
mass);
 
 2294     if (
masses.size() != NTrk) {
 
 2295       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2299     return invariantMassErrorBeforeFit(vxCandidate,
masses,
vertex, ctx, extrap);
 
 2303   double V0Tools::invariantMassErrorBeforeFit(
const xAOD::Vertex * vxCandidate, 
 
 2307     if (
masses.size() != NTrk) {
 
 2308       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2312     double E=0., Px=0., Py=0., Pz=0.;
 
 2314     std::vector<double>dm2dphi(NTrk), dm2dtheta(NTrk), dm2dqOverP(NTrk);
 
 2316     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2319         if (TP == 
nullptr) 
return -999999.;
 
 2320         std::unique_ptr<const Trk::TrackParameters> extrPer =
 
 2322         if (extrPer == 
nullptr)
 
 2324         const AmgSymMatrix(5)* cov_tmp = extrPer->covariance();
 
 2325         V0_cor(5*
it+2,5*
it+2) = (*cov_tmp)(2,2);
 
 2326         V0_cor(5*
it+2,5*
it+3) = (*cov_tmp)(2,3);
 
 2327         V0_cor(5*
it+2,5*
it+4) = (*cov_tmp)(2,4);
 
 2328         V0_cor(5*
it+3,5*
it+3) = (*cov_tmp)(3,3);
 
 2329         V0_cor(5*
it+3,5*
it+4) = (*cov_tmp)(3,4);
 
 2330         V0_cor(5*
it+4,5*
it+4) = (*cov_tmp)(4,4);
 
 2331         V0_cor(5*
it+3,5*
it+2) = (*cov_tmp)(2,3);
 
 2332         V0_cor(5*
it+4,5*
it+2) = (*cov_tmp)(2,4);
 
 2333         V0_cor(5*
it+4,5*
it+3) = (*cov_tmp)(3,4);
 
 2339         double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 2347     double msq = 
E*
E - Px*Px - Py*Py - Pz*Pz;
 
 2348     double mass = (msq>0.) ? sqrt(msq) : 0.;
 
 2350     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2359     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2360       D_vec(5*
it+0,0)  = 0.;
 
 2361       D_vec(5*
it+1,0)  = 0.;
 
 2362       D_vec(5*
it+2,0)  = dm2dphi[
it];
 
 2363       D_vec(5*
it+3,0)  = dm2dtheta[
it];
 
 2364       D_vec(5*
it+4,0)  = dm2dqOverP[
it];
 
 2366     Amg::MatrixX V0_merr = D_vec.transpose() * V0_cor * D_vec;
 
 2368     double massVarsq = V0_merr(0,0);
 
 2369     if (massVarsq <= 0.) 
ATH_MSG_DEBUG(
"massError: negative sqrt massVarsq " << massVarsq);
 
 2370     double massVar = (massVarsq>0.) ? sqrt(massVarsq) : 0.;
 
 2371     double massErr = massVar/(2.*
mass);
 
 2380     if (
masses.size() != NTrk) {
 
 2381       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2385     double CONST = 1000./299.792;
 
 2386     double PT = V0Momentum(vxCandidate).perp();
 
 2388     double dx = vert.x();
 
 2389     double dy = vert.y();
 
 2390     double M = invariantMass(vxCandidate, 
masses);
 
 2391     double E=0., Px=0., Py=0., Pz=0.;
 
 2392     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 2393     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 2394     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk), dedqOverP(NTrk);
 
 2395     std::vector<double>dMdqOverP(NTrk), dMdtheta(NTrk), dMdphi(NTrk);
 
 2396     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 2398     auto fullCov = convertCovMatrix(vxCandidate);
 
 2399     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2401       double trkCharge = 1.;
 
 2402       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 2407       double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 2422     double LXY = Px*
dx+Py*
dy;
 
 2424     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2425       dMdqOverP[
it]   = -(Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it]-
E*dedqOverP[
it])/M;
 
 2426       dMdtheta[
it]    = -(Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/M;
 
 2427       dMdphi[
it]      = -(Px*dpxdphi[
it]+Py*dpydphi[
it])/M;
 
 2428       double dPTdqOverP  =  (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
 2429       double dPTdtheta  =  (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
 2430       double dPTdphi     =  (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
 2431       double dLXYdqOverP =  
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it];
 
 2432       double dLXYdtheta  =  
dx*dpxdtheta[
it]+
dy*dpydtheta[
it];
 
 2433       double dLXYdphi    =  
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 2434       dTaudqOverP[
it] =  (LXY*dMdqOverP[
it]+M*dLXYdqOverP)/(
PT*
PT)-(2.*LXY*M*dPTdqOverP)/(
PT*
PT*
PT);
 
 2435       dTaudtheta[
it]  =  (LXY*dMdtheta[
it]+M*dLXYdtheta)/(
PT*
PT)-(2.*LXY*M*dPTdtheta)/(
PT*
PT*
PT);
 
 2436       dTaudphi[
it]    =  (LXY*dMdphi[
it]+M*dLXYdphi)/(
PT*
PT)-(2.*LXY*M*dPTdphi)/(
PT*
PT*
PT);
 
 2438     double dTaudx = (M*Px)/(
PT*
PT);
 
 2439     double dTaudy = (M*Py)/(
PT*
PT);
 
 2440     double dTaudx0 = -dTaudx;
 
 2441     double dTaudy0 = -dTaudy;
 
 2443     unsigned int ndim = 0;
 
 2444     if (fullCov.size() != 0) {
 
 2445       ndim = fullCov.rows();
 
 2451     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 2453       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2454         D_mat(5*
it+0,0)  = 0.;
 
 2455         D_mat(5*
it+1,0)  = 0.;
 
 2458         D_mat(5*
it+4,0)  = 
CONST*dTaudqOverP[
it];
 
 2459         D_mat(5*
it+0,1)  = 0.;
 
 2460         D_mat(5*
it+1,1)  = 0.;
 
 2461         D_mat(5*
it+2,1)  = dMdphi[
it];
 
 2462         D_mat(5*
it+3,1)  = dMdtheta[
it];
 
 2463         D_mat(5*
it+4,1)  = dMdqOverP[
it];
 
 2465       D_mat(5*NTrk+0,0) = 
CONST*dTaudx;
 
 2466       D_mat(5*NTrk+1,0) = 
CONST*dTaudy;
 
 2467       D_mat(5*NTrk+2,0) = 0.;
 
 2468       D_mat(5*NTrk+3,0) = 
CONST*dTaudx0;
 
 2469       D_mat(5*NTrk+4,0) = 
CONST*dTaudy0;
 
 2470       D_mat(5*NTrk+5,0) = 0.;
 
 2471       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 2472       if (fullCov.size() != 0) {
 
 2473         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 2476         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 2477         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 2479       W_mat.block(5*NTrk+3,5*NTrk+3,3,3) =  
vertex->covariancePosition();
 
 2480       V0_err = D_mat.transpose() * W_mat * D_mat;
 
 2481     } 
else if (ndim == 3*NTrk+3) {
 
 2483       D_mat(0,0)  = 
CONST*dTaudx;
 
 2484       D_mat(1,0)  = 
CONST*dTaudy;
 
 2486       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2489         D_mat(3*
it+5,0)  = 
CONST*dTaudqOverP[
it];
 
 2490         D_mat(3*
it+3,1)  = dMdphi[
it];
 
 2491         D_mat(3*
it+4,1)  = dMdtheta[
it];
 
 2492         D_mat(3*
it+5,1)  = dMdqOverP[
it];
 
 2494       D_mat(3*NTrk+3,0) = 
CONST*dTaudx0;
 
 2495       D_mat(3*NTrk+4,0) = 
CONST*dTaudy0;
 
 2496       D_mat(3*NTrk+5,0) = 0.;
 
 2497       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 2498       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 2499       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 2500       V0_err = D_mat.transpose() * W_mat * D_mat;
 
 2508       for( 
unsigned int it=0; 
it<NTrk; 
it++){
 
 2511           V0_cov(5*
it+2,5*
it+2) = (*cov_tmp)(2,2);
 
 2512           V0_cov(5*
it+2,5*
it+3) = (*cov_tmp)(2,3);
 
 2513           V0_cov(5*
it+2,5*
it+4) = (*cov_tmp)(2,4);
 
 2514           V0_cov(5*
it+3,5*
it+3) = (*cov_tmp)(3,3);
 
 2515           V0_cov(5*
it+3,5*
it+4) = (*cov_tmp)(3,4);
 
 2516           V0_cov(5*
it+4,5*
it+4) = (*cov_tmp)(4,4);
 
 2517           V0_cov(5*
it+3,5*
it+2) = (*cov_tmp)(2,3);
 
 2518           V0_cov(5*
it+4,5*
it+2) = (*cov_tmp)(2,4);
 
 2519           V0_cov(5*
it+4,5*
it+3) = (*cov_tmp)(3,4);
 
 2529     if (
masses.size() != NTrk) {
 
 2530       ATH_MSG_DEBUG(
"The provided number of masses does not match the number of tracks in the vertex");
 
 2534     double CONST = 1000./299.792;
 
 2535     double PT = V0Momentum(vxCandidate).perp();
 
 2537     double dx = vert.x();
 
 2538     double dy = vert.y();
 
 2539     double M = invariantMass(vxCandidate, 
masses);
 
 2540     double E=0., Px=0., Py=0., Pz=0.;
 
 2541     std::vector<double>dpxdqOverP(NTrk), dpxdtheta(NTrk), dpxdphi(NTrk);
 
 2542     std::vector<double>dpydqOverP(NTrk), dpydtheta(NTrk), dpydphi(NTrk);
 
 2543     std::vector<double>dpzdqOverP(NTrk), dpzdtheta(NTrk), dedqOverP(NTrk);
 
 2544     std::vector<double>dMdqOverP(NTrk), dMdtheta(NTrk), dMdphi(NTrk);
 
 2545     std::vector<double>dTaudqOverP(NTrk), dTaudtheta(NTrk), dTaudphi(NTrk);
 
 2547     auto fullCov = convertCovMatrix(vxCandidate);
 
 2548     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2550       double trkCharge = 1.;
 
 2551       if (bPer->parameters()[
Trk::qOverP] < 0.) trkCharge = -1.;
 
 2556       double pe = (
tmp>0.) ? sqrt(
tmp) : 0.;
 
 2571     double LXY = Px*
dx+Py*
dy;
 
 2573     for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2574       dMdqOverP[
it]   = -(Px*dpxdqOverP[
it]+Py*dpydqOverP[
it]+Pz*dpzdqOverP[
it]-
E*dedqOverP[
it])/M;
 
 2575       dMdtheta[
it]    = -(Px*dpxdtheta[
it]+Py*dpydtheta[
it]+Pz*dpzdtheta[
it])/M;
 
 2576       dMdphi[
it]      = -(Px*dpxdphi[
it]+Py*dpydphi[
it])/M;
 
 2577       double dPTdqOverP  =  (Px*dpxdqOverP[
it]+Py*dpydqOverP[
it])/
PT;
 
 2578       double dPTdtheta   =  (Px*dpxdtheta[
it]+Py*dpydtheta[
it])/
PT;
 
 2579       double dPTdphi     =  (Px*dpxdphi[
it]+Py*dpydphi[
it])/
PT;
 
 2580       double dLXYdqOverP =  
dx*dpxdqOverP[
it]+
dy*dpydqOverP[
it];
 
 2581       double dLXYdtheta  =  
dx*dpxdtheta[
it]+
dy*dpydtheta[
it];
 
 2582       double dLXYdphi    =  
dx*dpxdphi[
it]+
dy*dpydphi[
it];
 
 2583       dTaudqOverP[
it] =  (LXY*dMdqOverP[
it]+M*dLXYdqOverP)/(
PT*
PT)-(2.*LXY*M*dPTdqOverP)/(
PT*
PT*
PT);
 
 2584       dTaudtheta[
it]  =  (LXY*dMdtheta[
it]+M*dLXYdtheta)/(
PT*
PT)-(2.*LXY*M*dPTdtheta)/(
PT*
PT*
PT);
 
 2585       dTaudphi[
it]    =  (LXY*dMdphi[
it]+M*dLXYdphi)/(
PT*
PT)-(2.*LXY*M*dPTdphi)/(
PT*
PT*
PT);
 
 2587     double dTaudx = (M*Px)/(
PT*
PT);
 
 2588     double dTaudy = (M*Py)/(
PT*
PT);
 
 2589     double dTaudx0 = -dTaudx;
 
 2590     double dTaudy0 = -dTaudy;
 
 2592     unsigned int ndim = 0;
 
 2593     if (fullCov.size() != 0) {
 
 2594       ndim = fullCov.rows();
 
 2599     if (ndim == 5*NTrk+3 || ndim == 5*NTrk+6) {
 
 2601       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2602         D_mat(5*
it+0,0)  = 0.;
 
 2603         D_mat(5*
it+1,0)  = 0.;
 
 2606         D_mat(5*
it+4,0)  = 
CONST*dTaudqOverP[
it];
 
 2607         D_mat(5*
it+0,1)  = 0.;
 
 2608         D_mat(5*
it+1,1)  = 0.;
 
 2609         D_mat(5*
it+2,1)  = dMdphi[
it];
 
 2610         D_mat(5*
it+3,1)  = dMdtheta[
it];
 
 2611         D_mat(5*
it+4,1)  = dMdqOverP[
it];
 
 2613       D_mat(5*NTrk+0,0) = 
CONST*dTaudx;
 
 2614       D_mat(5*NTrk+1,0) = 
CONST*dTaudy;
 
 2615       D_mat(5*NTrk+2,0) = 0.;
 
 2616       D_mat(5*NTrk+3,0) = 
CONST*dTaudx0;
 
 2617       D_mat(5*NTrk+4,0) = 
CONST*dTaudy0;
 
 2618       D_mat(5*NTrk+5,0) = 0.;
 
 2619       Amg::MatrixX W_mat(5*NTrk+6,5*NTrk+6); W_mat.setZero();
 
 2620       if (fullCov.size() != 0) {
 
 2621         W_mat.block(0,0,ndim,ndim) = fullCov;
 
 2624         W_mat.block(0,0,V0_cov.rows(),V0_cov.rows()) = V0_cov;
 
 2625         W_mat.block(5*NTrk,5*NTrk,3,3) = vxCandidate->covariancePosition();
 
 2627       W_mat.block(5*NTrk+3,5*NTrk,3,3) = 
vertex->covariancePosition();
 
 2628       V0_err = D_mat.transpose() * W_mat * D_mat;
 
 2629     } 
else if (ndim == 3*NTrk+3) {
 
 2631       D_mat(0,0)  = 
CONST*dTaudx;
 
 2632       D_mat(1,0)  = 
CONST*dTaudy;
 
 2634       for( 
unsigned int it=0; 
it<NTrk; 
it++) {
 
 2637         D_mat(3*
it+5,0)  = 
CONST*dTaudqOverP[
it];
 
 2638         D_mat(3*
it+3,1)  = dMdphi[
it];
 
 2639         D_mat(3*
it+4,1)  = dMdtheta[
it];
 
 2640         D_mat(3*
it+5,1)  = dMdqOverP[
it];
 
 2642       D_mat(3*NTrk+3,0) = 
CONST*dTaudx0;
 
 2643       D_mat(3*NTrk+4,0) = 
CONST*dTaudy0;
 
 2644       D_mat(3*NTrk+5,0) = 0.;
 
 2645       Amg::MatrixX W_mat(3*NTrk+6,3*NTrk+6); W_mat.setZero();
 
 2646       W_mat.block(0,0,ndim,ndim) = fullCov;
 
 2647       W_mat.block(3*NTrk+3,3*NTrk+3,3,3) = 
vertex->covariancePosition();
 
 2648       V0_err = D_mat.transpose() * W_mat * D_mat;
 
 2660     if ( 
matrix.size() == (3*NTrk+3)*(3*NTrk+3+1)/2) {
 
 2662     } 
else if (
matrix.size() == (5*NTrk+3)*(5*NTrk+3+1)/2) {
 
 2671     for (
int i=1; 
i<= ndim; 
i++) {
 
 2672       for (
int j=1; j<=
i; j++){
 
 2676           mtx.fillSymmetric(
i-1,j-1,
matrix[ij]);