31 static const double muon_barrel_endcap_boundary = 1.05;
46 m_appliedSystematics(nullptr),
49 m_efficiencyMapReplicaArray(),
50 m_muonquality(
"Medium"),
51 m_calibration_version(
"250731_SummerUpdate"),
55 m_experimental(false),
58 m_replicaTriggerList(),
61 m_ReplicaRandomSeed(12345) {
74 declareProperty(
"AllowZeroSF",
m_allowZeroSF,
"If a trigger is not available will return 0 instead of throwing an error. More difficult to spot configuration issues. Use at own risk");
84 if (
year == 2015)
fileName =
"muontrigger_sf_2015_mc20a_v3.root";
85 else if (
year == 2016)
fileName =
"muontrigger_sf_2016_mc20a_v3.root";
86 else if (
year == 2017)
fileName =
"muontrigger_sf_2017_mc20d_v3.root";
87 else if (
year == 2018)
fileName =
"muontrigger_sf_2018_mc20e_v3.root";
88 else if (
year == 2022)
fileName =
"muontrigger_sf_2022_mc23a_v3.root";
89 else if (
year == 2023)
fileName =
"muontrigger_sf_2023_mc23d_v3.root";
90 else if (
year == 2024)
fileName =
"muontrigger_sf_2024_mc23e_v1.root";
93 return StatusCode::SUCCESS;
108 ATH_MSG_INFO(
"Note: setting up with user specified input file location " <<
m_custom_dir <<
" - this is not encouraged!");
114 if (
file ==
nullptr || !
file->IsOpen()) {
116 return StatusCode::FAILURE;
121 static const std::vector<std::string>
type {
"data",
"mc" };
122 static const std::vector<std::string> region {
"barrel",
"endcap" };
123 static const std::vector<std::string> systematic {
"nominal",
"stat_up",
"stat_down",
"syst_up",
"syst_down" };
128 if (qualityDirectory ==
nullptr) {
129 ATH_MSG_FATAL(
"MuonTriggerScaleFactors::initialize cannot find directory with selected quality");
130 return StatusCode::FAILURE;
133 TIter nextPeriod(qualityDirectory->GetListOfKeys());
134 while ((periodKey = (TKey*) nextPeriod())) {
135 if (not periodKey->IsFolder())
continue;
136 TDirectory* periodDirectory = qualityDirectory->GetDirectory(periodKey->GetName());
137 std::string
periodName = std::string(periodKey->GetName());
141 TIter nextTrigger(periodDirectory->GetListOfKeys());
142 while ((triggerKey = (TKey*) nextTrigger())) {
143 if (not triggerKey->IsFolder())
continue;
144 TDirectory* triggerDirectory = periodDirectory->GetDirectory(triggerKey->GetName());
145 std::string triggerName = std::string(triggerKey->GetName());
146 if(!std::set<std::string>{
"HLT_mu26_ivarmedium",
"HLT_mu50",
"HLT_mu26_ivarmedium_OR_HLT_mu50"}.count(triggerName) &&
m_binning ==
"coarse"){
147 ATH_MSG_DEBUG(
"Coarse binning not supported for di-muon trigger legs at the moment");
150 for (
const auto& iregion : region) {
151 bool isBarrel = iregion.find(
"barrel") != std::string::npos;
152 for (
const auto& itype :
type) {
153 bool isData = itype.find(
"data") != std::string::npos;
155 for (
const auto& isys : systematic) {
156 if (itype.find(
"data") != std::string::npos && isys.find(
"syst") != std::string::npos)
continue;
157 std::string
path =
"eff_etaphi_" +
m_binning +
"_" + iregion +
"_" + itype +
"_" + isys;
158 TH2*
hist =
dynamic_cast<TH2*
>(triggerDirectory->Get(
path.c_str()));
161 ATH_MSG_FATAL(
"MuonTriggerScaleFactors::initialize " <<
path <<
" not found under trigger " << triggerName <<
" and period " <<
periodName <<
" for year: " <<
year);
164 hist->SetDirectory(0);
169 return StatusCode::FAILURE;
171 m_efficiencyMap.insert(std::pair<EffiHistoIdent, TH1_Ptr>(HistoId, std::shared_ptr < TH1 > (
hist)));
181 TH1_Ptr tmp_h2 =
TH1_Ptr(
dynamic_cast<TH2F*
>(Nominal_H->Clone(Form(
"tmp_h2_%s", Nominal_H->GetName()))));
182 const int xbins = tmp_h2->GetNbinsX(),
ybins = tmp_h2->GetNbinsY();
183 for (
int x_i = 0; x_i <=
xbins; ++x_i) {
184 for (
int y_i = 0; y_i <=
ybins; ++y_i) {
185 double statErr = std::abs(tmp_h2->GetBinContent(x_i, y_i) - StatUp_H->GetBinContent(x_i, y_i));
186 tmp_h2->SetBinError(x_i, y_i, statErr);
198 return StatusCode::SUCCESS;
215 return StatusCode::FAILURE;
220 return StatusCode::FAILURE;
227 constexpr
auto years_to_run = std::to_array<int>({2015, 2016, 2017, 2018, 2022, 2023, 2024});
228 for (
const int &
year: years_to_run) {
231 return StatusCode::SUCCESS;
236 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getTriggerScaleFactor This is an experimental function. If you really know what you are doing set UseExperimental property.");
240 if (trigger.empty()) {
241 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getTriggerScaleFactor Trigger must have value.");
247 if (trigger ==
"HLT_mu8noL1")
248 ATH_MSG_WARNING(
"What you are trying to do is not correct. For di-muon triggers you should get the efficiency with getTriggerEfficiency and compute the SF by yourself.");
249 else if (trigger.find(
"HLT_2mu10") != std::string::npos || trigger.find(
"HLT_2mu14") != std::string::npos)
250 ATH_MSG_WARNING(
"Di-muon trigger scale factors for single reco muons are not supported!");
257 if (trigger.empty()) {
258 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getTriggerScaleFactor Trigger must have value.");
264 if (trigger ==
"HLT_mu8noL1") {
265 ATH_MSG_WARNING(
"What you are trying to do is not correct. For di-muon triggers you should get the efficiency with getTriggerEfficiency and compute the SF by yourself.");
267 else if (trigger.find(
"HLT_2mu10") != std::string::npos || trigger.find(
"HLT_2mu14") != std::string::npos) {
285 std::size_t
pos = sysBaseName.find(
"MCTOY");
286 if (
pos == std::string::npos)
return -1;
287 return atoi(sysBaseName.substr(
pos + 5,
pos + 8).c_str());
291 if (trigger.empty()) {
292 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getTriggerEfficiency Trigger must have value.");
312 std::string systype =
"";
314 systype =
"syst_down";
318 systype =
"stat_down";
332 if (configuration.
replicaIndex != -1) systype =
"replicas";
349 std::vector<TH1_Ptr> replica_v;
350 const int xbins =
h->GetNbinsX(),
ybins =
h->GetNbinsY();
352 for (
int t = 0;
t < nrep; ++
t) {
353 TH2* replica =
dynamic_cast<TH2*
>(
h->Clone(Form(
"rep%d_%s",
t,
h->GetName())));
355 for (
int x_i = 0; x_i <=
xbins; ++x_i) {
356 for (
int y_i = 0; y_i <=
ybins; ++y_i) {
357 replica->SetBinContent(x_i, y_i, Rndm.Gaus(
h->GetBinContent(x_i, y_i),
h->GetBinError(x_i, y_i)));
360 replica_v.push_back(
TH1_Ptr(replica));
367 return H1.get() !=
nullptr;
372 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getTriggerScaleFactor This is an experimental function. If you really know what you are doing set UseExperimental property.");
382 ATH_MSG_ERROR(
"Could not find efficiency map for muon with eta: " <<
mu_eta <<
" and phi: " <<
mu_phi <<
". Something is inconsistent. Please check your settings for year, mc and trigger." );
386 double mu_phi_corr =
mu_phi;
387 if (mu_phi_corr < eff_h2->GetYaxis()->GetXmin()) mu_phi_corr += 2.0 *
M_PI;
388 if (mu_phi_corr > eff_h2->GetYaxis()->GetXmax()) mu_phi_corr -= 2.0 *
M_PI;
389 return eff_h2->FindFixBin(
mu_eta, mu_phi_corr);
395 return std::hash<std::string>()(
histName);
430 ATH_MSG_WARNING(
"Could not find what you are looking for in the efficiency map. The trigger you are looking for, year and mc are not consistent, or the trigger is unavailable in this data period. Returning efficiency = 0.");
436 ATH_MSG_ERROR(
"Could not find what you are looking for in the efficiency map. The trigger you are looking for, year and mc are not consistent, or the trigger is unavailable in this data period. Please check how you set up the tool.");
441 if (configuration.
replicaIndex >= (
int) cit->second.size()) {
442 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getMuonEfficiency ; index for replicated histograms is out of range.");
449 if (cit.get() ==
nullptr) {
451 ATH_MSG_WARNING(
"Could not find what you are looking for in the efficiency map. The trigger you are looking for, year and mc are not consistent, or the trigger is unavailable in this data period. Returning efficiency = 0.");
455 ATH_MSG_ERROR(
"Could not find what you are looking for in the efficiency map. The trigger you are looking for, year and mc are not consistent, or the trigger is unavailable in this data period. Please check how you set up the tool.");
462 double mu_phi_corr =
mu_phi;
463 if (mu_phi_corr < eff_h2->GetYaxis()->GetXmin()) mu_phi_corr += 2.0 *
M_PI;
464 if (mu_phi_corr > eff_h2->GetYaxis()->GetXmax()) mu_phi_corr -= 2.0 *
M_PI;
466 const int bin = eff_h2->FindFixBin(
mu_eta, mu_phi_corr);
479 if (mucont.
size() != 2) {
480 ATH_MSG_FATAL(
"MuonTriggerScaleFactors::GetTriggerSF;Currently dimuon trigger chains only implemented for events with exactly 2 muons.");
484 Double_t eff_data = 0;
487 std::string data_err =
"";
488 std::string mc_err =
"";
491 data_err =
"nominal";
494 data_err =
"nominal";
495 mc_err =
"syst_down";
497 data_err =
"stat_down";
500 data_err =
"stat_up";
503 data_err =
"nominal";
514 if (configuration.
replicaIndex != -1) data_err =
"replicas";
517 configuration.
isData =
true;
521 configuration.
isData =
false;
526 double event_SF = 1.;
528 if (std::abs(1. - eff_mc) > 0.0001) {
529 event_SF = eff_data / eff_mc;
532 TriggerSF = event_SF;
541 double rate_not_fired_data = 1.;
542 double rate_not_fired_mc = 1.;
544 for (
const auto mu : mucont) {
546 double eff_data = 0., eff_mc = 0.;
555 std::string muon_trigger_name = trigger;
556 std::string data_err =
"";
557 std::string mc_err =
"";
566 data_err =
"nominal";
569 data_err =
"nominal";
570 mc_err =
"syst_down";
572 data_err =
"stat_down";
575 data_err =
"stat_up";
578 data_err =
"nominal";
589 if (configuration.
replicaIndex != -1) data_err =
"replicas";
592 configuration.
isData =
true;
595 configuration.
isData =
false;
600 rate_not_fired_data *= (1. - eff_data);
601 rate_not_fired_mc *= (1. - eff_mc);
604 double event_SF = 1.;
605 if (1 - rate_not_fired_data == 0) event_SF = 0;
606 if ((mucont.size()) and (std::abs(1. - rate_not_fired_mc) > 0.0001)) {
608 event_SF = (1. - rate_not_fired_data) / (1. - rate_not_fired_mc);
610 TriggerSF = event_SF;
621 double eff_data = 0., eff_mc = 0.;
630 std::string muon_trigger_name = trigger;
631 std::string data_err =
"";
632 std::string mc_err =
"";
641 data_err =
"nominal";
644 data_err =
"nominal";
645 mc_err =
"syst_down";
647 data_err =
"stat_down";
650 data_err =
"stat_up";
653 data_err =
"nominal";
659 if (configuration.
replicaIndex != -1) data_err =
"replicas";
662 configuration.
isData =
true;
666 configuration.
isData =
false;
673 if (std::abs(eff_mc) > 0.0001)
674 TriggerSF = eff_data / eff_mc;
704 if (trigger.find(
"2mu10") != std::string::npos)
return "HLT_mu10";
705 if (trigger.find(
"2mu14") != std::string::npos)
return "HLT_mu14";
706 throw std::runtime_error(
"Unknown dimuon trigger");
710 std::size_t
index = trigger.find(
"HLT_mu");
711 if (
index != std::string::npos) {
712 std::string rawNumber = trigger.substr(
index + 6);
713 if (!rawNumber.empty() && isdigit(rawNumber[0])) {
714 std::stringstream(rawNumber) >>
threshold;
720 ATH_MSG_ERROR(
"MuonTriggerScaleFactors::getThreshold Could not extract threshold for trigger " << trigger);
758 else if (
year == 2016) {
771 else if (
year == 2017) {
782 else if (
year == 2018) {
800 else if (
year == 2022) {
805 else if (
year == 2023) {
809 else if (
year == 2024) {
821 ATH_MSG_FATAL(
"RunNumber: " <<
runNumber <<
" not known! Will stop the code to prevent using wrong SFs.");
822 throw std::invalid_argument{
""};
828 if (
info.operator->()==
nullptr) {
830 throw std::invalid_argument{
""};
833 ATH_MSG_DEBUG(
"The current event is a data event. Return runNumber instead.");
834 return info->runNumber();
838 ATH_MSG_FATAL(
"Failed to find the RandomRunNumber decoration. Please call the apply() method from the PileupReweightingTool beforehand in order to get period dependent SFs");
839 throw std::invalid_argument{
""};
840 }
else if (acc_rnd(*
info) == 0) {
841 ATH_MSG_FATAL(
"Pile up tool has given runNumber 0. Exiting the code.");
842 throw std::invalid_argument{
""};
846 return acc_rnd(*
info);
851 TDirectory* tempDir = 0;
853 while (not tempDir) {
856 if (gROOT->GetDirectory((
dirname.str()).c_str())) {
860 tempDir = gROOT->mkdir((
dirname.str()).c_str());
862 ATH_MSG_ERROR(
"getTemporaryDirectory::Temporary directory could not be created");
872 if (!systematic.
empty()) {
874 return sys.find(systematic) !=
sys.end();
902 if (
registry.registerSystematics(*
this) != StatusCode::SUCCESS) {
903 ATH_MSG_ERROR(
"Failed to add systematic to list of recommended systematics.");
904 return StatusCode::FAILURE;
906 return StatusCode::SUCCESS;
925 ATH_MSG_ERROR(
"Unsupported combination of systematics passed to the tool!");
926 return StatusCode::FAILURE;
930 itr =
m_systFilter.insert(std::make_pair(systConfig, filteredSys)).first;
943 return StatusCode::FAILURE;
947 return StatusCode::SUCCESS;