[Rivet-svn] r3054 - in trunk: include/Rivet include/Rivet/Tools src/Tools

blackhole at projects.hepforge.org blackhole at projects.hepforge.org
Wed Apr 13 15:24:22 BST 2011


Author: dgrell
Date: Wed Apr 13 15:24:21 2011
New Revision: 3054

Log:
mT2 support: Cheng/Han code and wrapper

Added:
   trunk/include/Rivet/Tools/RivetMT2.hh
   trunk/src/Tools/RivetMT2.cc
   trunk/src/Tools/mt2_bisect.cc   (contents, props changed)
   trunk/src/Tools/mt2_bisect.hh
Modified:
   trunk/include/Rivet/Makefile.am
   trunk/src/Tools/Makefile.am

Modified: trunk/include/Rivet/Makefile.am
==============================================================================
--- trunk/include/Rivet/Makefile.am	Fri Apr  8 18:03:59 2011	(r3053)
+++ trunk/include/Rivet/Makefile.am	Wed Apr 13 15:24:21 2011	(r3054)
@@ -90,7 +90,8 @@
   Tools/RivetPaths.hh \
   Tools/BinnedHistogram.hh \
   Tools/ParticleIdUtils.hh \
-  Tools/TypeTraits.hh
+  Tools/TypeTraits.hh \
+  Tools/RivetMT2.hh
 nobase_dist_noinst_HEADERS += \
   Tools/osdir.hh
 

Added: trunk/include/Rivet/Tools/RivetMT2.hh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/include/Rivet/Tools/RivetMT2.hh	Wed Apr 13 15:24:21 2011	(r3054)
@@ -0,0 +1,23 @@
+// -*- C++ -*-
+#ifndef RIVET_MT2_HH
+#define RIVET_MT2_HH
+
+// Convenience wrapper for the m_T2 calculator of Cheng/Han
+// (arXiv:0810.5178). Could be adapted for other backends in future
+
+namespace Rivet {
+
+  class FourMomentum;
+
+  namespace mT2 {
+    
+    double mT2(const FourMomentum & a, 
+	       const FourMomentum & b, 
+	       const FourMomentum & pTmiss, 
+	       double invisiblesMass);
+
+  }
+}
+
+
+#endif

Modified: trunk/src/Tools/Makefile.am
==============================================================================
--- trunk/src/Tools/Makefile.am	Fri Apr  8 18:03:59 2011	(r3053)
+++ trunk/src/Tools/Makefile.am	Wed Apr 13 15:24:21 2011	(r3054)
@@ -14,9 +14,11 @@
   TinyXML/tinyxml.cpp \
   TinyXML/tinyxmlerror.cpp \
   TinyXML/tinyxmlparser.cpp \
-  BinnedHistogram.cc
+  BinnedHistogram.cc \
+  mt2_bisect.cc \
+  RivetMT2.cc
 
-dist_noinst_HEADERS = binreloc.h
+dist_noinst_HEADERS = binreloc.h mt2_bisect.hh
 
 libRivetTools_la_CPPFLAGS = \
   $(AM_CPPFLAGS) \

Added: trunk/src/Tools/RivetMT2.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/Tools/RivetMT2.cc	Wed Apr 13 15:24:21 2011	(r3054)
@@ -0,0 +1,29 @@
+#include "Rivet/Tools/RivetMT2.hh"
+#include "Rivet/Math/Vector4.hh"
+#include "mt2_bisect.hh"
+
+
+namespace Rivet {
+  namespace mT2 {
+      
+    double mT2(const FourMomentum & a, 
+	       const FourMomentum & b, 
+	       const FourMomentum & pTmiss, 
+	       double invisiblesMass) 
+    {
+      mt2_bisect::mt2 mt2_event;
+      
+      double unused = -999.999;
+      
+      double pa[3]    = { 0.0, a.x(), a.y() };
+      double pb[3]    = { 0.0, b.x(), b.y() };
+      double pmiss[3] = { unused, pTmiss.x(), pTmiss.y() };
+      
+      mt2_event.set_momenta( pa, pb, pmiss );
+      mt2_event.set_mn( invisiblesMass );
+      
+      return mt2_event.get_mt2();
+    }
+
+  }
+}

