10 #include <analysis/variables/HelicityVariables.h>
12 #include <analysis/VariableManager/Utility.h>
14 #include <analysis/variables/EventVariables.h>
16 #include <analysis/dataobjects/Particle.h>
18 #include <analysis/utility/ReferenceFrame.h>
19 #include <analysis/VariableManager/Manager.h>
21 #include <framework/utilities/Conversion.h>
22 #include <framework/gearbox/Const.h>
24 #include <boost/algorithm/string.hpp>
26 #include <Math/Boost.h>
27 #include <Math/Vector4D.h>
28 using namespace ROOT::Math;
38 double cosHelicityAngleMomentum(
const Particle* part)
41 const auto& frame = ReferenceFrame::GetCurrent();
42 B2Vector3D motherBoost = frame.getMomentum(part).BoostToCM();
43 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
44 const auto& daughters = part -> getDaughters() ;
46 if (daughters.size() == 2) {
48 bool isOneConversion =
false;
50 for (
auto& idaughter : daughters) {
51 if (idaughter -> getNDaughters() == 2) {
52 if (std::abs(idaughter -> getDaughters()[0]-> getPDGCode()) == Const::electron.getPDGCode()
53 && std::abs(idaughter -> getDaughters()[1]-> getPDGCode()) == Const::electron.getPDGCode()) {
54 isOneConversion =
true;
59 if (isOneConversion) {
64 for (
auto& idaughter : daughters) {
65 if (idaughter -> getNDaughters() == 2)
continue;
66 else pGamma = frame.getMomentum(idaughter);
69 pGamma = Boost(motherBoost) * pGamma;
71 return std::cos(motherMomentum.Angle(pGamma.Vect()));
74 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
75 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
77 pDaughter1 = Boost(motherBoost) * pDaughter1;
78 pDaughter2 = Boost(motherBoost) * pDaughter2;
80 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
82 return std::cos(motherMomentum.Angle(p12));
85 }
else if (daughters.size() == 3) {
87 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
88 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
89 PxPyPzEVector pDaughter3 = frame.getMomentum(daughters[2]);
91 pDaughter1 = Boost(motherBoost) * pDaughter1;
92 pDaughter2 = Boost(motherBoost) * pDaughter2;
93 pDaughter3 = Boost(motherBoost) * pDaughter3;
95 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
96 B2Vector3D p13 = (pDaughter3 - pDaughter1).Vect();
100 return std::cos(motherMomentum.Angle(n));
102 }
else return Const::doubleNaN;
106 double cosHelicityAngleMomentumPi0Dalitz(
const Particle* part)
109 const auto& frame = ReferenceFrame::GetCurrent();
110 B2Vector3D motherBoost = frame.getMomentum(part).BoostToCM();
111 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
112 const auto& daughters = part -> getDaughters() ;
115 if (daughters.size() == 3) {
117 PxPyPzEVector pGamma;
119 for (
auto& idaughter : daughters) {
120 if (std::abs(idaughter -> getPDGCode()) == Const::photon.getPDGCode()) pGamma = frame.getMomentum(idaughter);
123 pGamma = Boost(motherBoost) * pGamma;
125 return std::cos(motherMomentum.Angle(pGamma.Vect()));
127 }
else return Const::doubleNaN;
132 double cosHelicityAngleBeamMomentum(
const Particle* mother,
const std::vector<double>& index)
134 if (index.size() != 1) {
135 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfCMSIsTheMother");
138 int idau = std::lround(index[0]);
140 const Particle* part = mother->getDaughter(idau);
142 B2FATAL(
"Couldn't find the " << idau <<
"th daughter");
145 PxPyPzEVector beam4Vector(getBeamPx(
nullptr), getBeamPy(
nullptr), getBeamPz(
nullptr), getBeamE(
nullptr));
146 PxPyPzEVector part4Vector = part->get4Vector();
147 PxPyPzEVector mother4Vector = mother->get4Vector();
149 B2Vector3D motherBoost = mother4Vector.BoostToCM();
151 beam4Vector = Boost(motherBoost) * beam4Vector;
152 part4Vector = Boost(motherBoost) * part4Vector;
154 return - part4Vector.Vect().
Dot(beam4Vector.Vect()) / part4Vector.P() / beam4Vector.P();
158 double cosHelicityAngle(
const Particle* mother,
const std::vector<double>& indices)
160 if (indices.size() != 2) {
161 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfRefFrameIsTheDaughter: two are needed.");
164 int iDau = std::lround(indices[0]);
165 int iGrandDau = std::lround(indices[1]);
167 const Particle* daughter = mother->getDaughter(iDau);
169 B2FATAL(
"Couldn't find the " << iDau <<
"th daughter.");
171 const Particle* grandDaughter = daughter->getDaughter(iGrandDau);
173 B2FATAL(
"Couldn't find the " << iGrandDau <<
"th daughter of the " << iDau <<
"th daughter.");
175 PxPyPzEVector mother4Vector = mother->get4Vector();
176 PxPyPzEVector daughter4Vector = daughter->get4Vector();
177 PxPyPzEVector grandDaughter4Vector = grandDaughter->get4Vector();
179 B2Vector3D daughterBoost = daughter4Vector.BoostToCM();
182 grandDaughter4Vector = Boost(daughterBoost) * grandDaughter4Vector;
183 mother4Vector = Boost(daughterBoost) * mother4Vector;
185 return - grandDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / grandDaughter4Vector.P() / mother4Vector.P();
188 double cosAcoplanarityAngle(
const Particle* mother,
const std::vector<double>& granddaughters)
190 if (granddaughters.size() != 2) {
191 B2FATAL(
"Wrong number of arguments for cosAcoplanarityAngleIfRefFrameIsTheMother: two are needed.");
194 if (mother->getNDaughters() != 2)
195 B2FATAL(
"cosAcoplanarityAngleIfRefFrameIsTheMother: this variable works only for two-body decays.");
197 int iGrandDau1 = std::lround(granddaughters[0]);
198 int iGrandDau2 = std::lround(granddaughters[1]);
200 const Particle* daughter1 = mother->getDaughter(0);
201 const Particle* daughter2 = mother->getDaughter(1);
203 const Particle* grandDaughter1 = daughter1->getDaughter(iGrandDau1);
205 B2FATAL(
"Couldn't find the " << iGrandDau1 <<
"th daughter of the first daughter.");
207 const Particle* grandDaughter2 = daughter2->getDaughter(iGrandDau2);
209 B2FATAL(
"Couldn't find the " << iGrandDau2 <<
"th daughter of the second daughter.");
211 PxPyPzEVector mother4Vector = mother->get4Vector();
212 PxPyPzEVector daughter4Vector1 = daughter1->get4Vector();
213 PxPyPzEVector daughter4Vector2 = daughter2->get4Vector();
214 PxPyPzEVector grandDaughter4Vector1 = grandDaughter1->get4Vector();
215 PxPyPzEVector grandDaughter4Vector2 = grandDaughter2->get4Vector();
217 B2Vector3D motherBoost = mother4Vector.BoostToCM();
218 B2Vector3D daughter1Boost = daughter4Vector1.BoostToCM();
219 B2Vector3D daughter2Boost = daughter4Vector2.BoostToCM();
222 daughter4Vector1 = Boost(motherBoost) * daughter4Vector1;
223 daughter4Vector2 = Boost(motherBoost) * daughter4Vector2;
226 grandDaughter4Vector1 = Boost(daughter1Boost) * grandDaughter4Vector1;
227 grandDaughter4Vector2 = Boost(daughter2Boost) * grandDaughter4Vector2;
230 B2Vector3D normalVector1 = daughter4Vector1.Vect().
Cross(grandDaughter4Vector1.Vect());
231 B2Vector3D normalVector2 = daughter4Vector2.Vect().
Cross(grandDaughter4Vector2.Vect());
233 return std::cos(normalVector1.Angle(normalVector2));
236 double cosHelicityAnglePrimary(
const Particle* part)
238 return part->getCosHelicity();
241 double cosHelicityAngleDaughter(
const Particle* part,
const std::vector<double>& indices)
243 if ((indices.size() == 0) || (indices.size() > 2)) {
244 B2FATAL(
"Wrong number of arguments for cosHelicityAngleDaughter: one or two are needed.");
247 int iDaughter = std::lround(indices[0]);
248 int iGrandDaughter = 0;
249 if (indices.size() == 2) {
250 iGrandDaughter = std::lround(indices[1]);
253 return part->getCosHelicityDaughter(iDaughter, iGrandDaughter);
256 double acoplanarityAngle(
const Particle* part)
258 return part->getAcoplanarity();
262 double cosHelicityAngleForQuasiTwoBodyDecay(
const Particle* mother,
const std::vector<double>& indices)
264 if (indices.size() != 2) {
265 B2FATAL(
"Wrong number of arguments for cosHelicityAngleForQuasiTwoBodyDecay: two are needed.");
268 if (mother->getNDaughters() != 3)
269 return Const::doubleNaN;
271 int iDau = std::lround(indices[0]);
272 int jDau = std::lround(indices[1]);
274 const Particle* iDaughter = mother->getDaughter(iDau);
276 return Const::doubleNaN;
278 const Particle* jDaughter = mother->getDaughter(jDau);
280 return Const::doubleNaN;
282 PxPyPzEVector mother4Vector = mother->get4Vector();
283 PxPyPzEVector iDaughter4Vector = iDaughter->get4Vector();
284 PxPyPzEVector jDaughter4Vector = jDaughter->get4Vector();
286 PxPyPzEVector resonance4Vector = iDaughter4Vector + jDaughter4Vector;
287 B2Vector3D resonanceBoost = resonance4Vector.BoostToCM();
289 iDaughter4Vector = Boost(resonanceBoost) * iDaughter4Vector;
290 mother4Vector = Boost(resonanceBoost) * mother4Vector;
292 return - iDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / iDaughter4Vector.P() / mother4Vector.P();
295 Manager::FunctionPtr momentaTripleProduct(
const std::vector<std::string>& arguments)
297 if (arguments.size() != 3) {
298 B2FATAL(
"Wrong number of arguments for momentaTripleProduct: three (particles) are needed.");
302 auto func = [arguments](
const Particle * mother) ->
double {
303 auto iDau = arguments[0];
304 auto jDau = arguments[1];
305 auto kDau = arguments[2];
307 const Particle* iDaughter = mother->getParticleFromGeneralizedIndexString(iDau);
308 if (!iDaughter) B2FATAL(
"Couldn't find the " << iDau <<
"th daughter.");
309 const Particle* jDaughter = mother->getParticleFromGeneralizedIndexString(jDau);
310 if (!jDaughter) B2FATAL(
"Couldn't find the " << jDau <<
"th daughter.");
311 const Particle* kDaughter = mother->getParticleFromGeneralizedIndexString(kDau);
312 if (!kDaughter) B2FATAL(
"Couldn't find the " << kDau <<
"th daughter.");
314 PxPyPzEVector mother4Vector = mother->get4Vector();
315 PxPyPzEVector iDaughter4Vector = iDaughter->get4Vector();
316 PxPyPzEVector jDaughter4Vector = jDaughter->get4Vector();
317 PxPyPzEVector kDaughter4Vector = kDaughter->get4Vector();
319 B2Vector3D motherBoost = mother4Vector.BoostToCM();
322 iDaughter4Vector = Boost(motherBoost) * iDaughter4Vector;
323 jDaughter4Vector = Boost(motherBoost) * jDaughter4Vector;
324 kDaughter4Vector = Boost(motherBoost) * kDaughter4Vector;
327 B2Vector3D jkDaughterCrossProduct = jDaughter4Vector.Vect().
Cross(kDaughter4Vector.Vect());
329 return iDaughter4Vector.Vect().
Dot(jkDaughterCrossProduct) ;
335 VARIABLE_GROUP(
"Helicity variables");
337 REGISTER_VARIABLE(
"cosHelicityAngleMomentum", cosHelicityAngleMomentum, R
"DOC(
338 If the given particle has two daughters: cosine of the angle between the line defined by the momentum difference of the two daughters
339 in the frame of the given particle (mother)
340 and the momentum of the given particle in the lab frame.
342 If the given particle has three daughters: cosine of the angle between the normal vector of the plane defined by
343 the momenta of the three daughters in the frame of the given particle (mother)
344 and the momentum of the given particle in the lab frame.
346 Otherwise, it returns 0.)DOC");
348 REGISTER_VARIABLE("cosHelicityAngleMomentumPi0Dalitz", cosHelicityAngleMomentumPi0Dalitz, R
"DOC(
349 To be used for the decay :math:`\pi^0 \to e^+ e^- \gamma`:
350 cosine of the angle between the momentum of the gamma in the frame of the given particle (mother)
351 and the momentum of the given particle in the lab frame.
353 Otherwise, it returns 0.)DOC");
355 REGISTER_VARIABLE("cosHelicityAngleBeamMomentum(i)", cosHelicityAngleBeamMomentum, R
"DOC(
356 Cosine of the helicity angle of the :math:`i`-th daughter of the particle provided,
357 assuming that the mother of the provided particle corresponds to the centre-of-mass system, whose parameters are
358 automatically loaded by the function, given the accelerator's conditions.)DOC");
360 REGISTER_VARIABLE("cosHelicityAngle(i, j)", cosHelicityAngle, R
"DOC(
361 Cosine of the helicity angle between the momentum of the selected granddaughter and the direction opposite to the momentum of the provided particle
362 in the reference frame of the selected daughter (:math:`\theta_1` and :math:`\theta_2` in the
363 `PDG <https://journals.aps.org/prd/abstract/10.1103/PhysRevD.98.030001>`_ 2018, p. 722).
365 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.
367 For example, in the decay :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`,
368 if the provided particle is :math:`B^0` and the selected indices are (0, 0),
369 the variable will return the angle between the momentum of the :math:`\mu^+` and the direction opposite to the momentum of
370 the :math:`B^0`, both momenta in the rest frame of the :math:`J/\psi`.
372 This variable is needed for angular analyses of :math:`B`-meson decays into two vector particles.)DOC");
374 REGISTER_VARIABLE("cosAcoplanarityAngle(i, j)", cosAcoplanarityAngle, R
"DOC(
375 Cosine of the acoplanarity angle (:math:`\Phi` in the `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_).
376 Given a two-body decay, the acoplanarity angle is defined as
377 the angle between the two decay planes in the reference frame of the mother.
379 We calculate the acoplanarity angle as the angle between the two
380 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
381 momentum of one of the granddaughters (in the reference frame of the daughter).
383 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
384 second granddaughter.
386 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),
387 the variable will return the acoplanarity using the :math:`\mu^+` and the :math:`K^+` granddaughters.)DOC");
389 REGISTER_VARIABLE("cosHelicityAnglePrimary", cosHelicityAnglePrimary, R
"DOC(
390 Cosine of the helicity angle (see``Particle::getCosHelicity``) assuming the center of mass system as mother rest frame.
391 See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
393 REGISTER_VARIABLE("cosHelicityAngleDaughter(i [, j] )", cosHelicityAngleDaughter, R
"DOC(
394 Cosine of the helicity angle of the i-th daughter (see ``Particle::getCosHelicityDaughter``).
395 The optional second argument is the index of the granddaughter that defines the angle, default is 0.
397 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,
398 the variable will return the helicity angle of the :math:`\mu^+`.
399 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}`).
400 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^-`).
402 See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
404 REGISTER_VARIABLE("acoplanarityAngle", acoplanarityAngle, R
"DOC(
405 Acoplanarity angle (see ``Particle::getAcoplanarity``) assuming a two body decay of the particle and its daughters.
406 See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the acoplanarity angle.
410 REGISTER_VARIABLE(
"cosHelicityAngleForQuasiTwoBodyDecay(i, j)", cosHelicityAngleForQuasiTwoBodyDecay, R
"DOC(
411 Cosine of the helicity angle between the momentum of the provided particle and the momentum of the first selected
412 daughter (i-th) in the reference frame of the sum of two selected daughters (i-th + j-th).
414 The variable is supposed to be used for the analysis of a quasi-two-body decay. The number of daughters of the given
415 particle must be three. Otherwise, the variable returns NaN.
417 For example, in the decay :math:`\bar{B}^0 \to D^+ K^- K^{*0}`, if the provided particle is :math:`\bar{B}^0` and
418 the selected indices are (1, 2), the variable will return the angle between the momentum of the :math:`\bar{B}^0`
419 and the momentum of the :math:`K^-`, both momenta in the rest frame of the :math:`K^- K^{*0}`.)DOC");
421 REGISTER_METAVARIABLE("momentaTripleProduct(i,j,k)", momentaTripleProduct, R
"DOC(
422 a triple-product of three momenta of offspring in the mother rest frame: :math:`C_T=\vec{p}_i\cdot(\vec{p}_j\times\vec{p}_k)`. For examples,
423 In a four-body decay M->D1D2D3D4, momentaTripleProduct(0,1,2) returns CT using the momenta of D1D2D3 particles.
424 In other decays involving secondary decay, e.g. for M->(R->D1D2)D3D4, momentaTripleProduct(0:0,1,2) returns C_T using momenta of D1D3D4 particles.
425 )DOC", Manager::VariableDataType::c_double);
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.