CMS 3D CMS Logo

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