Page Menu
Home
HEPForge
Search
Configure Global Search
Log In
Files
F7879002
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
35 KB
Subscribers
None
View Options
Index: trunk/siscone/split_merge.cpp
===================================================================
--- trunk/siscone/split_merge.cpp (revision 355)
+++ trunk/siscone/split_merge.cpp (revision 356)
@@ -1,1171 +1,1171 @@
///////////////////////////////////////////////////////////////////////////////
// File: split_merge.cpp //
// Description: source file for splitting/merging (contains the CJet class) //
// This file is part of the SISCone project. //
// For more details, see http://projects.hepforge.org/siscone //
// //
// Copyright (c) 2006 Gavin Salam and Gregory Soyez //
// //
// This program 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. //
// //
// This program 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 this program; if not, write to the Free Software //
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA //
// //
// $Revision:: $//
// $Date:: $//
///////////////////////////////////////////////////////////////////////////////
#include "split_merge.h"
#include "siscone_error.h"
#include "momentum.h"
#include <math.h>
#include <limits> // for max
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cassert>
namespace siscone{
using namespace std;
/********************************************************
* class Cjet implementation *
* real Jet information. *
* This class contains information for one single jet. *
* That is, first, its momentum carrying information *
* about its centre and pT, and second, its particle *
* contents *
********************************************************/
// default ctor
//--------------
Cjet::Cjet(){
n = 0;
v = Cmomentum();
pt_tilde = 0.0;
sm_var2 = 0.0;
}
// default dtor
//--------------
Cjet::~Cjet(){
}
// ordering of jets in pt (e.g. used in final jets ordering)
//-----------------------------------------------------------
bool jets_pt_less(const Cjet &j1, const Cjet &j2){
return j1.v.perp2() > j2.v.perp2();
}
/********************************************************
* Csplit_merge_ptcomparison implementation *
* This deals with the ordering of the jets candidates *
********************************************************/
// odering of two jets
// The variable of the ordering is pt or mt
// depending on 'split_merge_scale' choice
//
// with EPSILON_SPLITMERGE defined, this attempts to identify
// delicate cases where two jets have identical momenta except for
// softish particles -- the difference of pt's may not be correctly
// identified normally and so lead to problems for the fate of the
// softish particle.
//
// NB: there is a potential issue in momentum-conserving events,
// whereby the harder of two jets becomes ill-defined when a soft
// particle is emitted --- this may have a knock-on effect on
// subsequent split-merge steps in cases with sufficiently large R
// (but we don't know what the limit is...)
//------------------------------------------------------------------
bool Csplit_merge_ptcomparison::operator ()(const Cjet &jet1, const Cjet &jet2) const{
double q1, q2;
// compute the value for comparison for both jets
// This depends on the choice of variable (mt is the default)
q1 = jet1.sm_var2;
q2 = jet2.sm_var2;
bool res = q1 > q2;
// if we enable the refined version of the comparison (see defines.h),
// we compute the difference more precisely when the two jets are very
// close in the ordering variable.
#ifdef EPSILON_SPLITMERGE
if ( (fabs(q1-q2) < EPSILON_SPLITMERGE*max(q1,q2)) &&
(jet1.v.ref != jet2.v.ref) ) {
// get the momentum of the difference
Cmomentum difference;
double pt_tilde_difference;
get_difference(jet1,jet2,&difference,&pt_tilde_difference);
// use the following relation: pt1^2 - pt2^2 = (pt1+pt2)*(pt1-pt2)
double qdiff;
Cmomentum sum = jet1.v ;
sum += jet2.v;
double pt_tilde_sum = jet1.pt_tilde + jet2.pt_tilde;
// depending on the choice of ordering variable, set the result
switch (split_merge_scale){
case SM_mt:
qdiff = sum.E*difference.E - sum.pz*difference.pz;
break;
case SM_pt:
qdiff = sum.px*difference.px + sum.py*difference.py;
break;
case SM_pttilde:
qdiff = pt_tilde_sum*pt_tilde_difference;
break;
case SM_Et:
// diff = E^2 (dpt^2 pz^2- pt^2 dpz^2)
// + dE^2 (pt^2+pz^2) pt2^2
// where, unless explicitely specified the variables
// refer to the first jet or differences jet1-jet2.
qdiff = jet1.v.E*jet1.v.E*
((sum.px*difference.px + sum.py*difference.py)*jet1.v.pz*jet1.v.pz
-jet1.v.perp2()*sum.pz*difference.pz)
+sum.E*difference.E*(jet1.v.perp2()+jet1.v.pz*jet1.v.pz)*jet2.v.perp2();
break;
default:
throw Csiscone_error("Unsupported split-merge scale choice: "
+ SM_scale_name());
}
res = qdiff > 0;
}
#endif // EPSILON_SPLITMERGE
return res;
}
/// return a name for the sm scale choice
/// NB: used internally and also by fastjet
std::string split_merge_scale_name(Esplit_merge_scale sms) {
switch(sms) {
case SM_pt:
return "pt (IR unsafe)";
case SM_Et:
return "Et (boost dep.)";
case SM_mt:
return "mt (IR safe except for pairs of identical decayed heavy particles)";
case SM_pttilde:
return "pttilde (scalar sum of pt's)";
default:
return "[SM scale without a name]";
}
}
// get the difference between 2 jets
// - j1 first jet
// - j2 second jet
// - v jet1-jet2
// - pt_tilde jet1-jet2 pt_tilde
// return true if overlapping, false if disjoint
//-----------------------------------------------
void Csplit_merge_ptcomparison::get_difference(const Cjet &j1, const Cjet &j2, Cmomentum *v, double *pt_tilde) const {
int i1,i2;
// initialise
i1=i2=0;
*v = Cmomentum();
*pt_tilde = 0.0;
// compute overlap
// at the same time, we store union in indices
do{
if (j1.contents[i1]==j2.contents[i2]) {
i1++;
i2++;
} else if (j1.contents[i1]<j2.contents[i2]){
(*v) += (*particles)[j1.contents[i1]];
(*pt_tilde) += (*pt)[j1.contents[i1]];
i1++;
} else if (j1.contents[i1]>j2.contents[i2]){
(*v) -= (*particles)[j2.contents[i2]];
(*pt_tilde) -= (*pt)[j2.contents[i2]];
i2++;
} else {
throw Csiscone_error("get_non_overlap reached part it should never have seen...");
}
} while ((i1<j1.n) && (i2<j2.n));
// deal with particles at the end of the list...
while (i1 < j1.n) {
(*v) += (*particles)[j1.contents[i1]];
(*pt_tilde) += (*pt)[j1.contents[i1]];
i1++;
}
while (i2 < j2.n) {
(*v) -= (*particles)[j2.contents[i2]];
(*pt_tilde) -= (*pt)[j2.contents[i2]];
i2++;
}
}
/********************************************************
* class Csplit_merge implementation *
* Class used to split and merge jets. *
********************************************************/
// default ctor
//--------------
Csplit_merge::Csplit_merge(){
merge_identical_protocones = false;
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
#ifdef MERGE_IDENTICAL_PROTOCONES_DEFAULT_TRUE
merge_identical_protocones = true;
#endif
#endif
indices = NULL;
// ensure that ptcomparison points to our set of particles (though params not correct)
ptcomparison.particles = &particles;
ptcomparison.pt = &pt;
candidates.reset(new multiset<Cjet,Csplit_merge_ptcomparison>(ptcomparison));
// no hardest cut (col-unsafe)
SM_var2_hardest_cut_off = -1.0;
// no pt cutoff for the particles to put in p_uncol_hard
stable_cone_soft_pt2_cutoff = -1.0;
// no pt-weighted splitting
use_pt_weighted_splitting = false;
}
// default dtor
//--------------
Csplit_merge::~Csplit_merge(){
full_clear();
}
// initialisation function
// - _particles list of particles
// - protocones list of protocones (initial jet candidates)
// - R2 cone radius (squared)
// - ptmin minimal pT allowed for jets
//-------------------------------------------------------------
int Csplit_merge::init(vector<Cmomentum> & /*_particles*/, vector<Cmomentum> *protocones, double R2, double ptmin){
// browse protocones
return add_protocones(protocones, R2, ptmin);
}
// initialisation function for particle list
// - _particles list of particles
//-------------------------------------------------------------
int Csplit_merge::init_particles(vector<Cmomentum> &_particles){
full_clear();
// compute the list of particles
// here, we do not need to throw away particles
// with infinite rapidity (colinear with the beam)
particles = _particles;
n = particles.size();
// build the vector of particles' pt
pt.resize(n);
for (int i=0;i<n;i++)
pt[i] = particles[i].perp();
// ensure that ptcomparison points to our set of particles (though params not correct)
ptcomparison.particles = &particles;
ptcomparison.pt = &pt;
// set up the list of particles left.
init_pleft();
indices = new int[n];
return 0;
}
// build initial list of remaining particles
//------------------------------------------
int Csplit_merge::init_pleft(){
// at this level, we only rule out particles with
// infinite rapidity
// in the parent particle list, index contain the run
// at which particles are puts in jets:
// - -1 means infinity rapidity
// - 0 means not included
// - i mean included at run i
int i,j;
// copy particles removing the ones with infinite rapidity
// determine min,max eta
j=0;
double eta_min=0.0; /// for the Ceta_phi_range static member!
double eta_max=0.0; /// for the Ceta_phi_range static member!
p_remain.clear();
for (i=0;i<n;i++){
// set ref for checkxor
particles[i].ref.randomize();
// check if rapidity is not infinite or ill-defined
if (fabs(particles[i].pz) < (particles[i].E)){
p_remain.push_back(particles[i]);
// set up parent index for tracability
p_remain[j].parent_index = i;
// left particles are marked with a 1
// IMPORTANT NOTE: the meaning of index in p_remain is
// somehow different as in the initial particle list.
// here, within one pass, we use the index to track whether
// a particle is included in the current pass (index set to 0
// in add_protocones) or still remain (index still 1)
p_remain[j].index = 1;
j++;
// set up parent-particle index
particles[i].index = 0;
eta_min = min(eta_min, particles[i].eta);
eta_max = max(eta_max, particles[i].eta);
} else {
particles[i].index = -1;
}
}
n_left = p_remain.size();
n_pass = 0;
Ceta_phi_range epr;
epr.eta_min = eta_min-0.01;
epr.eta_max = eta_max+0.01;
merge_collinear_and_remove_soft();
return 0;
}
// partial clearance
// we want to keep particle list and indices
// for future usage, so do not clear it !
// this is done in full_clear
//----------------------------------------
int Csplit_merge::partial_clear(){
// release jets
// set up the auto_ptr for the multiset with the _current_ state of
// ptcomparison (which may have changed since we constructed the
// class)
candidates.reset(new multiset<Cjet,Csplit_merge_ptcomparison>(ptcomparison));
// start off with huge number
most_ambiguous_split = numeric_limits<double>::max();
jets.clear();
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
if (merge_identical_protocones)
cand_refs.clear();
#endif
p_remain.clear();
return 0;
}
// full clearance
//----------------
int Csplit_merge::full_clear(){
partial_clear();
// clear previously allocated memory
if (indices != NULL){
delete[] indices;
}
particles.clear();
return 0;
}
// build the list 'p_uncol_hard' from p_remain by clustering collinear particles
// note that thins in only used for stable-cone detection
// so the parent_index field is unnecessary
//-------------------------------------------------------------------------
int Csplit_merge::merge_collinear_and_remove_soft(){
int i,j;
vector<Cmomentum> p_sorted;
bool collinear;
double dphi;
p_uncol_hard.clear();
// we first sort the particles according to their rapidity
for (i=0;i<n_left;i++)
p_sorted.push_back(p_remain[i]);
sort(p_sorted.begin(), p_sorted.end(), momentum_eta_less);
// then we cluster particles looping over the particles in the following way
// if (a particle i has same eta-phi a one after (j))
// then add momentum i to j
// else add i to the p_uncol_hard list
i = 0;
while (i<n_left){
// check if the particle passes the stable_cone_soft_pt2_cutoff
if (p_sorted[i].perp2()<stable_cone_soft_pt2_cutoff) {
i++;
continue;
}
// check if there is(are) particle(s) with the 'same' eta
collinear = false;
j=i+1;
while ((j<n_left) && (fabs(p_sorted[j].eta-p_sorted[i].eta)<EPSILON_COLLINEAR) && (!collinear)){
dphi = fabs(p_sorted[j].phi-p_sorted[i].phi);
if (dphi>M_PI) dphi = twopi-dphi;
if (dphi<EPSILON_COLLINEAR){
// i is collinear with j; add the momentum (i) to the momentum (j)
p_sorted[j] += p_sorted[i];
// set collinearity test to true
collinear = true;
}
j++;
}
// if no collinearity detected, add the particle to our list
if (!collinear)
p_uncol_hard.push_back(p_sorted[i]);
i++;
}
return 0;
}
// add a list of protocones
// - protocones list of protocones (initial jet candidates)
// - R2 cone radius (squared)
// - ptmin minimal pT allowed for jets
//-------------------------------------------------------------
int Csplit_merge::add_protocones(vector<Cmomentum> *protocones, double R2, double ptmin){
int i;
Cmomentum *c;
Cmomentum *v;
double eta, phi;
double dx, dy;
double R;
Cjet jet;
if (protocones->size()==0)
return 1;
pt_min2 = ptmin*ptmin;
R = sqrt(R2);
// browse protocones
// for each of them, build the list of particles in them
for (vector<Cmomentum>::iterator p_it = protocones->begin();p_it != protocones->end();p_it++){
// initialise variables
c = &(*p_it);
// note: cones have been tested => their (eta,phi) coordinates are computed
eta = c->eta;
phi = c->phi;
// browse particles to create cone contents
// note that jet is always initialised with default values at this level
jet.v = Cmomentum();
jet.pt_tilde=0;
jet.contents.clear();
for (i=0;i<n_left;i++){
v = &(p_remain[i]);
// for security, avoid including particles with infinite rapidity)
// NO NEEDED ANYMORE SINCE REMOVED FROM p_remain FROM THE BEGINNING
//if (fabs(v->pz)!=v->E){
dx = eta - v->eta;
dy = fabs(phi - v->phi);
if (dy>M_PI)
dy -= twopi;
if (dx*dx+dy*dy<R2){
jet.contents.push_back(v->parent_index);
jet.v+= *v;
jet.pt_tilde+= pt[v->parent_index];
v->index=0;
}
}
jet.n=jet.contents.size();
// set the momentum in protocones
// (it was only known through eta and phi up to now)
*c = jet.v;
c->eta = eta; // restore exact original coords
c->phi = phi; // to avoid rounding error inconsistencies
// set the jet range
jet.range=Ceta_phi_range(eta,phi,R);
#ifdef DEBUG_SPLIT_MERGE
cout << "adding jet: ";
for (int i2=0;i2<jet.n;i2++)
cout << jet.contents[i2] << " ";
cout << endl;
#endif
// add it to the list of jets
insert(jet);
}
// update list of included particles
n_pass++;
#ifdef DEBUG_SPLIT_MERGE
cout << "remaining particles: ";
#endif
int j=0;
for (i=0;i<n_left;i++){
if (p_remain[i].index){
// copy particle
p_remain[j]=p_remain[i];
p_remain[j].parent_index = p_remain[i].parent_index;
p_remain[j].index=1;
// set run in initial list
particles[p_remain[j].parent_index].index = n_pass;
#ifdef DEBUG_SPLIT_MERGE
cout << p_remain[j].parent_index << " ";
#endif
j++;
}
}
#ifdef DEBUG_SPLIT_MERGE
cout << endl;
#endif
n_left = j;
p_remain.resize(j);
merge_collinear_and_remove_soft();
return 0;
}
/*
* remove the hardest protocone and declare it a a jet
* - protocones list of protocones (initial jet candidates)
* - R2 cone radius (squared)
* - ptmin minimal pT allowed for jets
* return 0 on success, 1 on error
*
* The list of remaining particles (and the uncollinear-hard ones)
* is updated.
*/
int Csplit_merge::add_hardest_protocone_to_jets(std::vector<Cmomentum> *protocones, double R2, double ptmin){
int i;
Cmomentum *c;
Cmomentum *v;
double eta, phi;
double dx, dy;
double R;
Cjet jet, jet_candidate;
bool found_jet = false;
if (protocones->size()==0)
return 1;
pt_min2 = ptmin*ptmin;
R = sqrt(R2);
// browse protocones
// for each of them, build the list of particles in them
for (vector<Cmomentum>::iterator p_it = protocones->begin();p_it != protocones->end();p_it++){
// initialise variables
c = &(*p_it);
// note: cones have been tested => their (eta,phi) coordinates are computed
eta = c->eta;
phi = c->phi;
// NOTE: this is common to this method and add_protocones, so it
// could be moved into a 'build_jet_from_protocone' method
//
// browse particles to create cone contents
jet_candidate.v = Cmomentum();
jet_candidate.pt_tilde=0;
jet_candidate.contents.clear();
for (i=0;i<n_left;i++){
v = &(p_remain[i]);
// for security, avoid including particles with infinite rapidity)
// NO NEEDED ANYMORE SINCE REMOVED FROM p_remain FROM THE BEGINNING
//if (fabs(v->pz)!=v->E){
dx = eta - v->eta;
dy = fabs(phi - v->phi);
if (dy>M_PI)
dy -= twopi;
if (dx*dx+dy*dy<R2){
jet_candidate.contents.push_back(v->parent_index);
jet_candidate.v+= *v;
jet_candidate.pt_tilde+= pt[v->parent_index];
v->index=0;
}
}
jet_candidate.n=jet_candidate.contents.size();
// set the momentum in protocones
// (it was only known through eta and phi up to now)
*c = jet_candidate.v;
c->eta = eta; // restore exact original coords
c->phi = phi; // to avoid rounding error inconsistencies
// set the jet range
jet_candidate.range=Ceta_phi_range(eta,phi,R);
// check that the protojet has large enough pt
if (jet_candidate.v.perp2()<pt_min2)
continue;
// assign SM variable
jet_candidate.sm_var2 = get_sm_var2(jet_candidate.v, jet_candidate.pt_tilde);
- if (j1->sm_var2<SM_var2_hardest_cut_off) continue;
+ if (jet_candidate.sm_var2<SM_var2_hardest_cut_off) continue;
// now check if it is possibly the hardest
if ((! found_jet) ||
(ptcomparison(jet_candidate, jet))){
jet = jet_candidate;
found_jet = true;
}
}
// update list of included particles
n_pass++;
// add the jet to the list of jets
jets.push_back(jet);
jets[jets.size()-1].v.build_etaphi();
jets[jets.size()-1].pass = particles[jet.contents[0]].index;
#ifdef DEBUG_SPLIT_MERGE
cout << "PR-Jet " << jets.size() << " [size " << next_jet.contents.size() << "]:";
#endif
// update the list of what particles are left
int p_remain_index = 0;
int contents_index = 0;
//sort(next_jet.contents.begin(),next_jet.contents.end());
for (int index=0;index<n_left;index++){
if ((contents_index<(int) jet.contents.size()) &&
(p_remain[index].parent_index == jet.contents[contents_index])){
// this particle belongs to the newly found jet
#ifdef DEBUG_SPLIT_MERGE
cout << " " << jet.contents[contents_index];
#endif
contents_index++;
} else {
// this particle still has to be clustered
p_remain[p_remain_index] = p_remain[index];
p_remain[p_remain_index].parent_index = p_remain[index].parent_index;
p_remain[p_remain_index].index=1;
p_remain_index++;
}
}
p_remain.resize(n_left-jet.contents.size());
n_left = p_remain.size();
#ifdef DEBUG_SPLIT_MERGE
cout << endl;
#endif
// male sure the list of uncol_hard particles (used for the next
// stable cone finding) is updated [could probably be more
// efficient]
merge_collinear_and_remove_soft();
return 0;
}
/*
* really do the splitting and merging
* At the end, the vector jets is filled with the jets found.
* the 'contents' field of each jets contains the indices
* of the particles included in that jet.
* - overlap_tshold threshold for splitting/merging transition
* - ptmin minimal pT allowed for jets
* return the number of jets is returned
******************************************************************/
int Csplit_merge::perform(double overlap_tshold, double ptmin){
// iterators for the 2 jets
cjet_iterator j1;
cjet_iterator j2;
pt_min2 = ptmin*ptmin;
if (candidates->size()==0)
return 0;
if (overlap_tshold>=1.0 || overlap_tshold <= 0) {
ostringstream message;
message << "Illegal value for overlap_tshold, f = " << overlap_tshold;
message << " (legal values are 0<f<1)";
throw Csiscone_error(message.str());
}
// overlap (the contents of this variable depends on the choice for
// the split--merge variable.)
// Note that the square of the ovelap is used
double overlap2;
// avoid to compute tshold*tshold at each overlap
double overlap_tshold2 = overlap_tshold*overlap_tshold;
do{
if (candidates->size()>0){
// browse for the first jet
j1 = candidates->begin();
// if hardest jet does not pass threshold then nothing else will
// either so one stops the split merge.
if (j1->sm_var2<SM_var2_hardest_cut_off) {break;}
// browse for the second jet
j2 = j1;
j2++;
int j2_relindex = 1; // used only in ifdef, but costs little so keep it outside
while (j2 != candidates->end()){
#ifdef DEBUG_SPLIT_MERGE
show();
#endif
// check overlapping
if (get_overlap(*j1, *j2, &overlap2)){
// check if overlapping energy passes threshold
// Note that this depends on the ordering variable
#ifdef DEBUG_SPLIT_MERGE
cout << "overlap between cdt 1 and cdt " << j2_relindex+1 << " with overlap "
<< sqrt(overlap2/j2->sm_var2) << endl<<endl;
#endif
if (overlap2<overlap_tshold2*j2->sm_var2){
// split jets
split(j1, j2);
// update iterators
j2 = j1 = candidates->begin();
j2_relindex = 0;
} else {
// merge jets
merge(j1, j2);
// update iterators
j2 = j1 = candidates->begin();
j2_relindex = 0;
}
}
// watch out: split/merge might have caused new jets with pt <
// ptmin to disappear, so the total number of jets may
// have changed by more than expected and j2 might already by
// the end of the candidates list...
j2_relindex++;
if (j2 != candidates->end()) j2++;
} // end of loop on the second jet
if (j1 != candidates->end()) {
// all "second jet" passed without overlapping
// (otherwise we won't leave the j2 loop)
// => store jet 1 as real jet
jets.push_back(*j1);
jets[jets.size()-1].v.build_etaphi();
// a bug where the contents has non-zero size has been cropping
// up in many contexts -- so catch it!
assert(j1->contents.size() > 0);
jets[jets.size()-1].pass = particles[j1->contents[0]].index;
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
cand_refs.erase(j1->v.ref);
#endif
candidates->erase(j1);
//// test that the hardest jet pass the potential cut-off
//if ((candidates->size()!=0) &&
// (candidates->begin()->sm_var2<SM_var2_hardest_cut_off)){
// candidates->clear();
//}
}
}
} while (candidates->size()>0);
// sort jets by pT
sort(jets.begin(), jets.end(), jets_pt_less);
#ifdef DEBUG_SPLIT_MERGE
show();
#endif
return jets.size();
}
// save the event on disk
// - flux stream used to save jet contents
//--------------------------------------------
int Csplit_merge::save_contents(FILE *flux){
jet_iterator it_j;
Cjet *j1;
int i1, i2;
fprintf(flux, "# %d jets found\n", (int) jets.size());
fprintf(flux, "# columns are: eta, phi, pt and number of particles for each jet\n");
for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
j1 = &(*it_j);
j1->v.build_etaphi();
fprintf(flux, "%f\t%f\t%e\t%d\n",
j1->v.eta, j1->v.phi, j1->v.perp(), j1->n);
}
fprintf(flux, "# jet contents\n");
fprintf(flux, "# columns are: eta, phi, pt, particle index and jet number\n");
for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
j1 = &(*it_j);
for (i2=0;i2<j1->n;i2++)
fprintf(flux, "%f\t%f\t%e\t%d\t%d\n",
particles[j1->contents[i2]].eta, particles[j1->contents[i2]].phi,
particles[j1->contents[i2]].perp(), j1->contents[i2], i1);
}
return 0;
}
// show current jets/candidate status
//------------------------------------
int Csplit_merge::show(){
jet_iterator it_j;
cjet_iterator it_c;
Cjet *j;
const Cjet *c;
int i1, i2;
for (it_j = jets.begin(), i1=0 ; it_j != jets.end() ; it_j++, i1++){
j = &(*it_j);
fprintf(stdout, "jet %2d: %e\t%e\t%e\t%e\t", i1+1,
j->v.px, j->v.py, j->v.pz, j->v.E);
for (i2=0;i2<j->n;i2++)
fprintf(stdout, "%d ", j->contents[i2]);
fprintf(stdout, "\n");
}
for (it_c = candidates->begin(), i1=0 ; it_c != candidates->end() ; it_c++, i1++){
c = &(*it_c);
fprintf(stdout, "cdt %2d: %e\t%e\t%e\t%e\t%e\t", i1+1,
c->v.px, c->v.py, c->v.pz, c->v.E, sqrt(c->sm_var2));
for (i2=0;i2<c->n;i2++)
fprintf(stdout, "%d ", c->contents[i2]);
fprintf(stdout, "\n");
}
fprintf(stdout, "\n");
return 0;
}
// get the overlap between 2 jets
// - j1 first jet
// - j2 second jet
// - overlap2 returned overlap^2 (determined by the choice of SM variable)
// return true if overlapping, false if disjoint
//---------------------------------------------------------------------
bool Csplit_merge::get_overlap(const Cjet &j1, const Cjet &j2, double *overlap2){
// check if ranges overlap
if (!is_range_overlap(j1.range,j2.range))
return false;
int i1,i2;
bool is_overlap;
// initialise
i1=i2=idx_size=0;
is_overlap = false;
Cmomentum v;
double pt_tilde=0.0;
// compute overlap
// at the same time, we store union in indices
do{
if (j1.contents[i1]<j2.contents[i2]){
indices[idx_size] = j1.contents[i1];
i1++;
} else if (j1.contents[i1]>j2.contents[i2]){
indices[idx_size] = j2.contents[i2];
i2++;
} else { // (j1.contents[i1]==j2.contents[i2])
v += particles[j1.contents[i1]];
pt_tilde += pt[j1.contents[i1]];
indices[idx_size] = j1.contents[i1];
i1++;
i2++;
is_overlap = true;
}
idx_size++;
} while ((i1<j1.n) && (i2<j2.n));
// finish computing union
// (only needed if overlap !)
if (is_overlap){
while (i1<j1.n){
indices[idx_size] = j1.contents[i1];
i1++;
idx_size++;
}
while (i2<j2.n){
indices[idx_size] = j2.contents[i2];
i2++;
idx_size++;
}
}
// assign the overlapping var as return variable
(*overlap2) = get_sm_var2(v, pt_tilde);
return is_overlap;
}
// split the two given jet.
// during this procedure, the jets j1 & j2 are replaced
// by 2 new jets. Common particles are associted to the
// closest initial jet.
// - it_j1 iterator of the first jet in 'candidates'
// - it_j2 iterator of the second jet in 'candidates'
// - j1 first jet (Cjet instance)
// - j2 second jet (Cjet instance)
// return true on success, false on error
////////////////////////////////////////////////////////////////
bool Csplit_merge::split(cjet_iterator &it_j1, cjet_iterator &it_j2){
int i1, i2;
Cjet jet1, jet2;
double eta1, phi1, pt1_weight, eta2, phi2, pt2_weight;
double dx1, dy1, dx2, dy2;
Cmomentum tmp;
Cmomentum *v;
// shorthand to avoid having "->" all over the place
const Cjet & j1 = * it_j1;
const Cjet & j2 = * it_j2;
i1=i2=0;
jet2.v = jet1.v = Cmomentum();
jet2.pt_tilde = jet1.pt_tilde = 0.0;
// compute centroids
// When use_pt_weighted_splitting is activated, the
// "geometrical" distance is weighted by the inverse
// of the pt of the protojet
// This is stored in pt{1,2}_weight
tmp = j1.v;
tmp.build_etaphi();
eta1 = tmp.eta;
phi1 = tmp.phi;
pt1_weight = (use_pt_weighted_splitting) ? 1.0/tmp.perp2() : 1.0;
tmp = j2.v;
tmp.build_etaphi();
eta2 = tmp.eta;
phi2 = tmp.phi;
pt2_weight = (use_pt_weighted_splitting) ? 1.0/tmp.perp2() : 1.0;
jet1.v = jet2.v = Cmomentum();
// compute jet splitting
do{
if (j1.contents[i1]<j2.contents[i2]){
// particle i1 belong only to jet 1
v = &(particles[j1.contents[i1]]);
jet1.contents.push_back(j1.contents[i1]);
jet1.v += *v;
jet1.pt_tilde += pt[j1.contents[i1]];
i1++;
jet1.range.add_particle(v->eta,v->phi);
} else if (j1.contents[i1]>j2.contents[i2]){
// particle i2 belong only to jet 2
v = &(particles[j2.contents[i2]]);
jet2.contents.push_back(j2.contents[i2]);
jet2.v += *v;
jet2.pt_tilde += pt[j2.contents[i2]];
i2++;
jet2.range.add_particle(v->eta,v->phi);
} else { // (j1.contents[i1]==j2.contents[i2])
// common particle, decide which is the closest centre
v = &(particles[j1.contents[i1]]);
// distance w.r.t. centroid 1
dx1 = eta1 - v->eta;
dy1 = fabs(phi1 - v->phi);
if (dy1>M_PI)
dy1 -= twopi;
// distance w.r.t. centroid 2
dx2 = eta2 - v->eta;
dy2 = fabs(phi2 - v->phi);
if (dy2>M_PI)
dy2 -= twopi;
//? what when == ?
// When use_pt_weighted_splitting is activated, the
// "geometrical" distance is weighted by the inverse
// of the pt of the protojet
double d1sq = (dx1*dx1+dy1*dy1)*pt1_weight;
double d2sq = (dx2*dx2+dy2*dy2)*pt2_weight;
// do bookkeeping on most ambiguous split
if (fabs(d1sq-d2sq) < most_ambiguous_split)
most_ambiguous_split = fabs(d1sq-d2sq);
if (d1sq<d2sq){
// particle i1 belong only to jet 1
jet1.contents.push_back(j1.contents[i1]);
jet1.v += *v;
jet1.pt_tilde += pt[j1.contents[i1]];
jet1.range.add_particle(v->eta,v->phi);
} else {
// particle i2 belong only to jet 2
jet2.contents.push_back(j2.contents[i2]);
jet2.v += *v;
jet2.pt_tilde += pt[j2.contents[i2]];
jet2.range.add_particle(v->eta,v->phi);
}
i1++;
i2++;
}
} while ((i1<j1.n) && (i2<j2.n));
while (i1<j1.n){
v = &(particles[j1.contents[i1]]);
jet1.contents.push_back(j1.contents[i1]);
jet1.v += *v;
jet1.pt_tilde += pt[j1.contents[i1]];
i1++;
jet1.range.add_particle(v->eta,v->phi);
}
while (i2<j2.n){
v = &(particles[j2.contents[i2]]);
jet2.contents.push_back(j2.contents[i2]);
jet2.v += *v;
jet2.pt_tilde += pt[j2.contents[i2]];
i2++;
jet2.range.add_particle(v->eta,v->phi);
}
// finalise jets
jet1.n = jet1.contents.size();
jet2.n = jet2.contents.size();
//jet1.range = j1.range;
//jet2.range = j2.range;
// remove previous jets
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
cand_refs.erase(j1.v.ref);
cand_refs.erase(j2.v.ref);
#endif
candidates->erase(it_j1);
candidates->erase(it_j2);
// reinsert new ones
insert(jet1);
insert(jet2);
return true;
}
// merge the two given jet.
// during this procedure, the jets j1 & j2 are replaced
// by 1 single jets containing both of them.
// - it_j1 iterator of the first jet in 'candidates'
// - it_j2 iterator of the second jet in 'candidates'
// return true on success, false on error
////////////////////////////////////////////////////////////////
bool Csplit_merge::merge(cjet_iterator &it_j1, cjet_iterator &it_j2){
Cjet jet;
int i;
// build new jet
// note: particles within j1 & j2 have already been stored in indices
for (i=0;i<idx_size;i++){
jet.contents.push_back(indices[i]);
jet.v += particles[indices[i]];
jet.pt_tilde += pt[indices[i]];
}
jet.n = jet.contents.size();
// deal with ranges
jet.range = range_union(it_j1->range, it_j2->range);
// remove old candidates
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
if (merge_identical_protocones){
cand_refs.erase(it_j1->v.ref);
cand_refs.erase(it_j2->v.ref);
}
#endif
candidates->erase(it_j1);
candidates->erase(it_j2);
// reinsert new candidate
insert(jet);
return true;
}
/**
* Check whether or not a jet has to be inserted in the
* list of protojets. If it has, set its sm_variable and
* insert it to the list of protojets.
*/
bool Csplit_merge::insert(Cjet &jet){
// eventually check that no other candidate are present with the
// same cone contents. We recall that this automatic merging of
// identical protocones can lead to infrared-unsafe situations.
#ifdef ALLOW_MERGE_IDENTICAL_PROTOCONES
if ((merge_identical_protocones) && (!cand_refs.insert(jet.v.ref).second))
return false;
#endif
// check that the protojet has large enough pt
if (jet.v.perp2()<pt_min2)
return false;
// assign SM variable
jet.sm_var2 = get_sm_var2(jet.v, jet.pt_tilde);
// insert the jet.
candidates->insert(jet);
return true;
}
/**
* given a 4-momentum and its associated pT, return the
* variable that has to be used for SM
* \param v 4 momentum of the protojet
* \param pt_tilde pt_tilde of the protojet
*/
double Csplit_merge::get_sm_var2(Cmomentum &v, double &pt_tilde){
switch(ptcomparison.split_merge_scale) {
case SM_pt: return v.perp2();
case SM_mt: return v.perpmass2();
case SM_pttilde: return pt_tilde*pt_tilde;
case SM_Et: return v.Et2();
default:
throw Csiscone_error("Unsupported split-merge scale choice: "
+ ptcomparison.SM_scale_name());
}
return 0.0;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Nov 19, 7:14 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3805785
Default Alt Text
(35 KB)
Attached To
rSISCONESVN sisconesvn
Event Timeline
Log In to Comment