ATLAS Offline Software
Loading...
Searching...
No Matches
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
10using namespace CP;
11
12//=============================================================================
13// Constructor
14//=============================================================================
19
20//=============================================================================
21// Destructor
22//=============================================================================
26
31
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
133bool 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
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
static Double_t fs
virtual StatusCode addEventCustom() override
ApplyFakeFactor(const std::string &name)
Standard constructor.
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
virtual StatusCode getEventWeightCustom(FakeBkgTools::Weight &weight, const FakeBkgTools::FinalState &fs) override
~ApplyFakeFactor()
Standard destructor.
bool eventSatisfiesCriteria(const FakeBkgTools::FinalState &fs, unsigned long &expectedTightLeptonsBitset)
virtual FakeBkgTools::Client clientForDB() override final
This indicates which type of efficiencies/fake factor need to be filled.
std::vector< FakeBkgTools::ParticleData > m_particles
BaseLinearFakeBkgTool(const std::string &toolname)
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
StatusCode incrementTotalYield()
be sure to only call this once per event! (typically at the end of addEvent())
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 ...
Select isolated Photons, Electrons and Muons.
std::bitset< maxCombinations()> FSBitset
std::map< uint16_t, FakeBkgTools::Uncertainty > uncertainties
a structure to hold a weight together with a variable number of systematic uncertainties