00001 #include "Alignment/MuonAlignmentAlgorithms/interface/MuonResidualsFitter.h"
00002 #include <fstream>
00003 #include "TMath.h"
00004
00005
00006
00007
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
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
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
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
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
00176 MuonResidualsFitter_lookup_table[gsbin][tsbin] = MuonResidualsFitter_compute_log_convolution(toversigma, gammaoversigma);
00177
00178
00179
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;
00216
00217
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
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
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
00242 if (try_again) {
00243
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
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 }
00301
00302
00303
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 }
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 }