mt2  8bbb7ce09375b7fc0edeb89e1fe1dbb76bbd0555
mt2.cpp
Go to the documentation of this file.
1 #include "mt2.hpp"
2 
3 #include <cmath>
4 
5 #include "polynomial.hpp"
6 
7 using namespace std;
8 
9 void MT2::SetTestMass(double test_mass){
10  cached_momenta_ = false;
11  cached_mt2_ = false;
12  m_ = max(test_mass, 0.);
13 }
14 
15 void MT2::SetMomenta(const TLorentzVector &visible_A,
16  const TLorentzVector &visible_B,
17  double invisible_px, double invisible_py){
18  cached_momenta_ = false;
19  cached_mt2_ = false;
20  mA_ = max(visible_A.M(), 0.);
21  xA_ = visible_A.Px();
22  yA_ = visible_A.Py();
23  mB_ = max(visible_B.M(), 0.);
24  xB_ = visible_B.Px();
25  yB_ = visible_B.Py();
26  x_ = invisible_px;
27  y_ = invisible_py;
28  TransformMomenta();
29 }
30 
31 void MT2::SetMomenta(double visible_mass_a, double visible_px_a, double visible_py_a,
32  double visible_mass_b, double visible_px_b, double visible_py_b,
33  double invisible_px, double invisible_py){
34  cached_momenta_ = false;
35  cached_mt2_ = false;
36  mA_ = max(visible_mass_a, 0.);
37  xA_ = visible_px_a;
38  yA_ = visible_py_a;
39  mB_ = max(visible_mass_b, 0.);
40  xB_ = visible_px_b;
41  yB_ = visible_py_b;
42  x_ = invisible_px;
43  y_ = invisible_py;
44  TransformMomenta();
45 }
46 
47 double MT2::GetMT2() const{
48  ComputeMT2();
49  return mt2_;
50 }
51 
52 double MT2::GetTrialMT2(double invisible_px_a,
53  double invisible_py_a) const{
54  Rotate(invisible_px_a, invisible_py_a, rotation_angle_);
55  double invisible_px_b = x_ - invisible_px_a;
56  double invisible_py_b = y_ - invisible_py_a;
57  if(sides_swapped_){
58  swap(invisible_px_a, invisible_px_b);
59  swap(invisible_py_a, invisible_py_b);
60  }
61  double mta = ComputeMT(mA_, xA_, yA_, m_, invisible_px_a, invisible_py_a);
62  double mtb = ComputeMT(mB_, xB_, yB_, m_, invisible_px_b, invisible_py_b);
63  return mta>mtb ? mta : mtb;
64 }
65 
66 void MT2::GetInvisibleMomenta(TLorentzVector &invisible_a,
67  TLorentzVector &invisible_b) const{
68  ComputeMomenta();
69  double invisible_px_a = 0.5*(x_+deltaX_);
70  double invisible_py_a = 0.5*(y_+deltaY_);
71  double invisible_px_b = 0.5*(x_-deltaX_);
72  double invisible_py_b = 0.5*(y_-deltaY_);
73  if(sides_swapped_){
74  swap(invisible_px_a, invisible_px_b);
75  swap(invisible_py_a, invisible_py_b);
76  }
77  Rotate(invisible_px_a, invisible_py_a, -rotation_angle_);
78  Rotate(invisible_px_b, invisible_py_b, -rotation_angle_);
79  invisible_a.SetXYZM(invisible_px_a, invisible_py_a, 0., m_);
80  invisible_b.SetXYZM(invisible_px_b, invisible_py_b, 0., m_);
81 }
82 
83 void MT2::GetInvisibleMomenta(double &invisible_px_a,
84  double &invisible_py_a,
85  double &invisible_px_b,
86  double &invisible_py_b) const{
87  ComputeMomenta();
88  invisible_px_a = 0.5*(x_+deltaX_);
89  invisible_py_a = 0.5*(y_+deltaY_);
90  invisible_px_b = 0.5*(x_-deltaX_);
91  invisible_py_b = 0.5*(y_-deltaY_);
92  if(sides_swapped_){
93  swap(invisible_px_a, invisible_px_b);
94  swap(invisible_py_a, invisible_py_b);
95  }
96  Rotate(invisible_px_a, invisible_py_a, -rotation_angle_);
97  Rotate(invisible_px_b, invisible_py_b, -rotation_angle_);
98 }
99 
100 double MT2::IsUnbalanced() const{
101  ComputeMT2();
102  return unbalanced_;
103 }
104 
106  if(mA_ < mB_){
107  swap(mA_, mB_);
108  swap(xA_, xB_);
109  swap(yA_, yB_);
110  sides_swapped_ = true;
111  }else{
112  sides_swapped_ = false;
113  }
114  rotation_angle_ = -atan2(yA_, xA_);
115  Rotate(xA_, yA_, rotation_angle_);
116  Rotate(xB_, yB_, rotation_angle_);
117  Rotate(x_, y_, rotation_angle_);
118 }
119 
120 void MT2::Rotate(double &x, double &y, double phi){
121  double pt = hypot(y, x);
122  phi += atan2(y, x);
123  x = pt * cos(phi);
124  y = pt * sin(phi);
125 }
126 
127 void MT2::ComputeMT2() const{
128  if(cached_mt2_) return;
129 
130  double lower_bound, upper_bound;
131  ComputeUnbalancedMT2(lower_bound, upper_bound);
132  double middle = lower_bound + 0.5*(upper_bound - lower_bound);
133  unbalanced_ = upper_bound-lower_bound;
134  while(lower_bound < middle && middle < upper_bound){
135  unsigned num_solutions = GetNumSolutions(middle);
136  if(num_solutions > 1){
137  upper_bound = middle;
138  }else{
139  lower_bound = middle;
140  }
141  middle = lower_bound + 0.5*(upper_bound - lower_bound);
142  }
143 
144  mt2_ = upper_bound;
145  cached_mt2_ = true;
146 }
147 
148 void MT2::ComputeUnbalancedMT2(double &lower_bound, double &upper_bound) const{
149  lower_bound = m_ + mA_;
150  upper_bound = -1.;
151  if(mA_ == 0. && m_ == 0. /* && mB_ == 0. implied since mA_ >= mB_*/){
152  //Check for analytic solution in massless case
153  double alpha = (x_*yB_ - xB_*y_)/(xA_*yB_ - xB_*yA_);
154  double beta = (xA_*y_ - x_*yA_)/(xA_*yB_ - xB_*yA_);
155  if(alpha >= 0. && beta >= 0.){
156  deltaX_ = 2.*alpha*xA_ - x_;
157  deltaY_ = 2.*alpha*yA_ - y_;
158  lower_bound = 0.;
159  upper_bound = 0.;
160  cached_momenta_ = true;
161  }
162  }else if(mA_ > 0.){
163  //Check for unbalanced case
164  double xa_mina = m_/mA_ * xA_;
165  double ya_mina = m_/mA_ * yA_;
166  lower_bound = m_ + mA_;
167  upper_bound = ComputeMT(mB_, xB_, yB_, m_, x_-xa_mina, y_-ya_mina);
168  if(upper_bound <= lower_bound){
169  upper_bound = lower_bound;
170  deltaX_ = 2.*xa_mina - x_;
171  deltaY_ = 2.*ya_mina - y_;
172  cached_momenta_ = true;
173  }
174  }
175  if(lower_bound > upper_bound){
176  //Couldn't find analytic solution. Try to set good bounds...
177  lower_bound = m_ + mA_;
178  double mta = ComputeMT(mA_, xA_, yA_, m_, 0.5*x_, 0.5*y_);
179  double mtb = ComputeMT(mB_, xB_, yB_, m_, 0.5*x_, 0.5*y_);
180  upper_bound = max(mta, mtb);
181  if(upper_bound < lower_bound){
182  //Can only happen due to rounding errors in ComputeMT
183  upper_bound = lower_bound;
184  }
185  }
186 }
187 
188 double MT2::ComputeMT(double m1, double x1, double y1,
189  double m2, double x2, double y2){
190  return sqrt(m1*m1+m2*m2+2.*(sqrt((m1*m1+x1*x1+y1*y1)*(m2*m2+x2*x2+y2*y2))-x1*x2-y1*y2));
191 }
192 
193 void MT2::ComputeMomenta() const{
194  if(cached_momenta_) return;
195  ComputeMT2();
196 
197  //Find deltaX_ as root of quartic
198  long double c4, c3, c2, c1, c0;
199  GetCoefficients(mt2_, c4, c3, c2, c1, c0);
200  double high = 10000.;
201  double low = -high;
202  unsigned num_solutions = NumRoots(Polynomial<long double>({c0, c1, c2, c3, c4}), low, high);
203  while(num_solutions == 0 && high < numeric_limits<double>::max()){
204  low*=2.;
205  high*=2.;
206  num_solutions = NumRoots(Polynomial<long double>({c0, c1, c2, c3, c4}), low, high);
207  }
208  double middle = low + 0.5*(high-low);
209  while(low < middle && middle < high){
210  num_solutions = NumRoots(Polynomial<long double>({c0, c1, c2, c3, c4}), low, middle);
211  if(num_solutions == 0){
212  low=middle;
213  }else{
214  high=middle;
215  }
216  middle = low + 0.5*(high-low);
217  }
218  deltaX_ = middle;
219 
220  //Get two possible deltaY from knowin mt of side A and deltaX_
221  long double T2 = 4.*m_*m_ + x_*x_ + y_*y_;
222  long double zetaA2 = xA_*x_ + yA_*y_ + mt2_*mt2_ - mA_*mA_ - m_*m_;
223  long double ETA2 = mA_*mA_ + xA_*xA_ + yA_*yA_;
224  long double XA2 = mA_*mA_ + xA_*xA_;
225  long double YA2 = mA_*mA_ + yA_*yA_;
226  long double kappaA2 = xA_*yA_;
227  long double chiA3 = ETA2*x_ - xA_*zetaA2;
228  long double gammaA3 = ETA2*y_ - yA_*zetaA2;
229  long double lambdaA4 = ETA2*T2 - zetaA2*zetaA2;
230  long double xiA4 = kappaA2*kappaA2 - XA2*YA2;
231  long double rhoA5 = kappaA2*gammaA3 + XA2*chiA3;
232  long double sigmaA6 = gammaA3*gammaA3 - XA2*lambdaA4;
233  double dya1 = (kappaA2*deltaX_-gammaA3+sqrt(xiA4*deltaX_*deltaX_-2.*rhoA5*deltaX_+sigmaA6))/XA2;
234  double dya2 = (kappaA2*deltaX_-gammaA3-sqrt(xiA4*deltaX_*deltaX_-2.*rhoA5*deltaX_+sigmaA6))/XA2;
235 
236  //Pick the one with the right mt2
237  double mta1 = ComputeMT(mA_, xA_, yA_, m_, 0.5*(x_+deltaX_), 0.5*(y_+dya1));
238  double mtb1 = ComputeMT(mB_, xB_, yB_, m_, 0.5*(x_-deltaX_), 0.5*(y_-dya1));
239  double mta2 = ComputeMT(mA_, xA_, yA_, m_, 0.5*(x_+deltaX_), 0.5*(y_+dya2));
240  double mtb2 = ComputeMT(mB_, xB_, yB_, m_, 0.5*(x_-deltaX_), 0.5*(y_-dya2));
241  double mt21 = max(mta1, mtb1);
242  double mt22 = max(mta2, mtb2);
243  if(mt21 <= mt22){
244  deltaY_ = dya1;
245  }else{
246  deltaY_ = dya2;
247  }
248 
249  cached_momenta_ = true;
250 }
251 
252 unsigned MT2::GetNumSolutions(double mt) const{
253  long double c4, c3, c2, c1, c0;
254  GetCoefficients(mt, c4, c3, c2, c1, c0);
255  auto answer = NumRoots(Polynomial<long double>({c0, c1, c2, c3, c4}));
256  return answer;
257 }
258 
259 void MT2::GetCoefficients(double mt,
260  long double &c4,
261  long double &c3,
262  long double &c2,
263  long double &c1,
264  long double &c0) const{
265  long double T2 = 4.*m_*m_ + x_*x_ + y_*y_;
266  long double zetaA2 = xA_*x_ + yA_*y_ + mt*mt - mA_*mA_ - m_*m_;
267  long double ETA2 = mA_*mA_ + xA_*xA_ + yA_*yA_;
268  long double XA2 = mA_*mA_ + xA_*xA_;
269  long double YA2 = mA_*mA_ + yA_*yA_;
270  long double kappaA2 = xA_*yA_;
271  long double chiA3 = ETA2*x_ - xA_*zetaA2;
272  long double gammaA3 = ETA2*y_ - yA_*zetaA2;
273  long double lambdaA4 = ETA2*T2 - zetaA2*zetaA2;
274  long double xiA4 = kappaA2*kappaA2 - XA2*YA2;
275  long double rhoA5 = kappaA2*gammaA3 + XA2*chiA3;
276  long double sigmaA6 = gammaA3*gammaA3 - XA2*lambdaA4;
277  long double zetaB2 = xB_*x_ + yB_*y_ + mt*mt - mB_*mB_ - m_*m_;
278  long double ETB2 = mB_*mB_ + xB_*xB_ + yB_*yB_;
279  long double XB2 = mB_*mB_ + xB_*xB_;
280  long double YB2 = mB_*mB_ + yB_*yB_;
281  long double kappaB2 = xB_*yB_;
282  long double chiB3 = ETB2*x_ - xB_*zetaB2;
283  long double gammaB3 = ETB2*y_ - yB_*zetaB2;
284  long double lambdaB4 = ETB2*T2 - zetaB2*zetaB2;
285  //long double xiB4 = kappaB2*kappaB2 - XB2*YB2;
286  //long double rhoB5 = kappaB2*gammaB3 + XB2*chiB3;
287  //long double sigmaB6 = gammaB3*gammaB3 - XB2*lambdaB4;
288  long double D4 = XA2*kappaB2 - kappaA2*XB2;
289  long double F5 = gammaA3*XB2 + XA2*gammaB3;
290  long double G6 = XA2*XA2*YB2 - 2.*XA2*kappaA2*kappaB2 + kappaA2*kappaA2*XB2 + xiA4*XB2;
291  long double H7 = XA2*gammaA3*kappaB2 - kappaA2*gammaA3*XB2 - rhoA5*XB2 - XA2*XA2*chiB3 - XA2*kappaA2*gammaB3;
292  long double J8 = gammaA3*gammaA3*XB2 + sigmaA6*XB2 + 2.*XA2*gammaA3*gammaB3 + XA2*XA2*lambdaB4;
293  c4 = G6*G6 - 4.*D4*D4*xiA4;
294  c3 = 4.*(G6*H7 - 2.*xiA4*D4*F5 + 2.*rhoA5*D4*D4);
295  c2 = 2.*(G6*J8 + 2.*H7*H7 - 2.*xiA4*F5*F5 + 8.*rhoA5*D4*F5 - 2.*sigmaA6*D4*D4);
296  c1 = 4.*(H7*J8 - 2.*sigmaA6*D4*F5 + 2.*rhoA5*F5*F5);
297  c0 = J8*J8 - 4.*sigmaA6*F5*F5;
298 }
unsigned NumRoots(const Polynomial< CoeffType > &poly)
Definition: polynomial.hpp:273
void ComputeMomenta() const
Definition: mt2.cpp:193
void SetMomenta(const TLorentzVector &visible_A, const TLorentzVector &visible_B, double invisible_px, double invisible_py)
Definition: mt2.cpp:15
double GetMT2() const
Definition: mt2.cpp:47
static void Rotate(double &x, double &y, double phi)
Definition: mt2.cpp:120
void ComputeUnbalancedMT2(double &lower_bound, double &upper_bound) const
Definition: mt2.cpp:148
STL namespace.
void GetInvisibleMomenta(TLorentzVector &invisible_a, TLorentzVector &invisible_b) const
Definition: mt2.cpp:66
double IsUnbalanced() const
Definition: mt2.cpp:100
void GetCoefficients(double mt, long double &c4, long double &c3, long double &c2, long double &c1, long double &c0) const
Definition: mt2.cpp:259
void TransformMomenta()
Definition: mt2.cpp:105
double GetTrialMT2(double invisible_px_a, double invisible_py_a) const
Definition: mt2.cpp:52
static double ComputeMT(double m1, double x1, double y1, double m2, double x2, double y2)
Definition: mt2.cpp:188
void ComputeMT2() const
Definition: mt2.cpp:127
unsigned GetNumSolutions(double mt) const
Definition: mt2.cpp:252
void SetTestMass(double test_mass)
Definition: mt2.cpp:9