CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/RecoJets/FFTJetProducers/plugins/FFTJetProducer.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:    FFTJetProducers
00004 // Class:      FFTJetProducer
00005 // 
00013 //
00014 // Original Author:  Igor Volobouev
00015 //         Created:  Sun Jun 20 14:32:36 CDT 2010
00016 // $Id: FFTJetProducer.cc,v 1.2 2010/12/07 00:19:43 igv Exp $
00017 //
00018 //
00019 
00020 #include <iostream>
00021 #include <fstream>
00022 #include <algorithm>
00023 
00024 // Header for this class
00025 #include "RecoJets/FFTJetProducers/plugins/FFTJetProducer.h"
00026 
00027 // Additional FFTJet headers
00028 #include "fftjet/VectorRecombinationAlgFactory.hh"
00029 #include "fftjet/RecombinationAlgFactory.hh"
00030 
00031 // Framework include files
00032 #include "FWCore/Framework/interface/MakerMacros.h"
00033 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00034 
00035 // Data formats
00036 #include "DataFormats/Common/interface/View.h"
00037 #include "DataFormats/Common/interface/Handle.h"
00038 #include "DataFormats/VertexReco/interface/Vertex.h"
00039 #include "DataFormats/JetReco/interface/FFTCaloJetCollection.h"
00040 #include "DataFormats/JetReco/interface/FFTGenJetCollection.h"
00041 #include "DataFormats/JetReco/interface/FFTPFJetCollection.h"
00042 #include "DataFormats/JetReco/interface/FFTJPTJetCollection.h"
00043 #include "DataFormats/JetReco/interface/FFTBasicJetCollection.h"
00044 #include "DataFormats/JetReco/interface/FFTTrackJetCollection.h"
00045 #include "DataFormats/Candidate/interface/Candidate.h"
00046 #include "DataFormats/JetReco/interface/FFTJetProducerSummary.h"
00047 
00048 #include "RecoJets/FFTJetProducers/interface/FFTJetParameterParser.h"
00049 
00050 #include "RecoJets/FFTJetAlgorithms/interface/clusteringTreeConverters.h"
00051 #include "RecoJets/FFTJetAlgorithms/interface/jetConverters.h"
00052 #include "RecoJets/FFTJetAlgorithms/interface/DiscretizedEnergyFlow.h"
00053 
00054 #include "RecoJets/JetProducers/interface/JetSpecific.h"
00055 
00056 
00057 #define make_param(type, varname) const \
00058     type & varname (ps.getParameter< type >( #varname ))
00059 
00060 #define init_param(type, varname) varname (ps.getParameter< type >( #varname ))
00061 
00062 // A generic switch statement based on jet type.
00063 // Defining it in a single place avoids potential errors
00064 // in case another jet type is introduced in the future.
00065 //
00066 // JPTJet is omitted for now: there is no reco::writeSpecific method
00067 // for it (see header JetSpecific.h in the JetProducers package) 
00068 //
00069 #define jet_type_switch(method, arg1, arg2) do {\
00070     switch (jetType)\
00071     {\
00072     case CALOJET:\
00073         method <reco::CaloJet> ( arg1 , arg2 );\
00074         break;\
00075     case PFJET:\
00076         method <reco::PFJet> ( arg1 , arg2 );\
00077         break;\
00078     case GENJET:\
00079         method <reco::GenJet> ( arg1 , arg2 );\
00080         break;\
00081     case TRACKJET:\
00082         method <reco::TrackJet> ( arg1 , arg2 );\
00083         break;\
00084     case BASICJET:\
00085         method <reco::BasicJet> ( arg1 , arg2 );\
00086         break;\
00087     default:\
00088         assert(!"ERROR in FFTJetProducer : invalid jet type."\
00089                " This is a bug. Please report.");\
00090     }\
00091 } while(0);
00092 
00093 using namespace fftjetcms;
00094 
00095 FFTJetProducer::Resolution FFTJetProducer::parse_resolution(
00096     const std::string& name)
00097 {
00098     if (!name.compare("fixed"))
00099         return FIXED;
00100     else if (!name.compare("maximallyStable"))
00101         return MAXIMALLY_STABLE;
00102     else if (!name.compare("globallyAdaptive"))
00103         return GLOBALLY_ADAPTIVE;
00104     else if (!name.compare("locallyAdaptive"))
00105         return LOCALLY_ADAPTIVE;
00106     else
00107         throw cms::Exception("FFTJetBadConfig")
00108             << "Invalid resolution specification \""
00109             << name << "\"" << std::endl;
00110 }
00111 
00112 
00113 template <typename T>
00114 void FFTJetProducer::makeProduces(
00115     const std::string& alias, const std::string& tag)
00116 {
00117     produces<std::vector<reco::FFTAnyJet<T> > >(tag).setBranchAlias(alias);
00118 }
00119 
00120 //
00121 // constructors and destructor
00122 //
00123 FFTJetProducer::FFTJetProducer(const edm::ParameterSet& ps)
00124     : FFTJetInterface(ps),
00125       myConfiguration(ps),
00126       init_param(edm::InputTag, treeLabel),
00127       init_param(bool, useGriddedAlgorithm),
00128       init_param(bool, reuseExistingGrid),
00129       init_param(unsigned, maxIterations),
00130       init_param(unsigned, nJetsRequiredToConverge),
00131       init_param(double, convergenceDistance),
00132       init_param(bool, assignConstituents),
00133       init_param(bool, resumConstituents),
00134       init_param(double, fixedScale),
00135       init_param(double, minStableScale),
00136       init_param(double, maxStableScale),
00137       init_param(double, stabilityAlpha),
00138       init_param(double, noiseLevel),
00139       init_param(unsigned, nClustersRequested),
00140       init_param(double, gridScanMaxEta),
00141       init_param(std::string, recombinationAlgorithm),
00142       init_param(bool, isCrisp),
00143       init_param(double, unlikelyBgWeight),
00144       init_param(double, recombinationDataCutoff),
00145       resolution(parse_resolution(ps.getParameter<std::string>("resolution"))),
00146 
00147       minLevel(0),
00148       maxLevel(0),
00149       usedLevel(0),
00150       unused(0.0),
00151       iterationsPerformed(1U),
00152       constituents(200)
00153 {
00154     // Check that the settings make sense
00155     if (resumConstituents && !assignConstituents)
00156         throw cms::Exception("FFTJetBadConfig") 
00157             << "Can't resum constituents if they are not assigned"
00158             << std::endl;
00159 
00160     produces<reco::FFTJetProducerSummary>(outputLabel);
00161     const std::string alias(ps.getUntrackedParameter<std::string>(
00162                                 "alias", outputLabel));
00163     jet_type_switch(makeProduces, alias, outputLabel);
00164 
00165     // Build the set of pattern recognition scales.
00166     // This is needed in order to read the clustering tree
00167     // from the event record.
00168     iniScales = fftjet_ScaleSet_parser(
00169         ps.getParameter<edm::ParameterSet>("InitialScales"));
00170     checkConfig(iniScales, "invalid set of scales");
00171     std::sort(iniScales->begin(), iniScales->end(), std::greater<double>());
00172 
00173     // Most of the configuration has to be performed inside
00174     // the "beginJob" method. This is because chaining of the
00175     // parsers between this base class and the derived classes
00176     // can not work from the constructor of the base class.
00177 }
00178 
00179 
00180 FFTJetProducer::~FFTJetProducer()
00181 {
00182 }
00183 
00184 //
00185 // member functions
00186 //
00187 template<class Real>
00188 void FFTJetProducer::loadSparseTreeData(const edm::Event& iEvent)
00189 {
00190     typedef reco::PattRecoTree<Real,reco::PattRecoPeak<Real> > StoredTree;
00191 
00192     // Get the input
00193     edm::Handle<StoredTree> input;
00194     iEvent.getByLabel(treeLabel, input);
00195 
00196     if (!input->isSparse())
00197         throw cms::Exception("FFTJetBadConfig") 
00198             << "The stored clustering tree is not sparse" << std::endl;
00199 
00200     sparsePeakTreeFromStorable(*input, iniScales.get(), getEventScale(), &sparseTree);
00201     sparseTree.sortNodes();
00202 }
00203 
00204 
00205 void FFTJetProducer::selectPreclusters(
00206     const SparseTree& tree,
00207     const fftjet::Functor1<bool,fftjet::Peak>& peakSelector,
00208     std::vector<fftjet::Peak>* preclusters)
00209 {
00210     nodes.clear();
00211     selectTreeNodes(tree, peakSelector, &nodes);
00212 
00213     // Fill out the vector of preclusters using the tree node ids
00214     const unsigned nNodes = nodes.size();
00215     const SparseTree::NodeId* pnodes = nNodes ? &nodes[0] : 0;
00216     preclusters->reserve(nNodes);
00217     for (unsigned i=0; i<nNodes; ++i)
00218         preclusters->push_back(
00219             sparseTree.uncheckedNode(pnodes[i]).getCluster());
00220 
00221     // Set the status word to indicate the resolution scheme used
00222     fftjet::Peak* clusters = nNodes ? &(*preclusters)[0] : 0;
00223     for (unsigned i=0; i<nNodes; ++i)
00224         clusters[i].setStatus(resolution);
00225 }
00226 
00227 
00228 void FFTJetProducer::selectTreeNodes(
00229     const SparseTree& tree,
00230     const fftjet::Functor1<bool,fftjet::Peak>& peakSelect,
00231     std::vector<SparseTree::NodeId>* mynodes)
00232 {
00233     minLevel = maxLevel = usedLevel = 0;
00234 
00235     // Get the tree nodes which pass the cuts
00236     // (according to the selected resolution strategy)
00237     switch (resolution)
00238     {
00239     case FIXED:
00240     {
00241         usedLevel = tree.getLevel(fixedScale);
00242         tree.getPassingNodes(usedLevel, peakSelect, mynodes);
00243     }
00244     break;
00245 
00246     case MAXIMALLY_STABLE:
00247     {
00248         const unsigned minStartingLevel = maxStableScale > 0.0 ? 
00249             tree.getLevel(maxStableScale) : 0;
00250         const unsigned maxStartingLevel = minStableScale > 0.0 ?
00251             tree.getLevel(minStableScale) : UINT_MAX;
00252 
00253         if (tree.stableClusterCount(
00254                 peakSelect, &minLevel, &maxLevel, stabilityAlpha,
00255                 minStartingLevel, maxStartingLevel))
00256         {
00257             usedLevel = (minLevel + maxLevel)/2;
00258             tree.getPassingNodes(usedLevel, peakSelect, mynodes);
00259         }
00260     }
00261     break;
00262 
00263     case GLOBALLY_ADAPTIVE:
00264     {
00265         const bool stable = tree.clusterCountLevels(
00266             nClustersRequested, peakSelect, &minLevel, &maxLevel);
00267         if (minLevel || maxLevel)
00268         {
00269             usedLevel = (minLevel + maxLevel)/2;
00270             if (!stable)
00271             {
00272                 const int maxlev = tree.maxStoredLevel();
00273                 bool levelFound = false;
00274                 for (int delta=0; delta<=maxlev && !levelFound; ++delta)
00275                     for (int ifac=1; ifac>-2 && !levelFound; ifac-=2)
00276                     {
00277                         const int level = usedLevel + ifac*delta;
00278                         if (level > 0 && level <= maxlev)
00279                             if (occupancy[level] == nClustersRequested)
00280                             {
00281                                 usedLevel = level;
00282                                 levelFound = true;
00283                             }
00284                     }
00285                 assert(levelFound);
00286             }
00287         }
00288         else
00289         {
00290             // Can't find that exact number of preclusters.
00291             // Try to get the next best thing.
00292             usedLevel = 1;
00293             const unsigned occ1 = occupancy[1];
00294             if (nClustersRequested >= occ1)
00295             {
00296                 const unsigned maxlev = tree.maxStoredLevel();
00297                 if (nClustersRequested > occupancy[maxlev])
00298                     usedLevel = maxlev;
00299                 else
00300                 {
00301                     // It would be nice to use "lower_bound" here,
00302                     // but the occupancy is not necessarily monotonous.
00303                     unsigned bestDelta = nClustersRequested > occ1 ?
00304                         nClustersRequested - occ1 : occ1 - nClustersRequested;
00305                     for (unsigned level=2; level<=maxlev; ++level)
00306                     {
00307                         const unsigned n = occupancy[level];
00308                         const unsigned d = nClustersRequested > n ? 
00309                             nClustersRequested - n : n - nClustersRequested;
00310                         if (d < bestDelta)
00311                         {
00312                             bestDelta = d;
00313                             usedLevel = level;
00314                         }
00315                     }
00316                 }
00317             }
00318         }
00319         tree.getPassingNodes(usedLevel, peakSelect, mynodes);
00320     }
00321     break;
00322 
00323     case LOCALLY_ADAPTIVE:
00324     {
00325         usedLevel = tree.getLevel(fixedScale);
00326         tree.getMagS2OptimalNodes(peakSelect, nClustersRequested,
00327                                   usedLevel, mynodes, &thresholds);
00328     }
00329     break;
00330 
00331     default:
00332         assert(!"ERROR in FFTJetProducer::selectTreeNodes : "
00333                "should never get here! This is a bug. Please report.");
00334     }
00335 }
00336 
00337 
00338 void FFTJetProducer::prepareRecombinationScales()
00339 {
00340     const unsigned nClus = preclusters.size();
00341     if (nClus)
00342     {
00343         fftjet::Peak* clus = &preclusters[0];
00344         fftjet::Functor1<double,fftjet::Peak>& 
00345             scaleCalc(*recoScaleCalcPeak);
00346         fftjet::Functor1<double,fftjet::Peak>& 
00347             ratioCalc(*recoScaleRatioCalcPeak);
00348         fftjet::Functor1<double,fftjet::Peak>& 
00349             factorCalc(*memberFactorCalcPeak);
00350 
00351         for (unsigned i=0; i<nClus; ++i)
00352         {
00353             clus[i].setRecoScale(scaleCalc(clus[i]));
00354             clus[i].setRecoScaleRatio(ratioCalc(clus[i]));
00355             clus[i].setMembershipFactor(factorCalc(clus[i]));
00356         }
00357     }
00358 }
00359 
00360 
00361 void FFTJetProducer::buildGridAlg()
00362 {
00363     int minBin = energyFlow->getEtaBin(-gridScanMaxEta);
00364     if (minBin < 0)
00365         minBin = 0;
00366     int maxBin = energyFlow->getEtaBin(gridScanMaxEta) + 1;
00367     if (maxBin < 0)
00368         maxBin = 0;
00369     
00370     fftjet::DefaultRecombinationAlgFactory<
00371         Real,VectorLike,BgData,VBuilder> factory;
00372     if (factory[recombinationAlgorithm] == NULL)
00373         throw cms::Exception("FFTJetBadConfig")
00374             << "Invalid grid recombination algorithm \""
00375             << recombinationAlgorithm << "\"" << std::endl;
00376     gridAlg = std::auto_ptr<GridAlg>(
00377         factory[recombinationAlgorithm]->create(
00378             jetMembershipFunction.get(),
00379             bgMembershipFunction.get(),
00380             unlikelyBgWeight, recombinationDataCutoff,
00381             isCrisp, false, assignConstituents, minBin, maxBin));
00382 }
00383 
00384 
00385 void FFTJetProducer::loadEnergyFlow(const edm::Event& iEvent)
00386 {
00387     edm::Handle<DiscretizedEnergyFlow> input;
00388     iEvent.getByLabel(treeLabel, input);
00389 
00390     // Make sure that the grid is compatible with the stored one
00391     bool rebuildGrid = energyFlow.get() == NULL;
00392     if (!rebuildGrid)
00393         rebuildGrid = 
00394             !(energyFlow->nEta() == input->nEtaBins() &&
00395               energyFlow->nPhi() == input->nPhiBins() &&
00396               energyFlow->etaMin() == input->etaMin() &&
00397               energyFlow->etaMax() == input->etaMax() &&
00398               energyFlow->phiBin0Edge() == input->phiBin0Edge());
00399     if (rebuildGrid)
00400     {
00401         // We should not get here very often...
00402         energyFlow = std::auto_ptr<fftjet::Grid2d<Real> >(
00403             new fftjet::Grid2d<Real>(
00404                 input->nEtaBins(), input->etaMin(), input->etaMax(),
00405                 input->nPhiBins(), input->phiBin0Edge(), input->title()));
00406         buildGridAlg();
00407     }
00408     energyFlow->blockSet(input->data(), input->nEtaBins(), input->nPhiBins());
00409 }
00410 
00411 
00412 bool FFTJetProducer::checkConvergence(const std::vector<RecoFFTJet>& previous,
00413                                       std::vector<RecoFFTJet>& nextSet)
00414 {
00415     fftjet::Functor2<double,RecoFFTJet,RecoFFTJet>&
00416         distanceCalc(*jetDistanceCalc);
00417 
00418     const unsigned nJets = previous.size();
00419     const RecoFFTJet* prev = &previous[0];
00420     RecoFFTJet* next = &nextSet[0];
00421 
00422     // Calculate convergence distances for all jets
00423     bool converged = true;
00424     for (unsigned i=0; i<nJets; ++i)
00425     {
00426         const double d = distanceCalc(prev[i], next[i]);
00427         next[i].setConvergenceDistance(d);
00428         if (i < nJetsRequiredToConverge && d > convergenceDistance)
00429             converged = false;
00430     }
00431 
00432     return converged;
00433 }
00434 
00435 
00436 unsigned FFTJetProducer::iterateJetReconstruction()
00437 {
00438     fftjet::Functor1<double,RecoFFTJet>& scaleCalc(*recoScaleCalcJet);
00439     fftjet::Functor1<double,RecoFFTJet>& ratioCalc(*recoScaleRatioCalcJet);
00440     fftjet::Functor1<double,RecoFFTJet>& factorCalc(*memberFactorCalcJet);
00441 
00442     const unsigned nJets = recoJets.size();
00443 
00444     unsigned iterNum = 1U;
00445     bool converged = false;
00446     for (; iterNum<maxIterations && !converged; ++iterNum)
00447     {
00448         // Recreate the vector of preclusters using the jets
00449         const RecoFFTJet* jets = &recoJets[0];
00450         iterPreclusters.clear();
00451         iterPreclusters.reserve(nJets);
00452         for (unsigned i=0; i<nJets; ++i)
00453         {
00454             const RecoFFTJet& jet(jets[i]);
00455             fftjet::Peak p(jet.precluster());
00456             p.setEtaPhi(jet.vec().Eta(), jet.vec().Phi());
00457             p.setRecoScale(scaleCalc(jet));
00458             p.setRecoScaleRatio(ratioCalc(jet));
00459             p.setMembershipFactor(factorCalc(jet));
00460             iterPreclusters.push_back(p);
00461         }
00462 
00463         // Run the algorithm
00464         int status = 0;
00465         if (useGriddedAlgorithm)
00466             status = gridAlg->run(iterPreclusters, *energyFlow,
00467                                   &noiseLevel, 1U, 1U,
00468                                   &iterJets, &unclustered, &unused);
00469         else
00470             status = recoAlg->run(iterPreclusters, eventData, &noiseLevel, 1U,
00471                                   &iterJets, &unclustered, &unused);
00472         if (status)
00473             throw cms::Exception("FFTJetInterface")
00474                 << "FFTJet algorithm failed" << std::endl;
00475         assert(iterJets.size() == nJets);
00476 
00477         // Figure out if the iterations have converged
00478         converged = checkConvergence(recoJets, iterJets);
00479 
00480         // Prepare for the next cycle
00481         iterJets.swap(recoJets);
00482     }
00483 
00484     // Plug in the original precluster coordinates into the result
00485     assert(preclusters.size() == nJets);
00486     RecoFFTJet* jets = &recoJets[0];
00487     for (unsigned i=0; i<nJets; ++i)
00488     {
00489         const fftjet::Peak& oldp(preclusters[i]);
00490         jets[i].setPeakEtaPhi(oldp.eta(), oldp.phi());
00491     }
00492 
00493     // If we have converged on the last cycle, the result
00494     // would be indistinguishable from no convergence.
00495     // Because of this, raise the counter by one to indicate
00496     // the case when the convergence is not achieved.
00497     if (!converged)
00498         ++iterNum;
00499 
00500     return iterNum;
00501 }
00502 
00503 
00504 void FFTJetProducer::determineGriddedConstituents()
00505 {
00506     const unsigned nJets = recoJets.size();
00507     const unsigned* clusterMask = gridAlg->getClusterMask();
00508     const int nEta = gridAlg->getLastNEta();
00509     const int nPhi = gridAlg->getLastNPhi();
00510     const fftjet::Grid2d<Real>& g(*energyFlow);
00511 
00512     const unsigned nInputs = eventData.size();
00513     const VectorLike* inp = nInputs ? &eventData[0] : 0;
00514     const unsigned* candIdx = nInputs ? &candidateIndex[0] : 0;
00515     for (unsigned i=0; i<nInputs; ++i)
00516     {
00517         const VectorLike& item(inp[i]);
00518         const int iPhi = g.getPhiBin(item.Phi());
00519         const int iEta = g.getEtaBin(item.Eta());
00520         const unsigned mask = iEta >= 0 && iEta < nEta ?
00521             clusterMask[iEta*nPhi + iPhi] : 0;
00522         assert(mask <= nJets);
00523         constituents[mask].push_back(inputCollection->ptrAt(candIdx[i]));
00524     }
00525 }
00526 
00527 
00528 void FFTJetProducer::determineVectorConstituents()
00529 {
00530     const unsigned nJets = recoJets.size();
00531     const unsigned* clusterMask = recoAlg->getClusterMask();
00532     const unsigned maskLength = recoAlg->getLastNData();
00533     assert(maskLength == eventData.size());
00534 
00535     const unsigned* candIdx = maskLength ? &candidateIndex[0] : 0;
00536     for (unsigned i=0; i<maskLength; ++i)
00537     {
00538         // In FFTJet, the mask value of 0 corresponds to unclustered
00539         // energy. We will do the same here. Jet numbers are therefore
00540         // shifted by 1 wrt constituents vector, and constituents[1]
00541         // corresponds to jet number 0.
00542         const unsigned mask = clusterMask[i];
00543         assert(mask <= nJets);
00544         constituents[mask].push_back(inputCollection->ptrAt(candIdx[i]));
00545     }
00546 }
00547 
00548 
00549 // The following code more or less coincides with the similar method
00550 // implemented in VirtualJetProducer
00551 template <typename T>
00552 void FFTJetProducer::writeJets(edm::Event& iEvent,
00553                                const edm::EventSetup& iSetup)
00554 {
00555     using namespace reco;
00556 
00557     typedef FFTAnyJet<T> OutputJet;
00558     typedef std::vector<OutputJet> OutputCollection;
00559 
00560     // Area of a single eta-phi cell for jet area calculations.
00561     // Set it to 0 in case the module configuration does not allow
00562     // us to calculate jet areas reliably.
00563     const double cellArea = useGriddedAlgorithm && 
00564                             recombinationDataCutoff < 0.0 ?
00565         energyFlow->etaBinWidth() * energyFlow->phiBinWidth() : 0.0;
00566 
00567     // allocate output jet collection
00568     std::auto_ptr<OutputCollection> jets(new OutputCollection());
00569     const unsigned nJets = recoJets.size();
00570     jets->reserve(nJets);
00571 
00572     for (unsigned ijet=0; ijet<nJets; ++ijet)
00573     {
00574         const RecoFFTJet& myjet(recoJets[ijet]);
00575 
00576         // Check if we should resum jet constituents
00577         VectorLike jet4vec(myjet.vec());
00578         if (resumConstituents)
00579         {
00580             VectorLike sum(0.0, 0.0, 0.0, 0.0);
00581             const unsigned nCon = constituents[ijet+1].size();
00582             const reco::CandidatePtr* cn = nCon ? &constituents[ijet+1][0] : 0;
00583             for (unsigned i=0; i<nCon; ++i)
00584                 sum += cn[i]->p4();
00585             jet4vec = sum;
00586         }
00587 
00588         // Write the specifics to the jet (simultaneously sets 4-vector,
00589         // vertex, constituents). These are overridden functions that will
00590         // call the appropriate specific code.
00591         T jet;
00592         writeSpecific(jet, jet4vec, vertexUsed(),
00593                       constituents[ijet+1], iSetup);
00594 
00595         // calcuate the jet area
00596         jet.setJetArea(cellArea*myjet.ncells());
00597 
00598         // add jet to the list
00599         jets->push_back(OutputJet(jet, jetToStorable<float>(myjet)));
00600     }
00601 
00602     // put the collection into the event
00603     iEvent.put(jets, outputLabel);
00604 }
00605 
00606 
00607 void FFTJetProducer::saveResults(edm::Event& ev, const edm::EventSetup& iSetup)
00608 {
00609     // Write recombined jets
00610     jet_type_switch(writeJets, ev, iSetup);
00611 
00612     // Check if we should resum unclustered energy constituents
00613     VectorLike unclusE(unclustered);
00614     if (resumConstituents)
00615     {
00616         VectorLike sum(0.0, 0.0, 0.0, 0.0);
00617         const unsigned nCon = constituents[0].size();
00618         const reco::CandidatePtr* cn = nCon ? &constituents[0][0] : 0;
00619         for (unsigned i=0; i<nCon; ++i)
00620             sum += cn[i]->p4();
00621         unclusE = sum;
00622     }
00623 
00624     // Write the jet reconstruction summary
00625     const double minScale = minLevel ? sparseTree.getScale(minLevel) : 0.0;
00626     const double maxScale = maxLevel ? sparseTree.getScale(maxLevel) : 0.0;
00627     const double scaleUsed = usedLevel ? sparseTree.getScale(usedLevel) : 0.0;
00628 
00629     std::auto_ptr<reco::FFTJetProducerSummary> summary(
00630         new reco::FFTJetProducerSummary(
00631             thresholds, occupancy, unclusE,
00632             constituents[0], unused,
00633             minScale, maxScale, scaleUsed,
00634             preclusters.size(), iterationsPerformed,
00635             iterationsPerformed == 1U ||
00636             iterationsPerformed <= maxIterations));
00637     ev.put(summary, outputLabel);
00638 }
00639 
00640 
00641 // ------------ method called to for each event  ------------
00642 void FFTJetProducer::produce(edm::Event& iEvent,
00643                              const edm::EventSetup& iSetup)
00644 {
00645     // Load the clustering tree made by FFTJetPatRecoProducer
00646     if (storeInSinglePrecision())
00647         loadSparseTreeData<float>(iEvent);
00648     else
00649         loadSparseTreeData<double>(iEvent);
00650 
00651     // Do we need to load the candidate collection?
00652     if (assignConstituents || !(useGriddedAlgorithm && reuseExistingGrid))
00653         loadInputCollection(iEvent);
00654 
00655     // Do we need to have discretized energy flow?
00656     if (useGriddedAlgorithm)
00657     {
00658         if (reuseExistingGrid)
00659             loadEnergyFlow(iEvent);
00660         else
00661             discretizeEnergyFlow();
00662     }
00663 
00664     // Calculate cluster occupancy as a function of level number
00665     sparseTree.occupancyInScaleSpace(*peakSelector, &occupancy);
00666 
00667     // Select the preclusters using the requested resolution scheme
00668     preclusters.clear();
00669     selectPreclusters(sparseTree, *peakSelector, &preclusters);
00670 
00671     // Prepare to run the jet recombination procedure
00672     prepareRecombinationScales();
00673 
00674     // Assign membership functions to preclusters. If this function
00675     // is not overriden in a derived class, default algorithm membership
00676     // function will be used for every cluster.
00677     assignMembershipFunctions(&preclusters);
00678 
00679     // Run the recombination algorithm once
00680     int status = 0;
00681     if (useGriddedAlgorithm)
00682         status = gridAlg->run(preclusters, *energyFlow,
00683                               &noiseLevel, 1U, 1U,
00684                               &recoJets, &unclustered, &unused);
00685     else
00686         status = recoAlg->run(preclusters, eventData, &noiseLevel, 1U,
00687                               &recoJets, &unclustered, &unused);
00688     if (status)
00689         throw cms::Exception("FFTJetInterface")
00690             << "FFTJet algorithm failed (first iteration)" << std::endl;
00691 
00692     // If requested, iterate the jet recombination procedure
00693     if (maxIterations > 1U && !recoJets.empty())
00694         iterationsPerformed = iterateJetReconstruction();
00695     else
00696         iterationsPerformed = 1U;
00697 
00698     // Determine jet constituents. FFTJet returns a map
00699     // of constituents which is inverse to what we need here.
00700     const unsigned nJets = recoJets.size();
00701     if (constituents.size() <= nJets)
00702         constituents.resize(nJets + 1U);
00703     if (assignConstituents)
00704     {
00705         for (unsigned i=0; i<=nJets; ++i)
00706             constituents[i].clear();
00707         if (useGriddedAlgorithm)
00708             determineGriddedConstituents();
00709         else
00710             determineVectorConstituents();
00711     }
00712 
00713     // Write out the results
00714     saveResults(iEvent, iSetup);
00715 }
00716 
00717 
00718 std::auto_ptr<fftjet::Functor1<bool,fftjet::Peak> >
00719 FFTJetProducer::parse_peakSelector(const edm::ParameterSet& ps)
00720 {
00721     return fftjet_PeakSelector_parser(
00722         ps.getParameter<edm::ParameterSet>("PeakSelectorConfiguration"));
00723 }
00724 
00725 
00726 // Parser for the jet membership function
00727 std::auto_ptr<fftjet::ScaleSpaceKernel>
00728 FFTJetProducer::parse_jetMembershipFunction(const edm::ParameterSet& ps)
00729 {
00730     return fftjet_MembershipFunction_parser(
00731         ps.getParameter<edm::ParameterSet>("jetMembershipFunction"));
00732 }
00733 
00734 
00735 // Parser for the background membership function
00736 std::auto_ptr<AbsBgFunctor>
00737 FFTJetProducer::parse_bgMembershipFunction(const edm::ParameterSet& ps)
00738 {
00739     return fftjet_BgFunctor_parser(
00740         ps.getParameter<edm::ParameterSet>("bgMembershipFunction"));
00741 }
00742 
00743 
00744 // Calculator for the recombination scale
00745 std::auto_ptr<fftjet::Functor1<double,fftjet::Peak> >
00746 FFTJetProducer::parse_recoScaleCalcPeak(const edm::ParameterSet& ps)
00747 {
00748     return fftjet_PeakFunctor_parser(
00749         ps.getParameter<edm::ParameterSet>("recoScaleCalcPeak"));
00750 }
00751 
00752 
00753 // Calculator for the recombination scale ratio
00754 std::auto_ptr<fftjet::Functor1<double,fftjet::Peak> >
00755 FFTJetProducer::parse_recoScaleRatioCalcPeak(const edm::ParameterSet& ps)
00756 {
00757     return fftjet_PeakFunctor_parser(
00758         ps.getParameter<edm::ParameterSet>("recoScaleRatioCalcPeak"));
00759 }
00760 
00761 
00762 // Calculator for the membership function factor
00763 std::auto_ptr<fftjet::Functor1<double,fftjet::Peak> >
00764 FFTJetProducer::parse_memberFactorCalcPeak(const edm::ParameterSet& ps)
00765 {
00766     return fftjet_PeakFunctor_parser(
00767         ps.getParameter<edm::ParameterSet>("memberFactorCalcPeak"));
00768 }
00769 
00770 
00771 std::auto_ptr<fftjet::Functor1<double,FFTJetProducer::RecoFFTJet> >
00772 FFTJetProducer::parse_recoScaleCalcJet(const edm::ParameterSet& ps)
00773 {
00774     return fftjet_JetFunctor_parser(
00775         ps.getParameter<edm::ParameterSet>("recoScaleCalcJet"));
00776 }
00777 
00778 
00779 std::auto_ptr<fftjet::Functor1<double,FFTJetProducer::RecoFFTJet> >
00780 FFTJetProducer::parse_recoScaleRatioCalcJet(const edm::ParameterSet& ps)
00781 {
00782     return fftjet_JetFunctor_parser(
00783         ps.getParameter<edm::ParameterSet>("recoScaleRatioCalcJet"));
00784 }
00785 
00786 
00787 std::auto_ptr<fftjet::Functor1<double,FFTJetProducer::RecoFFTJet> >
00788 FFTJetProducer::parse_memberFactorCalcJet(const edm::ParameterSet& ps)
00789 {
00790     return fftjet_JetFunctor_parser(
00791         ps.getParameter<edm::ParameterSet>("memberFactorCalcJet"));
00792 }
00793 
00794 
00795 std::auto_ptr<fftjet::Functor2<
00796     double,FFTJetProducer::RecoFFTJet,FFTJetProducer::RecoFFTJet> >
00797 FFTJetProducer::parse_jetDistanceCalc(const edm::ParameterSet& ps)
00798 {
00799     return fftjet_JetDistance_parser(
00800         ps.getParameter<edm::ParameterSet>("jetDistanceCalc"));
00801 }
00802 
00803 
00804 void FFTJetProducer::assignMembershipFunctions(std::vector<fftjet::Peak>*)
00805 {
00806 }
00807 
00808 
00809 // ------------ method called once each job just before starting event loop
00810 void FFTJetProducer::beginJob()
00811 {
00812     const edm::ParameterSet& ps(myConfiguration);
00813 
00814     // Parse the peak selector definition
00815     peakSelector = parse_peakSelector(ps);
00816     checkConfig(peakSelector, "invalid peak selector");
00817 
00818     jetMembershipFunction = parse_jetMembershipFunction(ps);
00819     checkConfig(jetMembershipFunction, "invalid jet membership function");
00820 
00821     bgMembershipFunction = parse_bgMembershipFunction(ps);
00822     checkConfig(bgMembershipFunction, "invalid noise membership function");
00823 
00824     // Build the energy recombination algorithm
00825     if (!useGriddedAlgorithm)
00826     {
00827         fftjet::DefaultVectorRecombinationAlgFactory<
00828             VectorLike,BgData,VBuilder> factory;
00829         if (factory[recombinationAlgorithm] == NULL)
00830             throw cms::Exception("FFTJetBadConfig")
00831                 << "Invalid vector recombination algorithm \""
00832                 << recombinationAlgorithm << "\"" << std::endl;
00833         recoAlg = std::auto_ptr<RecoAlg>(
00834             factory[recombinationAlgorithm]->create(
00835                 jetMembershipFunction.get(),
00836                 &VectorLike::Et, &VectorLike::Eta, &VectorLike::Phi,
00837                 bgMembershipFunction.get(),
00838                 unlikelyBgWeight, isCrisp, false, assignConstituents));
00839     }
00840     else if (!reuseExistingGrid)
00841     {
00842         energyFlow = fftjet_Grid2d_parser(
00843             ps.getParameter<edm::ParameterSet>("GridConfiguration"));
00844         checkConfig(energyFlow, "invalid discretization grid");
00845         buildGridAlg();
00846     }
00847 
00848     // Parse the calculator of the recombination scale
00849     recoScaleCalcPeak = parse_recoScaleCalcPeak(ps);
00850     checkConfig(recoScaleCalcPeak, "invalid spec for the "
00851                 "reconstruction scale calculator from peaks");
00852 
00853     // Parse the calculator of the recombination scale ratio
00854     recoScaleRatioCalcPeak = parse_recoScaleRatioCalcPeak(ps);
00855     checkConfig(recoScaleRatioCalcPeak, "invalid spec for the "
00856                 "reconstruction scale ratio calculator from peaks");
00857 
00858     // Calculator for the membership function factor
00859     memberFactorCalcPeak = parse_memberFactorCalcPeak(ps);
00860     checkConfig(memberFactorCalcPeak, "invalid spec for the "
00861                 "membership function factor calculator from peaks");
00862 
00863     if (maxIterations > 1)
00864     {
00865         // We are going to run iteratively. Make required objects.
00866         recoScaleCalcJet = parse_recoScaleCalcJet(ps);
00867         checkConfig(recoScaleCalcJet, "invalid spec for the "
00868                     "reconstruction scale calculator from jets");
00869 
00870         recoScaleRatioCalcJet = parse_recoScaleRatioCalcJet(ps);
00871         checkConfig(recoScaleRatioCalcJet, "invalid spec for the "
00872                     "reconstruction scale ratio calculator from jets");
00873 
00874         memberFactorCalcJet = parse_memberFactorCalcJet(ps);
00875         checkConfig(memberFactorCalcJet, "invalid spec for the "
00876                     "membership function factor calculator from jets");
00877 
00878         jetDistanceCalc = parse_jetDistanceCalc(ps);
00879         checkConfig(memberFactorCalcJet, "invalid spec for the "
00880                     "jet distance calculator");
00881     }
00882 }
00883 
00884 
00885 // ------------ method called once each job just after ending the event loop
00886 void FFTJetProducer::endJob()
00887 {
00888 }
00889 
00890 //define this as a plug-in
00891 DEFINE_FWK_MODULE(FFTJetProducer);