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