StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
FJcore.cc
1 // fjcore -- extracted from FastJet v3.2.1 (http://fastjet.fr)
2 //
3 // fjcore constitutes a digest of the main FastJet functionality.
4 // The files fjcore.hh and fjcore.cc are meant to provide easy access to these
5 // core functions, in the form of single files and without the need of a full
6 // FastJet installation:
7 //
8 // g++ main.cc fjcore.cc
9 //
10 // with main.cc including fjcore.hh.
11 //
12 // A fortran interface, fjcorefortran.cc, is also provided. See the example
13 // and the Makefile for instructions.
14 //
15 // The results are expected to be identical to those obtained by linking to
16 // the full FastJet distribution.
17 //
18 // NOTE THAT, IN ORDER TO MAKE IT POSSIBLE FOR FJCORE AND THE FULL FASTJET
19 // TO COEXIST, THE FORMER USES THE "fjcore" NAMESPACE INSTEAD OF "fastjet".
20 //
21 // In particular, fjcore provides:
22 //
23 // - access to all native pp and ee algorithms, kt, anti-kt, C/A.
24 // For C/A, the NlnN method is available, while anti-kt and kt
25 // are limited to the N^2 one (still the fastest for N < 100k particles)
26 // - access to selectors, for implementing cuts and selections
27 // - access to all functionalities related to pseudojets (e.g. a jet's
28 // structure or user-defined information)
29 //
30 // Instead, it does NOT provide:
31 //
32 // - jet areas functionality
33 // - background estimation
34 // - access to other algorithms via plugins
35 // - interface to CGAL
36 // - fastjet tools, e.g. filters, taggers
37 //
38 // If these functionalities are needed, the full FastJet installation must be
39 // used. The code will be fully compatible, with the sole replacement of the
40 // header files and of the fjcore namespace with the fastjet one.
41 //
42 // fjcore.hh and fjcore.cc are not meant to be human-readable.
43 // For documentation, see the full FastJet manual and doxygen at http://fastjet.fr
44 //
45 // Like FastJet, fjcore is released under the terms of the GNU General Public
46 // License version 2 (GPLv2). If you use this code as part of work towards a
47 // scientific publication, whether directly or contained within another program
48 // (e.g. Delphes, MadGraph, SpartyJet, Rivet, LHC collaboration software frameworks,
49 // etc.), you should include a citation to
50 //
51 // EPJC72(2012)1896 [arXiv:1111.6097] (FastJet User Manual)
52 // and, optionally, Phys.Lett.B641 (2006) 57 [arXiv:hep-ph/0512210]
53 //
54 // Copyright (c) 2005-2016, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
55 //
56 //----------------------------------------------------------------------
57 // This file is part of FastJet.
58 //
59 // FastJet is free software; you can redistribute it and/or modify
60 // it under the terms of the GNU General Public License as published by
61 // the Free Software Foundation; either version 2 of the License, or
62 // (at your option) any later version.
63 //
64 // The algorithms that underlie FastJet have required considerable
65 // development and are described in hep-ph/0512210. If you use
66 // FastJet as part of work towards a scientific publication, please
67 // include a citation to the FastJet paper.
68 //
69 // FastJet is distributed in the hope that it will be useful,
70 // but WITHOUT ANY WARRANTY; without even the implied warranty of
71 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72 // GNU General Public License for more details.
73 //
74 // You should have received a copy of the GNU General Public License
75 // along with FastJet. If not, see <http://www.gnu.org/licenses/>.
76 //----------------------------------------------------------------------
77 //
78 //#include "fjcore.hh"
79 // For inclusion in Pythia8 line above is replaced by line below.
80 #include "Pythia8/FJcore.h"
81 #ifndef __FJCORE_VERSION_HH__
82 #define __FJCORE_VERSION_HH__
83 #include<string>
84 FJCORE_BEGIN_NAMESPACE
85 const char* fastjet_version = FJCORE_PACKAGE_VERSION;
86 FJCORE_END_NAMESPACE
87 #endif // __FJCORE_VERSION_HH__
88 #ifndef __FJCORE_CLUSTERQUENCE_N2_ICC__
89 #define __FJCORE_CLUSTERQUENCE_N2_ICC__
90 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
91 template<class BJ> void ClusterSequence::_simple_N2_cluster() {
92  int n = _jets.size();
93  BJ * briefjets = new BJ[n];
94  BJ * jetA = briefjets, * jetB;
95  for (int i = 0; i< n; i++) {
96  _bj_set_jetinfo(jetA, i);
97  jetA++; // move on to next entry of briefjets
98  }
99  BJ * tail = jetA; // a semaphore for the end of briefjets
100  BJ * head = briefjets; // a nicer way of naming start
101  for (jetA = head + 1; jetA != tail; jetA++) {
102  _bj_set_NN_crosscheck(jetA, head, jetA);
103  }
104  double * diJ = new double[n];
105  jetA = head;
106  for (int i = 0; i < n; i++) {
107  diJ[i] = _bj_diJ(jetA);
108  jetA++; // have jetA follow i
109  }
110  int history_location = n-1;
111  while (tail != head) {
112  double diJ_min = diJ[0];
113  int diJ_min_jet = 0;
114  for (int i = 1; i < n; i++) {
115  if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min = diJ[i];}
116  }
117  history_location++;
118  jetA = & briefjets[diJ_min_jet];
119  jetB = static_cast<BJ *>(jetA->NN);
120  diJ_min *= _invR2;
121  if (jetB != NULL) {
122  if (jetA < jetB) {std::swap(jetA,jetB);}
123  int nn; // new jet index
124  _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
125  _bj_set_jetinfo(jetB, nn);
126  } else {
127  _do_iB_recombination_step(jetA->_jets_index, diJ_min);
128  }
129  tail--; n--;
130  *jetA = *tail;
131  diJ[jetA - head] = diJ[tail-head];
132  for (BJ * jetI = head; jetI != tail; jetI++) {
133  if (jetI->NN == jetA || jetI->NN == jetB) {
134  _bj_set_NN_nocross(jetI, head, tail);
135  diJ[jetI-head] = _bj_diJ(jetI); // update diJ
136  }
137  if (jetB != NULL) {
138  double dist = _bj_dist(jetI,jetB);
139  if (dist < jetI->NN_dist) {
140  if (jetI != jetB) {
141  jetI->NN_dist = dist;
142  jetI->NN = jetB;
143  diJ[jetI-head] = _bj_diJ(jetI); // update diJ...
144  }
145  }
146  if (dist < jetB->NN_dist) {
147  if (jetI != jetB) {
148  jetB->NN_dist = dist;
149  jetB->NN = jetI;}
150  }
151  }
152  if (jetI->NN == tail) {jetI->NN = jetA;}
153  }
154  if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
155  }
156  delete[] diJ;
157  delete[] briefjets;
158 }
159 FJCORE_END_NAMESPACE
160 #endif // __FJCORE_CLUSTERQUENCE_N2_ICC__
161 #ifndef __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
162 #define __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
163 #include<vector>
164 #include<string>
165 #include<iostream>
166 #include<sstream>
167 #include<cassert>
168 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
169 class EtaPhi {
170 public:
171  double first, second;
172  EtaPhi() {}
173  EtaPhi(double a, double b) {first = a; second = b;}
174  void sanitize() {
175  if (second < 0) second += twopi;
176  if (second >= twopi) second -= twopi;
177  }
178 };
179 class DnnError : public Error {
180 public:
181  DnnError(const std::string & message_in) : Error(message_in) {}
182 };
184 public:
185  virtual int NearestNeighbourIndex(const int ii) const = 0;
186  virtual double NearestNeighbourDistance(const int ii) const = 0;
187  virtual bool Valid(const int index) const = 0;
188  virtual void RemoveAndAddPoints(const std::vector<int> & indices_to_remove,
189  const std::vector<EtaPhi> & points_to_add,
190  std::vector<int> & indices_added,
191  std::vector<int> & indices_of_updated_neighbours) = 0;
192  inline void RemovePoint (const int index,
193  std::vector<int> & indices_of_updated_neighbours) {
194  std::vector<int> indices_added;
195  std::vector<EtaPhi> points_to_add;
196  std::vector<int> indices_to_remove(1);
197  indices_to_remove[0] = index;
198  RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
199  indices_of_updated_neighbours
200  );};
201  inline void RemoveCombinedAddCombination(
202  const int index1, const int index2,
203  const EtaPhi & newpoint,
204  int & index3,
205  std::vector<int> & indices_of_updated_neighbours) {
206  std::vector<int> indices_added(1);
207  std::vector<EtaPhi> points_to_add(1);
208  std::vector<int> indices_to_remove(2);
209  indices_to_remove[0] = index1;
210  indices_to_remove[1] = index2;
211  points_to_add[0] = newpoint;
212  RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
213  indices_of_updated_neighbours
214  );
215  index3 = indices_added[0];
216  };
217  virtual ~DynamicNearestNeighbours () {}
218 };
219 FJCORE_END_NAMESPACE
220 #endif // __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
221 #ifndef __FJCORE_SEARCHTREE_HH__
222 #define __FJCORE_SEARCHTREE_HH__
223 #include<vector>
224 #include<cassert>
225 #include<cstddef>
226 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
227 template<class T> class SearchTree {
228 public:
229  class Node;
230  class circulator;
231  class const_circulator;
232  SearchTree(const std::vector<T> & init);
233  SearchTree(const std::vector<T> & init, unsigned int max_size);
234  void remove(unsigned node_index);
235  void remove(typename SearchTree::Node * node);
236  void remove(typename SearchTree::circulator & circ);
237  circulator insert(const T & value);
238  const Node & operator[](int i) const {return _nodes[i];};
239  unsigned int size() const {return _nodes.size() - _available_nodes.size();}
240  void verify_structure();
241  void verify_structure_linear() const;
242  void verify_structure_recursive(const Node * , const Node * , const Node * ) const;
243  void print_elements();
244 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
245  inline unsigned int max_depth() const {return _max_depth;};
246 #else
247  inline unsigned int max_depth() const {return 0;};
248 #endif
249  int loc(const Node * node) const ;
250  Node * _find_predecessor(const Node *);
251  Node * _find_successor(const Node *);
252  const Node & operator[](unsigned int i) const {return _nodes[i];};
253  const_circulator somewhere() const;
254  circulator somewhere();
255 private:
256  void _initialize(const std::vector<T> & init);
257  std::vector<Node> _nodes;
258  std::vector<Node *> _available_nodes;
259  Node * _top_node;
260  unsigned int _n_removes;
261  void _do_initial_connections(unsigned int this_one, unsigned int scale,
262  unsigned int left_edge, unsigned int right_edge,
263  unsigned int depth);
264 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
265  unsigned int _max_depth;
266 #endif
267 };
268 template<class T> class SearchTree<T>::Node{
269 public:
270  Node() {};
271  bool treelinks_null() const {
272  return ((parent==0) && (left==0) && (right==0));};
273  inline void nullify_treelinks() {
274  parent = NULL;
275  left = NULL;
276  right = NULL;
277  };
278  void reset_parents_link_to_me(Node * XX);
279  T value;
280  Node * left;
281  Node * right;
282  Node * parent;
283  Node * successor;
284  Node * predecessor;
285 };
286 template<class T> void SearchTree<T>::Node::reset_parents_link_to_me(typename SearchTree<T>::Node * XX) {
287  if (parent == NULL) {return;}
288  if (parent->right == this) {parent->right = XX;}
289  else {parent->left = XX;}
290 }
291 template<class T> class SearchTree<T>::circulator{
292 public:
293  friend class SearchTree<T>::const_circulator;
294  friend class SearchTree<T>;
295  circulator() : _node(NULL) {}
296  circulator(Node * node) : _node(node) {}
297  const T * operator->() const {return &(_node->value);}
298  T * operator->() {return &(_node->value);}
299  const T & operator*() const {return _node->value;}
300  T & operator*() {return _node->value;}
301  circulator & operator++() {
302  _node = _node->successor;
303  return *this;}
304  circulator operator++(int) {
305  circulator tmp = *this;
306  _node = _node->successor;
307  return tmp;}
308  circulator & operator--() {
309  _node = _node->predecessor;
310  return *this;}
311  circulator operator--(int) {
312  circulator tmp = *this;
313  _node = _node->predecessor;
314  return tmp;}
315  circulator next() const {
316  return circulator(_node->successor);}
317  circulator previous() const {
318  return circulator(_node->predecessor);}
319  bool operator!=(const circulator & other) const {return other._node != _node;}
320  bool operator==(const circulator & other) const {return other._node == _node;}
321 private:
322  Node * _node;
323 };
324 template<class T> class SearchTree<T>::const_circulator{
325 public:
326  const_circulator() : _node(NULL) {}
327  const_circulator(const Node * node) : _node(node) {}
328  const_circulator(const circulator & circ) :_node(circ._node) {}
329  const T * operator->() {return &(_node->value);}
330  const T & operator*() const {return _node->value;}
331  const_circulator & operator++() {
332  _node = _node->successor;
333  return *this;}
334  const_circulator operator++(int) {
335  const_circulator tmp = *this;
336  _node = _node->successor;
337  return tmp;}
338  const_circulator & operator--() {
339  _node = _node->predecessor;
340  return *this;}
341  const_circulator operator--(int) {
342  const_circulator tmp = *this;
343  _node = _node->predecessor;
344  return tmp;}
345  const_circulator next() const {
346  return const_circulator(_node->successor);}
347  const_circulator previous() const {
348  return const_circulator(_node->predecessor);}
349  bool operator!=(const const_circulator & other) const {return other._node != _node;}
350  bool operator==(const const_circulator & other) const {return other._node == _node;}
351 private:
352  const Node * _node;
353 };
354 template<class T> SearchTree<T>::SearchTree(const std::vector<T> & init,
355  unsigned int max_size) :
356  _nodes(max_size) {
357  _available_nodes.reserve(max_size);
358  _available_nodes.resize(max_size - init.size());
359  for (unsigned int i = init.size(); i < max_size; i++) {
360  _available_nodes[i-init.size()] = &(_nodes[i]);
361  }
362  _initialize(init);
363 }
364 template<class T> SearchTree<T>::SearchTree(const std::vector<T> & init) :
365  _nodes(init.size()), _available_nodes(0) {
366  _available_nodes.reserve(init.size());
367  _initialize(init);
368 }
369 template<class T> void SearchTree<T>::_initialize(const std::vector<T> & init) {
370  _n_removes = 0;
371  unsigned n = init.size();
372  assert(n>=1);
373 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
374  _max_depth = 0;
375 #endif
376  for (unsigned int i = 1; i<n; i++) {
377  assert(!(init[i] < init[i-1]));
378  }
379  for(unsigned int i = 0; i < n; i++) {
380  _nodes[i].value = init[i];
381  _nodes[i].predecessor = (& (_nodes[i])) - 1;
382  _nodes[i].successor = (& (_nodes[i])) + 1;
383  _nodes[i].nullify_treelinks();
384  }
385  _nodes[0].predecessor = (& (_nodes[n-1]));
386  _nodes[n-1].successor = (& (_nodes[0]));
387  unsigned int scale = (n+1)/2;
388  unsigned int top = std::min(n-1,scale);
389  _nodes[top].parent = NULL;
390  _top_node = &(_nodes[top]);
391  _do_initial_connections(top, scale, 0, n, 0);
392 }
393 template<class T> inline int SearchTree<T>::loc(const Node * node) const {return node == NULL?
394  -999 : node - &(_nodes[0]);}
395 template<class T> void SearchTree<T>::_do_initial_connections(
396  unsigned int this_one,
397  unsigned int scale,
398  unsigned int left_edge,
399  unsigned int right_edge,
400  unsigned int depth
401  ) {
402 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
403  _max_depth = max(depth, _max_depth);
404 #endif
405  unsigned int ref_new_scale = (scale+1)/2;
406  unsigned new_scale = ref_new_scale;
407  bool did_child = false;
408  while(true) {
409  int left = this_one - new_scale; // be careful here to use signed int...
410  if (left >= static_cast<int>(left_edge)
411  && _nodes[left].treelinks_null() ) {
412  _nodes[left].parent = &(_nodes[this_one]);
413  _nodes[this_one].left = &(_nodes[left]);
414  _do_initial_connections(left, new_scale, left_edge, this_one, depth+1);
415  did_child = true;
416  break;
417  }
418  unsigned int old_new_scale = new_scale;
419  new_scale = (old_new_scale + 1)/2;
420  if (new_scale == old_new_scale) break;
421  }
422  if (!did_child) {_nodes[this_one].left = NULL;}
423  new_scale = ref_new_scale;
424  did_child = false;
425  while(true) {
426  unsigned int right = this_one + new_scale;
427  if (right < right_edge && _nodes[right].treelinks_null()) {
428  _nodes[right].parent = &(_nodes[this_one]);
429  _nodes[this_one].right = &(_nodes[right]);
430  _do_initial_connections(right, new_scale, this_one+1,right_edge,depth+1);
431  did_child = true;
432  break;
433  }
434  unsigned int old_new_scale = new_scale;
435  new_scale = (old_new_scale + 1)/2;
436  if (new_scale == old_new_scale) break;
437  }
438  if (!did_child) {_nodes[this_one].right = NULL;}
439 }
440 template<class T> void SearchTree<T>::remove(unsigned int node_index) {
441  remove(&(_nodes[node_index]));
442 }
443 template<class T> void SearchTree<T>::remove(circulator & circ) {
444  remove(circ._node);
445 }
446 template<class T> void SearchTree<T>::remove(typename SearchTree<T>::Node * node) {
447  assert(size() > 1); // switch this to throw...?
448  assert(!node->treelinks_null());
449  node->predecessor->successor = node->successor;
450  node->successor->predecessor = node->predecessor;
451  if (node->left == NULL && node->right == NULL) {
452  node->reset_parents_link_to_me(NULL);
453  } else if (node->left != NULL && node->right == NULL){
454  node->reset_parents_link_to_me(node->left);
455  node->left->parent = node->parent;
456  if (_top_node == node) {_top_node = node->left;}
457  } else if (node->left == NULL && node->right != NULL){
458  node->reset_parents_link_to_me(node->right);
459  node->right->parent = node->parent;
460  if (_top_node == node) {_top_node = node->right;}
461  } else {
462  Node * replacement;
463  bool use_predecessor = (_n_removes % 2 == 1);
464  if (use_predecessor) {
465  replacement = node->predecessor;
466  assert(replacement->right == NULL); // guaranteed if it's our predecessor
467  if (replacement != node->left) {
468  if (replacement->left != NULL) {
469  replacement->left->parent = replacement->parent;}
470  replacement->reset_parents_link_to_me(replacement->left);
471  replacement->left = node->left;
472  }
473  replacement->parent = node->parent;
474  replacement->right = node->right;
475  } else {
476  replacement = node->successor;
477  assert(replacement->left == NULL); // guaranteed if it's our successor
478  if (replacement != node->right) {
479  if (replacement->right != NULL) {
480  replacement->right->parent = replacement->parent;}
481  replacement->reset_parents_link_to_me(replacement->right);
482  replacement->right = node->right;
483  }
484  replacement->parent = node->parent;
485  replacement->left = node->left;
486  }
487  node->reset_parents_link_to_me(replacement);
488  if (node->left != replacement) {node->left->parent = replacement;}
489  if (node->right != replacement) {node->right->parent = replacement;}
490  if (_top_node == node) {_top_node = replacement;}
491  }
492  node->nullify_treelinks();
493  node->predecessor = NULL;
494  node->successor = NULL;
495  _n_removes++;
496  _available_nodes.push_back(node);
497 }
498 template<class T> typename SearchTree<T>::circulator SearchTree<T>::insert(const T & value) {
499  assert(_available_nodes.size() > 0);
500  Node * node = _available_nodes.back();
501  _available_nodes.pop_back();
502  node->value = value;
503  Node * location = _top_node;
504  Node * old_location = NULL;
505  bool on_left = true; // (init not needed -- but soothes g++4)
506 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
507  unsigned int depth = 0;
508 #endif
509  while(location != NULL) {
510 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
511  depth++;
512 #endif
513  old_location = location;
514  on_left = value < location->value;
515  if (on_left) {location = location->left;}
516  else {location = location->right;}
517  }
518 #ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
519  _max_depth = max(depth, _max_depth);
520 #endif
521  node->parent = old_location;
522  if (on_left) {node->parent->left = node;}
523  else {node->parent->right = node;}
524  node->left = NULL;
525  node->right = NULL;
526  node->predecessor = _find_predecessor(node);
527  if (node->predecessor != NULL) {
528  node->successor = node->predecessor->successor;
529  node->predecessor->successor = node;
530  node->successor->predecessor = node;
531  } else {
532  node->successor = _find_successor(node);
533  assert(node->successor != NULL); // can only happen if we're sole element
534  node->predecessor = node->successor->predecessor;
535  node->successor->predecessor = node;
536  node->predecessor->successor = node;
537  }
538  return circulator(node);
539 }
540 template<class T> void SearchTree<T>::verify_structure() {
541  verify_structure_linear();
542  const Node * left_limit = _top_node;
543  while (left_limit->left != NULL) {left_limit = left_limit->left;}
544  const Node * right_limit = _top_node;
545  while (right_limit->right != NULL) {right_limit = right_limit->right;}
546  verify_structure_recursive(_top_node, left_limit, right_limit);
547 }
548 template<class T> void SearchTree<T>::verify_structure_recursive(
549  const typename SearchTree<T>::Node * element,
550  const typename SearchTree<T>::Node * left_limit,
551  const typename SearchTree<T>::Node * right_limit) const {
552  assert(!(element->value < left_limit->value));
553  assert(!(right_limit->value < element->value));
554  const Node * left = element->left;
555  if (left != NULL) {
556  assert(!(element->value < left->value));
557  if (left != left_limit) {
558  verify_structure_recursive(left, left_limit, element);}
559  }
560  const Node * right = element->right;
561  if (right != NULL) {
562  assert(!(right->value < element->value));
563  if (right != right_limit) {
564  verify_structure_recursive(right, element, right_limit);}
565  }
566 }
567 template<class T> void SearchTree<T>::verify_structure_linear() const {
568  unsigned n_top = 0;
569  unsigned n_null = 0;
570  for(unsigned i = 0; i < _nodes.size(); i++) {
571  const typename SearchTree<T>::Node * node = &(_nodes[i]);
572  if (node->treelinks_null()) {n_null++; continue;}
573  if (node->parent == NULL) {
574  n_top++;
575  } else {
576  assert((node->parent->left == node) ^ (node->parent->right == node));
577  }
578  if (node->left != NULL) {
579  assert(!(node->value < node->left->value ));}
580  if (node->right != NULL) {
581  assert(!(node->right->value < node->value ));}
582  }
583  assert(n_top == 1 || (n_top == 0 && size() <= 1) );
584  assert(n_null == _available_nodes.size() ||
585  (n_null == _available_nodes.size() + 1 && size() == 1));
586 }
587 template<class T> typename SearchTree<T>::Node * SearchTree<T>::_find_predecessor(const typename SearchTree<T>::Node * node) {
588  typename SearchTree<T>::Node * newnode;
589  if (node->left != NULL) {
590  newnode = node->left;
591  while(newnode->right != NULL) {newnode = newnode->right;}
592  return newnode;
593  } else {
594  const typename SearchTree<T>::Node * lastnode = node;
595  newnode = node->parent;
596  while(newnode != NULL) {
597  if (newnode->right == lastnode) {return newnode;}
598  lastnode = newnode;
599  newnode = newnode->parent;
600  }
601  return newnode;
602  }
603 }
604 template<class T> typename SearchTree<T>::Node * SearchTree<T>::_find_successor(const typename SearchTree<T>::Node * node) {
605  typename SearchTree<T>::Node * newnode;
606  if (node->right != NULL) {
607  newnode = node->right;
608  while(newnode->left != NULL) {newnode = newnode->left;}
609  return newnode;
610  } else {
611  const typename SearchTree<T>::Node * lastnode = node;
612  newnode = node->parent;
613  while(newnode != NULL) {
614  if (newnode->left == lastnode) {return newnode;}
615  lastnode = newnode;
616  newnode = newnode->parent;
617  }
618  return newnode;
619  }
620 }
621 template<class T> void SearchTree<T>::print_elements() {
622  typename SearchTree<T>::Node * base_node = &(_nodes[0]);
623  typename SearchTree<T>::Node * node = base_node;
624  int n = _nodes.size();
625  for(; node - base_node < n ; node++) {
626  printf("%4d parent:%4d left:%4d right:%4d pred:%4d succ:%4d value:%10.6f\n",loc(node), loc(node->parent), loc(node->left), loc(node->right), loc(node->predecessor),loc(node->successor),node->value);
627  }
628 }
629 template<class T> typename SearchTree<T>::circulator SearchTree<T>::somewhere() {
630  return circulator(_top_node);
631 }
632 template<class T> typename SearchTree<T>::const_circulator SearchTree<T>::somewhere() const {
633  return const_circulator(_top_node);
634 }
635 FJCORE_END_NAMESPACE
636 #endif // __FJCORE_SEARCHTREE_HH__
637 #ifndef __FJCORE_MINHEAP__HH__
638 #define __FJCORE_MINHEAP__HH__
639 #include<vector>
640 #include<cassert>
641 #include<memory>
642 #include<limits>
643 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
644 class MinHeap {
645 public:
646  MinHeap (const std::vector<double> & values, unsigned int max_size) :
647  _heap(max_size) {initialise(values);}
648  MinHeap (unsigned int max_size) : _heap(max_size) {}
649  MinHeap (const std::vector<double> & values) :
650  _heap(values.size()) {initialise(values);}
651  void initialise(const std::vector<double> & values);
652  inline unsigned int minloc() const {
653  return (_heap[0].minloc) - &(_heap[0]);}
654  inline double minval() const {return _heap[0].minloc->value;}
655  inline double operator[](int i) const {return _heap[i].value;}
656  void remove(unsigned int loc) {
657  update(loc,std::numeric_limits<double>::max());};
658  void update(unsigned int, double);
659 private:
660  struct ValueLoc{
661  double value;
662  ValueLoc * minloc;
663  };
664  std::vector<ValueLoc> _heap;
665 };
666 FJCORE_END_NAMESPACE
667 #endif // __FJCORE_MINHEAP__HH__
668 #ifndef __FJCORE_CLOSESTPAIR2DBASE__HH__
669 #define __FJCORE_CLOSESTPAIR2DBASE__HH__
670 #include<vector>
671 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
672 class Coord2D {
673 public:
674  double x, y;
675  Coord2D() : x(0.0), y(0.0) {};
676  Coord2D(double a, double b): x(a), y(b) {};
677  Coord2D operator-(const Coord2D & other) const {
678  return Coord2D(x - other.x, y - other.y);};
679  Coord2D operator+(const Coord2D & other) const {
680  return Coord2D(x + other.x, y + other.y);};
681  Coord2D operator*(double factor) const {return Coord2D(factor*x,factor*y);};
682  friend Coord2D operator*(double factor, const Coord2D & coord) {
683  return Coord2D(factor*coord.x,factor*coord.y);
684  }
685  Coord2D operator/(double divisor) const {
686  return Coord2D(x / divisor, y / divisor);};
687  friend double distance2(const Coord2D & a, const Coord2D & b) {
688  double dx = a.x - b.x, dy = a.y-b.y;
689  return dx*dx+dy*dy;
690  };
691  double distance2(const Coord2D & b) const {
692  double dx = x - b.x, dy = y-b.y;
693  return dx*dx+dy*dy;
694  };
695 };
696 class ClosestPair2DBase {
697 public:
698  virtual void closest_pair(unsigned int & ID1, unsigned int & ID2,
699  double & distance2) const = 0;
700  virtual void remove(unsigned int ID) = 0;
701  virtual unsigned int insert(const Coord2D & position) = 0;
702  virtual unsigned int replace(unsigned int ID1, unsigned int ID2,
703  const Coord2D & position) {
704  remove(ID1);
705  remove(ID2);
706  unsigned new_ID = insert(position);
707  return(new_ID);
708  };
709  virtual void replace_many(const std::vector<unsigned int> & IDs_to_remove,
710  const std::vector<Coord2D> & new_positions,
711  std::vector<unsigned int> & new_IDs) {
712  for(unsigned i = 0; i < IDs_to_remove.size(); i++) {
713  remove(IDs_to_remove[i]);}
714  new_IDs.resize(0);
715  for(unsigned i = 0; i < new_positions.size(); i++) {
716  new_IDs.push_back(insert(new_positions[i]));}
717  }
718  virtual unsigned int size() = 0;
719  virtual ~ClosestPair2DBase() {};
720 };
721 FJCORE_END_NAMESPACE
722 #endif // __FJCORE_CLOSESTPAIR2DBASE__HH__
723 #ifndef __FJCORE_CLOSESTPAIR2D__HH__
724 #define __FJCORE_CLOSESTPAIR2D__HH__
725 #include<vector>
726 #include<stack>
727 #include<iostream>
728 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
729 class ClosestPair2D : public ClosestPair2DBase {
730 public:
731  ClosestPair2D(const std::vector<Coord2D> & positions,
732  const Coord2D & left_corner, const Coord2D & right_corner) {
733  _initialize(positions, left_corner, right_corner, positions.size());
734  };
735  ClosestPair2D(const std::vector<Coord2D> & positions,
736  const Coord2D & left_corner, const Coord2D & right_corner,
737  const unsigned int max_size) {
738  _initialize(positions, left_corner, right_corner, max_size);
739  };
740  void closest_pair(unsigned int & ID1, unsigned int & ID2,
741  double & distance2) const;
742  void remove(unsigned int ID);
743  unsigned int insert(const Coord2D &);
744  virtual unsigned int replace(unsigned int ID1, unsigned int ID2,
745  const Coord2D & position);
746  virtual void replace_many(const std::vector<unsigned int> & IDs_to_remove,
747  const std::vector<Coord2D> & new_positions,
748  std::vector<unsigned int> & new_IDs);
749  inline void print_tree_depths(std::ostream & outdev) const {
750  outdev << _trees[0]->max_depth() << " "
751  << _trees[1]->max_depth() << " "
752  << _trees[2]->max_depth() << "\n";
753  };
754  unsigned int size();
755 private:
756  void _initialize(const std::vector<Coord2D> & positions,
757  const Coord2D & left_corner, const Coord2D & right_corner,
758  const unsigned int max_size);
759  static const unsigned int _nshift = 3;
760  class Point; // will be defined below
761  template<class T> class triplet {
762  public:
763  inline const T & operator[](unsigned int i) const {return _contents[i];};
764  inline T & operator[](unsigned int i) {return _contents[i];};
765  private:
766  T _contents[_nshift];
767  };
768  class Shuffle {
769  public:
770  unsigned int x, y;
771  Point * point;
772  bool operator<(const Shuffle &) const;
773  void operator+=(unsigned int shift) {x += shift; y+= shift;};
774  };
775  typedef SearchTree<Shuffle> Tree;
776  typedef Tree::circulator circulator;
777  typedef Tree::const_circulator const_circulator;
778  triplet<SharedPtr<Tree> > _trees;
779  SharedPtr<MinHeap> _heap;
780  std::vector<Point> _points;
781  std::stack<Point *> _available_points;
782  std::vector<Point *> _points_under_review;
783  static const unsigned int _remove_heap_entry = 1;
784  static const unsigned int _review_heap_entry = 2;
785  static const unsigned int _review_neighbour = 4;
786  void _add_label(Point * point, unsigned int review_flag);
787  void _set_label(Point * point, unsigned int review_flag);
788  void _deal_with_points_to_review();
789  void _remove_from_search_tree(Point * point_to_remove);
790  void _insert_into_search_tree(Point * new_point);
791  void _point2shuffle(Point & , Shuffle & , unsigned int shift);
792  Coord2D _left_corner;
793  double _range;
794  int _ID(const Point *) const;
795  triplet<unsigned int> _shifts; // absolute shifts
796  triplet<unsigned int> _rel_shifts; // shifts relative to previous shift
797  unsigned int _cp_search_range;
798 };
799 class ClosestPair2D::Point {
800 public:
801  Coord2D coord;
802  Point * neighbour;
803  double neighbour_dist2;
804  triplet<circulator> circ;
805  unsigned int review_flag;
806  double distance2(const Point & other) const {
807  return coord.distance2(other.coord);
808  };
809 };
810 inline bool floor_ln2_less(unsigned x, unsigned y) {
811  if (x>y) return false;
812  return (x < (x^y)); // beware of operator precedence...
813 }
814 inline int ClosestPair2D::_ID(const Point * point) const {
815  return point - &(_points[0]);
816 }
817 inline unsigned int ClosestPair2D::size() {
818  return _points.size() - _available_points.size();
819 }
820 FJCORE_END_NAMESPACE
821 #endif // __FJCORE_CLOSESTPAIR2D__HH__
822 #ifndef __FJCORE_LAZYTILING9ALT_HH__
823 #define __FJCORE_LAZYTILING9ALT_HH__
824 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
825 const double tile_edge_security_margin=1.0e-7;
826 class TiledJet {
827 public:
828  double eta, phi, kt2, NN_dist;
829  TiledJet * NN, *previous, * next;
830  int _jets_index, tile_index;
831  bool _minheap_update_needed;
832  inline void label_minheap_update_needed() {_minheap_update_needed = true;}
833  inline void label_minheap_update_done() {_minheap_update_needed = false;}
834  inline bool minheap_update_needed() const {return _minheap_update_needed;}
835 };
836 const int n_tile_neighbours = 9;
837 class Tile {
838 public:
839  typedef double (Tile::*DistToTileFn)(const TiledJet*) const;
840  typedef std::pair<Tile *, DistToTileFn> TileFnPair;
841  TileFnPair begin_tiles[n_tile_neighbours];
842  TileFnPair * surrounding_tiles;
843  TileFnPair * RH_tiles;
844  TileFnPair * end_tiles;
845  TiledJet * head;
846  bool tagged;
847  bool use_periodic_delta_phi;
848  double max_NN_dist;
849  double eta_min, eta_max, phi_min, phi_max;
850  double distance_to_centre(const TiledJet *) const {return 0;}
851  double distance_to_left(const TiledJet * jet) const {
852  double deta = jet->eta - eta_min;
853  return deta*deta;
854  }
855  double distance_to_right(const TiledJet * jet) const {
856  double deta = jet->eta - eta_max;
857  return deta*deta;
858  }
859  double distance_to_bottom(const TiledJet * jet) const {
860  double dphi = jet->phi - phi_min;
861  return dphi*dphi;
862  }
863  double distance_to_top(const TiledJet * jet) const {
864  double dphi = jet->phi - phi_max;
865  return dphi*dphi;
866  }
867  double distance_to_left_top(const TiledJet * jet) const {
868  double deta = jet->eta - eta_min;
869  double dphi = jet->phi - phi_max;
870  return deta*deta + dphi*dphi;
871  }
872  double distance_to_left_bottom(const TiledJet * jet) const {
873  double deta = jet->eta - eta_min;
874  double dphi = jet->phi - phi_min;
875  return deta*deta + dphi*dphi;
876  }
877  double distance_to_right_top(const TiledJet * jet) const {
878  double deta = jet->eta - eta_max;
879  double dphi = jet->phi - phi_max;
880  return deta*deta + dphi*dphi;
881  }
882  double distance_to_right_bottom(const TiledJet * jet) const {
883  double deta = jet->eta - eta_max;
884  double dphi = jet->phi - phi_min;
885  return deta*deta + dphi*dphi;
886  }
887 };
888 class LazyTiling9Alt {
889 public:
891  void run();
892 protected:
893  ClusterSequence & _cs;
894  const std::vector<PseudoJet> & _jets;
895  std::vector<Tile> _tiles;
896  double _Rparam, _R2, _invR2;
897  double _tiles_eta_min, _tiles_eta_max;
898  double _tile_size_eta, _tile_size_phi;
899  double _tile_half_size_eta, _tile_half_size_phi;
900  int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
901  std::vector<TiledJet *> _jets_for_minheap;
902  void _initialise_tiles();
903  inline int _tile_index (int ieta, int iphi) const {
904  return (ieta-_tiles_ieta_min)*_n_tiles_phi
905  + (iphi+_n_tiles_phi) % _n_tiles_phi;
906  }
907  void _bj_remove_from_tiles(TiledJet * const jet);
908  int _tile_index(const double eta, const double phi) const;
909  void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
910  void _print_tiles(TiledJet * briefjets ) const;
911  void _add_neighbours_to_tile_union(const int tile_index,
912  std::vector<int> & tile_union, int & n_near_tiles) const;
913  void _add_untagged_neighbours_to_tile_union(const int tile_index,
914  std::vector<int> & tile_union, int & n_near_tiles);
915  void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
916  std::vector<int> & tile_union, int & n_near_tiles);
917  void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
918  void _set_NN(TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
919  template <class J> double _bj_diJ(const J * const jet) const {
920  double kt2 = jet->kt2;
921  if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
922  return jet->NN_dist * kt2;
923  }
924  template <class J> inline void _bj_set_jetinfo(
925  J * const jetA, const int _jets_index) const {
926  jetA->eta = _jets[_jets_index].rap();
927  jetA->phi = _jets[_jets_index].phi_02pi();
928  jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
929  jetA->_jets_index = _jets_index;
930  jetA->NN_dist = _R2;
931  jetA->NN = NULL;
932  }
933  template <class J> inline double _bj_dist(
934  const J * const jetA, const J * const jetB) const {
935  double dphi = std::abs(jetA->phi - jetB->phi);
936  double deta = (jetA->eta - jetB->eta);
937  if (dphi > pi) {dphi = twopi - dphi;}
938  return dphi*dphi + deta*deta;
939  }
940  template <class J> inline double _bj_dist_not_periodic(
941  const J * const jetA, const J * const jetB) const {
942  double dphi = jetA->phi - jetB->phi;
943  double deta = (jetA->eta - jetB->eta);
944  return dphi*dphi + deta*deta;
945  }
946 };
947 FJCORE_END_NAMESPACE
948 #endif // __FJCORE_LAZYTILING9ALT_HH__
949 #ifndef __FJCORE_LAZYTILING9_HH__
950 #define __FJCORE_LAZYTILING9_HH__
951 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
952 template<int NN>
953 class Tile2Base {
954 public:
955  Tile2Base * begin_tiles[NN];
956  Tile2Base ** surrounding_tiles;
957  Tile2Base ** RH_tiles;
958  Tile2Base ** end_tiles;
959  TiledJet * head;
960  bool tagged;
961  bool use_periodic_delta_phi;
962  double max_NN_dist;
963  double eta_centre, phi_centre;
964  int jet_count() const {
965  int count = 0;
966  const TiledJet * jet = head;
967  while (jet != 0) {
968  count++;
969  jet = jet->next;
970  }
971  return count;
972  }
973 };
974 typedef Tile2Base<9> Tile2;
975 class LazyTiling9 {
976 public:
978  void run();
979 protected:
980  ClusterSequence & _cs;
981  const std::vector<PseudoJet> & _jets;
982  std::vector<Tile2> _tiles;
983 #ifdef INSTRUMENT2
984  int _ncall; // GPS tmp
985  int _ncall_dtt; // GPS tmp
986 #endif // INSTRUMENT2
987  double _Rparam, _R2, _invR2;
988  double _tiles_eta_min, _tiles_eta_max;
989  double _tile_size_eta, _tile_size_phi;
990  double _tile_half_size_eta, _tile_half_size_phi;
991  int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
992  std::vector<TiledJet *> _jets_for_minheap;
993  void _initialise_tiles();
994  inline int _tile_index (int ieta, int iphi) const {
995  return (ieta-_tiles_ieta_min)*_n_tiles_phi
996  + (iphi+_n_tiles_phi) % _n_tiles_phi;
997  }
998  void _bj_remove_from_tiles(TiledJet * const jet);
999  int _tile_index(const double eta, const double phi) const;
1000  void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
1001  void _print_tiles(TiledJet * briefjets ) const;
1002  void _add_neighbours_to_tile_union(const int tile_index,
1003  std::vector<int> & tile_union, int & n_near_tiles) const;
1004  void _add_untagged_neighbours_to_tile_union(const int tile_index,
1005  std::vector<int> & tile_union, int & n_near_tiles);
1006  void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
1007  std::vector<int> & tile_union, int & n_near_tiles);
1008  double _distance_to_tile(const TiledJet * bj, const Tile2 *)
1009 #ifdef INSTRUMENT2
1010  ;
1011 #else
1012  const;
1013 #endif
1014  void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
1015  void _set_NN(TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
1016  template <class J> double _bj_diJ(const J * const jet) const {
1017  double kt2 = jet->kt2;
1018  if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
1019  return jet->NN_dist * kt2;
1020  }
1021  template <class J> inline void _bj_set_jetinfo(
1022  J * const jetA, const int _jets_index) const {
1023  jetA->eta = _jets[_jets_index].rap();
1024  jetA->phi = _jets[_jets_index].phi_02pi();
1025  jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
1026  jetA->_jets_index = _jets_index;
1027  jetA->NN_dist = _R2;
1028  jetA->NN = NULL;
1029  }
1030  template <class J> inline double _bj_dist(
1031  const J * const jetA, const J * const jetB)
1032 #ifdef INSTRUMENT2
1033  {
1034  _ncall++; // GPS tmp
1035 #else
1036  const {
1037 #endif
1038  double dphi = std::abs(jetA->phi - jetB->phi);
1039  double deta = (jetA->eta - jetB->eta);
1040  if (dphi > pi) {dphi = twopi - dphi;}
1041  return dphi*dphi + deta*deta;
1042  }
1043  template <class J> inline double _bj_dist_not_periodic(
1044  const J * const jetA, const J * const jetB)
1045 #ifdef INSTRUMENT2
1046  {
1047  _ncall++; // GPS tmp
1048 #else
1049  const {
1050 #endif
1051  double dphi = jetA->phi - jetB->phi;
1052  double deta = (jetA->eta - jetB->eta);
1053  return dphi*dphi + deta*deta;
1054  }
1055 };
1056 FJCORE_END_NAMESPACE
1057 #endif // __FJCORE_LAZYTILING9_HH__
1058 #ifndef __FJCORE_LAZYTILING25_HH__
1059 #define __FJCORE_LAZYTILING25_HH__
1060 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
1061 typedef Tile2Base<25> Tile25;
1062 class LazyTiling25 {
1063 public:
1065  void run();
1066 protected:
1067  ClusterSequence & _cs;
1068  const std::vector<PseudoJet> & _jets;
1069  std::vector<Tile25> _tiles;
1070 #ifdef INSTRUMENT2
1071  int _ncall; // GPS tmp
1072  int _ncall_dtt; // GPS tmp
1073 #endif // INSTRUMENT2
1074  double _Rparam, _R2, _invR2;
1075  double _tiles_eta_min, _tiles_eta_max;
1076  double _tile_size_eta, _tile_size_phi;
1077  double _tile_half_size_eta, _tile_half_size_phi;
1078  int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
1079  std::vector<TiledJet *> _jets_for_minheap;
1080  void _initialise_tiles();
1081  inline int _tile_index (int ieta, int iphi) const {
1082  return (ieta-_tiles_ieta_min)*_n_tiles_phi
1083  + (iphi+_n_tiles_phi) % _n_tiles_phi;
1084  }
1085  void _bj_remove_from_tiles(TiledJet * const jet);
1086  int _tile_index(const double eta, const double phi) const;
1087  void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
1088  void _print_tiles(TiledJet * briefjets ) const;
1089  void _add_neighbours_to_tile_union(const int tile_index,
1090  std::vector<int> & tile_union, int & n_near_tiles) const;
1091  void _add_untagged_neighbours_to_tile_union(const int tile_index,
1092  std::vector<int> & tile_union, int & n_near_tiles);
1093  void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
1094  std::vector<int> & tile_union, int & n_near_tiles);
1095  double _distance_to_tile(const TiledJet * bj, const Tile25 *)
1096 #ifdef INSTRUMENT2
1097  ;
1098 #else
1099  const;
1100 #endif
1101  void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
1102  void _set_NN(TiledJet * jetI, std::vector<TiledJet *> & jets_for_minheap);
1103  template <class J> double _bj_diJ(const J * const jet) const {
1104  double kt2 = jet->kt2;
1105  if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
1106  return jet->NN_dist * kt2;
1107  }
1108  template <class J> inline void _bj_set_jetinfo(
1109  J * const jetA, const int _jets_index) const {
1110  jetA->eta = _jets[_jets_index].rap();
1111  jetA->phi = _jets[_jets_index].phi_02pi();
1112  jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
1113  jetA->_jets_index = _jets_index;
1114  jetA->NN_dist = _R2;
1115  jetA->NN = NULL;
1116  }
1117  template <class J> inline double _bj_dist(
1118  const J * const jetA, const J * const jetB)
1119 #ifdef INSTRUMENT2
1120  {
1121  _ncall++; // GPS tmp
1122 #else
1123  const {
1124 #endif
1125  double dphi = std::abs(jetA->phi - jetB->phi);
1126  double deta = (jetA->eta - jetB->eta);
1127  if (dphi > pi) {dphi = twopi - dphi;}
1128  return dphi*dphi + deta*deta;
1129  }
1130  template <class J> inline double _bj_dist_not_periodic(
1131  const J * const jetA, const J * const jetB)
1132 #ifdef INSTRUMENT2
1133  {
1134  _ncall++; // GPS tmp
1135 #else
1136  const {
1137 #endif
1138  double dphi = jetA->phi - jetB->phi;
1139  double deta = (jetA->eta - jetB->eta);
1140  return dphi*dphi + deta*deta;
1141  }
1142 };
1143 FJCORE_END_NAMESPACE
1144 #endif // __FJCORE_LAZYTILING25_HH__
1145 #ifndef __FJCORE_TILINGEXTENT_HH__
1146 #define __FJCORE_TILINGEXTENT_HH__
1147 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
1148 class TilingExtent {
1149 public:
1151  TilingExtent(const std::vector<PseudoJet> &particles);
1152  double minrap() const {return _minrap;}
1153  double maxrap() const {return _maxrap;}
1154  double sum_of_binned_squared_multiplicity() const {return _cumul2;}
1155 private:
1156  double _minrap, _maxrap, _cumul2;
1157  void _determine_rapidity_extent(const std::vector<PseudoJet> & particles);
1158 };
1159 FJCORE_END_NAMESPACE // defined in fastjet/internal/base.hh
1160 #endif // __FJCORE_TILINGEXTENT_HH__
1161 #include<limits>
1162 #include<iostream>
1163 #include<iomanip>
1164 #include<algorithm>
1165 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
1166 const unsigned int twopow31 = 2147483648U;
1167 using namespace std;
1168 void ClosestPair2D::_point2shuffle(Point & point, Shuffle & shuffle,
1169  unsigned int shift) {
1170  Coord2D renorm_point = (point.coord - _left_corner)/_range;
1171  assert(renorm_point.x >=0);
1172  assert(renorm_point.x <=1);
1173  assert(renorm_point.y >=0);
1174  assert(renorm_point.y <=1);
1175  shuffle.x = static_cast<unsigned int>(twopow31 * renorm_point.x) + shift;
1176  shuffle.y = static_cast<unsigned int>(twopow31 * renorm_point.y) + shift;
1177  shuffle.point = &point;
1178 }
1179 bool ClosestPair2D::Shuffle::operator<(const Shuffle & q) const {
1180  if (floor_ln2_less(x ^ q.x, y ^ q.y)) {
1181  return (y < q.y);
1182  } else {
1183  return (x < q.x);
1184  }
1185 }
1186 void ClosestPair2D::_initialize(const std::vector<Coord2D> & positions,
1187  const Coord2D & left_corner,
1188  const Coord2D & right_corner,
1189  unsigned int max_size) {
1190  unsigned int n_positions = positions.size();
1191  assert(max_size >= n_positions);
1192  _points.resize(max_size);
1193  for (unsigned int i = n_positions; i < max_size; i++) {
1194  _available_points.push(&(_points[i]));
1195  }
1196  _left_corner = left_corner;
1197  _range = max((right_corner.x - left_corner.x),
1198  (right_corner.y - left_corner.y));
1199  vector<Shuffle> shuffles(n_positions);
1200  for (unsigned int i = 0; i < n_positions; i++) {
1201  _points[i].coord = positions[i];
1202  _points[i].neighbour_dist2 = numeric_limits<double>::max();
1203  _points[i].review_flag = 0;
1204  _point2shuffle(_points[i], shuffles[i], 0);
1205  }
1206  for (unsigned ishift = 0; ishift < _nshift; ishift++) {
1207  _shifts[ishift] = static_cast<unsigned int>(((twopow31*1.0)*ishift)/_nshift);
1208  if (ishift == 0) {_rel_shifts[ishift] = 0;}
1209  else {_rel_shifts[ishift] = _shifts[ishift] - _shifts[ishift-1];}
1210  }
1211  _cp_search_range = 30;
1212  _points_under_review.reserve(_nshift * _cp_search_range);
1213  for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
1214  if (ishift > 0) {
1215  unsigned rel_shift = _rel_shifts[ishift];
1216  for (unsigned int i = 0; i < shuffles.size(); i++) {
1217  shuffles[i] += rel_shift; }
1218  }
1219  sort(shuffles.begin(), shuffles.end());
1220  _trees[ishift] = SharedPtr<Tree>(new Tree(shuffles, max_size));
1221  circulator circ = _trees[ishift]->somewhere(), start=circ;
1222  unsigned int CP_range = min(_cp_search_range, n_positions-1);
1223  do {
1224  Point * this_point = circ->point;
1225  this_point->circ[ishift] = circ;
1226  circulator other = circ;
1227  for (unsigned i=0; i < CP_range; i++) {
1228  ++other;
1229  double dist2 = this_point->distance2(*other->point);
1230  if (dist2 < this_point->neighbour_dist2) {
1231  this_point->neighbour_dist2 = dist2;
1232  this_point->neighbour = other->point;
1233  }
1234  }
1235  } while (++circ != start);
1236  }
1237  vector<double> mindists2(n_positions);
1238  for (unsigned int i = 0; i < n_positions; i++) {
1239  mindists2[i] = _points[i].neighbour_dist2;}
1240  _heap = SharedPtr<MinHeap>(new MinHeap(mindists2, max_size));
1241 }
1242 void ClosestPair2D::closest_pair(unsigned int & ID1, unsigned int & ID2,
1243  double & distance2) const {
1244  ID1 = _heap->minloc();
1245  ID2 = _ID(_points[ID1].neighbour);
1246  distance2 = _points[ID1].neighbour_dist2;
1247  if (ID1 > ID2) std::swap(ID1,ID2);
1248 }
1249 inline void ClosestPair2D::_add_label(Point * point, unsigned int review_flag) {
1250  if (point->review_flag == 0) _points_under_review.push_back(point);
1251  point->review_flag |= review_flag;
1252 }
1253 inline void ClosestPair2D::_set_label(Point * point, unsigned int review_flag) {
1254  if (point->review_flag == 0) _points_under_review.push_back(point);
1255  point->review_flag = review_flag;
1256 }
1257 void ClosestPair2D::remove(unsigned int ID) {
1258  Point * point_to_remove = & (_points[ID]);
1259  _remove_from_search_tree(point_to_remove);
1260  _deal_with_points_to_review();
1261 }
1262 void ClosestPair2D::_remove_from_search_tree(Point * point_to_remove) {
1263  _available_points.push(point_to_remove);
1264  _set_label(point_to_remove, _remove_heap_entry);
1265  unsigned int CP_range = min(_cp_search_range, size()-1);
1266  for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
1267  circulator removed_circ = point_to_remove->circ[ishift];
1268  circulator right_end = removed_circ.next();
1269  _trees[ishift]->remove(removed_circ);
1270  circulator left_end = right_end, orig_right_end = right_end;
1271  for (unsigned int i = 0; i < CP_range; i++) {left_end--;}
1272  if (size()-1 < _cp_search_range) {
1273  left_end--; right_end--;
1274  }
1275  do {
1276  Point * left_point = left_end->point;
1277  if (left_point->neighbour == point_to_remove) {
1278  // we'll deal with it later...
1279  _add_label(left_point, _review_neighbour);
1280  } else {
1281  // check to see if right point has become its closest neighbour
1282  double dist2 = left_point->distance2(*right_end->point);
1283  if (dist2 < left_point->neighbour_dist2) {
1284  left_point->neighbour = right_end->point;
1285  left_point->neighbour_dist2 = dist2;
1286  // NB: (LESSER) REVIEW NEEDED HERE TOO...
1287  _add_label(left_point, _review_heap_entry);
1288  }
1289  }
1290  ++right_end;
1291  } while (++left_end != orig_right_end);
1292  } // ishift...
1293 }
1294 void ClosestPair2D::_deal_with_points_to_review() {
1295  unsigned int CP_range = min(_cp_search_range, size()-1);
1296  while(_points_under_review.size() > 0) {
1297  Point * this_point = _points_under_review.back();
1298  _points_under_review.pop_back();
1299  if (this_point->review_flag & _remove_heap_entry) {
1300  assert(!(this_point->review_flag ^ _remove_heap_entry));
1301  _heap->remove(_ID(this_point));
1302  }
1303  else {
1304  if (this_point->review_flag & _review_neighbour) {
1305  this_point->neighbour_dist2 = numeric_limits<double>::max();
1306  // among all three shifts
1307  for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
1308  circulator other = this_point->circ[ishift];
1309  // among points within CP_range
1310  for (unsigned i=0; i < CP_range; i++) {
1311  ++other;
1312  double dist2 = this_point->distance2(*other->point);
1313  if (dist2 < this_point->neighbour_dist2) {
1314  this_point->neighbour_dist2 = dist2;
1315  this_point->neighbour = other->point;
1316  }
1317  }
1318  }
1319  }
1320  _heap->update(_ID(this_point), this_point->neighbour_dist2);
1321  }
1322  this_point->review_flag = 0;
1323  }
1324 }
1325 unsigned int ClosestPair2D::insert(const Coord2D & new_coord) {
1326  assert(_available_points.size() > 0);
1327  Point * new_point = _available_points.top();
1328  _available_points.pop();
1329  new_point->coord = new_coord;
1330  _insert_into_search_tree(new_point);
1331  _deal_with_points_to_review();
1332  return _ID(new_point);
1333 }
1334 unsigned int ClosestPair2D::replace(unsigned int ID1, unsigned int ID2,
1335  const Coord2D & position) {
1336  Point * point_to_remove = & (_points[ID1]);
1337  _remove_from_search_tree(point_to_remove);
1338  point_to_remove = & (_points[ID2]);
1339  _remove_from_search_tree(point_to_remove);
1340  Point * new_point = _available_points.top();
1341  _available_points.pop();
1342  new_point->coord = position;
1343  _insert_into_search_tree(new_point);
1344  _deal_with_points_to_review();
1345  return _ID(new_point);
1346 }
1347 void ClosestPair2D::replace_many(
1348  const std::vector<unsigned int> & IDs_to_remove,
1349  const std::vector<Coord2D> & new_positions,
1350  std::vector<unsigned int> & new_IDs) {
1351  for (unsigned int i = 0; i < IDs_to_remove.size(); i++) {
1352  _remove_from_search_tree(& (_points[IDs_to_remove[i]]));
1353  }
1354  new_IDs.resize(0);
1355  for (unsigned int i = 0; i < new_positions.size(); i++) {
1356  Point * new_point = _available_points.top();
1357  _available_points.pop();
1358  new_point->coord = new_positions[i];
1359  _insert_into_search_tree(new_point);
1360  new_IDs.push_back(_ID(new_point));
1361  }
1362  _deal_with_points_to_review();
1363 }
1364 void ClosestPair2D::_insert_into_search_tree(Point * new_point) {
1365  _set_label(new_point, _review_heap_entry);
1366  new_point->neighbour_dist2 = numeric_limits<double>::max();
1367  unsigned int CP_range = min(_cp_search_range, size()-1);
1368  for (unsigned ishift = 0; ishift < _nshift; ishift++) {
1369  Shuffle new_shuffle;
1370  _point2shuffle(*new_point, new_shuffle, _shifts[ishift]);
1371  circulator new_circ = _trees[ishift]->insert(new_shuffle);
1372  new_point->circ[ishift] = new_circ;
1373  circulator right_edge = new_circ; right_edge++;
1374  circulator left_edge = new_circ;
1375  for (unsigned int i = 0; i < CP_range; i++) {left_edge--;}
1376  do {
1377  Point * left_point = left_edge->point;
1378  Point * right_point = right_edge->point;
1379  double new_dist2 = left_point->distance2(*new_point);
1380  if (new_dist2 < left_point->neighbour_dist2) {
1381  left_point->neighbour_dist2 = new_dist2;
1382  left_point->neighbour = new_point;
1383  _add_label(left_point, _review_heap_entry);
1384  }
1385  new_dist2 = new_point->distance2(*right_point);
1386  if (new_dist2 < new_point->neighbour_dist2) {
1387  new_point->neighbour_dist2 = new_dist2;
1388  new_point->neighbour = right_point;
1389  }
1390  if (left_point->neighbour == right_point) {
1391  _add_label(left_point, _review_neighbour);
1392  }
1393  right_edge++;
1394  } while (++left_edge != new_circ);
1395  }
1396 }
1397 FJCORE_END_NAMESPACE
1398 #include<iostream>
1399 #include<sstream>
1400 #include<fstream>
1401 #include<cmath>
1402 #include<cstdlib>
1403 #include<cassert>
1404 #include<string>
1405 #include<set>
1406 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
1407 using namespace std;
1408 std::ostream * ClusterSequence::_fastjet_banner_ostr = &cout;
1409 ClusterSequence::~ClusterSequence () {
1410  if (_structure_shared_ptr){
1411  ClusterSequenceStructure* csi = dynamic_cast<ClusterSequenceStructure*>(_structure_shared_ptr.get());
1412  assert(csi != NULL);
1413  csi->set_associated_cs(NULL);
1414  if (_deletes_self_when_unused) {
1415  _structure_shared_ptr.set_count(_structure_shared_ptr.use_count()
1416  + _structure_use_count_after_construction);
1417  }
1418  }
1419 }
1420 void ClusterSequence::signal_imminent_self_deletion() const {
1421  assert(_deletes_self_when_unused);
1422  _deletes_self_when_unused = false;
1423 }
1424 void ClusterSequence::_initialise_and_run (
1425  const JetDefinition & jet_def_in,
1426  const bool & writeout_combinations) {
1427  _decant_options(jet_def_in, writeout_combinations);
1428  _initialise_and_run_no_decant();
1429 }
1430 void ClusterSequence::_initialise_and_run_no_decant () {
1431  _fill_initial_history();
1432  if (n_particles() == 0) return;
1433  if (_jet_algorithm == plugin_algorithm) {
1434  _plugin_activated = true;
1435  _jet_def.plugin()->run_clustering( (*this) );
1436  _plugin_activated = false;
1437  _update_structure_use_count();
1438  return;
1439  } else if (_jet_algorithm == ee_kt_algorithm ||
1440  _jet_algorithm == ee_genkt_algorithm) {
1441  _strategy = N2Plain;
1442  if (_jet_algorithm == ee_kt_algorithm) {
1443  assert(_Rparam > 2.0);
1444  _invR2 = 1.0;
1445  } else {
1446  if (_Rparam > pi) {
1447  // choose a value that ensures that back-to-back particles will
1448  // always recombine
1449  //_R2 = 4.0000000000001;
1450  _R2 = 2 * ( 3.0 + cos(_Rparam) );
1451  } else {
1452  _R2 = 2 * ( 1.0 - cos(_Rparam) );
1453  }
1454  _invR2 = 1.0/_R2;
1455  }
1456  _simple_N2_cluster_EEBriefJet();
1457  return;
1458  } else if (_jet_algorithm == undefined_jet_algorithm) {
1459  throw Error("A ClusterSequence cannot be created with an uninitialised JetDefinition");
1460  }
1461  if (_strategy == Best) {
1462  _strategy = _best_strategy();
1463 #ifdef __FJCORE_DROP_CGAL
1464  if (_strategy == NlnN) _strategy = N2MHTLazy25;
1465 #endif // __FJCORE_DROP_CGAL
1466  } else if (_strategy == BestFJ30) {
1467  int N = _jets.size();
1468  if (min(1.0,max(0.1,_Rparam)*3.3)*N <= 30) {
1469  _strategy = N2Plain;
1470  } else if (N > 6200/pow(_Rparam,2.0) && _jet_def.jet_algorithm() == cambridge_algorithm) {
1471  _strategy = NlnNCam;
1472 #ifndef __FJCORE_DROP_CGAL
1473  } else if ((N > 16000/pow(_Rparam,1.15) && _jet_def.jet_algorithm() != antikt_algorithm)
1474  || N > 35000/pow(_Rparam,1.15)) {
1475  _strategy = NlnN;
1476 #endif // __FJCORE_DROP_CGAL
1477  } else if (N <= 450) {
1478  _strategy = N2Tiled;
1479  } else {
1480  _strategy = N2MinHeapTiled;
1481  }
1482  }
1483  if (_Rparam >= twopi) {
1484  if ( _strategy == NlnN
1485  || _strategy == NlnN3pi
1486  || _strategy == NlnNCam
1487  || _strategy == NlnNCam2pi2R
1488  || _strategy == NlnNCam4pi) {
1489 #ifdef __FJCORE_DROP_CGAL
1490  _strategy = N2MinHeapTiled;
1491 #else
1492  _strategy = NlnN4pi;
1493 #endif
1494  }
1495  if (_jet_def.strategy() != Best && _strategy != _jet_def.strategy()) {
1496  ostringstream oss;
1497  oss << "Cluster strategy " << strategy_string(_jet_def.strategy())
1498  << " automatically changed to " << strategy_string()
1499  << " because the former is not supported for R = " << _Rparam
1500  << " >= 2pi";
1501  _changed_strategy_warning.warn(oss.str());
1502  }
1503  }
1504  if (_strategy == N2Plain) {
1505  this->_simple_N2_cluster_BriefJet();
1506  } else if (_strategy == N2Tiled) {
1507  this->_faster_tiled_N2_cluster();
1508  } else if (_strategy == N2MinHeapTiled) {
1509  this->_minheap_faster_tiled_N2_cluster();
1510  } else if (_strategy == N2MHTLazy9Alt) {
1511  _plugin_activated = true;
1512  LazyTiling9Alt tiling(*this);
1513  tiling.run();
1514  _plugin_activated = false;
1515  } else if (_strategy == N2MHTLazy25) {
1516  _plugin_activated = true;
1517  LazyTiling25 tiling(*this);
1518  tiling.run();
1519  _plugin_activated = false;
1520  } else if (_strategy == N2MHTLazy9) {
1521  _plugin_activated = true;
1522  LazyTiling9 tiling(*this);
1523  tiling.run();
1524  _plugin_activated = false;
1525  } else if (_strategy == N2MHTLazy9AntiKtSeparateGhosts) {
1526  throw Error("N2MHTLazy9AntiKtSeparateGhosts strategy not supported with FJCORE");
1527  } else if (_strategy == NlnN) {
1528  this->_delaunay_cluster();
1529  } else if (_strategy == NlnNCam) {
1530  this->_CP2DChan_cluster_2piMultD();
1531  } else if (_strategy == NlnN3pi || _strategy == NlnN4pi ) {
1532  this->_delaunay_cluster();
1533  } else if (_strategy == N3Dumb ) {
1534  this->_really_dumb_cluster();
1535  } else if (_strategy == N2PoorTiled) {
1536  this->_tiled_N2_cluster();
1537  } else if (_strategy == NlnNCam4pi) {
1538  this->_CP2DChan_cluster();
1539  } else if (_strategy == NlnNCam2pi2R) {
1540  this->_CP2DChan_cluster_2pi2R();
1541  } else {
1542  ostringstream err;
1543  err << "Unrecognised value for strategy: "<<_strategy;
1544  throw Error(err.str());
1545  }
1546 }
1547 bool ClusterSequence::_first_time = true;
1548 LimitedWarning ClusterSequence::_exclusive_warnings;
1549 string fastjet_version_string() {
1550  return "FastJet version "+string(fastjet_version)+" [fjcore]";
1551 }
1552 void ClusterSequence::print_banner() {
1553  if (!_first_time) {return;}
1554  _first_time = false;
1555  ostream * ostr = _fastjet_banner_ostr;
1556  if (!ostr) return;
1557  (*ostr) << "#--------------------------------------------------------------------------\n";
1558  (*ostr) << "# FastJet release " << fastjet_version << " [fjcore]" << endl;
1559  (*ostr) << "# M. Cacciari, G.P. Salam and G. Soyez \n";
1560  (*ostr) << "# A software package for jet finding and analysis at colliders \n";
1561  (*ostr) << "# http://fastjet.fr \n";
1562  (*ostr) << "# \n";
1563  (*ostr) << "# Please cite EPJC72(2012)1896 [arXiv:1111.6097] if you use this package\n";
1564  (*ostr) << "# for scientific work and optionally PLB641(2006)57 [hep-ph/0512210]. \n";
1565  (*ostr) << "# \n";
1566  (*ostr) << "# FastJet is provided without warranty under the terms of the GNU GPLv2.\n";
1567  (*ostr) << "# It uses T. Chan's closest pair algorithm, S. Fortune's Voronoi code";
1568 #ifndef __FJCORE_DROP_CGAL
1569  (*ostr) << ",\n# CGAL ";
1570 #else
1571  (*ostr) << "\n# ";
1572 #endif // __FJCORE_DROP_CGAL
1573  (*ostr) << "and 3rd party plugin jet algorithms. See COPYING file for details.\n";
1574  (*ostr) << "#--------------------------------------------------------------------------\n";
1575  ostr->flush();
1576 }
1577 void ClusterSequence::_decant_options(const JetDefinition & jet_def_in,
1578  const bool & writeout_combinations) {
1579  _jet_def = jet_def_in;
1580  _writeout_combinations = writeout_combinations;
1581  _structure_shared_ptr.reset(new ClusterSequenceStructure(this));
1582  _decant_options_partial();
1583 }
1584 void ClusterSequence::_decant_options_partial() {
1585  print_banner();
1586  _jet_algorithm = _jet_def.jet_algorithm();
1587  _Rparam = _jet_def.R(); _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
1588  _strategy = _jet_def.strategy();
1589  _plugin_activated = false;
1590  _update_structure_use_count(); // make sure it's correct already here
1591 }
1592 void ClusterSequence::_fill_initial_history () {
1593  _jets.reserve(_jets.size()*2);
1594  _history.reserve(_jets.size()*2);
1595  _Qtot = 0;
1596  for (int i = 0; i < static_cast<int>(_jets.size()) ; i++) {
1597  history_element element;
1598  element.parent1 = InexistentParent;
1599  element.parent2 = InexistentParent;
1600  element.child = Invalid;
1601  element.jetp_index = i;
1602  element.dij = 0.0;
1603  element.max_dij_so_far = 0.0;
1604  _history.push_back(element);
1605  _jet_def.recombiner()->preprocess(_jets[i]);
1606  _jets[i].set_cluster_hist_index(i);
1607  _set_structure_shared_ptr(_jets[i]);
1608  _Qtot += _jets[i].E();
1609  }
1610  _initial_n = _jets.size();
1611  _deletes_self_when_unused = false;
1612 }
1613 string ClusterSequence::strategy_string (Strategy strategy_in) const {
1614  string strategy;
1615  switch(strategy_in) {
1616  case NlnN:
1617  strategy = "NlnN"; break;
1618  case NlnN3pi:
1619  strategy = "NlnN3pi"; break;
1620  case NlnN4pi:
1621  strategy = "NlnN4pi"; break;
1622  case N2Plain:
1623  strategy = "N2Plain"; break;
1624  case N2Tiled:
1625  strategy = "N2Tiled"; break;
1626  case N2MinHeapTiled:
1627  strategy = "N2MinHeapTiled"; break;
1628  case N2PoorTiled:
1629  strategy = "N2PoorTiled"; break;
1630  case N2MHTLazy9:
1631  strategy = "N2MHTLazy9"; break;
1632  case N2MHTLazy9Alt:
1633  strategy = "N2MHTLazy9Alt"; break;
1634  case N2MHTLazy25:
1635  strategy = "N2MHTLazy25"; break;
1636  case N2MHTLazy9AntiKtSeparateGhosts:
1637  strategy = "N2MHTLazy9AntiKtSeparateGhosts"; break;
1638  case N3Dumb:
1639  strategy = "N3Dumb"; break;
1640  case NlnNCam4pi:
1641  strategy = "NlnNCam4pi"; break;
1642  case NlnNCam2pi2R:
1643  strategy = "NlnNCam2pi2R"; break;
1644  case NlnNCam:
1645  strategy = "NlnNCam"; break; // 2piMultD
1646  case plugin_strategy:
1647  strategy = "plugin strategy"; break;
1648  default:
1649  strategy = "Unrecognized";
1650  }
1651  return strategy;
1652 }
1653 double ClusterSequence::jet_scale_for_algorithm(
1654  const PseudoJet & jet) const {
1655  if (_jet_algorithm == kt_algorithm) {return jet.kt2();}
1656  else if (_jet_algorithm == cambridge_algorithm) {return 1.0;}
1657  else if (_jet_algorithm == antikt_algorithm) {
1658  double kt2=jet.kt2();
1659  return kt2 > 1e-300 ? 1.0/kt2 : 1e300;
1660  } else if (_jet_algorithm == genkt_algorithm) {
1661  double kt2 = jet.kt2();
1662  double p = jet_def().extra_param();
1663  if (p <= 0 && kt2 < 1e-300) kt2 = 1e-300; // dodgy safety check
1664  return pow(kt2, p);
1665  } else if (_jet_algorithm == cambridge_for_passive_algorithm) {
1666  double kt2 = jet.kt2();
1667  double lim = _jet_def.extra_param();
1668  if (kt2 < lim*lim && kt2 != 0.0) {
1669  return 1.0/kt2;
1670  } else {return 1.0;}
1671  } else {throw Error("Unrecognised jet algorithm");}
1672 }
1673 Strategy ClusterSequence::_best_strategy() const {
1674  int N = _jets.size();
1675  double bounded_R = max(_Rparam, 0.1);
1676  if (N <= 30 || N <= 39.0/(bounded_R + 0.6)) {
1677  return N2Plain;
1678  }
1679  const static _Parabola N_Tiled_to_MHT_lowR (-45.4947,54.3528,44.6283);
1680  const static _Parabola L_MHT_to_MHTLazy9_lowR (0.677807,-1.05006,10.6994);
1681  const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_lowR(0.169967,-0.512589,12.1572);
1682  const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_lowR (0.16237,-0.484612,12.3373);
1683  const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_lowR = L_MHTLazy9_to_MHTLazy25_kt_lowR;
1684  const static _Parabola L_MHTLazy25_to_NlnN_akt_lowR (0.0472051,-0.22043,15.9196);
1685  const static _Parabola L_MHTLazy25_to_NlnN_kt_lowR (0.118609,-0.326811,14.8287);
1686  const static _Parabola L_MHTLazy25_to_NlnN_cam_lowR (0.10119,-0.295748,14.3924);
1687  const static _Line L_Tiled_to_MHTLazy9_medR (-1.31304,7.29621);
1688  const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_medR = L_MHTLazy9_to_MHTLazy25_akt_lowR;
1689  const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_medR = L_MHTLazy9_to_MHTLazy25_kt_lowR;
1690  const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_medR = L_MHTLazy9_to_MHTLazy25_cam_lowR;
1691  const static _Parabola L_MHTLazy25_to_NlnN_akt_medR = L_MHTLazy25_to_NlnN_akt_lowR;
1692  const static _Parabola L_MHTLazy25_to_NlnN_kt_medR = L_MHTLazy25_to_NlnN_kt_lowR;
1693  const static _Parabola L_MHTLazy25_to_NlnN_cam_medR = L_MHTLazy25_to_NlnN_cam_lowR;
1694  const static double N_Plain_to_MHTLazy9_largeR = 75;
1695  const static double N_MHTLazy9_to_MHTLazy25_akt_largeR = 700;
1696  const static double N_MHTLazy9_to_MHTLazy25_kt_largeR = 1000;
1697  const static double N_MHTLazy9_to_MHTLazy25_cam_largeR = 1000;
1698  const static double N_MHTLazy25_to_NlnN_akt_largeR = 100000;
1699  const static double N_MHTLazy25_to_NlnN_kt_largeR = 40000;
1700  const static double N_MHTLazy25_to_NlnN_cam_largeR = 15000;
1701  JetAlgorithm jet_algorithm;
1702  if (_jet_algorithm == genkt_algorithm) {
1703  double p = jet_def().extra_param();
1704  if (p < 0.0) jet_algorithm = antikt_algorithm;
1705  else jet_algorithm = kt_algorithm;
1706  } else if (_jet_algorithm == cambridge_for_passive_algorithm) {
1707  jet_algorithm = kt_algorithm;
1708  } else {
1709  jet_algorithm = _jet_algorithm;
1710  }
1711  if (bounded_R < 0.65) {
1712  if (N < N_Tiled_to_MHT_lowR(bounded_R)) return N2Tiled;
1713  double logN = log(double(N));
1714  if (logN < L_MHT_to_MHTLazy9_lowR(bounded_R)) return N2MinHeapTiled;
1715  else {
1716  if (jet_algorithm == antikt_algorithm){
1717  if (logN < L_MHTLazy9_to_MHTLazy25_akt_lowR(bounded_R)) return N2MHTLazy9;
1718  else if (logN < L_MHTLazy25_to_NlnN_akt_lowR(bounded_R)) return N2MHTLazy25;
1719  else return NlnN;
1720  } else if (jet_algorithm == kt_algorithm){
1721  if (logN < L_MHTLazy9_to_MHTLazy25_kt_lowR(bounded_R)) return N2MHTLazy9;
1722  else if (logN < L_MHTLazy25_to_NlnN_kt_lowR(bounded_R)) return N2MHTLazy25;
1723  else return NlnN;
1724  } else if (jet_algorithm == cambridge_algorithm) {
1725  if (logN < L_MHTLazy9_to_MHTLazy25_cam_lowR(bounded_R)) return N2MHTLazy9;
1726  else if (logN < L_MHTLazy25_to_NlnN_cam_lowR(bounded_R)) return N2MHTLazy25;
1727  else return NlnNCam;
1728  }
1729  }
1730  } else if (bounded_R < 0.5*pi) {
1731  double logN = log(double(N));
1732  if (logN < L_Tiled_to_MHTLazy9_medR(bounded_R)) return N2Tiled;
1733  else {
1734  if (jet_algorithm == antikt_algorithm){
1735  if (logN < L_MHTLazy9_to_MHTLazy25_akt_medR(bounded_R)) return N2MHTLazy9;
1736  else if (logN < L_MHTLazy25_to_NlnN_akt_medR(bounded_R)) return N2MHTLazy25;
1737  else return NlnN;
1738  } else if (jet_algorithm == kt_algorithm){
1739  if (logN < L_MHTLazy9_to_MHTLazy25_kt_medR(bounded_R)) return N2MHTLazy9;
1740  else if (logN < L_MHTLazy25_to_NlnN_kt_medR(bounded_R)) return N2MHTLazy25;
1741  else return NlnN;
1742  } else if (jet_algorithm == cambridge_algorithm) {
1743  if (logN < L_MHTLazy9_to_MHTLazy25_cam_medR(bounded_R)) return N2MHTLazy9;
1744  else if (logN < L_MHTLazy25_to_NlnN_cam_medR(bounded_R)) return N2MHTLazy25;
1745  else return NlnNCam;
1746  }
1747  }
1748  } else {
1749  if (N < N_Plain_to_MHTLazy9_largeR) return N2Plain;
1750  else {
1751  if (jet_algorithm == antikt_algorithm){
1752  if (N < N_MHTLazy9_to_MHTLazy25_akt_largeR) return N2MHTLazy9;
1753  else if (N < N_MHTLazy25_to_NlnN_akt_largeR) return N2MHTLazy25;
1754  else return NlnN;
1755  } else if (jet_algorithm == kt_algorithm){
1756  if (N < N_MHTLazy9_to_MHTLazy25_kt_largeR) return N2MHTLazy9;
1757  else if (N < N_MHTLazy25_to_NlnN_kt_largeR) return N2MHTLazy25;
1758  else return NlnN;
1759  } else if (jet_algorithm == cambridge_algorithm) {
1760  if (N < N_MHTLazy9_to_MHTLazy25_cam_largeR) return N2MHTLazy9;
1761  else if (N < N_MHTLazy25_to_NlnN_cam_largeR) return N2MHTLazy25;
1762  else return NlnNCam;
1763  }
1764  }
1765  }
1766  assert(0 && "Code should never reach here");
1767  return N2MHTLazy9;
1768 }
1769 ClusterSequence & ClusterSequence::operator=(const ClusterSequence & cs) {
1770  if (&cs != this) {
1771  _deletes_self_when_unused = false;
1772  transfer_from_sequence(cs);
1773  }
1774  return *this;
1775 }
1776 void ClusterSequence::transfer_from_sequence(const ClusterSequence & from_seq,
1777  const FunctionOfPseudoJet<PseudoJet> * action_on_jets){
1778  if (will_delete_self_when_unused())
1779  throw(Error("cannot use CS::transfer_from_sequence after a call to delete_self_when_unused()"));
1780  _jet_def = from_seq._jet_def ;
1781  _writeout_combinations = from_seq._writeout_combinations ;
1782  _initial_n = from_seq._initial_n ;
1783  _Rparam = from_seq._Rparam ;
1784  _R2 = from_seq._R2 ;
1785  _invR2 = from_seq._invR2 ;
1786  _strategy = from_seq._strategy ;
1787  _jet_algorithm = from_seq._jet_algorithm ;
1788  _plugin_activated = from_seq._plugin_activated ;
1789  if (action_on_jets)
1790  _jets = (*action_on_jets)(from_seq._jets);
1791  else
1792  _jets = from_seq._jets;
1793  _history = from_seq._history;
1794  _extras = from_seq._extras;
1795  if (_structure_shared_ptr) {
1796  if (_deletes_self_when_unused) throw Error("transfer_from_sequence cannot be used for a cluster sequence that deletes self when unused");
1797  ClusterSequenceStructure* csi = dynamic_cast<ClusterSequenceStructure*>(_structure_shared_ptr.get());
1798  assert(csi != NULL);
1799  csi->set_associated_cs(NULL);
1800  }
1801  _structure_shared_ptr.reset(new ClusterSequenceStructure(this));
1802  _update_structure_use_count();
1803  for (unsigned int i=0; i<_jets.size(); i++){
1804  _jets[i].set_cluster_hist_index(from_seq._jets[i].cluster_hist_index());
1805  _set_structure_shared_ptr(_jets[i]);
1806  }
1807 }
1808 void ClusterSequence::plugin_record_ij_recombination(
1809  int jet_i, int jet_j, double dij,
1810  const PseudoJet & newjet, int & newjet_k) {
1811  plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
1812  int tmp_index = _jets[newjet_k].cluster_hist_index();
1813  _jets[newjet_k] = newjet;
1814  _jets[newjet_k].set_cluster_hist_index(tmp_index);
1815  _set_structure_shared_ptr(_jets[newjet_k]);
1816 }
1817 vector<PseudoJet> ClusterSequence::inclusive_jets (const double ptmin) const{
1818  double dcut = ptmin*ptmin;
1819  int i = _history.size() - 1; // last jet
1820  vector<PseudoJet> jets_local;
1821  if (_jet_algorithm == kt_algorithm) {
1822  while (i >= 0) {
1823  if (_history[i].max_dij_so_far < dcut) {break;}
1824  if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
1825  // for beam jets
1826  int parent1 = _history[i].parent1;
1827  jets_local.push_back(_jets[_history[parent1].jetp_index]);}
1828  i--;
1829  }
1830  } else if (_jet_algorithm == cambridge_algorithm) {
1831  while (i >= 0) {
1832  if (_history[i].parent2 != BeamJet) {break;}
1833  int parent1 = _history[i].parent1;
1834  const PseudoJet & jet = _jets[_history[parent1].jetp_index];
1835  if (jet.perp2() >= dcut) {jets_local.push_back(jet);}
1836  i--;
1837  }
1838  } else if (_jet_algorithm == plugin_algorithm
1839  || _jet_algorithm == ee_kt_algorithm
1840  || _jet_algorithm == antikt_algorithm
1841  || _jet_algorithm == genkt_algorithm
1842  || _jet_algorithm == ee_genkt_algorithm
1843  || _jet_algorithm == cambridge_for_passive_algorithm) {
1844  while (i >= 0) {
1845  if (_history[i].parent2 == BeamJet) {
1846  int parent1 = _history[i].parent1;
1847  const PseudoJet & jet = _jets[_history[parent1].jetp_index];
1848  if (jet.perp2() >= dcut) {jets_local.push_back(jet);}
1849  }
1850  i--;
1851  }
1852  } else {throw Error("cs::inclusive_jets(...): Unrecognized jet algorithm");}
1853  return jets_local;
1854 }
1855 int ClusterSequence::n_exclusive_jets (const double dcut) const {
1856  int i = _history.size() - 1; // last jet
1857  while (i >= 0) {
1858  if (_history[i].max_dij_so_far <= dcut) {break;}
1859  i--;
1860  }
1861  int stop_point = i + 1;
1862  int njets = 2*_initial_n - stop_point;
1863  return njets;
1864 }
1865 vector<PseudoJet> ClusterSequence::exclusive_jets (const double dcut) const {
1866  int njets = n_exclusive_jets(dcut);
1867  return exclusive_jets(njets);
1868 }
1869 vector<PseudoJet> ClusterSequence::exclusive_jets (const int njets) const {
1870  if (njets > _initial_n) {
1871  ostringstream err;
1872  err << "Requested " << njets << " exclusive jets, but there were only "
1873  << _initial_n << " particles in the event";
1874  throw Error(err.str());
1875  }
1876  return exclusive_jets_up_to(njets);
1877 }
1878 vector<PseudoJet> ClusterSequence::exclusive_jets_up_to (const int njets) const {
1879  if (( _jet_def.jet_algorithm() != kt_algorithm) &&
1880  ( _jet_def.jet_algorithm() != cambridge_algorithm) &&
1881  ( _jet_def.jet_algorithm() != ee_kt_algorithm) &&
1882  (((_jet_def.jet_algorithm() != genkt_algorithm) &&
1883  (_jet_def.jet_algorithm() != ee_genkt_algorithm)) ||
1884  (_jet_def.extra_param() <0)) &&
1885  ((_jet_def.jet_algorithm() != plugin_algorithm) ||
1886  (!_jet_def.plugin()->exclusive_sequence_meaningful()))) {
1887  _exclusive_warnings.warn("dcut and exclusive jets for jet-finders other than kt, C/A or genkt with p>=0 should be interpreted with care.");
1888  }
1889  int stop_point = 2*_initial_n - njets;
1890  if (stop_point < _initial_n) stop_point = _initial_n;
1891  if (2*_initial_n != static_cast<int>(_history.size())) {
1892  ostringstream err;
1893  err << "2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
1894  throw Error(err.str());
1895  }
1896  vector<PseudoJet> jets_local;
1897  for (unsigned int i = stop_point; i < _history.size(); i++) {
1898  int parent1 = _history[i].parent1;
1899  if (parent1 < stop_point) {
1900  jets_local.push_back(_jets[_history[parent1].jetp_index]);
1901  }
1902  int parent2 = _history[i].parent2;
1903  if (parent2 < stop_point && parent2 > 0) {
1904  jets_local.push_back(_jets[_history[parent2].jetp_index]);
1905  }
1906  }
1907  if (int(jets_local.size()) != min(_initial_n, njets)) {
1908  ostringstream err;
1909  err << "ClusterSequence::exclusive_jets: size of returned vector ("
1910  <<jets_local.size()<<") does not coincide with requested number of jets ("
1911  <<njets<<")";
1912  throw Error(err.str());
1913  }
1914  return jets_local;
1915 }
1916 double ClusterSequence::exclusive_dmerge (const int njets) const {
1917  assert(njets >= 0);
1918  if (njets >= _initial_n) {return 0.0;}
1919  return _history[2*_initial_n-njets-1].dij;
1920 }
1921 double ClusterSequence::exclusive_dmerge_max (const int njets) const {
1922  assert(njets >= 0);
1923  if (njets >= _initial_n) {return 0.0;}
1924  return _history[2*_initial_n-njets-1].max_dij_so_far;
1925 }
1926 std::vector<PseudoJet> ClusterSequence::exclusive_subjets
1927  (const PseudoJet & jet, const double dcut) const {
1928  set<const history_element*> subhist;
1929  get_subhist_set(subhist, jet, dcut, 0);
1930  vector<PseudoJet> subjets;
1931  subjets.reserve(subhist.size());
1932  for (set<const history_element*>::iterator elem = subhist.begin();
1933  elem != subhist.end(); elem++) {
1934  subjets.push_back(_jets[(*elem)->jetp_index]);
1935  }
1936  return subjets;
1937 }
1938 int ClusterSequence::n_exclusive_subjets(const PseudoJet & jet,
1939  const double dcut) const {
1940  set<const history_element*> subhist;
1941  get_subhist_set(subhist, jet, dcut, 0);
1942  return subhist.size();
1943 }
1944 std::vector<PseudoJet> ClusterSequence::exclusive_subjets
1945  (const PseudoJet & jet, int nsub) const {
1946  vector<PseudoJet> subjets = exclusive_subjets_up_to(jet, nsub);
1947  if (int(subjets.size()) < nsub) {
1948  ostringstream err;
1949  err << "Requested " << nsub << " exclusive subjets, but there were only "
1950  << subjets.size() << " particles in the jet";
1951  throw Error(err.str());
1952  }
1953  return subjets;
1954 }
1955 std::vector<PseudoJet> ClusterSequence::exclusive_subjets_up_to
1956  (const PseudoJet & jet, int nsub) const {
1957  set<const history_element*> subhist;
1958  vector<PseudoJet> subjets;
1959  if (nsub < 0) throw Error("Requested a negative number of subjets. This is nonsensical.");
1960  if (nsub == 0) return subjets;
1961  get_subhist_set(subhist, jet, -1.0, nsub);
1962  subjets.reserve(subhist.size());
1963  for (set<const history_element*>::iterator elem = subhist.begin();
1964  elem != subhist.end(); elem++) {
1965  subjets.push_back(_jets[(*elem)->jetp_index]);
1966  }
1967  return subjets;
1968 }
1969 double ClusterSequence::exclusive_subdmerge(const PseudoJet & jet, int nsub) const {
1970  set<const history_element*> subhist;
1971  get_subhist_set(subhist, jet, -1.0, nsub);
1972  set<const history_element*>::iterator highest = subhist.end();
1973  highest--;
1974  return (*highest)->dij;
1975 }
1976 double ClusterSequence::exclusive_subdmerge_max(const PseudoJet & jet, int nsub) const {
1977  set<const history_element*> subhist;
1978  get_subhist_set(subhist, jet, -1.0, nsub);
1979  set<const history_element*>::iterator highest = subhist.end();
1980  highest--;
1981  return (*highest)->max_dij_so_far;
1982 }
1983 void ClusterSequence::get_subhist_set(set<const history_element*> & subhist,
1984  const PseudoJet & jet,
1985  double dcut, int maxjet) const {
1986  assert(contains(jet));
1987  subhist.clear();
1988  subhist.insert(&(_history[jet.cluster_hist_index()]));
1989  int njet = 1;
1990  while (true) {
1991  set<const history_element*>::iterator highest = subhist.end();
1992  assert (highest != subhist.begin());
1993  highest--;
1994  const history_element* elem = *highest;
1995  if (njet == maxjet) break;
1996  if (elem->parent1 < 0) break;
1997  if (elem->max_dij_so_far <= dcut) break;
1998  subhist.erase(highest);
1999  subhist.insert(&(_history[elem->parent1]));
2000  subhist.insert(&(_history[elem->parent2]));
2001  njet++;
2002  }
2003 }
2004 bool ClusterSequence::object_in_jet(const PseudoJet & object,
2005  const PseudoJet & jet) const {
2006  assert(contains(object) && contains(jet));
2007  const PseudoJet * this_object = &object;
2008  const PseudoJet * childp;
2009  while(true) {
2010  if (this_object->cluster_hist_index() == jet.cluster_hist_index()) {
2011  return true;
2012  } else if (has_child(*this_object, childp)) {
2013  this_object = childp;
2014  } else {
2015  return false;
2016  }
2017  }
2018 }
2019 bool ClusterSequence::has_parents(const PseudoJet & jet, PseudoJet & parent1,
2020  PseudoJet & parent2) const {
2021  const history_element & hist = _history[jet.cluster_hist_index()];
2022  assert ((hist.parent1 >= 0 && hist.parent2 >= 0) ||
2023  (hist.parent1 < 0 && hist.parent2 < 0));
2024  if (hist.parent1 < 0) {
2025  parent1 = PseudoJet(0.0,0.0,0.0,0.0);
2026  parent2 = parent1;
2027  return false;
2028  } else {
2029  parent1 = _jets[_history[hist.parent1].jetp_index];
2030  parent2 = _jets[_history[hist.parent2].jetp_index];
2031  if (parent1.perp2() < parent2.perp2()) std::swap(parent1,parent2);
2032  return true;
2033  }
2034 }
2035 bool ClusterSequence::has_child(const PseudoJet & jet, PseudoJet & child) const {
2036  const PseudoJet * childp;
2037  bool res = has_child(jet, childp);
2038  if (res) {
2039  child = *childp;
2040  return true;
2041  } else {
2042  child = PseudoJet(0.0,0.0,0.0,0.0);
2043  return false;
2044  }
2045 }
2046 bool ClusterSequence::has_child(const PseudoJet & jet, const PseudoJet * & childp) const {
2047  const history_element & hist = _history[jet.cluster_hist_index()];
2048  if (hist.child >= 0 && _history[hist.child].jetp_index >= 0) {
2049  childp = &(_jets[_history[hist.child].jetp_index]);
2050  return true;
2051  } else {
2052  childp = NULL;
2053  return false;
2054  }
2055 }
2056 bool ClusterSequence::has_partner(const PseudoJet & jet,
2057  PseudoJet & partner) const {
2058  const history_element & hist = _history[jet.cluster_hist_index()];
2059  if (hist.child >= 0 && _history[hist.child].parent2 >= 0) {
2060  const history_element & child_hist = _history[hist.child];
2061  if (child_hist.parent1 == jet.cluster_hist_index()) {
2062  partner = _jets[_history[child_hist.parent2].jetp_index];
2063  } else {
2064  partner = _jets[_history[child_hist.parent1].jetp_index];
2065  }
2066  return true;
2067  } else {
2068  partner = PseudoJet(0.0,0.0,0.0,0.0);
2069  return false;
2070  }
2071 }
2072 vector<PseudoJet> ClusterSequence::constituents (const PseudoJet & jet) const {
2073  vector<PseudoJet> subjets;
2074  add_constituents(jet, subjets);
2075  return subjets;
2076 }
2077 void ClusterSequence::print_jets_for_root(const std::vector<PseudoJet> & jets_in,
2078  ostream & ostr) const {
2079  for (unsigned i = 0; i < jets_in.size(); i++) {
2080  ostr << i << " "
2081  << jets_in[i].px() << " "
2082  << jets_in[i].py() << " "
2083  << jets_in[i].pz() << " "
2084  << jets_in[i].E() << endl;
2085  vector<PseudoJet> cst = constituents(jets_in[i]);
2086  for (unsigned j = 0; j < cst.size() ; j++) {
2087  ostr << " " << j << " "
2088  << cst[j].rap() << " "
2089  << cst[j].phi() << " "
2090  << cst[j].perp() << endl;
2091  }
2092  ostr << "#END" << endl;
2093  }
2094 }
2095 void ClusterSequence::print_jets_for_root(const std::vector<PseudoJet> & jets_in,
2096  const std::string & filename,
2097  const std::string & comment ) const {
2098  std::ofstream ostr(filename.c_str());
2099  if (comment != "") ostr << "# " << comment << endl;
2100  print_jets_for_root(jets_in, ostr);
2101 }
2102 vector<int> ClusterSequence::particle_jet_indices(
2103  const vector<PseudoJet> & jets_in) const {
2104  vector<int> indices(n_particles());
2105  for (unsigned ipart = 0; ipart < n_particles(); ipart++)
2106  indices[ipart] = -1;
2107  for (unsigned ijet = 0; ijet < jets_in.size(); ijet++) {
2108  vector<PseudoJet> jet_constituents(constituents(jets_in[ijet]));
2109  for (unsigned ip = 0; ip < jet_constituents.size(); ip++) {
2110  unsigned iclust = jet_constituents[ip].cluster_hist_index();
2111  unsigned ipart = history()[iclust].jetp_index;
2112  indices[ipart] = ijet;
2113  }
2114  }
2115  return indices;
2116 }
2117 void ClusterSequence::add_constituents (
2118  const PseudoJet & jet, vector<PseudoJet> & subjet_vector) const {
2119  int i = jet.cluster_hist_index();
2120  int parent1 = _history[i].parent1;
2121  int parent2 = _history[i].parent2;
2122  if (parent1 == InexistentParent) {
2123  subjet_vector.push_back(_jets[i]);
2124  return;
2125  }
2126  add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
2127  if (parent2 != BeamJet) {
2128  add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
2129  }
2130 }
2131 void ClusterSequence::_add_step_to_history (
2132  const int parent1,
2133  const int parent2, const int jetp_index,
2134  const double dij) {
2135  history_element element;
2136  element.parent1 = parent1;
2137  element.parent2 = parent2;
2138  element.jetp_index = jetp_index;
2139  element.child = Invalid;
2140  element.dij = dij;
2141  element.max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
2142  _history.push_back(element);
2143  int local_step = _history.size()-1;
2144  assert(parent1 >= 0);
2145  if (_history[parent1].child != Invalid){
2146  throw InternalError("trying to recomine an object that has previsously been recombined");
2147  }
2148  _history[parent1].child = local_step;
2149  if (parent2 >= 0) {
2150  if (_history[parent2].child != Invalid){
2151  throw InternalError("trying to recomine an object that has previsously been recombined");
2152  }
2153  _history[parent2].child = local_step;
2154  }
2155  if (jetp_index != Invalid) {
2156  assert(jetp_index >= 0);
2157  _jets[jetp_index].set_cluster_hist_index(local_step);
2158  _set_structure_shared_ptr(_jets[jetp_index]);
2159  }
2160  if (_writeout_combinations) {
2161  cout << local_step << ": "
2162  << parent1 << " with " << parent2
2163  << "; y = "<< dij<<endl;
2164  }
2165 }
2166 vector<int> ClusterSequence::unique_history_order() const {
2167  valarray<int> lowest_constituent(_history.size());
2168  int hist_n = _history.size();
2169  lowest_constituent = hist_n; // give it a large number
2170  for (int i = 0; i < hist_n; i++) {
2171  lowest_constituent[i] = min(lowest_constituent[i],i);
2172  if (_history[i].child > 0) lowest_constituent[_history[i].child]
2173  = min(lowest_constituent[_history[i].child],lowest_constituent[i]);
2174  }
2175  valarray<bool> extracted(_history.size()); extracted = false;
2176  vector<int> unique_tree;
2177  unique_tree.reserve(_history.size());
2178  for (unsigned i = 0; i < n_particles(); i++) {
2179  if (!extracted[i]) {
2180  unique_tree.push_back(i);
2181  extracted[i] = true;
2182  _extract_tree_children(i, extracted, lowest_constituent, unique_tree);
2183  }
2184  }
2185  return unique_tree;
2186 }
2187 void ClusterSequence::_extract_tree_children(
2188  int position,
2189  valarray<bool> & extracted,
2190  const valarray<int> & lowest_constituent,
2191  vector<int> & unique_tree) const {
2192  if (!extracted[position]) {
2193  _extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
2194  }
2195  int child = _history[position].child;
2196  if (child >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
2197 }
2198 vector<PseudoJet> ClusterSequence::unclustered_particles() const {
2199  vector<PseudoJet> unclustered;
2200  for (unsigned i = 0; i < n_particles() ; i++) {
2201  if (_history[i].child == Invalid)
2202  unclustered.push_back(_jets[_history[i].jetp_index]);
2203  }
2204  return unclustered;
2205 }
2206 vector<PseudoJet> ClusterSequence::childless_pseudojets() const {
2207  vector<PseudoJet> unclustered;
2208  for (unsigned i = 0; i < _history.size() ; i++) {
2209  if ((_history[i].child == Invalid) && (_history[i].parent2 != BeamJet))
2210  unclustered.push_back(_jets[_history[i].jetp_index]);
2211  }
2212  return unclustered;
2213 }
2214 bool ClusterSequence::contains(const PseudoJet & jet) const {
2215  return jet.cluster_hist_index() >= 0
2216  && jet.cluster_hist_index() < int(_history.size())
2217  && jet.has_valid_cluster_sequence()
2218  && jet.associated_cluster_sequence() == this;
2219 }
2220 void ClusterSequence::_extract_tree_parents(
2221  int position,
2222  valarray<bool> & extracted,
2223  const valarray<int> & lowest_constituent,
2224  vector<int> & unique_tree) const {
2225  if (!extracted[position]) {
2226  int parent1 = _history[position].parent1;
2227  int parent2 = _history[position].parent2;
2228  if (parent1 >= 0 && parent2 >= 0) {
2229  if (lowest_constituent[parent1] > lowest_constituent[parent2])
2230  std::swap(parent1, parent2);
2231  }
2232  if (parent1 >= 0 && !extracted[parent1])
2233  _extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
2234  if (parent2 >= 0 && !extracted[parent2])
2235  _extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
2236  unique_tree.push_back(position);
2237  extracted[position] = true;
2238  }
2239 }
2240 void ClusterSequence::_do_ij_recombination_step(
2241  const int jet_i, const int jet_j,
2242  const double dij,
2243  int & newjet_k) {
2244  PseudoJet newjet(false);
2245  _jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
2246  _jets.push_back(newjet);
2247  newjet_k = _jets.size()-1;
2248  int newstep_k = _history.size();
2249  _jets[newjet_k].set_cluster_hist_index(newstep_k);
2250  int hist_i = _jets[jet_i].cluster_hist_index();
2251  int hist_j = _jets[jet_j].cluster_hist_index();
2252  _add_step_to_history(min(hist_i, hist_j), max(hist_i,hist_j),
2253  newjet_k, dij);
2254 }
2255 void ClusterSequence::_do_iB_recombination_step(
2256  const int jet_i, const double diB) {
2257  _add_step_to_history(_jets[jet_i].cluster_hist_index(),BeamJet,
2258  Invalid, diB);
2259 }
2260 LimitedWarning ClusterSequence::_changed_strategy_warning;
2261 void ClusterSequence::_set_structure_shared_ptr(PseudoJet & j) {
2262  j.set_structure_shared_ptr(_structure_shared_ptr);
2263  _update_structure_use_count();
2264 }
2265 void ClusterSequence::_update_structure_use_count() {
2266  _structure_use_count_after_construction = _structure_shared_ptr.use_count();
2267 }
2268 void ClusterSequence::delete_self_when_unused() {
2269  int new_count = _structure_shared_ptr.use_count() - _structure_use_count_after_construction;
2270  if (new_count <= 0) {
2271  throw Error("delete_self_when_unused may only be called if at least one object outside the CS (e.g. a jet) is already associated with the CS");
2272  }
2273  _structure_shared_ptr.set_count(new_count);
2274  _deletes_self_when_unused = true;
2275 }
2276 FJCORE_END_NAMESPACE
2277 #include<limits>
2278 #include<vector>
2279 #include<cmath>
2280 #include<iostream>
2281 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2282 using namespace std;
2283 namespace Private {
2284  class MirrorInfo{
2285  public:
2286  int orig, mirror;
2287  MirrorInfo(int a, int b) : orig(a), mirror(b) {}
2288  MirrorInfo() : orig(0), mirror(0) {} // set dummy values to keep static code checkers happy
2289  };
2290  bool make_mirror(Coord2D & point, double Dlim) {
2291  if (point.y < Dlim) {point.y += twopi; return true;}
2292  if (twopi-point.y < Dlim) {point.y -= twopi; return true;}
2293  return false;
2294  }
2295 }
2296 using namespace Private;
2297 void ClusterSequence::_CP2DChan_limited_cluster (double Dlim) {
2298  unsigned int n = _initial_n;
2299  vector<MirrorInfo> coordIDs(2*n); // coord IDs of a given jetID
2300  vector<int> jetIDs(2*n); // jet ID for a given coord ID
2301  vector<Coord2D> coords(2*n); // our coordinates (and copies)
2302  double Dlim4mirror = min(Dlim,pi);
2303  double minrap = numeric_limits<double>::max();
2304  double maxrap = -minrap;
2305  int coord_index = -1;
2306  int n_active = 0;
2307  for (unsigned jet_i = 0; jet_i < _jets.size(); jet_i++) {
2308  if (_history[_jets[jet_i].cluster_hist_index()].child != Invalid ||
2309  (_jets[jet_i].E() == abs(_jets[jet_i].pz()) &&
2310  _jets[jet_i].perp2() == 0.0)
2311  ) {continue;}
2312  n_active++;
2313  coordIDs[jet_i].orig = ++coord_index;
2314  coords[coord_index] = Coord2D(_jets[jet_i].rap(), _jets[jet_i].phi_02pi());
2315  jetIDs[coord_index] = jet_i;
2316  minrap = min(coords[coord_index].x,minrap);
2317  maxrap = max(coords[coord_index].x,maxrap);
2318  Coord2D mirror_point(coords[coord_index]);
2319  if (make_mirror(mirror_point, Dlim4mirror)) {
2320  coordIDs[jet_i].mirror = ++coord_index;
2321  coords[coord_index] = mirror_point;
2322  jetIDs[coord_index] = jet_i;
2323  } else {
2324  coordIDs[jet_i].mirror = Invalid;
2325  }
2326  }
2327  coords.resize(coord_index+1);
2328  Coord2D left_edge(minrap-1.0, -3.15); // a security margin below -pi
2329  Coord2D right_edge(maxrap+1.0, 9.45); // a security margin above 3*pi
2330  ClosestPair2D cp(coords, left_edge, right_edge);
2331  vector<Coord2D> new_points(2);
2332  vector<unsigned int> cIDs_to_remove(4);
2333  vector<unsigned int> new_cIDs(2);
2334  do {
2335  unsigned int cID1, cID2;
2336  double distance2;
2337  cp.closest_pair(cID1,cID2,distance2);
2338  if (distance2 > Dlim*Dlim) {break;}
2339  distance2 *= _invR2;
2340  int jet_i = jetIDs[cID1];
2341  int jet_j = jetIDs[cID2];
2342  assert (jet_i != jet_j); // to catch issue of recombining with mirror point
2343  int newjet_k;
2344  _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k);
2345  if (--n_active == 1) {break;}
2346  cIDs_to_remove.resize(0);
2347  cIDs_to_remove.push_back(coordIDs[jet_i].orig);
2348  cIDs_to_remove.push_back(coordIDs[jet_j].orig);
2349  if (coordIDs[jet_i].mirror != Invalid)
2350  cIDs_to_remove.push_back(coordIDs[jet_i].mirror);
2351  if (coordIDs[jet_j].mirror != Invalid)
2352  cIDs_to_remove.push_back(coordIDs[jet_j].mirror);
2353  Coord2D new_point(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi());
2354  new_points.resize(0);
2355  new_points.push_back(new_point);
2356  if (make_mirror(new_point, Dlim4mirror)) new_points.push_back(new_point); //< same warning as before concerning the mirroring
2357  cp.replace_many(cIDs_to_remove, new_points, new_cIDs);
2358  coordIDs[newjet_k].orig = new_cIDs[0];
2359  jetIDs[new_cIDs[0]] = newjet_k;
2360  if (new_cIDs.size() == 2) {
2361  coordIDs[newjet_k].mirror = new_cIDs[1];
2362  jetIDs[new_cIDs[1]] = newjet_k;
2363  } else {coordIDs[newjet_k].mirror = Invalid;}
2364  } while(true);
2365 }
2366 void ClusterSequence::_CP2DChan_cluster_2pi2R () {
2367  if (_jet_algorithm != cambridge_algorithm) throw Error("CP2DChan clustering method called for a jet-finder that is not the cambridge algorithm");
2368  _CP2DChan_limited_cluster(_Rparam);
2369  _do_Cambridge_inclusive_jets();
2370 }
2371 void ClusterSequence::_CP2DChan_cluster_2piMultD () {
2372  if (_Rparam >= 0.39) {
2373  _CP2DChan_limited_cluster(min(_Rparam/2,0.3));
2374  }
2375  _CP2DChan_cluster_2pi2R ();
2376 }
2377 void ClusterSequence::_CP2DChan_cluster () {
2378  if (_jet_algorithm != cambridge_algorithm) throw Error("_CP2DChan_cluster called for a jet-finder that is not the cambridge algorithm");
2379  unsigned int n = _jets.size();
2380  vector<MirrorInfo> coordIDs(2*n); // link from original to mirror indices
2381  vector<int> jetIDs(2*n); // link from mirror to original indices
2382  vector<Coord2D> coords(2*n); // our coordinates (and copies)
2383  double minrap = numeric_limits<double>::max();
2384  double maxrap = -minrap;
2385  int coord_index = 0;
2386  for (unsigned i = 0; i < n; i++) {
2387  if (_jets[i].E() == abs(_jets[i].pz()) && _jets[i].perp2() == 0.0) {
2388  coordIDs[i] = MirrorInfo(BeamJet,BeamJet);
2389  } else {
2390  coordIDs[i].orig = coord_index;
2391  coordIDs[i].mirror = coord_index+1;
2392  coords[coord_index] = Coord2D(_jets[i].rap(), _jets[i].phi_02pi());
2393  coords[coord_index+1] = Coord2D(_jets[i].rap(), _jets[i].phi_02pi()+twopi);
2394  jetIDs[coord_index] = i;
2395  jetIDs[coord_index+1] = i;
2396  minrap = min(coords[coord_index].x,minrap);
2397  maxrap = max(coords[coord_index].x,maxrap);
2398  coord_index += 2;
2399  }
2400  }
2401  for (unsigned i = n; i < 2*n; i++) {coordIDs[i].orig = Invalid;}
2402  coords.resize(coord_index);
2403  Coord2D left_edge(minrap-1.0, 0.0);
2404  Coord2D right_edge(maxrap+1.0, 2*twopi);
2405  ClosestPair2D cp(coords, left_edge, right_edge);
2406  vector<Coord2D> new_points(2);
2407  vector<unsigned int> cIDs_to_remove(4);
2408  vector<unsigned int> new_cIDs(2);
2409  do {
2410  unsigned int cID1, cID2;
2411  double distance2;
2412  cp.closest_pair(cID1,cID2,distance2);
2413  distance2 *= _invR2;
2414  if (distance2 > 1.0) {break;}
2415  int jet_i = jetIDs[cID1];
2416  int jet_j = jetIDs[cID2];
2417  assert (jet_i != jet_j); // to catch issue of recombining with mirror point
2418  int newjet_k;
2419  _do_ij_recombination_step(jet_i, jet_j, distance2, newjet_k);
2420  cIDs_to_remove[0] = coordIDs[jet_i].orig;
2421  cIDs_to_remove[1] = coordIDs[jet_i].mirror;
2422  cIDs_to_remove[2] = coordIDs[jet_j].orig;
2423  cIDs_to_remove[3] = coordIDs[jet_j].mirror;
2424  new_points[0] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi());
2425  new_points[1] = Coord2D(_jets[newjet_k].rap(),_jets[newjet_k].phi_02pi()+twopi);
2426  new_cIDs[0] = cp.replace(cIDs_to_remove[0], cIDs_to_remove[2], new_points[0]);
2427  new_cIDs[1] = cp.replace(cIDs_to_remove[1], cIDs_to_remove[3], new_points[1]);
2428  coordIDs[jet_i].orig = Invalid;
2429  coordIDs[jet_j].orig = Invalid;
2430  coordIDs[newjet_k] = MirrorInfo(new_cIDs[0], new_cIDs[1]);
2431  jetIDs[new_cIDs[0]] = newjet_k;
2432  jetIDs[new_cIDs[1]] = newjet_k;
2433  n--;
2434  if (n == 1) {break;}
2435  } while(true);
2436  _do_Cambridge_inclusive_jets();
2437 }
2438 void ClusterSequence::_do_Cambridge_inclusive_jets () {
2439  unsigned int n = _history.size();
2440  for (unsigned int hist_i = 0; hist_i < n; hist_i++) {
2441  if (_history[hist_i].child == Invalid) {
2442  _do_iB_recombination_step(_history[hist_i].jetp_index, 1.0);
2443  }
2444  }
2445 }
2446 FJCORE_END_NAMESPACE
2447 #include<iostream>
2448 #include<sstream>
2449 #include<cmath>
2450 #include <cstdlib>
2451 #include<cassert>
2452 #include<memory>
2453 #ifndef __FJCORE_DROP_CGAL // in case we do not have the code for CGAL
2454 #include "fastjet/internal/Dnn4piCylinder.hh"
2455 #include "fastjet/internal/Dnn3piCylinder.hh"
2456 #include "fastjet/internal/Dnn2piCylinder.hh"
2457 #endif // __FJCORE_DROP_CGAL
2458 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2459 using namespace std;
2460 void ClusterSequence::_delaunay_cluster () {
2461  int n = _jets.size();
2462  vector<EtaPhi> points(n); // recall EtaPhi is just a typedef'd pair<double>
2463  for (int i = 0; i < n; i++) {
2464  points[i] = EtaPhi(_jets[i].rap(),_jets[i].phi_02pi());
2465  points[i].sanitize(); // make sure things are in the right range
2466  }
2468  const bool verbose = false;
2469 #ifndef __FJCORE_DROP_CGAL // strategy = NlnN* are not supported if we drop CGAL...
2470  bool ignore_nearest_is_mirror = (_Rparam < twopi);
2471  if (_strategy == NlnN4pi) {
2472  DNN.reset(new Dnn4piCylinder(points,verbose));
2473  } else if (_strategy == NlnN3pi) {
2474  DNN.reset(new Dnn3piCylinder(points,ignore_nearest_is_mirror,verbose));
2475  } else if (_strategy == NlnN) {
2476  DNN.reset(new Dnn2piCylinder(points,ignore_nearest_is_mirror,verbose));
2477  } else
2478 #else
2479  if (_strategy == NlnN4pi || _strategy == NlnN3pi || _strategy == NlnN) {
2480  ostringstream err;
2481  err << "ERROR: Requested strategy "<<strategy_string()<<" but it is not"<<endl;
2482  err << " supported because FastJet was compiled without CGAL"<<endl;
2483  throw Error(err.str());
2484  } else
2485 #endif // __FJCORE_DROP_CGAL
2486  {
2487  assert(false);
2488  }
2489  DistMap DijMap;
2490  for (int ii = 0; ii < n; ii++) {
2491  _add_ktdistance_to_map(ii, DijMap, DNN.get());
2492  }
2493  for (int i=0;i<n;i++) {
2494  TwoVertices SmallestDijPair;
2495  int jet_i, jet_j;
2496  double SmallestDij;
2497  bool Valid2;
2498  bool recombine_with_beam;
2499  do {
2500  SmallestDij = DijMap.begin()->first;
2501  SmallestDijPair = DijMap.begin()->second;
2502  jet_i = SmallestDijPair.first;
2503  jet_j = SmallestDijPair.second;
2504  if (verbose) cout << "CS_Delaunay found recombination candidate: " << jet_i << " " << jet_j << " " << SmallestDij << endl; // GPS debugging
2505  DijMap.erase(DijMap.begin());
2506  recombine_with_beam = (jet_j == BeamJet);
2507  if (!recombine_with_beam) {Valid2 = DNN->Valid(jet_j);}
2508  else {Valid2 = true;}
2509  if (verbose) cout << "CS_Delaunay validities i & j: " << DNN->Valid(jet_i) << " " << Valid2 << endl;
2510  } while ( !DNN->Valid(jet_i) || !Valid2);
2511  if (! recombine_with_beam) {
2512  int nn; // will be index of new jet
2513  if (verbose) cout << "CS_Delaunay call _do_ij_recomb: " << jet_i << " " << jet_j << " " << SmallestDij << endl; // GPS debug
2514  _do_ij_recombination_step(jet_i, jet_j, SmallestDij, nn);
2515  EtaPhi newpoint(_jets[nn].rap(), _jets[nn].phi_02pi());
2516  newpoint.sanitize(); // make sure it is in correct range
2517  points.push_back(newpoint);
2518  } else {
2519  if (verbose) cout << "CS_Delaunay call _do_iB_recomb: " << jet_i << " " << SmallestDij << endl; // GPS debug
2520  _do_iB_recombination_step(jet_i, SmallestDij);
2521  }
2522  if (i == n-1) {break;}
2523  vector<int> updated_neighbours;
2524  if (! recombine_with_beam) {
2525  int point3;
2526  DNN->RemoveCombinedAddCombination(jet_i, jet_j,
2527  points[points.size()-1], point3,
2528  updated_neighbours);
2529  if (static_cast<unsigned int> (point3) != points.size()-1) {
2530  throw Error("INTERNAL ERROR: point3 != points.size()-1");}
2531  } else {
2532  DNN->RemovePoint(jet_i, updated_neighbours);
2533  }
2534  vector<int>::iterator it = updated_neighbours.begin();
2535  for (; it != updated_neighbours.end(); ++it) {
2536  int ii = *it;
2537  _add_ktdistance_to_map(ii, DijMap, DNN.get());
2538  }
2539  } // end clustering loop
2540 }
2541 void ClusterSequence::_add_ktdistance_to_map(
2542  const int ii,
2543  DistMap & DijMap,
2544  const DynamicNearestNeighbours * DNN) {
2545  double yiB = jet_scale_for_algorithm(_jets[ii]);
2546  if (yiB == 0.0) {
2547  DijMap.insert(DijEntry(yiB, TwoVertices(ii,-1)));
2548  } else {
2549  double DeltaR2 = DNN->NearestNeighbourDistance(ii) * _invR2;
2550  if (DeltaR2 > 1.0) {
2551  DijMap.insert(DijEntry(yiB, TwoVertices(ii,-1)));
2552  } else {
2553  double kt2i = jet_scale_for_algorithm(_jets[ii]);
2554  int jj = DNN->NearestNeighbourIndex(ii);
2555  if (kt2i <= jet_scale_for_algorithm(_jets[jj])) {
2556  double dij = DeltaR2 * kt2i;
2557  DijMap.insert(DijEntry(dij, TwoVertices(ii,jj)));
2558  }
2559  }
2560  }
2561 }
2562 FJCORE_END_NAMESPACE
2563 #include<iostream>
2564 #include<cmath>
2565 #include <cstdlib>
2566 #include<cassert>
2567 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2568 using namespace std;
2569 void ClusterSequence::_really_dumb_cluster () {
2570  vector<PseudoJet *> jetsp(_jets.size());
2571  vector<int> indices(_jets.size());
2572  for (size_t i = 0; i<_jets.size(); i++) {
2573  jetsp[i] = & _jets[i];
2574  indices[i] = i;
2575  }
2576  for (int n = jetsp.size(); n > 0; n--) {
2577  int ii, jj;
2578  double ymin = jet_scale_for_algorithm(*(jetsp[0]));
2579  ii = 0; jj = -2;
2580  for (int i = 0; i < n; i++) {
2581  double yiB = jet_scale_for_algorithm(*(jetsp[i]));
2582  if (yiB < ymin) {
2583  ymin = yiB; ii = i; jj = -2;}
2584  }
2585  for (int i = 0; i < n-1; i++) {
2586  for (int j = i+1; j < n; j++) {
2587  //double y = jetsp[i]->kt_distance(*jetsp[j])*_invR2;
2588  double y = min(jet_scale_for_algorithm(*(jetsp[i])),
2589  jet_scale_for_algorithm(*(jetsp[j])))
2590  * jetsp[i]->plain_distance(*jetsp[j])*_invR2;
2591  if (y < ymin) {ymin = y; ii = i; jj = j;}
2592  }
2593  }
2594  int newn = 2*jetsp.size() - n;
2595  if (jj >= 0) {
2596  int nn; // new jet index
2597  _do_ij_recombination_step(jetsp[ii]-&_jets[0],
2598  jetsp[jj]-&_jets[0], ymin, nn);
2599  jetsp[ii] = &_jets[nn];
2600  jetsp[jj] = jetsp[n-1];
2601  indices[ii] = newn;
2602  indices[jj] = indices[n-1];
2603  } else {
2604  _do_iB_recombination_step(jetsp[ii]-&_jets[0], ymin);
2605  jetsp[ii] = jetsp[n-1];
2606  indices[ii] = indices[n-1];
2607  }
2608  }
2609 }
2610 FJCORE_END_NAMESPACE
2611 #include<iostream>
2612 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2613 using namespace std;
2614 template<> inline void ClusterSequence::_bj_set_jetinfo(
2615  EEBriefJet * const jetA, const int _jets_index) const {
2616  double E = _jets[_jets_index].E();
2617  double scale = E*E; // the default energy scale for the kt alg
2618  double p = jet_def().extra_param(); // in case we're ee_genkt
2619  switch (_jet_algorithm) {
2620  case ee_kt_algorithm:
2621  assert(_Rparam > 2.0); // force this to be true! [not best place, but works]
2622  break;
2623  case ee_genkt_algorithm:
2624  if (p <= 0 && scale < 1e-300) scale = 1e-300; // same dodgy safety as genkt
2625  scale = pow(scale,p);
2626  break;
2627  default:
2628  throw Error("Unrecognised jet algorithm");
2629  }
2630  jetA->kt2 = scale; // "kt2" might one day be renamed as "scale" or some such
2631  double norm = _jets[_jets_index].modp2();
2632  if (norm > 0) {
2633  norm = 1.0/sqrt(norm);
2634  jetA->nx = norm * _jets[_jets_index].px();
2635  jetA->ny = norm * _jets[_jets_index].py();
2636  jetA->nz = norm * _jets[_jets_index].pz();
2637  } else {
2638  jetA->nx = 0.0;
2639  jetA->ny = 0.0;
2640  jetA->nz = 1.0;
2641  }
2642  jetA->_jets_index = _jets_index;
2643  jetA->NN_dist = _R2;
2644  jetA->NN = NULL;
2645 }
2646 template<> double ClusterSequence::_bj_dist(
2647  const EEBriefJet * const jeta,
2648  const EEBriefJet * const jetb) const {
2649  double dist = 1.0
2650  - jeta->nx*jetb->nx
2651  - jeta->ny*jetb->ny
2652  - jeta->nz*jetb->nz;
2653  dist *= 2; // distance is _2_*min(Ei^2,Ej^2)*(1-cos theta)
2654  return dist;
2655 }
2656 void ClusterSequence::_simple_N2_cluster_BriefJet() {
2657  _simple_N2_cluster<BriefJet>();
2658 }
2659 void ClusterSequence::_simple_N2_cluster_EEBriefJet() {
2660  _simple_N2_cluster<EEBriefJet>();
2661 }
2662 FJCORE_END_NAMESPACE
2663 #include <iostream>
2664 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2665 using namespace std;
2666 ClusterSequenceStructure::~ClusterSequenceStructure(){
2667  if (_associated_cs != NULL
2668  && _associated_cs->will_delete_self_when_unused()) {
2669  _associated_cs->signal_imminent_self_deletion();
2670  delete _associated_cs;
2671  }
2672 }
2673 bool ClusterSequenceStructure::has_valid_cluster_sequence() const{
2674  return (_associated_cs != NULL);
2675 }
2676 const ClusterSequence* ClusterSequenceStructure::associated_cluster_sequence() const{
2677  return _associated_cs;
2678 }
2679 const ClusterSequence * ClusterSequenceStructure::validated_cs() const {
2680  if (!_associated_cs)
2681  throw Error("you requested information about the internal structure of a jet, but its associated ClusterSequence has gone out of scope.");
2682  return _associated_cs;
2683 }
2684 bool ClusterSequenceStructure::has_partner(const PseudoJet &reference, PseudoJet &partner) const{
2685  return validated_cs()->has_partner(reference, partner);
2686 }
2687 bool ClusterSequenceStructure::has_child(const PseudoJet &reference, PseudoJet &child) const{
2688  return validated_cs()->has_child(reference, child);
2689 }
2690 bool ClusterSequenceStructure::has_parents(const PseudoJet &reference, PseudoJet &parent1, PseudoJet &parent2) const{
2691  return validated_cs()->has_parents(reference, parent1, parent2);
2692 }
2693 bool ClusterSequenceStructure::object_in_jet(const PseudoJet &reference, const PseudoJet &jet) const{
2694  if ((!has_associated_cluster_sequence()) || (!jet.has_associated_cluster_sequence()))
2695  throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
2696  if (reference.associated_cluster_sequence() != jet.associated_cluster_sequence()) return false;
2697  return validated_cs()->object_in_jet(reference, jet);
2698 }
2699 bool ClusterSequenceStructure::has_constituents() const{
2700  if (!has_associated_cluster_sequence())
2701  throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
2702  return true;
2703 }
2704 vector<PseudoJet> ClusterSequenceStructure::constituents(const PseudoJet &reference) const{
2705  return validated_cs()->constituents(reference);
2706 }
2707 bool ClusterSequenceStructure::has_exclusive_subjets() const{
2708  if (!has_associated_cluster_sequence())
2709  throw Error("you requested information about the internal structure of a jet, but it is not associated with a ClusterSequence or its associated ClusterSequence has gone out of scope.");
2710  return true;
2711 }
2712 std::vector<PseudoJet> ClusterSequenceStructure::exclusive_subjets (const PseudoJet &reference, const double & dcut) const {
2713  return validated_cs()->exclusive_subjets(reference, dcut);
2714 }
2715 int ClusterSequenceStructure::n_exclusive_subjets(const PseudoJet &reference, const double & dcut) const {
2716  return validated_cs()->n_exclusive_subjets(reference, dcut);
2717 }
2718 std::vector<PseudoJet> ClusterSequenceStructure::exclusive_subjets_up_to (const PseudoJet &reference, int nsub) const {
2719  return validated_cs()->exclusive_subjets_up_to(reference, nsub);
2720 }
2721 double ClusterSequenceStructure::exclusive_subdmerge(const PseudoJet &reference, int nsub) const {
2722  return validated_cs()->exclusive_subdmerge(reference, nsub);
2723 }
2724 double ClusterSequenceStructure::exclusive_subdmerge_max(const PseudoJet &reference, int nsub) const {
2725  return validated_cs()->exclusive_subdmerge_max(reference, nsub);
2726 }
2727 bool ClusterSequenceStructure::has_pieces(const PseudoJet &reference) const{
2728  PseudoJet dummy1, dummy2;
2729  return has_parents(reference, dummy1, dummy2);
2730 }
2731 vector<PseudoJet> ClusterSequenceStructure::pieces(const PseudoJet &reference) const{
2732  PseudoJet j1, j2;
2733  vector<PseudoJet> res;
2734  if (has_parents(reference, j1, j2)){
2735  res.push_back(j1);
2736  res.push_back(j2);
2737  }
2738  return res;
2739 }
2740 FJCORE_END_NAMESPACE
2741 #include<iostream>
2742 #include<vector>
2743 #include<cmath>
2744 #include<algorithm>
2745 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
2746 using namespace std;
2747 void ClusterSequence::_bj_remove_from_tiles(TiledJet * const jet) {
2748  Tile * tile = & _tiles[jet->tile_index];
2749  if (jet->previous == NULL) {
2750  tile->head = jet->next;
2751  } else {
2752  jet->previous->next = jet->next;
2753  }
2754  if (jet->next != NULL) {
2755  jet->next->previous = jet->previous;
2756  }
2757 }
2758 void ClusterSequence::_initialise_tiles() {
2759  double default_size = max(0.1,_Rparam);
2760  _tile_size_eta = default_size;
2761  _n_tiles_phi = max(3,int(floor(twopi/default_size)));
2762  _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi
2763  TilingExtent tiling_analysis(*this);
2764  _tiles_eta_min = tiling_analysis.minrap();
2765  _tiles_eta_max = tiling_analysis.maxrap();
2766  _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta));
2767  _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta));
2768  _tiles_eta_min = _tiles_ieta_min * _tile_size_eta;
2769  _tiles_eta_max = _tiles_ieta_max * _tile_size_eta;
2770  _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi);
2771  for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) {
2772  for (int iphi = 0; iphi < _n_tiles_phi; iphi++) {
2773  Tile * tile = & _tiles[_tile_index(ieta,iphi)];
2774  tile->head = NULL; // first element of tiles points to itself
2775  tile->begin_tiles[0] = tile;
2776  Tile ** pptile = & (tile->begin_tiles[0]);
2777  pptile++;
2778  tile->surrounding_tiles = pptile;
2779  if (ieta > _tiles_ieta_min) {
2780  // with the itile subroutine, we can safely run tiles from
2781  // idphi=-1 to idphi=+1, because it takes care of
2782  // negative and positive boundaries
2783  for (int idphi = -1; idphi <=+1; idphi++) {
2784  *pptile = & _tiles[_tile_index(ieta-1,iphi+idphi)];
2785  pptile++;
2786  }
2787  }
2788  *pptile = & _tiles[_tile_index(ieta,iphi-1)];
2789  pptile++;
2790  tile->RH_tiles = pptile;
2791  *pptile = & _tiles[_tile_index(ieta,iphi+1)];
2792  pptile++;
2793  if (ieta < _tiles_ieta_max) {
2794  for (int idphi = -1; idphi <= +1; idphi++) {
2795  *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)];
2796  pptile++;
2797  }
2798  }
2799  tile->end_tiles = pptile;
2800  tile->tagged = false;
2801  }
2802  }
2803 }
2804 int ClusterSequence::_tile_index(const double eta, const double phi) const {
2805  int ieta, iphi;
2806  if (eta <= _tiles_eta_min) {ieta = 0;}
2807  else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;}
2808  else {
2809  ieta = int(((eta - _tiles_eta_min) / _tile_size_eta));
2810  if (ieta > _tiles_ieta_max-_tiles_ieta_min) {
2811  ieta = _tiles_ieta_max-_tiles_ieta_min;}
2812  }
2813  iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi;
2814  return (iphi + ieta * _n_tiles_phi);
2815 }
2816 inline void ClusterSequence::_tj_set_jetinfo( TiledJet * const jet,
2817  const int _jets_index) {
2818  _bj_set_jetinfo<>(jet, _jets_index);
2819  jet->tile_index = _tile_index(jet->eta, jet->phi);
2820  Tile * tile = &_tiles[jet->tile_index];
2821  jet->previous = NULL;
2822  jet->next = tile->head;
2823  if (jet->next != NULL) {jet->next->previous = jet;}
2824  tile->head = jet;
2825 }
2826 void ClusterSequence::_print_tiles(TiledJet * briefjets ) const {
2827  for (vector<Tile>::const_iterator tile = _tiles.begin();
2828  tile < _tiles.end(); tile++) {
2829  cout << "Tile " << tile - _tiles.begin()<<" = ";
2830  vector<int> list;
2831  for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
2832  list.push_back(jetI-briefjets);
2833  }
2834  sort(list.begin(),list.end());
2835  for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];}
2836  cout <<"\n";
2837  }
2838 }
2839 void ClusterSequence::_add_neighbours_to_tile_union(const int tile_index,
2840  vector<int> & tile_union, int & n_near_tiles) const {
2841  for (Tile * const * near_tile = _tiles[tile_index].begin_tiles;
2842  near_tile != _tiles[tile_index].end_tiles; near_tile++){
2843  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
2844  n_near_tiles++;
2845  }
2846 }
2847 inline void ClusterSequence::_add_untagged_neighbours_to_tile_union(
2848  const int tile_index,
2849  vector<int> & tile_union, int & n_near_tiles) {
2850  for (Tile ** near_tile = _tiles[tile_index].begin_tiles;
2851  near_tile != _tiles[tile_index].end_tiles; near_tile++){
2852  if (! (*near_tile)->tagged) {
2853  (*near_tile)->tagged = true;
2854  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
2855  n_near_tiles++;
2856  }
2857  }
2858 }
2859 void ClusterSequence::_tiled_N2_cluster() {
2860  _initialise_tiles();
2861  int n = _jets.size();
2862  TiledJet * briefjets = new TiledJet[n];
2863  TiledJet * jetA = briefjets, * jetB;
2864  TiledJet oldB;
2865  oldB.tile_index=0; // prevents a gcc warning
2866  vector<int> tile_union(3*n_tile_neighbours);
2867  for (int i = 0; i< n; i++) {
2868  _tj_set_jetinfo(jetA, i);
2869  jetA++; // move on to next entry of briefjets
2870  }
2871  TiledJet * tail = jetA; // a semaphore for the end of briefjets
2872  TiledJet * head = briefjets; // a nicer way of naming start
2873  vector<Tile>::const_iterator tile;
2874  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
2875  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
2876  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
2877  double dist = _bj_dist(jetA,jetB);
2878  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
2879  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
2880  }
2881  }
2882  for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
2883  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
2884  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
2885  double dist = _bj_dist(jetA,jetB);
2886  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
2887  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
2888  }
2889  }
2890  }
2891  }
2892  double * diJ = new double[n];
2893  jetA = head;
2894  for (int i = 0; i < n; i++) {
2895  diJ[i] = _bj_diJ(jetA);
2896  jetA++; // have jetA follow i
2897  }
2898  int history_location = n-1;
2899  while (tail != head) {
2900  double diJ_min = diJ[0];
2901  int diJ_min_jet = 0;
2902  for (int i = 1; i < n; i++) {
2903  if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min = diJ[i];}
2904  }
2905  history_location++;
2906  jetA = & briefjets[diJ_min_jet];
2907  jetB = jetA->NN;
2908  diJ_min *= _invR2;
2909  if (jetB != NULL) {
2910  if (jetA < jetB) {std::swap(jetA,jetB);}
2911  int nn; // new jet index
2912  _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
2913  _bj_remove_from_tiles(jetA);
2914  oldB = * jetB; // take a copy because we will need it...
2915  _bj_remove_from_tiles(jetB);
2916  _tj_set_jetinfo(jetB, nn); // also registers the jet in the tiling
2917  } else {
2918  _do_iB_recombination_step(jetA->_jets_index, diJ_min);
2919  _bj_remove_from_tiles(jetA);
2920  }
2921  int n_near_tiles = 0;
2922  _add_neighbours_to_tile_union(jetA->tile_index, tile_union, n_near_tiles);
2923  if (jetB != NULL) {
2924  bool sort_it = false;
2925  if (jetB->tile_index != jetA->tile_index) {
2926  sort_it = true;
2927  _add_neighbours_to_tile_union(jetB->tile_index,tile_union,n_near_tiles);
2928  }
2929  if (oldB.tile_index != jetA->tile_index &&
2930  oldB.tile_index != jetB->tile_index) {
2931  sort_it = true;
2932  _add_neighbours_to_tile_union(oldB.tile_index,tile_union,n_near_tiles);
2933  }
2934  if (sort_it) {
2935  // sort the tiles before then compressing the list
2936  sort(tile_union.begin(), tile_union.begin()+n_near_tiles);
2937  // and now condense the list
2938  int nnn = 1;
2939  for (int i = 1; i < n_near_tiles; i++) {
2940  if (tile_union[i] != tile_union[nnn-1]) {
2941  tile_union[nnn] = tile_union[i];
2942  nnn++;
2943  }
2944  }
2945  n_near_tiles = nnn;
2946  }
2947  }
2948  tail--; n--;
2949  if (jetA == tail) {
2950  } else {
2951  *jetA = *tail;
2952  diJ[jetA - head] = diJ[tail-head];
2953  if (jetA->previous == NULL) {
2954  _tiles[jetA->tile_index].head = jetA;
2955  } else {
2956  jetA->previous->next = jetA;
2957  }
2958  if (jetA->next != NULL) {jetA->next->previous = jetA;}
2959  }
2960  for (int itile = 0; itile < n_near_tiles; itile++) {
2961  Tile * tile_ptr = &_tiles[tile_union[itile]];
2962  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
2963  // see if jetI had jetA or jetB as a NN -- if so recalculate the NN
2964  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
2965  jetI->NN_dist = _R2;
2966  jetI->NN = NULL;
2967  // now go over tiles that are neighbours of I (include own tile)
2968  for (Tile ** near_tile = tile_ptr->begin_tiles;
2969  near_tile != tile_ptr->end_tiles; near_tile++) {
2970  // and then over the contents of that tile
2971  for (TiledJet * jetJ = (*near_tile)->head;
2972  jetJ != NULL; jetJ = jetJ->next) {
2973  double dist = _bj_dist(jetI,jetJ);
2974  if (dist < jetI->NN_dist && jetJ != jetI) {
2975  jetI->NN_dist = dist; jetI->NN = jetJ;
2976  }
2977  }
2978  }
2979  diJ[jetI-head] = _bj_diJ(jetI); // update diJ
2980  }
2981  // check whether new jetB is closer than jetI's current NN and
2982  // if need to update things
2983  if (jetB != NULL) {
2984  double dist = _bj_dist(jetI,jetB);
2985  if (dist < jetI->NN_dist) {
2986  if (jetI != jetB) {
2987  jetI->NN_dist = dist;
2988  jetI->NN = jetB;
2989  diJ[jetI-head] = _bj_diJ(jetI); // update diJ...
2990  }
2991  }
2992  if (dist < jetB->NN_dist) {
2993  if (jetI != jetB) {
2994  jetB->NN_dist = dist;
2995  jetB->NN = jetI;}
2996  }
2997  }
2998  }
2999  }
3000  if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
3001  for (Tile ** near_tile = _tiles[tail->tile_index].begin_tiles;
3002  near_tile!= _tiles[tail->tile_index].end_tiles; near_tile++){
3003  for (TiledJet * jetJ = (*near_tile)->head;
3004  jetJ != NULL; jetJ = jetJ->next) {
3005  if (jetJ->NN == tail) {jetJ->NN = jetA;}
3006  }
3007  }
3008  if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
3009  }
3010  delete[] diJ;
3011  delete[] briefjets;
3012 }
3013 void ClusterSequence::_faster_tiled_N2_cluster() {
3014  _initialise_tiles();
3015  int n = _jets.size();
3016  TiledJet * briefjets = new TiledJet[n];
3017  TiledJet * jetA = briefjets, * jetB;
3018  TiledJet oldB;
3019  oldB.tile_index=0; // prevents a gcc warning
3020  vector<int> tile_union(3*n_tile_neighbours);
3021  for (int i = 0; i< n; i++) {
3022  _tj_set_jetinfo(jetA, i);
3023  jetA++; // move on to next entry of briefjets
3024  }
3025  TiledJet * head = briefjets; // a nicer way of naming start
3026  vector<Tile>::const_iterator tile;
3027  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
3028  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
3029  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
3030  double dist = _bj_dist(jetA,jetB);
3031  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
3032  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
3033  }
3034  }
3035  for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
3036  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
3037  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
3038  double dist = _bj_dist(jetA,jetB);
3039  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
3040  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
3041  }
3042  }
3043  }
3044  }
3045  struct diJ_plus_link {
3046  double diJ; // the distance
3047  TiledJet * jet; // the jet (i) for which we've found this distance
3048  };
3049  diJ_plus_link * diJ = new diJ_plus_link[n];
3050  jetA = head;
3051  for (int i = 0; i < n; i++) {
3052  diJ[i].diJ = _bj_diJ(jetA); // kt distance * R^2
3053  diJ[i].jet = jetA; // our compact diJ table will not be in
3054  jetA->diJ_posn = i; // one-to-one corresp. with non-compact jets,
3055  jetA++; // have jetA follow i
3056  }
3057  int history_location = n-1;
3058  while (n > 0) {
3059  diJ_plus_link * best, *stop; // pointers a bit faster than indices
3060  double diJ_min = diJ[0].diJ; // initialise the best one here.
3061  best = diJ; // and here
3062  stop = diJ+n;
3063  for (diJ_plus_link * here = diJ+1; here != stop; here++) {
3064  if (here->diJ < diJ_min) {best = here; diJ_min = here->diJ;}
3065  }
3066  history_location++;
3067  jetA = best->jet;
3068  jetB = jetA->NN;
3069  diJ_min *= _invR2;
3070  if (jetB != NULL) {
3071  if (jetA < jetB) {std::swap(jetA,jetB);}
3072  int nn; // new jet index
3073  _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
3074  _bj_remove_from_tiles(jetA);
3075  oldB = * jetB; // take a copy because we will need it...
3076  _bj_remove_from_tiles(jetB);
3077  _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
3078  } else {
3079  _do_iB_recombination_step(jetA->_jets_index, diJ_min);
3080  _bj_remove_from_tiles(jetA);
3081  }
3082  int n_near_tiles = 0;
3083  _add_untagged_neighbours_to_tile_union(jetA->tile_index,
3084  tile_union, n_near_tiles);
3085  if (jetB != NULL) {
3086  if (jetB->tile_index != jetA->tile_index) {
3087  _add_untagged_neighbours_to_tile_union(jetB->tile_index,
3088  tile_union,n_near_tiles);
3089  }
3090  if (oldB.tile_index != jetA->tile_index &&
3091  oldB.tile_index != jetB->tile_index) {
3092  _add_untagged_neighbours_to_tile_union(oldB.tile_index,
3093  tile_union,n_near_tiles);
3094  }
3095  }
3096  n--;
3097  diJ[n].jet->diJ_posn = jetA->diJ_posn;
3098  diJ[jetA->diJ_posn] = diJ[n];
3099  for (int itile = 0; itile < n_near_tiles; itile++) {
3100  Tile * tile_ptr = &_tiles[tile_union[itile]];
3101  tile_ptr->tagged = false; // reset tag, since we're done with unions
3102  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
3103  // see if jetI had jetA or jetB as a NN -- if so recalculate the NN
3104  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
3105  jetI->NN_dist = _R2;
3106  jetI->NN = NULL;
3107  // now go over tiles that are neighbours of I (include own tile)
3108  for (Tile ** near_tile = tile_ptr->begin_tiles;
3109  near_tile != tile_ptr->end_tiles; near_tile++) {
3110  // and then over the contents of that tile
3111  for (TiledJet * jetJ = (*near_tile)->head;
3112  jetJ != NULL; jetJ = jetJ->next) {
3113  double dist = _bj_dist(jetI,jetJ);
3114  if (dist < jetI->NN_dist && jetJ != jetI) {
3115  jetI->NN_dist = dist; jetI->NN = jetJ;
3116  }
3117  }
3118  }
3119  diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ kt-dist
3120  }
3121  // check whether new jetB is closer than jetI's current NN and
3122  // if jetI is closer than jetB's current (evolving) nearest
3123  // neighbour. Where relevant update things
3124  if (jetB != NULL) {
3125  double dist = _bj_dist(jetI,jetB);
3126  if (dist < jetI->NN_dist) {
3127  if (jetI != jetB) {
3128  jetI->NN_dist = dist;
3129  jetI->NN = jetB;
3130  diJ[jetI->diJ_posn].diJ = _bj_diJ(jetI); // update diJ...
3131  }
3132  }
3133  if (dist < jetB->NN_dist) {
3134  if (jetI != jetB) {
3135  jetB->NN_dist = dist;
3136  jetB->NN = jetI;}
3137  }
3138  }
3139  }
3140  }
3141  if (jetB != NULL) {diJ[jetB->diJ_posn].diJ = _bj_diJ(jetB);}
3142  }
3143  delete[] diJ;
3144  delete[] briefjets;
3145 }
3146 void ClusterSequence::_minheap_faster_tiled_N2_cluster() {
3147  _initialise_tiles();
3148  int n = _jets.size();
3149  TiledJet * briefjets = new TiledJet[n];
3150  TiledJet * jetA = briefjets, * jetB;
3151  TiledJet oldB;
3152  oldB.tile_index=0; // prevents a gcc warning
3153  vector<int> tile_union(3*n_tile_neighbours);
3154  for (int i = 0; i< n; i++) {
3155  _tj_set_jetinfo(jetA, i);
3156  jetA++; // move on to next entry of briefjets
3157  }
3158  TiledJet * head = briefjets; // a nicer way of naming start
3159  vector<Tile>::const_iterator tile;
3160  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
3161  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
3162  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
3163  double dist = _bj_dist(jetA,jetB);
3164  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
3165  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
3166  }
3167  }
3168  for (Tile ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
3169  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
3170  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
3171  double dist = _bj_dist(jetA,jetB);
3172  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
3173  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
3174  }
3175  }
3176  }
3177  }
3178  vector<double> diJs(n);
3179  for (int i = 0; i < n; i++) {
3180  diJs[i] = _bj_diJ(&briefjets[i]);
3181  briefjets[i].label_minheap_update_done();
3182  }
3183  MinHeap minheap(diJs);
3184  vector<TiledJet *> jets_for_minheap;
3185  jets_for_minheap.reserve(n);
3186  int history_location = n-1;
3187  while (n > 0) {
3188  double diJ_min = minheap.minval() *_invR2;
3189  jetA = head + minheap.minloc();
3190  history_location++;
3191  jetB = jetA->NN;
3192  if (jetB != NULL) {
3193  if (jetA < jetB) {std::swap(jetA,jetB);}
3194  int nn; // new jet index
3195  _do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
3196  _bj_remove_from_tiles(jetA);
3197  oldB = * jetB; // take a copy because we will need it...
3198  _bj_remove_from_tiles(jetB);
3199  _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
3200  } else {
3201  _do_iB_recombination_step(jetA->_jets_index, diJ_min);
3202  _bj_remove_from_tiles(jetA);
3203  }
3204  minheap.remove(jetA-head);
3205  int n_near_tiles = 0;
3206  _add_untagged_neighbours_to_tile_union(jetA->tile_index,
3207  tile_union, n_near_tiles);
3208  if (jetB != NULL) {
3209  if (jetB->tile_index != jetA->tile_index) {
3210  _add_untagged_neighbours_to_tile_union(jetB->tile_index,
3211  tile_union,n_near_tiles);
3212  }
3213  if (oldB.tile_index != jetA->tile_index &&
3214  oldB.tile_index != jetB->tile_index) {
3215  // GS: the line below generates a warning that oldB.tile_index
3216  // may be used uninitialised. However, to reach this point, we
3217  // ned jetB != NULL (see test a few lines above) and is jetB
3218  // !=NULL, one would have gone through "oldB = *jetB before
3219  // (see piece of code ~20 line above), so the index is
3220  // initialised. We do not do anything to avoid the warning to
3221  // avoid any potential speed impact.
3222  _add_untagged_neighbours_to_tile_union(oldB.tile_index,
3223  tile_union,n_near_tiles);
3224  }
3225  jetB->label_minheap_update_needed();
3226  jets_for_minheap.push_back(jetB);
3227  }
3228  for (int itile = 0; itile < n_near_tiles; itile++) {
3229  Tile * tile_ptr = &_tiles[tile_union[itile]];
3230  tile_ptr->tagged = false; // reset tag, since we're done with unions
3231  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
3232  // see if jetI had jetA or jetB as a NN -- if so recalculate the NN
3233  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
3234  jetI->NN_dist = _R2;
3235  jetI->NN = NULL;
3236  // label jetI as needing heap action...
3237  if (!jetI->minheap_update_needed()) {
3238  jetI->label_minheap_update_needed();
3239  jets_for_minheap.push_back(jetI);}
3240  // now go over tiles that are neighbours of I (include own tile)
3241  for (Tile ** near_tile = tile_ptr->begin_tiles;
3242  near_tile != tile_ptr->end_tiles; near_tile++) {
3243  // and then over the contents of that tile
3244  for (TiledJet * jetJ = (*near_tile)->head;
3245  jetJ != NULL; jetJ = jetJ->next) {
3246  double dist = _bj_dist(jetI,jetJ);
3247  if (dist < jetI->NN_dist && jetJ != jetI) {
3248  jetI->NN_dist = dist; jetI->NN = jetJ;
3249  }
3250  }
3251  }
3252  }
3253  // check whether new jetB is closer than jetI's current NN and
3254  // if jetI is closer than jetB's current (evolving) nearest
3255  // neighbour. Where relevant update things
3256  if (jetB != NULL) {
3257  double dist = _bj_dist(jetI,jetB);
3258  if (dist < jetI->NN_dist) {
3259  if (jetI != jetB) {
3260  jetI->NN_dist = dist;
3261  jetI->NN = jetB;
3262  // label jetI as needing heap action...
3263  if (!jetI->minheap_update_needed()) {
3264  jetI->label_minheap_update_needed();
3265  jets_for_minheap.push_back(jetI);}
3266  }
3267  }
3268  if (dist < jetB->NN_dist) {
3269  if (jetI != jetB) {
3270  jetB->NN_dist = dist;
3271  jetB->NN = jetI;}
3272  }
3273  }
3274  }
3275  }
3276  while (jets_for_minheap.size() > 0) {
3277  TiledJet * jetI = jets_for_minheap.back();
3278  jets_for_minheap.pop_back();
3279  minheap.update(jetI-head, _bj_diJ(jetI));
3280  jetI->label_minheap_update_done();
3281  }
3282  n--;
3283  }
3284  delete[] briefjets;
3285 }
3286 FJCORE_END_NAMESPACE
3287 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
3288 using namespace std;
3289 CompositeJetStructure::CompositeJetStructure(const std::vector<PseudoJet> & initial_pieces,
3290  const JetDefinition::Recombiner * recombiner)
3291  : _pieces(initial_pieces){
3292  if (recombiner){}; // ugly trick to prevent a gcc warning
3293  _area_4vector_ptr = 0;
3294 }
3295 std::string CompositeJetStructure::description() const{
3296  string str = "Composite PseudoJet";
3297  return str;
3298 }
3299 bool CompositeJetStructure::has_constituents() const{
3300  return _pieces.size()!=0;
3301 }
3302 std::vector<PseudoJet> CompositeJetStructure::constituents(const PseudoJet & /*jet*/) const{
3303  vector<PseudoJet> all_constituents;
3304  for (unsigned i = 0; i < _pieces.size(); i++) {
3305  if (_pieces[i].has_constituents()){
3306  vector<PseudoJet> constits = _pieces[i].constituents();
3307  copy(constits.begin(), constits.end(), back_inserter(all_constituents));
3308  } else {
3309  all_constituents.push_back(_pieces[i]);
3310  }
3311  }
3312  return all_constituents;
3313 }
3314 std::vector<PseudoJet> CompositeJetStructure::pieces(const PseudoJet & /*jet*/) const{
3315  return _pieces;
3316 }
3317 FJCORE_END_NAMESPACE // defined in fastjet/internal/base.hh
3318 #include <sstream>
3319 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
3320 using namespace std;
3321 bool Error::_print_errors = true;
3322 bool Error::_print_backtrace = false;
3323 ostream * Error::_default_ostr = & cerr;
3324 #if (!defined(FJCORE_HAVE_EXECINFO_H)) || defined(__FJCORE__)
3325  LimitedWarning Error::_execinfo_undefined;
3326 #endif
3327 Error::Error(const std::string & message_in) {
3328  _message = message_in;
3329  if (_print_errors && _default_ostr){
3330  ostringstream oss;
3331  oss << "fjcore::Error: "<< message_in << endl;
3332  *_default_ostr << oss.str();
3333  _default_ostr->flush();
3334  }
3335 }
3336 void Error::set_print_backtrace(bool enabled) {
3337 #if (!defined(FJCORE_HAVE_EXECINFO_H)) || defined(__FJCORE__)
3338  if (enabled) {
3339  _execinfo_undefined.warn("Error::set_print_backtrace(true) will not work with this build of FastJet");
3340  }
3341 #endif
3342  _print_backtrace = enabled;
3343 }
3344 FJCORE_END_NAMESPACE
3345 #include <string>
3346 #include <sstream>
3347 using namespace std;
3348 FJCORE_BEGIN_NAMESPACE
3349 FJCORE_END_NAMESPACE
3350 #include<sstream>
3351 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
3352 using namespace std;
3353 const double JetDefinition::max_allowable_R = 1000.0;
3354 JetDefinition::JetDefinition(JetAlgorithm jet_algorithm_in,
3355  double R_in,
3356  RecombinationScheme recomb_scheme_in,
3357  Strategy strategy_in,
3358  int nparameters) :
3359  _jet_algorithm(jet_algorithm_in), _Rparam(R_in), _strategy(strategy_in) {
3360  if (_jet_algorithm == ee_kt_algorithm) {
3361  _Rparam = 4.0; // introduce a fictional R that ensures that
3362  } else {
3363  if (R_in > max_allowable_R) {
3364  ostringstream oss;
3365  oss << "Requested R = " << R_in << " for jet definition is larger than max_allowable_R = " << max_allowable_R;
3366  throw Error(oss.str());
3367  }
3368  }
3369  unsigned int nparameters_expected = n_parameters_for_algorithm(jet_algorithm_in);
3370  if (nparameters != (int) nparameters_expected){
3371  ostringstream oss;
3372  oss << "The jet algorithm you requested ("
3373  << jet_algorithm_in << ") should be constructed with " << nparameters_expected
3374  << " parameter(s) but was called with " << nparameters << " parameter(s)\n";
3375  throw Error(oss.str());
3376  }
3377  assert (_strategy != plugin_strategy);
3378  _plugin = NULL;
3379  set_recombination_scheme(recomb_scheme_in);
3380  set_extra_param(0.0); // make sure it's defined
3381 }
3382 bool JetDefinition::is_spherical() const {
3383  if (jet_algorithm() == plugin_algorithm) {
3384  return plugin()->is_spherical();
3385  } else {
3386  return (jet_algorithm() == ee_kt_algorithm || // as of 2013-02-14, the two
3387  jet_algorithm() == ee_genkt_algorithm // native spherical algorithms
3388  );
3389  }
3390 }
3391 string JetDefinition::description() const {
3392  ostringstream name;
3393  name << description_no_recombiner();
3394  if ((jet_algorithm() == plugin_algorithm) || (jet_algorithm() == undefined_jet_algorithm)){
3395  return name.str();
3396  }
3397  if (n_parameters_for_algorithm(jet_algorithm()) == 0)
3398  name << " with ";
3399  else
3400  name << " and ";
3401  name << recombiner()->description();
3402  return name.str();
3403 }
3404 string JetDefinition::description_no_recombiner() const {
3405  ostringstream name;
3406  if (jet_algorithm() == plugin_algorithm) {
3407  return plugin()->description();
3408  } else if (jet_algorithm() == undefined_jet_algorithm) {
3409  return "uninitialised JetDefinition (jet_algorithm=undefined_jet_algorithm)" ;
3410  }
3411  name << algorithm_description(jet_algorithm());
3412  switch (n_parameters_for_algorithm(jet_algorithm())){
3413  case 0: name << " (NB: no R)"; break;
3414  case 1: name << " with R = " << R(); break; // the parameter is always R
3415  case 2:
3416  name << " with R = " << R();
3417  if (jet_algorithm() == cambridge_for_passive_algorithm){
3418  name << "and a special hack whereby particles with kt < "
3419  << extra_param() << "are treated as passive ghosts";
3420  } else {
3421  name << ", p = " << extra_param();
3422  }
3423  };
3424  return name.str();
3425 }
3426 string JetDefinition::algorithm_description(const JetAlgorithm jet_alg){
3427  ostringstream name;
3428  switch (jet_alg){
3429  case plugin_algorithm: return "plugin algorithm";
3430  case kt_algorithm: return "Longitudinally invariant kt algorithm";
3431  case cambridge_algorithm: return "Longitudinally invariant Cambridge/Aachen algorithm";
3432  case antikt_algorithm: return "Longitudinally invariant anti-kt algorithm";
3433  case genkt_algorithm: return "Longitudinally invariant generalised kt algorithm";
3434  case cambridge_for_passive_algorithm: return "Longitudinally invariant Cambridge/Aachen algorithm";
3435  case ee_kt_algorithm: return "e+e- kt (Durham) algorithm (NB: no R)";
3436  case ee_genkt_algorithm: return "e+e- generalised kt algorithm";
3437  case undefined_jet_algorithm: return "undefined jet algorithm";
3438  default:
3439  throw Error("JetDefinition::algorithm_description(): unrecognized jet_algorithm");
3440  };
3441 }
3442 unsigned int JetDefinition::n_parameters_for_algorithm(const JetAlgorithm jet_alg){
3443  switch (jet_alg) {
3444  case ee_kt_algorithm: return 0;
3445  case genkt_algorithm:
3446  case ee_genkt_algorithm: return 2;
3447  default: return 1;
3448  };
3449 }
3450 void JetDefinition::set_recombination_scheme(
3451  RecombinationScheme recomb_scheme) {
3452  _default_recombiner = JetDefinition::DefaultRecombiner(recomb_scheme);
3453  if (_shared_recombiner) _shared_recombiner.reset();
3454  _recombiner = 0;
3455 }
3456 void JetDefinition::set_recombiner(const JetDefinition &other_jet_def){
3457  assert(other_jet_def._recombiner ||
3458  other_jet_def.recombination_scheme() != external_scheme);
3459  if (other_jet_def._recombiner == 0){
3460  set_recombination_scheme(other_jet_def.recombination_scheme());
3461  return;
3462  }
3463  _recombiner = other_jet_def._recombiner;
3464  _default_recombiner = DefaultRecombiner(external_scheme);
3465  _shared_recombiner.reset(other_jet_def._shared_recombiner);
3466 }
3467 bool JetDefinition::has_same_recombiner(const JetDefinition &other_jd) const{
3468  const RecombinationScheme & scheme = recombination_scheme();
3469  if (other_jd.recombination_scheme() != scheme) return false;
3470  return (scheme != external_scheme)
3471  || (recombiner() == other_jd.recombiner());
3472 }
3473 void JetDefinition::delete_recombiner_when_unused(){
3474  if (_recombiner == 0){
3475  throw Error("tried to call JetDefinition::delete_recombiner_when_unused() for a JetDefinition without a user-defined recombination scheme");
3476  } else if (_shared_recombiner.get()) {
3477  throw Error("Error in JetDefinition::delete_recombiner_when_unused: the recombiner is already scheduled for deletion when unused (or was already set as shared)");
3478  }
3479  _shared_recombiner.reset(_recombiner);
3480 }
3481 void JetDefinition::delete_plugin_when_unused(){
3482  if (_plugin == 0){
3483  throw Error("tried to call JetDefinition::delete_plugin_when_unused() for a JetDefinition without a plugin");
3484  }
3485  _plugin_shared.reset(_plugin);
3486 }
3487 string JetDefinition::DefaultRecombiner::description() const {
3488  switch(_recomb_scheme) {
3489  case E_scheme:
3490  return "E scheme recombination";
3491  case pt_scheme:
3492  return "pt scheme recombination";
3493  case pt2_scheme:
3494  return "pt2 scheme recombination";
3495  case Et_scheme:
3496  return "Et scheme recombination";
3497  case Et2_scheme:
3498  return "Et2 scheme recombination";
3499  case BIpt_scheme:
3500  return "boost-invariant pt scheme recombination";
3501  case BIpt2_scheme:
3502  return "boost-invariant pt2 scheme recombination";
3503  case WTA_pt_scheme:
3504  return "pt-ordered Winner-Takes-All recombination";
3505  case WTA_modp_scheme:
3506  return "|3-momentum|-ordered Winner-Takes-All recombination";
3507  default:
3508  ostringstream err;
3509  err << "DefaultRecombiner: unrecognized recombination scheme "
3510  << _recomb_scheme;
3511  throw Error(err.str());
3512  }
3513 }
3514 void JetDefinition::DefaultRecombiner::recombine(
3515  const PseudoJet & pa, const PseudoJet & pb,
3516  PseudoJet & pab) const {
3517  double weighta, weightb;
3518  switch(_recomb_scheme) {
3519  case E_scheme:
3520  pab.reset(pa.px()+pb.px(),
3521  pa.py()+pb.py(),
3522  pa.pz()+pb.pz(),
3523  pa.E ()+pb.E ());
3524  return;
3525  case pt_scheme:
3526  case Et_scheme:
3527  case BIpt_scheme:
3528  weighta = pa.perp();
3529  weightb = pb.perp();
3530  break;
3531  case pt2_scheme:
3532  case Et2_scheme:
3533  case BIpt2_scheme:
3534  weighta = pa.perp2();
3535  weightb = pb.perp2();
3536  break;
3537  case WTA_pt_scheme:{
3538  const PseudoJet & phard = (pa.pt2() >= pb.pt2()) ? pa : pb;
3539  pab.reset_PtYPhiM(pa.pt()+pb.pt(),
3540  phard.rap(), phard.phi(), phard.m());
3541  return;}
3542  case WTA_modp_scheme:{
3543  bool a_hardest = (pa.modp2() >= pb.modp2());
3544  const PseudoJet & phard = a_hardest ? pa : pb;
3545  const PseudoJet & psoft = a_hardest ? pb : pa;
3546  double modp_hard = phard.modp();
3547  double modp_ab = modp_hard + psoft.modp();
3548  if (phard.modp2()==0.0){
3549  pab.reset(0.0, 0.0, 0.0, phard.m());
3550  } else {
3551  double scale = modp_ab/modp_hard;
3552  pab.reset(phard.px()*scale, phard.py()*scale, phard.pz()*scale,
3553  sqrt(modp_ab*modp_ab + phard.m2()));
3554  }
3555  return;}
3556  default:
3557  ostringstream err;
3558  err << "DefaultRecombiner: unrecognized recombination scheme "
3559  << _recomb_scheme;
3560  throw Error(err.str());
3561  }
3562  double perp_ab = pa.perp() + pb.perp();
3563  if (perp_ab != 0.0) { // weights also non-zero...
3564  double y_ab = (weighta * pa.rap() + weightb * pb.rap())/(weighta+weightb);
3565  double phi_a = pa.phi(), phi_b = pb.phi();
3566  if (phi_a - phi_b > pi) phi_b += twopi;
3567  if (phi_a - phi_b < -pi) phi_b -= twopi;
3568  double phi_ab = (weighta * phi_a + weightb * phi_b)/(weighta+weightb);
3569  pab.reset_PtYPhiM(perp_ab,y_ab,phi_ab);
3570  } else { // weights are zero
3571  pab.reset(0.0, 0.0, 0.0, 0.0);
3572  }
3573 }
3574 void JetDefinition::DefaultRecombiner::preprocess(PseudoJet & p) const {
3575  switch(_recomb_scheme) {
3576  case E_scheme:
3577  case BIpt_scheme:
3578  case BIpt2_scheme:
3579  case WTA_pt_scheme:
3580  case WTA_modp_scheme:
3581  break;
3582  case pt_scheme:
3583  case pt2_scheme:
3584  {
3585  double newE = sqrt(p.perp2()+p.pz()*p.pz());
3586  p.reset_momentum(p.px(), p.py(), p.pz(), newE);
3587  }
3588  break;
3589  case Et_scheme:
3590  case Et2_scheme:
3591  {
3592  double rescale = p.E()/sqrt(p.perp2()+p.pz()*p.pz());
3593  p.reset_momentum(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
3594  }
3595  break;
3596  default:
3597  ostringstream err;
3598  err << "DefaultRecombiner: unrecognized recombination scheme "
3599  << _recomb_scheme;
3600  throw Error(err.str());
3601  }
3602 }
3603 void JetDefinition::Plugin::set_ghost_separation_scale(double /*scale*/) const {
3604  throw Error("set_ghost_separation_scale not supported");
3605 }
3606 PseudoJet join(const vector<PseudoJet> & pieces, const JetDefinition::Recombiner & recombiner){
3607  PseudoJet result; // automatically initialised to 0
3608  if (pieces.size()>0){
3609  result = pieces[0];
3610  for (unsigned int i=1; i<pieces.size(); i++)
3611  recombiner.plus_equal(result, pieces[i]);
3612  }
3613  CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces, &recombiner);
3614  result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
3615  return result;
3616 }
3617 PseudoJet join(const PseudoJet & j1,
3618  const JetDefinition::Recombiner & recombiner){
3619  return join(vector<PseudoJet>(1,j1), recombiner);
3620 }
3621 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2,
3622  const JetDefinition::Recombiner & recombiner){
3623  vector<PseudoJet> pieces;
3624  pieces.push_back(j1);
3625  pieces.push_back(j2);
3626  return join(pieces, recombiner);
3627 }
3628 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3,
3629  const JetDefinition::Recombiner & recombiner){
3630  vector<PseudoJet> pieces;
3631  pieces.push_back(j1);
3632  pieces.push_back(j2);
3633  pieces.push_back(j3);
3634  return join(pieces, recombiner);
3635 }
3636 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4,
3637  const JetDefinition::Recombiner & recombiner){
3638  vector<PseudoJet> pieces;
3639  pieces.push_back(j1);
3640  pieces.push_back(j2);
3641  pieces.push_back(j3);
3642  pieces.push_back(j4);
3643  return join(pieces, recombiner);
3644 }
3645 FJCORE_END_NAMESPACE
3646 #include <sstream>
3647 #include <limits>
3648 using namespace std;
3649 FJCORE_BEGIN_NAMESPACE
3650 ostream * LimitedWarning::_default_ostr = &cerr;
3651 std::list< LimitedWarning::Summary > LimitedWarning::_global_warnings_summary;
3652 int LimitedWarning::_max_warn_default = 5;
3653 void LimitedWarning::warn(const char * warning, std::ostream * ostr) {
3654  if (_this_warning_summary == 0) {
3655  _global_warnings_summary.push_back(Summary(warning, 0));
3656  _this_warning_summary = & (_global_warnings_summary.back());
3657  }
3658  if (_n_warn_so_far < _max_warn) {
3659  ostringstream warnstr;
3660  warnstr << "WARNING from FastJet: ";
3661  warnstr << warning;
3662  _n_warn_so_far++;
3663  if (_n_warn_so_far == _max_warn) warnstr << " (LAST SUCH WARNING)";
3664  warnstr << std::endl;
3665  if (ostr) {
3666  (*ostr) << warnstr.str();
3667  ostr->flush(); // get something written to file even if the program aborts
3668  }
3669  }
3670  if (_this_warning_summary->second < numeric_limits<unsigned>::max()) {
3671  _this_warning_summary->second++;
3672  }
3673 }
3674 string LimitedWarning::summary() {
3675  ostringstream str;
3676  for (list<Summary>::const_iterator it = _global_warnings_summary.begin();
3677  it != _global_warnings_summary.end(); it++) {
3678  str << it->second << " times: " << it->first << endl;
3679  }
3680  return str.str();
3681 }
3682 FJCORE_END_NAMESPACE
3683 #include<iostream>
3684 #include<cmath>
3685 #include<limits>
3686 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
3687 using namespace std;
3688 void MinHeap::initialise(const std::vector<double> & values){
3689  for (unsigned i = values.size(); i < _heap.size(); i++) {
3690  _heap[i].value = std::numeric_limits<double>::max();
3691  _heap[i].minloc = &(_heap[i]);
3692  }
3693  for (unsigned i = 0; i < values.size(); i++) {
3694  _heap[i].value = values[i];
3695  _heap[i].minloc = &(_heap[i]);
3696  }
3697  for (unsigned i = _heap.size()-1; i > 0; i--) {
3698  ValueLoc * parent = &(_heap[(i-1)/2]);
3699  ValueLoc * here = &(_heap[i]);
3700  if (here->minloc->value < parent->minloc->value) {
3701  parent->minloc = here->minloc;
3702  }
3703  }
3704 }
3705 void MinHeap::update(unsigned int loc, double new_value) {
3706  assert(loc < _heap.size());
3707  ValueLoc * start = &(_heap[loc]);
3708  if (start->minloc != start && !(new_value < start->minloc->value)) {
3709  start->value = new_value;
3710  return;
3711  }
3712  start->value = new_value;
3713  start->minloc = start;
3714  bool change_made = true;
3715  ValueLoc * heap_end = (&(_heap[0])) + _heap.size();
3716  while(change_made) {
3717  ValueLoc * here = &(_heap[loc]);
3718  change_made = false;
3719  if (here->minloc == start) {
3720  here->minloc = here; change_made = true;
3721  }
3722  ValueLoc * child = &(_heap[2*loc+1]);
3723  if (child < heap_end && child->minloc->value < here->minloc->value ) {
3724  here->minloc = child->minloc;
3725  change_made = true;}
3726  child++;
3727  if (child < heap_end && child->minloc->value < here->minloc->value ) {
3728  here->minloc = child->minloc;
3729  change_made = true;}
3730  if (loc == 0) {break;}
3731  loc = (loc-1)/2;
3732  }
3733 }
3734 FJCORE_END_NAMESPACE
3735 #include<valarray>
3736 #include<iostream>
3737 #include<sstream>
3738 #include<cmath>
3739 #include<algorithm>
3740 #include <cstdarg>
3741 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
3742 using namespace std;
3743 PseudoJet::PseudoJet(const double px_in, const double py_in, const double pz_in, const double E_in) {
3744  _E = E_in ;
3745  _px = px_in;
3746  _py = py_in;
3747  _pz = pz_in;
3748  this->_finish_init();
3749  _reset_indices();
3750 }
3751 void PseudoJet::_finish_init () {
3752  _kt2 = this->px()*this->px() + this->py()*this->py();
3753  _phi = pseudojet_invalid_phi;
3754  _rap = pseudojet_invalid_rap;
3755 }
3756 void PseudoJet::_set_rap_phi() const {
3757  if (_kt2 == 0.0) {
3758  _phi = 0.0; }
3759  else {
3760  _phi = atan2(this->py(),this->px());
3761  }
3762  if (_phi < 0.0) {_phi += twopi;}
3763  if (_phi >= twopi) {_phi -= twopi;} // can happen if phi=-|eps<1e-15|?
3764  if (this->E() == abs(this->pz()) && _kt2 == 0) {
3765  double MaxRapHere = MaxRap + abs(this->pz());
3766  if (this->pz() >= 0.0) {_rap = MaxRapHere;} else {_rap = -MaxRapHere;}
3767  } else {
3768  double effective_m2 = max(0.0,m2()); // force non tachyonic mass
3769  double E_plus_pz = _E + abs(_pz); // the safer of p+, p-
3770  _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
3771  if (_pz > 0) {_rap = - _rap;}
3772  }
3773 }
3774 valarray<double> PseudoJet::four_mom() const {
3775  valarray<double> mom(4);
3776  mom[0] = _px;
3777  mom[1] = _py;
3778  mom[2] = _pz;
3779  mom[3] = _E ;
3780  return mom;
3781 }
3782 double PseudoJet::operator () (int i) const {
3783  switch(i) {
3784  case X:
3785  return px();
3786  case Y:
3787  return py();
3788  case Z:
3789  return pz();
3790  case T:
3791  return e();
3792  default:
3793  ostringstream err;
3794  err << "PseudoJet subscripting: bad index (" << i << ")";
3795  throw Error(err.str());
3796  }
3797  return 0.;
3798 }
3799 double PseudoJet::pseudorapidity() const {
3800  if (px() == 0.0 && py() ==0.0) return MaxRap;
3801  if (pz() == 0.0) return 0.0;
3802  double theta = atan(perp()/pz());
3803  if (theta < 0) theta += pi;
3804  return -log(tan(theta/2));
3805 }
3806 PseudoJet operator+ (const PseudoJet & jet1, const PseudoJet & jet2) {
3807  return PseudoJet(jet1.px()+jet2.px(),
3808  jet1.py()+jet2.py(),
3809  jet1.pz()+jet2.pz(),
3810  jet1.E() +jet2.E() );
3811 }
3812 PseudoJet operator- (const PseudoJet & jet1, const PseudoJet & jet2) {
3813  return PseudoJet(jet1.px()-jet2.px(),
3814  jet1.py()-jet2.py(),
3815  jet1.pz()-jet2.pz(),
3816  jet1.E() -jet2.E() );
3817 }
3818 PseudoJet operator* (double coeff, const PseudoJet & jet) {
3819  jet._ensure_valid_rap_phi();
3820  PseudoJet coeff_times_jet(jet);
3821  coeff_times_jet *= coeff;
3822  return coeff_times_jet;
3823 }
3824 PseudoJet operator* (const PseudoJet & jet, double coeff) {
3825  return coeff*jet;
3826 }
3827 PseudoJet operator/ (const PseudoJet & jet, double coeff) {
3828  return (1.0/coeff)*jet;
3829 }
3830 void PseudoJet::operator*=(double coeff) {
3831  _ensure_valid_rap_phi();
3832  _px *= coeff;
3833  _py *= coeff;
3834  _pz *= coeff;
3835  _E *= coeff;
3836  _kt2*= coeff*coeff;
3837 }
3838 void PseudoJet::operator/=(double coeff) {
3839  (*this) *= 1.0/coeff;
3840 }
3841 void PseudoJet::operator+=(const PseudoJet & other_jet) {
3842  _px += other_jet._px;
3843  _py += other_jet._py;
3844  _pz += other_jet._pz;
3845  _E += other_jet._E ;
3846  _finish_init(); // we need to recalculate phi,rap,kt2
3847 }
3848 void PseudoJet::operator-=(const PseudoJet & other_jet) {
3849  _px -= other_jet._px;
3850  _py -= other_jet._py;
3851  _pz -= other_jet._pz;
3852  _E -= other_jet._E ;
3853  _finish_init(); // we need to recalculate phi,rap,kt2
3854 }
3855 bool operator==(const PseudoJet & a, const PseudoJet & b) {
3856  if (a.px() != b.px()) return false;
3857  if (a.py() != b.py()) return false;
3858  if (a.pz() != b.pz()) return false;
3859  if (a.E () != b.E ()) return false;
3860  if (a.user_index() != b.user_index()) return false;
3861  if (a.cluster_hist_index() != b.cluster_hist_index()) return false;
3862  if (a.user_info_ptr() != b.user_info_ptr()) return false;
3863  if (a.structure_ptr() != b.structure_ptr()) return false;
3864  return true;
3865 }
3866 bool operator==(const PseudoJet & jet, const double val) {
3867  if (val != 0)
3868  throw Error("comparing a PseudoJet with a non-zero constant (double) is not allowed.");
3869  return (jet.px() == 0 && jet.py() == 0 &&
3870  jet.pz() == 0 && jet.E() == 0);
3871 }
3872 PseudoJet & PseudoJet::boost(const PseudoJet & prest) {
3873  if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
3874  return *this;
3875  double m_local = prest.m();
3876  assert(m_local != 0);
3877  double pf4 = ( px()*prest.px() + py()*prest.py()
3878  + pz()*prest.pz() + E()*prest.E() )/m_local;
3879  double fn = (pf4 + E()) / (prest.E() + m_local);
3880  _px += fn*prest.px();
3881  _py += fn*prest.py();
3882  _pz += fn*prest.pz();
3883  _E = pf4;
3884  _finish_init(); // we need to recalculate phi,rap,kt2
3885  return *this;
3886 }
3887 PseudoJet & PseudoJet::unboost(const PseudoJet & prest) {
3888  if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
3889  return *this;
3890  double m_local = prest.m();
3891  assert(m_local != 0);
3892  double pf4 = ( -px()*prest.px() - py()*prest.py()
3893  - pz()*prest.pz() + E()*prest.E() )/m_local;
3894  double fn = (pf4 + E()) / (prest.E() + m_local);
3895  _px -= fn*prest.px();
3896  _py -= fn*prest.py();
3897  _pz -= fn*prest.pz();
3898  _E = pf4;
3899  _finish_init(); // we need to recalculate phi,rap,kt2
3900  return *this;
3901 }
3902 bool have_same_momentum(const PseudoJet & jeta, const PseudoJet & jetb) {
3903  return jeta.px() == jetb.px()
3904  && jeta.py() == jetb.py()
3905  && jeta.pz() == jetb.pz()
3906  && jeta.E() == jetb.E();
3907 }
3908 void PseudoJet::set_cached_rap_phi(double rap_in, double phi_in) {
3909  _rap = rap_in; _phi = phi_in;
3910  if (_phi >= twopi) _phi -= twopi;
3911  if (_phi < 0) _phi += twopi;
3912 }
3913 void PseudoJet::reset_momentum_PtYPhiM(double pt_in, double y_in, double phi_in, double m_in) {
3914  assert(phi_in < 2*twopi && phi_in > -twopi);
3915  double ptm = (m_in == 0) ? pt_in : sqrt(pt_in*pt_in+m_in*m_in);
3916  double exprap = exp(y_in);
3917  double pminus = ptm/exprap;
3918  double pplus = ptm*exprap;
3919  double px_local = pt_in*cos(phi_in);
3920  double py_local = pt_in*sin(phi_in);
3921  reset_momentum(px_local,py_local,0.5*(pplus-pminus),0.5*(pplus+pminus));
3922  set_cached_rap_phi(y_in,phi_in);
3923 }
3924 PseudoJet PtYPhiM(double pt, double y, double phi, double m) {
3925  assert(phi < 2*twopi && phi > -twopi);
3926  double ptm = (m == 0) ? pt : sqrt(pt*pt+m*m);
3927  double exprap = exp(y);
3928  double pminus = ptm/exprap;
3929  double pplus = ptm*exprap;
3930  double px = pt*cos(phi);
3931  double py = pt*sin(phi);
3932  PseudoJet mom(px,py,0.5*(pplus-pminus),0.5*(pplus+pminus));
3933  mom.set_cached_rap_phi(y,phi);
3934  return mom;
3935 }
3936 double PseudoJet::kt_distance(const PseudoJet & other) const {
3937  double distance = min(_kt2, other._kt2);
3938  double dphi = abs(phi() - other.phi());
3939  if (dphi > pi) {dphi = twopi - dphi;}
3940  double drap = rap() - other.rap();
3941  distance = distance * (dphi*dphi + drap*drap);
3942  return distance;
3943 }
3944 double PseudoJet::plain_distance(const PseudoJet & other) const {
3945  double dphi = abs(phi() - other.phi());
3946  if (dphi > pi) {dphi = twopi - dphi;}
3947  double drap = rap() - other.rap();
3948  return (dphi*dphi + drap*drap);
3949 }
3950 double PseudoJet::delta_phi_to(const PseudoJet & other) const {
3951  double dphi = other.phi() - phi();
3952  if (dphi > pi) dphi -= twopi;
3953  if (dphi < -pi) dphi += twopi;
3954  return dphi;
3955 }
3956 string PseudoJet::description() const{
3957  if (!_structure)
3958  return "standard PseudoJet (with no associated clustering information)";
3959  return _structure->description();
3960 }
3961 bool PseudoJet::has_associated_cluster_sequence() const{
3962  return (_structure) && (_structure->has_associated_cluster_sequence());
3963 }
3964 const ClusterSequence* PseudoJet::associated_cluster_sequence() const{
3965  if (! has_associated_cluster_sequence()) return NULL;
3966  return _structure->associated_cluster_sequence();
3967 }
3968 bool PseudoJet::has_valid_cluster_sequence() const{
3969  return (_structure) && (_structure->has_valid_cluster_sequence());
3970 }
3971 const ClusterSequence * PseudoJet::validated_cs() const {
3972  return validated_structure_ptr()->validated_cs();
3973 }
3974 void PseudoJet::set_structure_shared_ptr(const SharedPtr<PseudoJetStructureBase> &structure_in){
3975  _structure = structure_in;
3976 }
3977 bool PseudoJet::has_structure() const{
3978  return bool(_structure);
3979 }
3980 const PseudoJetStructureBase* PseudoJet::structure_ptr() const {
3981  return _structure.get();
3982 }
3983 PseudoJetStructureBase* PseudoJet::structure_non_const_ptr(){
3984  return _structure.get();
3985 }
3986 const PseudoJetStructureBase* PseudoJet::validated_structure_ptr() const {
3987  if (!_structure)
3988  throw Error("Trying to access the structure of a PseudoJet which has no associated structure");
3989  return _structure.get();
3990 }
3991 const SharedPtr<PseudoJetStructureBase> & PseudoJet::structure_shared_ptr() const {
3992  return _structure;
3993 }
3994 bool PseudoJet::has_partner(PseudoJet &partner) const{
3995  return validated_structure_ptr()->has_partner(*this, partner);
3996 }
3997 bool PseudoJet::has_child(PseudoJet &child) const{
3998  return validated_structure_ptr()->has_child(*this, child);
3999 }
4000 bool PseudoJet::has_parents(PseudoJet &parent1, PseudoJet &parent2) const{
4001  return validated_structure_ptr()->has_parents(*this, parent1, parent2);
4002 }
4003 bool PseudoJet::contains(const PseudoJet &constituent) const{
4004  return validated_structure_ptr()->object_in_jet(constituent, *this);
4005 }
4006 bool PseudoJet::is_inside(const PseudoJet &jet) const{
4007  return validated_structure_ptr()->object_in_jet(*this, jet);
4008 }
4009 bool PseudoJet::has_constituents() const{
4010  return (_structure) && (_structure->has_constituents());
4011 }
4012 vector<PseudoJet> PseudoJet::constituents() const{
4013  return validated_structure_ptr()->constituents(*this);
4014 }
4015 bool PseudoJet::has_exclusive_subjets() const{
4016  return (_structure) && (_structure->has_exclusive_subjets());
4017 }
4018 std::vector<PseudoJet> PseudoJet::exclusive_subjets (const double dcut) const {
4019  return validated_structure_ptr()->exclusive_subjets(*this, dcut);
4020 }
4021 int PseudoJet::n_exclusive_subjets(const double dcut) const {
4022  return validated_structure_ptr()->n_exclusive_subjets(*this, dcut);
4023 }
4024 std::vector<PseudoJet> PseudoJet::exclusive_subjets_up_to (int nsub) const {
4025  return validated_structure_ptr()->exclusive_subjets_up_to(*this, nsub);
4026 }
4027 std::vector<PseudoJet> PseudoJet::exclusive_subjets (int nsub) const {
4028  vector<PseudoJet> subjets = exclusive_subjets_up_to(nsub);
4029  if (int(subjets.size()) < nsub) {
4030  ostringstream err;
4031  err << "Requested " << nsub << " exclusive subjets, but there were only "
4032  << subjets.size() << " particles in the jet";
4033  throw Error(err.str());
4034  }
4035  return subjets;
4036 }
4037 double PseudoJet::exclusive_subdmerge(int nsub) const {
4038  return validated_structure_ptr()->exclusive_subdmerge(*this, nsub);
4039 }
4040 double PseudoJet::exclusive_subdmerge_max(int nsub) const {
4041  return validated_structure_ptr()->exclusive_subdmerge_max(*this, nsub);
4042 }
4043 bool PseudoJet::has_pieces() const{
4044  return ((_structure) && (_structure->has_pieces(*this)));
4045 }
4046 std::vector<PseudoJet> PseudoJet::pieces() const{
4047  return validated_structure_ptr()->pieces(*this);
4048 }
4049 PseudoJet::InexistentUserInfo::InexistentUserInfo() : Error("you attempted to perform a dynamic cast of a PseudoJet's extra info, but the extra info pointer was null")
4050 {}
4051 void sort_indices(vector<int> & indices,
4052  const vector<double> & values) {
4053  IndexedSortHelper index_sort_helper(&values);
4054  sort(indices.begin(), indices.end(), index_sort_helper);
4055 }
4056 vector<PseudoJet> sorted_by_pt(const vector<PseudoJet> & jets) {
4057  vector<double> minus_kt2(jets.size());
4058  for (size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
4059  return objects_sorted_by_values(jets, minus_kt2);
4060 }
4061 vector<PseudoJet> sorted_by_rapidity(const vector<PseudoJet> & jets) {
4062  vector<double> rapidities(jets.size());
4063  for (size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
4064  return objects_sorted_by_values(jets, rapidities);
4065 }
4066 vector<PseudoJet> sorted_by_E(const vector<PseudoJet> & jets) {
4067  vector<double> energies(jets.size());
4068  for (size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
4069  return objects_sorted_by_values(jets, energies);
4070 }
4071 vector<PseudoJet> sorted_by_pz(const vector<PseudoJet> & jets) {
4072  vector<double> pz(jets.size());
4073  for (size_t i = 0; i < jets.size(); i++) {pz[i] = jets[i].pz();}
4074  return objects_sorted_by_values(jets, pz);
4075 }
4076 PseudoJet join(const vector<PseudoJet> & pieces){
4077  PseudoJet result; // automatically initialised to 0
4078  for (unsigned int i=0; i<pieces.size(); i++)
4079  result += pieces[i];
4080  CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces);
4081  result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
4082  return result;
4083 }
4084 PseudoJet join(const PseudoJet & j1){
4085  return join(vector<PseudoJet>(1,j1));
4086 }
4087 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2){
4088  vector<PseudoJet> pieces;
4089  pieces.reserve(2);
4090  pieces.push_back(j1);
4091  pieces.push_back(j2);
4092  return join(pieces);
4093 }
4094 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3){
4095  vector<PseudoJet> pieces;
4096  pieces.reserve(3);
4097  pieces.push_back(j1);
4098  pieces.push_back(j2);
4099  pieces.push_back(j3);
4100  return join(pieces);
4101 }
4102 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4){
4103  vector<PseudoJet> pieces;
4104  pieces.reserve(4);
4105  pieces.push_back(j1);
4106  pieces.push_back(j2);
4107  pieces.push_back(j3);
4108  pieces.push_back(j4);
4109  return join(pieces);
4110 }
4111 FJCORE_END_NAMESPACE
4112 using namespace std;
4113 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
4114 const ClusterSequence* PseudoJetStructureBase::associated_cluster_sequence() const{
4115  return NULL;
4116 }
4117 const ClusterSequence * PseudoJetStructureBase::validated_cs() const{
4118  throw Error("This PseudoJet structure is not associated with a valid ClusterSequence");
4119 }
4120 bool PseudoJetStructureBase::has_partner(const PseudoJet & /*reference */, PseudoJet & /*partner*/) const{
4121  throw Error("This PseudoJet structure has no implementation for has_partner");
4122 }
4123 bool PseudoJetStructureBase::has_child(const PseudoJet & /*reference*/, PseudoJet & /*child*/) const{
4124  throw Error("This PseudoJet structure has no implementation for has_child");
4125 }
4126 bool PseudoJetStructureBase::has_parents(const PseudoJet & /*reference*/, PseudoJet &/*parent1*/, PseudoJet &/*parent2*/) const{
4127  throw Error("This PseudoJet structure has no implementation for has_parents");
4128 }
4129 bool PseudoJetStructureBase::object_in_jet(const PseudoJet & /*reference*/, const PseudoJet & /*jet*/) const{
4130  throw Error("This PseudoJet structure has no implementation for is_inside");
4131 }
4132 vector<PseudoJet> PseudoJetStructureBase::constituents(const PseudoJet &/*reference*/) const{
4133  throw Error("This PseudoJet structure has no implementation for constituents");
4134 }
4135 vector<PseudoJet> PseudoJetStructureBase::exclusive_subjets (const PseudoJet & /*reference*/, const double & /*dcut*/) const{
4136  throw Error("This PseudoJet structure has no implementation for exclusive_subjets");
4137 }
4138 int PseudoJetStructureBase::n_exclusive_subjets(const PseudoJet & /*reference*/, const double & /*dcut*/) const{
4139  throw Error("This PseudoJet structure has no implementation for n_exclusive_subjets");
4140 }
4141 vector<PseudoJet> PseudoJetStructureBase::exclusive_subjets_up_to (const PseudoJet & /*reference*/, int /*nsub*/) const{
4142  throw Error("This PseudoJet structure has no implementation for exclusive_subjets");
4143 }
4144 double PseudoJetStructureBase::exclusive_subdmerge(const PseudoJet & /*reference*/, int /*nsub*/) const{
4145  throw Error("This PseudoJet structure has no implementation for exclusive_submerge");
4146 }
4147 double PseudoJetStructureBase::exclusive_subdmerge_max(const PseudoJet & /*reference*/, int /*nsub*/) const{
4148  throw Error("This PseudoJet structure has no implementation for exclusive_submerge_max");
4149 }
4150 std::vector<PseudoJet> PseudoJetStructureBase::pieces(const PseudoJet & /*reference*/) const{
4151  throw Error("This PseudoJet structure has no implementation for pieces");
4152 }
4153 FJCORE_END_NAMESPACE
4154 #include <sstream>
4155 #include <algorithm>
4156 using namespace std;
4157 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
4158 std::vector<PseudoJet> Selector::operator()(const std::vector<PseudoJet> & jets) const {
4159  std::vector<PseudoJet> result;
4160  const SelectorWorker * worker_local = validated_worker();
4161  if (worker_local->applies_jet_by_jet()) {
4162  for (std::vector<PseudoJet>::const_iterator jet = jets.begin();
4163  jet != jets.end(); jet++) {
4164  if (worker_local->pass(*jet)) result.push_back(*jet);
4165  }
4166  } else {
4167  std::vector<const PseudoJet *> jetptrs(jets.size());
4168  for (unsigned i = 0; i < jets.size(); i++) {
4169  jetptrs[i] = & jets[i];
4170  }
4171  worker_local->terminator(jetptrs);
4172  for (unsigned i = 0; i < jetptrs.size(); i++) {
4173  if (jetptrs[i]) result.push_back(jets[i]);
4174  }
4175  }
4176  return result;
4177 }
4178 unsigned int Selector::count(const std::vector<PseudoJet> & jets) const {
4179  unsigned n = 0;
4180  const SelectorWorker * worker_local = validated_worker();
4181  if (worker_local->applies_jet_by_jet()) {
4182  for (unsigned i = 0; i < jets.size(); i++) {
4183  if (worker_local->pass(jets[i])) n++;
4184  }
4185  } else {
4186  std::vector<const PseudoJet *> jetptrs(jets.size());
4187  for (unsigned i = 0; i < jets.size(); i++) {
4188  jetptrs[i] = & jets[i];
4189  }
4190  worker_local->terminator(jetptrs);
4191  for (unsigned i = 0; i < jetptrs.size(); i++) {
4192  if (jetptrs[i]) n++;
4193  }
4194  }
4195  return n;
4196 }
4197 PseudoJet Selector::sum(const std::vector<PseudoJet> & jets) const {
4198  PseudoJet this_sum(0,0,0,0);
4199  const SelectorWorker * worker_local = validated_worker();
4200  if (worker_local->applies_jet_by_jet()) {
4201  for (unsigned i = 0; i < jets.size(); i++) {
4202  if (worker_local->pass(jets[i])) this_sum += jets[i];
4203  }
4204  } else {
4205  std::vector<const PseudoJet *> jetptrs(jets.size());
4206  for (unsigned i = 0; i < jets.size(); i++) {
4207  jetptrs[i] = & jets[i];
4208  }
4209  worker_local->terminator(jetptrs);
4210  for (unsigned i = 0; i < jetptrs.size(); i++) {
4211  if (jetptrs[i]) this_sum += jets[i];
4212  }
4213  }
4214  return this_sum;
4215 }
4216 double Selector::scalar_pt_sum(const std::vector<PseudoJet> & jets) const {
4217  double this_sum = 0.0;
4218  const SelectorWorker * worker_local = validated_worker();
4219  if (worker_local->applies_jet_by_jet()) {
4220  for (unsigned i = 0; i < jets.size(); i++) {
4221  if (worker_local->pass(jets[i])) this_sum += jets[i].pt();
4222  }
4223  } else {
4224  std::vector<const PseudoJet *> jetptrs(jets.size());
4225  for (unsigned i = 0; i < jets.size(); i++) {
4226  jetptrs[i] = & jets[i];
4227  }
4228  worker_local->terminator(jetptrs);
4229  for (unsigned i = 0; i < jetptrs.size(); i++) {
4230  if (jetptrs[i]) this_sum += jets[i].pt();
4231  }
4232  }
4233  return this_sum;
4234 }
4235 void Selector::sift(const std::vector<PseudoJet> & jets,
4236  std::vector<PseudoJet> & jets_that_pass,
4237  std::vector<PseudoJet> & jets_that_fail
4238  ) const {
4239  const SelectorWorker * worker_local = validated_worker();
4240  jets_that_pass.clear();
4241  jets_that_fail.clear();
4242  if (worker_local->applies_jet_by_jet()) {
4243  for (unsigned i = 0; i < jets.size(); i++) {
4244  if (worker_local->pass(jets[i])) {
4245  jets_that_pass.push_back(jets[i]);
4246  } else {
4247  jets_that_fail.push_back(jets[i]);
4248  }
4249  }
4250  } else {
4251  std::vector<const PseudoJet *> jetptrs(jets.size());
4252  for (unsigned i = 0; i < jets.size(); i++) {
4253  jetptrs[i] = & jets[i];
4254  }
4255  worker_local->terminator(jetptrs);
4256  for (unsigned i = 0; i < jetptrs.size(); i++) {
4257  if (jetptrs[i]) {
4258  jets_that_pass.push_back(jets[i]);
4259  } else {
4260  jets_that_fail.push_back(jets[i]);
4261  }
4262  }
4263  }
4264 }
4265 bool SelectorWorker::has_finite_area() const {
4266  if (! is_geometric()) return false;
4267  double rapmin, rapmax;
4268  get_rapidity_extent(rapmin, rapmax);
4269  return (rapmax != std::numeric_limits<double>::infinity())
4270  && (-rapmin != std::numeric_limits<double>::infinity());
4271 }
4272 class SW_Identity : public SelectorWorker {
4273 public:
4274  SW_Identity(){}
4275  virtual bool pass(const PseudoJet &) const {
4276  return true;
4277  }
4278  virtual void terminator(vector<const PseudoJet *> &) const {
4279  return;
4280  }
4281  virtual string description() const { return "Identity";}
4282  virtual bool is_geometric() const { return true;}
4283 };
4284 Selector SelectorIdentity() {
4285  return Selector(new SW_Identity);
4286 }
4287 class SW_Not : public SelectorWorker {
4288 public:
4289  SW_Not(const Selector & s) : _s(s) {}
4290  virtual SelectorWorker* copy(){ return new SW_Not(*this);}
4291  virtual bool pass(const PseudoJet & jet) const {
4292  if (!applies_jet_by_jet())
4293  throw Error("Cannot apply this selector worker to an individual jet");
4294  return ! _s.pass(jet);
4295  }
4296  virtual bool applies_jet_by_jet() const {return _s.applies_jet_by_jet();}
4297  virtual void terminator(vector<const PseudoJet *> & jets) const {
4298  if (applies_jet_by_jet()){
4299  SelectorWorker::terminator(jets);
4300  return;
4301  }
4302  vector<const PseudoJet *> s_jets = jets;
4303  _s.worker()->terminator(s_jets);
4304  for (unsigned int i=0; i<s_jets.size(); i++){
4305  if (s_jets[i]) jets[i] = NULL;
4306  }
4307  }
4308  virtual string description() const {
4309  ostringstream ostr;
4310  ostr << "!(" << _s.description() << ")";
4311  return ostr.str();
4312  }
4313  virtual bool is_geometric() const { return _s.is_geometric();}
4314  virtual bool takes_reference() const { return _s.takes_reference();}
4315  virtual void set_reference(const PseudoJet &ref) { _s.set_reference(ref);}
4316 protected:
4317  Selector _s;
4318 };
4319 Selector operator!(const Selector & s) {
4320  return Selector(new SW_Not(s));
4321 }
4322 class SW_BinaryOperator: public SelectorWorker {
4323 public:
4324  SW_BinaryOperator(const Selector & s1, const Selector & s2) : _s1(s1), _s2(s2) {
4325  _applies_jet_by_jet = _s1.applies_jet_by_jet() && _s2.applies_jet_by_jet();
4326  _takes_reference = _s1.takes_reference() || _s2.takes_reference();
4327  _is_geometric = _s1.is_geometric() && _s2.is_geometric();
4328  }
4329  virtual bool applies_jet_by_jet() const {return _applies_jet_by_jet;}
4330  virtual bool takes_reference() const{
4331  return _takes_reference;
4332  }
4333  virtual void set_reference(const PseudoJet &centre){
4334  _s1.set_reference(centre);
4335  _s2.set_reference(centre);
4336  }
4337  virtual bool is_geometric() const { return _is_geometric;}
4338 protected:
4339  Selector _s1, _s2;
4340  bool _applies_jet_by_jet;
4341  bool _takes_reference;
4342  bool _is_geometric;
4343 };
4344 class SW_And: public SW_BinaryOperator {
4345 public:
4346  SW_And(const Selector & s1, const Selector & s2) : SW_BinaryOperator(s1,s2){}
4347  virtual SelectorWorker* copy(){ return new SW_And(*this);}
4348  virtual bool pass(const PseudoJet & jet) const {
4349  if (!applies_jet_by_jet())
4350  throw Error("Cannot apply this selector worker to an individual jet");
4351  return _s1.pass(jet) && _s2.pass(jet);
4352  }
4353  virtual void terminator(vector<const PseudoJet *> & jets) const {
4354  if (applies_jet_by_jet()){
4355  SelectorWorker::terminator(jets);
4356  return;
4357  }
4358  vector<const PseudoJet *> s1_jets = jets;
4359  _s1.worker()->terminator(s1_jets);
4360  _s2.worker()->terminator(jets);
4361  for (unsigned int i=0; i<jets.size(); i++){
4362  if (! s1_jets[i]) jets[i] = NULL;
4363  }
4364  }
4365  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const {
4366  double s1min, s1max, s2min, s2max;
4367  _s1.get_rapidity_extent(s1min, s1max);
4368  _s2.get_rapidity_extent(s2min, s2max);
4369  rapmax = min(s1max, s2max);
4370  rapmin = max(s1min, s2min);
4371  }
4372  virtual string description() const {
4373  ostringstream ostr;
4374  ostr << "(" << _s1.description() << " && " << _s2.description() << ")";
4375  return ostr.str();
4376  }
4377 };
4378 Selector operator&&(const Selector & s1, const Selector & s2) {
4379  return Selector(new SW_And(s1,s2));
4380 }
4381 class SW_Or: public SW_BinaryOperator {
4382 public:
4383  SW_Or(const Selector & s1, const Selector & s2) : SW_BinaryOperator(s1,s2) {}
4384  virtual SelectorWorker* copy(){ return new SW_Or(*this);}
4385  virtual bool pass(const PseudoJet & jet) const {
4386  if (!applies_jet_by_jet())
4387  throw Error("Cannot apply this selector worker to an individual jet");
4388  return _s1.pass(jet) || _s2.pass(jet);
4389  }
4390  virtual bool applies_jet_by_jet() const {
4391  return _s1.applies_jet_by_jet() && _s2.applies_jet_by_jet();
4392  }
4393  virtual void terminator(vector<const PseudoJet *> & jets) const {
4394  if (applies_jet_by_jet()){
4395  SelectorWorker::terminator(jets);
4396  return;
4397  }
4398  vector<const PseudoJet *> s1_jets = jets;
4399  _s1.worker()->terminator(s1_jets);
4400  _s2.worker()->terminator(jets);
4401  for (unsigned int i=0; i<jets.size(); i++){
4402  if (s1_jets[i]) jets[i] = s1_jets[i];
4403  }
4404  }
4405  virtual string description() const {
4406  ostringstream ostr;
4407  ostr << "(" << _s1.description() << " || " << _s2.description() << ")";
4408  return ostr.str();
4409  }
4410  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const {
4411  double s1min, s1max, s2min, s2max;
4412  _s1.get_rapidity_extent(s1min, s1max);
4413  _s2.get_rapidity_extent(s2min, s2max);
4414  rapmax = max(s1max, s2max);
4415  rapmin = min(s1min, s2min);
4416  }
4417 };
4418 Selector operator ||(const Selector & s1, const Selector & s2) {
4419  return Selector(new SW_Or(s1,s2));
4420 }
4421 class SW_Mult: public SW_And {
4422 public:
4423  SW_Mult(const Selector & s1, const Selector & s2) : SW_And(s1,s2) {}
4424  virtual SelectorWorker* copy(){ return new SW_Mult(*this);}
4425  virtual void terminator(vector<const PseudoJet *> & jets) const {
4426  if (applies_jet_by_jet()){
4427  SelectorWorker::terminator(jets);
4428  return;
4429  }
4430  _s2.worker()->terminator(jets);
4431  _s1.worker()->terminator(jets);
4432  }
4433  virtual string description() const {
4434  ostringstream ostr;
4435  ostr << "(" << _s1.description() << " * " << _s2.description() << ")";
4436  return ostr.str();
4437  }
4438 };
4439 Selector operator*(const Selector & s1, const Selector & s2) {
4440  return Selector(new SW_Mult(s1,s2));
4441 }
4442 class QuantityBase{
4443 public:
4444  QuantityBase(double q) : _q(q){}
4445  virtual ~QuantityBase(){}
4446  virtual double operator()(const PseudoJet & jet ) const =0;
4447  virtual string description() const =0;
4448  virtual bool is_geometric() const { return false;}
4449  virtual double comparison_value() const {return _q;}
4450  virtual double description_value() const {return comparison_value();}
4451 protected:
4452  double _q;
4453 };
4454 class QuantitySquareBase : public QuantityBase{
4455 public:
4456  QuantitySquareBase(double sqrtq) : QuantityBase(sqrtq*sqrtq), _sqrtq(sqrtq){}
4457  virtual double description_value() const {return _sqrtq;}
4458 protected:
4459  double _sqrtq;
4460 };
4461 template<typename QuantityType>
4462 class SW_QuantityMin : public SelectorWorker{
4463 public:
4464  SW_QuantityMin(double qmin) : _qmin(qmin) {}
4465  virtual bool pass(const PseudoJet & jet) const {return _qmin(jet) >= _qmin.comparison_value();}
4466  virtual string description() const {
4467  ostringstream ostr;
4468  ostr << _qmin.description() << " >= " << _qmin.description_value();
4469  return ostr.str();
4470  }
4471  virtual bool is_geometric() const { return _qmin.is_geometric();}
4472 protected:
4473  QuantityType _qmin;
4474 };
4475 template<typename QuantityType>
4476 class SW_QuantityMax : public SelectorWorker {
4477 public:
4478  SW_QuantityMax(double qmax) : _qmax(qmax) {}
4479  virtual bool pass(const PseudoJet & jet) const {return _qmax(jet) <= _qmax.comparison_value();}
4480  virtual string description() const {
4481  ostringstream ostr;
4482  ostr << _qmax.description() << " <= " << _qmax.description_value();
4483  return ostr.str();
4484  }
4485  virtual bool is_geometric() const { return _qmax.is_geometric();}
4486 protected:
4487  QuantityType _qmax;
4488 };
4489 template<typename QuantityType>
4490 class SW_QuantityRange : public SelectorWorker {
4491 public:
4492  SW_QuantityRange(double qmin, double qmax) : _qmin(qmin), _qmax(qmax) {}
4493  virtual bool pass(const PseudoJet & jet) const {
4494  double q = _qmin(jet); // we could identically use _qmax
4495  return (q >= _qmin.comparison_value()) && (q <= _qmax.comparison_value());
4496  }
4497  virtual string description() const {
4498  ostringstream ostr;
4499  ostr << _qmin.description_value() << " <= " << _qmin.description() << " <= " << _qmax.description_value();
4500  return ostr.str();
4501  }
4502  virtual bool is_geometric() const { return _qmin.is_geometric();}
4503 protected:
4504  QuantityType _qmin; // the lower cut
4505  QuantityType _qmax; // the upper cut
4506 };
4507 class QuantityPt2 : public QuantitySquareBase{
4508 public:
4509  QuantityPt2(double pt) : QuantitySquareBase(pt){}
4510  virtual double operator()(const PseudoJet & jet ) const { return jet.perp2();}
4511  virtual string description() const {return "pt";}
4512 };
4513 Selector SelectorPtMin(double ptmin) {
4514  return Selector(new SW_QuantityMin<QuantityPt2>(ptmin));
4515 }
4516 Selector SelectorPtMax(double ptmax) {
4517  return Selector(new SW_QuantityMax<QuantityPt2>(ptmax));
4518 }
4519 Selector SelectorPtRange(double ptmin, double ptmax) {
4520  return Selector(new SW_QuantityRange<QuantityPt2>(ptmin, ptmax));
4521 }
4522 class QuantityEt2 : public QuantitySquareBase{
4523 public:
4524  QuantityEt2(double Et) : QuantitySquareBase(Et){}
4525  virtual double operator()(const PseudoJet & jet ) const { return jet.Et2();}
4526  virtual string description() const {return "Et";}
4527 };
4528 Selector SelectorEtMin(double Etmin) {
4529  return Selector(new SW_QuantityMin<QuantityEt2>(Etmin));
4530 }
4531 Selector SelectorEtMax(double Etmax) {
4532  return Selector(new SW_QuantityMax<QuantityEt2>(Etmax));
4533 }
4534 Selector SelectorEtRange(double Etmin, double Etmax) {
4535  return Selector(new SW_QuantityRange<QuantityEt2>(Etmin, Etmax));
4536 }
4537 class QuantityE : public QuantityBase{
4538 public:
4539  QuantityE(double E) : QuantityBase(E){}
4540  virtual double operator()(const PseudoJet & jet ) const { return jet.E();}
4541  virtual string description() const {return "E";}
4542 };
4543 Selector SelectorEMin(double Emin) {
4544  return Selector(new SW_QuantityMin<QuantityE>(Emin));
4545 }
4546 Selector SelectorEMax(double Emax) {
4547  return Selector(new SW_QuantityMax<QuantityE>(Emax));
4548 }
4549 Selector SelectorERange(double Emin, double Emax) {
4550  return Selector(new SW_QuantityRange<QuantityE>(Emin, Emax));
4551 }
4552 class QuantityM2 : public QuantitySquareBase{
4553 public:
4554  QuantityM2(double m) : QuantitySquareBase(m){}
4555  virtual double operator()(const PseudoJet & jet ) const { return jet.m2();}
4556  virtual string description() const {return "mass";}
4557 };
4558 Selector SelectorMassMin(double mmin) {
4559  return Selector(new SW_QuantityMin<QuantityM2>(mmin));
4560 }
4561 Selector SelectorMassMax(double mmax) {
4562  return Selector(new SW_QuantityMax<QuantityM2>(mmax));
4563 }
4564 Selector SelectorMassRange(double mmin, double mmax) {
4565  return Selector(new SW_QuantityRange<QuantityM2>(mmin, mmax));
4566 }
4567 class QuantityRap : public QuantityBase{
4568 public:
4569  QuantityRap(double rap) : QuantityBase(rap){}
4570  virtual double operator()(const PseudoJet & jet ) const { return jet.rap();}
4571  virtual string description() const {return "rap";}
4572  virtual bool is_geometric() const { return true;}
4573 };
4574 class SW_RapMin : public SW_QuantityMin<QuantityRap>{
4575 public:
4576  SW_RapMin(double rapmin) : SW_QuantityMin<QuantityRap>(rapmin){}
4577  virtual void get_rapidity_extent(double &rapmin, double & rapmax) const{
4578  rapmax = std::numeric_limits<double>::max();
4579  rapmin = _qmin.comparison_value();
4580  }
4581 };
4582 class SW_RapMax : public SW_QuantityMax<QuantityRap>{
4583 public:
4584  SW_RapMax(double rapmax) : SW_QuantityMax<QuantityRap>(rapmax){}
4585  virtual void get_rapidity_extent(double &rapmin, double & rapmax) const{
4586  rapmax = _qmax.comparison_value();
4587  rapmin = -std::numeric_limits<double>::max();
4588  }
4589 };
4590 class SW_RapRange : public SW_QuantityRange<QuantityRap>{
4591 public:
4592  SW_RapRange(double rapmin, double rapmax) : SW_QuantityRange<QuantityRap>(rapmin, rapmax){
4593  assert(rapmin<=rapmax);
4594  }
4595  virtual void get_rapidity_extent(double &rapmin, double & rapmax) const{
4596  rapmax = _qmax.comparison_value();
4597  rapmin = _qmin.comparison_value();
4598  }
4599  virtual bool has_known_area() const { return true;}
4600  virtual double known_area() const {
4601  return twopi * (_qmax.comparison_value()-_qmin.comparison_value());
4602  }
4603 };
4604 Selector SelectorRapMin(double rapmin) {
4605  return Selector(new SW_RapMin(rapmin));
4606 }
4607 Selector SelectorRapMax(double rapmax) {
4608  return Selector(new SW_RapMax(rapmax));
4609 }
4610 Selector SelectorRapRange(double rapmin, double rapmax) {
4611  return Selector(new SW_RapRange(rapmin, rapmax));
4612 }
4613 class QuantityAbsRap : public QuantityBase{
4614 public:
4615  QuantityAbsRap(double absrap) : QuantityBase(absrap){}
4616  virtual double operator()(const PseudoJet & jet ) const { return abs(jet.rap());}
4617  virtual string description() const {return "|rap|";}
4618  virtual bool is_geometric() const { return true;}
4619 };
4620 class SW_AbsRapMax : public SW_QuantityMax<QuantityAbsRap>{
4621 public:
4622  SW_AbsRapMax(double absrapmax) : SW_QuantityMax<QuantityAbsRap>(absrapmax){}
4623  virtual void get_rapidity_extent(double &rapmin, double & rapmax) const{
4624  rapmax = _qmax.comparison_value();
4625  rapmin = -_qmax.comparison_value();
4626  }
4627  virtual bool has_known_area() const { return true;}
4628  virtual double known_area() const {
4629  return twopi * 2 * _qmax.comparison_value();
4630  }
4631 };
4632 class SW_AbsRapRange : public SW_QuantityRange<QuantityAbsRap>{
4633 public:
4634  SW_AbsRapRange(double absrapmin, double absrapmax) : SW_QuantityRange<QuantityAbsRap>(absrapmin, absrapmax){}
4635  virtual void get_rapidity_extent(double &rapmin, double & rapmax) const{
4636  rapmax = _qmax.comparison_value();
4637  rapmin = -_qmax.comparison_value();
4638  }
4639  virtual bool has_known_area() const { return true;}
4640  virtual double known_area() const {
4641  return twopi * 2 * (_qmax.comparison_value()-max(_qmin.comparison_value(),0.0)); // this should handle properly absrapmin<0
4642  }
4643 };
4644 Selector SelectorAbsRapMin(double absrapmin) {
4645  return Selector(new SW_QuantityMin<QuantityAbsRap>(absrapmin));
4646 }
4647 Selector SelectorAbsRapMax(double absrapmax) {
4648  return Selector(new SW_AbsRapMax(absrapmax));
4649 }
4650 Selector SelectorAbsRapRange(double rapmin, double rapmax) {
4651  return Selector(new SW_AbsRapRange(rapmin, rapmax));
4652 }
4653 class QuantityEta : public QuantityBase{
4654 public:
4655  QuantityEta(double eta) : QuantityBase(eta){}
4656  virtual double operator()(const PseudoJet & jet ) const { return jet.eta();}
4657  virtual string description() const {return "eta";}
4658 };
4659 Selector SelectorEtaMin(double etamin) {
4660  return Selector(new SW_QuantityMin<QuantityEta>(etamin));
4661 }
4662 Selector SelectorEtaMax(double etamax) {
4663  return Selector(new SW_QuantityMax<QuantityEta>(etamax));
4664 }
4665 Selector SelectorEtaRange(double etamin, double etamax) {
4666  return Selector(new SW_QuantityRange<QuantityEta>(etamin, etamax));
4667 }
4668 class QuantityAbsEta : public QuantityBase{
4669 public:
4670  QuantityAbsEta(double abseta) : QuantityBase(abseta){}
4671  virtual double operator()(const PseudoJet & jet ) const { return abs(jet.eta());}
4672  virtual string description() const {return "|eta|";}
4673  virtual bool is_geometric() const { return true;}
4674 };
4675 Selector SelectorAbsEtaMin(double absetamin) {
4676  return Selector(new SW_QuantityMin<QuantityAbsEta>(absetamin));
4677 }
4678 Selector SelectorAbsEtaMax(double absetamax) {
4679  return Selector(new SW_QuantityMax<QuantityAbsEta>(absetamax));
4680 }
4681 Selector SelectorAbsEtaRange(double absetamin, double absetamax) {
4682  return Selector(new SW_QuantityRange<QuantityAbsEta>(absetamin, absetamax));
4683 }
4684 class SW_PhiRange : public SelectorWorker {
4685 public:
4686  SW_PhiRange(double phimin, double phimax) : _phimin(phimin), _phimax(phimax){
4687  assert(_phimin<_phimax);
4688  assert(_phimin>-twopi);
4689  assert(_phimax<2*twopi);
4690  _phispan = _phimax - _phimin;
4691  }
4692  virtual bool pass(const PseudoJet & jet) const {
4693  double dphi=jet.phi()-_phimin;
4694  if (dphi >= twopi) dphi -= twopi;
4695  if (dphi < 0) dphi += twopi;
4696  return (dphi <= _phispan);
4697  }
4698  virtual string description() const {
4699  ostringstream ostr;
4700  ostr << _phimin << " <= phi <= " << _phimax;
4701  return ostr.str();
4702  }
4703  virtual bool is_geometric() const { return true;}
4704 protected:
4705  double _phimin; // the lower cut
4706  double _phimax; // the upper cut
4707  double _phispan; // the span of the range
4708 };
4709 Selector SelectorPhiRange(double phimin, double phimax) {
4710  return Selector(new SW_PhiRange(phimin, phimax));
4711 }
4712 class SW_RapPhiRange : public SW_And{
4713 public:
4714  SW_RapPhiRange(double rapmin, double rapmax, double phimin, double phimax)
4715  : SW_And(SelectorRapRange(rapmin, rapmax), SelectorPhiRange(phimin, phimax)){
4716  _known_area = ((phimax-phimin > twopi) ? twopi : phimax-phimin) * (rapmax-rapmin);
4717  }
4718  virtual double known_area() const{
4719  return _known_area;
4720  }
4721 protected:
4722  double _known_area;
4723 };
4724 Selector SelectorRapPhiRange(double rapmin, double rapmax, double phimin, double phimax) {
4725  return Selector(new SW_RapPhiRange(rapmin, rapmax, phimin, phimax));
4726 }
4727 class SW_NHardest : public SelectorWorker {
4728 public:
4729  SW_NHardest(unsigned int n) : _n(n) {};
4730  virtual bool pass(const PseudoJet &) const {
4731  if (!applies_jet_by_jet())
4732  throw Error("Cannot apply this selector worker to an individual jet");
4733  return false;
4734  }
4735  virtual void terminator(vector<const PseudoJet *> & jets) const {
4736  if (jets.size() < _n) return;
4737  vector<double> minus_pt2(jets.size());
4738  vector<unsigned int> indices(jets.size());
4739  for (unsigned int i=0; i<jets.size(); i++){
4740  indices[i] = i;
4741  minus_pt2[i] = jets[i] ? -jets[i]->perp2() : 0.0;
4742  }
4743  IndexedSortHelper sort_helper(& minus_pt2);
4744  partial_sort(indices.begin(), indices.begin()+_n, indices.end(), sort_helper);
4745  for (unsigned int i=_n; i<jets.size(); i++)
4746  jets[indices[i]] = NULL;
4747  }
4748  virtual bool applies_jet_by_jet() const {return false;}
4749  virtual string description() const {
4750  ostringstream ostr;
4751  ostr << _n << " hardest";
4752  return ostr.str();
4753  }
4754 protected:
4755  unsigned int _n;
4756 };
4757 Selector SelectorNHardest(unsigned int n) {
4758  return Selector(new SW_NHardest(n));
4759 }
4760 class SW_WithReference : public SelectorWorker{
4761 public:
4762  SW_WithReference() : _is_initialised(false){};
4763  virtual bool takes_reference() const { return true;}
4764  virtual void set_reference(const PseudoJet &centre){
4765  _is_initialised = true;
4766  _reference = centre;
4767  }
4768 protected:
4769  PseudoJet _reference;
4770  bool _is_initialised;
4771 };
4772 class SW_Circle : public SW_WithReference {
4773 public:
4774  SW_Circle(const double radius) : _radius2(radius*radius) {}
4775  virtual SelectorWorker* copy(){ return new SW_Circle(*this);}
4776  virtual bool pass(const PseudoJet & jet) const {
4777  if (! _is_initialised)
4778  throw Error("To use a SelectorCircle (or any selector that requires a reference), you first have to call set_reference(...)");
4779  return jet.squared_distance(_reference) <= _radius2;
4780  }
4781  virtual string description() const {
4782  ostringstream ostr;
4783  ostr << "distance from the centre <= " << sqrt(_radius2);
4784  return ostr.str();
4785  }
4786  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const{
4787  if (! _is_initialised)
4788  throw Error("To use a SelectorCircle (or any selector that requires a reference), you first have to call set_reference(...)");
4789  rapmax = _reference.rap()+sqrt(_radius2);
4790  rapmin = _reference.rap()-sqrt(_radius2);
4791  }
4792  virtual bool is_geometric() const { return true;}
4793  virtual bool has_finite_area() const { return true;}
4794  virtual bool has_known_area() const { return true;}
4795  virtual double known_area() const {
4796  return pi * _radius2;
4797  }
4798 protected:
4799  double _radius2;
4800 };
4801 Selector SelectorCircle(const double radius) {
4802  return Selector(new SW_Circle(radius));
4803 }
4804 class SW_Doughnut : public SW_WithReference {
4805 public:
4806  SW_Doughnut(const double radius_in, const double radius_out)
4807  : _radius_in2(radius_in*radius_in), _radius_out2(radius_out*radius_out) {}
4808  virtual SelectorWorker* copy(){ return new SW_Doughnut(*this);}
4809  virtual bool pass(const PseudoJet & jet) const {
4810  if (! _is_initialised)
4811  throw Error("To use a SelectorDoughnut (or any selector that requires a reference), you first have to call set_reference(...)");
4812  double distance2 = jet.squared_distance(_reference);
4813  return (distance2 <= _radius_out2) && (distance2 >= _radius_in2);
4814  }
4815  virtual string description() const {
4816  ostringstream ostr;
4817  ostr << sqrt(_radius_in2) << " <= distance from the centre <= " << sqrt(_radius_out2);
4818  return ostr.str();
4819  }
4820  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const{
4821  if (! _is_initialised)
4822  throw Error("To use a SelectorDoughnut (or any selector that requires a reference), you first have to call set_reference(...)");
4823  rapmax = _reference.rap()+sqrt(_radius_out2);
4824  rapmin = _reference.rap()-sqrt(_radius_out2);
4825  }
4826  virtual bool is_geometric() const { return true;}
4827  virtual bool has_finite_area() const { return true;}
4828  virtual bool has_known_area() const { return true;}
4829  virtual double known_area() const {
4830  return pi * (_radius_out2-_radius_in2);
4831  }
4832 protected:
4833  double _radius_in2, _radius_out2;
4834 };
4835 Selector SelectorDoughnut(const double radius_in, const double radius_out) {
4836  return Selector(new SW_Doughnut(radius_in, radius_out));
4837 }
4838 class SW_Strip : public SW_WithReference {
4839 public:
4840  SW_Strip(const double delta) : _delta(delta) {}
4841  virtual SelectorWorker* copy(){ return new SW_Strip(*this);}
4842  virtual bool pass(const PseudoJet & jet) const {
4843  if (! _is_initialised)
4844  throw Error("To use a SelectorStrip (or any selector that requires a reference), you first have to call set_reference(...)");
4845  return abs(jet.rap()-_reference.rap()) <= _delta;
4846  }
4847  virtual string description() const {
4848  ostringstream ostr;
4849  ostr << "|rap - rap_reference| <= " << _delta;
4850  return ostr.str();
4851  }
4852  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const{
4853  if (! _is_initialised)
4854  throw Error("To use a SelectorStrip (or any selector that requires a reference), you first have to call set_reference(...)");
4855  rapmax = _reference.rap()+_delta;
4856  rapmin = _reference.rap()-_delta;
4857  }
4858  virtual bool is_geometric() const { return true;}
4859  virtual bool has_finite_area() const { return true;}
4860  virtual bool has_known_area() const { return true;}
4861  virtual double known_area() const {
4862  return twopi * 2 * _delta;
4863  }
4864 protected:
4865  double _delta;
4866 };
4867 Selector SelectorStrip(const double half_width) {
4868  return Selector(new SW_Strip(half_width));
4869 }
4870 class SW_Rectangle : public SW_WithReference {
4871 public:
4872  SW_Rectangle(const double delta_rap, const double delta_phi)
4873  : _delta_rap(delta_rap), _delta_phi(delta_phi) {}
4874  virtual SelectorWorker* copy(){ return new SW_Rectangle(*this);}
4875  virtual bool pass(const PseudoJet & jet) const {
4876  if (! _is_initialised)
4877  throw Error("To use a SelectorRectangle (or any selector that requires a reference), you first have to call set_reference(...)");
4878  return (abs(jet.rap()-_reference.rap()) <= _delta_rap) && (abs(jet.delta_phi_to(_reference)) <= _delta_phi);
4879  }
4880  virtual string description() const {
4881  ostringstream ostr;
4882  ostr << "|rap - rap_reference| <= " << _delta_rap << " && |phi - phi_reference| <= " << _delta_phi ;
4883  return ostr.str();
4884  }
4885  virtual void get_rapidity_extent(double & rapmin, double & rapmax) const{
4886  if (! _is_initialised)
4887  throw Error("To use a SelectorRectangle (or any selector that requires a reference), you first have to call set_reference(...)");
4888  rapmax = _reference.rap()+_delta_rap;
4889  rapmin = _reference.rap()-_delta_rap;
4890  }
4891  virtual bool is_geometric() const { return true;}
4892  virtual bool has_finite_area() const { return true;}
4893  virtual bool has_known_area() const { return true;}
4894  virtual double known_area() const {
4895  return 4 * _delta_rap * _delta_phi;
4896  }
4897 protected:
4898  double _delta_rap, _delta_phi;
4899 };
4900 Selector SelectorRectangle(const double half_rap_width, const double half_phi_width) {
4901  return Selector(new SW_Rectangle(half_rap_width, half_phi_width));
4902 }
4903 class SW_PtFractionMin : public SW_WithReference {
4904 public:
4905  SW_PtFractionMin(double fraction) : _fraction2(fraction*fraction){}
4906  virtual SelectorWorker* copy(){ return new SW_PtFractionMin(*this);}
4907  virtual bool pass(const PseudoJet & jet) const {
4908  if (! _is_initialised)
4909  throw Error("To use a SelectorPtFractionMin (or any selector that requires a reference), you first have to call set_reference(...)");
4910  return (jet.perp2() >= _fraction2*_reference.perp2());
4911  }
4912  virtual string description() const {
4913  ostringstream ostr;
4914  ostr << "pt >= " << sqrt(_fraction2) << "* pt_ref";
4915  return ostr.str();
4916  }
4917 protected:
4918  double _fraction2;
4919 };
4920 Selector SelectorPtFractionMin(double fraction){
4921  return Selector(new SW_PtFractionMin(fraction));
4922 }
4923 class SW_IsZero : public SelectorWorker {
4924 public:
4925  SW_IsZero(){}
4926  virtual bool pass(const PseudoJet & jet) const {
4927  return jet==0;
4928  }
4929  virtual string description() const { return "zero";}
4930 };
4931 Selector SelectorIsZero(){
4932  return Selector(new SW_IsZero());
4933 }
4934 Selector & Selector::operator &=(const Selector & b){
4935  _worker.reset(new SW_And(*this, b));
4936  return *this;
4937 }
4938 Selector & Selector::operator |=(const Selector & b){
4939  _worker.reset(new SW_Or(*this, b));
4940  return *this;
4941 }
4942 FJCORE_END_NAMESPACE // defined in fastjet/internal/base.hh
4943 #include <iomanip>
4944 using namespace std;
4945 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
4946 LazyTiling25::LazyTiling25(ClusterSequence & cs) :
4947  _cs(cs), _jets(cs.jets())
4948 {
4949 #ifdef INSTRUMENT2
4950  _ncall = 0; // gps tmp
4951  _ncall_dtt = 0; // gps tmp
4952 #endif // INSTRUMENT2
4953  _Rparam = cs.jet_def().R();
4954  _R2 = _Rparam * _Rparam;
4955  _invR2 = 1.0 / _R2;
4956  _initialise_tiles();
4957 }
4958 void LazyTiling25::_initialise_tiles() {
4959  double default_size = max(0.1,_Rparam)/2;
4960  _tile_size_eta = default_size;
4961  _n_tiles_phi = max(5,int(floor(twopi/default_size)));
4962  _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi
4963 #define _FJCORE_TILING25_USE_TILING_ANALYSIS_
4964 #ifdef _FASTJET_TILING25_USE_TILING_ANALYSIS_
4965  TilingExtent tiling_analysis(_cs);
4966  _tiles_eta_min = tiling_analysis.minrap();
4967  _tiles_eta_max = tiling_analysis.maxrap();
4968 #else // not _FASTJET_TILING25_USE_TILING_ANALYSIS_
4969  _tiles_eta_min = 0.0;
4970  _tiles_eta_max = 0.0;
4971  const double maxrap = 7.0;
4972  for(unsigned int i = 0; i < _jets.size(); i++) {
4973  double eta = _jets[i].rap();
4974  if (abs(eta) < maxrap) {
4975  if (eta < _tiles_eta_min) {_tiles_eta_min = eta;}
4976  if (eta > _tiles_eta_max) {_tiles_eta_max = eta;}
4977  }
4978  }
4979 #endif // _FASTJET_TILING25_USE_TILING_ANALYSIS_
4980 # define FJCORE_LAZY25_MIN3TILESY
4981 #ifdef FJCORE_LAZY25_MIN3TILESY
4982  if (_tiles_eta_max - _tiles_eta_min < 3*_tile_size_eta) {
4983  _tile_size_eta = (_tiles_eta_max - _tiles_eta_min)/3;
4984  _tiles_ieta_min = 0;
4985  _tiles_ieta_max = 2;
4986  _tiles_eta_max -= _tile_size_eta;
4987  } else {
4988 #endif //FASTJET_LAZY25_MIN3TILESY
4989  _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta));
4990  _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta));
4991  _tiles_eta_min = _tiles_ieta_min * _tile_size_eta;
4992  _tiles_eta_max = _tiles_ieta_max * _tile_size_eta;
4993 #ifdef FJCORE_LAZY25_MIN3TILESY
4994  }
4995 #endif
4996  _tile_half_size_eta = _tile_size_eta * 0.5;
4997  _tile_half_size_phi = _tile_size_phi * 0.5;
4998  vector<bool> use_periodic_delta_phi(_n_tiles_phi, false);
4999  if (_n_tiles_phi <= 5) {
5000  fill(use_periodic_delta_phi.begin(), use_periodic_delta_phi.end(), true);
5001  } else {
5002  use_periodic_delta_phi[0] = true;
5003  use_periodic_delta_phi[1] = true;
5004  use_periodic_delta_phi[_n_tiles_phi-2] = true;
5005  use_periodic_delta_phi[_n_tiles_phi-1] = true;
5006  }
5007  _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi);
5008  for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) {
5009  for (int iphi = 0; iphi < _n_tiles_phi; iphi++) {
5010  Tile25 * tile = & _tiles[_tile_index(ieta,iphi)];
5011  tile->head = NULL; // first element of tiles points to itself
5012  tile->begin_tiles[0] = tile;
5013  Tile25 ** pptile = & (tile->begin_tiles[0]);
5014  pptile++;
5015  tile->surrounding_tiles = pptile;
5016  if (ieta > _tiles_ieta_min) {
5017  // with the itile subroutine, we can safely run tiles from
5018  // idphi=-1 to idphi=+1, because it takes care of
5019  // negative and positive boundaries
5020  for (int idphi = -2; idphi <=+2; idphi++) {
5021  *pptile = & _tiles[_tile_index(ieta-1,iphi+idphi)];
5022  pptile++;
5023  }
5024  }
5025  if (ieta > _tiles_ieta_min + 1) {
5026  // with the itile subroutine, we can safely run tiles from
5027  // idphi=-1 to idphi=+1, because it takes care of
5028  // negative and positive boundaries
5029  for (int idphi = -2; idphi <= +2; idphi++) {
5030  *pptile = & _tiles[_tile_index(ieta-2,iphi+idphi)];
5031  pptile++;
5032  }
5033  }
5034  *pptile = & _tiles[_tile_index(ieta,iphi-1)];
5035  pptile++;
5036  *pptile = & _tiles[_tile_index(ieta,iphi-2)];
5037  pptile++;
5038  tile->RH_tiles = pptile;
5039  *pptile = & _tiles[_tile_index(ieta,iphi+1)];
5040  pptile++;
5041  *pptile = & _tiles[_tile_index(ieta,iphi+2)];
5042  pptile++;
5043  if (ieta < _tiles_ieta_max) {
5044  for (int idphi = -2; idphi <= +2; idphi++) {
5045  *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)];
5046  pptile++;
5047  }
5048  }
5049  if (ieta < _tiles_ieta_max - 1) {
5050  for (int idphi = -2; idphi <= +2; idphi++) {
5051  *pptile = & _tiles[_tile_index(ieta+2,iphi+idphi)];
5052  pptile++;
5053  }
5054  }
5055  tile->end_tiles = pptile;
5056  tile->tagged = false;
5057  tile->use_periodic_delta_phi = use_periodic_delta_phi[iphi];
5058  tile->max_NN_dist = 0;
5059  tile->eta_centre = (ieta-_tiles_ieta_min+0.5)*_tile_size_eta + _tiles_eta_min;
5060  tile->phi_centre = (iphi+0.5)*_tile_size_phi;
5061  }
5062  }
5063 }
5064 int LazyTiling25::_tile_index(const double eta, const double phi) const {
5065  int ieta, iphi;
5066  if (eta <= _tiles_eta_min) {ieta = 0;}
5067  else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;}
5068  else {
5069  ieta = int(((eta - _tiles_eta_min) / _tile_size_eta));
5070  if (ieta > _tiles_ieta_max-_tiles_ieta_min) {
5071  ieta = _tiles_ieta_max-_tiles_ieta_min;}
5072  }
5073  iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi;
5074  return (iphi + ieta * _n_tiles_phi);
5075 }
5076 inline void LazyTiling25::_tj_set_jetinfo( TiledJet * const jet,
5077  const int _jets_index) {
5078  _bj_set_jetinfo<>(jet, _jets_index);
5079  jet->tile_index = _tile_index(jet->eta, jet->phi);
5080  Tile25 * tile = &_tiles[jet->tile_index];
5081  jet->previous = NULL;
5082  jet->next = tile->head;
5083  if (jet->next != NULL) {jet->next->previous = jet;}
5084  tile->head = jet;
5085 }
5086 void LazyTiling25::_bj_remove_from_tiles(TiledJet * const jet) {
5087  Tile25 * tile = & _tiles[jet->tile_index];
5088  if (jet->previous == NULL) {
5089  tile->head = jet->next;
5090  } else {
5091  jet->previous->next = jet->next;
5092  }
5093  if (jet->next != NULL) {
5094  jet->next->previous = jet->previous;
5095  }
5096 }
5097 void LazyTiling25::_print_tiles(TiledJet * briefjets ) const {
5098  for (vector<Tile25>::const_iterator tile = _tiles.begin();
5099  tile < _tiles.end(); tile++) {
5100  cout << "Tile " << tile - _tiles.begin()
5101  << " at " << setw(10) << tile->eta_centre << "," << setw(10) << tile->phi_centre
5102  << " = ";
5103  vector<int> list;
5104  for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
5105  list.push_back(jetI-briefjets);
5106  }
5107  sort(list.begin(),list.end());
5108  for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];}
5109  cout <<"\n";
5110  }
5111 }
5112 void LazyTiling25::_add_neighbours_to_tile_union(const int tile_index,
5113  vector<int> & tile_union, int & n_near_tiles) const {
5114  for (Tile25 * const * near_tile = _tiles[tile_index].begin_tiles;
5115  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5116  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5117  n_near_tiles++;
5118  }
5119 }
5120 inline void LazyTiling25::_add_untagged_neighbours_to_tile_union(
5121  const int tile_index,
5122  vector<int> & tile_union, int & n_near_tiles) {
5123  for (Tile25 ** near_tile = _tiles[tile_index].begin_tiles;
5124  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5125  if (! (*near_tile)->tagged) {
5126  (*near_tile)->tagged = true;
5127  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5128  n_near_tiles++;
5129  }
5130  }
5131 }
5132 inline void LazyTiling25::_add_untagged_neighbours_to_tile_union_using_max_info(
5133  const TiledJet * jet,
5134  vector<int> & tile_union, int & n_near_tiles) {
5135  Tile25 & tile = _tiles[jet->tile_index];
5136  for (Tile25 ** near_tile = tile.begin_tiles; near_tile != tile.end_tiles; near_tile++){
5137  if ((*near_tile)->tagged) continue;
5138  double dist = _distance_to_tile(jet, *near_tile) - tile_edge_security_margin;
5139  if (dist > (*near_tile)->max_NN_dist) continue;
5140  (*near_tile)->tagged = true;
5141  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5142  n_near_tiles++;
5143  }
5144 }
5145 inline double LazyTiling25::_distance_to_tile(const TiledJet * bj, const Tile25 * tile)
5146 #ifdef INSTRUMENT2
5147  {
5148  _ncall_dtt++; // GPS tmp
5149 #else
5150  const {
5151 #endif // INSTRUMENT2
5152  double deta;
5153  if (_tiles[bj->tile_index].eta_centre == tile->eta_centre) deta = 0;
5154  else deta = std::abs(bj->eta - tile->eta_centre) - _tile_half_size_eta;
5155  double dphi = std::abs(bj->phi - tile->phi_centre);
5156  if (dphi > pi) dphi = twopi-dphi;
5157  dphi -= _tile_half_size_phi;
5158  if (dphi < 0) dphi = 0;
5159  return dphi*dphi + deta*deta;
5160 }
5161 inline void LazyTiling25::_update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, vector<TiledJet *> & jets_for_minheap) {
5162  double dist = _bj_dist(jetI,jetX);
5163  if (dist < jetI->NN_dist) {
5164  if (jetI != jetX) {
5165  jetI->NN_dist = dist;
5166  jetI->NN = jetX;
5167  if (!jetI->minheap_update_needed()) {
5168  jetI->label_minheap_update_needed();
5169  jets_for_minheap.push_back(jetI);
5170  }
5171  }
5172  }
5173  if (dist < jetX->NN_dist) {
5174  if (jetI != jetX) {
5175  jetX->NN_dist = dist;
5176  jetX->NN = jetI;}
5177  }
5178 }
5179 inline void LazyTiling25::_set_NN(TiledJet * jetI,
5180  vector<TiledJet *> & jets_for_minheap) {
5181  jetI->NN_dist = _R2;
5182  jetI->NN = NULL;
5183  if (!jetI->minheap_update_needed()) {
5184  jetI->label_minheap_update_needed();
5185  jets_for_minheap.push_back(jetI);}
5186  Tile25 * tile_ptr = &_tiles[jetI->tile_index];
5187  for (Tile25 ** near_tile = tile_ptr->begin_tiles;
5188  near_tile != tile_ptr->end_tiles; near_tile++) {
5189  if (jetI->NN_dist < _distance_to_tile(jetI, *near_tile)) continue;
5190  for (TiledJet * jetJ = (*near_tile)->head;
5191  jetJ != NULL; jetJ = jetJ->next) {
5192  double dist = _bj_dist(jetI,jetJ);
5193  if (dist < jetI->NN_dist && jetJ != jetI) {
5194  jetI->NN_dist = dist; jetI->NN = jetJ;
5195  }
5196  }
5197  }
5198 }
5199 void LazyTiling25::run() {
5200  int n = _jets.size();
5201  if (n == 0) return;
5202  TiledJet * briefjets = new TiledJet[n];
5203  TiledJet * jetA = briefjets, * jetB;
5204  TiledJet oldB = briefjets[0];
5205  vector<int> tile_union(3*25);
5206  for (int i = 0; i< n; i++) {
5207  _tj_set_jetinfo(jetA, i);
5208  jetA++; // move on to next entry of briefjets
5209  }
5210  TiledJet * head = briefjets; // a nicer way of naming start
5211  vector<Tile25>::iterator tile;
5212  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5213  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5214  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
5215  double dist = _bj_dist_not_periodic(jetA,jetB);
5216  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5217  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5218  }
5219  }
5220  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5221  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
5222  }
5223  }
5224  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5225  if (tile->use_periodic_delta_phi) {
5226  for (Tile25 ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
5227  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5228  double dist_to_tile = _distance_to_tile(jetA, *RTile);
5229  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
5230  bool relevant_for_RTile = dist_to_tile <= (*RTile)->max_NN_dist;
5231  if (relevant_for_jetA || relevant_for_RTile) {
5232  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
5233  double dist = _bj_dist(jetA,jetB);
5234  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5235  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5236  }
5237  }
5238  }
5239  }
5240  } else {
5241  for (Tile25 ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
5242  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5243  double dist_to_tile = _distance_to_tile(jetA, *RTile);
5244  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
5245  bool relevant_for_RTile = dist_to_tile <= (*RTile)->max_NN_dist;
5246  if (relevant_for_jetA || relevant_for_RTile) {
5247  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
5248  double dist = _bj_dist_not_periodic(jetA,jetB);
5249  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5250  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5251  }
5252  }
5253  }
5254  }
5255  }
5256  }
5257  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5258  tile->max_NN_dist = 0;
5259  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5260  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
5261  }
5262  }
5263 #ifdef INSTRUMENT2
5264  cout << "intermediate ncall, dtt = " << _ncall << " " << _ncall_dtt << endl; // GPS tmp
5265 #endif // INSTRUMENT2
5266  vector<double> diJs(n);
5267  for (int i = 0; i < n; i++) {
5268  diJs[i] = _bj_diJ(&briefjets[i]);
5269  briefjets[i].label_minheap_update_done();
5270  }
5271  MinHeap minheap(diJs);
5272  vector<TiledJet *> jets_for_minheap;
5273  jets_for_minheap.reserve(n);
5274  int history_location = n-1;
5275  while (n > 0) {
5276  double diJ_min = minheap.minval() *_invR2;
5277  jetA = head + minheap.minloc();
5278  history_location++;
5279  jetB = jetA->NN;
5280  if (jetB != NULL) {
5281  if (jetA < jetB) {std::swap(jetA,jetB);}
5282  int nn; // new jet index
5283  _cs.plugin_record_ij_recombination(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
5284  _bj_remove_from_tiles(jetA);
5285  oldB = * jetB; // take a copy because we will need it...
5286  _bj_remove_from_tiles(jetB);
5287  _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
5288  } else {
5289  _cs.plugin_record_iB_recombination(jetA->_jets_index, diJ_min);
5290  _bj_remove_from_tiles(jetA);
5291  }
5292  minheap.remove(jetA-head);
5293  int n_near_tiles = 0;
5294  if (jetB != NULL) {
5295  Tile25 & jetB_tile = _tiles[jetB->tile_index];
5296  for (Tile25 ** near_tile = jetB_tile.begin_tiles;
5297  near_tile != jetB_tile.end_tiles; near_tile++) {
5298  double dist_to_tile = _distance_to_tile(jetB, *near_tile);
5299  bool relevant_for_jetB = dist_to_tile <= jetB->NN_dist;
5300  bool relevant_for_near_tile = dist_to_tile <= (*near_tile)->max_NN_dist;
5301  bool relevant = relevant_for_jetB || relevant_for_near_tile;
5302  if (! relevant) continue;
5303  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5304  (*near_tile)->tagged = true;
5305  n_near_tiles++;
5306  for (TiledJet * jetI = (*near_tile)->head; jetI != NULL; jetI = jetI->next) {
5307  if (jetI->NN == jetA || jetI->NN == jetB) _set_NN(jetI, jets_for_minheap);
5308  _update_jetX_jetI_NN(jetB, jetI, jets_for_minheap);
5309  }
5310  }
5311  }
5312  int n_done_tiles = n_near_tiles;
5313  _add_untagged_neighbours_to_tile_union_using_max_info(jetA,
5314  tile_union, n_near_tiles);
5315  if (jetB != NULL) {
5316  _add_untagged_neighbours_to_tile_union_using_max_info(&oldB,
5317  tile_union,n_near_tiles);
5318  jetB->label_minheap_update_needed();
5319  jets_for_minheap.push_back(jetB);
5320  }
5321  for (int itile = 0; itile < n_done_tiles; itile++) {
5322  _tiles[tile_union[itile]].tagged = false;
5323  }
5324  for (int itile = n_done_tiles; itile < n_near_tiles; itile++) {
5325  Tile25 * tile_ptr = &_tiles[tile_union[itile]];
5326  tile_ptr->tagged = false;
5327  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
5328  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
5329  _set_NN(jetI, jets_for_minheap);
5330  }
5331  }
5332  }
5333  while (jets_for_minheap.size() > 0) {
5334  TiledJet * jetI = jets_for_minheap.back();
5335  jets_for_minheap.pop_back();
5336  minheap.update(jetI-head, _bj_diJ(jetI));
5337  jetI->label_minheap_update_done();
5338  Tile25 & tile_I = _tiles[jetI->tile_index];
5339  if (tile_I.max_NN_dist < jetI->NN_dist) tile_I.max_NN_dist = jetI->NN_dist;
5340  }
5341  n--;
5342  }
5343  delete[] briefjets;
5344 #ifdef INSTRUMENT2
5345  cout << "ncall, dtt = " << _ncall << " " << _ncall_dtt << endl; // GPS tmp
5346 #endif // INSTRUMENT2
5347 }
5348 FJCORE_END_NAMESPACE
5349 #include <iomanip>
5350 #include <limits>
5351 #include <cmath>
5352 using namespace std;
5353 #define _FJCORE_TILING2_USE_TILING_ANALYSIS_
5354 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
5355 LazyTiling9::LazyTiling9(ClusterSequence & cs) :
5356  _cs(cs), _jets(cs.jets())
5357 {
5358 #ifdef INSTRUMENT2
5359  _ncall = 0; // gps tmp
5360  _ncall_dtt = 0; // gps tmp
5361 #endif // INSTRUMENT2
5362  _Rparam = cs.jet_def().R();
5363  _R2 = _Rparam * _Rparam;
5364  _invR2 = 1.0 / _R2;
5365  _initialise_tiles();
5366 }
5367 void LazyTiling9::_initialise_tiles() {
5368  double default_size = max(0.1,_Rparam);
5369  _tile_size_eta = default_size;
5370  _n_tiles_phi = max(3,int(floor(twopi/default_size)));
5371  _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi
5372 #ifdef _FJCORE_TILING2_USE_TILING_ANALYSIS_
5373  TilingExtent tiling_analysis(_cs);
5374  _tiles_eta_min = tiling_analysis.minrap();
5375  _tiles_eta_max = tiling_analysis.maxrap();
5376 #else
5377  _tiles_eta_min = 0.0;
5378  _tiles_eta_max = 0.0;
5379  const double maxrap = 7.0;
5380  for(unsigned int i = 0; i < _jets.size(); i++) {
5381  double eta = _jets[i].rap();
5382  if (abs(eta) < maxrap) {
5383  if (eta < _tiles_eta_min) {_tiles_eta_min = eta;}
5384  if (eta > _tiles_eta_max) {_tiles_eta_max = eta;}
5385  }
5386  }
5387 #endif
5388 # define FJCORE_LAZY9_MIN2TILESY
5389 #ifdef FJCORE_LAZY9_MIN2TILESY
5390  if (_tiles_eta_max - _tiles_eta_min < 2*_tile_size_eta) {
5391  _tile_size_eta = (_tiles_eta_max - _tiles_eta_min)/2;
5392  _tiles_ieta_min = 0;
5393  _tiles_ieta_max = 1;
5394  _tiles_eta_max -= _tile_size_eta;
5395  } else {
5396 #endif //FASTJET_LAZY9_MIN2TILESY
5397  _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta));
5398  _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta));
5399  _tiles_eta_min = _tiles_ieta_min * _tile_size_eta;
5400  _tiles_eta_max = _tiles_ieta_max * _tile_size_eta;
5401 #ifdef FJCORE_LAZY9_MIN2TILESY
5402  }
5403 #endif
5404  _tile_half_size_eta = _tile_size_eta * 0.5;
5405  _tile_half_size_phi = _tile_size_phi * 0.5;
5406  vector<bool> use_periodic_delta_phi(_n_tiles_phi, false);
5407  if (_n_tiles_phi <= 3) {
5408  fill(use_periodic_delta_phi.begin(), use_periodic_delta_phi.end(), true);
5409  } else {
5410  use_periodic_delta_phi[0] = true;
5411  use_periodic_delta_phi[_n_tiles_phi-1] = true;
5412  }
5413  _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi);
5414  for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) {
5415  for (int iphi = 0; iphi < _n_tiles_phi; iphi++) {
5416  Tile2 * tile = & _tiles[_tile_index(ieta,iphi)];
5417  tile->head = NULL; // first element of tiles points to itself
5418  tile->begin_tiles[0] = tile;
5419  Tile2 ** pptile = & (tile->begin_tiles[0]);
5420  pptile++;
5421  tile->surrounding_tiles = pptile;
5422  if (ieta > _tiles_ieta_min) {
5423  // with the itile subroutine, we can safely run tiles from
5424  // idphi=-1 to idphi=+1, because it takes care of
5425  // negative and positive boundaries
5426  for (int idphi = -1; idphi <=+1; idphi++) {
5427  *pptile = & _tiles[_tile_index(ieta-1,iphi+idphi)];
5428  pptile++;
5429  }
5430  }
5431  *pptile = & _tiles[_tile_index(ieta,iphi-1)];
5432  pptile++;
5433  tile->RH_tiles = pptile;
5434  *pptile = & _tiles[_tile_index(ieta,iphi+1)];
5435  pptile++;
5436  if (ieta < _tiles_ieta_max) {
5437  for (int idphi = -1; idphi <= +1; idphi++) {
5438  *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)];
5439  pptile++;
5440  }
5441  }
5442  tile->end_tiles = pptile;
5443  tile->tagged = false;
5444  tile->use_periodic_delta_phi = use_periodic_delta_phi[iphi];
5445  tile->max_NN_dist = 0;
5446  tile->eta_centre = (ieta-_tiles_ieta_min+0.5)*_tile_size_eta + _tiles_eta_min;
5447  tile->phi_centre = (iphi+0.5)*_tile_size_phi;
5448  }
5449  }
5450 }
5451 int LazyTiling9::_tile_index(const double eta, const double phi) const {
5452  int ieta, iphi;
5453  if (eta <= _tiles_eta_min) {ieta = 0;}
5454  else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;}
5455  else {
5456  ieta = int(((eta - _tiles_eta_min) / _tile_size_eta));
5457  if (ieta > _tiles_ieta_max-_tiles_ieta_min) {
5458  ieta = _tiles_ieta_max-_tiles_ieta_min;}
5459  }
5460  iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi;
5461  return (iphi + ieta * _n_tiles_phi);
5462 }
5463 inline void LazyTiling9::_tj_set_jetinfo( TiledJet * const jet,
5464  const int _jets_index) {
5465  _bj_set_jetinfo<>(jet, _jets_index);
5466  jet->tile_index = _tile_index(jet->eta, jet->phi);
5467  Tile2 * tile = &_tiles[jet->tile_index];
5468  jet->previous = NULL;
5469  jet->next = tile->head;
5470  if (jet->next != NULL) {jet->next->previous = jet;}
5471  tile->head = jet;
5472 }
5473 void LazyTiling9::_bj_remove_from_tiles(TiledJet * const jet) {
5474  Tile2 * tile = & _tiles[jet->tile_index];
5475  if (jet->previous == NULL) {
5476  tile->head = jet->next;
5477  } else {
5478  jet->previous->next = jet->next;
5479  }
5480  if (jet->next != NULL) {
5481  jet->next->previous = jet->previous;
5482  }
5483 }
5484 void LazyTiling9::_print_tiles(TiledJet * briefjets ) const {
5485  for (vector<Tile2>::const_iterator tile = _tiles.begin();
5486  tile < _tiles.end(); tile++) {
5487  cout << "Tile " << tile - _tiles.begin()<<" = ";
5488  vector<int> list;
5489  for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
5490  list.push_back(jetI-briefjets);
5491  }
5492  sort(list.begin(),list.end());
5493  for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];}
5494  cout <<"\n";
5495  }
5496 }
5497 void LazyTiling9::_add_neighbours_to_tile_union(const int tile_index,
5498  vector<int> & tile_union, int & n_near_tiles) const {
5499  for (Tile2 * const * near_tile = _tiles[tile_index].begin_tiles;
5500  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5501  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5502  n_near_tiles++;
5503  }
5504 }
5505 inline void LazyTiling9::_add_untagged_neighbours_to_tile_union(
5506  const int tile_index,
5507  vector<int> & tile_union, int & n_near_tiles) {
5508  for (Tile2 ** near_tile = _tiles[tile_index].begin_tiles;
5509  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5510  if (! (*near_tile)->tagged) {
5511  (*near_tile)->tagged = true;
5512  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5513  n_near_tiles++;
5514  }
5515  }
5516 }
5517 inline void LazyTiling9::_add_untagged_neighbours_to_tile_union_using_max_info(
5518  const TiledJet * jet,
5519  vector<int> & tile_union, int & n_near_tiles) {
5520  Tile2 & tile = _tiles[jet->tile_index];
5521  for (Tile2 ** near_tile = tile.begin_tiles; near_tile != tile.end_tiles; near_tile++){
5522  if ((*near_tile)->tagged) continue;
5523  double dist = _distance_to_tile(jet, *near_tile) - tile_edge_security_margin;
5524  if (dist > (*near_tile)->max_NN_dist) continue;
5525  (*near_tile)->tagged = true;
5526  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5527  n_near_tiles++;
5528  }
5529 }
5530 inline double LazyTiling9::_distance_to_tile(const TiledJet * bj, const Tile2 * tile)
5531 #ifdef INSTRUMENT2
5532  {
5533  _ncall_dtt++; // GPS tmp
5534 #else
5535  const {
5536 #endif // INSTRUMENT2
5537  double deta;
5538  if (_tiles[bj->tile_index].eta_centre == tile->eta_centre) deta = 0;
5539  else deta = std::abs(bj->eta - tile->eta_centre) - _tile_half_size_eta;
5540  double dphi = std::abs(bj->phi - tile->phi_centre);
5541  if (dphi > pi) dphi = twopi-dphi;
5542  dphi -= _tile_half_size_phi;
5543  if (dphi < 0) dphi = 0;
5544  return dphi*dphi + deta*deta;
5545 }
5546 inline void LazyTiling9::_update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, vector<TiledJet *> & jets_for_minheap) {
5547  double dist = _bj_dist(jetI,jetX);
5548  if (dist < jetI->NN_dist) {
5549  if (jetI != jetX) {
5550  jetI->NN_dist = dist;
5551  jetI->NN = jetX;
5552  if (!jetI->minheap_update_needed()) {
5553  jetI->label_minheap_update_needed();
5554  jets_for_minheap.push_back(jetI);
5555  }
5556  }
5557  }
5558  if (dist < jetX->NN_dist) {
5559  if (jetI != jetX) {
5560  jetX->NN_dist = dist;
5561  jetX->NN = jetI;}
5562  }
5563 }
5564 inline void LazyTiling9::_set_NN(TiledJet * jetI,
5565  vector<TiledJet *> & jets_for_minheap) {
5566  jetI->NN_dist = _R2;
5567  jetI->NN = NULL;
5568  if (!jetI->minheap_update_needed()) {
5569  jetI->label_minheap_update_needed();
5570  jets_for_minheap.push_back(jetI);}
5571  Tile2 * tile_ptr = &_tiles[jetI->tile_index];
5572  for (Tile2 ** near_tile = tile_ptr->begin_tiles;
5573  near_tile != tile_ptr->end_tiles; near_tile++) {
5574  if (jetI->NN_dist < _distance_to_tile(jetI, *near_tile)) continue;
5575  for (TiledJet * jetJ = (*near_tile)->head;
5576  jetJ != NULL; jetJ = jetJ->next) {
5577  double dist = _bj_dist(jetI,jetJ);
5578  if (dist < jetI->NN_dist && jetJ != jetI) {
5579  jetI->NN_dist = dist; jetI->NN = jetJ;
5580  }
5581  }
5582  }
5583 }
5584 void LazyTiling9::run() {
5585  int n = _jets.size();
5586  if (n == 0) return;
5587  TiledJet * briefjets = new TiledJet[n];
5588  TiledJet * jetA = briefjets, * jetB;
5589  TiledJet oldB = briefjets[0];
5590  vector<int> tile_union(3*n_tile_neighbours);
5591  for (int i = 0; i< n; i++) {
5592  _tj_set_jetinfo(jetA, i);
5593  jetA++; // move on to next entry of briefjets
5594  }
5595  TiledJet * head = briefjets; // a nicer way of naming start
5596  vector<Tile2>::iterator tile;
5597  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5598  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5599  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
5600  double dist = _bj_dist_not_periodic(jetA,jetB);
5601  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5602  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5603  }
5604  }
5605  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5606  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
5607  }
5608  }
5609  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5610  if (tile->use_periodic_delta_phi) {
5611  for (Tile2 ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
5612  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5613  double dist_to_tile = _distance_to_tile(jetA, *RTile);
5614  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
5615  bool relevant_for_RTile = dist_to_tile <= (*RTile)->max_NN_dist;
5616  if (relevant_for_jetA || relevant_for_RTile) {
5617  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
5618  double dist = _bj_dist(jetA,jetB);
5619  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5620  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5621  }
5622  }
5623  }
5624  }
5625  } else {
5626  for (Tile2 ** RTile = tile->RH_tiles; RTile != tile->end_tiles; RTile++) {
5627  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5628  double dist_to_tile = _distance_to_tile(jetA, *RTile);
5629  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
5630  bool relevant_for_RTile = dist_to_tile <= (*RTile)->max_NN_dist;
5631  if (relevant_for_jetA || relevant_for_RTile) {
5632  for (jetB = (*RTile)->head; jetB != NULL; jetB = jetB->next) {
5633  double dist = _bj_dist_not_periodic(jetA,jetB);
5634  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5635  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5636  }
5637  }
5638  }
5639  }
5640  }
5641  }
5642  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5643  tile->max_NN_dist = 0;
5644  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5645  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
5646  }
5647  }
5648 #ifdef INSTRUMENT2
5649  cout << "intermediate ncall, dtt = " << _ncall << " " << _ncall_dtt << endl; // GPS tmp
5650 #endif // INSTRUMENT2
5651  vector<double> diJs(n);
5652  for (int i = 0; i < n; i++) {
5653  diJs[i] = _bj_diJ(&briefjets[i]);
5654  briefjets[i].label_minheap_update_done();
5655  }
5656  MinHeap minheap(diJs);
5657  vector<TiledJet *> jets_for_minheap;
5658  jets_for_minheap.reserve(n);
5659  int history_location = n-1;
5660  while (n > 0) {
5661  double diJ_min = minheap.minval() *_invR2;
5662  jetA = head + minheap.minloc();
5663  history_location++;
5664  jetB = jetA->NN;
5665  if (jetB != NULL) {
5666  if (jetA < jetB) {std::swap(jetA,jetB);}
5667  int nn; // new jet index
5668  _cs.plugin_record_ij_recombination(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
5669  _bj_remove_from_tiles(jetA);
5670  oldB = * jetB; // take a copy because we will need it...
5671  _bj_remove_from_tiles(jetB);
5672  _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
5673  } else {
5674  _cs.plugin_record_iB_recombination(jetA->_jets_index, diJ_min);
5675  _bj_remove_from_tiles(jetA);
5676  }
5677  minheap.remove(jetA-head);
5678  int n_near_tiles = 0;
5679  if (jetB != NULL) {
5680  Tile2 & jetB_tile = _tiles[jetB->tile_index];
5681  for (Tile2 ** near_tile = jetB_tile.begin_tiles;
5682  near_tile != jetB_tile.end_tiles; near_tile++) {
5683  double dist_to_tile = _distance_to_tile(jetB, *near_tile);
5684  bool relevant_for_jetB = dist_to_tile <= jetB->NN_dist;
5685  bool relevant_for_near_tile = dist_to_tile <= (*near_tile)->max_NN_dist;
5686  bool relevant = relevant_for_jetB || relevant_for_near_tile;
5687  if (! relevant) continue;
5688  tile_union[n_near_tiles] = *near_tile - & _tiles[0];
5689  (*near_tile)->tagged = true;
5690  n_near_tiles++;
5691  for (TiledJet * jetI = (*near_tile)->head; jetI != NULL; jetI = jetI->next) {
5692  if (jetI->NN == jetA || jetI->NN == jetB) _set_NN(jetI, jets_for_minheap);
5693  _update_jetX_jetI_NN(jetB, jetI, jets_for_minheap);
5694  }
5695  }
5696  }
5697  int n_done_tiles = n_near_tiles;
5698  _add_untagged_neighbours_to_tile_union_using_max_info(jetA,
5699  tile_union, n_near_tiles);
5700  if (jetB != NULL) {
5701  _add_untagged_neighbours_to_tile_union_using_max_info(&oldB,
5702  tile_union,n_near_tiles);
5703  jetB->label_minheap_update_needed();
5704  jets_for_minheap.push_back(jetB);
5705  }
5706  for (int itile = 0; itile < n_done_tiles; itile++) {
5707  _tiles[tile_union[itile]].tagged = false;
5708  }
5709  for (int itile = n_done_tiles; itile < n_near_tiles; itile++) {
5710  Tile2 * tile_ptr = &_tiles[tile_union[itile]];
5711  tile_ptr->tagged = false;
5712  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
5713  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
5714  _set_NN(jetI, jets_for_minheap);
5715  }
5716  }
5717  }
5718  while (jets_for_minheap.size() > 0) {
5719  TiledJet * jetI = jets_for_minheap.back();
5720  jets_for_minheap.pop_back();
5721  minheap.update(jetI-head, _bj_diJ(jetI));
5722  jetI->label_minheap_update_done();
5723  Tile2 & tile_I = _tiles[jetI->tile_index];
5724  if (tile_I.max_NN_dist < jetI->NN_dist) tile_I.max_NN_dist = jetI->NN_dist;
5725  }
5726  n--;
5727  }
5728  delete[] briefjets;
5729 #ifdef INSTRUMENT2
5730  cout << "ncall, dtt = " << _ncall << " " << _ncall_dtt << endl; // GPS tmp
5731 #endif // INSTRUMENT2
5732 }
5733 FJCORE_END_NAMESPACE
5734 #include <iomanip>
5735 using namespace std;
5736 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
5737 LazyTiling9Alt::LazyTiling9Alt(ClusterSequence & cs) :
5738  _cs(cs), _jets(cs.jets())
5739 {
5740  _Rparam = cs.jet_def().R();
5741  _R2 = _Rparam * _Rparam;
5742  _invR2 = 1.0 / _R2;
5743  _initialise_tiles();
5744 }
5745 void LazyTiling9Alt::_initialise_tiles() {
5746  double default_size = max(0.1,_Rparam);
5747  _tile_size_eta = default_size;
5748  _n_tiles_phi = max(3,int(floor(twopi/default_size)));
5749  _tile_size_phi = twopi / _n_tiles_phi; // >= _Rparam and fits in 2pi
5750  _tiles_eta_min = 0.0;
5751  _tiles_eta_max = 0.0;
5752  const double maxrap = 7.0;
5753  for(unsigned int i = 0; i < _jets.size(); i++) {
5754  double eta = _jets[i].rap();
5755  if (abs(eta) < maxrap) {
5756  if (eta < _tiles_eta_min) {_tiles_eta_min = eta;}
5757  if (eta > _tiles_eta_max) {_tiles_eta_max = eta;}
5758  }
5759  }
5760  _tiles_ieta_min = int(floor(_tiles_eta_min/_tile_size_eta));
5761  _tiles_ieta_max = int(floor( _tiles_eta_max/_tile_size_eta));
5762  _tiles_eta_min = _tiles_ieta_min * _tile_size_eta;
5763  _tiles_eta_max = _tiles_ieta_max * _tile_size_eta;
5764  _tile_half_size_eta = _tile_size_eta * 0.5;
5765  _tile_half_size_phi = _tile_size_phi * 0.5;
5766  vector<bool> use_periodic_delta_phi(_n_tiles_phi, false);
5767  if (_n_tiles_phi <= 3) {
5768  fill(use_periodic_delta_phi.begin(), use_periodic_delta_phi.end(), true);
5769  } else {
5770  use_periodic_delta_phi[0] = true;
5771  use_periodic_delta_phi[_n_tiles_phi-1] = true;
5772  }
5773  _tiles.resize((_tiles_ieta_max-_tiles_ieta_min+1)*_n_tiles_phi);
5774  for (int ieta = _tiles_ieta_min; ieta <= _tiles_ieta_max; ieta++) {
5775  for (int iphi = 0; iphi < _n_tiles_phi; iphi++) {
5776  Tile * tile = & _tiles[_tile_index(ieta,iphi)];
5777  tile->head = NULL; // first element of tiles points to itself
5778  tile->begin_tiles[0] = Tile::TileFnPair(tile,&Tile::distance_to_centre);
5779  Tile::TileFnPair * pptile = & (tile->begin_tiles[0]);
5780  pptile++;
5781  tile->surrounding_tiles = pptile;
5782  if (ieta > _tiles_ieta_min) {
5783  // with the itile subroutine, we can safely run tiles from
5784  // idphi=-1 to idphi=+1, because it takes care of
5785  // negative and positive boundaries
5786  //for (int idphi = -1; idphi <=+1; idphi++) {
5787  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta-1,iphi-1)],
5788  &Tile::distance_to_left_bottom);
5789  pptile++;
5790  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta-1,iphi)],
5791  &Tile::distance_to_left);
5792  pptile++;
5793  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta-1,iphi+1)],
5794  &Tile::distance_to_left_top);
5795  pptile++;
5796  }
5797  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta,iphi-1)],
5798  &Tile::distance_to_bottom);
5799  pptile++;
5800  tile->RH_tiles = pptile;
5801  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta,iphi+1)],
5802  &Tile::distance_to_top);
5803  pptile++;
5804  if (ieta < _tiles_ieta_max) {
5805  //for (int idphi = -1; idphi <= +1; idphi++) {
5806  // *pptile = & _tiles[_tile_index(ieta+1,iphi+idphi)];
5807  // pptile++;
5808  //}
5809  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta+1,iphi-1)],
5810  &Tile::distance_to_right_bottom);
5811  pptile++;
5812  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta+1,iphi)],
5813  &Tile::distance_to_right);
5814  pptile++;
5815  *pptile = Tile::TileFnPair(& _tiles[_tile_index(ieta+1,iphi+1)],
5816  &Tile::distance_to_right_top);
5817  pptile++;
5818  }
5819  tile->end_tiles = pptile;
5820  tile->tagged = false;
5821  tile->use_periodic_delta_phi = use_periodic_delta_phi[iphi];
5822  tile->max_NN_dist = 0;
5823  tile->eta_min = ieta*_tile_size_eta;
5824  tile->eta_max = (ieta+1)*_tile_size_eta;
5825  tile->phi_min = iphi*_tile_size_phi;
5826  tile->phi_max = (iphi+1)*_tile_size_phi;
5827  }
5828  }
5829 }
5830 int LazyTiling9Alt::_tile_index(const double eta, const double phi) const {
5831  int ieta, iphi;
5832  if (eta <= _tiles_eta_min) {ieta = 0;}
5833  else if (eta >= _tiles_eta_max) {ieta = _tiles_ieta_max-_tiles_ieta_min;}
5834  else {
5835  ieta = int(((eta - _tiles_eta_min) / _tile_size_eta));
5836  if (ieta > _tiles_ieta_max-_tiles_ieta_min) {
5837  ieta = _tiles_ieta_max-_tiles_ieta_min;}
5838  }
5839  iphi = int((phi+twopi)/_tile_size_phi) % _n_tiles_phi;
5840  return (iphi + ieta * _n_tiles_phi);
5841 }
5842 inline void LazyTiling9Alt::_tj_set_jetinfo( TiledJet * const jet,
5843  const int _jets_index) {
5844  _bj_set_jetinfo<>(jet, _jets_index);
5845  jet->tile_index = _tile_index(jet->eta, jet->phi);
5846  Tile * tile = &_tiles[jet->tile_index];
5847  jet->previous = NULL;
5848  jet->next = tile->head;
5849  if (jet->next != NULL) {jet->next->previous = jet;}
5850  tile->head = jet;
5851 }
5852 void LazyTiling9Alt::_bj_remove_from_tiles(TiledJet * const jet) {
5853  Tile * tile = & _tiles[jet->tile_index];
5854  if (jet->previous == NULL) {
5855  tile->head = jet->next;
5856  } else {
5857  jet->previous->next = jet->next;
5858  }
5859  if (jet->next != NULL) {
5860  jet->next->previous = jet->previous;
5861  }
5862 }
5863 void LazyTiling9Alt::_print_tiles(TiledJet * briefjets ) const {
5864  for (vector<Tile>::const_iterator tile = _tiles.begin();
5865  tile < _tiles.end(); tile++) {
5866  cout << "Tile " << tile - _tiles.begin()<<" = ";
5867  vector<int> list;
5868  for (TiledJet * jetI = tile->head; jetI != NULL; jetI = jetI->next) {
5869  list.push_back(jetI-briefjets);
5870  }
5871  sort(list.begin(),list.end());
5872  for (unsigned int i = 0; i < list.size(); i++) {cout <<" "<<list[i];}
5873  cout <<"\n";
5874  }
5875 }
5876 void LazyTiling9Alt::_add_neighbours_to_tile_union(const int tile_index,
5877  vector<int> & tile_union, int & n_near_tiles) const {
5878  for (Tile::TileFnPair const * near_tile = _tiles[tile_index].begin_tiles;
5879  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5880  tile_union[n_near_tiles] = near_tile->first - & _tiles[0];
5881  n_near_tiles++;
5882  }
5883 }
5884 inline void LazyTiling9Alt::_add_untagged_neighbours_to_tile_union(
5885  const int tile_index,
5886  vector<int> & tile_union, int & n_near_tiles) {
5887  for (Tile::TileFnPair * near_tile = _tiles[tile_index].begin_tiles;
5888  near_tile != _tiles[tile_index].end_tiles; near_tile++){
5889  if (! (near_tile->first)->tagged) {
5890  (near_tile->first)->tagged = true;
5891  tile_union[n_near_tiles] = near_tile->first - & _tiles[0];
5892  n_near_tiles++;
5893  }
5894  }
5895 }
5896 inline void LazyTiling9Alt::_add_untagged_neighbours_to_tile_union_using_max_info(
5897  const TiledJet * jet,
5898  vector<int> & tile_union, int & n_near_tiles) {
5899  Tile & tile = _tiles[jet->tile_index];
5900  for (Tile::TileFnPair * near_tile = tile.begin_tiles; near_tile != tile.end_tiles; near_tile++){
5901  if ((near_tile->first)->tagged) continue;
5902  double dist = (tile.*(near_tile->second))(jet) - tile_edge_security_margin;
5903  if (dist > (near_tile->first)->max_NN_dist) continue;
5904  (near_tile->first)->tagged = true;
5905  tile_union[n_near_tiles] = near_tile->first - & _tiles[0];
5906  n_near_tiles++;
5907  }
5908 }
5909 ostream & operator<<(ostream & ostr, const TiledJet & jet) {
5910  ostr << "j" << setw(3) << jet._jets_index << ":pt2,rap,phi=" ; ostr.flush();
5911  ostr << jet.kt2 << ","; ostr.flush();
5912  ostr << jet.eta << ","; ostr.flush();
5913  ostr << jet.phi; ostr.flush();
5914  ostr << ", tile=" << jet.tile_index; ostr.flush();
5915  return ostr;
5916 }
5917 inline void LazyTiling9Alt::_update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, vector<TiledJet *> & jets_for_minheap) {
5918  double dist = _bj_dist(jetI,jetX);
5919  if (dist < jetI->NN_dist) {
5920  if (jetI != jetX) {
5921  jetI->NN_dist = dist;
5922  jetI->NN = jetX;
5923  if (!jetI->minheap_update_needed()) {
5924  jetI->label_minheap_update_needed();
5925  jets_for_minheap.push_back(jetI);
5926  }
5927  }
5928  }
5929  if (dist < jetX->NN_dist) {
5930  if (jetI != jetX) {
5931  jetX->NN_dist = dist;
5932  jetX->NN = jetI;}
5933  }
5934 }
5935 inline void LazyTiling9Alt::_set_NN(TiledJet * jetI,
5936  vector<TiledJet *> & jets_for_minheap) {
5937  jetI->NN_dist = _R2;
5938  jetI->NN = NULL;
5939  if (!jetI->minheap_update_needed()) {
5940  jetI->label_minheap_update_needed();
5941  jets_for_minheap.push_back(jetI);}
5942  Tile * tile_ptr = &_tiles[jetI->tile_index];
5943  for (Tile::TileFnPair * near_tile = tile_ptr->begin_tiles;
5944  near_tile != tile_ptr->end_tiles; near_tile++) {
5945  if (jetI->NN_dist < (tile_ptr->*(near_tile->second))(jetI)) continue;
5946  for (TiledJet * jetJ = (near_tile->first)->head;
5947  jetJ != NULL; jetJ = jetJ->next) {
5948  double dist = _bj_dist(jetI,jetJ);
5949  if (dist < jetI->NN_dist && jetJ != jetI) {
5950  jetI->NN_dist = dist; jetI->NN = jetJ;
5951  }
5952  }
5953  }
5954 }
5955 void LazyTiling9Alt::run() {
5956  int n = _jets.size();
5957  TiledJet * briefjets = new TiledJet[n];
5958  TiledJet * jetA = briefjets, * jetB;
5959  TiledJet oldB;
5960  vector<int> tile_union(3*n_tile_neighbours);
5961  for (int i = 0; i< n; i++) {
5962  _tj_set_jetinfo(jetA, i);
5963  jetA++; // move on to next entry of briefjets
5964  }
5965  TiledJet * head = briefjets; // a nicer way of naming start
5966  vector<Tile>::iterator tile;
5967  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5968  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5969  for (jetB = tile->head; jetB != jetA; jetB = jetB->next) {
5970  double dist = _bj_dist_not_periodic(jetA,jetB);
5971  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5972  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5973  }
5974  }
5975  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5976  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
5977  }
5978  }
5979  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
5980  if (tile->use_periodic_delta_phi) {
5981  for (Tile::TileFnPair * RTileFnPair = tile->RH_tiles;
5982  RTileFnPair != tile->end_tiles; RTileFnPair++) {
5983  Tile *RTile = RTileFnPair->first;
5984  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
5985  double dist_to_tile = ((*tile).*(RTileFnPair->second))(jetA);
5986  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
5987  bool relevant_for_RTile = dist_to_tile <= RTile->max_NN_dist;
5988  if (relevant_for_jetA || relevant_for_RTile) {
5989  for (jetB = RTile->head; jetB != NULL; jetB = jetB->next) {
5990  double dist = _bj_dist(jetA,jetB);
5991  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
5992  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
5993  }
5994  }
5995  }
5996  }
5997  } else {
5998  for (Tile::TileFnPair* RTileFnPair = tile->RH_tiles;
5999  RTileFnPair != tile->end_tiles; RTileFnPair++) {
6000  Tile *RTile = RTileFnPair->first;
6001  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
6002  double dist_to_tile = ((*tile).*(RTileFnPair->second))(jetA);
6003  bool relevant_for_jetA = dist_to_tile <= jetA->NN_dist;
6004  bool relevant_for_RTile = dist_to_tile <= RTile->max_NN_dist;
6005  if (relevant_for_jetA || relevant_for_RTile) {
6006  for (jetB = RTile->head; jetB != NULL; jetB = jetB->next) {
6007  double dist = _bj_dist_not_periodic(jetA,jetB);
6008  if (dist < jetA->NN_dist) {jetA->NN_dist = dist; jetA->NN = jetB;}
6009  if (dist < jetB->NN_dist) {jetB->NN_dist = dist; jetB->NN = jetA;}
6010  }
6011  }
6012  }
6013  }
6014  }
6015  }
6016  for (tile = _tiles.begin(); tile != _tiles.end(); tile++) {
6017  tile->max_NN_dist = 0;
6018  for (jetA = tile->head; jetA != NULL; jetA = jetA->next) {
6019  if (jetA->NN_dist > tile->max_NN_dist) tile->max_NN_dist = jetA->NN_dist;
6020  }
6021  }
6022  vector<double> diJs(n);
6023  for (int i = 0; i < n; i++) {
6024  diJs[i] = _bj_diJ(&briefjets[i]);
6025  briefjets[i].label_minheap_update_done();
6026  }
6027  MinHeap minheap(diJs);
6028  vector<TiledJet *> jets_for_minheap;
6029  jets_for_minheap.reserve(n);
6030  int history_location = n-1;
6031  while (n > 0) {
6032  double diJ_min = minheap.minval() *_invR2;
6033  jetA = head + minheap.minloc();
6034  history_location++;
6035  jetB = jetA->NN;
6036  if (jetB != NULL) {
6037  if (jetA < jetB) {std::swap(jetA,jetB);}
6038  int nn; // new jet index
6039  _cs.plugin_record_ij_recombination(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
6040  _bj_remove_from_tiles(jetA);
6041  oldB = * jetB; // take a copy because we will need it...
6042  _bj_remove_from_tiles(jetB);
6043  _tj_set_jetinfo(jetB, nn); // cause jetB to become _jets[nn]
6044  } else {
6045  _cs.plugin_record_iB_recombination(jetA->_jets_index, diJ_min);
6046  _bj_remove_from_tiles(jetA);
6047  }
6048  minheap.remove(jetA-head);
6049  int n_near_tiles = 0;
6050  _add_untagged_neighbours_to_tile_union_using_max_info(jetA,
6051  tile_union, n_near_tiles);
6052  if (jetB != NULL) {
6053  _add_untagged_neighbours_to_tile_union_using_max_info(&oldB,
6054  tile_union,n_near_tiles);
6055  jetB->label_minheap_update_needed();
6056  jets_for_minheap.push_back(jetB);
6057  }
6058  if (jetB != NULL) {
6059  Tile & jetB_tile = _tiles[jetB->tile_index];
6060  for (Tile::TileFnPair * near_tile_fn_pair = jetB_tile.begin_tiles;
6061  near_tile_fn_pair != jetB_tile.end_tiles; near_tile_fn_pair++) {
6062  Tile * near_tile = near_tile_fn_pair->first;
6063  double dist_to_tile = (jetB_tile.*(near_tile_fn_pair->second))(jetB);
6064  bool relevant_for_jetB = dist_to_tile <= jetB->NN_dist;
6065  bool relevant_for_near_tile = dist_to_tile <= near_tile->max_NN_dist;
6066  bool relevant = relevant_for_jetB || relevant_for_near_tile;
6067  if (relevant) {
6068  if (near_tile->tagged) {
6069  for (TiledJet * jetI = near_tile->head; jetI != NULL; jetI = jetI->next) {
6070  if (jetI->NN == jetA || jetI->NN == jetB) _set_NN(jetI, jets_for_minheap);
6071  _update_jetX_jetI_NN(jetB, jetI, jets_for_minheap);
6072  }
6073  near_tile->tagged = false;
6074  } else {
6075  for (TiledJet * jetI = near_tile->head; jetI != NULL; jetI = jetI->next) {
6076  _update_jetX_jetI_NN(jetB, jetI, jets_for_minheap);
6077  }
6078  }
6079  }
6080  // // -- Keep this old inline code for later speed tests
6081  }
6082  }
6083  for (int itile = 0; itile < n_near_tiles; itile++) {
6084  Tile * tile_ptr = &_tiles[tile_union[itile]];
6085  if (!tile_ptr->tagged) continue; // because earlier loop may have undone the tag
6086  tile_ptr->tagged = false;
6087  for (TiledJet * jetI = tile_ptr->head; jetI != NULL; jetI = jetI->next) {
6088  if (jetI->NN == jetA || (jetI->NN == jetB && jetB != NULL)) {
6089  _set_NN(jetI, jets_for_minheap);
6090  }
6091  }
6092  }
6093  while (jets_for_minheap.size() > 0) {
6094  TiledJet * jetI = jets_for_minheap.back();
6095  jets_for_minheap.pop_back();
6096  minheap.update(jetI-head, _bj_diJ(jetI));
6097  jetI->label_minheap_update_done();
6098  Tile & tile_I = _tiles[jetI->tile_index];
6099  if (tile_I.max_NN_dist < jetI->NN_dist) tile_I.max_NN_dist = jetI->NN_dist;
6100  }
6101  n--;
6102  }
6103  delete[] briefjets;
6104 }
6105 FJCORE_END_NAMESPACE
6106 #include <iomanip>
6107 #include <limits>
6108 #include <cmath>
6109 using namespace std;
6110 FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
6111 TilingExtent::TilingExtent(ClusterSequence & cs) {
6112  _determine_rapidity_extent(cs.jets());
6113 }
6114 TilingExtent::TilingExtent(const vector<PseudoJet> &particles) {
6115  _determine_rapidity_extent(particles);
6116 }
6117 void TilingExtent::_determine_rapidity_extent(const vector<PseudoJet> & particles) {
6118  int nrap = 20;
6119  int nbins = 2*nrap;
6120  vector<double> counts(nbins, 0);
6121  _minrap = numeric_limits<double>::max();
6122  _maxrap = -numeric_limits<double>::max();
6123  int ibin;
6124  for (unsigned i = 0; i < particles.size(); i++) {
6125  if (particles[i].E() == abs(particles[i].pz())) continue;
6126  double rap = particles[i].rap();
6127  if (rap < _minrap) _minrap = rap;
6128  if (rap > _maxrap) _maxrap = rap;
6129  ibin = int(rap+nrap);
6130  if (ibin < 0) ibin = 0;
6131  if (ibin >= nbins) ibin = nbins - 1;
6132  counts[ibin]++;
6133  }
6134  double max_in_bin = 0;
6135  for (ibin = 0; ibin < nbins; ibin++) {
6136  if (max_in_bin < counts[ibin]) max_in_bin = counts[ibin];
6137  }
6138  const double allowed_max_fraction = 0.25;
6139  const double min_multiplicity = 4;
6140  double allowed_max_cumul = floor(max(max_in_bin * allowed_max_fraction, min_multiplicity));
6141  if (allowed_max_cumul > max_in_bin) allowed_max_cumul = max_in_bin;
6142  double cumul_lo = 0;
6143  _cumul2 = 0;
6144  for (ibin = 0; ibin < nbins; ibin++) {
6145  cumul_lo += counts[ibin];
6146  if (cumul_lo >= allowed_max_cumul) {
6147  double y = ibin-nrap;
6148  if (y > _minrap) _minrap = y;
6149  break;
6150  }
6151  }
6152  assert(ibin != nbins); // internal consistency check that you found a bin
6153  _cumul2 += cumul_lo*cumul_lo;
6154  int ibin_lo = ibin;
6155  double cumul_hi = 0;
6156  for (ibin = nbins-1; ibin >= 0; ibin--) {
6157  cumul_hi += counts[ibin];
6158  if (cumul_hi >= allowed_max_cumul) {
6159  double y = ibin-nrap+1; // +1 here is the rapidity bin width
6160  if (y < _maxrap) _maxrap = y;
6161  break;
6162  }
6163  }
6164  assert(ibin >= 0); // internal consistency check that you found a bin
6165  int ibin_hi = ibin;
6166  assert(ibin_hi >= ibin_lo);
6167  if (ibin_hi == ibin_lo) {
6168  _cumul2 = pow(double(cumul_lo + cumul_hi - counts[ibin_hi]), 2);
6169  } else {
6170  _cumul2 += cumul_hi*cumul_hi;
6171  for (ibin = ibin_lo+1; ibin < ibin_hi; ibin++) {
6172  _cumul2 += counts[ibin]*counts[ibin];
6173  }
6174  }
6175 }
6176 FJCORE_END_NAMESPACE
Definition: FJcore.h:367
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4639
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4599
virtual bool is_geometric() const
implies a finite area
Definition: FJcore.cc:4792
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4627
virtual bool has_finite_area() const
regardless of the reference
Definition: FJcore.cc:4892
virtual bool is_geometric() const
implies a finite area
Definition: FJcore.cc:4858
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4794
virtual bool has_finite_area() const
regardless of the reference
Definition: FJcore.cc:4859
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4893
Definition: FJcore.cc:837
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4828
virtual bool has_finite_area() const
regardless of the reference
Definition: FJcore.cc:4793
virtual bool has_finite_area() const
regardless of the reference
Definition: FJcore.cc:4827
virtual bool has_known_area() const
the area is analytically known
Definition: FJcore.cc:4860
bool treelinks_null() const
default constructor
Definition: FJcore.cc:271
virtual bool is_geometric() const
implies a finite area
Definition: FJcore.cc:4891
Definition: dbStruct.hh:78
virtual bool is_geometric() const
implies a finite area
Definition: FJcore.cc:4826