CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
mt2w_bisect.cc
Go to the documentation of this file.
1 /***********************************************************************/
2 /* */
3 /* Finding MT2W */
4 /* Reference: arXiv:1203.4813 [hep-ph] */
5 /* Authors: Yang Bai, Hsin-Chia Cheng, */
6 /* Jason Gallicchio, Jiayin Gu */
7 /* Based on MT2 by: Hsin-Chia Cheng, Zhenyu Han */
8 /* May 8, 2012, v1.00a */
9 /* */
10 /***********************************************************************/
11 
12 /*******************************************************************************
13  Usage:
14 
15  1. Define an object of type "mt2w":
16 
17  mt2w_bisect::mt2w mt2w_event;
18 
19  2. Set momenta:
20 
21  mt2w_event.set_momenta(pl,pb1,pb2,pmiss);
22 
23  where array pl[0..3], pb1[0..3], pb2[0..3] contains (E,px,py,pz), pmiss[0..2] contains (0,px,py)
24  for the visible particles and the missing momentum. pmiss[0] is not used.
25  All quantities are given in double.
26 
27  (Or use non-pointer method to do the same.)
28 
29  3. Use mt2w::get_mt2w() to obtain the value of mt2w:
30 
31  double mt2w_value = mt2w_event.get_mt2w();
32 
33 *******************************************************************************/
34 
35 #include <iostream>
36 #include <cmath>
38 
39 using namespace std;
40 
41 namespace heppy {
42 
43  namespace mt2w_bisect {
44 
45  /*The user can change the desired precision below, the larger one of the following two definitions is used. Relative precision less than 0.00001 is not guaranteed to be achievable--use with caution*/
46 
47  const float mt2w::RELATIVE_PRECISION = 0.00001;
48  const float mt2w::ABSOLUTE_PRECISION = 0.0;
49  const float mt2w::MIN_MASS = 0.1;
50  const float mt2w::ZERO_MASS = 0.0;
51  const float mt2w::SCANSTEP = 0.1;
52 
53  mt2w::mt2w(double upper_bound, double error_value, double scan_step) {
54  solved = false;
55  momenta_set = false;
56  mt2w_b = 0.; // The result field. Start it off at zero.
57  this->upper_bound = upper_bound; // the upper bound of search for MT2W, default value is 500 GeV
58  this->error_value =
59  error_value; // if we couldn't find any compatible region below the upper_bound, output mt2w = error_value;
60  this->scan_step = scan_step; // if we need to scan to find the compatible region, this is the step of the scan
61  }
62 
63  double mt2w::get_mt2w() {
64  if (!momenta_set) {
65  cout << " Please set momenta first!" << endl;
66  return error_value;
67  }
68 
69  if (!solved)
70  mt2w_bisect();
71  return mt2w_b;
72  }
73 
74  void mt2w::set_momenta(double *pl, double *pb1, double *pb2, double *pmiss) {
75  // Pass in pointers to 4-vectors {E, px, py, px} of doubles.
76  // and pmiss must have [1] and [2] components for x and y. The [0] component is ignored.
77  set_momenta(
78  pl[0], pl[1], pl[2], pl[3], pb1[0], pb1[1], pb1[2], pb1[3], pb2[0], pb2[1], pb2[2], pb2[3], pmiss[1], pmiss[2]);
79  }
80 
81  void mt2w::set_momenta(double El,
82  double plx,
83  double ply,
84  double plz,
85  double Eb1,
86  double pb1x,
87  double pb1y,
88  double pb1z,
89  double Eb2,
90  double pb2x,
91  double pb2y,
92  double pb2z,
93  double pmissx,
94  double pmissy) {
95  solved = false; //reset solved tag when momenta are changed.
96  momenta_set = true;
97 
98  double msqtemp; //used for saving the mass squared temporarily
99 
100  //l is the visible lepton
101 
102  this->El = El;
103  this->plx = plx;
104  this->ply = ply;
105  this->plz = plz;
106 
107  Elsq = El * El;
108 
109  msqtemp = El * El - plx * plx - ply * ply - plz * plz;
110  if (msqtemp > 0.0) {
111  mlsq = msqtemp;
112  } else {
113  mlsq = 0.0;
114  } //mass squared can not be negative
115  ml = sqrt(mlsq); // all the input masses are calculated from sqrt(p^2)
116 
117  //b1 is the bottom on the same side as the visible lepton
118 
119  this->Eb1 = Eb1;
120  this->pb1x = pb1x;
121  this->pb1y = pb1y;
122  this->pb1z = pb1z;
123 
124  Eb1sq = Eb1 * Eb1;
125 
126  msqtemp = Eb1 * Eb1 - pb1x * pb1x - pb1y * pb1y - pb1z * pb1z;
127  if (msqtemp > 0.0) {
128  mb1sq = msqtemp;
129  } else {
130  mb1sq = 0.0;
131  } //mass squared can not be negative
132  mb1 = sqrt(mb1sq); // all the input masses are calculated from sqrt(p^2)
133 
134  //b2 is the other bottom (paired with the invisible W)
135 
136  this->Eb2 = Eb2;
137  this->pb2x = pb2x;
138  this->pb2y = pb2y;
139  this->pb2z = pb2z;
140 
141  Eb2sq = Eb2 * Eb2;
142 
143  msqtemp = Eb2 * Eb2 - pb2x * pb2x - pb2y * pb2y - pb2z * pb2z;
144  if (msqtemp > 0.0) {
145  mb2sq = msqtemp;
146  } else {
147  mb2sq = 0.0;
148  } //mass squared can not be negative
149  mb2 = sqrt(mb2sq); // all the input masses are calculated from sqrt(p^2)
150 
151  //missing pt
152 
153  this->pmissx = pmissx;
154  this->pmissy = pmissy;
155 
156  //set the values of masses
157 
158  mv = 0.0; //mass of neutrino
159  mw = 80.4; //mass of W-boson
160 
161  //precision?
162 
163  if (ABSOLUTE_PRECISION > 100. * RELATIVE_PRECISION)
164  precision = ABSOLUTE_PRECISION;
165  else
166  precision = 100. * RELATIVE_PRECISION;
167  }
168 
169  void mt2w::mt2w_bisect() {
170  solved = true;
171  cout.precision(11);
172 
173  // In normal running, mtop_high WILL be compatible, and mtop_low will NOT.
174  double mtop_high = upper_bound; //set the upper bound of the search region
175  double mtop_low; //the lower bound of the search region is best chosen as m_W + m_b
176 
177  if (mb1 >= mb2) {
178  mtop_low = mw + mb1;
179  } else {
180  mtop_low = mw + mb2;
181  }
182 
183  // The following if and while deal with the case where there might be a compatable region
184  // between mtop_low and 500 GeV, but it doesn't extend all the way up to 500.
185  //
186 
187  // If our starting high guess is not compatible, start the high guess from the low guess...
188  if (teco(mtop_high) == 0) {
189  mtop_high = mtop_low;
190  }
191 
192  // .. and scan up until a compatible high bound is found.
193  //We can also raise the lower bound since we scaned over a region that is not compatible
194  while (teco(mtop_high) == 0 && mtop_high < upper_bound + 2. * scan_step) {
195  mtop_low = mtop_high;
196  mtop_high = mtop_high + scan_step;
197  }
198 
199  // if we can not find a compatible region under the upper bound, output the error value
200  if (mtop_high > upper_bound) {
201  mt2w_b = error_value;
202  return;
203  }
204 
205  // Once we have an compatible mtop_high, we can find mt2w using bisection method
206  while (mtop_high - mtop_low > precision) {
207  double mtop_mid, teco_mid;
208  //bisect
209  mtop_mid = (mtop_high + mtop_low) / 2.;
210  teco_mid = teco(mtop_mid);
211 
212  if (teco_mid == 0) {
213  mtop_low = mtop_mid;
214  } else {
215  mtop_high = mtop_mid;
216  }
217  }
218  mt2w_b = mtop_high; //output the value of mt2w
219  return;
220  }
221 
222  // for a given event, teco ( mtop ) gives 1 if trial top mass mtop is compatible, 0 if mtop is not.
223 
224  int mt2w::teco(double mtop) {
225  //first test if mtop is larger than mb+mw
226 
227  if (mtop < mb1 + mw || mtop < mb2 + mw) {
228  return 0;
229  }
230 
231  //define delta for convenience, note the definition is different from the one in mathematica code by 2*E^2_{b2}
232 
233  double ETb2sq = Eb2sq - pb2z * pb2z; //transverse energy of b2
234  double delta = (mtop * mtop - mw * mw - mb2sq) / (2. * ETb2sq);
235 
236  //del1 and del2 are \Delta'_1 and \Delta'_2 in the notes eq. 10,11
237 
238  double del1 = mw * mw - mv * mv - mlsq;
239  double del2 = mtop * mtop - mw * mw - mb1sq - 2 * (El * Eb1 - plx * pb1x - ply * pb1y - plz * pb1z);
240 
241  // aa bb cc are A B C in the notes eq.15
242 
243  double aa = (El * pb1x - Eb1 * plx) / (Eb1 * plz - El * pb1z);
244  double bb = (El * pb1y - Eb1 * ply) / (Eb1 * plz - El * pb1z);
245  double cc = (El * del2 - Eb1 * del1) / (2. * Eb1 * plz - 2. * El * pb1z);
246 
247  //calculate coefficients for the two quadratic equations (ellipses), which are
248  //
249  // a1 x^2 + 2 b1 x y + c1 y^2 + 2 d1 x + 2 e1 y + f1 = 0 , from the 2 steps decay chain (with visible lepton)
250  //
251  // a2 x^2 + 2 b2 x y + c2 y^2 + 2 d2 x + 2 e2 y + f2 <= 0 , from the 1 stop decay chain (with W missing)
252  //
253  // where x and y are px and py of the neutrino on the visible lepton chain
254 
255  a1 = Eb1sq * (1. + aa * aa) - (pb1x + pb1z * aa) * (pb1x + pb1z * aa);
256  b1 = Eb1sq * aa * bb - (pb1x + pb1z * aa) * (pb1y + pb1z * bb);
257  c1 = Eb1sq * (1. + bb * bb) - (pb1y + pb1z * bb) * (pb1y + pb1z * bb);
258  d1 = Eb1sq * aa * cc - (pb1x + pb1z * aa) * (pb1z * cc + del2 / 2.0);
259  e1 = Eb1sq * bb * cc - (pb1y + pb1z * bb) * (pb1z * cc + del2 / 2.0);
260  f1 = Eb1sq * (mv * mv + cc * cc) - (pb1z * cc + del2 / 2.0) * (pb1z * cc + del2 / 2.0);
261 
262  // First check if ellipse 1 is real (don't need to do this for ellipse 2, ellipse 2 is always real for mtop > mw+mb)
263 
264  double det1 = (a1 * (c1 * f1 - e1 * e1) - b1 * (b1 * f1 - d1 * e1) + d1 * (b1 * e1 - c1 * d1)) / (a1 + c1);
265 
266  if (det1 > 0.0) {
267  return 0;
268  }
269 
270  //coefficients of the ellptical region
271 
272  a2 = 1 - pb2x * pb2x / (ETb2sq);
273  b2 = -pb2x * pb2y / (ETb2sq);
274  c2 = 1 - pb2y * pb2y / (ETb2sq);
275 
276  // d2o e2o f2o are coefficients in the p2x p2y plane (p2 is the momentum of the missing W-boson)
277  // it is convenient to calculate them first and transfer the ellipse to the p1x p1y plane
278  d2o = -delta * pb2x;
279  e2o = -delta * pb2y;
280  f2o = mw * mw - delta * delta * ETb2sq;
281 
282  d2 = -d2o - a2 * pmissx - b2 * pmissy;
283  e2 = -e2o - c2 * pmissy - b2 * pmissx;
284  f2 = a2 * pmissx * pmissx + 2 * b2 * pmissx * pmissy + c2 * pmissy * pmissy + 2 * d2o * pmissx +
285  2 * e2o * pmissy + f2o;
286 
287  //find a point in ellipse 1 and see if it's within the ellipse 2, define h0 for convenience
288  double x0, h0, y0, r0;
289  x0 = (c1 * d1 - b1 * e1) / (b1 * b1 - a1 * c1);
290  h0 = (b1 * x0 + e1) * (b1 * x0 + e1) - c1 * (a1 * x0 * x0 + 2 * d1 * x0 + f1);
291  if (h0 < 0.0) {
292  return 0;
293  } // if h0 < 0, y0 is not real and ellipse 1 is not real, this is a redundant check.
294  y0 = (-b1 * x0 - e1 + sqrt(h0)) / c1;
295  r0 = a2 * x0 * x0 + 2 * b2 * x0 * y0 + c2 * y0 * y0 + 2 * d2 * x0 + 2 * e2 * y0 + f2;
296  if (r0 < 0.0) {
297  return 1;
298  } // if the point is within the 2nd ellipse, mtop is compatible
299 
300  //obtain the coefficients for the 4th order equation
301  //devided by Eb1^n to make the variable dimensionless
302  long double A4, A3, A2, A1, A0;
303 
304  A4 = -4 * a2 * b1 * b2 * c1 + 4 * a1 * b2 * b2 * c1 + a2 * a2 * c1 * c1 + 4 * a2 * b1 * b1 * c2 -
305  4 * a1 * b1 * b2 * c2 - 2 * a1 * a2 * c1 * c2 + a1 * a1 * c2 * c2;
306 
307  A3 = (-4 * a2 * b2 * c1 * d1 + 8 * a2 * b1 * c2 * d1 - 4 * a1 * b2 * c2 * d1 - 4 * a2 * b1 * c1 * d2 +
308  8 * a1 * b2 * c1 * d2 - 4 * a1 * b1 * c2 * d2 - 8 * a2 * b1 * b2 * e1 + 8 * a1 * b2 * b2 * e1 +
309  4 * a2 * a2 * c1 * e1 - 4 * a1 * a2 * c2 * e1 + 8 * a2 * b1 * b1 * e2 - 8 * a1 * b1 * b2 * e2 -
310  4 * a1 * a2 * c1 * e2 + 4 * a1 * a1 * c2 * e2) /
311  Eb1;
312 
313  A2 = (4 * a2 * c2 * d1 * d1 - 4 * a2 * c1 * d1 * d2 - 4 * a1 * c2 * d1 * d2 + 4 * a1 * c1 * d2 * d2 -
314  8 * a2 * b2 * d1 * e1 - 8 * a2 * b1 * d2 * e1 + 16 * a1 * b2 * d2 * e1 + 4 * a2 * a2 * e1 * e1 +
315  16 * a2 * b1 * d1 * e2 - 8 * a1 * b2 * d1 * e2 - 8 * a1 * b1 * d2 * e2 - 8 * a1 * a2 * e1 * e2 +
316  4 * a1 * a1 * e2 * e2 - 4 * a2 * b1 * b2 * f1 + 4 * a1 * b2 * b2 * f1 + 2 * a2 * a2 * c1 * f1 -
317  2 * a1 * a2 * c2 * f1 + 4 * a2 * b1 * b1 * f2 - 4 * a1 * b1 * b2 * f2 - 2 * a1 * a2 * c1 * f2 +
318  2 * a1 * a1 * c2 * f2) /
319  Eb1sq;
320 
321  A1 = (-8 * a2 * d1 * d2 * e1 + 8 * a1 * d2 * d2 * e1 + 8 * a2 * d1 * d1 * e2 - 8 * a1 * d1 * d2 * e2 -
322  4 * a2 * b2 * d1 * f1 - 4 * a2 * b1 * d2 * f1 + 8 * a1 * b2 * d2 * f1 + 4 * a2 * a2 * e1 * f1 -
323  4 * a1 * a2 * e2 * f1 + 8 * a2 * b1 * d1 * f2 - 4 * a1 * b2 * d1 * f2 - 4 * a1 * b1 * d2 * f2 -
324  4 * a1 * a2 * e1 * f2 + 4 * a1 * a1 * e2 * f2) /
325  (Eb1sq * Eb1);
326 
327  A0 = (-4 * a2 * d1 * d2 * f1 + 4 * a1 * d2 * d2 * f1 + a2 * a2 * f1 * f1 + 4 * a2 * d1 * d1 * f2 -
328  4 * a1 * d1 * d2 * f2 - 2 * a1 * a2 * f1 * f2 + a1 * a1 * f2 * f2) /
329  (Eb1sq * Eb1sq);
330 
331  long double A3sq;
332  /*
333  long double A0sq, A1sq, A2sq, A3sq, A4sq;
334  A0sq = A0*A0;
335  A1sq = A1*A1;
336  A2sq = A2*A2;
337  A4sq = A4*A4;
338  */
339  A3sq = A3 * A3;
340 
341  long double B3, B2, B1, B0;
342  B3 = 4 * A4;
343  B2 = 3 * A3;
344  B1 = 2 * A2;
345  B0 = A1;
346 
347  long double C2, C1, C0;
348  C2 = -(A2 / 2 - 3 * A3sq / (16 * A4));
349  C1 = -(3 * A1 / 4. - A2 * A3 / (8 * A4));
350  C0 = -A0 + A1 * A3 / (16 * A4);
351 
352  long double D1, D0;
353  D1 = -B1 - (B3 * C1 * C1 / C2 - B3 * C0 - B2 * C1) / C2;
354  D0 = -B0 - B3 * C0 * C1 / (C2 * C2) + B2 * C0 / C2;
355 
356  long double E0;
357  E0 = -C0 - C2 * D0 * D0 / (D1 * D1) + C1 * D0 / D1;
358 
359  long double t1, t2, t3, t4, t5;
360  //find the coefficients for the leading term in the Sturm sequence
361  t1 = A4;
362  t2 = A4;
363  t3 = C2;
364  t4 = D1;
365  t5 = E0;
366 
367  //The number of solutions depends on diffence of number of sign changes for x->Inf and x->-Inf
368  int nsol;
369  nsol = signchange_n(t1, t2, t3, t4, t5) - signchange_p(t1, t2, t3, t4, t5);
370 
371  //Cannot have negative number of solutions, must be roundoff effect
372  if (nsol < 0)
373  nsol = 0;
374 
375  int out;
376  if (nsol == 0) {
377  out = 0;
378  } //output 0 if there is no solution, 1 if there is solution
379  else {
380  out = 1;
381  }
382 
383  return out;
384  }
385 
386  inline int mt2w::signchange_n(long double t1, long double t2, long double t3, long double t4, long double t5) {
387  int nsc;
388  nsc = 0;
389  if (t1 * t2 > 0)
390  nsc++;
391  if (t2 * t3 > 0)
392  nsc++;
393  if (t3 * t4 > 0)
394  nsc++;
395  if (t4 * t5 > 0)
396  nsc++;
397  return nsc;
398  }
399  inline int mt2w::signchange_p(long double t1, long double t2, long double t3, long double t4, long double t5) {
400  int nsc;
401  nsc = 0;
402  if (t1 * t2 < 0)
403  nsc++;
404  if (t2 * t3 < 0)
405  nsc++;
406  if (t3 * t4 < 0)
407  nsc++;
408  if (t4 * t5 < 0)
409  nsc++;
410  return nsc;
411  }
412 
413  } //end namespace mt2w_bisect
414 
415 } // namespace heppy
Divides< arg, void > D0
Definition: Factorize.h:135
__host__ __device__ constexpr RandomIt upper_bound(RandomIt first, RandomIt last, const T &value, Compare comp={})
T sqrt(T t)
Definition: SSEVec.h:19
Divides< A, C > D1
Definition: Factorize.h:136
tuple cout
Definition: gather_cfg.py:144
static constexpr float b2
static constexpr float d1
static constexpr float b1