babymaker  e95a6a9342d4604277fe7cc6149b6b5b24447d89
lester_mt2_bisect.h
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2014, Christopher Lester, Univeristy of Cambridge
4  *
5  * version 5: arXiv:1411.4312v5
6  * * made more portable by removal of use of __FILE__ and __LINE__ macros in debug statement
7  * * made fewer demands on poor C++ compilers (ROOT5/CINT) by removal of certain inline statements
8  * * added this changelog!
9  *
10  * version 4: arXiv:1411.4312v4
11  * * added copyright information
12  *
13  * version 3: arXiv:1411.4312v3
14  * * added option to turn on/off deci-sectioning
15  * * made code slightly slower for readability gain
16  *
17  * version 2: arXiv:1411.4312v2
18  * * no changes w.r.t. version 1
19  *
20  * version 1: arXiv:1411.4312v1
21  * * initial public release
22  *
23  * This file will let you calculate MT2 or Asymmetric MT2 relatively easily.
24  * An example showing how to do so, may be found below this copyright message.
25  *
26  * (Note that this is a low-level library. Various wrappers exist around
27  * it to allow easier interfacing to ROOT or ATLAS code.)
28  *
29  * If you use this implementation, please cite:
30  *
31  * http://arxiv.org/abs/1411.4312
32  *
33  * as the paper documenting this particular implementation.
34  *
35  * You might also need to cite:
36  *
37  * http://arxiv.org/abs/hep-ph/9906349
38  * Journal reference: Phys.Lett.B463:99-103,1999
39  * DOI: 10.1016/S0370-2693(99)00945-4
40  *
41  * as the paper defining MT2.
42  *
43  * Here is an example of it's use:
44 
45 event 2355...
46 double mVisA = 0; // mass of visible object on side A. Must be >=0.
47 double pxA = 179.52; // x momentum of visible object on side A.
48 double pyA = -19.815; // y momentum of visible object on side A.
49 
50 double mVisB = 0; // mass of visible object on side B. Must be >=0.
51 double pxB = -8.435; // x momentum of visible object on side B.
52 double pyB = 13.652; // y momentum of visible object on side B.
53 
54 double pxMiss = -188.19; // x component of missing transverse momentum.
55 double pyMiss = 188.28; // y component of missing transverse momentum.
56 
57 double chiA = 0; // hypothesised mass of invisible on side A. Must be >=0.
58 double chiB = 0; // hypothesised mass of invisible on side B. Must be >=0.
59 
60 //event 5662...
61  double mVisA = 0; // mass of visible object on side A. Must be >=0.
62  double pxA = 55.6; // x momentum of visible object on side A.
63  double pyA = 49.76; // y momentum of visible object on side A.
64 
65  double mVisB = 0; // mass of visible object on side B. Must be >=0.
66  double pxB = -12.5; // x momentum of visible object on side B.
67  double pyB = -14.5; // y momentum of visible object on side B.
68 
69  double pxMiss = -264; // x component of missing transverse momentum.
70  double pyMiss = -378; // y component of missing transverse momentum.
71 
72  double chiA = 0; // hypothesised mass of invisible on side A. Must be >=0.
73  double chiB = 0; // hypothesised mass of invisible on side B. Must be >=0.
74 double desiredPrecisionOnMt2 = 0; // Must be >=0. If 0 alg aims for machine precision. if >0, MT2 computed to supplied absolute precision.
75 
76 
77  //event 1827...
78  double mVisA = 0; // mass of visible object on side A. Must be >=0.
79  double pxA = -174.96; // x momentum of visible object on side A.
80  double pyA = 105; // y momentum of visible object on side A.
81 
82  double mVisB = 0; // mass of visible object on side B. Must be >=0.
83  double pxB = 42.707; // x momentum of visible object on side B.
84  double pyB = -6.4748; // y momentum of visible object on side B.
85 
86  double pxMiss = 429.9; // x component of missing transverse momentum.
87  double pyMiss = -111.5; // y component of missing transverse momentum.
88 
89  double chiA = 0; // hypothesised mass of invisible on side A. Must be >=0.
90  double chiB = 0; // hypothesised mass of invisible on side B. Must be >=0.
91  double desiredPrecisionOnMt2 = 0; // Must be >=0. If 0 alg aims for machine precision. if >0, MT2 computed to supplied absolute precision.
92 
93 // asymm_mt2_lester_bisect::disableCopyrightMessage();
94 
95 double MT2 = asymm_mt2_lester_bisect::get_mT2(
96  mVisA, pxA, pyA,
97  mVisB, pxB, pyB,
98  pxMiss, pyMiss,
99  chiA, chiB,
100  desiredPrecisionOnMt2);
101 
102 
103 */
104 
105 #ifndef LESTER_TESTWHETHERELLIPSESAREDISJOINT_H
106 #define LESTER_TESTWHETHERELLIPSESAREDISJOINT_H
107 
108 #include <cmath> // for fabs( ... )
109 
110 /*
111  * The
112  *
113  * bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2);
114  *
115  * function determines whether two ellipses (not both singular) are disjoint.
116  * Ellipses are assumed to be solid objects with a filled interior.
117  * They are disjoint it no part of their interiors overlap.
118  * Singular (in this context) is defined below.
119  *
120  * It uses the method of:
121 
122 Computer Aided Geometric Design 23 (2006) 324–350
123 A new approach to characterizing the relative position of two ellipses depending on one parameter
124 Fernando Etayo 1,3, Laureano Gonzalez-Vega ∗,2,3, Natalia del Rio 3
125 Departamento de Matematicas, Estadistica y Computacion, Universidad de Cantabria, Spain
126 Received 15 September 2004; received in revised form 2 November 2005; accepted 10 January 2006 Available online 28 February 2006
127 
128 pointed out to me by Gary B. Huges and Mohcine Chraibi authors of
129 
130  Comput Visual Sci (2012) 15:291–301 DOI 10.1007/s00791-013-0214-3
131  Calculating ellipse overlap areas Gary B. Hughes · Mohcine Chraibi
132 
133  * Note:
134  *
135  * Though the paper above talks only about ellipses, from playing with some test cases, I (CGL) have conjectured that the algorithm actually works well even if the conics are parabolas provided that the axx>0&&ayy>0 test is reduced to axx>=0&&ayy>=0&&axx*ayy!=0 ... which is true is good news for the similicity of the MT2 calculator ... as the MT2 calculator will not need to distinguish these two possibilities. In a private communication between me (CGL) and the authors of Computer Aided Geometric Design 23 (2006) 324–350, the authors have indicated that it is not unreasonable to believe that the code does indeed work on the parabolica cases too. This algorithm relies on that generalisation, which may be the subject of a paper (to appear) from Etayo and Gonzalez-Vega.
136  *
137  *
138  * Definition: an ellipse is defined with respect to cartesian co-ordinates (x,y) by an equation of the form;
139  *
140  * xVec^T A xVec = 0 (1)
141  *
142  * where xVec is a columnar three vec containing (x,y,1) and where A is a symmetric matrix having elements:
143  *
144  * [ axx axy ax ]
145  * A = [ axy ayy ay ]
146  * [ ax ay a ].
147  *
148  * Therfore the ellipse equation would look like:
149  *
150  * axx x^2 + 2 axy x y + ayy y^2 + 2 ax x + 2 ay y + a = 0.
151  *
152  * Note that this parametrisation has one parameter too many ... the "A"-matrix can be multiplied by a non-zero constant, and the ellipse is not changed.
153  * Etayo et al's implementation REQUIRES that axx and ayy be strictly positive.
154  * The implementation herein doesn't quite enforce that. The implementation herein allows axx or ayy to be non-negative .... and it is left to the user to ensure that axx and ayy are not exactly zero.
155  * Note also that (1) is general enough to contain all conic sections, so it is left to the user to ensure that only values of A consistent
156  * with (non-singluar) ellipses are fed into the program below. For our purposes, an ellipse is "singular" iff coeffLamPow3 (see below) is zero.
157  */
158 
159 namespace Lester {
160 
162 
163 
164  // Constructor for non-degenerate ellipses:
165  /*
166  * Ellipse is represented algebraically by:
167  * c_xx x^2 + 2 c_xy x y + c_yy y^2 + 2 c_x x + 2 c_y y + c = 0.
168  */
170  const double c_xx2,
171  const double c_yy2,
172  const double c_xy2,
173  const double c_x2,
174  const double c_y2,
175  const double c2) :
176  c_xx(c_xx2),
177  c_yy(c_yy2),
178  c_xy(c_xy2),
179  c_x(c_x2),
180  c_y(c_y2),
181  c(c2) {
182  //Etayo et al REQUIRE that c_xx and c_yy are non-negative, so:
183  if (c_xx<0 || c_yy<0) {
184  throw "precondition violation";
185  }
186  setDet();
187  }
189  }
190  void setDet() {
191  det = (2.0*c_x*c_xy*c_y + c*c_xx*c_yy - c_yy*c_x*c_x - c*c_xy*c_xy - c_xx*c_y*c_y) ;
192  }
193  // Consstructor for degenerate ellipse (i.e. a "dot" at (x0,y0) ).
195  const double x0,
196  const double y0) :
197  c_xx(1),
198  c_yy(1),
199  c_xy(0),
200  c_x(-x0),
201  c_y(-y0),
202  c(x0*x0 + y0*y0),
203  det(0) {
204  }
205  double lesterFactor(const EllipseParams & e2) const {
206  const EllipseParams & e1 = *this;
207  const double ans = e1.c_xx*e1.c_yy*e2.c + 2.0*e1.c_xy*e1.c_y*e2.c_x - 2.0*e1.c_x*e1.c_yy*e2.c_x + e1.c*e1.c_yy*e2.c_xx - 2.0*e1.c*e1.c_xy*e2.c_xy + 2.0*e1.c_x*e1.c_y*e2.c_xy + 2.0*e1.c_x*e1.c_xy*e2.c_y - 2.0*e1.c_xx*e1.c_y*e2.c_y + e1.c*e1.c_xx*e2.c_yy - e2.c_yy*(e1.c_x*e1.c_x) - e2.c*(e1.c_xy*e1.c_xy) - e2.c_xx*(e1.c_y*e1.c_y);
208  return ans;
209  }
210  bool operator==(const EllipseParams & other) const {
211  return
212  c_xx == other.c_xx &&
213  c_yy == other.c_yy &&
214  c_xy == other.c_xy &&
215  c_x == other.c_x &&
216  c_y == other.c_y &&
217  c == other.c;
218  }
219  public:
220  // Data
221  double c_xx;
222  double c_yy;
223  double c_xy; // note factor of 2 above
224  double c_x; // note factor of 2 above
225  double c_y; // note factor of 2 above
226  double c;
227  double det; // The determinant of the 3x3 conic matrix
228 };
229 
230 // This is the interface: users should call this function:
231 bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2);
232 
233 // This is an implementation thing: users should not call it:
234 bool __private_ellipsesAreDisjoint(const double coeffLamPow3, const double coeffLamPow2, const double coeffLamPow1, const double coeffLamPow0);
235 
236 bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2) {
237  /* We want to construct the polynomial "Det(lamdba A + B)" where A and B are the 3x3 matrices associated with e1 and e2, and we want to get that
238  polynomial in the form lambda^3 + a lambda^2 + b lambda + c.
239 
240 
241  Note that by default we will not have unity as the coefficient of the lambda^3 term, however the redundancy in the parametrisation of A and B allows us to scale the whole ply until the first term does have a unit coefficient.
242  */
243 
244  if (e1==e2) {
245  return false; // Probably won't catch many cases, but may as well have it here.
246  }
247 
248  // first get unscaled terms:
249  const double coeffLamPow3 = e1.det; // Note that this is the determinant of the symmetric matrix associated with e1.
250  const double coeffLamPow2 = e1.lesterFactor(e2);
251  const double coeffLamPow1 = e2.lesterFactor(e1);
252  const double coeffLamPow0 = e2.det; // Note that this is the determinant of the symmetric matrix associated with e2.
253 
254  // Since question is "symmetric" and since we need to dovide by coeffLamPow3 ... do this the way round that involves dividing by the largest number:
255 
256  if (fabs(coeffLamPow3) >= fabs(coeffLamPow0)) {
257  return __private_ellipsesAreDisjoint(coeffLamPow3, coeffLamPow2, coeffLamPow1, coeffLamPow0); // normal order
258  } else {
259  return __private_ellipsesAreDisjoint(coeffLamPow0, coeffLamPow1, coeffLamPow2, coeffLamPow3); // reversed order
260  }
261 }
262 bool __private_ellipsesAreDisjoint(const double coeffLamPow3, const double coeffLamPow2, const double coeffLamPow1, const double coeffLamPow0) {
263 
264  // precondition of being called:
265  //assert(fabs(coeffLamPow3)>=fabs(coeffLamPow0));
266 
267  if(coeffLamPow3==0) {
268  // The ellipses were singular in some way.
269  // Cannot determine whether they are overlapping or not.
270  throw 1;
271  }
272 
273  // now scale terms to monomial form:
274  const double a = coeffLamPow2 / coeffLamPow3;
275  const double b = coeffLamPow1 / coeffLamPow3;
276  const double c = coeffLamPow0 / coeffLamPow3;
277 
278 #ifdef LESTER_DEEP_FIDDLE
279  {
280  const double thing1 = -3.0*b + a*a;
281  const double thing2 = -27.0*c*c + 18.0*c*a*b + a*a*b*b - 4.0*a*a*a*c - 4.0*b*b*b;
282  std::cout
283  << (thing1>0) << " && " << (thing2>0) << " && [[ " << (a>=0) << " " << (3.0*a*c + b*a*a - 4.0*b*b<0) << " ] or "
284  << "[ " << (a< 0) << " ] =("<< ((a >= 0 /*&& thing1 > 0*/ && 3.0*a*c + b*a*a - 4.0*b*b< 0 /*&& thing2 > 0*/) ||
285  (a < 0 /*&& thing1 > 0*/ /*&& thing2 > 0*/)) << ")] " << (
286  ( (a >= 0 && thing1 > 0 && 3.0*a*c + b*a*a - 4.0*b*b< 0 && thing2 > 0) ||
287  (a < 0 && thing1 > 0 && thing2 > 0))
288 
289  ) << std::endl;
290  }
291 #endif
292 
293  // Use the main result of the above paper:
294  const double thing1 = -3.0*b + a*a;
295  if (thing1<=0) return false;
296  const double thing2 = -27.0*c*c + 18.0*c*a*b + a*a*b*b - 4.0*a*a*a*c - 4.0*b*b*b;
297  if (thing2<=0) return false;
298 
299  // ans true means ellipses are disjoint:
300  const bool ans = ( (a >= 0 /*&& thing1 > 0*/ && 3.0*a*c + b*a*a - 4.0*b*b< 0 /*&& thing2 > 0*/) ||
301  (a < 0 /*&& thing1 > 0*/ /*&& thing2 > 0*/));
302  return ans;
303 
304 }
305 
306 }
307 
308 #endif
309 
310 
311 
312 
313 
314 
315 
316 
317 #ifndef ASYMM_MT2_BISECT_H
318 #define ASYMM_MT2_BISECT_H
319 
320 #include <iostream>
321 #include <iomanip>
322 #include <cmath>
323 #include <cassert>
324 
325 
327  public:
328 
329  static const int MT2_ERROR=-1;
330 
331  static double get_mT2( // returns asymmetric mT2 (which is >=0), or returns a negative number (such as MT2_ERROR) in the case of an error.
332  const double mVis1, const double pxVis1, const double pyVis1,
333  const double mVis2, const double pxVis2, const double pyVis2,
334  const double pxMiss, const double pyMiss,
335  const double mInvis1, const double mInvis2,
336  const double desiredPrecisionOnMT2=0, // This must be non-negative. If set to zero (default) MT2 will be calculated to the highest precision available on the machine (or as close to that as the algorithm permits). If set to a positive value, MT2 (note that is MT2, not its square) will be calculated to within +- desiredPrecisionOnMT2. Note that by requesting precision of +- 0.01 GeV on an MT2 value of 100 GeV can result in speedups of a factor of ...
337  const bool useDeciSectionsInitially=true // If true, interval is cut at the 10% point until first acceptance, which gives factor 3 increase in speed calculating kinematic min, but 3% slowdown for events in the bulk. Is on (true) by default, but can be turned off by setting to false.
338  ) {
339 
340  const double mT2_Sq = get_mT2_Sq(
341  mVis1, pxVis1, pyVis1,
342  mVis2, pxVis2, pyVis2,
343  pxMiss,pyMiss,
344  mInvis1, mInvis2,
345  desiredPrecisionOnMT2,
346  useDeciSectionsInitially);
347  if (mT2_Sq==MT2_ERROR) {
348  return MT2_ERROR;
349  }
350  return sqrt(mT2_Sq);
351  }
352 
353  static void disableCopyrightMessage(const bool printIfFirst=false) {
354  static bool first = true;
355  if (first && printIfFirst) {
356  std::cout
357  << "\n\n"
358  << "#=========================================================\n"
359  << "# To disable this message, place a call to \n"
360  << "# \n"
361  << "# asymm_mt2_lester_bisect::disableCopyrightMessage();\n"
362  << "# \n"
363  << "# somewhere before you begin to calculate your MT2 values.\n"
364  << "#=========================================================\n"
365  << "# You are calculating symmetric or asymmetric MT2 using\n"
366  << "# the implementation defined in:\n"
367  << "# \n"
368  << "# http://arxiv.org/abs/1411.4312\n"
369  << "# \n"
370  << "# Please cite the paper above if you use the MT2 values\n"
371  << "# for a scholarly purpose. For the variable MT2 itself,\n"
372  << "# please also cite:\n"
373  << "# \n"
374  << "# http://arxiv.org/abs/hep-ph/9906349\n"
375  << "#=========================================================\n"
376  << "\n\n" << std::flush;
377  }
378  first = false;
379  }
380 
381  static double get_mT2_Sq( // returns square of asymmetric mT2 (which is >=0), or returns a negative number (such as MT2_ERROR) in the case of an error.
382  const double mVis1, const double pxVis1, const double pyVis1,
383  const double mVis2, const double pxVis2, const double pyVis2,
384  const double pxMiss, const double pyMiss,
385  const double mInvis1, const double mInvis2,
386  const double desiredPrecisionOnMT2=0, // This must be non-negative. If set to zero (default) MT2 will be calculated to the highest precision available on the machine (or as close to that as the algorithm permits). If set to a positive value, MT2 (note that is MT2, not its square) will be calculated to within +- desiredPrecisionOnMT2. Note that by requesting precision of +- 0.01 GeV on an MT2 value of 100 GeV can resJult in speedups of a factor of ..
387  const bool useDeciSectionsInitially=true // If true, interval is cut at the 10% point until first acceptance, which gives factor 3 increase in speed calculating kinematic min, but 3% slowdown for events in the bulk. Is on (true) by default, but can be turned off by setting to false.
388  ) {
389 
390 
391  disableCopyrightMessage(true); // By supplying an argument to disable, we actually ask for the message to be printed, if printing is not already disabled. This counterintuitive function naming is to avoid the need to introduce static variable initialisations ....
392 
393  const double m1Min = mVis1+mInvis1; // when parent has this mass, ellipse 1 has smallest physical size
394  const double m2Min = mVis2+mInvis2; // when parent has this mass, ellipse 2 has smallest physical size
395 
396  if (m1Min>m2Min) {
397  // swap 1 and 2
399  mVis2, pxVis2, pyVis2,
400  mVis1, pxVis1, pyVis1,
401  pxMiss, pyMiss,
402  mInvis2, mInvis1,
403  desiredPrecisionOnMT2
404  );
405  }
406 
407  // By now, we can be sure that m1Min <= m2Min
408  assert(m1Min<=m2Min);
409 
410  const double mMin = m2Min; // when parent has this mass, both ellipses are physical, and at least one has zero size. Note that the name "min" expresses that it is the minimum potential parent mass we should consider, not that it is the min of m1Min and m2Min. It is in fact the MAX of them!
411 
412  // TODO: What about rounding? What about idiots who give us mVis values that have been computed from E^2-p^2 terms that are perilously close to zero, or perilously degenerate?
413 
414  const double msSq = mVis1*mVis1;
415  const double sx = pxVis1;
416  const double sy = pyVis1;
417  const double mpSq = mInvis1*mInvis1;
418 
419  const double mtSq = mVis2*mVis2;
420  const double tx = pxVis2;
421  const double ty = pyVis2;
422  const double mqSq = mInvis2*mInvis2;
423 
424  const double sSq = sx*sx + sy*sy;
425  const double tSq = tx*tx + ty*ty;
426  const double pMissSq = pxMiss*pxMiss + pyMiss*pyMiss;
427  const double massSqSum = msSq + mtSq + mpSq + mqSq;
428  const double scaleSq = (massSqSum + sSq + tSq + pMissSq)/8.0;
429 
430 // #define LESTER_DBG 1
431 
432 #ifdef LESTER_DBG
433  std::cout <<"\nMOO ";
434 #endif
435  // Check for an easy MT2 zero, not because we think it will speed up many cases, but because it will allow us to, ever after, assume that scaleSq>0.
436  if (scaleSq==0) {
437  return 0;
438  }
439  const double scale = sqrt(scaleSq);
440 
441  // disjoint at mMin. So find an mUpper at which they are not disjoint:
442  double mLower = mMin;
443  double mUpper = mMin + scale; // since scaleSq is guaranteed to be >0 at this stage, the adition of scaleSq quarantees that mUpperSq is also >0, so it can be exponentially grown (later) by doubling.
444  unsigned int attempts=0;
445  const unsigned int maxAttempts=10000;
446  while (true) {
447  ++attempts;
448 
449  const double mUpperSq = mUpper*mUpper;
450  const Lester::EllipseParams & side1=helper(mUpperSq, msSq, -sx, -sy, mpSq, 0, 0 ); // see side1Coeffs in mathematica notebook
451  const Lester::EllipseParams & side2=helper(mUpperSq, mtSq, +tx, +ty, mqSq, pxMiss, pyMiss); // see side2Coeffs in mathematica notebook
452 
453  bool disjoint;
454  try {
455  disjoint = Lester::ellipsesAreDisjoint(side1, side2);
456  } catch (...) {
457  return MT2_ERROR;
458  }
459 
460  if (!disjoint) {
461  break;
462  }
463 
464  if (attempts>=maxAttempts) {
465  std::cerr << "MT2 algorithm failed to find upper bound to MT2" << std::endl;
466  return MT2_ERROR;
467  }
468 
469 #ifdef LESTER_DBG
470  std::cout << " - ";
471 #endif
472  mUpper *= 2; // grow mUpper exponentially
473  }
474 
475  //const double tol = relativeTolerance * sqrt(scaleSq);
476 
477  // Now begin the bisection:
478  bool goLow = useDeciSectionsInitially;
479  while(desiredPrecisionOnMT2<=0 || mUpper-mLower>desiredPrecisionOnMT2) {
480 
481  const double trialM = ( goLow ?
482  (mLower*15+mUpper)/16 // bias low until evidence this is not a special case
483  :
484  (mUpper + mLower)/2.0 // bisect
485  ); // worry about this not being between mUpperSq and mLowerSq! TODO
486 
487  if (trialM<=mLower || trialM>=mUpper) {
488  // We reached a numerical precision limit: the interval can no longer be bisected!
489 #ifdef LESTER_DBG
490  std::cout << " MACHINE_PREC " << std::setprecision(10) << mLower << " " << trialM << " " << mUpper << " " << mUpper-mLower << " " << desiredPrecisionOnMT2 << std::endl;
491 #endif
492  return trialM*trialM;
493  }
494  const double trialMSq = trialM * trialM;
495  const Lester::EllipseParams & side1 = helper(trialMSq, msSq, -sx, -sy, mpSq, 0, 0 ); // see side1Coeffs in mathematica notebook
496  const Lester::EllipseParams & side2 = helper(trialMSq, mtSq, +tx, +ty, mqSq, pxMiss, pyMiss); // see side2Coeffs in mathematica notebook
497 
498  try {
499  const bool disjoint = Lester::ellipsesAreDisjoint(side1, side2);
500  if (disjoint) {
501  mLower = trialM;
502  goLow = false;
503 #ifdef LESTER_DBG
504  std::cout << "UP " ;
505 #endif
506  } else {
507  mUpper = trialM;
508 #ifdef LESTER_DBG
509  std::cout << "== ";
510 #endif
511  }
512  } catch (...) {
513  // The test for ellipses being disjoint failed ... this means the ellipses became degenerate, which can only happen right at the bottom of the MT2 search range (subject to numerical precision). So:
514 #ifdef LESTER_DBG
515  std::cout << " THROW " << std::endl;
516 #endif
517  return mLower*mLower;
518  }
519  }
520 
521  const double mAns = (mLower+mUpper)/2.0;
522 
523 #ifdef LESTER_DBG
524  std::cout << " USER_PREC " << std::endl;
525 #endif
526  return mAns*mAns;
527  };
528  private:
529  static double lestermax(const double x, const double y) {
530  return (x>y)?x:y;
531  }
532  static const Lester::EllipseParams helper(const double mSq, // The test parent-mass value (squared)
533  const double mtSq, const double tx, const double ty, // The visible particle transverse momentum
534  const double mqSq, // The mass of the invisible particle
535  const double pxmiss, const double pymiss
536  ) {
537  const double txSq = tx*tx;
538  const double tySq = ty*ty;
539  const double pxmissSq = pxmiss*pxmiss;
540  const double pymissSq = pymiss*pymiss;
541 
542 
543  const double c_xx = +4.0* mtSq + 4.0* tySq;
544 
545  const double c_yy = +4.0* mtSq + 4.0* txSq;
546 
547  const double c_xy = -4.0* tx*ty;
548 
549  const double c_x = -4.0* mtSq*pxmiss - 2.0* mqSq*tx + 2.0* mSq*tx - 2.0* mtSq*tx +
550  4.0* pymiss*tx*ty - 4.0* pxmiss*tySq;
551 
552  const double c_y = -4.0* mtSq*pymiss - 4.0* pymiss*txSq - 2.0* mqSq*ty + 2.0* mSq*ty - 2.0* mtSq*ty +
553  4.0* pxmiss*tx*ty;
554 
555  const double c = - mqSq*mqSq + 2*mqSq*mSq - mSq*mSq + 2*mqSq*mtSq + 2*mSq*mtSq - mtSq*mtSq +
556  4.0* mtSq*pxmissSq + 4.0* mtSq*pymissSq + 4.0* mqSq*pxmiss*tx -
557  4.0* mSq*pxmiss*tx + 4.0* mtSq*pxmiss*tx + 4.0* mqSq*txSq +
558  4.0* pymissSq*txSq + 4.0* mqSq*pymiss*ty - 4.0* mSq*pymiss*ty +
559  4.0* mtSq*pymiss*ty - 8.0* pxmiss*pymiss*tx*ty + 4.0* mqSq*tySq +
560  4.0* pxmissSq*tySq;
561 
562  return Lester::EllipseParams(c_xx, c_yy, c_xy, c_x, c_y, c);
563  }
564 };
565 
566 void myversion(){
567 
568  std::cout << "Version is : 2014_11_13" << std::endl;
569 
570 }
571 
572 double MT(double px1, double px2, double py1, double py2, double m1 , double m2){
573  double E1 = sqrt(px1*px1+py1*py1+m1*m1);
574  double E2 = sqrt(px2*px2+py2*py2+m2*m2);
575  double Msq = (E1+E2)*(E1+E2)-(px1+px2)*(px1+px2)-(py1+py2)*(py1+py2);
576  if (Msq < 0) Msq = 0;
577  return sqrt(Msq);
578 }
579 
580 std::pair <double,double> ben_findsols(double MT2, double px, double py, double visM, double Ma, double pxb, double pyb, double metx, double mety, double visMb, double Mb){
581 
582  //Visible particle (px,py,visM)
583  std::pair <double,double> sols;
584 
586  //Find the minimizing points given MT2
588 
589  double Pt = sqrt(px*px+py*py);
590  double E = sqrt(Pt*Pt+visM*visM);
591  double M = MT2;
592  double E2 = E*E;
593  double M2 = M*M;
594  double M4 = M2*M2;
595  double Ma2 = Ma*Ma;
596  double Ma4 = Ma2*Ma2;
597  double px2 = px*px;
598  double py2 = py*py;
599  double px4 = px2*px2;
600  double py4 = py2*py2;
601  double py3 = py2*py;
602  double E4 = E2*E2;
603  double TermA = E2*px-M2*px+Ma2*px-px2*px-px*py2;
604  double TermB = -2.*px*py;
605  double TermSqy0 = E4*E2-2.*E4*M2-2.*E4*Ma2-2.*E4*px2-2.*E4*py2+E2*M4-2.*E2*M2*Ma2+2.*E2*M2*px2+2.*E2*M2*py2+E2*Ma4+2.*E2*Ma2*px2-2.*E2*Ma2*py2+E2*px4+2.*E2*px2*py2+E2*py4;
606  double TermSqy1 = -4.*E4*py+4.*E2*M2*py-4.*E2*Ma2*py+4.*E2*px2*py+4.*E2*py3;
607  double TermSqy2 = -4.*E4+4.*E2*px2+4.*E2*py2;
608 
609  //First, determine the range.
610  double myx = 0.;
611  double myy = 0.;
612  if (TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2 < 0){
613  //unbalanced
614  }
615  else{
616  double sol1 = (-TermSqy1 - sqrt(TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2))/(2.*TermSqy2);
617  double sol2 = (-TermSqy1 + sqrt(TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2))/(2.*TermSqy2);
618  double low = sol1;
619  double high = sol2;
620  if (low > high){
621  low = sol2;
622  high = sol1;
623  }
624 
625  double myclose = 99999999.;
626  for (double metpy = low; metpy<=high; metpy+=(high-low)/10000.){
627  double metpx = -(TermB*metpy+TermA-sqrt(TermSqy0+TermSqy1*metpy+TermSqy2*metpy*metpy))*0.5/(E2-px2);
628  double metpx2 = -(TermB*metpy+TermA+sqrt(TermSqy0+TermSqy1*metpy+TermSqy2*metpy*metpy))*0.5/(E2-px2);
629  double mt1a = MT(px,metpx,py,metpy,visM,Ma);
630  double mt1b = MT(px,metpx2,py,metpy,visM,Ma);
631  double metpxb = metx-metpx;
632  double metpx2b = metx-metpx2;
633  double mt2a = MT(pxb,metpxb,pyb,mety-metpy,visMb,Mb);
634  double mt2b = MT(pxb,metpx2b,pyb,mety-metpy,visMb,Mb);
635  if (fabs(mt1a-mt2a) < myclose){
636  myclose = fabs(mt1a-mt2a);
637  myy = metpy;
638  myx = metpx;
639  }
640  if (fabs(mt1b-mt2b) < myclose){
641  myclose = fabs(mt1b-mt2b);
642  myy = metpy;
643  myx = metpx2;
644  }
645  }
646  }
647 
648  sols.first = myx;
649  sols.second = myy;
650 
651  return sols;
652 
653 }
654 
655 #endif
656 
657 
658 
659 
660 
661 
662 
663 
664 
665 
666 
667 
668 
669 
670 
671 
672 
673 
674 
675 
676 
677 
678 
679 
680 
681 
682 
683 
EllipseParams(const double c_xx2, const double c_yy2, const double c_xy2, const double c_x2, const double c_y2, const double c2)
static double get_mT2(const double mVis1, const double pxVis1, const double pyVis1, const double mVis2, const double pxVis2, const double pyVis2, const double pxMiss, const double pyMiss, const double mInvis1, const double mInvis2, const double desiredPrecisionOnMT2=0, const bool useDeciSectionsInitially=true)
bool operator==(const EllipseParams &other) const
bool __private_ellipsesAreDisjoint(const double coeffLamPow3, const double coeffLamPow2, const double coeffLamPow1, const double coeffLamPow0)
double MT(double px1, double px2, double py1, double py2, double m1, double m2)
def flush()
Definition: utilities.py:47
static double lestermax(const double x, const double y)
double lesterFactor(const EllipseParams &e2) const
void myversion()
static const Lester::EllipseParams helper(const double mSq, const double mtSq, const double tx, const double ty, const double mqSq, const double pxmiss, const double pymiss)
EllipseParams(const double x0, const double y0)
static double get_mT2_Sq(const double mVis1, const double pxVis1, const double pyVis1, const double mVis2, const double pxVis2, const double pyVis2, const double pxMiss, const double pyMiss, const double mInvis1, const double mInvis2, const double desiredPrecisionOnMT2=0, const bool useDeciSectionsInitially=true)
bool ellipsesAreDisjoint(const EllipseParams &e1, const EllipseParams &e2)
std::pair< double, double > ben_findsols(double MT2, double px, double py, double visM, double Ma, double pxb, double pyb, double metx, double mety, double visMb, double Mb)
static void disableCopyrightMessage(const bool printIfFirst=false)