12#define BOOST_TEST_MODULE Test EventDecayer class
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15#include <boost/test/unit_test.hpp>
25#include <TMCProcess.h>
38const std::string FORCE =
"4232:mayDecay = on\n4232:onMode = off\n4232:oneChannel = 1 1.0 0 3324 211\n4232:tau0 = 0.1358\n";
41const std::string DEFAULTSKIP =
"115 225 335 10221 10331 20223 20333 102132 102134 9010221";
44std::string writeCfg(std::string
const& text)
46 char name[] =
"/tmp/test_EventDecayer_XXXXXX";
47 int fd = mkstemp(
name);
49 std::ofstream out(
name);
55TParticle makeParticle(
int pdg,
double p,
bool toBeDone,
double vx = 0,
double vy = 0,
double vz = 0)
59 double e = std::sqrt(p * p +
m *
m);
60 TParticle part(pdg, 1, -1, -1, -1, -1, 0., 0., p, e, vx, vy, vz, 0.);
62 part.SetUniqueID(kPPrimary);
66int hepmc(TParticle
const& p)
71bool toBeDone(TParticle
const& p)
77void setParams(std::string
const& g4table =
"", std::string
const& extraCfg =
"",
int seed = 0)
79 static const std::string forcePath = writeCfg(FORCE);
94 BOOST_REQUIRE(decayer.
init());
95 auto xic = makeParticle(4232, 5.,
true, 0.1, 0.2, 0.3);
98 xic.SetProductionVertex(0.1, 0.2, 0.3, 1e-9);
99 std::vector<TParticle> particles{xic};
104bool sameParticle(TParticle
const&
a, TParticle
const&
b)
106 return a.GetPdgCode() ==
b.GetPdgCode() &&
a.Px() ==
b.Px() &&
a.Py() ==
b.Py() &&
a.Pz() ==
b.Pz() &&
107 a.Energy() ==
b.Energy() &&
a.Vx() ==
b.Vx() &&
a.Vy() ==
b.Vy() &&
a.Vz() ==
b.Vz() &&
a.T() ==
b.T() &&
108 a.GetStatusCode() ==
b.GetStatusCode() &&
a.TestBits(0xffffffff) ==
b.TestBits(0xffffffff) &&
109 a.GetFirstMother() ==
b.GetFirstMother() &&
a.GetFirstDaughter() ==
b.GetFirstDaughter() &&
110 a.GetLastDaughter() ==
b.GetLastDaughter() &&
a.GetUniqueID() ==
b.GetUniqueID();
114void checkUnchanged(std::vector<TParticle>
const& particles, std::vector<TParticle>
const& before)
116 BOOST_REQUIRE_EQUAL(particles.size(), before.size());
117 for (
size_t i = 0;
i < before.size(); ++
i) {
123bool isXi(TParticle
const& p)
125 return std::abs(p.GetPdgCode()) == 3312 || std::abs(p.GetPdgCode()) == 3322;
129std::vector<TParticle>
const& manyXic()
131 static std::vector<TParticle> particles;
132 if (particles.empty()) {
135 BOOST_REQUIRE(decayer.
init());
136 for (
int i = 0;
i < 20000; ++
i) {
137 particles.push_back(makeParticle(4232, 3.,
true));
140 BOOST_REQUIRE(
report.decayed[4232] == 20000);
150 auto particles = decayOneXic(
report);
152 auto const& xic = particles[0];
160 for (
int i = 1;
i < (int)particles.size(); ++
i) {
161 if (particles[
i].GetPdgCode() == 3324) {
165 if (particles[
i].GetPdgCode() == 211 && particles[
i].GetFirstMother() == 0) {
169 BOOST_REQUIRE_EQUAL(nXiStar, 1);
170 BOOST_REQUIRE(iPi > 0);
173 for (
int m = 0;
m < (int)particles.size(); ++
m) {
174 auto const& mother = particles[
m];
176 for (
auto const& p : particles) {
177 nChildren += p.GetFirstMother() ==
m;
179 if (hepmc(mother) != 2) {
183 BOOST_CHECK_EQUAL(mother.GetLastDaughter() - mother.GetFirstDaughter() + 1, nChildren);
184 for (
int d = mother.GetFirstDaughter(); d <= mother.GetLastDaughter(); ++d) {
191 for (
int i = 1;
i < (int)particles.size(); ++
i) {
195 auto const& xiStar = particles[iXiStar];
200 std::vector<int> dPdg;
201 for (
int d = xiStar.GetFirstDaughter(); d >= 0 && d <= xiStar.GetLastDaughter(); ++d) {
202 dPdg.push_back(particles[d].GetPdgCode());
207 BOOST_REQUIRE_EQUAL(dPdg.size(), 2);
208 bool charged = (dPdg[0] == 3312 && dPdg[1] == 211) || (dPdg[0] == 211 && dPdg[1] == 3312);
209 bool neutral = (dPdg[0] == 3322 && dPdg[1] == 111) || (dPdg[0] == 111 && dPdg[1] == 3322);
212 int first = xic.GetFirstDaughter();
213 int last = xic.GetLastDaughter();
218 double dx = xiStar.Vx() - 0.1;
219 double dy = xiStar.Vy() - 0.2;
220 double dz = xiStar.Vz() - 0.3;
221 BOOST_CHECK(std::sqrt(dx * dx + dy * dy + dz * dz) > 0.);
222 for (
int i = 1;
i < (int)particles.size(); ++
i) {
223 BOOST_CHECK_CLOSE(particles[
i].Vx(), xiStar.Vx(), 1e-6);
224 BOOST_CHECK_CLOSE(particles[
i].Vy(), xiStar.Vy(), 1e-6);
225 BOOST_CHECK_CLOSE(particles[
i].Vz(), xiStar.Vz(), 1e-6);
229 double flightTime = std::sqrt(dx * dx + dy * dy + dz * dz) / (xic.P() / xic.Energy() * 29.9792458) * 1e-9;
230 for (
int i = 1;
i < (int)particles.size(); ++
i) {
231 BOOST_CHECK_CLOSE(particles[
i].T(), xic.T() + flightTime, 1e-6);
240 BOOST_REQUIRE(decayer.
init());
241 std::vector<TParticle> particles{makeParticle(-4232, 5.,
true)};
244 for (
auto const& p : particles) {
245 nAntiXiStar += p.GetPdgCode() == -3324;
253 auto const& particles = manyXic();
256 for (
int i = 0;
i < 20000; ++
i) {
257 auto const& mother = particles[
i];
258 auto const& daughter = particles[mother.GetFirstDaughter()];
259 double dx = daughter.Vx() - mother.Vx();
260 double dy = daughter.Vy() - mother.Vy();
261 double dz = daughter.Vz() - mother.Vz();
262 sum += std::sqrt(dx * dx + dy * dy + dz * dz) * mother.GetCalcMass() / mother.P();
265 BOOST_CHECK_CLOSE(
sum /
n, 0.01358, 2.);
270 auto const& particles = manyXic();
273 for (
auto const& p : particles) {
274 if (p.GetPdgCode() != 3324) {
278 for (
int d = p.GetFirstDaughter(); d >= 0 && d <= p.GetLastDaughter(); ++d) {
279 if (particles[d].GetPdgCode() == 3312) {
284 BOOST_REQUIRE_EQUAL(nXiStar, 20000);
285 BOOST_CHECK_SMALL(
double(nCharged) / nXiStar - 0.667, 0.02);
292 BOOST_REQUIRE(decayer.
init());
293 std::vector<TParticle> particles;
294 for (
int pdg : {3312, 3122, 310, 3334}) {
295 particles.push_back(makeParticle(pdg, 2.,
true));
297 auto before = particles;
299 checkUnchanged(particles, before);
307 BOOST_REQUIRE(decayer.
init());
308 std::vector<TParticle> particles;
309 for (
int pdg : {211, -321, 2212, 22}) {
310 particles.push_back(makeParticle(pdg, 1.,
true, 0.01, 0.02, 0.03));
312 auto before = particles;
313 decayer.
decay(particles);
314 checkUnchanged(particles, before);
321 BOOST_REQUIRE(decayer.
init());
322 std::vector<TParticle> particles{makeParticle(4232, 5.,
false)};
323 auto before = particles;
325 checkUnchanged(particles, before);
332 auto particles = decayOneXic(
report);
333 auto before = particles;
335 BOOST_REQUIRE(decayer.
init());
336 auto second = decayer.
decay(particles);
337 checkUnchanged(particles, before);
345 BOOST_REQUIRE(decayer.
init());
346 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
347 particles[0].SetWeight(2.5);
348 decayer.
decay(particles);
349 BOOST_REQUIRE(particles.size() > 1);
350 for (
size_t i = 1;
i < particles.size(); ++
i) {
359 BOOST_REQUIRE(decayer.
init());
360 std::vector<TParticle> particles{makeParticle(1000020040, 5.,
true), makeParticle(1010010030, 5.,
true)};
361 auto before = particles;
363 checkUnchanged(particles, before);
372 BOOST_REQUIRE(decayer.
init());
373 auto xic = makeParticle(4232, 5.,
true);
375 xic.SetMomentum(0., 0., 5., std::sqrt(25. + 1.0));
376 xic.SetCalcMass(1.0);
377 std::vector<TParticle> particles{xic};
378 auto before = particles;
380 checkUnchanged(particles, before);
387 for (
auto limit : {
"limitTau",
"limitRadius",
"limitCylinder"}) {
388 setParams(
"", writeCfg(std::string(
"ParticleDecays:") + limit +
" = on\n"));
394 setParams(
"", writeCfg(
"ParticleDecays:limitTau0 = on\nParticleDecays:tau0Max = 0.05\n"));
397 BOOST_REQUIRE(decayer.
init());
399 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
409 auto table = writeCfg(
"# test table\n111 pi0 0 0 0\n211 pi+ 7804.5 0 1\n3312 xi- 49.1 0 1\n3322 xi0 87.1 0 1\n");
412 BOOST_REQUIRE(decayer.
init());
413 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
418 auto unknown = makeParticle(211, 1.,
true);
419 unknown.SetPdgCode(9900001);
420 std::vector<TParticle> more{unknown};
428 auto table = writeCfg(
"4232 xi_c+ 0.1300 0 1\n");
431 BOOST_REQUIRE(decayer.
init());
432 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
434 BOOST_REQUIRE(
report.lifetimeMismatch.count(4232) == 1);
435 BOOST_CHECK_CLOSE(
report.lifetimeMismatch[4232].first, 0.1358, 1e-6);
436 BOOST_CHECK_CLOSE(
report.lifetimeMismatch[4232].second, 0.1300, 1e-6);
442 const double mmc = 3.3356410e-12;
443 std::vector<TParticle> inCm;
444 std::vector<TParticle> inMm;
445 for (
bool mm : {
false,
true}) {
446 setParams(
"",
"", 4711);
448 BOOST_REQUIRE(decayer.
init());
449 auto xic = makeParticle(4232, 5.,
true);
452 xic.SetProductionVertex(1., 2., 3., 1e-9 / mmc);
454 xic.SetProductionVertex(0.1, 0.2, 0.3, 1e-9);
456 auto& particles = mm ? inMm : inCm;
457 particles.push_back(xic);
458 decayer.
decay(particles);
461 BOOST_REQUIRE(inCm.size() > 1);
462 BOOST_REQUIRE_EQUAL(inCm.size(), inMm.size());
463 for (
size_t i = 1;
i < inCm.size(); ++
i) {
464 BOOST_CHECK_CLOSE(inMm[
i].Vz(), 10. * inCm[
i].Vz(), 1e-6);
465 BOOST_CHECK_CLOSE(inMm[
i].T(), inCm[
i].T() / mmc, 1e-6);
468 auto const& xic = inMm[0];
469 auto const& d = inMm[xic.GetFirstDaughter()];
470 double length = std::sqrt(std::pow(d.Vx() - 1., 2) + std::pow(d.Vy() - 2., 2) + std::pow(d.Vz() - 3., 2));
472 BOOST_CHECK_CLOSE(d.T() - xic.T(),
length / (xic.P() / xic.Energy()), 1e-4);
478 auto run = [](
int seed) {
479 setParams(
"",
"", seed);
481 BOOST_REQUIRE(decayer.
init());
482 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
483 decayer.
decay(particles);
484 BOOST_REQUIRE(particles.size() > 1);
485 return std::make_pair(decayer.
seed(), particles[1].Vz());
488 auto large = run(1000000123);
489 auto reduced = run(100000122);
493 gRandom->SetSeed(777);
494 auto fromGRandom = run(0);
496 BOOST_CHECK(fromGRandom.first >= 0 && fromGRandom.first <= 900000000);
497 auto explicitSeed = run(fromGRandom.first);
499 gRandom->SetSeed(777);
501 gRandom->SetSeed(778);
510 int a = std::abs(pdg);
511 bool diquark =
a > 1100 &&
a < 5600 &&
a / 1000 < 6 && (
a / 10) % 10 == 0 && (
a / 100) % 10 <=
a / 1000 && (
a / 100) % 10 > 0 && (
a % 10) % 2 == 1;
512 return (
a >= 1 &&
a <= 8) ||
a == 21 || (
a >= 81 &&
a <= 99) || diquark;
518 setParams(
"", writeCfg(
"4232:oneChannel = 1 1.0 91 3 2203\n"));
520 BOOST_REQUIRE(decayer.
init());
521 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
522 auto before = particles;
524 for (
auto const& p : particles) {
527 if (
report.failed[4232] == 1) {
528 checkUnchanged(particles, before);
540 setParams(
"", writeCfg(
"3324:oneChannel = 1 1.0 0 3312 2212\n"));
542 BOOST_REQUIRE(decayer.
init());
543 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
544 auto before = particles;
546 checkUnchanged(particles, before);
553 static const std::string forcePath = writeCfg(FORCE);
555 for (
int i = 0;
i < 8; ++
i) {
565 BOOST_REQUIRE(decayer.
init());
567 BOOST_CHECK(summary.find(
"pythia8/decays/base.cfg;" + forcePath) != std::string::npos);
568 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
572 auto other = writeCfg(
"4232:mayDecay = off\n");
576 BOOST_REQUIRE(decayer.
init());
578 BOOST_CHECK(summary.find(
"pythia8/decays/base.cfg;" +
other) != std::string::npos);
579 BOOST_CHECK(summary.find(forcePath) == std::string::npos);
580 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
594 BOOST_REQUIRE(decayer.
init());
595 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
596 auto before = particles;
598 checkUnchanged(particles, before);
603 setParams(
"", writeCfg(
"3312:mayDecay = on\n3322:mayDecay = on\n"));
606 BOOST_REQUIRE(decayer.
init());
607 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
611 for (
auto const& p : particles) {
624 BOOST_REQUIRE(decayer.
init());
625 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
626 decayer.
decay(particles);
627 for (
auto const& p : particles) {
643 BOOST_REQUIRE(decayer.
init());
644 std::vector<TParticle> particles{makeParticle(4232, 5.,
true), makeParticle(-4232, 5.,
true)};
645 auto before = particles;
647 checkUnchanged(particles, before);
655 BOOST_REQUIRE(decayer.
init());
656 std::vector<TParticle> particles{makeParticle(4232, 5.,
true)};
659 BOOST_REQUIRE_EQUAL(particles.size(), 3);
660 for (
size_t i = 1;
i < particles.size(); ++
i) {
669 BOOST_REQUIRE(decayer.
init());
670 std::vector<TParticle> particles{makeParticle(102134, 2.,
true), makeParticle(-102134, 2.,
true)};
679 BOOST_REQUIRE(decayer.
init());
680 std::vector<TParticle> particles{makeParticle(102134, 2.,
true)};
690 std::vector<TParticle> inGeV;
691 std::vector<TParticle> inMeV;
692 for (
bool mev : {
false,
true}) {
693 setParams(
"",
"", 4711);
695 BOOST_REQUIRE(decayer.
init());
696 auto xic = makeParticle(4232, 5.,
true);
698 decayer.
setUnits(1., 1., 1e-3, 1e-3);
699 xic.SetMomentum(1e3 * xic.Px(), 1e3 * xic.Py(), 1e3 * xic.Pz(), 1e3 * xic.Energy());
701 auto& particles = mev ? inMeV : inGeV;
702 particles.push_back(xic);
703 decayer.
decay(particles);
706 BOOST_REQUIRE(inGeV.size() > 1);
707 BOOST_REQUIRE_EQUAL(inGeV.size(), inMeV.size());
708 for (
size_t i = 1;
i < inGeV.size(); ++
i) {
710 BOOST_CHECK_CLOSE(inMeV[
i].Pz(), 1e3 * inGeV[
i].Pz(), 1e-6);
711 BOOST_CHECK_CLOSE(inMeV[
i].Energy(), 1e3 * inGeV[
i].Energy(), 1e-6);
712 BOOST_CHECK_CLOSE(inMeV[
i].Vz(), inGeV[
i].Vz(), 1e-6);
std::vector< double > sum
Utility functions for MC particles.
static Double_t Mass(int pdg, bool &success, TDatabasePDG *db=O2DatabasePDG::Instance())
static void setValue(std::string const &mainkey, std::string const &subkey, T x)
Decays unstable generator particles with Pythia8 before transport, keeping the full chain.
bool vertexLimitsActive() const
void setUnits(double positionUnit, double timeUnit, double momentumUnit=1., double energyUnit=1.)
Sets the caller's units in cm, s, GeV/c and GeV, as the unit setters of Generator (default cm,...
EventDecayerReport decay(std::vector< TParticle > &particles)
std::string configSummary() const
static void encodeParticleStatusAndTracking(TParticle &particle, bool wanttracking=true)
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLuint GLsizei GLsizei * length
GLboolean GLboolean GLboolean GLboolean a
void report(gsl::span< o2::InteractionTimeRecord > irs, int threshold, bool verbose)
int getGenStatusCode(MCGenStatusEncoding enc)
int getHepMCStatusCode(MCGenStatusEncoding enc)
std::string to_string(gsl::span< T, Size > span)
Counts of what one or more EventDecayer::decay calls did, per PDG code.
std::map< int, long > decayed
VectorOfTObjectPtrs other
BOOST_AUTO_TEST_CASE(xic_to_xistar_chain)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())