susy_cfa  b611ccad937ea179f86a1f5663960264616c0a20
mt2w_bisect.cpp
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 "mt2w_bisect.hpp"
36 #include <cmath>
37 #include <iostream>
38 
39 using namespace std;
40 
41 namespace mt2w_bisect
42 {
43 
44  mt2w::mt2w(double upper_bound, double error_value, double scan_step)
45  {
46  solved_ = false;
47  momenta_set_ = false;
48  mt2w_b_ = 0.; // The result field. Start it off at zero.
49  upper_bound_ = upper_bound; // the upper bound of search for MT2W, default value is 500 GeV
50  error_value_ = error_value; // if we couldn't find any compatible region below the upper_bound, output mt2w = error_value;
51  scan_step_ = scan_step; // if we need to scan to find the compatible region, this is the step of the scan
52  }
53 
54  double mt2w::get_mt2w()
55  {
56  if (!momenta_set_)
57  {
58  cout <<" Please set momenta first!" << endl;
59  return error_value_;
60  }
61 
62  if (!solved_) mt2w_bisect();
63  return mt2w_b_;
64  }
65 
66  void mt2w::set_momenta(double *pl, double *pb1, double *pb2, double* pmiss)
67  {
68  // Pass in pointers to 4-vectors {E, px, py, px} of doubles.
69  // and pmiss must have [1] and [2] components for x and y. The [0] component is ignored.
70  set_momenta(pl[0], pl[1], pl[2], pl[3],
71  pb1[0], pb1[1], pb1[2], pb1[3],
72  pb2[0], pb2[1], pb2[2], pb2[3],
73  pmiss[1], pmiss[2]);
74  }
75 
76  void mt2w::set_momenta(double El, double plx, double ply, double plz,
77  double Eb1, double pb1x, double pb1y, double pb1z,
78  double Eb2, double pb2x, double pb2y, double pb2z,
79  double pmissx, double pmissy)
80  {
81  solved_ = false; //reset solved tag when momenta are changed.
82  momenta_set_ = true;
83 
84  double msqtemp; //used for saving the mass squared temporarily
85 
86  //l is the visible lepton
87 
88  El_ = El;
89  plx_ = plx;
90  ply_ = ply;
91  plz_ = plz;
92 
93  Elsq_ = El*El;
94 
95  msqtemp = El*El-plx*plx-ply*ply-plz*plz;
96  if (msqtemp > 0.0) {mlsq_ = msqtemp;}
97  else {mlsq_ = 0.0;} //mass squared can not be negative
98  ml_ = sqrt(mlsq_); // all the input masses are calculated from sqrt(p^2)
99 
100  //b1 is the bottom on the same side as the visible lepton
101 
102  Eb1_ = Eb1;
103  pb1x_ = pb1x;
104  pb1y_ = pb1y;
105  pb1z_ = pb1z;
106 
107  Eb1sq_ = Eb1*Eb1;
108 
109  msqtemp = Eb1*Eb1-pb1x*pb1x-pb1y*pb1y-pb1z*pb1z;
110  if (msqtemp > 0.0) {mb1sq_ = msqtemp;}
111  else {mb1sq_ = 0.0;} //mass squared can not be negative
112  mb1_ = sqrt(mb1sq_); // all the input masses are calculated from sqrt(p^2)
113 
114  //b2 is the other bottom (paired with the invisible W)
115 
116  Eb2_ = Eb2;
117  pb2x_ = pb2x;
118  pb2y_ = pb2y;
119  pb2z_ = pb2z;
120 
121  Eb2sq_ = Eb2*Eb2;
122 
123  msqtemp = Eb2*Eb2-pb2x*pb2x-pb2y*pb2y-pb2z*pb2z;
124  if (msqtemp > 0.0) {mb2sq_ = msqtemp;}
125  else {mb2sq_ = 0.0;} //mass squared can not be negative
126  mb2_ = sqrt(mb2sq_); // all the input masses are calculated from sqrt(p^2)
127 
128 
129  //missing pt
130 
131 
132  pmissx_ = pmissx;
133  pmissy_ = pmissy;
134 
135  //set the values of masses
136 
137  mv_ = 0.0; //mass of neutrino
138  mw_ = 80.385; //mass of W-boson
139 
140  //precision?
141 
143  else precision_ = 100.*RELATIVE_PRECISION;
144  }
145 
146  void mt2w::mt2w_bisect()
147  {
148 
149 
150  solved_ = true;
151  cout.precision(11);
152 
153  // In normal running, mtop_high WILL be compatible, and mtop_low will NOT.
154  double mtop_high = upper_bound_; //set the upper bound of the search region
155  double mtop_low; //the lower bound of the search region is best chosen as m_W + m_b
156 
157  if (mb1_ >= mb2_) {mtop_low = mw_ + mb1_;}
158  else {mtop_low = mw_ + mb2_;}
159 
160  // The following if and while deal with the case where there might be a compatable region
161  // between mtop_low and 500 GeV, but it doesn't extend all the way up to 500.
162  //
163 
164  // If our starting high guess is not compatible, start the high guess from the low guess...
165  if (teco(mtop_high)==0) {mtop_high = mtop_low;}
166 
167  // .. and scan up until a compatible high bound is found.
168  //We can also raise the lower bound since we scaned over a region that is not compatible
169  while (teco(mtop_high)==0 && mtop_high < upper_bound_ + 2.*scan_step_) {
170 
171  mtop_low=mtop_high;
172  mtop_high = mtop_high + scan_step_;
173  }
174 
175  // if we can not find a compatible region under the upper bound, output the error value
176  if (mtop_high > upper_bound_) {
177  mt2w_b_ = error_value_;
178  return;
179  }
180 
181  // Once we have an compatible mtop_high, we can find mt2w using bisection method
182  while(mtop_high - mtop_low > precision_)
183  {
184  double mtop_mid,teco_mid;
185  //bisect
186  mtop_mid = (mtop_high+mtop_low)/2.;
187  teco_mid = teco(mtop_mid);
188 
189  if(teco_mid == 0) {mtop_low = mtop_mid;}
190  else {mtop_high = mtop_mid;}
191 
192  }
193  mt2w_b_ = mtop_high; //output the value of mt2w
194  return;
195  }
196 
197  // for a given event, teco ( mtop ) gives 1 if trial top mass mtop is compatible, 0 if mtop is not.
198 
199  int mt2w::teco( double mtop)
200  {
201 
202  //first test if mtop is larger than mb+mw
203 
204  if (mtop < mb1_+mw_ || mtop < mb2_+mw_) {return 0;}
205 
206  //define delta for convenience, note the definition is different from the one in mathematica code by 2*E^2_{b2}
207 
208  double ETb2sq = Eb2sq_ - pb2z_*pb2z_; //transverse energy of b2
209  double delta = (mtop*mtop-mw_*mw_-mb2sq_)/(2.*ETb2sq);
210 
211 
212  //del1 and del2 are \Delta'_1 and \Delta'_2 in the notes eq. 10,11
213 
214  double del1 = mw_*mw_ - mv_*mv_ - mlsq_;
215  double del2 = mtop*mtop - mw_*mw_ - mb1sq_ - 2*(El_*Eb1_-plx_*pb1x_-ply_*pb1y_-plz_*pb1z_);
216 
217  // aa bb cc are A B C in the notes eq.15
218 
219  double aa = (El_*pb1x_-Eb1_*plx_)/(Eb1_*plz_-El_*pb1z_);
220  double bb = (El_*pb1y_-Eb1_*ply_)/(Eb1_*plz_-El_*pb1z_);
221  double cc = (El_*del2-Eb1_*del1)/(2.*Eb1_*plz_-2.*El_*pb1z_);
222 
223 
224  //calculate coefficients for the two quadratic equations (ellipses), which are
225  //
226  // 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)
227  //
228  // 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)
229  //
230  // where x and y are px and py of the neutrino on the visible lepton chain
231 
232  a1_ = Eb1sq_*(1.+aa*aa)-(pb1x_+pb1z_*aa)*(pb1x_+pb1z_*aa);
233  b1_ = Eb1sq_*aa*bb - (pb1x_+pb1z_*aa)*(pb1y_+pb1z_*bb);
234  c1_ = Eb1sq_*(1.+bb*bb)-(pb1y_+pb1z_*bb)*(pb1y_+pb1z_*bb);
235  d1_ = Eb1sq_*aa*cc - (pb1x_+pb1z_*aa)*(pb1z_*cc+del2/2.0);
236  e1_ = Eb1sq_*bb*cc - (pb1y_+pb1z_*bb)*(pb1z_*cc+del2/2.0);
237  f1_ = Eb1sq_*(mv_*mv_+cc*cc) - (pb1z_*cc+del2/2.0)*(pb1z_*cc+del2/2.0);
238 
239  // 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)
240 
241  double det1 = (a1_*(c1_*f1_ - e1_*e1_) - b1_*(b1_*f1_ - d1_*e1_) + d1_*(b1_*e1_-c1_*d1_))/(a1_+c1_);
242 
243  if (det1 > 0.0) {return 0;}
244 
245  //coefficients of the ellptical region
246 
247  a2_ = 1-pb2x_*pb2x_/(ETb2sq);
248  b2_ = -pb2x_*pb2y_/(ETb2sq);
249  c2_ = 1-pb2y_*pb2y_/(ETb2sq);
250 
251  // d2o e2o f2o are coefficients in the p2x p2y plane (p2 is the momentum of the missing W-boson)
252  // it is convenient to calculate them first and transfer the ellipse to the p1x p1y plane
253  d2o_ = -delta*pb2x_;
254  e2o_ = -delta*pb2y_;
255  f2o_ = mw_*mw_ - delta*delta*ETb2sq;
256 
257  d2_ = -d2o_ -a2_*pmissx_ -b2_*pmissy_;
258  e2_ = -e2o_ -c2_*pmissy_ -b2_*pmissx_;
259  f2_ = a2_*pmissx_*pmissx_ + 2*b2_*pmissx_*pmissy_ + c2_*pmissy_*pmissy_ + 2*d2o_*pmissx_ + 2*e2o_*pmissy_ + f2o_;
260 
261  //find a point in ellipse 1 and see if it's within the ellipse 2, define h0 for convenience
262  double x0, h0, y0, r0;
263  x0 = (c1_*d1_-b1_*e1_)/(b1_*b1_-a1_*c1_);
264  h0 = (b1_*x0 + e1_)*(b1_*x0 + e1_) - c1_*(a1_*x0*x0 + 2*d1_*x0 + f1_);
265  if (h0 < 0.0) {return 0;} // if h0 < 0, y0 is not real and ellipse 1 is not real, this is a redundant check.
266  y0 = (-b1_*x0 -e1_ + sqrt(h0))/c1_;
267  r0 = a2_*x0*x0 + 2*b2_*x0*y0 + c2_*y0*y0 + 2*d2_*x0 + 2*e2_*y0 + f2_;
268  if (r0 < 0.0) {return 1;} // if the point is within the 2nd ellipse, mtop is compatible
269 
270 
271  //obtain the coefficients for the 4th order equation
272  //devided by Eb1^n to make the variable dimensionless
273  long double A4, A3, A2, A1, A0;
274 
275  A4 =
276  -4*a2_*b1_*b2_*c1_ + 4*a1_*b2_*b2_*c1_ +a2_*a2_*c1_*c1_ +
277  4*a2_*b1_*b1_*c2_ - 4*a1_*b1_*b2_*c2_ - 2*a1_*a2_*c1_*c2_ +
278  a1_*a1_*c2_*c2_;
279 
280  A3 =
281  (-4*a2_*b2_*c1_*d1_ + 8*a2_*b1_*c2_*d1_ - 4*a1_*b2_*c2_*d1_ - 4*a2_*b1_*c1_*d2_ +
282  8*a1_*b2_*c1_*d2_ - 4*a1_*b1_*c2_*d2_ - 8*a2_*b1_*b2_*e1_ + 8*a1_*b2_*b2_*e1_ +
283  4*a2_*a2_*c1_*e1_ - 4*a1_*a2_*c2_*e1_ + 8*a2_*b1_*b1_*e2_ - 8*a1_*b1_*b2_*e2_ -
284  4*a1_*a2_*c1_*e2_ + 4*a1_*a1_*c2_*e2_)/Eb1_;
285 
286 
287  A2 =
288  (4*a2_*c2_*d1_*d1_ - 4*a2_*c1_*d1_*d2_ - 4*a1_*c2_*d1_*d2_ + 4*a1_*c1_*d2_*d2_ -
289  8*a2_*b2_*d1_*e1_ - 8*a2_*b1_*d2_*e1_ + 16*a1_*b2_*d2_*e1_ +
290  4*a2_*a2_*e1_*e1_ + 16*a2_*b1_*d1_*e2_ - 8*a1_*b2_*d1_*e2_ -
291  8*a1_*b1_*d2_*e2_ - 8*a1_*a2_*e1_*e2_ + 4*a1_*a1_*e2_*e2_ - 4*a2_*b1_*b2_*f1_ +
292  4*a1_*b2_*b2_*f1_ + 2*a2_*a2_*c1_*f1_ - 2*a1_*a2_*c2_*f1_ +
293  4*a2_*b1_*b1_*f2_ - 4*a1_*b1_*b2_*f2_ - 2*a1_*a2_*c1_*f2_ + 2*a1_*a1_*c2_*f2_)/Eb1sq_;
294 
295  A1 =
296  (-8*a2_*d1_*d2_*e1_ + 8*a1_*d2_*d2_*e1_ + 8*a2_*d1_*d1_*e2_ - 8*a1_*d1_*d2_*e2_ -
297  4*a2_*b2_*d1_*f1_ - 4*a2_*b1_*d2_*f1_ + 8*a1_*b2_*d2_*f1_ + 4*a2_*a2_*e1_*f1_ -
298  4*a1_*a2_*e2_*f1_ + 8*a2_*b1_*d1_*f2_ - 4*a1_*b2_*d1_*f2_ - 4*a1_*b1_*d2_*f2_ -
299  4*a1_*a2_*e1_*f2_ + 4*a1_*a1_*e2_*f2_)/(Eb1sq_*Eb1_);
300 
301  A0 =
302  (-4*a2_*d1_*d2_*f1_ + 4*a1_*d2_*d2_*f1_ + a2_*a2_*f1_*f1_ +
303  4*a2_*d1_*d1_*f2_ - 4*a1_*d1_*d2_*f2_ - 2*a1_*a2_*f1_*f2_ +
304  a1_*a1_*f2_*f2_)/(Eb1sq_*Eb1sq_);
305 
306  /*long double A0sq, A1sq, A2sq, A3sq, A4sq;
307  A0sq = A0*A0;
308  A1sq = A1*A1;
309  A2sq = A2*A2;
310  A3sq = A3*A3;
311  A4sq = A4*A4;*/
312  long double A3sq = A3*A3;
313 
314  long double B3, B2, B1, B0;
315  B3 = 4*A4;
316  B2 = 3*A3;
317  B1 = 2*A2;
318  B0 = A1;
319 
320  long double C2, C1, C0;
321  C2 = -(A2/2 - 3*A3sq/(16*A4));
322  C1 = -(3*A1/4. -A2*A3/(8*A4));
323  C0 = -A0 + A1*A3/(16*A4);
324 
325  long double D1, D0;
326  D1 = -B1 - (B3*C1*C1/C2 - B3*C0 -B2*C1)/C2;
327  D0 = -B0 - B3 *C0 *C1/(C2*C2)+ B2*C0/C2;
328 
329  long double E0;
330  E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
331 
332  long double t1,t2,t3,t4,t5;
333  //find the coefficients for the leading term in the Sturm sequence
334  t1 = A4;
335  t2 = A4;
336  t3 = C2;
337  t4 = D1;
338  t5 = E0;
339 
340 
341  //The number of solutions depends on diffence of number of sign changes for x->Inf and x->-Inf
342  int nsol;
343  nsol = signchange_n(t1,t2,t3,t4,t5) - signchange_p(t1,t2,t3,t4,t5);
344 
345  //Cannot have negative number of solutions, must be roundoff effect
346  if (nsol < 0) nsol = 0;
347 
348  int out;
349  if (nsol == 0) {out = 0;} //output 0 if there is no solution, 1 if there is solution
350  else {out = 1;}
351 
352  return out;
353 
354  }
355 
356  inline int mt2w::signchange_n( long double t1, long double t2, long double t3, long double t4, long double t5)
357  {
358  int nsc;
359  nsc=0;
360  if(t1*t2>0) nsc++;
361  if(t2*t3>0) nsc++;
362  if(t3*t4>0) nsc++;
363  if(t4*t5>0) nsc++;
364  return nsc;
365  }
366  inline int mt2w::signchange_p( long double t1, long double t2, long double t3, long double t4, long double t5)
367  {
368  int nsc;
369  nsc=0;
370  if(t1*t2<0) nsc++;
371  if(t2*t3<0) nsc++;
372  if(t3*t4<0) nsc++;
373  if(t4*t5<0) nsc++;
374  return nsc;
375  }
376 
377 }//end namespace mt2w_bisect
STL namespace.
#define ABSOLUTE_PRECISION
Definition: mt2_bisect.hpp:8
#define RELATIVE_PRECISION
Definition: mt2_bisect.hpp:7