CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/RecoJets/JetProducers/plugins/VirtualJetProducer.cc

Go to the documentation of this file.
00001 
00002 //
00003 // VirtualJetProducer
00004 // ------------------
00005 //
00006 //            04/21/2009 Philipp Schieferdecker <philipp.schieferdecker@cern.ch>
00008 
00009 #include "RecoJets/JetProducers/plugins/VirtualJetProducer.h"
00010 #include "RecoJets/JetProducers/interface/JetSpecific.h"
00011 #include "RecoJets/JetProducers/interface/BackgroundEstimator.h"
00012 #include "RecoJets/JetProducers/interface/VirtualJetProducerHelper.h"
00013 
00014 #include "FWCore/Framework/interface/Event.h"
00015 #include "FWCore/Framework/interface/EventSetup.h"
00016 #include "FWCore/Framework/interface/ESHandle.h"
00017 #include "FWCore/Utilities/interface/Exception.h"
00018 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00019 #include "FWCore/Framework/interface/MakerMacros.h"
00020 
00021 #include "DataFormats/Common/interface/View.h"
00022 #include "DataFormats/Common/interface/Handle.h"
00023 #include "DataFormats/VertexReco/interface/Vertex.h"
00024 #include "DataFormats/VertexReco/interface/VertexFwd.h"
00025 #include "DataFormats/JetReco/interface/CaloJetCollection.h"
00026 #include "DataFormats/JetReco/interface/GenJetCollection.h"
00027 #include "DataFormats/JetReco/interface/PFJetCollection.h"
00028 #include "DataFormats/JetReco/interface/BasicJetCollection.h"
00029 #include "DataFormats/JetReco/interface/TrackJetCollection.h"
00030 #include "DataFormats/JetReco/interface/PFClusterJetCollection.h"
00031 #include "DataFormats/Candidate/interface/CandidateFwd.h"
00032 #include "DataFormats/Candidate/interface/LeafCandidate.h"
00033 #include "DataFormats/Math/interface/deltaR.h"
00034 
00035 #include "fastjet/SISConePlugin.hh"
00036 #include "fastjet/CMSIterativeConePlugin.hh"
00037 #include "fastjet/ATLASConePlugin.hh"
00038 #include "fastjet/CDFMidPointPlugin.hh"
00039 
00040 #include <iostream>
00041 #include <memory>
00042 #include <algorithm>
00043 #include <limits>
00044 #include <cmath>
00045 
00046 
00047 using namespace std;
00048 
00049 
00050 namespace reco {
00051   namespace helper {
00052     struct GreaterByPtPseudoJet {
00053       bool operator()( const fastjet::PseudoJet & t1, const fastjet::PseudoJet & t2 ) const {
00054         return t1.perp() > t2.perp();
00055       }
00056     };
00057 
00058   }
00059 }
00060 
00061 //______________________________________________________________________________
00062 const char *VirtualJetProducer::JetType::names[] = {
00063   "BasicJet","GenJet","CaloJet","PFJet","TrackJet","PFClusterJet"
00064 };
00065 
00066 
00067 //______________________________________________________________________________
00068 VirtualJetProducer::JetType::Type
00069 VirtualJetProducer::JetType::byName(const string &name)
00070 {
00071   const char **pos = std::find(names, names + LastJetType, name);
00072   if (pos == names + LastJetType) {
00073     std::string errorMessage="Requested jetType not supported: "+name+"\n"; 
00074     throw cms::Exception("Configuration",errorMessage);
00075   }
00076   return (Type)(pos-names);
00077 }
00078 
00079 
00080 void VirtualJetProducer::makeProduces( std::string alias, std::string tag ) 
00081 {
00082   if (makeCaloJet(jetTypeE)) {
00083     produces<reco::CaloJetCollection>(tag).setBranchAlias(alias);
00084   }
00085   else if (makePFJet(jetTypeE)) {
00086     produces<reco::PFJetCollection>(tag).setBranchAlias(alias);
00087   }
00088   else if (makeGenJet(jetTypeE)) {
00089     produces<reco::GenJetCollection>(tag).setBranchAlias(alias);
00090   }
00091   else if (makeTrackJet(jetTypeE)) {
00092     produces<reco::TrackJetCollection>(tag).setBranchAlias(alias);
00093   }
00094   else if (makePFClusterJet(jetTypeE)) {
00095     produces<reco::PFClusterJetCollection>(tag).setBranchAlias(alias);
00096   }
00097   else if (makeBasicJet(jetTypeE)) {
00098     produces<reco::BasicJetCollection>(tag).setBranchAlias(alias);
00099   }
00100 }
00101 
00103 // construction / destruction
00105 
00106 //______________________________________________________________________________
00107 VirtualJetProducer::VirtualJetProducer(const edm::ParameterSet& iConfig)
00108   : moduleLabel_   (iConfig.getParameter<string>       ("@module_label"))
00109   , src_           (iConfig.getParameter<edm::InputTag>("src"))
00110   , srcPVs_        (iConfig.getParameter<edm::InputTag>("srcPVs"))
00111   , jetType_       (iConfig.getParameter<string>       ("jetType"))
00112   , jetAlgorithm_  (iConfig.getParameter<string>       ("jetAlgorithm"))
00113   , rParam_        (iConfig.getParameter<double>       ("rParam"))
00114   , inputEtMin_    (iConfig.getParameter<double>       ("inputEtMin"))
00115   , inputEMin_     (iConfig.getParameter<double>       ("inputEMin"))
00116   , jetPtMin_      (iConfig.getParameter<double>       ("jetPtMin"))
00117   , doPVCorrection_(iConfig.getParameter<bool>         ("doPVCorrection"))
00118   , restrictInputs_(false)
00119   , maxInputs_(99999999)
00120   , doAreaFastjet_ (iConfig.getParameter<bool>         ("doAreaFastjet"))
00121   , doAreaDiskApprox_       (false)
00122   , doRhoFastjet_  (iConfig.getParameter<bool>         ("doRhoFastjet"))
00123   , voronoiRfact_           (-9)
00124   , doPUOffsetCorr_(iConfig.getParameter<bool>         ("doPUOffsetCorr"))
00125   , puWidth_(0)
00126   , nExclude_(0)
00127   , jetCollInstanceName_ ("")
00128 {
00129   anomalousTowerDef_ = std::auto_ptr<AnomalousTower>(new AnomalousTower(iConfig));
00130 
00131   //
00132   // additional parameters to think about:
00133   // - overlap threshold (set to 0.75 for the time being)
00134   // - p parameter for generalized kT (set to -2 for the time being)
00135   // - fastjet PU subtraction parameters (not yet considered)
00136   //
00137   if (jetAlgorithm_=="SISCone") {
00138     fjPlugin_ = PluginPtr( new fastjet::SISConePlugin(rParam_,0.75,0,0.0,false,
00139                                                       fastjet::SISConePlugin::SM_pttilde) );
00140     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(&*fjPlugin_) );
00141   }
00142   else if (jetAlgorithm_=="IterativeCone") {
00143     fjPlugin_ = PluginPtr(new fastjet::CMSIterativeConePlugin(rParam_,1.0));
00144     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00145   }
00146   else if (jetAlgorithm_=="CDFMidPoint") {
00147     fjPlugin_ = PluginPtr(new fastjet::CDFMidPointPlugin(rParam_,0.75));
00148     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00149   }
00150   else if (jetAlgorithm_=="ATLASCone") {
00151     fjPlugin_ = PluginPtr(new fastjet::ATLASConePlugin(rParam_));
00152     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00153   }
00154   else if (jetAlgorithm_=="Kt")
00155     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(fastjet::kt_algorithm,rParam_));
00156   else if (jetAlgorithm_=="CambridgeAachen")
00157     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(fastjet::cambridge_algorithm,
00158                                                            rParam_) );
00159   else if (jetAlgorithm_=="AntiKt")
00160     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::antikt_algorithm,rParam_) );
00161   else if (jetAlgorithm_=="GeneralizedKt")
00162     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::genkt_algorithm,
00163                                                             rParam_,-2) );
00164   else
00165     throw cms::Exception("Invalid jetAlgorithm")
00166       <<"Jet algorithm for VirtualJetProducer is invalid, Abort!\n";
00167   
00168   jetTypeE=JetType::byName(jetType_);
00169 
00170   if ( iConfig.exists("jetCollInstanceName") ) {
00171     jetCollInstanceName_ = iConfig.getParameter<string>("jetCollInstanceName");
00172   }
00173 
00174   if ( doPUOffsetCorr_ ) {
00175      if ( jetTypeE != JetType::CaloJet ) {
00176         throw cms::Exception("InvalidInput") << "Can only offset correct jets of type CaloJet";
00177      }
00178      
00179      if(iConfig.exists("subtractorName")) puSubtractorName_  =  iConfig.getParameter<string> ("subtractorName");
00180      else puSubtractorName_ = std::string();
00181      
00182      if(puSubtractorName_.empty()){
00183        edm::LogWarning("VirtualJetProducer") << "Pile Up correction on; however, pile up type is not specified. Using default... \n";
00184        subtractor_ =  boost::shared_ptr<PileUpSubtractor>(new PileUpSubtractor(iConfig));
00185      }else{
00186        subtractor_ =  boost::shared_ptr<PileUpSubtractor>(PileUpSubtractorFactory::get()->create( puSubtractorName_, iConfig));
00187      }
00188   }
00189 
00190   // do approximate disk-based area calculation => warn if conflicting request
00191   if (iConfig.exists("doAreaDiskApprox")) {
00192     doAreaDiskApprox_ = iConfig.getParameter<bool>("doAreaDiskApprox");
00193     if (doAreaDiskApprox_ && doAreaFastjet_)
00194       throw cms::Exception("Conflicting area calculations") << "Both the calculation of jet area via fastjet and via an analytical disk approximation have been requested. Please decide on one.\n";
00195 
00196   }
00197   // turn off jet collection output for speed
00198   // Voronoi-based area calculation allows for an empirical scale factor
00199   if (iConfig.exists("voronoiRfact"))
00200     voronoiRfact_     = iConfig.getParameter<double>("voronoiRfact");
00201 
00202 
00203   // do fasjet area / rho calcluation? => accept corresponding parameters
00204   if ( doAreaFastjet_ || doRhoFastjet_ ) {
00205     // Eta range of jets to be considered for Rho calculation
00206     // Should be at most (jet acceptance - jet radius)
00207     double rhoEtaMax=iConfig.getParameter<double>("Rho_EtaMax");
00208     // default Ghost_EtaMax should be 5
00209     double ghostEtaMax = iConfig.getParameter<double>("Ghost_EtaMax");
00210     // default Active_Area_Repeats 1
00211     int    activeAreaRepeats = iConfig.getParameter<int> ("Active_Area_Repeats");
00212     // default GhostArea 0.01
00213     double ghostArea = iConfig.getParameter<double> ("GhostArea");
00214     if (voronoiRfact_ <= 0)
00215       fjActiveArea_     = ActiveAreaSpecPtr(new fastjet::ActiveAreaSpec(ghostEtaMax,activeAreaRepeats,ghostArea));
00216     fjRangeDef_ = RangeDefPtr( new fastjet::RangeDefinition(rhoEtaMax) );
00217   } 
00218 
00219   // restrict inputs to first "maxInputs" towers?
00220   if ( iConfig.exists("restrictInputs") ) {
00221     restrictInputs_ = iConfig.getParameter<bool>("restrictInputs");
00222     maxInputs_      = iConfig.getParameter<unsigned int>("maxInputs");
00223   }
00224  
00225 
00226   string alias=iConfig.getUntrackedParameter<string>("alias",moduleLabel_);
00227 
00228   // make the "produces" statements
00229   makeProduces( alias, jetCollInstanceName_ );
00230 
00231   doFastJetNonUniform_ = false;
00232   if(iConfig.exists("doFastJetNonUniform")) doFastJetNonUniform_ = iConfig.getParameter<bool>   ("doFastJetNonUniform");
00233   if(doFastJetNonUniform_){
00234     puCenters_ = iConfig.getParameter<std::vector<double> >("puCenters");
00235     puWidth_ = iConfig.getParameter<double>("puWidth");
00236     nExclude_ = iConfig.getParameter<unsigned int>("nExclude");
00237   }
00238 
00239   useDeterministicSeed_ = false;
00240   minSeed_ = 0;
00241   if ( iConfig.exists("useDeterministicSeed") ) {
00242     useDeterministicSeed_ = iConfig.getParameter<bool>("useDeterministicSeed");
00243     minSeed_ =              iConfig.getParameter<unsigned int>("minSeed");
00244   }
00245 
00246   produces<std::vector<double> >("rhos");
00247   produces<std::vector<double> >("sigmas");
00248   produces<double>("rho");
00249   produces<double>("sigma");
00250   
00251 }
00252 
00253 //______________________________________________________________________________
00254 VirtualJetProducer::~VirtualJetProducer()
00255 {
00256 } 
00257 
00258 
00260 // implementation of member functions
00262 
00263 //______________________________________________________________________________
00264 void VirtualJetProducer::produce(edm::Event& iEvent,const edm::EventSetup& iSetup)
00265 {
00266 
00267   // If requested, set the fastjet random seed to a deterministic function
00268   // of the run/lumi/event. 
00269   // NOTE!!! The fastjet random number sequence is a global singleton.
00270   // Thus, we have to create an object and get access to the global singleton
00271   // in order to change it. 
00272   if ( useDeterministicSeed_ ) {
00273     fastjet::GhostedAreaSpec gas;
00274     std::vector<int> seeds(2);
00275     seeds[0] = std::max(iEvent.id().run(),minSeed_ + 3) + 3 * iEvent.id().event();
00276     seeds[1] = std::max(iEvent.id().run(),minSeed_ + 5) + 5 * iEvent.id().event();
00277     gas.set_random_status(seeds);
00278   }
00279 
00280   LogDebug("VirtualJetProducer") << "Entered produce\n";
00281   //determine signal vertex
00282   vertex_=reco::Jet::Point(0,0,0);
00283   if (makeCaloJet(jetTypeE)&&doPVCorrection_) {
00284     LogDebug("VirtualJetProducer") << "Adding PV info\n";
00285     edm::Handle<reco::VertexCollection> pvCollection;
00286     iEvent.getByLabel(srcPVs_,pvCollection);
00287     if (pvCollection->size()>0) vertex_=pvCollection->begin()->position();
00288   }
00289 
00290   // For Pileup subtraction using offset correction:
00291   // set up geometry map
00292   if ( doPUOffsetCorr_ ) {
00293      subtractor_->setupGeometryMap(iEvent, iSetup);
00294   }
00295 
00296   // clear data
00297   LogDebug("VirtualJetProducer") << "Clear data\n";
00298   fjInputs_.clear();
00299   fjJets_.clear();
00300   inputs_.clear();  
00301   
00302   // get inputs and convert them to the fastjet format (fastjet::PeudoJet)
00303   edm::Handle<reco::CandidateView> inputsHandle;
00304   iEvent.getByLabel(src_,inputsHandle);
00305   for (size_t i = 0; i < inputsHandle->size(); ++i) {
00306     inputs_.push_back(inputsHandle->ptrAt(i));
00307   }
00308   LogDebug("VirtualJetProducer") << "Got inputs\n";
00309   
00310   // Convert candidates to fastjet::PseudoJets.
00311   // Also correct to Primary Vertex. Will modify fjInputs_
00312   // and use inputs_
00313   fjInputs_.reserve(inputs_.size());
00314   inputTowers();
00315   LogDebug("VirtualJetProducer") << "Inputted towers\n";
00316 
00317   // For Pileup subtraction using offset correction:
00318   // Subtract pedestal. 
00319   if ( doPUOffsetCorr_ ) {
00320      subtractor_->reset(inputs_,fjInputs_,fjJets_);
00321      subtractor_->calculatePedestal(fjInputs_); 
00322      subtractor_->subtractPedestal(fjInputs_);    
00323      LogDebug("VirtualJetProducer") << "Subtracted pedestal\n";
00324   }
00325 
00326   // Run algorithm. Will modify fjJets_ and allocate fjClusterSeq_. 
00327   // This will use fjInputs_
00328   runAlgorithm( iEvent, iSetup );
00329   if ( doPUOffsetCorr_ ) {
00330      subtractor_->setAlgorithm(fjClusterSeq_);
00331   }
00332 
00333   LogDebug("VirtualJetProducer") << "Ran algorithm\n";
00334 
00335   // For Pileup subtraction using offset correction:
00336   // Now we find jets and need to recalculate their energy,
00337   // mark towers participated in jet,
00338   // remove occupied towers from the list and recalculate mean and sigma
00339   // put the initial towers collection to the jet,   
00340   // and subtract from initial towers in jet recalculated mean and sigma of towers 
00341   if ( doPUOffsetCorr_ ) {
00342     LogDebug("VirtualJetProducer") << "Do PUOffsetCorr\n";
00343     vector<fastjet::PseudoJet> orphanInput;
00344     subtractor_->calculateOrphanInput(orphanInput);
00345     subtractor_->calculatePedestal(orphanInput);
00346     subtractor_->offsetCorrectJets();
00347   }
00348 
00349   // Write the output jets.
00350   // This will (by default) call the member function template
00351   // "writeJets", but can be overridden. 
00352   // this will use inputs_
00353   output( iEvent, iSetup );
00354   LogDebug("VirtualJetProducer") << "Wrote jets\n";
00355   
00356   return;
00357 }
00358 
00359 //______________________________________________________________________________
00360   
00361 void VirtualJetProducer::inputTowers( )
00362 {
00363   std::vector<edm::Ptr<reco::Candidate> >::const_iterator inBegin = inputs_.begin(),
00364     inEnd = inputs_.end(), i = inBegin;
00365   for (; i != inEnd; ++i ) {
00366     reco::CandidatePtr input = *i;
00367     if (std::isnan(input->pt()))           continue;
00368     if (input->et()    <inputEtMin_)  continue;
00369     if (input->energy()<inputEMin_)   continue;
00370     if (isAnomalousTower(input))      continue;
00371     if (input->pt() == 0) {
00372       edm::LogError("NullTransverseMomentum") << "dropping input candidate with pt=0";
00373       continue;
00374     }
00375     if (makeCaloJet(jetTypeE)&&doPVCorrection_) {
00376       const CaloTower* tower=dynamic_cast<const CaloTower*>(input.get());
00377       math::PtEtaPhiMLorentzVector ct(tower->p4(vertex_));
00378       fjInputs_.push_back(fastjet::PseudoJet(ct.px(),ct.py(),ct.pz(),ct.energy()));
00379     }
00380     else {
00381       fjInputs_.push_back(fastjet::PseudoJet(input->px(),input->py(),input->pz(),
00382                                             input->energy()));
00383     }
00384     fjInputs_.back().set_user_index(i - inBegin);
00385   }
00386 
00387   if ( restrictInputs_ && fjInputs_.size() > maxInputs_ ) {
00388     reco::helper::GreaterByPtPseudoJet   pTComparator;
00389     std::sort(fjInputs_.begin(), fjInputs_.end(), pTComparator);
00390     fjInputs_.resize(maxInputs_);
00391     edm::LogWarning("JetRecoTooManyEntries") << "Too many inputs in the event, limiting to first " << maxInputs_ << ". Output is suspect.";
00392   }
00393 }
00394 
00395 //______________________________________________________________________________
00396 bool VirtualJetProducer::isAnomalousTower(reco::CandidatePtr input)
00397 {
00398   if (!makeCaloJet(jetTypeE)) 
00399       return false;
00400   else
00401       return (*anomalousTowerDef_)(*input);
00402 }
00403 
00404 //------------------------------------------------------------------------------
00405 // This is pure virtual. 
00406 //______________________________________________________________________________
00407 // void VirtualJetProducer::runAlgorithm( edm::Event & iEvent, edm::EventSetup const& iSetup,
00408 //                                        std::vector<edm::Ptr<reco::Candidate> > const & inputs_);
00409 
00410 //______________________________________________________________________________
00411 void VirtualJetProducer::copyConstituents(const vector<fastjet::PseudoJet>& fjConstituents,
00412                                           reco::Jet* jet)
00413 {
00414   for (unsigned int i=0;i<fjConstituents.size();++i)
00415     jet->addDaughter(inputs_[fjConstituents[i].user_index()]);
00416 }
00417 
00418 
00419 //______________________________________________________________________________
00420 vector<reco::CandidatePtr>
00421 VirtualJetProducer::getConstituents(const vector<fastjet::PseudoJet>&fjConstituents)
00422 {
00423   vector<reco::CandidatePtr> result;
00424   for (unsigned int i=0;i<fjConstituents.size();i++) {
00425     int index = fjConstituents[i].user_index();
00426     reco::CandidatePtr candidate = inputs_[index];
00427     result.push_back(candidate);
00428   }
00429   return result;
00430 }
00431 
00432 
00433 //_____________________________________________________________________________
00434 
00435 void VirtualJetProducer::output(edm::Event & iEvent, edm::EventSetup const& iSetup)
00436 {
00437   // Write jets and constitutents. Will use fjJets_, inputs_
00438   // and fjClusterSeq_
00439   switch( jetTypeE ) {
00440   case JetType::CaloJet :
00441     writeJets<reco::CaloJet>( iEvent, iSetup);
00442     break;
00443   case JetType::PFJet :
00444     writeJets<reco::PFJet>( iEvent, iSetup);
00445     break;
00446   case JetType::GenJet :
00447     writeJets<reco::GenJet>( iEvent, iSetup);
00448     break;
00449   case JetType::TrackJet :
00450     writeJets<reco::TrackJet>( iEvent, iSetup);
00451     break;
00452   case JetType::PFClusterJet :
00453     writeJets<reco::PFClusterJet>( iEvent, iSetup);
00454     break;
00455   case JetType::BasicJet :
00456     writeJets<reco::BasicJet>( iEvent, iSetup);
00457     break;
00458   default:
00459     throw cms::Exception("InvalidInput") << "invalid jet type in VirtualJetProducer\n";
00460     break;
00461   };
00462   
00463 }
00464 
00465 template< typename T >
00466 void VirtualJetProducer::writeJets( edm::Event & iEvent, edm::EventSetup const& iSetup )
00467 {
00468   if (doRhoFastjet_) {
00469     // declare jet collection without the two jets, 
00470     // for unbiased background estimation.
00471     std::vector<fastjet::PseudoJet> fjexcluded_jets;
00472     fjexcluded_jets=fjJets_;
00473   
00474     if(fjexcluded_jets.size()>2) fjexcluded_jets.resize(nExclude_);
00475 
00476     if(doFastJetNonUniform_){
00477       std::auto_ptr<std::vector<double> > rhos(new std::vector<double>);
00478       std::auto_ptr<std::vector<double> > sigmas(new std::vector<double>);
00479       int nEta = puCenters_.size();
00480       rhos->reserve(nEta);
00481       sigmas->reserve(nEta);
00482       fastjet::ClusterSequenceAreaBase const* clusterSequenceWithArea =
00483         dynamic_cast<fastjet::ClusterSequenceAreaBase const *> ( &*fjClusterSeq_ );
00484 
00485 
00486       for(int ie = 0; ie < nEta; ++ie){
00487         double eta = puCenters_[ie];
00488         double etamin=eta-puWidth_;
00489         double etamax=eta+puWidth_;
00490         fastjet::RangeDefinition range_rho(etamin,etamax);
00491         fastjet::BackgroundEstimator bkgestim(*clusterSequenceWithArea,range_rho);
00492         bkgestim.set_excluded_jets(fjexcluded_jets);
00493         rhos->push_back(bkgestim.rho());
00494         sigmas->push_back(bkgestim.sigma());
00495       }
00496       iEvent.put(rhos,"rhos");
00497       iEvent.put(sigmas,"sigmas");
00498     }else{
00499       std::auto_ptr<double> rho(new double(0.0));
00500       std::auto_ptr<double> sigma(new double(0.0));
00501       double mean_area = 0;
00502      
00503       fastjet::ClusterSequenceAreaBase const* clusterSequenceWithArea =
00504         dynamic_cast<fastjet::ClusterSequenceAreaBase const *> ( &*fjClusterSeq_ );
00505       clusterSequenceWithArea->get_median_rho_and_sigma(*fjRangeDef_,false,*rho,*sigma,mean_area);
00506       iEvent.put(rho,"rho");
00507       iEvent.put(sigma,"sigma");
00508     }
00509   } // doRhoFastjet_
00510 
00511   // produce output jet collection
00512 
00513   using namespace reco;
00514 
00515   std::auto_ptr<std::vector<T> > jets(new std::vector<T>() );
00516   jets->reserve(fjJets_.size());
00517 
00518 
00519   // Distance between jet centers -- for disk-based area calculation
00520   std::vector<std::vector<double> >   rij(fjJets_.size());
00521 
00522   for (unsigned int ijet=0;ijet<fjJets_.size();++ijet) {
00523     // allocate this jet
00524     T jet;
00525     // get the fastjet jet
00526     const fastjet::PseudoJet& fjJet = fjJets_[ijet];
00527     // get the constituents from fastjet
00528     std::vector<fastjet::PseudoJet> fjConstituents =
00529       sorted_by_pt(fjClusterSeq_->constituents(fjJet));
00530     // convert them to CandidatePtr vector
00531     std::vector<CandidatePtr> constituents =
00532       getConstituents(fjConstituents);
00533 
00534     // calcuate the jet area
00535     double jetArea=0.0;
00536     if ( doAreaFastjet_ ) {
00537       fastjet::ClusterSequenceAreaBase const * clusterSequenceWithArea =
00538         dynamic_cast<fastjet::ClusterSequenceAreaBase const *>(&*fjClusterSeq_);
00539       jetArea = clusterSequenceWithArea->area(fjJet);
00540     }
00541     else if ( doAreaDiskApprox_ ) {
00542       // Here it is assumed that fjJets_ is in decreasing order of pT, 
00543       // which should happen in FastjetJetProducer::runAlgorithm() 
00544       jetArea   = M_PI;
00545       if (ijet) {
00546         std::vector<double>&  distance  = rij[ijet];
00547         distance.resize(ijet);
00548         for (unsigned jJet = 0; jJet < ijet; ++jJet) {
00549           distance[jJet]      = reco::deltaR(fjJets_[ijet],fjJets_[jJet]) / rParam_;
00550           jetArea            -= reco::helper::VirtualJetProducerHelper::intersection(distance[jJet]);
00551           for (unsigned kJet = 0; kJet < jJet; ++kJet) {
00552             jetArea          += reco::helper::VirtualJetProducerHelper::intersection(distance[jJet], distance[kJet], rij[jJet][kJet]);
00553           } // end loop over harder jets
00554         } // end loop over harder jets
00555       }
00556       jetArea  *= rParam_;
00557       jetArea  *= rParam_;
00558     }
00559     
00560     // write the specifics to the jet (simultaneously sets 4-vector, vertex).
00561     // These are overridden functions that will call the appropriate
00562     // specific allocator. 
00563     writeSpecific(jet,
00564                   Particle::LorentzVector(fjJet.px(),
00565                                           fjJet.py(),
00566                                           fjJet.pz(),
00567                                           fjJet.E()),
00568                   vertex_, 
00569                   constituents, iSetup);
00570     
00571     jet.setJetArea (jetArea);
00572 
00573     if(doPUOffsetCorr_){
00574       jet.setPileup(subtractor_->getPileUpEnergy(ijet));
00575     }else{
00576       jet.setPileup (0.0);
00577     }
00578     
00579     // add to the list
00580     jets->push_back(jet);        
00581   }
00582   
00583   // put the jets in the collection
00584   iEvent.put(jets);
00585   
00586 
00587 }
00588 
00589 
00590