|
| 1 | +#if !defined(__CLING__) || defined(__ROOTCLING__) |
| 2 | +#include "Pythia8/Pythia.h" |
| 3 | +#include "FairGenerator.h" |
| 4 | +#include "FairPrimaryGenerator.h" |
| 5 | +#include "Generators/GeneratorPythia8.h" |
| 6 | +#include "fairlogger/Logger.h" |
| 7 | +#include "TRandom3.h" |
| 8 | +#include "TParticlePDG.h" |
| 9 | +#include "TDatabasePDG.h" |
| 10 | +#include "TSystem.h" |
| 11 | +#include "TMath.h" |
| 12 | +#include <cmath> |
| 13 | +#include <vector> |
| 14 | +#include <fstream> |
| 15 | +#include <string> |
| 16 | +using namespace Pythia8; |
| 17 | +#endif |
| 18 | + |
| 19 | +/// First version of the simple coalescence generator based PYTHIA8 |
| 20 | +/// TODO: extend to other nuclei (only He3 is implemented now) |
| 21 | + |
| 22 | +class GeneratorPythia8Coalescence : public o2::eventgen::GeneratorPythia8 |
| 23 | +{ |
| 24 | +public: |
| 25 | + /// Constructor |
| 26 | + GeneratorPythia8Coalescence(int input_trigger_ratio = 1, double coal_momentum = 0.4) |
| 27 | + : o2::eventgen::GeneratorPythia8() |
| 28 | + { |
| 29 | + fmt::printf(">> Coalescence generator %d\n", input_trigger_ratio); |
| 30 | + mInverseTriggerRatio = input_trigger_ratio; |
| 31 | + mCoalMomentum = coal_momentum; |
| 32 | + } |
| 33 | + /// Destructor |
| 34 | + ~GeneratorPythia8Coalescence() = default; |
| 35 | + |
| 36 | + bool Init() override |
| 37 | + { |
| 38 | + addSubGenerator(0, "Minimum bias"); |
| 39 | + addSubGenerator(1, "Coalescence"); |
| 40 | + return o2::eventgen::GeneratorPythia8::Init(); |
| 41 | + } |
| 42 | + |
| 43 | +protected: |
| 44 | + bool generateEvent() override |
| 45 | + { |
| 46 | + fmt::printf(">> Generating event %d\n", mGeneratedEvents); |
| 47 | + // Simple straightforward check to alternate generators |
| 48 | + if (mGeneratedEvents % mInverseTriggerRatio == 0) |
| 49 | + { |
| 50 | + bool genOk = false; |
| 51 | + int localCounter{0}; |
| 52 | + while (!genOk) |
| 53 | + { |
| 54 | + if (GeneratorPythia8::generateEvent()) |
| 55 | + { |
| 56 | + genOk = selectEvent(mPythia.event); |
| 57 | + } |
| 58 | + localCounter++; |
| 59 | + } |
| 60 | + fmt::printf(">> Coalescence successful after %i generations\n", localCounter); |
| 61 | + std::cout << std::endl << std::endl; |
| 62 | + notifySubGenerator(1); |
| 63 | + } |
| 64 | + else |
| 65 | + { |
| 66 | + // Generate minimum-bias event |
| 67 | + bool genOk = false; |
| 68 | + while (!genOk) |
| 69 | + { |
| 70 | + genOk = GeneratorPythia8::generateEvent(); |
| 71 | + } |
| 72 | + notifySubGenerator(0); |
| 73 | + } |
| 74 | + |
| 75 | + mGeneratedEvents++; |
| 76 | + |
| 77 | + return true; |
| 78 | + } |
| 79 | + |
| 80 | + bool selectEvent(Pythia8::Event &event) |
| 81 | + { |
| 82 | + static int sign = -1; // start with antimatter |
| 83 | + std::vector<int> protons, neutrons, lambdas; |
| 84 | + for (auto iPart{0}; iPart < event.size(); ++iPart) |
| 85 | + { |
| 86 | + if (std::abs(event[iPart].y()) > 1.) // skip particles with y > 1 |
| 87 | + { |
| 88 | + continue; |
| 89 | + } |
| 90 | + if (event[iPart].id() == 2212 * sign) |
| 91 | + { |
| 92 | + protons.push_back(iPart); |
| 93 | + } |
| 94 | + else if (event[iPart].id() == 2112 * sign) |
| 95 | + { |
| 96 | + neutrons.push_back(iPart); |
| 97 | + } |
| 98 | + else if (event[iPart].id() == 3122 * sign) |
| 99 | + { |
| 100 | + lambdas.push_back(iPart); |
| 101 | + } |
| 102 | + } |
| 103 | + double coalescenceRadius{0.5 * 1.122462 * mCoalMomentum}; /// 1.122462 [2^(1/6)] from PRL 126, 101101 (2021), only for 3 body coalescence |
| 104 | + if (protons.size() < 2 || neutrons.size() < 1) // at least 2 protons and 1 neutron |
| 105 | + { |
| 106 | + return false; |
| 107 | + } |
| 108 | + for (uint32_t i{0}; i < protons.size(); ++i) |
| 109 | + { |
| 110 | + for (uint32_t j{i + 1}; j < protons.size(); ++j) |
| 111 | + { |
| 112 | + for (uint32_t k{0}; k < neutrons.size(); ++k) |
| 113 | + { |
| 114 | + auto p1 = event[protons[i]].p(); |
| 115 | + auto p2 = event[protons[j]].p(); |
| 116 | + auto p3 = event[neutrons[k]].p(); |
| 117 | + auto p = p1 + p2 + p3; |
| 118 | + p1.bstback(p); |
| 119 | + p2.bstback(p); |
| 120 | + p3.bstback(p); |
| 121 | + |
| 122 | + if (p1.pAbs() <= coalescenceRadius && p2.pAbs() <= coalescenceRadius && p3.pAbs() <= coalescenceRadius) |
| 123 | + { |
| 124 | + p.e(std::hypot(p.pAbs(), 2.80839160743)); |
| 125 | + /// In order to avoid the transport of the mother particles, but to still keep them in the stack, we set the status to negative and we mark the nucleus status as 94 (decay product) |
| 126 | + event.append(sign * 1000020030, 94, 0, 0, 0, 0, 0, 0, p.px(), p.py(), p.pz(), p.e(), 2.80839160743); |
| 127 | + event[protons[i]].statusNeg(); |
| 128 | + event[protons[i]].daughter1(event.size() - 1); |
| 129 | + event[protons[j]].statusNeg(); |
| 130 | + event[protons[j]].daughter1(event.size() - 1); |
| 131 | + event[neutrons[k]].statusNeg(); |
| 132 | + event[neutrons[k]].daughter1(event.size() - 1); |
| 133 | + |
| 134 | + fmt::printf(">> Adding a He3 with p = %f, %f, %f, E = %f\n", p.px(), p.py(), p.pz(), p.e()); |
| 135 | + std::cout << std::endl; |
| 136 | + std::cout << std::endl; |
| 137 | + |
| 138 | + sign *= -1; |
| 139 | + return true; |
| 140 | + } |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + return false; |
| 145 | + } |
| 146 | + |
| 147 | +private: |
| 148 | + // Control gap-triggering |
| 149 | + float mCoalMomentum = 0.4; |
| 150 | + uint64_t mGeneratedEvents = 0; /// number of events generated so far |
| 151 | + int mInverseTriggerRatio = 1; /// injection gap |
| 152 | +}; |
| 153 | + |
| 154 | +///___________________________________________________________ |
| 155 | +FairGenerator *generateCoalescence(int input_trigger_ratio, double coal_momentum = 0.4) |
| 156 | +{ |
| 157 | + auto myGen = new GeneratorPythia8Coalescence(input_trigger_ratio, coal_momentum); |
| 158 | + auto seed = (gRandom->TRandom::GetSeed() % 900000000); |
| 159 | + myGen->readString("Random:setSeed on"); |
| 160 | + myGen->readString("Random:seed " + std::to_string(seed)); |
| 161 | + return myGen; |
| 162 | +} |
0 commit comments