CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_4_5_patch3/src/Alignment/MuonAlignmentAlgorithms/src/MuonResidualsFitter.cc

Go to the documentation of this file.
00001 #include "Alignment/MuonAlignmentAlgorithms/interface/MuonResidualsFitter.h"
00002 #include <fstream>
00003 #include "TMath.h"
00004 
00005 // all global variables begin with "MuonResidualsFitter_" to avoid
00006 // namespace clashes (that is, they do what would ordinarily be done
00007 // with a class structure, but Minuit requires them to be global)
00008 
00009 const double MuonResidualsFitter_gsbinsize = 0.01;
00010 const double MuonResidualsFitter_tsbinsize = 0.1;
00011 const int MuonResidualsFitter_numgsbins = 500;
00012 const int MuonResidualsFitter_numtsbins = 500;
00013 
00014 bool MuonResidualsFitter_table_initialized = false;
00015 double MuonResidualsFitter_lookup_table[MuonResidualsFitter_numgsbins][MuonResidualsFitter_numtsbins];
00016 
00017 static TMinuit* MuonResidualsFitter_TMinuit;
00018 
00019 // fit function
00020 double MuonResidualsFitter_logPureGaussian(double residual, double center, double sigma) {
00021   sigma = fabs(sigma);
00022   return (-pow(residual - center, 2) / 2. / sigma / sigma) + log(1. / sqrt(2.*M_PI) / sigma);
00023 }
00024 
00025 // TF1 interface version
00026 Double_t MuonResidualsFitter_pureGaussian_TF1(Double_t *xvec, Double_t *par) {
00027   return par[0] * exp(MuonResidualsFitter_logPureGaussian(xvec[0], par[1], par[2]));
00028 }
00029 
00030 double MuonResidualsFitter_compute_log_convolution(double toversigma, double gammaoversigma, double max, double step, double power) {
00031   if (gammaoversigma == 0.) return (-toversigma*toversigma/2.) - log(sqrt(2*M_PI));
00032 
00033   double sum = 0.;
00034   double uplus = 0.;
00035   double integrandplus_last = 0.;
00036   double integrandminus_last = 0.;
00037   for (double inc = 0.;  uplus < max;  inc += step) {
00038     double uplus_last = uplus;
00039     uplus = pow(inc, power);
00040 
00041     double integrandplus = exp(-pow(uplus - toversigma, 2)/2.) / (uplus*uplus/gammaoversigma + gammaoversigma) / M_PI / sqrt(2.*M_PI);
00042     double integrandminus = exp(-pow(-uplus - toversigma, 2)/2.) / (uplus*uplus/gammaoversigma + gammaoversigma) / M_PI / sqrt(2.*M_PI);
00043 
00044     sum += integrandplus * (uplus - uplus_last);
00045     sum += 0.5 * fabs(integrandplus_last - integrandplus) * (uplus - uplus_last);
00046 
00047     sum += integrandminus * (uplus - uplus_last);
00048     sum += 0.5 * fabs(integrandminus_last - integrandminus) * (uplus - uplus_last);
00049 
00050     integrandplus_last = integrandplus;
00051     integrandminus_last = integrandminus;
00052   }
00053   return log(sum);
00054 }
00055 
00056 // fit function
00057 double MuonResidualsFitter_logPowerLawTails(double residual, double center, double sigma, double gamma) {
00058   sigma = fabs(sigma);
00059   double gammaoversigma = fabs(gamma / sigma);
00060   double toversigma = fabs((residual - center) / sigma);
00061 
00062   int gsbin0 = int(floor(gammaoversigma / MuonResidualsFitter_gsbinsize));
00063   int gsbin1 = int(ceil(gammaoversigma / MuonResidualsFitter_gsbinsize));
00064   int tsbin0 = int(floor(toversigma / MuonResidualsFitter_tsbinsize));
00065   int tsbin1 = int(ceil(toversigma / MuonResidualsFitter_tsbinsize));
00066 
00067   bool gsisbad = (gsbin0 >= MuonResidualsFitter_numgsbins  ||  gsbin1 >= MuonResidualsFitter_numgsbins);
00068   bool tsisbad = (tsbin0 >= MuonResidualsFitter_numtsbins  ||  tsbin1 >= MuonResidualsFitter_numtsbins);
00069 
00070   if (gsisbad  ||  tsisbad) {
00071     return log(gammaoversigma/M_PI) - log(toversigma*toversigma + gammaoversigma*gammaoversigma) - log(sigma);
00072   }
00073   else {
00074     double val00 = MuonResidualsFitter_lookup_table[gsbin0][tsbin0];
00075     double val01 = MuonResidualsFitter_lookup_table[gsbin0][tsbin1];
00076     double val10 = MuonResidualsFitter_lookup_table[gsbin1][tsbin0];
00077     double val11 = MuonResidualsFitter_lookup_table[gsbin1][tsbin1];
00078 
00079     double val0 = val00 + ((toversigma / MuonResidualsFitter_tsbinsize) - tsbin0) * (val01 - val00);
00080     double val1 = val10 + ((toversigma / MuonResidualsFitter_tsbinsize) - tsbin0) * (val11 - val10);
00081     
00082     double val = val0 + ((gammaoversigma / MuonResidualsFitter_gsbinsize) - gsbin0) * (val1 - val0);
00083     
00084     return val - log(sigma);
00085   }
00086 }
00087 
00088 // TF1 interface version
00089 Double_t MuonResidualsFitter_powerLawTails_TF1(Double_t *xvec, Double_t *par) {
00090   return par[0] * exp(MuonResidualsFitter_logPowerLawTails(xvec[0], par[1], par[2], par[3]));
00091 }
00092 
00093 double MuonResidualsFitter_logROOTVoigt(double residual, double center, double sigma, double gamma) {
00094   return log(TMath::Voigt(residual - center, fabs(sigma), fabs(gamma)*2.));
00095 }
00096 
00097 Double_t MuonResidualsFitter_ROOTVoigt_TF1(Double_t *xvec, Double_t *par) {
00098   return par[0] * TMath::Voigt(xvec[0] - par[1], fabs(par[2]), fabs(par[3])*2.);
00099 }
00100 
00101 double MuonResidualsFitter_logGaussPowerTails(double residual, double center, double sigma) {
00102   double x = residual-center;
00103   double s = fabs(sigma);
00104   double m = 2*s;
00105   double a = pow(m,4)*exp(-2);
00106   double n = sqrt(2*M_PI)*s*erf(sqrt(2))+2*a*pow(m,-3)/3;
00107 
00108   if (fabs(x)<m) return -x*x/(2*s*s) - log(n);
00109   else return log(a) -4*log(fabs(x)) - log(n);
00110 }
00111 
00112 Double_t MuonResidualsFitter_GaussPowerTails_TF1(Double_t *xvec, Double_t *par) {
00113   return par[0] * exp(MuonResidualsFitter_logGaussPowerTails(xvec[0], par[1], par[2]));
00114 }
00115 
00116 double MuonResidualsFitter_integrate_pureGaussian(double low, double high, double center, double sigma) {
00117   return (erf((high + center) / sqrt(2.) / sigma) - erf((low + center) / sqrt(2.) / sigma)) * exp(0.5/sigma/sigma) / 2.;
00118 }
00119 
00120 void MuonResidualsFitter::initialize_table() {
00121   if (MuonResidualsFitter_table_initialized  ||  residualsModel() != kPowerLawTails) return;
00122   MuonResidualsFitter_table_initialized = true;
00123 
00124   std::ifstream convolution_table("convolution_table.txt");
00125   if (convolution_table.is_open()) {
00126     int numgsbins = 0;
00127     int numtsbins = 0;
00128     double tsbinsize = 0.;
00129     double gsbinsize = 0.;
00130 
00131     convolution_table >> numgsbins >> numtsbins >> tsbinsize >> gsbinsize;
00132     if (numgsbins != MuonResidualsFitter_numgsbins  ||  numtsbins != MuonResidualsFitter_numtsbins  ||  
00133         tsbinsize != MuonResidualsFitter_tsbinsize  ||  gsbinsize != MuonResidualsFitter_gsbinsize) {
00134       throw cms::Exception("MuonResidualsFitter") << "convolution_table.txt has the wrong bin width/bin size.  Throw it away and let the fitter re-create the file." << std::endl;
00135     }
00136 
00137     for (int gsbin = 0;  gsbin < MuonResidualsFitter_numgsbins;  gsbin++) {
00138       for (int tsbin = 0;  tsbin < MuonResidualsFitter_numtsbins;  tsbin++) {
00139         int read_gsbin = 0;
00140         int read_tsbin = 0;
00141         double value = 0.;
00142 
00143         convolution_table >> read_gsbin >> read_tsbin >> value;
00144         if (read_gsbin != gsbin  ||  read_tsbin != tsbin) {
00145           throw cms::Exception("MuonResidualsFitter") << "convolution_table.txt is out of order.  Throw it away and let the fitter re-create the file." << std::endl;
00146         }
00147 
00148         MuonResidualsFitter_lookup_table[gsbin][tsbin] = value;
00149       }
00150     }
00151 
00152     convolution_table.close();
00153   }
00154 
00155   else {
00156     std::ofstream convolution_table2("convolution_table.txt");
00157 
00158     if (!convolution_table2.is_open()) {
00159       throw cms::Exception("MuonResidualsFitter") << "Couldn't write to file convolution_table.txt" << std::endl;
00160     }
00161 
00162     convolution_table2 << MuonResidualsFitter_numgsbins << " " << MuonResidualsFitter_numtsbins << " " << MuonResidualsFitter_tsbinsize << " " << MuonResidualsFitter_gsbinsize << std::endl;
00163 
00164     edm::LogWarning("MuonResidualsFitter") << "Initializing convolution look-up table (takes a few minutes)..." << std::endl;
00165     std::cout << "Initializing convolution look-up table (takes a few minutes)..." << std::endl;
00166 
00167     for (int gsbin = 0;  gsbin < MuonResidualsFitter_numgsbins;  gsbin++) {
00168       double gammaoversigma = double(gsbin) * MuonResidualsFitter_gsbinsize;
00169 
00170       std::cout << "    gsbin " << gsbin << "/" << MuonResidualsFitter_numgsbins << std::endl;
00171 
00172       for (int tsbin = 0;  tsbin < MuonResidualsFitter_numtsbins;  tsbin++) {
00173         double toversigma = double(tsbin) * MuonResidualsFitter_tsbinsize;
00174 
00175         // 1e-6 errors (out of a value of ~0.01) with max=100, step=0.001, power=4 (max=1000 does a little better with the tails)
00176         MuonResidualsFitter_lookup_table[gsbin][tsbin] = MuonResidualsFitter_compute_log_convolution(toversigma, gammaoversigma);
00177 
00178         // <10% errors with max=20, step=0.005, power=4 (faster computation for testing)
00179         // MuonResidualsFitter_lookup_table[gsbin][tsbin] = MuonResidualsFitter_compute_log_convolution(toversigma, gammaoversigma, 100., 0.005, 4.);
00180 
00181         convolution_table2 << gsbin << " " << tsbin << " " << MuonResidualsFitter_lookup_table[gsbin][tsbin] << std::endl;
00182       }
00183     }
00184 
00185     convolution_table2.close();
00186 
00187     edm::LogWarning("MuonResidualsFitter") << "Initialization done!" << std::endl;
00188     std::cout << "Initialization done!" << std::endl;
00189   }
00190 }
00191 
00192 bool MuonResidualsFitter::dofit(void (*fcn)(int&,double*,double&,double*,int), std::vector<int> &parNum, std::vector<std::string> &parName, std::vector<double> &start, std::vector<double> &step, std::vector<double> &low, std::vector<double> &high) {
00193   MuonResidualsFitterFitInfo *fitinfo = new MuonResidualsFitterFitInfo(this);
00194 
00195   MuonResidualsFitter_TMinuit = new TMinuit(npar());
00196   MuonResidualsFitter_TMinuit->SetPrintLevel(m_printLevel);
00197   MuonResidualsFitter_TMinuit->SetObjectFit(fitinfo);
00198   MuonResidualsFitter_TMinuit->SetFCN(fcn);
00199   inform(MuonResidualsFitter_TMinuit);
00200 
00201   std::vector<int>::const_iterator iNum = parNum.begin();
00202   std::vector<std::string>::const_iterator iName = parName.begin();
00203   std::vector<double>::const_iterator istart = start.begin();
00204   std::vector<double>::const_iterator istep = step.begin();
00205   std::vector<double>::const_iterator ilow = low.begin();
00206   std::vector<double>::const_iterator ihigh = high.begin();
00207 
00208   for (; iNum != parNum.end();  ++iNum, ++iName, ++istart, ++istep, ++ilow, ++ihigh) {
00209     MuonResidualsFitter_TMinuit->DefineParameter(*iNum, iName->c_str(), *istart, *istep, *ilow, *ihigh);
00210     if (fixed(*iNum)) MuonResidualsFitter_TMinuit->FixParameter(*iNum);
00211   }
00212 
00213   double arglist[10];
00214   int ierflg;
00215   int smierflg; //second MIGRAD ierflg
00216 
00217   // chi^2 errors should be 1.0, log-likelihood should be 0.5
00218   for (int i = 0;  i < 10;  i++) arglist[i] = 0.;
00219   arglist[0] = 0.5;
00220   ierflg = 0;
00221   smierflg = 0;
00222   MuonResidualsFitter_TMinuit->mnexcm("SET ERR", arglist, 1, ierflg);
00223   if (ierflg != 0) { delete MuonResidualsFitter_TMinuit; delete fitinfo; return false; }
00224 
00225   // set strategy = 2 (more refined fits)
00226   for (int i = 0;  i < 10;  i++) arglist[i] = 0.;
00227   arglist[0] = m_strategy;
00228   ierflg = 0;
00229   MuonResidualsFitter_TMinuit->mnexcm("SET STR", arglist, 1, ierflg);
00230   if (ierflg != 0) { delete MuonResidualsFitter_TMinuit; delete fitinfo; return false; }
00231 
00232   bool try_again = false;
00233 
00234   // minimize
00235   for (int i = 0;  i < 10;  i++) arglist[i] = 0.;
00236   arglist[0] = 50000;
00237   ierflg = 0;
00238   MuonResidualsFitter_TMinuit->mnexcm("MIGRAD", arglist, 1, ierflg);
00239   if (ierflg != 0) try_again = true;
00240 
00241   // just once more, if needed (using the final Minuit parameters from the failed fit; often works)
00242   if (try_again) {
00243     // minimize
00244     for (int i = 0;  i < 10;  i++) arglist[i] = 0.;
00245     arglist[0] = 50000;
00246     MuonResidualsFitter_TMinuit->mnexcm("MIGRAD", arglist, 1, smierflg);
00247   }
00248 
00249   Double_t fmin, fedm, errdef;
00250   Int_t npari, nparx, istat;
00251   MuonResidualsFitter_TMinuit->mnstat(fmin, fedm, errdef, npari, nparx, istat);
00252 
00253   if (istat != 3) {
00254     for (int i = 0;  i < 10;  i++) arglist[i] = 0.;
00255     ierflg = 0;
00256     MuonResidualsFitter_TMinuit->mnexcm("HESSE", arglist, 0, ierflg);
00257   }
00258 
00259   // read-out the results
00260   m_loglikelihood = -fmin;
00261 
00262   m_value.clear();
00263   m_error.clear();
00264   for (int i = 0;  i < npar();  i++) {
00265     double v, e;
00266     MuonResidualsFitter_TMinuit->GetParameter(i, v, e);
00267     m_value.push_back(v);
00268     m_error.push_back(e);
00269   }
00270 
00271   delete MuonResidualsFitter_TMinuit;
00272   delete fitinfo;
00273   if (smierflg != 0) return false;
00274   return true;
00275 }
00276 
00277 void MuonResidualsFitter::write(FILE *file, int which) {
00278   long rows = numResiduals();
00279   int cols = ndata();
00280   int whichcopy = which;
00281 
00282   fwrite(&rows, sizeof(long), 1, file);
00283   fwrite(&cols, sizeof(int), 1, file);
00284   fwrite(&whichcopy, sizeof(int), 1, file);
00285 
00286   double *likeAChecksum = new double[cols];
00287   double *likeAChecksum2 = new double[cols];
00288   for (int i = 0;  i < cols;  i++) {
00289     likeAChecksum[i] = 0.;
00290     likeAChecksum2[i] = 0.;
00291   }
00292 
00293   for (std::vector<double*>::const_iterator residual = residuals_begin();  residual != residuals_end();  ++residual) {
00294     fwrite((*residual), sizeof(double), cols, file);
00295 
00296     for (int i = 0;  i < cols;  i++) {
00297       if (fabs((*residual)[i]) > likeAChecksum[i]) likeAChecksum[i] = fabs((*residual)[i]);
00298       if (fabs((*residual)[i]) < likeAChecksum2[i]) likeAChecksum2[i] = fabs((*residual)[i]);
00299     }
00300   } // end loop over residuals
00301 
00302   // the idea is that mal-formed doubles are likely to be huge values (or tiny values)
00303   // because the exponent gets screwed up; we want to check for that
00304   fwrite(likeAChecksum, sizeof(double), cols, file);
00305   fwrite(likeAChecksum2, sizeof(double), cols, file);
00306 
00307   delete [] likeAChecksum;
00308   delete [] likeAChecksum2;
00309 }
00310 
00311 void MuonResidualsFitter::read(FILE *file, int which) {
00312   long rows = -100;
00313   int cols = -100;
00314   int readwhich = -100;
00315 
00316   fread(&rows, sizeof(long), 1, file);
00317   fread(&cols, sizeof(int), 1, file);
00318   fread(&readwhich, sizeof(int), 1, file);
00319 
00320   if (cols != ndata()  ||  rows < 0  ||  readwhich != which) throw cms::Exception("MuonResidualsFitter") << "temporary file is corrupted (which = " << which << " readwhich = " << readwhich << " rows = " << rows << " cols = " << cols << ")" << std::endl;
00321 
00322   double *likeAChecksum = new double[cols];
00323   double *likeAChecksum2 = new double[cols];
00324   for (int i = 0;  i < cols;  i++) {
00325     likeAChecksum[i] = 0.;
00326     likeAChecksum2[i] = 0.;
00327   }
00328 
00329   for (long row = 0;  row < rows;  row++) {
00330     double *residual = new double[cols];
00331     fread(residual, sizeof(double), cols, file);
00332     fill(residual);
00333 
00334     for (int i = 0;  i < cols;  i++) {
00335       if (fabs(residual[i]) > likeAChecksum[i]) likeAChecksum[i] = fabs(residual[i]);
00336       if (fabs(residual[i]) < likeAChecksum2[i]) likeAChecksum2[i] = fabs(residual[i]);
00337     }
00338   } // end loop over records in file
00339 
00340   double *readChecksum = new double[cols];
00341   double *readChecksum2 = new double[cols];
00342   fread(readChecksum, sizeof(double), cols, file);
00343   fread(readChecksum2, sizeof(double), cols, file);
00344 
00345   for (int i = 0;  i < cols;  i++) {
00346     if (fabs(likeAChecksum[i] - readChecksum[i]) > 1e-10  ||  fabs(1./likeAChecksum2[i] - 1./readChecksum2[i]) > 1e10) {
00347       throw cms::Exception("MuonResidualsFitter") << "temporary file is corrupted (which = " << which << " rows = " << rows << " likeAChecksum " << likeAChecksum[i] << " != readChecksum " << readChecksum[i] << " " << " likeAChecksum2 " << likeAChecksum2[i] << " != readChecksum2 " << readChecksum2[i] << ")" << std::endl;
00348     }
00349   }
00350 
00351   delete [] likeAChecksum;
00352   delete [] likeAChecksum2;
00353 }
00354 
00355 void MuonResidualsFitter::plotsimple(std::string name, TFileDirectory *dir, int which, double multiplier) {
00356    double window = 100.;
00357    if (which == 0) window = 2.*30.;
00358    else if (which == 1) window = 2.*30.;
00359    else if (which == 2) window = 2.*20.;
00360    else if (which == 3) window = 2.*50.;
00361 
00362    TH1F *hist = dir->make<TH1F>(name.c_str(), "", 200, -window, window);
00363 
00364    for (std::vector<double*>::const_iterator r = residuals_begin();  r != residuals_end();  ++r) {
00365       hist->Fill(multiplier * (*r)[which]);
00366    }
00367 }
00368 
00369 void MuonResidualsFitter::plotweighted(std::string name, TFileDirectory *dir, int which, int whichredchi2, double multiplier) {
00370    double window = 100.;
00371    if (which == 0) window = 2.*30.;
00372    else if (which == 1) window = 2.*30.;
00373    else if (which == 2) window = 2.*20.;
00374    else if (which == 3) window = 2.*50.;
00375 
00376    TH1F *hist = dir->make<TH1F>(name.c_str(), "", 200, -window, window);
00377 
00378    for (std::vector<double*>::const_iterator r = residuals_begin();  r != residuals_end();  ++r) {
00379       double weight = 1./(*r)[whichredchi2];
00380       if (TMath::Prob(1./weight*12, 12) < 0.99) {
00381          hist->Fill(multiplier * (*r)[which], weight);
00382       }
00383    }
00384 }