ATLAS Offline Software
Loading...
Searching...
No Matches
JetUncertaintiesTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// General package includes
12
13// UncertaintyHistogram types
16
17// UncertaintyComponent types
37
38// xAOD includes
41
42// CP interface includes
45
46// ROOT includes
47#include "TString.h"
48#include "TFile.h"
49#include "TDirectory.h"
50#include "TROOT.h"
51#include "TEnv.h"
52#include "TH2D.h"
53
54// C++ includes
55#include <unordered_set>
56
57using namespace jet;
58
60// //
61// Constructor/destructor/initialization //
62// //
64
66 : asg::AsgTool(name)
67 , m_isInit(false)
68 , m_name(name)
69 , m_energyScale(1.e-3)
70 , m_release("")
71 , m_jetDef("")
72 , m_mcType("")
73 , m_configFile("")
74 , m_calibArea("CalibArea-08")
75 , m_path("")
76 , m_analysisFile("")
78 , m_NJetAccessorName("Njet")
80 , m_defAnaFile("")
81 , m_refNPV(-1)
82 , m_refMu(-1)
83 , m_refNPVHist(nullptr)
84 , m_refMuHist(nullptr)
85 , m_groups()
89 , m_currentUncSet(nullptr)
91 , m_systSetMap()
92 , m_fileValidHist(nullptr)
93 , m_caloMassWeight(nullptr)
94 , m_TAMassWeight(nullptr)
98 , m_userSeed(0)
99 , m_rand()
100 , m_isData(true)
101 , m_resHelper(nullptr)
102 , m_namePrefix("JET_")
103 , m_accTagScaleFactor("temp_SF")
104 , m_accEffSF("temp_effSF")
105 , m_accSigeffSF("temp_sigeffSF")
106 , m_accEfficiency("temp_efficiency")
107 , m_accTagResult("temp_accept")
110{
111 declareProperty("JetDefinition",m_jetDef);
112 declareProperty("MCType",m_mcType);
113 declareProperty("ConfigFile",m_configFile);
114 declareProperty("CalibArea",m_calibArea);
115 declareProperty("Path",m_path);
116 declareProperty("AnalysisFile",m_analysisFile);
117 declareProperty("AnalysisHistPattern",m_analysisHistPattern);
118 declareProperty("NJetAccessorName",m_NJetAccessorName);
119 declareProperty("VariablesToShift",m_systFilters);
120 declareProperty("IsData",m_isData);
121 declareProperty("AbsEtaGluonFraction",m_absEtaGluonFraction);
122 declareProperty("PseudoDataJERsmearingMode",m_pseudoDataJERsmearingMode);
123
124 ATH_MSG_DEBUG("Creating JetUncertaintiesTool named "<<m_name);
125
126 // Set dummy default systematic (do nothing)
127 // Prevents NULL access if user tries to apply correction without first calling function
129 ATH_MSG_ERROR(Form("Failed to pre-set applySystematicVariation to no variation"));
130}
131
133 : asg::AsgTool(toCopy.m_name+"_copy")
134 , m_isInit(toCopy.m_isInit)
135 , m_name(toCopy.m_name+"_copy")
136 , m_energyScale(1.e-3)
137 , m_release(toCopy.m_release)
138 , m_jetDef(toCopy.m_jetDef)
139 , m_mcType(toCopy.m_mcType)
140 , m_configFile(toCopy.m_configFile)
141 , m_calibArea(toCopy.m_calibArea)
142 , m_path(toCopy.m_path)
147 , m_defAnaFile(toCopy.m_defAnaFile)
148 , m_refNPV(toCopy.m_refNPV)
149 , m_refMu(toCopy.m_refMu)
150 , m_refNPVHist(toCopy.m_refNPVHist?new UncertaintyHistogram(*toCopy.m_refNPVHist):nullptr)
151 , m_refMuHist(toCopy.m_refMuHist?new UncertaintyHistogram(*toCopy.m_refMuHist):nullptr)
152 , m_groups()
156 , m_currentUncSet(nullptr)
158 , m_systSetMap()
160 , m_caloMassWeight(nullptr)
161 , m_TAMassWeight(nullptr)
165 , m_userSeed(toCopy.m_userSeed)
166 , m_rand(toCopy.m_rand)
167 , m_isData(toCopy.m_isData)
169 , m_namePrefix(toCopy.m_namePrefix)
171 , m_accEffSF(toCopy.m_accEffSF)
177{
178 ATH_MSG_DEBUG("Creating copy of JetUncertaintiesTool named "<<m_name);
179
180 for (size_t iGroup = 0; iGroup < toCopy.m_groups.size(); ++iGroup)
181 m_groups.push_back(new UncertaintyGroup(*toCopy.m_groups.at(iGroup)));
182
184 ATH_MSG_ERROR(Form("Failed to re-set applySystematicVariation in new tool copy"));
185}
186
188{
189 ATH_MSG_DEBUG(Form("Deleting JetUncertaintiesTool named %s",m_name.c_str()));
190
191 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
192 JESUNC_SAFE_DELETE(m_groups.at(iGroup));
193 m_groups.clear();
194
200
201 m_currentUncSet = nullptr;
202
203 m_systFilterMap.clear();
204
205 std::unordered_map<CP::SystematicSet,UncertaintySet*>::iterator iter;
206 for (iter = m_systSetMap.begin(); iter != m_systSetMap.end(); ++iter)
207 JESUNC_SAFE_DELETE(iter->second);
208 m_systSetMap.clear();
209
211}
212
214{
215 // Ensure it hasn't been initialized yet
216 if (m_isInit)
217 {
218 ATH_MSG_FATAL("Cannot set the energy scale after initialization of tool: " << m_name);
219 return StatusCode::FAILURE;
220 }
221
222 m_energyScale = 1.e-3;
223 return StatusCode::SUCCESS;
224}
225
227{
228 // Ensure it hasn't been initialized yet
229 if (m_isInit)
230 {
231 ATH_MSG_FATAL("Cannot set the energy scale after initialization of tool: " << m_name);
232 return StatusCode::FAILURE;
233 }
234
235 m_energyScale = 1;
236 return StatusCode::SUCCESS;
237}
238
240{
241 // Ensure it hasn't been initialized already
242 if (m_isInit)
243 {
244 ATH_MSG_FATAL(Form("Blocking re-initialization of tool named %s",m_name.c_str()));
245 return StatusCode::FAILURE;
246 }
247
248 ATH_MSG_INFO(Form("Preparing to initialize the JetUncertaintiesTool named %s",m_name.c_str()));
249
250 // Cache the current directory
251 TDirectory* currentDir = gDirectory;
252 gROOT->cd();
253
254 // Read the config file
255 const TString configFilePath = jet::utils::findFilePath(m_configFile.c_str(),m_path.c_str(),m_calibArea.c_str());
256 if (configFilePath == "")
257 {
258 ATH_MSG_ERROR("Cannot find config file: " << m_configFile << " (path is \"" << m_path << "\", CalibArea is \"" << m_calibArea << "\")");
259 return StatusCode::FAILURE;
260 }
261
262 TEnv settings;
263 if (settings.ReadFile(configFilePath.Data(),kEnvGlobal))
264 {
265 ATH_MSG_ERROR("Cannot read config file: " << configFilePath.Data());
266 return StatusCode::FAILURE;
267 }
268
269 // We can read it - start printing
270 ATH_MSG_INFO(Form("================================================"));
271 ATH_MSG_INFO(Form(" Initializing the JetUncertaintiesTool named %s",m_name.c_str()));
272 ATH_MSG_INFO(Form(" Path is: \"%s\"",m_path.c_str()));
273 ATH_MSG_INFO(Form(" CalibArea is: \"%s\"",m_calibArea.c_str()));
274 ATH_MSG_INFO(Form(" IsData is: \"%s\"",m_isData ? "true" : "false"));
275 ATH_MSG_INFO(Form(" Configuration file: \"%s\"",m_configFile.c_str()));
276 ATH_MSG_INFO(Form(" Location: %s",configFilePath.Data()));
277
278
279 // Get the uncertainty release
280 m_release = settings.GetValue("UncertaintyRelease","UNKNOWN");
281 ATH_MSG_INFO(Form(" Uncertainty release: %s",m_release.c_str()));
282
283 // Check the jet definition
284 TString allowedJetDefStr = settings.GetValue("SupportedJetDefs","");
285 if (allowedJetDefStr == "")
286 {
287 ATH_MSG_ERROR("Cannot find supported jet definitions in config");
288 return StatusCode::FAILURE;
289 }
290 std::vector<TString> allowedJetDefs = jet::utils::vectorize<TString>(allowedJetDefStr," ,");
291 bool foundJetDef = false;
292 for (size_t iDef = 0; iDef < allowedJetDefs.size(); ++iDef)
293 if (!allowedJetDefs.at(iDef).CompareTo(m_jetDef.c_str(),TString::kIgnoreCase))
294 {
295 foundJetDef = true;
296 m_jetDef = allowedJetDefs.at(iDef); // To ensure right capitalization
297 break;
298 }
299 if (!foundJetDef)
300 {
301 ATH_MSG_ERROR("Unsupported jet definition: " << m_jetDef);
302 return StatusCode::FAILURE;
303 }
304 ATH_MSG_INFO(Form(" Jet definition: %s",m_jetDef.c_str()));
305
306 // Check the MC type
307 TString allowedMCtypeStr = settings.GetValue("SupportedMCTypes","");
308 if (allowedMCtypeStr == "")
309 {
310 ATH_MSG_ERROR("Cannot find supported MC types in config");
311 return StatusCode::FAILURE;
312 }
313 std::vector<TString> allowedMCtypes = jet::utils::vectorize<TString>(allowedMCtypeStr," ,");
314 bool foundMCtype = false;
315 for (size_t iType = 0; iType < allowedMCtypes.size(); ++iType)
316 if (!allowedMCtypes.at(iType).CompareTo(m_mcType.c_str(),TString::kIgnoreCase))
317 {
318 foundMCtype = true;
319 m_mcType = allowedMCtypes.at(iType); // To ensure right capitalization
320 break;
321 }
322 if (!foundMCtype)
323 {
324 ATH_MSG_ERROR("Unsupported MC type: " << m_mcType);
325 return StatusCode::FAILURE;
326 }
327 ATH_MSG_INFO(Form(" MC type: %s",m_mcType.c_str()));
328
329
330 // Get the file to read uncertainties in from
331 TString histFileName = settings.GetValue("UncertaintyRootFile","");
332 if (histFileName == "")
333 {
334 ATH_MSG_ERROR("Cannot find uncertainty histogram file");
335 return StatusCode::FAILURE;
336 }
337 ATH_MSG_INFO(Form(" UncertaintyFile: \"%s\"",histFileName.Data()));
338
339 // Now find the histogram file
340 const TString histFilePath = utils::findFilePath(histFileName,m_path.c_str(),m_calibArea.c_str());
341 if (histFilePath == "")
342 {
343 ATH_MSG_ERROR("Cannot find the path of the uncertainty histogram file");
344 return StatusCode::FAILURE;
345 }
346 ATH_MSG_INFO(Form(" Location: %s",histFilePath.Data()));
347
348 // Now open the histogram file
349 TFile* histFile = new TFile(histFilePath,"READ");
350 if (!histFile || histFile->IsZombie())
351 {
352 ATH_MSG_ERROR("Cannot open uncertainty histogram file: " << histFileName.Data());
353 return StatusCode::FAILURE;
354 }
355
356
357 // Get the default analysis ROOT file for later use
358 // Overwrite the analysisFile if it wasn't specified
359 m_defAnaFile = settings.GetValue("AnalysisRootFile","");
360 if (m_analysisFile.empty())
362 if (!m_analysisFile.empty())
363 {
364 ATH_MSG_INFO(Form(" AnalysisFile: \"%s\"",m_analysisFile.c_str()));
365 // Ensure that we can find the file
366 const TString analysisFilePath = utils::findFilePath(m_analysisFile.c_str(),m_path.c_str(),m_calibArea.c_str());
367 if (analysisFilePath == "")
368 {
369 ATH_MSG_ERROR("Cannot find the path of the analysis histogram file");
370 return StatusCode::FAILURE;
371 }
372 ATH_MSG_INFO(Form(" Location: %s",analysisFilePath.Data()));
373 }
374 if (m_defAnaFile != m_analysisFile && !m_defAnaFile.empty())
375 {
376 ATH_MSG_INFO(Form(" DefaultAnalysisFile: \"%s\"",m_defAnaFile.c_str()));
377 // Ensure that we can find the file
378 const TString analysisFilePath = utils::findFilePath(m_defAnaFile.c_str(),m_path.c_str(),m_calibArea.c_str());
379 if (analysisFilePath == "")
380 {
381 ATH_MSG_ERROR("Cannot find the path of the default analysis histogram file");
382 return StatusCode::FAILURE;
383 }
384 ATH_MSG_INFO(Form(" Location: %s",analysisFilePath.Data()));
385 // if a histogram pattern was provided, then use it (only if an analysis file is used)
386 if (!m_analysisHistPattern.empty())
387 {
388 ATH_MSG_INFO(Form(" AnalysisHistPattern: \"%s\"",m_analysisHistPattern.c_str()));
389 }
390 }
391
392 // Get a file-wide validity histogram if specified
393 TString validHistForFile = settings.GetValue("FileValidHistogram","");
394 if (validHistForFile != "")
395 {
396 // Ensure that the parametrization is also specified
397 TString validHistForFileParam = settings.GetValue("FileValidHistParam","");
398 if (validHistForFileParam == "")
399 {
400 ATH_MSG_ERROR("Specified a FileValidHistogram without an accompanying FileValidHistParam: " << validHistForFile.Data());
401 return StatusCode::FAILURE;
402 }
403
404 // Translate parametrization to enum
405 const CompParametrization::TypeEnum validHistParam = CompParametrization::stringToEnum(validHistForFileParam);
406
407 // Check if a mass def was specified (optional)
408 const CompMassDef::TypeEnum validHistMassDef = CompMassDef::stringToEnum(settings.GetValue("FileValidHistMassDef",""));
409
410 // Create and initialize the validity histogram
411 m_fileValidHist = new ValidityHistogram(validHistForFile+"_"+m_jetDef,validHistParam,m_energyScale,validHistMassDef);
412 if (m_fileValidHist->initialize(histFile).isFailure())
413 return StatusCode::FAILURE;
414
415 ATH_MSG_INFO(Form(" FileValidHistogram: %s (%s)%s",validHistForFile.Data(),validHistForFileParam.Data(),validHistMassDef == CompMassDef::UNKNOWN ? "" : Form(" [%s]",CompMassDef::enumToString(validHistMassDef).Data())));
416 }
417
418 // Check if combined mass weights have been specified
419 const TString caloMassWeight = TString(settings.GetValue("CombMassWeightCaloHist",""));
420 const TString TAMassWeight = TString(settings.GetValue("CombMassWeightTAHist",""));
421 if (caloMassWeight != "" && TAMassWeight != "")
422 {
423 m_caloMassWeight = new UncertaintyHistogram(caloMassWeight+"_"+m_jetDef.c_str(),Interpolate::Full);
424 m_TAMassWeight = new UncertaintyHistogram(TAMassWeight+"_"+m_jetDef.c_str(),Interpolate::Full);
425
426 if (m_caloMassWeight->initialize(histFile).isFailure())
427 return StatusCode::FAILURE;
428 if (m_TAMassWeight->initialize(histFile).isFailure())
429 return StatusCode::FAILURE;
430
431 // Get the weight parametrization, defaulting to pT vs m/pT
432 const TString combMassParam = TString(settings.GetValue("CombMassWeightParam","PtMass"));
435 {
436 ATH_MSG_ERROR("Unexpected combined mass parametrization: " << combMassParam.Data());
437 return StatusCode::FAILURE;
438 }
439
440 ATH_MSG_INFO(" Found and loaded combined mass weight factors");
441 ATH_MSG_INFO(" WeightCaloHist = " << m_caloMassWeight->getName());
442 ATH_MSG_INFO(" WeightTAHist = " << m_TAMassWeight->getName());
444
445 // Check for custom mass definitions for the weight factors (not required, defaults exist)
446 const TString caloWeightMassDef = settings.GetValue("CombMassWeightCaloMassDef","Calo");
447 const TString TAWeightMassDef = settings.GetValue("CombMassWeightTAMassDef","TA");
448 if (caloWeightMassDef != "")
449 {
451 ATH_MSG_INFO(" WeightCaloMassDef was set to " << CompMassDef::enumToString(m_combMassWeightCaloMassDef).Data());
452 }
453 if (TAWeightMassDef != "")
454 {
456 ATH_MSG_INFO(" WeightTAMassDef was set to " << CompMassDef::enumToString(m_combMassWeightTAMassDef).Data());
457 }
458 }
459 else if (caloMassWeight != "" && TAMassWeight == "")
460 {
461 ATH_MSG_ERROR(" Found combined mass weight factors for the calo term, but not the TA term");
462 return StatusCode::FAILURE;
463 }
464 else if (caloMassWeight == "" && TAMassWeight != "")
465 {
466 ATH_MSG_ERROR(" Found combined mass weight factors for the TA term, but not the calo term");
467 return StatusCode::FAILURE;
468 }
469
470 // Get name of accessor to SF value
471 m_name_TagScaleFactor = TString(settings.GetValue("TagSFName","temp_SF"));
472 m_name_EffSF = TString(settings.GetValue("TagSFEffName","temp_effSF"));
473 m_name_Efficiency = TString(settings.GetValue("TagEfficiencyName","temp_efficiency"));
474 m_name_TagResult = TString(settings.GetValue("TagResultName","temp_accept")).ReplaceAll("accept", "Tagged");
475 m_name_SigeffSF = TString(m_name_EffSF).ReplaceAll("effSF", "sigeffSF");
476 if ( m_name_TagScaleFactor != "temp_SF") {
477 ATH_MSG_INFO(" accessor of SF is " << m_name_TagScaleFactor);
478 }
484
485 // Get the NPV/mu reference values
486 // These may not be set - only needed if a pileup component is requested
487 TString refNPV = settings.GetValue("Pileup.NPVRef","");
488 TString refMu = settings.GetValue("Pileup.MuRef","");
489 if ( (refNPV != "" && refMu == "") || (refNPV == "" && refMu != "") )
490 {
491 ATH_MSG_ERROR(Form("Only one of the pileup references was specified: (NPV,mu) = (%.1f,%.1f)",m_refNPV,m_refMu));
492 return StatusCode::FAILURE;
493 }
494 else if ( refNPV != "" && refMu != "")
495 {
496 // Check if these are floating point values for the pileup references
497 // If so, then fill the float, otherwise retrieve the histogram
500 else
501 {
503 if (m_refNPVHist->initialize(histFile).isFailure())
504 return StatusCode::FAILURE;
505 }
506
509 else
510 {
512 if (m_refMuHist->initialize(histFile).isFailure())
513 return StatusCode::FAILURE;
514 }
515 }
516
517 // If systematic filters were specified, first-order validate them
518 // Then inform the user
519 if (!m_systFilters.empty())
520 {
521 std::string varString = "";
522 for (size_t iFilter = 0; iFilter < m_systFilters.size(); ++iFilter)
523 {
525 {
526 ATH_MSG_ERROR("Unable to parse VariablesToShift due to unknown variable, please check for typos: " << m_systFilters.at(iFilter));
527 return StatusCode::FAILURE;
528 }
529 if (!varString.empty())
530 varString += ", ";
531 varString += m_systFilters.at(iFilter);
532 }
533 ATH_MSG_INFO(Form(" VariablesToShift: %s",varString.c_str()));
534 }
535
536 // Attempt to read in nominal resolution information
537 // There may be no such information - this is perfectly normal
539 if(m_resHelper->initialize(settings,histFile,m_mcType.c_str()).isFailure())
540 return StatusCode::FAILURE;
541
542 // Prepare for reading components and groups
543 // Components can be a group by themself (single component groups) if "Group" == 0
544 // Components can also form simple groups with "SubComp"
545 // Otherwise, need to specify group info separately from component info
546 // As such, start with groups, then handle components
547
548 // Loop over uncertainty components and groups in the config
549 ATH_MSG_INFO("");
550 ATH_MSG_INFO(Form("%6s %-40s : %s","","JES uncert. comp.","Description"));
551 ATH_MSG_INFO(Form("%6s %-40s -%s","","-----------------","-----------"));
552 for (size_t iGroup = 0; iGroup < 999; ++iGroup)
553 {
554 // Format the style
555 const TString prefix = Form("JESGroup.%zu.",iGroup);
556
557 // Read in information in the uncertainty group
558 ConfigHelper helper(prefix,m_mcType.c_str(),m_energyScale);
559 if (helper.initialize(settings).isFailure())
560 return StatusCode::FAILURE;
561
562 // Ignore the group if it's not defined
563 if (!helper.isGroup()) continue;
564
565 // All groups have to follow a given prefix matching ASG conventions
566 // Enforce this condition here where the helper is not yet const
567 if (!m_namePrefix.empty())
568 helper.enforceGroupNamePrefix(m_namePrefix);
569
570 // Call the uncertainty group helper method to add a new group
571 if (addUncertaintyGroup(helper).isFailure())
572 return StatusCode::FAILURE;
573 }
574 for (size_t iComp = 0; iComp < 999; ++iComp)
575 {
576 // Format the style
577 const TString prefix = Form("JESComponent.%zu.",iComp);
578
579 // Read in information on the uncertainty component
580 ConfigHelper helper(prefix,m_mcType.c_str(),m_energyScale);
581 if (helper.initialize(settings).isFailure())
582 return StatusCode::FAILURE;
583
584 // Ignore component if it is not defined
585 if (!helper.isComponent() && !helper.isCompGroup())
586 continue;
587
588 // All groups have to follow a given prefix matching ASG conventions
589 // Enforce this condition here where the helper is not yet const
590 // (Still relevant for components as many will be simple groups)
591 if (!m_namePrefix.empty())
592 helper.enforceGroupNamePrefix(m_namePrefix);
593
594 // Also add the component name suffix for the jet definition
595 helper.setComponentJetDefSuffix(m_jetDef);
596
597 // Call the uncertainty component helper method to add a new component
598 if(addUncertaintyComponent(helper).isFailure())
599 return StatusCode::FAILURE;
600 }
601
602 // Preparing for a sanity check done after group merger
603 // Do this with components rather than groups to make sure totals are the same
604 size_t numCompsBeforeMerger = 0;
605 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup) {
606 numCompsBeforeMerger += m_groups.at(iGroup)->getNumComponents();
607// std::cout << "Beginning group " << m_groups.at(iGroup)->getName() << std::endl;
608// for (int i=0; i<m_groups.at(iGroup)->getComponents().size(); i++) {
609// std::cout << "\t" << m_groups.at(iGroup)->getComponents().at(i)->getName() << std::endl;
610// }
611// for (int i=0; i<m_groups.at(iGroup)->getSubgroups().size(); i++) {
612// for (int j=0; j<m_groups.at(iGroup)->getSubgroups().at(i)->getComponents().size(); j++)
613// std::cout << "\t" << m_groups.at(iGroup)->getSubgroups().at(i)->getComponents().at(j)->getName() << std::endl;
614// }
615 }
616
617 // Merge all of the subgroups into their parent groups
618 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
619 {
620 const int groupNum = m_groups.at(iGroup)->getGroupNum();
621 const int subgroupNum = m_groups.at(iGroup)->getSubgroupNum();
622
623 // groupNum == 0 means this is an independent group (no merging possible)
624 // subgroupNum == 0 means this is not a subgroup of anything (no merging possible)
625 if (!groupNum || !subgroupNum) continue;
626
627 // Ensure we didn't do something silly
628 if (groupNum == subgroupNum)
629 {
630 ATH_MSG_ERROR(Form("Specified group %d (%s) as the parent of itself, blocking for safety",groupNum,m_groups.at(iGroup)->getName().Data()));
631 return StatusCode::FAILURE;
632 }
633
634 // Find the parent group
635 for (size_t iParentGroup = 0; iParentGroup < m_groups.size(); ++iParentGroup)
636 {
637 if (iParentGroup == iGroup) continue;
638
639 const int parentGroupNum = m_groups.at(iParentGroup)->getGroupNum();
640 if (parentGroupNum == subgroupNum)
641 {
642 // Add the subgroup to the parent group
643 if (m_groups.at(iParentGroup)->addSubgroup(m_groups.at(iGroup)).isFailure())
644 {
645 ATH_MSG_ERROR(Form("Failed to add group %d (%s) as a subgroup of group %d (%s)",groupNum,m_groups.at(iGroup)->getName().Data(),parentGroupNum,m_groups.at(iParentGroup)->getName().Data()));
646 return StatusCode::FAILURE;
647 }
648 }
649 }
650 }
651
652 // Remove all of the subgroups from the class vector which contains the outermost groups for users to interact with
653 // Faster to do it this way rather than deleting individual entries of the vector
654 std::vector<UncertaintyGroup*> localGroupVec;
655 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
656 localGroupVec.push_back(m_groups.at(iGroup));
657 m_groups.clear();
658
659 for (size_t iGroup = 0; iGroup < localGroupVec.size(); ++iGroup)
660 {
661 // If the group is not a sub-group, keep it
662 if (!localGroupVec.at(iGroup)->getSubgroupNum())
663 m_groups.push_back(localGroupVec.at(iGroup));
664 }
665
666 // Sanity check that things make sense
667 // Do this with components rather than groups to make sure totals are the same
668 size_t numCompsAfterMerger = 0;
669 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup) {
670 numCompsAfterMerger += m_groups.at(iGroup)->getNumComponents();
671// std::cout << "Beginning group " << m_groups.at(iGroup)->getName() << std::endl;
672// for (int i=0; i<m_groups.at(iGroup)->getComponents().size(); i++) {
673// std::cout << "\t" << m_groups.at(iGroup)->getComponents().at(i)->getName() << std::endl;
674// }
675// for (int i=0; i<m_groups.at(iGroup)->getSubgroups().size(); i++) {
676// for (int j=0; j<m_groups.at(iGroup)->getSubgroups().at(i)->getComponents().size(); j++)
677// std::cout << "\t" << m_groups.at(iGroup)->getSubgroups().at(i)->getComponents().at(j)->getName() << std::endl;
678// }
679 }
680
681 if (numCompsBeforeMerger != numCompsAfterMerger)
682 {
683 ATH_MSG_ERROR(Form("Something went wrong merging groups: %zu before merger and %zu after merger",numCompsBeforeMerger,numCompsAfterMerger));
684 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
685 {
686 ATH_MSG_ERROR(Form("\tFound %zu components in group: %s",m_groups.at(iGroup)->getNumComponents(),m_groups.at(iGroup)->getName().Data()));
687 }
688 return StatusCode::FAILURE;
689 }
690
691
692
693 // Initialize all of the groups (and thus all of the components)
694 // Also ensure that there are no empty groups
695 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
696 {
697 if (m_groups.at(iGroup)->getNumComponents() == 0)
698 {
699 ATH_MSG_ERROR("An empty group was encountered: " << m_groups.at(iGroup)->getName().Data());
700 return StatusCode::FAILURE;
701 }
702 if (m_groups.at(iGroup)->initialize(histFile).isFailure())
703 return StatusCode::FAILURE;
704
705 // Determine if the group is a recommended systematic
706 // Currently, all small-R systematics are recommended with one exception:
707 // MC closure systematics can be zero (when working with the reference MC)
708 // Still, check if the component is always zero and don't recommend if so
709 // For large-R, users are allowed to specify a set of filters for systematics
710 // Done for Moriond2017 as many variables were provided for studies
711 // Allows for users to not run variations of variables they don't use
712 // If unspecified, all variables are systematically shifted by default
713 const bool isRecommended = checkIfRecommendedSystematic(*m_groups.at(iGroup));
714 CP::SystematicVariation systVar(m_groups.at(iGroup)->getName().Data(),CP::SystematicVariation::CONTINUOUS);
715 if (addAffectingSystematic(systVar,isRecommended) != StatusCode::SUCCESS)
716 return StatusCode::FAILURE;
718 if (systVar.basename().find("JER") != std::string::npos) {
720 if (addAffectingSystematic(systVarPD,isRecommended) != StatusCode::SUCCESS)
721 return StatusCode::FAILURE;
722 }
723 }
724 }
725
726 // Ensure that we have nominal resolutions for any requested resolution uncertainties
727 // Do this at initialization, even if it is also checked in execution
728 // Also ensure that it was specified whether this is data or MC if resolutions are specified
729 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
730 {
731 std::set<CompScaleVar::TypeEnum> scaleVars = m_groups.at(iGroup)->getScaleVars();
732 for (CompScaleVar::TypeEnum var : scaleVars)
733 {
735 {
736 if (!m_resHelper->hasRelevantInfo(var,m_groups.at(iGroup)->getTopology()))
737 {
738 ATH_MSG_ERROR("Config file requests a resolution uncertainty without specifying the corresponding nominal resolution: " << CompScaleVar::enumToString(var).Data());
739 return StatusCode::FAILURE;
740 }
741 }
742 }
743 }
744
745
746 // Ensure that the filters are sane (they are all associated to at least one group)
747 for (size_t iFilter = 0; iFilter < m_systFilters.size(); ++iFilter)
748 {
749 bool filterIsSane = false;
750 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
751 {
752 if (m_groups.at(iGroup)->getScaleVars().count(CompScaleVar::stringToEnum(m_systFilters.at(iFilter))))
753 {
754 filterIsSane = true;
755 break;
756 }
757 }
758 if (!filterIsSane)
759 {
760 ATH_MSG_ERROR(" One of the specified VariablesToShift is not associated with any components, please check for typos: " << m_systFilters.at(iFilter));
761 return StatusCode::FAILURE;
762 }
763 }
764
765
766 // Determine the number of input parameters
767 size_t numCompInGroups = 0;
768 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
769 numCompInGroups += m_groups.at(iGroup)->getNumComponents();
770
771 // Summary message
772 ATH_MSG_INFO(Form(" Found and read in %zu individual components into %zu component groups of which %zu are recommended",numCompInGroups,m_groups.size(),m_recommendedSystematics.size()));
773
775 //ATH_MSG_INFO(Form(" Found and read in %zu components%s",m_components.size(),m_groups.size()?Form(" (%zu inputs in %zu groups, %zu independent input%s):",numCompInGroups,m_groups.size(),m_components.size()-m_groups.size(),m_components.size()-m_groups.size()!=1?"s":""):""));
776 //if (m_groups.size())
777 // for (size_t iComp = 0; iComp < m_components.size(); ++iComp)
778 // ATH_MSG_INFO(Form("%5zu. %-35s : %s",iComp+1,m_components.at(iComp)->getName().Data(),m_components.at(iComp)->getDesc().Data()));
779 ATH_MSG_INFO(Form("================================================"));
780
781 // Close the histogram file
782 histFile->Close();
783 // Go back to initial directory
784 gDirectory = currentDir;
785
786 // Finally done!
787 m_isInit = true;
789}
790
792// //
793// Initialization helper methods //
794// //
796
798{
799 const GroupHelper& group = *helper.getGroupInfo();
800
801 // Ensure the group number is specified and doesn't conflict with existing groups
802 if (group.groupNum == 0)
803 {
804 ATH_MSG_ERROR("Group number was not specified for group: " << group.name.Data());
805 return StatusCode::FAILURE;
806 }
807 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
808 if (m_groups.at(iGroup)->getGroupNum() == group.groupNum)
809 {
810 ATH_MSG_ERROR("Group number matches previous group (" << m_groups.at(iGroup)->getName().Data() << "): " << group.name.Data());
811 return StatusCode::FAILURE;
812 }
813
814 // Build the new group
815 UncertaintyGroup* toAdd = new UncertaintyGroup(group);
816 if (!toAdd)
817 {
818 ATH_MSG_ERROR("Failed to build new group: " << group.name.Data());
819 return StatusCode::FAILURE;
820 }
821
822 m_groups.push_back(toAdd);
823 if (!m_groups.back()->getSubgroupNum())
824 {
825 size_t numGroups = 0;
826 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
827 if (!m_groups.at(iGroup)->getSubgroupNum())
828 numGroups++;
829 ATH_MSG_INFO(Form("%5zu. %-40s : %s",numGroups //m_groups.size()
830 ,m_groups.back()->getName().Data()
831 ,m_groups.back()->getDesc().Data() ));
832 }
833 return StatusCode::SUCCESS;
834}
835
837{
838 const bool isSimpleGroup = helper.isCompGroup();
839 const ComponentHelper& component = *helper.getComponentInfo();
840 const GroupHelper& group = *helper.getGroupInfo();
841
842 ATH_MSG_DEBUG(Form("Starting to process %s named %s",isSimpleGroup?"simple component group":"standard component",component.name.Data()));
843
844 // Find the group index that this component belongs to
845 // Note that if this is a simple group, we first need to build the associated group
846 if (isSimpleGroup)
847 {
848 UncertaintyGroup* simpleGroup = new UncertaintyGroup(group);
849 if (!simpleGroup)
850 {
851 ATH_MSG_ERROR("Failed to build simple group for component: " << component.name.Data());
852 return StatusCode::FAILURE;
853 }
854 const size_t groupIndex = m_groups.size();
855 m_groups.push_back(simpleGroup);
856 ATH_MSG_DEBUG(Form("Created new group \"%s\" for a simple component at index %zu",simpleGroup->getName().Data(),groupIndex));
857
858 if (!m_groups.back()->getSubgroupNum())
859 {
860 size_t numGroups = 0;
861 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
862 if (!m_groups.at(iGroup)->getSubgroupNum())
863 numGroups++;
864 ATH_MSG_INFO(Form("%5zu. %-40s : %s",numGroups //m_groups.size()
865 ,m_groups.back()->getName().Data()
866 ,m_groups.back()->getDesc().Data() ));
867 }
868
869 // We now have the simple component group
870 // Check if we are in the simple case (one component) or more difficult case (sub components)
871 if (component.subComps.empty())
872 {
873 // Easy case, build the component and add it directly
874 UncertaintyComponent* compObject = buildUncertaintyComponent(component);
875 if (!compObject)
876 return StatusCode::FAILURE;
877
878 if (m_groups.at(groupIndex)->addComponent(compObject).isFailure())
879 return StatusCode::FAILURE;
880 ATH_MSG_DEBUG(Form("Added single component \"%s\" to simple group \"%s\" (index %zu)",compObject->getName().Data(),m_groups.at(groupIndex)->getName().Data(),groupIndex));
881 }
882 else
883 {
884 for (size_t iSubComp = 0; iSubComp < component.subComps.size(); ++iSubComp)
885 {
886 // Build a new ComponentHelper object for each subcomponent
887 ComponentHelper subComp(component);
888 subComp.uncNames.clear();
889 subComp.subComps.clear();
890 subComp.name = component.subComps.at(iSubComp);
891 subComp.uncNames.push_back(component.subComps.at(iSubComp));
892
893 UncertaintyComponent* subCompObject = buildUncertaintyComponent(subComp);
894 if (!subCompObject)
895 return StatusCode::FAILURE;
896
897 if (m_groups.at(groupIndex)->addComponent(subCompObject).isFailure())
898 return StatusCode::FAILURE;
899 ATH_MSG_DEBUG(Form("Added component \"%s\" (%zu of %zu) to simple group \"%s\" (index %zu)",subCompObject->getName().Data(),iSubComp+1,component.subComps.size(),m_groups.at(groupIndex)->getName().Data(),groupIndex));
900 }
901 }
902 }
903 else
904 {
905 size_t groupIndex = 0;
906 if (m_groups.empty())
907 {
908 ATH_MSG_ERROR("No groups exist to add the component to: " << component.name.Data());
909 return StatusCode::FAILURE;
910 }
911 for (size_t iGroup = 0; iGroup < m_groups.size(); ++iGroup)
912 if (m_groups.at(iGroup)->getGroupNum() == component.groupNum)
913 {
914 groupIndex = iGroup;
915 break;
916 }
917 if (groupIndex == 0 && m_groups.at(0)->getGroupNum() != component.groupNum)
918 {
919 ATH_MSG_ERROR("Failed to find group " << component.groupNum << " for the component: " << component.name.Data());
920 return StatusCode::FAILURE;
921 }
922
923 // We now have the group index where the component belongs
924 // Get the component we want to add (complicated function...)
925 UncertaintyComponent* compObject = buildUncertaintyComponent(component);
926 if (!compObject)
927 return StatusCode::FAILURE;
928
929 if (m_groups.at(groupIndex)->addComponent(compObject).isFailure())
930 return StatusCode::FAILURE;
931 ATH_MSG_DEBUG(Form("Added component \"%s\" to group \"%s\" (index %zu)",compObject->getName().Data(),m_groups.at(groupIndex)->getName().Data(),groupIndex));
932 }
933
934 return StatusCode::SUCCESS;
935}
936
938{
939 // Safety checks for required information
940 if (component.name == "")
941 {
942 ATH_MSG_ERROR("Attempting to create a component with no name");
943 return nullptr;
944 }
946 {
947 ATH_MSG_ERROR("Attempting to create a component with no parametrization: " << component.name.Data());
948 return nullptr;
949 }
950 if (component.scaleVar == CompScaleVar::UNKNOWN)
951 {
952 ATH_MSG_ERROR("Attempting to create a component with no variable to scale: " << component.name.Data());
953 return nullptr;
954 }
955
956 // Special cases first
957 if (component.isSpecial)
958 {
959 // First check pileup components
960 if (component.pileupType != PileupComp::UNKNOWN)
961 {
962 // Ensure that the reference values were specified
963 if (m_refNPV < 0 && !m_refNPVHist)
964 {
965 ATH_MSG_ERROR("Attempted to create pileup component without NPV reference value: " << component.name.Data());
966 return nullptr;
967 }
968 if (m_refMu < 0 && !m_refMuHist)
969 {
970 ATH_MSG_ERROR("Attempted to create pileup component without mu reference value: " << component.name.Data());
971 return nullptr;
972 }
973
975 {
978 else if (!m_refNPVHist && !m_refMuHist)
979 return new PileupUncertaintyComponent(component,m_refNPV,m_refMu);
980 else if (m_refNPVHist && !m_refMuHist)
981 return new PileupUncertaintyComponent(component,m_refNPVHist,m_refMu);
982 else if (!m_refNPVHist && m_refMuHist)
983 return new PileupUncertaintyComponent(component,m_refNPV,m_refMuHist);
984 }
985 else
986 {
987 ATH_MSG_ERROR(Form("Unexpected parametrization of %s for component %s",CompParametrization::enumToString(component.parametrization).Data(),component.name.Data()));
988 return nullptr;
989 }
990 }
991 // Next check flavour components
992 else if (component.flavourType != FlavourComp::UNKNOWN)
993 {
994 if (m_analysisFile.empty())
995 {
996 ATH_MSG_ERROR("Attempting to create a flavour uncertainty component without having specified an AnalysisRootFile");
997 return nullptr;
998 }
1000 {
1001
1002 if (component.flavourType == FlavourComp::PerJetResponse ||
1007 return new PerJetFlavourUncertaintyComponent(component);
1008 }else
1010
1011 }
1012 else
1013 {
1014 ATH_MSG_ERROR(Form("Unexpected parametrization of %s for component %s",CompParametrization::enumToString(component.parametrization).Data(),component.name.Data()));
1015 return nullptr;
1016 }
1017 }
1018 // Next check punchthrough
1019 else if (component.name.Contains("PunchThrough",TString::kIgnoreCase))
1020 {
1022 return new PunchthroughUncertaintyComponent(component);
1023 else
1024 {
1025 ATH_MSG_ERROR(Form("Unexpected parametrization of %s for component %s",CompParametrization::enumToString(component.parametrization).Data(),component.name.Data()));
1026 return nullptr;
1027 }
1028 }
1029 // Next check closeby
1030 else if (component.name.Contains("Closeby",TString::kIgnoreCase))
1031 {
1033 return new ClosebyUncertaintyComponent(component);
1034 else
1035 {
1036 ATH_MSG_ERROR(Form("Unexpected parametrization of %s for component %s",CompParametrization::enumToString(component.parametrization).Data(),component.name.Data()));
1037 return nullptr;
1038 }
1039 }
1040 // Next check combined mass
1041 else if (component.combMassType != CombMassComp::UNKNOWN)
1042 {
1043 // Ensure we have the weights we need for combined mass uncertainties
1045 {
1046 ATH_MSG_ERROR("Asking to create a combined mass term without specifying weights: " << component.name.Data());
1047 return nullptr;
1048 }
1049
1050 // Create the component
1051 ComponentHelper combComp(component);
1052 combComp.name = component.name;
1053 combComp.uncNames.clear();
1055
1056 // Set the weights
1057 if (cmuc->setCaloWeights(m_caloMassWeight).isFailure()) return nullptr;
1058 if (cmuc->setTAWeights(m_TAMassWeight).isFailure()) return nullptr;
1060 if (cmuc->setCombWeightParam(m_combMassParam).isFailure()) return nullptr;
1061 if (component.combMassType == CombMassComp::Calo || component.combMassType == CombMassComp::Both)
1062 {
1063 // Define the calorimeter group if applicable
1064 GroupHelper caloGroupH(component.name+"_CaloGroup");
1065 caloGroupH.groupNum = 0;
1066 caloGroupH.subgroupNum = 0;
1067 caloGroupH.category = CompCategory::UNKNOWN;
1069 caloGroupH.reducible = false;
1070
1071 UncertaintyGroup* caloGroup = new UncertaintyGroup(caloGroupH);
1072 if (!caloGroup)
1073 {
1074 ATH_MSG_ERROR("Failed to build calo-group for combined mass component: " << component.name.Data());
1075 return nullptr;
1076 }
1077
1078 // Get the calo terms and calo mass definitions
1079 std::vector<TString> caloComps = jet::utils::vectorize<TString>(component.caloMassTerm,", ");
1080 std::vector<TString> caloMassDefs = jet::utils::vectorize<TString>(component.caloMassDef,", ");
1081 if (caloComps.size() != caloMassDefs.size())
1082 {
1083 ATH_MSG_ERROR("Unbalanced number of calo mass terms and calo mass definitions, " << caloComps.size() << " vs " << caloMassDefs.size() << " for combined mass component: " << component.name.Data());
1084 return nullptr;
1085 }
1086
1087 // Build the component(s) and add them directly
1088 for (size_t iComp = 0; iComp < caloComps.size(); ++iComp)
1089 {
1090 // Prepare the helper
1091 ComponentHelper caloCompH(component);
1092 caloCompH.uncNames.clear();
1093 caloCompH.isSpecial = false;
1094 caloCompH.name = caloComps.at(iComp);
1095 caloCompH.uncNames.push_back(caloCompH.name+"_"+m_jetDef);
1096 caloCompH.massDef = CompMassDef::stringToEnum(caloMassDefs.at(iComp));
1097 if (caloCompH.massDef == CompMassDef::UNKNOWN)
1098 {
1099 ATH_MSG_ERROR("Failed to parse calo mass definition " << iComp << " (" << caloMassDefs.at(iComp).Data() << ") for combined mass component: " << component.name.Data());
1100 return nullptr;
1101 }
1102
1103 // Build the component
1104 UncertaintyComponent* caloComp = buildUncertaintyComponent(caloCompH);
1105 if (!caloComp)
1106 return nullptr;
1107
1108 if (caloGroup->addComponent(caloComp).isFailure())
1109 return nullptr;
1110 }
1111
1112 // Done preparations, now set the calo mass group
1113 if (cmuc->setCaloTerm(caloGroup).isFailure())
1114 return nullptr;
1115 }
1116 if (component.combMassType == CombMassComp::TA || component.combMassType == CombMassComp::Both)
1117 {
1118 // Define the track-assisted group if applicable
1119 GroupHelper TAGroupH(component.name+"_TAGroup");
1120 TAGroupH.groupNum = 0;
1121 TAGroupH.subgroupNum = 0;
1124 TAGroupH.reducible = false;
1125
1126 UncertaintyGroup* TAGroup = new UncertaintyGroup(TAGroupH);
1127 if (!TAGroup)
1128 {
1129 ATH_MSG_ERROR("Failed to build TA-group for combined mass component: " << component.name.Data());
1130 return nullptr;
1131 }
1132
1133 // Set the TA terms and TA mass definitions
1134 std::vector<TString> TAComps = jet::utils::vectorize<TString>(component.TAMassTerm,", ");
1135 std::vector<TString> TAMassDefs = jet::utils::vectorize<TString>(component.TAMassDef,", ");
1136 if (TAComps.size() != TAMassDefs.size())
1137 {
1138 ATH_MSG_ERROR("Unbalanced number of TA mass terms and TA mass definitions, " << TAComps.size() << " vs " << TAMassDefs.size() << " for combined mass component: " << component.name.Data());
1139 return nullptr;
1140 }
1141
1142 // Build the component(s) and add them directly
1143 for (size_t iComp = 0; iComp < TAComps.size(); ++iComp)
1144 {
1145 // Prepare the helper
1146 ComponentHelper TACompH(component);
1147 TACompH.uncNames.clear();
1148 TACompH.isSpecial = false;
1149 TACompH.name = TAComps.at(iComp);
1150 TACompH.uncNames.push_back(TACompH.name+"_"+m_jetDef);
1151 TACompH.massDef = CompMassDef::stringToEnum(TAMassDefs.at(iComp));
1152 if (TACompH.massDef == CompMassDef::UNKNOWN)
1153 {
1154 ATH_MSG_ERROR("Failed to parse TA mass definition " << iComp << " (" << TAMassDefs.at(iComp).Data() << ") for combined mass component: " << component.name.Data());
1155 return nullptr;
1156 }
1157
1158 //ATH_MSG_INFO("Creating TA component \"" << TACompH.name.Data() << "\" for combined mass component: " << component.name.Data());
1159
1160 // Build the component
1162 if (!TAComp)
1163 return nullptr;
1164
1165 if (TAGroup->addComponent(TAComp).isFailure())
1166 return nullptr;
1167 }
1168
1169 // Done preparations, now set the TA mass group
1170 if (cmuc->setTATerm(TAGroup).isFailure())
1171 return nullptr;
1172 }
1173
1174 // Done, return the component
1175 return cmuc;
1176 }
1177 // Next check large-R topology
1178 else if (component.name.Contains("Large",TString::kIgnoreCase) && component.name.Contains("Topology",TString::kIgnoreCase))
1179 {
1181 {
1182 if (!component.LargeRJetTruthLabels.empty())
1183 {
1184 return new LargeRTopologyUncertaintyComponent(component);
1185 }
1186 else
1187 {
1188 ATH_MSG_ERROR(Form("No LargeRJetTruthLabels specified for Large-R jet topology component %s",component.name.Data()));
1189 return nullptr;
1190 }
1191 }
1192 else
1193 {
1194 ATH_MSG_ERROR(Form("Unexpected parametrization of %s for component %s",CompParametrization::enumToString(component.parametrization).Data(),component.name.Data()));
1195 return nullptr;
1196 }
1197 }
1198 else
1199 {
1200 ATH_MSG_ERROR("Unexpected special component: " << component.name.Data());
1201 return nullptr;
1202 }
1203
1204 }
1205 // Standard components
1206 else
1207 {
1208 switch(component.parametrization)
1209 {
1211 return new PtUncertaintyComponent(component);
1214 return new PtEtaUncertaintyComponent(component);
1216 return new PtAbsMassUncertaintyComponent(component);
1218 return new PtMassUncertaintyComponent(component);
1220 return new PtLogPtMassForTagSFUncertaintyComponent(component);
1223 return new PtMassEtaUncertaintyComponent(component);
1226 return new PtAbsMassEtaUncertaintyComponent(component);
1228 return new ELogMassUncertaintyComponent(component);
1231 return new ELogMassEtaUncertaintyComponent(component);
1232 default:
1233 ATH_MSG_ERROR("Encountered unexpected parameter type: " << component.param.Data());
1234 return nullptr;
1235 }
1236 }
1237
1238 ATH_MSG_ERROR("Failed to find the type of component to build: " << component.name.Data());
1239 return nullptr;
1240}
1241
1242
1243
1245// //
1246// Methods to implement from ISystematicsTool //
1247// //
1249
1251{
1252 // Compare using basenames to avoid continious vs fixed value comparisons
1253 const std::set<std::string> baseNames = m_recognizedSystematics.getBaseNames();
1254 return baseNames.find(systematic.basename()) != baseNames.end();
1255 //return m_recognizedSystematics.find(systematic) != m_recognizedSystematics.end();
1256}
1257
1262
1267
1272
1274{
1275 // Check for things like AFII non-closure in full sim configurations
1276 if (systematic.isAlwaysZero())
1277 return false;
1278
1279 // Check for filters
1280 bool passesFilter = m_systFilters.empty();
1281 const std::set<CompScaleVar::TypeEnum> scaleVars = systematic.getScaleVars();
1282
1283 for (size_t iFilter = 0; iFilter < m_systFilters.size(); ++iFilter)
1284 {
1285 if (scaleVars.count(CompScaleVar::stringToEnum(m_systFilters.at(iFilter))))
1286 {
1287 passesFilter = true;
1288 break;
1289 }
1290 }
1291 if (!passesFilter)
1292 return false;
1293
1294 // All checked, this is a recommended systematic
1295 return true;
1296}
1297
1298StatusCode JetUncertaintiesTool::addAffectingSystematic(const CP::SystematicVariation& systematic, bool recommended)
1299{
1301 registry.registerSystematic(systematic);
1302 m_recognizedSystematics.insert(systematic);
1303 if (recommended)
1304 {
1305 m_recommendedSystematics.insert(systematic);
1306 if (registry.addSystematicToRecommended(systematic) != StatusCode::SUCCESS)
1307 {
1308 ATH_MSG_ERROR("Failed to add systematic to list of recommended systematics: " << systematic.name());
1309 return StatusCode::FAILURE;
1310 }
1311 }
1312 return StatusCode::SUCCESS;
1313}
1314
1316{
1317 //if (!m_isInit)
1318 //{
1319 // ATH_MSG_FATAL("Tool must be initialized before calling applySystematicVariation");
1320 // return StatusCode::FAILURE;
1321 //}
1322 CP::SystematicSet filteredSet;
1324 std::string remappedName = systConfig.name();
1325 size_t found = remappedName.find("_PseudoData");
1326 if (found != std::string::npos) {
1327 remappedName.erase(found, std::string("_PseudoData").length());
1328 }
1329
1330 CP::SystematicSet altConfig(remappedName);
1331 // Filter the full set of systematics to the set we care about
1332 if (getFilteredSystematicSet(altConfig,filteredSet) != StatusCode::SUCCESS)
1333 return StatusCode::FAILURE;
1334 }
1335 else {
1336 // Filter the full set of systematics to the set we care about
1337 if (getFilteredSystematicSet(systConfig,filteredSet) != StatusCode::SUCCESS)
1338 return StatusCode::FAILURE;
1339 }
1340
1341 // Get the uncertainty set associated to the filtered systematics set
1342 jet::UncertaintySet* uncSet = nullptr;
1343 if (getUncertaintySet(filteredSet,uncSet) != StatusCode::SUCCESS)
1344 return StatusCode::FAILURE;
1345
1346 // Change the current state
1347 m_currentSystSet.swap(filteredSet);
1348 m_currentUncSet = uncSet;
1349 return StatusCode::SUCCESS;
1350}
1351
1353{
1354 // Check if we have already encountered this set
1355 std::unordered_map<CP::SystematicSet,CP::SystematicSet>::iterator iter = m_systFilterMap.find(systConfig);
1356 if (iter != m_systFilterMap.end())
1357 filteredSet = iter->second;
1358 // Make the filtered set and store it
1359 else
1360 {
1361 if (CP::SystematicSet::filterForAffectingSystematics(systConfig,m_recognizedSystematics,filteredSet) != StatusCode::SUCCESS)
1362 return StatusCode::FAILURE;
1363 m_systFilterMap.insert(std::make_pair(systConfig,filteredSet));
1364 }
1365
1366 return StatusCode::SUCCESS;
1367}
1368
1370{
1371 // Check if we have already encountered this set
1372 std::unordered_map<CP::SystematicSet,UncertaintySet*>::iterator iter = m_systSetMap.find(filteredSet);
1373
1374 // If we have dealt with this set previously, we're done
1375 if (iter != m_systSetMap.end())
1376 {
1377 uncSet = iter->second;
1378 }
1379 // Make the new set and store it
1380 else
1381 {
1382 uncSet = new UncertaintySet(filteredSet.name());
1383 if (uncSet == nullptr || uncSet->initialize(filteredSet,m_groups).isFailure())
1384 {
1385 ATH_MSG_ERROR("Failed to create UncertaintySet for filtered CP::SystematicSet: " << filteredSet.name());
1386 JESUNC_SAFE_DELETE(uncSet);
1387 return StatusCode::FAILURE;
1388 }
1389 m_systSetMap.insert(std::make_pair(filteredSet,uncSet));
1390 }
1391
1392 return StatusCode::SUCCESS;
1393}
1394
1395
1397// //
1398// Information retrieval methods //
1399// //
1401
1403{
1404 float sqrtS = -1;
1405 const TString release = getRelease().c_str();
1406 if (release.BeginsWith("2011_"))
1407 sqrtS = 7000.*m_energyScale;
1408 else if (release.BeginsWith("2012_"))
1409 sqrtS = 8000.*m_energyScale;
1410 else if (release.BeginsWith("2015_") || release.BeginsWith("2016"))
1411 sqrtS = 13000.*m_energyScale;
1412 return sqrtS;
1413}
1414
1415
1417{
1418 if (!m_isInit)
1419 {
1420 ATH_MSG_FATAL("Tool must be initialized before calling getRefMu");
1421 return JESUNC_ERROR_CODE;
1422 }
1423 if (m_refMuHist)
1424 {
1425 ATH_MSG_FATAL("Tool contains a histogram for refMu, cannot return float");
1426 return JESUNC_ERROR_CODE;
1427 }
1428 return m_refMu;
1429}
1430
1432{
1433 if (!m_isInit)
1434 {
1435 ATH_MSG_FATAL("Tool must be initialized before calling getRefNPV");
1436 return JESUNC_ERROR_CODE;
1437 }
1438 if (m_refNPVHist)
1439 {
1440 ATH_MSG_FATAL("Tool contains a histogram for refNPV, cannot return float");
1441 return JESUNC_ERROR_CODE;
1442 }
1443 return m_refNPV;
1444}
1445
1447{
1448 if (!m_isInit)
1449 {
1450 ATH_MSG_FATAL("Tool must be initialized before calling getRefMu");
1451 return JESUNC_ERROR_CODE;
1452 }
1453 return m_refMuHist ? m_refMuHist->getValue(fabs(jet.eta())) : m_refMu;
1454}
1455
1457{
1458 if (!m_isInit)
1459 {
1460 ATH_MSG_FATAL("Tool must be initialized before calling getRefNPV");
1461 return JESUNC_ERROR_CODE;
1462 }
1463 return m_refNPVHist ? m_refNPVHist->getValue(fabs(jet.eta())) : m_refNPV;
1464}
1465
1466
1468{
1469 if (!m_isInit)
1470 {
1471 ATH_MSG_FATAL("Tool must be initialized before calling getNumComponents");
1472 return 0;
1473 }
1474
1475 return m_groups.size();
1476}
1477
1478size_t JetUncertaintiesTool::getComponentIndex(const std::string& name) const
1479{
1480 return getComponentIndex(TString(name.c_str()));
1481}
1482
1483size_t JetUncertaintiesTool::getComponentIndex(const TString& name) const
1484{
1485 if (!m_isInit)
1486 {
1487 ATH_MSG_FATAL("Tool must be initialized before calling getComponentIndex");
1488 return m_groups.size();
1489 }
1490
1491 for (size_t iComp = 0; iComp < m_groups.size(); ++iComp)
1492 if (m_groups.at(iComp)->getName().CompareTo(name,TString::kIgnoreCase) == 0)
1493 return iComp;
1494
1495 ATH_MSG_ERROR("Failed to find index for requested component: " << name.Data());
1496 return m_groups.size();
1497}
1498
1499std::string JetUncertaintiesTool::getComponentName(const size_t index) const
1500{
1501 if (!m_isInit)
1502 {
1503 ATH_MSG_FATAL("Tool must be initialized before calling getComponentName");
1504 return "";
1505 }
1506
1507 if (index < m_groups.size())
1508 return m_groups.at(index)->getName().Data();
1509
1510 ATH_MSG_ERROR("Index out of bounds for component name: " << index);
1511 return "";
1512}
1513
1514std::string JetUncertaintiesTool::getComponentDesc(const size_t index) const
1515{
1516 if (!m_isInit)
1517 {
1518 ATH_MSG_FATAL("Tool must be initialized before calling getComponentDesc");
1519 return "";
1520 }
1521
1522 if (index < m_groups.size())
1523 return m_groups.at(index)->getDesc().Data();
1524
1525 ATH_MSG_ERROR("Index out of bounds for component desc: " << index);
1526 return "";
1527}
1528
1530{
1531 if (!m_isInit)
1532 {
1533 ATH_MSG_FATAL("Tool must be initialized before calling getComponentCategory");
1534 return "";
1535 }
1536
1537 if (index < m_groups.size())
1538 return CompCategory::enumToString(m_groups.at(index)->getCategory()).Data();
1539
1540 ATH_MSG_ERROR("Index out of bounds for component category: " << index);
1541 return "";
1542}
1543
1545{
1546 if (!m_isInit)
1547 {
1548 ATH_MSG_FATAL("Tool must be initialized before calling getComponentIsReducible");
1549 return false;
1550 }
1551
1552 if (index < m_groups.size())
1553 return m_groups.at(index)->getIsReducible();
1554
1555 ATH_MSG_ERROR("Index out of bounds for component category: " << index);
1556 return false;
1557}
1558
1559StatusCode JetUncertaintiesTool::checkIndexInput(const size_t index) const
1560{
1561 if (!m_isInit)
1562 {
1563 ATH_MSG_FATAL("Tool must be initialized before asking for information pertaining to a given component index");
1564 return StatusCode::FAILURE;
1565 }
1566
1567 if (index >= m_groups.size())
1568 {
1569 ATH_MSG_ERROR(Form("Index out of bounds, asking for %zu in a container of size %zu",index,m_groups.size()));
1570 return StatusCode::FAILURE;
1571 }
1572
1573
1574 return StatusCode::SUCCESS;
1575}
1576
1577bool checkScalesSingleVar(const std::set<CompScaleVar::TypeEnum>& varSet, const CompScaleVar::TypeEnum var)
1578{
1579 return varSet.size() == 1 && *(varSet.begin()) == var;
1580}
1581
1583{
1584 if (checkIndexInput(index).isFailure()) return false;
1585 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::FourVec);
1586}
1588{
1589 if (checkIndexInput(index).isFailure()) return false;
1590 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Pt);
1591}
1593{
1594 if (checkIndexInput(index).isFailure()) return false;
1595 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Mass);
1596}
1598{
1599 if (checkIndexInput(index).isFailure()) return false;
1600 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::D12);
1601}
1603{
1604 if (checkIndexInput(index).isFailure()) return false;
1605 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::D23);
1606}
1608{
1609 if (checkIndexInput(index).isFailure()) return false;
1610 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Tau21);
1611}
1613{
1614 if (checkIndexInput(index).isFailure()) return false;
1615 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Tau32);
1616}
1618{
1619 if (checkIndexInput(index).isFailure()) return false;
1620 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Tau21WTA);
1621}
1623{
1624 if (checkIndexInput(index).isFailure()) return false;
1625 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Tau32WTA);
1626}
1628{
1629 if (checkIndexInput(index).isFailure()) return false;
1630 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::D2Beta1);
1631}
1633{
1634 if (checkIndexInput(index).isFailure()) return false;
1635 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::C2Beta1);
1636}
1638{
1639 if (checkIndexInput(index).isFailure()) return false;
1640 return checkScalesSingleVar(m_groups.at(index)->getScaleVars(),CompScaleVar::Qw);
1641}
1643{
1644 if (checkIndexInput(index).isFailure()) return false;
1646}
1648{
1649 if (checkIndexInput(index).isFailure()) return false;
1650 return m_groups.at(index)->getScaleVars().size() > 1;
1651}
1652std::set<CompScaleVar::TypeEnum> JetUncertaintiesTool::getComponentScaleVars(const size_t index) const
1653{
1654 if (checkIndexInput(index).isFailure()) return {};
1655 return m_groups.at(index)->getScaleVars();
1656}
1658{
1659 if (checkIndexInput(index).isFailure()) return JetTopology::UNKNOWN;
1660 return m_groups.at(index)->getTopology();
1661}
1662
1663
1669{
1671}
1673{
1674 const xAOD::EventInfo* eInfo = getDefaultEventInfo();
1675 if (!eInfo) return false;
1676 return getValidity(index,jet,*eInfo,scaleVar);
1677}
1678bool JetUncertaintiesTool::getValidity(size_t index, const xAOD::Jet& jet, const xAOD::EventInfo& eInfo, const CompScaleVar::TypeEnum scaleVar) const
1679{
1680 if (!m_isInit)
1681 {
1682 ATH_MSG_FATAL("Tool must be initialized before calling getValidity");
1683 return false;
1684 }
1685
1686 // Ensure we are within bounds
1687 if (index >= m_groups.size())
1688 {
1689 ATH_MSG_ERROR("Index out of bounds for validity: " << index);
1690 return false;
1691 }
1692
1693 // Check for a global validity histogram
1694 if (m_fileValidHist && !m_fileValidHist->getValidity(jet))
1695 return false;
1696
1697 // Deal with different possible scale types
1698 // If scaleVar is unknown, work if comp is just one type
1699 // If scaleVar is specified, request that specific type regardless
1700 if (scaleVar == CompScaleVar::UNKNOWN)
1701 {
1702 if (m_groups.at(index)->getScaleVars().size() != 1)
1703 {
1704 ATH_MSG_ERROR("Asked for the validity of a set which scales multiple variables without specifying the variable of interest:" << m_groups.at(index)->getName().Data());
1705 return false;
1706 }
1707 return m_groups.at(index)->getValidity(jet,eInfo,*(m_groups.at(index)->getScaleVars().begin()));
1708 }
1709 return m_groups.at(index)->getValidity(jet,eInfo,scaleVar);
1710}
1711
1712
1713
1719{
1721}
1723{
1724 const xAOD::EventInfo* eInfo = getDefaultEventInfo();
1725 if (!eInfo) return JESUNC_ERROR_CODE;
1726 return getUncertainty(index,jet,*eInfo,scaleVar);
1727}
1728double JetUncertaintiesTool::getUncertainty(size_t index, const xAOD::Jet& jet, const xAOD::EventInfo& eInfo, const CompScaleVar::TypeEnum scaleVar) const
1729{
1730 if (!m_isInit)
1731 {
1732 ATH_MSG_FATAL("Tool must be initialized before calling getUncertainty");
1733 return JESUNC_ERROR_CODE;
1734 }
1735
1736 // Ensure we are within bounds
1737 if (index >= m_groups.size())
1738 {
1739 ATH_MSG_ERROR("Index out of bounds for uncertainty: " << index);
1740 return JESUNC_ERROR_CODE;
1741 }
1742
1743 // Watch for a global validity histogram
1744 if (m_fileValidHist && !m_fileValidHist->getValidity(jet))
1745 {
1746 ATH_MSG_ERROR("Jet is out of validity bounds for uncertainty: " << index);
1747 return JESUNC_ERROR_CODE;
1748 }
1749
1750
1751 // Deal with different possible scale types
1752 // If scaleVar is unknown, work if comp is just one type
1753 // If scaleVar is specified, request that specific type regardless
1754 if (scaleVar == CompScaleVar::UNKNOWN)
1755 {
1756 if (m_groups.at(index)->getScaleVars().size() != 1)
1757 {
1758 ATH_MSG_ERROR("Asked for the uncertainty of a set which scales multiple variables without specifying the variable of interest:" << m_groups.at(index)->getName().Data());
1759 return JESUNC_ERROR_CODE;
1760 }
1761 return m_groups.at(index)->getUncertainty(jet,eInfo,*(m_groups.at(index)->getScaleVars().begin()));
1762 }
1763 return m_groups.at(index)->getUncertainty(jet,eInfo,scaleVar);
1764}
1765
1766
1767
1768bool JetUncertaintiesTool::getValidUncertainty(size_t index, double& unc, const xAOD::Jet& jet) const
1769{
1771}
1772bool JetUncertaintiesTool::getValidUncertainty(size_t index, double& unc, const xAOD::Jet& jet, const xAOD::EventInfo& eInfo) const
1773{
1774 return getValidUncertainty(index, unc, jet, eInfo, CompScaleVar::UNKNOWN);
1775}
1776bool JetUncertaintiesTool::getValidUncertainty(size_t index, double& unc, const xAOD::Jet& jet, const CompScaleVar::TypeEnum scaleVar) const
1777{
1778 const xAOD::EventInfo* eInfo = getDefaultEventInfo();
1779 if (!eInfo) return false;
1780 return getValidUncertainty(index,unc,jet,*eInfo,scaleVar);
1781}
1782bool JetUncertaintiesTool::getValidUncertainty(size_t index, double& unc, const xAOD::Jet& jet, const xAOD::EventInfo& eInfo, const CompScaleVar::TypeEnum scaleVar) const
1783{
1784 if (!m_isInit)
1785 {
1786 ATH_MSG_FATAL("Tool must be initialized before calling getValidUncertainty");
1787 return false;
1788 }
1789
1790 // Ensure we are within bounds
1791 if (index >= m_groups.size())
1792 {
1793 ATH_MSG_ERROR("Index out of bounds for valid uncertainty: " << index);
1794 return false;
1795 }
1796
1797 // Check for a global validity histogram
1798 if (m_fileValidHist && !m_fileValidHist->getValidity(jet))
1799 return false;
1800
1801
1802 // Deal with different possible scale types
1803 // If scaleVar is unknown, work if comp is just one type
1804 // If scaleVar is specified, request that specific type regardless
1805 if (scaleVar == CompScaleVar::UNKNOWN)
1806 {
1807 if (m_groups.at(index)->getScaleVars().size() != 1)
1808 {
1809 ATH_MSG_ERROR("Asked for the valid uncertainty of a set which scales multiple variables without specifying the variable of interest:" << m_groups.at(index)->getName().Data());
1810 return JESUNC_ERROR_CODE;
1811 }
1812 return m_groups.at(index)->getValidUncertainty(unc,jet,eInfo,*(m_groups.at(index)->getScaleVars().begin()));
1813 }
1814 return m_groups.at(index)->getValidUncertainty(unc,jet,eInfo,scaleVar);
1815}
1816
1817
1819{
1820 return getNominalResolution(jet,smearType,topology,true);
1821}
1822
1824{
1825 return getNominalResolution(jet,smearType,topology,false);
1826}
1827
1828double JetUncertaintiesTool::getNominalResolution(const xAOD::Jet& jet, const CompScaleVar::TypeEnum smearType, const JetTopology::TypeEnum topology, const bool readMC) const
1829{
1830 if (!m_isInit)
1831 {
1832 ATH_MSG_FATAL("Tool must be initialized before calling getNominalResolution");
1833 return JESUNC_ERROR_CODE;
1834 }
1835 if (!m_resHelper)
1836 {
1837 ATH_MSG_ERROR("The ResolutionHelper class was not created");
1838 return JESUNC_ERROR_CODE;
1839 }
1840
1841 // Get the nominal histogram, parametrization, and mass def (if relevant) from the helper
1842 std::tuple<const UncertaintyHistogram*,CompParametrization::TypeEnum,CompMassDef::TypeEnum> resolution = m_resHelper->getNominalResolution(smearType,topology,readMC);
1843
1844 // Check that we retrieved them successfully
1845 if (!std::get<0>(resolution) || std::get<1>(resolution) == CompParametrization::UNKNOWN)
1846 return JESUNC_ERROR_CODE;
1847 if (CompParametrization::includesMass(std::get<1>(resolution)) && std::get<2>(resolution) == CompMassDef::UNKNOWN)
1848 {
1849 // We should never reach this, as it was also checked during initialization
1850 ATH_MSG_ERROR("Parametrization involves mass but mass def is unknown");
1851 return JESUNC_ERROR_CODE;
1852 }
1853
1854 // Now read the uncertainty from the histogram
1855 return readHistoFromParam(jet,*std::get<0>(resolution),std::get<1>(resolution),std::get<2>(resolution));
1856}
1857
1858
1860{
1861 // Simple case (no mass dependence)
1863 return readHistoFromParam(jet.jetP4(),histo,param);
1864
1865 // Complex case (need to check the mass type to use)
1866 // Simple four-vector case
1867 if (massDef == CompMassDef::UNKNOWN || massDef == CompMassDef::FourVecMass)
1868 return readHistoFromParam(jet.jetP4(),histo,param);
1869 // Special scale case
1870 JetFourMomAccessor massScaleAccessor(CompMassDef::getJetScaleString(massDef).Data());
1871 return readHistoFromParam(massScaleAccessor(jet),histo,param);
1872}
1873
1875{
1876 double value = 0;
1877 switch (param)
1878 {
1880 value = histo.getValue(jet4vec.Pt()*m_energyScale);
1881 break;
1883 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.Eta());
1884 break;
1886 value = histo.getValue(jet4vec.Pt()*m_energyScale,fabs(jet4vec.Eta()));
1887 break;
1889 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()*m_energyScale);
1890 break;
1892 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()/jet4vec.Pt());
1893 break;
1895 value = histo.getValue(jet4vec.Pt()*m_energyScale,log(jet4vec.M()/jet4vec.Pt()));
1896 break;
1898 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()/jet4vec.Pt(),jet4vec.Eta());
1899 break;
1901 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()/jet4vec.Pt(),fabs(jet4vec.Eta()));
1902 break;
1904 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()*m_energyScale,jet4vec.Eta());
1905 break;
1907 value = histo.getValue(jet4vec.Pt()*m_energyScale,jet4vec.M()*m_energyScale,fabs(jet4vec.Eta()));
1908 break;
1910 value = histo.getValue(jet4vec.E()*m_energyScale,log(jet4vec.M()/jet4vec.E()));
1911 break;
1913 value = histo.getValue(jet4vec.E()*m_energyScale,log(jet4vec.M()/jet4vec.E()),jet4vec.Eta());
1914 break;
1916 value = histo.getValue(jet4vec.E()*m_energyScale,log(jet4vec.M()/jet4vec.E()),fabs(jet4vec.Eta()));
1917 break;
1918 default:
1919 ATH_MSG_ERROR("Failed to read histogram due to unknown parametrization type in " << getName());
1920 break;
1921 }
1922 return value;
1923}
1924
1925
1927{
1928 if (!m_caloMassWeight || !m_TAMassWeight) return 0;
1929
1932
1933 const double caloRes = m_caloMassWeight ? readHistoFromParam(caloScale(jet),*m_caloMassWeight,m_combMassParam) : 0;
1934 const double TARes = m_TAMassWeight ? readHistoFromParam(TAScale(jet),*m_TAMassWeight,m_combMassParam) : 0;
1935
1936 if (caloRes == 0 || TARes == 0) return 0;
1937
1938 const double caloFactor = (caloRes == 0) ? 0 : 1./(caloRes*caloRes);
1939 const double TAFactor = ( TARes == 0) ? 0 : 1./(TARes*TARes);
1940
1941 if (caloFactor + TAFactor == 0) return 0;
1942
1943 return caloFactor/(caloFactor+TAFactor);
1944}
1945
1947{
1948 if (!m_caloMassWeight || !m_TAMassWeight) return 0;
1949
1952
1953
1954 const double caloRes = m_caloMassWeight->getValue(caloScale.pt(jet)*m_energyScale,caloScale.m(jet)/caloScale.pt(jet) );
1955 const double TARes = m_TAMassWeight->getValue(TAScale.pt(jet)*m_energyScale,TAScale.m(jet)/TAScale.pt(jet));
1956
1957 if (caloRes == 0 || TARes == 0) return 0;
1958
1959 const double caloFactor = 1./(caloRes*caloRes);
1960 const double TAFactor = 1./(TARes*TARes);
1961
1962 if (caloFactor + TAFactor == 0) return 0;
1963
1964 return TAFactor/(caloFactor+TAFactor);
1965}
1966
1968// //
1969// Mulit-component retrieval methods //
1970// //
1972
1973std::vector<std::string> JetUncertaintiesTool::getComponentCategories() const
1974{
1975 if (!m_isInit)
1976 {
1977 ATH_MSG_FATAL("Tool must be initialized before calling getComponentCategories");
1978 return {};
1979 }
1980
1981 // Internally use a set for speed
1982 // Use std::string rather than CompCategory::TypeEnum because std::string has a hash
1983 // Hashed access should mean there is no speed difference between using the two types
1984 std::unordered_set<std::string> categories;
1985 for (size_t iComp = 0; iComp < m_groups.size(); ++iComp)
1986 categories.insert(CompCategory::enumToString(m_groups.at(iComp)->getCategory()).Data());
1987
1988 // Convert the set to a vector
1989 std::vector<std::string> categoryStrings;
1990 for (std::unordered_set<std::string>::const_iterator iter = categories.begin() ; iter != categories.end(); ++iter)
1991 categoryStrings.push_back(*iter);
1992
1993 return categoryStrings;
1994}
1995
1996std::vector<size_t> JetUncertaintiesTool::getComponentsInCategory(const std::string& category) const
1997{
1998 if (!m_isInit)
1999 {
2000 ATH_MSG_FATAL("Tool must be initialized before calling getComponentsInCategory");
2001 return {};
2002 }
2003
2004 // Internally conver to an enum for both checking and speed of comparison
2005 const CompCategory::TypeEnum categoryEnum = CompCategory::stringToEnum(category.c_str());
2006 if (categoryEnum == CompCategory::UNKNOWN)
2007 {
2008 ATH_MSG_WARNING("Unrecognized category: " << category);
2009 return {};
2010 }
2011
2012 // Now find the components
2013 std::vector<size_t> components;
2014 for (size_t iComp = 0; iComp < m_groups.size(); ++iComp)
2015 if (m_groups.at(iComp)->getCategory() == categoryEnum)
2016 components.push_back(iComp);
2017
2018 return components;
2019}
2020
2021std::vector<std::string> JetUncertaintiesTool::getComponentNamesInCategory(const std::string& category) const
2022{
2023 if (!m_isInit)
2024 {
2025 ATH_MSG_FATAL("Tool must be initialized before calling getComponentNamesInCategory");
2026 return {};
2027 }
2028
2029 std::vector<size_t> components = getComponentsInCategory(category);
2030 std::vector<std::string> names;
2031 for (size_t iComp = 0; iComp < components.size(); ++iComp)
2032 names.push_back(getComponentName(components.at(iComp)));
2033
2034 return names;
2035}
2036
2037
2039// //
2040// Methods to build the correlation matrix //
2041// //
2043
2044TH2D* JetUncertaintiesTool::getPtCorrelationMatrix(const int numBins, const double minPt, const double maxPt, const double valEta)
2045{
2046 return getPtCorrelationMatrix(numBins,minPt,maxPt,valEta,valEta);
2047}
2048
2049TH2D* JetUncertaintiesTool::getPtCorrelationMatrix(const int numBins, const double minPt, const double maxPt, const double valEta1, const double valEta2)
2050{
2051 if (!m_isInit)
2052 {
2053 ATH_MSG_FATAL("Tool must be initialized before calling getCorrelationMatrix");
2054 return nullptr;
2055 }
2056
2057 std::cout << "Creating with max values " << valEta1 << " " << valEta2 << std::endl;
2058 CorrelationMatrix corrMat(Form("%s_varpt_eta%.2f_eta%.2f",m_name.c_str(),valEta1,valEta2),numBins,minPt*m_energyScale,maxPt*m_energyScale,valEta1,valEta2);
2059 if (corrMat.initializeForPt(*this).isFailure())
2060 return nullptr;
2061 return new TH2D(*corrMat.getMatrix());
2062}
2063
2064TH2D* JetUncertaintiesTool::getEtaCorrelationMatrix(const int numBins, const double minEta, const double maxEta, const double valPt)
2065{
2066 return getEtaCorrelationMatrix(numBins,minEta,maxEta,valPt,valPt);
2067}
2068
2069TH2D* JetUncertaintiesTool::getEtaCorrelationMatrix(const int numBins, const double minEta, const double maxEta, const double valPt1, const double valPt2)
2070{
2071 if (!m_isInit)
2072 {
2073 ATH_MSG_FATAL("Tool must be initialized before calling getCorrelationMatrix");
2074 return nullptr;
2075 }
2076
2077 CorrelationMatrix corrMat(Form("%s_vareta_pt%.1f_pt%.1f",m_name.c_str(),valPt1/1.e3,valPt2/1.e3),numBins,minEta,maxEta,valPt1*m_energyScale,valPt2*m_energyScale);
2078 if (corrMat.initializeForEta(*this).isFailure())
2079 return nullptr;
2080 return new TH2D(*corrMat.getMatrix());
2081}
2082
2083
2085// //
2086// Methods to apply variations or get a copy //
2087// //
2089
2096
2098{
2099 if (!m_isInit)
2100 {
2101 ATH_MSG_FATAL("Tool must be initialized before calling applyCorrection");
2103 }
2104
2105 // Check for a global validity histogram
2106 if (m_fileValidHist && !m_fileValidHist->getValidity(jet)){
2108 }
2109
2110 // Scale the jet and/or its moments by the uncertainty/uncertainties
2111 // Note that uncertainties may be either positive or negative
2112 // Make sure to check the validity at the same time
2113 std::vector< std::pair<CompScaleVar::TypeEnum,double> > uncSet;
2114 const std::vector< std::pair<CompScaleVar::TypeEnum,bool> > validitySet = m_currentUncSet->getValidUncertaintySet(uncSet,jet,eInfo);
2115
2116 // Ensure every case was successful
2117 bool allValid = true;
2118 for (size_t iVar = 0; iVar < validitySet.size(); ++iVar)
2119 {
2120 const bool validity = validitySet.at(iVar).second;
2121
2122 if (!validity)
2123 {
2124 allValid = false;
2125 // Disabled following email from Karsten Koeneke on Jan 28 2016: ATLAS rule is no error messages for out of validity range
2126 //const CompScaleVar::TypeEnum scaleVar = validitySet.at(iVar).first;
2127 //ATH_MSG_ERROR("Uncertainty configuration is not valid for the specified jet when attempting to scale " << CompScaleVar::enumToString(scaleVar).Data() << ". Set: " << m_currentUncSet->getName());
2128 }
2129 }
2130 if (!allValid)
2132
2133 // Ensure that we don't mix relative and absolute resolution uncertainties of the same type
2134 // Such situations violate the current code structure
2135 std::vector<CompScaleVar::TypeEnum> scaleVars = m_currentUncSet->getScaleVars();
2136 bool hasMassRes = false;
2137 bool hasPtRes = false;
2138 bool hasFvRes = false;
2139 for (CompScaleVar::TypeEnum var : scaleVars)
2140 {
2142 {
2143 if (hasMassRes)
2144 {
2145 ATH_MSG_ERROR("Varying both absolute and relative mass resolution components simultaneously is not supported");
2147 }
2148 else
2149 hasMassRes = true;
2150 }
2151 else if (var == CompScaleVar::PtRes || var == CompScaleVar::PtResAbs)
2152 {
2153 if (hasPtRes)
2154 {
2155 ATH_MSG_ERROR("Varying both absolute and relative pT resolution components simultaneously is not supported");
2157 }
2158 else
2159 hasPtRes = true;
2160 }
2161 else if (var == CompScaleVar::FourVecRes || var == CompScaleVar::FourVecResAbs)
2162 {
2163 if (hasFvRes)
2164 {
2165 ATH_MSG_ERROR("Varying both absolute and relative four-vector resolution components simultaneously is not supported");
2167 }
2168 else
2169 hasFvRes = true;
2170 }
2171 }
2172
2173 // Handle each case as needed
2174 for (size_t iVar = 0; iVar < uncSet.size(); ++iVar)
2175 {
2176 const CompScaleVar::TypeEnum scaleVar = uncSet.at(iVar).first;
2177 //const double unc = uncSet.at(iVar).second;
2178 const double shift = 1 + uncSet.at(iVar).second;
2179 const double smear = uncSet.at(iVar).second;
2180
2181 // Careful of const vs non-const objects with accessors
2182 // Can unintentionally create something new which didn't exist, as jet is non-const
2183 double smearingFactor = 1;
2184 switch (scaleVar)
2185 {
2187 jet.setJetP4(xAOD::JetFourMom_t(shift*jet.pt(),jet.eta(),jet.phi(),shift*jet.m()));
2188 break;
2189 case CompScaleVar::Pt:
2190 jet.setJetP4(xAOD::JetFourMom_t(shift*jet.pt(),jet.eta(),jet.phi(),jet.m()));
2191 break;
2192 case CompScaleVar::Mass:
2193 jet.setJetP4(xAOD::JetFourMom_t(jet.pt(),jet.eta(),jet.phi(),shift*jet.m()));
2194 break;
2195 case CompScaleVar::D12:
2196 if (updateSplittingScale12(jet,shift).isFailure())
2198 break;
2199 case CompScaleVar::D23:
2200 if (updateSplittingScale23(jet,shift).isFailure())
2202 break;
2204 if (updateTau21(jet,shift).isFailure())
2206 break;
2208 if (updateTau32(jet,shift).isFailure())
2210 break;
2212 if (updateTau21WTA(jet,shift).isFailure())
2214 break;
2216 if (updateTau32WTA(jet,shift).isFailure())
2218 break;
2220 if (updateD2Beta1(jet,shift).isFailure())
2222 break;
2224 if (updateC2Beta1(jet,shift).isFailure())
2226 break;
2227 case CompScaleVar::Qw:
2228 if (updateQw(jet,shift).isFailure())
2230 break;
2232 if (updateTagScaleFactor(jet,shift).isFailure())
2234 break;
2236 if (updateTagEfficiency(jet,uncSet.at(iVar).second).isFailure())
2238 break;
2241 if (m_currentUncSet->getTopology() == JetTopology::UNKNOWN)
2242 {
2243 // The JMR requires that there is a topology specified
2244 // (JMR uncertainties are topology-specific)
2245 ATH_MSG_ERROR("Smearing the mass without specifying the topology is not supported");
2247 }
2248 if (m_currentUncSet->getTopology() == JetTopology::MIXED)
2249 {
2250 // We can't handle multi-topology JMR uncertainties
2251 ATH_MSG_ERROR("Smearing the mass using multiple topology definitions is not supported");
2253 }
2254 smearingFactor = getSmearingFactor(jet,scaleVar,smear);
2255 jet.setJetP4(xAOD::JetFourMom_t(jet.pt(),jet.eta(),jet.phi(),smearingFactor*jet.m()));
2256 break;
2259 smearingFactor = getSmearingFactor(jet,scaleVar,smear);
2260 jet.setJetP4(xAOD::JetFourMom_t(smearingFactor*jet.pt(),jet.eta(),jet.phi(),jet.m()));
2261 break;
2264 smearingFactor = getSmearingFactor(jet,scaleVar,smear);
2265 jet.setJetP4(xAOD::JetFourMom_t(smearingFactor*jet.pt(),jet.eta(),jet.phi(),smearingFactor*jet.m()));
2266 break;
2267 default:
2268 ATH_MSG_ERROR("Asked to scale an UNKNOWN variable for set: " << m_currentUncSet->getName());
2270 }
2271 }
2272
2274}
2275
2277{
2278 const xAOD::EventInfo* eInfo = getDefaultEventInfo();
2279 if (!eInfo) return CP::CorrectionCode::Error;
2280 return correctedCopy(input,output,*eInfo);
2281}
2282
2284{
2285 xAOD::Jet* copy = new xAOD::Jet(input);
2286
2287 // Call the implemented function
2288 if (applyCorrection(*copy,eInfo) != CP::CorrectionCode::Ok)
2289 {
2290 delete copy;
2292 }
2293 output = copy;
2295}
2296
2303
2305{
2307
2308 // Loop over the container
2309 for (size_t iJet = 0; iJet < inputs.size(); ++iJet)
2310 {
2311 result = applyCorrection(*inputs.at(iJet),eInfo);
2313 break;
2314 }
2315 return result;
2316}
2317
2319{
2320 // Define static EventInfo objects
2321 // Unfortunately this is messy, but needed as we are caching across tool calls
2322 // Using voltatile class variables doesn't work well as we need to return a const object
2323 // Interesting enough, the shallow copy link is updated when evtStore()->retrieve() is called
2324 // As such, just retrieving the new EventInfo object updates this copy
2325 // We therefore need to also store our own local copy of the eventNumber
2326 static xAOD::EventInfo* eInfoObj = nullptr;
2327 static xAOD::ShallowAuxContainer* eInfoAux = nullptr;
2328 static unsigned long long eventNum = 0;
2329 static const SG::AuxElement::Accessor<float> accNPV("NPV");
2330
2331 // Retrieve the EventInfo object
2332 const xAOD::EventInfo* eInfoConst = nullptr;
2333 if (evtStore()->retrieve(eInfoConst,"EventInfo").isFailure())
2334 {
2335 ATH_MSG_ERROR("Failed to retrieve default EventInfo object");
2336 return nullptr;
2337 }
2338
2339 // Check if this is a new event or if we can re-use the existing EventInfo object
2340 if (eInfoObj && eventNum == eInfoConst->eventNumber())
2341 return eInfoObj;
2342 eventNum = eInfoConst->eventNumber();
2343
2344 // It's a new event, get rid of the old object and build a new one
2345 JESUNC_SAFE_DELETE(eInfoObj);
2346 JESUNC_SAFE_DELETE(eInfoAux);
2347
2348 // Make a shallow copy
2349 std::pair<xAOD::EventInfo*,xAOD::ShallowAuxContainer*> eInfoPair = xAOD::shallowCopyObject(*eInfoConst);
2350 eInfoObj = eInfoPair.first;
2351 eInfoAux = eInfoPair.second;
2352
2353 // Check if NPV already exists on const EventInfo object, return if so
2354 if (accNPV.isAvailable(*eInfoConst))
2355 return eInfoObj;
2356
2357 // NPV doesn't already exist, so calculate it
2358 const xAOD::VertexContainer* vertices = nullptr;
2359 if (evtStore()->retrieve(vertices,"PrimaryVertices").isFailure())
2360 {
2361 ATH_MSG_ERROR("Failed to retrieve default NPV value from PrimaryVertices");
2362 JESUNC_SAFE_DELETE(eInfoObj);
2363 JESUNC_SAFE_DELETE(eInfoAux);
2364 return nullptr;
2365 }
2366
2367 unsigned NPV = 0;
2369 for (itr = vertices->begin(); itr != vertices->end(); ++itr)
2370 if ( (*itr)->nTrackParticles() > 1)
2371 NPV++;
2372
2373 // Add NPV to the shallow copy EventInfo object
2374 accNPV(*eInfoObj) = NPV;
2375
2376 // Done, return EventInfo decorated with NPV
2377 return eInfoObj;
2378}
2379
2380
2381
2382
2383double JetUncertaintiesTool::getSmearingFactor(const xAOD::Jet& jet, const CompScaleVar::TypeEnum smearType, const double variation) const
2384{
2385 /*
2386 Below follows discussion between B Malaescu, C Young, and S Schramm on 14/08/2018
2387
2388 sigma_smear^2 = (sigma_nominal + |n*x + m*y + ...|)^2 - (sigma_nominal)^2
2389 sigma_smear: width of the Gaussian to smear with
2390 sigma_nominal: the nominal resolution in either (pseudo-)data OR mc (see below)
2391 n: #sigma variation for NP1
2392 m: #sigma variation for NP2
2393 x: uncertainty from NP1
2394 y: uncertainty from NP2
2395 Note that n,m,x,y all are signed quantities
2396 n,m are + for upward variations and - for downward variations
2397 x,y are + or - to differentiate regions of anticorrelations within a given NP
2398
2399 As the MC has been smeared to the data in JetCalibTools and we have saved the histograms
2400 before this smearing has been applied we need to take the maximum of the data and MC
2401 resolutions to find the nominal resolution which to smear against. For cases when the data
2402 resolution is better than that in simulation and we additionally are using data as
2403 pseudo-data (extremely rare in analyses) this might result in a slightly more conservative
2404 uncertainty.
2405 sigma_nominal = max(sigma_MC,sigma_data)
2406
2407 In some cases, it is not desireable to smear (pseudo-)data
2408 Result: two correlation smearing options, "full" and "simple"
2409 Full = full correlations preserved, smear both (peudo-)data and MC
2410 Simple = simplified correlations (= loss of correlations), smear only MC
2411
2412 In "simple" case, we are smearing MC even if we should ideally smear (pseudo-)data
2413 sign(nx+my+...) --> no longer matters, always use sigma_nominal^MC
2414 Furthermore, take the absolute value as we are forcing an upward variation
2415 sigma_smear^2 = (sigma_nom^MC + |n*x + m*y + ...|)^2 - (sigma_nom^MC)^2
2416 In the case of 1 NP, analysis gets same result if n is positive or negative
2417 Analysis must symmetrize uncertainties themselves to get downward variations
2418
2419 The above is all for absolute resolution uncertainties
2420 In the case of relative resolution uncertainties, not much changes
2421 n*x --> n*sigma_nominal*x
2422 n: unchanged from before, #sigma variation for NP1
2423 x: now this is a fractional uncertainty, but it is still the value of NP1
2424 sigma_nominal: uncertainty measurement varies (sign unaffected by nominal)
2425 In other words, all of the above is directly extended
2426
2427 This all relies on the fact that absolute and relative resolutions are not mixed
2428 This is enforced by the tool enums, which are one or the other
2429 Asking for both relative and absolute smearing is two separate scale variables
2430 The tool checks for such cases and explicitly blocks them
2431
2432 There is one exception to the above: a "data-MC difference" smearing
2433 If MC is below data, then we smear MC to match data (nominal smearing)
2434 Occurs if (sigma_nom^MC - sigma_nom^data) < 0, or equivalently (sigma_nom^data - sigma_nom^MC) > 0
2435 If data is below MC, we don't want to degrade the resolution of data to match MC
2436 Occurs if (sigma_nom^MC - sigma_nom^data) > 0, or equivalently (sigma_nom^data - sigma_nom^MC) < 0
2437 We also can't anti-smear MC (at least not with Gaussian smearing)
2438 Instead, smear by sigma_smear^2 = (sigma_nom + |Nsigma*[sigma_nom^data - sigma_nom^MC]|)^2 - (sigma_nom)^2
2439 This uses the second form of the above inequalities to stick with convention
2440 This way, we signify that we are smearing data (uncertainty < 0 if Nsigma > 0)
2441 This should be smearing of data (sigma_nom = sigma_nom^data)
2442 However, in the simple scenario, we still only smear MC
2443 Apply the uncertainty as-is, with sigma_nom = sigma_nom^MC
2444 This is actually "conservative" (in magnitude, not necessarily in correlations)
2445 |Nsigma*(sigma_nom^data - sigma_nom^MC)| is a fixed value independent of choice, call it X
2446 sigma_smear^2 = (sigma_nom + X)^2 - (sigma_nom)^2
2447 sigma_smear^2 = sigma_nom^2 [ (1 + X/sigma_nom)^2 - 1 ]
2448 Taylor expand: sigma_smear^2 ~ sigma_nom^2 ( 1 + 2*X/sigma_nom - 1 )
2449 sigma_smear^2 ~ sigma_nom^2 * 2 X / sigma_nom
2450 sigma_smear^2 ~ sigma_nom * 2 X
2451 Therefore, larger sigma_nom --> larger sigma_smear
2452 In this case, we know that sigma_nom^MC > sigma_nom^data (motivation for uncertainty)
2453 As such, sigma_nom = sigma_nom^MC is conservative
2454 This does not need to be handled any different than other uncertainties in the code
2455 However, the inputs will need to be made carefully to do the correct thing
2456 In particular, smear data occurs if sign(unc) < 0
2457 That is why it is written above as (sigma_nom^data - sigma_nom^MC) < 0
2458 In other words, the histogram must be created to be <= 0
2459 It should be <0 when data is below MC, and =0 when data is above MC
2460 This *could* be calculated on-the-fly from the two nominal histograms
2461 This requires substantial code development, as now this one NP is different from all others
2462 In the interest of time and code re-use, instead demand an extra histogram input
2463
2464 In the end, smear by a Gaussian of mean 1 and width sigma_smear
2465
2466 ----------
2467
2468 Given this, the arguments to the function are:
2469 jet: jet to smear, needed for the kinematic dependence of nominal resolutions
2470 smearType: the resolution type to select the relevant nominal resolutions
2471 variation: the signed value of n*x + m*y + ... (for both relative and absolute)
2472
2473 Dedicated class member variables used by this function are:
2474 m_isData: needed to control whether or not to smear the jet
2475 m_resHelper: contains lots of global resolution information
2476 - Whether to smear MC and data, or only MC
2477 - Nominal resolution histograms for data
2478 - Nominal resolution histograms for MC
2479 - Parametrizations of nominal resolution histograms
2480 m_rand: the random number generator
2481 m_userSeed: the optional user-specified seed to use for the random generator
2482
2483 Technical detail on relative uncertainties:
2484 The input value of "variation" is always n*x + m*y + ...
2485 This is trivially correct for absolute uncertainties, but not relative
2486 However, for relative uncertainties, all NPs are with respect to same nominal
2487 As such, it factors out, and we can take variation*sigma_nominal^data
2488 Furthermore, as it factors out, the nominal doesn't matter to determine the sign
2489 This is important as the sign sets whether data or MC is the nominal
2490 */
2491
2492 // Check if we need to do anything at all
2493 if (variation == 0)
2494 return 1; // No smearing if the variation is 0
2495 else if (m_isData)
2496 {
2497 if (m_resHelper->smearOnlyMC())
2498 return 1; // No smearing if this is data and we are in the simple scenario
2499 if (variation > 0)
2500 return 1; // No smearing if this is data and the sign says to smear MC
2501 }
2502 else if (variation < 0 && !m_resHelper->smearOnlyMC())
2503 return 1; // No smearing if this is MC and the sign says to smear data and this is not the simple scenario
2504
2505 // Get the relevant nominal resolution
2506 const double sigmaMC = getNominalResolution(jet,smearType,m_currentUncSet->getTopology(),true);
2507 const double sigmaData = getNominalResolution(jet,smearType,m_currentUncSet->getTopology(),false);
2508 const double sigmaNom = std::max(sigmaMC,sigmaData);
2509
2510 // If this is a relative uncertainty, get the relevant nominal data histogram
2511 // This is used to scale the input relative variation to get the absolute impact
2512 const double relativeFactor = CompScaleVar::isRelResolutionType(smearType) ? sigmaNom : 1;
2513
2514 // We now have the required information, so let's calculate the smearing factor
2515 // Note that relativeFactor is 1 if this is an absolute uncertainty
2516 const double sigmaSmear = sqrt(pow(sigmaNom + fabs(variation)*relativeFactor,2) - pow(sigmaNom,2));
2517
2518 // Throw an error if the userSeed is set to 1 as this is the seed used in JetCalibTools so leads to correlated smearing
2519 if (m_userSeed == 1){
2520 ATH_MSG_ERROR("A seed of 1e5 times the jet phi is used in JetCalibTools so using it here leads to correlated smearing");
2521 return 0;
2522 }
2523
2524 // We have the smearing factor, so prepare to smear
2525 // If the user specified a seed, then use it times the jet's phi times 1*10^5
2526 // If not, then use the jet's phi times 2*10^5 in MC, 1.23*10^5 in (pseudo-)data
2527 // Difference in seed between allows for easy use of pseudo-data
2528 long long int seed = m_userSeed != 0 ? m_userSeed*1.00e+5*fabs(jet.phi()) : (m_isData ? 1.23e+5 : 2.00e+5)*fabs(jet.phi());
2529 // SetSeed(0) uses the clock, avoid this
2530 if(seed == 0) seed = m_isData ? 34545654 : 45583453; // arbitrary numbers which the seed couldn't otherwise be
2531 m_rand.SetSeed(seed);
2532
2533 // Calculate and return the smearing factor
2534 // Force this to be a positive value
2535 // Negative values should be extraordinarily rare, but they do exist
2536 double smearingFactor = -1;
2537 while (smearingFactor < 0)
2538 smearingFactor = m_rand.Gaus(1.,sigmaSmear);
2539 return smearingFactor;
2540}
2541
2542
2543
2544
2545
2546
2547
2548
2549StatusCode JetUncertaintiesTool::updateSplittingScale12(xAOD::Jet& jet, const double shift) const
2550{
2551 static const SG::AuxElement::Accessor<float> accD12("Split12");
2552
2553 const xAOD::Jet& constJet = jet;
2554 if (accD12.isAvailable(constJet))
2555 {
2556 const float value = accD12(constJet);
2557 accD12(jet) = shift*value;
2558 return StatusCode::SUCCESS;
2559 }
2560
2561 ATH_MSG_ERROR("Split12 moment (D12) is not available on the jet, please make sure to set Split12 before calling the tool");
2562 return StatusCode::FAILURE;
2563}
2564
2565StatusCode JetUncertaintiesTool::updateSplittingScale23(xAOD::Jet& jet, const double shift) const
2566{
2567 static const SG::AuxElement::Accessor<float> accD23("Split23");
2568
2569 const xAOD::Jet& constJet = jet;
2570 if (accD23.isAvailable(constJet))
2571 {
2572 const float value = accD23(constJet);
2573 accD23(jet) = shift*value;
2574 return StatusCode::SUCCESS;
2575 }
2576
2577 ATH_MSG_ERROR("Split23 moment (D23) is not available on the jet, please make sure to set Split23 before calling the tool");
2578 return StatusCode::FAILURE;
2579}
2580
2581StatusCode JetUncertaintiesTool::updateTau21(xAOD::Jet& jet, const double shift) const
2582{
2583 static const SG::AuxElement::Accessor<float> accTau1("Tau1");
2584 static const SG::AuxElement::Accessor<float> accTau2("Tau2");
2585 static const SG::AuxElement::Accessor<float> accTau21("Tau21");
2586 static const bool Tau21wasAvailable = accTau21.isAvailable(jet);
2587 static const bool TauNNwasAvailable = accTau2.isAvailable(jet) && accTau1.isAvailable(jet);
2588
2589 const xAOD::Jet& constJet = jet;
2590 if (Tau21wasAvailable)
2591 {
2592 if (!accTau21.isAvailable(jet))
2593 {
2594 ATH_MSG_ERROR("The Tau21 moment was previously available but is not available on this jet. This functionality is not supported.");
2595 return StatusCode::FAILURE;
2596 }
2597 const float value = accTau21(constJet);
2598 accTau21(jet) = shift*value;
2599 return StatusCode::SUCCESS;
2600 }
2601 if (TauNNwasAvailable)
2602 {
2603 if (! (accTau2.isAvailable(jet) && accTau1.isAvailable(jet)) )
2604 {
2605 ATH_MSG_ERROR("The Tau2 and Tau1 moments were previously available but are not available on this jet. This functionality is not supported.");
2606 return StatusCode::FAILURE;
2607 }
2608 const float tau2 = accTau2(constJet);
2609 const float tau1 = accTau1(constJet);
2610 accTau21(jet) = fabs(tau1) > 1.e-6 ? shift*(tau2/tau1) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2611 return StatusCode::SUCCESS;
2612 }
2613 //if (accTau21.isAvailable(constJet))
2614 //{
2615 // const float value = accTau21(constJet);
2616 // accTau21(jet) = shift*value;
2617 // return StatusCode::SUCCESS;
2618 //}
2619 //if (accTau1.isAvailable(constJet) && accTau2.isAvailable(constJet))
2620 //{
2621 // const float value = accTau2(constJet)/accTau1(constJet);
2622 // accTau21(jet) = shift*value;
2623 // return StatusCode::SUCCESS;
2624 //}
2625
2626 ATH_MSG_ERROR("Neither Tau21 nor Tau1+Tau2 moments are available on the jet, please make sure one of these options is available before calling the tool.");
2627 return StatusCode::FAILURE;
2628}
2629
2630StatusCode JetUncertaintiesTool::updateTau32(xAOD::Jet& jet, const double shift) const
2631{
2632 static const SG::AuxElement::Accessor<float> accTau2("Tau2");
2633 static const SG::AuxElement::Accessor<float> accTau3("Tau3");
2634 static const SG::AuxElement::Accessor<float> accTau32("Tau32");
2635 static const bool Tau32wasAvailable = accTau32.isAvailable(jet);
2636 static const bool TauNNwasAvailable = accTau3.isAvailable(jet) && accTau2.isAvailable(jet);
2637
2638 const xAOD::Jet& constJet = jet;
2639 if (Tau32wasAvailable)
2640 {
2641 if (!accTau32.isAvailable(jet))
2642 {
2643 ATH_MSG_ERROR("The Tau32 moment was previously available but is not available on this jet. This functionality is not supported.");
2644 return StatusCode::FAILURE;
2645 }
2646 const float value = accTau32(constJet);
2647 accTau32(jet) = shift*value;
2648 return StatusCode::SUCCESS;
2649 }
2650 if (TauNNwasAvailable)
2651 {
2652 if (! (accTau3.isAvailable(jet) && accTau2.isAvailable(jet)) )
2653 {
2654 ATH_MSG_ERROR("The Tau3 and Tau2 moments were previously available but are not available on this jet. This functionality is not supported.");
2655 return StatusCode::FAILURE;
2656 }
2657 const float tau3 = accTau3(constJet);
2658 const float tau2 = accTau2(constJet);
2659 accTau32(jet) = fabs(tau2) > 1.e-6 ? shift*(tau3/tau2) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2660 return StatusCode::SUCCESS;
2661 }
2662 //if (accTau32.isAvailable(constJet))
2663 //{
2664 // const float value = accTau32(constJet);
2665 // accTau32(jet) = shift*value;
2666 // return StatusCode::SUCCESS;
2667 //}
2668 //if (accTau2.isAvailable(constJet) && accTau3.isAvailable(constJet))
2669 //{
2670 // const float value = accTau3(constJet)/accTau2(constJet);
2671 // accTau32(jet) = shift*value;
2672 // return StatusCode::SUCCESS;
2673 //}
2674
2675 ATH_MSG_ERROR("Neither Tau32 nor Tau2+Tau3 moments are available on the jet, please make sure one of these options is available before calling the tool");
2676 return StatusCode::FAILURE;
2677}
2678
2679StatusCode JetUncertaintiesTool::updateTau21WTA(xAOD::Jet& jet, const double shift) const
2680{
2681 static const SG::AuxElement::Accessor<float> accTau1wta("Tau1_wta");
2682 static const SG::AuxElement::Accessor<float> accTau2wta("Tau2_wta");
2683 static const SG::AuxElement::Accessor<float> accTau21wta("Tau21_wta");
2684 static const SG::AuxElement::Accessor<float> accTau1WTA("Tau1_WTA");
2685 static const SG::AuxElement::Accessor<float> accTau2WTA("Tau2_WTA");
2686 static const SG::AuxElement::Accessor<float> accTau21WTA("Tau21_WTA");
2687 static const bool Tau21wtawasAvailable = accTau21wta.isAvailable(jet);
2688 static const bool Tau21WTAwasAvailable = accTau21WTA.isAvailable(jet);
2689 static const bool TauNNwtawasAvailable = accTau2wta.isAvailable(jet) && accTau1wta.isAvailable(jet);
2690 static const bool TauNNWTAwasAvailable = accTau2WTA.isAvailable(jet) && accTau1WTA.isAvailable(jet);
2691
2692 const xAOD::Jet& constJet = jet;
2693 if (Tau21wtawasAvailable)
2694 {
2695 if (!accTau21wta.isAvailable(jet))
2696 {
2697 ATH_MSG_ERROR("The Tau21_wta moment was previously available but is not available on this jet. This functionality is not supported.");
2698 return StatusCode::FAILURE;
2699 }
2700 const float value = accTau21wta(constJet);
2701 accTau21wta(jet) = shift*value;
2702 return StatusCode::SUCCESS;
2703 }
2704 if (Tau21WTAwasAvailable)
2705 {
2706 if (!accTau21WTA.isAvailable(jet))
2707 {
2708 ATH_MSG_ERROR("The Tau21_WTA moment was previously available but is not available on this jet. This functionality is not supported.");
2709 return StatusCode::FAILURE;
2710 }
2711 const float value = accTau21WTA(constJet);
2712 accTau21WTA(jet) = shift*value;
2713 return StatusCode::SUCCESS;
2714 }
2715 if (TauNNwtawasAvailable)
2716 {
2717 if (! (accTau2wta.isAvailable(jet) && accTau1wta.isAvailable(jet)) )
2718 {
2719 ATH_MSG_ERROR("The Tau2_wta and Tau1_wta moments were previously available but are not available on this jet. This functionality is not supported.");
2720 return StatusCode::FAILURE;
2721 }
2722 const float tau2 = accTau2wta(constJet);
2723 const float tau1 = accTau1wta(constJet);
2724 accTau21wta(jet) = fabs(tau1) > 1.e-6 ? shift*(tau2/tau1) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2725 return StatusCode::SUCCESS;
2726 }
2727 if (TauNNWTAwasAvailable)
2728 {
2729 if (! (accTau2WTA.isAvailable(jet) && accTau1WTA.isAvailable(jet)) )
2730 {
2731 ATH_MSG_ERROR("The Tau2_WTA and Tau1_WTA moments were previously available but are not available on this jet. This functionality is not supported.");
2732 return StatusCode::FAILURE;
2733 }
2734 const float tau2 = accTau2WTA(constJet);
2735 const float tau1 = accTau1WTA(constJet);
2736 accTau21WTA(jet) = fabs(tau1) > 1.e-6 ? shift*(tau2/tau1) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2737 return StatusCode::SUCCESS;
2738 }
2739
2740 ATH_MSG_ERROR("Neither Tau21_wta nor Tau1_wta+Tau2_wta moments are available on the jet, please make sure one of these options is available before calling the tool");
2741 return StatusCode::FAILURE;
2742}
2743StatusCode JetUncertaintiesTool::updateTau32WTA(xAOD::Jet& jet, const double shift) const
2744{
2745 static const SG::AuxElement::Accessor<float> accTau2wta("Tau2_wta");
2746 static const SG::AuxElement::Accessor<float> accTau3wta("Tau3_wta");
2747 static const SG::AuxElement::Accessor<float> accTau32wta("Tau32_wta");
2748 static const SG::AuxElement::Accessor<float> accTau2WTA("Tau2_WTA");
2749 static const SG::AuxElement::Accessor<float> accTau3WTA("Tau3_WTA");
2750 static const SG::AuxElement::Accessor<float> accTau32WTA("Tau32_WTA");
2751 static const bool Tau32wtawasAvailable = accTau32wta.isAvailable(jet);
2752 static const bool Tau32WTAwasAvailable = accTau32WTA.isAvailable(jet);
2753 static const bool TauNNwtawasAvailable = accTau3wta.isAvailable(jet) && accTau2wta.isAvailable(jet);
2754 static const bool TauNNWTAwasAvailable = accTau3WTA.isAvailable(jet) && accTau2WTA.isAvailable(jet);
2755
2756 const xAOD::Jet& constJet = jet;
2757 if (Tau32wtawasAvailable)
2758 {
2759 if (!accTau32wta.isAvailable(jet))
2760 {
2761 ATH_MSG_ERROR("The Tau32_wta moment was previously available but is not available on this jet. This functionality is not supported.");
2762 return StatusCode::FAILURE;
2763 }
2764 const float value = accTau32wta(constJet);
2765 accTau32wta(jet) = shift*value;
2766 return StatusCode::SUCCESS;
2767 }
2768 if (Tau32WTAwasAvailable)
2769 {
2770 if (!accTau32WTA.isAvailable(jet))
2771 {
2772 ATH_MSG_ERROR("The Tau32_WTA moment was previously available but is not available on this jet. This functionality is not supported.");
2773 return StatusCode::FAILURE;
2774 }
2775 const float value = accTau32WTA(constJet);
2776 accTau32WTA(jet) = shift*value;
2777 return StatusCode::SUCCESS;
2778 }
2779 if (TauNNwtawasAvailable)
2780 {
2781 if (! (accTau3wta.isAvailable(jet) && accTau2wta.isAvailable(jet)) )
2782 {
2783 ATH_MSG_ERROR("The Tau3_wta and Tau2_wta moments were previously available but are not available on this jet. This functionality is not supported.");
2784 return StatusCode::FAILURE;
2785 }
2786 const float tau3 = accTau3wta(constJet);
2787 const float tau2 = accTau2wta(constJet);
2788 accTau32wta(jet) = fabs(tau2) > 1.e-6 ? shift*(tau3/tau2) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2789 return StatusCode::SUCCESS;
2790 }
2791 if (TauNNWTAwasAvailable)
2792 {
2793 if (! (accTau3WTA.isAvailable(jet) && accTau2WTA.isAvailable(jet)) )
2794 {
2795 ATH_MSG_ERROR("The Tau3_WTA and Tau2_WTA moments were previously available but are not available on this jet. This functionality is not supported.");
2796 return StatusCode::FAILURE;
2797 }
2798 const float tau3 = accTau3WTA(constJet);
2799 const float tau2 = accTau2WTA(constJet);
2800 accTau32WTA(jet) = fabs(tau2) > 1.e-6 ? shift*(tau3/tau2) : -999; // 999 to match JetSubStructureMomentTools/NSubjettinessRatiosTool
2801 return StatusCode::SUCCESS;
2802 }
2803 //if (accTau32wta.isAvailable(constJet))
2804 //{
2805 // const float value = accTau32wta(constJet);
2806 // accTau32wta(jet) = shift*value;
2807 // return StatusCode::SUCCESS;
2808 //}
2809 //if (accTau32WTA.isAvailable(constJet))
2810 //{
2811 // const float value = accTau32WTA(constJet);
2812 // accTau32WTA(jet) = shift*value;
2813 // return StatusCode::SUCCESS;
2814 //}
2815 //if (accTau2wta.isAvailable(constJet) && accTau3wta.isAvailable(constJet))
2816 //{
2817 // const float value = accTau3wta(constJet)/accTau2wta(constJet);
2818 // accTau32wta(jet) = shift*value;
2819 // return StatusCode::SUCCESS;
2820 //}
2821 //if (accTau2WTA.isAvailable(constJet) && accTau3WTA.isAvailable(constJet))
2822 //{
2823 // const float value = accTau3WTA(constJet)/accTau2WTA(constJet);
2824 // accTau32WTA(jet) = shift*value;
2825 // return StatusCode::SUCCESS;
2826 //}
2827
2828 ATH_MSG_ERROR("Neither Tau32_wta nor Tau2_wta+Tau3_wta moments are available on the jet, please make sure one of these options is available before calling the tool");
2829 return StatusCode::FAILURE;
2830}
2831
2832StatusCode JetUncertaintiesTool::updateD2Beta1(xAOD::Jet& jet, const double shift) const
2833{
2834 static const SG::AuxElement::Accessor<float> accD2("D2");
2835 static const SG::AuxElement::Accessor<float> accECF1("ECF1");
2836 static const SG::AuxElement::Accessor<float> accECF2("ECF2");
2837 static const SG::AuxElement::Accessor<float> accECF3("ECF3");
2838 static const bool D2wasAvailable = accD2.isAvailable(jet);
2839 static const bool ECFwasAvailable = accECF1.isAvailable(jet) && accECF2.isAvailable(jet) && accECF3.isAvailable(jet);
2840
2841 const xAOD::Jet& constJet = jet;
2842 if (D2wasAvailable)
2843 {
2844 if (!accD2.isAvailable(jet))
2845 {
2846 ATH_MSG_ERROR("The D2 moment was previously available but is not available on this jet. This functionality is not supported.");
2847 return StatusCode::FAILURE;
2848 }
2849 const float value = accD2(constJet);
2850 accD2(jet) = shift*value;
2851 return StatusCode::SUCCESS;
2852 }
2853 if (ECFwasAvailable)
2854 {
2855 if (! (accECF1.isAvailable(constJet) && accECF2.isAvailable(constJet) && accECF3.isAvailable(constJet)) )
2856 {
2857 ATH_MSG_ERROR("The ECF1, ECF2, and ECF3 moments were previously available but are not available on this jet. This functionality is not supported.");
2858 return StatusCode::FAILURE;
2859 }
2860 const float ecf1 = accECF1(constJet);
2861 const float ecf2 = accECF2(constJet);
2862 const float ecf3 = accECF3(constJet);
2863 accD2(jet) = fabs(ecf2) > 1.e-6 ? shift * (pow(ecf1/ecf2,3)*ecf3) : -999; // 999 to match JetSubStructureMomentTools/EnergyCorrelatorRatiosTool
2864 return StatusCode::SUCCESS;
2865 }
2866
2867 //if (accD2.isAvailable(constJet))
2868 //{
2869 // const float value = accD2(constJet);
2870 // accD2(jet) = shift*value;
2871 // return StatusCode::SUCCESS;
2872 //}
2873 //if (accECF1.isAvailable(constJet) && accECF2.isAvailable(constJet) && accECF3.isAvailable(constJet))
2874 //{
2875 // const float ecf1 = accECF1(constJet);
2876 // const float ecf2 = accECF2(constJet);
2877 // const float ecf3 = accECF3(constJet);
2878 // accD2(jet) = shift * (pow(ecf1/ecf2,3)*ecf3);
2879 // return StatusCode::SUCCESS;
2880 //}
2881
2882 ATH_MSG_ERROR("Neither D2 nor ECF1+ECF2+ECF3 moments are available on the jet, please make sure one of these options is available before calling the tool");
2883 return StatusCode::FAILURE;
2884}
2885
2886StatusCode JetUncertaintiesTool::updateC2Beta1(xAOD::Jet& jet, const double shift) const
2887{
2888 static const SG::AuxElement::Accessor<float> accC2("C2");
2889 static const SG::AuxElement::Accessor<float> accECF1("ECF1");
2890 static const SG::AuxElement::Accessor<float> accECF2("ECF2");
2891 static const SG::AuxElement::Accessor<float> accECF3("ECF3");
2892 static const bool C2wasAvailable = accC2.isAvailable(jet);
2893 static const bool ECFwasAvailable = accECF1.isAvailable(jet) && accECF2.isAvailable(jet) && accECF3.isAvailable(jet);
2894
2895 const xAOD::Jet& constJet = jet;
2896 if (C2wasAvailable)
2897 {
2898 if (!accC2.isAvailable(jet))
2899 {
2900 ATH_MSG_ERROR("The C2 moment was previously available but is not available on this jet. This functionality is not supported.");
2901 return StatusCode::FAILURE;
2902 }
2903 const float value = accC2(constJet);
2904 accC2(jet) = shift*value;
2905 return StatusCode::SUCCESS;
2906 }
2907 if (ECFwasAvailable)
2908 {
2909 if (! (accECF1.isAvailable(constJet) && accECF2.isAvailable(constJet) && accECF3.isAvailable(constJet)) )
2910 {
2911 ATH_MSG_ERROR("The ECF1, ECF2, and ECF3 moments were previously available but are not available on this jet. This functionality is not supported.");
2912 return StatusCode::FAILURE;
2913 }
2914 const float ecf1 = accECF1(constJet);
2915 const float ecf2 = accECF2(constJet);
2916 const float ecf3 = accECF3(constJet);
2917 accC2(jet) = fabs(ecf2) > 1.e-6 ? shift * (ecf3*ecf1/pow(ecf2,2)) : -999; // 999 to match JetSubStructureMomentTools/EnergyCorrelatorRatiosTool
2918 return StatusCode::SUCCESS;
2919 }
2920
2921 ATH_MSG_ERROR("Neither C2 nor ECF1+ECF2+ECF3 moments are available on the jet, please make sure one of these options is available before calling the tool");
2922 return StatusCode::FAILURE;
2923}
2924
2925StatusCode JetUncertaintiesTool::updateQw(xAOD::Jet& jet, const double shift) const
2926{
2927 static const SG::AuxElement::Accessor<float> accQw("Qw");
2928
2929 const xAOD::Jet& constJet = jet;
2930 if (accQw.isAvailable(constJet))
2931 {
2932 const float value = accQw(constJet);
2933 accQw(jet) = shift*value;
2934 return StatusCode::SUCCESS;
2935 }
2936
2937 ATH_MSG_ERROR("Qw moment is not available on the jet, please make sure to set Qw before calling the tool");
2938 return StatusCode::FAILURE;
2939}
2940
2941StatusCode JetUncertaintiesTool::updateTagScaleFactor(xAOD::Jet& jet, const double shift) const
2942{
2943 const bool TagScaleFactorwasAvailable = m_accTagScaleFactor.isAvailable(jet);
2944 const xAOD::Jet& constJet = jet;
2945 if (TagScaleFactorwasAvailable)
2946 {
2947 if (!m_accTagScaleFactor.isAvailable(jet))
2948 {
2949 ATH_MSG_ERROR("TagScaleFactor was previously available but is not available on this jet. This functionality is not supported.");
2950 return StatusCode::FAILURE;
2951 }
2952 const float value = m_accTagScaleFactor(constJet);
2953 if ( value < 1e-5 ) {
2954 // if the central SF is 0, we don't consider any uncertainties
2955 return StatusCode::SUCCESS;
2956 }
2957 if (m_accEffSF.isAvailable(jet)) {
2958 // if efficiency and efficiency SF are available, inefficiency SF will be calculated
2959 const float effSF = m_accEffSF(constJet);
2960 const float efficiency = m_accEfficiency(constJet);
2961
2962
2963 const bool tagResult = m_accTagResult(constJet);
2964 if ( tagResult ){
2965 // update the efficiency SF
2966
2967 if ( shift*value < 0.0 ){
2968 m_accTagScaleFactor(jet) = 0.0;
2969 } else {
2970 m_accTagScaleFactor(jet) = shift*value;
2971 }
2972 return StatusCode::SUCCESS;
2973 } else {
2974 // this jet is "failed", since SF applied to the event is (1-effSF*efficiency)/(1-efficiency)
2975 // so inefficiency SF will be recalculated for given uncertainty
2976 if ( efficiency < 1.0 ){
2977 if ( shift*value < 0.0 ){
2978 m_accTagScaleFactor(jet) = 1.0/(1. - efficiency);
2979 } else {
2980 m_accTagScaleFactor(jet) = (1. - shift*effSF*efficiency) / (1. - efficiency);
2981 }
2982 }
2983 return StatusCode::SUCCESS;
2984 }
2985 } else {
2986 // if efficiency and efficiency SF are NOT available, inefficiency SF will not be calculated
2987
2988 if ( shift*value < 0.0 ){
2989 m_accTagScaleFactor(jet) = 0.0;
2990 } else {
2991 m_accTagScaleFactor(jet) = shift*value;
2992 }
2993 return StatusCode::SUCCESS;
2994 }
2995 }
2996
2997 ATH_MSG_ERROR("TagScaleFactor is not available on the jet, please make sure you called BoostedJetTaggers tag() function before calling this function.");
2998 return StatusCode::FAILURE;
2999}
3000
3001StatusCode JetUncertaintiesTool::updateTagEfficiency(xAOD::Jet& jet, const double shift) const
3002{
3003 const bool TagScaleFactorwasAvailable = m_accTagScaleFactor.isAvailable(jet);
3004 const xAOD::Jet& constJet = jet;
3005 if (TagScaleFactorwasAvailable)
3006 {
3007 if (!m_accTagScaleFactor.isAvailable(jet))
3008 {
3009 ATH_MSG_ERROR("TagScaleFactor was previously available but is not available on this jet. This functionality is not supported.");
3010 return StatusCode::FAILURE;
3011 }
3012 const float value = m_accTagScaleFactor(constJet);
3013 if ( value < 1e-5 ) {
3014 // if the central SF is 0, we don't consider any uncertainties
3015 return StatusCode::SUCCESS;
3016 }
3017 if (m_accEffSF.isAvailable(jet)) {
3018 // if efficiency and efficiency SF are available, inefficiency SF will be calculated
3019
3020 const float effSF = m_accEffSF(constJet);
3021 const float efficiency = m_accEfficiency(constJet);
3022 float sigeffSF = 1.0;
3023 float updated_efficiency = efficiency + shift; // efficiency value is varied
3024
3025 if ( updated_efficiency < 1e-5 ) updated_efficiency=1e-5;
3026 if ( updated_efficiency > 1.0-1e-5 ) updated_efficiency=1.0-1e-5;
3027 m_accEfficiency(jet) = updated_efficiency;
3028 if (m_accSigeffSF.isAvailable(jet)) sigeffSF = m_accSigeffSF(constJet);
3029
3030 const bool tagResult = m_accTagResult(constJet);
3031 if ( tagResult ) {
3032 // do nothing, since efficiency variation does not affect the tagged jets
3033 return StatusCode::SUCCESS;
3034 } else {
3035 // this jet is "failed"
3036 // inefficiency SF will be recalculated for given uncertainty
3037 if ( std::abs(effSF - 1.0) < 1e-5 && std::abs(shift)>0 ) {
3038 // For other category, effSF=1.0. So efficiency variation cannot be propagated to the ineffSF i.e. (1 - eff)/(1 - eff) is always 1 not depending on eff value.
3039 // SF for signal (sigeffSF) is used instead of effSF when calculating it
3040 // Relative variation of ineffSF for signal is calculated here and used for the other category
3041 float nominalIneffSFsig = (1. - sigeffSF*efficiency)/(1. - efficiency);
3042 float variatedIneffSFsig = (1. - sigeffSF*updated_efficiency)/(1. - updated_efficiency);
3043 m_accTagScaleFactor(jet) = variatedIneffSFsig/nominalIneffSFsig;
3044 } else {
3045 m_accTagScaleFactor(jet) = (1. - effSF*updated_efficiency) / (1. - updated_efficiency);
3046 }
3047 return StatusCode::SUCCESS;
3048 }
3049 } else {
3050 // if efficiency and efficiency SF are NOT available, inefficiency SF will not be calculated
3051 // do nothing
3052 return StatusCode::SUCCESS;
3053 }
3054 }
3055
3056 ATH_MSG_ERROR("TagScaleFactor is not available on the jet, please make sure you called BoostedJetTaggers tag() function before calling this function.");
3057 return StatusCode::FAILURE;
3058}
3059
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
@ Data
Definition BaseObject.h:11
double length(const pvec &v)
bool checkScalesSingleVar(const std::set< CompScaleVar::TypeEnum > &varSet, const CompScaleVar::TypeEnum var)
constexpr int pow(int base, int exp) noexcept
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
This module implements the central registry for handling systematic uncertainties with CP tools.
StatusCode addSystematicToRecommended(const SystematicVariation &systematic)
description: add a systematic to the recommended set
static SystematicRegistry & getInstance()
Get the singleton instance of the registry for the curren thread.
void registerSystematic(const SystematicVariation &systematic)
description: add a systematic to the global registry set
Class to wrap a set of SystematicVariations.
std::string name() const
returns: the systematics joined into a single string.
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
std::string basename() const
description: the base name, i.e.
const std::string & name() const
description: the full systematics name, for use in strings, etc.
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
virtual bool getComponentScalesTagScaleFactor(const size_t index) const
virtual CP::CorrectionCode correctedCopy(const xAOD::Jet &input, xAOD::Jet *&output) const
StatusCode addUncertaintyGroup(const jet::ConfigHelper &helper)
virtual bool getComponentScalesFourVec(const size_t index) const
virtual bool getComponentScalesMass(const size_t index) const
virtual double getNominalResolutionMC(const xAOD::Jet &jet, const jet::CompScaleVar::TypeEnum smearType, const jet::JetTopology::TypeEnum topology=jet::JetTopology::UNKNOWN) const
jet::UncertaintyHistogram * m_caloMassWeight
virtual bool getComponentScalesPt(const size_t index) const
virtual TH2D * getEtaCorrelationMatrix(const int numBins, const double minEta, const double maxEta, const double valPt)
virtual CP::CorrectionCode applyContainerCorrection(xAOD::JetContainer &inputs) const
virtual StatusCode addAffectingSystematic(const CP::SystematicVariation &systematic, bool recommended)
StatusCode updateTau32(xAOD::Jet &jet, const double shift) const
CP::SystematicSet m_currentSystSet
virtual double getNormalizedTAMassWeight(const xAOD::Jet &jet) const
std::vector< jet::UncertaintyGroup * > m_groups
jet::UncertaintyHistogram * m_refMuHist
virtual bool getComponentScalesC2Beta1(const size_t index) const
virtual bool getComponentScalesTau32WTA(const size_t index) const
virtual std::set< jet::CompScaleVar::TypeEnum > getComponentScaleVars(const size_t index) const
jet::CompMassDef::TypeEnum m_combMassWeightTAMassDef
virtual float getRefNPV() const
virtual bool getValidity(size_t index, const xAOD::Jet &jet) const
virtual bool isAffectedBySystematic(const CP::SystematicVariation &systematic) const
Declare the interface that this class provides.
virtual StatusCode setScaleToGeV()
StatusCode updateTagEfficiency(xAOD::Jet &jet, const double shift) const
jet::UncertaintyComponent * buildUncertaintyComponent(const jet::ComponentHelper &component) const
StatusCode updateC2Beta1(xAOD::Jet &jet, const double shift) const
const xAOD::EventInfo * getDefaultEventInfo() const
virtual bool getComponentIsReducible(const size_t index) const
double getSmearingFactor(const xAOD::Jet &jet, const jet::CompScaleVar::TypeEnum smearType, const double variation) const
virtual CP::SystematicSet recommendedSystematics() const
the list of all systematics this tool recommends to use
virtual StatusCode getUncertaintySet(const CP::SystematicSet &filteredSet, jet::UncertaintySet *&uncSet)
jet::UncertaintyHistogram * m_refNPVHist
std::vector< std::string > m_systFilters
StatusCode updateTau32WTA(xAOD::Jet &jet, const double shift) const
CP::SystematicSet m_recommendedSystematics
StatusCode updateTau21(xAOD::Jet &jet, const double shift) const
virtual size_t getComponentIndex(const std::string &name) const
virtual double getUncertainty(size_t index, const xAOD::Jet &jet) const
virtual bool getComponentScalesMultiple(const size_t index) const
SG::AuxElement::Accessor< float > m_accEfficiency
virtual std::string getComponentDesc(const size_t index) const
std::unordered_map< CP::SystematicSet, CP::SystematicSet > m_systFilterMap
virtual float getRefMu() const
virtual bool getValidUncertainty(size_t index, double &unc, const xAOD::Jet &jet) const
virtual bool getComponentScalesTau21(const size_t index) const
StatusCode updateSplittingScale12(xAOD::Jet &jet, const double shift) const
CP::SystematicSet m_recognizedSystematics
StatusCode updateTagScaleFactor(xAOD::Jet &jet, const double shift) const
virtual StatusCode setScaleToMeV()
StatusCode updateSplittingScale23(xAOD::Jet &jet, const double shift) const
SG::AuxElement::Accessor< float > m_accEffSF
virtual std::string getName() const
StatusCode updateD2Beta1(xAOD::Jet &jet, const double shift) const
virtual bool getComponentScalesTau21WTA(const size_t index) const
double readHistoFromParam(const xAOD::Jet &jet, const jet::UncertaintyHistogram &histo, const jet::CompParametrization::TypeEnum param, const jet::CompMassDef::TypeEnum massDef) const
virtual TH2D * getPtCorrelationMatrix(const int numBins, const double minPt, const double maxPt, const double valEta)
JetUncertaintiesTool(const std::string &name="JetUncertaintiesTool")
virtual std::string getRelease() const
jet::UncertaintyHistogram * m_TAMassWeight
virtual float getSqrtS() const
virtual CP::SystematicSet affectingSystematics() const
the list of all systematics this tool can be affected by
virtual bool getComponentScalesQw(const size_t index) const
StatusCode addUncertaintyComponent(const jet::ConfigHelper &helper)
virtual StatusCode applySystematicVariation(const CP::SystematicSet &systConfig)
effects: configure this tool for the given list of systematic variations.
virtual size_t getNumComponents() const
virtual std::vector< std::string > getComponentCategories() const
virtual CP::SystematicSet appliedSystematics() const
virtual double getNormalizedCaloMassWeight(const xAOD::Jet &jet) const
virtual std::string getComponentName(const size_t index) const
const std::string m_namePrefix
double getNominalResolution(const xAOD::Jet &jet, const jet::CompScaleVar::TypeEnum smearType, const jet::JetTopology::TypeEnum topology, const bool readMC) const
virtual bool getComponentScalesD12(const size_t index) const
virtual double getNominalResolutionData(const xAOD::Jet &jet, const jet::CompScaleVar::TypeEnum smearType, const jet::JetTopology::TypeEnum topology=jet::JetTopology::UNKNOWN) const
StatusCode updateQw(xAOD::Jet &jet, const double shift) const
virtual std::string getComponentCategory(const size_t index) const
virtual bool getComponentScalesD23(const size_t index) const
bool checkIfRecommendedSystematic(const jet::UncertaintyGroup &systematic) const
std::unordered_map< CP::SystematicSet, jet::UncertaintySet * > m_systSetMap
StatusCode checkIndexInput(const size_t index) const
virtual std::vector< std::string > getComponentNamesInCategory(const std::string &category) const
SG::AuxElement::Accessor< bool > m_accTagResult
jet::ValidityHistogram * m_fileValidHist
jet::CompParametrization::TypeEnum m_combMassParam
virtual StatusCode getFilteredSystematicSet(const CP::SystematicSet &systConfig, CP::SystematicSet &filteredSet)
StatusCode updateTau21WTA(xAOD::Jet &jet, const double shift) const
SG::AuxElement::Accessor< float > m_accSigeffSF
jet::ResolutionHelper * m_resHelper
virtual bool getComponentScalesD2Beta1(const size_t index) const
SG::AuxElement::Accessor< float > m_accTagScaleFactor
virtual jet::JetTopology::TypeEnum getComponentTopology(const size_t index) const
virtual StatusCode initialize()
Dummy implementation of the initialisation function.
jet::UncertaintySet * m_currentUncSet
jet::CompMassDef::TypeEnum m_combMassWeightCaloMassDef
virtual std::vector< size_t > getComponentsInCategory(const std::string &category) const
virtual CP::CorrectionCode applyCorrection(xAOD::Jet &jet) const
virtual bool getComponentScalesTau32(const size_t index) const
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
virtual StatusCode initialize()
Dummy implementation of the initialisation function.
Definition AsgTool.h:133
virtual StatusCode setCaloTerm(UncertaintyGroup *caloComp)
virtual StatusCode setCombWeightParam(const CompParametrization::TypeEnum param)
virtual StatusCode setTAWeights(const UncertaintyHistogram *TAWeights)
virtual StatusCode setCombWeightMassDefs(const CompMassDef::TypeEnum caloMassDef, const CompMassDef::TypeEnum TAMassDef)
virtual StatusCode setCaloWeights(const UncertaintyHistogram *caloWeights)
virtual StatusCode setTATerm(UncertaintyGroup *TAComp)
PileupComp::TypeEnum pileupType
CompScaleVar::TypeEnum scaleVar
CompMassDef::TypeEnum massDef
std::vector< TString > uncNames
std::vector< LargeRJetTruthLabel::TypeEnum > LargeRJetTruthLabels
FlavourComp::TypeEnum flavourType
CompParametrization::TypeEnum parametrization
CombMassComp::TypeEnum combMassType
std::vector< TString > subComps
virtual const TH2D * getMatrix() const
virtual StatusCode initializeForEta(const JetUncertaintiesTool &uncTool)
virtual StatusCode initializeForPt(const JetUncertaintiesTool &uncTool)
CompCorrelation::TypeEnum correlation
CompCategory::TypeEnum category
JetFourMomAccessor is an extension of JetAttributeAccessor::AccessorWrapper<xAOD::JetFourMom_t> Acces...
virtual TString getName() const
virtual StatusCode addComponent(UncertaintyComponent *component)
virtual TString getName() const
virtual bool isAlwaysZero() const
virtual std::set< CompScaleVar::TypeEnum > getScaleVars() const
virtual StatusCode initialize(const CP::SystematicSet &systConfig, const std::vector< UncertaintyGroup * > &groups)
uint64_t eventNumber() const
The current event's event number.
Class creating a shallow copy of an existing auxiliary container.
static std::string release
Definition computils.h:50
void efficiency(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
Definition index.py:1
TypeEnum stringToEnum(const TString &type)
TString enumToString(const TypeEnum type)
TypeEnum stringToEnum(const TString &type)
TString getJetScaleString(const TypeEnum type)
TString enumToString(const TypeEnum type)
TypeEnum stringToEnum(const TString &type)
bool includesMass(const TypeEnum type)
TString enumToString(const TypeEnum type)
TypeEnum stringToEnum(const TString &type)
bool isRelResolutionType(const TypeEnum type)
bool isResolutionType(const TypeEnum type)
TString enumToString(const TypeEnum type)
bool getTypeObjFromString(const std::string &str, T &obj)
bool vectorize(const TString &str, const TString &sep, std::vector< T > &result)
TString findFilePath(const TString &fileName, const TString &path="", const TString &calibArea="")
Jet_v1 Jet
Definition of the current "jet version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
std::pair< T *, ShallowAuxInfo * > shallowCopyObject(const T &obj)
Function making a shallow copy of a constant standalone object.
JetContainer_v1 JetContainer
Definition of the current "jet container version".
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< double > > JetFourMom_t
Base 4 Momentum type for Jet.
Definition JetTypes.h:17