Added: trunk/src/Tools/mt2_bisect.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/Tools/mt2_bisect.cc	Wed Apr 13 15:24:21 2011	(r3054)
@@ -0,0 +1,676 @@
+/***********************************************************************/
+/*                                                                     */
+/*              Finding mt2 by Bisection                               */
+/*                                                                     */
+/*              Authors: Hsin-Chia Cheng, Zhenyu Han                   */ 
+/*              Dec 11, 2008, v1.01a                                   */
+/*                                                                     */
+/*              see arXiv:0810.5178                                    */  
+/*                                                                     */  
+/*              Wrapped for Rivet by D. Grellscheid                    */
+/*              Apr 13, 2011                                           */
+/*                                                                     */  
+/***********************************************************************/
+
+
+/*******************************************************************************
+  Usage: 
+
+  1. Define an object of type "mt2":
+     
+     mt2_bisect::mt2 mt2_event;
+ 
+  2. Set momenta and the mass of the invisible particle, mn:
+ 
+     mt2_event.set_momenta( pa, pb, pmiss );
+     mt2_event.set_mass( mn );
+ 
+     where array pa[0..2], pb[0..2], pmiss[0..2] contains (mass,px,py) 
+     for the visible particles and the missing momentum. pmiss[0] is not used. 
+     All quantities are given in double.    
+
+  3. Use mt2::get_mt2() to obtain the value of mt2:
+
+     double mt2_value = mt2_event.get_mt2();       
+          
+*******************************************************************************/ 
+#include "mt2_bisect.hh"
+#include "Rivet/Tools/Logging.hh"
+#include <cmath>
+#include <cassert>
+
+namespace Rivet {
+
+namespace mt2_bisect
+{
+using namespace std;
+
+mt2::mt2()
+{
+   solved = false;
+   momenta_set = false;
+   mt2_b  = 0.;
+   scale = 1.;
+}
+
+double mt2::get_mt2()
+{
+   assert(momenta_set);
+   if (!solved) mt2_bisect();
+   return mt2_b*scale;
+}
+
+void mt2::set_momenta(double* pa0, double* pb0, double* pmiss0)
+{
+   solved = false;     //reset solved tag when momenta are changed.
+   momenta_set = true;
+
+   ma = fabs(pa0[0]);  // mass cannot be negative
+
+   if (ma < ZERO_MASS) ma = ZERO_MASS;
+
+   pax  = pa0[1]; 
+   pay  = pa0[2];
+   masq = ma*ma;
+   Easq = masq+pax*pax+pay*pay;
+   Ea   = sqrt(Easq);
+   
+   mb = fabs(pb0[0]);
+
+   if (mb < ZERO_MASS) mb = ZERO_MASS;
+
+   pbx  = pb0[1]; 
+   pby  = pb0[2];
+   mbsq = mb*mb;
+   Ebsq = mbsq+pbx*pbx+pby*pby;
+   Eb   = sqrt(Ebsq);
+     
+   pmissx   = pmiss0[1]; pmissy = pmiss0[2];
+   pmissxsq = pmissx*pmissx;
+   pmissysq = pmissy*pmissy;
+
+// set ma>= mb
+   if(masq < mbsq)
+   {
+      double temp;
+      temp = pax;  pax  = pbx;  pbx  = temp;
+      temp = pay;  pay  = pby;  pby  = temp;
+      temp = Ea;   Ea   = Eb;   Eb   = temp;
+      temp = Easq; Easq = Ebsq; Ebsq = temp;
+      temp = masq; masq = mbsq; mbsq = temp;
+      temp = ma;   ma   = mb;   mb   = temp;   
+   }
+//normalize max{Ea, Eb} to 100
+   if (Ea > Eb) scale = Ea/100.;
+   else scale = Eb/100.;
+   
+   if (sqrt(pmissxsq+pmissysq)/100 > scale) scale = sqrt(pmissxsq+pmissysq)/100;
+   //scale = 1;
+   double scalesq = scale * scale;
+   ma  = ma/scale;
+   mb  = mb/scale;
+   masq = masq/scalesq;
+   mbsq = mbsq/scalesq;
+   pax = pax/scale; pay = pay/scale;
+   pbx = pbx/scale; pby = pby/scale;
+   Ea  = Ea/scale;  Eb = Eb/scale;
+   
+   Easq = Easq/scalesq;
+   Ebsq = Ebsq/scalesq;
+   pmissx = pmissx/scale;
+   pmissy = pmissy/scale;
+   pmissxsq = pmissxsq/scalesq;
+   pmissysq = pmissysq/scalesq;
+   mn   = mn_unscale/scale; 
+   mnsq = mn*mn;
+  
+   if (ABSOLUTE_PRECISION > 100.*RELATIVE_PRECISION) precision = ABSOLUTE_PRECISION;
+   else precision = 100.*RELATIVE_PRECISION;
+}
+
+void mt2::set_mn(double mn0)
+{
+   solved = false;    //reset solved tag when mn is changed.
+   mn_unscale   = fabs(mn0);  //mass cannot be negative
+   mn = mn_unscale/scale;
+   mnsq = mn*mn;
+}
+
+// void mt2::print()
+// {
+//    cout << " pax = " << pax*scale << ";   pay = " << pay*scale << ";   ma = " << ma*scale <<";"<< endl;
+//    cout << " pbx = " << pbx*scale << ";   pby = " << pby*scale << ";   mb = " << mb*scale <<";"<< endl;
+//    cout << " pmissx = " << pmissx*scale << ";   pmissy = " << pmissy*scale <<";"<< endl;
+//    cout << " mn = " << mn_unscale<<";" << endl;
+// }
+
+//special case, the visible particle is massless
+void mt2::mt2_massless()
+{
+   
+//rotate so that pay = 0 
+   double theta,s,c;
+   theta = atan(pay/pax);
+   s = sin(theta);
+   c = cos(theta);
+
+   double pxtemp,pytemp;
+   Easq   = pax*pax+pay*pay;
+   Ebsq   = pbx*pbx+pby*pby;
+   Ea     = sqrt(Easq);
+   Eb     = sqrt(Ebsq);
+  
+   pxtemp = pax*c+pay*s;
+   pax    = pxtemp;
+   pay    = 0;
+   pxtemp = pbx*c+pby*s;
+   pytemp = -s*pbx+c*pby;
+   pbx    = pxtemp;
+   pby    = pytemp;
+   pxtemp = pmissx*c+pmissy*s;
+   pytemp = -s*pmissx+c*pmissy;
+   pmissx = pxtemp;
+   pmissy = pytemp;
+
+   a2  = 1-pbx*pbx/(Ebsq);
+   b2  = -pbx*pby/(Ebsq);
+   c2  = 1-pby*pby/(Ebsq);
+
+   d21 = (Easq*pbx)/Ebsq;
+   d20 = - pmissx +  (pbx*(pbx*pmissx + pby*pmissy))/Ebsq;
+   e21 = (Easq*pby)/Ebsq;
+   e20 = - pmissy +  (pby*(pbx*pmissx + pby*pmissy))/Ebsq;
+   f22 = -(Easq*Easq/Ebsq);
+   f21 = -2*Easq*(pbx*pmissx + pby*pmissy)/Ebsq;
+   f20 = mnsq + pmissxsq + pmissysq - (pbx*pmissx + pby*pmissy)*(pbx*pmissx + pby*pmissy)/Ebsq;
+
+   double Deltasq0    = 0; 
+   double Deltasq_low, Deltasq_high;
+   int    nsols_high, nsols_low;
+
+   Deltasq_low = Deltasq0 + precision;
+   nsols_low = nsols_massless(Deltasq_low);
+   
+   if(nsols_low > 1) 
+   { 
+      mt2_b = (double) sqrt(Deltasq0+mnsq);
+      return;
+   }
+
+/*   
+   if( nsols_massless(Deltasq_high) > 0 )
+   {
+      mt2_b = (double) sqrt(mnsq+Deltasq0);
+      return;
+   }*/
+
+//look for when both parablos contain origin  
+   double Deltasq_high1, Deltasq_high2;
+   Deltasq_high1 = 2*Eb*sqrt(pmissx*pmissx+pmissy*pmissy+mnsq)-2*pbx*pmissx-2*pby*pmissy;
+   Deltasq_high2 = 2*Ea*mn;
+ 
+   if(Deltasq_high1 < Deltasq_high2) Deltasq_high = Deltasq_high2;
+     else Deltasq_high = Deltasq_high1;
+
+   nsols_high=nsols_massless(Deltasq_high);
+  
+   int foundhigh;
+   if (nsols_high == nsols_low)
+   {
+      
+      
+      foundhigh=0;
+      
+      double minmass, maxmass;
+      minmass  = mn ;
+      maxmass  = sqrt(mnsq + Deltasq_high);
+      for(double mass = minmass + SCANSTEP; mass < maxmass; mass += SCANSTEP)
+      {
+	 Deltasq_high = mass*mass - mnsq;
+      
+         nsols_high = nsols_massless(Deltasq_high);
+         if(nsols_high>0)
+         {
+            foundhigh=1;
+            Deltasq_low = (mass-SCANSTEP)*(mass-SCANSTEP) - mnsq;
+            break;
+         }
+      }
+      if(foundhigh==0) 
+      {
+       
+	Log::getLog("Rivet.Tools.mt2") 
+	  << Log::WARN  
+	  << "Deltasq_high not found at event " << nevt << '\n';
+       
+         mt2_b = (double)sqrt(Deltasq_low+mnsq);
+         return;
+      }
+   }
+
+   if(nsols_high == nsols_low)
+   { 
+     Log::getLog("Rivet.Tools.mt2") 
+       << Log::ERROR  
+       << "error: nsols_low=nsols_high=" << nsols_high << '\n'
+       << "Deltasq_high=" << Deltasq_high << '\n'
+       << "Deltasq_low= "<< Deltasq_low << '\n';
+    
+      mt2_b = sqrt(mnsq + Deltasq_low);
+      return;
+   }
+   double minmass, maxmass;
+   minmass = sqrt(Deltasq_low+mnsq);
+   maxmass = sqrt(Deltasq_high+mnsq);
+   while(maxmass - minmass > precision)
+   {
+      double Delta_mid, midmass, nsols_mid;
+      midmass   = (minmass+maxmass)/2.;
+      Delta_mid = midmass * midmass - mnsq;
+      nsols_mid = nsols_massless(Delta_mid);
+      if(nsols_mid != nsols_low) maxmass = midmass;
+      if(nsols_mid == nsols_low) minmass = midmass;
+   }
+   mt2_b = minmass;
+   return;
+}
+
+int mt2::nsols_massless(double Dsq)
+{
+  double delta;
+  delta = Dsq/(2*Easq);
+  d1    = d11*delta;
+  e1    = e11*delta;
+  f1    = f12*delta*delta+f10;
+  d2    = d21*delta+d20;
+  e2    = e21*delta+e20;
+  f2    = f22*delta*delta+f21*delta+f20;
+  
+  double a,b;
+  if (pax > 0) a = Ea/Dsq;
+  else         a = -Ea/Dsq;
+  if (pax > 0) b = -Dsq/(4*Ea)+mnsq*Ea/Dsq;
+  else         b = Dsq/(4*Ea)-mnsq*Ea/Dsq;
+  
+  double A4,A3,A2,A1,A0;
+
+  A4 = a*a*a2;
+  A3 = 2*a*b2/Ea;
+  A2 = (2*a*a2*b+c2+2*a*d2)/(Easq);
+  A1 = (2*b*b2+2*e2)/(Easq*Ea);
+  A0 = (a2*b*b+2*b*d2+f2)/(Easq*Easq);
+  
+  long  double A0sq, A1sq, A2sq, A3sq, A4sq;
+  A0sq = A0*A0;
+  A1sq = A1*A1;
+  A2sq = A2*A2;
+  A3sq = A3*A3;
+  A4sq = A4*A4;
+
+  long double B3, B2, B1, B0;
+  B3 = 4*A4;
+  B2 = 3*A3;
+  B1 = 2*A2;
+  B0 = A1;
+  long double C2, C1, C0;
+  C2 = -(A2/2 - 3*A3sq/(16*A4));
+  C1 = -(3*A1/4. -A2*A3/(8*A4));
+  C0 = -A0 + A1*A3/(16*A4);
+  long double  D1, D0;
+  D1 = -B1 - (B3*C1*C1/C2 - B3*C0 -B2*C1)/C2;
+  D0 = -B0 - B3 *C0 *C1/(C2*C2)+ B2*C0/C2;
+ 
+  long double E0;
+  E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
+ 
+  long  double t1,t2,t3,t4,t5;
+   
+//find the coefficients for the leading term in the Sturm sequence  
+   t1 = A4;
+   t2 = A4;
+   t3 = C2;
+   t4 = D1;
+   t5 = E0;
+  
+   int nsol;
+   nsol = signchange_n(t1,t2,t3,t4,t5)-signchange_p(t1,t2,t3,t4,t5);
+   if( nsol < 0 ) nsol=0;
+
+   return nsol;
+  
+}
+
+void mt2::mt2_bisect()
+{   
+  solved = true;
+
+//if masses are very small, use code for massless case.  
+   if(masq < MIN_MASS && mbsq < MIN_MASS) 
+   { 
+      mt2_massless();
+      return;
+   }
+ 
+
+   double Deltasq0;     
+   Deltasq0 = ma*(ma + 2*mn); //The minimum mass square to have two ellipses 
+ 
+// find the coefficients for the two quadratic equations when Deltasq=Deltasq0.
+  
+   a1 = 1-pax*pax/(Easq);
+   b1 = -pax*pay/(Easq);
+   c1 = 1-pay*pay/(Easq);
+   d1 = -pax*(Deltasq0-masq)/(2*Easq);
+   e1 = -pay*(Deltasq0-masq)/(2*Easq);
+   a2 = 1-pbx*pbx/(Ebsq);
+   b2 = -pbx*pby/(Ebsq);
+   c2 = 1-pby*pby/(Ebsq);
+   d2 = -pmissx+pbx*(Deltasq0-mbsq)/(2*Ebsq)+pbx*(pbx*pmissx+pby*pmissy)/(Ebsq);
+   e2 = -pmissy+pby*(Deltasq0-mbsq)/(2*Ebsq)+pby*(pbx*pmissx+pby*pmissy)/(Ebsq);
+   f2 = pmissx*pmissx+pmissy*pmissy-((Deltasq0-mbsq)/(2*Eb)+
+        (pbx*pmissx+pby*pmissy)/Eb)*((Deltasq0-mbsq)/(2*Eb)+
+        (pbx*pmissx+pby*pmissy)/Eb)+mnsq;
+   
+// find the center of the smaller ellipse 
+   double x0,y0;
+   x0 = (c1*d1-b1*e1)/(b1*b1-a1*c1);
+   y0 = (a1*e1-b1*d1)/(b1*b1-a1*c1);
+
+   
+// Does the larger ellipse contain the smaller one? 
+   double dis=a2*x0*x0+2*b2*x0*y0+c2*y0*y0+2*d2*x0+2*e2*y0+f2;
+
+   if(dis<=0.01)
+   { 
+      mt2_b  = (double) sqrt(mnsq+Deltasq0);
+      return;
+   }
+   
+
+/* find the coefficients for the two quadratic equations           */
+/* coefficients for quadratic terms do not change                  */
+/* coefficients for linear and constant terms are polynomials of   */
+/*       delta=(Deltasq-m7sq)/(2 E7sq)                             */  
+   d11 = -pax;
+   e11 = -pay;
+   f10 = mnsq;
+   f12 = -Easq;
+   d21 = (Easq*pbx)/Ebsq;
+   d20 = ((masq - mbsq)*pbx)/(2.*Ebsq) - pmissx +
+         (pbx*(pbx*pmissx + pby*pmissy))/Ebsq;
+   e21 = (Easq*pby)/Ebsq;
+   e20 = ((masq - mbsq)*pby)/(2.*Ebsq) - pmissy +
+         (pby*(pbx*pmissx + pby*pmissy))/Ebsq;
+   f22 = -Easq*Easq/Ebsq;
+   f21 = (-2*Easq*((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb))/Eb;
+   f20 = mnsq + pmissx*pmissx + pmissy*pmissy - 
+         ((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb)
+         *((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb);
+
+//Estimate upper bound of mT2
+//when Deltasq > Deltasq_high1, the larger encloses the center of the smaller 
+   double p2x0,p2y0;
+   double Deltasq_high1;
+   p2x0 = pmissx-x0;
+   p2y0 = pmissy-y0;
+   Deltasq_high1 = 2*Eb*sqrt(p2x0*p2x0+p2y0*p2y0+mnsq)-2*pbx*p2x0-2*pby*p2y0+mbsq;
+   
+//Another estimate, if both ellipses enclose the origin, Deltasq > mT2
+
+   double Deltasq_high2, Deltasq_high21, Deltasq_high22;
+   Deltasq_high21 = 2*Eb*sqrt(pmissx*pmissx+pmissy*pmissy+mnsq)-2*pbx*pmissx-2*pby*pmissy+mbsq;
+   Deltasq_high22 = 2*Ea*mn+masq;
+  
+   if ( Deltasq_high21 < Deltasq_high22 ) Deltasq_high2 = Deltasq_high22;
+   else Deltasq_high2 = Deltasq_high21;
+
+//pick the smaller upper bound   
+   double Deltasq_high;
+   if(Deltasq_high1 < Deltasq_high2) Deltasq_high = Deltasq_high1;
+   else Deltasq_high = Deltasq_high2;
+   
+  
+   double Deltasq_low; //lower bound
+   Deltasq_low = Deltasq0;
+
+//number of solutions at Deltasq_low should not be larger than zero
+   if( nsols(Deltasq_low) > 0 )
+   {
+     //cout << "nsolutions(Deltasq_low) > 0"<<endl;
+     mt2_b = (double) sqrt(mnsq+Deltasq0);
+     return;
+   }
+  
+   int nsols_high, nsols_low;
+
+   nsols_low  = nsols(Deltasq_low);
+   int foundhigh;
+  
+
+//if nsols_high=nsols_low, we missed the region where the two ellipse overlap 
+//if nsols_high=4, also need a scan because we may find the wrong tangent point.
+
+   nsols_high = nsols(Deltasq_high);
+  
+   if(nsols_high == nsols_low || nsols_high == 4)
+   {
+      //foundhigh = scan_high(Deltasq_high);
+      foundhigh = find_high(Deltasq_high);
+      if(foundhigh == 0) 
+      {
+	 Log::getLog("Rivet.Tools.mt2") 
+	   << Log::WARN  
+	   << "Deltasq_high not found at event " << nevt << '\n';
+         mt2_b = sqrt( Deltasq_low + mnsq );
+         return;
+      }
+      
+   }
+
+   while(sqrt(Deltasq_high+mnsq) - sqrt(Deltasq_low+mnsq) > precision)
+   {
+      double Deltasq_mid,nsols_mid;
+      //bisect
+      Deltasq_mid = (Deltasq_high+Deltasq_low)/2.;
+      nsols_mid = nsols(Deltasq_mid);
+      // if nsols_mid = 4, rescan for Deltasq_high
+      if ( nsols_mid == 4 ) 
+      {
+         Deltasq_high = Deltasq_mid;
+         //scan_high(Deltasq_high);
+         find_high(Deltasq_high);
+         continue;
+      } 
+         
+      
+      if(nsols_mid != nsols_low) Deltasq_high = Deltasq_mid;
+      if(nsols_mid == nsols_low) Deltasq_low  = Deltasq_mid;
+   }
+   mt2_b = (double) sqrt( mnsq + Deltasq_high);
+   return;
+}
+
+int mt2::find_high(double & Deltasq_high)
+{
+   double x0,y0;
+   x0 = (c1*d1-b1*e1)/(b1*b1-a1*c1);
+   y0 = (a1*e1-b1*d1)/(b1*b1-a1*c1);
+   double Deltasq_low = (mn + ma)*(mn + ma) - mnsq;
+   do 
+   {
+      double Deltasq_mid = (Deltasq_high + Deltasq_low)/2.;
+      int nsols_mid = nsols(Deltasq_mid);
+      if ( nsols_mid == 2 )
+      {
+         Deltasq_high = Deltasq_mid;
+         return 1;
+      }
+      else if (nsols_mid == 4)
+      {
+         Deltasq_high = Deltasq_mid;
+         continue;
+      }
+      else if (nsols_mid ==0)
+      {
+         d1 = -pax*(Deltasq_mid-masq)/(2*Easq);
+         e1 = -pay*(Deltasq_mid-masq)/(2*Easq);
+         d2 = -pmissx + pbx*(Deltasq_mid - mbsq)/(2*Ebsq)
+              + pbx*(pbx*pmissx+pby*pmissy)/(Ebsq);
+         e2 = -pmissy + pby*(Deltasq_mid - mbsq)/(2*Ebsq)
+              + pby*(pbx*pmissx+pby*pmissy)/(Ebsq);
+         f2 = pmissx*pmissx+pmissy*pmissy-((Deltasq_mid-mbsq)/(2*Eb)+
+              (pbx*pmissx+pby*pmissy)/Eb)*((Deltasq_mid-mbsq)/(2*Eb)+
+              (pbx*pmissx+pby*pmissy)/Eb)+mnsq;
+// Does the larger ellipse contain the smaller one? 
+         double dis = a2*x0*x0 + 2*b2*x0*y0 + c2*y0*y0 + 2*d2*x0 + 2*e2*y0 + f2;
+         if (dis < 0) Deltasq_high = Deltasq_mid;
+           else Deltasq_low = Deltasq_mid;
+      }
+      
+   } while ( Deltasq_high - Deltasq_low > 0.001);
+   return 0;
+}  
+int mt2::scan_high(double & Deltasq_high)
+{
+   int foundhigh = 0 ;
+   int nsols_high;
+
+   
+   double Deltasq_low;
+   double tempmass, maxmass;
+   tempmass = mn + ma;
+   maxmass  = sqrt(mnsq + Deltasq_high);
+   // if (nevt == 32334) {
+     
+   //   cout << "Deltasq_high = " << Deltasq_high << endl;
+   // }
+   for(double mass = tempmass + SCANSTEP; mass < maxmass; mass += SCANSTEP)
+   {
+      Deltasq_high = mass*mass - mnsq;
+      nsols_high   = nsols(Deltasq_high);
+      
+      if( nsols_high > 0)
+      {
+	 Deltasq_low = (mass-SCANSTEP)*(mass-SCANSTEP) - mnsq;
+         foundhigh   = 1;
+         break;
+      }
+    }
+    return foundhigh;
+}
+int mt2::nsols(  double Dsq)
+{
+   double delta = (Dsq-masq)/(2*Easq);
+  
+//calculate coefficients for the two quadratic equations
+   d1 = d11*delta;
+   e1 = e11*delta;
+   f1 = f12*delta*delta+f10;
+   d2 = d21*delta+d20;
+   e2 = e21*delta+e20;
+   f2 = f22*delta*delta+f21*delta+f20;
+
+//obtain the coefficients for the 4th order equation 
+//devided by Ea^n to make the variable dimensionless
+   long double A4, A3, A2, A1, A0;
+
+   A4 = 
+   -4*a2*b1*b2*c1 + 4*a1*b2*b2*c1 +a2*a2*c1*c1 + 
+   4*a2*b1*b1*c2 - 4*a1*b1*b2*c2 - 2*a1*a2*c1*c2 + 
+   a1*a1*c2*c2;  
+
+   A3 =
+     (-4*a2*b2*c1*d1 + 8*a2*b1*c2*d1 - 4*a1*b2*c2*d1 - 4*a2*b1*c1*d2 + 
+   8*a1*b2*c1*d2 - 4*a1*b1*c2*d2 - 8*a2*b1*b2*e1 + 8*a1*b2*b2*e1 + 
+   4*a2*a2*c1*e1 - 4*a1*a2*c2*e1 + 8*a2*b1*b1*e2 - 8*a1*b1*b2*e2 - 
+     4*a1*a2*c1*e2 + 4*a1*a1*c2*e2)/Ea;
+
+   
+   A2 =
+     (4*a2*c2*d1*d1 - 4*a2*c1*d1*d2 - 4*a1*c2*d1*d2 + 4*a1*c1*d2*d2 - 
+   8*a2*b2*d1*e1 - 8*a2*b1*d2*e1 + 16*a1*b2*d2*e1 + 
+   4*a2*a2*e1*e1 + 16*a2*b1*d1*e2 - 8*a1*b2*d1*e2 - 
+   8*a1*b1*d2*e2 - 8*a1*a2*e1*e2 + 4*a1*a1*e2*e2 - 4*a2*b1*b2*f1 + 
+   4*a1*b2*b2*f1 + 2*a2*a2*c1*f1 - 2*a1*a2*c2*f1 + 
+     4*a2*b1*b1*f2 - 4*a1*b1*b2*f2 - 2*a1*a2*c1*f2 + 2*a1*a1*c2*f2)/Easq;
+  
+   A1 =
+     (-8*a2*d1*d2*e1 + 8*a1*d2*d2*e1 + 8*a2*d1*d1*e2 - 8*a1*d1*d2*e2 - 
+   4*a2*b2*d1*f1 - 4*a2*b1*d2*f1 + 8*a1*b2*d2*f1 + 4*a2*a2*e1*f1 - 
+   4*a1*a2*e2*f1 + 8*a2*b1*d1*f2 - 4*a1*b2*d1*f2 - 4*a1*b1*d2*f2 - 
+     4*a1*a2*e1*f2 + 4*a1*a1*e2*f2)/(Easq*Ea);
+  
+   A0 =
+     (-4*a2*d1*d2*f1 + 4*a1*d2*d2*f1 + a2*a2*f1*f1 + 
+   4*a2*d1*d1*f2 - 4*a1*d1*d2*f2 - 2*a1*a2*f1*f2 + 
+     a1*a1*f2*f2)/(Easq*Easq);
+   
+   long  double A0sq, A1sq, A2sq, A3sq, A4sq;
+   A0sq = A0*A0;
+   A1sq = A1*A1;
+   A2sq = A2*A2;
+   A3sq = A3*A3;
+   A4sq = A4*A4;
+   
+   long double B3, B2, B1, B0;
+   B3 = 4*A4;
+   B2 = 3*A3;
+   B1 = 2*A2;
+   B0 = A1;
+   
+   long double C2, C1, C0;
+   C2 = -(A2/2 - 3*A3sq/(16*A4));
+   C1 = -(3*A1/4. -A2*A3/(8*A4));
+   C0 = -A0 + A1*A3/(16*A4);
+   
+   long double D1, D0;
+   D1 = -B1 - (B3*C1*C1/C2 - B3*C0 -B2*C1)/C2;
+   D0 = -B0 - B3 *C0 *C1/(C2*C2)+ B2*C0/C2;
+   
+   long double E0;
+   E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
+   
+   long  double t1,t2,t3,t4,t5;
+//find the coefficients for the leading term in the Sturm sequence  
+   t1 = A4;
+   t2 = A4;
+   t3 = C2;
+   t4 = D1;
+   t5 = E0;
+ 
+
+//The number of solutions depends on diffence of number of sign changes for x->Inf and x->-Inf
+   int nsol;
+   nsol = signchange_n(t1,t2,t3,t4,t5) - signchange_p(t1,t2,t3,t4,t5);
+
+//Cannot have negative number of solutions, must be roundoff effect
+   if (nsol < 0) nsol = 0;
+
+   return nsol;
+  
+}  
+
+inline int mt2::signchange_n( long double t1, long double t2, long double t3, long double t4, long double t5)
+{
+   int nsc;
+   nsc=0;
+   if(t1*t2>0) nsc++;
+   if(t2*t3>0) nsc++;
+   if(t3*t4>0) nsc++;
+   if(t4*t5>0) nsc++;
+   return nsc;
+}
+inline int mt2::signchange_p( long double t1, long double t2, long double t3, long double t4, long double t5)
+{
+   int nsc;
+   nsc=0;
+   if(t1*t2<0) nsc++;
+   if(t2*t3<0) nsc++;
+   if(t3*t4<0) nsc++;
+   if(t4*t5<0) nsc++;
+   return nsc;
+}
+
+}//end namespace mt2_bisect
+
+}//end namespace Rivet

Added: trunk/src/Tools/mt2_bisect.hh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/src/Tools/mt2_bisect.hh	Wed Apr 13 15:24:21 2011	(r3054)
@@ -0,0 +1,85 @@
+#ifndef MT2_BISECT_H
+#define MT2_BISECT_H
+
+/***********************************************************************/
+/*                                                                     */
+/*              Finding mt2 by Bisection                               */
+/*                                                                     */
+/*              Authors: Hsin-Chia Cheng, Zhenyu Han                   */ 
+/*              Dec 11, 2008, v1.01a                                   */
+/*                                                                     */
+/*              see arXiv:0810.5178                                    */  
+/*                                                                     */  
+/*              Wrapped for Rivet by D. Grellscheid                    */
+/*              Apr 13, 2011                                           */
+/*                                                                     */  
+/***********************************************************************/
+
+namespace Rivet {
+
+namespace mt2_bisect
+{
+
+/*The user can change the desired precision below, the larger one of the following two definitions is used. Relative precision less than 0.00001 is not guaranteed to be achievable--use with caution*/ 
+
+  const double RELATIVE_PRECISION = 0.00001; 
+  //defined as precision = RELATIVE_PRECISION * scale, where scale = max{Ea, Eb}
+
+  const double ABSOLUTE_PRECISION = 0.0;     
+  //absolute precision for mt2, unused by default
+
+
+//Reserved for expert
+  const double MIN_MASS = 0.1; //if ma<MINMASS and mb<MINMASS, use massless code
+  const double ZERO_MASS = 0.000; //give massless particles a small mass
+  const double SCANSTEP = 0.1;
+
+class mt2
+{  
+   public:
+
+      mt2();
+      void   mt2_bisect();
+      void   mt2_massless();
+      void   set_momenta(double *pa0, double *pb0, double* pmiss0);
+      void   set_mn(double mn);
+      double get_mt2();
+  // void   print();
+      int    nevt;
+   private:  
+
+      bool   solved;
+      bool   momenta_set;
+      double mt2_b;
+
+      int    nsols(double Dsq);
+      int    nsols_massless(double Dsq);
+      inline int    signchange_n( long double t1, long double t2, long double t3, long double t4, long double t5);
+      inline int    signchange_p( long double t1, long double t2, long double t3, long double t4, long double t5);
+      int scan_high(double &Deltasq_high);
+      int find_high(double &Deltasq_high);
+      //data members
+      double pax, pay, ma, Ea;
+      double pmissx, pmissy;
+      double pbx, pby, mb, Eb;
+      double mn, mn_unscale;
+     
+      //auxiliary definitions
+      double masq, Easq;
+      double mbsq, Ebsq;
+      double pmissxsq, pmissysq;
+      double mnsq;
+
+      //auxiliary coefficients
+      double a1, b1, c1, a2, b2, c2, d1, e1, f1, d2, e2, f2;
+      double d11, e11, f12, f10, d21, d20, e21, e20, f22, f21, f20;
+
+      double scale;
+      double precision;
+};
+
+}//end namespace mt2_bisect
+
+}//end namespace Rivet
+
+#endif


More information about the Rivet-svn mailing list