Skip to content

Commit 5bf78f0

Browse files
committed
Update CMSSW exercise and analysis files; correct paths and add new scripts
1 parent bbb0894 commit 5bf78f0

10 files changed

Lines changed: 284 additions & 2 deletions

episodes/02-cmsswexercise.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Copy the analysis code into your CMSSW work area:
118118
```bash
119119
cd ${CMSSW_BASE}/src/
120120
mkdir -p AnalysisCode
121-
cp -r ~/cmsdas/cmsdas-gitlab-cms/ZPeakAnalysis AnalysisCode/
121+
cp -r ~/cmsdas/cmsdas/cmsdas-gitlab-cms/ZPeakAnalysis AnalysisCode/
122122
```
123123

124124
Now your code is in the right place for CMSSW to find and compile it.

episodes/04-gitlabci-run-analysis.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ cmssw_compile:
113113
- cmsenv
114114
- mkdir -p AnalysisCode
115115
- cp -r $CI_PROJECT_DIR/ZPeakAnalysis AnalysisCode/
116-
- cd ${CMSSW_RELEASE}/src
116+
- cd ${CMSSW_BASE}/src
117117
- scram b -j 4
118118
artifacts:
119119
untracked: true

episodes/files/ZPeakAnalysis.zip

-2.8 KB
Binary file not shown.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<use name="root"/>
2+
<export>
3+
<lib name="1"/>
4+
</export>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<use name="FWCore/Framework"/>
2+
<use name="FWCore/ParameterSet"/>
3+
<use name="FWCore/ServiceRegistry"/>
4+
<use name="PhysicsTools/UtilAlgos"/>
5+
<library file="*.cc" name="AnalysisCodeZPeakAnalysisPlugins">
6+
<flags EDM_PLUGIN="1"/>
7+
</library>
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#include <map>
2+
#include <string>
3+
4+
#include "TH1.h"
5+
6+
#include "FWCore/Framework/interface/Frameworkfwd.h"
7+
#include "FWCore/Framework/interface/Event.h"
8+
#include "FWCore/Framework/interface/EDAnalyzer.h"
9+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
10+
#include "FWCore/ServiceRegistry/interface/Service.h"
11+
#include "CommonTools/UtilAlgos/interface/TFileService.h"
12+
#include "DataFormats/PatCandidates/interface/Muon.h"
13+
14+
#include "DataFormats/PatCandidates/interface/Electron.h"
15+
#include "DataFormats/PatCandidates/interface/Muon.h"
16+
17+
class MyZPeakAnalyzer : public edm::EDAnalyzer {
18+
19+
public:
20+
explicit MyZPeakAnalyzer(const edm::ParameterSet&);
21+
~MyZPeakAnalyzer();
22+
23+
private:
24+
25+
virtual void beginJob() ;
26+
virtual void analyze(const edm::Event&, const edm::EventSetup&);
27+
virtual void endJob() ;
28+
29+
// simple map to contain all histograms;
30+
// histograms are booked in the beginJob()
31+
// method
32+
std::map<std::string,TH1F*> histContainer_;
33+
// ----------member data ---------------------------
34+
edm::EDGetTokenT<pat::MuonCollection> muonCollToken;
35+
edm::EDGetTokenT<pat::ElectronCollection> elecCollToken;
36+
37+
// input tags
38+
edm::InputTag muonSrc_;
39+
edm::InputTag elecSrc_;
40+
};
41+
42+
43+
MyZPeakAnalyzer::MyZPeakAnalyzer(const edm::ParameterSet& iConfig):
44+
45+
histContainer_(),
46+
muonSrc_(iConfig.getUntrackedParameter<edm::InputTag>("muonSrc")),
47+
elecSrc_(iConfig.getUntrackedParameter<edm::InputTag>("elecSrc")){
48+
49+
muonCollToken = consumes<pat::MuonCollection>(muonSrc_);
50+
elecCollToken = consumes<pat::ElectronCollection>(elecSrc_);
51+
52+
}
53+
54+
MyZPeakAnalyzer::~MyZPeakAnalyzer(){
55+
}
56+
57+
void
58+
MyZPeakAnalyzer::analyze(const edm::Event& iEvent,
59+
const edm::EventSetup& iSetup){
60+
61+
// get pat muon collection
62+
edm::Handle< std::vector<pat::Muon>> muons;
63+
iEvent.getByToken(muonCollToken, muons);
64+
65+
// fill pat muon histograms
66+
for (auto it = muons->cbegin(); it != muons->cend(); ++it) {
67+
histContainer_["muonPt"] ->Fill(it->pt());
68+
histContainer_["muonEta"]->Fill(it->eta());
69+
histContainer_["muonPhi"]->Fill(it->phi());
70+
71+
if( it->pt()>20 && fabs(it->eta())<2.1 ){
72+
for (auto it2 = muons->cbegin(); it2 != muons->cend(); ++it2){
73+
if (it2 > it){
74+
// check only muon pairs of unequal charge
75+
if( it->charge()*it2->charge()<0){
76+
histContainer_["mumuMass"]->Fill((it->p4()+it2->p4()).mass());
77+
}
78+
}
79+
}
80+
}
81+
}
82+
83+
// get pat electron collection
84+
edm::Handle< std::vector<pat::Electron>> electrons;
85+
iEvent.getByToken(elecCollToken, electrons);
86+
87+
// loop over electrons
88+
for (auto it = electrons->cbegin(); it != electrons->cend(); ++it) {
89+
histContainer_["elePt"] ->Fill(it->pt());
90+
histContainer_["eleEta"]->Fill(it->eta());
91+
histContainer_["elePhi"]->Fill(it->phi());
92+
}
93+
94+
// Multiplicity
95+
histContainer_["eleMult" ]->Fill(electrons->size());
96+
histContainer_["muonMult"]->Fill(muons->size() );
97+
}
98+
99+
void
100+
MyZPeakAnalyzer::beginJob()
101+
{
102+
// register to the TFileService
103+
edm::Service<TFileService> fs;
104+
105+
106+
histContainer_["mumuMass"]=fs->make<TH1F>("mumuMass", "mass", 90, 30., 120.);
107+
108+
// book histograms for Multiplicity:
109+
110+
histContainer_["eleMult"]=fs->make<TH1F>("eleMult", "electron multiplicity", 100, 0, 50);
111+
histContainer_["muonMult"]=fs->make<TH1F>("muonMult", "muon multiplicity", 100, 0, 50);
112+
113+
// book histograms for Pt:
114+
115+
histContainer_["elePt"]=fs->make<TH1F>("elePt", "electron Pt", 100, 0, 200);
116+
histContainer_["muonPt"]=fs->make<TH1F>("muonPt", "muon Pt", 100, 0, 200);
117+
118+
// book histograms for Eta:
119+
histContainer_["eleEta"]=fs->make<TH1F>("eleEta", "electron Eta",100, -5, 5);
120+
histContainer_["muonEta"]=fs->make<TH1F>("muonEta", "muon Eta", 100, -5, 5);
121+
122+
123+
// book histograms for Phi:
124+
histContainer_["elePhi"]=fs->make<TH1F>("elePhi", "electron Phi", 100, -3.5, 3.5);
125+
histContainer_["muonPhi"]=fs->make<TH1F>("muonPhi", "muon Phi", 100, -3.5, 3.5);
126+
127+
}
128+
129+
void
130+
MyZPeakAnalyzer::endJob()
131+
{
132+
}
133+
134+
#include "FWCore/Framework/interface/MakerMacros.h"
135+
DEFINE_FWK_MODULE(MyZPeakAnalyzer);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import FWCore.ParameterSet.Config as cms
2+
from FWCore.ParameterSet.VarParsing import VarParsing
3+
4+
options = VarParsing ('analysis')
5+
6+
process = cms.Process("Test")
7+
8+
process.source = cms.Source("PoolSource",
9+
fileNames = cms.untracked.vstring (options.inputFiles)
10+
)
11+
12+
process.MessageLogger = cms.Service("MessageLogger")
13+
process.maxEvents = cms.untracked.PSet(
14+
input = cms.untracked.int32(10000)
15+
)
16+
17+
process.analyzeBasicPat = cms.EDAnalyzer("MyZPeakAnalyzer",
18+
muonSrc = cms.untracked.InputTag("slimmedMuons"),
19+
elecSrc = cms.untracked.InputTag("slimmedElectrons"),
20+
)
21+
22+
process.TFileService = cms.Service("TFileService",
23+
fileName = cms.string('myZPeak.root')
24+
)
25+
26+
process.p = cms.Path(process.analyzeBasicPat)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python3
2+
import sys
3+
import argparse
4+
5+
def parse_integral_file(filename):
6+
"""Parses the text file and returns a dictionary of {variable: value}."""
7+
data = {}
8+
try:
9+
with open(filename, 'r') as f:
10+
for line in f:
11+
if ':' in line:
12+
parts = line.split(':')
13+
key = parts[0].replace('Integral of ', '').strip()
14+
value = float(parts[1].strip())
15+
data[key] = value
16+
return data
17+
except FileNotFoundError:
18+
print(f"Error: File '{filename}' not found.")
19+
sys.exit(1)
20+
except Exception as e:
21+
print(f"Error parsing '{filename}': {e}")
22+
sys.exit(1)
23+
24+
def compare(file1, file2, tolerance=1e-6):
25+
data1 = parse_integral_file(file1)
26+
data2 = parse_integral_file(file2)
27+
28+
all_keys = set(data1.keys()).union(set(data2.keys()))
29+
match = True
30+
31+
print(f"{'Variable':<20} | {'File 1':<15} | {'File 2':<15} | {'Status'}")
32+
print("-" * 70)
33+
34+
for key in sorted(all_keys):
35+
val1 = data1.get(key, None)
36+
val2 = data2.get(key, None)
37+
38+
if val1 is None or val2 is None:
39+
status = "MISSING"
40+
match = False
41+
elif abs(val1 - val2) <= tolerance:
42+
status = "PASS"
43+
else:
44+
status = "FAIL"
45+
match = False
46+
47+
print(f"{key:<20} | {str(val1):<15} | {str(val2):<15} | {status}")
48+
49+
return match
50+
51+
if __name__ == "__main__":
52+
parser = argparse.ArgumentParser(description="Compare CMSSW integral outputs.")
53+
parser.add_argument("file1", help="First txt file (reference)")
54+
parser.add_argument("file2", help="Second txt file (new run)")
55+
args = parser.parse_args()
56+
57+
if compare(args.file1, args.file2):
58+
print("\nSUCCESS: The files match.")
59+
sys.exit(0)
60+
else:
61+
print("\nFAILURE: Differences detected between the runs.")
62+
sys.exit(1)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import ROOT
2+
import sys
3+
4+
# Define the input and output filenames
5+
input_file = 'myZPeak.root'
6+
output_txt = 'number_of_events.txt'
7+
8+
# Open the ROOT file
9+
f = ROOT.TFile.Open(input_file)
10+
if not f or f.IsZombie():
11+
print(f"Error: Could not open {input_file}")
12+
sys.exit(1)
13+
14+
# In TFileService, histograms are usually inside a directory
15+
# named after the module label in your python config.
16+
# Based on your config, the label is 'analyzeBasicPat'
17+
dir_name = "analyzeBasicPat"
18+
hist_dir = f.Get(dir_name)
19+
20+
if not hist_dir:
21+
print(f"Error: Directory {dir_name} not found in {input_file}")
22+
f.ls() # List contents to help debugging
23+
sys.exit(1)
24+
25+
# Retrieve the histograms
26+
h_muonMult = hist_dir.Get("muonMult")
27+
h_eleMult = hist_dir.Get("eleMult")
28+
h_mumuMass = hist_dir.Get("mumuMass")
29+
30+
# Calculate integrals
31+
# Integral() returns the sum of bin contents (excluding under/overflow by default)
32+
muon_integral = h_muonMult.Integral()
33+
ele_integral = h_eleMult.Integral()
34+
mumuMass_integral = h_mumuMass.Integral()
35+
36+
# Write to a text file
37+
with open(output_txt, 'w') as f_out:
38+
f_out.write(f"muonMult: {muon_integral}\n")
39+
f_out.write(f"eleMult: {ele_integral}\n")
40+
f_out.write(f"mumuMass: {mumuMass_integral}\n")
41+
42+
print(f"Successfully wrote integrals to {output_txt}")
43+
44+
# Close ROOT file
45+
f.Close()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
muonMult: 54856.0
2+
eleMult: 54856.0
3+
mumuMass: 16324.0

0 commit comments

Comments
 (0)