Belle II Software development
SpecificKinematicVariables.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9// Own header.
10#include <analysis/variables/SpecificKinematicVariables.h>
11
12// include VariableManager
13#include <analysis/VariableManager/Manager.h>
14
15#include <analysis/utility/PCmsLabTransform.h>
16#include <analysis/variables/Variables.h>
17
18// dataobjects
19#include <analysis/dataobjects/Particle.h>
20
21#include <TRandom.h>
22#include <TMath.h>
23#include <Math/Vector3D.h>
24#include <Math/Vector4D.h>
25
26using namespace ROOT::Math;
27using namespace std;
28
29namespace Belle2 {
34 namespace Variable {
35
36
37 double REC_q2BhSimple(const Particle* particle)
38 {
39 // calculates q^2 = (p_B - p_h) in decays of B -> h_1 .. h_n ell nu_ell,
40 // where p_h = Sum_i^n p_h_i is the 4-momentum of hadrons in the final
41 // state. The calculation is performed in the CMS system, where B-meson
42 // is assumed to be at rest p_B = (m_B, 0).
43
44 PxPyPzEVector hadron4vec;
45
46 unsigned n = particle->getNDaughters();
47
48 if (n < 1)
49 return Const::doubleNaN;
50
51 for (unsigned i = 0; i < n; i++) {
52 int absPDG = abs(particle->getDaughter(i)->getPDGCode());
53 if (absPDG == Const::electron.getPDGCode() || absPDG == Const::muon.getPDGCode() || absPDG == 15)
54 continue;
55
56 hadron4vec += particle->getDaughter(i)->get4Vector();
57 }
58
59 // boost to CMS
60 PCmsLabTransform T;
61 PxPyPzEVector phCMS = T.rotateLabToCms() * hadron4vec;
62 PxPyPzMVector pBCMS(0.0, 0.0, 0.0, particle->getPDGMass());
63 return (pBCMS - phCMS).mag2();
64 }
65
66 double REC_q2Bh(const Particle* particle)
67 {
68 // calculates q^2 = (p_B - p_h) in decays of B -> h_1 .. h_n ell nu_ell,
69 // where p_h = Sum_i^n p_h_i is the 4-momentum of hadrons in the final
70 // state. The calculation is performed in the CMS system,
71 // with a weighter average in a cone around the true B direction
72
73 PxPyPzEVector hadron4vec;
74
75 unsigned n = particle->getNDaughters();
76
77 if (n < 1)
78 return Const::doubleNaN;
79
80 for (unsigned i = 0; i < n; i++) {
81 int absPDG = abs(particle->getDaughter(i)->getPDGCode());
82 if (absPDG == Const::electron.getPDGCode() || absPDG == Const::muon.getPDGCode() || absPDG == 15)
83 continue;
84
85 hadron4vec += particle->getDaughter(i)->get4Vector();
86 }
87
88 // boost to CMS
89 PCmsLabTransform T;
90 PxPyPzEVector had_cm = T.rotateLabToCms() * hadron4vec;
91 PxPyPzEVector Y_cm = T.rotateLabToCms() * particle->get4Vector();
92
93
94 double bmass = particle->getPDGMass();
95 // B theta angle
96 double cos_cone_angle = Variable::cosThetaBetweenParticleAndNominalB(particle);
97 if (abs(cos_cone_angle) > 1) {
98 //makes no sense in this case, return simple value
99 double q2 = Variable::REC_q2BhSimple(particle);
100 if (q2 < 0) {
101 return 0;
102 }
103 return q2;
104 }
105 double thetaBY = TMath::ACos(cos_cone_angle);
106 const double E_B = T.getCMSEnergy() / 2.0;
107 const double p_B = sqrt(E_B * E_B - bmass * bmass);
108
109 double phi_start = gRandom->Uniform(0, TMath::Pi() / 2);
110
111 double q2 = 0;
112 double denom = 0;
113
114 XYZVector zHatY(Y_cm.Vect().Unit());
115 XYZVector yHatY((had_cm.Vect().Cross(zHatY)).Unit());
116 XYZVector xHatY(yHatY.Cross(zHatY));
117
118 double phi = phi_start;
119 double dphi = TMath::Pi() / 2;
120 PxPyPzEVector static_B(0, 0, 0, bmass);
121
122 for (int around_the_cone = 0; around_the_cone < 4; around_the_cone++) {
123 //Define the momentum of B in the Y rest frame using the angles thetaBY and the
124 //current phi in the loop.
125
126 //The purpose of these lines is to calculate the B momentum in the BY cone in the coordinate system previously developed.
127 double B0_px_Y_frame = p_B * TMath::Sin(thetaBY) * TMath::Cos(phi);
128 double B0_py_Y_frame = p_B * TMath::Sin(thetaBY) * TMath::Sin(phi);
129 double B0_pz_Y_frame = p_B * TMath::Cos(thetaBY);
130
131 //The 3 components of the guess for the B0 p direction at the current phi are
132 //calculated by scaling the 3 basis vectors computed before by the corresponding B
133 //momentum in that direction.
134
135 XYZVector B0_px_Dframe(xHatY);
136 B0_px_Dframe *= B0_px_Y_frame;
137 XYZVector B0_py_Dframe(yHatY);
138 B0_py_Dframe *= B0_py_Y_frame;
139 XYZVector B0_pz_Dframe(zHatY);
140 B0_pz_Dframe *= B0_pz_Y_frame;
141 //Construct the B0 p 3-vector with the current phi by summing the 3 components.
142
143 XYZVector B0_p3_Dframe(B0_px_Dframe + B0_py_Dframe + B0_pz_Dframe);
144 PxPyPzEVector B0_p4_Dframe(B0_p3_Dframe.X(), B0_p3_Dframe.Y(), B0_p3_Dframe.Z(), E_B);
145
146 //This is the polar angle of B0.
147
148 double cosThetaB = cos(B0_p3_Dframe.Theta());
149 double sinThetaB2 = (1 - cosThetaB * cosThetaB);
150
151 //The weight is given by the sin squared of such angle.
152 double wt = sinThetaB2;
153
154 //Boost the hadronic daughter to the computed B0 rest frame.
155 // In that frame, q2 can simply be calculated by subtracting the hadron 4-momentum from the momentum of a static B.
156 PxPyPzEVector had_B0(had_cm);
157 had_B0 = Boost(B0_p4_Dframe.BoostToCM()) * had_B0;
158 q2 += wt * ((static_B - had_B0).M2());
159 denom += wt;
160 phi += dphi;
161 }
162
163 q2 /= denom;
164 if (q2 < 0) {
165 q2 = 0.0;
166 }
167 return q2;
168 }
169
170 double REC_MissM2(const Particle* particle)
171 {
172 PCmsLabTransform T;
173 PxPyPzEVector rec4vecLAB = particle->get4Vector();
174 PxPyPzEVector rec4vec = T.rotateLabToCms() * rec4vecLAB;
175
176 double E_beam_cms = T.getCMSEnergy() / 2.0;
177
178 PxPyPzEVector miss4vec(-rec4vec.px(), -rec4vec.py(), -rec4vec.pz(), E_beam_cms - rec4vec.E());
179
180 return miss4vec.mag2();
181 }
182
183
184 VARIABLE_GROUP("Specific kinematic variables");
185
186 REGISTER_VARIABLE("recQ2BhSimple", REC_q2BhSimple,
187 "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_B - p_h)^2`, \n"
188 "where p_h is the CMS momentum of all hadrons in the decay :math:`B \\to H_1 ... H_n \\ell \\nu_\\ell`.\n"
189 "The B meson momentum in CMS is assumed to be 0.\n\n", ":math:`[\\text{GeV}/\\text{c}]^2`");
190
191 REGISTER_VARIABLE("recQ2Bh", REC_q2Bh,
192 "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_B - p_h)^2`, \n"
193 "where p_h is the CMS momentum of all hadrons in the decay :math:`B \\to H_1\\dots H_n \\ell \\nu_\\ell`.\n"
194 "This calculation uses a weighted average of the B meson around the reco B cone. \n"
195 "Based on diamond frame calculation of :math:`q^2` following the idea presented in https://www.osti.gov/biblio/1442697 \n"
196 "It will switch to use of :b2:var:`recQ2BhSimple` if absolute of :b2:var:`cosThetaBetweenParticleAndNominalB` > 1.\n\n",
197 ":math:`[\\text{GeV}/\\text{c}]^2`");
198
199 REGISTER_VARIABLE("recMissM2", REC_MissM2, R"DOC(
200 Returns the invariant mass squared of the missing momentum calculated assumings the
201 reco B is at rest and calculating the neutrino (missing) momentum from :math:`p_\nu = p_B - p_{\rm had} - p_{\rm lep}`
202
203 )DOC", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
204
205
206
207 }
209}
static const ChargedStable muon
muon particle
Definition: Const.h:660
static const double doubleNaN
quiet_NaN
Definition: Const.h:703
static const ChargedStable electron
electron particle
Definition: Const.h:659
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.