Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:16:38

0001 // Allows the user to generate hijing events and store the results in
0002 // a HepMC file.
0003 //
0004 // Inspired by code from ATLAS.  Thanks!
0005 //
0006 #include "HiMain1.h"
0007 #include "HiMain2.h"
0008 #include "HiParnt.h"
0009 #include "HiStrng.h"
0010 #include "HijCrdn.h"
0011 #include "HijJet1.h"
0012 #include "HijJet2.h"
0013 #include "HijJet4.h"
0014 #include "RanSeed.h"
0015 
0016 #include <HepMC/GenEvent.h>
0017 #include <HepMC/GenParticle.h>
0018 #include <HepMC/GenVertex.h>
0019 #include <HepMC/IO_AsciiParticles.h>
0020 #include <HepMC/IO_GenEvent.h>
0021 
0022 #include <CLHEP/Geometry/Point3D.h>
0023 #include <CLHEP/Random/MTwistEngine.h>
0024 #include <CLHEP/Random/RandFlat.h>
0025 #include <CLHEP/Random/RandomEngine.h>
0026 #include <CLHEP/Vector/LorentzVector.h>
0027 
0028 #include <boost/algorithm/string.hpp>
0029 #include <boost/foreach.hpp>
0030 #include <boost/lexical_cast.hpp>
0031 #include <boost/property_tree/ptree.hpp>
0032 #include <boost/property_tree/xml_parser.hpp>
0033 
0034 #include <cmath>
0035 #include <cstdlib>
0036 #include <iostream>
0037 #include <memory>
0038 #include <numeric>
0039 #include <random>
0040 #include <string>
0041 #include <vector>
0042 
0043 #define f2cFortran
0044 #define gFortran
0045 // cppcheck-suppress *
0046 #include <cfortran.h>
0047 
0048 // This prevents cppcheck to flag the next line as error
0049 // cppcheck-suppress *
0050 PROTOCCALLSFSUB3(HIJING, hijing, STRING, FLOAT, FLOAT)
0051 #define HIJING(FRAME, BMIN0, BMAX0) \
0052   CCALLSFSUB3(HIJING, hijing, STRING, FLOAT, FLOAT, FRAME, BMIN0, BMAX0)
0053 
0054 PROTOCCALLSFSUB8(HIJSET, hijset, FLOAT, STRING, STRING, STRING, INT, INT, INT, INT)
0055 #define HIJSET(EFRM, FRAME, PROJ, TARG, IAP, IZP, IAT, IZT)                      \
0056   CCALLSFSUB8(HIJSET, hijset, FLOAT, STRING, STRING, STRING, INT, INT, INT, INT, \
0057               EFRM, FRAME, PROJ, TARG, IAP, IZP, IAT, IZT)
0058 
0059 void hijfst_control(int, const std::vector<std::string>&, const std::vector<float>&,const std::vector<int>&, const std::vector<float>&, const std::vector<float>&, const std::vector<float>&);
0060 
0061 CLHEP::HepRandomEngine *engine;
0062 
0063 float atl_ran(int *)
0064 {
0065   return (float) CLHEP::RandFlat::shoot(engine);
0066 }
0067 // This prevents cppcheck to flag the next line as error
0068 // cppcheck-suppress *
0069 FCALLSCFUN1(FLOAT, atl_ran, ATL_RAN, atl_ran, PINT)
0070 
0071 typedef HepGeom::Point3D<double> HepPoint3D;
0072 typedef HepMC::GenEvent::particle_iterator piter;
0073 
0074 int fillEvent(HepMC::GenEvent *evt);
0075 
0076 // Accessor to HIJING Options and parameters COMMON
0077 HiParnt m_hiparnt;
0078 
0079 // Accessor to HIJING Random number seed COMMON
0080 RanSeed m_ranseed;
0081 
0082 // Accessors to HIJING Event information COMMONS
0083 HiMain1 m_himain1;
0084 HiMain2 m_himain2;
0085 HijJet1 m_hijjet1;
0086 HijJet2 m_hijjet2;
0087 HijJet4 m_hijjet4;
0088 HiStrng m_histrng;
0089 HijCrdn m_hijcrdn;
0090 
0091 float efrm;
0092 std::string m_frame;
0093 std::string m_proj;
0094 std::string m_targ;
0095 int iap;
0096 int iat;
0097 int izp;
0098 int izt;
0099 int spec;
0100 double m_vertexOffsetCut = 1.0E-7;
0101 bool keepSpectators;
0102 
0103 int main(int argc, char **argv)
0104 {
0105   std::string config_filename = "sHijing.xml";
0106   std::string output;
0107   long randomSeed = 0;
0108   bool randomseed_set = false;
0109   unsigned int N = 1;
0110   bool NEvents_set = false;
0111   for (int i = 1; i < argc; ++i)
0112   {
0113     std::string optionstring = argv[i];
0114     if (optionstring == "-h")
0115     {
0116       std::cout << std::endl
0117            << "Usage: sHijing <config xmlfile [sHijing.xml]>" << std::endl;
0118       std::cout << std::endl;
0119       std::cout << "Parameters:" << std::endl;
0120       std::cout << "-n <number of events [1]>" << std::endl;
0121       std::cout << "-o <outputfile [sHijing.dat]>" << std::endl;
0122       std::cout << "-s <random seet [std::random_device]>" << std::endl;
0123       exit(0);
0124     }
0125     else if (optionstring == "-o")
0126     {
0127       if (i + 1 < argc)
0128       {                      // Make sure we aren't at the end of argv!
0129         output = argv[++i];  // Increment 'i' so we get the argument
0130       }
0131       else
0132       {  // Uh-oh, there was no argument to the destination option.
0133         std::cout << "-o option requires one argument." << std::endl;
0134         exit(1);
0135       }
0136       continue;
0137     }
0138     else if (optionstring == "-s")
0139     {
0140       if (i + 1 < argc)
0141       {                                     // Make sure we aren't at the end of argv!
0142         randomSeed = std::stol(argv[++i]);  // Increment 'i' so get the argument.
0143         randomseed_set = true;
0144       }
0145       else
0146       {  // Uh-oh, there was no argument to the destination option.
0147         std::cout << "-s option requires one argument." << std::endl;
0148         exit(1);
0149       }
0150       continue;
0151     }
0152     else if (optionstring == "-n")
0153     {
0154       if (i + 1 < argc)
0155       {                             // Make sure we aren't at the end of argv!
0156         N = std::stoul(argv[++i]);  // Increment 'i' so get the argument.
0157         NEvents_set = true;
0158       }
0159       else
0160       {  // Uh-oh, there was no argument to the destination option.
0161         std::cout << "-s option requires one argument." << std::endl;
0162         exit(1);
0163       }
0164       continue;
0165     }
0166     else
0167     {
0168       config_filename = argv[i];
0169     }
0170   }
0171   char frame[] = "        ";
0172   char proj[] = "        ";
0173   char targ[] = "        ";
0174 
0175   using boost::property_tree::ptree;
0176   boost::property_tree::iptree pt, null;
0177   std::ifstream config_file(config_filename);
0178 
0179   if (config_file)
0180   {
0181     // Read XML configuration file.
0182     read_xml(config_file, pt);
0183     std::cout << "using config file: " << config_filename << std::endl;
0184   }
0185   else
0186   {
0187     std::cout << "no xml config file - using internal values" << std::endl;
0188   }
0189   efrm = pt.get("HIJING.EFRM", 200.0);
0190   m_frame = pt.get("HIJING.FRAME", "CMS");
0191   m_proj = pt.get("HIJING.PROJ", "A");
0192   m_targ = pt.get("HIJING.TARG", "A");
0193   iap = pt.get("HIJING.IAP", 197);
0194   izp = pt.get("HIJING.IZP", 79);
0195   iat = pt.get("HIJING.IAT", 197);
0196   izt = pt.get("HIJING.IZT", 79);
0197   float bmin = pt.get("HIJING.BMIN", 0.0);
0198   float bmax = pt.get("HIJING.BMAX", 0.0);
0199   if (!NEvents_set)
0200   {
0201     N = pt.get("HIJING.N", 1);
0202   }
0203   keepSpectators = pt.get("HIJING.KEEP_SPECTATORS", 1);
0204   if (output.empty())
0205   {
0206     output = pt.get("HIJING.OUTPUT", "sHijing.dat");
0207   }
0208   if (!randomseed_set)
0209   {
0210     std::random_device rdev;
0211     randomSeed = pt.get("HIJING.RANDOM.SEED", rdev());
0212   }
0213   engine = new CLHEP::MTwistEngine(randomSeed);
0214 
0215   // See if there are any sections for HIPR1, IHPR2
0216   boost::property_tree::iptree &pr1 = pt.get_child("HIJING.HIPR1", null);
0217   BOOST_FOREACH (boost::property_tree::iptree::value_type &v, pr1)
0218   {
0219     int key = boost::lexical_cast<int>(v.first.data());
0220     float value = boost::lexical_cast<float>(v.second.data());
0221     m_hiparnt.hipr1(key) = value;
0222   }
0223   boost::property_tree::iptree &pr2 = pt.get_child("HIJING.IHPR2", null);
0224   BOOST_FOREACH (boost::property_tree::iptree::value_type &v, pr2)
0225   {
0226     int key = boost::lexical_cast<int>(v.first.data());
0227     int value = boost::lexical_cast<int>(v.second.data());
0228     m_hiparnt.ihpr2(key) = value;
0229   }
0230 
0231   int fastjet_enable_p = 0;
0232   std::vector<std::string> algorithm_v;
0233   std::vector<float> R_v;
0234   std::vector<int> PID_v;
0235   std::vector<float> EtaMin_v;
0236   std::vector<float> EtaMax_v;
0237   std::vector<float> EtMin_v;
0238 
0239   boost::property_tree::iptree &it = pt.get_child("HIJING.FASTJET", null);
0240   BOOST_FOREACH (boost::property_tree::iptree::value_type &v, it)
0241   {
0242     if (boost::to_upper_copy(v.first) != "ALGORITHM") continue;
0243     algorithm_v.push_back(boost::to_upper_copy(v.second.get("NAME", "ANTIKT")));
0244     R_v.push_back(v.second.get("R", 0.2));
0245     PID_v.push_back(v.second.get("PID", 2000000));
0246 
0247     EtaMin_v.push_back(v.second.get("EtaMin", -2));
0248     EtaMax_v.push_back(v.second.get("EtaMax", 2));
0249     EtMin_v.push_back(v.second.get("EtMin", 5));
0250 
0251     fastjet_enable_p = 1;
0252   }
0253   std::cout << "seed: " << randomSeed << std::endl;
0254   std::cout << "output: " << output << std::endl;
0255   std::cout << "Number of Events: " << N << std::endl;
0256 
0257   hijfst_control(fastjet_enable_p, algorithm_v, R_v, PID_v, EtaMin_v, EtaMax_v, EtMin_v);
0258 
0259   // The call to Hijing needs simple C-style strings.
0260   m_frame.copy(frame, m_frame.size());
0261   m_proj.copy(proj, m_proj.size());
0262   m_targ.copy(targ, m_targ.size());
0263 
0264   HIJSET(efrm, frame, proj, targ, iap, izp, iat, izt);
0265 
0266   //  int status;
0267   HepMC::IO_GenEvent ascii_io(output.c_str(), std::ios::out);
0268   unsigned int events = 0;
0269   do
0270   {
0271     HIJING(frame, bmin, bmax);
0272 
0273     if (m_himain1.ierrstat() != 0)
0274     {
0275       continue;
0276     }
0277     events++;
0278 
0279     HepMC::GenEvent *evt = new HepMC::GenEvent();
0280     evt->use_units(HepMC::Units::GEV, HepMC::Units::MM);
0281     evt->set_event_number(events);
0282 
0283     fillEvent(evt);
0284 
0285     ascii_io << evt;
0286 
0287     delete evt;
0288   } while (events < N);
0289 
0290   return 0;
0291 }
0292 
0293 int fillEvent(HepMC::GenEvent *evt)
0294 {
0295   int np = m_himain1.np();
0296   int nt = m_himain1.nt();
0297   int n0 = m_himain1.n0();
0298   int n01 = m_himain1.n01();
0299   int n10 = m_himain1.n10();
0300   int n11 = m_himain1.n11();
0301 
0302   // The Hijing documentation is a little unclear about this, but the
0303   // four values, n0, n01, n10 and n11, count collisions between
0304   // nucleons that have already (or have not already had) collisions
0305   // with other nucleons.  N_coll, the way we use it, is the sum of
0306   // all these values.
0307   int ncoll = n0 + n01 + n10 + n11;
0308 
0309   int natt = m_himain1.natt();
0310   float b = m_hiparnt.hint1(19);
0311   float bphi = m_hiparnt.hint1(20);
0312 
0313   // Determine the participant eccentricity.
0314   std::vector<float> x;
0315   std::vector<float> y;
0316   float tx, ty;
0317   float bbx = b * cos(bphi);
0318   float bby = b * sin(bphi);
0319   // std::cout << "x,y,c" << std::endl;
0320   for (int i = 0; i < m_hiparnt.ihnt2(1); i++)
0321   {
0322     if (m_histrng.nfp(i, 5) > 2)
0323     {
0324       tx = m_hijcrdn.yp(1, i) + bbx;
0325       ty = m_hijcrdn.yp(2, i) + bby;
0326       x.push_back(tx);
0327       y.push_back(ty);
0328 
0329       // std::cout << tx << "," << ty << "," << "0" << std::endl;
0330     }
0331   }
0332   for (int i = 0; i < m_hiparnt.ihnt2(3); i++)
0333   {
0334     if (m_histrng.nft(i, 5) > 2)
0335     {
0336       tx = m_hijcrdn.yt(1, i);
0337       ty = m_hijcrdn.yt(2, i);
0338       x.push_back(tx);
0339       y.push_back(ty);
0340 
0341       // std::cout << tx << "," << ty << "," << "1" << std::endl;
0342     }
0343   }
0344 
0345   float e_part = 0.0;
0346   if (x.size() != 0)
0347   {
0348     float N = x.size();
0349     float xa = std::accumulate(x.begin(), x.end(), 0) / N;
0350     float ya = std::accumulate(y.begin(), y.end(), 0) / N;
0351 
0352     float sxx = 0;
0353     float syy = 0;
0354     float sxy = 0;
0355     for (int i = 0; i < N; i++)
0356     {
0357       sxx += (x[i] - xa) * (x[i] - xa);
0358       syy += (y[i] - ya) * (y[i] - ya);
0359       sxy += (x[i] - xa) * (y[i] - ya);
0360     }
0361     sxx /= N;
0362     syy /= N;
0363     sxy /= N;
0364     e_part = std::sqrt((sxx - syy) * (sxx - syy) + 4 * sxy * sxy) / (sxx + syy);
0365   }
0366 
0367   // Need to calculate a few things missing from this list
0368   HepMC::HeavyIon hi(1, np, nt, ncoll, 0, 0, n01, n10, n11, b, bphi, e_part, 42.0);
0369 
0370   evt->set_heavy_ion(hi);
0371 
0372   // Set the random generator seeds.  How do people handle the fact
0373   // that CLHEP produced unsigned longs and HepMC wants signed ones?
0374   // evt->set_random_states(engine->put());
0375 
0376   //  Did we keep decay history?
0377   bool keptHistory = (m_hiparnt.ihpr2(21) == 1);
0378 
0379   //  The number of particles in the hijing output
0380   int numHijingPart = m_himain1.natt();
0381 
0382   // Vectors that will keep track of where particles originate from and die
0383   std::vector<int> partOriginVertex_vec;
0384   std::vector<int> partDecayVertex_vec;
0385   std::vector<HepMC::GenParticle *> particleHepPartPtr_vec;
0386 
0387   partOriginVertex_vec.assign(numHijingPart, 0);
0388   partDecayVertex_vec.assign(numHijingPart, -1);
0389   particleHepPartPtr_vec.assign(numHijingPart, (HepMC::GenParticle *) 0);
0390 
0391   // Vector that will keep pointers to generated vertices
0392   std::vector<HepMC::GenVertex *> vertexPtrVec;
0393 
0394   // Create the event vertex
0395   CLHEP::HepLorentzVector newVertex;
0396   newVertex = CLHEP::HepLorentzVector(0., 0., 0., 0.);
0397   HepMC::GenVertex *v1 = new HepMC::GenVertex(newVertex);
0398 
0399   evt->add_vertex(v1);
0400   vertexPtrVec.push_back(v1);
0401 
0402   double eproj = (m_frame == "CMS") ? efrm / 2.0 : efrm;
0403   int proj_id = (m_proj == "A") ? 3000000 + iap : 2212;
0404   v1->add_particle_in(new HepMC::GenParticle(CLHEP::HepLorentzVector(0., 0., eproj, eproj),
0405                                              proj_id, 101));
0406 
0407   double etarg = (m_frame == "CMS") ? efrm / 2.0 : efrm;
0408   int targ_id = (m_targ == "A") ? 3000000 + iap : 2212;
0409   v1->add_particle_in(new HepMC::GenParticle(CLHEP::HepLorentzVector(0., 0., -etarg, etarg),
0410                                              targ_id, 102));
0411 
0412   // Loop on all Hijing particles and put them all as outgoing from the event vertex
0413   for (int i = 1; i <= natt; ++i)
0414   {
0415     if (m_himain2.katt(i, 4) == 103)
0416     {
0417       // We handle jets a little differently.
0418       CLHEP::HepLorentzVector jetP4(m_himain2.patt(i, 1),
0419                                     m_himain2.patt(i, 2),
0420                                     m_himain2.patt(i, 3),
0421                                     m_himain2.patt(i, 4));
0422       v1->add_particle_out(new HepMC::GenParticle(jetP4,
0423                                                   m_himain2.katt(i, 1),
0424                                                   m_himain2.katt(i, 4)));
0425 
0426       continue;
0427     }
0428 
0429     //  Skip non-interacting projectile and target nucleons
0430     if (!keepSpectators &&
0431         ((m_himain2.katt(i, 2) == 0) || (m_himain2.katt(i, 2)) == 10))
0432       continue;
0433 
0434     //  Find the vertex of the parent particle
0435     int parentIndex = m_himain2.katt(i, 3) - 1;
0436     int parentOriginIndex = 0;
0437     int parentDecayIndex = -1;
0438 
0439     //  If the particle has a true parent, record its vertex info
0440     if (parentIndex >= 0)
0441     {
0442       parentOriginIndex = partOriginVertex_vec[parentIndex];
0443       parentDecayIndex = partDecayVertex_vec[parentIndex];
0444     }
0445 
0446     //  A CLHEP vector containing the particle start point
0447     CLHEP::HepLorentzVector particleStart(m_himain2.vatt(i, 1),
0448                                           m_himain2.vatt(i, 2),
0449                                           m_himain2.vatt(i, 3),
0450                                           m_himain2.vatt(i, 4));
0451 
0452     //  By default, the particle originates from the primary vertex
0453     int particleVertexIndex = 0;
0454 
0455     //  Have we kept the history?
0456     if (keptHistory)
0457     {
0458       //  Check to see if we've already generated a decay vertex
0459       //  for this parent
0460       if (parentDecayIndex != -1)
0461       {
0462         //  Make sure it is consistent with this track origin
0463         HepPoint3D vertex_pos(vertexPtrVec[parentDecayIndex]->point3d().x(),
0464                               vertexPtrVec[parentDecayIndex]->point3d().y(),
0465                               vertexPtrVec[parentDecayIndex]->point3d().z());
0466         double distance = vertex_pos.distance(particleStart.vect());
0467 
0468         if (distance > m_vertexOffsetCut)
0469         {
0470           HepMC::GenVertex::particles_out_const_iterator iter;
0471           for (iter = vertexPtrVec[parentDecayIndex]->particles_out_const_begin();
0472                iter != vertexPtrVec[parentDecayIndex]->particles_out_const_end();
0473                iter++)
0474           {
0475             std::cout << (*iter)->barcode() << ", ";
0476           }
0477 
0478           std::cout << std::endl;
0479         }
0480 
0481         //  Nonetheless set the parent decay vertex to be this particle's vertex
0482         particleVertexIndex = parentDecayIndex;
0483       }
0484       else
0485       {
0486         //  Now compare the distance between the vertex FROM
0487         //  which the parent originates and the start of this
0488         //  particle
0489         HepPoint3D vertex_pos(vertexPtrVec[parentOriginIndex]->point3d().x(),
0490                               vertexPtrVec[parentOriginIndex]->point3d().y(),
0491                               vertexPtrVec[parentOriginIndex]->point3d().z());
0492         double distance = vertex_pos.distance(particleStart.vect());
0493 
0494         if (distance > m_vertexOffsetCut && parentIndex == -1)
0495         {
0496           //  *** Explicitly handle Hijing bug which generates
0497           //  *** particle with displaced vertex but no parent
0498           //  *** ????
0499 
0500           std::cout
0501               << "HIJING BUG:: Particle found with displaced vertex but no parent "
0502               << std::endl;
0503         }
0504         if (distance > m_vertexOffsetCut || parentOriginIndex != 0)
0505         {
0506           // We need to create a new vertex
0507           HepMC::GenVertex *newVertex_p = new HepMC::GenVertex(particleStart);
0508 
0509           evt->add_vertex(newVertex_p);
0510           vertexPtrVec.push_back(newVertex_p);
0511           particleVertexIndex = vertexPtrVec.size() - 1;
0512 
0513           //  Now we indicate that the parent has a decay vertex
0514           partDecayVertex_vec[parentIndex] = particleVertexIndex;
0515 
0516           //  Now tell the vertex about the particle that created it
0517           newVertex_p->add_particle_in(particleHepPartPtr_vec[parentIndex]);
0518         }
0519         else
0520         {
0521           //  Assign the particle to its parent's vertex
0522           particleVertexIndex = parentOriginIndex;
0523         }
0524       }
0525     }
0526     else
0527     {
0528       //  We have to brute-force search for a vertex that might match this particle
0529       int foundVert = -1;
0530       for (unsigned int ivert = 0; ivert < vertexPtrVec.size(); ivert++)
0531       {
0532         HepPoint3D vertex_pos(vertexPtrVec[ivert]->point3d().x(),
0533                               vertexPtrVec[ivert]->point3d().y(),
0534                               vertexPtrVec[ivert]->point3d().z());
0535         double distance = vertex_pos.distance(particleStart.vect());
0536         if (distance < m_vertexOffsetCut)
0537         {
0538           foundVert = ivert;
0539           break;
0540         }
0541       }
0542 
0543       if (foundVert == -1)
0544       {
0545         //  We need to create a new vertex
0546         HepMC::GenVertex *newVertex_p = new HepMC::GenVertex(particleStart);
0547 
0548         evt->add_vertex(newVertex_p);
0549         vertexPtrVec.push_back(newVertex_p);
0550         particleVertexIndex = vertexPtrVec.size() - 1;
0551       }
0552       else
0553       {
0554         particleVertexIndex = foundVert;
0555       }
0556     }
0557 
0558     //  If the Hijing particle has decayed, set the status appropriately
0559     int particleId = m_himain2.katt(i, 1);
0560     int particleStatus = 1;
0561     if (m_himain2.katt(i, 4) == 11)
0562     {
0563       particleStatus = 2;
0564     }
0565 
0566     // Create the new particle
0567     CLHEP::HepLorentzVector particleP4(m_himain2.patt(i, 1),
0568                                        m_himain2.patt(i, 2),
0569                                        m_himain2.patt(i, 3),
0570                                        m_himain2.patt(i, 4));
0571 
0572     HepMC::GenParticle *newParticle_p = new HepMC::GenParticle(particleP4,
0573                                                                particleId,
0574                                                                particleStatus);
0575 
0576     //  Record the particle in the vector of pointers (ostensibly we
0577     //  only need this when we have the history but for simplicity
0578     //  always do it)
0579     particleHepPartPtr_vec[i - 1] = newParticle_p;
0580 
0581     // Now add the particle to its vertex
0582     vertexPtrVec[particleVertexIndex]->add_particle_out(newParticle_p);
0583     partOriginVertex_vec[i - 1] = particleVertexIndex;
0584   }
0585 
0586   return 0;
0587 }