File indexing completed on 2025-08-05 08:19:25
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "epemGun.h"
0019 #include <sstream>
0020
0021 #define MAGENTA "\033[35m"
0022
0023 using namespace std;
0024
0025
0026 RegisterJetScapeModule<epemGun> epemGun::reg("epemGun");
0027
0028 epemGun::~epemGun() { VERBOSE(8); }
0029
0030 void epemGun::InitTask() {
0031
0032 JSDEBUG << "Initialize epemGun";
0033 VERBOSE(8);
0034
0035
0036 readString("Init:showProcesses = off");
0037 readString("Init:showChangedSettings = off");
0038 readString("Init:showMultipartonInteractions = off");
0039 readString("Init:showChangedParticleData = off");
0040 if (JetScapeLogger::Instance()->GetInfo()) {
0041 readString("Init:showProcesses = on");
0042 readString("Init:showChangedSettings = on");
0043 readString("Init:showMultipartonInteractions = on");
0044 readString("Init:showChangedParticleData = on");
0045 }
0046
0047
0048 readString("Next:numberShowInfo = 0");
0049 readString("Next:numberShowProcess = 0");
0050 readString("Next:numberShowEvent = 0");
0051
0052
0053 readString("HadronLevel:all = off");
0054
0055
0056 readString("PartonLevel:FSR = off");
0057
0058 readString("PDF:lepton = off");
0059 readString("WeakSingleBoson:ffbar2gmz=on");
0060 readString("WeakDoubleBoson:all=on");
0061 readString("WeakBosonExchange:all=on");
0062
0063
0064 readString("23:onMode = off");
0065 readString("23:onIfAny = 1 2 3 4 5");
0066
0067
0068 stringstream numbf(stringstream::app | stringstream::in | stringstream::out);
0069 numbf.setf(ios::fixed, ios::floatfield);
0070 numbf.setf(ios::showpoint);
0071 numbf.precision(1);
0072 stringstream numbi(stringstream::app | stringstream::in | stringstream::out);
0073
0074 std::string s = GetXMLElementText({"Hard", "epemGun", "name"});
0075 SetId(s);
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 tinyxml2::XMLElement *RandomXmlDescription = GetXMLElement({"Random"});
0102 readString("Random:setSeed = on");
0103 numbi.str("Random:seed = ");
0104 unsigned int seed = 0;
0105 if (RandomXmlDescription) {
0106 tinyxml2::XMLElement *xmle =
0107 RandomXmlDescription->FirstChildElement("seed");
0108 if (!xmle)
0109 throw std::runtime_error("Cannot parse xml");
0110 xmle->QueryUnsignedText(&seed);
0111 } else {
0112 JSWARN << "No <Random> element found in xml, seeding to 0";
0113 }
0114 VERBOSE(7) << "Seeding pythia to " << seed;
0115 numbi << seed;
0116 readString(numbi.str());
0117
0118
0119 readString("Beams:idA = 11");
0120 readString("Beams:idB = -11");
0121
0122
0123 eCM = GetXMLElementDouble({"Hard", "epemGun", "eCM"});
0124 numbf.str("Beams:eCM = ");
0125 numbf << eCM;
0126 readString(numbf.str());
0127
0128 std::stringstream lines;
0129 lines << GetXMLElementText({"Hard", "epemGun", "LinesToRead"}, false);
0130 int i = 0;
0131 while (std::getline(lines, s, '\n')) {
0132 if (s.find_first_not_of(" \t\v\f\r") == s.npos)
0133 continue;
0134 VERBOSE(7) << "Also reading in: " << s;
0135 readString(s);
0136 }
0137
0138
0139 if (!init()) {
0140 throw std::runtime_error("Pythia init() failed.");
0141 }
0142
0143
0144 ZeroOneDistribution = uniform_real_distribution<double>{0.0, 1.0};
0145
0146 }
0147
0148 void epemGun::Exec() {
0149 VERBOSE(1) << "Run Hard Process : " << GetId() << " ...";
0150 VERBOSE(8) << "Current Event #" << GetCurrentEvent();
0151
0152 double vir_factor = GetXMLElementDouble({"Eloss", "Matter", "vir_factor"});
0153
0154 bool flag62 = false;
0155 vector<Pythia8::Particle> p62;
0156
0157
0158 struct greater_than_pt {
0159 inline bool operator()(const Pythia8::Particle &p1,
0160 const Pythia8::Particle &p2) {
0161 return (p1.pT() > p2.pT());
0162 }
0163 };
0164
0165 do {
0166 next();
0167
0168 p62.clear();
0169
0170 for (int parid = 0; parid < event.size(); parid++) {
0171 if (parid < 3)
0172 continue;
0173 Pythia8::Particle &particle = event[parid];
0174
0175
0176
0177
0178
0179 if( (std::abs(particle.id()) > 1100) && (std::abs(particle.id()) < 6000) && ((std::abs(particle.id())/10)%10 == 0) ){
0180
0181
0182 particle.id( -1*particle.id()/1000 );
0183 }
0184
0185
0186
0187
0188 if ( particle.status()<0 ) {continue;}
0189
0190
0191 if (fabs(particle.id()) > 6 && (particle.id() != 21 && particle.id() != 22)) {
0192 continue;
0193 }
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 p62.push_back(particle);
0207 }
0208
0209
0210 if (p62.size() < 2)
0211 continue;
0212
0213
0214
0215
0216 std::sort(p62.begin(), p62.end(), greater_than_pt());
0217
0218
0219
0220 flag62 = true;
0221
0222 } while (!flag62);
0223
0224 double p[4], xLoc[4];
0225
0226
0227 for (int i = 0; i <= 3; i++) {
0228 xLoc[i] = 0.0;
0229 };
0230
0231
0232
0233
0234 if(p62.size() == 2 && std::abs(p62[0].e() - 0.5*eCM) < 0.001 && std::abs(p62[1].e() - 0.5*eCM) < 0.001 && std::abs(p62[0].id()) < 6 && std::abs(p62[1].id()) < 6){
0235
0236
0237 double q1 = 0.;
0238 double q2 = 0.;
0239 const double QS = 0.9;
0240
0241
0242 for(int pass=0; pass<2; ++pass){
0243
0244 double mass = p62[pass].m0();
0245
0246
0247
0248
0249 double max_vir = (0.25*eCM*eCM - mass*mass) * std::abs(vir_factor);
0250 double min_vir = (0.5 * QS * QS ) * (1.0 + std::sqrt(1.0 + 4.0 * mass*mass / (QS*QS)));
0251
0252 double tQ2 = 0.;
0253
0254 if (max_vir <= QS * QS){
0255 tQ2 = 0.0;
0256 }else if(max_vir < min_vir){
0257 tQ2 = QS * QS;
0258 }else{
0259
0260 double numer = 1.0;
0261 double random = ZeroOneDistribution(*GetMt19937Generator());
0262 double ratio = 1.0;
0263 double diff = ratio;
0264 if(random > rounding_error){
0265 diff = (ratio - random) / random;
0266 }
0267
0268 if(max_vir >= (QS*QS / 2.) * (1.0 + std::sqrt(1.0 + 2.0 * mass * mass / (QS*QS / 2.)))){
0269 double g = (QS*QS / 2.) * (1.0 + std::sqrt(1.0 + 2.0 * mass * mass / (QS*QS / 2.)));
0270 numer = exp(-1.0 * (Cf / 2.0 / pi) * sud_val_QG_w_M(mass,(QS*QS / 2.), g, max_vir, 0.5*eCM));
0271 }
0272
0273 if (numer > random){tQ2 = min_vir;}
0274 else{
0275
0276 double t_hi = max_vir;
0277 double t_low = min_vir;
0278 double t_mid = t_low;
0279
0280 double denom = 1.0;
0281
0282 do{
0283 t_mid = 0.5*(t_low + t_hi);
0284
0285 if (t_mid < (QS*QS / 2.) * (1.0 + std::sqrt(1.0 + 2.0 * mass * mass / (QS*QS / 2.)))){
0286 denom = 1.0;
0287 }else{
0288 double g = (QS*QS / 2.) * (1.0 + std::sqrt(1.0 + 2.0 * mass * mass / (QS*QS / 2.)));
0289 denom = exp(-1.0 * (Cf / 2.0 / pi) * sud_val_QG_w_M(mass,(QS*QS / 2.), g, t_mid, 0.5*eCM));
0290 }
0291
0292 ratio = numer / denom;
0293
0294 diff = (ratio - random) / random;
0295
0296 if (diff < 0.0){t_low = t_mid;}
0297 else{t_hi = t_mid;}
0298
0299 }while((abs(diff) > s_approx) && (abs(t_hi - t_low) / t_hi > s_error));
0300
0301 tQ2 = t_mid;
0302
0303 }
0304 }
0305
0306 if(pass==0){q1=sqrt(tQ2);}
0307 else if(pass==1){q2=sqrt(tQ2);}
0308 }
0309
0310 double modm_sq1 = q1*q1 + p62[0].m0()*p62[0].m0();
0311 double modm_sq2 = q2*q2 + p62[1].m0()*p62[1].m0();
0312
0313 if(eCM > sqrt(modm_sq1)+sqrt(modm_sq2)){
0314
0315 double pnew = 0.5*sqrt((eCM*eCM-modm_sq1-modm_sq2)*(eCM*eCM-modm_sq1-modm_sq2)-4.*modm_sq1*modm_sq2)/eCM;
0316
0317 auto magnitude = [](const Pythia8::Particle &p) {
0318 return std::sqrt(p.px() * p.px() + p.py() * p.py() + p.pz() * p.pz());
0319 };
0320
0321 double scale1 = pnew/magnitude(p62[0]);
0322 double scale2 = pnew/magnitude(p62[1]);
0323 double e1new = sqrt(pnew*pnew + modm_sq1);
0324 double e2new = sqrt(pnew*pnew + modm_sq2);
0325 p62[0].e(e1new);
0326 p62[0].px(p62[0].px()*scale1);
0327 p62[0].py(p62[0].py()*scale1);
0328 p62[0].pz(p62[0].pz()*scale1);
0329 p62[1].e(e2new);
0330 p62[1].px(p62[1].px()*scale2);
0331 p62[1].py(p62[1].py()*scale2);
0332 p62[1].pz(p62[1].pz()*scale2);
0333 }
0334 }
0335
0336
0337 for (int np = 0; np < p62.size(); ++np) {
0338 Pythia8::Particle &particle = p62.at(np);
0339
0340 VERBOSE(7) << "Adding particle with pid = " << particle.id()
0341 << " at x=" << xLoc[1] << ", y=" << xLoc[2] << ", z=" << xLoc[3];
0342
0343 VERBOSE(7) << "Adding particle with pid = " << particle.id()
0344 << ", pT = " << particle.pT() << ", eta = " << particle.eta()
0345 << ", phi = " << particle.phi() << ", e = " << particle.e();
0346
0347 VERBOSE(7) << " at x=" << xLoc[1] << ", y=" << xLoc[2] << ", z=" << xLoc[3];
0348
0349 auto ptn = make_shared<Parton>(0, particle.id(), 0, particle.pT(), particle.eta(), particle.phi(), particle.e(), xLoc);
0350 ptn->set_color(particle.col());
0351 ptn->set_anti_color(particle.acol());
0352 ptn->set_max_color(1000 * (np + 1));
0353
0354 if(p62.size() == 2 && std::abs(particle.id()) < 6){
0355 double mean_form_time = (2.*ptn->e()) / (ptn->e()*ptn->e()
0356 - ptn->px()*ptn->px() - ptn->py()*ptn->py()
0357 - ptn->pz()*ptn->pz() - ptn->restmass()*ptn->restmass()
0358 + rounding_error) / fmToGeVinv;
0359 ptn->set_form_time(mean_form_time);
0360 ptn->set_mean_form_time();
0361
0362 double velocity[4];
0363 velocity[0] = 1.0;
0364 for (int j = 1; j <= 3; j++) {
0365 velocity[j] = ptn->p(j) / ptn->e();
0366 }
0367 ptn->set_jet_v(velocity);
0368 }
0369 AddParton(ptn);
0370 }
0371
0372
0373
0374 VERBOSE(8) << GetNHardPartons();
0375 }
0376
0377 double epemGun::sud_val_QG_w_M(double M, double h0, double h1, double h2, double E1) {
0378 double val, h, intg, hL, hR, diff, intg_L, intg_R, span;
0379
0380 val = 0.0;
0381
0382 h = (h1 + h2) / 2.0;
0383
0384 span = (h2 - h1) / h2;
0385
0386 val = alpha_s(h) * sud_z_QG_w_M(M, h0, h, E1);
0387
0388 intg = val * (h2 - h1);
0389
0390 hL = (h1 + h) / 2.0;
0391
0392 intg_L = alpha_s(hL) * sud_z_QG_w_M(M, h0, hL, E1) * (h - h1);
0393
0394 hR = (h + h2) / 2.0;
0395
0396 intg_R = alpha_s(hR) * sud_z_QG_w_M(M, h0, hR, E1) * (h2 - h);
0397
0398 diff = std::abs((intg_L + intg_R - intg) / intg);
0399
0400 if ((diff > approx) || (span > error)) {
0401 intg = sud_val_QG_w_M(M, h0, h1, h, E1) +
0402 sud_val_QG_w_M(M, h0, h, h2, E1);
0403 }
0404
0405 return intg;
0406 }
0407
0408 double epemGun::sud_z_QG_w_M(double M, double cg, double cg1, double E2){
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 if (cg1 < 2.0 * cg + M * M / (1.0 + M * M / cg1)) {
0429 JSINFO << MAGENTA << " returning with cg, cg1 = " << cg << " " << cg1
0430 << " " << E_minimum << " " << E2;
0431 return M * M;
0432 };
0433
0434 double t1 = 1.0 / cg1;
0435 double t2 = t1 * cg;
0436 double t4 = std::pow(1.0 - t2, 2.0);
0437 double t7 = std::log(t2);
0438 double t9 = M * M;
0439 double t10 = t1 * t9;
0440 double t13 = 1.0 / (t10 + 1.0) * t10;
0441 double t15 = std::pow(t2 + t13, 2.0);
0442 double t18 = std::log(1.0 - t2 - t13);
0443 double t21 = t1 * (-t4 / 2.0 - 1.0 + 2.0 * t2 - 2.0 * t7 + t15 / 2.0 + t13 +
0444 2.0 * t18);
0445
0446 if (t21 < 0.0) {
0447 cerr << "ERROR: t21 negative in sud_z_QG_w_M = " << t21 << endl;
0448 throw std::runtime_error("ERROR: medium contribution negative in sud_z_QG_w_M");
0449 }
0450
0451 return t21;
0452 }
0453
0454 double epemGun::alpha_s(double q2) {
0455 double a, L2, q24, c_nf;
0456
0457 L2 = std::pow(Lambda_QCD, 2);
0458
0459 q24 = q2 / 4.0;
0460
0461 c_nf = nf;
0462
0463 if (q24 > 4.0) {
0464 c_nf = 4;
0465 }
0466
0467 if (q24 > 64.0) {
0468 c_nf = 5;
0469 }
0470
0471 if (q24 > L2) {
0472 a = 12.0 * pi / (11.0 * Nc - 2.0 * c_nf) / std::log(q24 / L2);
0473 } else {
0474 JSWARN << " alpha too large ";
0475 a = 0.6;
0476 }
0477
0478 return a;
0479 }