ATLAS Offline Software
ApplyFakeFactor.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
3 */
4 
7 
8 #include <cmath>
9 
10 using namespace CP;
11 
12 //=============================================================================
13 // Constructor
14 //=============================================================================
17 {
18 }
19 
20 //=============================================================================
21 // Destructor
22 //=============================================================================
24 {
25 }
26 
28 {
30 }
31 
33 {
35 }
36 
38 {
39  m_cachedWeights.clear();
40 
41  return incrementTotalYield();
42 }
43 
45  FakeBkgTools::Weight& outputEventWeight, const FakeBkgTools::FinalState& fs) {
46 
47  ATH_MSG_DEBUG("entering getEventWeight");
48 
49  // for the FF, we can handle the following (e.g. for a 2L final state):
50  // N_LT, N_TL, N_LL
51  // but not N_RR, N_FR, etc. (other than via the MC for N_RR)
52  // and not N_TT, since this is part of what we want to estimate
53  //
54  // in general, we want to compute N_TT^{RF,FR,FF} = N_TT - N_TT^{RR}
55  // which might need to be coded up as its own string
56  //
57  // maybe we want to only allow strProc == ">=1F"
58 
59  // reset initial values since they will be multiplied by
60  // each lepton's FF and rel uncertainty
61  outputEventWeight.nominal = 1;
62  outputEventWeight.uncertainties.clear();
63 
64  // check if the event satisfies the selection of interest
65  // e.g. LT vs. TL, SS events, etc.
66  unsigned long expectedTightLeptonsBitset = 0;
67  if(!eventSatisfiesCriteria(fs, expectedTightLeptonsBitset)){
68 
69  ATH_MSG_DEBUG("event failed eventSatisfiesCriteria");
70 
71  // for an inappropriate event for our desired selection,
72  // return a weight of 0 and uncertainties of 0
73  outputEventWeight.nominal = 0;
74 
75  // quit now, since the event does not satisfy our selection
76  return StatusCode::SUCCESS;
77  }
78 
79  ATH_MSG_DEBUG("event passed eventSatisfiesCriteria!");
80 
81  // in principle m_particles may also include baseline,
82  // but we only want to have loose and tight at this stage!
83  // User must *only* pass loose and tight leptons to the tool
84  unsigned int nLooseLeps = 0;
85  unsigned int ipart = 0;
86  const FakeBkgTools::FSBitset newtights(expectedTightLeptonsBitset);
87 
89 
90  // only antiID (loose) leptons need an FF applied
91  if(particle.tight) continue;
92  if(!newtights[ipart++]) continue; // only multiply fake factors from loose leptons that are supposed to be tight in the wanted final state
93 
94  // FIXME when we load in the FFs, need to allow for e.g. pT, eta binning and arbitrary parameterizations
95  float FF_value = particle.fake_factor.nominal;
96  ATH_MSG_DEBUG("FF_value is " << FF_value);
97  outputEventWeight.nominal *= FF_value;
98  for(auto const& particleUncPair : particle.fake_factor.uncertainties){
99 
100  float FF_abs_err_up = particleUncPair.second.up;
101  float FF_abs_err_down = particleUncPair.second.down;
102 
103  float FF_rel_err_up = FF_abs_err_up / fabs(FF_value);
104  float FF_rel_err_down = FF_abs_err_down / fabs(FF_value);
105 
106  // note that these are all relative uncertainties at this stage
107  auto& unc = outputEventWeight.uncertainties.emplace(particleUncPair.first, FakeBkgTools::Uncertainty{1.f, 1.f}).first->second;
108  unc.up *= (1+FF_rel_err_up);
109  unc.down *= (1-FF_rel_err_down);
110  }
111  ++nLooseLeps;
112  // nLooseLeps will only count loose leptons "upgraded" to tight.
113  }
114 
115  // Subtraction for double counting of events with two antiID leptons
116  // which have had a FF applied, to "promote" them to a tight lepton.
117  // It turns out this is true for all even multiplicities.
118  if(nLooseLeps % 2 == 0){
119  outputEventWeight.nominal *= -1;
120  }
121 
122 
123  for(auto& eventUncPair : outputEventWeight.uncertainties){
124  eventUncPair.second.up = (eventUncPair.second.up - 1.f) * outputEventWeight.nominal;
125  eventUncPair.second.down = (1.f - eventUncPair.second.down) * outputEventWeight.nominal;
126  }
127 
128  ATH_MSG_DEBUG("outputEventWeight.nominal is " << outputEventWeight.nominal);
129 
130  return StatusCode::SUCCESS;
131 }
132 
133 bool ApplyFakeFactor::eventSatisfiesCriteria(const FakeBkgTools::FinalState& fs, unsigned long& expectedTightLeptonsBitset){
134 
135  // fill bitset for tight leptons
136  FakeBkgTools::FSBitset tights(0);
137  unsigned int ipart = 0;
139 
140  if(particle.tight){
141  tights.set(ipart);
142  }
143 
144  ++ipart;
145  }
146 
147  // the logic is following: the event is accepted only if there's at least one "turn a loose lepton into tight" operation that gives the wanted final state
148  FakeBkgTools::FSBitset charges = fs.retrieveCharges(m_particles); // could also use the code above instead, if it is need for other purposes
149  unsigned int nValidCombinations = 0; // count the number of different possible+acceptable final states obtained by changing loose leptons into tight
150  const unsigned long nc = (1<<m_particles.size());
151  for(unsigned long c=0;c<nc;++c) // loop over all possible combinations for n leptons
152  {
153  auto newtights = FakeBkgTools::FSBitset(c);
154  if(!fs.accept_selection(newtights, charges)){
155  ATH_MSG_DEBUG("eventSatisfiesCriteria: failed selection");
156  continue; // discard unwanted combinations (including charge requirements)
157  }
158 
159  // if no loose lepton has been "upgraded", not a valid combination:
160  if((newtights | tights) == tights){
161  ATH_MSG_DEBUG("eventSatisfiesCriteria: newtights|tights == tights. newtights is " << newtights << " while tights is " << tights);
162  continue;
163  }
164  // also, the combination can't have tight leptons "downgraded" to loose:
165  if((newtights&tights) != tights){
166  ATH_MSG_DEBUG("eventSatisfiesCriteria: newtights&tights != tights. newtights is " << newtights << " while tights is " << tights);
167  continue;
168  }
169  ++nValidCombinations;
170  expectedTightLeptonsBitset = c;
171  }
172 
173  if(!nValidCombinations) return false;
174  if(nValidCombinations > 1) // if > 1, would need to modify getEventWeight() to sum over all different combinations, I think
175  {
176  ATH_MSG_ERROR("this type of selection/process is currently not supported by the fake factor method");
177  return false;
178  }
179  // process argument ignored for the moment. Should probably make sure that nothing exotic was requested.
180 
181  return true;
182 }
183 
CP::BaseLinearFakeBkgTool::incrementTotalYield
StatusCode incrementTotalYield()
be sure to only call this once per event! (typically at the end of addEvent())
Definition: BaseLinearFakeBkgTool.cxx:97
CP::ApplyFakeFactor::eventSatisfiesCriteria
bool eventSatisfiesCriteria(const FakeBkgTools::FinalState &fs, unsigned long &expectedTightLeptonsBitset)
Definition: ApplyFakeFactor.cxx:133
FakeBkgTools::Uncertainty
Definition: FakeBkgInternals.h:27
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
CP::ApplyFakeFactor::getEventWeightCustom
virtual StatusCode getEventWeightCustom(FakeBkgTools::Weight &weight, const FakeBkgTools::FinalState &fs) override
Definition: ApplyFakeFactor.cxx:44
FakeBkgTools::Client::FAKE_FACTOR
@ FAKE_FACTOR
FakeBkgTools::Client
Client
Definition: FakeBkgInternals.h:141
FakeBkgTools::ParticleData
Definition: FakeBkgInternals.h:85
CP::BaseLinearFakeBkgTool::initialize
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Definition: BaseLinearFakeBkgTool.cxx:34
CP
Select isolated Photons, Electrons and Muons.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:48
CP::ApplyFakeFactor::clientForDB
virtual FakeBkgTools::Client clientForDB() override final
This indicates which type of efficiencies/fake factor need to be filled.
Definition: ApplyFakeFactor.cxx:27
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
CP::BaseLinearFakeBkgTool
Definition: BaseLinearFakeBkgTool.h:39
CP::ApplyFakeFactor::~ApplyFakeFactor
~ApplyFakeFactor()
Standard destructor.
Definition: ApplyFakeFactor.cxx:23
CP::ApplyFakeFactor::ApplyFakeFactor
ApplyFakeFactor(const std::string &name)
Standard constructor.
Definition: ApplyFakeFactor.cxx:15
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
FakeBkgInternals.h
FakeBkgTools::Weight
a structure to hold a weight together with a variable number of systematic uncertainties
Definition: FakeBkgInternals.h:62
CP::BaseFakeBkgTool::m_particles
std::vector< FakeBkgTools::ParticleData > m_particles
Definition: BaseFakeBkgTool.h:85
FakeBkgTools::Efficiency::nominal
float nominal
Definition: FakeBkgInternals.h:42
FakeBkgTools::FinalState
Definition: FakeBkgInternals.h:98
Herwig7_QED_EvtGen_ll.fs
dictionary fs
Definition: Herwig7_QED_EvtGen_ll.py:17
CP::ApplyFakeFactor::addEventCustom
virtual StatusCode addEventCustom() override
Definition: ApplyFakeFactor.cxx:37
FakeBkgTools::FSBitset
std::bitset< maxCombinations()> FSBitset
Definition: FakeBkgInternals.h:95
CP::BaseLinearFakeBkgTool::m_cachedWeights
std::map< FakeBkgTools::FinalState, FakeBkgTools::Weight > m_cachedWeights
cached weight+uncertainties for a single event Each tool derived from this base class MUST clear the ...
Definition: BaseLinearFakeBkgTool.h:67
python.compressB64.c
def c
Definition: compressB64.py:93
ApplyFakeFactor.h
plotBeamSpotMon.nc
int nc
Definition: plotBeamSpotMon.py:83
FakeBkgTools::Efficiency::uncertainties
std::map< uint16_t, FakeBkgTools::Uncertainty > uncertainties
Definition: FakeBkgInternals.h:43
CP::ApplyFakeFactor::initialize
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Definition: ApplyFakeFactor.cxx:32