CMS 3D CMS Logo

BackgroundHandler.cc
Go to the documentation of this file.
1 #ifndef BackgroundHandler_cc
2 #define BackgroundHandler_cc
3 
5 #include <algorithm>
6 #include <TF1.h>
7 #include <iostream>
8 
10 
11 BackgroundHandler::BackgroundHandler(const std::vector<int>& identifiers,
12  const std::vector<double>& leftWindowBorders,
13  const std::vector<double>& rightWindowBorders,
14  const double* ResMass,
15  const double* massWindowHalfWidth) {
16  // : leftWindowFactors_(leftWindowFactors),
17  // rightWindowFactors_(rightWindowFactors)
18 
19  // Define the correspondence between regions and halfWidth to use
20  // Defines also the function type to use (but they are checked to be consistent over a region)
21  regToResHW_[0] = 0; // Region 0 use the one from Z
22  regToResHW_[1] = 3; // Region 1 use the one from Upsilon1S
23  regToResHW_[2] = 5; // Region 2 use the one from J/Psi
24 
25  // Define the correspondence between resonances and regions
26  resToReg_[0] = 0; // Z
27  resToReg_[1] = 1; // Upsilon3S
28  resToReg_[2] = 1; // Upsilon2S
29  resToReg_[3] = 1; // Upsilon1S
30  resToReg_[4] = 2; // Psi2S
31  resToReg_[5] = 2; // J/Psi
32 
33  // Throws cms::Exception("Configuration") in case the parameters are not what is expected
34  consistencyCheck(identifiers, leftWindowBorders, rightWindowBorders);
35 
36  // Build the resonance windows
37  for (unsigned int i = 0; i < 6; ++i) {
38  double mass = ResMass[i];
39  double lowerLimit = mass - massWindowHalfWidth[i];
40  double upperLimit = mass + massWindowHalfWidth[i];
41  resonanceWindow_.push_back(
43  lowerLimit,
44  upperLimit,
45  std::vector<unsigned int>(1, i),
46  backgroundFunctionService(identifiers[resToReg_[i]], lowerLimit, upperLimit)));
47  }
48 
49  // Build the background windows
50  // ----------------------------
51  // Compute the mass center of each region
52  double resMassForRegion[3];
53  resMassForRegion[0] = ResMass[0];
54  resMassForRegion[1] = (ResMass[1] + ResMass[2] + ResMass[3]) / 3;
55  resMassForRegion[2] = (ResMass[4] + ResMass[5]) / 2;
56 
57  // Define which resonance is in which background window
58  std::vector<std::vector<unsigned int> > indexes;
59  indexes.push_back(std::vector<unsigned int>(1, 0));
60  indexes.push_back(std::vector<unsigned int>());
61  for (int i = 1; i <= 3; ++i) {
62  indexes[1].push_back(i);
63  }
64  indexes.push_back(std::vector<unsigned int>());
65  for (int i = 4; i <= 5; ++i) {
66  indexes[2].push_back(i);
67  }
68 
69  unsigned int i = 0;
70  typedef std::vector<unsigned int> indexVec;
71  for (auto const& index : indexes) {
72  // double lowerLimit = resMassForRegion[i] - massWindowHalfWidth[regToResHW_[i]]*leftWindowFactors[i];
73  // double upperLimit = resMassForRegion[i] + massWindowHalfWidth[regToResHW_[i]]*rightWindowFactors[i];
74  // backgroundWindow_.push_back( MassWindow( resMassForRegion[i], lowerLimit, upperLimit, index,
75  // backgroundFunctionService(identifiers[i], lowerLimit, upperLimit ) ) );
76  backgroundWindow_.push_back(
77  MassWindow(resMassForRegion[i],
78  leftWindowBorders[i],
79  rightWindowBorders[i],
80  index,
81  backgroundFunctionService(identifiers[i], leftWindowBorders[i], rightWindowBorders[i])));
82  ++i;
83  }
84  // Initialize the parNums to be used in the shifts of parval
86 }
87 
89 
91  // Initialize the parNums to be used in the shifts of parval
92  parNumsRegions_[0] = 0;
93  for (unsigned int i = 1; i < backgroundWindow_.size(); ++i) {
94  parNumsRegions_[i] = parNumsRegions_[i - 1] + backgroundWindow_[i - 1].backgroundFunction()->parNum();
95  }
96  parNumsResonances_[0] = parNumsRegions_[2] + backgroundWindow_[2].backgroundFunction()->parNum();
97  for (unsigned int i = 1; i < resonanceWindow_.size(); ++i) {
98  parNumsResonances_[i] = parNumsResonances_[i - 1] + resonanceWindow_[i - 1].backgroundFunction()->parNum();
99  }
100 }
101 
103  double* Step,
104  double* Mini,
105  double* Maxi,
106  int* ind,
107  TString* parname,
108  const std::vector<double>& parBgr,
109  const std::vector<int>& parBgrOrder,
110  const int muonType) {
111  std::vector<double>::const_iterator parBgrIt = parBgr.begin();
112  std::vector<int>::const_iterator parBgrOrderIt = parBgrOrder.begin();
113  // Set the parameters for the regions only if this is not a rescaling
114  for (int iReg = 0; iReg < 3; ++iReg) {
115  int shift = parNumsRegions_[iReg];
116  backgroundWindow_[iReg].backgroundFunction()->setParameters(&(Start[shift]),
117  &(Step[shift]),
118  &(Mini[shift]),
119  &(Maxi[shift]),
120  &(ind[shift]),
121  &(parname[shift]),
122  parBgrIt + shift,
123  parBgrOrderIt + shift,
124  muonType);
125  }
126  for (int iRes = 0; iRes < 6; ++iRes) {
127  // parNumsResonances is already shifted for the regions parameters
128  int shift = parNumsResonances_[iRes];
129  resonanceWindow_[iRes].backgroundFunction()->setParameters(&(Start[shift]),
130  &(Step[shift]),
131  &(Mini[shift]),
132  &(Maxi[shift]),
133  &(ind[shift]),
134  &(parname[shift]),
135  parBgrIt + shift,
136  parBgrOrderIt + shift,
137  muonType);
138  }
139 }
140 
141 bool BackgroundHandler::unlockParameter(const std::vector<int>& resfind, const unsigned int ipar) {
142  // parNumsRegions_ are shifted: [1] contains the number of parameters for 0 and so on.
143  if (ipar < unsigned(parNumsRegions_[1]) && resfind[0] > 0) {
144  return true;
145  }
146  if (ipar >= unsigned(parNumsRegions_[1]) && ipar < unsigned(parNumsRegions_[2]) &&
147  (resfind[1] > 0 || resfind[2] > 0 || resfind[3] > 0)) {
148  return true;
149  }
150  // The first of parNumsResonances_ has the sum of parNums of the regions.
151  if (ipar >= unsigned(parNumsRegions_[2]) && ipar < unsigned(parNumsResonances_[0]) &&
152  (resfind[4] > 0 || resfind[5] > 0)) {
153  return true;
154  }
155  return false;
156 }
157 
158 // std::pair<double, double> BackgroundHandler::windowFactors( const bool doBackgroundFit, const int ires )
159 // {
160 // if( doBackgroundFit ) {
161 // // Fitting the background: use the regions
162 // return std::make_pair(leftWindowFactors_[resToReg_[ires]], rightWindowFactors_[resToReg_[ires]]);
163 // }
164 // else {
165 // // Not fitting the background: use the resonances
166 // return std::make_pair(1.,1.);
167 // }
168 // }
169 
170 std::pair<double, double> BackgroundHandler::windowBorders(const bool doBackgroundFit, const int ires) {
171  if (doBackgroundFit) {
172  // Fitting the background: use the regions
173  return std::make_pair(backgroundWindow_[resToReg_[ires]].lowerBound(),
174  backgroundWindow_[resToReg_[ires]].upperBound());
175  } else {
176  // Not fitting the background: use the resonances
177  // return std::make_pair(1.,1.);
178  return std::make_pair(resonanceWindow_[ires].lowerBound(), resonanceWindow_[ires].upperBound());
179  }
180 }
181 
182 double BackgroundHandler::resMass(const bool doBackgroundFit, const int ires) {
183  if (doBackgroundFit) {
184  // Fitting the background: use the regions
185  return backgroundWindow_[resToReg_[ires]].mass();
186  } else {
187  // Not fitting the background: use the resonances
188  return resonanceWindow_[ires].mass();
189  }
190 }
191 
193  std::vector<double>& parBgr,
194  const double* ResMass,
195  const double* massWindowHalfWidth,
196  const std::vector<std::pair<reco::Particle::LorentzVector, reco::Particle::LorentzVector> >& muonPairs,
197  const double& weight) {
198  countEventsInAllWindows(muonPairs, weight);
199 
200  // Loop on all regions and on all the resonances of each region and compute the background fraction
201  // for each resonance window.
202  unsigned int iRegion = 0;
203  for (auto const& backgroundWindow : backgroundWindow_) {
204  // Iterator pointing to the first parameter of this background function in the full set of parameters
205  std::vector<double>::const_iterator parBgrIt = (parBgr.begin() + parNumsRegions_[iRegion]);
206  TF1* backgroundFunctionForIntegral = backgroundWindow.backgroundFunction()->functionForIntegral(parBgrIt);
207  // WARNING: this expects the background fraction parameter to be parBgr[0] for all the background functions.
208  double kOld = *parBgrIt;
209  double Nbw = backgroundWindow.events();
210  double Ibw = backgroundFunctionForIntegral->Integral(backgroundWindow.lowerBound(), backgroundWindow.upperBound());
211 
212  // index is the index of the resonance in the background window
213  for (unsigned int index : *(backgroundWindow.indexes())) {
214  // First set all parameters of the resonance window background function to those of the corresponding region
215  for (int iPar = 0; iPar < resonanceWindow_[index].backgroundFunction()->parNum(); ++iPar) {
216  parBgr[parNumsResonances_[index] + iPar] = parBgr[parNumsRegions_[resToReg_[index]] + iPar];
217  }
218  // Estimated fraction of events in the resonance window
219  double Irw = backgroundFunctionForIntegral->Integral(resonanceWindow_[index].lowerBound(),
220  resonanceWindow_[index].upperBound());
221  double Nrw = resonanceWindow_[index].events();
222 
223  // Ibw is 1 (to avoid effects from approximation errors we set it to 1 and do not include it in the computation).
224  if (Nrw != 0)
225  parBgr[parNumsResonances_[index]] = kOld * Nbw / Nrw * Irw;
226  else
227  parBgr[parNumsResonances_[index]] = 0.;
228 
229  // Protect against fluctuations of number of events which could cause the fraction to go above 1.
230  if (parBgr[parNumsResonances_[index]] > 1.)
231  parBgr[parNumsResonances_[index]] = 1.;
232 
233  double kNew = parBgr[parNumsResonances_[index]];
234  std::cout << "For resonance = " << index << std::endl;
235  std::cout << "backgroundWindow.lowerBound = " << backgroundWindow.lowerBound() << std::endl;
236  std::cout << "backgroundWindow.upperBound = " << backgroundWindow.upperBound() << std::endl;
237  std::cout << "parNumsResonances_[" << index << "] = " << parNumsResonances_[index] << std::endl;
238  std::cout << "Nbw = " << Nbw << ", Ibw = " << Ibw << std::endl;
239  std::cout << "Nrw = " << Nrw << ", Irw = " << Irw << std::endl;
240  std::cout << "k = " << kOld << ", k' = " << parBgr[parNumsResonances_[index]] << std::endl;
241  std::cout << "background fraction in background window = Nbw*k = " << Nbw * kOld << std::endl;
242  std::cout << "background fraction in resonance window = Nrw*k' = " << Nrw * kNew << std::endl;
243  }
244  ++iRegion;
245  delete backgroundFunctionForIntegral;
246  }
247 }
248 
249 std::pair<double, double> BackgroundHandler::backgroundFunction(const bool doBackgroundFit,
250  const double* parval,
251  const int resTotNum,
252  const int ires,
253  const bool* resConsidered,
254  const double* ResMass,
255  const double ResHalfWidth[],
256  const int MuonType,
257  const double& mass,
258  const double& eta1,
259  const double& eta2) {
260  if (doBackgroundFit) {
261  // Return the values for the region
262  int iReg = resToReg_[ires];
263  // return std::make_pair( parval[parNumsRegions_[iReg]] * backgroundWindow_[iReg].backgroundFunction()->fracVsEta(&(parval[parNumsRegions_[iReg]]), resEta),
264  return std::make_pair(
265  parval[parNumsRegions_[iReg]] *
266  backgroundWindow_[iReg].backgroundFunction()->fracVsEta(&(parval[parNumsRegions_[iReg]]), eta1, eta2),
267  (*(backgroundWindow_[iReg].backgroundFunction()))(&(parval[parNumsRegions_[iReg]]), mass, eta1, eta2));
268  // return std::make_pair( backgroundWindow_[iReg].backgroundFunction()->fracVsEta(&(parval[parNumsRegions_[iReg]]), eta1, eta2),
269  // (*(backgroundWindow_[iReg].backgroundFunction()))( &(parval[parNumsRegions_[iReg]]), mass, eta1, eta2 ) );
270  }
271  // Return the values for the resonance
272  // return std::make_pair( parval[parNumsResonances_[ires]] * resonanceWindow_[ires].backgroundFunction()->fracVsEta(&(parval[parNumsResonances_[ires]]), resEta),
273  // (*(resonanceWindow_[ires].backgroundFunction()))( &(parval[parNumsResonances_[ires]]), mass, resEta ) );
274  return std::make_pair(
275  parval[parNumsResonances_[ires]] *
276  resonanceWindow_[ires].backgroundFunction()->fracVsEta(&(parval[parNumsResonances_[ires]]), eta1, eta2),
277  (*(resonanceWindow_[ires].backgroundFunction()))(&(parval[parNumsResonances_[ires]]), mass, eta1, eta2));
278 }
279 
281  const std::vector<std::pair<reco::Particle::LorentzVector, reco::Particle::LorentzVector> >& muonPairs,
282  const double& weight) {
283  // First reset all the counters
284  for (auto& resonanceWindow : resonanceWindow_) {
285  resonanceWindow.resetCounter();
286  }
287  // Count events in background windows
288  for (auto& backgroundWindow : backgroundWindow_) {
289  backgroundWindow.resetCounter();
290  }
291 
292  // Now count the events in each window
293  std::pair<lorentzVector, lorentzVector> muonPair;
294  for (auto const& muonPair : muonPairs) {
295  // Count events in resonance windows
296  for (auto& resonanceWindow : resonanceWindow_) {
297  resonanceWindow.count((muonPair.first + muonPair.second).mass(), weight);
298  }
299  // Count events in background windows
300  for (auto& backgroundWindow : backgroundWindow_) {
301  backgroundWindow.count((muonPair.first + muonPair.second).mass(), weight);
302  }
303  }
304 }
305 
306 void BackgroundHandler::consistencyCheck(const std::vector<int>& identifiers,
307  const std::vector<double>& leftWindowBorders,
308  const std::vector<double>& rightWindowBorders) const noexcept(false) {
309  if (leftWindowBorders.size() != rightWindowBorders.size()) {
310  throw cms::Exception("Configuration")
311  << "BackgroundHandler::BackgroundHandler: leftWindowBorders.size() = " << leftWindowBorders.size()
312  << " != rightWindowBorders.size() = " << rightWindowBorders.size() << std::endl;
313  }
314  if (leftWindowBorders.size() != 3) {
315  throw cms::Exception("Configuration")
316  << "BackgroundHandler::BackgroundHandler: leftWindowBorders.size() = rightWindowBorders.size() = "
317  << leftWindowBorders.size() << " != 3" << std::endl;
318  }
319  if (identifiers.size() != 3) {
320  throw cms::Exception("Configuration")
321  << "BackgroundHandler::BackgroundHandler: identifiers must match the number of regions = 3" << std::endl;
322  }
323 }
324 
325 #endif // BackgroundHandler_cc
std::vector< MassWindow > backgroundWindow_
std::vector< MassWindow > resonanceWindow_
std::pair< double, double > backgroundFunction(const bool doBackgroundFit, const double *parval, const int resTotNum, const int ires, const bool *resConsidered, const double *ResMass, const double ResHalfWidth[], const int MuonType, const double &mass, const double &eta1, const double &eta2)
reco::Particle::LorentzVector lorentzVector
Definition: weight.py:1
void consistencyCheck(const std::vector< int > &identifiers, const std::vector< double > &leftWindowBorders, const std::vector< double > &rightWindowBorders) const noexcept(false)
Used to check the consistency of passed parameters.
void rescale(std::vector< double > &parBgr, const double *ResMass, const double *massWindowHalfWidth, const std::vector< std::pair< reco::Particle::LorentzVector, reco::Particle::LorentzVector > > &muonPairs, const double &weight=1.)
double resMass(const bool doBackgroundFit, const int ires)
void setParameters(double *Start, double *Step, double *Mini, double *Maxi, int *ind, TString *parname, const std::vector< double > &parBgr, const std::vector< int > &parBgrOrder, const int muonType)
Sets initial parameters for all the functions.
std::pair< double, double > windowBorders(const bool doBackgroundFit, const int ires)
Returns the appropriate window borders depending on whether the background is being fitted and on the...
bool unlockParameter(const std::vector< int > &resfind, const unsigned int ipar)
returns true if the parameter is to be unlocked
void countEventsInAllWindows(const std::vector< std::pair< reco::Particle::LorentzVector, reco::Particle::LorentzVector > > &muonPairs, const double &weight)
static unsigned int const shift
BackgroundHandler(const std::vector< int > &identifiers, const std::vector< double > &leftWindowBorders, const std::vector< double > &rightWindowBorders, const double *ResMass, const double *massWindowHalfWidth)
backgroundFunctionBase * backgroundFunctionService(const int identifier, const double &lowerLimit, const double &upperLimit)
Service to build the background functor corresponding to the passed identifier.
Definition: Functions.cc:114
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: Particle.h:21
void initializeParNums()
Initialize the parNums to be used in the shifts of parval.