// JetsWithoutJets Package
// Questions/Comments? danbert@mit.edu jthaler@mit.edu
//
// Copyright (c) 2013
// Daniele Bertolini and Jesse Thaler
//
// $Id$
//----------------------------------------------------------------------
// This file is part of FastJet contrib.
//
// It 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.
//
// It 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 code. If not, see .
//----------------------------------------------------------------------
#ifndef __FASTJET_CONTRIB_JETSWITHOUTJETS_HH__
#define __FASTJET_CONTRIB_JETSWITHOUTJETS_HH__
#include
#include "fastjet/FunctionOfPseudoJet.hh"
#include "fastjet/tools/Transformer.hh"
#include "fastjet/JetDefinition.hh"
#include "fastjet/PseudoJet.hh"
#include "fastjet/ClusterSequence.hh"
#include "fastjet/SharedPtr.hh"
#include
#include
#include "EventStorage.hh"
FASTJET_BEGIN_NAMESPACE // defined in fastjet/internal/base.hh
namespace jwj {
//////
//
// Defining a function of a vector of PseudoJets
//
//////
//----------------------------------------------------------------------
// MyFunctionOfVectorOfPseudoJets
// In current version of FastJet there is no standard interface for a function
// that takes a vector of PseudoJets as argument. This class serves as a base class
// and it is the analog of FunctionOfPseudoJet, it only differs in taking a vector
// of PseudoJets as argument. Should a standard interface become available, this
// class could be removed and the classes below (like JetLikeEventShape,
// FunctionUnity, etc.) could derive from the standard base class.
template
class MyFunctionOfVectorOfPseudoJets {
public:
MyFunctionOfVectorOfPseudoJets(){}
MyFunctionOfVectorOfPseudoJets(const TOut &constant_value);
virtual ~MyFunctionOfVectorOfPseudoJets(){}
virtual std::string description() const{ return "";}
virtual TOut result(const std::vector &pjs) const = 0;
TOut operator()(const std::vector &pjs) const { return result(pjs);}
};
//////
//
// Extendable Jet-like Event Shapes
// (works on any function of vector that returns double)
//
//////
//----------------------------------------------------------------------
// JetLikeEventShape
// Event shape that corresponds to a jet-based observable (summed over all jets).
// It takes a Function (derived from MyFunctionOfVectorOfPseudoJets) that would
// correspond to a measurement done on each jet as an argument and it applies it to cones or radius R around each particle,
// then sums over all such "jets" which are above pTcut threshold.
// Optional trimming built in. Note that in general trimming first,
// then applying the event shape gives a different answer.
// Only works with quantities that are doubles for each jet
// (could templatize, but easier to deal with case by case)
// If one wants to derive one's own JetLikeEventShape that is not based on a measurement,
// then one has to overload the virtual result(EventStorage & myStorage) function.
class JetLikeEventShape: public MyFunctionOfVectorOfPseudoJets{
public:
JetLikeEventShape(): _measurement(NULL),_useLocalStorage(true) {}
// Constructor without trimming. By default it uses LocalStorage, it stores neighbors and and it does not store mass of neighbors.
// Measurement is automatically deleted when destructor is called.
JetLikeEventShape(MyFunctionOfVectorOfPseudoJets * measurement, double Rjet, double ptcut)
: _measurement(measurement), _Rjet(Rjet), _ptcut(ptcut), _Rsub(Rjet), _fcut(1.0), _trim(false),_useLocalStorage(true),_storeNeighbors(true),_storeMass(false) {}
// Constructor with trimming. By default it uses LocalStorage, it stores neighbors and it does not store mass of neighbors.
// Measurement is automatically deleted when destructor is called.
JetLikeEventShape(MyFunctionOfVectorOfPseudoJets * measurement, double Rjet, double ptcut, double Rsub, double fcut)
: _measurement(measurement), _Rjet(Rjet), _ptcut(ptcut), _Rsub(Rsub), _fcut(fcut), _trim(true),_useLocalStorage(true),_storeNeighbors(true),_storeMass(false) {}
virtual ~JetLikeEventShape(){ if(_measurement) delete _measurement;}
// This result function takes an EventStorage as input and returns the event shape value.
// Call directly this function if you want to use a pre-built EventStorage
// This function is overloaded for built-in JetLikeEventShapes
virtual double result(EventStorage & myStorage) const {
double myMeasurement = 0.0;
// check if storage can be used for this shape
if (!_check_storage_parameters(myStorage) || !myStorage.storeNeighbors() ) {
throw Error("Storage cannot be used for this shape");
} else {
// loop through all particles
for (unsigned int i = 0; iresult(myStorage.particles_near_to(i));
}
}
return myMeasurement;
}
// Standard result function. It takes a vector as input and returns the event shape.
// It creates the appropriate EventStorage and calls result(EventStorage & myStorage)
double result(const std::vector & particles) const {
EventStorage myStorage(_Rjet,_ptcut,_Rsub,_fcut,_useLocalStorage,_storeNeighbors,_storeMass);
myStorage.establishStorage(particles);
return (result(myStorage));
}
// Choose whether to use LocalStorage or not (on by default).
// In general, no reason not turn it off except for debugging.
void setUseLocalStorage(bool useLocalStorage) {_useLocalStorage = useLocalStorage;}
// Description
std::string jetParameterString() const {
std::stringstream stream;
stream << "R_jet=" << _Rjet << ", pT_cut=" << _ptcut;
if (_trim) stream << ", trimming with R_sub=" << _Rsub <<", fcut=" << _fcut;
return stream.str();
}
virtual std::string description() const {
return "Summed " + _measurement->description() + " as event shape, " + jetParameterString();
}
protected:
MyFunctionOfVectorOfPseudoJets * _measurement;
double _Rjet, _ptcut, _Rsub, _fcut;
bool _trim;
// optional storage array to cache the 2R x 2R partitions.
bool _useLocalStorage;
// Choose whether to store neighbors or not, and wheter to store mass of neighbors or not.
// By default it stores neighbors, but not needed for the built-in JetLikeEventShapes
// Also, by default it does not store mass of neighbors, but needed for built-in jet mass or mass squared shapes.
bool _storeNeighbors,_storeMass;
void _setStoreNeighbors(bool storeNeighbors) {_storeNeighbors=storeNeighbors;}
void _setStoreMass(bool storeMass) {_storeMass=storeMass;}
// helper to check if an external EventStorage can be used for this JetLikeEventShape (i.e. whether it has been built using the same parameters)
bool _check_storage_parameters(EventStorage & myStorage) const {
bool answer = false;
if(!_trim) answer = myStorage.Rjet()==_Rjet && myStorage.ptcut()==_ptcut;
else answer = myStorage.Rjet()==_Rjet && myStorage.ptcut()==_ptcut && myStorage.Rsub()==_Rsub && myStorage.fcut()==_fcut;
return answer;
}
};
//////
//
// Example Functions to Use
//
//////
//----------------------------------------------------------------------
// Below are examples of function to use as measurement in JetLikeEventShape.
// Most of these are irrevant since there are built-in JetLikeEventShapes,
// but we have maintained them for debugging purposes.
//----------------------------------------------------------------------
// FunctionUnity
// Returns 1 for each jet
class FunctionUnity : public MyFunctionOfVectorOfPseudoJets {
double result(const std::vector & particles) const { return 1.0; }
std::string description() const { return "Jet unit weight";}
};
//----------------------------------------------------------------------
// FunctionScalarPtSum
// Finds the summed pt of the jet constituents (NOT the pT of the jet)
class FunctionScalarPtSum : public MyFunctionOfVectorOfPseudoJets {
double result(const std::vector & particles) const {
double myPt = 0.0;
for (unsigned int i = 0; i {
private:
int _n;
public:
FunctionScalarPtSumToN(int n) : _n(n) {}
double result(const std::vector & particles) const {
FunctionScalarPtSum sumPt = FunctionScalarPtSum();
return pow(sumPt(particles),_n);
}
std::string description() const {
std::stringstream myStream;
myStream << "Jet Scalar Pt^" << _n;
return myStream.str();
}
};
//----------------------------------------------------------------------
// FunctionInvariantMass
// Finds the mass of the jet
class FunctionInvariantMass : public MyFunctionOfVectorOfPseudoJets {
double result(const std::vector & particles) const {
PseudoJet myJet(0,0,0,0);
for (unsigned int i = 0; i {
double result(const std::vector & particles) const {
PseudoJet myJet(0,0,0,0);
for (unsigned int i = 0; i _ptsubcut ) myMeasurement += myStorage[i].pt()/myStorage[i].pt_in_Rsub();
}
}
return myMeasurement;
}
std::string description() const {
std::stringstream myStream;
myStream << "Trimmed subjet multiplicity as event shape, ptsub_cut=" << _ptsubcut <<"and, ";
return myStream.str()+jetParameterString();
}
protected:
double _ptsubcut; // additional subjet pT cut, if desired
};
//////
//
// Shape Trimming
//
//////
//----------------------------------------------------------------------
// SelectorShapeTrimming
// Event-wide trimming is implemented as a selector
Selector SelectorShapeTrimming(double Rjet, double ptcut, double Rsub, double fcut);
//----------------------------------------------------------------------
// SelectorJetShapeTrimming
// Jet-based trimming, implimented as a selector.
// It takes the jet pT as the sum of the given four-vectors
Selector SelectorJetShapeTrimming(double Rsub, double fcut);
//----------------------------------------------------------------------
// JetShapeTrimmer
// For convenience, a Transformer version of jet-shape trimming which
// acts on individual jets. Simply a wrapper for SelectorJetShapeTrimming
class JetShapeTrimmer : public Transformer {
private:
double _Rsub, _fcut;
Selector _selector;
public:
JetShapeTrimmer(double Rsub, double fcut) : _Rsub(Rsub), _fcut(fcut){
_selector = SelectorJetShapeTrimming(_Rsub,_fcut);
}
virtual PseudoJet result(const PseudoJet & original) const {
return join(_selector(original.constituents()));
}
std::string jetParameterString() const {
std::stringstream stream;
stream << "R_sub=" << _Rsub <<", fcut=" << _fcut;
return stream.str();
}
virtual std::string description() const {
return "Jet shape trimmer, " + jetParameterString();
}
};
//////
//
// Multiple pT_cut values
//
//////
//----------------------------------------------------------------------
// JetLikeEventShape_MultiplePtCutValues
// Generic class to get the whole range of event shape values as ptcut
// is changed.
class JetLikeEventShape_MultiplePtCutValues {
public:
JetLikeEventShape_MultiplePtCutValues(): _measurement(NULL), _useLocalStorage(true) {}
// Constructor without trimming. By default it uses LocalStorage. Measurement is automatically deleted when destructor is called.
JetLikeEventShape_MultiplePtCutValues(MyFunctionOfVectorOfPseudoJets * measurement, double Rjet, double offset = 0.0): _measurement(measurement), _Rjet(Rjet), _Rsub(Rjet), _fcut(1.0), _offset(offset), _trim(false),_useLocalStorage(true) {}
// Constructor with trimming. By default it uses LocalStorage. Measurement is automatically deleted when destructor is called.
JetLikeEventShape_MultiplePtCutValues(MyFunctionOfVectorOfPseudoJets * measurement, double Rjet, double Rsub, double fcut, double offset = 0.0): _measurement(measurement), _Rjet(Rjet), _Rsub(Rsub), _fcut(fcut), _offset(offset), _trim(true), _useLocalStorage(true) {}
virtual ~JetLikeEventShape_MultiplePtCutValues() {if(_measurement) delete _measurement;}
// Initialization: input particles and build step function.
virtual void set_input(const std::vector & particles) {
_storeLocalInfo(particles);
_buildStepFunction();
}
// Get the event shape for any value of ptcut.
virtual double eventShapeFor(const double ptcut_0) const;
// Pseudo-inverse: get ptcut for a given event shape value. If initialized it uses an offset, default offset is zero.
virtual double ptCutFor(const double eventShape_0) const;
// Get the full function array. This is a vector of vector. Each vector contains a ptcut/eventShape pair
virtual const std::vector< std::vector >& functionArray() const {return _functionArray;}
void setUseLocalStorage(bool useLocalStorage) {_useLocalStorage = useLocalStorage;}
std::string ParameterString() const {
std::stringstream stream;
stream << "R_jet=" << _Rjet;
if (_trim) stream << ", trimming with R_sub=" << _Rsub <<", fcut=" << _fcut;
stream << ", offset for inverse function=" << _offset;
return stream.str();
}
virtual std::string description() const {
return _measurement->description() + "as function of pT_cut, " + ParameterString();
}
protected:
// The jet measurement of interest
MyFunctionOfVectorOfPseudoJets * _measurement;
double _Rjet, _Rsub, _fcut, _offset;
bool _trim, _useLocalStorage;
// Build up the event shape as a function of ptcut.
void _storeLocalInfo(const std::vector particles);
void _buildStepFunction();
std::vector< std::vector > _functionArray;
};
//----------------------------------------------------------------------
// ShapeJetMultiplicity_MultiplePtCutValues
// Example of an event shape with muiltiple ptcut values. Here, we are just doing
// jet multiplicity, but the same could be done for any of the other event shapes.
// Again ShapeJetMultiplicity_MultiplePtCutValues does not use an external measurement but it is hard-coded
// and it uses information cached in EventStorage to improve speed.
class ShapeJetMultiplicity_MultiplePtCutValues: public JetLikeEventShape_MultiplePtCutValues {
public:
// As per the physics paper, the default offset is 0.5
ShapeJetMultiplicity_MultiplePtCutValues(double Rjet, double offset = 0.5): JetLikeEventShape_MultiplePtCutValues(NULL, Rjet, offset) {};
ShapeJetMultiplicity_MultiplePtCutValues(double Rjet, double Rsub, double fcut, double offset = 0.5): JetLikeEventShape_MultiplePtCutValues(NULL, Rjet, Rsub, fcut, offset) {};
~ShapeJetMultiplicity_MultiplePtCutValues(){}
void set_input(const std::vector & particles) {
EventStorage myEventStorage(_Rjet,0.0,_Rsub,_fcut,_useLocalStorage,false);
myEventStorage.establishStorage(particles);
_functionArray.resize(myEventStorage.size());
for (unsigned int i = 0; i < myEventStorage.size(); i++){
_functionArray[i].push_back(myEventStorage[i].pt_in_Rjet());
_functionArray[i].push_back(myEventStorage[i].weight());
}
_buildStepFunction();
}
std::string description() const {
return "Shape jet multiplicity as function of pT_cut, " + ParameterString();
}
};
//////
//
// Njet with multiple R_jet values
//
//////
//----------------------------------------------------------------------
// ShapeJetMultiplicity_MultipleRValues
// It calculates jet multiplicity for all values of R_jet.
// It needs to store all particle mutual distances,
// so memory required scales as N^2 for N particles in the event.
// This is the only event shape we have coded up with the ability to do
// multiple R.
class ShapeJetMultiplicity_MultipleRValues {
public:
ShapeJetMultiplicity_MultipleRValues(){}
// constructor without trimming
ShapeJetMultiplicity_MultipleRValues(double ptcut):_ptcut(ptcut), _Rsub(0.0), _fcut(1.0), _trim(false) {}
// constructor with trimming
ShapeJetMultiplicity_MultipleRValues(double ptcut, double Rsub, double fcut): _ptcut(ptcut), _Rsub(Rsub), _fcut(fcut), _trim(true) {}
~ShapeJetMultiplicity_MultipleRValues() {}
// Initialization: input particles and build step function.
void set_input(const std::vector & particles) {_buildStepFunction(particles);}
// Get the event shape for any value of R.
virtual double eventShapeFor(const double Rjet_0) const;
// Get the full function array. This is a vector of vectors. Each vector contains a Rjet/eventShape pair
const std::vector< std::vector >& functionArray() const {return _functionArray;}
std::string ParameterString() const {
std::stringstream stream;
stream << "pT_cut=" << _ptcut;
if (_trim) stream << ", trimming with R_sub=" << _Rsub <<", fcut=" << _fcut;
return stream.str();
}
std::string description() const {
return "Shape jet multiplicity as function of Rjet, " + ParameterString();
}
protected:
double _ptcut, _Rsub, _fcut;
bool _trim;
// Build up the event shape as a function of Rjet
void _buildStepFunction(const std::vector particles);
std::vector< std::vector > _functionArray;
};
//////
//
// Finding Jet Axes with the Event Shape Density
//
//////
//--------------------------------------------------------
// FunctionJetAxis
// Function to find jet axis according to a given jet definition.
// Needed for the event shape densities
class FunctionJetAxis : public MyFunctionOfVectorOfPseudoJets< PseudoJet > {
public:
FunctionJetAxis(){}
FunctionJetAxis(fastjet::JetDefinition &jetDef) : _jetDef(jetDef) {}
~FunctionJetAxis(){}
PseudoJet result(const std::vector & particles) const {
fastjet::ClusterSequence clustSeq(particles,_jetDef);
fastjet::PseudoJet myAxis = clustSeq.inclusive_jets(0.0)[0]; // should cluster everything
return(myAxis);
}
std::string description() const { return "Jet axis with " + _jetDef.description();}
private:
fastjet::JetDefinition _jetDef;
};
//--------------------------------------------------------
// LightLikeAxis
// Takes a pseudojet and returns a light-like version with no mass,
// pT is set to 1, and it maintains the input rapidity and azimuth
class LightLikeAxis : public FunctionOfPseudoJet< PseudoJet > {
public:
LightLikeAxis() {}
// Convert to light-like object
PseudoJet result(const PseudoJet & jet) const {
PseudoJet p = jet;
p.reset_momentum_PtYPhiM(1.0, jet.rap(), jet.phi(),0.0);
return p;
}
std::string description() const { return "Light-like version with pT=1";}
};
//--------------------------------------------------------
// Winner-take-all recombiner.
// Returns a recombined pseudojet whose pt is the sum of the input pts,
// but direction is the hardest jet direction.
class WinnerTakeAllRecombiner : public fastjet::JetDefinition::Recombiner {
public:
WinnerTakeAllRecombiner() {}
virtual std::string description() const {return "WinnerTakeAll Recombination Scheme";}
// recombine pa and pb and put result into pab
virtual void recombine(const PseudoJet & pa, const PseudoJet & pb, PseudoJet & pab) const {
PseudoJet harder = pa;
PseudoJet softer = pb;
double pTa = pa.pt();
double pTb = pb.pt();
if (pTa < pTb) std::swap(harder,softer);
PseudoJet direction = lightLikeVersion(harder);
double newpT = pTa+pTb;
pab = newpT * direction;
}
protected:
LightLikeAxis lightLikeVersion;
};
//--------------------------------------------------------
// EventShapeDensity_JetAxes
// This is the hybrid probability density shape for jet axes position
// It calculates axis directions using the winner-take-all recombination,
// and also returns weights
class EventShapeDensity_JetAxes {
public:
EventShapeDensity_JetAxes(){}
// using default cluster measure (anti-kT with winner-take-all recombination). By default it doesn't apply global consistency
// and it uses LocalStorage
EventShapeDensity_JetAxes(double Rjet, double ptcut, bool applyGlobalConsistency = false): _Rjet(Rjet), _ptcut(ptcut), _jetDef(fastjet::JetDefinition(fastjet::antikt_algorithm, 2.0*Rjet, new WinnerTakeAllRecombiner(), fastjet::Best)), _applyGlobalConsistency(applyGlobalConsistency), _useLocalStorage(true) {_jetDef.delete_recombiner_when_unused();}
// Using arbitrary jet clustering procedure
EventShapeDensity_JetAxes(double Rjet, double ptcut, const fastjet::JetAlgorithm &jetAlgo, bool applyGlobalConsistency = false): _Rjet(Rjet), _ptcut(ptcut), _jetDef(fastjet::JetDefinition(jetAlgo, 2.0*Rjet, new WinnerTakeAllRecombiner(), fastjet::Best)), _applyGlobalConsistency(applyGlobalConsistency), _useLocalStorage(true) { _jetDef.delete_recombiner_when_unused();}
~EventShapeDensity_JetAxes(){}
// Set input and find local axes
void set_input(const std::vector & particles) {
_find_local_axes(particles);
find_axes_and_weights();
}
//Turn on/off global consistency requirement
void setGlobalConsistencyCheck(bool applyGlobalConsistency) {_applyGlobalConsistency = applyGlobalConsistency;}
//(re)find axes and weights
void find_axes_and_weights();
//Turn on/off global use of LocalStorage
void setUseLocalStorage(bool useLocalStorage) {_useLocalStorage = useLocalStorage;}
//Return a vector of PseudoJets sorted by pT. pT of each axis is its corresponding pT weight.
std::vector axes() const { return _distinctAxes; }
//Return the corresponding vector of Njet weights
std::vector Njet_weights() const { return _tot_Njet_weights; }
//Description
std::string ParameterString() const {
std::stringstream stream;
stream << "R_jet=" << _Rjet << ", pT_cut=" << _ptcut;
stream << ". Local clustering with " << _jetDef.description()<<".";
if (_applyGlobalConsistency) stream << " Global consistency condition on.";
return stream.str();
}
std::string description() const { return "Hybrid event shape density for finding jet axes." + ParameterString();}
private:
double _Rjet, _ptcut;
fastjet::JetDefinition _jetDef;
bool _applyGlobalConsistency;
void _find_local_axes(const std::vector & particles);
bool _isStable(const int thisAxis) const;
unsigned int _N;
std::vector _tot_Njet_weights,_Njet_weights, _pt_weights;
std::vector _axes;
std::vector _myParticles, _distinctAxes;
LightLikeAxis _lightLikeVersion;
bool _useLocalStorage;
LocalStorage _myLocalStorage;
};
} // namespace jwj
FASTJET_END_NAMESPACE
#endif // __FASTJET_CONTRIB_JETSWITHOUTJETS_HH__