CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/FastSimulation/PileUpProducer/plugins/PileUpProducer.cc

Go to the documentation of this file.
00001 #include "FWCore/Framework/interface/Event.h"
00002 #include "FWCore/Framework/interface/MakerMacros.h"
00003 #include "FWCore/ServiceRegistry/interface/Service.h"
00004 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00005 
00006 #include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
00007 
00008 #include "FastSimDataFormats/PileUpEvents/interface/PUEvent.h"
00009 
00010 #include "FastSimulation/PileUpProducer/plugins/PileUpProducer.h"
00011 #include "FastSimulation/Event/interface/BetaFuncPrimaryVertexGenerator.h"
00012 #include "FastSimulation/Event/interface/GaussianPrimaryVertexGenerator.h"
00013 #include "FastSimulation/Event/interface/FlatPrimaryVertexGenerator.h"
00014 #include "FastSimulation/Event/interface/NoPrimaryVertexGenerator.h"
00015 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00016 
00017 #include "HepMC/GenEvent.h"
00018 #include "TFile.h"
00019 #include "TTree.h"
00020 #include "TROOT.h"
00021 
00022 #include <iostream>
00023 #include <memory>
00024 #include <sys/stat.h>
00025 #include <cmath>
00026 
00027 PileUpProducer::PileUpProducer(edm::ParameterSet const & p) : hprob(0)
00028 {    
00029 
00030   // This producer produces an object PileupMixingContent, needed by PileupSummaryInfo
00031   produces<PileupMixingContent>();
00032   // This producer produces a HepMCProduct, with all pileup vertices/particles
00033   produces<edm::HepMCProduct>("PileUpEvents");
00034   
00035   // Initialize the random number generator service
00036   edm::Service<edm::RandomNumberGenerator> rng;
00037   if ( ! rng.isAvailable() ) {
00038     throw cms::Exception("Configuration")
00039       << "PileUpProducer requires the RandomGeneratorService\n"
00040          "which is not present in the configuration file.\n"
00041          "You must add the service in the configuration file\n"
00042          "or remove the module that requires it";
00043   }  
00044   random = new RandomEngine(&(*rng));
00045 
00046   // The pile-up event generation condition
00047   const edm::ParameterSet& pu = p.getParameter<edm::ParameterSet>("PileUpSimulator");
00048   usePoisson_ = pu.getParameter<bool>("usePoisson");
00049   averageNumber_ = 0.;
00050   if (usePoisson_) {
00051     std::cout << " FastSimulation/PileUpProducer -> poissonian distribution" << std::endl;
00052     averageNumber_ = pu.getParameter<double>("averageNumber");
00053   } else {//take distribution from configuration
00054     dataProbFunctionVar = pu.getParameter<std::vector<int> >("probFunctionVariable");
00055     dataProb = pu.getParameter<std::vector<double> >("probValue");
00056     varSize = (int) dataProbFunctionVar.size();
00057     probSize = (int) dataProb.size();
00058     //    std::cout << " FastSimulation/PileUpProducer -> varSize = " << varSize  << std::endl;
00059     //    std::cout << " FastSimulation/PileUpProducer -> probSize = " << probSize  << std::endl;
00060     
00061     std::cout << " FastSimulation/PileUpProducer -> distribution from configuration file "  << std::endl;
00062     if (probSize < varSize){
00063       for (int i=0; i<(varSize - probSize); i++) dataProb.push_back(0);
00064       edm::LogWarning("") << " The probability function data will be completed with " 
00065                           << (varSize - probSize) <<" values `0';"
00066                           << " the number of the P(x) data set after adding those 0's is " << dataProb.size();
00067       probSize = dataProb.size();
00068     }
00069     // Create an histogram with the data from the probability function provided by the user  
00070     int xmin = (int) dataProbFunctionVar[0];
00071     int xmax = (int) dataProbFunctionVar[varSize-1]+1;  // need upper edge to be one beyond last value
00072     int numBins = varSize;
00073     std::cout << " FastSimulation/PileUpProducer -> An histogram will be created with " << numBins 
00074               << " bins in the range ("<< xmin << "," << xmax << ")." << std::endl;
00075     hprob = new TH1F("h","Histo from the user's probability function",numBins,xmin,xmax); 
00076     LogDebug("") << " FastSimulation/PileUpProducer -> Filling histogram with the following data:";
00077     for (int j=0; j < numBins ; j++){
00078       LogDebug("") << " x = " << dataProbFunctionVar[j ]<< " P(x) = " << dataProb[j];
00079       hprob->Fill(dataProbFunctionVar[j]+0.5,dataProb[j]); // assuming integer values for the bins, fill bin centers, not edges 
00080     }
00081 
00082     // Check if the histogram is normalized
00083     if (((hprob->Integral() - 1) > 1.0e-02) && ((hprob->Integral() - 1) < -1.0e-02)) throw cms::Exception("BadHistoDistribution") << "The histogram should be normalized!" << std::endl;
00084     
00085     // Get the averageNumber from the histo 
00086     averageNumber_ = hprob->GetMean();
00087   }
00088   theFileNames = pu.getUntrackedParameter<std::vector<std::string> >("fileNames");
00089   inputFile = pu.getUntrackedParameter<std::string>("inputFile");
00090   theNumberOfFiles = theFileNames.size();
00091   theFiles.resize(theNumberOfFiles);
00092   theTrees.resize(theNumberOfFiles);
00093   theBranches.resize(theNumberOfFiles);
00094   thePUEvents.resize(theNumberOfFiles);
00095   theCurrentEntry.resize(theNumberOfFiles);
00096   theCurrentMinBiasEvt.resize(theNumberOfFiles);
00097   theNumberOfEntries.resize(theNumberOfFiles);
00098   theNumberOfMinBiasEvts.resize(theNumberOfFiles);
00099 
00100   // Initialize the primary vertex generator
00101   const edm::ParameterSet& vtx = p.getParameter<edm::ParameterSet>("VertexGenerator");
00102   std::string vtxType = vtx.getParameter<std::string>("type");
00103   if ( vtxType == "Gaussian" ) 
00104     theVertexGenerator = new GaussianPrimaryVertexGenerator(vtx,random);
00105   else if ( vtxType == "Flat" ) 
00106     theVertexGenerator = new FlatPrimaryVertexGenerator(vtx,random);
00107   else if ( vtxType == "BetaFunc" )
00108     theVertexGenerator = new BetaFuncPrimaryVertexGenerator(vtx,random);
00109   else
00110     theVertexGenerator = new NoPrimaryVertexGenerator();
00111 
00112 
00113 
00114   if (averageNumber_ > 0.)
00115     {
00116       std::cout << " FastSimulation/PileUpProducer -> MinBias events taken from " << theFileNames[0] << " et al., " ;
00117       std::cout << " with an average number of events of " << averageNumber_ << std::endl;
00118     }
00119   else std::cout << " FastSimulation/PileUpProducer -> No pileup " << std::endl;
00120 
00121 
00122 }
00123 
00124 PileUpProducer::~PileUpProducer() { 
00125 
00126   delete theVertexGenerator;
00127   if (hprob) delete hprob;
00128 
00129 }
00130 
00131 void PileUpProducer::beginRun(edm::Run & run, edm::EventSetup const& es)
00132 {
00133   
00134   gROOT->cd();
00135   
00136   std::string fullPath;
00137   
00138   // Read the information from a previous run (to keep reproducibility)
00139   bool input = this->read(inputFile);
00140   if ( input ) 
00141     std::cout << "***WARNING*** You are reading pile-up information from the file "
00142               << inputFile << " created in an earlier run."
00143               << std::endl;
00144 
00145   // Open the file for saving the information of the current run
00146   myOutputFile.open ("PileUpOutputFile.txt");
00147   myOutputBuffer = 0;
00148 
00149   // Open the root files
00150   for ( unsigned file=0; file<theNumberOfFiles; ++file ) {
00151 
00152     if (theFileNames[file].find("file:")==0) {
00153       fullPath = theFileNames[file].erase(0,5);
00154     }
00155     else {
00156       edm::FileInPath myDataFile("FastSimulation/PileUpProducer/data/"+theFileNames[file]);
00157       fullPath = myDataFile.fullPath();
00158     }
00159     //    theFiles[file] = TFile::Open(theFileNames[file].c_str());
00160     theFiles[file] = TFile::Open(fullPath.c_str());
00161     if ( !theFiles[file] ) throw cms::Exception("FastSimulation/PileUpProducer") 
00162       << "File " << theFileNames[file] << " " << fullPath <<  " not found ";
00163     //
00164     theTrees[file] = (TTree*) theFiles[file]->Get("MinBiasEvents"); 
00165     if ( !theTrees[file] ) throw cms::Exception("FastSimulation/PileUpProducer") 
00166       << "Tree with name MinBiasEvents not found in " << theFileNames[file];
00167     //
00168     theBranches[file] = theTrees[file]->GetBranch("puEvent");
00169     if ( !theBranches[file] ) throw cms::Exception("FastSimulation/PileUpProducer") 
00170       << "Branch with name puEvent not found in " << theFileNames[file];
00171     //
00172     thePUEvents[file] = new PUEvent();
00173     theBranches[file]->SetAddress(&thePUEvents[file]);
00174     //
00175     theNumberOfEntries[file] = theTrees[file]->GetEntries();
00176     // Add some randomness (if there was no input file)
00177     if ( !input ) 
00178       theCurrentEntry[file] 
00179         = (unsigned) (theNumberOfEntries[file] * random->flatShoot());
00180 
00181     theTrees[file]->GetEntry(theCurrentEntry[file]);
00182     unsigned NMinBias = thePUEvents[file]->nMinBias();
00183     theNumberOfMinBiasEvts[file] = NMinBias;
00184     // Add some randomness (if there was no input file)
00185     if ( !input )
00186         theCurrentMinBiasEvt[file] = 
00187           (unsigned) (theNumberOfMinBiasEvts[file] * random->flatShoot());
00188     
00189     /*
00190     std::cout << "File " << theFileNames[file]
00191               << " is opened with " << theNumberOfEntries[file] 
00192               << " entries and will be read from Entry/Event "
00193               << theCurrentEntry[file] << "/" << theCurrentMinBiasEvt[file]
00194               << std::endl;
00195     */
00196   }
00197   
00198   // Return Loot in the same state as it was when entering. 
00199   gROOT->cd();
00200   
00201 }
00202  
00203 void PileUpProducer::endRun()
00204 { 
00205   // Close all local files
00206   // Among other things, this allows the TROOT destructor to end up 
00207   // without crashing, while trying to close these files from outside
00208   for ( unsigned file=0; file<theFiles.size(); ++file ) {
00209     
00210     // std::cout << "Closing " << theFileNames[file] << std::endl;
00211     theFiles[file]->Close();
00212     
00213   }
00214   
00215   // Close the output file
00216   myOutputFile.close();
00217   
00218   // And return Loot in the same state as it was when entering. 
00219   gROOT->cd();
00220   
00221 }
00222  
00223 void PileUpProducer::produce(edm::Event & iEvent, const edm::EventSetup & es)
00224 {
00225 
00226   // Create the GenEvent and the HepMCProduct
00227   std::auto_ptr<edm::HepMCProduct> pu_product(new edm::HepMCProduct());  
00228   HepMC::GenEvent* evt = new HepMC::GenEvent();
00229   
00230   // How many pile-up events?
00231   int PUevts = usePoisson_ ? (int) random->poissonShoot(averageNumber_) : (int) hprob->GetRandom();
00232   //  std::cout << "PUevts = " << PUevts << std::endl;
00233 
00234   // Save this information in the PileupMixingContent object
00235   // IMPORTANT: the bunch crossing number is always 0 because FastSim has no out-of-time PU
00236   std::auto_ptr< PileupMixingContent > PileupMixing_;
00237 
00238   std::vector<int> bunchCrossingList;
00239   bunchCrossingList.push_back(0);
00240 
00241   std::vector<int> numInteractionList;
00242   numInteractionList.push_back(PUevts);
00243   
00244   std::vector<float> trueInteractionList;
00245   trueInteractionList.push_back((float)averageNumber_);
00246   
00247   PileupMixing_ = std::auto_ptr< PileupMixingContent >(new PileupMixingContent(bunchCrossingList,numInteractionList,trueInteractionList));
00248   iEvent.put(PileupMixing_);
00249 
00250   // Get N events from random files
00251   for ( int ievt=0; ievt<PUevts; ++ievt ) { 
00252     
00253     // Draw a file in a ramdom manner 
00254     unsigned file = (unsigned) (theNumberOfFiles * random->flatShoot());
00255     /*
00256     if ( debug )  
00257       std::cout << "The file chosen for event " << ievt 
00258                 << " is the file number " << file << std::endl; 
00259     */
00260 
00261     // Smear the primary vertex and express it in mm (stupid GenEvent convention...)
00262     theVertexGenerator->generate();
00263     HepMC::FourVector smearedVertex =  
00264       HepMC::FourVector(theVertexGenerator->X()*10.,
00265                         theVertexGenerator->Y()*10.,
00266                         theVertexGenerator->Z()*10.,
00267                         0.);
00268     HepMC::GenVertex* aVertex = new HepMC::GenVertex(smearedVertex);
00269     evt->add_vertex(aVertex);
00270 
00271     // Some rotation around the z axis, for more randomness
00272     double theAngle = random->flatShoot() * 2. * 3.14159265358979323;
00273     double cAngle = std::cos(theAngle);
00274     double sAngle = std::sin(theAngle);
00275 
00276     /*
00277     if ( debug ) 
00278       std::cout << "File chosen : " << file 
00279                 << " Current entry in this file " << theCurrentEntry[file] 
00280                 << " Current minbias in this chunk= " << theCurrentMinBiasEvt[file] 
00281                 << " Total number of minbias in this chunk = " << theNumberOfMinBiasEvts[file] << std::endl;
00282     */
00283 
00284     //      theFiles[file]->cd();
00285     //      gDirectory->ls();
00286     // Check we are not either at the end of a minbias bunch 
00287     // or at the end of a file
00288     if ( theCurrentMinBiasEvt[file] == theNumberOfMinBiasEvts[file] ) {
00289       // if ( debug ) std::cout << "End of MinBias bunch ! ";
00290       ++theCurrentEntry[file];
00291       // if ( debug) std::cout << "Read the next entry " << theCurrentEntry[file] << std::endl;
00292       theCurrentMinBiasEvt[file] = 0;
00293       if ( theCurrentEntry[file] == theNumberOfEntries[file] ) { 
00294         theCurrentEntry[file] = 0;
00295         // if ( debug ) std::cout << "End of file - Rewind! " << std::endl;
00296       }
00297       // if ( debug ) std::cout << "The PUEvent is reset ... "; 
00298       thePUEvents[file]->reset();
00299       unsigned myEntry = theCurrentEntry[file];
00300       /* 
00301       if ( debug ) std::cout << "The new entry " << myEntry 
00302                              << " is read ... in TTree " << theTrees[file] << " "; 
00303       */
00304       theTrees[file]->GetEntry(myEntry);
00305       /*
00306       if ( debug ) 
00307         std::cout << "The number of interactions in the new entry is ... ";     
00308       */
00309       theNumberOfMinBiasEvts[file] = thePUEvents[file]->nMinBias();
00310       // if ( debug ) std::cout << theNumberOfMinBiasEvts[file] << std::endl;
00311     }
00312   
00313     // Read a minbias event chunk
00314     const PUEvent::PUMinBiasEvt& aMinBiasEvt 
00315       = thePUEvents[file]->thePUMinBiasEvts()[theCurrentMinBiasEvt[file]];
00316   
00317     // Find corresponding particles
00318     unsigned firstTrack = aMinBiasEvt.first; 
00319     unsigned trackSize = firstTrack + aMinBiasEvt.size;
00320     /*
00321     if ( debug ) std::cout << "First and last+1 tracks are " 
00322                            << firstTrack << " " << trackSize << std::endl;
00323     */
00324 
00325     // Loop on particles
00326     for ( unsigned iTrack=firstTrack; iTrack<trackSize; ++iTrack ) {
00327       
00328       const PUEvent::PUParticle& aParticle 
00329         = thePUEvents[file]->thePUParticles()[iTrack];
00330       /*
00331       if ( debug) 
00332         std::cout << "Track " << iTrack 
00333                   << " id/px/py/pz/mass "
00334                   << aParticle.id << " " 
00335                   << aParticle.px << " " 
00336                   << aParticle.py << " " 
00337                   << aParticle.pz << " " 
00338                   << aParticle.mass << " " << std::endl; 
00339       */
00340       
00341       // Create a FourVector, with rotation 
00342       double energy = std::sqrt( aParticle.px*aParticle.px
00343                                + aParticle.py*aParticle.py
00344                                + aParticle.pz*aParticle.pz
00345                                + aParticle.mass*aParticle.mass );
00346 
00347       HepMC::FourVector myPart(cAngle * aParticle.px + sAngle * aParticle.py,
00348                               -sAngle * aParticle.px + cAngle * aParticle.py,
00349                                aParticle.pz, energy);
00350 
00351       // Add a GenParticle
00352       HepMC::GenParticle* aGenParticle = new HepMC::GenParticle(myPart,aParticle.id);
00353       aVertex->add_particle_out(aGenParticle);
00354 
00355     }
00356     // End of particle loop
00357     
00358     // Increment for next time
00359     ++theCurrentMinBiasEvt[file];
00360     
00361   }
00362   // End of pile-up event loop
00363 
00364   // evt->print();
00365 
00366   // Fill the HepMCProduct from the GenEvent
00367   if ( evt )  { 
00368     pu_product->addHepMCData( evt );
00369     // Boost in case of beam crossing angle
00370     TMatrixD* boost = theVertexGenerator->boost();
00371     if ( boost ) pu_product->boostToLab(boost,"momentum");
00372   }
00373 
00374   // Put the HepMCProduct onto the event
00375   iEvent.put(pu_product,"PileUpEvents");
00376   // delete evt;
00377 
00378   // Save the current location in each pile-up event files
00379   this->save();
00380 
00381 }
00382 
00383 void
00384 PileUpProducer::save() {
00385 
00386   // Size of buffer
00387   ++myOutputBuffer;
00388 
00389   // Periodically close the current file and open a new one
00390   if ( myOutputBuffer/1000*1000 == myOutputBuffer ) { 
00391     myOutputFile.close();
00392     myOutputFile.open ("PileUpOutputFile.txt");
00393     //    myOutputFile.seekp(0); // No need to rewind in that case
00394   }
00395 
00396   // Save the current position to file
00397   myOutputFile.write((const char*)(&theCurrentEntry.front()),
00398                      theCurrentEntry.size()*sizeof(unsigned));
00399   myOutputFile.write((const char*)&theCurrentMinBiasEvt.front(),
00400                      theCurrentMinBiasEvt.size()*sizeof(unsigned));
00401   myOutputFile.flush();
00402 
00403 }
00404 
00405 bool
00406 PileUpProducer::read(std::string inputFile) {
00407 
00408   ifstream myInputFile;
00409   struct stat results;
00410   unsigned size1 = theCurrentEntry.size()*sizeof(unsigned);
00411   unsigned size2 = theCurrentMinBiasEvt.size()*sizeof(unsigned);
00412   unsigned size = 0;
00413 
00414 
00415   // Open the file (if any)
00416   myInputFile.open (inputFile.c_str());
00417   if ( myInputFile.is_open() ) { 
00418 
00419     // Get the size of the file
00420     if ( stat(inputFile.c_str(), &results) == 0 ) size = results.st_size;
00421     else return false; // Something is wrong with that file !
00422   
00423     // Position the pointer just before the last record
00424     myInputFile.seekg(size-size1-size2);
00425 
00426     // Read the information
00427     myInputFile.read((char*)(&theCurrentEntry.front()),size1);
00428     myInputFile.read((char*)&theCurrentMinBiasEvt.front(),size2);
00429     myInputFile.close();
00430 
00431     return true;
00432 
00433   } 
00434 
00435   return false;
00436 
00437 }
00438 
00439 DEFINE_FWK_MODULE(PileUpProducer);