10 #include <analysis/variables/HelicityVariables.h>
12 #include <analysis/variables/EventVariables.h>
14 #include <analysis/dataobjects/Particle.h>
16 #include <analysis/utility/ReferenceFrame.h>
17 #include <analysis/VariableManager/Manager.h>
19 #include <framework/utilities/Conversion.h>
20 #include <framework/gearbox/Const.h>
22 #include <Math/Boost.h>
23 #include <Math/Vector4D.h>
24 using namespace ROOT::Math;
34 double cosHelicityAngleMomentum(
const Particle* part)
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() ;
42 if (daughters.size() == 2) {
44 bool isOneConversion =
false;
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;
55 if (isOneConversion) {
60 for (
auto& idaughter : daughters) {
61 if (idaughter -> getNDaughters() == 2)
continue;
62 else pGamma = frame.getMomentum(idaughter);
65 pGamma = Boost(motherBoost) * pGamma;
67 return std::cos(motherMomentum.Angle(pGamma.Vect()));
70 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
71 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
73 pDaughter1 = Boost(motherBoost) * pDaughter1;
74 pDaughter2 = Boost(motherBoost) * pDaughter2;
76 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
78 return std::cos(motherMomentum.Angle(p12));
81 }
else if (daughters.size() == 3) {
83 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
84 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
85 PxPyPzEVector pDaughter3 = frame.getMomentum(daughters[2]);
87 pDaughter1 = Boost(motherBoost) * pDaughter1;
88 pDaughter2 = Boost(motherBoost) * pDaughter2;
89 pDaughter3 = Boost(motherBoost) * pDaughter3;
91 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
92 B2Vector3D p13 = (pDaughter3 - pDaughter1).Vect();
96 return std::cos(motherMomentum.Angle(n));
98 }
else return std::numeric_limits<float>::quiet_NaN();
102 double cosHelicityAngleMomentumPi0Dalitz(
const Particle* part)
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() ;
111 if (daughters.size() == 3) {
113 PxPyPzEVector pGamma;
115 for (
auto& idaughter : daughters) {
116 if (std::abs(idaughter -> getPDGCode()) == Const::photon.getPDGCode()) pGamma = frame.getMomentum(idaughter);
119 pGamma = Boost(motherBoost) * pGamma;
121 return std::cos(motherMomentum.Angle(pGamma.Vect()));
123 }
else return std::numeric_limits<float>::quiet_NaN();
128 double cosHelicityAngleBeamMomentum(
const Particle* mother,
const std::vector<double>& index)
130 if (index.size() != 1) {
131 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfCMSIsTheMother");
134 int idau = std::lround(index[0]);
136 const Particle* part = mother->getDaughter(idau);
138 B2FATAL(
"Couldn't find the " << idau <<
"th daughter");
141 PxPyPzEVector beam4Vector(getBeamPx(
nullptr), getBeamPy(
nullptr), getBeamPz(
nullptr), getBeamE(
nullptr));
142 PxPyPzEVector part4Vector = part->get4Vector();
143 PxPyPzEVector mother4Vector = mother->get4Vector();
145 B2Vector3D motherBoost = mother4Vector.BoostToCM();
147 beam4Vector = Boost(motherBoost) * beam4Vector;
148 part4Vector = Boost(motherBoost) * part4Vector;
150 return - part4Vector.Vect().
Dot(beam4Vector.Vect()) / part4Vector.P() / beam4Vector.P();
154 double cosHelicityAngle(
const Particle* mother,
const std::vector<double>& indices)
156 if (indices.size() != 2) {
157 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfRefFrameIsTheDaughter: two are needed.");
160 int iDau = std::lround(indices[0]);
161 int iGrandDau = std::lround(indices[1]);
163 const Particle* daughter = mother->getDaughter(iDau);
165 B2FATAL(
"Couldn't find the " << iDau <<
"th daughter.");
167 const Particle* grandDaughter = daughter->getDaughter(iGrandDau);
169 B2FATAL(
"Couldn't find the " << iGrandDau <<
"th daughter of the " << iDau <<
"th daughter.");
171 PxPyPzEVector mother4Vector = mother->get4Vector();
172 PxPyPzEVector daughter4Vector = daughter->get4Vector();
173 PxPyPzEVector grandDaughter4Vector = grandDaughter->get4Vector();
175 B2Vector3D daughterBoost = daughter4Vector.BoostToCM();
178 grandDaughter4Vector = Boost(daughterBoost) * grandDaughter4Vector;
179 mother4Vector = Boost(daughterBoost) * mother4Vector;
181 return - grandDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / grandDaughter4Vector.P() / mother4Vector.P();
184 double cosAcoplanarityAngle(
const Particle* mother,
const std::vector<double>& granddaughters)
186 if (granddaughters.size() != 2) {
187 B2FATAL(
"Wrong number of arguments for cosAcoplanarityAngleIfRefFrameIsTheMother: two are needed.");
190 if (mother->getNDaughters() != 2)
191 B2FATAL(
"cosAcoplanarityAngleIfRefFrameIsTheMother: this variable works only for two-body decays.");
193 int iGrandDau1 = std::lround(granddaughters[0]);
194 int iGrandDau2 = std::lround(granddaughters[1]);
196 const Particle* daughter1 = mother->getDaughter(0);
197 const Particle* daughter2 = mother->getDaughter(1);
199 const Particle* grandDaughter1 = daughter1->getDaughter(iGrandDau1);
201 B2FATAL(
"Couldn't find the " << iGrandDau1 <<
"th daughter of the first daughter.");
203 const Particle* grandDaughter2 = daughter2->getDaughter(iGrandDau2);
205 B2FATAL(
"Couldn't find the " << iGrandDau2 <<
"th daughter of the second daughter.");
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();
213 B2Vector3D motherBoost = mother4Vector.BoostToCM();
214 B2Vector3D daughter1Boost = daughter4Vector1.BoostToCM();
215 B2Vector3D daughter2Boost = daughter4Vector2.BoostToCM();
218 daughter4Vector1 = Boost(motherBoost) * daughter4Vector1;
219 daughter4Vector2 = Boost(motherBoost) * daughter4Vector2;
222 grandDaughter4Vector1 = Boost(daughter1Boost) * grandDaughter4Vector1;
223 grandDaughter4Vector2 = Boost(daughter2Boost) * grandDaughter4Vector2;
226 B2Vector3D normalVector1 = daughter4Vector1.Vect().
Cross(grandDaughter4Vector1.Vect());
227 B2Vector3D normalVector2 = daughter4Vector2.Vect().
Cross(grandDaughter4Vector2.Vect());
229 return std::cos(normalVector1.Angle(normalVector2));
232 double cosHelicityAnglePrimary(
const Particle* part)
234 return part->getCosHelicity();
237 double cosHelicityAngleDaughter(
const Particle* part,
const std::vector<double>& indices)
239 if ((indices.size() == 0) || (indices.size() > 2)) {
240 B2FATAL(
"Wrong number of arguments for cosHelicityAngleDaughter: one or two are needed.");
243 int iDaughter = std::lround(indices[0]);
244 int iGrandDaughter = 0;
245 if (indices.size() == 2) {
246 iGrandDaughter = std::lround(indices[1]);
249 return part->getCosHelicityDaughter(iDaughter, iGrandDaughter);
252 double acoplanarityAngle(
const Particle* part)
254 return part->getAcoplanarity();
258 double cosHelicityAngleForQuasiTwoBodyDecay(
const Particle* mother,
const std::vector<double>& indices)
260 if (indices.size() != 2) {
261 B2FATAL(
"Wrong number of arguments for cosHelicityAngleForQuasiTwoBodyDecay: two are needed.");
264 if (mother->getNDaughters() != 3)
265 return std::numeric_limits<float>::quiet_NaN();
267 int iDau = std::lround(indices[0]);
268 int jDau = std::lround(indices[1]);
270 const Particle* iDaughter = mother->getDaughter(iDau);
272 return std::numeric_limits<float>::quiet_NaN();
274 const Particle* jDaughter = mother->getDaughter(jDau);
276 return std::numeric_limits<float>::quiet_NaN();
278 PxPyPzEVector mother4Vector = mother->get4Vector();
279 PxPyPzEVector iDaughter4Vector = iDaughter->get4Vector();
280 PxPyPzEVector jDaughter4Vector = jDaughter->get4Vector();
282 PxPyPzEVector resonance4Vector = iDaughter4Vector + jDaughter4Vector;
283 B2Vector3D resonanceBoost = resonance4Vector.BoostToCM();
285 iDaughter4Vector = Boost(resonanceBoost) * iDaughter4Vector;
286 mother4Vector = Boost(resonanceBoost) * mother4Vector;
288 return - iDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / iDaughter4Vector.P() / mother4Vector.P();
292 VARIABLE_GROUP(
"Helicity variables");
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.
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.
303 Otherwise, it returns 0.)DOC");
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.
310 Otherwise, it returns 0.)DOC");
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");
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).
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.
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`.
329 This variable is needed for angular analyses of :math:`B`-meson decays into two vector particles.)DOC");
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.
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).
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.
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");
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");
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.
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^-`).
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");
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",
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).
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.
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");
B2Vector3< DataType > Cross(const B2Vector3< DataType > &p) const
Cross product.
DataType Dot(const B2Vector3< DataType > &p) const
Scalar product.
B2Vector3< double > B2Vector3D
typedef for common usage with double
Abstract base class for different kinds of events.