FastJet 3.0beta1
JetDefinition.cc
00001 //STARTHEADER
00002 // $Id: JetDefinition.cc 2386 2011-07-07 13:53:47Z soyez $
00003 //
00004 // Copyright (c) 2005-2007, Matteo Cacciari and Gavin Salam
00005 //
00006 //----------------------------------------------------------------------
00007 // This file is part of FastJet.
00008 //
00009 //  FastJet is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU General Public License as published by
00011 //  the Free Software Foundation; either version 2 of the License, or
00012 //  (at your option) any later version.
00013 //
00014 //  The algorithms that underlie FastJet have required considerable
00015 //  development and are described in hep-ph/0512210. If you use
00016 //  FastJet as part of work towards a scientific publication, please
00017 //  include a citation to the FastJet paper.
00018 //
00019 //  FastJet is distributed in the hope that it will be useful,
00020 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 //  GNU General Public License for more details.
00023 //
00024 //  You should have received a copy of the GNU General Public License
00025 //  along with FastJet; if not, write to the Free Software
00026 //  Foundation, Inc.:
00027 //      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028 //----------------------------------------------------------------------
00029 //ENDHEADER
00030 
00031 #include "fastjet/JetDefinition.hh"
00032 #include "fastjet/Error.hh"
00033 #include "fastjet/CompositeJetStructure.hh"
00034 #include<sstream>
00035 
00036 FASTJET_BEGIN_NAMESPACE      // defined in fastjet/internal/base.hh
00037 
00038 using namespace std;
00039 
00040 //----------------------------------------------------------------------
00041 // [NB: implementation was getting complex, so in 2.4-devel moved it
00042 //  from .hh to .cc]
00043 JetDefinition::JetDefinition(JetAlgorithm jet_algorithm, 
00044                              double R, 
00045                              Strategy strategy,
00046                              RecombinationScheme recomb_scheme,
00047                              int nparameters) :
00048   _jet_algorithm(jet_algorithm), _Rparam(R), _strategy(strategy) {
00049 
00050   // set R parameter or ensure its sensibleness, as appropriate
00051   if (jet_algorithm == ee_kt_algorithm) {
00052     _Rparam = 4.0; // introduce a fictional R that ensures that
00053                    // our clustering sequence will not produce
00054                    // "beam" jets except when only a single particle remains.
00055                    // Any value > 2 would have done here
00056   } else {
00057     // We maintain some limit on R because particles with pt=0, m=0
00058     // can have rapidities O(10000) and one doesn't want the
00059     // clustering to start including them as if their rapidities were
00060     // physical.
00061     assert ( R < 1000.0);
00062   }
00063 
00064   // cross-check the number of parameters that were declared in setting up the
00065   // algorithm (passed internally from the public constructors)
00066   ostringstream oss;
00067   switch (jet_algorithm) {
00068   case ee_kt_algorithm:
00069     if (nparameters != 0) oss << "ee_kt_algorithm should be constructed with 0 parameters but was called with " 
00070                               << nparameters << " parameter(s)\n";
00071     break;
00072   case genkt_algorithm: 
00073   case ee_genkt_algorithm: 
00074     if (nparameters != 2) oss << "(ee_)genkt_algorithm should be constructed with 2 parameters but was called with " 
00075                               << nparameters << " parameter(s)\n";
00076     break;
00077   default:
00078     if (nparameters != 1)
00079     oss << "The jet algorithm you requested ("
00080         << jet_algorithm << ") should be constructed with 1 parameter but was called with " 
00081         << nparameters << " parameter(s)\n";
00082   }
00083   if (oss.str() != "") throw Error(oss.str()); 
00084 
00085   // make sure the strategy requested is sensible
00086   assert (_strategy  != plugin_strategy);
00087 
00088   _plugin = NULL;
00089   set_recombination_scheme(recomb_scheme);
00090   set_extra_param(0.0); // make sure it's defined
00091 }
00092 
00093 
00094 //----------------------------------------------------------------------
00095 string JetDefinition::description() const {
00096   ostringstream name;
00097   if (jet_algorithm() == plugin_algorithm) {
00098     return plugin()->description();
00099   } else if (jet_algorithm() == kt_algorithm) {
00100     name << "Longitudinally invariant kt algorithm with R = " << R();
00101     name << " and " << recombiner()->description();
00102   } else if (jet_algorithm() == cambridge_algorithm) {
00103     name << "Longitudinally invariant Cambridge/Aachen algorithm with R = " 
00104          << R() ;
00105     name << " and " << recombiner()->description();
00106   } else if (jet_algorithm() == antikt_algorithm) {
00107     name << "Longitudinally invariant anti-kt algorithm with R = " 
00108          << R() ;
00109     name << " and " << recombiner()->description();
00110   } else if (jet_algorithm() == genkt_algorithm) {
00111     name << "Longitudinally invariant generalised kt algorithm with R = " 
00112          << R() << ", p = " << extra_param();
00113     name << " and " << recombiner()->description();
00114   } else if (jet_algorithm() == cambridge_for_passive_algorithm) {
00115     name << "Longitudinally invariant Cambridge/Aachen algorithm with R = " 
00116          << R() << "and a special hack whereby particles with kt < " 
00117          << extra_param() << "are treated as passive ghosts";
00118   } else if (jet_algorithm() == ee_kt_algorithm) {
00119     name << "e+e- kt (Durham) algorithm (NB: no R)";
00120     name << " with " << recombiner()->description();
00121   } else if (jet_algorithm() == ee_genkt_algorithm) {
00122     name << "e+e- generalised kt algorithm with R = " 
00123          << R() << ", p = " << extra_param();
00124     name << " and " << recombiner()->description();
00125   } else if (jet_algorithm() == undefined_jet_algorithm) {
00126     name << "uninitialised JetDefinition (jet_algorithm=undefined_jet_algorithm)" ;
00127   } else {
00128     throw Error("JetDefinition::description(): unrecognized jet_algorithm");
00129   }
00130   return name.str();
00131 }
00132 
00133 
00134 void JetDefinition::set_recombination_scheme(
00135                                RecombinationScheme recomb_scheme) {
00136   _default_recombiner = JetDefinition::DefaultRecombiner(recomb_scheme);
00137 
00138   // do not forget to delete the existing recombiner if needed
00139   if (_recombiner_shared()) _recombiner_shared.reset();
00140 
00141   _recombiner = 0;
00142 }
00143 
00144 
00145 // returns true if the current jet definitions shares the same
00146 // recombiner as teh one passed as an argument
00147 bool JetDefinition::has_same_recombiner(const JetDefinition &other_jd) const{
00148   // first make sure that they have the same recombination scheme
00149   const RecombinationScheme & scheme = recombination_scheme();
00150   if (other_jd.recombination_scheme() != scheme) return false;
00151 
00152   // if the scheme is "external", also check that they ahve the same
00153   // recombiner
00154   return (scheme != external_scheme) 
00155     || (recombiner() == other_jd.recombiner());
00156 }
00157 
00158 /// allows to let the JetDefinition handle the deletion of the
00159 /// recombiner when it is no longer used
00160 void JetDefinition::delete_recombiner_when_unused(){
00161   if (_recombiner == 0){
00162     throw Error("tried to call JetDefinition::delete_recombiner_when_unused() for a JetDefinition without a user-defined recombination scheme");
00163   }
00164 
00165   _recombiner_shared.reset(_recombiner);
00166 }
00167 
00168 /// allows to let the JetDefinition handle the deletion of the
00169 /// plugin when it is no longer used
00170 void JetDefinition::delete_plugin_when_unused(){
00171   if (_plugin == 0){
00172     throw Error("tried to call JetDefinition::delete_plugin_when_unused() for a JetDefinition without a plugin");
00173   }
00174 
00175   _plugin_shared.reset(_plugin);
00176 }
00177 
00178 
00179 
00180 string JetDefinition::DefaultRecombiner::description() const {
00181   switch(_recomb_scheme) {
00182   case E_scheme:
00183     return "E scheme recombination";
00184   case pt_scheme:
00185     return "pt scheme recombination";
00186   case pt2_scheme:
00187     return "pt2 scheme recombination";
00188   case Et_scheme:
00189     return "Et scheme recombination";
00190   case Et2_scheme:
00191     return "Et2 scheme recombination";
00192   case BIpt_scheme:
00193     return "boost-invariant pt scheme recombination";
00194   case BIpt2_scheme:
00195     return "boost-invariant pt2 scheme recombination";
00196   default:
00197     ostringstream err;
00198     err << "DefaultRecombiner: unrecognized recombination scheme " 
00199         << _recomb_scheme;
00200     throw Error(err.str());
00201   }
00202 }
00203 
00204 
00205 void JetDefinition::DefaultRecombiner::recombine(
00206            const PseudoJet & pa, const PseudoJet & pb,
00207            PseudoJet & pab) const {
00208   
00209   double weighta, weightb;
00210 
00211   switch(_recomb_scheme) {
00212   case E_scheme:
00213     // a call to reset turns out to be somewhat more efficient
00214     // than a sum and assignment
00215     //pab = pa + pb; 
00216     pab.reset(pa.px()+pb.px(),
00217               pa.py()+pb.py(),
00218               pa.pz()+pb.pz(),
00219               pa.E ()+pb.E ());
00220     return;
00221   // all remaining schemes are massless recombinations and locally
00222   // we just set weights, while the hard work is done below...
00223   case pt_scheme:
00224   case Et_scheme:
00225   case BIpt_scheme:
00226     weighta = pa.perp(); 
00227     weightb = pb.perp();
00228     break;
00229   case pt2_scheme:
00230   case Et2_scheme:
00231   case BIpt2_scheme:
00232     weighta = pa.perp2(); 
00233     weightb = pb.perp2();
00234     break;
00235   default:
00236     ostringstream err;
00237     err << "DefaultRecombiner: unrecognized recombination scheme " 
00238         << _recomb_scheme;
00239     throw Error(err.str());
00240   }
00241 
00242   double perp_ab = pa.perp() + pb.perp();
00243   if (perp_ab != 0.0) { // weights also non-zero...
00244     double y_ab    = (weighta * pa.rap() + weightb * pb.rap())/(weighta+weightb);
00245     
00246     // take care with periodicity in phi...
00247     double phi_a = pa.phi(), phi_b = pb.phi();
00248     if (phi_a - phi_b > pi)  phi_b += twopi;
00249     if (phi_a - phi_b < -pi) phi_b -= twopi;
00250     double phi_ab = (weighta * phi_a + weightb * phi_b)/(weighta+weightb);
00251 
00252     // this is much more efficient...
00253     pab.reset_PtYPhiM(perp_ab,y_ab,phi_ab);
00254     // pab = PseudoJet(perp_ab*cos(phi_ab),
00255     //              perp_ab*sin(phi_ab),
00256     //              perp_ab*sinh(y_ab),
00257     //              perp_ab*cosh(y_ab));
00258   } else { // weights are zero
00259     //pab = PseudoJet(0.0,0.0,0.0,0.0);
00260     pab.reset(0.0, 0.0, 0.0, 0.0);
00261   }
00262 }
00263 
00264 
00265 void JetDefinition::DefaultRecombiner::preprocess(PseudoJet & p) const {
00266   switch(_recomb_scheme) {
00267   case E_scheme:
00268   case BIpt_scheme:
00269   case BIpt2_scheme:
00270     break;
00271   case pt_scheme:
00272   case pt2_scheme:
00273     {
00274       // these schemes (as in the ktjet implementation) need massless
00275       // initial 4-vectors with essentially E=|p|.
00276       double newE = sqrt(p.perp2()+p.pz()*p.pz());
00277       p.reset_momentum(p.px(), p.py(), p.pz(), newE);
00278       // FJ2.x version
00279       // int    user_index = p.user_index();
00280       // p = PseudoJet(p.px(), p.py(), p.pz(), newE);
00281       // p.set_user_index(user_index);
00282     }
00283     break;
00284   case Et_scheme:
00285   case Et2_scheme:
00286     {
00287       // these schemes (as in the ktjet implementation) need massless
00288       // initial 4-vectors with essentially E=|p|.
00289       double rescale = p.E()/sqrt(p.perp2()+p.pz()*p.pz());
00290       p.reset_momentum(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
00291       // FJ2.x version
00292       // int    user_index = p.user_index();
00293       // p = PseudoJet(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
00294       // p.set_user_index(user_index);
00295     }
00296     break;
00297   default:
00298     ostringstream err;
00299     err << "DefaultRecombiner: unrecognized recombination scheme " 
00300         << _recomb_scheme;
00301     throw Error(err.str());
00302   }
00303 }
00304 
00305 void JetDefinition::Plugin::set_ghost_separation_scale(double scale) const {
00306       throw Error("set_ghost_separation_scale not supported");
00307 }
00308 
00309 
00310 
00311 //-------------------------------------------------------------------------------
00312 // helper functions to build a jet made of pieces
00313 //
00314 // This is the extended version with support for a user-defined
00315 // recombination-scheme
00316 // -------------------------------------------------------------------------------
00317 
00318 // build a "CompositeJet" from the vector of its pieces
00319 //
00320 // the user passes the reciombination scheme used to "sum" the pieces.
00321 PseudoJet join(const vector<PseudoJet> & pieces, const JetDefinition::Recombiner & recombiner){
00322   // compute the total momentum
00323   //--------------------------------------------------
00324   PseudoJet result;  // automatically initialised to 0
00325   if (pieces.size()>0){
00326     result = pieces[0];
00327     for (unsigned int i=1; i<pieces.size(); i++)
00328       recombiner.plus_equal(result, pieces[i]);
00329   }
00330 
00331   // attach a CompositeJetStructure to the result
00332   //--------------------------------------------------
00333   CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces, &recombiner);
00334 
00335   result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
00336 
00337   return result;
00338 }
00339 
00340 // build a "CompositeJet" from a single PseudoJet
00341 PseudoJet join(const PseudoJet & j1, 
00342                const JetDefinition::Recombiner & recombiner){
00343   return join(vector<PseudoJet>(1,j1), recombiner);
00344 }
00345 
00346 // build a "CompositeJet" from two PseudoJet
00347 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, 
00348                const JetDefinition::Recombiner & recombiner){
00349   vector<PseudoJet> pieces;
00350   pieces.push_back(j1);
00351   pieces.push_back(j2);
00352   return join(pieces, recombiner);
00353 }
00354 
00355 // build a "CompositeJet" from 3 PseudoJet
00356 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, 
00357                const JetDefinition::Recombiner & recombiner){
00358   vector<PseudoJet> pieces;
00359   pieces.push_back(j1);
00360   pieces.push_back(j2);
00361   pieces.push_back(j3);
00362   return join(pieces, recombiner);
00363 }
00364 
00365 // build a "CompositeJet" from 4 PseudoJet
00366 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4,
00367                const JetDefinition::Recombiner & recombiner){
00368   vector<PseudoJet> pieces;
00369   pieces.push_back(j1);
00370   pieces.push_back(j2);
00371   pieces.push_back(j3);
00372   pieces.push_back(j4);
00373   return join(pieces, recombiner);
00374 }
00375 
00376 
00377  
00378 
00379 FASTJET_END_NAMESPACE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends