CMS 3D CMS Logo

BeamProfileFitter.cc

Go to the documentation of this file.
00001 
00008 #include "Alignment/LaserAlignment/interface/BeamProfileFitter.h"
00009 
00010 // Framework headers
00011 #include "FWCore/Framework/interface/ESHandle.h"
00012 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00013 
00014 // Geometry headers
00015 #include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
00016 #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
00017 #include "Geometry/CommonTopologies/interface/StripTopology.h"
00018 #include "Geometry/TrackerGeometryBuilder/interface/StripGeomDetUnit.h"
00019 #include "Geometry/CommonDetUnit/interface/GeomDetUnit.h"
00020 #include "DataFormats/GeometryCommonDetAlgo/interface/GlobalError.h"
00021 #include "DataFormats/GeometryCommonDetAlgo/interface/ErrorFrameTransformer.h"
00022 
00023 // Topology
00024 
00025 #include "TF1.h"
00026 #include "TH1.h"
00027 #include "TMath.h"
00028 
00029 // function to return an angle in radian between 0 and 2 Pi
00030 double BeamProfileFitter::angle(double theAngle)
00031 {
00032         if ( theAngle >= 0.0 )
00033                 { return theAngle; }
00034         else if ( theAngle < 0.0 )
00035                 { return theAngle + 2.0 * M_PI; }
00036         else 
00037         { 
00038                 edm::LogError("BeamProfileFitter") << "BeamProfileFitter::Angle(..): Warning! Something wrong with this Angle = " 
00039                         << theAngle << "! Please check!!!";
00040                 return -666;
00041         }
00042 }
00043 
00044 // default constructor
00045 BeamProfileFitter::BeamProfileFitter(edm::ParameterSet const& theConf, const edm::EventSetup* aSetup ) : 
00046   theClearHistoAfterFit(theConf.getUntrackedParameter<bool>("ClearHistogramAfterFit",true)),
00047   theScaleHisto(theConf.getUntrackedParameter<bool>("ScaleHistogramBeforeFit",true)),
00048   theMinSignalHeight(theConf.getUntrackedParameter<double>("MinimalSignalHeight",0.0)),
00049   theCorrectBSkink(theConf.getUntrackedParameter<bool>("CorrectBeamSplitterKink",true)),
00050   theBSAnglesSystematic(theConf.getUntrackedParameter<double>("BSAnglesSystematic",0.0007)) {
00051 
00052   theSetup = aSetup;
00053 
00054 }
00055 
00056 
00057 // default destructor
00058 BeamProfileFitter::~BeamProfileFitter() {}
00059 
00060 
00061 
00062 // the fitting routine
00063 std::vector<LASBeamProfileFit> BeamProfileFitter::doFit(
00064         DetId theDetUnitId, 
00065         TH1D * theHistogram,
00066         bool theSaveHistograms,
00067         int ScalingFactor, 
00068         int theBeam, 
00069         int theDisc, 
00070         int theRing, 
00071         int theSide,
00072         bool isTEC2TEC, 
00073         bool & isGoodResult) {
00074 
00075 
00076         double theScalingFactor = (double)ScalingFactor;
00077 
00078         // access the Tracker
00079         edm::ESHandle<TrackerGeometry> theTrackerGeometry;
00080         theSetup->get<TrackerDigiGeometryRecord>().get(theTrackerGeometry);
00081         const TrackerGeometry& theTracker(*theTrackerGeometry);
00082 
00083         // return the result of the fit as a vector of LASBeamProfileFits. They are later on stored into the Event data
00084         std::vector<LASBeamProfileFit> theResult;
00085 
00086         if ( theHistogram )
00087           {
00088             if ( theHistogram->GetEntries() > 0 )
00089               { 
00090                 // get the name of the histogram
00091                 const char * theHistoName = theHistogram->GetName();
00092                 
00093                 if (theSaveHistograms)
00094                   {
00095                     // save a copy of the histogram before scaling and clearing, so it is still available in the root file
00096                     // first get the name
00097                     std::string theSavedHistoName = theHistoName;
00098                     // append Saved to the histogram name
00099                     theSavedHistoName += "Saved";
00100                     // clone the original histogram and give it a new name
00101                     TH1D *theSavedHist = (TH1D*)theHistogram->Clone(theSavedHistoName.c_str());
00102                     // set the directory for the copy of the histogram
00103                     theSavedHist->SetDirectory(theHistogram->GetDirectory());
00104                   }
00105                 
00106                 // clone the histogram and scale it
00107                 TH1D *theCloneHist = (TH1D*)theHistogram->Clone("CloneHist");
00108                 if (theScaleHisto) theCloneHist->Scale(theScalingFactor);
00109                 
00110                 // find peaks and fit the beam profile
00111                 std::vector<double> thePeakPosition = findPeakGaus(theCloneHist,theDisc, theRing);
00112 
00113 
00114                 // finally if the fit was ok, calculate the fitted beam coordinates in the CMS detector
00115                 if ( thePeakPosition.at(0) > 0.0 && thePeakPosition.at(1) > 0.0 &&
00116                      thePeakPosition.at(2) > 0.0 && thePeakPosition.at(3) > 0.0) 
00117                   {
00118                     // get the mean, sigma and the errors
00119                     double theMean = thePeakPosition.at(0);
00120                     double theSigma = thePeakPosition.at(1);
00121                     double theMeanError = thePeakPosition.at(2);
00122                     double theSigmaError = thePeakPosition.at(3);
00123                     
00124                     // correct for the BeamSplitter kink
00125                     
00126                     // the known kinks for TEC+
00127                     std::vector<double> bsKinkPosTEC;
00128                     bsKinkPosTEC.push_back(-0.001399 + theBSAnglesSystematic); // kink of beam 0 in ring 4 (sector 1)
00129                     bsKinkPosTEC.push_back(-0.000796 + theBSAnglesSystematic); // kink of beam 1 in ring 4 (sector 2)
00130                     bsKinkPosTEC.push_back(0.000397 + theBSAnglesSystematic); // kink of beam 2 in ring 4 (sector 3)
00131                     bsKinkPosTEC.push_back(-0.001260 + theBSAnglesSystematic); // kink of beam 3 in ring 4 (sector 4)
00132                     bsKinkPosTEC.push_back(0.000160 + theBSAnglesSystematic); // kink of beam 4 in ring 4 (sector 5)
00133                     bsKinkPosTEC.push_back(0.000068 + theBSAnglesSystematic); // kink of beam 5 in ring 4 (sector 6)
00134                     bsKinkPosTEC.push_back(-0.000632 + theBSAnglesSystematic); // kink of beam 6 in ring 4 (sector 7)
00135                     bsKinkPosTEC.push_back(0.000562 + theBSAnglesSystematic); // kink of beam 7 in ring 4 (sector 8)
00136                     bsKinkPosTEC.push_back(-0.002532 + theBSAnglesSystematic); // kink of beam 0 (8) in ring 6 (sector 1)
00137                     bsKinkPosTEC.push_back(-0.000274 + theBSAnglesSystematic); // kink of beam 1 (9) in ring 6 (sector 2)
00138                     bsKinkPosTEC.push_back(-0.002072 + theBSAnglesSystematic); // kink of beam 2 (10) in ring 6 (sector 3)
00139                     bsKinkPosTEC.push_back(-0.001195 + theBSAnglesSystematic); // kink of beam 3 (11) in ring 6 (sector 4)
00140                     bsKinkPosTEC.push_back(-0.001983 + theBSAnglesSystematic); // kink of beam 4 (12) in ring 6 (sector 5)
00141                     bsKinkPosTEC.push_back(0.000816 + theBSAnglesSystematic); // kink of beam 5 (13) in ring 6 (sector 6)
00142                     bsKinkPosTEC.push_back(0.000693 + theBSAnglesSystematic); // kink of beam 6 (14) in ring 6 (sector 7)
00143                     bsKinkPosTEC.push_back(0.000009 + theBSAnglesSystematic); // kink of beam 7 (15) in ring 6 (sector 8)
00144 
00145                     // the known kinks for TEC-
00146                     std::vector<double> bsKinkNegTEC;
00147                     bsKinkNegTEC.push_back(0.001010 + theBSAnglesSystematic); // kink of beam 0 in ring 4 (sector 1)
00148                     bsKinkNegTEC.push_back(0.000346 + theBSAnglesSystematic); // kink of beam 1 in ring 4 (sector 2)
00149                     bsKinkNegTEC.push_back(-0.002120 + theBSAnglesSystematic); // kink of beam 2 in ring 4 (sector 3)
00150                     bsKinkNegTEC.push_back(0.000151 + theBSAnglesSystematic); // kink of beam 3 in ring 4 (sector 4)
00151                     bsKinkNegTEC.push_back(0.001206 + theBSAnglesSystematic); // kink of beam 4 in ring 4 (sector 5)
00152                     bsKinkNegTEC.push_back(-0.002780 + theBSAnglesSystematic); // kink of beam 5 in ring 4 (sector 6)
00153                     bsKinkNegTEC.push_back(0.000313 + theBSAnglesSystematic); // kink of beam 6 in ring 4 (sector 7)
00154                     bsKinkNegTEC.push_back(-0.001397 + theBSAnglesSystematic); // kink of beam 7 in ring 4 (sector 8)
00155                     bsKinkNegTEC.push_back(-0.000386 + theBSAnglesSystematic); // kink of beam 0 (8) in ring 6 (sector 1)
00156                     bsKinkNegTEC.push_back(0.000356 + theBSAnglesSystematic); // kink of beam 1 (9) in ring 6 (sector 2)
00157                     bsKinkNegTEC.push_back(-0.002350 + theBSAnglesSystematic); // kink of beam 2 (10) in ring 6 (sector 3)
00158                     bsKinkNegTEC.push_back(-0.000432 + theBSAnglesSystematic); // kink of beam 3 (11) in ring 6 (sector 4)
00159                     bsKinkNegTEC.push_back(0.000251 + theBSAnglesSystematic); // kink of beam 4 (12) in ring 6 (sector 5)
00160                     bsKinkNegTEC.push_back(-0.001587 + theBSAnglesSystematic); // kink of beam 5 (13) in ring 6 (sector 6)
00161                     bsKinkNegTEC.push_back(-0.002577 + theBSAnglesSystematic); // kink of beam 6 (14) in ring 6 (sector 7)
00162                     bsKinkNegTEC.push_back(-0.000478 + theBSAnglesSystematic); // kink of beam 7 (15) in ring 6 (sector 8)
00163 
00164                     // known kinks for BS in the Alignment Tubes???
00165 
00166                     const double theBSPosition = 70.5;
00167 
00168                     // calculate the coordinates of the fitted beam profile
00169                     if ( theMean > 0.0 && theMean < 512.0 )
00170                       {
00171                         // get the DetUnit via the DetUnitId and cast it to a StripGeomDetUnit
00172                         const StripGeomDetUnit* const theStripDet = dynamic_cast<const StripGeomDetUnit*>(theTracker.idToDet(theDetUnitId));
00173 
00174                         // store the uncorrected mean
00175                         double theUncorrectedMean = theMean;
00176 
00177                         if (theCorrectBSkink)
00178                           {
00179                             if ( (theDisc == 5) || (theDisc == 6) || (theDisc == 7) || (theDisc == 8) )
00180                               {
00181                                 if (theSide == 1)
00182                                   {
00183                                     // correction for TEC-
00184                                     // correct the fitted mean for the BS kink
00185                                     theMean -= (TMath::Abs(theStripDet->position().z()) - theBSPosition) * tan(bsKinkNegTEC.at(theBeam));
00186                                   }
00187                                 else if (theSide == 2)
00188                                   {
00189                                     // correction for TEC+
00190                                     // correct the fitted mean for the BS kink
00191                                     theMean -= (TMath::Abs(theStripDet->position().z()) - theBSPosition) * tan(bsKinkPosTEC.at(theBeam));
00192                                   }
00193                               }
00194                           }
00195 
00196                         // global position of the LaserProfile
00197                         TVector3 GlobalPos(theStripDet->surface().toGlobal(theStripDet->specificTopology().localPosition(theMean)).x(),
00198                                            theStripDet->surface().toGlobal(theStripDet->specificTopology().localPosition(theMean)).y(),
00199                                            theStripDet->surface().toGlobal(theStripDet->specificTopology().localPosition(theMean)).z());
00200 
00201                         // use the error on the mean from the fit to calculate the error on phi
00202                         ErrorFrameTransformer theErrorTransformer;
00203                         GlobalError theGlobalPositionError = theErrorTransformer.transform(theStripDet->specificTopology().localError(theMean,pow(theMeanError,2)),
00204                                                                                            theStripDet->surface());
00205 
00206                         Float_t gerrors[9] = { theGlobalPositionError.matrix()(1,1), theGlobalPositionError.matrix()(1,2), theGlobalPositionError.matrix()(1,3),
00207                                                theGlobalPositionError.matrix()(2,1), theGlobalPositionError.matrix()(2,2), theGlobalPositionError.matrix()(2,3),
00208                                                theGlobalPositionError.matrix()(3,1), theGlobalPositionError.matrix()(3,2), theGlobalPositionError.matrix()(3,3) };
00209                         TMatrix GlobalError(3,3,gerrors,"");
00210 
00211 
00212                         // errors of the x,y and z coordinate are given as the square root of the (i,i) element of the Covariance Matrix
00213                         TVector3 GlobalPosError(TMath::Sqrt(GlobalError(0,0)),TMath::Sqrt(GlobalError(1,1)),TMath::Sqrt(GlobalError(2,2)));
00214 
00215                         // global phi and error of the LaserProfile
00216                         Double_t GlobalPhi = angle(GlobalPos.Phi());
00217                         Double_t GlobalPhiError = phiError(GlobalPos, GlobalError);
00218 
00219                         // create a new LASBeamProfileFit from the result and return it
00220                         theResult.push_back(LASBeamProfileFit(theHistoName, theMean, theMeanError, theUncorrectedMean, 
00221                                                               theSigma, theSigmaError, theStripDet->specificTopology().localPitch(theStripDet->specificTopology().localPosition(theMean)), GlobalPhi, GlobalPhiError));
00222                         // this is a good fit!?
00223                         isGoodResult = true;
00224 
00225                         // some final output about the result of the fit
00226                         LogDebug("BeamProfileFitter:doFit") << " **** Results of the Beam Profile Fit for " << theHistoName << " **** "
00227                                                             << "\n Mean            = " << theMean << " +/- " << theMeanError
00228                                                             << "\n Sigma           = " << theSigma << " +/- " << theSigmaError
00229                                                             << "\n Pitch           = " << theStripDet->specificTopology().localPitch(theStripDet->specificTopology().localPosition(theMean))
00230                                                             << "\n Fitted Global Position = (" << GlobalPos.X() << "," << GlobalPos.Y() << "," << GlobalPos.Z() << ")"
00231                                                             << "\n Global Position Error  = (" << GlobalPosError.X() << "," << GlobalPosError.Y() << "," << GlobalPosError.Z() << ")"
00232                                                             << "\n Fitted Global Phi      = " << GlobalPhi << " +/- " << GlobalPhiError
00233                                                             << "\n ******************************************************************************* ";
00234                       }
00235                     else
00236                       {
00237                         edm::LogWarning("BeamProfileFitter::Fit ERROR") << " Error! Result of the fit for detId: " << theDetUnitId.rawId()
00238                                                                         << " is not ok! Mean: " << theMean << "  is not a value between 0 and 512 ... ";
00239 
00240                         // return an empty LASBeamProfileFit and set isGoodResult to false            
00241                         theResult.push_back(LASBeamProfileFit(theHistoName, 0.0, 0.0, 0.0, 0.0));
00242                         // this is not a good fit
00243                         isGoodResult = false;
00244                       }
00245 
00246                   }
00247                 else
00248                   { 
00249                     edm::LogWarning("BeamProfileFitter:Fit ERROR") << " Error! Result of the fit for detId: " << theDetUnitId.rawId()
00250                                                                    << " is not ok! No position information available ... "; 
00251 
00252                     // return an empty LASBeamProfileFit and set isGoodResult to false        
00253                     theResult.push_back(LASBeamProfileFit(theHistoName, 0.0, 0.0, 0.0, 0.0));
00254                     // this is not a good fit
00255                     isGoodResult = false;
00256                   }
00257               }
00258             else
00259               { 
00260                 edm::LogWarning("BeamProfileFitter:Fit ERROR") << "<BeamProfileFitter::DoFit(...)>: Histogram for detId: " << theDetUnitId.rawId() 
00261                                                                << " is empty!!! Skipping the fit :-( ... ";
00262 
00263                 // return an empty LASBeamProfileFit and set isGoodResult to false            
00264                 theResult.push_back(LASBeamProfileFit(theHistogram->GetName(), 0.0, 0.0, 0.0, 0.0));
00265                 // this is not a good fit
00266                 isGoodResult = false;
00267               }
00268           }
00269         else 
00270           { 
00271             edm::LogWarning("BeamProfileFitter:Fit ERROR") << "<BeamProfileFitter::DoFit(...)>: Histogram for detId: " << theDetUnitId.rawId()
00272                                                            << " does not exist!???? Nothing to fit :-( ... "; 
00273 
00274             // return an empty LASBeamProfileFit and set isGoodResult to false        
00275             theResult.push_back(LASBeamProfileFit("no histogram found", 0.0, 0.0, 0.0, 0.0));
00276             // this is not a good fit
00277             isGoodResult = false;
00278           }
00279 
00280         // clear the histogram
00281         if (theClearHistoAfterFit) 
00282           {
00283             theHistogram->Reset("");
00284           }
00285 
00286         // return the result of the fit
00287         return theResult;
00288 }
00289 
00290 
00291 
00292 
00293 std::vector<double> BeamProfileFitter::findPeakGaus(TH1D * hist, int theDisc, int theRing)
00294 {
00295         double position = -1.0;
00296         double positionError = -1.0;
00297         double sigmaError = -1.0;
00298 
00299         TF1 *fitSignal   = new TF1("fitSignal", "gaus"  ,0.0,50000.0);
00300         TF1 *fitFun;
00301 
00302         hist->SetLineColor(kBlue);
00303         int    iMax    = hist->GetMaximumBin();
00304         double mu      = hist->GetBinCenter(iMax);
00305         double sigma   = 200.0;
00306         double sMax    = hist->GetBinContent(iMax);
00307         hist->SetMaximum(1.3*sMax);
00308         hist->SetMinimum(0.0);
00309 
00310         if (sMax < theMinSignalHeight) 
00311         {
00312                 LogDebug("BeamProfileFitter:findPeakGaus") << "R" << theRing 
00313                         << ": Laser signal below threshold for Disc " 
00314                         << theDisc+1;
00315                 std::vector<double> result;
00316                 for (int i = 0; i < 4; i++)
00317                         { result.push_back(-2.0); }
00318 
00319                 return result; // no signal
00320         }
00321 
00322 
00323         fitSignal->SetParameters(sMax,mu,sigma);
00324         hist->Fit("fitSignal","EQ","",mu-4*sigma,mu+4*sigma);
00325         fitFun = hist->GetFunction("fitSignal");
00326         sMax       = fitFun->GetParameter(0);
00327         mu         = fitFun->GetParameter(1);
00328         sigma      = fabs(fitFun->GetParameter(2));
00329         fitSignal->SetParameters(sMax,mu,sigma);
00330         hist->Fit("fitSignal","EQ","",mu-2*sigma,mu+2*sigma); //was 3*sigma
00331         fitFun     = hist->GetFunction("fitSignal");
00332         position = fitFun->GetParameter(1);
00333 
00334         // only needed for Ring 6; setting sMax,mu and sigma from previous fit
00335         // makes fit result worse? therefore only refitting with smaller range?
00336         if ( (theDisc == 0 || theDisc == 1)  &&  (theRing == 6) )
00337         {
00338                 fitSignal->SetParameters(sMax,mu,sigma);
00339                 hist->Fit("fitSignal","EQ","",mu-1*sigma,mu+1*sigma);
00340                 fitFun     = hist->GetFunction("fitSignal");
00341                 position = fitFun->GetParameter(1);
00342 
00343         }
00344 
00345         int iBin0 = hist->FindBin(position-6*sigma);
00346         int iBin1 = hist->FindBin(position+6*sigma);
00347         bool refit = false;
00348         for (int i=iBin0; i<=iBin1; i++) 
00349         {
00350                 if (hist->GetBinContent(i)<=0) 
00351                 {
00352                         hist->SetBinError(i,100000.0);
00353                         refit = true;
00354                 }
00355         }
00356         if (refit) 
00357         {
00358                 if (theDisc != 0 && theDisc != 1)
00359                 {
00360                         fitSignal->SetParameters(hist->GetBinContent(iMax),hist->GetBinCenter(iMax),200.0);
00361                         hist->Fit("fitSignal","EQ","",mu-4*sigma,mu+4*sigma);
00362                         fitFun = hist->GetFunction("fitSignal");
00363                         position = fitFun->GetParameter(1);
00364                 }
00365                 else 
00366                 {
00367                         sigma = 100.0;
00368                         fitSignal->SetParameters(hist->GetBinContent(iMax),hist->GetBinCenter(iMax),200.0);
00369                         hist->Fit("fitSignal","EQ","",mu-4*sigma,mu+4*sigma);
00370                         fitFun = hist->GetFunction("fitSignal");
00371                         sMax       = fitFun->GetParameter(0);
00372                         mu         = fitFun->GetParameter(1);
00373                         sigma      = fabs(fitFun->GetParameter(2));
00374                         fitSignal->SetParameters(sMax,mu,sigma);
00375                         hist->Fit("fitSignal","EQ","",mu-2*sigma,mu+2*sigma); //was 3*sigma
00376                         fitFun = hist->GetFunction("fitSignal");
00377                         position = fitFun->GetParameter(1);
00378                         sigma = fitFun->GetParameter(2);
00379                 }
00380         }
00381 
00382         position      = fitFun->GetParameter(1);
00383         positionError = fitFun->GetParError(1);
00384         sigma         = fitFun->GetParameter(2);
00385         sigmaError    = fitFun->GetParError(2);
00386 
00387 
00388         std::vector<double> result;
00389         result.push_back(position);
00390         result.push_back(sigma);
00391         result.push_back(positionError);
00392         result.push_back(sigmaError);
00393 
00394         return result;
00395 }  
00396 
00397 Double_t BeamProfileFitter::phiError(TVector3 thePosition, TMatrix theCovarianceMatrix)
00398 {
00399         // function to calculate the error on phi, using the position and covariance matrix of the LaserProfile
00400         Double_t aX = thePosition.X();
00401         Double_t aY = thePosition.Y();
00402         Double_t aVarX = theCovarianceMatrix(0,0);
00403         Double_t aVarY = theCovarianceMatrix(1,1);
00404         Double_t aCovXY = theCovarianceMatrix(0,1);
00405 
00406         Double_t thePhiError = 0.0; // error to calculate
00407 
00408         thePhiError = TMath::Sqrt( TMath::Abs( pow(aY, 2)/( pow(aX, 4) + 2 * pow(aX,2) * pow(aY,2) + pow(aY, 4) ) * aVarX          // first term in the error propagation for sigma x
00409                 + pow(aX, 2)/( pow(aX, 4) + 2 * pow(aX,2) * pow(aY,2) + pow(aY, 4) ) * aVarY        // second term in the error propagation for sigma y
00410                 - 2.0 * aX*aY/( pow(aX, 4) + 2 * pow(aX,2) * pow(aY,2) + pow(aY, 4) ) *aCovXY       // third term in the error propagation for cov(x,y)
00411                 ));
00412 
00413         return thePhiError;
00414 }
00415 

Generated on Tue Jun 9 17:24:08 2009 for CMSSW by  doxygen 1.5.4