File indexing completed on 2025-08-05 08:15:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include "flowAfterburner.h"
0015
0016 #include <phool/phool.h>
0017
0018 #include <gsl/gsl_errno.h>
0019 #include <gsl/gsl_math.h>
0020 #include <gsl/gsl_roots.h>
0021
0022 #include <HepMC/GenEvent.h>
0023 #include <HepMC/GenParticle.h> // for GenParticle
0024 #include <HepMC/GenRanges.h>
0025 #include <HepMC/GenVertex.h> // for GenVertex, GenVertex::part...
0026 #include <HepMC/HeavyIon.h> // for HeavyIon
0027 #include <HepMC/IteratorRange.h> // for children, descendants
0028 #include <HepMC/SimpleVector.h> // for FourVector
0029
0030 #include <CLHEP/Random/RandFlat.h>
0031 #include <CLHEP/Vector/LorentzVector.h>
0032
0033 #include <cmath>
0034 #include <cstdlib> // for exit
0035 #include <iostream>
0036 #include <map> // for map
0037
0038 namespace CLHEP
0039 {
0040 class HepRandomEngine;
0041 }
0042
0043 namespace
0044 {
0045 flowAfterburnerAlgorithm algorithm;
0046 std::map<std::string, flowAfterburnerAlgorithm> algorithms;
0047
0048 struct loaderObj
0049 {
0050 loaderObj()
0051 {
0052 static bool init = false;
0053 if (!init)
0054 {
0055 algorithms["MINBIAS"] = minbias_algorithm;
0056 algorithms["MINBIAS_V2_ONLY"] = minbias_v2_algorithm;
0057 algorithms["CUSTOM"] = custom_algorithm;
0058 }
0059 }
0060 };
0061
0062 loaderObj loader;
0063
0064 double
0065 vn_func(double x, void *params)
0066 {
0067 float *par_float = (float *) params;
0068 float phi_0 = par_float[0];
0069 float *vn = par_float + 1;
0070 float *psi_n = vn + 6;
0071 double val =
0072 x + (2 * (vn[0] * sin(1 * (x - psi_n[0])) / 1.0 +
0073 vn[1] * sin(2 * (x - psi_n[1])) / 2.0 +
0074 vn[2] * sin(3 * (x - psi_n[2])) / 3.0 +
0075 vn[3] * sin(4 * (x - psi_n[3])) / 4.0 +
0076 vn[4] * sin(5 * (x - psi_n[4])) / 5.0 +
0077 vn[5] * sin(6 * (x - psi_n[5])) / 6.0));
0078 return val - phi_0;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098 float psi_n[6], v1, v2, v3, v4, v5, v6;
0099
0100 void MoveDescendantsToParent(HepMC::GenParticle *parent,
0101 double phishift)
0102 {
0103
0104
0105 HepMC::GenVertex *endvtx = parent->end_vertex();
0106 if (endvtx)
0107 {
0108
0109 for (HepMC::GenVertex::vertex_iterator descvtxit = endvtx->vertices_begin(HepMC::descendants);
0110 descvtxit != endvtx->vertices_end(HepMC::descendants);
0111 ++descvtxit)
0112 {
0113 HepMC::GenVertex *descvtx = (*descvtxit);
0114
0115
0116 if (fabs(phishift) > 1e-7)
0117 {
0118 CLHEP::HepLorentzVector position(descvtx->position().x(),
0119 descvtx->position().y(),
0120 descvtx->position().z(),
0121 descvtx->position().t());
0122 position.rotateZ(phishift);
0123 descvtx->set_position(position);
0124 }
0125
0126
0127 for (HepMC::GenVertex::particle_iterator descpartit = descvtx->particles_begin(HepMC::children);
0128 descpartit != descvtx->particles_end(HepMC::children);
0129 ++descpartit)
0130 {
0131 HepMC::GenParticle *descpart = (*descpartit);
0132 CLHEP::HepLorentzVector momentum(descpart->momentum().px(),
0133 descpart->momentum().py(),
0134 descpart->momentum().pz(),
0135 descpart->momentum().e());
0136
0137 if (fabs(phishift) > 1e-7)
0138 {
0139 momentum.rotateZ(phishift);
0140 descpart->set_momentum(momentum);
0141 }
0142 }
0143 }
0144 }
0145
0146 return;
0147 }
0148
0149 float calc_v2(double b, double eta, double pt)
0150 {
0151 float a1;
0152 float a2;
0153 float a3;
0154 float a4;
0155 a1 = 0.4397 * exp(-(b - 4.526) * (b - 4.526) / 72.0) + 0.636;
0156 a2 = 1.916 / (b + 2) + 0.1;
0157 a3 = 4.79 * 0.0001 * (b - 0.621) * (b - 10.172) * (b - 23) + 1.2;
0158 a4 = 0.135 * exp(-0.5 * (b - 10.855) * (b - 10.855) / 4.607 / 4.607) + 0.0120;
0159
0160 float temp1 = pow(pt, a1) / (1 + exp((pt - 3.0) / a3));
0161 float temp2 = pow(pt + 0.1, -a2) / (1 + exp(-(pt - 4.5) / a3));
0162 float temp3 = 0.01 / (1 + exp(-(pt - 4.5) / a3));
0163
0164
0165
0166
0167
0168
0169
0170 v2 = (a4 * (temp1 + temp2) + temp3) * exp(-0.5 * eta * eta / 3.43 / 3.43);
0171
0172 return v2;
0173 }
0174
0175
0176 void jjia_minbias_new(double b, double eta, double pt)
0177 {
0178 v2 = calc_v2(b, eta, pt);
0179
0180 float fb = 0.97 + (1.06 * exp(-0.5 * b * b / 3.2 / 3.2));
0181 v3 = pow(fb * sqrt(v2), 3);
0182
0183 float gb = 1.096 + (1.36 * exp(-0.5 * b * b / 3.0 / 3.0));
0184 gb = gb * sqrt(v2);
0185 v4 = pow(gb, 4);
0186 v5 = pow(gb, 5);
0187 v6 = pow(gb, 6);
0188 v1 = 0;
0189 }
0190
0191
0192 void jjia_minbias_new_v2only(double b, double eta, double pt)
0193 {
0194 v2 = calc_v2(b, eta, pt);
0195
0196 v1 = 0;
0197 v3 = 0;
0198 v4 = 0;
0199 v5 = 0;
0200 v6 = 0;
0201 }
0202
0203
0204 void custom_vn(double , double , double )
0205 {
0206 v1 = 0.0000;
0207 v2 = 0.0500;
0208 v3 = 0.0280;
0209 v4 = 0.0130;
0210 v5 = 0.0045;
0211 v6 = 0.0015;
0212 }
0213
0214 double
0215 AddFlowToParent(HepMC::GenEvent *event, HepMC::GenParticle *parent)
0216 {
0217 CLHEP::HepLorentzVector momentum(parent->momentum().px(),
0218 parent->momentum().py(),
0219 parent->momentum().pz(),
0220 parent->momentum().e());
0221 double pt = momentum.perp();
0222 double eta = momentum.pseudoRapidity();
0223 double phi_0 = momentum.phi();
0224
0225 HepMC::HeavyIon *hi = event->heavy_ion();
0226 double b = hi->impact_parameter();
0227
0228 v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0, v6 = 0;
0229
0230
0231 if (algorithm == minbias_algorithm)
0232 {
0233 jjia_minbias_new(b, eta, pt);
0234 }
0235 else if (algorithm == minbias_v2_algorithm)
0236 {
0237 jjia_minbias_new_v2only(b, eta, pt);
0238 }
0239 else if (algorithm == custom_algorithm)
0240 {
0241 custom_vn(b, eta, pt);
0242 }
0243
0244 double phishift = 0;
0245
0246 const gsl_root_fsolver_type *T = gsl_root_fsolver_brent;
0247 gsl_root_fsolver *s = gsl_root_fsolver_alloc(T);
0248 double x_lo = -2 * M_PI;
0249 double x_hi = 2 * M_PI;
0250 float params[13];
0251 for (float ¶m : params)
0252 {
0253 param = 0;
0254 }
0255 gsl_function F;
0256 F.function = &vn_func;
0257 F.params = ¶ms;
0258 gsl_root_fsolver_set(s, &F, x_lo, x_hi);
0259 int iter = 0;
0260 params[0] = phi_0;
0261 params[1] = v1;
0262 params[2] = v2;
0263 params[3] = v3;
0264 params[4] = v4;
0265 params[5] = v5;
0266 params[6] = v6;
0267 params[7] = psi_n[0];
0268 params[8] = psi_n[1];
0269 params[9] = psi_n[2];
0270 params[10] = psi_n[3];
0271 params[11] = psi_n[4];
0272 params[12] = psi_n[5];
0273 int status;
0274 double phi;
0275 do
0276 {
0277 iter++;
0278 gsl_root_fsolver_iterate(s);
0279 phi = gsl_root_fsolver_root(s);
0280 x_lo = gsl_root_fsolver_x_lower(s);
0281 x_hi = gsl_root_fsolver_x_upper(s);
0282 status = gsl_root_test_interval(x_lo, x_hi, 0, 0.00001);
0283 } while (status == GSL_CONTINUE && iter < 1000);
0284 gsl_root_fsolver_free(s);
0285
0286 if (iter >= 1000)
0287 {
0288 return 0;
0289 }
0290
0291 phishift = phi - phi_0;
0292
0293 if (fabs(phishift) > 1e-7)
0294 {
0295 momentum.rotateZ(phishift);
0296 parent->set_momentum(momentum);
0297 }
0298
0299 return phishift;
0300 }
0301 }
0302
0303 int flowAfterburner(HepMC::GenEvent *event,
0304 CLHEP::HepRandomEngine *engine,
0305 const std::string &algorithmName,
0306 float mineta, float maxeta,
0307 float minpt, float maxpt)
0308 {
0309 algorithm = algorithms[algorithmName];
0310 HepMC::HeavyIon *hi = event->heavy_ion();
0311 if (!hi)
0312 {
0313 std::cout << PHWHERE << ": Flow Afterburner needs the Heavy Ion Event Info, GenEvent::heavy_ion() returns NULL" << std::endl;
0314 exit(1);
0315 }
0316
0317
0318 for (int i = 0; i < 6; i++)
0319 {
0320
0321 psi_n[i] = (CLHEP::RandFlat::shoot(engine) - 0.5) * 2 * M_PI / (i + 1);
0322 }
0323
0324
0325 psi_n[1] = hi->event_plane_angle();
0326
0327
0328 psi_n[1] = atan2(sin(2 * psi_n[1]), cos(2 * psi_n[1])) / 2.0;
0329
0330 HepMC::GenVertex *mainvtx = event->barcode_to_vertex(-1);
0331
0332
0333 HepMC::GenVertexParticleRange r(*mainvtx, HepMC::children);
0334
0335 for (HepMC::GenVertex::particle_iterator it = r.begin(); it != r.end(); it++)
0336 {
0337
0338 HepMC::GenParticle *parent = (*it);
0339
0340
0341
0342
0343
0344
0345 CLHEP::HepLorentzVector momentum(parent->momentum().px(),
0346 parent->momentum().py(),
0347 parent->momentum().pz(),
0348 parent->momentum().e());
0349
0350 float eta = momentum.pseudoRapidity();
0351 if (eta < mineta || eta > maxeta)
0352 {
0353 continue;
0354 }
0355
0356
0357 float pT = momentum.perp();
0358 if (pT < minpt || pT > maxpt)
0359 {
0360 continue;
0361 }
0362
0363
0364 double phishift = AddFlowToParent(event, parent);
0365 MoveDescendantsToParent(parent, phishift);
0366 }
0367
0368 return 0;
0369 }