ATLAS Offline Software
Loading...
Searching...
No Matches
SSVWeightsAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8#include <fstream>
9#include <nlohmann/json.hpp>
11#include <boost/math/distributions/poisson.hpp>
12using json = nlohmann::json;
13
14namespace CP{
15 SSVWeightsAlg::SSVWeightsAlg(const std::string &name, ISvcLocator *pSvcLocator)
16 : EL::AnaAlgorithm(name, pSvcLocator){
17 }
18
20 ANA_MSG_INFO("Initialising SSVWeightsAlg");
21 ANA_MSG_INFO("WARNING: The Run3 SSV calibration has not been performed yet -> the scale factors are not usable yet");
22
33
34 if (m_OutputVariableSize == "standard") {
36 }
37 else if (m_OutputVariableSize == "extended") {
39 }
40 else if (m_OutputVariableSize == "additional") {
42 }
43 else if (m_OutputVariableSize == "all") {
45 }
46 else {
47 ATH_MSG_ERROR("Unknown OutputVariableSizeType: " << m_OutputVariableSize <<" , accepted options are: 'standard', 'extended', 'additional', 'all'" );
48 return StatusCode::FAILURE;
49 }
50
55 }
56
64 }
65
72 }
73
74 ANA_CHECK(m_systematicsList.initialize());
75
76 //retrieve the JSON file
77 std::string json_file_SSVWeightsAlg = PathResolverFindCalibFile(m_jsonConfigPath_SSVWeightsAlg);
78 std::ifstream jsonFile_SSVWeightsAlg(json_file_SSVWeightsAlg);
79 if (!jsonFile_SSVWeightsAlg.is_open()) {
80 ATH_MSG_ERROR("Could not open JSON file: " << m_jsonConfigPath_SSVWeightsAlg);
81 return StatusCode::FAILURE;
82 }
83
84 m_jsonConfig_SSVWeightsAlg = json::parse(jsonFile_SSVWeightsAlg);
85 jsonFile_SSVWeightsAlg.close();
86
87 // Check that b-tagging working point is the same as in the calibration
88 if (m_BTaggingWP.value() != m_jsonConfig_SSVWeightsAlg["CalibrationInformation"]["btaggingWP"].get<std::string>()){
89 ANA_MSG_ERROR("WARNING: You are using b-tagging working point: "<< m_BTaggingWP.value() <<" , which is different to the one used in the SSV Calibration: " << m_jsonConfig_SSVWeightsAlg["CalibrationInformation"]["btaggingWP"].get<std::string>());
90 return StatusCode::FAILURE;
91 }
92
93 // retrieve scale factors
94 m_SF_eff = m_jsonConfig_SSVWeightsAlg["CalibrationScaleFactors"]["SF_eff"];
95 m_SF_fake_low = m_jsonConfig_SSVWeightsAlg["CalibrationScaleFactors"]["SF_fake"]["mu_low"];
96 m_SF_fake_high = m_jsonConfig_SSVWeightsAlg["CalibrationScaleFactors"]["SF_fake"]["mu_high"];
97
98 // Initialize EfficiencyMethodClass
99 if (m_EfficiencyMethod == "bjet_based") {
101 m_EfficiencyMethodBJetBasedPtr = std::make_unique<EfficiencyMethodBJetBasedClass>( m_jsonConfig_SSVWeightsAlg );
102 }
103 else if (m_EfficiencyMethod == "Bhadron_pT_eta_based") {
105 m_EfficiencyMethodBhadronPtEtaBasedPtr = std::make_unique<EfficiencyMethodBhadronPtEtaBasedClass>( m_jsonConfig_SSVWeightsAlg );
106 }
107 else {
108 ATH_MSG_ERROR("Unknown efficiency method: " << m_EfficiencyMethod << " , accepted efficiency methods are: 'bjet_based','Bhadron_pT_eta_based'");
109 return StatusCode::FAILURE;
110 }
111
112 //Initialize nFMethodClass
113 if (m_nFMethod == "pileup_bjet_based") {
115 m_nFPileupBJetBasedPtr = std::make_unique<nFMethodPileupBJetBasedClass>( m_jsonConfig_SSVWeightsAlg );
116 }
117 else if (m_nFMethod == "pileup_based_linearfit") {
119 m_nFPileupBasedLinearFitPtr = std::make_unique<nFMethodPileupBasedLinearFitClass>( m_jsonConfig_SSVWeightsAlg );
120 }
121 else if (m_nFMethod == "pileup_based_binned") {
123 m_nFPileupBasedBinnedPtr = std::make_unique<nFMethodPileupBasedBinnedClass>( m_jsonConfig_SSVWeightsAlg );
124 }
125 else {
126 ATH_MSG_ERROR("Unknown nF method: " << m_nFMethod << " , accepted nF methods are: 'pileup_bjet_based', 'pileup_based_linearfit', 'pileup_based_binned'");
127 return StatusCode::FAILURE;
128 }
129 // If OutputVariableSize = all -> Initialize all EfficiencyMethods and nFMethods
130 // Also check if pointers have already been created (see code just above)
131 // as depending on the user method settings some of them might have been set already
134 m_EfficiencyMethodBJetBasedPtr = std::make_unique<EfficiencyMethodBJetBasedClass>( m_jsonConfig_SSVWeightsAlg );
135 }
137 m_EfficiencyMethodBhadronPtEtaBasedPtr = std::make_unique<EfficiencyMethodBhadronPtEtaBasedClass>( m_jsonConfig_SSVWeightsAlg );
138 }
140 m_nFPileupBJetBasedPtr = std::make_unique<nFMethodPileupBJetBasedClass>( m_jsonConfig_SSVWeightsAlg );
141 }
143 m_nFPileupBasedLinearFitPtr = std::make_unique<nFMethodPileupBasedLinearFitClass>( m_jsonConfig_SSVWeightsAlg );
144 }
146 m_nFPileupBasedBinnedPtr = std::make_unique<nFMethodPileupBasedBinnedClass>( m_jsonConfig_SSVWeightsAlg );
147 }
148 }
149
150
151 return StatusCode::SUCCESS;
152 }
153
155
156 for (const auto &sys : m_systematicsList.systematicsVector()){
157 const xAOD::EventInfo *evtInfo = nullptr;
158 ANA_CHECK(m_eventInfoHandle.retrieve(evtInfo, sys));
159
160 const xAOD::VertexContainer* vertices = nullptr;
161 ANA_CHECK(m_ssvHandle.retrieve(vertices, sys));
162
163 // create SSVs
164 std::vector<const xAOD::Vertex*> SSVs;
165 for(const xAOD::Vertex* ssvvtx : *vertices){
166 SSVs.push_back(ssvvtx);
167 }
168
169 //create jets
170 const xAOD::JetContainer *jets = nullptr;
171 ANA_CHECK(m_jetsHandle.retrieve(jets, sys));
172
173 std::vector<const xAOD::Jet*> jets_Selected;
174 int b_jet_count=0;
175 static const SG::AuxElement::ConstAccessor<char> jet_btag_accessor(m_BTaggingWP);
176
177 //create jets that pass your jet selection
178 for(const xAOD::Jet* jet : *jets){
179 if (m_jetSelection.getBool (*jet, sys)){
180 jets_Selected.push_back(jet);
181
182 // Count number of bjets
183 if (jet_btag_accessor(*jet)){
184 b_jet_count = b_jet_count+1;
185 }
186 }
187 }
188
189 // create electrons
190 const xAOD::ElectronContainer *electrons = nullptr;
191 ANA_CHECK(m_electronsHandle.retrieve(electrons, sys));
192
193 std::vector<const xAOD::Electron*> electrons_Selected;
194
195 //create electrons that pass your electron selection
196 for(const xAOD::Electron* electron : *electrons){
197 if (m_electronSelection.getBool (*electron, sys)){
198 electrons_Selected.push_back (electron);
199 }
200 }
201
202 //create muons
203 const xAOD::MuonContainer *muons = nullptr;
204 ANA_CHECK(m_muonsHandle.retrieve(muons, sys));
205 std::vector<const xAOD::Muon*> muons_Selected;
206
207 //create muons that pass your muon selection
208 for(const xAOD::Muon* muon : *muons){
209 if (m_muonSelection.getBool (*muon, sys)){
210 muons_Selected.push_back( muon );
211 }
212 }
213
214 // create good SSVs
215 std::vector<const xAOD::Vertex*> good_SSVs = create_good_SSVs(jets_Selected, electrons_Selected, muons_Selected, SSVs);
216
217 //create truth b-hadrons (truthBhs)
218 std::vector<const xAOD::TruthParticle*> truthBhs;
219
220 const xAOD::TruthParticleContainer *particles = nullptr;
221 ANA_CHECK(m_truthParticlesHandle.retrieve(particles, sys));
222
223 for (const xAOD::TruthParticle *part : *particles){
224 if ( part->isBottomHadron() && isHFHadronFinalState(part, 5) ){
225 truthBhs.push_back(part);
226 }
227 }
228
229
230 //create truthBhs in acceptance
231 std::vector<const xAOD::TruthParticle*> accepted_truthBhs = create_accepted_truthBhs(truthBhs, jets_Selected);
232
233 //do the DeltaR matching between truthBh and SSV
234 std::vector<bool> truthBh_to_SSV_matched = truthBh_to_SSV_matching(accepted_truthBhs, good_SSVs);
235
236 //count matched truthBh,missed truthBh (not matched truthBh) and number of fake SSV (not matched SSV)
237 int N_matched = count_matched_objects(truthBh_to_SSV_matched);
238 int N_missed = count_not_matched_objects(truthBh_to_SSV_matched);
239 int N_fake = count_number_of_fake_SSVs(accepted_truthBhs, good_SSVs);
240
241 // retrieve pileup
242 double muactual = evtInfo->actualInteractionsPerCrossing();
243
244 // calculate P_eff
245 double P_eff = std::pow(m_SF_eff, N_matched);
246
247 //calculate P_ineff according to the chosen method
248 double P_ineff = 1;
250 P_ineff = m_EfficiencyMethodBJetBasedPtr->getPIneff(b_jet_count, N_missed,m_SF_eff);
251 }
253 P_ineff = m_EfficiencyMethodBhadronPtEtaBasedPtr->getPIneff(accepted_truthBhs, truthBh_to_SSV_matched, m_SF_eff);
254 }
255 else {
256 ATH_MSG_ERROR("Unknown efficiency method: " << m_EfficiencyMethod << " , accepted efficiency methods are: 'bjet_based','Bhadron_pT_eta_based'");
257 return StatusCode::FAILURE;
258 }
259
260 // calculate P_fake according to the chosen method
261 double P_fake = 1;
263 P_fake = m_nFPileupBJetBasedPtr->getPFake(muactual, b_jet_count, N_fake,m_SF_fake_low, m_SF_fake_high);
264 }
266 P_fake = m_nFPileupBasedLinearFitPtr->getPFake(muactual,N_fake);
267 }
269 P_fake = m_nFPileupBasedBinnedPtr->getPFake(muactual, N_fake, m_SF_fake_low, m_SF_fake_high);
270 }
271 else {
272 ATH_MSG_ERROR("Unknown nF method: " << m_nFMethod << " , accepted nF methods are: 'pileup_bjet_based', 'pileup_based_linearfit', 'pileup_based_binned'");
273 return StatusCode::FAILURE;
274 }
275
276 //calculate SSV_weight
277 double SSV_weight = P_eff * P_ineff * P_fake;
278
279 // decorate SSV weight
280 m_SSV_weight_decor.set(*evtInfo, SSV_weight, sys);
281
283 // decorate P factors
284 m_P_eff_decor.set(*evtInfo, P_eff, sys);
285 m_P_ineff_decor.set(*evtInfo, P_ineff, sys);
286 m_P_fake_decor.set(*evtInfo, P_fake, sys);
287 }
289 //decorate additional information
290 m_N_matched_decor.set(*evtInfo, N_matched, sys);
291 m_N_missed_decor.set(*evtInfo, N_missed, sys);
292 m_N_fake_decor.set(*evtInfo, N_fake, sys);
293 m_number_of_bjets_decor.set(*evtInfo, b_jet_count, sys);
294 m_number_of_accepted_Bhadrons_decor.set(*evtInfo, accepted_truthBhs.size(), sys);
295 m_number_of_good_SSVs_decor.set(*evtInfo, good_SSVs.size(), sys);
296 }
297 //decorate all possible P factors
299 double P_ineff_bjet_based = m_EfficiencyMethodBJetBasedPtr->getPIneff(b_jet_count, N_missed,m_SF_eff);
300 double P_ineff_pt_eta_based = m_EfficiencyMethodBhadronPtEtaBasedPtr->getPIneff(accepted_truthBhs, truthBh_to_SSV_matched, m_SF_eff);
301 double P_fake_pileup_bjet_based = m_nFPileupBJetBasedPtr->getPFake(muactual, b_jet_count, N_fake, m_SF_fake_low, m_SF_fake_high);
302 double P_fake_pileup_based_linearfit = m_nFPileupBasedLinearFitPtr->getPFake(muactual,N_fake);
303 double P_fake_pileup_based_binned = m_nFPileupBasedBinnedPtr->getPFake(muactual, N_fake, m_SF_fake_low, m_SF_fake_high);
304
305 m_P_ineff_bjet_based_decor.set(*evtInfo, P_ineff_bjet_based, sys);
306 m_P_ineff_pt_eta_based_decor.set(*evtInfo, P_ineff_pt_eta_based, sys);
307 m_P_fake_pileup_bjet_based_decor.set(*evtInfo, P_fake_pileup_bjet_based, sys);
308 m_P_fake_pileup_based_linearfit_decor.set(*evtInfo, P_fake_pileup_based_linearfit, sys);
309 m_P_fake_pileup_based_binned_decor.set(*evtInfo, P_fake_pileup_based_binned, sys);
310 }
311 }
312 return StatusCode::SUCCESS;
313 }
314
315 // create vector that indicates which SSV is a so-called good SSV
316 std::vector<const xAOD::Vertex*> SSVWeightsAlg::create_good_SSVs(
317 const std::vector<const xAOD::Jet*> &jets,
318 const std::vector<const xAOD::Electron*> &electrons,
319 const std::vector<const xAOD::Muon*> &muons,
320 const std::vector<const xAOD::Vertex*> &SSVs) const {
321
322 static const SG::AuxElement::ConstAccessor<float> ssv_pt_accessor(("bvrtPt"));
323 static const SG::AuxElement::ConstAccessor<float> ssv_m_accessor("bvrtM");
324 static const SG::AuxElement::ConstAccessor<float> ssv_eta_accessor("bvrtEta");
325
326 std::vector<const xAOD::Vertex*> good_SSVs;
327
328 for (const xAOD::Vertex* SSV : SSVs) {
329 bool overlaps = false;
330
331 //check if SSV fails good SSV definition
332 if ( (ssv_pt_accessor(*SSV) < 3000) || (ssv_m_accessor(*SSV) < 600) || (std::abs(ssv_eta_accessor(*SSV)) > 2.5) ){
333 continue;
334 }
335
336 //check if SSV overlaps with jet
337 for (const xAOD::Jet* jet : jets) {
338 double DeltaR_jet = compute_DeltaR_between_SSV_and_particle( SSV , jet );
339 if (DeltaR_jet < 0.6){
340 overlaps = true;
341 break;
342 }
343 }
344
345 if (overlaps == true){
346 continue;
347 }
348 //check if SSV overlaps with electron
349 for (const xAOD::Electron* electron : electrons) {
350 double DeltaR_el = compute_DeltaR_between_SSV_and_particle( SSV , electron );
351 if (DeltaR_el < 0.2){
352 overlaps = true;
353 break;
354 }
355 }
356
357 if (overlaps == true){
358 continue;
359 }
360
361 //check if SSV overlaps with muon
362 for (const xAOD::Muon* muon : muons) {
363 double DeltaR_mu = compute_DeltaR_between_SSV_and_particle( SSV , muon );
364 if (DeltaR_mu < 0.2){
365 overlaps = true;
366 break;
367 }
368 }
369
370 if (overlaps == true){
371 continue;
372 }
373 good_SSVs.push_back(SSV);
374 }
375 return good_SSVs;
376 };
377
378 // You construct a vector to see if the truthBh is an acceptance. An entry in this vector is true if the truth Bh is in acceptance and false if not
379 std::vector<const xAOD::TruthParticle*> SSVWeightsAlg::create_accepted_truthBhs(
380 const std::vector<const xAOD::TruthParticle*> &truthBhs,
381 const std::vector<const xAOD::Jet*> &jets) const {
382
383 std::vector<const xAOD::TruthParticle*> accepted_truthBhs;
384
385 for (const xAOD::TruthParticle* truthBh : truthBhs) {
386 // Check if truthBh fails truthBh in acceptance definition
387 if (truthBh->pt() < 2000 || (std::abs(truthBh->eta()) > 2.8)){
388 continue;
389 }
390
391 // check if truthBh overlaps with jet
392 bool overlaps = false;
393 for (const xAOD::Jet* jet : jets) {
394 double DeltaR = truthBh->p4().DeltaR(jet->p4());
395 if (DeltaR<0.6){
396 overlaps = true;
397 break;
398 }
399 }
400
401 if (overlaps == true){
402 continue;
403 }
404
405 accepted_truthBhs.push_back(truthBh);
406 }
407 return accepted_truthBhs;
408 };
409
411 const std::vector<const xAOD::TruthParticle*> &truthBhs,
412 const std::vector<const xAOD::Vertex*> &SSVs) const {
413
414 int N_fake_SSV = 0;
415 for (const xAOD::Vertex* SSV : SSVs){
416 bool foundMatch = false;
417 for (const xAOD::TruthParticle* truthBh : truthBhs){
418 double DeltaR = compute_DeltaR_between_SSV_and_particle(SSV, truthBh);
419 if (DeltaR < 0.3){
420 foundMatch = true;
421 break;
422 }
423 }
424 if (!foundMatch){
425 // In this case no match was found between the current SSV and any truth particle
426 // Hence it is a fake SSV
427 // Increase the number of fake SSV counter
428 N_fake_SSV = N_fake_SSV + 1;
429 }
430 }
431 return N_fake_SSV;
432 }
433
434
435
436
437 // create a vector that indicates if a truthBh got matched to a SSV
439 const std::vector<const xAOD::TruthParticle*> &truthBhs,
440 const std::vector<const xAOD::Vertex*> &SSVs) const {
441
442 std::vector<bool> matched_vector(truthBhs.size(), false);
443 for (size_t i = 0; i < truthBhs.size(); ++i){
444 const xAOD::TruthParticle* truthBh = truthBhs[i];
445 for (size_t j = 0; j < SSVs.size(); ++j){
446 const xAOD::Vertex* SSV = SSVs[j];
447 double DeltaR = compute_DeltaR_between_SSV_and_particle(SSV, truthBh);
448 if (DeltaR < 0.3){
449 matched_vector[i] = true;
450 break;
451 }
452 }
453 }
454 return matched_vector;
455 };
456
457 // compute the DeltaR between a SSV and another particle (jet,electron,truthparticle etc.)
459 const xAOD::Vertex* vtx,
460 const xAOD::IParticle * part) const {
461
462 static const SG::AuxElement::ConstAccessor<float> ssv_eta_accessor("bvrtEta");
463 static const SG::AuxElement::ConstAccessor<float> ssv_phi_accessor("bvrtPhi");
464 // Compute delta eta between vertex and particle
465 double eta_diff = ssv_eta_accessor(*vtx) - part->eta() ;
466
467 // Compute delta phi between vertex and particle
468 // See TLorentzVector::DeltaR function
469 double phi_diff = TVector2::Phi_mpi_pi(ssv_phi_accessor(*vtx) - part->phi() );
470
471 // Compute deltaR between vertex and particle
472 return std::sqrt( eta_diff*eta_diff + phi_diff*phi_diff );
473 }
474
475
476 // count number of matched objects
478 const std::vector<bool> &matching_vector) const {
479
480 // Count the number of times true appears in the vector
481 return std::count(matching_vector.begin(), matching_vector.end(), true);
482 }
483
484
485 // count number of objects that are not matched
487 const std::vector<bool> &matching_vector) const {
488
489 return matching_vector.size() - count_matched_objects(matching_vector);
490 }
491
492 const std::vector<const xAOD::TruthParticle*> SSVWeightsAlg::construct_not_matched_vectors(
493 const std::vector<const xAOD::TruthParticle*> &truthBhs,
494 const std::vector<bool> &matched_vector) {
495
496 std::vector<const xAOD::TruthParticle*> missed_vector;
497 for (size_t i = 0; i < truthBhs.size(); ++i){
498 if (matched_vector[i] == false){
499 missed_vector.push_back(truthBhs[i]);
500 }
501 }
502 return missed_vector;
503 };
504
505 // Indicate if hadron is heavy flavour hadron and in the final state in the truthparticle tree
507 const xAOD::TruthParticle *part,
508 const int type) const {
509
510 for (unsigned int i = 0; i < part->nChildren(); ++i){
511 const xAOD::TruthParticle *child = part->child(i);
512 if (!child){
513 continue;
514 }
515 if (type == 5){
516 if (child->isBottomHadron()){
517 return false;
518 }
519 if (child->isGenStable()){
520 if (!isHFHadronFinalState(child, type)){
521 return false;
522 }
523 }
524 }
525
526 if (type == 4){
527 if (child->isCharmHadron()){
528 return false;
529 }
530 if (child->isGenStable()){
531 if (!isHFHadronFinalState(child, type)){
532 return false;
533 }
534 }
535 }
536 }
537 return true;
538 }
539
541 const int k,
542 const double lambda){
543 // Returns $P(k;\lambda) = \frac{e^{-\lambda}\lambda^k}{k!}$
544 boost::math::poisson distrib(lambda);
545 return boost::math::pdf(distrib, k);
546 }
547
549 : m_ptbins(jsonConfig["efficiency_Bhadron_pT_eta_based"]["pt_bins"].get<std::vector<double>>())
550 {
551 // Extract information from JSON file for EfficiencyMethod EfficiencyMethodBhadronPtEtaBased
552 for (size_t i = 0; i < m_ptbins.size() - 1; ++i) {
553 std::string pT_bin_key = "pt_bin_" + std::to_string((int)m_ptbins[i]) + "_" + std::to_string((int)m_ptbins[i+1]);
554 m_BhadronPtEtaEfficiencyMap[pT_bin_key] = jsonConfig["efficiency_Bhadron_pT_eta_based"][pT_bin_key];
555 }
556 m_upperboundpT = m_ptbins[m_ptbins.size()-1];
557 }
558
559 //calculate P_ineff based on the Bhadron pT and eta
561 const std::vector<const xAOD::TruthParticle*> &accepted_truthBhs,
562 const std::vector<bool> &truthBh_to_SSV_matched,
563 double SF_eff) const{
564 //construct missed truthBhs
565 const std::vector<const xAOD::TruthParticle*> missed_truthBhs = construct_not_matched_vectors(accepted_truthBhs, truthBh_to_SSV_matched);
566
567 //read off pt bins from JSON file
568 const std::vector<double> &ptbins = m_ptbins;
569
570 double P_ineff = 1;
571 for (size_t i = 0; i < missed_truthBhs.size(); ++i) {
572 //retrieve pt,eta of missed truthBh
573 double pt = missed_truthBhs[i]->pt();
574 double eta = std::abs(missed_truthBhs[i]->eta());
575 std::string pt_bin_of_truthBh = "";
576 // iterate pt bins to find appropriate efficiency bin for the truthBh pT
577 for (size_t j = 0; j < ptbins.size() - 1; ++j) {
578 if (pt >= ptbins[j] && pt < ptbins[j+1]) {
579 //construct pt bin name
580 pt_bin_of_truthBh = "pt_bin_" + std::to_string((int)ptbins[j]) + "_" + std::to_string((int)ptbins[j+1]);
581 }
582 else if (pt > m_upperboundpT){
583 pt_bin_of_truthBh = "pt_bin_" + std::to_string(m_upperboundpT) + "plus";
584 }
585 }
586 if (pt_bin_of_truthBh == ""){
587 //no pt bin found or no missed truthBh"
588 continue;
589 }
590 //retrieve eta and efficiency bins for the pT bin
591 const std::vector<double>& eta_bins = m_BhadronPtEtaEfficiencyMap.at(pt_bin_of_truthBh).at("eta");
592 const std::vector<double>& efficiencies = m_BhadronPtEtaEfficiencyMap.at(pt_bin_of_truthBh).at("efficiency");
593
594 double efficiency = 1;
595
596 //iterate eta bins to find appropriate eta bin for truthBh eta
597 for (size_t k = 0; k < eta_bins.size() - 1; ++k) {
598 double eta_low = eta_bins[k];
599 double eta_up = eta_bins[k+1];
600 if (eta >= eta_low && eta < eta_up) {
601 //eta bin found -> read off corresponding efficiency
602 efficiency = efficiencies[k];
603 }
604 }
605 //calculate P_ineff using the found efficiency
606 P_ineff = P_ineff*(1-SF_eff*efficiency)/(1-efficiency);
607 }
608 return P_ineff;
609 }
610
612 : m_bjetEfficiencyMap(jsonConfig["efficiency_bjet_based"])
613 {
614 // Extract information from JSON file for EfficiencyMethodBJetBased
615 std::map<std::string, double>::iterator lastItem = std::prev(m_bjetEfficiencyMap.end());
616 std::string lastItemKey = lastItem->first;
617 m_upperboundNbjets = std::stoi(lastItemKey);
618 }
619
620
621 //calculate P_ineff based on the bjet multiplicity
623 const int b_jet_count,
624 const int N_missed,
625 const double SF_eff) const{
626
627 double P_ineff = 1;
628
629 // Get the value
630 double epsilon = 1;
631
632 //retrieve efficiency and average number of fake SSV depending on number of jets in event
633 if (b_jet_count < m_upperboundNbjets){
634 // Build the bjets key string
635 std::string bjets_key = std::to_string(b_jet_count) + "_bjets";
636 epsilon = m_bjetEfficiencyMap.at(bjets_key);
637 }
638 else{
639 std::string bjets_key = std::to_string(m_upperboundNbjets) + "p_bjets";
640 epsilon = m_bjetEfficiencyMap.at(bjets_key);
641 }
642
643 P_ineff = std::pow((1-SF_eff*epsilon)/(1-epsilon), N_missed);
644
645 return P_ineff;
646 }
647
649 : m_nFPileupBJetMap(jsonConfig["nF_pileup_bjet_based"])
650 {
651 // Extract information from JSON file for nFMethodPileupBJetBased
652 std::map<std::string, double>::iterator lastItem = std::prev(m_nFPileupBJetMap.at("high_muactual").end());
653 std::string lastItemKey = lastItem->first;
654 m_upperboundNbjets = std::stoi(lastItemKey);
655 m_lowMuHighMuThreshold = jsonConfig["CalibrationInformation"]["lowMuHighMuThreshold"];
656 }
657
658 //calculate P_fake based on the bjet multiplicity in the high pileup and low pileup region
660 const double muactual,
661 const int b_jet_count,
662 const int N_fake,
663 const double SF_fake_low,
664 const double SF_fake_high) const{
665
666 double P_fake = 1;
667 // 2D map muactual and Nbjets
668 std::string mu_key = (muactual >= m_lowMuHighMuThreshold) ? "high_muactual" : "low_muactual";
669
670 // Get the value
671 double n_F_value = 0;
672
673 if (b_jet_count < m_upperboundNbjets){
674 // Build the bjets key string
675 std::string bjets_key = std::to_string(b_jet_count) + "_bjets";
676 n_F_value = m_nFPileupBJetMap.at(mu_key).at(bjets_key);
677 }
678 else{
679 // Build the bjets key string
680 std::string bjets_key = std::to_string(m_upperboundNbjets) + "p_bjets";
681 n_F_value = m_nFPileupBJetMap.at(mu_key).at(bjets_key);
682 }
683
684 if (muactual >= m_lowMuHighMuThreshold){
685 P_fake = (poisson_pmf(N_fake, SF_fake_high*n_F_value))/poisson_pmf(N_fake, n_F_value);
686 }
687 else {
688 P_fake = (poisson_pmf(N_fake, SF_fake_low*n_F_value))/poisson_pmf(N_fake, n_F_value);
689 }
690
691 return P_fake;
692 }
693
695 // Extract information from JSON file for nFMethodPileupBasedLinearFit
696 m_slopeUnscaled = jsonConfig["nF_pileup_based_linearfit"]["unscaled"]["slope"];
697 m_interceptUnscaled = jsonConfig["nF_pileup_based_linearfit"]["unscaled"]["intercept"];
698 m_slopeScaled = jsonConfig["nF_pileup_based_linearfit"]["scaled"]["slope"];
699 m_interceptScaled = jsonConfig["nF_pileup_based_linearfit"]["scaled"]["intercept"];
700 }
701
702 //calculate P_fake based on a linear fit of the average number of fake SSVs (nF) to the pileup (muactual)
704 const double muactual,
705 const int N_fake) const{
706 // Calculate expected counts
707 double n_F = m_slopeUnscaled * muactual + m_interceptUnscaled;
708 double n_F_scaled = m_slopeScaled * muactual + m_interceptScaled;
709
710 // Calculate P_fake
711 double P_fake = poisson_pmf(N_fake, n_F_scaled) / poisson_pmf(N_fake, n_F);
712
713 return P_fake;
714 }
715
717 : m_muactualBins(jsonConfig["nF_pileup_based_binned"]["muactual_bins"].get<std::vector<double>>()),
718 m_nFBins(jsonConfig["nF_pileup_based_binned"]["values"].get<std::vector<double>>())
719 {
720 // Extract information from JSON file for nFMethodPileupBasedBinned
721 m_lowMuHighMuThreshold = jsonConfig["CalibrationInformation"]["lowMuHighMuThreshold"];
722 }
723
724
725 //calculate P_fake with the pileup binned
727 const double muactual,
728 const int N_fake,
729 const double SF_fake_low,
730 const double SF_fake_high) const{
731
732 double nF = 0;
733 double P_fake = 1;
734
735 // Find the correct bin for muactual
736 for (size_t j = 0; j < m_muactualBins.size() - 1; ++j) {
737 if (muactual >= m_muactualBins[j] && muactual < m_muactualBins[j + 1]) {
738 nF = m_nFBins[j];
739 if (muactual < m_lowMuHighMuThreshold){
740 P_fake = poisson_pmf(N_fake, SF_fake_low * nF) / poisson_pmf(N_fake, nF);
741 } else {
742 P_fake = poisson_pmf(N_fake, SF_fake_high * nF) / poisson_pmf(N_fake, nF);
743 }
744 break; // Bin found, no need to continue loop
745 }
746 }
747 return P_fake;
748 }
749}
Scalar eta() const
pseudorapidity method
#define ATH_MSG_ERROR(x)
#define ANA_MSG_INFO(xmsg)
Macro printing info messages.
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
nlohmann::json json
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
TEfficiency * efficiency(const std::string &effName, const std::string &tDir="", const std::string &stream="")
Simplify the retrieval of registered TEfficiency.
EfficiencyMethodBJetBasedClass(const nlohmann::json &jsonConfig)
double getPIneff(const int b_jet_count, const int N_missed, const double SF_eff) const
std::map< std::string, double > m_bjetEfficiencyMap
EfficiencyMethodBhadronPtEtaBasedClass(const nlohmann::json &jsonConfig)
std::map< std::string, std::map< std::string, std::vector< double > > > m_BhadronPtEtaEfficiencyMap
double getPIneff(const std::vector< const xAOD::TruthParticle * > &accepted_truthBh, const std::vector< bool > &truthBh_to_SSV_matched, double SF_eff) const
double getPFake(const double muactual, const int b_jet_count, const int N_fake, const double SF_fake_low, const double SF_fake_high) const
nFMethodPileupBJetBasedClass(const nlohmann::json &jsonConfig)
std::map< std::string, std::map< std::string, double > > m_nFPileupBJetMap
double getPFake(const double muactual, const int N_fake, const double SF_fake_low, const double SF_fake_high) const
nFMethodPileupBasedBinnedClass(const nlohmann::json &jsonConfig)
double getPFake(const double muactual, const int N_fake) const
nFMethodPileupBasedLinearFitClass(const nlohmann::json &jsonConfig)
CP::SysReadSelectionHandle m_muonSelection
std::vector< bool > truthBh_to_SSV_matching(const std::vector< const xAOD::TruthParticle * > &truthBhs, const std::vector< const xAOD::Vertex * > &SSVs) const
int count_not_matched_objects(const std::vector< bool > &matching_vector) const
CP::SysWriteDecorHandle< float > m_number_of_good_SSVs_decor
CP::SysReadHandle< xAOD::JetContainer > m_jetsHandle
OutputVariableSizeType m_OutputVariableSizeType
CP::SysReadHandle< xAOD::VertexContainer > m_ssvHandle
std::unique_ptr< nFMethodPileupBasedLinearFitClass > m_nFPileupBasedLinearFitPtr
CP::SysWriteDecorHandle< float > m_SSV_weight_decor
std::vector< const xAOD::Vertex * > create_good_SSVs(const std::vector< const xAOD::Jet * > &jets, const std::vector< const xAOD::Electron * > &electrons, const std::vector< const xAOD::Muon * > &muons, const std::vector< const xAOD::Vertex * > &SSVs) const
std::unique_ptr< EfficiencyMethodBJetBasedClass > m_EfficiencyMethodBJetBasedPtr
CP::SysReadHandle< xAOD::MuonContainer > m_muonsHandle
virtual StatusCode initialize() override
double compute_DeltaR_between_SSV_and_particle(const xAOD::Vertex *vtx, const xAOD::IParticle *part) const
CP::SysWriteDecorHandle< float > m_P_fake_pileup_based_linearfit_decor
static const std::vector< const xAOD::TruthParticle * > construct_not_matched_vectors(const std::vector< const xAOD::TruthParticle * > &truthBhs, const std::vector< bool > &matched_vector)
std::unique_ptr< EfficiencyMethodBhadronPtEtaBasedClass > m_EfficiencyMethodBhadronPtEtaBasedPtr
nlohmann::json m_jsonConfig_SSVWeightsAlg
bool isHFHadronFinalState(const xAOD::TruthParticle *part, const int type) const
std::vector< const xAOD::TruthParticle * > create_accepted_truthBhs(const std::vector< const xAOD::TruthParticle * > &truthBhs, const std::vector< const xAOD::Jet * > &jets) const
CP::SysWriteDecorHandle< float > m_N_missed_decor
CP::SysWriteDecorHandle< float > m_number_of_accepted_Bhadrons_decor
CP::SysReadSelectionHandle m_electronSelection
static double poisson_pmf(const int k, const double lambda)
CP::SysWriteDecorHandle< float > m_number_of_bjets_decor
virtual StatusCode execute() override
int count_matched_objects(const std::vector< bool > &matching_vector) const
Gaudi::Property< std::string > m_jsonConfigPath_SSVWeightsAlg
nFMethodType m_nFMethodType
CP::SysWriteDecorHandle< float > m_N_matched_decor
CP::SysWriteDecorHandle< float > m_P_fake_pileup_bjet_based_decor
Gaudi::Property< std::string > m_nFMethod
Gaudi::Property< std::string > m_EfficiencyMethod
CP::SysReadHandle< xAOD::TruthParticleContainer > m_truthParticlesHandle
std::unique_ptr< nFMethodPileupBJetBasedClass > m_nFPileupBJetBasedPtr
CP::SysWriteDecorHandle< float > m_P_ineff_bjet_based_decor
CP::SysWriteDecorHandle< float > m_P_ineff_decor
SSVWeightsAlg(const std::string &name, ISvcLocator *pSvcLocator)
CP::SysReadSelectionHandle m_jetSelection
int count_number_of_fake_SSVs(const std::vector< const xAOD::TruthParticle * > &truthBhs, const std::vector< const xAOD::Vertex * > &SSVs) const
CP::SysReadHandle< xAOD::EventInfo > m_eventInfoHandle
CP::SysListHandle m_systematicsList
Gaudi::Property< std::string > m_OutputVariableSize
Gaudi::Property< std::string > m_BTaggingWP
CP::SysWriteDecorHandle< float > m_P_ineff_pt_eta_based_decor
CP::SysWriteDecorHandle< float > m_P_fake_pileup_based_binned_decor
CP::SysWriteDecorHandle< float > m_N_fake_decor
CP::SysWriteDecorHandle< float > m_P_fake_decor
CP::SysReadHandle< xAOD::ElectronContainer > m_electronsHandle
CP::SysWriteDecorHandle< float > m_P_eff_decor
EfficiencyMethodType m_EfficiencyMethodType
std::unique_ptr< nFMethodPileupBasedBinnedClass > m_nFPileupBasedBinnedPtr
AnaAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
constructor with parameters
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:570
float actualInteractionsPerCrossing() const
Average interactions per crossing for the current BCID - for in-time pile-up.
Class providing the definition of the 4-vector interface.
bool isBottomHadron() const
Determine if the PID is that of a b-hadron.
bool isGenStable() const
Check if this is generator stable particle.
bool isCharmHadron() const
Determine if the PID is that of a c-hadron.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
Select isolated Photons, Electrons and Muons.
This module defines the arguments passed from the BATCH driver to the BATCH worker.
STL namespace.
Jet_v1 Jet
Definition of the current "jet version".
setRcore setEtHad setFside pt
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TruthParticle_v1 TruthParticle
Typedef to implementation.
Muon_v1 Muon
Reference the current persistent version:
JetContainer_v1 JetContainer
Definition of the current "jet container version".
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.
Electron_v1 Electron
Definition of the current "egamma version".