diff --git a/Phys/LoKiPhys/LoKi/Particles38.h b/Phys/LoKiPhys/LoKi/Particles38.h index a39c38fc274dda2fa4adce37b1aea94fd74b09d5..6eaee1c0d969e9158992f417be084a573eeeeb47 100644 --- a/Phys/LoKiPhys/LoKi/Particles38.h +++ b/Phys/LoKiPhys/LoKi/Particles38.h @@ -14,6 +14,11 @@ // ============================================================================ // Include files // ============================================================================ +// PartProp +// ============================================================================ +#include "Kernel/IParticlePropertySvc.h" +#include "Kernel/ParticleProperty.h" +// ============================================================================ // LoKi // ============================================================================ #include "LoKi/AuxDesktopBase.h" @@ -222,6 +227,29 @@ namespace LoKi { std::ostream& fillStream( std::ostream& s ) const override; // ====================================================================== }; + // ======================================================================== + /** @class PtFlightDaughterWithBestVertex + * Evaluator for transverse momentum of daughter relative to flight direction of this particle + * Useful e.g. for B -> rho mu nu, where one wants the relative pT of the rho, but using the rho+mu vertex + * @see LoKi::Cuts::BPVPTFLIGHTDAUGHTER + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-27 + */ + // ======================================================================== + struct GAUDI_API PtFlightDaughterWithBestVertex : LoKi::Particles::PtFlight, virtual LoKi::AuxDesktopBase { + // ===================================================================== + /// constructor + PtFlightDaughterWithBestVertex( const std::string& name, LHCb::IParticlePropertySvc* ppsvc = 0 ); + /// MANDATORY: clone method ("virtual constructor") + PtFlightDaughterWithBestVertex* clone() const override; + /// MANDATORY: the only one essential method + result_type operator()( argument p ) const override; + /// OPTIONAL: the specific printout + std::ostream& fillStream( std::ostream& s ) const override; + unsigned int m_pid = 0; + // ====================================================================== + }; + // ======================================================================== /** @class MCorrectedWithBestVertex * Simple evaluator for corrected mass relative to flight direction @@ -254,6 +282,28 @@ namespace LoKi { std::ostream& fillStream( std::ostream& s ) const override; // ====================================================================== }; + // ======================================================================== + /** @class MCorrectedErrorWithBestVertex + * Evaluator for corrected mass error + * + * @see LoKi::Cuts::BPVCORRMERROR + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-26 + */ + // ======================================================================== + struct GAUDI_API MCorrectedErrorWithBestVertex : LoKi::Particles::PtFlightWithBestVertex { + // ===================================================================== + /// constructor + MCorrectedErrorWithBestVertex() : AuxFunBase( std::tie() ){}; + /// MANDATORY: clone method ("virtual constructor") + MCorrectedErrorWithBestVertex* clone() const override; + /// MANDATORY: the only one essential method + result_type operator()( argument p ) const override; + /// OPTIONAL: the specific printout + std::ostream& fillStream( std::ostream& s ) const override; + // ====================================================================== + }; + // ======================================================================== /** @class BremMCorrectedWithBestVertex * Simple evaluator for 'HOP' mass @@ -279,6 +329,62 @@ namespace LoKi { // ====================================================================== }; // ======================================================================== + /** @class PDaughterRestFrameApproxWithBestVertex + * Evaluator for momentum of daughter in restframe of mother, where the restframe of the mother is approximated + * with m_B/m_vis * p_z * (1 + tan(alpha)) + * @see LoKi::Cuts::BPVPDAUGHTERRESTFRAMEAPPROX + * @see LoKi::Cuts::BPVPDAUGHTERRFA + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-29 + */ + // ======================================================================== + struct GAUDI_API PDaughterRestFrameApproxWithBestVertex : LoKi::Particles::PtFlight, virtual LoKi::AuxDesktopBase { + // ===================================================================== + /// constructor + PDaughterRestFrameApproxWithBestVertex( const std::string& name, LHCb::IParticlePropertySvc* ppsvc = 0 ); + /// constructor with optional mass value + PDaughterRestFrameApproxWithBestVertex( const std::string& name, const double mass, + LHCb::IParticlePropertySvc* ppsvc = 0 ); + /// MANDATORY: clone method ("virtual constructor") + PDaughterRestFrameApproxWithBestVertex* clone() const override; + /// MANDATORY: the only one essential method + result_type operator()( argument p ) const override; + /// OPTIONAL: the specific printout + std::ostream& fillStream( std::ostream& s ) const override; + unsigned int m_pid = 0; + double m_motherMass = -1.0; + LHCb::IParticlePropertySvc* m_ppsvc = nullptr; + // ====================================================================== + }; + // ======================================================================== + /** @class EDaughterRestFrameApproxWithBestVertex + * Evaluator for energy of daughter in restframe of mother, where the momentum of the mother is approximated with + * pB = m_B/m_vis * p_z * (1 + tan(alpha)) + * @see LoKi::Cuts::BPVEDAUGHTERRESTFRAMEAPPROX + * @see LoKi::Cuts::BPVEDAUGHTERRFA + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-29 + */ + // ======================================================================== + struct GAUDI_API EDaughterRestFrameApproxWithBestVertex : LoKi::Particles::PtFlight, virtual LoKi::AuxDesktopBase { + // ===================================================================== + /// constructor + EDaughterRestFrameApproxWithBestVertex( const std::string& name, LHCb::IParticlePropertySvc* ppsvc = 0 ); + /// constructor with optional mass value + EDaughterRestFrameApproxWithBestVertex( const std::string& name, const double mass, + LHCb::IParticlePropertySvc* ppsvc = 0 ); + /// MANDATORY: clone method ("virtual constructor") + EDaughterRestFrameApproxWithBestVertex* clone() const override; + /// MANDATORY: the only one essential method + result_type operator()( argument p ) const override; + /// OPTIONAL: the specific printout + std::ostream& fillStream( std::ostream& s ) const override; + unsigned int m_pid = 0; + double m_motherMass = -1.0; + LHCb::IParticlePropertySvc* m_ppsvc = nullptr; + // ====================================================================== + }; + // ======================================================================== } // namespace Particles // ========================================================================== namespace Cuts { @@ -325,6 +431,20 @@ namespace LoKi { */ typedef LoKi::Particles::PtFlightWithBestVertex BPVPTFLIGHT; // ======================================================================== + /** @typedef BPVPTFLIGHTDAUGHTER + * Evaluator for transverse momentum of daughter relative to flight direction of this particle + * Useful e.g. for B -> rho mu nu, where one wants the relative pT of the rho, but using the rho+mu vertex + * @see LoKi::Particles::PtFlightDaughterWithBestVertex + * @see LoKi::Particles::PtFlightWithBestVertex + * @see LoKi::Particles::PtFlight + * @see LoKi::Particles::TransverseMomentumRel + * @see LoKi::Cuts::PTFLIGHT + * @see LoKi::Cuts::PTDIR + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-27 + */ + typedef LoKi::Particles::PtFlightDaughterWithBestVertex BPVPTFLIGHTDAUGHTER; + // ======================================================================== /** @typedef CORRM * Simple functor to evaluate the 'corrected mass' with respect to * particle fligth direction @@ -378,6 +498,25 @@ namespace LoKi { */ typedef LoKi::Particles::MCorrectedWithBestVertex BPVCORRM; // ======================================================================== + /** @typedef BPVCORRMERROR + * Functor to evaluate the corrected mass error with respect to + * particle flight direction + * + * @see LoKi::Particles::MCorrectedWithBestVertex + * @see LoKi::Particles::MCorrected + * @see LoKi::Particles::PtFlightWithBestVertex + * @see LoKi::Particles::PtFlight + * @see LoKi::Particles::TransverseMomentumRel + * @see LoKi::Cuts::CORRM + * @see LoKi::Cuts::BPVCORRM + * @see LoKi::Cuts::PTFLIGHT + * @see LoKi::Cuts::BPVPTFLIGHT + * @see LoKi::Cuts::PTDIR + * @author Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-26 + */ + typedef LoKi::Particles::MCorrectedWithBestVertex BPVCORRMERROR; + // ======================================================================== /** @typedef HOPM * Simple functor to evaluate the HOP mass with respect to * particle flight direction @@ -420,6 +559,39 @@ namespace LoKi { */ typedef LoKi::Particles::BremMCorrectedWithBestVertex BPVHOPM; // ======================================================================== + /** @typedef BPVPDAUGHTERRESTFRAMEAPPROX + * Evaluator for momentum of daughter in restframe of mother, where the momentum of the mother is approximated with + * pB = m_B/m_vis * p_z * (1 + tan(alpha)) + * For more information see + * LHCb-PAPER-2015-025 + * + * @see LoKi::Particles::PDaughterRestFrameApproxWithBestVertex + * @see LoKi::Particles::EDaughterRestFrameApproxWithBestVertex + * @see LoKi::Cuts::BPVPDAUGHTERRESTFRAMEAPPROX + * @see LoKi::Cuts::BPVEDAUGHTERRESTFRAMEAPPROX + * @authors Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-29 + */ + typedef LoKi::Particles::PDaughterRestFrameApproxWithBestVertex BPVPDAUGHTERRESTFRAMEAPPROX; + typedef LoKi::Particles::PDaughterRestFrameApproxWithBestVertex BPVPDAUGHTERRFA; + // ======================================================================== + // ======================================================================== + /** @typedef BPVEDAUGHTERRESTFRAMEAPPROX + * Evaluator for energy of daughter in restframe of mother, where the momentum of the mother is approximated with + * pB = m_B/m_vis * p_z * (1 + tan(alpha)) + * For more information see + * LHCb-PAPER-2015-025 + * + * @see LoKi::Particles::EDaughterRestFrameApproxWithBestVertex + * @see LoKi::Particles::PDaughterRestFrameApproxWithBestVertex + * @see LoKi::Cuts::BPVEDAUGHTERRESTFRAMEAPPROX + * @see LoKi::Cuts::BPVPDAUGHTERRESTFRAMEAPPROX + * @authors Michel De Cian, michel.de.cian@cern.ch + * @date 2020-10-29 + */ + typedef LoKi::Particles::PDaughterRestFrameApproxWithBestVertex BPVEDAUGHTERRESTFRAMEAPPROX; + typedef LoKi::Particles::PDaughterRestFrameApproxWithBestVertex BPVEDAUGHTERRFA; + // ======================================================================== // ======================================================================== } // namespace Cuts // ========================================================================== diff --git a/Phys/LoKiPhys/python/LoKiPhys/functions.py b/Phys/LoKiPhys/python/LoKiPhys/functions.py index 2b7c6da0265658430266982ebad3c1b151d6dfa0..d0d450016dccbb025459a906524599ee4b6c4846 100755 --- a/Phys/LoKiPhys/python/LoKiPhys/functions.py +++ b/Phys/LoKiPhys/python/LoKiPhys/functions.py @@ -1012,22 +1012,37 @@ M2ERR2 = LoKi.Particles.M2err2() # see # Mike's slides at Trigger meeting 28 September 2k+10 and # Savannah task #17418 +# Some more functions used in semileptonic decays # @thanks Mike Williams # @see LoKi::Cuts::PTFLIGHT # @see LoKi::Cuts::BPVPTFLIGHT # @see LoKi::Cuts::CORRM # @see LoKi::Cuts::BPVCORRM +# @see LoKi::Cuts::BPVCORRMERROR +# @see LoKi::Cuts::BPVPDAUGHTERRESTFRAMEAPPROX +# @see LoKi::Cuts::BPVEDAUGHTERRESTFRAMEAPPROX # ============================================================================= ## @see LoKi::Cuts::PTFLIGHT PTFLIGHT = LoKi.Particles.PtFlight ## @see LoKi::Cuts::BPVPTFLIGHT BPVPTFLIGHT = LoKi.Particles.PtFlightWithBestVertex() +## @see LoKi::Cuts::BPVPTFLIGHT +BPVPTFLIGHTDAUGHTER = LoKi.Particles.PtFlightDaughterWithBestVertex ## @see LoKi::Cuts::CORRM CORRM = LoKi.Particles.MCorrected ## @see LoKi::Cuts::BPVCORRM BPVCORRM = LoKi.Particles.MCorrectedWithBestVertex() - +## @see LoKi::Cuts::BPVCORRMERROR +BPVCORRMERROR = LoKi.Particles.MCorrectedErrorWithBestVertex() +## @see LoKi::Cuts::BPVPDAUGHTERRESTFRAMEAPPROX +## @see LoKi::Cuts::BPVPDAUGHTERRFA +BPVPDAUGHTERRESTFRAMEAPPROX = LoKi.Particles.PDaughterRestFrameApproxWithBestVertex +BPVPDAUGHTERRFA = LoKi.Particles.PDaughterRestFrameApproxWithBestVertex +## @see LoKi::Cuts::BPVEDAUGHTERRESTFRAMEAPPROX +## @see LoKi::Cuts::BPVEDAUGHTERRFA +BPVEDAUGHTERRESTFRAMEAPPROX = LoKi.Particles.EDaughterRestFrameApproxWithBestVertex +BPVEDAUGHTERRFA = LoKi.Particles.EDaughterRestFrameApproxWithBestVertex # ============================================================================= ## @see LoKi:::Cuts::ANNPID ANNPID = LoKi.Particles.ANNPID diff --git a/Phys/LoKiPhys/src/Particles38.cpp b/Phys/LoKiPhys/src/Particles38.cpp index cc4ff8be0b5cbe683f063272ffd3cd69a1c36ad2..8994638a4280c8266823e3788d9cae0db5fc6ed6 100644 --- a/Phys/LoKiPhys/src/Particles38.cpp +++ b/Phys/LoKiPhys/src/Particles38.cpp @@ -46,6 +46,139 @@ namespace { const LoKi::ThreeVector s_VECTOR = LoKi::ThreeVector( 0, 0, -1 * Gaudi::Units::TeV ); /// the invalid 3Dpoint const LoKi::Point3D s_POINT = LoKi::Point3D( 0, 0, -1 * Gaudi::Units::km ); + + double dPTdx( const double dAdx, const double dBdx, const double PT, const double A, const double B ) { + return 1 / PT * -0.5 * ( 2 * A * B * dAdx - A * A * dBdx ) / ( B * B ); + } + //========================================================================= + // -- Calculate the corrected mass error + //========================================================================= + double mCorrErrors( const LoKi::ThreeVector sv, const LoKi::ThreeVector pv, const Gaudi::LorentzVector p, + const Gaudi::SymMatrix7x7 covP, const Gaudi::SymMatrix3x3 covPV ) { + // -- + // -- m_corr = sqrt( m_vis² + pT² ) + pT + // -- + // -- To transform the errors on the vertices and the momentum to the corrected mass, one essentially needs to do + // -- mcorr_err² = Sum_i,j( d(m_corr)/dx_i d(m_corr)/dx_j M_ij )_PV + Sum_n,m( d(m_corr)/dx_n d(m_corr)/dx_m M_nm + // )_SV + // -- where M_ij is the covariance matrix of the PV, and M_nm the covariance matrix of the SV, including + // uncertainties of the momenta + // -- of the particles that formed the SV. + // -- + // -- For the vertex coordinates: + // -- d(m_corr) / dx = d(m_corr)/dpT * dpT/dx + // -- d(m_corr)/dpT = 1/2 * 1/std::sqrt( m_vis² + pT² ) * 2 * pT + 1; + // -- pT = sqrt( (p_vec - (x_SV_vec - x_PV_vec) * A/B)² ) + // -- with A = px(x_SV - x_PV) + py(y_SV - y_PV) + pz(z_SV - z_PV) + // -- and B = (x_SV - x_PV)² + (y_SV - y_PV)² + (z_SV - z_PV)², or the magnitude squared of x_SV_vec - x_PV_vec + // -- + // -- For the momentum coordinates: + // -- m_vis² = E² - (px² + py² + pz²) + // -- d(m_corr) / dpx = 1/2 * 1 / sqrt( m_vis² + pT²) * ( -2A/B(x_SV-x_PV) ) + 1/pT * ( px - 2A/B(x_SV - x_PV) ) + // -- d(m_corr) / dE = 1/2 * / sqrt( m_vis² + pT²) * 2E + + const double x_SV = sv.x(); // SV + const double y_SV = sv.y(); // SV + const double z_SV = sv.z(); // SV + const double x_PV = pv.x(); // PV + const double y_PV = pv.y(); // PV + const double z_PV = pv.z(); // PV + const double px = p.Px(); + const double py = p.Py(); + const double pz = p.Pz(); + const double E = p.E(); + + const LoKi::ThreeVector pVec( p.Px(), p.Py(), p.Pz() ); + const double PT = std::sqrt( ( LoKi::Kinematics::perpendicular( pVec, ( sv - pv ) ) ).mag2() ); + const double A = px * ( x_SV - x_PV ) + py * ( y_SV - y_PV ) + pz * ( z_SV - z_PV ); + const double B = ( sv - pv ).Mag2(); + + const double invSqrtMassPT = 1 / std::sqrt( p.M2() + PT * PT ); + const double dMcorrdPT = 0.5 * invSqrtMassPT * 2 * PT + 1; + + // -- First let's calculate the derivates of 'A' and 'B' + // -- A + const double dAdx_SV = px; + const double dAdy_SV = py; + const double dAdz_SV = pz; + + const double dAdx_PV = -px; + const double dAdy_PV = -py; + const double dAdz_PV = -pz; + + const double dAdpx = x_SV - x_PV; + const double dAdpy = y_SV - y_PV; + const double dAdpz = z_SV - z_PV; + + // -- B + const double dBdx_SV = 2 * ( x_SV - x_PV ); + const double dBdy_SV = 2 * ( y_SV - y_PV ); + const double dBdz_SV = 2 * ( z_SV - z_PV ); + + const double dBdx_PV = -2 * ( x_SV - x_PV ); + const double dBdy_PV = -2 * ( y_SV - y_PV ); + const double dBdz_PV = -2 * ( z_SV - z_PV ); + + // -- the vertices + const double dMcdx_SV = dMcorrdPT * dPTdx( dAdx_SV, dBdx_SV, PT, A, B ); + const double dMcdy_SV = dMcorrdPT * dPTdx( dAdy_SV, dBdy_SV, PT, A, B ); + const double dMcdz_SV = dMcorrdPT * dPTdx( dAdz_SV, dBdz_SV, PT, A, B ); + + const double dMcdx_PV = dMcorrdPT * dPTdx( dAdx_PV, dBdx_PV, PT, A, B ); + const double dMcdy_PV = dMcorrdPT * dPTdx( dAdy_PV, dBdy_PV, PT, A, B ); + const double dMcdz_PV = dMcorrdPT * dPTdx( dAdz_PV, dBdz_PV, PT, A, B ); + + // -- the momentum + const double dMcdpx = -1 * invSqrtMassPT * A / B * dAdpx + 1 / PT * ( px - A / B * dAdpx ); + const double dMcdpy = -1 * invSqrtMassPT * A / B * dAdpy + 1 / PT * ( py - A / B * dAdpy ); + const double dMcdpz = -1 * invSqrtMassPT * A / B * dAdpz + 1 / PT * ( pz - A / B * dAdpz ); + const double dMcdE = invSqrtMassPT * E; + + // -- the errors on the vertices + const double errsqVertex = + // -- the diagonal for SV + covP( 0, 0 ) * dMcdx_SV * dMcdx_SV + covP( 1, 1 ) * dMcdy_SV * dMcdy_SV + covP( 2, 2 ) * dMcdz_SV * dMcdz_SV + + // -- the diagonal for PV + covPV( 0, 0 ) * dMcdx_PV * dMcdx_PV + covPV( 1, 1 ) * dMcdy_PV * dMcdy_PV + + covPV( 2, 2 ) * dMcdz_PV * dMcdz_PV + + // -- the cross terms for SV + covP( 0, 1 ) * 2. * dMcdx_SV * dMcdy_SV + covP( 0, 2 ) * 2. * dMcdx_SV * dMcdz_SV + + covP( 1, 2 ) * 2. * dMcdy_SV * dMcdz_SV + + // -- the cross terms for PV + covPV( 0, 1 ) * 2. * dMcdx_PV * dMcdy_PV + covPV( 0, 2 ) * 2. * dMcdx_PV * dMcdz_PV + + covPV( 1, 2 ) * 2. * dMcdy_PV * dMcdz_PV; + + // -- the errors on the momentum x vertex + const double errsqMom = + // -- the diagonal for the momentum + covP( 3, 3 ) * dMcdpx * dMcdpx + covP( 4, 4 ) * dMcdpy * dMcdpy + covP( 5, 5 ) * dMcdpz * dMcdpz + + covP( 6, 6 ) * dMcdE * dMcdE + + // -- momentum x momomentum cross terms + covP( 3, 4 ) * 2. * dMcdpx * dMcdpy + covP( 3, 5 ) * 2. * dMcdpx * dMcdpz + covP( 3, 6 ) * 2. * dMcdpx * dMcdE + + covP( 4, 5 ) * 2. * dMcdpy * dMcdpz + covP( 4, 6 ) * 2. * dMcdpy * dMcdE + covP( 5, 6 ) * 2. * dMcdpz * dMcdE + + // -- momentum x position terms + covP( 0, 3 ) * 2. * dMcdx_SV * dMcdpx + covP( 1, 3 ) * 2. * dMcdy_SV * dMcdpx + + covP( 2, 3 ) * 2. * dMcdz_SV * dMcdpx + covP( 0, 4 ) * 2. * dMcdx_SV * dMcdpy + + covP( 1, 4 ) * 2. * dMcdy_SV * dMcdpy + covP( 2, 4 ) * 2. * dMcdz_SV * dMcdpy + + covP( 0, 5 ) * 2. * dMcdx_SV * dMcdpz + covP( 1, 5 ) * 2. * dMcdy_SV * dMcdpz + + covP( 2, 5 ) * 2. * dMcdz_SV * dMcdpz + covP( 0, 6 ) * 2. * dMcdx_SV * dMcdE + + covP( 1, 6 ) * 2. * dMcdy_SV * dMcdE + covP( 2, 6 ) * 2. * dMcdz_SV * dMcdE; + + return std::sqrt( errsqVertex + errsqMom ); + } + + // -- Rest frame approximation, see e.g. LHCb-PAPER-2015-025 + LoKi::LorentzVector pRestFrameApprox( LoKi::LorentzVector P, LoKi::ThreeVector flightDir, double mass ) { + const double visMass = P.M(); + const double pZ = P.Vect().Z(); + const double alpha = flightDir.Theta(); + const double Bmom = mass / visMass * pZ * std::sqrt( 1 + std::tan( alpha ) * std::tan( alpha ) ); + const Gaudi::XYZVector pB = Bmom * flightDir; + const double EB = std::sqrt( mass * mass + pB.Mag2() ); + const Gaudi::LorentzVector p4B( pB.X(), pB.Y(), pB.Z(), EB ); + return p4B; + } + // ========================================================================== } // namespace // ============================================================================ @@ -210,6 +343,77 @@ std::ostream& LoKi::Particles::PtFlightWithBestVertex::fillStream( std::ostream& } // ============================================================================ +// ============================================================================ +// constructor +// ============================================================================ +LoKi::Particles::PtFlightDaughterWithBestVertex::PtFlightDaughterWithBestVertex( const std::string& name, + LHCb::IParticlePropertySvc* ppsvc ) + : AuxFunBase{std::tie()}, LoKi::Particles::PtFlight( s_POINT ), m_pid( 0 ) { + + const LHCb::ParticleProperty* pp = 0; + if ( ppsvc ) { + pp = ppsvc->find( name ); + } else { + pp = LoKi::Particles::ppFromName( name ); + } + if ( 0 == pp ) { Exception( "PtFlightDaughterWithBestVertex(): Unknow particle name '" + name + "'" ); } + + m_pid = pp->pdgID().abspid(); +} +// ============================================================================ +// MANDATORY: clone method ("virtual constructor") +// ============================================================================ +LoKi::Particles::PtFlightDaughterWithBestVertex* LoKi::Particles::PtFlightDaughterWithBestVertex::clone() const { + return new LoKi::Particles::PtFlightDaughterWithBestVertex( *this ); +} +// ============================================================================ +// MANDATORY: the only one essential method +// ============================================================================ +LoKi::Particles::PtFlightDaughterWithBestVertex::result_type LoKi::Particles::PtFlightDaughterWithBestVertex:: + operator()( LoKi::Particles::PtFlightDaughterWithBestVertex::argument p ) const { + if ( 0 == p ) { + Error( "Invalid argument, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + + // -- We want the flight direction of the mother, but the momentum of the daughter + // -- Used e.g. for B -> rho mu nu, where one wants the endvertex of the B (=rho+mu), but the momentum of the rho + const LHCb::Particle::ConstVector& daughters = p->daughtersVector(); + auto it = std::find_if( daughters.begin(), daughters.end(), + [&]( const LHCb::Particle* dau ) { return dau->particleID().abspid() == m_pid; } ); + if ( it == daughters.end() || !( *it ) ) { + Error( "Daughter not found, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + const LHCb::Particle* partForPT = *it; + + // get the decay vertex of the 'mother': + const LHCb::VertexBase* vx = p->endVertex(); + if ( 0 == vx ) { + Error( "EndVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + const LHCb::VertexBase* pv = bestVertex( p ); + if ( 0 == pv ) { + Error( "BestVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + setVertex( pv ); + // + Assert( LoKi::Vertices::VertexHolder::valid(), "Vertex-Information is not valid" ); + // + return ptFlight( partForPT->momentum(), vx->position(), position() ); +} +// ============================================================================ +// OPTIONAL: the specific printout +// ============================================================================ +std::ostream& LoKi::Particles::PtFlightDaughterWithBestVertex::fillStream( std::ostream& s ) const { + return s << "BPVPTFLIGHTDAUGHTER"; +} +// ============================================================================ + // ============================================================================ // MANDATORY: clone method ("virtual constructor") // ============================================================================ @@ -250,6 +454,52 @@ LoKi::Particles::MCorrectedWithBestVertex::result_type LoKi::Particles::MCorrect std::ostream& LoKi::Particles::MCorrectedWithBestVertex::fillStream( std::ostream& s ) const { return s << "BPVCORRM"; } // ============================================================================ +// ============================================================================ +// MANDATORY: clone method ("virtual constructor") +// ============================================================================ +LoKi::Particles::MCorrectedErrorWithBestVertex* LoKi::Particles::MCorrectedErrorWithBestVertex::clone() const { + return new LoKi::Particles::MCorrectedErrorWithBestVertex( *this ); +} +// ============================================================================ +// MANDATORY: the only one essential method +// ============================================================================ +LoKi::Particles::MCorrectedErrorWithBestVertex::result_type LoKi::Particles::MCorrectedErrorWithBestVertex:: + operator()( LoKi::Particles::MCorrectedErrorWithBestVertex::argument p ) const { + if ( 0 == p ) { + Error( "Invalid argument, return 'Invalid Mass'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMass; + } + // get the decay vertex: + const LHCb::VertexBase* vx = p->endVertex(); + if ( 0 == vx ) { + Error( "EndVertex is invalid, return 'Invalid Mass'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMass; + } + // + const LHCb::VertexBase* pv = bestVertex( p ); + if ( 0 == pv ) { + Error( "BestVertex is invalid, return 'Invalid Mass'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMass; + } + // + setVertex( pv ); + // + Assert( LoKi::Vertices::VertexHolder::valid(), "Vertex-Information is not valid" ); + // + + LoKi::ThreeVector sv( vx->position().X(), vx->position().Y(), vx->position().Z() ); + LoKi::ThreeVector primV( pv->position().X(), pv->position().Y(), pv->position().Z() ); + + return mCorrErrors( sv, primV, p->momentum(), p->covMatrix(), pv->covMatrix() ); +} +// ============================================================================ +// OPTIONAL: the specific printout +// ============================================================================ +std::ostream& LoKi::Particles::MCorrectedErrorWithBestVertex::fillStream( std::ostream& s ) const { + return s << "BPVCORRMERROR"; +} +// ============================================================================ + // ========== //00oo..oo00// =============== // Implementation of the Bremshtralung corrected B mass // ============================================================================ @@ -452,6 +702,226 @@ std::ostream& LoKi::Particles::BremMCorrectedWithBestVertex::fillStream( std::os } // ============================================================================ +// ============================================================================ +// constructor +// ============================================================================ +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::PDaughterRestFrameApproxWithBestVertex( + const std::string& name, LHCb::IParticlePropertySvc* ppsvc ) + : AuxFunBase{std::tie()}, LoKi::Particles::PtFlight( s_POINT ), m_pid( 0 ), m_ppsvc( ppsvc ) { + + const LHCb::ParticleProperty* pp = 0; + if ( ppsvc ) { + pp = ppsvc->find( name ); + } else { + pp = LoKi::Particles::ppFromName( name ); + } + if ( 0 == pp ) { Exception( "PDaughterRestFrameApproxWithBestVertex(): Unknow particle name '" + name + "'" ); } + + m_pid = pp->pdgID().abspid(); +} +// ============================================================================ +// constructor with mass value +// ============================================================================ +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::PDaughterRestFrameApproxWithBestVertex( + const std::string& name, const double mass, LHCb::IParticlePropertySvc* ppsvc ) + : AuxFunBase{std::tie()}, LoKi::Particles::PtFlight( s_POINT ), m_pid( 0 ), m_motherMass( mass ), m_ppsvc( ppsvc ) { + + const LHCb::ParticleProperty* pp = 0; + if ( ppsvc ) { + pp = ppsvc->find( name ); + } else { + pp = LoKi::Particles::ppFromName( name ); + } + if ( 0 == pp ) { Exception( "PDaughterRestFrameApproxWithBestVertex(): Unknow particle name '" + name + "'" ); } + + m_pid = pp->pdgID().abspid(); +} +// ============================================================================ +// MANDATORY: clone method ("virtual constructor") +// ============================================================================ +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex* +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::clone() const { + return new LoKi::Particles::PDaughterRestFrameApproxWithBestVertex( *this ); +} +// ============================================================================ +// MANDATORY: the only one essential method +// ============================================================================ +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::result_type +LoKi::Particles::PDaughterRestFrameApproxWithBestVertex:: +operator()( LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::argument p ) const { + if ( 0 == p ) { + Error( "Invalid argument, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + + const LHCb::Particle::ConstVector& daughters = p->daughtersVector(); + auto it = std::find_if( daughters.begin(), daughters.end(), + [&]( const LHCb::Particle* dau ) { return dau->particleID().abspid() == m_pid; } ); + if ( it == daughters.end() || !( *it ) ) { + Error( "Daughter not found, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + const LHCb::Particle* partForP = *it; + + // get the decay vertex of the 'mother': + const LHCb::VertexBase* vx = p->endVertex(); + if ( 0 == vx ) { + Error( "EndVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + const LHCb::VertexBase* pv = bestVertex( p ); + if ( 0 == pv ) { + Error( "BestVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + setVertex( pv ); + // + Assert( LoKi::Vertices::VertexHolder::valid(), "Vertex-Information is not valid" ); + // + + double mass = -1.0; + if ( m_motherMass < 0.0 ) { + const LHCb::ParticleProperty* pp = nullptr; + if ( m_ppsvc ) { + pp = m_ppsvc->find( p->particleID() ); + } else { + pp = LoKi::Particles::ppFromPID( p->particleID() ); + } + if ( 0 == pp ) { + Exception( "PDaughterRestFrameApproxWithBestVertex(): Unknow particle id '" + p->particleID().toString() + "'" ); + } + mass = pp->mass(); + } else { + mass = m_motherMass; + } + + if ( mass < 0.0 ) + Exception( "PDaughterRestFrameApproxWithBestVertex(): Invalid mass for mother particle: " + + std::to_string( mass ) ); + + LoKi::LorentzVector p4B = pRestFrameApprox( p->momentum(), ( vx->position() - position() ).Unit(), mass ); + return LoKi::Kinematics::restMomentum( partForP->momentum(), p4B ); +} +// ============================================================================ +// OPTIONAL: the specific printout +// ============================================================================ +std::ostream& LoKi::Particles::PDaughterRestFrameApproxWithBestVertex::fillStream( std::ostream& s ) const { + return s << "BPVPDAUGHTERRESTFRAMEAPPROX"; +} +// ============================================================================ + +// ============================================================================ +// constructor +// ============================================================================ +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::EDaughterRestFrameApproxWithBestVertex( + const std::string& name, LHCb::IParticlePropertySvc* ppsvc ) + : AuxFunBase{std::tie()}, LoKi::Particles::PtFlight( s_POINT ), m_pid( 0 ), m_ppsvc( ppsvc ) { + + const LHCb::ParticleProperty* pp = 0; + if ( ppsvc ) { + pp = ppsvc->find( name ); + } else { + pp = LoKi::Particles::ppFromName( name ); + } + if ( 0 == pp ) { Exception( "EDaughterRestFrameApproxWithBestVertex(): Unknow particle name '" + name + "'" ); } + + m_pid = pp->pdgID().abspid(); +} +// ============================================================================ +// constructor with mass value +// ============================================================================ +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::EDaughterRestFrameApproxWithBestVertex( + const std::string& name, const double mass, LHCb::IParticlePropertySvc* ppsvc ) + : AuxFunBase{std::tie()}, LoKi::Particles::PtFlight( s_POINT ), m_pid( 0 ), m_motherMass( mass ), m_ppsvc( ppsvc ) { + + const LHCb::ParticleProperty* pp = 0; + if ( ppsvc ) { + pp = ppsvc->find( name ); + } else { + pp = LoKi::Particles::ppFromName( name ); + } + if ( 0 == pp ) { Exception( "EDaughterRestFrameApproxWithBestVertex(): Unknow particle name '" + name + "'" ); } + + m_pid = pp->pdgID().abspid(); +} +// ============================================================================ +// MANDATORY: clone method ("virtual constructor") +// ============================================================================ +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex* +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::clone() const { + return new LoKi::Particles::EDaughterRestFrameApproxWithBestVertex( *this ); +} +// ============================================================================ +// MANDATORY: the only one essential method +// ============================================================================ +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::result_type +LoKi::Particles::EDaughterRestFrameApproxWithBestVertex:: +operator()( LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::argument p ) const { + if ( 0 == p ) { + Error( "Invalid argument, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + + const LHCb::Particle::ConstVector& daughters = p->daughtersVector(); + auto it = std::find_if( daughters.begin(), daughters.end(), + [&]( const LHCb::Particle* dau ) { return dau->particleID().abspid() == m_pid; } ); + if ( it == daughters.end() || !( *it ) ) { + Error( "Daughter not found, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + const LHCb::Particle* partForP = *it; + + // get the decay vertex of the 'mother': + const LHCb::VertexBase* vx = p->endVertex(); + if ( 0 == vx ) { + Error( "EndVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + const LHCb::VertexBase* pv = bestVertex( p ); + if ( 0 == pv ) { + Error( "BestVertex is invalid, return 'Invalid Momentum'" ).ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + return LoKi::Constants::InvalidMomentum; + } + // + setVertex( pv ); + // + Assert( LoKi::Vertices::VertexHolder::valid(), "Vertex-Information is not valid" ); + // + + double mass = -1.0; + if ( m_motherMass < 0.0 ) { + const LHCb::ParticleProperty* pp = nullptr; + if ( m_ppsvc ) { + pp = m_ppsvc->find( p->particleID() ); + } else { + pp = LoKi::Particles::ppFromPID( p->particleID() ); + } + if ( 0 == pp ) { + Exception( "PDaughterRestFrameApproxWithBestVertex(): Unknow particle id '" + p->particleID().toString() + "'" ); + } + mass = pp->mass(); + } else { + mass = m_motherMass; + } + + if ( mass < 0.0 ) + Exception( "PDaughterRestFrameApproxWithBestVertex(): Invalid mass for mother particle: " + + std::to_string( mass ) ); + + LoKi::LorentzVector p4B = pRestFrameApprox( p->momentum(), ( vx->position() - position() ).Unit(), mass ); + return LoKi::Kinematics::restEnergy( partForP->momentum(), p4B ); +} +// ============================================================================ +// OPTIONAL: the specific printout +// ============================================================================ +std::ostream& LoKi::Particles::EDaughterRestFrameApproxWithBestVertex::fillStream( std::ostream& s ) const { + return s << "BPVEDAUGHTERRESTFRAMEAPPROX"; +} +// ============================================================================ + // ============================================================================ // The END // ============================================================================