Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QAG4SimulationTpc.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file QAG4SimulationTpc.cc
1 #include "QAG4SimulationTpc.h"
2 #include <qautils/QAUtil.h>
3 #include <qautils/QAHistManagerDef.h>
4 
6 
7 #include <g4main/PHG4Particle.h>
9 
11 
13 
14 #include <trackbase/ActsGeometry.h>
15 #include <trackbase/TpcDefs.h>
17 #include <trackbase/TrkrCluster.h>
20 #include <trackbase/TrkrDefs.h> // for getTrkrId
22 
23 #include <g4eval/SvtxClusterEval.h> // for SvtxClusterEval
24 #include <g4eval/SvtxEvalStack.h>
25 #include <g4eval/SvtxTruthEval.h> // for SvtxTruthEval
26 
29 #include <fun4all/SubsysReco.h> // for SubsysReco
30 
31 #include <phool/getClass.h>
32 #include <phool/phool.h> // for PHWHERE
33 
34 #include <TAxis.h> // for TAxis
35 #include <TH1.h>
36 #include <TString.h> // for Form
37 
38 #include <cassert>
39 #include <cmath> // for atan2
40 #include <iostream> // for operator<<, basic...
41 #include <iterator> // for distance
42 #include <map> // for map
43 #include <utility> // for pair, make_pair
44 #include <vector> // for vector
45 
46 //________________________________________________________________________
48  : SubsysReco(name)
49  , m_truthContainer(nullptr)
50 {
51 }
52 
53 //________________________________________________________________________
55 {
56  // prevent multiple creations of histograms
57  if (m_initialized)
59  else
60  m_initialized = true;
61 
62  if (!m_svtxEvalStack)
63  {
64  m_svtxEvalStack.reset(new SvtxEvalStack(topNode));
65  m_svtxEvalStack->set_strict(true);
66  m_svtxEvalStack->set_verbosity(Verbosity());
67  }
68 
69  m_truthContainer = findNode::getClass<PHG4TruthInfoContainer>(topNode,
70  "G4TruthInfo");
71  if (!m_truthContainer)
72  {
73  std::cout << "QAG4SimulationTpc::InitRun - Fatal Error - "
74  << "unable to find node G4TruthInfo" << std::endl;
76  }
77 
78  // find tpc geometry
79  PHG4TpcCylinderGeomContainer* geom_container =
80  findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
81  // auto geom_container = findNode::getClass<PHG4CylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
82  if (!geom_container)
83  {
84  std::cout << PHWHERE << " unable to find DST node CYLINDERCELLGEOM_SVTX" << std::endl;
86  }
87 
88  // TPC has 3 regions, inner, mid and outer
89  std::vector<int> region_layer_low = {7, 23, 39};
90  ;
91  std::vector<int> region_layer_high = {22, 38, 54};
92 
93  // get layers from tpc geometry
94  // make a layer to region multimap
95  const auto range = geom_container->get_begin_end();
96  for (auto iter = range.first; iter != range.second; ++iter)
97  {
98  m_layers.insert(iter->first);
99 
100  for (int region = 0; region < 3; ++region)
101  {
102  if (iter->first >= region_layer_low[region] && iter->first <= region_layer_high[region])
103  m_layer_region_map.insert(std::make_pair(iter->first, region));
104  }
105  }
106 
107  // histogram manager
109  assert(hm);
110 
111  // create histograms
112 
113  // truth clusters
114  {
115  auto h = new TH1F(Form("%sefficiency_0", get_histo_prefix().c_str()), Form("TPC_truth_clusters"), 48, 7, 54);
116  h->GetXaxis()->SetTitle("sPHENIX layer");
117  hm->registerHisto(h);
118  }
119  // matched clusters
120  {
121  auto h = new TH1F(Form("%sefficiency_1", get_histo_prefix().c_str()), Form("TPC_matched_clusters"), 48, 7, 54);
122  h->GetXaxis()->SetTitle("sPHENIX layer");
123  hm->registerHisto(h);
124  }
125 
126  // cluster parameters
127  for (int region = 0; region < 3; ++region)
128  {
129  if (Verbosity()) std::cout << PHWHERE << " adding region " << region << " with layers " << region_layer_low[region] << " to " << region_layer_high[region] << std::endl;
130  {
131  // rphi residuals (cluster - truth)
132  auto h = new TH1F(Form("%sdrphi_%i", get_histo_prefix().c_str(), region), Form("TPC r#Delta#phi_{cluster-truth} region_%i", region), 100, -0.079, 0.075);
133  h->GetXaxis()->SetTitle("r#Delta#phi_{cluster-truth} (cm)");
134  hm->registerHisto(h);
135  }
136 
137  {
138  // rphi cluster errors
139  auto h = new TH1F(Form("%srphi_error_%i", get_histo_prefix().c_str(), region), Form("TPC r#Delta#phi error region_%i", region), 100, 0, 0.075);
140  h->GetXaxis()->SetTitle("r#Delta#phi error (cm)");
141  hm->registerHisto(h);
142  }
143 
144  {
145  // phi pulls (cluster - truth)
146  auto h = new TH1F(Form("%sphi_pulls_%i", get_histo_prefix().c_str(), region), Form("TPC #Delta#phi_{cluster-truth}/#sigma#phi region_%i", region), 100, -3, 3);
147  h->GetXaxis()->SetTitle("#Delta#phi_{cluster-truth}/#sigma#phi (cm)");
148  hm->registerHisto(h);
149  }
150 
151  {
152  // z residuals (cluster - truth)
153  auto h = new TH1F(Form("%sdz_%i", get_histo_prefix().c_str(), region), Form("TPC #Deltaz_{cluster-truth} region_%i", region), 100, -0.19, 0.19);
154  h->GetXaxis()->SetTitle("#Delta#z_{cluster-truth} (cm)");
155  hm->registerHisto(h);
156  }
157 
158  {
159  // z cluster errors
160  auto h = new TH1F(Form("%sz_error_%i", get_histo_prefix().c_str(), region), Form("TPC z error region_%i", region), 100, 0, 0.18);
161  h->GetXaxis()->SetTitle("z error (cm)");
162  hm->registerHisto(h);
163  }
164 
165  {
166  // z pulls (cluster - truth)
167  auto h = new TH1F(Form("%sz_pulls_%i", get_histo_prefix().c_str(), region), Form("TPC #Deltaz_{cluster-truth}/#sigmaz region_%i", region), 100, -3, 3);
168  h->GetXaxis()->SetTitle("#Delta#z_{cluster-truth}/#sigmaz (cm)");
169  hm->registerHisto(h);
170  }
171 
172  {
173  // total cluster size
174  auto h = new TH1F(Form("%sclus_size_%i", get_histo_prefix().c_str(), region), Form("TPC cluster size region_%i", region), 30, 0, 30);
175  h->GetXaxis()->SetTitle("csize");
176  hm->registerHisto(h);
177  }
178 
179  {
180  // cluster size in phi
181  auto h = new TH1F(Form("%sclus_size_phi_%i", get_histo_prefix().c_str(), region), Form("TPC cluster size (#phi) region_%i", region), 10, 0, 10);
182  h->GetXaxis()->SetTitle("csize_{#phi}");
183  hm->registerHisto(h);
184  }
185 
186  {
187  // cluster size in z
188  auto h = new TH1F(Form("%sclus_size_z_%i", get_histo_prefix().c_str(), region), Form("TPC cluster size (z) region_%i", region), 12, 0, 12);
189  h->GetXaxis()->SetTitle("csize_{z}");
190  hm->registerHisto(h);
191  }
192  }
193 
195 }
196 
197 //_____________________________________________________________________
199 {
200  // load nodes
201  auto res = load_nodes(topNode);
202  if (res != Fun4AllReturnCodes::EVENT_OK) return res;
203 
204  if (m_svtxEvalStack)
205  m_svtxEvalStack->next_event(topNode);
206 
207  // run evaluation
210 }
211 
212 //________________________________________________________________________
214 {
215  return std::string("h_") + Name() + std::string("_");
216 }
217 
218 //________________________________________________________________________
220 {
221  m_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
222  if (!m_cluster_map)
223  {
224  std::cout << PHWHERE << " unable to find DST node TRKR_CLUSTER" << std::endl;
226  }
227 
228  m_tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
229  if (!m_tGeometry)
230  {
231  std::cout << PHWHERE << "No acts tracking geometry, exiting."
232  << std::endl;
234  }
235 
236  m_cluster_hit_map = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
237  if (!m_cluster_hit_map)
238  {
239  std::cout << PHWHERE << " unable to find DST node TRKR_CLUSTERHITASSOC" << std::endl;
241  }
242 
243  m_hit_truth_map = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
244  if (!m_hit_truth_map)
245  {
246  std::cout << PHWHERE << " unable to find DST node TRKR_HITTRUTHASSOC" << std::endl;
248  }
249 
250  m_g4hits_tpc = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_TPC");
251  if (!m_g4hits_tpc)
252  {
253  std::cout << PHWHERE << " unable to find DST node G4HIT_TPC" << std::endl;
255  }
256 
258 }
259 
260 //________________________________________________________________________
262 {
263  SvtxTruthEval* trutheval = m_svtxEvalStack->get_truth_eval();
264  assert(trutheval);
265  SvtxClusterEval* clustereval = m_svtxEvalStack->get_cluster_eval();
266  assert(clustereval);
267 
268  // histogram manager
270  assert(hm);
271 
272  // get histograms for cluster efficiency
273  TH1* h_eff0 = dynamic_cast<TH1*>(hm->getHisto(Form("%sefficiency_0", get_histo_prefix().c_str())));
274  assert(h_eff0);
275  TH1* h_eff1 = dynamic_cast<TH1*>(hm->getHisto(Form("%sefficiency_1", get_histo_prefix().c_str())));
276  assert(h_eff1);
277 
278  // get histograms for cluster parameters vs truth
279  struct HistogramList
280  {
281  TH1* drphi = nullptr;
282  TH1* rphi_error = nullptr;
283  TH1* phi_pulls = nullptr;
284 
285  TH1* dz = nullptr;
286  TH1* z_error = nullptr;
287  TH1* z_pulls = nullptr;
288 
289  TH1* csize = nullptr;
290  TH1* csize_phi = nullptr;
291  TH1* csize_z = nullptr;
292  };
293 
294  using HistogramMap = std::map<int, HistogramList>;
295  HistogramMap histograms;
296 
297  for (int region = 0; region < 3; ++region)
298  {
299  HistogramList h;
300  h.drphi = dynamic_cast<TH1*>(hm->getHisto(Form("%sdrphi_%i", get_histo_prefix().c_str(), region)));
301  h.rphi_error = dynamic_cast<TH1*>(hm->getHisto(Form("%srphi_error_%i", get_histo_prefix().c_str(), region)));
302  h.phi_pulls = dynamic_cast<TH1*>(hm->getHisto(Form("%sphi_pulls_%i", get_histo_prefix().c_str(), region)));
303 
304  h.dz = dynamic_cast<TH1*>(hm->getHisto(Form("%sdz_%i", get_histo_prefix().c_str(), region)));
305  h.z_error = dynamic_cast<TH1*>(hm->getHisto(Form("%sz_error_%i", get_histo_prefix().c_str(), region)));
306  h.z_pulls = dynamic_cast<TH1*>(hm->getHisto(Form("%sz_pulls_%i", get_histo_prefix().c_str(), region)));
307 
308  h.csize = dynamic_cast<TH1*>(hm->getHisto(Form("%sclus_size_%i", get_histo_prefix().c_str(), region)));
309  h.csize_phi = dynamic_cast<TH1*>(hm->getHisto(Form("%sclus_size_phi_%i", get_histo_prefix().c_str(), region)));
310  h.csize_z = dynamic_cast<TH1*>(hm->getHisto(Form("%sclus_size_z_%i", get_histo_prefix().c_str(), region)));
311 
312  histograms.insert(std::make_pair(region, h));
313  }
314 
315  // Get all truth clusters
316  //===============
317  if (Verbosity() > 0)
318  std::cout << PHWHERE << " get all truth clusters for primary particles " << std::endl;
319 
320  // PHG4TruthInfoContainer::ConstRange range = m_truthContainer->GetParticleRange(); // all truth cluters
321  PHG4TruthInfoContainer::ConstRange range = m_truthContainer->GetPrimaryParticleRange(); // only from primary particles
322 
323  for (PHG4TruthInfoContainer::ConstIterator iter = range.first;
324  iter != range.second;
325  ++iter)
326  {
327  PHG4Particle* g4particle = iter->second;
328 
329  float gtrackID = g4particle->get_track_id();
330  float gflavor = g4particle->get_pid();
331  float gembed = trutheval->get_embed(g4particle);
332  float gprimary = trutheval->is_primary(g4particle);
333 
334  if (Verbosity() > 0)
335  std::cout << PHWHERE << " PHG4Particle ID " << gtrackID << " gembed " << gembed << " gflavor " << gflavor << " gprimary " << gprimary << std::endl;
336 
337  // Get the truth clusters from this particle
338  const auto truth_clusters = trutheval->all_truth_clusters(g4particle);
339 
340  // get circle fit parameters first
343 
344  for (const auto& [gkey, gclus] : truth_clusters)
345  {
346  const auto layer = TrkrDefs::getLayer(gkey);
347  if (layer < 7) continue;
348 
349  float gx = gclus->getX();
350  float gy = gclus->getY();
351  float gz = gclus->getZ();
352 
353  xy_pts.emplace_back(gx, gy);
354  rz_pts.emplace_back(std::sqrt(gx * gx + gy * gy), gz);
355  }
356 
357  // fit a circle through x,y coordinates
358  const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(xy_pts);
359 
360  // skip chain entirely if fit fails
361  if (std::isnan(R)) continue;
362 
363  // process residuals and pulls
364  for (const auto& [gkey, gclus] : truth_clusters)
365  {
366  const auto layer = TrkrDefs::getLayer(gkey);
367  const auto detID = TrkrDefs::getTrkrId(gkey);
368  // if (detID != TrkrDefs::tpcId) continue;
369  if (layer < 7) continue;
370 
371  float gx = gclus->getX();
372  float gy = gclus->getY();
373  float gz = gclus->getZ();
374  float gedep = gclus->getError(0, 0);
375  float ng4hits = gclus->getAdc();
376 
377  const auto gr = QAG4Util::get_r(gclus->getX(), gclus->getY());
378  const auto gphi = std::atan2(gclus->getY(), gclus->getX());
379 
380  if (Verbosity() > 0)
381  {
382  std::cout << " gkey " << gkey << " detID " << detID << " tpcId " << TrkrDefs::tpcId << " layer " << layer << " truth clus " << gkey << " ng4hits " << ng4hits << " gr " << gr << " gx " << gx << " gy " << gy << " gz " << gz
383  << " gphi " << gphi << " gedep " << gedep << std::endl;
384  }
385 
386  // fill the truth cluster histo
387  h_eff0->Fill(layer);
388 
389  // find matching reco cluster histo
390  const auto [rkey, rclus] = clustereval->reco_cluster_from_truth_cluster(gkey, gclus);
391  if (rclus)
392  {
393  // fill the matched cluster histo
394  h_eff1->Fill(layer);
395 
396  const auto global = m_tGeometry->getGlobalPosition(rkey, rclus);
397 
398  // get relevant cluster information
399  const auto r_cluster = QAG4Util::get_r(global(0), global(1));
400  const auto z_cluster = global(2);
401  const auto phi_cluster = (float) std::atan2(global(1), global(0));
402 
403  double phi_error = rclus->getRPhiError() / r_cluster;
404  double z_error = rclus->getZError();
405 
406  const auto dphi = QAG4Util::delta_phi(phi_cluster, gphi);
407  const auto dz = z_cluster - gz;
408 
409  // get region from layer, fill histograms
410  const auto it = m_layer_region_map.find(layer);
411  int region = it->second;
412 
413  if (Verbosity() > 0)
414  {
415  std::cout << " Found match in layer " << layer << " region " << region << " for gtrackID " << gtrackID << std::endl;
416  std::cout << " x " << rclus->getX() << " y " << rclus->getY() << " z " << rclus->getZ() << std::endl;
417  std::cout << " gx " << gclus->getX() << " gy " << gclus->getY() << " gz " << gclus->getZ() << std::endl;
418  std::cout << " drphi " << r_cluster * dphi << " rphi_error " << r_cluster * phi_error << " dz " << dz << " z_error " << z_error << std::endl;
419  }
420 
421  const auto hiter = histograms.find(region);
422  if (hiter == histograms.end()) continue;
423 
424  // fill phi residuals, errors and pulls
425  auto fill = [](TH1* h, float value)
426  { if( h ) h->Fill( value ); };
427  fill(hiter->second.drphi, r_cluster * dphi);
428  fill(hiter->second.rphi_error, r_cluster * phi_error);
429  fill(hiter->second.phi_pulls, dphi / phi_error);
430 
431  // fill z residuals, errors and pulls
432  fill(hiter->second.dz, dz);
433  fill(hiter->second.z_error, z_error);
434  fill(hiter->second.z_pulls, dz / z_error);
435 
436  // cluster sizes
437  // get associated hits
438  const auto hit_range = m_cluster_hit_map->getHits(rkey);
439  fill(hiter->second.csize, std::distance(hit_range.first, hit_range.second));
440 
441  std::set<int> phibins;
442  std::set<int> zbins;
443  for (auto hit_iter = hit_range.first; hit_iter != hit_range.second; ++hit_iter)
444  {
445  const auto& hit_key = hit_iter->second;
446  phibins.insert(TpcDefs::getPad(hit_key));
447  zbins.insert(TpcDefs::getTBin(hit_key));
448  }
449 
450  fill(hiter->second.csize_phi, phibins.size());
451  fill(hiter->second.csize_z, zbins.size());
452  }
453  }
454  }
455 }
456 
457 //_____________________________________________________________________
459 {
460  // find hitset associated to cluster
461  G4HitSet out;
462  const auto hitset_key = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
463 
464  // loop over hits associated to clusters
465  const auto range = m_cluster_hit_map->getHits(cluster_key);
466  for (auto iter = range.first; iter != range.second; ++iter)
467  {
468  // hit key
469  const auto& hit_key = iter->second;
470 
471  // store hits to g4hit associations
472  TrkrHitTruthAssoc::MMap g4hit_map;
473  m_hit_truth_map->getG4Hits(hitset_key, hit_key, g4hit_map);
474 
475  // find corresponding g4 hist
476  for (auto truth_iter = g4hit_map.begin(); truth_iter != g4hit_map.end(); ++truth_iter)
477  {
478  // g4hit key
479  const auto g4hit_key = truth_iter->second.second;
480 
481  // g4 hit
482  PHG4Hit* g4hit = (TrkrDefs::getTrkrId(hitset_key) == TrkrDefs::tpcId) ? m_g4hits_tpc->findHit(g4hit_key) : nullptr;
483 
484  // insert in set
485  if (g4hit) out.insert(g4hit);
486  }
487  }
488 
489  return out;
490 }