Belle II Software  release-06-01-15
HelicityVariables.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 
10 #include <analysis/variables/HelicityVariables.h>
11 #include <analysis/variables/EventVariables.h>
12 
13 #include <analysis/dataobjects/Particle.h>
14 
15 #include <analysis/utility/ReferenceFrame.h>
16 
17 #include <framework/utilities/Conversion.h>
18 #include <framework/gearbox/Const.h>
19 
20 #include <TLorentzVector.h>
21 #include <TVector3.h>
22 #include <cmath>
23 
24 namespace Belle2 {
29  namespace Variable {
30 
31  double cosHelicityAngleMomentum(const Particle* part)
32  {
33 
34  const auto& frame = ReferenceFrame::GetCurrent();
35  TVector3 motherBoost = - frame.getMomentum(part).BoostVector();
36  TVector3 motherMomentum = frame.getMomentum(part).Vect();
37  const auto& daughters = part -> getDaughters() ;
38 
39  if (daughters.size() == 2) {
40 
41  bool isOneConversion = false;
42 
43  for (auto& idaughter : daughters) {
44  if (idaughter -> getNDaughters() == 2) {
45  if (std::abs(idaughter -> getDaughters()[0]-> getPDGCode()) == Const::electron.getPDGCode()
46  && std::abs(idaughter -> getDaughters()[1]-> getPDGCode()) == Const::electron.getPDGCode()) {
47  isOneConversion = true;
48  }
49  }
50  }
51 
52  if (isOneConversion) {
53  //only for pi0 decay where one gamma converts
54 
55  TLorentzVector pGamma;
56 
57  for (auto& idaughter : daughters) {
58  if (idaughter -> getNDaughters() == 2) continue;
59  else pGamma = frame.getMomentum(idaughter);
60  }
61 
62  pGamma.Boost(motherBoost);
63 
64  return std::cos(motherMomentum.Angle(pGamma.Vect()));
65 
66  } else {
67  TLorentzVector pDaughter1 = frame.getMomentum(daughters[0]);
68  TLorentzVector pDaughter2 = frame.getMomentum(daughters[1]);
69 
70  pDaughter1.Boost(motherBoost);
71  pDaughter2.Boost(motherBoost);
72 
73  TVector3 p12 = (pDaughter2 - pDaughter1).Vect();
74 
75  return std::cos(motherMomentum.Angle(p12));
76  }
77 
78  } else if (daughters.size() == 3) {
79 
80  TLorentzVector pDaughter1 = frame.getMomentum(daughters[0]);
81  TLorentzVector pDaughter2 = frame.getMomentum(daughters[1]);
82  TLorentzVector pDaughter3 = frame.getMomentum(daughters[2]);
83 
84  pDaughter1.Boost(motherBoost);
85  pDaughter2.Boost(motherBoost);
86  pDaughter3.Boost(motherBoost);
87 
88  TVector3 p12 = (pDaughter2 - pDaughter1).Vect();
89  TVector3 p13 = (pDaughter3 - pDaughter1).Vect();
90 
91  TVector3 n = p12.Cross(p13);
92 
93  return std::cos(motherMomentum.Angle(n));
94 
95  } else return std::numeric_limits<float>::quiet_NaN();
96 
97  }
98 
99  double cosHelicityAngleMomentumPi0Dalitz(const Particle* part)
100  {
101 
102  const auto& frame = ReferenceFrame::GetCurrent();
103  TVector3 motherBoost = - frame.getMomentum(part).BoostVector();
104  TVector3 motherMomentum = frame.getMomentum(part).Vect();
105  const auto& daughters = part -> getDaughters() ;
106 
107 
108  if (daughters.size() == 3) {
109 
110  TLorentzVector pGamma;
111 
112  for (auto& idaughter : daughters) {
113  if (std::abs(idaughter -> getPDGCode()) == Const::photon.getPDGCode()) pGamma = frame.getMomentum(idaughter);
114  }
115 
116  pGamma.Boost(motherBoost);
117 
118  return std::cos(motherMomentum.Angle(pGamma.Vect()));
119 
120  } else return std::numeric_limits<float>::quiet_NaN();
121 
122  }
123 
124 
125  Manager::FunctionPtr cosHelicityAngleBeamMomentum(const std::vector<std::string>& arguments)
126  {
127  int idau = 0;
128  if (arguments.size() == 1) {
129  try {
130  idau = Belle2::convertString<int>(arguments[0]);
131  } catch (std::invalid_argument&) {
132  B2FATAL("The argument of cosHelicityAngleWrtCMSFrame must be an integer!");
133  }
134  } else {
135  B2FATAL("Wrong number of arguments for cosHelicityAngleIfCMSIsTheMother");
136  }
137  auto func = [idau](const Particle * mother) -> double {
138  const Particle* part = mother->getDaughter(idau);
139  if (!part)
140  {
141  B2FATAL("Couldn't find the " << idau << "th daughter");
142  }
143 
144  TLorentzVector beam4Vector(getBeamPx(nullptr), getBeamPy(nullptr), getBeamPz(nullptr), getBeamE(nullptr));
145  TLorentzVector part4Vector = part->get4Vector();
146  TLorentzVector mother4Vector = mother->get4Vector();
147 
148  TVector3 motherBoost = -(mother4Vector.BoostVector());
149 
150  beam4Vector.Boost(motherBoost);
151  part4Vector.Boost(motherBoost);
152 
153  return - part4Vector.Vect().Dot(beam4Vector.Vect()) / part4Vector.Vect().Mag() / beam4Vector.Vect().Mag();
154  };
155  return func;
156  }
157 
158 
159  Manager::FunctionPtr cosHelicityAngle(const std::vector<std::string>& arguments)
160  {
161  int iDau = 0;
162  int iGrandDau = 0;
163  if (arguments.size() == 2) {
164  try {
165  iDau = Belle2::convertString<int>(arguments[0]);
166  iGrandDau = Belle2::convertString<int>(arguments[1]);
167  } catch (std::invalid_argument&) {
168  B2FATAL("The two arguments of cosHelicityAngleIfRefFrameIsTheDaughter must be integers!");
169  }
170  } else {
171  B2FATAL("Wrong number of arguments for cosHelicityAngleIfRefFrameIsTheDaughter: two are needed.");
172  }
173  auto func = [iDau, iGrandDau](const Particle * mother) -> double {
174 
175  const Particle* daughter = mother->getDaughter(iDau);
176  if (!daughter)
177  B2FATAL("Couldn't find the " << iDau << "th daughter.");
178 
179  const Particle* grandDaughter = daughter->getDaughter(iGrandDau);
180  if (!grandDaughter)
181  B2FATAL("Couldn't find the " << iGrandDau << "th daughter of the " << iDau << "th daughter.");
182 
183 
184  TLorentzVector mother4Vector = mother->get4Vector();
185  TLorentzVector daughter4Vector = daughter->get4Vector();
186  TLorentzVector grandDaughter4Vector = grandDaughter->get4Vector();
187 
188  TVector3 daughterBoost = -(daughter4Vector.BoostVector());
189 
190  // We boost the momentum of the mother and of the granddaughter to the reference frame of the daughter.
191  grandDaughter4Vector.Boost(daughterBoost);
192  mother4Vector.Boost(daughterBoost);
193 
194  return - grandDaughter4Vector.Vect().Dot(mother4Vector.Vect()) / grandDaughter4Vector.Vect().Mag() / mother4Vector.Vect().Mag();
195 
196  };
197  return func;
198  }
199 
200  Manager::FunctionPtr cosAcoplanarityAngle(const std::vector<std::string>& arguments)
201  {
202  int iGrandDau1 = 0;
203  int iGrandDau2 = 0;
204  if (arguments.size() == 2) {
205  try {
206  iGrandDau1 = Belle2::convertString<int>(arguments[0]);
207  iGrandDau2 = Belle2::convertString<int>(arguments[1]);
208  } catch (std::invalid_argument&) {
209  B2FATAL("The two arguments of cosAcoplanarityAngleIfRefFrameIsTheMother must be integers!");
210  }
211  } else {
212  B2FATAL("Wrong number of arguments for cosAcoplanarityAngleIfRefFrameIsTheMother: two are needed.");
213  }
214  auto func = [iGrandDau1, iGrandDau2](const Particle * mother) -> double {
215 
216  if (mother->getNDaughters() != 2)
217  B2FATAL("cosAcoplanarityAngleIfRefFrameIsTheMother: this variable works only for two-body decays.");
218 
219  const Particle* daughter1 = mother-> getDaughter(0);
220  const Particle* daughter2 = mother-> getDaughter(1);
221 
222  const Particle* grandDaughter1 = daughter1 -> getDaughter(iGrandDau1);
223  if (!grandDaughter1)
224  B2FATAL("Couldn't find the " << iGrandDau1 << "th daughter of the first daughter.");
225 
226  const Particle* grandDaughter2 = daughter2 -> getDaughter(iGrandDau2);
227  if (!grandDaughter2)
228  B2FATAL("Couldn't find the " << iGrandDau2 << "th daughter of the second daughter.");
229 
230  TLorentzVector mother4Vector = mother->get4Vector();
231  TLorentzVector daughter4Vector1 = daughter1->get4Vector();
232  TLorentzVector daughter4Vector2 = daughter2->get4Vector();
233  TLorentzVector grandDaughter4Vector1 = grandDaughter1->get4Vector();
234  TLorentzVector grandDaughter4Vector2 = grandDaughter2->get4Vector();
235 
236  TVector3 motherBoost = -(mother4Vector.BoostVector());
237  TVector3 daughter1Boost = -(daughter4Vector1.BoostVector());
238  TVector3 daughter2Boost = -(daughter4Vector2.BoostVector());
239 
240  // Boosting daughters to reference frame of the mother
241  daughter4Vector1.Boost(motherBoost);
242  daughter4Vector2.Boost(motherBoost);
243 
244  // Boosting each granddaughter to reference frame of its mother
245  grandDaughter4Vector1.Boost(daughter1Boost);
246  grandDaughter4Vector2.Boost(daughter2Boost);
247 
248  // We calculate the normal vectors of the decay two planes
249  TVector3 normalVector1 = daughter4Vector1.Vect().Cross(grandDaughter4Vector1.Vect());
250  TVector3 normalVector2 = daughter4Vector2.Vect().Cross(grandDaughter4Vector2.Vect());
251 
252  return std::cos(normalVector1.Angle(normalVector2));
253 
254  };
255  return func;
256  }
257 
258 
259  double cosHelicityAnglePrimary(const Particle* part)
260  {
261  return part->getCosHelicity();
262  }
263 
264  Manager::FunctionPtr cosHelicityAngleDaughter(const std::vector<std::string>& arguments)
265  {
266  int iDaughter = 0;
267  int iGrandDaughter = 0;
268  if ((arguments.size() == 0) || (arguments.size() > 2)) {
269  B2FATAL("Wrong number of arguments for cosHelicityAngleDaughter: one or two are needed.");
270  }
271  try {
272  iDaughter = Belle2::convertString<int>(arguments[0]);
273  if (arguments.size() == 2) {
274  iGrandDaughter = Belle2::convertString<int>(arguments[1]);
275  }
276  } catch (std::invalid_argument&) {
277  B2FATAL("The arguments of cosHelicityAngleDaughter must be integers!");
278  }
279 
280  auto func = [iDaughter, iGrandDaughter](const Particle * part) -> double {
281  return part->getCosHelicityDaughter(iDaughter, iGrandDaughter);
282  };
283  return func;
284  }
285 
286  double acoplanarityAngle(const Particle* part)
287  {
288  return part->getAcoplanarity();
289  }
290 
291 
292  VARIABLE_GROUP("Helicity variables");
293 
294  REGISTER_VARIABLE("cosHelicityAngleMomentum",
295  cosHelicityAngleMomentum,
296  R"DOC(
297  If the given particle has two daughters: cosine of the angle between the line defined by the momentum difference of the two daughters
298  in the frame of the given particle (mother)
299  and the momentum of the given particle in the lab frame.
300 
301  If the given particle has three daughters: cosine of the angle between the normal vector of the plane defined by
302  the momenta of the three daughters in the frame of the given particle (mother)
303  and the momentum of the given particle in the lab frame.
304 
305  Otherwise, it returns 0.)DOC");
306 
307  REGISTER_VARIABLE("cosHelicityAngleMomentumPi0Dalitz",
308  cosHelicityAngleMomentumPi0Dalitz,
309  R"DOC(
310  To be used for the decay :math:`\pi^0 \to e^+ e^- \gamma`:
311  cosine of the angle between the momentum of the gamma in the frame of the given particle (mother)
312  and the momentum of the given particle in the lab frame.
313 
314  Otherwise, it returns 0.)DOC");
315 
316  REGISTER_VARIABLE("cosHelicityAngleBeamMomentum(i)", cosHelicityAngleBeamMomentum,
317  R"DOC(
318  Cosine of the helicity angle of the :math:`i`-th daughter of the particle provided,
319  assuming that the mother of the provided particle corresponds to the centre-of-mass system, whose parameters are
320  automatically loaded by the function, given the accelerator's conditions.)DOC");
321 
322  REGISTER_VARIABLE("cosHelicityAngle(i, j)", cosHelicityAngle,
323  R"DOC(
324  Cosine of the helicity angle between the momentum of the provided particle and the momentum of the selected granddaughter
325  in the reference frame of the selected daughter (:math:`\theta_1` and :math:`\theta_2` in the
326  `PDG <https://journals.aps.org/prd/abstract/10.1103/PhysRevD.98.030001>`_ 2018, p. 722).
327 
328  This variable needs two integer arguments: the first one, ``i``, is the index of the daughter and the second one, ``j`` is the index of the granddaughter.
329 
330  For example, in the decay :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`,
331  if the provided particle is :math:`B^0` and the selected indices are (0, 0),
332  the variable will return the angle between the momentum of the :math:`B^0` and the momentum of the :math:`\mu^+`,
333  both momenta in the rest frame of the :math:`J/\psi`.
334 
335  This variable is needed for angular analyses of :math:`B`-meson decays into two vector particles.)DOC");
336 
337  REGISTER_VARIABLE("cosAcoplanarityAngle(i, j)", cosAcoplanarityAngle,
338  R"DOC(
339  Cosine of the acoplanarity angle (:math:`\Phi` in the `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_).
340  Given a two-body decay, the acoplanarity angle is defined as
341  the angle between the two decay planes in the reference frame of the mother.
342 
343  We calculate the acoplanarity angle as the angle between the two
344  normal vectors of the decay planes. Each normal vector is the cross product of the momentum of one daughter (in the frame of the mother) and the
345  momentum of one of the granddaughters (in the reference frame of the daughter).
346 
347  This variable needs two integer arguments: the first one, ``i`` is the index of the first granddaughter, and the second one, ``j`` the index of the
348  second granddaughter.
349 
350  For example, in the decay :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`, if the provided particle is :math:`B^0` and the selected indices are (0, 0),
351  the variable will return the acoplanarity using the :math:`\mu^+` and the :math:`K^+` granddaughters.)DOC");
352 
353  REGISTER_VARIABLE("cosHelicityAnglePrimary", cosHelicityAnglePrimary,
354  R"DOC(
355  Cosine of the helicity angle (see``Particle::getCosHelicity``) assuming the center of mass system as mother rest frame.
356  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
357 
358  REGISTER_VARIABLE("cosHelicityAngleDaughter(i [, j] )", cosHelicityAngleDaughter,
359  R"DOC(
360  Cosine of the helicity angle of the i-th daughter (see ``Particle::getCosHelicityDaughter``).
361  The optional second argument is the index of the granddaughter that defines the angle, default is 0.
362 
363  For example, in the decay: :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`, if the provided particle is :math:`B^0` and the selected index is 0,
364  the variable will return the helicity angle of the :math:`\mu^+`.
365  If the selected index is 1 the variable will return the helicity angle of the :math:`K^+` (defined via the rest frame of the :math:`K^{*0}`).
366  In rare cases if one wanted the helicity angle of the second granddaughter, indices 1,1 would return the helicity angle of the :math:`\pi^-`).
367 
368  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
369 
370  REGISTER_VARIABLE("acoplanarityAngle", acoplanarityAngle,
371  R"DOC(
372  Acoplanarity angle (see ``Particle::getAcoplanarity``) assuming a two body decay of the particle and its daughters.
373  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the acoplanarity angle.)DOC");
374 
375  }
377 }
static const ParticleType photon
photon particle
Definition: Const.h:554
static const ChargedStable electron
electron particle
Definition: Const.h:540
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< double(const Particle *)> FunctionPtr
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
Definition: Manager.h:108
Abstract base class for different kinds of events.