Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-08-30 08:16:12

0001 // HerwigSTARUECheck
0002 //
0003 // Truth-level cross-check of a HERWIG (Nashville tune) sPHENIX production
0004 // against the STAR underlying-event measurement,
0005 // PRD 101, 052004 (2020) [arXiv:1912.08187].
0006 //
0007 // Reproduces the observable in Fig. 4 (top right) of the HERWIG7 RHIC tune
0008 // paper [arXiv:2411.16897]: mean charged-particle multiplicity density
0009 // <dNch/(deta dphi)> in the Transverse region vs leading-jet pT.
0010 //
0011 // Two independent particle sources are analyzed in the same pass and written
0012 // to *separate* histograms so they can be compared directly:
0013 //   "hepmc" -- generator-level HepMC record (PHHepMCGenEventMap), status==1
0014 //   "g4"    -- PHG4TruthInfoContainer sPHENIX primary particles
0015 // Either can be switched off with set_do_hepmc() / set_do_g4truth().
0016 // Histogram names carry the suffix "_hepmc" / "_g4".
0017 //
0018 // Selections follow the Rivet reference implementation STAR_2019_I1771348
0019 // (github.com/star-bnl/star-pythia8-tune), which is what both the Detroit
0020 // (PYTHIA8) and Nashville/New Haven (HERWIG7) tune papers used:
0021 //   - final-state particles: pT > 0.2 GeV/c, |eta| < 1.0
0022 //   - jets: anti-kT, R = 0.6, clustered from ALL such particles
0023 //   - leading jet: hardest jet with 5 < pT < 45 GeV/c and |eta| < 0.4
0024 //   - regions w.r.t. leading jet: Toward |dphi| < pi/3,
0025 //     Transverse pi/3 < |dphi| < 2pi/3, Away |dphi| > 2pi/3
0026 //   - density normalization: Nch / (deta * dphi) = Nch / (2 * 2pi/3)
0027 
0028 #ifndef HERWIGSTARUECHECK_H
0029 #define HERWIGSTARUECHECK_H
0030 
0031 #include <fun4all/SubsysReco.h>
0032 
0033 #include <fastjet/PseudoJet.hh>
0034 
0035 #include <map>
0036 #include <string>
0037 #include <vector>
0038 
0039 class PHCompositeNode;
0040 class TFile;
0041 class TH1;
0042 class TH2;
0043 
0044 class HerwigSTARUECheck : public SubsysReco
0045 {
0046  public:
0047   explicit HerwigSTARUECheck(const std::string &name = "HerwigSTARUECheck",
0048                              const std::string &outfile = "herwig_ue_check.root");
0049   ~HerwigSTARUECheck() override = default;
0050 
0051   int Init(PHCompositeNode *topNode) override;
0052   int process_event(PHCompositeNode *topNode) override;
0053   int End(PHCompositeNode *topNode) override;
0054 
0055   //! STAR PRD 101, 052004 defaults; setters provided for variations
0056   void set_jet_R(double r) { m_jetR = r; }
0057   void set_jet_pt_window(double lo, double hi)
0058   {
0059     m_jetPtMin = lo;
0060     m_jetPtMax = hi;
0061   }
0062   void set_jet_abs_eta_max(double e) { m_jetEtaMax = e; }
0063   void set_constituent_pt_min(double p) { m_constPtMin = p; }
0064   void set_particle_abs_eta_max(double e) { m_partEtaMax = e; }
0065 
0066   //! The Rivet reference uses a plain FinalState projection, which keeps
0067   //! neutrinos in the jet clustering. Default matches that; set false to
0068   //! cluster visible particles only (per-mille level effect here).
0069   //! NOTE: only acts on the HepMC branch -- PHG4TruthInfoContainer primaries
0070   //! do not contain neutrinos to begin with.
0071   void set_include_neutrinos(bool b) { m_includeNeutrinos = b; }
0072 
0073   //! Which embedded HepMC event to analyze (sPHENIX embedding id, default 0)
0074   void set_embedding_id(int id) { m_embeddingId = id; }
0075 
0076   //! enable/disable each particle source independently
0077   void set_do_hepmc(bool b) { m_doHepMC = b; }
0078   void set_do_g4truth(bool b) { m_doG4Truth = b; }
0079 
0080   //! if true, a missing PHHepMCGenEventMap / G4TruthInfo node is a hard error
0081   //! rather than a silently skipped branch
0082   void set_require_both_sources(bool b) { m_requireBoth = b; }
0083 
0084   void SetSimSample(std::string sampleName) { m_sampleName = sampleName; };
0085   std::string GetSimSample() { return m_sampleName; }
0086 
0087   void useCSWeights(bool use) { m_useCSWeights = use; }
0088 
0089  private:
0090   //! One complete set of observables. Booked once per particle source, with
0091   //! a name suffix (tag) and a title suffix (label).
0092   struct UEHistSet
0093   {
0094     void book(const std::string &tag, const std::string &label);
0095     void write();
0096 
0097     //! profiles vs leading-jet pT (STAR binning {5,7,9,11,15,20,25,35,45})
0098     TH2 *dens_trans_02{nullptr};   //!< <dNch/detadphi>, Transverse, pT>0.2 -- THE fig.4 (top right) observable
0099     TH2 *dens_toward_02{nullptr};  //!< Toward, pT>0.2
0100     TH2 *dens_away_02{nullptr};    //!< Away, pT>0.2
0101     TH2 *dens_trans_05{nullptr};   //!< Transverse, pT>0.5
0102 
0103     TH2 *avgpt_trans_02{nullptr};  //!< <pT_ch>, Transverse, pT>0.2
0104     TH2 *avgpt_toward_02{nullptr};
0105     TH2 *avgpt_away_02{nullptr};
0106     TH2 *avgpt_trans_05{nullptr};
0107 
0108     TH2 *sumET_trans_02{nullptr};
0109     TH2 *sumET_toward_02{nullptr};
0110     TH2 *sumET_away_02{nullptr};
0111     TH2 *sumET_trans_05{nullptr};
0112     TH2 *sumET_trans_R04{nullptr};
0113 
0114     TH1 *pi_spec{nullptr};
0115 
0116     //! diagnostics for judging whether the production is "sufficient"
0117     TH1 *leadjet_pt{nullptr};
0118     TH1 *leadjet_pt_R04{nullptr};
0119     TH1 *leadjet_eta{nullptr};
0120     TH1 *dphi{nullptr};      //!< |dphi(particle, leading jet)|, pT>0.2
0121     TH1 *cutflow{nullptr};   //!< particles found / R=0.6 lead / R=0.4 lead
0122 
0123     std::vector<TH1 *> all;  //!< everything booked, in creation order
0124 
0125    private:
0126     TH2 *mk2(const std::string &name, const std::string &title,
0127              int nx, const double *xbins, int ny, double ylo, double yhi);
0128     TH1 *mk1(const std::string &name, const std::string &title,
0129              int nx, const double *xbins);
0130     TH1 *mk1(const std::string &name, const std::string &title,
0131              int nx, double xlo, double xhi);
0132   };
0133 
0134   //! fill parts/pids from the generator record; false if the node is absent
0135   bool collect_hepmc(PHCompositeNode *topNode,
0136                      std::vector<fastjet::PseudoJet> &parts,
0137                      std::vector<int> &pids);
0138 
0139   //! fill parts/pids from the G4 primary particles; false if node is absent
0140   bool collect_g4truth(PHCompositeNode *topNode,
0141                        std::vector<fastjet::PseudoJet> &parts,
0142                        std::vector<int> &pids);
0143 
0144   //! the actual UE analysis, run once per particle source
0145   void analyze(UEHistSet &H,
0146                const std::vector<fastjet::PseudoJet> &parts,
0147                const std::vector<int> &pids,
0148                double w);
0149 
0150   double pdg_charge(int pid);
0151 
0152   std::string m_outfileName;
0153 
0154   double m_jetR = 0.6;
0155   double m_jetPtMin = 5.0;
0156   double m_jetPtMax = 45.0;
0157   double m_jetEtaMax = 0.4;
0158   double m_constPtMin = 0.2;
0159   double m_partEtaMax = 1.0;
0160   bool m_includeNeutrinos = true;
0161   int m_embeddingId = 0;
0162 
0163   bool m_doHepMC{true};
0164   bool m_doG4Truth{true};
0165   bool m_requireBoth{false};
0166 
0167   std::string m_sampleName{"Jet20"};
0168   int sampleNumber{-999};
0169 
0170   bool m_useCSWeights{false};
0171   double m_weight{1.0};  //!< per-event weight, identical for both sources
0172 
0173   const std::string sampleNames[8] = {"MB", "Jet5", "Jet12", "Jet20", "Jet30", "Jet40", "Jet50", "Jet60"};
0174   const std::string HerwigsampleNames[7] = {"HerwigMB", "HerwigJet5", "HerwigJet12", "HerwigJet20", "HerwigJet30", "HerwigJet40", "HerwigJet50"};
0175   const float truthJet_min_pT[8] = {0, 12, 22, 29, 41, 53, 63, 72};
0176   const float truthJet_min_pT_R04[8] = {0, 7, 14, 21, 32, 42, 52, 62};
0177   const double cs[8] = {4.1970e+10, 1.3878e+08, 1.4903e+06, 6.2623e+04, 2.5298e+03, 1.3553e+02, 7.3113, 3.3261e-01};
0178   const double HerwigCS[7] = {3.1909e+10, 1.8437e+08, 6.7108e+05, 5.2613e+04, 2.0694e+03, 1.0510e+02, 5.2089};
0179 
0180   std::map<int, double> m_chargeCache;
0181 
0182   TFile *m_outfile{nullptr};
0183 
0184   UEHistSet m_hHepMC;  //!< generator-level (HepMC) observables
0185   UEHistSet m_hG4;     //!< G4 primary-particle observables
0186 
0187   TH1 *m_h_nevents{nullptr};  //!< processed / HepMC node / G4 node
0188 };
0189 
0190 #endif  // HERWIGSTARUECHECK_H