Belle II Software  light-2205-abys
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  VARIABLE_GROUP("Helicity variables");
259 
260  REGISTER_VARIABLE("cosHelicityAngleMomentum", cosHelicityAngleMomentum, R"DOC(
261  If the given particle has two daughters: cosine of the angle between the line defined by the momentum difference of the two daughters
262  in the frame of the given particle (mother)
263  and the momentum of the given particle in the lab frame.
264 
265  If the given particle has three daughters: cosine of the angle between the normal vector of the plane defined by
266  the momenta of the three daughters in the frame of the given particle (mother)
267  and the momentum of the given particle in the lab frame.
268 
269  Otherwise, it returns 0.)DOC");
270 
271  REGISTER_VARIABLE("cosHelicityAngleMomentumPi0Dalitz", cosHelicityAngleMomentumPi0Dalitz, R"DOC(
272  To be used for the decay :math:`\pi^0 \to e^+ e^- \gamma`:
273  cosine of the angle between the momentum of the gamma in the frame of the given particle (mother)
274  and the momentum of the given particle in the lab frame.
275 
276  Otherwise, it returns 0.)DOC");
277 
278  REGISTER_VARIABLE("cosHelicityAngleBeamMomentum(i)", cosHelicityAngleBeamMomentum, R"DOC(
279  Cosine of the helicity angle of the :math:`i`-th daughter of the particle provided,
280  assuming that the mother of the provided particle corresponds to the centre-of-mass system, whose parameters are
281  automatically loaded by the function, given the accelerator's conditions.)DOC");
282 
283  REGISTER_VARIABLE("cosHelicityAngle(i, j)", cosHelicityAngle, R"DOC(
284  Cosine of the helicity angle between the momentum of the provided particle and the momentum of the selected granddaughter
285  in the reference frame of the selected daughter (:math:`\theta_1` and :math:`\theta_2` in the
286  `PDG <https://journals.aps.org/prd/abstract/10.1103/PhysRevD.98.030001>`_ 2018, p. 722).
287 
288  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.
289 
290  For example, in the decay :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`,
291  if the provided particle is :math:`B^0` and the selected indices are (0, 0),
292  the variable will return the angle between the momentum of the :math:`B^0` and the momentum of the :math:`\mu^+`,
293  both momenta in the rest frame of the :math:`J/\psi`.
294 
295  This variable is needed for angular analyses of :math:`B`-meson decays into two vector particles.)DOC");
296 
297  REGISTER_VARIABLE("cosAcoplanarityAngle(i, j)", cosAcoplanarityAngle, R"DOC(
298  Cosine of the acoplanarity angle (:math:`\Phi` in the `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_).
299  Given a two-body decay, the acoplanarity angle is defined as
300  the angle between the two decay planes in the reference frame of the mother.
301 
302  We calculate the acoplanarity angle as the angle between the two
303  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
304  momentum of one of the granddaughters (in the reference frame of the daughter).
305 
306  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
307  second granddaughter.
308 
309  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),
310  the variable will return the acoplanarity using the :math:`\mu^+` and the :math:`K^+` granddaughters.)DOC");
311 
312  REGISTER_VARIABLE("cosHelicityAnglePrimary", cosHelicityAnglePrimary, R"DOC(
313  Cosine of the helicity angle (see``Particle::getCosHelicity``) assuming the center of mass system as mother rest frame.
314  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
315 
316  REGISTER_VARIABLE("cosHelicityAngleDaughter(i [, j] )", cosHelicityAngleDaughter, R"DOC(
317  Cosine of the helicity angle of the i-th daughter (see ``Particle::getCosHelicityDaughter``).
318  The optional second argument is the index of the granddaughter that defines the angle, default is 0.
319 
320  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,
321  the variable will return the helicity angle of the :math:`\mu^+`.
322  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}`).
323  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^-`).
324 
325  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
326 
327  REGISTER_VARIABLE("acoplanarityAngle", acoplanarityAngle, R"DOC(
328  Acoplanarity angle (see ``Particle::getAcoplanarity``) assuming a two body decay of the particle and its daughters.
329  See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the acoplanarity angle.)DOC",
330  "rad");
331  }
333 }
B2Vector3< DataType > Cross(const B2Vector3< DataType > &p) const
Cross product.
Definition: B2Vector3.h:290
DataType Dot(const B2Vector3< DataType > &p) const
Scalar product.
Definition: B2Vector3.h:284
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:502
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23