The Source
Overview
Teaching: 10 min
Exercises: 30 minQuestions
What are the elements of the source of an EDAnalyzer?
How do I modify the source to get additional information?
Objectives
Learn the basic structure of the C++ implementation of an EDAnalyzer.
Learn the basics on how to modify the source in order to do perform analysis.
Playing with the DemoAnalyzer.cc file
The DemoAnalyzer.cc
file is the main file of our EDAnalyzer. As it was mentioned, the default structure is always the same. Let’s look at what is inside using an editor like vi
(here you can find a good cheatsheet for that editor):
vi Demo/DemoAnalyzer/src/DemoAnalyzer.cc
The first thing that you will see is a set of includes:
// system include files
#include <memory>
// user include files
#include "FWCore/Framework/interface/Frameworkfwd.h"
#include "FWCore/Framework/interface/EDAnalyzer.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
These are the most basic Framework classes that are needed to mobilize the CMSSW machinery. In particular, notice the Event.h
class. This class contains essentially all the accessors that are needed to extract information from the Event, i.e., from the particle collision. Another important class is the ParameterSet.h
. This one will allow us to extract configuration parameters, which can be manipulated using the Demo/DemoAnalyzer/demoanalyzer_cfg.py
python file.
Something important to take into account is that you can learn a lot about the sort of information you have access to by exploring the code in the CMSSW repository on Github. For instance, you can look at the Event.h header and check all the available methods. You will notice, for instance, the presence of the getByLabel
accessors; we will be using one these to access physics objects.
When exploring CMSSW code on Github, remember to choose the CMSSW_5_3_X branch.
Including muon headers
Let’s pretend that we are interested in extracting the energy of all the muons in the event. We would need to add the appropriate classes for this. After quickly reviewing this guide, we conclude that we need to add these two header lines to our analyzer:
//classes to extract Muon information #include "DataFormats/MuonReco/interface/Muon.h" #include "DataFormats/MuonReco/interface/MuonFwd.h"
Let’s add them at the end of the header section together with the standard vector C++ library:
#include<vector>
So our header section becomes:
// system include files #include <memory> // user include files #include "FWCore/Framework/interface/Frameworkfwd.h" #include "FWCore/Framework/interface/EDAnalyzer.h" #include "FWCore/Framework/interface/Event.h" #include "FWCore/Framework/interface/MakerMacros.h" #include "FWCore/ParameterSet/interface/ParameterSet.h" //classes to extract Muon information #include "DataFormats/MuonReco/interface/Muon.h" #include "DataFormats/MuonReco/interface/MuonFwd.h" #include<vector>
Next, you will see the class declaration:
//
// class declaration
//
class DemoAnalyzer : public edm::EDAnalyzer {
public:
explicit DemoAnalyzer(const edm::ParameterSet&);
~DemoAnalyzer();
static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
private:
virtual void beginJob() ;
virtual void analyze(const edm::Event&, const edm::EventSetup&);
virtual void endJob() ;
virtual void beginRun(edm::Run const&, edm::EventSetup const&);
virtual void endRun(edm::Run const&, edm::EventSetup const&);
virtual void beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&);
virtual void endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&);
// ----------member data ---------------------------
};
The first thing one notices is that our class inherits from the edm::EDAnalyzer
class. It follows the same structure as any class in C++. The declaration of the methods reflect the functionality needed for particle physics analysis. Their implementation are further below in the same file.
Declaring info containers
Let’s add the declaration of a vector for our energy values:
std::vector<float> muon_e;
This section becomes:
// // class declaration // class DemoAnalyzer : public edm::EDAnalyzer { public: explicit DemoAnalyzer(const edm::ParameterSet&); ~DemoAnalyzer(); static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); private: virtual void beginJob() ; virtual void analyze(const edm::Event&, const edm::EventSetup&); virtual void endJob() ; virtual void beginRun(edm::Run const&, edm::EventSetup const&); virtual void endRun(edm::Run const&, edm::EventSetup const&); virtual void beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&); virtual void endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&); // ----------member data --------------------------- std::vector<float> muon_e; //energy values for muons in the event };
Next, we can see the constructor and destructor of our DemoAnalyzer class:
// constructors and destructor
//
DemoAnalyzer::DemoAnalyzer(const edm::ParameterSet& iConfig)
{
//now do what ever initialization is needed
}
DemoAnalyzer::~DemoAnalyzer()
{
// do anything here that needs to be done at desctruction time
// (e.g. close files, deallocate resources etc.)
}
Note that a ParameterSet
object is passed to the constructor. This is then the place where we will read any configuration we might end up implementing through our Demo/DemoAnalyzer/demoanalyzer_cfg.py
python configuration file.
The heart of the source file is the analyze
method:
// ------------ method called for each event ------------
void
DemoAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup)
{
using namespace edm;
#ifdef THIS_IS_AN_EVENT_EXAMPLE
Handle<ExampleData> pIn;
iEvent.getByLabel("example",pIn);
#endif
#ifdef THIS_IS_AN_EVENTSETUP_EXAMPLE
ESHandle<SetupData> pSetup;
iSetup.get<SetupRecord>().get(pSetup);
#endif
}
Anything that goes inside this routine will loop over all available events. The CMSSW Framework will take care of that, so you do not really have to write a for
loop to go over all events. Note that an edm::Event
object and a edm::EventSetup
object are passed by default. While from the Event we can extract information like physics objects, from the EventSetup we can get information like trigger prescales.
Get the muons energy
Now let’s add a few lines in the analyzer so we can retrieve the energy of all the muons in each event. We will print out this information as an example. Again, after checking out this guide, the analyze method becomes:
// ------------ method called for each event ------------ void DemoAnalyzer::analyze(const edm::Event& iEvent, const edm::EventSetup& iSetup) { using namespace edm; //clean the container muon_e.clear(); //define the handler and get by label Handle<reco::MuonCollection> mymuons; iEvent.getByLabel("muons", mymuons); //if collection is valid, loop over muons in event if(mymuons.isValid()){ for (reco::MuonCollection::const_iterator itmuon=mymuons->begin(); itmuon!=mymuons->end(); ++itmuon){ muon_e.push_back(itmuon->energy()); } } //print the vector for(unsigned int i=0; i < muon_e.size(); i++){ std::cout <<"Muon # "<<i<<" with E = "<<muon_e.at(i)<<" GeV."<<std::endl; } #ifdef THIS_IS_AN_EVENT_EXAMPLE Handle<ExampleData> pIn; iEvent.getByLabel("example",pIn); #endif #ifdef THIS_IS_AN_EVENTSETUP_EXAMPLE ESHandle<SetupData> pSetup; iSetup.get<SetupRecord>().get(pSetup); #endif }
The other methods are designed to execute instructions according to their own name description.
// ------------ method called once each job just before starting event loop ------------
void
DemoAnalyzer::beginJob()
{
}
// ------------ method called once each job just after ending the event loop ------------
void
DemoAnalyzer::endJob()
{
}
// ------------ method called when starting to processes a run ------------
void
DemoAnalyzer::beginRun(edm::Run const&, edm::EventSetup const&)
{
}
// ------------ method called when ending the processing of a run ------------
void
DemoAnalyzer::endRun(edm::Run const&, edm::EventSetup const&)
{
}
// ------------ method called when starting to processes a luminosity block ------------
void
DemoAnalyzer::beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
{
}
// ------------ method called when ending the processing of a luminosity block ------------
void
DemoAnalyzer::endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
{
}
For instance, any instructions placed inside the beginRun
routine will be executed every time the Framework sees a new Run (a Run is determined by the start and stop of the acquisition of the CMS detector). During the workshop, we will use the beginJob
and endJob
routines to book histograms and write output files.
Let’s compile
scram b
Look at the output
Well, it fails.
>> Local Products Rules ..... started >> Local Products Rules ..... done >> Building CMSSW version CMSSW_5_3_32 ---- >> Subsystem FT_53_LV5_AN1 built >> Entering Package Demo/DemoAnalyzer >> Creating project symlinks src/Demo/DemoAnalyzer/python -> python/Demo/DemoAnalyzer Entering library rule at Demo/DemoAnalyzer >> Compiling edm plugin /home/cmsusr/test/CMSSW_5_3_32/src/Demo/DemoAnalyzer/src/DemoAnalyzer.cc In file included from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/TrackingRecHit/interface/TrackingRecHit.h:4:0, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/TrackingRecHit/interface/RecSegment.h:17, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/DTRecHit/interface/DTRecSegment4D.h:16, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/DTRecHit/interface/DTRecSegment4DCollection.h:20, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/MuonSegmentMatch.h:6, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/MuonChamberMatch.h:5, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/Muon.h:17, from /home/cmsusr/test/CMSSW_5_3_32/src/Demo/DemoAnalyzer/src/DemoAnalyzer.cc:34: /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/CLHEP/interface/AlgebraicObjects.h:8:33: fatal error: CLHEP/Matrix/Vector.h: No such file or directory compilation terminated. In file included from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/TrackingRecHit/interface/TrackingRecHit.h:4:0, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/TrackingRecHit/interface/RecSegment.h:17, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/DTRecHit/interface/DTRecSegment4D.h:16, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/DTRecHit/interface/DTRecSegment4DCollection.h:20, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/MuonSegmentMatch.h:6, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/MuonChamberMatch.h:5, from /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/MuonReco/interface/Muon.h:17, from /home/cmsusr/test/CMSSW_5_3_32/src/Demo/DemoAnalyzer/src/DemoAnalyzer.cc:34: /opt/cms/slc6_amd64_gcc472/cms/cmssw/CMSSW_5_3_32/src/DataFormats/CLHEP/interface/AlgebraicObjects.h:8:33: fatal error: CLHEP/Matrix/Vector.h: No such file or directory compilation terminated. gmake: *** [tmp/slc6_amd64_gcc472/src/Demo/DemoAnalyzer/src/DemoDemoAnalyzer/DemoAnalyzer.o] Error 1 gmake: *** [There are compilation/build errors. Please see the detail log above.] Error 2
This is because the Muon classes we added introduced some dependencies that need to be taken care of in the
BuildFile.xml
So let’s modify the Demo/DemoAnalyzer/BuildFile.xml
to include DataFormats/MuonReco
dependencies. It should look like:
<use name="FWCore/Framework"/>
<use name="FWCore/PluginManager"/>
<use name="DataFormats/MuonReco"/>
<use name="FWCore/ParameterSet"/>
<flags EDM_PLUGIN="1"/>
<export>
<lib name="1"/>
</export>
Now, if you compile again, it should work. Then, we can run with the cmsRun
executable:
cmsRun Demo/DemoAnalyzer/demoanalyzer_cfg.py > mylog.log 2>&1 &
Well, it turns out that in the 10 events you looped over, there weren’t many muons. Of course, the ROOT file over which you are running is from an ElectronHad
(ronic) datset, so
it won’t have that many. In any case, your log file should output something like:
cat mylog.log
18-Sep-2020 08:22:40 CEST Initiating request to open file root://eospublic.cern.ch//eos/opendata/cms/Run2011A/ElectronHad/AOD/12Oct2013-v1/20001/001F9231-F141-E311-8F76-003048F00942.root
18-Sep-2020 08:22:42 CEST Successfully opened file root://eospublic.cern.ch//eos/opendata/cms/Run2011A/ElectronHad/AOD/12Oct2013-v1/20001/001F9231-F141-E311-8F76-003048F00942.root
Begin processing the 1st record. Run 166782, Event 340184599, LumiSection 309 at 18-Sep-2020 08:22:56.695 CEST
Begin processing the 2nd record. Run 166782, Event 340185007, LumiSection 309 at 18-Sep-2020 08:22:56.716 CEST
Begin processing the 3rd record. Run 166782, Event 340187903, LumiSection 309 at 18-Sep-2020 08:22:56.717 CEST
Begin processing the 4th record. Run 166782, Event 340227487, LumiSection 309 at 18-Sep-2020 08:22:56.717 CEST
Begin processing the 5th record. Run 166782, Event 340210607, LumiSection 309 at 18-Sep-2020 08:22:56.717 CEST
Begin processing the 6th record. Run 166782, Event 340256207, LumiSection 309 at 18-Sep-2020 08:22:56.718 CEST
Begin processing the 7th record. Run 166782, Event 340165759, LumiSection 309 at 18-Sep-2020 08:22:56.718 CEST
Begin processing the 8th record. Run 166782, Event 340396487, LumiSection 309 at 18-Sep-2020 08:22:56.718 CEST
Muon # 0 with E = 27.3492 GeV.
Begin processing the 9th record. Run 166782, Event 340390767, LumiSection 309 at 18-Sep-2020 08:22:56.720 CEST
Begin processing the 10th record. Run 166782, Event 340435263, LumiSection 309 at 18-Sep-2020 08:22:56.720 CEST
18-Sep-2020 08:22:56 CEST Closed file root://eospublic.cern.ch//eos/opendata/cms/Run2011A/ElectronHad/AOD/12Oct2013-v1/20001/001F9231-F141-E311-8F76-003048F00942.root
=============================================
MessageLogger Summary
type category sev module subroutine count total
---- -------------------- -- ---------------- ---------------- ----- -----
1 fileAction -s file_close 1 1
2 fileAction -s file_open 2 2
type category Examples: run/evt run/evt run/evt
---- -------------------- ---------------- ---------------- ----------------
1 fileAction PostEndRun
2 fileAction pre-events pre-events
Severity # Occurrences Total Occurrences
-------- ------------- -----------------
System 3 3
Key Points
The C++ source file of an EDAnalyzer is taylored for particle physics analysis under the CMSSW Framework.
This source file needs to be modified according to the analyzer needs