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, 1
e-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(), 1
e-6);
224 BOOST_CHECK_CLOSE(particles[
i].Vy(), xiStar.Vy(), 1
e-6);
225 BOOST_CHECK_CLOSE(particles[
i].Vz(), xiStar.Vz(), 1
e-6);
229 double flightTime = std::sqrt(dx * dx + dy * dy + dz * dz) / (xic.P() / xic.Energy() * 29.9792458) * 1
e-9;
230 for (
int i = 1;
i < (int)particles.size(); ++
i) {
231 BOOST_CHECK_CLOSE(particles[
i].T(), xic.T() + flightTime, 1
e-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, 1
e-6);
436 BOOST_CHECK_CLOSE(
report.lifetimeMismatch[4232].second, 0.1300, 1
e-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., 1
e-9 / mmc);
454 xic.SetProductionVertex(0.1, 0.2, 0.3, 1
e-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(), 1
e-6);
465 BOOST_CHECK_CLOSE(inMm[
i].T(), inCm[
i].T() / mmc, 1
e-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()), 1
e-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);
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(), 1
e-6);
711 BOOST_CHECK_CLOSE(inMeV[
i].Energy(), 1e3 * inGeV[
i].Energy(), 1
e-6);
712 BOOST_CHECK_CLOSE(inMeV[
i].Vz(), inGeV[
i].Vz(), 1
e-6);
std::vector< double > sum
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events d
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())