CMS 3D CMS Logo

BTagSFProducer.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Original Author: Spandan Mondal
4 // Created: Tue, 13 Mar 2018 09:26:52 GMT
5 //
6 //
7 
8 // system include files
9 #include <memory>
10 
11 // user include files
14 
17 
22 
25 
28 
31 
33 
34 #include <vector>
35 #include <string>
36 
38  public:
40  src_(consumes<std::vector<pat::Jet>>(iConfig.getParameter<edm::InputTag>("src"))),
41  cut_(iConfig.getParameter<std::string>("cut")),
42  discNames_(iConfig.getParameter<std::vector<std::string>>("discNames")),
43  discShortNames_(iConfig.getParameter<std::vector<std::string>>("discShortNames")),
44  weightFiles_(iConfig.getParameter<std::vector<std::string>>("weightFiles")),
45  operatingPoints_(iConfig.getParameter<std::vector<std::string>>("operatingPoints")),
46  measurementTypesB_(iConfig.getParameter<std::vector<std::string>>("measurementTypesB")),
47  measurementTypesC_(iConfig.getParameter<std::vector<std::string>>("measurementTypesC")),
48  measurementTypesUDSG_(iConfig.getParameter<std::vector<std::string>>("measurementTypesUDSG")),
49  sysTypes_(iConfig.getParameter<std::vector<std::string>>("sysTypes"))
50  {
51  produces<nanoaod::FlatTable>();
52 
53  nDiscs=discNames_.size();
54  assert(discShortNames_.size()==nDiscs && weightFiles_.size()==nDiscs && operatingPoints_.size()==nDiscs && measurementTypesB_.size()==nDiscs && measurementTypesC_.size()==nDiscs && measurementTypesUDSG_.size()==nDiscs && sysTypes_.size()==nDiscs);
55 
56  bool validate = iConfig.getUntrackedParameter<bool>("validate");
57  for (unsigned int iDisc = 0; iDisc < nDiscs; ++iDisc) {
58 
59  if (weightFiles_[iDisc]!="unavailable") {
60  // setup calibration
62  edm::FileInPath fip(weightFiles_[iDisc]);
63  calib=BTagCalibration(discShortNames_[iDisc],fip.fullPath(), validate);
64 
65  // determine op
66  std::string opname;
67  if (operatingPoints_[iDisc] == "0" || operatingPoints_[iDisc] == "loose") {
69  opname="loose";
70  }
71  else if (operatingPoints_[iDisc] == "1" || operatingPoints_[iDisc] == "medium") {
73  opname="medium";
74  }
75  else if (operatingPoints_[iDisc] == "2" || operatingPoints_[iDisc] == "tight") {
77  opname="tight";
78  }
79  else if (operatingPoints_[iDisc] == "3" || operatingPoints_[iDisc] == "reshaping") {
81  opname="discriminator reshaping";
82  }
83 
84  // setup reader
86  reader=BTagCalibrationReader(op, sysTypes_[iDisc]);
87  reader.load(calib, BTagEntry::FLAV_B, measurementTypesB_[iDisc]);
88  reader.load(calib, BTagEntry::FLAV_C, measurementTypesC_[iDisc]);
89  reader.load(calib, BTagEntry::FLAV_UDSG, measurementTypesUDSG_[iDisc]);
90 
91  //calibs.push_back(calib);
92  readers.push_back(reader);
93 
94  // report
95  edm::LogInfo("BTagSFProducer") << "Loaded "+discShortNames_[iDisc]+" SFs from weight file "+weightFiles_[iDisc]+" with\noperating point: "+opname+",\nmeasurement type: B="+measurementTypesB_[iDisc]+", C="+measurementTypesC_[iDisc]+", UDSG="+measurementTypesUDSG_[iDisc]+",\nsystematic type: "+sysTypes_[iDisc]+".\n" << std::endl;
96 
97  // find if multiple MiniAOD branches need to be summed up (e.g., DeepCSV b+bb) and separate them using '+' delimiter from config
98  std::stringstream dName(discNames_[iDisc]);
100  std::vector<std::string> branches;
101  while (std::getline(dName, branch, '+')) {
102  branches.push_back(branch);
103  }
104  inBranchNames.push_back(branches);
105  }
106  else {
107  //BTagCalibration calib;
109  //calibs.push_back(calib); //dummy, so that index of vectors still match
110  readers.push_back(reader); //dummy, so that index of vectors still match
111  std::vector<std::string> branches;
112  branches.push_back("");
113  inBranchNames.push_back(branches);
114 
115  // report
116  edm::LogWarning("BTagSFProducer") << "Skipped loading BTagCalibration for "+discShortNames_[iDisc]+" as it was marked as unavailable in the configuration file. Event weights will not be stored.\n" << std::endl;
117  }
118  }
119  }
120 
121  ~BTagSFProducer() override {};
122 
125 
126  desc.add<edm::InputTag>("src")->setComment("input AK4 jet collection");
127  desc.add<std::string>("cut")->setComment("minimum pT and maximum eta cuts for jets");
128  desc.add<std::vector<std::string>>("discNames")->setComment("name of b-tag discriminator branch in MiniAOD");
129  desc.add<std::vector<std::string>>("discShortNames")->setComment("common name of discriminator");
130  desc.add<std::vector<std::string>>("weightFiles")->setComment("path to the .csv file containing the SFs");
131  desc.add<std::vector<std::string>>("operatingPoints")->setComment("loose = 0, medium = 1, tight = 2, disriminator reshaping = 3");
132  desc.add<std::vector<std::string>>("measurementTypesB")->setComment("e.g. \"ttbar\", \"comb\", \"incl\", \"iterativefit\" for b jets");
133  desc.add<std::vector<std::string>>("measurementTypesC")->setComment("e.g. \"ttbar\", \"comb\", \"incl\", \"iterativefit\" for c jets");
134  desc.add<std::vector<std::string>>("measurementTypesUDSG")->setComment("e.g. \"ttbar\", \"comb\", \"incl\", \"iterativefit\" for light jets");
135  desc.add<std::vector<std::string>>("sysTypes")->setComment("\"up\", \"central\", \"down\", but arbitrary strings possible, like \"up_generator\" or \"up_jec\"");
136  desc.addUntracked<bool>("validate", false)->setComment("validate the function expressions in the weightFiles");
137 
138  descriptions.add("BTagWeightTable", desc);
139  }
140 
141  private:
142  void produce(edm::Event&, const edm::EventSetup&) override;
143 
146 
147  std::vector<std::string> discNames_;
148  std::vector<std::string> discShortNames_;
149  std::vector<std::string> weightFiles_;
150  std::vector<std::string> operatingPoints_;
151  std::vector<std::string> measurementTypesB_;
152  std::vector<std::string> measurementTypesC_;
153  std::vector<std::string> measurementTypesUDSG_;
154  std::vector<std::string> sysTypes_;
155 
157  std::vector<std::vector<std::string>> inBranchNames;
158  //std::vector<BTagCalibration> calibs;
159  std::vector<BTagCalibrationReader> readers;
160  unsigned int nDiscs;
161 };
162 
163 
164 // ------------ method called to produce the data ------------
165 void
167 {
168  using namespace edm;
169  using namespace std;
170 
172  iEvent.getByToken(src_, jets);
173 
174  double pt;
175  double eta;
176  int flavour;
177  double bdisc;
178  double SF;
179 
180  double EventWt;
181 
182  auto out = std::make_unique<nanoaod::FlatTable>(1, "btagWeight", true);
183  out->setDoc("b-tagging event weights");
184 
185  for (unsigned int iDisc = 0; iDisc < nDiscs; ++iDisc) { // loop over b-tagging algorithms
186 
187  if (weightFiles_[iDisc]!="unavailable") {
188  EventWt=1.;
189  for (const pat::Jet & jet : *jets) { // loop over jets and accumulate product of SF for each jet
190  pt=jet.pt();
191  eta=jet.eta();
192  bdisc=0.;
193 
195  for (string inBranch : inBranchNames[iDisc]) { //sum up the discriminator values if multiple, e.g. DeepCSV b+bb
196  bdisc+=jet.bDiscriminator(inBranch);
197  }
198  }
199 
200  flavour=jet.hadronFlavour();
201 
202  if (cut_(jet)) { //multiply SF of only the jets that pass the cut
203  if (fabs(flavour) == 5) { // b jets
204  SF = readers[iDisc].eval_auto_bounds(sysTypes_[iDisc],BTagEntry::FLAV_B,eta,pt,bdisc);
205  }
206  else if (fabs(flavour) == 4) { // c jets
207  SF = readers[iDisc].eval_auto_bounds(sysTypes_[iDisc],BTagEntry::FLAV_C,eta,pt,bdisc);
208  }
209  else { // others
210  SF = readers[iDisc].eval_auto_bounds(sysTypes_[iDisc],BTagEntry::FLAV_UDSG,eta,pt,bdisc);
211  }
212  }
213  else {
214  SF=1.;
215  }
216 
217 
218 
219  if (SF==0.) { // default value of SF is set to 1 in case BTagCalibration returns 0
220  //no need to log this as could be pretty common, leaving the cout commented in case this is needed by the author for simple debugging
221  //cout << discShortNames_[iDisc]+" SF not found for jet with pT="+to_string(pt)+", eta="+to_string(eta)+", discValue="+to_string(bdisc)+", flavour="+to_string(flavour) +". Setting SF to 1." << endl;
222  SF=1.;
223  }
224 
225  EventWt *= SF;
226  }
227 
228  out->addColumnValue<float>(discShortNames_[iDisc], EventWt, "b-tag event weight for "+discShortNames_[iDisc], nanoaod::FlatTable::FloatColumn);
229  }
230  }
231 
232  iEvent.put(move(out));
233 }
234 
235 //define this as a plug-in
T getUntrackedParameter(std::string const &, T const &) const
OrphanHandle< PROD > put(std::unique_ptr< PROD > product)
Put a new product.
Definition: Event.h:125
BTagEntry::OperatingPoint op
const StringCutObjectSelector< pat::Jet > cut_
BTagSFProducer(const edm::ParameterSet &iConfig)
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
edm::EDGetTokenT< std::vector< pat::Jet > > src_
bool getByToken(EDGetToken token, Handle< PROD > &result) const
Definition: Event.h:517
unsigned int nDiscs
std::vector< std::string > measurementTypesUDSG_
std::vector< std::string > measurementTypesB_
Definition: HeavyIon.h:7
std::vector< std::string > weightFiles_
std::vector< std::string > measurementTypesC_
MVATrainerComputer * calib
Definition: MVATrainer.cc:64
int iEvent
Definition: GenABIO.cc:224
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::vector< std::string > sysTypes_
Definition: Jet.py:1
vector< PseudoJet > jets
void produce(edm::Event &, const edm::EventSetup &) override
std::vector< BTagCalibrationReader > readers
ParameterDescriptionBase * add(U const &iLabel, T const &value)
OperatingPoint
Definition: BTagEntry.h:27
std::vector< std::vector< std::string > > inBranchNames
std::vector< std::string > discNames_
~BTagSFProducer() override
std::vector< std::string > operatingPoints_
Analysis-level calorimeter jet class.
Definition: Jet.h:80
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void load(const BTagCalibration &c, BTagEntry::JetFlavor jf, const std::string &measurementType="comb")
HLT enums.
std::string fullPath() const
Definition: FileInPath.cc:163
std::vector< std::string > discShortNames_
def move(src, dest)
Definition: eostools.py:511