FastJet  3.1.0-beta.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
JetDefinition.cc
1 //FJSTARTHEADER
2 // $Id: JetDefinition.cc 3492 2014-07-30 16:58:20Z soyez $
3 //
4 // Copyright (c) 2005-2014, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
5 //
6 //----------------------------------------------------------------------
7 // This file is part of FastJet.
8 //
9 // FastJet is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // The algorithms that underlie FastJet have required considerable
15 // development. They are described in the original FastJet paper,
16 // hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
17 // FastJet as part of work towards a scientific publication, please
18 // quote the version you use and include a citation to the manual and
19 // optionally also to hep-ph/0512210.
20 //
21 // FastJet is distributed in the hope that it will be useful,
22 // but WITHOUT ANY WARRANTY; without even the implied warranty of
23 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 // GNU General Public License for more details.
25 //
26 // You should have received a copy of the GNU General Public License
27 // along with FastJet. If not, see <http://www.gnu.org/licenses/>.
28 //----------------------------------------------------------------------
29 //FJENDHEADER
30 
31 #include "fastjet/JetDefinition.hh"
32 #include "fastjet/Error.hh"
33 #include "fastjet/CompositeJetStructure.hh"
34 #include<sstream>
35 
36 FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
37 
38 using namespace std;
39 
40 const double JetDefinition::max_allowable_R = 1000.0;
41 
42 //----------------------------------------------------------------------
43 // [NB: implementation was getting complex, so in 2.4-devel moved it
44 // from .hh to .cc]
45 JetDefinition::JetDefinition(JetAlgorithm jet_algorithm_in,
46  double R_in,
47  Strategy strategy_in,
48  RecombinationScheme recomb_scheme_in,
49  int nparameters) :
50  _jet_algorithm(jet_algorithm_in), _Rparam(R_in), _strategy(strategy_in) {
51 
52  // set R parameter or ensure its sensibleness, as appropriate
53  if (_jet_algorithm == ee_kt_algorithm) {
54  _Rparam = 4.0; // introduce a fictional R that ensures that
55  // our clustering sequence will not produce
56  // "beam" jets except when only a single particle remains.
57  // Any value > 2 would have done here
58  } else {
59  // We maintain some limit on R because particles with pt=0, m=0
60  // can have rapidities O(100000) and one doesn't want the
61  // clustering to start including them as if their rapidities were
62  // physical.
63  if (R_in > max_allowable_R) {
64  ostringstream oss;
65  oss << "Requested R = " << R_in << " for jet definition is larger than max_allowable_R = " << max_allowable_R;
66  throw Error(oss.str());
67  }
68  }
69 
70  // cross-check the number of parameters that were declared in setting up the
71  // algorithm (passed internally from the public constructors)
72  unsigned int nparameters_expected = n_parameters_for_algorithm(jet_algorithm_in);
73  if (nparameters != (int) nparameters_expected){
74  ostringstream oss;
75  oss << "The jet algorithm you requested ("
76  << jet_algorithm_in << ") should be constructed with " << nparameters_expected
77  << " parameter(s) but was called with " << nparameters << " parameter(s)\n";
78  throw Error(oss.str());
79  }
80 
81  // make sure the strategy requested is sensible
82  assert (_strategy != plugin_strategy);
83 
84  _plugin = NULL;
85  set_recombination_scheme(recomb_scheme_in);
86  set_extra_param(0.0); // make sure it's defined
87 }
88 
89 
90 //----------------------------------------------------------------------
91 // returns true if the jet definition involves an algorithm
92 // intended for use on a spherical geometry (e.g. e+e- algorithms,
93 // as opposed to most pp algorithms, which use a cylindrical,
94 // rapidity-phi geometry).
97  return plugin()->is_spherical();
98  } else {
99  return (jet_algorithm() == ee_kt_algorithm || // as of 2013-02-14, the two
100  jet_algorithm() == ee_genkt_algorithm // native spherical algorithms
101  );
102  }
103 }
104 
105 //----------------------------------------------------------------------
107  ostringstream name;
108 
109  name << description_no_recombiner();
110 
112  return name.str();
113  }
114 
116  name << " with ";
117  else
118  name << " and ";
119  name << recombiner()->description();
120 
121  return name.str();
122 }
123 
124 //----------------------------------------------------------------------
126 
127  ostringstream name;
128  if (jet_algorithm() == plugin_algorithm) {
129  return plugin()->description();
130  } else if (jet_algorithm() == undefined_jet_algorithm) {
131  return "uninitialised JetDefinition (jet_algorithm=undefined_jet_algorithm)" ;
132  }
133 
136  case 0: name << " (NB: no R)"; break;
137  case 1: name << " with R = " << R(); break; // the parameter is always R
138  case 2:
139  // the 1st parameter is always R
140  name << " with R = " << R();
141  // the 2nd depends on the algorithm
143  name << "and a special hack whereby particles with kt < "
144  << extra_param() << "are treated as passive ghosts";
145  } else {
146  name << ", p = " << extra_param();
147  }
148  };
149 
150  return name.str();
151 }
152 
153 //----------------------------------------------------------------------
155  ostringstream name;
156  switch (jet_alg){
157  case plugin_algorithm: return "plugin algorithm";
158  case kt_algorithm: return "Longitudinally invariant kt algorithm";
159  case cambridge_algorithm: return "Longitudinally invariant Cambridge/Aachen algorithm";
160  case antikt_algorithm: return "Longitudinally invariant anti-kt algorithm";
161  case genkt_algorithm: return "Longitudinally invariant generalised kt algorithm";
162  case cambridge_for_passive_algorithm: return "Longitudinally invariant Cambridge/Aachen algorithm";
163  case ee_kt_algorithm: return "e+e- kt (Durham) algorithm (NB: no R)";
164  case ee_genkt_algorithm: return "e+e- generalised kt algorithm";
165  case undefined_jet_algorithm: return "undefined jet algorithm";
166  default:
167  throw Error("JetDefinition::algorithm_description(): unrecognized jet_algorithm");
168  };
169 }
170 
171 //----------------------------------------------------------------------
173  switch (jet_alg) {
174  case ee_kt_algorithm: return 0;
175  case genkt_algorithm:
176  case ee_genkt_algorithm: return 2;
177  default: return 1;
178  };
179 }
180 
181 //----------------------------------------------------------------------
183  RecombinationScheme recomb_scheme) {
184  _default_recombiner = JetDefinition::DefaultRecombiner(recomb_scheme);
185 
186  // do not forget to delete the existing recombiner if needed
187  if (_shared_recombiner()) _shared_recombiner.reset();
188 
189  _recombiner = 0;
190 }
191 
192 void JetDefinition::set_recombiner(const JetDefinition &other_jet_def){
193  // make sure the "invariants" of the other jet def are sensible
194  assert(other_jet_def._recombiner ||
195  other_jet_def.recombination_scheme() != external_scheme);
196 
197  // first treat the situation where we're using the default recombiner
198  if (other_jet_def._recombiner == 0){
199  set_recombination_scheme(other_jet_def.recombination_scheme());
200  return;
201  }
202 
203  // in other cases, copy the pointer to the recombiner
204  _recombiner = other_jet_def._recombiner;
205  // set the default recombiner appropriately
206  _default_recombiner = DefaultRecombiner(external_scheme);
207  // and set the _shared_recombiner to the same state
208  // as in the other_jet_def, whatever that was
209  _shared_recombiner.reset(other_jet_def._shared_recombiner);
210 
211  // NB: it is tempting to go via set_recombiner and then to sort
212  // out the shared part, but this would be dangerous in the
213  // specific (rare?) case where other_jet_def is the same as this
214  // it deletes_recombiner_when_unused. In that case the shared
215  // pointer reset would delete the recombiner.
216 }
217 
218 
219 // returns true if the current jet definitions shares the same
220 // recombiner as teh one passed as an argument
222  // first make sure that they have the same recombination scheme
223  const RecombinationScheme & scheme = recombination_scheme();
224  if (other_jd.recombination_scheme() != scheme) return false;
225 
226  // if the scheme is "external", also check that they have the same
227  // recombiner
228  return (scheme != external_scheme)
229  || (recombiner() == other_jd.recombiner());
230 }
231 
232 /// causes the JetDefinition to handle the deletion of the
233 /// recombiner when it is no longer used
235  if (_recombiner == 0){
236  throw Error("tried to call JetDefinition::delete_recombiner_when_unused() for a JetDefinition without a user-defined recombination scheme");
237  } else if (_shared_recombiner.get()) {
238  throw Error("Error in JetDefinition::delete_recombiner_when_unused: the recombiner is already scheduled for deletion when unused (or was already set as shared)");
239  }
240 
241  _shared_recombiner.reset(_recombiner);
242 }
243 
244 /// allows to let the JetDefinition handle the deletion of the
245 /// plugin when it is no longer used
247  if (_plugin == 0){
248  throw Error("tried to call JetDefinition::delete_plugin_when_unused() for a JetDefinition without a plugin");
249  }
250 
251  _plugin_shared.reset(_plugin);
252 }
253 
254 
255 
257  switch(_recomb_scheme) {
258  case E_scheme:
259  return "E scheme recombination";
260  case pt_scheme:
261  return "pt scheme recombination";
262  case pt2_scheme:
263  return "pt2 scheme recombination";
264  case Et_scheme:
265  return "Et scheme recombination";
266  case Et2_scheme:
267  return "Et2 scheme recombination";
268  case BIpt_scheme:
269  return "boost-invariant pt scheme recombination";
270  case BIpt2_scheme:
271  return "boost-invariant pt2 scheme recombination";
272  default:
273  ostringstream err;
274  err << "DefaultRecombiner: unrecognized recombination scheme "
275  << _recomb_scheme;
276  throw Error(err.str());
277  }
278 }
279 
280 
282  const PseudoJet & pa, const PseudoJet & pb,
283  PseudoJet & pab) const {
284 
285  double weighta, weightb;
286 
287  switch(_recomb_scheme) {
288  case E_scheme:
289  // a call to reset turns out to be somewhat more efficient
290  // than a sum and assignment
291  //pab = pa + pb;
292  pab.reset(pa.px()+pb.px(),
293  pa.py()+pb.py(),
294  pa.pz()+pb.pz(),
295  pa.E ()+pb.E ());
296  return;
297  // all remaining schemes are massless recombinations and locally
298  // we just set weights, while the hard work is done below...
299  case pt_scheme:
300  case Et_scheme:
301  case BIpt_scheme:
302  weighta = pa.perp();
303  weightb = pb.perp();
304  break;
305  case pt2_scheme:
306  case Et2_scheme:
307  case BIpt2_scheme:
308  weighta = pa.perp2();
309  weightb = pb.perp2();
310  break;
311  default:
312  ostringstream err;
313  err << "DefaultRecombiner: unrecognized recombination scheme "
314  << _recomb_scheme;
315  throw Error(err.str());
316  }
317 
318  double perp_ab = pa.perp() + pb.perp();
319  if (perp_ab != 0.0) { // weights also non-zero...
320  double y_ab = (weighta * pa.rap() + weightb * pb.rap())/(weighta+weightb);
321 
322  // take care with periodicity in phi...
323  double phi_a = pa.phi(), phi_b = pb.phi();
324  if (phi_a - phi_b > pi) phi_b += twopi;
325  if (phi_a - phi_b < -pi) phi_b -= twopi;
326  double phi_ab = (weighta * phi_a + weightb * phi_b)/(weighta+weightb);
327 
328  // this is much more efficient...
329  pab.reset_PtYPhiM(perp_ab,y_ab,phi_ab);
330  // pab = PseudoJet(perp_ab*cos(phi_ab),
331  // perp_ab*sin(phi_ab),
332  // perp_ab*sinh(y_ab),
333  // perp_ab*cosh(y_ab));
334  } else { // weights are zero
335  //pab = PseudoJet(0.0,0.0,0.0,0.0);
336  pab.reset(0.0, 0.0, 0.0, 0.0);
337  }
338 }
339 
340 
342  switch(_recomb_scheme) {
343  case E_scheme:
344  case BIpt_scheme:
345  case BIpt2_scheme:
346  break;
347  case pt_scheme:
348  case pt2_scheme:
349  {
350  // these schemes (as in the ktjet implementation) need massless
351  // initial 4-vectors with essentially E=|p|.
352  double newE = sqrt(p.perp2()+p.pz()*p.pz());
353  p.reset_momentum(p.px(), p.py(), p.pz(), newE);
354  // FJ2.x version
355  // int user_index = p.user_index();
356  // p = PseudoJet(p.px(), p.py(), p.pz(), newE);
357  // p.set_user_index(user_index);
358  }
359  break;
360  case Et_scheme:
361  case Et2_scheme:
362  {
363  // these schemes (as in the ktjet implementation) need massless
364  // initial 4-vectors with essentially E=|p|.
365  double rescale = p.E()/sqrt(p.perp2()+p.pz()*p.pz());
366  p.reset_momentum(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
367  // FJ2.x version
368  // int user_index = p.user_index();
369  // p = PseudoJet(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
370  // p.set_user_index(user_index);
371  }
372  break;
373  default:
374  ostringstream err;
375  err << "DefaultRecombiner: unrecognized recombination scheme "
376  << _recomb_scheme;
377  throw Error(err.str());
378  }
379 }
380 
382  throw Error("set_ghost_separation_scale not supported");
383 }
384 
385 
386 
387 //-------------------------------------------------------------------------------
388 // helper functions to build a jet made of pieces
389 //
390 // This is the extended version with support for a user-defined
391 // recombination-scheme
392 // -------------------------------------------------------------------------------
393 
394 // build a "CompositeJet" from the vector of its pieces
395 //
396 // the user passes the reciombination scheme used to "sum" the pieces.
397 PseudoJet join(const vector<PseudoJet> & pieces, const JetDefinition::Recombiner & recombiner){
398  // compute the total momentum
399  //--------------------------------------------------
400  PseudoJet result; // automatically initialised to 0
401  if (pieces.size()>0){
402  result = pieces[0];
403  for (unsigned int i=1; i<pieces.size(); i++)
404  recombiner.plus_equal(result, pieces[i]);
405  }
406 
407  // attach a CompositeJetStructure to the result
408  //--------------------------------------------------
409  CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces, &recombiner);
410 
412 
413  return result;
414 }
415 
416 // build a "CompositeJet" from a single PseudoJet
417 PseudoJet join(const PseudoJet & j1,
418  const JetDefinition::Recombiner & recombiner){
419  return join(vector<PseudoJet>(1,j1), recombiner);
420 }
421 
422 // build a "CompositeJet" from two PseudoJet
423 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2,
424  const JetDefinition::Recombiner & recombiner){
425  vector<PseudoJet> pieces;
426  pieces.push_back(j1);
427  pieces.push_back(j2);
428  return join(pieces, recombiner);
429 }
430 
431 // build a "CompositeJet" from 3 PseudoJet
432 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3,
433  const JetDefinition::Recombiner & recombiner){
434  vector<PseudoJet> pieces;
435  pieces.push_back(j1);
436  pieces.push_back(j2);
437  pieces.push_back(j3);
438  return join(pieces, recombiner);
439 }
440 
441 // build a "CompositeJet" from 4 PseudoJet
442 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4,
443  const JetDefinition::Recombiner & recombiner){
444  vector<PseudoJet> pieces;
445  pieces.push_back(j1);
446  pieces.push_back(j2);
447  pieces.push_back(j3);
448  pieces.push_back(j4);
449  return join(pieces, recombiner);
450 }
451 
452 
453 
454 
455 FASTJET_END_NAMESPACE