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