FastJet 3.0alpha3
JetDefinition.cc
00001 //STARTHEADER
00002 // $Id: JetDefinition.cc 2222 2011-06-02 23:27:59Z 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   _recombiner = 0;
00138 }
00139 
00140 
00141 // returns true if the current jet definitions shares the same
00142 // recombiner as teh one passed as an argument
00143 bool JetDefinition::has_same_recombiner(const JetDefinition &other_jd) const{
00144   // first make sure that they have the same recombination scheme
00145   const RecombinationScheme & scheme = recombination_scheme();
00146   if (other_jd.recombination_scheme() != scheme) return false;
00147 
00148   // if the scheme is "external", also check that they ahve the same
00149   // recombiner
00150   return (scheme != external_scheme) 
00151     || (recombiner() == other_jd.recombiner());
00152 }
00153 
00154 string JetDefinition::DefaultRecombiner::description() const {
00155   switch(_recomb_scheme) {
00156   case E_scheme:
00157     return "E scheme recombination";
00158   case pt_scheme:
00159     return "pt scheme recombination";
00160   case pt2_scheme:
00161     return "pt2 scheme recombination";
00162   case Et_scheme:
00163     return "Et scheme recombination";
00164   case Et2_scheme:
00165     return "Et2 scheme recombination";
00166   case BIpt_scheme:
00167     return "boost-invariant pt scheme recombination";
00168   case BIpt2_scheme:
00169     return "boost-invariant pt2 scheme recombination";
00170   default:
00171     ostringstream err;
00172     err << "DefaultRecombiner: unrecognized recombination scheme " 
00173         << _recomb_scheme;
00174     throw Error(err.str());
00175   }
00176 }
00177 
00178 
00179 void JetDefinition::DefaultRecombiner::recombine(
00180            const PseudoJet & pa, const PseudoJet & pb,
00181            PseudoJet & pab) const {
00182   
00183   double weighta, weightb;
00184 
00185   switch(_recomb_scheme) {
00186   case E_scheme:
00187     pab = pa + pb; 
00188     return;
00189   // all remaining schemes are massless recombinations and locally
00190   // we just set weights, while the hard work is done below...
00191   case pt_scheme:
00192   case Et_scheme:
00193   case BIpt_scheme:
00194     weighta = pa.perp(); 
00195     weightb = pb.perp();
00196     break;
00197   case pt2_scheme:
00198   case Et2_scheme:
00199   case BIpt2_scheme:
00200     weighta = pa.perp2(); 
00201     weightb = pb.perp2();
00202     break;
00203   default:
00204     ostringstream err;
00205     err << "DefaultRecombiner: unrecognized recombination scheme " 
00206         << _recomb_scheme;
00207     throw Error(err.str());
00208   }
00209 
00210   double perp_ab = pa.perp() + pb.perp();
00211   if (perp_ab != 0.0) { // weights also non-zero...
00212     double y_ab    = (weighta * pa.rap() + weightb * pb.rap())/(weighta+weightb);
00213     
00214     // take care with periodicity in phi...
00215     double phi_a = pa.phi(), phi_b = pb.phi();
00216     if (phi_a - phi_b > pi)  phi_b += twopi;
00217     if (phi_a - phi_b < -pi) phi_b -= twopi;
00218     double phi_ab = (weighta * phi_a + weightb * phi_b)/(weighta+weightb);
00219     
00220     pab = PseudoJet(perp_ab*cos(phi_ab),
00221                     perp_ab*sin(phi_ab),
00222                     perp_ab*sinh(y_ab),
00223                     perp_ab*cosh(y_ab));
00224   } else { // weights are zero
00225     pab = PseudoJet(0.0,0.0,0.0,0.0);
00226   }
00227 }
00228 
00229 
00230 void JetDefinition::DefaultRecombiner::preprocess(PseudoJet & p) const {
00231   switch(_recomb_scheme) {
00232   case E_scheme:
00233   case BIpt_scheme:
00234   case BIpt2_scheme:
00235     break;
00236   case pt_scheme:
00237   case pt2_scheme:
00238     {
00239       // these schemes (as in the ktjet implementation) need massless
00240       // initial 4-vectors with essentially E=|p|.
00241       double newE = sqrt(p.perp2()+p.pz()*p.pz());
00242       int    user_index = p.user_index();
00243       p = PseudoJet(p.px(), p.py(), p.pz(), newE);
00244       p.set_user_index(user_index);
00245     }
00246     break;
00247   case Et_scheme:
00248   case Et2_scheme:
00249     {
00250       // these schemes (as in the ktjet implementation) need massless
00251       // initial 4-vectors with essentially E=|p|.
00252       double rescale = p.E()/sqrt(p.perp2()+p.pz()*p.pz());
00253       int    user_index = p.user_index();
00254       p = PseudoJet(rescale*p.px(), rescale*p.py(), rescale*p.pz(), p.E());
00255       p.set_user_index(user_index);
00256     }
00257     break;
00258   default:
00259     ostringstream err;
00260     err << "DefaultRecombiner: unrecognized recombination scheme " 
00261         << _recomb_scheme;
00262     throw Error(err.str());
00263   }
00264 }
00265 
00266 void JetDefinition::Plugin::set_ghost_separation_scale(double scale) const {
00267       throw Error("set_ghost_separation_scale not supported");
00268 }
00269 
00270 
00271 
00272 //-------------------------------------------------------------------------------
00273 // helper functions to build a jet made of pieces
00274 //
00275 // This is the extended version with support for a user-defined
00276 // recombination-scheme
00277 // -------------------------------------------------------------------------------
00278 
00279 // build a "CompositeJet" from the vector of its pieces
00280 //
00281 // the user passes the reciombination scheme used to "sum" the pieces.
00282 PseudoJet join(const vector<PseudoJet> & pieces, const JetDefinition::Recombiner & recombiner){
00283   // compute the total momentum
00284   //--------------------------------------------------
00285   PseudoJet result;  // automatically initialised to 0
00286   if (pieces.size()>0){
00287     result = pieces[0];
00288     for (unsigned int i=1; i<pieces.size(); i++)
00289       recombiner.plus_equal(result, pieces[i]);
00290   }
00291 
00292   // attach a CompositeJetStructure to the result
00293   //--------------------------------------------------
00294   CompositeJetStructure *cj_struct = new CompositeJetStructure(pieces, &recombiner);
00295 
00296   result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(cj_struct));
00297 
00298   return result;
00299 }
00300 
00301 // build a "CompositeJet" from a single PseudoJet
00302 PseudoJet join(const PseudoJet & j1, 
00303                const JetDefinition::Recombiner & recombiner){
00304   return join(vector<PseudoJet>(1,j1), recombiner);
00305 }
00306 
00307 // build a "CompositeJet" from two PseudoJet
00308 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, 
00309                const JetDefinition::Recombiner & recombiner){
00310   vector<PseudoJet> pieces;
00311   pieces.push_back(j1);
00312   pieces.push_back(j2);
00313   return join(pieces, recombiner);
00314 }
00315 
00316 // build a "CompositeJet" from 3 PseudoJet
00317 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, 
00318                const JetDefinition::Recombiner & recombiner){
00319   vector<PseudoJet> pieces;
00320   pieces.push_back(j1);
00321   pieces.push_back(j2);
00322   pieces.push_back(j3);
00323   return join(pieces, recombiner);
00324 }
00325 
00326 // build a "CompositeJet" from 4 PseudoJet
00327 PseudoJet join(const PseudoJet & j1, const PseudoJet & j2, const PseudoJet & j3, const PseudoJet & j4,
00328                const JetDefinition::Recombiner & recombiner){
00329   vector<PseudoJet> pieces;
00330   pieces.push_back(j1);
00331   pieces.push_back(j2);
00332   pieces.push_back(j3);
00333   pieces.push_back(j4);
00334   return join(pieces, recombiner);
00335 }
00336 
00337 
00338  
00339 
00340 FASTJET_END_NAMESPACE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends