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
// ============================================================================