Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:18:11

0001 #include "PHG4SimpleEventGenerator.h"
0002 
0003 #include "PHG4InEvent.h"
0004 #include "PHG4Particle.h"  // for PHG4Particle
0005 #include "PHG4Particlev2.h"
0006 #include "PHG4Utils.h"
0007 
0008 #include <fun4all/Fun4AllReturnCodes.h>
0009 
0010 #include <phool/PHCompositeNode.h>
0011 #include <phool/PHDataNode.h>      // for PHDataNode
0012 #include <phool/PHNode.h>          // for PHNode
0013 #include <phool/PHNodeIterator.h>  // for PHNodeIterator
0014 #include <phool/PHObject.h>        // for PHObject
0015 #include <phool/getClass.h>
0016 #include <phool/phool.h>  // for PHWHERE
0017 
0018 #include <TSystem.h>
0019 
0020 #include <gsl/gsl_randist.h>
0021 #include <gsl/gsl_rng.h>  // for gsl_rng_uniform_pos
0022 
0023 #include <cassert>
0024 #include <cmath>
0025 #include <cstdlib>
0026 #include <iostream>  // for operator<<, endl, basic_ostream
0027 #include <memory>    // for allocator_traits<>::value_type
0028 
0029 PHG4SimpleEventGenerator::PHG4SimpleEventGenerator(const std::string &name)
0030   : PHG4ParticleGeneratorBase(name)
0031 {
0032   return;
0033 }
0034 
0035 void PHG4SimpleEventGenerator::add_particles(const std::string &name, const unsigned int num)
0036 {
0037   _particle_names.emplace_back(name, num);
0038   return;
0039 }
0040 
0041 void PHG4SimpleEventGenerator::add_particles(const int pid, const unsigned int num)
0042 {
0043   _particle_codes.emplace_back(pid, num);
0044   return;
0045 }
0046 
0047 void PHG4SimpleEventGenerator::set_eta_range(const double min, const double max)
0048 {
0049   if (min > max)
0050   {
0051     std::cout << "not setting eta bc etamin " << min << " > etamax: " << max << std::endl;
0052     gSystem->Exit(1);
0053   }
0054   m_EtaMin = min;
0055   m_EtaMax = max;
0056   m_ThetaMin = NAN;
0057   m_ThetaMax = NAN;
0058   return;
0059 }
0060 
0061 void PHG4SimpleEventGenerator::set_theta_range(const double min, const double max)
0062 {
0063   if (min > max)
0064   {
0065     std::cout << __PRETTY_FUNCTION__ << " thetamin " << min << " > thetamax: " << max << std::endl;
0066     gSystem->Exit(1);
0067   }
0068   if (min < 0 || max > M_PI)
0069   {
0070     std::cout << __PRETTY_FUNCTION__ << " min or max outside range (range is 0 to pi) min: " << min << ", max: " << max << std::endl;
0071     gSystem->Exit(1);
0072   }
0073   m_ThetaMin = min;
0074   m_ThetaMax = max;
0075   m_EtaMin = NAN;
0076   m_EtaMax = NAN;
0077   return;
0078 }
0079 
0080 void PHG4SimpleEventGenerator::set_phi_range(const double min, const double max)
0081 {
0082   if (min > max)
0083   {
0084     std::cout << __PRETTY_FUNCTION__ << " phimin " << min << " > phimax: " << max << std::endl;
0085     gSystem->Exit(1);
0086     return;
0087   }
0088   if (min < -M_PI || max > M_PI)
0089   {
0090     std::cout << __PRETTY_FUNCTION__ << "min or max outside range (range is -pi to pi), min: " << min << ", max: " << max << std::endl;
0091     gSystem->Exit(1);
0092   }
0093 
0094   m_PhiMin = min;
0095   m_PhiMax = max;
0096   return;
0097 }
0098 
0099 void PHG4SimpleEventGenerator::set_power_law_n(const double n)
0100 {
0101   m_powerLawN = n;
0102 }
0103 
0104 void PHG4SimpleEventGenerator::set_pt_range(const double min, const double max, const double pt_gaus_width)
0105 {
0106   if (min > max)
0107   {
0108     std::cout << __PRETTY_FUNCTION__ << " ptmin " << min << " > ptmax: " << max << std::endl;
0109     gSystem->Exit(1);
0110   }
0111   if (min < 0 || max < 0 || pt_gaus_width < 0)
0112   {
0113     std::cout << __PRETTY_FUNCTION__ << " values need to be >= 0, min: " << min
0114               << ", max: " << max << ", pt_gaus_width: " << pt_gaus_width << std::endl;
0115     gSystem->Exit(1);
0116   }
0117 
0118   m_Pt_Min = min;
0119   m_Pt_Max = max;
0120   m_Pt_GausWidth = pt_gaus_width;
0121   m_P_Min = NAN;
0122   m_P_Max = NAN;
0123   m_P_GausWidth = NAN;
0124   return;
0125 }
0126 
0127 void PHG4SimpleEventGenerator::set_p_range(const double min, const double max, const double p_gaus_width)
0128 {
0129   if (min > max)
0130   {
0131     std::cout << __PRETTY_FUNCTION__ << " pmin " << min << " > pmax: " << max << std::endl;
0132     gSystem->Exit(1);
0133   }
0134   if (min < 0 || max < 0 || p_gaus_width < 0)
0135   {
0136     std::cout << __PRETTY_FUNCTION__ << " values need to be >= 0, min: " << min
0137               << ", max: " << max << ", p_gaus_width: " << p_gaus_width << std::endl;
0138     gSystem->Exit(1);
0139   }
0140   m_Pt_Min = NAN;
0141   m_Pt_Max = NAN;
0142   m_Pt_GausWidth = NAN;
0143   m_P_Min = min;
0144   m_P_Max = max;
0145   m_P_GausWidth = p_gaus_width;
0146   return;
0147 }
0148 
0149 void PHG4SimpleEventGenerator::set_vertex_distribution_function(FUNCTION x, FUNCTION y, FUNCTION z)
0150 {
0151   m_VertexFunc_x = x;
0152   m_VertexFunc_y = y;
0153   m_VertexFunc_z = z;
0154   return;
0155 }
0156 
0157 void PHG4SimpleEventGenerator::set_vertex_distribution_mean(const double x, const double y, const double z)
0158 {
0159   m_Vertex_x = x;
0160   m_Vertex_y = y;
0161   m_Vertex_z = z;
0162   return;
0163 }
0164 
0165 void PHG4SimpleEventGenerator::set_vertex_distribution_width(const double x, const double y, const double z)
0166 {
0167   m_VertexWidth_x = x;
0168   m_VertexWidth_y = y;
0169   m_VertexWidth_z = z;
0170   return;
0171 }
0172 
0173 void PHG4SimpleEventGenerator::set_existing_vertex_offset_vector(const double x, const double y, const double z)
0174 {
0175   m_VertexOffset_x = x;
0176   m_VertexOffset_y = y;
0177   m_VertexOffset_z = z;
0178   return;
0179 }
0180 
0181 void PHG4SimpleEventGenerator::set_vertex_size_parameters(const double mean, const double width)
0182 {
0183   m_VertexSizeMean = mean;
0184   m_VertexSizeWidth = width;
0185   return;
0186 }
0187 
0188 int PHG4SimpleEventGenerator::InitRun(PHCompositeNode *topNode)
0189 {
0190   if (m_FunctionNames.find(m_VertexFunc_x) == m_FunctionNames.end())
0191   {
0192     std::cout << PHWHERE << "::Error - unknown x vertex distribution function requested" << std::endl;
0193     gSystem->Exit(1);
0194   }
0195   if (m_FunctionNames.find(m_VertexFunc_y) == m_FunctionNames.end())
0196   {
0197     std::cout << PHWHERE << "::Error - unknown y vertex distribution function requested" << std::endl;
0198     gSystem->Exit(1);
0199   }
0200   if (m_FunctionNames.find(m_VertexFunc_z) == m_FunctionNames.end())
0201   {
0202     std::cout << PHWHERE << "::Error - unknown z vertex distribution function requested" << std::endl;
0203     gSystem->Exit(1);
0204   }
0205 
0206   m_InEvent = findNode::getClass<PHG4InEvent>(topNode, "PHG4INEVENT");
0207   if (!m_InEvent)
0208   {
0209     PHNodeIterator iter(topNode);
0210     PHCompositeNode *dstNode;
0211     dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0212 
0213     m_InEvent = new PHG4InEvent();
0214     PHDataNode<PHObject> *newNode = new PHDataNode<PHObject>(m_InEvent, "PHG4INEVENT", "PHObject");
0215     dstNode->addNode(newNode);
0216   }
0217 
0218   if (Verbosity() > 0)
0219   {
0220     std::cout << "================ PHG4SimpleEventGenerator::InitRun() ======================" << std::endl;
0221     std::cout << " Random seed = " << get_seed() << std::endl;
0222     std::cout << " Particles:" << std::endl;
0223     for (auto &_particle_code : _particle_codes)
0224     {
0225       std::cout << "    " << _particle_code.first << ", count = " << _particle_code.second << std::endl;
0226     }
0227     for (auto &_particle_name : _particle_names)
0228     {
0229       std::cout << "    " << _particle_name.first << ", count = " << _particle_name.second << std::endl;
0230     }
0231     if (get_reuse_existing_vertex())
0232     {
0233       std::cout << " Vertex Distribution: Set to reuse a previously generated sim vertex" << std::endl;
0234       std::cout << " Vertex offset vector (x,y,z) = (" << m_VertexOffset_x << "," << m_VertexOffset_y << "," << m_VertexOffset_z << ")" << std::endl;
0235     }
0236     else
0237     {
0238       std::cout << " Vertex Distribution Function (x,y,z) = ("
0239                 << m_FunctionNames.find(m_VertexFunc_x)->second << ","
0240                 << m_FunctionNames.find(m_VertexFunc_y)->second << ","
0241                 << m_FunctionNames.find(m_VertexFunc_z)->second << ")"
0242                 << std::endl;
0243       std::cout << " Vertex mean (x,y,z) = (" << m_Vertex_x << "," << m_Vertex_y << "," << m_Vertex_z << ")" << std::endl;
0244       std::cout << " Vertex width (x,y,z) = (" << m_VertexWidth_x << "," << m_VertexWidth_y << "," << m_VertexWidth_z << ")" << std::endl;
0245     }
0246     std::cout << " Vertex size function (r) = ("
0247               << m_FunctionNames.find(m_VertexSizeFunc_r)->second << ")"
0248               << std::endl;
0249     std::cout << " Vertex size (mean) = (" << m_VertexSizeMean << ")" << std::endl;
0250     std::cout << " Vertex size (width) = (" << m_VertexSizeWidth << ")" << std::endl;
0251     if (std::isfinite(m_EtaMin) && std::isfinite(m_EtaMax))
0252     {
0253       std::cout << " Eta range = " << m_EtaMin << " - " << m_EtaMax << std::endl;
0254     }
0255     if (std::isfinite(m_ThetaMin) && std::isfinite(m_ThetaMax))
0256     {
0257       std::cout << " Theta range = " << m_ThetaMin << " - " << m_ThetaMax
0258                 << ", deg: " << m_ThetaMin / M_PI * 180. << " - " << m_ThetaMax / M_PI * 180. << std::endl;
0259     }
0260     std::cout << " Phi range = " << m_PhiMin << " - " << m_PhiMax
0261               << ", deg: " << m_PhiMin / M_PI * 180. << " - " << m_PhiMax / M_PI * 180. << std::endl;
0262     if (std::isfinite(m_Pt_Min) && std::isfinite(m_Pt_Max))
0263     {
0264       std::cout << " pT range = " << m_Pt_Min << " - " << m_Pt_Max << std::endl;
0265     }
0266     if (std::isfinite(m_P_Min) && std::isfinite(m_P_Max))
0267     {
0268       std::cout << " p range = " << m_P_Min << " - " << m_P_Max << std::endl;
0269     }
0270     std::cout << " t0 = " << get_t0() << std::endl;
0271     std::cout << "===========================================================================" << std::endl;
0272   }
0273 
0274   // the definition table should be filled now, so convert codes into names
0275   for (auto &_particle_code : _particle_codes)
0276   {
0277     int pdgcode = _particle_code.first;
0278     unsigned int count = _particle_code.second;
0279     std::string pdgname = get_pdgname(pdgcode);
0280     _particle_names.emplace_back(pdgname, count);
0281   }
0282 
0283   return Fun4AllReturnCodes::EVENT_OK;
0284 }
0285 
0286 int PHG4SimpleEventGenerator::process_event(PHCompositeNode *topNode)
0287 {
0288   if (Verbosity() > 0)
0289   {
0290     std::cout << "====================== PHG4SimpleEventGenerator::process_event() =====================" << std::endl;
0291     std::cout << "PHG4SimpleEventGenerator::process_event - reuse_existing_vertex = " << get_reuse_existing_vertex() << std::endl;
0292   }
0293 
0294   if (!ReuseExistingVertex(topNode))
0295   {
0296     // generate a new vertex point
0297     set_vtx(smearvtx(m_Vertex_x, m_VertexWidth_x, m_VertexFunc_x),
0298             smearvtx(m_Vertex_y, m_VertexWidth_y, m_VertexFunc_y),
0299             smearvtx(m_Vertex_z, m_VertexWidth_z, m_VertexFunc_z));
0300   }
0301   set_vtx(get_vtx_x() + m_VertexOffset_x,
0302           get_vtx_y() + m_VertexOffset_y,
0303           get_vtx_z() + m_VertexOffset_z);
0304 
0305   if (Verbosity() > 0)
0306   {
0307     std::cout << "PHG4SimpleEventGenerator::process_event - vertex center" << get_reuse_existing_vertex()
0308               << get_vtx_x() << ", " << get_vtx_y() << ", " << get_vtx_z() << " cm"
0309               << std::endl;
0310   }
0311 
0312   int vtxindex = -1;
0313   int trackid = -1;
0314   for (unsigned int i = 0; i < _particle_names.size(); ++i)
0315   {
0316     std::string pdgname = _particle_names[i].first;
0317     int pdgcode = get_pdgcode(pdgname);
0318     unsigned int nparticles = _particle_names[i].second;
0319 
0320     for (unsigned int j = 0; j < nparticles; ++j)
0321     {
0322       if ((m_VertexSizeWidth > 0.0) || (m_VertexSizeMean != 0.0))
0323       {
0324         double r = smearvtx(m_VertexSizeMean, m_VertexSizeWidth, m_VertexSizeFunc_r);
0325 
0326         double x = 0.0;
0327         double y = 0.0;
0328         double z = 0.0;
0329         gsl_ran_dir_3d(RandomGenerator(), &x, &y, &z);
0330         x *= r;
0331         y *= r;
0332         z *= r;
0333 
0334         vtxindex = m_InEvent->AddVtx(get_vtx_x() + x, get_vtx_y() + y, get_vtx_z() + z, get_t0());
0335       }
0336       else if ((i == 0) && (j == 0))
0337       {
0338         vtxindex = m_InEvent->AddVtx(get_vtx_x(), get_vtx_y(), get_vtx_z(), get_t0());
0339       }
0340 
0341       ++trackid;
0342 
0343       double eta;
0344       if (!std::isnan(m_EtaMin) && !std::isnan(m_EtaMax))
0345       {
0346         eta = (m_EtaMax - m_EtaMin) * gsl_rng_uniform_pos(RandomGenerator()) + m_EtaMin;
0347       }
0348       else if (!std::isnan(m_ThetaMin) && !std::isnan(m_ThetaMax))
0349       {
0350         double theta = (m_ThetaMax - m_ThetaMin) * gsl_rng_uniform_pos(RandomGenerator()) + m_ThetaMin;
0351         eta = PHG4Utils::get_eta(theta);
0352       }
0353       else
0354       {
0355         std::cout << PHWHERE << "Error: neither eta range or theta range was specified" << std::endl;
0356         std::cout << "That should not happen, please inform the software group howthis happened" << std::endl;
0357         exit(-1);
0358       }
0359 
0360       double phi = (m_PhiMax - m_PhiMin) * gsl_rng_uniform_pos(RandomGenerator()) + m_PhiMin;
0361 
0362       double pt;
0363 
0364       if (!std::isnan(m_P_Min) && !std::isnan(m_P_Max) && !std::isnan(m_P_GausWidth))
0365       {
0366         pt = ((m_P_Max - m_P_Min) * gsl_rng_uniform_pos(RandomGenerator()) + m_P_Min + gsl_ran_gaussian(RandomGenerator(), m_P_GausWidth)) / cosh(eta);
0367         if (!std::isnan(m_powerLawN))
0368         {
0369           double y = gsl_rng_uniform_pos(RandomGenerator());
0370           double x1 = pow(m_Pt_Max, m_powerLawN + 1);
0371           double x0 = pow(m_Pt_Min, m_powerLawN + 1);
0372           pt = pow((x1 - x0) * y + x0, 1. / (m_powerLawN + 1.));
0373         }
0374       }
0375       else if (!std::isnan(m_Pt_Min) && !std::isnan(m_Pt_Max) && !std::isnan(m_Pt_GausWidth))
0376       {
0377         pt = (m_Pt_Max - m_Pt_Min) * gsl_rng_uniform_pos(RandomGenerator()) + m_Pt_Min + gsl_ran_gaussian(RandomGenerator(), m_Pt_GausWidth);
0378         if (!std::isnan(m_powerLawN))
0379         {
0380           double y = gsl_rng_uniform_pos(RandomGenerator());
0381           double x1 = pow(m_Pt_Max, m_powerLawN + 1);
0382           double x0 = pow(m_Pt_Min, m_powerLawN + 1);
0383           pt = pow((x1 - x0) * y + x0, 1. / (m_powerLawN + 1.));
0384         }
0385       }
0386       else
0387       {
0388         std::cout << PHWHERE << "Error: neither a p range or pt range was specified" << std::endl;
0389         exit(-1);
0390       }
0391 
0392       double px = pt * cos(phi);
0393       double py = pt * sin(phi);
0394       double pz = pt * sinh(eta);
0395       double m = get_mass(pdgcode);
0396       double e = sqrt(px * px + py * py + pz * pz + m * m);
0397 
0398       PHG4Particle *particle = new PHG4Particlev2();
0399       particle->set_track_id(trackid);
0400       particle->set_vtx_id(vtxindex);
0401       particle->set_parent_id(0);
0402       particle->set_name(pdgname);
0403       particle->set_pid(pdgcode);
0404       particle->set_px(px);
0405       particle->set_py(py);
0406       particle->set_pz(pz);
0407       particle->set_e(e);
0408 
0409       m_InEvent->AddParticle(vtxindex, particle);
0410       if (EmbedFlag() != 0)
0411       {
0412         m_InEvent->AddEmbeddedParticle(particle, EmbedFlag());
0413       }
0414     }
0415   }
0416 
0417   if (Verbosity() > 0)
0418   {
0419     m_InEvent->identify();
0420     std::cout << "======================================================================================" << std::endl;
0421   }
0422 
0423   return Fun4AllReturnCodes::EVENT_OK;
0424 }
0425 
0426 double
0427 PHG4SimpleEventGenerator::smearvtx(const double position, const double width, FUNCTION dist) const
0428 {
0429   double res = position;
0430   if (dist == Uniform)
0431   {
0432     res = (position - width) + 2 * gsl_rng_uniform_pos(RandomGenerator()) * width;
0433   }
0434   else if (dist == Gaus)
0435   {
0436     res = position + gsl_ran_gaussian(RandomGenerator(), width);
0437   }
0438   else
0439   {
0440     std::cout << __PRETTY_FUNCTION__ << " invalid distribution function " << dist
0441               << " (" << m_FunctionNames.find(dist)->second << ")" << std::endl;
0442     gSystem->Exit(1);
0443   }
0444   return res;
0445 }