gambit is hosted by Hepforge, IPPP Durham
GAMBIT  v1.5.0-2191-ga4742ac
a Global And Modular Bsm Inference Tool
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 
46 double mVisA = 10; // mass of visible object on side A. Must be >=0.
47 double pxA = 20; // x momentum of visible object on side A.
48 double pyA = 30; // y momentum of visible object on side A.
49 
50 double mVisB = 10; // mass of visible object on side B. Must be >=0.
51 double pxB = -20; // x momentum of visible object on side B.
52 double pyB = -30; // y momentum of visible object on side B.
53 
54 double pxMiss = -5; // x component of missing transverse momentum.
55 double pyMiss = -5; // y component of missing transverse momentum.
56 
57 double chiA = 4; // hypothesised mass of invisible on side A. Must be >=0.
58 double chiB = 7; // hypothesised mass of invisible on side B. Must be >=0.
59 
60 double desiredPrecisionOnMt2 = 0; // Must be >=0. If 0 alg aims for machine precision. if >0, MT2 computed to supplied absolute precision.
61 
62 // asymm_mt2_lester_bisect::disableCopyrightMessage();
63 
64 double MT2 = asymm_mt2_lester_bisect::get_mT2(
65  mVisA, pxA, pyA,
66  mVisB, pxB, pyB,
67  pxMiss, pyMiss,
68  chiA, chiB,
69  desiredPrecisionOnMt2);
70 
71  */
72 
73 
74 #ifndef LESTER_TESTWHETHERELLIPSESAREDISJOINT_H
75 #define LESTER_TESTWHETHERELLIPSESAREDISJOINT_H
76 
77 #include <cmath> // for fabs( ... )
78 
79 /*
80  * The
81  *
82  * bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2);
83  *
84  * function determines whether two ellipses (not both singular) are disjoint.
85  * Ellipses are assumed to be solid objects with a filled interior.
86  * They are disjoint it no part of their interiors overlap.
87  * Singular (in this context) is defined below.
88  *
89  * It uses the method of:
90 
91 Computer Aided Geometric Design 23 (2006) 324–350
92 A new approach to characterizing the relative position of two ellipses depending on one parameter
93 Fernando Etayo 1,3, Laureano Gonzalez-Vega ∗,2,3, Natalia del Rio 3
94 Departamento de Matematicas, Estadistica y Computacion, Universidad de Cantabria, Spain
95 Received 15 September 2004; received in revised form 2 November 2005; accepted 10 January 2006 Available online 28 February 2006
96 
97 pointed out to me by Gary B. Huges and Mohcine Chraibi authors of
98 
99  Comput Visual Sci (2012) 15:291–301 DOI 10.1007/s00791-013-0214-3
100  Calculating ellipse overlap areas Gary B. Hughes · Mohcine Chraibi
101 
102  * Note:
103  *
104  * 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.
105  *
106  *
107  * Definition: an ellipse is defined with respect to cartesian co-ordinates (x,y) by an equation of the form;
108  *
109  * xVec^T A xVec = 0 (1)
110  *
111  * where xVec is a columnar three vec containing (x,y,1) and where A is a symmetric matrix having elements:
112  *
113  * [ axx axy ax ]
114  * A = [ axy ayy ay ]
115  * [ ax ay a ].
116  *
117  * Therfore the ellipse equation would look like:
118  *
119  * axx x^2 + 2 axy x y + ayy y^2 + 2 ax x + 2 ay y + a = 0.
120  *
121  * 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.
122  * Etayo et al's implementation REQUIRES that axx and ayy be strictly positive.
123  * 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.
124  * 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
125  * with (non-singluar) ellipses are fed into the program below. For our purposes, an ellipse is "singular" iff coeffLamPow3 (see below) is zero.
126  */
127 
128 namespace Lester {
129 
131 
132 
133  // Constructor for non-degenerate ellipses:
134  /*
135  * Ellipse is represented algebraically by:
136  * c_xx x^2 + 2 c_xy x y + c_yy y^2 + 2 c_x x + 2 c_y y + c = 0.
137  */
139  const double c_xx2,
140  const double c_yy2,
141  const double c_xy2,
142  const double c_x2,
143  const double c_y2,
144  const double c2) :
145  c_xx(c_xx2),
146  c_yy(c_yy2),
147  c_xy(c_xy2),
148  c_x(c_x2),
149  c_y(c_y2),
150  c(c2) {
151  //Etayo et al REQUIRE that c_xx and c_yy are non-negative, so:
152  if (c_xx<0 || c_yy<0) {
153  throw "precondition violation";
154  }
155  setDet();
156  }
158  }
159  void setDet() {
160  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) ;
161  }
162  // Consstructor for degenerate ellipse (i.e. a "dot" at (x0,y0) ).
164  const double x0,
165  const double y0) :
166  c_xx(1),
167  c_yy(1),
168  c_xy(0),
169  c_x(-x0),
170  c_y(-y0),
171  c(x0*x0 + y0*y0),
172  det(0) {
173  }
174  double lesterFactor(const EllipseParams & e2) const {
175  const EllipseParams & e1 = *this;
176  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);
177  return ans;
178  }
179  bool operator==(const EllipseParams & other) const {
180  return
181  c_xx == other.c_xx &&
182  c_yy == other.c_yy &&
183  c_xy == other.c_xy &&
184  c_x == other.c_x &&
185  c_y == other.c_y &&
186  c == other.c;
187  }
188  public:
189  // Data
190  double c_xx;
191  double c_yy;
192  double c_xy; // note factor of 2 above
193  double c_x; // note factor of 2 above
194  double c_y; // note factor of 2 above
195  double c;
196  double det; // The determinant of the 3x3 conic matrix
197 };
198 
199 // This is the interface: users should call this function:
200 bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2);
201 
202 // This is an implementation thing: users should not call it:
203 bool __private_ellipsesAreDisjoint(const double coeffLamPow3, const double coeffLamPow2, const double coeffLamPow1, const double coeffLamPow0);
204 
205 bool ellipsesAreDisjoint(const EllipseParams & e1, const EllipseParams & e2) {
206  /* 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
207  polynomial in the form lambda^3 + a lambda^2 + b lambda + c.
208 
209 
210  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.
211  */
212 
213  if (e1==e2) {
214  return false; // Probably won't catch many cases, but may as well have it here.
215  }
216 
217  // first get unscaled terms:
218  const double coeffLamPow3 = e1.det; // Note that this is the determinant of the symmetric matrix associated with e1.
219  const double coeffLamPow2 = e1.lesterFactor(e2);
220  const double coeffLamPow1 = e2.lesterFactor(e1);
221  const double coeffLamPow0 = e2.det; // Note that this is the determinant of the symmetric matrix associated with e2.
222 
223  // Since question is "symmetric" and since we need to dovide by coeffLamPow3 ... do this the way round that involves dividing by the largest number:
224 
225  if (fabs(coeffLamPow3) >= fabs(coeffLamPow0)) {
226  return __private_ellipsesAreDisjoint(coeffLamPow3, coeffLamPow2, coeffLamPow1, coeffLamPow0); // normal order
227  } else {
228  return __private_ellipsesAreDisjoint(coeffLamPow0, coeffLamPow1, coeffLamPow2, coeffLamPow3); // reversed order
229  }
230 }
231 bool __private_ellipsesAreDisjoint(const double coeffLamPow3, const double coeffLamPow2, const double coeffLamPow1, const double coeffLamPow0) {
232 
233  // precondition of being called:
234  //assert(fabs(coeffLamPow3)>=fabs(coeffLamPow0));
235 
236  if(coeffLamPow3==0) {
237  // The ellipses were singular in some way.
238  // Cannot determine whether they are overlapping or not.
239  throw 1;
240  }
241 
242  // now scale terms to monomial form:
243  const double a = coeffLamPow2 / coeffLamPow3;
244  const double b = coeffLamPow1 / coeffLamPow3;
245  const double c = coeffLamPow0 / coeffLamPow3;
246 
247 #ifdef LESTER_DEEP_FIDDLE
248  {
249  const double thing1 = -3.0*b + a*a;
250  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;
251  std::cout
252  << (thing1>0) << " && " << (thing2>0) << " && [[ " << (a>=0) << " " << (3.0*a*c + b*a*a - 4.0*b*b<0) << " ] or "
253  << "[ " << (a< 0) << " ] =("<< ((a >= 0 /*&& thing1 > 0*/ && 3.0*a*c + b*a*a - 4.0*b*b< 0 /*&& thing2 > 0*/) ||
254  (a < 0 /*&& thing1 > 0*/ /*&& thing2 > 0*/)) << ")] " << (
255  ( (a >= 0 && thing1 > 0 && 3.0*a*c + b*a*a - 4.0*b*b< 0 && thing2 > 0) ||
256  (a < 0 && thing1 > 0 && thing2 > 0))
257 
258  ) << std::endl;
259  }
260 #endif
261 
262  // Use the main result of the above paper:
263  const double thing1 = -3.0*b + a*a;
264  if (thing1<=0) return false;
265  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;
266  if (thing2<=0) return false;
267 
268  // ans true means ellipses are disjoint:
269  const bool ans = ( (a >= 0 /*&& thing1 > 0*/ && 3.0*a*c + b*a*a - 4.0*b*b< 0 /*&& thing2 > 0*/) ||
270  (a < 0 /*&& thing1 > 0*/ /*&& thing2 > 0*/));
271  return ans;
272 
273 }
274 
275 }
276 
277 #endif
278 
279 
280 
281 
282 
283 
284 
285 
286 #ifndef ASYMM_MT2_BISECT_H
287 #define ASYMM_MT2_BISECT_H
288 
289 #include <iostream>
290 #include <iomanip>
291 #include <cmath>
292 #include <cassert>
293 
294 
296  public:
297 
298  static const int MT2_ERROR=-1;
299 
300  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.
301  const double mVis1, const double pxVis1, const double pyVis1,
302  const double mVis2, const double pxVis2, const double pyVis2,
303  const double pxMiss, const double pyMiss,
304  const double mInvis1, const double mInvis2,
305  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 ...
306  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.
307  ) {
308 
309  const double mT2_Sq = get_mT2_Sq(
310  mVis1, pxVis1, pyVis1,
311  mVis2, pxVis2, pyVis2,
312  pxMiss,pyMiss,
313  mInvis1, mInvis2,
314  desiredPrecisionOnMT2,
315  useDeciSectionsInitially);
316  if (mT2_Sq==MT2_ERROR) {
317  return MT2_ERROR;
318  }
319  return sqrt(mT2_Sq);
320  }
321 
322  static void disableCopyrightMessage(const bool printIfFirst=false) {
323  static bool first = true;
324  if (first && printIfFirst) {
325  std::cout
326  << "\n\n"
327  << "#=========================================================\n"
328  << "# To disable this message, place a call to \n"
329  << "# \n"
330  << "# asymm_mt2_lester_bisect::disableCopyrightMessage();\n"
331  << "# \n"
332  << "# somewhere before you begin to calculate your MT2 values.\n"
333  << "#=========================================================\n"
334  << "# You are calculating symmetric or asymmetric MT2 using\n"
335  << "# the implementation defined in:\n"
336  << "# \n"
337  << "# http://arxiv.org/abs/1411.4312\n"
338  << "# \n"
339  << "# Please cite the paper above if you use the MT2 values\n"
340  << "# for a scholarly purpose. For the variable MT2 itself,\n"
341  << "# please also cite:\n"
342  << "# \n"
343  << "# http://arxiv.org/abs/hep-ph/9906349\n"
344  << "#=========================================================\n"
345  << "\n\n" << std::flush;
346  }
347  first = false;
348  }
349 
350  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.
351  const double mVis1, const double pxVis1, const double pyVis1,
352  const double mVis2, const double pxVis2, const double pyVis2,
353  const double pxMiss, const double pyMiss,
354  const double mInvis1, const double mInvis2,
355  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 ..
356  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.
357  ) {
358 
359 
360  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 ....
361 
362  const double m1Min = mVis1+mInvis1; // when parent has this mass, ellipse 1 has smallest physical size
363  const double m2Min = mVis2+mInvis2; // when parent has this mass, ellipse 2 has smallest physical size
364 
365  if (m1Min>m2Min) {
366  // swap 1 and 2
368  mVis2, pxVis2, pyVis2,
369  mVis1, pxVis1, pyVis1,
370  pxMiss, pyMiss,
371  mInvis2, mInvis1,
372  desiredPrecisionOnMT2
373  );
374  }
375 
376  // By now, we can be sure that m1Min <= m2Min
377  assert(m1Min<=m2Min);
378 
379  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!
380 
381  // 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?
382 
383  const double msSq = mVis1*mVis1;
384  const double sx = pxVis1;
385  const double sy = pyVis1;
386  const double mpSq = mInvis1*mInvis1;
387 
388  const double mtSq = mVis2*mVis2;
389  const double tx = pxVis2;
390  const double ty = pyVis2;
391  const double mqSq = mInvis2*mInvis2;
392 
393  const double sSq = sx*sx + sy*sy;
394  const double tSq = tx*tx + ty*ty;
395  const double pMissSq = pxMiss*pxMiss + pyMiss*pyMiss;
396  const double massSqSum = msSq + mtSq + mpSq + mqSq;
397  const double scaleSq = (massSqSum + sSq + tSq + pMissSq)/8.0;
398 
399 // #define LESTER_DBG 1
400 
401 #ifdef LESTER_DBG
402  std::cout <<"\nMOO ";
403 #endif
404  // 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.
405  if (scaleSq==0) {
406  return 0;
407  }
408  const double scale = sqrt(scaleSq);
409 
410  // disjoint at mMin. So find an mUpper at which they are not disjoint:
411  double mLower = mMin;
412  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.
413  unsigned int attempts=0;
414  const unsigned int maxAttempts=10000;
415  while (true) {
416  ++attempts;
417 
418  const double mUpperSq = mUpper*mUpper;
419  const Lester::EllipseParams & side1=helper(mUpperSq, msSq, -sx, -sy, mpSq, 0, 0 ); // see side1Coeffs in mathematica notebook
420  const Lester::EllipseParams & side2=helper(mUpperSq, mtSq, +tx, +ty, mqSq, pxMiss, pyMiss); // see side2Coeffs in mathematica notebook
421 
422  bool disjoint;
423  try {
424  disjoint = Lester::ellipsesAreDisjoint(side1, side2);
425  } catch (...) {
426  return MT2_ERROR;
427  }
428 
429  if (!disjoint) {
430  break;
431  }
432 
433  if (attempts>=maxAttempts) {
434  std::cerr << "MT2 algorithm failed to find upper bound to MT2" << std::endl;
435  return MT2_ERROR;
436  }
437 
438 #ifdef LESTER_DBG
439  std::cout << " - ";
440 #endif
441  mUpper *= 2; // grow mUpper exponentially
442  }
443 
444  //const double tol = relativeTolerance * sqrt(scaleSq);
445 
446  // Now begin the bisection:
447  bool goLow = useDeciSectionsInitially;
448  while(desiredPrecisionOnMT2<=0 || mUpper-mLower>desiredPrecisionOnMT2) {
449 
450  const double trialM = ( goLow ?
451  (mLower*15+mUpper)/16 // bias low until evidence this is not a special case
452  :
453  (mUpper + mLower)/2.0 // bisect
454  ); // worry about this not being between mUpperSq and mLowerSq! TODO
455 
456  if (trialM<=mLower || trialM>=mUpper) {
457  // We reached a numerical precision limit: the interval can no longer be bisected!
458 #ifdef LESTER_DBG
459  std::cout << " MACHINE_PREC " << std::setprecision(10) << mLower << " " << trialM << " " << mUpper << " " << mUpper-mLower << " " << desiredPrecisionOnMT2 << std::endl;
460 #endif
461  return trialM*trialM;
462  }
463  const double trialMSq = trialM * trialM;
464  const Lester::EllipseParams & side1 = helper(trialMSq, msSq, -sx, -sy, mpSq, 0, 0 ); // see side1Coeffs in mathematica notebook
465  const Lester::EllipseParams & side2 = helper(trialMSq, mtSq, +tx, +ty, mqSq, pxMiss, pyMiss); // see side2Coeffs in mathematica notebook
466 
467  try {
468  const bool disjoint = Lester::ellipsesAreDisjoint(side1, side2);
469  if (disjoint) {
470  mLower = trialM;
471  goLow = false;
472 #ifdef LESTER_DBG
473  std::cout << "UP " ;
474 #endif
475  } else {
476  mUpper = trialM;
477 #ifdef LESTER_DBG
478  std::cout << "== ";
479 #endif
480  }
481  } catch (...) {
482  // 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:
483 #ifdef LESTER_DBG
484  std::cout << " THROW " << std::endl;
485 #endif
486  return mLower*mLower;
487  }
488  }
489 
490  const double mAns = (mLower+mUpper)/2.0;
491 
492 #ifdef LESTER_DBG
493  std::cout << " USER_PREC " << std::endl;
494 #endif
495  return mAns*mAns;
496  };
497  private:
498  static double lestermax(const double x, const double y) {
499  return (x>y)?x:y;
500  }
501  static const Lester::EllipseParams helper(const double mSq, // The test parent-mass value (squared)
502  const double mtSq, const double tx, const double ty, // The visible particle transverse momentum
503  const double mqSq, // The mass of the invisible particle
504  const double pxmiss, const double pymiss
505  ) {
506  const double txSq = tx*tx;
507  const double tySq = ty*ty;
508  const double pxmissSq = pxmiss*pxmiss;
509  const double pymissSq = pymiss*pymiss;
510 
511 
512  const double c_xx = +4.0* mtSq + 4.0* tySq;
513 
514  const double c_yy = +4.0* mtSq + 4.0* txSq;
515 
516  const double c_xy = -4.0* tx*ty;
517 
518  const double c_x = -4.0* mtSq*pxmiss - 2.0* mqSq*tx + 2.0* mSq*tx - 2.0* mtSq*tx +
519  4.0* pymiss*tx*ty - 4.0* pxmiss*tySq;
520 
521  const double c_y = -4.0* mtSq*pymiss - 4.0* pymiss*txSq - 2.0* mqSq*ty + 2.0* mSq*ty - 2.0* mtSq*ty +
522  4.0* pxmiss*tx*ty;
523 
524  const double c = - mqSq*mqSq + 2*mqSq*mSq - mSq*mSq + 2*mqSq*mtSq + 2*mSq*mtSq - mtSq*mtSq +
525  4.0* mtSq*pxmissSq + 4.0* mtSq*pymissSq + 4.0* mqSq*pxmiss*tx -
526  4.0* mSq*pxmiss*tx + 4.0* mtSq*pxmiss*tx + 4.0* mqSq*txSq +
527  4.0* pymissSq*txSq + 4.0* mqSq*pymiss*ty - 4.0* mSq*pymiss*ty +
528  4.0* mtSq*pymiss*ty - 8.0* pxmiss*pymiss*tx*ty + 4.0* mqSq*tySq +
529  4.0* pxmissSq*tySq;
530 
531  return Lester::EllipseParams(c_xx, c_yy, c_xy, c_x, c_y, c);
532  }
533 };
534 
535 void myversion(){
536 
537  std::cout << "Version is : 2014_11_13" << std::endl;
538 
539 }
540 
541 double MT(double px1, double px2, double py1, double py2, double m1 , double m2){
542  double E1 = sqrt(px1*px1+py1*py1+m1*m1);
543  double E2 = sqrt(px2*px2+py2*py2+m2*m2);
544  double Msq = (E1+E2)*(E1+E2)-(px1+px2)*(px1+px2)-(py1+py2)*(py1+py2);
545  if (Msq < 0) Msq = 0;
546  return sqrt(Msq);
547 }
548 
549 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){
550 
551  //Visible particle (px,py,visM)
552  std::pair <double,double> sols;
553 
555  //Find the minimizing points given MT2
557 
558  double Pt = sqrt(px*px+py*py);
559  double E = sqrt(Pt*Pt+visM*visM);
560  double M = MT2;
561  double E2 = E*E;
562  double M2 = M*M;
563  double M4 = M2*M2;
564  double Ma2 = Ma*Ma;
565  double Ma4 = Ma2*Ma2;
566  double px2 = px*px;
567  double py2 = py*py;
568  double px4 = px2*px2;
569  double py4 = py2*py2;
570  double py3 = py2*py;
571  double E4 = E2*E2;
572  double TermA = E2*px-M2*px+Ma2*px-px2*px-px*py2;
573  double TermB = -2.*px*py;
574  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;
575  double TermSqy1 = -4.*E4*py+4.*E2*M2*py-4.*E2*Ma2*py+4.*E2*px2*py+4.*E2*py3;
576  double TermSqy2 = -4.*E4+4.*E2*px2+4.*E2*py2;
577 
578  //First, determine the range.
579  double myx = 0.;
580  double myy = 0.;
581  if (TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2 < 0){
582  //unbalanced
583  }
584  else{
585  double sol1 = (-TermSqy1 - sqrt(TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2))/(2.*TermSqy2);
586  double sol2 = (-TermSqy1 + sqrt(TermSqy1*TermSqy1-4.*TermSqy0*TermSqy2))/(2.*TermSqy2);
587  double low = sol1;
588  double high = sol2;
589  if (low > high){
590  low = sol2;
591  high = sol1;
592  }
593 
594  double myclose = 99999999.;
595  for (double metpy = low; metpy<=high; metpy+=(high-low)/10000.){
596  double metpx = -(TermB*metpy+TermA-sqrt(TermSqy0+TermSqy1*metpy+TermSqy2*metpy*metpy))*0.5/(E2-px2);
597  double metpx2 = -(TermB*metpy+TermA+sqrt(TermSqy0+TermSqy1*metpy+TermSqy2*metpy*metpy))*0.5/(E2-px2);
598  double mt1a = MT(px,metpx,py,metpy,visM,Ma);
599  double mt1b = MT(px,metpx2,py,metpy,visM,Ma);
600  double metpxb = metx-metpx;
601  double metpx2b = metx-metpx2;
602  double mt2a = MT(pxb,metpxb,pyb,mety-metpy,visMb,Mb);
603  double mt2b = MT(pxb,metpx2b,pyb,mety-metpy,visMb,Mb);
604  if (fabs(mt1a-mt2a) < myclose){
605  myclose = fabs(mt1a-mt2a);
606  myy = metpy;
607  myx = metpx;
608  }
609  if (fabs(mt1b-mt2b) < myclose){
610  myclose = fabs(mt1b-mt2b);
611  myy = metpy;
612  myx = metpx2;
613  }
614  }
615  }
616 
617  sols.first = myx;
618  sols.second = myy;
619 
620  return sols;
621 
622 }
623 
624 #endif
625 
626 
627 
628 
629 
630 
631 
632 
633 
634 
635 
636 
637 
638 
639 
640 
641 
642 
643 
644 
645 
646 
647 
648 
649 
650 
651 
652 
EllipseParams(const double c_xx2, const double c_yy2, const double c_xy2, const double c_x2, const double c_y2, const double c2)
bool operator==(const EllipseParams &other) const
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 __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)
START_MODEL b
Definition: demo.hpp:270
static double lestermax(const double x, const double y)
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)
START_MODEL M
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)
double E(const double x, const double y)
static void disableCopyrightMessage(const bool printIfFirst=false)
double lesterFactor(const EllipseParams &e2) const