Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FastJetAlgo.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FastJetAlgo.cc
1 #include "FastJetAlgo.h"
2 
3 #include "Jet.h"
4 #include "Jetv2.h"
5 #include "JetContainer.h"
6 
7 #include <phool/phool.h>
8 
9 #include <TSystem.h>
10 #include <TClonesArray.h>
11 
12 // fastjet includes
13 #include <fastjet/AreaDefinition.hh>
14 #include <fastjet/ClusterSequenceArea.hh>
15 #include <fastjet/Selector.hh>
16 #include <fastjet/tools/BackgroundEstimatorBase.hh>
17 #include <fastjet/tools/JetMedianBackgroundEstimator.hh>
18 #include <fastjet/tools/GridMedianBackgroundEstimator.hh>
19 #include <fastjet/ClusterSequence.hh>
20 #include <fastjet/FunctionOfPseudoJet.hh> // for FunctionOfPse...
21 #include <fastjet/JetDefinition.hh>
22 #include <fastjet/PseudoJet.hh>
23 #include <fastjet/contrib/RecursiveSymmetryCutBase.hh> // for RecursiveSymm...
24 #include <fastjet/contrib/SoftDrop.hh>
25 #include <fastjet/contrib/ConstituentSubtractor.hh>
26 
27 
28 // standard includes
29 #include <cmath> // for isfinite
30 #include <iostream>
31 #include <map> // for _Rb_tree_iterator
32 #include <memory> // for allocator_traits<>::value_type
33 #include <string> // for operator<<
34 #include <utility> // for pair
35 #include <vector>
36 #include <fstream>
37 #include <cassert>
38 
40  m_opt { options }
41 {
42  fastjet::ClusterSequence clusseq;
43  if (m_opt.verbosity > 0)
44  {
45  clusseq.print_banner();
46  }
47  else
48  {
49  std::ostringstream nullstream;
50  clusseq.set_fastjet_banner_stream(&nullstream);
51  clusseq.print_banner();
52  clusseq.set_fastjet_banner_stream(&std::cout);
53  }
54 }
55 
56 void FastJetAlgo::identify(std::ostream& os)
57 {
58  os << " FastJetAlgo: ";
59  if (m_opt.algo == Jet::ANTIKT)
60  {
61  os << "ANTIKT r=" << m_opt.jet_R;
62  }
63  else if (m_opt.algo == Jet::KT)
64  {
65  os << "KT r=" << m_opt.jet_R;
66  }
67  else if (m_opt.algo == Jet::CAMBRIDGE)
68  {
69  os << "CAMBRIDGE r=" << m_opt.jet_R;
70  }
71  os << std::endl;
72 
73  m_opt.print(os);
74 }
75 
76 fastjet::JetDefinition FastJetAlgo::get_fastjet_definition() {
77  if (m_opt.algo == Jet::ANTIKT)
78  {
79  return fastjet::JetDefinition(fastjet::antikt_algorithm, m_opt.jet_R, fastjet::E_scheme, fastjet::Best);
80  }
81  else if (m_opt.algo == Jet::KT)
82  {
83  return fastjet::JetDefinition(fastjet::kt_algorithm, m_opt.jet_R, fastjet::E_scheme, fastjet::Best);
84  }
85  else if (m_opt.algo == Jet::CAMBRIDGE)
86  {
88  }
89  else
90  {
91  std::cout << PHWHERE << std::endl;
92  std::cout << "Warning, no recognized jet clustering algorithm provided in FastJetAlgo" << std::endl
93  << "defaulting to antikt_algorithm" << std::endl;
94  //return a dummy definition
95  return fastjet::JetDefinition(fastjet::antikt_algorithm, m_opt.jet_R, fastjet::E_scheme, fastjet::Best);
96  }
97 }
98 
99 fastjet::Selector FastJetAlgo::get_selector() {
100  // only selectors available are jet_min_pt and jet_max_eta
104  } else if (m_opt.use_jet_max_eta) {
106  } else {
108  }
109 }
110 
111 std::vector<fastjet::PseudoJet> FastJetAlgo::cluster_jets(
112  std::vector<fastjet::PseudoJet>& pseudojets
113 ) {
114  auto jetdef = get_fastjet_definition();
115  m_cluseq = new fastjet::ClusterSequence( pseudojets, jetdef );
116 
117  if (m_opt.use_jet_selection) {
118  auto selector = get_selector();
119  return fastjet::sorted_by_pt(selector(m_cluseq->inclusive_jets()));
120  } else {
121  return fastjet::sorted_by_pt(m_cluseq->inclusive_jets());
122  }
123 }
124 
125 std::vector<fastjet::PseudoJet> FastJetAlgo::cluster_area_jets(
126  std::vector<fastjet::PseudoJet>& pseudojets
127 ) {
128 
129  auto jetdef = get_fastjet_definition();
130 
131  fastjet::AreaDefinition area_def (
132  fastjet::active_area_explicit_ghosts,
133  fastjet::GhostedAreaSpec(m_opt.ghost_max_rap, 1, m_opt.ghost_area)
134  );
135 
136  m_cluseqarea = new fastjet::ClusterSequenceArea( pseudojets, jetdef, area_def );
137 
138  fastjet::Selector selector = (
140  ? (!fastjet::SelectorIsPureGhost() && get_selector())
141  : !fastjet::SelectorIsPureGhost()
142  );
143 
144  return fastjet::sorted_by_pt(selector(m_cluseqarea->inclusive_jets()));
145 
146 }
147 
148 float FastJetAlgo::calc_rhomeddens(std::vector<fastjet::PseudoJet>& constituents) {
149  fastjet::AreaDefinition area_def (
150  fastjet::active_area_explicit_ghosts,
151  fastjet::GhostedAreaSpec(m_opt.ghost_max_rap, 1, m_opt.ghost_area)
152  );
153 
154  fastjet::Selector rho_select = (!fastjet::SelectorNHardest(m_opt.nhardestcut_jetmedbkgdens))
156 
157  fastjet::JetDefinition jet_def_bkgd(fastjet::kt_algorithm, m_opt.jet_R); // <--
158  fastjet::JetMedianBackgroundEstimator bge {rho_select, jet_def_bkgd, area_def};
159  bge.set_particles(constituents);
160  return bge.rho();
161 }
162 
163 std::vector<fastjet::PseudoJet>
165  std::vector<fastjet::PseudoJet> pseudojets;
166  for (unsigned int ipart = 0; ipart < particles.size(); ++ipart)
167  {
168  // fastjet performs strangely with exactly (px,py,pz,E) =
169  // (0,0,0,0) inputs, such as placeholder towers or those with
170  // zero'd out energy after CS. this catch also in FastJetAlgoSub
171  if (particles[ipart]->get_e() == 0.) continue;
172  if (!std::isfinite(particles[ipart]->get_px()) ||
173  !std::isfinite(particles[ipart]->get_py()) ||
174  !std::isfinite(particles[ipart]->get_pz()) ||
175  !std::isfinite(particles[ipart]->get_e()))
176  {
177  std::cout << PHWHERE << " invalid particle kinematics:"
178  << " px: " << particles[ipart]->get_px()
179  << " py: " << particles[ipart]->get_py()
180  << " pz: " << particles[ipart]->get_pz()
181  << " e: " << particles[ipart]->get_e() << std::endl;
182  gSystem->Exit(1);
183  }
184  fastjet::PseudoJet pseudojet(particles[ipart]->get_px(),
185  particles[ipart]->get_py(),
186  particles[ipart]->get_pz(),
187  particles[ipart]->get_e());
188  if (m_opt.use_constituent_min_pt && pseudojet.perp() < m_opt.constituent_min_pt) continue;
189  pseudojet.set_user_index(ipart);
190  pseudojets.push_back(pseudojet);
191  }
192  return pseudojets;
193 }
194 
196  m_first_cluster_call = false;
197  m_opt.initialize();
198 
199  if (jetcont == nullptr) return;
200 
201  if (m_opt.doSoftDrop) {
202  jetcont->add_property( {Jet::PROPERTY::prop_zg, Jet::PROPERTY::prop_Rg, Jet::PROPERTY::prop_mu} );
203  m_zg_index = jetcont->property_index(Jet::PROPERTY::prop_zg);
204  m_Rg_index = jetcont->property_index(Jet::PROPERTY::prop_Rg);
205  m_mu_index = jetcont->property_index(Jet::PROPERTY::prop_mu);
206  }
207 
208  if (m_opt.calc_area) {
209  jetcont->add_property(Jet::PROPERTY::prop_area);
210  m_area_index = jetcont->property_index(Jet::PROPERTY::prop_area);
211  }
212 
213  if (m_opt.cs_calc_constsub) {
214  cs_bge_rho = new fastjet::GridMedianBackgroundEstimator(m_opt.cs_max_eta, 0.5);
215  cs_subtractor = new fastjet::contrib::ConstituentSubtractor();
217  cs_subtractor->set_max_distance(m_opt.cs_max_dist); // free parameter for the maximal allowed distance between particle i and ghost k
218  cs_subtractor->set_alpha(m_opt.cs_alpha); // free parameter for the distance measure (the exponent of particle pt). The larger the parameter alpha, the more are favoured the lower pt particles in the subtraction process
219  cs_subtractor->set_ghost_area(m_opt.cs_ghost_area); // free parameter for the density of ghosts.
220  cs_subtractor->set_max_eta(m_opt.cs_max_eta); // parameter for the maximal eta cut
221  cs_subtractor->set_background_estimator(cs_bge_rho); // specify the background estimator to estimate rho.
222  if (m_opt.cs_max_pt > 0) {
223  cs_sel_max_pt = new fastjet::Selector(fastjet::SelectorPtMax(m_opt.cs_max_pt));
224  cs_subtractor->set_particle_selector(cs_sel_max_pt);
225  }
226  cs_subtractor->initialize();
227  if (m_opt.verbosity > 1) std::cout << cs_subtractor->description() << std::endl;
228  }
229 
230  jetcont->set_algo(m_opt.algo);
231  jetcont->set_jetpar_R(m_opt.jet_R);
232 }
233 
234 void FastJetAlgo::cluster_and_fill(std::vector<Jet*>& particles, JetContainer* jetcont)
235 {
237  // initalize the properties in JetContainer
238 
239  if (m_opt.verbosity > 1) std::cout << " Verbosity>1 FastJetAlgo::process_event -- entered" << std::endl;
240  if (m_opt.verbosity > 8) std::cout << " Verbosity>8 #input particles: " << particles.size() << std::endl;
241 
242  // translate input jets to input fastjets
243  auto pseudojets = jets_to_pseudojets(particles);
244 
245  // if using constituent subtraction, oberve maximum eta and subtract the constituents
246  if (m_opt.cs_calc_constsub) {
247  if (m_opt.verbosity > 100) {
248  std::cout << " Before Constituent Subtraction: " << std::endl;
249  int i = 0;
250  double sumpt = 0.;
251  for (auto c : pseudojets) {
252  sumpt += c.perp();
253  if (i<100) std::cout << Form(" jet[%2i] %8.4f sum %8.4f", i, c.perp(), sumpt) << std::endl;
254  i++;
255  }
256  auto _c = pseudojets.back();
257  std::cout << Form(" jet[%2i] %8.4f sum %8.4f", i++, _c.perp(), sumpt) << std::endl << std::endl;
258  }
259 
260  pseudojets = fastjet::SelectorAbsEtaMax(m_opt.cs_max_eta)(pseudojets);
261  cs_bge_rho->set_particles(pseudojets);
262  auto subtracted_pseudojets = cs_subtractor->subtract_event(pseudojets);
263  pseudojets = std::move(subtracted_pseudojets);
264 
265  if (m_opt.verbosity > 100) {
266  std::cout << " After Constituent Subtraction: " << std::endl;
267  int i = 0;
268  double sumpt = 0.;
269  for (auto c : pseudojets) {
270  sumpt += c.perp();
271  if (i<100) std::cout << Form(" jet[%2i] %8.4f sum %8.4f", i, c.perp(), sumpt) << std::endl;
272  i++;
273  }
274  auto _c = pseudojets.back();
275  std::cout << Form(" jet[%2i] %8.4f sum %8.4f", i++, _c.perp(), sumpt) << std::endl << std::endl;
276  }
277  }
278 
279  if (m_opt.calc_jetmedbkgdens) jetcont->set_rho_median(calc_rhomeddens(pseudojets));
280 
281  auto fastjets = (m_opt.calc_area ? cluster_area_jets(pseudojets) : cluster_jets(pseudojets));
282 
283  if (m_opt.verbosity > 8) std::cout << " Verbosity>8 fastjets: " << fastjets.size() << std::endl;
284  for (unsigned int ijet = 0; ijet < fastjets.size(); ++ijet)
285  {
286  auto* jet = jetcont->add_jet(); // put a new Jetv2 into the TClonesArray
287  jet->set_px(fastjets[ijet].px());
288  jet->set_py(fastjets[ijet].py());
289  jet->set_pz(fastjets[ijet].pz());
290  jet->set_e(fastjets[ijet].e());
291  jet->set_id(ijet);
292 
293  if (m_opt.calc_area) {
294  jet->set_property(m_area_index, fastjets[ijet].area());
295  }
296 
297  // if SoftDrop enabled, and jets have > 5 GeV (do not waste time
298  // on very low-pT jets), run SD and pack output into jet properties
299  if (m_opt.doSoftDrop && fastjets[ijet].perp() > 5)
300  {
301  fastjet::contrib::SoftDrop sd(m_opt.SD_beta, m_opt.SD_zcut);
302  if (m_opt.verbosity > 5)
303  {
304  std::cout << "FastJetAlgo::get_jets : created SoftDrop groomer configuration : "
305  << sd.description() << std::endl;
306  }
307 
308  fastjet::PseudoJet sd_jet = sd(fastjets[ijet]);
309 
310  if (m_opt.verbosity > 5)
311  {
312  std::cout << "original jet: pt / eta / phi / m = " << fastjets[ijet].perp()
313  << " / " << fastjets[ijet].eta() << " / " << fastjets[ijet].phi() << " / "
314  << fastjets[ijet].m() << std::endl;
315  std::cout << "SoftDropped jet: pt / eta / phi / m = " << sd_jet.perp() << " / "
316  << sd_jet.eta() << " / " << sd_jet.phi() << " / " << sd_jet.m() << std::endl;
317 
318  std::cout << " delta_R between subjets: " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().delta_R() << std::endl;
319  std::cout << " symmetry measure(z): " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().symmetry() << std::endl;
320  std::cout << " mass drop(mu): " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().mu() << std::endl;
321  }
322 
323  // attach SoftDrop quantities as jet properties
324  jet->set_property(m_zg_index, sd_jet.structure_of<fastjet::contrib::SoftDrop>().symmetry());
325  jet->set_property(m_Rg_index, sd_jet.structure_of<fastjet::contrib::SoftDrop>().delta_R() );
326  jet->set_property(m_mu_index, sd_jet.structure_of<fastjet::contrib::SoftDrop>().mu() );
327  }
328 
329  // Count clustered components. If desired, put original components into the output jet.
330  int n_clustered = 0;
331  std::vector<fastjet::PseudoJet> constituents = fastjets[ijet].constituents();
332  if (m_opt.calc_area) {
333  for (auto& comp : constituents) {
334  if (comp.is_pure_ghost()) continue;
335  ++n_clustered;
337  jet->insert_comp(particles[comp.user_index()]->get_comp_vec(), true);
338  }
339  } // end loop over all constituents
340  } else { // didn't calculate jet area
341  n_clustered += constituents.size();
343  for (auto& comp : constituents) {
344  jet->insert_comp(particles[comp.user_index()]->get_comp_vec(), true);
345  }
346  }
347  }
348  jet->set_comp_sort_flag(); // make surce comp knows it might not be sorted
349  }
350  if (m_opt.verbosity > 1) std::cout << "FastJetAlgo::process_event -- exited" << std::endl;
351  delete (m_opt.calc_area ? m_cluseqarea : m_cluseq); //if (m_cluseq) delete m_cluseq;
352 }
353 
354 
355 std::vector<Jet*> FastJetAlgo::get_jets(std::vector<Jet*> particles)
356 {
357  // translate to fastjet
358  auto pseudojets = jets_to_pseudojets(particles);
359  auto fastjets = cluster_jets(pseudojets);
360 
361  fastjet::contrib::SoftDrop sd(m_opt.SD_beta, m_opt.SD_zcut);
362  if (m_opt.verbosity > 5)
363  {
364  std::cout << "FastJetAlgo::get_jets : created SoftDrop groomer configuration : " << sd.description() << std::endl;
365  }
366 
367  // translate into jet output...
368  std::vector<Jet*> jets;
369  for (unsigned int ijet = 0; ijet < fastjets.size(); ++ijet)
370  {
371  Jet* jet = new Jetv2();
372  jet->set_px(fastjets[ijet].px());
373  jet->set_py(fastjets[ijet].py());
374  jet->set_pz(fastjets[ijet].pz());
375  jet->set_e(fastjets[ijet].e());
376  jet->set_id(ijet);
377 
378  // if SoftDrop enabled, and jets have > 5 GeV (do not waste time
379  // on very low-pT jets), run SD and pack output into jet properties
380  if (m_opt.doSoftDrop && fastjets[ijet].perp() > 5)
381  {
382  fastjet::PseudoJet sd_jet = sd(fastjets[ijet]);
383 
384  if (m_opt.verbosity > 5)
385  {
386  std::cout << "original jet: pt / eta / phi / m = " << fastjets[ijet].perp() << " / " << fastjets[ijet].eta() << " / " << fastjets[ijet].phi() << " / " << fastjets[ijet].m() << std::endl;
387  std::cout << "SoftDropped jet: pt / eta / phi / m = " << sd_jet.perp() << " / " << sd_jet.eta() << " / " << sd_jet.phi() << " / " << sd_jet.m() << std::endl;
388 
389  std::cout << " delta_R between subjets: " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().delta_R() << std::endl;
390  std::cout << " symmetry measure(z): " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().symmetry() << std::endl;
391  std::cout << " mass drop(mu): " << sd_jet.structure_of<fastjet::contrib::SoftDrop>().mu() << std::endl;
392  }
393 
394  // attach SoftDrop quantities as jet properties
395  jet->set_property(Jet::PROPERTY::prop_zg, sd_jet.structure_of<fastjet::contrib::SoftDrop>().symmetry());
396  jet->set_property(Jet::PROPERTY::prop_Rg, sd_jet.structure_of<fastjet::contrib::SoftDrop>().delta_R());
397  jet->set_property(Jet::PROPERTY::prop_mu, sd_jet.structure_of<fastjet::contrib::SoftDrop>().mu());
398  }
399 
400  // Count clustered components. If desired, put original components into the output jet.
401  int n_clustered = 0;
402  std::vector<fastjet::PseudoJet> constituents = fastjets[ijet].constituents();
403  if (m_opt.calc_area) {
404  for (auto& comp : constituents) {
405  if (comp.is_pure_ghost()) continue;
406  ++n_clustered;
408  jet->insert_comp(particles[comp.user_index()]->get_comp_vec(), true);
409  }
410  } // end loop over all constituents
411  } else { // didn't save jet area
412  n_clustered += constituents.size();
414  for (auto& comp : constituents) {
415  jet->insert_comp(particles[comp.user_index()]->get_comp_vec(), true);
416  }
417  }
418  }
419  /* jet->set_n_clustered(n_clustered); */
420  jet->set_comp_sort_flag(); // make surce comp knows it might not be sorted
421  // can alternatively just remove the `true` parameter
422  // from the insert_comp function calls above
423  jets.push_back(jet);
424  }
425 
426  /* std::sort(jets.begin(), jets.end(), [](Jet*a, Jet*b){ return a->get_et() > b->get_et();} ); */
427 
428  if (m_opt.verbosity > 1) std::cout << "FastJetAlgo::process_event -- exited" << std::endl;
429 
430  delete m_cluseq;
431 
432  return jets;
433 }
434