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