~ma5/madanalysis5/madanalysis-development

70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
1
////////////////////////////////////////////////////////////////////////////////
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
2
//  
3
//  Copyright (C) 2012-2016 Eric Conte, Benjamin Fuks
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
4
//  The MadAnalysis development team, email: <ma5team@iphc.cnrs.fr>
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
5
//  
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
6
//  This file is part of MadAnalysis 5.
7
//  Official website: <https://launchpad.net/madanalysis5>
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
8
//  
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
9
//  MadAnalysis 5 is free software: you can redistribute it and/or modify
10
//  it under the terms of the GNU General Public License as published by
11
//  the Free Software Foundation, either version 3 of the License, or
12
//  (at your option) any later version.
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
13
//  
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
14
//  MadAnalysis 5 is distributed in the hope that it will be useful,
15
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
//  GNU General Public License for more details.
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
18
//  
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
19
//  You should have received a copy of the GNU General Public License
20
//  along with MadAnalysis 5. If not, see <http://www.gnu.org/licenses/>
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
21
//  
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
22
////////////////////////////////////////////////////////////////////////////////
23
112.1.50 by Eric Conte
update all-file with MA5banner + logging.getLogger(MA5)
24
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
25
// STL headers
115.1.9 by Eric Conte
replace fabs by std::abs
26
#include <cmath>
27
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
28
// SampleAnalyzer headers
72.1.29 by Eric Conte
new compilation structure
29
#include "SampleAnalyzer/Commons/Service/TransverseVariables.h"
30
#include "SampleAnalyzer/Commons/Service/LogService.h"
31
#include "SampleAnalyzer/Commons/Service/SortingService.h"
109.1.45 by Eric Conte
no more Root first step
32
#include "SampleAnalyzer/Commons/Vector/MARotation3axis.h"
33
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
34
35
using namespace MA5;
36
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
37
/// -----------------------------------------------
38
/// Funcions related to the computation of the mt2
39
/// -----------------------------------------------
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
40
41
inline int signchange_n(long double t1,long double t2,long double t3,long double t4,long double t5)
42
{
43
  int nsc=0;
44
  if(t1*t2>0) nsc++;
45
  if(t2*t3>0) nsc++;
46
  if(t3*t4>0) nsc++;
47
  if(t4*t5>0) nsc++;
48
  return nsc;
49
}
50
51
inline int signchange_p(long double t1,long double t2,long double t3,long double t4,long double t5)
52
{
53
   int nsc=0;
54
   if(t1*t2<0) nsc++;
55
   if(t2*t3<0) nsc++;
56
   if(t3*t4<0) nsc++;
57
   if(t4*t5<0) nsc++;
58
   return nsc;
59
}
60
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
61
int TransverseVariables::Nsolutions(const double &E)
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
62
{
63
  //obtain the coefficients for the 4th order equation
64
  //divided by Ea^n to make the variable dimensionless
65
  long double A4 = -4.*C2_[0]*C1_[1]*C2_[1]*C1_[2] + 4.*C1_[0]*C2_[1]*C2_[1]*C1_[2] +
66
    C2_[0]*C2_[0]*C1_[2]*C1_[2] + 4.*C2_[0]*C1_[1]*C1_[1]*C2_[2] -
67
    4.*C1_[0]*C1_[1]*C2_[1]*C2_[2] - 2.*C1_[0]*C2_[0]*C1_[2]*C2_[2] + C1_[0]*C1_[0]*C2_[2]*C2_[2];
68
  long double A3 = (-4.*C2_[0]*C2_[1]*C1_[2]*C1_[3] + 8.*C2_[0]*C1_[1]*C2_[2]*C1_[3] -
69
    4.*C1_[0]*C2_[1]*C2_[2]*C1_[3] - 4.*C2_[0]*C1_[1]*C1_[2]*C2_[3] +
70
    8.*C1_[0]*C2_[1]*C1_[2]*C2_[3] - 4.*C1_[0]*C1_[1]*C2_[2]*C2_[3] -
71
    8.*C2_[0]*C1_[1]*C2_[1]*C1_[4] + 8.*C1_[0]*C2_[1]*C2_[1]*C1_[4] +
72
    4.*C2_[0]*C2_[0]*C1_[2]*C1_[4] - 4.*C1_[0]*C2_[0]*C2_[2]*C1_[4] +
73
    8.*C2_[0]*C1_[1]*C1_[1]*C2_[4] - 8.*C1_[0]*C1_[1]*C2_[1]*C2_[4] -
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
74
    4.*C1_[0]*C2_[0]*C1_[2]*C2_[4] + 4.*C1_[0]*C1_[0]*C2_[2]*C2_[4])/E;
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
75
  long double A2 = (4.*C2_[0]*C2_[2]*C1_[3]*C1_[3] - 4.*C2_[0]*C1_[2]*C1_[3]*C2_[3] -
76
    4.*C1_[0]*C2_[2]*C1_[3]*C2_[3] + 4.*C1_[0]*C1_[2]*C2_[3]*C2_[3] -
77
    8.*C2_[0]*C2_[1]*C1_[3]*C1_[4] - 8.*C2_[0]*C1_[1]*C2_[3]*C1_[4] +
78
    16.*C1_[0]*C2_[1]*C2_[3]*C1_[4] + 4.*C2_[0]*C2_[0]*C1_[4]*C1_[4] +
79
    16.*C2_[0]*C1_[1]*C1_[3]*C2_[4] - 8.*C1_[0]*C2_[1]*C1_[3]*C2_[4] -
80
    8.*C1_[0]*C1_[1]*C2_[3]*C2_[4] - 8.*C1_[0]*C2_[0]*C1_[4]*C2_[4] +
81
    4.*C1_[0]*C1_[0]*C2_[4]*C2_[4] - 4.*C2_[0]*C1_[1]*C2_[1]*C1_[5] +
82
    4.*C1_[0]*C2_[1]*C2_[1]*C1_[5] + 2.*C2_[0]*C2_[0]*C1_[2]*C1_[5] -
83
    2.*C1_[0]*C2_[0]*C2_[2]*C1_[5] + 4.*C2_[0]*C1_[1]*C1_[1]*C2_[5] -
84
    4.*C1_[0]*C1_[1]*C2_[1]*C2_[5] - 2.*C1_[0]*C2_[0]*C1_[2]*C2_[5] +
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
85
    2.*C1_[0]*C1_[0]*C2_[2]*C2_[5])/pow(E,2.);
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
86
  long double A1 = (-8.*C2_[0]*C1_[3]*C2_[3]*C1_[4] + 8.*C1_[0]*C2_[3]*C2_[3]*C1_[4] +
87
    8.*C2_[0]*C1_[3]*C1_[3]*C2_[4] - 8.*C1_[0]*C1_[3]*C2_[3]*C2_[4] -
88
    4.*C2_[0]*C2_[1]*C1_[3]*C1_[5] - 4.*C2_[0]*C1_[1]*C2_[3]*C1_[5] +
89
    8.*C1_[0]*C2_[1]*C2_[3]*C1_[5] + 4.*C2_[0]*C2_[0]*C1_[4]*C1_[5] -
90
    4.*C1_[0]*C2_[0]*C2_[4]*C1_[5] + 8.*C2_[0]*C1_[1]*C1_[3]*C2_[5] -
91
    4.*C1_[0]*C2_[1]*C1_[3]*C2_[5] - 4.*C1_[0]*C1_[1]*C2_[3]*C2_[5] -
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
92
    4.*C1_[0]*C2_[0]*C1_[4]*C2_[5] + 4.*C1_[0]*C1_[0]*C2_[4]*C2_[5])/pow(E,3);
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
93
  long double A0 = (-4.*C2_[0]*C1_[3]*C2_[3]*C1_[5] + 4.*C1_[0]*C2_[3]*C2_[3]*C1_[5] +
94
    C2_[0]*C2_[0]*C1_[5]*C1_[5] + 4.*C2_[0]*C1_[3]*C1_[3]*C2_[5] -
95
    4.*C1_[0]*C1_[3]*C2_[3]*C2_[5] - 2.*C1_[0]*C2_[0]*C1_[5]*C2_[5] +
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
96
    C1_[0]*C1_[0]*C2_[5]*C2_[5])/pow(E,4);
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
97
98
  long double C2 = -(A2/2. - 3.*pow(A3,2)/(16.*A4));
99
  long double C1 = -(3.*A1/4. -A2*A3/(8.*A4));
100
  long double C0 = -A0 + A1*A3/(16.*A4);
101
  long double D1 = -2.*A2 - (4.*A4*C1*C1/C2 - 4.*A4*C0 -3.*A3*C1)/C2;
102
  long double D0 = -A1 - 4.*A4*C0*C1/pow(C2,2) + 3.*A3*C0/C2;
103
  long double E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
104
105
  // Find the coefficients for the leading term in the Sturm sequence
106
  // The number of solutions depends on diffence of number of sign changes
107
  // for x->Inf and x->-Inf
108
  int nsol = signchange_n(A4,A4,C2,D1,E0) - signchange_p(A4,A4,C2,D1,E0);
109
  if (nsol < 0) nsol = 0; //rounding effects
110
  return nsol;
111
}
112
113
114
template <typename T> int sgn(T val) { return (T(0) < val) - (val < T(0)); }
115
116
int TransverseVariables::Nsolutions_massless(const double &dsq)
117
{
118
  //obtain the coefficients for the 4th order equation
119
  //divided by Ea^n to make the variable dimensionless
120
  long double a = sgn(p2_.Px())*p2_.Mt()/dsq;
121
  long double b = sgn(p2_.Px())*(msq_*p2_.Mt()/dsq - dsq/(4.*p2_.Mt()));
122
  long double A4 = a*a*C2_[0];
123
  long double A3 = 2.*a*C2_[1]/p2_.Mt();
124
  long double A2 = (2.*a*C2_[0]*b+C2_[2]+2.*a*C2_[3])/p2_.Mt2();
125
  long double A1 = (2.*b*C2_[1]+2.*C2_[4])/pow(p2_.Mt(),3);
126
  long double A0 = (C2_[0]*b*b+2.*b*C2_[3]+C2_[5])/pow(p2_.Mt2(),2);
127
128
  long double C2 = -(A2/2.-3.*pow(A3,2)/(16.*A4));
129
  long double C1 = -(3.*A1/4.-A2*A3/(8.*A4));
130
  long double C0 = -A0+A1*A3/(16.*A4);
131
  long double D1 = -2.*A2-(4.*A4*C1*C1/C2 -4.*A4*C0-3.*A3*C1)/C2;
132
  long double D0 = -A1-4.*A4*C0*C1/(C2*C2)+3.*A3*C0/C2;
133
  long double E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
134
135
  // Find the coefficients for the leading term in the Sturm sequence
136
  // The number of solutions depends on diffence of number of sign changes
137
  // for x->Inf and x->-Inf
138
  int nsol = signchange_n(A4,A4,C2,D1,E0)-signchange_p(A4,A4,C2,D1,E0);
139
  if( nsol < 0 ) nsol=0;  // possible rounding effects
140
  return nsol;
141
}
142
143
144
145
bool TransverseVariables::FindHigh(double &dsqH)
146
{
147
   double x0 = (C1_[2]*C1_[3]-C1_[1]*C1_[4])/(C1_[1]*C1_[1]-C1_[0]*C1_[2]);
148
   double y0 = (C1_[0]*C1_[4]-C1_[1]*C1_[3])/(C1_[1]*C1_[1]-C1_[0]*C1_[2]);
70.1.13 by Benjamin Fuks
Small bug in the MT2 routine (thanks to J. Bernon)
149
   double dsqL = p2_.M()*(2.*m_+p2_.M());
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
150
   do
151
   {
152
      double dsqM = (dsqH + dsqL)/2.;
153
      UpdateC1((dsqM-p2_.M2())/(2.*p2_.Mt2()));
154
      UpdateC2(((dsqM-p1_.M2())/2.+p1met_)/p1_.Mt2());
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
155
      int nsolM = Nsolutions(p2_.Mt());
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
156
      if     (nsolM==2) { dsqH = dsqM; return true; }
157
      else if(nsolM==4) { dsqH = dsqM; continue; }
158
      else if(nsolM==0)
159
      {
160
        UpdateC1((dsqM-p2_.M2())/(2.*p2_.Mt2()));
161
        UpdateC2(((dsqM-p1_.M2())/2.+p1met_)/p1_.Mt2());
162
        // Does the larger ellipse contain the smaller one? 
163
        double dis = C2_[0]*x0*x0+2.*C2_[1]*x0*y0+C2_[2]*y0*y0+2.*C2_[3]*x0+2.*C2_[4]*y0+C2_[5];
164
        if(dis<0) dsqH=dsqM;
165
        else      dsqL=dsqM;
166
      }
167
   } while ((dsqH-dsqL)>0.001);
168
   return false;
169
}
170
171
double TransverseVariables::GetMT2()
172
{
173
  // massless case
174
  if(p1_.M()<=0.1 && p2_.M()<=0.1)  { return GetMT2_massless(); }
175
176
  // Solving the two quadratic equations: initialization of the coefficients
177
  double dsq0 = p2_.M()*(p2_.M() + 2.*m_);
178
  InitCoefs();
179
  UpdateC1( (dsq0-p2_.M2())/(2.*p2_.Mt2()) );
180
  UpdateC2( ((dsq0-p1_.M2())/2.+p1met_)/p1_.Mt2() );
181
182
  // Get the center of the ellipses amd check if the larger ellipse contains
183
  // the smaller one
184
  double x0 = (C1_[2]*C1_[3]-C1_[1]*C1_[4])/(C1_[1]*C1_[1]-C1_[0]*C1_[2]);
185
  double y0 = (C1_[0]*C1_[4]-C1_[1]*C1_[3])/(C1_[1]*C1_[1]-C1_[0]*C1_[2]);
186
  double dis= C2_[0]*x0*x0+2.*C2_[1]*x0*y0+C2_[2]*y0*y0+2.*C2_[3]*x0+2.*C2_[4]*y0+C2_[5];
187
  if(dis<=0.01) { return sqrt(msq_+dsq0); }
188
189
  // If not, check if the larger ellipse contains the center of the smaller one
190
  // and get two estimates for an upper bound on MT2 (dsqH)
191
  double p2x0 = pmx_-x0, p2y0 = pmy_-y0;
192
  double dsqH = 2.*(p1_.Mt()*sqrt(pow(p2x0,2)+pow(p2y0,2)+msq_)-p1_.Px()*p2x0-p1_.Py()*p2y0)
193
    +p1_.M2();
194
  double dsqH2 = 2.*(p1_.Mt()*sqrt(pmtm_)-p1met_)+p1_.M2();
195
  double dsqH3 = 2.*p2_.Mt()*m_ + p2_.M2();
196
  if(dsqH3 > dsqH2) dsqH2 = dsqH3;
197
  if(dsqH  > dsqH2) dsqH  = dsqH2;
198
199
  // Calculating the number of solutions: coefficients for the two quadratic equations
200
  // bissection method
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
201
  int nsolL = Nsolutions(p2_.Mt());
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
202
  if(nsolL>0) { return sqrt(msq_+dsq0); }
203
204
  UpdateC1( (dsqH-p2_.M2())/(2.*p2_.Mt2()) );
205
  UpdateC2( ((dsqH-p1_.M2())/2.+p1met_)/p1_.Mt2() );
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
206
  int nsolH = Nsolutions(p2_.Mt());
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
207
  if(nsolH==nsolL || nsolH==4) { if(!FindHigh(dsqH)) { return sqrt(dsq0+msq_); } }
208
209
  while(sqrt(dsqH+msq_) - sqrt(dsq0+msq_) > 0.001)
210
  {
211
    double dsqM = (dsqH+dsq0)/2.;
212
    UpdateC1( (dsqM-p2_.M2())/(2.*p2_.Mt2()) );
213
    UpdateC2( ((dsqM-p1_.M2())/2.+p1met_)/p1_.Mt2() );
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
214
    int nsolM = Nsolutions(p2_.Mt());
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
215
    if(nsolM==4) { dsqH=dsqM; FindHigh(dsqH); continue; }
216
    if(nsolM!=nsolL) dsqH=dsqM;
217
    if(nsolM==nsolL) dsq0=dsqM;
218
  }
219
  return sqrt(msq_+dsqH);
220
}
221
222
double TransverseVariables::GetMT2_massless()
223
{
224
  // Rotation of all four-momenta so that p2_.Py() = 0
225
  double th=-atan(p2_.Py()/p2_.Px());
109.1.45 by Eric Conte
no more Root first step
226
  MARotation3axis rot(th,MARotation3axis::Zaxis);
227
  rot.rotate(p2_);
228
  rot.rotate(p1_);
70.1.5 by Benjamin Fuks
MT2 variable + macos change of stdc++ library (bug #1250337) + ...
229
  double pxtmp = pmx_*cos(th)-pmy_*sin(th);
230
  double pytmp = sin(th)*pmx_+cos(th)*pmy_;
231
  pmx_ = pxtmp;
232
  pmy_ = pytmp;
233
234
  // Initialization of the C2 coefficients + dsq0 + proceed with the calculation
235
  // of the number of solutions for the lower bourd
236
  double dsq0 = 0.0005/p2_.Mt2();
237
  InitC(p1_,C2_);
238
  UpdateC2( (dsq0+p1met_)/p1_.Mt2() );
239
240
  // Calculating the number of solutions: coefficients for the two quadratic equations
241
  // bissection method
242
  int nsolL = Nsolutions_massless(dsq0);
243
  if(nsolL>0) { return sqrt(msq_+dsq0); }
244
245
  // When both parabolas contain origin: two estimates for an upper bound on MT2 (dsqH)
246
  double dsqH  = 2.*(p1_.Mt()*sqrt(pmtm_) - p1met_);
247
  double dsqH2 = 2.*m_*p2_.Mt();
248
  if(dsqH  < dsqH2) dsqH = dsqH2;
249
250
  UpdateC2( (dsqH/2.+p1met_)/p1_.Mt2() );
251
  int nsolH = Nsolutions_massless(dsqH);
252
253
  // Scanning to get a new lower bound (bissection method)
254
  bool found=false;
255
  if (nsolH==nsolL)
256
  {
257
    for(double mass = m_+0.1; mass < sqrt(msq_+dsqH); mass+=0.1)
258
    {
259
      dsqH = pow(mass,2) - msq_;
260
      UpdateC2( (dsqH/2.+p1met_)/p1_.Mt2() );
261
      nsolH = Nsolutions_massless(dsqH);
262
      if(nsolH>0)  { found=true; dsq0=pow(mass-0.1,2)-msq_; break; }
263
    }
264
    if(!found) { return sqrt(dsq0+msq_); }
265
  }
266
  if(nsolH==nsolL) { return sqrt(dsq0+msq_); }
267
268
  // Now we apply the bissection method
269
  while(sqrt(dsqH+msq_) - sqrt(dsq0+msq_) > 0.001)
270
  {
271
    double dsqM = (dsqH+dsq0)/2.;
272
    UpdateC2( (dsqM/2.+p1met_)/p1_.Mt2() );
273
    int nsolM = Nsolutions_massless(dsqM);
274
    if(nsolM!=nsolL) dsqH=dsqM;
275
    if(nsolM==nsolL) dsq0=dsqM;
276
  }
277
  return sqrt(dsqH+msq_);
278
}
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
279
280
/// -----------------------------------------------
281
/// Funcions related to the computation of the mt2w
282
/// -----------------------------------------------
283
/// Core function for the computation of mt2w
109.1.62 by Benjamin Fuks
logging + -no-root
284
double TransverseVariables::GetMT2W(const ParticleBaseFormat* lep,const ParticleBaseFormat* j1,
285
  const ParticleBaseFormat*j2,const ParticleBaseFormat&met)
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
286
{
287
  /// We define a mt2w region in which we will search for the bissection
288
  /// (default: from mw+mb to 500 GeV)
109.1.62 by Benjamin Fuks
logging + -no-root
289
  InitializeMT2W(lep->momentum(), j1->momentum(), j2->momentum(), met.momentum());
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
290
  double mt_high = 500., upper=500.;
291
  double mt_low  = mw_ + std::max(p2_.M(), p3_.M());
292
293
  /// First, we need to check the 500 GeV hypothesis -> otherwise, we start at threshold
294
  if(!TestComp(mt_high)) mt_high = mt_low;
295
296
  // Scan to find the upper bound
297
  double step=0.5;
298
  while(!TestComp(mt_high) && mt_high < upper+2.*step)
299
  {
300
    mt_low = mt_high;
301
    mt_high += step;
302
  }
303
304
  // No compatible region found under the upper bound -> return upper bound - 1 GeV
305
  if (mt_high > upper) { return upper-2.*step; }
306
307
  // mt_high is compatible -> bissection method
308
  while(mt_high-mt_low>0.001)
309
  {
310
    double mt_mid = (mt_high+mt_low)/2.; 
311
    if(!TestComp(mt_mid)) mt_low  = mt_mid;
312
    else                  mt_high = mt_mid;
313
  }
314
  return mt_high;
315
}
316
317
/// Test if for a given event, the trial top mass is compatible with the real top mass
318
bool TransverseVariables::TestComp(const double &mt)
319
{
320
  // Quick check if the trial top mass is larger than the two possible thresholds
321
  if(mt<(p2_.M()+mw_) || mt<(p3_.M()+mw_)) { return false;}
322
323
  // Calculate the delta,  delta1 and delta2 quantities
324
  double delta = (pow(mt,2.) - mw2_ - p3_.M2())/(2.*p3_.Mt2());
325
  double del1 = mw2_ - p1_.M2();
70.1.35 by Benjamin Fuks
Few bugs corrected in the mt2w implementation (thanks to Jeremy ...
326
  double del2 = pow(mt,2.) - mw2_ - p2_.M2() - 2.*plpb1_;
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
327
328
  // Removing pbz
329
  double aa = (p1_.E()*p2_.Px()-p2_.E()*p1_.Px())/ (p2_.E()*p1_.Pz()-p1_.E()*p2_.Pz());
330
  double bb = (p1_.E()*p2_.Py()-p2_.E()*p1_.Py())/ (p2_.E()*p1_.Pz()-p1_.E()*p2_.Pz());
331
  double cc = (p1_.E()*del2-p2_.E()*del1)/(2.*(p2_.E()*p1_.Pz()-p1_.E()*p2_.Pz()));
332
333
  // Computing the coefficients of the two quadratic equations
334
  C1_.resize(0);
335
  C1_.push_back(E2sq_*(1.+pow(aa,2.))-pow(p2_.Px()+p2_.Pz()*aa,2.));
336
  C1_.push_back(E2sq_*aa*bb-(p2_.Px()+p2_.Pz()*aa)*(p2_.Py()+p2_.Pz()*bb));
337
  C1_.push_back(E2sq_*(1.+pow(bb,2.))-pow(p2_.Py()+p2_.Pz()*bb,2.));
338
  C1_.push_back(E2sq_*aa*cc-(p2_.Px()+p2_.Pz()*aa)*(del2/2.+p2_.Pz()*cc));
339
  C1_.push_back(E2sq_*bb*cc-(p2_.Py()+p2_.Pz()*bb)*(del2/2.+p2_.Pz()*cc));
340
  C1_.push_back(E2sq_*pow(cc,2.)-pow(del2/2.+p2_.Pz()*cc,2.));
341
342
  // Checking if the first equation admits real solutions
343
  if( ((C1_[0]*(C1_[2]*C1_[5]-pow(C1_[4],2.))-C1_[1]*(C1_[1]*C1_[5]-C1_[3]*C1_[4])+
344
    C1_[3]*(C1_[1]*C1_[4]-C1_[2]*C1_[3]))/(C1_[0]+C1_[2]))>0.) { return false; }
345
346
  // Defining the coefficients for the second ellipse
347
  C2_.resize(0);
348
  C2_.push_back(1.-pow(p3_.Px(),2.)/p3_.Mt2());
349
  C2_.push_back(-p3_.Px()*p3_.Py()/p3_.Mt2());
350
  C2_.push_back(1.-pow(p3_.Py(),2.)/p3_.Mt2());
351
  C2_.push_back(delta*p3_.Px());
352
  C2_.push_back(delta*p3_.Py());
353
  C2_.push_back(C2_[0]*pow(pmx_,2.)+2.*C2_[1]*pmx_*pmy_+C2_[2]*pow(pmy_,2.)-2.*C2_[3]*pmx_
354
    -2.*C2_[4]*pmy_+mw2_-pow(delta,2.)*p3_.Et2());
355
  C2_[3] += -C2_[0]*pmx_-C2_[1]*pmy_;
356
  C2_[4] += -C2_[2]*pmy_-C2_[1]*pmx_;
357
358
  // Get a point on the 1st ellipse and checks if it lies within the 2nd ellipse
359
  // It is always possible to define (x0,y0) has ellipse 1 admits real solutions
360
  // if True, then mt is compatible
361
  double x0 = (C1_[2]*C1_[3]-C1_[1]*C1_[4])/(C1_[1]*C1_[1]-C1_[0]*C1_[2]);
362
  double x0sq = pow(x0,2.);
363
  double y0 = (-C1_[1]*x0-C1_[4]+
364
    sqrt(pow(C1_[1]*x0+C1_[4],2.)-C1_[2]*(C1_[0]*x0sq+2.*C1_[3]*x0+C1_[5])))/C1_[2];
365
  double y0sq = pow(y0,2.);
366
  if((C2_[0]*x0sq+2.*C2_[1]*x0*y0+C2_[2]*y0sq+2.*C2_[3]*x0+2.*C2_[4]*y0+C2_[5])<0.)
367
    return true;
368
369
  // Computing the number of intersections between the two ellipses and returning the
370
  // result as a function of the number of intersections
371
  if (Nsolutions(p2_.E())==0) { return false;}
372
  return true;
373
}
374
375
376
/// Wrapper fuction for the computation of mt2w
109.1.62 by Benjamin Fuks
logging + -no-root
377
double TransverseVariables::MT2W(std::vector<const RecJetFormat*> jets, const RecLeptonFormat* lep, const ParticleBaseFormat& met)
70.1.34 by Benjamin Fuks
Implementation of the MT2W variable + sorting functions
378
{
379
  /// We need at least 2 jets
380
  if(jets.size()<2) return 0.;
381
382
  /// Split the jet collection according to b-tags
383
  std::vector<const RecParticleFormat*> bjets, nbjets;
384
  for(unsigned int ii=0 ;ii<jets.size(); ii++)
385
  {
386
    if(jets[ii]->btag())  bjets.push_back(jets[ii]);
387
    else                  nbjets.push_back(jets[ii]);
388
  }
389
  /// pt-ordering
390
  SORTER->sort(nbjets,PTordering);
391
  SORTER->sort(bjets,PTordering);
392
393
  /// We neglect the fourth jets and all the others. If less than 3 jets in total
394
  /// only light jets are considered.
395
  unsigned int N=3;
396
  if(jets.size()<=3) N = nbjets.size();
397
398
  /// no b-jets
399
  /// We select the minimum mt2w obtained from all possible jet combinations
400
  if(bjets.size()==0)
401
  {
402
    double min_mt2w=1e9;
403
    for (unsigned int ii=0; ii<N; ii++)
404
      for (unsigned int jj=0; jj<N; jj++)
405
      {
406
        if (ii==jj) continue;
109.1.62 by Benjamin Fuks
logging + -no-root
407
        double tmp_mt2w = GetMT2W(lep, nbjets[ii], nbjets[jj],met);
408
        if(tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
409
      }
410
      return min_mt2w;
411
  }
412
413
  /// 1 b-jet
414
  else if (bjets.size()==1)
415
  {
416
    double min_mt2w=1e9;
417
    for (unsigned int ii=0; ii<N; ii++)
418
    {
419
      double tmp_mt2w = GetMT2W(lep,bjets[0],nbjets[ii],met);
420
      if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
421
      tmp_mt2w = GetMT2W(lep,nbjets[ii],bjets[0],met);
422
      if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
423
    }
424
    return min_mt2w;
425
  }
426
427
  /// More than 1 b-tag
428
  else
429
  {
430
    double min_mt2w=1e9;
431
    for (unsigned int ii=0; ii<bjets.size(); ii++)
432
      for (unsigned int jj=0; jj<bjets.size(); jj++)
433
      {
434
        if (ii==jj) continue;
435
        double tmp_mt2w = GetMT2W(lep, bjets[ii], bjets[jj],met);
436
        if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
437
      }
438
      return min_mt2w;
439
  }
440
}
441
442
double TransverseVariables::MT2W(std::vector<const MCParticleFormat*> jets, const MCParticleFormat* lep, const ParticleBaseFormat& met)
443
{
444
  /// We need at least 2 jets
445
  if(jets.size()<2) return 0.;
446
447
  /// Split the jet collection according to b-tags
448
  std::vector<const MCParticleFormat*> bjets, nbjets;
449
  for(unsigned int ii=0 ;ii<jets.size(); ii++)
450
  {
451
    if(abs(jets[ii]->pdgid()==5))  bjets.push_back(jets[ii]);
452
    else                          nbjets.push_back(jets[ii]);
453
  }
454
  /// pt-ordering
455
  SORTER->sort(nbjets,PTordering);
456
  SORTER->sort(bjets,PTordering);
457
458
  /// We neglect the fourth jets and all the others. If less than 3 jets in total
459
  /// only light jets are considered.
460
  unsigned int N=3;
461
  if(jets.size()<=3) N = nbjets.size();
462
463
  /// no b-jets
464
  /// We select the minimum mt2w obtained from all possible jet combinations
465
  if(bjets.size()==0)
466
  {
467
    double min_mt2w=1e9;
468
    for (unsigned int ii=0; ii<N; ii++)
469
      for (unsigned int jj=0; jj<N; jj++)
470
      {
471
        if (ii==jj) continue;
472
        double tmp_mt2w = GetMT2W(lep, nbjets[ii], nbjets[jj],met);
473
        if(tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
474
      }
475
      return min_mt2w;
476
  }
477
478
  /// 1 b-jet
479
  else if (bjets.size()==1)
480
  {
481
    double min_mt2w=1e9;
482
    for (unsigned int ii=0; ii<N; ii++)
483
    {
484
      double tmp_mt2w = GetMT2W(lep,bjets[0],nbjets[ii],met);
485
      if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
486
      tmp_mt2w = GetMT2W(lep,nbjets[ii],bjets[0],met);
487
      if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
488
    }
489
    return min_mt2w;
490
  }
491
492
  /// More than 1 b-tag
493
  else
494
  {
495
    double min_mt2w=1e9;
496
    for (unsigned int ii=0; ii<bjets.size(); ii++)
497
      for (unsigned int jj=0; jj<bjets.size(); jj++)
498
      {
499
        if (ii==jj) continue;
500
        double tmp_mt2w = GetMT2W(lep, bjets[ii], bjets[jj],met);
501
        if (tmp_mt2w < min_mt2w) min_mt2w = tmp_mt2w;
502
      }
503
      return min_mt2w;
504
  }
505
}
506
109.1.11 by Benjamin Fuks
updating mt2w
507
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
508
509
/// The alphaT variable
510
void LoopForAlphaT(const unsigned int n1, const std::vector<const MCParticleFormat*> jets,
511
  double &MinDHT, const int last, std::vector<unsigned int> Ids)
512
{
513
   // We have enough information to form the pseudo jets
514
   if(Ids.size()==n1)
515
   {
516
     // Forming the two pseudo jets
517
     std::vector<const MCParticleFormat*> jets1;
518
     std::vector<const MCParticleFormat*> jets2=jets;
519
     for (int j=n1-1; j>=0; j--)
520
     { 
521
        jets1.push_back(jets[Ids[j]]);
522
        jets2.erase(jets2.begin()+Ids[j]);
523
     }
524
525
     // Computing the DeltaHT of the pseudo jets and checking if minimum
526
     double THT1 = 0; double THT2 = 0;
527
     for (unsigned int i=0;i<jets1.size();i++) THT1+=jets1[i]->et();
528
     for (unsigned int i=0;i<jets2.size();i++) THT2+=jets2[i]->et();
115.1.9 by Eric Conte
replace fabs by std::abs
529
     double DeltaHT = std::abs(THT1-THT2);
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
530
     if (DeltaHT<MinDHT) MinDHT=DeltaHT;
531
532
    // Exit
533
    return;
534
   }
535
536
   // The first pseudo jet is incomplete -> adding one element
537
   std::vector<unsigned int> Save=Ids;
538
   for(unsigned int i=last+1; i<=jets.size()-n1+Save.size(); i++)
539
   {
540
     Ids = Save;   
541
     Ids.push_back(i);   
542
     LoopForAlphaT(n1, jets, MinDHT, i, Ids); 
543
   }
544
}
545
546
void LoopForAlphaT(const unsigned int n1, std::vector<RecJetFormat> jets,
547
  double &MinDHT, const int last, std::vector<unsigned int> Ids)
548
{
549
   // We have enough information to form the pseudo jets
550
   if(Ids.size()==n1)
551
   {
552
     // Forming the two pseudo jets
553
     std::vector<RecJetFormat> jets1;
554
     std::vector<RecJetFormat> jets2=jets;
555
     for (int j=n1-1; j>=0; j--)
556
     { 
557
        jets1.push_back(jets[Ids[j]]);
558
        jets2.erase(jets2.begin()+Ids[j]);
559
     }
560
561
     // Computing the DeltaHT of the pseudo jets and checking if minimum
562
     double THT1 = 0; double THT2 = 0;
563
     for (unsigned int i=0;i<jets1.size();i++) THT1+=jets1[i].et();
564
     for (unsigned int i=0;i<jets2.size();i++) THT2+=jets2[i].et();
115.1.9 by Eric Conte
replace fabs by std::abs
565
     double DeltaHT = std::abs(THT1-THT2);
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
566
     if (DeltaHT<MinDHT) MinDHT=DeltaHT;
567
568
    // Exit
569
    return;
570
   }
571
572
   // The first pseudo jet is incomplete -> adding one element
573
   std::vector<unsigned int> Save=Ids;
574
   for(unsigned int i=last+1; i<=jets.size()-n1+Save.size(); i++)
575
   {
576
     Ids = Save;   
577
     Ids.push_back(i);   
578
     LoopForAlphaT(n1, jets, MinDHT, i, Ids); 
579
   }
580
}
581
582
double TransverseVariables::AlphaT(const MCEventFormat* event)
583
{
584
  std::vector<const MCParticleFormat*> jets;
585
586
  // Creating jet collection
587
  for (unsigned int i=0;i<event->particles().size();i++)
588
  {
589
    if (event->particles()[i].statuscode()!=event->particles()[event->particles().size()-1].statuscode()) continue;
590
    if (event->particles()[i].pdgid()!=21 && (abs(event->particles()[i].pdgid())<1 || 
591
        abs(event->particles()[i].pdgid())>5)) continue;
592
    jets.push_back(&event->particles()[i]);
593
  }
594
595
  // safety
596
  if (jets.size()<2) return 0;
597
598
  // dijet event
109.1.45 by Eric Conte
no more Root first step
599
  if (jets.size()==2) return std::min(jets[0]->et(),jets[1]->et()) /
115.1.30 by Eric Conte
remove tabs form h & cpp files
600
                             ( jets[0]->momentum()+jets[1]->momentum() ).Mt();
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
601
602
  double MinDeltaHT = 1e6;
603
604
  // compute vectum sum of jet momenta
109.1.45 by Eric Conte
no more Root first step
605
  MALorentzVector q(0.,0.,0.,0.);
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
606
  for (unsigned int i=0;i<jets.size();i++) q+=jets[i]->momentum();
607
  double MHT = q.Pt();
608
609
  // compute HT
610
  double THT = 0;
611
  for (unsigned int i=0;i<jets.size();i++) THT+=jets[i]->et();
612
613
  // Safety
614
  if (THT==0) return -1.;
615
  else if (MHT/THT>=1) return -1.;
616
617
  // more than 3 jets : split into 2 sets
618
  // n1 = number of jets in the first set
619
  // n2 = number of jets in the second set
620
  for (unsigned int n1=1; n1<=(jets.size()/2); n1++)
621
  {
622
    std::vector<unsigned int> DummyJet;
623
    LoopForAlphaT(n1,jets,MinDeltaHT,-1,DummyJet);
624
  }
625
626
  // Final
627
  return 0.5*(1.-MinDeltaHT/THT)/sqrt(1.-MHT/THT*MHT/THT);
628
}
629
630
double TransverseVariables::AlphaT(const RecEventFormat* event)
631
{
632
  // jets
633
  std::vector<RecJetFormat> jets = event->jets();
634
635
  // safety
636
  if (jets.size()<2) return 0;
637
638
  // dijet event
639
  if (jets.size()==2) return std::min(jets[0].et(),jets[1].et()) / 
109.1.45 by Eric Conte
no more Root first step
640
  ((jets[0].momentum())+(jets[1].momentum())).Mt();
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
641
642
  double MinDeltaHT = 1e6;
643
644
  // compute vectum sum of jet momenta
109.1.45 by Eric Conte
no more Root first step
645
  MALorentzVector q(0.,0.,0.,0.);
70.1.45 by Benjamin Fuks
Splitting the physics services in subcategories
646
  for (unsigned int i=0;i<jets.size();i++) q+=jets[i].momentum();
647
  double MHT = q.Pt();
648
649
  // compute HT
650
  double THT = 0;
651
  for (unsigned int i=0;i<jets.size();i++) THT+=jets[i].et();
652
653
  // Safety
654
  if (THT==0) return -1.;
655
  else if (MHT/THT>=1) return -1.;
656
657
  // more than 3 jets : split into 2 sets
658
  // n1 = number of jets in the first set
659
  // n2 = number of jets in the second set
660
  for (unsigned int n1=1; n1<=(jets.size()/2); n1++)
661
          {
662
            std::vector<unsigned int> DummyJet;
663
    LoopForAlphaT(n1,jets,MinDeltaHT,-1,DummyJet);
664
  }
665
666
  // Final
667
  return 0.5*(1.-MinDeltaHT/THT)/sqrt(1.-MHT/THT*MHT/THT);
668
}
669
670
671
672