rivet is hosted by Hepforge, IPPP Durham
mt2_bisect.cc
Go to the documentation of this file.
00001 /***********************************************************************/
00002 /*                                                                     */
00003 /*              Finding mt2 by Bisection                               */
00004 /*                                                                     */
00005 /*              Authors: Hsin-Chia Cheng, Zhenyu Han                   */ 
00006 /*              Dec 11, 2008, v1.01a                                   */
00007 /*                                                                     */
00008 /*              see arXiv:0810.5178                                    */  
00009 /*                                                                     */  
00010 /*              Wrapped for Rivet by D. Grellscheid                    */
00011 /*              Apr 13, 2011                                           */
00012 /*                                                                     */  
00013 /***********************************************************************/
00014 
00015 
00016 /*******************************************************************************
00017   Usage: 
00018 
00019   1. Define an object of type "mt2":
00020      
00021      mt2_bisect::mt2 mt2_event;
00022  
00023   2. Set momenta and the mass of the invisible particle, mn:
00024  
00025      mt2_event.set_momenta( pa, pb, pmiss );
00026      mt2_event.set_mass( mn );
00027  
00028      where array pa[0..2], pb[0..2], pmiss[0..2] contains (mass,px,py) 
00029      for the visible particles and the missing momentum. pmiss[0] is not used. 
00030      All quantities are given in double.    
00031 
00032   3. Use mt2::get_mt2() to obtain the value of mt2:
00033 
00034      double mt2_value = mt2_event.get_mt2();       
00035           
00036 *******************************************************************************/ 
00037 #include "mt2_bisect.hh"
00038 #include "Rivet/Tools/Logging.hh"
00039 #include <cmath>
00040 #include <cassert>
00041 
00042 namespace Rivet {
00043 
00044 namespace mt2_bisect
00045 {
00046 using namespace std;
00047 
00048 mt2::mt2()
00049 {
00050    solved = false;
00051    momenta_set = false;
00052    mt2_b  = 0.;
00053    scale = 1.;
00054 }
00055 
00056 double mt2::get_mt2()
00057 {
00058    assert(momenta_set);
00059    if (!solved) mt2_bisect();
00060    return mt2_b*scale;
00061 }
00062 
00063 void mt2::set_momenta(double* pa0, double* pb0, double* pmiss0)
00064 {
00065    solved = false;     //reset solved tag when momenta are changed.
00066    momenta_set = true;
00067 
00068    ma = fabs(pa0[0]);  // mass cannot be negative
00069 
00070    if (ma < ZERO_MASS) ma = ZERO_MASS;
00071 
00072    pax  = pa0[1]; 
00073    pay  = pa0[2];
00074    masq = ma*ma;
00075    Easq = masq+pax*pax+pay*pay;
00076    Ea   = sqrt(Easq);
00077    
00078    mb = fabs(pb0[0]);
00079 
00080    if (mb < ZERO_MASS) mb = ZERO_MASS;
00081 
00082    pbx  = pb0[1]; 
00083    pby  = pb0[2];
00084    mbsq = mb*mb;
00085    Ebsq = mbsq+pbx*pbx+pby*pby;
00086    Eb   = sqrt(Ebsq);
00087      
00088    pmissx   = pmiss0[1]; pmissy = pmiss0[2];
00089    pmissxsq = pmissx*pmissx;
00090    pmissysq = pmissy*pmissy;
00091 
00092 // set ma>= mb
00093    if(masq < mbsq)
00094    {
00095       double temp;
00096       temp = pax;  pax  = pbx;  pbx  = temp;
00097       temp = pay;  pay  = pby;  pby  = temp;
00098       temp = Ea;   Ea   = Eb;   Eb   = temp;
00099       temp = Easq; Easq = Ebsq; Ebsq = temp;
00100       temp = masq; masq = mbsq; mbsq = temp;
00101       temp = ma;   ma   = mb;   mb   = temp;   
00102    }
00103 //normalize max{Ea, Eb} to 100
00104    if (Ea > Eb) scale = Ea/100.;
00105    else scale = Eb/100.;
00106    
00107    if (sqrt(pmissxsq+pmissysq)/100 > scale) scale = sqrt(pmissxsq+pmissysq)/100;
00108    //scale = 1;
00109    double scalesq = scale * scale;
00110    ma  = ma/scale;
00111    mb  = mb/scale;
00112    masq = masq/scalesq;
00113    mbsq = mbsq/scalesq;
00114    pax = pax/scale; pay = pay/scale;
00115    pbx = pbx/scale; pby = pby/scale;
00116    Ea  = Ea/scale;  Eb = Eb/scale;
00117    
00118    Easq = Easq/scalesq;
00119    Ebsq = Ebsq/scalesq;
00120    pmissx = pmissx/scale;
00121    pmissy = pmissy/scale;
00122    pmissxsq = pmissxsq/scalesq;
00123    pmissysq = pmissysq/scalesq;
00124    mn   = mn_unscale/scale; 
00125    mnsq = mn*mn;
00126   
00127    if (ABSOLUTE_PRECISION > 100.*RELATIVE_PRECISION) precision = ABSOLUTE_PRECISION;
00128    else precision = 100.*RELATIVE_PRECISION;
00129 }
00130 
00131 void mt2::set_mn(double mn0)
00132 {
00133    solved = false;    //reset solved tag when mn is changed.
00134    mn_unscale   = fabs(mn0);  //mass cannot be negative
00135    mn = mn_unscale/scale;
00136    mnsq = mn*mn;
00137 }
00138 
00139 // void mt2::print()
00140 // {
00141 //    cout << " pax = " << pax*scale << ";   pay = " << pay*scale << ";   ma = " << ma*scale <<";"<< endl;
00142 //    cout << " pbx = " << pbx*scale << ";   pby = " << pby*scale << ";   mb = " << mb*scale <<";"<< endl;
00143 //    cout << " pmissx = " << pmissx*scale << ";   pmissy = " << pmissy*scale <<";"<< endl;
00144 //    cout << " mn = " << mn_unscale<<";" << endl;
00145 // }
00146 
00147 //special case, the visible particle is massless
00148 void mt2::mt2_massless()
00149 {
00150    
00151 //rotate so that pay = 0 
00152    double theta,s,c;
00153    theta = atan(pay/pax);
00154    s = sin(theta);
00155    c = cos(theta);
00156 
00157    double pxtemp,pytemp;
00158    Easq   = pax*pax+pay*pay;
00159    Ebsq   = pbx*pbx+pby*pby;
00160    Ea     = sqrt(Easq);
00161    Eb     = sqrt(Ebsq);
00162   
00163    pxtemp = pax*c+pay*s;
00164    pax    = pxtemp;
00165    pay    = 0;
00166    pxtemp = pbx*c+pby*s;
00167    pytemp = -s*pbx+c*pby;
00168    pbx    = pxtemp;
00169    pby    = pytemp;
00170    pxtemp = pmissx*c+pmissy*s;
00171    pytemp = -s*pmissx+c*pmissy;
00172    pmissx = pxtemp;
00173    pmissy = pytemp;
00174 
00175    a2  = 1-pbx*pbx/(Ebsq);
00176    b2  = -pbx*pby/(Ebsq);
00177    c2  = 1-pby*pby/(Ebsq);
00178 
00179    d21 = (Easq*pbx)/Ebsq;
00180    d20 = - pmissx +  (pbx*(pbx*pmissx + pby*pmissy))/Ebsq;
00181    e21 = (Easq*pby)/Ebsq;
00182    e20 = - pmissy +  (pby*(pbx*pmissx + pby*pmissy))/Ebsq;
00183    f22 = -(Easq*Easq/Ebsq);
00184    f21 = -2*Easq*(pbx*pmissx + pby*pmissy)/Ebsq;
00185    f20 = mnsq + pmissxsq + pmissysq - (pbx*pmissx + pby*pmissy)*(pbx*pmissx + pby*pmissy)/Ebsq;
00186 
00187    double Deltasq0    = 0; 
00188    double Deltasq_low, Deltasq_high;
00189    int    nsols_high, nsols_low;
00190 
00191    Deltasq_low = Deltasq0 + precision;
00192    nsols_low = nsols_massless(Deltasq_low);
00193    
00194    if(nsols_low > 1) 
00195    { 
00196       mt2_b = (double) sqrt(Deltasq0+mnsq);
00197       return;
00198    }
00199 
00200 /*   
00201    if( nsols_massless(Deltasq_high) > 0 )
00202    {
00203       mt2_b = (double) sqrt(mnsq+Deltasq0);
00204       return;
00205    }*/
00206 
00207 //look for when both parablos contain origin  
00208    double Deltasq_high1, Deltasq_high2;
00209    Deltasq_high1 = 2*Eb*sqrt(pmissx*pmissx+pmissy*pmissy+mnsq)-2*pbx*pmissx-2*pby*pmissy;
00210    Deltasq_high2 = 2*Ea*mn;
00211  
00212    if(Deltasq_high1 < Deltasq_high2) Deltasq_high = Deltasq_high2;
00213      else Deltasq_high = Deltasq_high1;
00214 
00215    nsols_high=nsols_massless(Deltasq_high);
00216   
00217    int foundhigh;
00218    if (nsols_high == nsols_low)
00219    {
00220       
00221       
00222       foundhigh=0;
00223       
00224       double minmass, maxmass;
00225       minmass  = mn ;
00226       maxmass  = sqrt(mnsq + Deltasq_high);
00227       for(double mass = minmass + SCANSTEP; mass < maxmass; mass += SCANSTEP)
00228       {
00229      Deltasq_high = mass*mass - mnsq;
00230       
00231          nsols_high = nsols_massless(Deltasq_high);
00232          if(nsols_high>0)
00233          {
00234             foundhigh=1;
00235             Deltasq_low = (mass-SCANSTEP)*(mass-SCANSTEP) - mnsq;
00236             break;
00237          }
00238       }
00239       if(foundhigh==0) 
00240       {
00241        
00242     Log::getLog("Rivet.Tools.mt2") 
00243       << Log::WARN  
00244       << "Deltasq_high not found at event " << nevt << '\n';
00245        
00246          mt2_b = (double)sqrt(Deltasq_low+mnsq);
00247          return;
00248       }
00249    }
00250 
00251    if(nsols_high == nsols_low)
00252    { 
00253      Log::getLog("Rivet.Tools.mt2") 
00254        << Log::ERROR  
00255        << "error: nsols_low=nsols_high=" << nsols_high << '\n'
00256        << "Deltasq_high=" << Deltasq_high << '\n'
00257        << "Deltasq_low= "<< Deltasq_low << '\n';
00258     
00259       mt2_b = sqrt(mnsq + Deltasq_low);
00260       return;
00261    }
00262    double minmass, maxmass;
00263    minmass = sqrt(Deltasq_low+mnsq);
00264    maxmass = sqrt(Deltasq_high+mnsq);
00265    while(maxmass - minmass > precision)
00266    {
00267       double Delta_mid, midmass, nsols_mid;
00268       midmass   = (minmass+maxmass)/2.;
00269       Delta_mid = midmass * midmass - mnsq;
00270       nsols_mid = nsols_massless(Delta_mid);
00271       if(nsols_mid != nsols_low) maxmass = midmass;
00272       if(nsols_mid == nsols_low) minmass = midmass;
00273    }
00274    mt2_b = minmass;
00275    return;
00276 }
00277 
00278 int mt2::nsols_massless(double Dsq)
00279 {
00280   double delta;
00281   delta = Dsq/(2*Easq);
00282   d1    = d11*delta;
00283   e1    = e11*delta;
00284   f1    = f12*delta*delta+f10;
00285   d2    = d21*delta+d20;
00286   e2    = e21*delta+e20;
00287   f2    = f22*delta*delta+f21*delta+f20;
00288   
00289   double a,b;
00290   if (pax > 0) a = Ea/Dsq;
00291   else         a = -Ea/Dsq;
00292   if (pax > 0) b = -Dsq/(4*Ea)+mnsq*Ea/Dsq;
00293   else         b = Dsq/(4*Ea)-mnsq*Ea/Dsq;
00294   
00295   double A4,A3,A2,A1,A0;
00296 
00297   A4 = a*a*a2;
00298   A3 = 2*a*b2/Ea;
00299   A2 = (2*a*a2*b+c2+2*a*d2)/(Easq);
00300   A1 = (2*b*b2+2*e2)/(Easq*Ea);
00301   A0 = (a2*b*b+2*b*d2+f2)/(Easq*Easq);
00302   
00303   long double B3, B2, B1, B0;
00304   B3 = 4*A4;
00305   B2 = 3*A3;
00306   B1 = 2*A2;
00307   B0 = A1;
00308   long double C2, C1, C0;
00309   C2 = -(A2/2 - 3*A3*A3/(16*A4));
00310   C1 = -(3*A1/4. -A2*A3/(8*A4));
00311   C0 = -A0 + A1*A3/(16*A4);
00312   long double  D1, D0;
00313   D1 = -B1 - (B3*C1*C1/C2 - B3*C0 -B2*C1)/C2;
00314   D0 = -B0 - B3 *C0 *C1/(C2*C2)+ B2*C0/C2;
00315  
00316   long double E0;
00317   E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
00318  
00319   long  double t1,t2,t3,t4,t5;
00320    
00321 //find the coefficients for the leading term in the Sturm sequence  
00322    t1 = A4;
00323    t2 = A4;
00324    t3 = C2;
00325    t4 = D1;
00326    t5 = E0;
00327   
00328    int nsol;
00329    nsol = signchange_n(t1,t2,t3,t4,t5)-signchange_p(t1,t2,t3,t4,t5);
00330    if( nsol < 0 ) nsol=0;
00331 
00332    return nsol;
00333   
00334 }
00335 
00336 void mt2::mt2_bisect()
00337 {   
00338   solved = true;
00339 
00340 //if masses are very small, use code for massless case.  
00341    if(masq < MIN_MASS && mbsq < MIN_MASS) 
00342    { 
00343       mt2_massless();
00344       return;
00345    }
00346  
00347 
00348    double Deltasq0;     
00349    Deltasq0 = ma*(ma + 2*mn); //The minimum mass square to have two ellipses 
00350  
00351 // find the coefficients for the two quadratic equations when Deltasq=Deltasq0.
00352   
00353    a1 = 1-pax*pax/(Easq);
00354    b1 = -pax*pay/(Easq);
00355    c1 = 1-pay*pay/(Easq);
00356    d1 = -pax*(Deltasq0-masq)/(2*Easq);
00357    e1 = -pay*(Deltasq0-masq)/(2*Easq);
00358    a2 = 1-pbx*pbx/(Ebsq);
00359    b2 = -pbx*pby/(Ebsq);
00360    c2 = 1-pby*pby/(Ebsq);
00361    d2 = -pmissx+pbx*(Deltasq0-mbsq)/(2*Ebsq)+pbx*(pbx*pmissx+pby*pmissy)/(Ebsq);
00362    e2 = -pmissy+pby*(Deltasq0-mbsq)/(2*Ebsq)+pby*(pbx*pmissx+pby*pmissy)/(Ebsq);
00363    f2 = pmissx*pmissx+pmissy*pmissy-((Deltasq0-mbsq)/(2*Eb)+
00364         (pbx*pmissx+pby*pmissy)/Eb)*((Deltasq0-mbsq)/(2*Eb)+
00365         (pbx*pmissx+pby*pmissy)/Eb)+mnsq;
00366    
00367 // find the center of the smaller ellipse 
00368    double x0,y0;
00369    x0 = (c1*d1-b1*e1)/(b1*b1-a1*c1);
00370    y0 = (a1*e1-b1*d1)/(b1*b1-a1*c1);
00371 
00372    
00373 // Does the larger ellipse contain the smaller one? 
00374    double dis=a2*x0*x0+2*b2*x0*y0+c2*y0*y0+2*d2*x0+2*e2*y0+f2;
00375 
00376    if(dis<=0.01)
00377    { 
00378       mt2_b  = (double) sqrt(mnsq+Deltasq0);
00379       return;
00380    }
00381    
00382 
00383 /* find the coefficients for the two quadratic equations           */
00384 /* coefficients for quadratic terms do not change                  */
00385 /* coefficients for linear and constant terms are polynomials of   */
00386 /*       delta=(Deltasq-m7sq)/(2 E7sq)                             */  
00387    d11 = -pax;
00388    e11 = -pay;
00389    f10 = mnsq;
00390    f12 = -Easq;
00391    d21 = (Easq*pbx)/Ebsq;
00392    d20 = ((masq - mbsq)*pbx)/(2.*Ebsq) - pmissx +
00393          (pbx*(pbx*pmissx + pby*pmissy))/Ebsq;
00394    e21 = (Easq*pby)/Ebsq;
00395    e20 = ((masq - mbsq)*pby)/(2.*Ebsq) - pmissy +
00396          (pby*(pbx*pmissx + pby*pmissy))/Ebsq;
00397    f22 = -Easq*Easq/Ebsq;
00398    f21 = (-2*Easq*((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb))/Eb;
00399    f20 = mnsq + pmissx*pmissx + pmissy*pmissy - 
00400          ((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb)
00401          *((masq - mbsq)/(2.*Eb) + (pbx*pmissx + pby*pmissy)/Eb);
00402 
00403 //Estimate upper bound of mT2
00404 //when Deltasq > Deltasq_high1, the larger encloses the center of the smaller 
00405    double p2x0,p2y0;
00406    double Deltasq_high1;
00407    p2x0 = pmissx-x0;
00408    p2y0 = pmissy-y0;
00409    Deltasq_high1 = 2*Eb*sqrt(p2x0*p2x0+p2y0*p2y0+mnsq)-2*pbx*p2x0-2*pby*p2y0+mbsq;
00410    
00411 //Another estimate, if both ellipses enclose the origin, Deltasq > mT2
00412 
00413    double Deltasq_high2, Deltasq_high21, Deltasq_high22;
00414    Deltasq_high21 = 2*Eb*sqrt(pmissx*pmissx+pmissy*pmissy+mnsq)-2*pbx*pmissx-2*pby*pmissy+mbsq;
00415    Deltasq_high22 = 2*Ea*mn+masq;
00416   
00417    if ( Deltasq_high21 < Deltasq_high22 ) Deltasq_high2 = Deltasq_high22;
00418    else Deltasq_high2 = Deltasq_high21;
00419 
00420 //pick the smaller upper bound   
00421    double Deltasq_high;
00422    if(Deltasq_high1 < Deltasq_high2) Deltasq_high = Deltasq_high1;
00423    else Deltasq_high = Deltasq_high2;
00424    
00425   
00426    double Deltasq_low; //lower bound
00427    Deltasq_low = Deltasq0;
00428 
00429 //number of solutions at Deltasq_low should not be larger than zero
00430    if( nsols(Deltasq_low) > 0 )
00431    {
00432      //cout << "nsolutions(Deltasq_low) > 0"<<endl;
00433      mt2_b = (double) sqrt(mnsq+Deltasq0);
00434      return;
00435    }
00436   
00437    int nsols_high, nsols_low;
00438 
00439    nsols_low  = nsols(Deltasq_low);
00440    int foundhigh;
00441   
00442 
00443 //if nsols_high=nsols_low, we missed the region where the two ellipse overlap 
00444 //if nsols_high=4, also need a scan because we may find the wrong tangent point.
00445 
00446    nsols_high = nsols(Deltasq_high);
00447   
00448    if(nsols_high == nsols_low || nsols_high == 4)
00449    {
00450       //foundhigh = scan_high(Deltasq_high);
00451       foundhigh = find_high(Deltasq_high);
00452       if(foundhigh == 0) 
00453       {
00454      Log::getLog("Rivet.Tools.mt2") 
00455        << Log::WARN  
00456        << "Deltasq_high not found at event " << nevt << '\n';
00457          mt2_b = sqrt( Deltasq_low + mnsq );
00458          return;
00459       }
00460       
00461    }
00462 
00463    while(sqrt(Deltasq_high+mnsq) - sqrt(Deltasq_low+mnsq) > precision)
00464    {
00465       double Deltasq_mid,nsols_mid;
00466       //bisect
00467       Deltasq_mid = (Deltasq_high+Deltasq_low)/2.;
00468       nsols_mid = nsols(Deltasq_mid);
00469       // if nsols_mid = 4, rescan for Deltasq_high
00470       if ( nsols_mid == 4 ) 
00471       {
00472          Deltasq_high = Deltasq_mid;
00473          //scan_high(Deltasq_high);
00474          find_high(Deltasq_high);
00475          continue;
00476       } 
00477          
00478       
00479       if(nsols_mid != nsols_low) Deltasq_high = Deltasq_mid;
00480       if(nsols_mid == nsols_low) Deltasq_low  = Deltasq_mid;
00481    }
00482    mt2_b = (double) sqrt( mnsq + Deltasq_high);
00483    return;
00484 }
00485 
00486 int mt2::find_high(double & Deltasq_high)
00487 {
00488    double x0,y0;
00489    x0 = (c1*d1-b1*e1)/(b1*b1-a1*c1);
00490    y0 = (a1*e1-b1*d1)/(b1*b1-a1*c1);
00491    double Deltasq_low = (mn + ma)*(mn + ma) - mnsq;
00492    do 
00493    {
00494       double Deltasq_mid = (Deltasq_high + Deltasq_low)/2.;
00495       int nsols_mid = nsols(Deltasq_mid);
00496       if ( nsols_mid == 2 )
00497       {
00498          Deltasq_high = Deltasq_mid;
00499          return 1;
00500       }
00501       else if (nsols_mid == 4)
00502       {
00503          Deltasq_high = Deltasq_mid;
00504          continue;
00505       }
00506       else if (nsols_mid ==0)
00507       {
00508          d1 = -pax*(Deltasq_mid-masq)/(2*Easq);
00509          e1 = -pay*(Deltasq_mid-masq)/(2*Easq);
00510          d2 = -pmissx + pbx*(Deltasq_mid - mbsq)/(2*Ebsq)
00511               + pbx*(pbx*pmissx+pby*pmissy)/(Ebsq);
00512          e2 = -pmissy + pby*(Deltasq_mid - mbsq)/(2*Ebsq)
00513               + pby*(pbx*pmissx+pby*pmissy)/(Ebsq);
00514          f2 = pmissx*pmissx+pmissy*pmissy-((Deltasq_mid-mbsq)/(2*Eb)+
00515               (pbx*pmissx+pby*pmissy)/Eb)*((Deltasq_mid-mbsq)/(2*Eb)+
00516               (pbx*pmissx+pby*pmissy)/Eb)+mnsq;
00517 // Does the larger ellipse contain the smaller one? 
00518          double dis = a2*x0*x0 + 2*b2*x0*y0 + c2*y0*y0 + 2*d2*x0 + 2*e2*y0 + f2;
00519          if (dis < 0) Deltasq_high = Deltasq_mid;
00520            else Deltasq_low = Deltasq_mid;
00521       }
00522       
00523    } while ( Deltasq_high - Deltasq_low > 0.001);
00524    return 0;
00525 }  
00526 int mt2::scan_high(double & Deltasq_high)
00527 {
00528    int foundhigh = 0 ;
00529    int nsols_high;
00530 
00531    
00532    double tempmass, maxmass;
00533    tempmass = mn + ma;
00534    maxmass  = sqrt(mnsq + Deltasq_high);
00535    // if (nevt == 32334) {
00536      
00537    //   cout << "Deltasq_high = " << Deltasq_high << endl;
00538    // }
00539    for(double mass = tempmass + SCANSTEP; mass < maxmass; mass += SCANSTEP)
00540    {
00541       Deltasq_high = mass*mass - mnsq;
00542       nsols_high   = nsols(Deltasq_high);
00543       
00544       if( nsols_high > 0)
00545       {
00546          foundhigh   = 1;
00547          break;
00548       }
00549     }
00550     return foundhigh;
00551 }
00552 int mt2::nsols(  double Dsq)
00553 {
00554    double delta = (Dsq-masq)/(2*Easq);
00555   
00556 //calculate coefficients for the two quadratic equations
00557    d1 = d11*delta;
00558    e1 = e11*delta;
00559    f1 = f12*delta*delta+f10;
00560    d2 = d21*delta+d20;
00561    e2 = e21*delta+e20;
00562    f2 = f22*delta*delta+f21*delta+f20;
00563 
00564 //obtain the coefficients for the 4th order equation 
00565 //devided by Ea^n to make the variable dimensionless
00566    long double A4, A3, A2, A1, A0;
00567 
00568    A4 = 
00569    -4*a2*b1*b2*c1 + 4*a1*b2*b2*c1 +a2*a2*c1*c1 + 
00570    4*a2*b1*b1*c2 - 4*a1*b1*b2*c2 - 2*a1*a2*c1*c2 + 
00571    a1*a1*c2*c2;  
00572 
00573    A3 =
00574      (-4*a2*b2*c1*d1 + 8*a2*b1*c2*d1 - 4*a1*b2*c2*d1 - 4*a2*b1*c1*d2 + 
00575    8*a1*b2*c1*d2 - 4*a1*b1*c2*d2 - 8*a2*b1*b2*e1 + 8*a1*b2*b2*e1 + 
00576    4*a2*a2*c1*e1 - 4*a1*a2*c2*e1 + 8*a2*b1*b1*e2 - 8*a1*b1*b2*e2 - 
00577      4*a1*a2*c1*e2 + 4*a1*a1*c2*e2)/Ea;
00578 
00579    
00580    A2 =
00581      (4*a2*c2*d1*d1 - 4*a2*c1*d1*d2 - 4*a1*c2*d1*d2 + 4*a1*c1*d2*d2 - 
00582    8*a2*b2*d1*e1 - 8*a2*b1*d2*e1 + 16*a1*b2*d2*e1 + 
00583    4*a2*a2*e1*e1 + 16*a2*b1*d1*e2 - 8*a1*b2*d1*e2 - 
00584    8*a1*b1*d2*e2 - 8*a1*a2*e1*e2 + 4*a1*a1*e2*e2 - 4*a2*b1*b2*f1 + 
00585    4*a1*b2*b2*f1 + 2*a2*a2*c1*f1 - 2*a1*a2*c2*f1 + 
00586      4*a2*b1*b1*f2 - 4*a1*b1*b2*f2 - 2*a1*a2*c1*f2 + 2*a1*a1*c2*f2)/Easq;
00587   
00588    A1 =
00589      (-8*a2*d1*d2*e1 + 8*a1*d2*d2*e1 + 8*a2*d1*d1*e2 - 8*a1*d1*d2*e2 - 
00590    4*a2*b2*d1*f1 - 4*a2*b1*d2*f1 + 8*a1*b2*d2*f1 + 4*a2*a2*e1*f1 - 
00591    4*a1*a2*e2*f1 + 8*a2*b1*d1*f2 - 4*a1*b2*d1*f2 - 4*a1*b1*d2*f2 - 
00592      4*a1*a2*e1*f2 + 4*a1*a1*e2*f2)/(Easq*Ea);
00593   
00594    A0 =
00595      (-4*a2*d1*d2*f1 + 4*a1*d2*d2*f1 + a2*a2*f1*f1 + 
00596    4*a2*d1*d1*f2 - 4*a1*d1*d2*f2 - 2*a1*a2*f1*f2 + 
00597      a1*a1*f2*f2)/(Easq*Easq);
00598    
00599    long double B3, B2, B1, B0;
00600    B3 = 4*A4;
00601    B2 = 3*A3;
00602    B1 = 2*A2;
00603    B0 = A1;
00604    
00605    long double C2, C1, C0;
00606    C2 = -(A2/2 - 3*A3*A3/(16*A4));
00607    C1 = -(3*A1/4. -A2*A3/(8*A4));
00608    C0 = -A0 + A1*A3/(16*A4);
00609    
00610    long double D1, D0;
00611    D1 = -B1 - (B3*C1*C1/C2 - B3*C0 -B2*C1)/C2;
00612    D0 = -B0 - B3 *C0 *C1/(C2*C2)+ B2*C0/C2;
00613    
00614    long double E0;
00615    E0 = -C0 - C2*D0*D0/(D1*D1) + C1*D0/D1;
00616    
00617    long  double t1,t2,t3,t4,t5;
00618 //find the coefficients for the leading term in the Sturm sequence  
00619    t1 = A4;
00620    t2 = A4;
00621    t3 = C2;
00622    t4 = D1;
00623    t5 = E0;
00624  
00625 
00626 //The number of solutions depends on diffence of number of sign changes for x->Inf and x->-Inf
00627    int nsol;
00628    nsol = signchange_n(t1,t2,t3,t4,t5) - signchange_p(t1,t2,t3,t4,t5);
00629 
00630 //Cannot have negative number of solutions, must be roundoff effect
00631    if (nsol < 0) nsol = 0;
00632 
00633    return nsol;
00634   
00635 }  
00636 
00637 inline int mt2::signchange_n( long double t1, long double t2, long double t3, long double t4, long double t5)
00638 {
00639    int nsc;
00640    nsc=0;
00641    if(t1*t2>0) nsc++;
00642    if(t2*t3>0) nsc++;
00643    if(t3*t4>0) nsc++;
00644    if(t4*t5>0) nsc++;
00645    return nsc;
00646 }
00647 inline int mt2::signchange_p( long double t1, long double t2, long double t3, long double t4, long double t5)
00648 {
00649    int nsc;
00650    nsc=0;
00651    if(t1*t2<0) nsc++;
00652    if(t2*t3<0) nsc++;
00653    if(t3*t4<0) nsc++;
00654    if(t4*t5<0) nsc++;
00655    return nsc;
00656 }
00657 
00658 }//end namespace mt2_bisect
00659 
00660 }//end namespace Rivet