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