// fjcore -- extracted from FastJet v3.2.1 (http://fastjet.fr)
//
// fjcore constitutes a digest of the main FastJet functionality.
// The files fjcore.hh and fjcore.cc are meant to provide easy access to these
// core functions, in the form of single files and without the need of a full
// FastJet installation:
//
// g++ main.cc fjcore.cc
//
// with main.cc including fjcore.hh.
//
// A fortran interface, fjcorefortran.cc, is also provided. See the example
// and the Makefile for instructions.
//
// The results are expected to be identical to those obtained by linking to
// the full FastJet distribution.
//
// NOTE THAT, IN ORDER TO MAKE IT POSSIBLE FOR FJCORE AND THE FULL FASTJET
// TO COEXIST, THE FORMER USES THE "fjcore" NAMESPACE INSTEAD OF "fastjet".
//
// In particular, fjcore provides:
//
// - access to all native pp and ee algorithms, kt, anti-kt, C/A.
// For C/A, the NlnN method is available, while anti-kt and kt
// are limited to the N^2 one (still the fastest for N < 100k particles)
// - access to selectors, for implementing cuts and selections
// - access to all functionalities related to pseudojets (e.g. a jet's
// structure or user-defined information)
//
// Instead, it does NOT provide:
//
// - jet areas functionality
// - background estimation
// - access to other algorithms via plugins
// - interface to CGAL
// - fastjet tools, e.g. filters, taggers
//
// If these functionalities are needed, the full FastJet installation must be
// used. The code will be fully compatible, with the sole replacement of the
// header files and of the fjcore namespace with the fastjet one.
//
// fjcore.hh and fjcore.cc are not meant to be human-readable.
// For documentation, see the full FastJet manual and doxygen at http://fastjet.fr
//
// Like FastJet, fjcore is released under the terms of the GNU General Public
// License version 2 (GPLv2). If you use this code as part of work towards a
// scientific publication, whether directly or contained within another program
// (e.g. Delphes, MadGraph, SpartyJet, Rivet, LHC collaboration software frameworks,
// etc.), you should include a citation to
//
// EPJC72(2012)1896 [arXiv:1111.6097] (FastJet User Manual)
// and, optionally, Phys.Lett.B641 (2006) 57 [arXiv:hep-ph/0512210]
//
// Copyright (c) 2005-2016, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
//
//----------------------------------------------------------------------
// This file is part of FastJet.
//
// FastJet is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// The algorithms that underlie FastJet have required considerable
// development and are described in hep-ph/0512210. If you use
// FastJet as part of work towards a scientific publication, please
// include a citation to the FastJet paper.
//
// FastJet is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with FastJet. If not, see .
//----------------------------------------------------------------------
//
//#include "fjcore.hh"
// For inclusion in Pythia8 line above is replaced by line below.
#include "Pythia8/FJcore.h"
#ifndef __FJCORE_VERSION_HH__
#define __FJCORE_VERSION_HH__
#include
FJCORE_BEGIN_NAMESPACE
const char* fastjet_version = FJCORE_PACKAGE_VERSION;
FJCORE_END_NAMESPACE
#endif // __FJCORE_VERSION_HH__
#ifndef __FJCORE_CLUSTERQUENCE_N2_ICC__
#define __FJCORE_CLUSTERQUENCE_N2_ICC__
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
template void ClusterSequence::_simple_N2_cluster() {
int n = _jets.size();
BJ * briefjets = new BJ[n];
BJ * jetA = briefjets, * jetB;
for (int i = 0; i< n; i++) {
_bj_set_jetinfo(jetA, i);
jetA++; // move on to next entry of briefjets
}
BJ * tail = jetA; // a semaphore for the end of briefjets
BJ * head = briefjets; // a nicer way of naming start
for (jetA = head + 1; jetA != tail; jetA++) {
_bj_set_NN_crosscheck(jetA, head, jetA);
}
double * diJ = new double[n];
jetA = head;
for (int i = 0; i < n; i++) {
diJ[i] = _bj_diJ(jetA);
jetA++; // have jetA follow i
}
int history_location = n-1;
while (tail != head) {
double diJ_min = diJ[0];
int diJ_min_jet = 0;
for (int i = 1; i < n; i++) {
if (diJ[i] < diJ_min) {diJ_min_jet = i; diJ_min = diJ[i];}
}
history_location++;
jetA = & briefjets[diJ_min_jet];
jetB = static_cast(jetA->NN);
diJ_min *= _invR2;
if (jetB != NULL) {
if (jetA < jetB) {std::swap(jetA,jetB);}
int nn; // new jet index
_do_ij_recombination_step(jetA->_jets_index, jetB->_jets_index, diJ_min, nn);
_bj_set_jetinfo(jetB, nn);
} else {
_do_iB_recombination_step(jetA->_jets_index, diJ_min);
}
tail--; n--;
*jetA = *tail;
diJ[jetA - head] = diJ[tail-head];
for (BJ * jetI = head; jetI != tail; jetI++) {
if (jetI->NN == jetA || jetI->NN == jetB) {
_bj_set_NN_nocross(jetI, head, tail);
diJ[jetI-head] = _bj_diJ(jetI); // update diJ
}
if (jetB != NULL) {
double dist = _bj_dist(jetI,jetB);
if (dist < jetI->NN_dist) {
if (jetI != jetB) {
jetI->NN_dist = dist;
jetI->NN = jetB;
diJ[jetI-head] = _bj_diJ(jetI); // update diJ...
}
}
if (dist < jetB->NN_dist) {
if (jetI != jetB) {
jetB->NN_dist = dist;
jetB->NN = jetI;}
}
}
if (jetI->NN == tail) {jetI->NN = jetA;}
}
if (jetB != NULL) {diJ[jetB-head] = _bj_diJ(jetB);}
}
delete[] diJ;
delete[] briefjets;
}
FJCORE_END_NAMESPACE
#endif // __FJCORE_CLUSTERQUENCE_N2_ICC__
#ifndef __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
#define __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
#include
#include
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
class EtaPhi {
public:
double first, second;
EtaPhi() {}
EtaPhi(double a, double b) {first = a; second = b;}
void sanitize() {
if (second < 0) second += twopi;
if (second >= twopi) second -= twopi;
}
};
class DnnError : public Error {
public:
DnnError(const std::string & message_in) : Error(message_in) {}
};
class DynamicNearestNeighbours {
public:
virtual int NearestNeighbourIndex(const int ii) const = 0;
virtual double NearestNeighbourDistance(const int ii) const = 0;
virtual bool Valid(const int index) const = 0;
virtual void RemoveAndAddPoints(const std::vector & indices_to_remove,
const std::vector & points_to_add,
std::vector & indices_added,
std::vector & indices_of_updated_neighbours) = 0;
inline void RemovePoint (const int index,
std::vector & indices_of_updated_neighbours) {
std::vector indices_added;
std::vector points_to_add;
std::vector indices_to_remove(1);
indices_to_remove[0] = index;
RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
indices_of_updated_neighbours
);};
inline void RemoveCombinedAddCombination(
const int index1, const int index2,
const EtaPhi & newpoint,
int & index3,
std::vector & indices_of_updated_neighbours) {
std::vector indices_added(1);
std::vector points_to_add(1);
std::vector indices_to_remove(2);
indices_to_remove[0] = index1;
indices_to_remove[1] = index2;
points_to_add[0] = newpoint;
RemoveAndAddPoints(indices_to_remove, points_to_add, indices_added,
indices_of_updated_neighbours
);
index3 = indices_added[0];
};
virtual ~DynamicNearestNeighbours () {}
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_DYNAMICNEARESTNEIGHBOURS_HH__
#ifndef __FJCORE_SEARCHTREE_HH__
#define __FJCORE_SEARCHTREE_HH__
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
template class SearchTree {
public:
class Node;
class circulator;
class const_circulator;
SearchTree(const std::vector & init);
SearchTree(const std::vector & init, unsigned int max_size);
void remove(unsigned node_index);
void remove(typename SearchTree::Node * node);
void remove(typename SearchTree::circulator & circ);
circulator insert(const T & value);
const Node & operator[](int i) const {return _nodes[i];};
unsigned int size() const {return _nodes.size() - _available_nodes.size();}
void verify_structure();
void verify_structure_linear() const;
void verify_structure_recursive(const Node * , const Node * , const Node * ) const;
void print_elements();
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
inline unsigned int max_depth() const {return _max_depth;};
#else
inline unsigned int max_depth() const {return 0;};
#endif
int loc(const Node * node) const ;
Node * _find_predecessor(const Node *);
Node * _find_successor(const Node *);
const Node & operator[](unsigned int i) const {return _nodes[i];};
const_circulator somewhere() const;
circulator somewhere();
private:
void _initialize(const std::vector & init);
std::vector _nodes;
std::vector _available_nodes;
Node * _top_node;
unsigned int _n_removes;
void _do_initial_connections(unsigned int this_one, unsigned int scale,
unsigned int left_edge, unsigned int right_edge,
unsigned int depth);
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
unsigned int _max_depth;
#endif
};
template class SearchTree::Node{
public:
Node() {}; /// default constructor
bool treelinks_null() const {
return ((parent==0) && (left==0) && (right==0));};
inline void nullify_treelinks() {
parent = NULL;
left = NULL;
right = NULL;
};
void reset_parents_link_to_me(Node * XX);
T value;
Node * left;
Node * right;
Node * parent;
Node * successor;
Node * predecessor;
};
template void SearchTree::Node::reset_parents_link_to_me(typename SearchTree::Node * XX) {
if (parent == NULL) {return;}
if (parent->right == this) {parent->right = XX;}
else {parent->left = XX;}
}
template class SearchTree::circulator{
public:
friend class SearchTree::const_circulator;
friend class SearchTree;
circulator() : _node(NULL) {}
circulator(Node * node) : _node(node) {}
const T * operator->() const {return &(_node->value);}
T * operator->() {return &(_node->value);}
const T & operator*() const {return _node->value;}
T & operator*() {return _node->value;}
circulator & operator++() {
_node = _node->successor;
return *this;}
circulator operator++(int) {
circulator tmp = *this;
_node = _node->successor;
return tmp;}
circulator & operator--() {
_node = _node->predecessor;
return *this;}
circulator operator--(int) {
circulator tmp = *this;
_node = _node->predecessor;
return tmp;}
circulator next() const {
return circulator(_node->successor);}
circulator previous() const {
return circulator(_node->predecessor);}
bool operator!=(const circulator & other) const {return other._node != _node;}
bool operator==(const circulator & other) const {return other._node == _node;}
private:
Node * _node;
};
template class SearchTree::const_circulator{
public:
const_circulator() : _node(NULL) {}
const_circulator(const Node * node) : _node(node) {}
const_circulator(const circulator & circ) :_node(circ._node) {}
const T * operator->() {return &(_node->value);}
const T & operator*() const {return _node->value;}
const_circulator & operator++() {
_node = _node->successor;
return *this;}
const_circulator operator++(int) {
const_circulator tmp = *this;
_node = _node->successor;
return tmp;}
const_circulator & operator--() {
_node = _node->predecessor;
return *this;}
const_circulator operator--(int) {
const_circulator tmp = *this;
_node = _node->predecessor;
return tmp;}
const_circulator next() const {
return const_circulator(_node->successor);}
const_circulator previous() const {
return const_circulator(_node->predecessor);}
bool operator!=(const const_circulator & other) const {return other._node != _node;}
bool operator==(const const_circulator & other) const {return other._node == _node;}
private:
const Node * _node;
};
template SearchTree::SearchTree(const std::vector & init,
unsigned int max_size) :
_nodes(max_size) {
_available_nodes.reserve(max_size);
_available_nodes.resize(max_size - init.size());
for (unsigned int i = init.size(); i < max_size; i++) {
_available_nodes[i-init.size()] = &(_nodes[i]);
}
_initialize(init);
}
template SearchTree::SearchTree(const std::vector & init) :
_nodes(init.size()), _available_nodes(0) {
_available_nodes.reserve(init.size());
_initialize(init);
}
template void SearchTree::_initialize(const std::vector & init) {
_n_removes = 0;
unsigned n = init.size();
assert(n>=1);
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
_max_depth = 0;
#endif
for (unsigned int i = 1; i inline int SearchTree::loc(const Node * node) const {return node == NULL?
-999 : node - &(_nodes[0]);}
template void SearchTree::_do_initial_connections(
unsigned int this_one,
unsigned int scale,
unsigned int left_edge,
unsigned int right_edge,
unsigned int depth
) {
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
_max_depth = max(depth, _max_depth);
#endif
unsigned int ref_new_scale = (scale+1)/2;
unsigned new_scale = ref_new_scale;
bool did_child = false;
while(true) {
int left = this_one - new_scale; // be careful here to use signed int...
if (left >= static_cast(left_edge)
&& _nodes[left].treelinks_null() ) {
_nodes[left].parent = &(_nodes[this_one]);
_nodes[this_one].left = &(_nodes[left]);
_do_initial_connections(left, new_scale, left_edge, this_one, depth+1);
did_child = true;
break;
}
unsigned int old_new_scale = new_scale;
new_scale = (old_new_scale + 1)/2;
if (new_scale == old_new_scale) break;
}
if (!did_child) {_nodes[this_one].left = NULL;}
new_scale = ref_new_scale;
did_child = false;
while(true) {
unsigned int right = this_one + new_scale;
if (right < right_edge && _nodes[right].treelinks_null()) {
_nodes[right].parent = &(_nodes[this_one]);
_nodes[this_one].right = &(_nodes[right]);
_do_initial_connections(right, new_scale, this_one+1,right_edge,depth+1);
did_child = true;
break;
}
unsigned int old_new_scale = new_scale;
new_scale = (old_new_scale + 1)/2;
if (new_scale == old_new_scale) break;
}
if (!did_child) {_nodes[this_one].right = NULL;}
}
template void SearchTree::remove(unsigned int node_index) {
remove(&(_nodes[node_index]));
}
template void SearchTree::remove(circulator & circ) {
remove(circ._node);
}
template void SearchTree::remove(typename SearchTree::Node * node) {
assert(size() > 1); // switch this to throw...?
assert(!node->treelinks_null());
node->predecessor->successor = node->successor;
node->successor->predecessor = node->predecessor;
if (node->left == NULL && node->right == NULL) {
node->reset_parents_link_to_me(NULL);
} else if (node->left != NULL && node->right == NULL){
node->reset_parents_link_to_me(node->left);
node->left->parent = node->parent;
if (_top_node == node) {_top_node = node->left;}
} else if (node->left == NULL && node->right != NULL){
node->reset_parents_link_to_me(node->right);
node->right->parent = node->parent;
if (_top_node == node) {_top_node = node->right;}
} else {
Node * replacement;
bool use_predecessor = (_n_removes % 2 == 1);
if (use_predecessor) {
replacement = node->predecessor;
assert(replacement->right == NULL); // guaranteed if it's our predecessor
if (replacement != node->left) {
if (replacement->left != NULL) {
replacement->left->parent = replacement->parent;}
replacement->reset_parents_link_to_me(replacement->left);
replacement->left = node->left;
}
replacement->parent = node->parent;
replacement->right = node->right;
} else {
replacement = node->successor;
assert(replacement->left == NULL); // guaranteed if it's our successor
if (replacement != node->right) {
if (replacement->right != NULL) {
replacement->right->parent = replacement->parent;}
replacement->reset_parents_link_to_me(replacement->right);
replacement->right = node->right;
}
replacement->parent = node->parent;
replacement->left = node->left;
}
node->reset_parents_link_to_me(replacement);
if (node->left != replacement) {node->left->parent = replacement;}
if (node->right != replacement) {node->right->parent = replacement;}
if (_top_node == node) {_top_node = replacement;}
}
node->nullify_treelinks();
node->predecessor = NULL;
node->successor = NULL;
_n_removes++;
_available_nodes.push_back(node);
}
template typename SearchTree::circulator SearchTree::insert(const T & value) {
assert(_available_nodes.size() > 0);
Node * node = _available_nodes.back();
_available_nodes.pop_back();
node->value = value;
Node * location = _top_node;
Node * old_location = NULL;
bool on_left = true; // (init not needed -- but soothes g++4)
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
unsigned int depth = 0;
#endif
while(location != NULL) {
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
depth++;
#endif
old_location = location;
on_left = value < location->value;
if (on_left) {location = location->left;}
else {location = location->right;}
}
#ifdef __FJCORE_SEARCHTREE_TRACK_DEPTH
_max_depth = max(depth, _max_depth);
#endif
node->parent = old_location;
if (on_left) {node->parent->left = node;}
else {node->parent->right = node;}
node->left = NULL;
node->right = NULL;
node->predecessor = _find_predecessor(node);
if (node->predecessor != NULL) {
node->successor = node->predecessor->successor;
node->predecessor->successor = node;
node->successor->predecessor = node;
} else {
node->successor = _find_successor(node);
assert(node->successor != NULL); // can only happen if we're sole element
node->predecessor = node->successor->predecessor;
node->successor->predecessor = node;
node->predecessor->successor = node;
}
return circulator(node);
}
template void SearchTree::verify_structure() {
verify_structure_linear();
const Node * left_limit = _top_node;
while (left_limit->left != NULL) {left_limit = left_limit->left;}
const Node * right_limit = _top_node;
while (right_limit->right != NULL) {right_limit = right_limit->right;}
verify_structure_recursive(_top_node, left_limit, right_limit);
}
template void SearchTree::verify_structure_recursive(
const typename SearchTree::Node * element,
const typename SearchTree::Node * left_limit,
const typename SearchTree::Node * right_limit) const {
assert(!(element->value < left_limit->value));
assert(!(right_limit->value < element->value));
const Node * left = element->left;
if (left != NULL) {
assert(!(element->value < left->value));
if (left != left_limit) {
verify_structure_recursive(left, left_limit, element);}
}
const Node * right = element->right;
if (right != NULL) {
assert(!(right->value < element->value));
if (right != right_limit) {
verify_structure_recursive(right, element, right_limit);}
}
}
template void SearchTree::verify_structure_linear() const {
unsigned n_top = 0;
unsigned n_null = 0;
for(unsigned i = 0; i < _nodes.size(); i++) {
const typename SearchTree::Node * node = &(_nodes[i]);
if (node->treelinks_null()) {n_null++; continue;}
if (node->parent == NULL) {
n_top++;
} else {
assert((node->parent->left == node) ^ (node->parent->right == node));
}
if (node->left != NULL) {
assert(!(node->value < node->left->value ));}
if (node->right != NULL) {
assert(!(node->right->value < node->value ));}
}
assert(n_top == 1 || (n_top == 0 && size() <= 1) );
assert(n_null == _available_nodes.size() ||
(n_null == _available_nodes.size() + 1 && size() == 1));
}
template typename SearchTree::Node * SearchTree::_find_predecessor(const typename SearchTree::Node * node) {
typename SearchTree::Node * newnode;
if (node->left != NULL) {
newnode = node->left;
while(newnode->right != NULL) {newnode = newnode->right;}
return newnode;
} else {
const typename SearchTree::Node * lastnode = node;
newnode = node->parent;
while(newnode != NULL) {
if (newnode->right == lastnode) {return newnode;}
lastnode = newnode;
newnode = newnode->parent;
}
return newnode;
}
}
template typename SearchTree::Node * SearchTree::_find_successor(const typename SearchTree::Node * node) {
typename SearchTree::Node * newnode;
if (node->right != NULL) {
newnode = node->right;
while(newnode->left != NULL) {newnode = newnode->left;}
return newnode;
} else {
const typename SearchTree::Node * lastnode = node;
newnode = node->parent;
while(newnode != NULL) {
if (newnode->left == lastnode) {return newnode;}
lastnode = newnode;
newnode = newnode->parent;
}
return newnode;
}
}
template void SearchTree::print_elements() {
typename SearchTree::Node * base_node = &(_nodes[0]);
typename SearchTree::Node * node = base_node;
int n = _nodes.size();
for(; node - base_node < n ; node++) {
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);
}
}
template typename SearchTree::circulator SearchTree::somewhere() {
return circulator(_top_node);
}
template typename SearchTree::const_circulator SearchTree::somewhere() const {
return const_circulator(_top_node);
}
FJCORE_END_NAMESPACE
#endif // __FJCORE_SEARCHTREE_HH__
#ifndef __FJCORE_MINHEAP__HH__
#define __FJCORE_MINHEAP__HH__
#include
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
class MinHeap {
public:
MinHeap (const std::vector & values, unsigned int max_size) :
_heap(max_size) {initialise(values);}
MinHeap (unsigned int max_size) : _heap(max_size) {}
MinHeap (const std::vector & values) :
_heap(values.size()) {initialise(values);}
void initialise(const std::vector & values);
inline unsigned int minloc() const {
return (_heap[0].minloc) - &(_heap[0]);}
inline double minval() const {return _heap[0].minloc->value;}
inline double operator[](int i) const {return _heap[i].value;}
void remove(unsigned int loc) {
update(loc,std::numeric_limits::max());};
void update(unsigned int, double);
private:
struct ValueLoc{
double value;
ValueLoc * minloc;
};
std::vector _heap;
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_MINHEAP__HH__
#ifndef __FJCORE_CLOSESTPAIR2DBASE__HH__
#define __FJCORE_CLOSESTPAIR2DBASE__HH__
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
class Coord2D {
public:
double x, y;
Coord2D() : x(0.0), y(0.0) {};
Coord2D(double a, double b): x(a), y(b) {};
Coord2D operator-(const Coord2D & other) const {
return Coord2D(x - other.x, y - other.y);};
Coord2D operator+(const Coord2D & other) const {
return Coord2D(x + other.x, y + other.y);};
Coord2D operator*(double factor) const {return Coord2D(factor*x,factor*y);};
friend Coord2D operator*(double factor, const Coord2D & coord) {
return Coord2D(factor*coord.x,factor*coord.y);
}
Coord2D operator/(double divisor) const {
return Coord2D(x / divisor, y / divisor);};
friend double distance2(const Coord2D & a, const Coord2D & b) {
double dx = a.x - b.x, dy = a.y-b.y;
return dx*dx+dy*dy;
};
double distance2(const Coord2D & b) const {
double dx = x - b.x, dy = y-b.y;
return dx*dx+dy*dy;
};
};
class ClosestPair2DBase {
public:
virtual void closest_pair(unsigned int & ID1, unsigned int & ID2,
double & distance2) const = 0;
virtual void remove(unsigned int ID) = 0;
virtual unsigned int insert(const Coord2D & position) = 0;
virtual unsigned int replace(unsigned int ID1, unsigned int ID2,
const Coord2D & position) {
remove(ID1);
remove(ID2);
unsigned new_ID = insert(position);
return(new_ID);
};
virtual void replace_many(const std::vector & IDs_to_remove,
const std::vector & new_positions,
std::vector & new_IDs) {
for(unsigned i = 0; i < IDs_to_remove.size(); i++) {
remove(IDs_to_remove[i]);}
new_IDs.resize(0);
for(unsigned i = 0; i < new_positions.size(); i++) {
new_IDs.push_back(insert(new_positions[i]));}
}
virtual unsigned int size() = 0;
virtual ~ClosestPair2DBase() {};
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_CLOSESTPAIR2DBASE__HH__
#ifndef __FJCORE_CLOSESTPAIR2D__HH__
#define __FJCORE_CLOSESTPAIR2D__HH__
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
class ClosestPair2D : public ClosestPair2DBase {
public:
ClosestPair2D(const std::vector & positions,
const Coord2D & left_corner, const Coord2D & right_corner) {
_initialize(positions, left_corner, right_corner, positions.size());
};
ClosestPair2D(const std::vector & positions,
const Coord2D & left_corner, const Coord2D & right_corner,
const unsigned int max_size) {
_initialize(positions, left_corner, right_corner, max_size);
};
void closest_pair(unsigned int & ID1, unsigned int & ID2,
double & distance2) const;
void remove(unsigned int ID);
unsigned int insert(const Coord2D &);
virtual unsigned int replace(unsigned int ID1, unsigned int ID2,
const Coord2D & position);
virtual void replace_many(const std::vector & IDs_to_remove,
const std::vector & new_positions,
std::vector & new_IDs);
inline void print_tree_depths(std::ostream & outdev) const {
outdev << _trees[0]->max_depth() << " "
<< _trees[1]->max_depth() << " "
<< _trees[2]->max_depth() << "\n";
};
unsigned int size();
private:
void _initialize(const std::vector & positions,
const Coord2D & left_corner, const Coord2D & right_corner,
const unsigned int max_size);
static const unsigned int _nshift = 3;
class Point; // will be defined below
template class triplet {
public:
inline const T & operator[](unsigned int i) const {return _contents[i];};
inline T & operator[](unsigned int i) {return _contents[i];};
private:
T _contents[_nshift];
};
class Shuffle {
public:
unsigned int x, y;
Point * point;
bool operator<(const Shuffle &) const;
void operator+=(unsigned int shift) {x += shift; y+= shift;};
};
typedef SearchTree Tree;
typedef Tree::circulator circulator;
typedef Tree::const_circulator const_circulator;
triplet > _trees;
SharedPtr _heap;
std::vector _points;
std::stack _available_points;
std::vector _points_under_review;
static const unsigned int _remove_heap_entry = 1;
static const unsigned int _review_heap_entry = 2;
static const unsigned int _review_neighbour = 4;
void _add_label(Point * point, unsigned int review_flag);
void _set_label(Point * point, unsigned int review_flag);
void _deal_with_points_to_review();
void _remove_from_search_tree(Point * point_to_remove);
void _insert_into_search_tree(Point * new_point);
void _point2shuffle(Point & , Shuffle & , unsigned int shift);
Coord2D _left_corner;
double _range;
int _ID(const Point *) const;
triplet _shifts; // absolute shifts
triplet _rel_shifts; // shifts relative to previous shift
unsigned int _cp_search_range;
};
class ClosestPair2D::Point {
public:
Coord2D coord;
Point * neighbour;
double neighbour_dist2;
triplet circ;
unsigned int review_flag;
double distance2(const Point & other) const {
return coord.distance2(other.coord);
};
};
inline bool floor_ln2_less(unsigned x, unsigned y) {
if (x>y) return false;
return (x < (x^y)); // beware of operator precedence...
}
inline int ClosestPair2D::_ID(const Point * point) const {
return point - &(_points[0]);
}
inline unsigned int ClosestPair2D::size() {
return _points.size() - _available_points.size();
}
FJCORE_END_NAMESPACE
#endif // __FJCORE_CLOSESTPAIR2D__HH__
#ifndef __FJCORE_LAZYTILING9ALT_HH__
#define __FJCORE_LAZYTILING9ALT_HH__
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
const double tile_edge_security_margin=1.0e-7;
class TiledJet {
public:
double eta, phi, kt2, NN_dist;
TiledJet * NN, *previous, * next;
int _jets_index, tile_index;
bool _minheap_update_needed;
inline void label_minheap_update_needed() {_minheap_update_needed = true;}
inline void label_minheap_update_done() {_minheap_update_needed = false;}
inline bool minheap_update_needed() const {return _minheap_update_needed;}
};
const int n_tile_neighbours = 9;
class Tile {
public:
typedef double (Tile::*DistToTileFn)(const TiledJet*) const;
typedef std::pair TileFnPair;
TileFnPair begin_tiles[n_tile_neighbours];
TileFnPair * surrounding_tiles;
TileFnPair * RH_tiles;
TileFnPair * end_tiles;
TiledJet * head;
bool tagged;
bool use_periodic_delta_phi;
double max_NN_dist;
double eta_min, eta_max, phi_min, phi_max;
double distance_to_centre(const TiledJet *) const {return 0;}
double distance_to_left(const TiledJet * jet) const {
double deta = jet->eta - eta_min;
return deta*deta;
}
double distance_to_right(const TiledJet * jet) const {
double deta = jet->eta - eta_max;
return deta*deta;
}
double distance_to_bottom(const TiledJet * jet) const {
double dphi = jet->phi - phi_min;
return dphi*dphi;
}
double distance_to_top(const TiledJet * jet) const {
double dphi = jet->phi - phi_max;
return dphi*dphi;
}
double distance_to_left_top(const TiledJet * jet) const {
double deta = jet->eta - eta_min;
double dphi = jet->phi - phi_max;
return deta*deta + dphi*dphi;
}
double distance_to_left_bottom(const TiledJet * jet) const {
double deta = jet->eta - eta_min;
double dphi = jet->phi - phi_min;
return deta*deta + dphi*dphi;
}
double distance_to_right_top(const TiledJet * jet) const {
double deta = jet->eta - eta_max;
double dphi = jet->phi - phi_max;
return deta*deta + dphi*dphi;
}
double distance_to_right_bottom(const TiledJet * jet) const {
double deta = jet->eta - eta_max;
double dphi = jet->phi - phi_min;
return deta*deta + dphi*dphi;
}
};
class LazyTiling9Alt {
public:
LazyTiling9Alt(ClusterSequence & cs);
void run();
protected:
ClusterSequence & _cs;
const std::vector & _jets;
std::vector _tiles;
double _Rparam, _R2, _invR2;
double _tiles_eta_min, _tiles_eta_max;
double _tile_size_eta, _tile_size_phi;
double _tile_half_size_eta, _tile_half_size_phi;
int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
std::vector _jets_for_minheap;
void _initialise_tiles();
inline int _tile_index (int ieta, int iphi) const {
return (ieta-_tiles_ieta_min)*_n_tiles_phi
+ (iphi+_n_tiles_phi) % _n_tiles_phi;
}
void _bj_remove_from_tiles(TiledJet * const jet);
int _tile_index(const double eta, const double phi) const;
void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
void _print_tiles(TiledJet * briefjets ) const;
void _add_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles) const;
void _add_untagged_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles);
void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
std::vector & tile_union, int & n_near_tiles);
void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector & jets_for_minheap);
void _set_NN(TiledJet * jetI, std::vector & jets_for_minheap);
template double _bj_diJ(const J * const jet) const {
double kt2 = jet->kt2;
if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
return jet->NN_dist * kt2;
}
template inline void _bj_set_jetinfo(
J * const jetA, const int _jets_index) const {
jetA->eta = _jets[_jets_index].rap();
jetA->phi = _jets[_jets_index].phi_02pi();
jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
jetA->_jets_index = _jets_index;
jetA->NN_dist = _R2;
jetA->NN = NULL;
}
template inline double _bj_dist(
const J * const jetA, const J * const jetB) const {
double dphi = std::abs(jetA->phi - jetB->phi);
double deta = (jetA->eta - jetB->eta);
if (dphi > pi) {dphi = twopi - dphi;}
return dphi*dphi + deta*deta;
}
template inline double _bj_dist_not_periodic(
const J * const jetA, const J * const jetB) const {
double dphi = jetA->phi - jetB->phi;
double deta = (jetA->eta - jetB->eta);
return dphi*dphi + deta*deta;
}
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_LAZYTILING9ALT_HH__
#ifndef __FJCORE_LAZYTILING9_HH__
#define __FJCORE_LAZYTILING9_HH__
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
template
class Tile2Base {
public:
Tile2Base * begin_tiles[NN];
Tile2Base ** surrounding_tiles;
Tile2Base ** RH_tiles;
Tile2Base ** end_tiles;
TiledJet * head;
bool tagged;
bool use_periodic_delta_phi;
double max_NN_dist;
double eta_centre, phi_centre;
int jet_count() const {
int count = 0;
const TiledJet * jet = head;
while (jet != 0) {
count++;
jet = jet->next;
}
return count;
}
};
typedef Tile2Base<9> Tile2;
class LazyTiling9 {
public:
LazyTiling9(ClusterSequence & cs);
void run();
protected:
ClusterSequence & _cs;
const std::vector & _jets;
std::vector _tiles;
#ifdef INSTRUMENT2
int _ncall; // GPS tmp
int _ncall_dtt; // GPS tmp
#endif // INSTRUMENT2
double _Rparam, _R2, _invR2;
double _tiles_eta_min, _tiles_eta_max;
double _tile_size_eta, _tile_size_phi;
double _tile_half_size_eta, _tile_half_size_phi;
int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
std::vector _jets_for_minheap;
void _initialise_tiles();
inline int _tile_index (int ieta, int iphi) const {
return (ieta-_tiles_ieta_min)*_n_tiles_phi
+ (iphi+_n_tiles_phi) % _n_tiles_phi;
}
void _bj_remove_from_tiles(TiledJet * const jet);
int _tile_index(const double eta, const double phi) const;
void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
void _print_tiles(TiledJet * briefjets ) const;
void _add_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles) const;
void _add_untagged_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles);
void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
std::vector & tile_union, int & n_near_tiles);
double _distance_to_tile(const TiledJet * bj, const Tile2 *)
#ifdef INSTRUMENT2
;
#else
const;
#endif
void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector & jets_for_minheap);
void _set_NN(TiledJet * jetI, std::vector & jets_for_minheap);
template double _bj_diJ(const J * const jet) const {
double kt2 = jet->kt2;
if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
return jet->NN_dist * kt2;
}
template inline void _bj_set_jetinfo(
J * const jetA, const int _jets_index) const {
jetA->eta = _jets[_jets_index].rap();
jetA->phi = _jets[_jets_index].phi_02pi();
jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
jetA->_jets_index = _jets_index;
jetA->NN_dist = _R2;
jetA->NN = NULL;
}
template inline double _bj_dist(
const J * const jetA, const J * const jetB)
#ifdef INSTRUMENT2
{
_ncall++; // GPS tmp
#else
const {
#endif
double dphi = std::abs(jetA->phi - jetB->phi);
double deta = (jetA->eta - jetB->eta);
if (dphi > pi) {dphi = twopi - dphi;}
return dphi*dphi + deta*deta;
}
template inline double _bj_dist_not_periodic(
const J * const jetA, const J * const jetB)
#ifdef INSTRUMENT2
{
_ncall++; // GPS tmp
#else
const {
#endif
double dphi = jetA->phi - jetB->phi;
double deta = (jetA->eta - jetB->eta);
return dphi*dphi + deta*deta;
}
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_LAZYTILING9_HH__
#ifndef __FJCORE_LAZYTILING25_HH__
#define __FJCORE_LAZYTILING25_HH__
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
typedef Tile2Base<25> Tile25;
class LazyTiling25 {
public:
LazyTiling25(ClusterSequence & cs);
void run();
protected:
ClusterSequence & _cs;
const std::vector & _jets;
std::vector _tiles;
#ifdef INSTRUMENT2
int _ncall; // GPS tmp
int _ncall_dtt; // GPS tmp
#endif // INSTRUMENT2
double _Rparam, _R2, _invR2;
double _tiles_eta_min, _tiles_eta_max;
double _tile_size_eta, _tile_size_phi;
double _tile_half_size_eta, _tile_half_size_phi;
int _n_tiles_phi,_tiles_ieta_min,_tiles_ieta_max;
std::vector _jets_for_minheap;
void _initialise_tiles();
inline int _tile_index (int ieta, int iphi) const {
return (ieta-_tiles_ieta_min)*_n_tiles_phi
+ (iphi+_n_tiles_phi) % _n_tiles_phi;
}
void _bj_remove_from_tiles(TiledJet * const jet);
int _tile_index(const double eta, const double phi) const;
void _tj_set_jetinfo(TiledJet * const jet, const int _jets_index);
void _print_tiles(TiledJet * briefjets ) const;
void _add_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles) const;
void _add_untagged_neighbours_to_tile_union(const int tile_index,
std::vector & tile_union, int & n_near_tiles);
void _add_untagged_neighbours_to_tile_union_using_max_info(const TiledJet * const jet,
std::vector & tile_union, int & n_near_tiles);
double _distance_to_tile(const TiledJet * bj, const Tile25 *)
#ifdef INSTRUMENT2
;
#else
const;
#endif
void _update_jetX_jetI_NN(TiledJet * jetX, TiledJet * jetI, std::vector & jets_for_minheap);
void _set_NN(TiledJet * jetI, std::vector & jets_for_minheap);
template double _bj_diJ(const J * const jet) const {
double kt2 = jet->kt2;
if (jet->NN != NULL) {if (jet->NN->kt2 < kt2) {kt2 = jet->NN->kt2;}}
return jet->NN_dist * kt2;
}
template inline void _bj_set_jetinfo(
J * const jetA, const int _jets_index) const {
jetA->eta = _jets[_jets_index].rap();
jetA->phi = _jets[_jets_index].phi_02pi();
jetA->kt2 = _cs.jet_scale_for_algorithm(_jets[_jets_index]);
jetA->_jets_index = _jets_index;
jetA->NN_dist = _R2;
jetA->NN = NULL;
}
template inline double _bj_dist(
const J * const jetA, const J * const jetB)
#ifdef INSTRUMENT2
{
_ncall++; // GPS tmp
#else
const {
#endif
double dphi = std::abs(jetA->phi - jetB->phi);
double deta = (jetA->eta - jetB->eta);
if (dphi > pi) {dphi = twopi - dphi;}
return dphi*dphi + deta*deta;
}
template inline double _bj_dist_not_periodic(
const J * const jetA, const J * const jetB)
#ifdef INSTRUMENT2
{
_ncall++; // GPS tmp
#else
const {
#endif
double dphi = jetA->phi - jetB->phi;
double deta = (jetA->eta - jetB->eta);
return dphi*dphi + deta*deta;
}
};
FJCORE_END_NAMESPACE
#endif // __FJCORE_LAZYTILING25_HH__
#ifndef __FJCORE_TILINGEXTENT_HH__
#define __FJCORE_TILINGEXTENT_HH__
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
class TilingExtent {
public:
TilingExtent(ClusterSequence & cs);
TilingExtent(const std::vector &particles);
double minrap() const {return _minrap;}
double maxrap() const {return _maxrap;}
double sum_of_binned_squared_multiplicity() const {return _cumul2;}
private:
double _minrap, _maxrap, _cumul2;
void _determine_rapidity_extent(const std::vector & particles);
};
FJCORE_END_NAMESPACE // defined in fastjet/internal/base.hh
#endif // __FJCORE_TILINGEXTENT_HH__
#include
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
const unsigned int twopow31 = 2147483648U;
using namespace std;
void ClosestPair2D::_point2shuffle(Point & point, Shuffle & shuffle,
unsigned int shift) {
Coord2D renorm_point = (point.coord - _left_corner)/_range;
assert(renorm_point.x >=0);
assert(renorm_point.x <=1);
assert(renorm_point.y >=0);
assert(renorm_point.y <=1);
shuffle.x = static_cast(twopow31 * renorm_point.x) + shift;
shuffle.y = static_cast(twopow31 * renorm_point.y) + shift;
shuffle.point = &point;
}
bool ClosestPair2D::Shuffle::operator<(const Shuffle & q) const {
if (floor_ln2_less(x ^ q.x, y ^ q.y)) {
return (y < q.y);
} else {
return (x < q.x);
}
}
void ClosestPair2D::_initialize(const std::vector & positions,
const Coord2D & left_corner,
const Coord2D & right_corner,
unsigned int max_size) {
unsigned int n_positions = positions.size();
assert(max_size >= n_positions);
_points.resize(max_size);
for (unsigned int i = n_positions; i < max_size; i++) {
_available_points.push(&(_points[i]));
}
_left_corner = left_corner;
_range = max((right_corner.x - left_corner.x),
(right_corner.y - left_corner.y));
vector shuffles(n_positions);
for (unsigned int i = 0; i < n_positions; i++) {
_points[i].coord = positions[i];
_points[i].neighbour_dist2 = numeric_limits::max();
_points[i].review_flag = 0;
_point2shuffle(_points[i], shuffles[i], 0);
}
for (unsigned ishift = 0; ishift < _nshift; ishift++) {
_shifts[ishift] = static_cast(((twopow31*1.0)*ishift)/_nshift);
if (ishift == 0) {_rel_shifts[ishift] = 0;}
else {_rel_shifts[ishift] = _shifts[ishift] - _shifts[ishift-1];}
}
_cp_search_range = 30;
_points_under_review.reserve(_nshift * _cp_search_range);
for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
if (ishift > 0) {
unsigned rel_shift = _rel_shifts[ishift];
for (unsigned int i = 0; i < shuffles.size(); i++) {
shuffles[i] += rel_shift; }
}
sort(shuffles.begin(), shuffles.end());
_trees[ishift] = SharedPtr(new Tree(shuffles, max_size));
circulator circ = _trees[ishift]->somewhere(), start=circ;
unsigned int CP_range = min(_cp_search_range, n_positions-1);
do {
Point * this_point = circ->point;
this_point->circ[ishift] = circ;
circulator other = circ;
for (unsigned i=0; i < CP_range; i++) {
++other;
double dist2 = this_point->distance2(*other->point);
if (dist2 < this_point->neighbour_dist2) {
this_point->neighbour_dist2 = dist2;
this_point->neighbour = other->point;
}
}
} while (++circ != start);
}
vector mindists2(n_positions);
for (unsigned int i = 0; i < n_positions; i++) {
mindists2[i] = _points[i].neighbour_dist2;}
_heap = SharedPtr(new MinHeap(mindists2, max_size));
}
void ClosestPair2D::closest_pair(unsigned int & ID1, unsigned int & ID2,
double & distance2) const {
ID1 = _heap->minloc();
ID2 = _ID(_points[ID1].neighbour);
distance2 = _points[ID1].neighbour_dist2;
if (ID1 > ID2) std::swap(ID1,ID2);
}
inline void ClosestPair2D::_add_label(Point * point, unsigned int review_flag) {
if (point->review_flag == 0) _points_under_review.push_back(point);
point->review_flag |= review_flag;
}
inline void ClosestPair2D::_set_label(Point * point, unsigned int review_flag) {
if (point->review_flag == 0) _points_under_review.push_back(point);
point->review_flag = review_flag;
}
void ClosestPair2D::remove(unsigned int ID) {
Point * point_to_remove = & (_points[ID]);
_remove_from_search_tree(point_to_remove);
_deal_with_points_to_review();
}
void ClosestPair2D::_remove_from_search_tree(Point * point_to_remove) {
_available_points.push(point_to_remove);
_set_label(point_to_remove, _remove_heap_entry);
unsigned int CP_range = min(_cp_search_range, size()-1);
for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
circulator removed_circ = point_to_remove->circ[ishift];
circulator right_end = removed_circ.next();
_trees[ishift]->remove(removed_circ);
circulator left_end = right_end, orig_right_end = right_end;
for (unsigned int i = 0; i < CP_range; i++) {left_end--;}
if (size()-1 < _cp_search_range) {
left_end--; right_end--;
}
do {
Point * left_point = left_end->point;
if (left_point->neighbour == point_to_remove) {
// we'll deal with it later...
_add_label(left_point, _review_neighbour);
} else {
// check to see if right point has become its closest neighbour
double dist2 = left_point->distance2(*right_end->point);
if (dist2 < left_point->neighbour_dist2) {
left_point->neighbour = right_end->point;
left_point->neighbour_dist2 = dist2;
// NB: (LESSER) REVIEW NEEDED HERE TOO...
_add_label(left_point, _review_heap_entry);
}
}
++right_end;
} while (++left_end != orig_right_end);
} // ishift...
}
void ClosestPair2D::_deal_with_points_to_review() {
unsigned int CP_range = min(_cp_search_range, size()-1);
while(_points_under_review.size() > 0) {
Point * this_point = _points_under_review.back();
_points_under_review.pop_back();
if (this_point->review_flag & _remove_heap_entry) {
assert(!(this_point->review_flag ^ _remove_heap_entry));
_heap->remove(_ID(this_point));
}
else {
if (this_point->review_flag & _review_neighbour) {
this_point->neighbour_dist2 = numeric_limits::max();
// among all three shifts
for (unsigned int ishift = 0; ishift < _nshift; ishift++) {
circulator other = this_point->circ[ishift];
// among points within CP_range
for (unsigned i=0; i < CP_range; i++) {
++other;
double dist2 = this_point->distance2(*other->point);
if (dist2 < this_point->neighbour_dist2) {
this_point->neighbour_dist2 = dist2;
this_point->neighbour = other->point;
}
}
}
}
_heap->update(_ID(this_point), this_point->neighbour_dist2);
}
this_point->review_flag = 0;
}
}
unsigned int ClosestPair2D::insert(const Coord2D & new_coord) {
assert(_available_points.size() > 0);
Point * new_point = _available_points.top();
_available_points.pop();
new_point->coord = new_coord;
_insert_into_search_tree(new_point);
_deal_with_points_to_review();
return _ID(new_point);
}
unsigned int ClosestPair2D::replace(unsigned int ID1, unsigned int ID2,
const Coord2D & position) {
Point * point_to_remove = & (_points[ID1]);
_remove_from_search_tree(point_to_remove);
point_to_remove = & (_points[ID2]);
_remove_from_search_tree(point_to_remove);
Point * new_point = _available_points.top();
_available_points.pop();
new_point->coord = position;
_insert_into_search_tree(new_point);
_deal_with_points_to_review();
return _ID(new_point);
}
void ClosestPair2D::replace_many(
const std::vector & IDs_to_remove,
const std::vector & new_positions,
std::vector & new_IDs) {
for (unsigned int i = 0; i < IDs_to_remove.size(); i++) {
_remove_from_search_tree(& (_points[IDs_to_remove[i]]));
}
new_IDs.resize(0);
for (unsigned int i = 0; i < new_positions.size(); i++) {
Point * new_point = _available_points.top();
_available_points.pop();
new_point->coord = new_positions[i];
_insert_into_search_tree(new_point);
new_IDs.push_back(_ID(new_point));
}
_deal_with_points_to_review();
}
void ClosestPair2D::_insert_into_search_tree(Point * new_point) {
_set_label(new_point, _review_heap_entry);
new_point->neighbour_dist2 = numeric_limits::max();
unsigned int CP_range = min(_cp_search_range, size()-1);
for (unsigned ishift = 0; ishift < _nshift; ishift++) {
Shuffle new_shuffle;
_point2shuffle(*new_point, new_shuffle, _shifts[ishift]);
circulator new_circ = _trees[ishift]->insert(new_shuffle);
new_point->circ[ishift] = new_circ;
circulator right_edge = new_circ; right_edge++;
circulator left_edge = new_circ;
for (unsigned int i = 0; i < CP_range; i++) {left_edge--;}
do {
Point * left_point = left_edge->point;
Point * right_point = right_edge->point;
double new_dist2 = left_point->distance2(*new_point);
if (new_dist2 < left_point->neighbour_dist2) {
left_point->neighbour_dist2 = new_dist2;
left_point->neighbour = new_point;
_add_label(left_point, _review_heap_entry);
}
new_dist2 = new_point->distance2(*right_point);
if (new_dist2 < new_point->neighbour_dist2) {
new_point->neighbour_dist2 = new_dist2;
new_point->neighbour = right_point;
}
if (left_point->neighbour == right_point) {
_add_label(left_point, _review_neighbour);
}
right_edge++;
} while (++left_edge != new_circ);
}
}
FJCORE_END_NAMESPACE
#include
#include
#include
#include
#include
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
using namespace std;
std::ostream * ClusterSequence::_fastjet_banner_ostr = &cout;
ClusterSequence::~ClusterSequence () {
if (_structure_shared_ptr){
ClusterSequenceStructure* csi = dynamic_cast(_structure_shared_ptr.get());
assert(csi != NULL);
csi->set_associated_cs(NULL);
if (_deletes_self_when_unused) {
_structure_shared_ptr.set_count(_structure_shared_ptr.use_count()
+ _structure_use_count_after_construction);
}
}
}
void ClusterSequence::signal_imminent_self_deletion() const {
assert(_deletes_self_when_unused);
_deletes_self_when_unused = false;
}
void ClusterSequence::_initialise_and_run (
const JetDefinition & jet_def_in,
const bool & writeout_combinations) {
_decant_options(jet_def_in, writeout_combinations);
_initialise_and_run_no_decant();
}
void ClusterSequence::_initialise_and_run_no_decant () {
_fill_initial_history();
if (n_particles() == 0) return;
if (_jet_algorithm == plugin_algorithm) {
_plugin_activated = true;
_jet_def.plugin()->run_clustering( (*this) );
_plugin_activated = false;
_update_structure_use_count();
return;
} else if (_jet_algorithm == ee_kt_algorithm ||
_jet_algorithm == ee_genkt_algorithm) {
_strategy = N2Plain;
if (_jet_algorithm == ee_kt_algorithm) {
assert(_Rparam > 2.0);
_invR2 = 1.0;
} else {
if (_Rparam > pi) {
// choose a value that ensures that back-to-back particles will
// always recombine
//_R2 = 4.0000000000001;
_R2 = 2 * ( 3.0 + cos(_Rparam) );
} else {
_R2 = 2 * ( 1.0 - cos(_Rparam) );
}
_invR2 = 1.0/_R2;
}
_simple_N2_cluster_EEBriefJet();
return;
} else if (_jet_algorithm == undefined_jet_algorithm) {
throw Error("A ClusterSequence cannot be created with an uninitialised JetDefinition");
}
if (_strategy == Best) {
_strategy = _best_strategy();
#ifdef __FJCORE_DROP_CGAL
if (_strategy == NlnN) _strategy = N2MHTLazy25;
#endif // __FJCORE_DROP_CGAL
} else if (_strategy == BestFJ30) {
int N = _jets.size();
if (min(1.0,max(0.1,_Rparam)*3.3)*N <= 30) {
_strategy = N2Plain;
} else if (N > 6200/pow(_Rparam,2.0) && _jet_def.jet_algorithm() == cambridge_algorithm) {
_strategy = NlnNCam;
#ifndef __FJCORE_DROP_CGAL
} else if ((N > 16000/pow(_Rparam,1.15) && _jet_def.jet_algorithm() != antikt_algorithm)
|| N > 35000/pow(_Rparam,1.15)) {
_strategy = NlnN;
#endif // __FJCORE_DROP_CGAL
} else if (N <= 450) {
_strategy = N2Tiled;
} else {
_strategy = N2MinHeapTiled;
}
}
if (_Rparam >= twopi) {
if ( _strategy == NlnN
|| _strategy == NlnN3pi
|| _strategy == NlnNCam
|| _strategy == NlnNCam2pi2R
|| _strategy == NlnNCam4pi) {
#ifdef __FJCORE_DROP_CGAL
_strategy = N2MinHeapTiled;
#else
_strategy = NlnN4pi;
#endif
}
if (_jet_def.strategy() != Best && _strategy != _jet_def.strategy()) {
ostringstream oss;
oss << "Cluster strategy " << strategy_string(_jet_def.strategy())
<< " automatically changed to " << strategy_string()
<< " because the former is not supported for R = " << _Rparam
<< " >= 2pi";
_changed_strategy_warning.warn(oss.str());
}
}
if (_strategy == N2Plain) {
this->_simple_N2_cluster_BriefJet();
} else if (_strategy == N2Tiled) {
this->_faster_tiled_N2_cluster();
} else if (_strategy == N2MinHeapTiled) {
this->_minheap_faster_tiled_N2_cluster();
} else if (_strategy == N2MHTLazy9Alt) {
_plugin_activated = true;
LazyTiling9Alt tiling(*this);
tiling.run();
_plugin_activated = false;
} else if (_strategy == N2MHTLazy25) {
_plugin_activated = true;
LazyTiling25 tiling(*this);
tiling.run();
_plugin_activated = false;
} else if (_strategy == N2MHTLazy9) {
_plugin_activated = true;
LazyTiling9 tiling(*this);
tiling.run();
_plugin_activated = false;
} else if (_strategy == N2MHTLazy9AntiKtSeparateGhosts) {
throw Error("N2MHTLazy9AntiKtSeparateGhosts strategy not supported with FJCORE");
} else if (_strategy == NlnN) {
this->_delaunay_cluster();
} else if (_strategy == NlnNCam) {
this->_CP2DChan_cluster_2piMultD();
} else if (_strategy == NlnN3pi || _strategy == NlnN4pi ) {
this->_delaunay_cluster();
} else if (_strategy == N3Dumb ) {
this->_really_dumb_cluster();
} else if (_strategy == N2PoorTiled) {
this->_tiled_N2_cluster();
} else if (_strategy == NlnNCam4pi) {
this->_CP2DChan_cluster();
} else if (_strategy == NlnNCam2pi2R) {
this->_CP2DChan_cluster_2pi2R();
} else {
ostringstream err;
err << "Unrecognised value for strategy: "<<_strategy;
throw Error(err.str());
}
}
bool ClusterSequence::_first_time = true;
LimitedWarning ClusterSequence::_exclusive_warnings;
string fastjet_version_string() {
return "FastJet version "+string(fastjet_version)+" [fjcore]";
}
void ClusterSequence::print_banner() {
if (!_first_time) {return;}
_first_time = false;
ostream * ostr = _fastjet_banner_ostr;
if (!ostr) return;
(*ostr) << "#--------------------------------------------------------------------------\n";
(*ostr) << "# FastJet release " << fastjet_version << " [fjcore]" << endl;
(*ostr) << "# M. Cacciari, G.P. Salam and G. Soyez \n";
(*ostr) << "# A software package for jet finding and analysis at colliders \n";
(*ostr) << "# http://fastjet.fr \n";
(*ostr) << "# \n";
(*ostr) << "# Please cite EPJC72(2012)1896 [arXiv:1111.6097] if you use this package\n";
(*ostr) << "# for scientific work and optionally PLB641(2006)57 [hep-ph/0512210]. \n";
(*ostr) << "# \n";
(*ostr) << "# FastJet is provided without warranty under the terms of the GNU GPLv2.\n";
(*ostr) << "# It uses T. Chan's closest pair algorithm, S. Fortune's Voronoi code";
#ifndef __FJCORE_DROP_CGAL
(*ostr) << ",\n# CGAL ";
#else
(*ostr) << "\n# ";
#endif // __FJCORE_DROP_CGAL
(*ostr) << "and 3rd party plugin jet algorithms. See COPYING file for details.\n";
(*ostr) << "#--------------------------------------------------------------------------\n";
ostr->flush();
}
void ClusterSequence::_decant_options(const JetDefinition & jet_def_in,
const bool & writeout_combinations) {
_jet_def = jet_def_in;
_writeout_combinations = writeout_combinations;
_structure_shared_ptr.reset(new ClusterSequenceStructure(this));
_decant_options_partial();
}
void ClusterSequence::_decant_options_partial() {
print_banner();
_jet_algorithm = _jet_def.jet_algorithm();
_Rparam = _jet_def.R(); _R2 = _Rparam*_Rparam; _invR2 = 1.0/_R2;
_strategy = _jet_def.strategy();
_plugin_activated = false;
_update_structure_use_count(); // make sure it's correct already here
}
void ClusterSequence::_fill_initial_history () {
_jets.reserve(_jets.size()*2);
_history.reserve(_jets.size()*2);
_Qtot = 0;
for (int i = 0; i < static_cast(_jets.size()) ; i++) {
history_element element;
element.parent1 = InexistentParent;
element.parent2 = InexistentParent;
element.child = Invalid;
element.jetp_index = i;
element.dij = 0.0;
element.max_dij_so_far = 0.0;
_history.push_back(element);
_jet_def.recombiner()->preprocess(_jets[i]);
_jets[i].set_cluster_hist_index(i);
_set_structure_shared_ptr(_jets[i]);
_Qtot += _jets[i].E();
}
_initial_n = _jets.size();
_deletes_self_when_unused = false;
}
string ClusterSequence::strategy_string (Strategy strategy_in) const {
string strategy;
switch(strategy_in) {
case NlnN:
strategy = "NlnN"; break;
case NlnN3pi:
strategy = "NlnN3pi"; break;
case NlnN4pi:
strategy = "NlnN4pi"; break;
case N2Plain:
strategy = "N2Plain"; break;
case N2Tiled:
strategy = "N2Tiled"; break;
case N2MinHeapTiled:
strategy = "N2MinHeapTiled"; break;
case N2PoorTiled:
strategy = "N2PoorTiled"; break;
case N2MHTLazy9:
strategy = "N2MHTLazy9"; break;
case N2MHTLazy9Alt:
strategy = "N2MHTLazy9Alt"; break;
case N2MHTLazy25:
strategy = "N2MHTLazy25"; break;
case N2MHTLazy9AntiKtSeparateGhosts:
strategy = "N2MHTLazy9AntiKtSeparateGhosts"; break;
case N3Dumb:
strategy = "N3Dumb"; break;
case NlnNCam4pi:
strategy = "NlnNCam4pi"; break;
case NlnNCam2pi2R:
strategy = "NlnNCam2pi2R"; break;
case NlnNCam:
strategy = "NlnNCam"; break; // 2piMultD
case plugin_strategy:
strategy = "plugin strategy"; break;
default:
strategy = "Unrecognized";
}
return strategy;
}
double ClusterSequence::jet_scale_for_algorithm(
const PseudoJet & jet) const {
if (_jet_algorithm == kt_algorithm) {return jet.kt2();}
else if (_jet_algorithm == cambridge_algorithm) {return 1.0;}
else if (_jet_algorithm == antikt_algorithm) {
double kt2=jet.kt2();
return kt2 > 1e-300 ? 1.0/kt2 : 1e300;
} else if (_jet_algorithm == genkt_algorithm) {
double kt2 = jet.kt2();
double p = jet_def().extra_param();
if (p <= 0 && kt2 < 1e-300) kt2 = 1e-300; // dodgy safety check
return pow(kt2, p);
} else if (_jet_algorithm == cambridge_for_passive_algorithm) {
double kt2 = jet.kt2();
double lim = _jet_def.extra_param();
if (kt2 < lim*lim && kt2 != 0.0) {
return 1.0/kt2;
} else {return 1.0;}
} else {throw Error("Unrecognised jet algorithm");}
}
Strategy ClusterSequence::_best_strategy() const {
int N = _jets.size();
double bounded_R = max(_Rparam, 0.1);
if (N <= 30 || N <= 39.0/(bounded_R + 0.6)) {
return N2Plain;
}
const static _Parabola N_Tiled_to_MHT_lowR (-45.4947,54.3528,44.6283);
const static _Parabola L_MHT_to_MHTLazy9_lowR (0.677807,-1.05006,10.6994);
const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_lowR(0.169967,-0.512589,12.1572);
const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_lowR (0.16237,-0.484612,12.3373);
const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_lowR = L_MHTLazy9_to_MHTLazy25_kt_lowR;
const static _Parabola L_MHTLazy25_to_NlnN_akt_lowR (0.0472051,-0.22043,15.9196);
const static _Parabola L_MHTLazy25_to_NlnN_kt_lowR (0.118609,-0.326811,14.8287);
const static _Parabola L_MHTLazy25_to_NlnN_cam_lowR (0.10119,-0.295748,14.3924);
const static _Line L_Tiled_to_MHTLazy9_medR (-1.31304,7.29621);
const static _Parabola L_MHTLazy9_to_MHTLazy25_akt_medR = L_MHTLazy9_to_MHTLazy25_akt_lowR;
const static _Parabola L_MHTLazy9_to_MHTLazy25_kt_medR = L_MHTLazy9_to_MHTLazy25_kt_lowR;
const static _Parabola L_MHTLazy9_to_MHTLazy25_cam_medR = L_MHTLazy9_to_MHTLazy25_cam_lowR;
const static _Parabola L_MHTLazy25_to_NlnN_akt_medR = L_MHTLazy25_to_NlnN_akt_lowR;
const static _Parabola L_MHTLazy25_to_NlnN_kt_medR = L_MHTLazy25_to_NlnN_kt_lowR;
const static _Parabola L_MHTLazy25_to_NlnN_cam_medR = L_MHTLazy25_to_NlnN_cam_lowR;
const static double N_Plain_to_MHTLazy9_largeR = 75;
const static double N_MHTLazy9_to_MHTLazy25_akt_largeR = 700;
const static double N_MHTLazy9_to_MHTLazy25_kt_largeR = 1000;
const static double N_MHTLazy9_to_MHTLazy25_cam_largeR = 1000;
const static double N_MHTLazy25_to_NlnN_akt_largeR = 100000;
const static double N_MHTLazy25_to_NlnN_kt_largeR = 40000;
const static double N_MHTLazy25_to_NlnN_cam_largeR = 15000;
JetAlgorithm jet_algorithm;
if (_jet_algorithm == genkt_algorithm) {
double p = jet_def().extra_param();
if (p < 0.0) jet_algorithm = antikt_algorithm;
else jet_algorithm = kt_algorithm;
} else if (_jet_algorithm == cambridge_for_passive_algorithm) {
jet_algorithm = kt_algorithm;
} else {
jet_algorithm = _jet_algorithm;
}
if (bounded_R < 0.65) {
if (N < N_Tiled_to_MHT_lowR(bounded_R)) return N2Tiled;
double logN = log(double(N));
if (logN < L_MHT_to_MHTLazy9_lowR(bounded_R)) return N2MinHeapTiled;
else {
if (jet_algorithm == antikt_algorithm){
if (logN < L_MHTLazy9_to_MHTLazy25_akt_lowR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_akt_lowR(bounded_R)) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == kt_algorithm){
if (logN < L_MHTLazy9_to_MHTLazy25_kt_lowR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_kt_lowR(bounded_R)) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == cambridge_algorithm) {
if (logN < L_MHTLazy9_to_MHTLazy25_cam_lowR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_cam_lowR(bounded_R)) return N2MHTLazy25;
else return NlnNCam;
}
}
} else if (bounded_R < 0.5*pi) {
double logN = log(double(N));
if (logN < L_Tiled_to_MHTLazy9_medR(bounded_R)) return N2Tiled;
else {
if (jet_algorithm == antikt_algorithm){
if (logN < L_MHTLazy9_to_MHTLazy25_akt_medR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_akt_medR(bounded_R)) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == kt_algorithm){
if (logN < L_MHTLazy9_to_MHTLazy25_kt_medR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_kt_medR(bounded_R)) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == cambridge_algorithm) {
if (logN < L_MHTLazy9_to_MHTLazy25_cam_medR(bounded_R)) return N2MHTLazy9;
else if (logN < L_MHTLazy25_to_NlnN_cam_medR(bounded_R)) return N2MHTLazy25;
else return NlnNCam;
}
}
} else {
if (N < N_Plain_to_MHTLazy9_largeR) return N2Plain;
else {
if (jet_algorithm == antikt_algorithm){
if (N < N_MHTLazy9_to_MHTLazy25_akt_largeR) return N2MHTLazy9;
else if (N < N_MHTLazy25_to_NlnN_akt_largeR) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == kt_algorithm){
if (N < N_MHTLazy9_to_MHTLazy25_kt_largeR) return N2MHTLazy9;
else if (N < N_MHTLazy25_to_NlnN_kt_largeR) return N2MHTLazy25;
else return NlnN;
} else if (jet_algorithm == cambridge_algorithm) {
if (N < N_MHTLazy9_to_MHTLazy25_cam_largeR) return N2MHTLazy9;
else if (N < N_MHTLazy25_to_NlnN_cam_largeR) return N2MHTLazy25;
else return NlnNCam;
}
}
}
assert(0 && "Code should never reach here");
return N2MHTLazy9;
}
ClusterSequence & ClusterSequence::operator=(const ClusterSequence & cs) {
if (&cs != this) {
_deletes_self_when_unused = false;
transfer_from_sequence(cs);
}
return *this;
}
void ClusterSequence::transfer_from_sequence(const ClusterSequence & from_seq,
const FunctionOfPseudoJet * action_on_jets){
if (will_delete_self_when_unused())
throw(Error("cannot use CS::transfer_from_sequence after a call to delete_self_when_unused()"));
_jet_def = from_seq._jet_def ;
_writeout_combinations = from_seq._writeout_combinations ;
_initial_n = from_seq._initial_n ;
_Rparam = from_seq._Rparam ;
_R2 = from_seq._R2 ;
_invR2 = from_seq._invR2 ;
_strategy = from_seq._strategy ;
_jet_algorithm = from_seq._jet_algorithm ;
_plugin_activated = from_seq._plugin_activated ;
if (action_on_jets)
_jets = (*action_on_jets)(from_seq._jets);
else
_jets = from_seq._jets;
_history = from_seq._history;
_extras = from_seq._extras;
if (_structure_shared_ptr) {
if (_deletes_self_when_unused) throw Error("transfer_from_sequence cannot be used for a cluster sequence that deletes self when unused");
ClusterSequenceStructure* csi = dynamic_cast(_structure_shared_ptr.get());
assert(csi != NULL);
csi->set_associated_cs(NULL);
}
_structure_shared_ptr.reset(new ClusterSequenceStructure(this));
_update_structure_use_count();
for (unsigned int i=0; i<_jets.size(); i++){
_jets[i].set_cluster_hist_index(from_seq._jets[i].cluster_hist_index());
_set_structure_shared_ptr(_jets[i]);
}
}
void ClusterSequence::plugin_record_ij_recombination(
int jet_i, int jet_j, double dij,
const PseudoJet & newjet, int & newjet_k) {
plugin_record_ij_recombination(jet_i, jet_j, dij, newjet_k);
int tmp_index = _jets[newjet_k].cluster_hist_index();
_jets[newjet_k] = newjet;
_jets[newjet_k].set_cluster_hist_index(tmp_index);
_set_structure_shared_ptr(_jets[newjet_k]);
}
vector ClusterSequence::inclusive_jets (const double ptmin) const{
double dcut = ptmin*ptmin;
int i = _history.size() - 1; // last jet
vector jets_local;
if (_jet_algorithm == kt_algorithm) {
while (i >= 0) {
if (_history[i].max_dij_so_far < dcut) {break;}
if (_history[i].parent2 == BeamJet && _history[i].dij >= dcut) {
// for beam jets
int parent1 = _history[i].parent1;
jets_local.push_back(_jets[_history[parent1].jetp_index]);}
i--;
}
} else if (_jet_algorithm == cambridge_algorithm) {
while (i >= 0) {
if (_history[i].parent2 != BeamJet) {break;}
int parent1 = _history[i].parent1;
const PseudoJet & jet = _jets[_history[parent1].jetp_index];
if (jet.perp2() >= dcut) {jets_local.push_back(jet);}
i--;
}
} else if (_jet_algorithm == plugin_algorithm
|| _jet_algorithm == ee_kt_algorithm
|| _jet_algorithm == antikt_algorithm
|| _jet_algorithm == genkt_algorithm
|| _jet_algorithm == ee_genkt_algorithm
|| _jet_algorithm == cambridge_for_passive_algorithm) {
while (i >= 0) {
if (_history[i].parent2 == BeamJet) {
int parent1 = _history[i].parent1;
const PseudoJet & jet = _jets[_history[parent1].jetp_index];
if (jet.perp2() >= dcut) {jets_local.push_back(jet);}
}
i--;
}
} else {throw Error("cs::inclusive_jets(...): Unrecognized jet algorithm");}
return jets_local;
}
int ClusterSequence::n_exclusive_jets (const double dcut) const {
int i = _history.size() - 1; // last jet
while (i >= 0) {
if (_history[i].max_dij_so_far <= dcut) {break;}
i--;
}
int stop_point = i + 1;
int njets = 2*_initial_n - stop_point;
return njets;
}
vector ClusterSequence::exclusive_jets (const double dcut) const {
int njets = n_exclusive_jets(dcut);
return exclusive_jets(njets);
}
vector ClusterSequence::exclusive_jets (const int njets) const {
if (njets > _initial_n) {
ostringstream err;
err << "Requested " << njets << " exclusive jets, but there were only "
<< _initial_n << " particles in the event";
throw Error(err.str());
}
return exclusive_jets_up_to(njets);
}
vector ClusterSequence::exclusive_jets_up_to (const int njets) const {
if (( _jet_def.jet_algorithm() != kt_algorithm) &&
( _jet_def.jet_algorithm() != cambridge_algorithm) &&
( _jet_def.jet_algorithm() != ee_kt_algorithm) &&
(((_jet_def.jet_algorithm() != genkt_algorithm) &&
(_jet_def.jet_algorithm() != ee_genkt_algorithm)) ||
(_jet_def.extra_param() <0)) &&
((_jet_def.jet_algorithm() != plugin_algorithm) ||
(!_jet_def.plugin()->exclusive_sequence_meaningful()))) {
_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.");
}
int stop_point = 2*_initial_n - njets;
if (stop_point < _initial_n) stop_point = _initial_n;
if (2*_initial_n != static_cast(_history.size())) {
ostringstream err;
err << "2*_initial_n != _history.size() -- this endangers internal assumptions!\n";
throw Error(err.str());
}
vector jets_local;
for (unsigned int i = stop_point; i < _history.size(); i++) {
int parent1 = _history[i].parent1;
if (parent1 < stop_point) {
jets_local.push_back(_jets[_history[parent1].jetp_index]);
}
int parent2 = _history[i].parent2;
if (parent2 < stop_point && parent2 > 0) {
jets_local.push_back(_jets[_history[parent2].jetp_index]);
}
}
if (int(jets_local.size()) != min(_initial_n, njets)) {
ostringstream err;
err << "ClusterSequence::exclusive_jets: size of returned vector ("
<= 0);
if (njets >= _initial_n) {return 0.0;}
return _history[2*_initial_n-njets-1].dij;
}
double ClusterSequence::exclusive_dmerge_max (const int njets) const {
assert(njets >= 0);
if (njets >= _initial_n) {return 0.0;}
return _history[2*_initial_n-njets-1].max_dij_so_far;
}
std::vector ClusterSequence::exclusive_subjets
(const PseudoJet & jet, const double dcut) const {
set subhist;
get_subhist_set(subhist, jet, dcut, 0);
vector subjets;
subjets.reserve(subhist.size());
for (set::iterator elem = subhist.begin();
elem != subhist.end(); elem++) {
subjets.push_back(_jets[(*elem)->jetp_index]);
}
return subjets;
}
int ClusterSequence::n_exclusive_subjets(const PseudoJet & jet,
const double dcut) const {
set subhist;
get_subhist_set(subhist, jet, dcut, 0);
return subhist.size();
}
std::vector ClusterSequence::exclusive_subjets
(const PseudoJet & jet, int nsub) const {
vector subjets = exclusive_subjets_up_to(jet, nsub);
if (int(subjets.size()) < nsub) {
ostringstream err;
err << "Requested " << nsub << " exclusive subjets, but there were only "
<< subjets.size() << " particles in the jet";
throw Error(err.str());
}
return subjets;
}
std::vector ClusterSequence::exclusive_subjets_up_to
(const PseudoJet & jet, int nsub) const {
set subhist;
vector subjets;
if (nsub < 0) throw Error("Requested a negative number of subjets. This is nonsensical.");
if (nsub == 0) return subjets;
get_subhist_set(subhist, jet, -1.0, nsub);
subjets.reserve(subhist.size());
for (set::iterator elem = subhist.begin();
elem != subhist.end(); elem++) {
subjets.push_back(_jets[(*elem)->jetp_index]);
}
return subjets;
}
double ClusterSequence::exclusive_subdmerge(const PseudoJet & jet, int nsub) const {
set subhist;
get_subhist_set(subhist, jet, -1.0, nsub);
set::iterator highest = subhist.end();
highest--;
return (*highest)->dij;
}
double ClusterSequence::exclusive_subdmerge_max(const PseudoJet & jet, int nsub) const {
set subhist;
get_subhist_set(subhist, jet, -1.0, nsub);
set::iterator highest = subhist.end();
highest--;
return (*highest)->max_dij_so_far;
}
void ClusterSequence::get_subhist_set(set & subhist,
const PseudoJet & jet,
double dcut, int maxjet) const {
assert(contains(jet));
subhist.clear();
subhist.insert(&(_history[jet.cluster_hist_index()]));
int njet = 1;
while (true) {
set::iterator highest = subhist.end();
assert (highest != subhist.begin());
highest--;
const history_element* elem = *highest;
if (njet == maxjet) break;
if (elem->parent1 < 0) break;
if (elem->max_dij_so_far <= dcut) break;
subhist.erase(highest);
subhist.insert(&(_history[elem->parent1]));
subhist.insert(&(_history[elem->parent2]));
njet++;
}
}
bool ClusterSequence::object_in_jet(const PseudoJet & object,
const PseudoJet & jet) const {
assert(contains(object) && contains(jet));
const PseudoJet * this_object = &object;
const PseudoJet * childp;
while(true) {
if (this_object->cluster_hist_index() == jet.cluster_hist_index()) {
return true;
} else if (has_child(*this_object, childp)) {
this_object = childp;
} else {
return false;
}
}
}
bool ClusterSequence::has_parents(const PseudoJet & jet, PseudoJet & parent1,
PseudoJet & parent2) const {
const history_element & hist = _history[jet.cluster_hist_index()];
assert ((hist.parent1 >= 0 && hist.parent2 >= 0) ||
(hist.parent1 < 0 && hist.parent2 < 0));
if (hist.parent1 < 0) {
parent1 = PseudoJet(0.0,0.0,0.0,0.0);
parent2 = parent1;
return false;
} else {
parent1 = _jets[_history[hist.parent1].jetp_index];
parent2 = _jets[_history[hist.parent2].jetp_index];
if (parent1.perp2() < parent2.perp2()) std::swap(parent1,parent2);
return true;
}
}
bool ClusterSequence::has_child(const PseudoJet & jet, PseudoJet & child) const {
const PseudoJet * childp;
bool res = has_child(jet, childp);
if (res) {
child = *childp;
return true;
} else {
child = PseudoJet(0.0,0.0,0.0,0.0);
return false;
}
}
bool ClusterSequence::has_child(const PseudoJet & jet, const PseudoJet * & childp) const {
const history_element & hist = _history[jet.cluster_hist_index()];
if (hist.child >= 0 && _history[hist.child].jetp_index >= 0) {
childp = &(_jets[_history[hist.child].jetp_index]);
return true;
} else {
childp = NULL;
return false;
}
}
bool ClusterSequence::has_partner(const PseudoJet & jet,
PseudoJet & partner) const {
const history_element & hist = _history[jet.cluster_hist_index()];
if (hist.child >= 0 && _history[hist.child].parent2 >= 0) {
const history_element & child_hist = _history[hist.child];
if (child_hist.parent1 == jet.cluster_hist_index()) {
partner = _jets[_history[child_hist.parent2].jetp_index];
} else {
partner = _jets[_history[child_hist.parent1].jetp_index];
}
return true;
} else {
partner = PseudoJet(0.0,0.0,0.0,0.0);
return false;
}
}
vector ClusterSequence::constituents (const PseudoJet & jet) const {
vector subjets;
add_constituents(jet, subjets);
return subjets;
}
void ClusterSequence::print_jets_for_root(const std::vector & jets_in,
ostream & ostr) const {
for (unsigned i = 0; i < jets_in.size(); i++) {
ostr << i << " "
<< jets_in[i].px() << " "
<< jets_in[i].py() << " "
<< jets_in[i].pz() << " "
<< jets_in[i].E() << endl;
vector cst = constituents(jets_in[i]);
for (unsigned j = 0; j < cst.size() ; j++) {
ostr << " " << j << " "
<< cst[j].rap() << " "
<< cst[j].phi() << " "
<< cst[j].perp() << endl;
}
ostr << "#END" << endl;
}
}
void ClusterSequence::print_jets_for_root(const std::vector & jets_in,
const std::string & filename,
const std::string & comment ) const {
std::ofstream ostr(filename.c_str());
if (comment != "") ostr << "# " << comment << endl;
print_jets_for_root(jets_in, ostr);
}
vector ClusterSequence::particle_jet_indices(
const vector & jets_in) const {
vector indices(n_particles());
for (unsigned ipart = 0; ipart < n_particles(); ipart++)
indices[ipart] = -1;
for (unsigned ijet = 0; ijet < jets_in.size(); ijet++) {
vector jet_constituents(constituents(jets_in[ijet]));
for (unsigned ip = 0; ip < jet_constituents.size(); ip++) {
unsigned iclust = jet_constituents[ip].cluster_hist_index();
unsigned ipart = history()[iclust].jetp_index;
indices[ipart] = ijet;
}
}
return indices;
}
void ClusterSequence::add_constituents (
const PseudoJet & jet, vector & subjet_vector) const {
int i = jet.cluster_hist_index();
int parent1 = _history[i].parent1;
int parent2 = _history[i].parent2;
if (parent1 == InexistentParent) {
subjet_vector.push_back(_jets[i]);
return;
}
add_constituents(_jets[_history[parent1].jetp_index], subjet_vector);
if (parent2 != BeamJet) {
add_constituents(_jets[_history[parent2].jetp_index], subjet_vector);
}
}
void ClusterSequence::_add_step_to_history (
const int parent1,
const int parent2, const int jetp_index,
const double dij) {
history_element element;
element.parent1 = parent1;
element.parent2 = parent2;
element.jetp_index = jetp_index;
element.child = Invalid;
element.dij = dij;
element.max_dij_so_far = max(dij,_history[_history.size()-1].max_dij_so_far);
_history.push_back(element);
int local_step = _history.size()-1;
assert(parent1 >= 0);
if (_history[parent1].child != Invalid){
throw InternalError("trying to recomine an object that has previsously been recombined");
}
_history[parent1].child = local_step;
if (parent2 >= 0) {
if (_history[parent2].child != Invalid){
throw InternalError("trying to recomine an object that has previsously been recombined");
}
_history[parent2].child = local_step;
}
if (jetp_index != Invalid) {
assert(jetp_index >= 0);
_jets[jetp_index].set_cluster_hist_index(local_step);
_set_structure_shared_ptr(_jets[jetp_index]);
}
if (_writeout_combinations) {
cout << local_step << ": "
<< parent1 << " with " << parent2
<< "; y = "<< dij< ClusterSequence::unique_history_order() const {
valarray lowest_constituent(_history.size());
int hist_n = _history.size();
lowest_constituent = hist_n; // give it a large number
for (int i = 0; i < hist_n; i++) {
lowest_constituent[i] = min(lowest_constituent[i],i);
if (_history[i].child > 0) lowest_constituent[_history[i].child]
= min(lowest_constituent[_history[i].child],lowest_constituent[i]);
}
valarray extracted(_history.size()); extracted = false;
vector unique_tree;
unique_tree.reserve(_history.size());
for (unsigned i = 0; i < n_particles(); i++) {
if (!extracted[i]) {
unique_tree.push_back(i);
extracted[i] = true;
_extract_tree_children(i, extracted, lowest_constituent, unique_tree);
}
}
return unique_tree;
}
void ClusterSequence::_extract_tree_children(
int position,
valarray & extracted,
const valarray & lowest_constituent,
vector & unique_tree) const {
if (!extracted[position]) {
_extract_tree_parents(position,extracted,lowest_constituent,unique_tree);
}
int child = _history[position].child;
if (child >= 0) _extract_tree_children(child,extracted,lowest_constituent,unique_tree);
}
vector ClusterSequence::unclustered_particles() const {
vector unclustered;
for (unsigned i = 0; i < n_particles() ; i++) {
if (_history[i].child == Invalid)
unclustered.push_back(_jets[_history[i].jetp_index]);
}
return unclustered;
}
vector ClusterSequence::childless_pseudojets() const {
vector unclustered;
for (unsigned i = 0; i < _history.size() ; i++) {
if ((_history[i].child == Invalid) && (_history[i].parent2 != BeamJet))
unclustered.push_back(_jets[_history[i].jetp_index]);
}
return unclustered;
}
bool ClusterSequence::contains(const PseudoJet & jet) const {
return jet.cluster_hist_index() >= 0
&& jet.cluster_hist_index() < int(_history.size())
&& jet.has_valid_cluster_sequence()
&& jet.associated_cluster_sequence() == this;
}
void ClusterSequence::_extract_tree_parents(
int position,
valarray & extracted,
const valarray & lowest_constituent,
vector & unique_tree) const {
if (!extracted[position]) {
int parent1 = _history[position].parent1;
int parent2 = _history[position].parent2;
if (parent1 >= 0 && parent2 >= 0) {
if (lowest_constituent[parent1] > lowest_constituent[parent2])
std::swap(parent1, parent2);
}
if (parent1 >= 0 && !extracted[parent1])
_extract_tree_parents(parent1,extracted,lowest_constituent,unique_tree);
if (parent2 >= 0 && !extracted[parent2])
_extract_tree_parents(parent2,extracted,lowest_constituent,unique_tree);
unique_tree.push_back(position);
extracted[position] = true;
}
}
void ClusterSequence::_do_ij_recombination_step(
const int jet_i, const int jet_j,
const double dij,
int & newjet_k) {
PseudoJet newjet(false);
_jet_def.recombiner()->recombine(_jets[jet_i], _jets[jet_j], newjet);
_jets.push_back(newjet);
newjet_k = _jets.size()-1;
int newstep_k = _history.size();
_jets[newjet_k].set_cluster_hist_index(newstep_k);
int hist_i = _jets[jet_i].cluster_hist_index();
int hist_j = _jets[jet_j].cluster_hist_index();
_add_step_to_history(min(hist_i, hist_j), max(hist_i,hist_j),
newjet_k, dij);
}
void ClusterSequence::_do_iB_recombination_step(
const int jet_i, const double diB) {
_add_step_to_history(_jets[jet_i].cluster_hist_index(),BeamJet,
Invalid, diB);
}
LimitedWarning ClusterSequence::_changed_strategy_warning;
void ClusterSequence::_set_structure_shared_ptr(PseudoJet & j) {
j.set_structure_shared_ptr(_structure_shared_ptr);
_update_structure_use_count();
}
void ClusterSequence::_update_structure_use_count() {
_structure_use_count_after_construction = _structure_shared_ptr.use_count();
}
void ClusterSequence::delete_self_when_unused() {
int new_count = _structure_shared_ptr.use_count() - _structure_use_count_after_construction;
if (new_count <= 0) {
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");
}
_structure_shared_ptr.set_count(new_count);
_deletes_self_when_unused = true;
}
FJCORE_END_NAMESPACE
#include
#include
#include
#include
FJCORE_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
using namespace std;
namespace Private {
class MirrorInfo{
public:
int orig, mirror;
MirrorInfo(int a, int b) : orig(a), mirror(b) {}
MirrorInfo() : orig(0), mirror(0) {} // set dummy values to keep static code checkers happy
};
bool make_mirror(Coord2D & point, double Dlim) {
if (point.y < Dlim) {point.y += twopi; return true;}
if (twopi-point.y < Dlim) {point.y -= twopi; return true;}
return false;
}
}
using namespace Private;
void ClusterSequence::_CP2DChan_limited_cluster (double Dlim) {
unsigned int n = _initial_n;
vector coordIDs(2*n); // coord IDs of a given jetID
vector jetIDs(2*n); // jet ID for a given coord ID
vector coords(2*n); // our coordinates (and copies)
double Dlim4mirror = min(Dlim,pi);
double minrap = numeric_limits