EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
jetspectra.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file jetspectra.cxx
1 
2 
3 // eicsmear
9 #include "eicsmear/smear/Smear.h"
11 
12 // ROOT
13 #include <TDatabasePDG.h>
14 #include <TFile.h>
15 #include <TChain.h>
16 #include <TH1.h>
17 #include <TH2.h>
18 #include <TCanvas.h>
19 #include <TLegend.h>
20 #include <TText.h>
21 #include <TStyle.h>
22 
23 // C++
24 #include <vector>
25 #include <cmath>
26 
27 // fastjet
28 #include "fastjet/ClusterSequence.hh"
29 #include "fastjet/PseudoJet.hh"
30 
31 // Convenience
32 using namespace fastjet;
33 using namespace std;
34 
35 int main(int argc, char* argv[]){
36 
37  // Parse arguments
38  // ---------------
39  TString smearedname = "truth.smeared.root";
40  TString outfilebase = "simplejet";
41  int nevents = -1;
42 
43  vector<string> arguments(argv + 1, argv + argc);
44  bool argsokay=true;
45  for ( auto parg = arguments.begin() ; parg!=arguments.end() ; ++parg){
46  string arg=*parg;
47  if ( arg == "-o" ){
48  if (++parg == arguments.end() ){ argsokay=false; break; }
49  outfilebase=*parg;
50  } else if ( arg == "-s" ){
51  if (++parg ==arguments.end() ){ argsokay=false; break; }
52  smearedname=*parg;
53  } else if ( arg == "-N" ){
54  if (++parg==arguments.end() ){ argsokay=false; break; }
55  nevents=std::stoi(parg->data());
56  } else {
57  argsokay=false;
58  break;
59  }
60  }
61 
62  if ( !argsokay ) {
63  cerr << "usage: " << argv[0] << endl
64  << " [-s smearedname] (root file)" << endl
65  << " [-o OutFileBase] (extension will be added)" << endl
66  << " [-N Nevents] (<0 for all)" << endl
67  << endl;
68  return -1;
69  }
70 
71  // jet definition - could also be made parameters
72  // ----------------------------------------------
73  // Note: We're doing everything in the lab frame
74  // In a real analysis, you may want to boost to for example
75  // the Breit frame before and/or after jetfinding
76 
77  double R=0.5;
78  JetDefinition jet_def = JetDefinition(kt_algorithm, R);
79 
80  // Only do jetfinding in the region covered by tracking AND calorimetry
81  double ConstEtaMax = 3.5;
82  double ConstEtaMin = -ConstEtaMax;
83 
84  double JetEtaMax = ConstEtaMax - R;
85  double JetEtaMin = -JetEtaMax;
86  double jetPtCut=4.0;
87  auto select_jet_eta = fastjet::SelectorEtaRange ( JetEtaMin + R, JetEtaMax -R );
88  auto select_jet_pt = SelectorPtRange( jetPtCut, 1000 );
89  auto select_jet = select_jet_eta * select_jet_pt;
90 
91 
92  // Some cuts
93  // ---------
94  double xmin = 1e-5;
95  double xmax = 0.99;
96  double ymin = 0.01;
97  double ymax = 0.95;
98  double Q2min = 1;
99  double Q2max = 1000000;
100 
101  // Afterburners etc.
102  // -----------------
103  // Here, we demonstrate a toy pT acceptance / efficiency combination
104  // PURELY a toy, NO connection to reality
105  TF1* eff = new TF1("eff","(x>[2]) * [0]*TMath::Erf(x-[1])",0, 100);
106 
107  // mostly 99%, dropping toward small pT, sharp cutoff at 0.2
108  eff->SetParameters (0.99,-0.8, 0.2);
109 
110  // --------------
111  // Load the trees
112  // --------------
113  TChain* inTreeS = new TChain("Smeared");
114  inTreeS->Add(smearedname);
115 
116  // Setup Input Event Buffer
117  Smear::Event* inEventS(NULL);
118  inTreeS->SetBranchAddress("eventS",&inEventS);
119 
120  // Open histo root file and book histograms
121  // ----------------------------------------
122  TFile * outfile = new TFile ( outfilebase + ".root", "RECREATE");
123 
124  TH1::SetDefaultSumw2(true);
125  float ptmin = 0;
126  float ptmax = 20;
127  int ptbins = 40;
128  TH1D* smearedpt=new TH1D("smearedpt",";p_{T}^{smeared} [GeV/c];counts", ptbins, ptmin, ptmax );
129 
130  // -------------
131  // Analysis loop
132  // -------------
133  // Here we demonstrate using the smeared tree only.
134  // Comparisons or afterburners will need access to the truth level
135  // which can be accessed via the friend mechanism --> See the extended example.
136 
137  // Containers for jet constituents
138  // -------------------------------
139  vector<PseudoJet> SmearedConstituents;
140 
141  for(long iEvent=0; iEvent<inTreeS->GetEntries(); iEvent++){
142 
143  //Read next Event
144  if(inTreeS->GetEntry(iEvent) <=0) break;
145  if(iEvent%10000 == 0) cout << "Event " << iEvent << endl;
146 
147  // ---------------
148  // event-wise cuts
149  // ---------------
150  bool smearacceptev=true;
151 
152  // For the high-Q^2 example, the double angle method does pretty well
153  auto xS = inEventS->GetXDoubleAngle();
154  auto yS = inEventS->GetYDoubleAngle();
155  auto Q2S = inEventS->GetQ2DoubleAngle();
156  if ( xS < xmin || xS > xmax ) smearacceptev = false;
157  if ( yS < ymin || yS > ymax ) smearacceptev = false;
158  if ( Q2S < Q2min || Q2S > Q2max ) smearacceptev = false;
159 
160  if ( !smearacceptev ) continue;
161 
162  // -------------------
163  // Loop over Particles
164  // -------------------
165  SmearedConstituents.clear();
166 
167  for(int j=0; j<inEventS->GetNTracks(); j++){
168 
169  // first three particles are always beam and the virtual photon. skip.
170  if ( j<3) continue;
171 
172  const Smear::ParticleMCS* inParticleS = inEventS->GetTrack(j); // Smeared Particle
173  if ( !inParticleS ) continue; // lost this particle
174 
175  // Skip non-final particles.
176  if ( inParticleS->GetStatus() != 1 ) continue;
177 
178  // Now we need to work like an experimentalist.
179  // For most particles, only partial information is available,
180  // and we need to use something "reasonable" to supply the rest
181  // This is complicated by the fact that in the default handbook, we don't have
182  // PID information. We could pull that from the truth tree or turn on
183  // a perfect PID detector, but here we do it the hard way, case by case.
184  //
185  // Non-measured is indicated by a 0 in the field
186  // (this is unfortunate, will be fixed in the future)
187 
188  double epsilon = 1e-7;
189  double E = inParticleS->GetE();
190  double px = inParticleS->GetPx();
191  double py = inParticleS->GetPy();
192  double pz = inParticleS->GetPz();
193  double P = inParticleS->GetP(); // not used, but will help identification
194 
195  bool charged=( fabs(P)>epsilon );
196  // Here is the right place for the pT efficiency afterburner.
197  // If the particle is lost, we set P=0 and the logic below will treat it right
198  if ( charged ){
199  auto ran = gRandom->Uniform (0,1);
200  auto pt = std::sqrt ( px*px + py*py ); // GetPt() may be better or worse - for now the same
201  if ( ran > eff->Eval ( pt ) ) {
202  P=px=py=pz=0;
203  }
204  }
205 
206  // the following logic should be safe. a particle should be treated
207  // by exactly one of the of cases.
208 
209  // Nothing measured:
210  if ( fabs(P) <= epsilon && fabs(E) <= epsilon ){
211  // This can happen when e.g. a low-p particle gets smeared below 0
212  // Should be rare but should count as if inParticleS==0 in the first place
213  continue;
214  }
215 
216  // Both measured
217  if ( fabs(P) > epsilon && fabs(E) > epsilon ){
218  // seen by tracker and a calorimeter
219  // either charged hadron or electron
220 
221  // Here an analyzer would have to use their judgement and decide
222  // whether for some phase space discarding one measurement may make sense
223  // because the other one has a better resolution.
224  // In this example, we use both.
225 
226  // Note: In this case, P and E are smeared independently, so in general
227  // the mass-energy relation is not conserved. FastJet does not mind at all.
228 
229  /* nothing to do */
230  }
231 
232  // Tracker only
233  if ( fabs(P) > epsilon && fabs(E) <= epsilon ){
234  // particle seems to be seen only by a tracker (or the calorimeter smeared E to <=0)
235  // For the handbook, this can only happen for the second case, but in principle
236  // it indicates a region not covered by calorimetry.
237  // What we should do is "cheat" and find out from the truth level if this particle
238  // is hadronic or EM. Not a real cheat since we'd know in reality which detector is missing.
239  // However, to keep this example free of truth information, we instead
240  // assume it's hadronic (because an EIC detector w/o EMCal coverage is silly).
241  // Typical assumptions are m=0 or m=m_pi. The latter is more realistic, so do that
242 
243  double m = 0.13957; // GeV
244  E = std::sqrt(P*P + m*m);
245  }
246 
247  // Calo only
248  if ( fabs(P) <= epsilon && fabs(E) > epsilon ){
249  // - neutral species (neutron, photon) that's covered only by calorimetry
250  // - region that's only covered by calorimetry (_should_ imply EMCAL in a sane detector)
251  // - missed track (or failed match)
252  // This is the most difficult case and definitely more realistically treated by
253  // getting at least the genre from the truth tree.
254  // In the absence of such info here, we will reject all of these.
255  // That's quite reasonable for HCAL info anyway, since without additional geometry information,
256  // any HCAL hit without a pointing track is impossible to treat together with charged constituents.
257  // BUT note that any direct-photon analysis is killed. See the extended example instead
258 
259  continue;
260  }
261 
262  // Combine into a Pseudojet now. In general, a more featureful class may
263  // be preferable (such as TParticle or better) to track pid etc.
264  auto pj = PseudoJet (px, py, pz, E);
265 
266  // Particle cuts
267  // -------------
268  // The previous section made up for missing information.
269  // Here, we can add cuts that define or refine our analysis
270 
271  // constituent eta cut
272  if ( pj.eta() < ConstEtaMin || pj.eta() > ConstEtaMax) continue;
273 
274 
275  // --------------------
276  // Collect constituents
277  // --------------------
278  SmearedConstituents.push_back ( pj );
279  }
280  // --------------------
281  // Perform jet analysis
282  // --------------------
283  ClusterSequence smearcs(SmearedConstituents, jet_def);
284  vector<PseudoJet> smearjets = sorted_by_pt( select_jet(smearcs.inclusive_jets()) );
285 
286  // -------------------
287  // Extract observables
288  // -------------------
289  for ( auto j : smearjets ){
290  smearedpt->Fill ( j.pt() );
291  }
292 
293  }
294 
295  new TCanvas;
296  gPad->SetLogy();
297  smearedpt->Draw();
298  gPad->SaveAs( outfilebase + "_pt.png");
299 
300  outfile->Write();
301 
302  return 0;
303 }