File indexing completed on 2025-08-06 08:18:48
0001 #include "QAG4SimulationUpsilon.h"
0002
0003 #include <qautils/QAHistManagerDef.h>
0004
0005 #include <g4eval/SvtxEvalStack.h>
0006
0007 #include <g4main/PHG4Particle.h>
0008 #include <g4main/PHG4TruthInfoContainer.h>
0009
0010 #include <trackbase_historic/SvtxTrack.h>
0011
0012 #include <g4eval/SvtxTrackEval.h> // for SvtxTrackEval
0013 #include <g4eval/SvtxTruthEval.h> // for SvtxTruthEval
0014
0015 #include <fun4all/Fun4AllHistoManager.h>
0016 #include <fun4all/Fun4AllReturnCodes.h>
0017 #include <fun4all/SubsysReco.h>
0018
0019 #include <phool/getClass.h>
0020
0021 #include <TAxis.h>
0022 #include <TDatabasePDG.h>
0023 #include <TH1.h>
0024 #include <TH2.h>
0025 #include <TParticlePDG.h> // for TParticlePDG
0026 #include <TString.h>
0027 #include <TVector3.h>
0028
0029 #include <CLHEP/Vector/LorentzVector.h>
0030 #include <CLHEP/Vector/ThreeVector.h> // for Hep3Vector
0031
0032 #include <cassert>
0033 #include <cmath>
0034 #include <cstdlib> // for abs
0035 #include <iostream>
0036 #include <set>
0037 #include <string>
0038 #include <utility> // for pair
0039
0040 QAG4SimulationUpsilon::QAG4SimulationUpsilon(const std::string &name)
0041 : SubsysReco(name)
0042 , _svtxEvalStack(nullptr)
0043 , m_etaRange(-1, 1)
0044 , _truthContainer(nullptr)
0045 {
0046 }
0047
0048 int QAG4SimulationUpsilon::InitRun(PHCompositeNode *topNode)
0049 {
0050 _truthContainer = findNode::getClass<PHG4TruthInfoContainer>(topNode,
0051 "G4TruthInfo");
0052 if (!_truthContainer)
0053 {
0054 std::cout << "QAG4SimulationUpsilon::InitRun - Fatal Error - "
0055 << "unable to find DST node "
0056 << "G4TruthInfo" << std::endl;
0057 assert(_truthContainer);
0058 }
0059
0060 if (!_svtxEvalStack)
0061 {
0062 _svtxEvalStack.reset(new SvtxEvalStack(topNode));
0063 _svtxEvalStack->set_strict(true);
0064 _svtxEvalStack->set_verbosity(Verbosity() + 1);
0065 }
0066
0067 return Fun4AllReturnCodes::EVENT_OK;
0068 }
0069
0070 int QAG4SimulationUpsilon::Init(PHCompositeNode * )
0071 {
0072 Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
0073 assert(hm);
0074
0075
0076 TH1 *h(nullptr);
0077
0078 h = new TH1F(TString(get_histo_prefix()) + "pTRecoGenRatio",
0079 ";Reco p_{T}/Truth p_{T}", 500, 0, 2);
0080 hm->registerHisto(h);
0081
0082 h = new TH2F(TString(get_histo_prefix()) + "pTRecoGenRatio_pTGen",
0083 ";Truth p_{T} [GeV/c];Reco p_{T}/Truth p_{T}", 200, 0, 50, 500, 0, 2);
0084
0085 hm->registerHisto(h);
0086
0087
0088 h = new TH1F(TString(get_histo_prefix()) + "nReco_pTGen",
0089 "Reco tracks at truth p_{T};Truth p_{T} [GeV/c]", 200, 0.1, 50.5);
0090 QAHistManagerDef::useLogBins(h->GetXaxis());
0091 hm->registerHisto(h);
0092
0093 h = new TH1F(TString(get_histo_prefix()) + "nGen_pTGen",
0094 ";Truth p_{T} [GeV/c];Track count / bin", 200, 0.1, 50.5);
0095 QAHistManagerDef::useLogBins(h->GetXaxis());
0096 hm->registerHisto(h);
0097
0098
0099 h = new TH1F(TString(get_histo_prefix()) + "nReco_etaGen",
0100 "Reco tracks at truth #eta;Truth #eta", 200, -2, 2);
0101
0102 hm->registerHisto(h);
0103
0104 h = new TH1F(TString(get_histo_prefix()) + "nGen_etaGen",
0105 ";Truth #eta;Track count / bin", 200, -2, 2);
0106
0107 hm->registerHisto(h);
0108
0109 h = new TH1F(TString(get_histo_prefix()) + "nGen_Pair_InvMassGen",
0110 ";Truth Invariant Mass [GeV/c^2];Pair count / bin", 450, 0, 15);
0111
0112 hm->registerHisto(h);
0113 h = new TH1F(TString(get_histo_prefix()) + "nReco_Pair_InvMassReco",
0114 ";Reco Invariant Mass [GeV/c^2];Pair count / bin", 450, 0, 15);
0115
0116 hm->registerHisto(h);
0117
0118
0119 h = new TH1F(TString(get_histo_prefix()) + "Normalization",
0120 TString(get_histo_prefix()) + " Normalization;Items;Count", 10, .5, 10.5);
0121 int i = 1;
0122 h->GetXaxis()->SetBinLabel(i++, "Event");
0123 h->GetXaxis()->SetBinLabel(i++, "Truth Track+");
0124 h->GetXaxis()->SetBinLabel(i++, "Truth Track-");
0125 h->GetXaxis()->SetBinLabel(i++, "Reco Track");
0126 h->GetXaxis()->SetBinLabel(i++, "Truth Upsilon");
0127 h->GetXaxis()->SetBinLabel(i++, "Truth Upsilon in Acc.");
0128 h->GetXaxis()->SetBinLabel(i++, "Reco Upsilon");
0129 h->GetXaxis()->LabelsOption("v");
0130 hm->registerHisto(h);
0131
0132 return Fun4AllReturnCodes::EVENT_OK;
0133 }
0134
0135 void QAG4SimulationUpsilon::addEmbeddingID(int embeddingID)
0136 {
0137 m_embeddingIDs.insert(embeddingID);
0138 }
0139
0140 int QAG4SimulationUpsilon::process_event(PHCompositeNode *topNode)
0141 {
0142 if (Verbosity() > 2)
0143 {
0144 std::cout << "QAG4SimulationUpsilon::process_event() entered" << std::endl;
0145 }
0146
0147
0148 Fun4AllHistoManager *hm = QAHistManagerDef::getHistoManager();
0149 assert(hm);
0150
0151 if (_svtxEvalStack)
0152 {
0153 _svtxEvalStack->next_event(topNode);
0154 }
0155
0156 SvtxTrackEval *trackeval = _svtxEvalStack->get_track_eval();
0157 assert(trackeval);
0158 SvtxTruthEval *trutheval = _svtxEvalStack->get_truth_eval();
0159 assert(trutheval);
0160
0161
0162 TH1 *h_pTRecoGenRatio = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "pTRecoGenRatio"));
0163 assert(h_pTRecoGenRatio);
0164
0165
0166 TH2 *h_pTRecoGenRatio_pTGen = dynamic_cast<TH2 *>(hm->getHisto(get_histo_prefix() + "pTRecoGenRatio_pTGen"));
0167 assert(h_pTRecoGenRatio);
0168
0169
0170 TH1 *h_nReco_pTGen = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nReco_pTGen"));
0171 assert(h_nReco_pTGen);
0172
0173
0174 TH1 *h_nGen_pTGen = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nGen_pTGen"));
0175 assert(h_nGen_pTGen);
0176
0177
0178 TH1 *h_nReco_etaGen = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nReco_etaGen"));
0179 assert(h_nReco_etaGen);
0180
0181
0182 TH1 *h_nGen_etaGen = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nGen_etaGen"));
0183 assert(h_nGen_etaGen);
0184
0185
0186 TH1 *h_nGen_Pair_InvMassGen = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nGen_Pair_InvMassGen"));
0187 assert(h_nGen_etaGen);
0188
0189 TH1 *h_nReco_Pair_InvMassReco = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "nReco_Pair_InvMassReco"));
0190 assert(h_nGen_etaGen);
0191
0192
0193 TH1 *h_norm = dynamic_cast<TH1 *>(hm->getHisto(get_histo_prefix() + "Normalization"));
0194 assert(h_norm);
0195 h_norm->Fill("Event", 1);
0196
0197
0198 using truth_reco_set_t = std::set<std::pair<PHG4Particle *, SvtxTrack *>>;
0199 truth_reco_set_t truth_reco_set_pos;
0200 truth_reco_set_t truth_reco_set_neg;
0201
0202
0203 if (!_truthContainer)
0204 {
0205 std::cout << "QAG4SimulationUpsilon::process_event - fatal error - missing _truthContainer! ";
0206 return Fun4AllReturnCodes::ABORTRUN;
0207 }
0208
0209 PHG4TruthInfoContainer::ConstRange const range = _truthContainer->GetPrimaryParticleRange();
0210 for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter)
0211 {
0212
0213 PHG4Particle *g4particle = iter->second;
0214
0215 if (Verbosity())
0216 {
0217 std::cout << "QAG4SimulationUpsilon::process_event - processing ";
0218 g4particle->identify();
0219 }
0220
0221 if (m_embeddingIDs.size() > 0)
0222 {
0223
0224 int candidate_embedding_id = trutheval->get_embed(g4particle);
0225 if (candidate_embedding_id < 0)
0226 {
0227 candidate_embedding_id = -1;
0228 }
0229
0230
0231 if (m_embeddingIDs.find(candidate_embedding_id) == m_embeddingIDs.end())
0232 {
0233 continue;
0234 }
0235 }
0236
0237 double const gpx = g4particle->get_px();
0238 double const gpy = g4particle->get_py();
0239 double const gpz = g4particle->get_pz();
0240 double gpt = 0;
0241 double geta = NAN;
0242
0243 if (gpx != 0 && gpy != 0)
0244 {
0245 TVector3 const gv(gpx, gpy, gpz);
0246 gpt = gv.Pt();
0247 geta = gv.Eta();
0248
0249 }
0250 if (m_etaRange.first < geta and geta < m_etaRange.second)
0251 {
0252 if (Verbosity())
0253 {
0254 std::cout << "QAG4SimulationUpsilon::process_event - accept particle eta = " << geta << std::endl;
0255 }
0256 }
0257 else
0258 {
0259 if (Verbosity())
0260 {
0261 std::cout << "QAG4SimulationUpsilon::process_event - ignore particle eta = " << geta << std::endl;
0262 }
0263 continue;
0264 }
0265
0266 const int pid = g4particle->get_pid();
0267
0268 if (abs(pid) != abs(m_daughterAbsPID))
0269 {
0270 if (Verbosity())
0271 {
0272 std::cout << "QAG4SimulationUpsilon::process_event - ignore particle PID = " << pid << " as m_daughterAbsPID = " << m_daughterAbsPID << std::endl;
0273 }
0274 continue;
0275 }
0276
0277 TParticlePDG *pdg_p = TDatabasePDG::Instance()->GetParticle(pid);
0278 if (!pdg_p)
0279 {
0280 std::cout << "QAG4SimulationUpsilon::process_event - Error - invalid particle ID = " << pid << std::endl;
0281 continue;
0282 }
0283
0284 const double gcharge = pdg_p->Charge() / 3;
0285 if (gcharge > 0)
0286 {
0287 h_norm->Fill("Truth Track+", 1);
0288 }
0289 else if (gcharge < 0)
0290 {
0291 h_norm->Fill("Truth Track-", 1);
0292 }
0293 else
0294 {
0295 if (Verbosity())
0296 {
0297 std::cout << "QAG4SimulationUpsilon::process_event - invalid neutral decay particle ID = " << pid << std::endl;
0298 }
0299 continue;
0300 }
0301
0302
0303 h_nGen_pTGen->Fill(gpt);
0304 h_nGen_etaGen->Fill(geta);
0305
0306
0307 SvtxTrack *track = trackeval->best_track_from(g4particle);
0308 if (track)
0309 {
0310 h_nReco_etaGen->Fill(geta);
0311 h_nReco_pTGen->Fill(gpt);
0312
0313 double const px = track->get_px();
0314 double const py = track->get_py();
0315 double const pz = track->get_pz();
0316 double pt;
0317 TVector3 const v(px, py, pz);
0318 pt = v.Pt();
0319
0320
0321
0322 float const pt_ratio = (gpt != 0) ? pt / gpt : 0;
0323 h_pTRecoGenRatio->Fill(pt_ratio);
0324 h_pTRecoGenRatio_pTGen->Fill(gpt, pt_ratio);
0325 h_norm->Fill("Reco Track", 1);
0326 }
0327
0328 if (gcharge > 0)
0329 {
0330 truth_reco_set_pos.insert(std::make_pair(g4particle, track));
0331 }
0332 else if (gcharge < 0)
0333 {
0334 truth_reco_set_neg.insert(std::make_pair(g4particle, track));
0335 }
0336 }
0337
0338
0339 TParticlePDG *pdg_p = TDatabasePDG::Instance()->GetParticle(m_quarkoniaPID);
0340 if (!pdg_p)
0341 {
0342 std::cout << "QAG4SimulationUpsilon::process_event - Fatal Error - invalid particle ID m_quarkoniaPID = " << m_quarkoniaPID << std::endl;
0343
0344 return Fun4AllReturnCodes::ABORTRUN;
0345 }
0346 const double quarkonium_mass = pdg_p->Mass();
0347 TParticlePDG *pdg_d = TDatabasePDG::Instance()->GetParticle(m_daughterAbsPID);
0348 if (!pdg_d)
0349 {
0350 std::cout << "QAG4SimulationUpsilon::process_event - Fatal Error - invalid particle ID m_daughterAbsPID = " << m_daughterAbsPID << std::endl;
0351
0352 return Fun4AllReturnCodes::ABORTRUN;
0353 }
0354 const double daughter_mass = pdg_d->Mass();
0355
0356 for (const auto &pair_pos : truth_reco_set_pos)
0357 {
0358 for (const auto &pair_neg : truth_reco_set_neg)
0359 {
0360 assert(pair_pos.first);
0361 assert(pair_neg.first);
0362
0363 const CLHEP::HepLorentzVector gv_pos(
0364 pair_pos.first->get_px(),
0365 pair_pos.first->get_py(),
0366 pair_pos.first->get_pz(),
0367 pair_pos.first->get_e());
0368
0369 const CLHEP::HepLorentzVector gv_neg(
0370 pair_neg.first->get_px(),
0371 pair_neg.first->get_py(),
0372 pair_neg.first->get_pz(),
0373 pair_neg.first->get_e());
0374
0375 const CLHEP::HepLorentzVector gv_quakonium = gv_pos + gv_neg;
0376
0377 if (fabs(quarkonium_mass - gv_quakonium.m()) > 1e-3)
0378 {
0379 if (Verbosity())
0380 {
0381 std::cout << "QAG4SimulationUpsilon::process_event - invalid pair with in compativle mass with " << quarkonium_mass << "GeV for PID = " << m_quarkoniaPID << ": " << std::endl;
0382 pair_pos.first->identify();
0383 pair_neg.first->identify();
0384 }
0385 continue;
0386 }
0387
0388 h_nGen_Pair_InvMassGen->Fill(gv_quakonium.m());
0389 h_norm->Fill("Truth Upsilon in Acc.", 1);
0390
0391 if (pair_pos.second and pair_neg.second)
0392 {
0393 CLHEP::HepLorentzVector v_pos;
0394 CLHEP::HepLorentzVector v_neg;
0395
0396 v_pos.setVectM(
0397 CLHEP::Hep3Vector(
0398 pair_pos.second->get_px(),
0399 pair_pos.second->get_py(),
0400 pair_pos.second->get_pz()),
0401 daughter_mass);
0402 v_neg.setVectM(
0403 CLHEP::Hep3Vector(
0404 pair_neg.second->get_px(),
0405 pair_neg.second->get_py(),
0406 pair_neg.second->get_pz()),
0407 daughter_mass);
0408
0409 const CLHEP::HepLorentzVector v_quakonium = v_pos + v_neg;
0410
0411 h_nReco_Pair_InvMassReco->Fill(v_quakonium.m());
0412 h_norm->Fill("Reco Upsilon", 1);
0413
0414 }
0415
0416 }
0417 }
0418
0419 return Fun4AllReturnCodes::EVENT_OK;
0420 }
0421
0422 std::string
0423 QAG4SimulationUpsilon::get_histo_prefix()
0424 {
0425 return std::string("h_") + Name() + std::string("_");
0426 }