CMS 3D CMS Logo

/data/git/CMSSW_5_3_11_patch5/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 "DataFormats/ParticleFlowCandidate/interface/PFCandidate.h"
00036 
00037 #include "fastjet/SISConePlugin.hh"
00038 #include "fastjet/CMSIterativeConePlugin.hh"
00039 #include "fastjet/ATLASConePlugin.hh"
00040 #include "fastjet/CDFMidPointPlugin.hh"
00041 
00042 #include <iostream>
00043 #include <memory>
00044 #include <algorithm>
00045 #include <limits>
00046 #include <cmath>
00047 
00048 
00049 using namespace std;
00050 
00051 
00052 namespace reco {
00053   namespace helper {
00054     struct GreaterByPtPseudoJet {
00055       bool operator()( const fastjet::PseudoJet & t1, const fastjet::PseudoJet & t2 ) const {
00056         return t1.perp() > t2.perp();
00057       }
00058     };
00059 
00060   }
00061 }
00062 
00063 //______________________________________________________________________________
00064 const char *VirtualJetProducer::JetType::names[] = {
00065   "BasicJet","GenJet","CaloJet","PFJet","TrackJet","PFClusterJet"
00066 };
00067 
00068 
00069 //______________________________________________________________________________
00070 VirtualJetProducer::JetType::Type
00071 VirtualJetProducer::JetType::byName(const string &name)
00072 {
00073   const char **pos = std::find(names, names + LastJetType, name);
00074   if (pos == names + LastJetType) {
00075     std::string errorMessage="Requested jetType not supported: "+name+"\n"; 
00076     throw cms::Exception("Configuration",errorMessage);
00077   }
00078   return (Type)(pos-names);
00079 }
00080 
00081 
00082 void VirtualJetProducer::makeProduces( std::string alias, std::string tag ) 
00083 {
00084 
00085 
00086   if ( writeCompound_ ) {
00087     produces<reco::BasicJetCollection>();
00088   }
00089 
00090   if (makeCaloJet(jetTypeE)) {
00091     produces<reco::CaloJetCollection>(tag).setBranchAlias(alias);
00092   }
00093   else if (makePFJet(jetTypeE)) {
00094     produces<reco::PFJetCollection>(tag).setBranchAlias(alias);
00095   }
00096   else if (makeGenJet(jetTypeE)) {
00097     produces<reco::GenJetCollection>(tag).setBranchAlias(alias);
00098   }
00099   else if (makeTrackJet(jetTypeE)) {
00100     produces<reco::TrackJetCollection>(tag).setBranchAlias(alias);
00101   }
00102   else if (makePFClusterJet(jetTypeE)) {
00103     produces<reco::PFClusterJetCollection>(tag).setBranchAlias(alias);
00104   }
00105   else if (makeBasicJet(jetTypeE)) {
00106     produces<reco::BasicJetCollection>(tag).setBranchAlias(alias);
00107   }
00108 }
00109 
00111 // construction / destruction
00113 
00114 //______________________________________________________________________________
00115 VirtualJetProducer::VirtualJetProducer(const edm::ParameterSet& iConfig)
00116   : moduleLabel_   (iConfig.getParameter<string>       ("@module_label"))
00117   , src_           (iConfig.getParameter<edm::InputTag>("src"))
00118   , srcPVs_        (iConfig.getParameter<edm::InputTag>("srcPVs"))
00119   , jetType_       (iConfig.getParameter<string>       ("jetType"))
00120   , jetAlgorithm_  (iConfig.getParameter<string>       ("jetAlgorithm"))
00121   , rParam_        (iConfig.getParameter<double>       ("rParam"))
00122   , inputEtMin_    (iConfig.getParameter<double>       ("inputEtMin"))
00123   , inputEMin_     (iConfig.getParameter<double>       ("inputEMin"))
00124   , jetPtMin_      (iConfig.getParameter<double>       ("jetPtMin"))
00125   , doPVCorrection_(iConfig.getParameter<bool>         ("doPVCorrection"))
00126   , restrictInputs_(false)
00127   , maxInputs_(99999999)
00128   , doAreaFastjet_ (iConfig.getParameter<bool>         ("doAreaFastjet"))
00129   , useExplicitGhosts_(false)
00130   , doAreaDiskApprox_       (false)
00131   , doRhoFastjet_  (iConfig.getParameter<bool>         ("doRhoFastjet"))
00132   , voronoiRfact_           (-9)
00133   , doPUOffsetCorr_(iConfig.getParameter<bool>         ("doPUOffsetCorr"))
00134   , puWidth_(0)
00135   , nExclude_(0)
00136   , jetCollInstanceName_ ("")
00137   , writeCompound_ ( false )
00138 {
00139   anomalousTowerDef_ = std::auto_ptr<AnomalousTower>(new AnomalousTower(iConfig));
00140 
00141   //
00142   // additional parameters to think about:
00143   // - overlap threshold (set to 0.75 for the time being)
00144   // - p parameter for generalized kT (set to -2 for the time being)
00145   // - fastjet PU subtraction parameters (not yet considered)
00146   //
00147   if (jetAlgorithm_=="SISCone") {
00148     fjPlugin_ = PluginPtr( new fastjet::SISConePlugin(rParam_,0.75,0,0.0,false,
00149                                                       fastjet::SISConePlugin::SM_pttilde) );
00150     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(&*fjPlugin_) );
00151   }
00152   else if (jetAlgorithm_=="IterativeCone") {
00153     fjPlugin_ = PluginPtr(new fastjet::CMSIterativeConePlugin(rParam_,1.0));
00154     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00155   }
00156   else if (jetAlgorithm_=="CDFMidPoint") {
00157     fjPlugin_ = PluginPtr(new fastjet::CDFMidPointPlugin(rParam_,0.75));
00158     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00159   }
00160   else if (jetAlgorithm_=="ATLASCone") {
00161     fjPlugin_ = PluginPtr(new fastjet::ATLASConePlugin(rParam_));
00162     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(&*fjPlugin_));
00163   }
00164   else if (jetAlgorithm_=="Kt")
00165     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(fastjet::kt_algorithm,rParam_));
00166   else if (jetAlgorithm_=="CambridgeAachen")
00167     fjJetDefinition_= JetDefPtr(new fastjet::JetDefinition(fastjet::cambridge_algorithm,
00168                                                            rParam_) );
00169   else if (jetAlgorithm_=="AntiKt")
00170     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::antikt_algorithm,rParam_) );
00171   else if (jetAlgorithm_=="GeneralizedKt")
00172     fjJetDefinition_= JetDefPtr( new fastjet::JetDefinition(fastjet::genkt_algorithm,
00173                                                             rParam_,-2) );
00174   else
00175     throw cms::Exception("Invalid jetAlgorithm")
00176       <<"Jet algorithm for VirtualJetProducer is invalid, Abort!\n";
00177   
00178   jetTypeE=JetType::byName(jetType_);
00179 
00180   if ( iConfig.exists("jetCollInstanceName") ) {
00181     jetCollInstanceName_ = iConfig.getParameter<string>("jetCollInstanceName");
00182   }
00183 
00184   if ( doPUOffsetCorr_ ) {
00185     if ( jetTypeE != JetType::CaloJet && jetTypeE != JetType::BasicJet) {
00186         throw cms::Exception("InvalidInput") << "Can only offset correct jets of type CaloJet or BasicJet";
00187      }
00188      
00189      if(iConfig.exists("subtractorName")) puSubtractorName_  =  iConfig.getParameter<string> ("subtractorName");
00190      else puSubtractorName_ = std::string();
00191      
00192      if(puSubtractorName_.empty()){
00193        edm::LogWarning("VirtualJetProducer") << "Pile Up correction on; however, pile up type is not specified. Using default... \n";
00194        subtractor_ =  boost::shared_ptr<PileUpSubtractor>(new PileUpSubtractor(iConfig));
00195      }else{
00196        subtractor_ =  boost::shared_ptr<PileUpSubtractor>(PileUpSubtractorFactory::get()->create( puSubtractorName_, iConfig));
00197      }
00198   }
00199 
00200   // use explicit ghosts in the fastjet clustering sequence?
00201   if ( iConfig.exists("useExplicitGhosts") ) {
00202     useExplicitGhosts_ = iConfig.getParameter<bool>("useExplicitGhosts");
00203   }
00204 
00205   // do approximate disk-based area calculation => warn if conflicting request
00206   if (iConfig.exists("doAreaDiskApprox")) {
00207     doAreaDiskApprox_ = iConfig.getParameter<bool>("doAreaDiskApprox");
00208     if (doAreaDiskApprox_ && doAreaFastjet_)
00209       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";
00210 
00211   }
00212   // turn off jet collection output for speed
00213   // Voronoi-based area calculation allows for an empirical scale factor
00214   if (iConfig.exists("voronoiRfact"))
00215     voronoiRfact_     = iConfig.getParameter<double>("voronoiRfact");
00216 
00217 
00218   // do fasjet area / rho calcluation? => accept corresponding parameters
00219   if ( doAreaFastjet_ || doRhoFastjet_ ) {
00220     // Eta range of jets to be considered for Rho calculation
00221     // Should be at most (jet acceptance - jet radius)
00222     double rhoEtaMax=iConfig.getParameter<double>("Rho_EtaMax");
00223     // default Ghost_EtaMax should be 5
00224     double ghostEtaMax = iConfig.getParameter<double>("Ghost_EtaMax");
00225     // default Active_Area_Repeats 1
00226     int    activeAreaRepeats = iConfig.getParameter<int> ("Active_Area_Repeats");
00227     // default GhostArea 0.01
00228     double ghostArea = iConfig.getParameter<double> ("GhostArea");
00229     if (voronoiRfact_ <= 0) {
00230       fjActiveArea_     = ActiveAreaSpecPtr(new fastjet::GhostedAreaSpec(ghostEtaMax,activeAreaRepeats,ghostArea));
00231       fjActiveArea_->set_fj2_placement(true);
00232       if ( ! useExplicitGhosts_ ) {
00233         fjAreaDefinition_ = AreaDefinitionPtr( new fastjet::AreaDefinition(fastjet::active_area, *fjActiveArea_ ) );
00234       } else {
00235         fjAreaDefinition_ = AreaDefinitionPtr( new fastjet::AreaDefinition(fastjet::active_area_explicit_ghosts, *fjActiveArea_ ) );
00236       }
00237     }
00238     fjRangeDef_ = RangeDefPtr( new fastjet::RangeDefinition(rhoEtaMax) );
00239   } 
00240 
00241   // restrict inputs to first "maxInputs" towers?
00242   if ( iConfig.exists("restrictInputs") ) {
00243     restrictInputs_ = iConfig.getParameter<bool>("restrictInputs");
00244     maxInputs_      = iConfig.getParameter<unsigned int>("maxInputs");
00245   }
00246  
00247 
00248   string alias=iConfig.getUntrackedParameter<string>("alias",moduleLabel_);
00249 
00250 
00251   // Check to see if we are writing compound jets for substructure
00252   // and jet grooming
00253   if ( iConfig.exists("writeCompound") ) {
00254     writeCompound_ = iConfig.getParameter<bool>("writeCompound");
00255   }
00256 
00257   // make the "produces" statements
00258   makeProduces( alias, jetCollInstanceName_ );
00259 
00260   doFastJetNonUniform_ = false;
00261   if(iConfig.exists("doFastJetNonUniform")) doFastJetNonUniform_ = iConfig.getParameter<bool>   ("doFastJetNonUniform");
00262   if(doFastJetNonUniform_){
00263     puCenters_ = iConfig.getParameter<std::vector<double> >("puCenters");
00264     puWidth_ = iConfig.getParameter<double>("puWidth");
00265     nExclude_ = iConfig.getParameter<unsigned int>("nExclude");
00266   }
00267 
00268   useDeterministicSeed_ = false;
00269   minSeed_ = 0;
00270   if ( iConfig.exists("useDeterministicSeed") ) {
00271     useDeterministicSeed_ = iConfig.getParameter<bool>("useDeterministicSeed");
00272     minSeed_ =              iConfig.getParameter<unsigned int>("minSeed");
00273   }
00274 
00275 
00276   produces<std::vector<double> >("rhos");
00277   produces<std::vector<double> >("sigmas");
00278   produces<double>("rho");
00279   produces<double>("sigma");
00280 
00281   
00282 }
00283 
00284 //______________________________________________________________________________
00285 VirtualJetProducer::~VirtualJetProducer()
00286 {
00287 } 
00288 
00289 
00291 // implementation of member functions
00293 
00294 //______________________________________________________________________________
00295 void VirtualJetProducer::produce(edm::Event& iEvent,const edm::EventSetup& iSetup)
00296 {
00297 
00298   // If requested, set the fastjet random seed to a deterministic function
00299   // of the run/lumi/event. 
00300   // NOTE!!! The fastjet random number sequence is a global singleton.
00301   // Thus, we have to create an object and get access to the global singleton
00302   // in order to change it. 
00303   if ( useDeterministicSeed_ ) {
00304     fastjet::GhostedAreaSpec gas;
00305     std::vector<int> seeds(2);
00306     seeds[0] = std::max(iEvent.id().run(),minSeed_ + 3) + 3 * iEvent.id().event();
00307     seeds[1] = std::max(iEvent.id().run(),minSeed_ + 5) + 5 * iEvent.id().event();
00308     gas.set_random_status(seeds);
00309   }
00310 
00311   LogDebug("VirtualJetProducer") << "Entered produce\n";
00312   //determine signal vertex2
00313   vertex_=reco::Jet::Point(0,0,0);
00314   if (makeCaloJet(jetTypeE)&&doPVCorrection_) {
00315     LogDebug("VirtualJetProducer") << "Adding PV info\n";
00316     edm::Handle<reco::VertexCollection> pvCollection;
00317     iEvent.getByLabel(srcPVs_,pvCollection);
00318     if (pvCollection->size()>0) vertex_=pvCollection->begin()->position();
00319   }
00320 
00321   // For Pileup subtraction using offset correction:
00322   // set up geometry map
00323   if ( doPUOffsetCorr_ ) {
00324      subtractor_->setupGeometryMap(iEvent, iSetup);
00325   }
00326 
00327   // clear data
00328   LogDebug("VirtualJetProducer") << "Clear data\n";
00329   fjInputs_.clear();
00330   fjJets_.clear();
00331   inputs_.clear();  
00332   
00333   // get inputs and convert them to the fastjet format (fastjet::PeudoJet)
00334   edm::Handle<reco::CandidateView> inputsHandle;
00335   iEvent.getByLabel(src_,inputsHandle);
00336   for (size_t i = 0; i < inputsHandle->size(); ++i) {
00337     inputs_.push_back(inputsHandle->ptrAt(i));
00338   }
00339   LogDebug("VirtualJetProducer") << "Got inputs\n";
00340   
00341   // Convert candidates to fastjet::PseudoJets.
00342   // Also correct to Primary Vertex. Will modify fjInputs_
00343   // and use inputs_
00344   fjInputs_.reserve(inputs_.size());
00345   inputTowers();
00346   LogDebug("VirtualJetProducer") << "Inputted towers\n";
00347 
00348   // For Pileup subtraction using offset correction:
00349   // Subtract pedestal. 
00350   if ( doPUOffsetCorr_ ) {
00351      subtractor_->setDefinition(fjJetDefinition_);
00352      subtractor_->reset(inputs_,fjInputs_,fjJets_);
00353      subtractor_->calculatePedestal(fjInputs_); 
00354      subtractor_->subtractPedestal(fjInputs_);    
00355      LogDebug("VirtualJetProducer") << "Subtracted pedestal\n";
00356   }
00357   // Run algorithm. Will modify fjJets_ and allocate fjClusterSeq_. 
00358   // This will use fjInputs_
00359   runAlgorithm( iEvent, iSetup );
00360 
00361   // if ( doPUOffsetCorr_ ) {
00362   //    subtractor_->setAlgorithm(fjClusterSeq_);
00363   // }
00364 
00365   LogDebug("VirtualJetProducer") << "Ran algorithm\n";
00366   // For Pileup subtraction using offset correction:
00367   // Now we find jets and need to recalculate their energy,
00368   // mark towers participated in jet,
00369   // remove occupied towers from the list and recalculate mean and sigma
00370   // put the initial towers collection to the jet,   
00371   // and subtract from initial towers in jet recalculated mean and sigma of towers 
00372   if ( doPUOffsetCorr_ ) {
00373     LogDebug("VirtualJetProducer") << "Do PUOffsetCorr\n";
00374     vector<fastjet::PseudoJet> orphanInput;
00375     subtractor_->calculateOrphanInput(orphanInput);
00376     subtractor_->calculatePedestal(orphanInput);
00377     subtractor_->offsetCorrectJets();
00378   }
00379   // Write the output jets.
00380   // This will (by default) call the member function template
00381   // "writeJets", but can be overridden. 
00382   // this will use inputs_
00383   output( iEvent, iSetup );
00384   LogDebug("VirtualJetProducer") << "Wrote jets\n";
00385   
00386   return;
00387 }
00388 
00389 //______________________________________________________________________________
00390   
00391 void VirtualJetProducer::inputTowers( )
00392 {
00393   std::vector<edm::Ptr<reco::Candidate> >::const_iterator inBegin = inputs_.begin(),
00394     inEnd = inputs_.end(), i = inBegin;
00395   for (; i != inEnd; ++i ) {
00396     reco::CandidatePtr input = *i;
00397     if (std::isnan(input->pt()))           continue;
00398     if (input->et()    <inputEtMin_)  continue;
00399     if (input->energy()<inputEMin_)   continue;
00400     if (isAnomalousTower(input))      continue;
00401     if (input->pt() == 0) {
00402       edm::LogError("NullTransverseMomentum") << "dropping input candidate with pt=0";
00403       continue;
00404     }
00405     if (makeCaloJet(jetTypeE)&&doPVCorrection_) {
00406       const CaloTower* tower=dynamic_cast<const CaloTower*>(input.get());
00407       math::PtEtaPhiMLorentzVector ct(tower->p4(vertex_));
00408       fjInputs_.push_back(fastjet::PseudoJet(ct.px(),ct.py(),ct.pz(),ct.energy()));
00409       //std::cout << "tower:" << *tower << '\n';
00410     }
00411     else {
00412       /*
00413       if(makePFJet(jetTypeE)) {
00414         reco::PFCandidate* pfc = (reco::PFCandidate*)input.get();
00415         std::cout << "PF cand:" << *pfc << '\n';
00416       }
00417       */
00418       fjInputs_.push_back(fastjet::PseudoJet(input->px(),input->py(),input->pz(),
00419                                              input->energy()));
00420     }
00421     fjInputs_.back().set_user_index(i - inBegin);
00422   }
00423 
00424   if ( restrictInputs_ && fjInputs_.size() > maxInputs_ ) {
00425     reco::helper::GreaterByPtPseudoJet   pTComparator;
00426     std::sort(fjInputs_.begin(), fjInputs_.end(), pTComparator);
00427     fjInputs_.resize(maxInputs_);
00428     edm::LogWarning("JetRecoTooManyEntries") << "Too many inputs in the event, limiting to first " << maxInputs_ << ". Output is suspect.";
00429   }
00430 }
00431 
00432 //______________________________________________________________________________
00433 bool VirtualJetProducer::isAnomalousTower(reco::CandidatePtr input)
00434 {
00435   if (!makeCaloJet(jetTypeE)) 
00436       return false;
00437   else
00438       return (*anomalousTowerDef_)(*input);
00439 }
00440 
00441 //------------------------------------------------------------------------------
00442 // This is pure virtual. 
00443 //______________________________________________________________________________
00444 // void VirtualJetProducer::runAlgorithm( edm::Event & iEvent, edm::EventSetup const& iSetup,
00445 //                                        std::vector<edm::Ptr<reco::Candidate> > const & inputs_);
00446 
00447 //______________________________________________________________________________
00448 void VirtualJetProducer::copyConstituents(const vector<fastjet::PseudoJet>& fjConstituents,
00449                                           reco::Jet* jet)
00450 {
00451   for (unsigned int i=0;i<fjConstituents.size();++i) { 
00452     int index = fjConstituents[i].user_index();
00453     if ( index >= 0 && static_cast<unsigned int>(index) < inputs_.size() )
00454       jet->addDaughter(inputs_[index]);
00455   }
00456 }
00457 
00458 
00459 //______________________________________________________________________________
00460 vector<reco::CandidatePtr>
00461 VirtualJetProducer::getConstituents(const vector<fastjet::PseudoJet>&fjConstituents)
00462 {
00463   vector<reco::CandidatePtr> result;
00464   for (unsigned int i=0;i<fjConstituents.size();i++) {
00465     int index = fjConstituents[i].user_index();
00466     if ( index >= 0 && static_cast<unsigned int>(index) < inputs_.size() ) {
00467       reco::CandidatePtr candidate = inputs_[index];
00468       result.push_back(candidate);
00469     }
00470   }
00471   return result;
00472 }
00473 
00474 
00475 //_____________________________________________________________________________
00476 
00477 void VirtualJetProducer::output(edm::Event & iEvent, edm::EventSetup const& iSetup)
00478 {
00479   // Write jets and constitutents. Will use fjJets_, inputs_
00480   // and fjClusterSeq_
00481 
00482   if ( !writeCompound_ ) {
00483     switch( jetTypeE ) {
00484     case JetType::CaloJet :
00485       writeJets<reco::CaloJet>( iEvent, iSetup);
00486       break;
00487     case JetType::PFJet :
00488       writeJets<reco::PFJet>( iEvent, iSetup);
00489       break;
00490     case JetType::GenJet :
00491       writeJets<reco::GenJet>( iEvent, iSetup);
00492       break;
00493     case JetType::TrackJet :
00494       writeJets<reco::TrackJet>( iEvent, iSetup);
00495       break;
00496     case JetType::PFClusterJet :
00497       writeJets<reco::PFClusterJet>( iEvent, iSetup);
00498       break;
00499     case JetType::BasicJet :
00500       writeJets<reco::BasicJet>( iEvent, iSetup);
00501       break;
00502     default:
00503       throw cms::Exception("InvalidInput") << "invalid jet type in VirtualJetProducer\n";
00504       break;
00505     };
00506   } else {
00507     // Write jets and constitutents.
00508     switch( jetTypeE ) {
00509     case JetType::CaloJet :
00510       writeCompoundJets<reco::CaloJet>( iEvent, iSetup );
00511       break;
00512     case JetType::PFJet :
00513       writeCompoundJets<reco::PFJet>( iEvent, iSetup );
00514       break;
00515     case JetType::GenJet :
00516       writeCompoundJets<reco::GenJet>( iEvent, iSetup );
00517       break;
00518     case JetType::BasicJet :
00519       writeCompoundJets<reco::BasicJet>( iEvent, iSetup );
00520       break;
00521     default:
00522       throw cms::Exception("InvalidInput") << "invalid jet type in CompoundJetProducer\n";
00523       break;
00524     };
00525   }
00526   
00527 }
00528 
00529 template< typename T >
00530 void VirtualJetProducer::writeJets( edm::Event & iEvent, edm::EventSetup const& iSetup )
00531 {
00532   if (doRhoFastjet_) {
00533     // declare jet collection without the two jets, 
00534     // for unbiased background estimation.
00535     std::vector<fastjet::PseudoJet> fjexcluded_jets;
00536     fjexcluded_jets=fjJets_;
00537     
00538     if(fjexcluded_jets.size()>2) fjexcluded_jets.resize(nExclude_);
00539     
00540     if(doFastJetNonUniform_){
00541       std::auto_ptr<std::vector<double> > rhos(new std::vector<double>);
00542       std::auto_ptr<std::vector<double> > sigmas(new std::vector<double>);
00543       int nEta = puCenters_.size();
00544       rhos->reserve(nEta);
00545       sigmas->reserve(nEta);
00546       fastjet::ClusterSequenceAreaBase const* clusterSequenceWithArea =
00547         dynamic_cast<fastjet::ClusterSequenceAreaBase const *> ( &*fjClusterSeq_ );
00548 
00549       
00550       for(int ie = 0; ie < nEta; ++ie){
00551         double eta = puCenters_[ie];
00552         double etamin=eta-puWidth_;
00553         double etamax=eta+puWidth_;
00554         fastjet::RangeDefinition range_rho(etamin,etamax);
00555         fastjet::BackgroundEstimator bkgestim(*clusterSequenceWithArea,range_rho);
00556         bkgestim.set_excluded_jets(fjexcluded_jets);
00557         rhos->push_back(bkgestim.rho());
00558         sigmas->push_back(bkgestim.sigma());
00559       }
00560       iEvent.put(rhos,"rhos");
00561       iEvent.put(sigmas,"sigmas");
00562     }else{
00563       std::auto_ptr<double> rho(new double(0.0));
00564       std::auto_ptr<double> sigma(new double(0.0));
00565       double mean_area = 0;
00566       
00567       fastjet::ClusterSequenceAreaBase const* clusterSequenceWithArea =
00568         dynamic_cast<fastjet::ClusterSequenceAreaBase const *> ( &*fjClusterSeq_ );
00569       /*
00570         const double nemptyjets = clusterSequenceWithArea->n_empty_jets(*fjRangeDef_);
00571         if(( nemptyjets  < -15 ) || ( nemptyjets > fjRangeDef_->area()+ 15)) {
00572         edm::LogWarning("StrangeNEmtpyJets") << "n_empty_jets is : " << clusterSequenceWithArea->n_empty_jets(*fjRangeDef_) << " with range " << fjRangeDef_->description() << ".";
00573         }
00574       */
00575       clusterSequenceWithArea->get_median_rho_and_sigma(*fjRangeDef_,false,*rho,*sigma,mean_area);
00576       if((*rho < 0)|| (std::isnan(*rho))) {
00577         edm::LogError("BadRho") << "rho value is " << *rho << " area:" << mean_area << " and n_empty_jets: " << clusterSequenceWithArea->n_empty_jets(*fjRangeDef_) << " with range " << fjRangeDef_->description()
00578                                 <<". Setting rho to rezo.";
00579         *rho = 0;
00580       }
00581       iEvent.put(rho,"rho");
00582       iEvent.put(sigma,"sigma");
00583     }
00584   } // doRhoFastjet_
00585   
00586   // produce output jet collection
00587   
00588   using namespace reco;
00589   
00590   std::auto_ptr<std::vector<T> > jets(new std::vector<T>() );
00591   jets->reserve(fjJets_.size());
00592   
00593   // Distance between jet centers -- for disk-based area calculation
00594   std::vector<std::vector<double> >   rij(fjJets_.size());
00595 
00596   for (unsigned int ijet=0;ijet<fjJets_.size();++ijet) {
00597     // allocate this jet
00598     T jet;
00599     // get the fastjet jet
00600     const fastjet::PseudoJet& fjJet = fjJets_[ijet];
00601     // get the constituents from fastjet
00602     std::vector<fastjet::PseudoJet> fjConstituents = fastjet::sorted_by_pt(fjJet.constituents());
00603     // convert them to CandidatePtr vector
00604     std::vector<CandidatePtr> constituents =
00605       getConstituents(fjConstituents);
00606 
00607 
00608     // calcuate the jet area
00609     double jetArea=0.0;
00610     if ( doAreaFastjet_ && fjJet.has_area() ) {
00611       jetArea = fjJet.area();
00612     }
00613     else if ( doAreaDiskApprox_ ) {
00614       // Here it is assumed that fjJets_ is in decreasing order of pT, 
00615       // which should happen in FastjetJetProducer::runAlgorithm() 
00616       jetArea   = M_PI;
00617       if (ijet) {
00618         std::vector<double>&  distance  = rij[ijet];
00619         distance.resize(ijet);
00620         for (unsigned jJet = 0; jJet < ijet; ++jJet) {
00621           distance[jJet]      = reco::deltaR(fjJets_[ijet],fjJets_[jJet]) / rParam_;
00622           jetArea            -= reco::helper::VirtualJetProducerHelper::intersection(distance[jJet]);
00623           for (unsigned kJet = 0; kJet < jJet; ++kJet) {
00624             jetArea          += reco::helper::VirtualJetProducerHelper::intersection(distance[jJet], distance[kJet], rij[jJet][kJet]);
00625           } // end loop over harder jets
00626         } // end loop over harder jets
00627       }
00628       jetArea  *= rParam_;
00629       jetArea  *= rParam_;
00630     }  
00631     // write the specifics to the jet (simultaneously sets 4-vector, vertex).
00632     // These are overridden functions that will call the appropriate
00633     // specific allocator. 
00634     writeSpecific(jet,
00635                   Particle::LorentzVector(fjJet.px(),
00636                                           fjJet.py(),
00637                                           fjJet.pz(),
00638                                           fjJet.E()),
00639                   vertex_, 
00640                   constituents, iSetup);
00641 
00642     jet.setJetArea (jetArea);
00643     
00644     if(doPUOffsetCorr_){
00645       jet.setPileup(subtractor_->getPileUpEnergy(ijet));
00646     }else{
00647       jet.setPileup (0.0);
00648     }
00649     
00650     // add to the list
00651     jets->push_back(jet);        
00652   }
00653   // put the jets in the collection
00654   iEvent.put(jets,jetCollInstanceName_);
00655   
00656 
00657 }
00658 
00659 
00660 
00662 template< class T>
00663 void VirtualJetProducer::writeCompoundJets(  edm::Event & iEvent, edm::EventSetup const& iSetup)
00664 {
00665 
00666   // get a list of output jets
00667   std::auto_ptr<reco::BasicJetCollection>  jetCollection( new reco::BasicJetCollection() );
00668   // get a list of output subjets
00669   std::auto_ptr<std::vector<T> >  subjetCollection( new std::vector<T>() );
00670 
00671   // This will store the handle for the subjets after we write them
00672   edm::OrphanHandle< std::vector<T> > subjetHandleAfterPut;
00673   // this is the mapping of subjet to hard jet
00674   std::vector< std::vector<int> > indices;
00675   // this is the list of hardjet 4-momenta
00676   std::vector<math::XYZTLorentzVector> p4_hardJets;
00677   // this is the hardjet areas
00678   std::vector<double> area_hardJets;
00679 
00680 
00681   // Loop over the hard jets
00682   std::vector<fastjet::PseudoJet>::const_iterator it = fjJets_.begin(),
00683     iEnd = fjJets_.end(),
00684     iBegin = fjJets_.begin();
00685   indices.resize( fjJets_.size() );
00686   for ( ; it != iEnd; ++it ) {
00687     fastjet::PseudoJet const & localJet = *it;
00688     unsigned int jetIndex = it - iBegin;
00689     // Get the 4-vector for the hard jet
00690     p4_hardJets.push_back( math::XYZTLorentzVector(localJet.px(), localJet.py(), localJet.pz(), localJet.e() ));
00691     double localJetArea = 0.0;
00692     if ( doAreaFastjet_ && localJet.has_area() ) {
00693       localJetArea = localJet.area();
00694     }
00695     area_hardJets.push_back( localJetArea );
00696 
00697     // create the subjet list
00698     std::vector<fastjet::PseudoJet> constituents;
00699     if ( it->has_pieces() ) {
00700       constituents = it->pieces();
00701     } else {
00702       constituents=it->constituents();
00703     }
00704 
00705     
00706     std::vector<fastjet::PseudoJet>::const_iterator itSubJetBegin = constituents.begin(),
00707       itSubJet = itSubJetBegin, itSubJetEnd = constituents.end();
00708     for (; itSubJet != itSubJetEnd; ++itSubJet ){
00709 
00710       fastjet::PseudoJet const & subjet = *itSubJet;      
00711 
00712       math::XYZTLorentzVector p4Subjet(subjet.px(), subjet.py(), subjet.pz(), subjet.e() );
00713       reco::Particle::Point point(0,0,0);
00714 
00715       // This will hold ptr's to the subjets
00716       std::vector<reco::CandidatePtr> subjetConstituents;
00717 
00718       // Get the transient subjet constituents from fastjet
00719       std::vector<fastjet::PseudoJet> subjetFastjetConstituents = subjet.constituents();
00720       std::vector<reco::CandidatePtr> constituents =
00721         getConstituents(subjetFastjetConstituents );    
00722 
00723       indices[jetIndex].push_back( subjetCollection->size() );
00724 
00725       // Add the concrete subjet type to the subjet list to write to event record
00726       T jet;
00727       reco::writeSpecific( jet, p4Subjet, point, constituents, iSetup);
00728       double subjetArea = 0.0;
00729       if ( doAreaFastjet_ && itSubJet->has_area() ){
00730         subjetArea = itSubJet->area();
00731       }
00732       jet.setJetArea( subjetArea );
00733       subjetCollection->push_back( jet );
00734 
00735     }
00736   }
00737   // put subjets into event record
00738   subjetHandleAfterPut = iEvent.put( subjetCollection, jetCollInstanceName_ );
00739   
00740   
00741   // Now create the hard jets with ptr's to the subjets as constituents
00742   std::vector<math::XYZTLorentzVector>::const_iterator ip4 = p4_hardJets.begin(),
00743     ip4Begin = p4_hardJets.begin(),
00744     ip4End = p4_hardJets.end();
00745 
00746   for ( ; ip4 != ip4End; ++ip4 ) {
00747     int p4_index = ip4 - ip4Begin;
00748     std::vector<int> & ind = indices[p4_index];
00749     std::vector<reco::CandidatePtr> i_hardJetConstituents;
00750     // Add the subjets to the hard jet
00751     for( std::vector<int>::const_iterator isub = ind.begin();
00752          isub != ind.end(); ++isub ) {
00753       reco::CandidatePtr candPtr( subjetHandleAfterPut, *isub, false );
00754       i_hardJetConstituents.push_back( candPtr );
00755     }   
00756     reco::Particle::Point point(0,0,0);
00757     reco::BasicJet toput( *ip4, point, i_hardJetConstituents);
00758     toput.setJetArea( area_hardJets[ip4 - ip4Begin] );
00759     jetCollection->push_back( toput );
00760   }
00761   
00762   // put hard jets into event record
00763   iEvent.put( jetCollection);
00764 
00765 }