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/gearbox/Const.h>
21#include <Math/Boost.h>
22#include <Math/Vector4D.h>
23using namespace ROOT::Math;
33 double cosHelicityAngleMomentum(
const Particle* part)
37 B2Vector3D motherBoost = frame.getMomentum(part).BoostToCM();
38 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
39 const auto& daughters = part -> getDaughters() ;
41 if (daughters.size() == 2) {
44 bool isOneConversion =
false;
46 for (
auto& idaughter : daughters) {
48 if (idaughter -> getPDGCode() !=
Const::photon.getPDGCode()) {
49 isOneConversion =
false;
53 if (idaughter -> getNDaughters() == 2) {
54 if (std::abs(idaughter -> getDaughters()[0]-> getPDGCode()) ==
Const::electron.getPDGCode()
55 && std::abs(idaughter -> getDaughters()[1]-> getPDGCode()) ==
Const::electron.getPDGCode()) {
56 isOneConversion =
true;
62 if (isOneConversion) {
63 B2WARNING(
"cosHelicityAngleMomentum: Special treatment for pi0->gamma gamma, gamma -> e+ e-, is called. "
64 "This treatment is going to be deprecated and we recommend using ``cosHelicityAngleMomentumPi0Dalitz`` "
65 "If you find this message in another case, it must be a bug. Please report it to the software mailing list.");
69 for (
auto& idaughter : daughters) {
70 if (idaughter -> getNDaughters() == 2)
continue;
71 else pGamma = frame.getMomentum(idaughter);
74 pGamma = Boost(motherBoost) * pGamma;
76 return std::cos(motherMomentum.Angle(pGamma.Vect()));
79 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
80 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
82 pDaughter1 = Boost(motherBoost) * pDaughter1;
83 pDaughter2 = Boost(motherBoost) * pDaughter2;
85 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
87 return std::cos(motherMomentum.Angle(p12));
90 }
else if (daughters.size() == 3) {
92 PxPyPzEVector pDaughter1 = frame.getMomentum(daughters[0]);
93 PxPyPzEVector pDaughter2 = frame.getMomentum(daughters[1]);
94 PxPyPzEVector pDaughter3 = frame.getMomentum(daughters[2]);
96 pDaughter1 = Boost(motherBoost) * pDaughter1;
97 pDaughter2 = Boost(motherBoost) * pDaughter2;
98 pDaughter3 = Boost(motherBoost) * pDaughter3;
100 B2Vector3D p12 = (pDaughter2 - pDaughter1).Vect();
101 B2Vector3D p13 = (pDaughter3 - pDaughter1).Vect();
105 return std::cos(motherMomentum.Angle(n));
111 double cosHelicityAngleMomentumPi0Dalitz(
const Particle* part)
115 B2Vector3D motherBoost = frame.getMomentum(part).BoostToCM();
116 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
117 const auto& daughters = part -> getDaughters() ;
120 if (daughters.size() == 3) {
122 PxPyPzEVector pGamma;
124 for (
auto& idaughter : daughters) {
125 if (std::abs(idaughter -> getPDGCode()) ==
Const::photon.getPDGCode()) {
126 pGamma = frame.getMomentum(idaughter);
130 pGamma = Boost(motherBoost) * pGamma;
132 return std::cos(motherMomentum.Angle(pGamma.Vect()));
134 }
else if (daughters.size() == 2) {
136 PxPyPzEVector pGamma;
139 if (daughters[0] -> getPDGCode() !=
Const::photon.getPDGCode() or
143 if (daughters[0] -> getNDaughters() == 2 and daughters[1] -> getNDaughters() == 0) {
144 if (std::abs(daughters[0] -> getDaughters()[0]-> getPDGCode()) ==
Const::electron.getPDGCode()
145 && std::abs(daughters[0] -> getDaughters()[1]-> getPDGCode()) ==
Const::electron.getPDGCode()) {
146 pGamma = frame.getMomentum(daughters[1]);
150 }
else if (daughters[0] -> getNDaughters() == 0 and daughters[1] -> getNDaughters() == 2) {
151 if (std::abs(daughters[1] -> getDaughters()[0]-> getPDGCode()) ==
Const::electron.getPDGCode()
152 && std::abs(daughters[1] -> getDaughters()[1]-> getPDGCode()) ==
Const::electron.getPDGCode()) {
153 pGamma = frame.getMomentum(daughters[0]);
161 pGamma = Boost(motherBoost) * pGamma;
163 return std::cos(motherMomentum.Angle(pGamma.Vect()));
170 double cosHelicityAngleBeamMomentum(
const Particle* mother,
const std::vector<double>& index)
172 if (index.size() != 1) {
173 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfCMSIsTheMother");
176 int idau = std::lround(index[0]);
178 const Particle* part = mother->getDaughter(idau);
180 B2FATAL(
"Couldn't find the " << idau <<
"th daughter");
183 PxPyPzEVector beam4Vector(getBeamPx(
nullptr), getBeamPy(
nullptr), getBeamPz(
nullptr), getBeamE(
nullptr));
184 PxPyPzEVector part4Vector = part->get4Vector();
185 PxPyPzEVector mother4Vector = mother->get4Vector();
187 B2Vector3D motherBoost = mother4Vector.BoostToCM();
189 beam4Vector = Boost(motherBoost) * beam4Vector;
190 part4Vector = Boost(motherBoost) * part4Vector;
192 return - part4Vector.Vect().
Dot(beam4Vector.Vect()) / part4Vector.P() / beam4Vector.P();
196 double cosHelicityAngle(
const Particle* mother,
const std::vector<double>& indices)
198 if (indices.size() != 2) {
199 B2FATAL(
"Wrong number of arguments for cosHelicityAngleIfRefFrameIsTheDaughter: two are needed.");
202 int iDau = std::lround(indices[0]);
203 int iGrandDau = std::lround(indices[1]);
205 const Particle* daughter = mother->getDaughter(iDau);
207 B2FATAL(
"Couldn't find the " << iDau <<
"th daughter.");
209 const Particle* grandDaughter = daughter->getDaughter(iGrandDau);
211 B2FATAL(
"Couldn't find the " << iGrandDau <<
"th daughter of the " << iDau <<
"th daughter.");
213 PxPyPzEVector mother4Vector = mother->get4Vector();
214 PxPyPzEVector daughter4Vector = daughter->get4Vector();
215 PxPyPzEVector grandDaughter4Vector = grandDaughter->get4Vector();
217 B2Vector3D daughterBoost = daughter4Vector.BoostToCM();
220 grandDaughter4Vector = Boost(daughterBoost) * grandDaughter4Vector;
221 mother4Vector = Boost(daughterBoost) * mother4Vector;
223 return - grandDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / grandDaughter4Vector.P() / mother4Vector.P();
226 double cosAcoplanarityAngle(
const Particle* mother,
const std::vector<double>& granddaughters)
228 if (granddaughters.size() != 2) {
229 B2FATAL(
"Wrong number of arguments for cosAcoplanarityAngleIfRefFrameIsTheMother: two are needed.");
232 if (mother->getNDaughters() != 2)
233 B2FATAL(
"cosAcoplanarityAngleIfRefFrameIsTheMother: this variable works only for two-body decays.");
235 int iGrandDau1 = std::lround(granddaughters[0]);
236 int iGrandDau2 = std::lround(granddaughters[1]);
238 const Particle* daughter1 = mother->getDaughter(0);
239 const Particle* daughter2 = mother->getDaughter(1);
241 const Particle* grandDaughter1 = daughter1->getDaughter(iGrandDau1);
243 B2FATAL(
"Couldn't find the " << iGrandDau1 <<
"th daughter of the first daughter.");
245 const Particle* grandDaughter2 = daughter2->getDaughter(iGrandDau2);
247 B2FATAL(
"Couldn't find the " << iGrandDau2 <<
"th daughter of the second daughter.");
249 PxPyPzEVector mother4Vector = mother->get4Vector();
250 PxPyPzEVector daughter4Vector1 = daughter1->get4Vector();
251 PxPyPzEVector daughter4Vector2 = daughter2->get4Vector();
252 PxPyPzEVector grandDaughter4Vector1 = grandDaughter1->get4Vector();
253 PxPyPzEVector grandDaughter4Vector2 = grandDaughter2->get4Vector();
255 B2Vector3D motherBoost = mother4Vector.BoostToCM();
256 B2Vector3D daughter1Boost = daughter4Vector1.BoostToCM();
257 B2Vector3D daughter2Boost = daughter4Vector2.BoostToCM();
260 daughter4Vector1 = Boost(motherBoost) * daughter4Vector1;
261 daughter4Vector2 = Boost(motherBoost) * daughter4Vector2;
264 grandDaughter4Vector1 = Boost(daughter1Boost) * grandDaughter4Vector1;
265 grandDaughter4Vector2 = Boost(daughter2Boost) * grandDaughter4Vector2;
268 B2Vector3D normalVector1 = daughter4Vector1.Vect().
Cross(grandDaughter4Vector1.Vect());
269 B2Vector3D normalVector2 = daughter4Vector2.Vect().
Cross(grandDaughter4Vector2.Vect());
271 return std::cos(normalVector1.Angle(normalVector2));
274 double cosHelicityAnglePrimary(
const Particle* part)
276 return part->getCosHelicity();
279 double cosHelicityAngleDaughter(
const Particle* part,
const std::vector<double>& indices)
281 if ((indices.size() == 0) || (indices.size() > 2)) {
282 B2FATAL(
"Wrong number of arguments for cosHelicityAngleDaughter: one or two are needed.");
285 int iDaughter = std::lround(indices[0]);
286 int iGrandDaughter = 0;
287 if (indices.size() == 2) {
288 iGrandDaughter = std::lround(indices[1]);
291 return part->getCosHelicityDaughter(iDaughter, iGrandDaughter);
294 double acoplanarityAngle(
const Particle* part)
296 return part->getAcoplanarity();
300 double cosHelicityAngleForQuasiTwoBodyDecay(
const Particle* mother,
const std::vector<double>& indices)
302 if (indices.size() != 2) {
303 B2FATAL(
"Wrong number of arguments for cosHelicityAngleForQuasiTwoBodyDecay: two are needed.");
306 if (mother->getNDaughters() != 3)
309 int iDau = std::lround(indices[0]);
310 int jDau = std::lround(indices[1]);
312 const Particle* iDaughter = mother->getDaughter(iDau);
316 const Particle* jDaughter = mother->getDaughter(jDau);
320 PxPyPzEVector mother4Vector = mother->get4Vector();
321 PxPyPzEVector iDaughter4Vector = iDaughter->get4Vector();
322 PxPyPzEVector jDaughter4Vector = jDaughter->get4Vector();
324 PxPyPzEVector resonance4Vector = iDaughter4Vector + jDaughter4Vector;
325 B2Vector3D resonanceBoost = resonance4Vector.BoostToCM();
327 iDaughter4Vector = Boost(resonanceBoost) * iDaughter4Vector;
328 mother4Vector = Boost(resonanceBoost) * mother4Vector;
330 return - iDaughter4Vector.Vect().
Dot(mother4Vector.Vect()) / iDaughter4Vector.P() / mother4Vector.P();
335 if (arguments.size() != 3) {
336 B2FATAL(
"Wrong number of arguments for momentaTripleProduct: three (particles) are needed.");
340 auto func = [arguments](
const Particle * mother) ->
double {
341 auto iDau = arguments[0];
342 auto jDau = arguments[1];
343 auto kDau = arguments[2];
345 const Particle* iDaughter = mother->getParticleFromGeneralizedIndexString(iDau);
346 if (!iDaughter) B2FATAL(
"Couldn't find the " << iDau <<
"th daughter.");
347 const Particle* jDaughter = mother->getParticleFromGeneralizedIndexString(jDau);
348 if (!jDaughter) B2FATAL(
"Couldn't find the " << jDau <<
"th daughter.");
349 const Particle* kDaughter = mother->getParticleFromGeneralizedIndexString(kDau);
350 if (!kDaughter) B2FATAL(
"Couldn't find the " << kDau <<
"th daughter.");
352 PxPyPzEVector mother4Vector = mother->get4Vector();
353 PxPyPzEVector iDaughter4Vector = iDaughter->get4Vector();
354 PxPyPzEVector jDaughter4Vector = jDaughter->get4Vector();
355 PxPyPzEVector kDaughter4Vector = kDaughter->get4Vector();
357 B2Vector3D motherBoost = mother4Vector.BoostToCM();
360 iDaughter4Vector = Boost(motherBoost) * iDaughter4Vector;
361 jDaughter4Vector = Boost(motherBoost) * jDaughter4Vector;
362 kDaughter4Vector = Boost(motherBoost) * kDaughter4Vector;
365 B2Vector3D jkDaughterCrossProduct = jDaughter4Vector.Vect().
Cross(kDaughter4Vector.Vect());
367 return iDaughter4Vector.Vect().
Dot(jkDaughterCrossProduct) ;
373 VARIABLE_GROUP(
"Helicity variables");
375 REGISTER_VARIABLE(
"cosHelicityAngleMomentum", cosHelicityAngleMomentum, R
"DOC(
376 If the given particle has two daughters: cosine of the angle between the line defined by the momentum difference of the two daughters
377 in the frame of the given particle (mother)
378 and the momentum of the given particle in the lab frame.
380 If the given particle has three daughters: cosine of the angle between the normal vector of the plane defined by
381 the momenta of the three daughters in the frame of the given particle (mother)
382 and the momentum of the given particle in the lab frame.
384 Otherwise, it returns 0.)DOC");
386 REGISTER_VARIABLE("cosHelicityAngleMomentumPi0Dalitz", cosHelicityAngleMomentumPi0Dalitz, R
"DOC(
387 To be used for the decay :math:`\pi^0 \to e^+ e^- \gamma`:
388 cosine of the angle between the momentum of the gamma in the frame of the given particle (mother)
389 and the momentum of the given particle in the lab frame.
391 One can call the variable for the decay :math:`\pi^0 \to \gamma \gamma, \gamma \to e^+ e^-` as well.
393 Otherwise, it returns 0.)DOC");
395 REGISTER_VARIABLE("cosHelicityAngleBeamMomentum(i)", cosHelicityAngleBeamMomentum, R
"DOC(
396 Cosine of the helicity angle of the :math:`i`-th daughter of the particle provided,
397 assuming that the mother of the provided particle corresponds to the centre-of-mass system, whose parameters are
398 automatically loaded by the function, given the accelerator's conditions.)DOC");
400 REGISTER_VARIABLE("cosHelicityAngle(i, j)", cosHelicityAngle, R
"DOC(
401 Cosine of the helicity angle between the momentum of the selected granddaughter and the direction opposite to the momentum of the provided particle
402 in the reference frame of the selected daughter (:math:`\theta_1` and :math:`\theta_2` in the
403 `PDG <https://journals.aps.org/prd/abstract/10.1103/PhysRevD.98.030001>`_ 2018, p. 722).
405 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.
407 For example, in the decay :math:`B^0 \to \left(J/\psi \to \mu^+ \mu^-\right) \left(K^{*0} \to K^+ \pi^-\right)`,
408 if the provided particle is :math:`B^0` and the selected indices are (0, 0),
409 the variable will return the angle between the momentum of the :math:`\mu^+` and the direction opposite to the momentum of
410 the :math:`B^0`, both momenta in the rest frame of the :math:`J/\psi`.
412 This variable is needed for angular analyses of :math:`B`-meson decays into two vector particles.)DOC");
414 REGISTER_VARIABLE("cosAcoplanarityAngle(i, j)", cosAcoplanarityAngle, R
"DOC(
415 Cosine of the acoplanarity angle (:math:`\Phi` in the `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_).
416 Given a two-body decay, the acoplanarity angle is defined as
417 the angle between the two decay planes in the reference frame of the mother.
419 We calculate the acoplanarity angle as the angle between the two
420 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
421 momentum of one of the granddaughters (in the reference frame of the daughter).
423 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
424 second granddaughter.
426 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),
427 the variable will return the acoplanarity using the :math:`\mu^+` and the :math:`K^+` granddaughters.)DOC");
429 REGISTER_VARIABLE("cosHelicityAnglePrimary", cosHelicityAnglePrimary, R
"DOC(
430 Cosine of the helicity angle (see``Particle::getCosHelicity``) assuming the center of mass system as mother rest frame.
431 See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
433 REGISTER_VARIABLE("cosHelicityAngleDaughter(i [, j] )", cosHelicityAngleDaughter, R
"DOC(
434 Cosine of the helicity angle of the i-th daughter (see ``Particle::getCosHelicityDaughter``).
435 The optional second argument is the index of the granddaughter that defines the angle, default is 0.
437 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,
438 the variable will return the helicity angle of the :math:`\mu^+`.
439 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}`).
440 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^-`).
442 See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the helicity angle.)DOC");
444 REGISTER_VARIABLE("acoplanarityAngle", acoplanarityAngle, R
"DOC(
445Acoplanarity angle (see ``Particle::getAcoplanarity``) assuming a two body decay of the particle and its daughters.
446See `PDG Polarization Review <http://pdg.lbl.gov/2019/reviews/rpp2018-rev-b-decays-polarization.pdf>`_ for the definition of the acoplanarity angle.
450 REGISTER_VARIABLE(
"cosHelicityAngleForQuasiTwoBodyDecay(i, j)", cosHelicityAngleForQuasiTwoBodyDecay, R
"DOC(
451 Cosine of the helicity angle between the momentum of the provided particle and the momentum of the first selected
452 daughter (i-th) in the reference frame of the sum of two selected daughters (i-th + j-th).
454 The variable is supposed to be used for the analysis of a quasi-two-body decay. The number of daughters of the given
455 particle must be three. Otherwise, the variable returns NaN.
457 For example, in the decay :math:`\bar{B}^0 \to D^+ K^- K^{*0}`, if the provided particle is :math:`\bar{B}^0` and
458 the selected indices are (1, 2), the variable will return the angle between the momentum of the :math:`\bar{B}^0`
459 and the momentum of the :math:`K^-`, both momenta in the rest frame of the :math:`K^- K^{*0}`.)DOC");
461 REGISTER_METAVARIABLE("momentaTripleProduct(i,j,k)", momentaTripleProduct, R
"DOC(
462a 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,
463In a four-body decay M->D1D2D3D4, momentaTripleProduct(0,1,2) returns CT using the momenta of D1D2D3 particles.
464In 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.
465)DOC", Manager::VariableDataType::c_double);
B2Vector3< DataType > Cross(const B2Vector3< DataType > &p) const
Cross product.
DataType Dot(const B2Vector3< DataType > &p) const
Scalar product.
int getPDGCode() const
PDG code.
static const ParticleType pi0
neutral pion particle
static const double doubleNaN
quiet_NaN
static const ParticleType photon
photon particle
static const ChargedStable electron
electron particle
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
B2Vector3< double > B2Vector3D
typedef for common usage with double
Abstract base class for different kinds of events.