Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BBCStudy.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BBCStudy.cc
1 #include "BBCStudy.h"
2 
3 #include <phool/phool.h>
4 #include <phool/getClass.h>
7 #include <g4main/PHG4Particle.h>
8 #include <g4main/PHG4Hit.h>
9 #include <g4main/PHG4VtxPoint.h>
10 #include <fun4all/PHTFileServer.h>
11 #include <fun4all/Fun4AllServer.h>
13 #include <mbd/MbdOut.h>
14 #include <mbd/MbdPmtContainer.h>
15 #include <mbd/MbdPmtHit.h>
16 #include <mbd/MbdGeom.h>
17 #include <mbd/MbdDefs.h>
18 
19 #include <TFile.h>
20 #include <TTree.h>
21 #include <TH1F.h>
22 #include <TH2F.h>
23 #include <TF1.h>
24 #include <TCanvas.h>
25 #include <TString.h>
26 #include <TLorentzVector.h>
27 //#include <TMath.h>
28 #include <TDatabasePDG.h>
29 #include <TRandom3.h>
30 #include <TSystem.h>
31 
32 #include <iostream>
33 #include <cmath>
34 
35 using namespace std;
36 using namespace MbdDefs;
37 
38 //const Double_t C = 29.9792458; // cm/ns
39 
40 //____________________________________
41 BBCStudy::BBCStudy(const string &name) : SubsysReco(name),
42  _tree( 0 ),
43  f_evt( 0 ),
44  _pdg( 0 ),
45  _rndm( 0 ),
46  _tres( 0.05 ),
47  _savefname( "bbcstudy.root" ),
48  _savefile( 0 )
49 {
50 
51 }
52 
53 //___________________________________
55 {
56  cout << PHWHERE << " Saving to file " << _savefname << endl;
57  //PHTFileServer::get().open( _outfile, "RECREATE");
58  _savefile = new TFile( _savefname.c_str(), "RECREATE" );
59 
60  // Global BBC variables
61  _tree = new TTree("t","BBC Study");
62  _tree->Branch("evt",&f_evt,"evt/I");
63  _tree->Branch("bimp",&f_bimp,"bimp/F");
64  _tree->Branch("ncoll",&f_ncoll,"ncoll/I");
65  _tree->Branch("npart",&f_npart,"npart/I");
66  _tree->Branch("vx",&f_vx,"vx/F");
67  _tree->Branch("vy",&f_vy,"vy/F");
68  _tree->Branch("vz",&f_vz,"vz/F");
69  _tree->Branch("bns",&f_bbcn[0],"bns/S");
70  _tree->Branch("bnn",&f_bbcn[1],"bnn/S");
71  _tree->Branch("bqs",&f_bbcq[0],"bqs/F");
72  _tree->Branch("bqn",&f_bbcq[1],"bqn/F");
73  _tree->Branch("bts",&f_bbct[0],"bts/F");
74  _tree->Branch("btn",&f_bbct[1],"btn/F");
75  _tree->Branch("btes",&f_bbcte[0],"btes/F");
76  _tree->Branch("bten",&f_bbcte[1],"bten/F");
77  _tree->Branch("bz",&f_bbcz,"bz/F");
78  _tree->Branch("bt0",&f_bbct0,"bt0/F");
79 
80  _pdg = TDatabasePDG::Instance(); // database of PDG info on particles
81  _rndm = new TRandom3(0);
82 
83  TString name, title;
84  for (int ipmt=0; ipmt<MbdDefs::MBD_N_PMT; ipmt++)
85  {
86  name = "h_bbcq"; name += ipmt;
87  title = "bbc charge, ch "; title += ipmt;
88  h_bbcq[ipmt] = new TH1F(name,title,1200,0,120*90);
89 
90  /*
91  name = "h_tdiff_ch"; name += ipmt;
92  title = "tdiff, ch "; title += ipmt;
93  h_tdiff_ch[ipmt] = new TH1F(name,title,600,-3,3);
94  */
95  }
96 
97  for (int iarm=0; iarm<2; iarm++)
98  {
99  name = "h_bbcqtot"; name += iarm;
100  title = "bbc charge, arm "; title += iarm;
101  h_bbcqtot[iarm] = new TH1F(name,title,1200,0,120*60); // npe for 1 mip = 120, and up to 30 mips are possible
102 
103  //
104  name = "hevt_bbct"; name += iarm;
105  title = "bbc times, arm "; title += iarm;
106  hevt_bbct[iarm] = new TH1F(name,title,200,7.5,11.5);
107  hevt_bbct[iarm]->SetLineColor(4);
108  }
109  h2_bbcqtot = new TH2F("h2_bbcqtot","north BBCQ vs South BBCQ",300,0,120*900,300,0,120*900);
110 
111  h_ztrue = new TH1F("h_ztrue","true z-vtx",600,-30,30);
112  h_tdiff = new TH1F("h_tdiff","dt (measured - true_time)",6000,-3,3);
113  h2_tdiff_ch = new TH2F("h2_tdiff_ch","dt (measured - true time) vs ch",MBD_N_PMT,-0.5,MBD_N_PMT-0.5,200,-2,2);
114 
115  gaussian = new TF1("gaussian","gaus",0,20);
116  gaussian->FixParameter(2,0.05); // set sigma to 50 ps
117 
118  c_bbct = new TCanvas("c_bbct","BBC Times",1200,800);
119  c_bbct->Divide(1,2);
120 
121  return 0;
122 }
123 
124 //___________________________________
126 {
127  _bbcgeom = new MbdGeom();
128  GetNodes(topNode);
129 
130  return 0;
131 }
132 
133 //__________________________________
134 //Call user instructions for every event
136 {
137  nprocessed++;
138 
139  //GetNodes(topNode);
140 
142  if(f_evt%1==0) cout << PHWHERE << "Event " << f_evt << "\t" << ", nprocessed = " << nprocessed << endl;
143 
144  // Initialize Variables
145  f_bbcn[0] = 0;
146  f_bbcn[1] = 0;
147  f_bbcq[0] = 0.;
148  f_bbcq[1] = 0.;
149  f_bbct[0] = -9999.;
150  f_bbct[1] = -9999.;
151  f_bbcte[0] = -9999.;
152  f_bbcte[1] = -9999.;
153  f_bbcz = NAN;
154  f_bbct0 = NAN;
155  hevt_bbct[0]->Reset();
156  hevt_bbct[1]->Reset();
157 
158  // Get Truth Centrality Info
162 
163  // Get Primaries AND Secondaries
164  /*
165  PHG4TruthInfoContainer::ConstRange primary_range = _truth_container->GetPrimaryParticleRange();
166  int nprimaries = 0;
167 
168  for (auto part_iter = primary_range.first; part_iter != primary_range.second; ++part_iter)
169  {
170  PHG4Particle *particle = part_iter->second;
171  Float_t e = particle->get_e();
172  Float_t px = particle->get_px();
173  Float_t py = particle->get_py();
174  Float_t pz = particle->get_pz();
175  Float_t eta = 0.5*log((particle->get_e()+particle->get_pz())/ (particle->get_e()-particle->get_pz()));
176  Float_t pt = sqrt( px*px + py*py );
177  Float_t phi = atan2(particle->get_py(), particle->get_px());
178  Float_t pid = particle->get_pid();
179 
180  nprimaries++;
181  }
182  if ( f_evt < 20 )
183  {
184  cout << "Num primaries = " << nprimaries << "\t" << _truth_container->GetNumPrimaryVertexParticles() << endl;
185  }
186  */
187 
188 
189  // Get True Vertex
190  // NB: Currently PrimaryVertexIndex is always 1, need to figure out how to handle collision pile-up
192  if ( vtxp != 0 )
193  {
194  f_vx = vtxp->get_x();
195  f_vy = vtxp->get_y();
196  f_vz = vtxp->get_z();
197  f_vt = vtxp->get_t();
198 
199  if ( f_evt<20 )
200  {
201  cout << "VTXP " << "\t" << f_vx << "\t" << f_vy << "\t" << f_vz << "\t" << f_vt << endl;
202  }
203 
204  h_ztrue->Fill( f_vz );
205 
206  }
207 
208 
209  // Get All Vertices
211  unsigned int nvtx = 0;
212 
213  /*
214  for (auto vtx_iter = vtx_range.first; vtx_iter != vtx_range.second; ++vtx_iter)
215  {
216  PHG4VtxPoint *vtx = vtx_iter->second;
217  double vx = vtx->get_x();
218  double vy = vtx->get_y();
219  double vz = vtx->get_z();
220  double vt = vtx->get_t();
221 
222  // look at first few tracks
223  // What are negative track id's?
224  if ( abs(vtx->get_id()) < 8 && f_evt<20 )
225  {
226  cout << "vtx " << nvtx << "\t" << vtx->get_id() << "\t" << vt << "\t" << vx << "\t" << vy << "\t" << vz << endl;
227  }
228  nvtx++;
229  }
230  */
231 
232  if ( f_evt<20 )
233  {
234  cout << "Num Vertices = " << nvtx << "\t" << _truth_container->GetNumVertices() << endl;
235  //cout << "Primary Vertex = " << _truth_container->GetPrimaryVertexIndex() << endl;
236  }
237 
238  // Go through BBC hits to see what they look like
239 
240  float len[MbdDefs::MBD_N_PMT] = {0.};
241  float edep[MbdDefs::MBD_N_PMT] = {0.};
242  float first_time[MbdDefs::MBD_N_PMT]; // First hit time for each tube
243  std::fill_n(first_time, MbdDefs::MBD_N_PMT, 1e12);
244 
245 
246  unsigned int nhits = 0;
247 
248  TLorentzVector v4;
249  //TLorentzVector hitpos;
250 
251  PHG4HitContainer::ConstRange bbc_hit_range = _bbchits->getHits();
252  for (auto hit_iter = bbc_hit_range.first; hit_iter != bbc_hit_range.second; hit_iter++)
253  {
254  PHG4Hit *this_hit = hit_iter->second;
255 
256  unsigned int ipmt = this_hit->get_layer(); // pmt channel
257  int arm = ipmt/64;; // south=0, north=1
258 
259  int trkid = this_hit->get_trkid();
260  if ( trkid>0 && f_evt<20 ) cout << "TRKID " << trkid << endl;
261 
262  PHG4Particle *part = _truth_container->GetParticle( trkid );
263  v4.SetPxPyPzE( part->get_px(), part->get_py(), part->get_pz(), part->get_e() );
264 
265  int pid = part->get_pid();
266  TParticlePDG *partinfo = _pdg->GetParticle( pid );
267  Double_t charge = -9999.;
268  if ( partinfo )
269  {
270  charge = partinfo->Charge()/3; // PDG gives charge in 1/3 e
271  }
272  else if ( part->isIon() )
273  {
274  charge = part->get_IonCharge();
275  }
276 
277  Double_t beta = v4.Beta();
278 
279  // Determine time
280  //hitpos.SetXYZT( this_hit->get_x(), this_hit->get_y(), this_hit->get_z(), this_hit->get_t() );
281 
282  float xsign = 1.;
283  float zsign = -1.;
284  if ( arm == 1 )
285  {
286  xsign = -1.;
287  zsign = 1.;
288  }
289 
290  float tube_x = _bbcgeom->get_x(ipmt);
291  float tube_y = _bbcgeom->get_y(ipmt);
292  float tube_z = zsign*253.;
293  float flight_z = fabs(tube_z - vtxp->get_z());
294 
295  float flight_time = sqrt( tube_x*tube_x + tube_y*tube_y + flight_z*flight_z )/C;
296  float tdiff = this_hit->get_t(1) - ( vtxp->get_t() + flight_time );
297 
298  // get the first time
299  if ( this_hit->get_t(1) < first_time[ipmt] )
300  {
301  if ( fabs( this_hit->get_t(1) ) < 106.5 )
302  {
303  first_time[ipmt] = this_hit->get_t(1) - vtxp->get_t();
304  Float_t dt = static_cast<float>( _rndm->Gaus( 0, _tres ) ); // get fluctuation in time
305  first_time[ipmt] += dt;
306  }
307  else
308  {
309  cout << "BAD " << ipmt << "\t" << this_hit->get_t(1) << endl;
310  }
311  }
312 
313  if ( f_evt<10 )
314  {
315  cout << "hit " << ipmt << "\t" << trkid << "\t" << pid
316  //<< "\t" << v4.M()
317  << "\t" << beta
318  << "\t" << this_hit->get_path_length()
319  << "\t" << this_hit->get_edep()
320  //<< "\t" << v4.Eta()
321  //<< "\t" << v4.Pt()
322  //<< "\t" << v4.P()
323  << "\t" << this_hit->get_x(1)
324  << "\t" << this_hit->get_y(1)
325  << "\t" << this_hit->get_z(1)
326  << "\t" << this_hit->get_t(1)
327  << "\t" << tdiff
328  << endl;
329 
330  //cout << "WWW " << first_time[ipmt] << endl;
331  }
332 
333  edep[ipmt] += this_hit->get_edep();
334 
335  // get summed path length for particles that can create CKOV light
336  // n.p.e. is determined from path length
337  if ( beta > MbdDefs::v_ckov && charge != 0. )
338  {
339  len[ipmt] += this_hit->get_path_length();
340 
341  if ( trkid>0 )
342  {
343  h_tdiff->Fill( tdiff );
344  h2_tdiff_ch->Fill( ipmt, tdiff );
345  }
346 
347  _pids[pid] += 1;
348  }
349 
350  // sanity check
351  if ( part->get_track_id() != trkid )
352  {
353  cout << "ERROR " << endl;
354  }
355 
356  nhits++;
357  }
358 
359  if ( f_evt<20 )
360  {
361  cout << "******** " << f_evt << " **************" << endl;
362  }
363 
364 
365  // process the data from each channel
366  for (int iarm=0; iarm<2; iarm++)
367  {
368  f_bbct[iarm] = 0.;
369  }
370 
371  vector<float> hit_times[2]; // times of the hits in each [arm]
372 
373  for (int ipmt=0; ipmt<MbdDefs::MBD_N_PMT; ipmt++)
374  {
375  //cout << "ZZZ " << ipmt << "\t" << first_time[ipmt] << "\t" << edep[ipmt] << "\t" << len[ipmt] << endl;
376 
377  int arm = _bbcgeom->get_arm(ipmt); // ch 0-63 = south, ch 64-127 = north
378 
379  // Fill charge and time info
380  if ( len[ipmt]>0. )
381  {
382  if ( f_evt<20 )
383  {
384  cout << "ipmt " << ipmt << "\t" << len[ipmt] << "\t" << edep[ipmt] << endl;
385  }
386 
387  // Get charge in BBC tube
388  float npe = len[ipmt]*(120/3.0); // we get 120 p.e. per 3 cm
389  float dnpe = static_cast<float>( _rndm->Gaus( 0, sqrt(npe) ) ); // get fluctuation in npe
390 
391  npe += dnpe; // apply the fluctuations in npe
392 
393  f_bbcq[arm] += npe;
394 
395  h_bbcq[ipmt]->Fill( npe );
396  h_bbcqtot[arm]->Fill( npe );
397 
398  // Now time
399  if ( first_time[ipmt] < 9999. )
400  {
401  // Fill evt histogram
402  hevt_bbct[arm]->Fill( first_time[ipmt] );
403  hit_times[arm].push_back( first_time[ipmt] );
404 
405  f_bbct[arm] += first_time[ipmt];
406  //cout << "XXX " << ipmt << "\t" << f_bbct[arm] << "\t" << first_time[ipmt] << endl;
407 
408  }
409  else // should never happen
410  {
411  cout << "ERROR, have hit but no time" << endl;
412  }
413 
414  // threshold should be > 0.
415  ++f_bbcn[arm];
416  }
417  }
418 
419  // Get best t
420  if ( f_bbcn[0]>0 && f_bbcn[1]> 0 )
421  {
422  for (int iarm=0; iarm<2; iarm++)
423  {
424  c_bbct->cd(iarm+1);
425 
426  std::sort( hit_times[iarm].begin(), hit_times[iarm].end() );
427  float earliest = hit_times[iarm][0];
428 
429  gaussian->SetParameter(0,5);
430  gaussian->SetParameter(1, earliest);
431  gaussian->SetRange(6, earliest+ 5*0.05);
432  //gaussian->SetParameter(1,hevt_bbct[iarm]->GetMean());
433  //gaussian->SetRange(6,hevt_bbct[iarm]->GetMean()+0.125);
434 
435  hevt_bbct[iarm]->Fit(gaussian,"BLR");
436  hevt_bbct[iarm]->Draw();
437 
438  if ( f_bbcn[iarm] > 0 )
439  {
440  //f_bbct[iarm] = f_bbct[iarm] / f_bbcn[iarm];
441  f_bbct[iarm] = gaussian->GetParameter(1);
442  f_bbcte[iarm] = earliest;
443  }
444  }
445 
446  // Now calculate zvtx, t0 from best times
447  f_bbcz = (f_bbct[0] - f_bbct[1])*C/2.0;
448  f_bbct0 = (f_bbct[0] + f_bbct[1])/2.0;
449 
450  }
451 
452  c_bbct->Modified();
453  c_bbct->Update();
454 
455  if ( fabs(f_bbcz-f_vz)>5.0 && f_bbcn[0]>1 && f_bbcn[1]>1 )
456  {
457  string response;
458  cout << "Event " << f_evt << " ? ";
459  //cin >> response;
460  //if ( response[0] == 'q' )
461  TString name = "evt_"; name += f_evt; name += ".png";
462  c_bbct->SaveAs( name );
463  }
464 
465  h2_bbcqtot->Fill( f_bbcq[0], f_bbcq[1] );
466 
467  _tree->Fill();
468 
469  //CheckDST(topNode);
470 
471  return 0;
472 }
473 
474 //___________________________________
476 {
477  // Get the DST objects
478 
479  // Truth container
480  _truth_container = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
481  if(!_truth_container && f_evt<10) cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << endl;
482 
483  // BBC hit container
484  _bbchits = findNode::getClass<PHG4HitContainer> (topNode, "G4HIT_BBC");
485  if(!_bbchits && f_evt<10) cout << PHWHERE << " G4HIT_BBC node not found on node tree" << endl;
486 
487  _evtheader = findNode::getClass<EventHeaderv1>(topNode, "EventHeader");
488  if (!_evtheader && f_evt<10) cout << PHWHERE << " G4HIT_BBC node not found on node tree" << endl;
489 
490 }
491 
492 //______________________________________
494 {
495  _savefile->cd();
496  _savefile->Write();
497  _savefile->Close();
498 
499  // print out list of pids that hit BBC
500  cout << "PIDs of Particles that hit BBC" << endl;
501  unsigned int ipid = 0;
502  double npart = 0;
503  for (auto & pid : _pids)
504  {
505  npart += pid.second;
506  }
507  for (auto & pid : _pids)
508  {
509  cout << pid.first << "\t" << pid.second << "\t" << pid.second/npart << endl;
510  ipid++;
511  }
512  cout << "There were " << ipid << " different particle types" << endl;
513 
514  return 0;
515 }
516 
518 {
519  // BbcOut
520  _bbcout = findNode::getClass<MbdOut>(topNode, "MbdOut");
521  if(!_bbcout && f_evt<4) cout << PHWHERE << " MbdOut node not found on node tree" << endl;
522 
523  // BbcOut
524  _bbcpmts = findNode::getClass<MbdPmtContainer>(topNode, "MbdPmtContainer");
525  if(!_bbcpmts && f_evt<4) cout << PHWHERE << " MbdPmtContainer node not found on node tree" << endl;
526 
527  Float_t bbcz = _bbcout->get_zvtx();
528  if ( f_bbcz != bbcz )
529  {
530  cout << "ERROR, f_bbcz != bbcz, " << f_bbcz << "\t" << bbcz << endl;
531  }
532 
533  for (int iarm=0; iarm<2; iarm++)
534  {
535  if ( f_bbcq[iarm] != _bbcout->get_q(iarm) )
536  {
537  cout << "ERROR, f_bbcq != bbcq, arm " << iarm << "\t" << f_bbcq[iarm] << "\t" << _bbcout->get_q(iarm) << endl;
538  }
539  }
540 
541 }