32#include "fastjet/Error.hh"
33#include "fastjet/PseudoJet.hh"
34#include "fastjet/ClusterSequence.hh"
36#include "fastjet/ClusterSequenceAreaBase.hh"
38#include "fastjet/CompositeJetStructure.hh"
46FASTJET_BEGIN_NAMESPACE
53PseudoJet::PseudoJet(
const double px_in,
const double py_in,
const double pz_in,
const double E_in) {
68#ifdef FASTJET_HAVE_THREAD_SAFETY
73 _structure = other_pj._structure;
74 _user_info = other_pj._user_info;
76 _cluster_hist_index = other_pj._cluster_hist_index;
77 _user_index = other_pj._user_index;
82 reset_momentum(other_pj);
115void PseudoJet::_finish_init () {
116 _kt2 = this->px()*this->px() + this->py()*this->py();
117 _phi = pseudojet_invalid_phi;
125 _rap = pseudojet_invalid_rap;
127#ifdef FASTJET_HAVE_THREAD_SAFETY
128 _init_status = Init_NotDone;
133#ifdef FASTJET_HAVE_THREAD_SAFETY
134void PseudoJet::_ensure_valid_rap_phi()
const{
138 if (_init_status!=Init_Done){
139 int expected = Init_NotDone;
150 if (_init_status.compare_exchange_strong(expected, Init_InProgress,
151 std::memory_order_seq_cst,
152 std::memory_order_relaxed)){
157 _init_status.store(Init_Done, memory_order_release);
166 while (_init_status.load(memory_order_acquire) != Init_Done);
174void PseudoJet::_set_rap_phi()
const {
179 _phi = atan2(this->py(),this->px());
181 if (_phi < 0.0) {_phi += twopi;}
182 if (_phi >= twopi) {_phi -= twopi;}
183 if (this->E() == abs(this->pz()) && _kt2 == 0) {
188 double MaxRapHere =
MaxRap + abs(this->pz());
189 if (this->pz() >= 0.0) {_rap = MaxRapHere;}
else {_rap = -MaxRapHere;}
194 double effective_m2 = max(0.0,m2());
195 double E_plus_pz = _E + abs(_pz);
197 _rap = 0.5*log((_kt2 + effective_m2)/(E_plus_pz*E_plus_pz));
198 if (_pz > 0) {_rap = - _rap;}
206valarray<double> PseudoJet::four_mom()
const {
207 valarray<double> mom(4);
218double PseudoJet::operator () (
int i)
const {
230 err <<
"PseudoJet subscripting: bad index (" << i <<
")";
231 throw Error(err.str());
238double PseudoJet::pseudorapidity()
const {
239 if (px() == 0.0 && py() ==0.0)
return MaxRap;
240 if (pz() == 0.0)
return 0.0;
242 double theta = atan(perp()/pz());
244 return -log(tan(
theta/2));
254 jet1.E() +jet2.E() );
259PseudoJet operator- (
const PseudoJet & jet1,
const PseudoJet & jet2) {
261 return PseudoJet(jet1.px()-jet2.px(),
264 jet1.E() -jet2.E() );
269PseudoJet
operator* (
double coeff,
const PseudoJet & jet) {
273 jet._ensure_valid_rap_phi();
276 PseudoJet coeff_times_jet(jet);
277 coeff_times_jet *= coeff;
278 return coeff_times_jet;
283PseudoJet
operator* (
const PseudoJet & jet,
double coeff) {
289PseudoJet operator/ (
const PseudoJet & jet,
double coeff) {
290 return (1.0/coeff)*jet;
303 _ensure_valid_rap_phi();
316 (*this) *= 1.0/coeff;
324 _px += other_jet._px;
325 _py += other_jet._py;
326 _pz += other_jet._pz;
336 _px -= other_jet._px;
337 _py -= other_jet._py;
338 _pz -= other_jet._pz;
346 if (a.px() != b.px())
return false;
347 if (a.py() != b.py())
return false;
348 if (a.pz() != b.pz())
return false;
349 if (a.E () != b.E ())
return false;
363 throw Error(
"comparing a PseudoJet with a non-zero constant (double) is not allowed.");
364 return (jet.px() == 0 && jet.py() == 0 &&
365 jet.pz() == 0 && jet.E() == 0);
378 if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
381 double m_local = prest.
m();
382 assert(m_local != 0);
384 double pf4 = ( px()*prest.px() + py()*prest.py()
385 + pz()*prest.pz() + E()*prest.E() )/m_local;
386 double fn = (pf4 + E()) / (prest.E() + m_local);
387 _px += fn*prest.px();
388 _py += fn*prest.py();
389 _pz += fn*prest.pz();
405 if (prest.px() == 0.0 && prest.py() == 0.0 && prest.pz() == 0.0)
408 double m_local = prest.
m();
409 assert(m_local != 0);
411 double pf4 = ( -px()*prest.px() - py()*prest.py()
412 - pz()*prest.pz() + E()*prest.E() )/m_local;
413 double fn = (pf4 + E()) / (prest.E() + m_local);
414 _px -= fn*prest.px();
415 _py -= fn*prest.py();
416 _pz -= fn*prest.pz();
427 return jeta.px() == jetb.px()
428 && jeta.py() == jetb.py()
429 && jeta.pz() == jetb.pz()
430 && jeta.E() == jetb.E();
434void PseudoJet::set_cached_rap_phi(
double rap_in,
double phi_in) {
435 _rap = rap_in; _phi = phi_in;
436 if (_phi >= twopi) _phi -= twopi;
437 if (_phi < 0) _phi += twopi;
438#ifdef FASTJET_HAVE_THREAD_SAFETY
439 _init_status = Init_Done;
444void PseudoJet::reset_momentum_PtYPhiM(
double pt_in,
double y_in,
double phi_in,
double m_in) {
445 assert(phi_in < 2*twopi && phi_in > -twopi);
446 double ptm = (m_in == 0) ? pt_in : sqrt(pt_in*pt_in+m_in*m_in);
447 double exprap = exp(y_in);
448 double pminus = ptm/exprap;
449 double pplus = ptm*exprap;
450 double px_local = pt_in*cos(phi_in);
451 double py_local = pt_in*sin(phi_in);
452 reset_momentum(px_local,py_local,0.5*(pplus-pminus),0.5*(pplus+pminus));
453 set_cached_rap_phi(y_in,phi_in);
459 assert(phi < 2*twopi && phi > -twopi);
460 double ptm = (m == 0) ? pt : sqrt(pt*pt+m*m);
461 double exprap = exp(y);
462 double pminus = ptm/exprap;
463 double pplus = ptm*exprap;
464 double px = pt*cos(phi);
465 double py = pt*sin(phi);
466 PseudoJet mom(px,py,0.5*(pplus-pminus),0.5*(pplus+pminus));
475double PseudoJet::kt_distance(
const PseudoJet & other)
const {
477 double distance = min(_kt2, other._kt2);
478 double dphi = abs(phi() - other.
phi());
479 if (dphi > pi) {dphi = twopi - dphi;}
480 double drap = rap() - other.
rap();
481 distance = distance * (dphi*dphi + drap*drap);
488double PseudoJet::plain_distance(
const PseudoJet & other)
const {
489 double dphi = abs(phi() - other.
phi());
490 if (dphi > pi) {dphi = twopi - dphi;}
491 double drap = rap() - other.
rap();
492 return (dphi*dphi + drap*drap);
498double PseudoJet::delta_phi_to(
const PseudoJet & other)
const {
499 double dphi = other.
phi() - phi();
500 if (dphi > pi) dphi -= twopi;
501 if (dphi < -pi) dphi += twopi;
506string PseudoJet::description()
const{
509 return "standard PseudoJet (with no associated clustering information)";
512 return _structure->description();
527bool PseudoJet::has_associated_cluster_sequence()
const{
528 return (_structure) && (_structure->has_associated_cluster_sequence());
535 if (! has_associated_cluster_sequence())
return NULL;
537 return _structure->associated_cluster_sequence();
544bool PseudoJet::has_valid_cluster_sequence()
const{
545 return (_structure) && (_structure->has_valid_cluster_sequence());
555 return validated_structure_ptr()->validated_cs();
566 _structure = structure_in;
571bool PseudoJet::has_structure()
const{
572 return (
bool) _structure;
582 return _structure.get();
597 return _structure.get();
607 throw Error(
"Trying to access the structure of a PseudoJet which has no associated structure");
608 return _structure.get();
627 return validated_structure_ptr()->has_partner(*
this, partner);
638 return validated_structure_ptr()->has_child(*
this, child);
649 return validated_structure_ptr()->has_parents(*
this, parent1, parent2);
658bool PseudoJet::contains(
const PseudoJet &constituent)
const{
659 return validated_structure_ptr()->object_in_jet(constituent, *
this);
669 return validated_structure_ptr()->object_in_jet(*
this, jet);
675bool PseudoJet::has_constituents()
const{
676 return (_structure) && (_structure->has_constituents());
681vector<PseudoJet> PseudoJet::constituents()
const{
682 return validated_structure_ptr()->constituents(*
this);
688bool PseudoJet::has_exclusive_subjets()
const{
689 return (_structure) && (_structure->has_exclusive_subjets());
704std::vector<PseudoJet> PseudoJet::exclusive_subjets (
const double dcut)
const {
705 return validated_structure_ptr()->exclusive_subjets(*
this, dcut);
715int PseudoJet::n_exclusive_subjets(
const double dcut)
const {
716 return validated_structure_ptr()->n_exclusive_subjets(*
this, dcut);
728std::vector<PseudoJet> PseudoJet::exclusive_subjets_up_to (
int nsub)
const {
729 return validated_structure_ptr()->exclusive_subjets_up_to(*
this, nsub);
735std::vector<PseudoJet> PseudoJet::exclusive_subjets (
int nsub)
const {
736 vector<PseudoJet> subjets = exclusive_subjets_up_to(nsub);
737 if (
int(subjets.size()) < nsub) {
739 err <<
"Requested " << nsub <<
" exclusive subjets, but there were only "
740 << subjets.size() <<
" particles in the jet";
741 throw Error(err.str());
752double PseudoJet::exclusive_subdmerge(
int nsub)
const {
753 return validated_structure_ptr()->exclusive_subdmerge(*
this, nsub);
763double PseudoJet::exclusive_subdmerge_max(
int nsub)
const {
764 return validated_structure_ptr()->exclusive_subdmerge_max(*
this, nsub);
772bool PseudoJet::has_pieces()
const{
773 return ((_structure) && (_structure->has_pieces(*
this)));
781std::vector<PseudoJet> PseudoJet::pieces()
const{
782 return validated_structure_ptr()->pieces(*
this);
802 if (csab == NULL)
throw Error(
"you requested jet-area related information, but the PseudoJet does not have associated area information.");
809bool PseudoJet::has_area()
const{
811 if (! has_structure())
return false;
812 return (validated_structure_ptr()->has_area() != 0);
818double PseudoJet::area()
const{
819 return validated_structure_ptr()->
area(*
this);
826double PseudoJet::area_error()
const{
827 return validated_structure_ptr()->area_error(*
this);
840bool PseudoJet::is_pure_ghost()
const{
855PseudoJet::InexistentUserInfo::InexistentUserInfo() :
Error(
"you attempted to perform a dynamic cast of a PseudoJet's extra info, but the extra info pointer was null")
862void sort_indices(vector<int> & indices,
863 const vector<double> & values) {
865 sort(indices.begin(), indices.end(), index_sort_helper);
872 vector<double> minus_kt2(jets.size());
873 for (
size_t i = 0; i < jets.size(); i++) {minus_kt2[i] = -jets[i].kt2();}
880 vector<double> rapidities(jets.size());
881 for (
size_t i = 0; i < jets.size(); i++) {rapidities[i] = jets[i].rap();}
888 vector<double> energies(jets.size());
889 for (
size_t i = 0; i < jets.size(); i++) {energies[i] = -jets[i].E();}
896 vector<double> pz(jets.size());
897 for (
size_t i = 0; i < jets.size(); i++) {pz[i] = jets[i].pz();}
915 for (
unsigned int i=0; i<
pieces.size(); i++)
920 CompositeJetStructure *cj_struct =
new CompositeJetStructure(
pieces);
922 result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
929 return join(vector<PseudoJet>(1,j1));
base class that sets interface for extensions of ClusterSequence that provide information about the a...
virtual double area(const PseudoJet &) const
return the area associated with the given jet; this base class returns 0.
base class corresponding to errors that can be thrown by FastJet
Contains any information related to the clustering that should be directly accessible to PseudoJet.
Class to contain pseudojets, including minimal information of use to jet-clustering routines.
PseudoJet()
default constructor, which as of FJ3.0 provides an object for which all operations are now valid and ...
void set_cached_rap_phi(double rap, double phi)
in some cases when setting a 4-momentum, the user/program knows what rapidity and azimuth are associa...
double rap() const
returns the rapidity or some large value when the rapidity is infinite
const UserInfoBase * user_info_ptr() const
retrieve a pointer to the (const) user information
virtual bool is_pure_ghost() const
true if this jet is made exclusively of ghosts.
double phi() const
returns phi (in the range 0..2pi)
const PseudoJetStructureBase * structure_ptr() const
return a pointer to the structure (of type PseudoJetStructureBase*) associated with this PseudoJet.
int cluster_hist_index() const
return the cluster_hist_index, intended to be used by clustering routines.
double m() const
returns the invariant mass (If m2() is negative then -sqrt(-m2()) is returned, as in CLHEP)
int user_index() const
return the user_index,
virtual std::vector< PseudoJet > pieces() const
retrieve the pieces that make up the jet.
virtual PseudoJet area_4vector() const
return the jet 4-vector area.
An implementation of shared pointers that is broadly similar to C++11 shared_ptr (https://en....
Selector operator*(const Selector &s1, const Selector &s2)
successive application of 2 selectors
vector< PseudoJet > sorted_by_rapidity(const vector< PseudoJet > &jets)
return a vector of jets sorted into increasing rapidity
const double MaxRap
Used to protect against parton-level events where pt can be zero for some partons,...
vector< PseudoJet > sorted_by_E(const vector< PseudoJet > &jets)
return a vector of jets sorted into decreasing energy
bool have_same_momentum(const PseudoJet &jeta, const PseudoJet &jetb)
returns true if the momenta of the two input jets are identical
bool operator==(const PseudoJet &a, const PseudoJet &b)
returns true if the 4 momentum components of the two PseudoJets are identical and all the internal in...
std::vector< T > objects_sorted_by_values(const std::vector< T > &objects, const std::vector< double > &values)
given a vector of values with a one-to-one correspondence with the vector of objects,...
vector< PseudoJet > sorted_by_pt(const vector< PseudoJet > &jets)
return a vector of jets sorted into decreasing kt2
double theta(const PseudoJet &a, const PseudoJet &b)
returns the angle between a and b
PseudoJet PtYPhiM(double pt, double y, double phi, double m)
return a pseudojet with the given pt, y, phi and mass
vector< PseudoJet > sorted_by_pz(const vector< PseudoJet > &jets)
return a vector of jets sorted into increasing pz