CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/PhysicsTools/IsolationUtils/src/IntegralOverPhiFunction.cc

Go to the documentation of this file.
00001 #include "PhysicsTools/IsolationUtils/interface/IntegralOverPhiFunction.h"
00002 
00003 // -*- C++ -*-
00004 //
00005 // Package:    IntegralOverPhiFunction
00006 // Class:      IntegralOverPhiFunction
00007 // 
00016 //
00017 // Original Author:  Christian Veelken, UC Davis
00018 //         Created:  Thu Nov  2 13:47:40 CST 2006
00019 // $Id: IntegralOverPhiFunction.cc,v 1.3 2009/01/14 10:53:15 hegner Exp $
00020 //
00021 //
00022 
00023 // system include files
00024 #include <iostream>
00025 #include <iomanip>
00026 #include <vector>
00027 
00028 // ROOT include files
00029 #include <TMath.h>
00030 
00031 // CMSSW include files
00032 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00033 
00034 #include "DataFormats/Math/interface/normalizedPhi.h"
00035 
00036 //
00037 // declaration of auxiliary functions
00038 //
00039 
00040 void checkSolutions(unsigned int i, unsigned int& numSolution1, unsigned int& numSolution2, unsigned int& numSolution3, unsigned int& numSolution4);
00041 
00042 //
00043 // constructors and destructor
00044 //
00045 
00046 IntegralOverPhiFunction::IntegralOverPhiFunction()
00047   : ROOT::Math::ParamFunction<ROOT::Math::IParametricGradFunctionOneDim>(3)
00048 { 
00049   theta0_ = 0.; 
00050   phi0_ = 0.; 
00051   alpha_ = 0.; 
00052 
00053 // !!! ONLY FOR TESTING
00054   numSolutionMin1_ = 0;
00055   numSolutionMax1_ = 0;
00056   numSolutionMin2_ = 0;
00057   numSolutionMax2_ = 0;
00058   numSolutionMin3_ = 0;
00059   numSolutionMax3_ = 0;
00060   numSolutionMin4_ = 0;
00061   numSolutionMax4_ = 0;
00062 //     FOR TESTING ONLY !!!
00063 }
00064 
00065 IntegralOverPhiFunction::~IntegralOverPhiFunction()
00066 {
00067 // !!! ONLY FOR TESTING
00068   if ( debugLevel_ > 0 ) {
00069     edm::LogVerbatim("") << "<IntegralOverPhiFunction::~IntegralOverPhiFunction>:" << std::endl
00070                          << " numSolutionMin1 = " << numSolutionMin1_ << std::endl
00071                          << " numSolutionMax1 = " << numSolutionMax1_ << std::endl
00072                          << " numSolutionMin2 = " << numSolutionMin2_ << std::endl
00073                          << " numSolutionMax2 = " << numSolutionMax2_ << std::endl
00074                          << " numSolutionMin3 = " << numSolutionMin3_ << std::endl
00075                          << " numSolutionMax3 = " << numSolutionMax3_ << std::endl
00076                          << " numSolutionMin4 = " << numSolutionMin4_ << std::endl
00077                          << " numSolutionMax4 = " << numSolutionMax4_ << std::endl;
00078   }
00079 //     FOR TESTING ONLY !!!
00080 }
00081 
00082 //
00083 // member functions
00084 //
00085 
00086 void IntegralOverPhiFunction::SetParameterTheta0(double theta0)
00087 {
00088   theta0_ = theta0;
00089 }
00090 
00091 void IntegralOverPhiFunction::SetParameterPhi0(double phi0)
00092 {
00093   phi0_ = normalizedPhi(phi0); // map azimuth angle into interval [-pi,+pi]
00094 }
00095 
00096 void IntegralOverPhiFunction::SetParameterAlpha(double alpha)
00097 {
00098   alpha_ = alpha;
00099 }
00100 
00101 void IntegralOverPhiFunction::SetParameters(double* param)
00102 {
00103   theta0_ = param[0];
00104   phi0_ = param[1];
00105   alpha_ = param[2];
00106 }
00107 
00108 double IntegralOverPhiFunction::DoEvalPar(double x, const double* param) const  //FIXME: in the current implementation const is not entirely true
00109 {
00110   theta0_ = param[0];
00111   phi0_ = param[1];
00112   alpha_ = param[2];
00113 
00114   return DoEval(x);
00115 }
00116 
00117 
00118 
00119 double IntegralOverPhiFunction::DoEval(double x) const
00120 {
00121 //--- return zero if theta either close to zero or close to Pi
00122 //    (phi not well-defined in that case;
00123 //     numerical expressions might become "NaN"s)
00124   const double epsilon = 1.e-3;
00125   if ( x < epsilon || x > (TMath::Pi() - epsilon) ) return 0.;
00126 
00127 //--- calculate trigonometric expressions
00128 //    (dependend on angle theta0;
00129 //     polar angle of cone axis);
00130 //    avoid theta0 exactly zero or exactly Pi
00131 //    (numerical expressions become "NaN"s)
00132   double theta0 = theta0_;
00133   if ( theta0 <                epsilon ) theta0 = epsilon;
00134   if ( theta0 > (TMath::Pi() - epsilon)) theta0 = (TMath::Pi() - epsilon);
00135   double cosTheta0 = TMath::Cos(theta0);
00136   double cos2Theta0 = TMath::Cos(2*theta0);
00137   double sinTheta0 = TMath::Sin(theta0);
00138   double cotTheta0 = 1./TMath::Tan(theta0);
00139   double cscTheta0 = 1./TMath::Sin(theta0);
00140 //    (dependend on angle phi0;
00141 //     azimuth angle of cone axis)
00142   double cosPhi0 = TMath::Cos(phi0_);
00143   double tanPhi0 = TMath::Tan(phi0_);
00144 //    (dependend on angle theta;
00145 //     polar angle of point within cone)
00146   double cosTheta = TMath::Cos(x);
00147   double cos2Theta = TMath::Cos(2*x);
00148   double sinTheta = TMath::Sin(x);
00149   double cotTheta = 1./TMath::Tan(x);
00150   double cscTheta = 1./TMath::Sin(x);
00151 //    (dependent on angle alpha;
00152 //     opening angle of cone, measured from cone axis)
00153   double cosAlpha = TMath::Cos(alpha_);
00154 
00155   double s = -cosPhi0*cosPhi0*(2*cosAlpha*cosAlpha + cos2Theta - 4*cosAlpha*cosTheta*cosTheta0 + cos2Theta0)*sinTheta*sinTheta*sinTheta0*sinTheta0;
00156 
00157 //--- return either zero or 2 Pi
00158 //    in case argument of square-root is zero or negative
00159 //    (negative values solely arise from rounding errors);
00160 //    check whether to return zero or 2 Pi:
00161 //     o return zero 
00162 //       if |theta- theta0| > alpha, 
00163 //       (theta outside cone of opening angle alpha, so vanishing integral over phi)
00164 //     o return 2 Pi
00165 //       if |theta- theta0| < alpha
00166 //       (theta within cone of opening angle alpha;
00167 //        actually theta0 < alpha in forward/backward direction,
00168 //        so that integral includes all phi values, hence yielding 2 Pi)
00169   if ( s <= 0 ) {
00170     if ( TMath::Abs(x - theta0) >  alpha_ ) return 0;
00171     if ( TMath::Abs(x - theta0) <= alpha_ ) return 2*TMath::Pi();
00172     std::cerr << "Error in <IntegralOverPhiFunction::operator()>: failed to compute return value !" << std::endl;
00173   }
00174 
00175   double r = (1./TMath::Sqrt(2.))*(cscTheta*cscTheta*cscTheta0*cscTheta0*TMath::Sqrt(s)*tanPhi0);
00176   double t = cosPhi0*(-cotTheta*cotTheta0 + cosAlpha*cscTheta*cscTheta0);
00177   
00178   double phi[4];
00179   phi[0] = -TMath::ACos(t - r);
00180   phi[1] =  TMath::ACos(t - r);
00181   phi[2] = -TMath::ACos(t + r);
00182   phi[3] =  TMath::ACos(t + r);
00183 
00184   if ( debugLevel_ > 0 ) {
00185     edm::LogVerbatim("") << "phi0 = " << phi0_ << std::endl
00186                          << "phi[0] = " << phi[0] << " (phi[0] - phi0 = " << (phi[0] - phi0_)*180/TMath::Pi() << ")" << std::endl
00187                          << "phi[1] = " << phi[1] << " (phi[1] - phi0 = " << (phi[1] - phi0_)*180/TMath::Pi() << ")" << std::endl
00188                          << "phi[2] = " << phi[2] << " (phi[2] - phi0 = " << (phi[2] - phi0_)*180/TMath::Pi() << ")" << std::endl
00189                          << "phi[3] = " << phi[3] << " (phi[3] - phi0 = " << (phi[3] - phi0_)*180/TMath::Pi() << ")" << std::endl;
00190   }
00191 
00192   double phiMin = 0.;
00193   double phiMax = 0.;  
00194   for ( unsigned int i = 0; i < 4; ++i ) {
00195     for ( unsigned int j = (i + 1); j < 4; ++j ) {
00196 //--- search for the two solutions for phi
00197 //    that have an equal distance to phi0
00198 //    and are on either side
00199       double dPhi_i = phi[i] - phi0_;
00200       double dPhi_j = phi0_ - phi[j];
00201       if ( TMath::Abs(normalizedPhi(dPhi_i - dPhi_j)) < epsilon ) { // map difference in azimuth angle into interval [-pi,+pi] and require it to be negligible
00202       //if ( TMath::Abs((phi[i] - phi0_) - (phi0_ - phi[j])) < epsilon ) { // map difference in azimuth angle into interval [-pi,+pi] and require it to be negligible
00203         phiMin = TMath::Min(phi[i], phi[j]);
00204         phiMax = TMath::Max(phi[i], phi[j]);
00205 
00206 // !!! ONLY FOR TESTING
00207         if ( phi[i] == phiMin ) checkSolutions(i, numSolutionMin1_, numSolutionMin2_, numSolutionMin3_, numSolutionMin4_);
00208         if ( phi[i] == phiMax ) checkSolutions(i, numSolutionMax1_, numSolutionMax2_, numSolutionMax3_, numSolutionMax4_);
00209         if ( phi[j] == phiMin ) checkSolutions(j, numSolutionMin1_, numSolutionMin2_, numSolutionMin3_, numSolutionMin4_);
00210         if ( phi[j] == phiMax ) checkSolutions(j, numSolutionMax1_, numSolutionMax2_, numSolutionMax3_, numSolutionMax4_);
00211 //     FOR TESTING ONLY !!!
00212       }
00213     }
00214   }
00215 
00216   if ( phiMin == 0 && phiMax == 0 ) {
00217     edm::LogError("") << "failed to compute Return Value !" << std::endl;
00218   }
00219 
00220   return TMath::Abs(normalizedPhi(phi0_ - phiMin)) + TMath::Abs(normalizedPhi(phiMax - phi0_));
00221 }  
00222 
00223 double IntegralOverPhiFunction::DoDerivative(double x) const
00224 {
00225 //--- virtual function inherited from ROOT::Math::ParamFunction base class;
00226 //    not implemented, because not neccessary, but needs to be defined to make code compile...
00227   edm::LogWarning("") << "Function not implemented yet !" << std::endl;
00228 
00229   return 0.;
00230 }
00231 
00232 double IntegralOverPhiFunction::DoParameterDerivative(double, const double*, unsigned int) const
00233 {
00234 //--- virtual function inherited from ROOT::Math::ParamFunction base class;
00235 //    not implemented, because not neccessary, but needs to be defined to make code compile...
00236   edm::LogWarning("") << "Function not implemented yet !" << std::endl;
00237 
00238   return 0.;
00239 }
00240 
00241 void IntegralOverPhiFunction::DoParameterGradient(double x, double* paramGradient) const
00242 {
00243 //--- virtual function inherited from ROOT::Math::ParamFunction base class;
00244 //    not implemented, because not neccessary, but needs to be defined to make code compile...
00245   edm::LogWarning("") << "Function not implemented yet !" << std::endl;
00246 }
00247 
00248 //
00249 // definition of auxiliary functions
00250 //
00251 
00252 void checkSolutions(unsigned int i, unsigned int& numSolution1, unsigned int& numSolution2, unsigned int& numSolution3, unsigned int& numSolution4)
00253 {
00254   switch ( i ) {
00255   case 0 : 
00256     ++numSolution1;
00257     break;
00258   case 1 : 
00259     ++numSolution2;
00260     break;
00261   case 2 : 
00262     ++numSolution3;
00263     break;
00264   case 3 : 
00265     ++numSolution4;
00266     break;
00267   }
00268 }