CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/Calibration/Tools/src/GenericHouseholder.cc

Go to the documentation of this file.
00001 
00009 #include "Calibration/Tools/interface/GenericHouseholder.h"
00010 #include <cfloat>
00011 #include <cmath>
00012 
00013 
00014 GenericHouseholder::GenericHouseholder(bool normalise)
00015   :normaliseFlag(normalise)
00016 {
00017 }
00018 
00019 
00020 GenericHouseholder::~GenericHouseholder()
00021 {
00022 }
00023 
00024 
00025 std::vector<float> GenericHouseholder::iterate(const std::vector<std::vector<float> >& eventMatrix, const std::vector<float>& energyVector, const int nIter)
00026 {
00027   std::vector<float> solution;
00028   std::vector<float> theCalibVector(energyVector.size(),1.);
00029   std::vector<std::vector<float> > myEventMatrix(eventMatrix);
00030   int Nevents = eventMatrix.size(); // Number of events to calibrate with
00031   int Nchannels = eventMatrix[0].size(); // Number of channel coefficients
00032 
00033   // Iterate the correction
00034   for (int iter=1;iter<=nIter;iter++) 
00035     {
00036       // make one iteration
00037       solution = iterate(myEventMatrix, energyVector);
00038 
00039       if (solution.empty()) return solution;
00040       // R.O.: or throw an exception, what's the standard CMS way ?
00041 
00042       // re-calibrate eventMatrix with solution
00043       for (int i=0; i<Nchannels; i++) 
00044         {
00045           for (int ievent = 0; ievent<Nevents; ievent++)
00046             {
00047               myEventMatrix[ievent][i] *= solution[i];
00048             }
00049           // save solution into theCalibVector
00050           theCalibVector[i] *= solution[i];
00051         }
00052 
00053     } // end iterate the correction
00054 
00055   return theCalibVector;
00056 }
00057 
00058 
00059 std::vector<float> GenericHouseholder::iterate(const std::vector<std::vector<float> >& eventMatrix, const std::vector<float>& energyVector)
00060 {
00061   // An implementation of the Householder in-situ calibration algorithm 
00062   // (Least squares minimisation of residual R=b-Ax, with QR decomposition of A)
00063   // A: matrix of channel response for all calib events
00064   // x: vector of channel calibration coefficients
00065   // b: vector of energies
00066   // adapted from the original code by Matt Probert 9/08/01.
00067 
00068   std::vector<float> solution; 
00069 
00070   unsigned int m=eventMatrix.size();      // Number of events to calibrate with
00071   unsigned int n=eventMatrix[0].size();           // Number of channel coefficients to optimize
00072 
00073   std::cout << "Householder::runIter(): starting calibration optimization:" << std::endl;
00074   std::cout << "  Events:" << m << ", channels: " << n << std::endl;
00075 
00076   // Sanity check
00077   if (m != energyVector.size())
00078     {
00079       std::cout << "Householder::runIter(): matrix dimensions non-conformant. " << std::endl;
00080       std::cout << "  energyVector.size()=" << energyVector.size() << std::endl;
00081       std::cout << "  eventMatrix[0].size()=" << eventMatrix[0].size() << std::endl;
00082       std::cout << " ******************    ERROR   *********************" << std::endl;
00083       return solution; // empty vector
00084     }
00085 
00086   // Reserve workspace
00087   float e25p;
00088   unsigned int i,j;
00089   std::vector<std::vector<float> > A(eventMatrix);
00090   std::vector<float> energies(energyVector);
00091 
00092   float normalisation = 0.;
00093   
00094   // Normalise if normaliseFlag is set
00095   if (normaliseFlag) 
00096     {
00097       std::cout << "Householder::iterate(): Normalising event data" << std::endl;
00098       std::cout << "  WARNING: assuming 5x5 filtering has already been done" << std::endl;
00099 
00100       for (i=0; i<m; i++) 
00101         {
00102           e25p = 0.;
00103           for (j=0;j<n;j++){
00104             e25p += eventMatrix[i][j]; // lorenzo -> trying to use ESetup which already performs calibs on rechits
00105           }     
00106           e25p /= energyVector[i];
00107           normalisation += e25p;        // SUM e25p for all events
00108         }
00109       normalisation/=m;
00110       std::cout << "  Normalisation = " << normalisation << std::endl;
00111       
00112       for (i=0;i<energies.size();++i)
00113         energies[i]*=normalisation;
00114     }
00115   
00116 
00117   // This is where the work goes on...
00118   // matrix decomposition
00119   std::vector<std::vector<float> > Acopy(A);
00120   std::vector<float> alpha(n);
00121   std::vector<int> pivot(n);
00122   if( !decompose(m, n, A, alpha, pivot)) {
00123     std::cout << "Householder::runIter(): Failed: Singular condition in decomposition." 
00124          << std::endl;
00125     std::cout << "***************** PROBLEM in DECOMPOSITION *************************"<<std::endl;
00126     return solution; // empty vector
00127   }
00128 
00129   /* DBL_EPSILON: Difference between 1.0 and the minimum float greater than 1.0 */
00130   float etasqr = DBL_EPSILON*DBL_EPSILON; 
00131   std::cout<<"LOOK at DBL_EPSILON :"<<DBL_EPSILON<<std::endl;
00132 
00133   std::vector<float> r(energies); // copy energies vector
00134   std::vector<float> e(n);
00135  
00136   // apply transformations to rhs - find solution vector
00137   solution.assign(n,0.);
00138   solve(m,n,A,alpha,pivot,r,solution);
00139 
00140   // compute residual vector r
00141   for (i=0;i<m;i++) {
00142     r[i]=energies[i];
00143     for (j=0;j<n;j++)
00144       r[i]-=Acopy[i][j]*solution[j];
00145   }
00146   // compute first correction vector e
00147   solve(m,n,A,alpha,pivot,r,e);
00148 
00149   float normy0=0.;
00150   float norme1=0.;
00151   float norme0;
00152     
00153   for (i=0;i<n;i++) {
00154     normy0+=solution[i]*solution[i];
00155     norme1+=e[i]*e[i];
00156   }
00157   
00158   std::cout << "Householder::runIter(): applying first correction" << std::endl;
00159   std::cout << " normy0 = " << normy0 << std::endl;
00160   std::cout << " norme1 = " << norme1 << std::endl;
00161 
00162   // not attempt at obtaining the solution is made unless the norm of the first
00163   // correction  is significantly smaller than the norm of the initial solution
00164   if (norme1>(0.0625*normy0)) {
00165     std::cout << "Householder::runIter(): first correction is too large. Failed." 
00166          << std::endl;
00167   }
00168 
00169   // improve the solution
00170   for (i=0;i<n;i++)
00171     solution[i]+=e[i];
00172 
00173   std::cout << "Householder::runIter(): improving solution...." << std::endl;
00174 
00175   // only continue iteration if the correction was significant
00176   while (norme1>(etasqr*normy0)) {
00177     std::cout << "Householder::runIter(): norme1 = " << norme1 << std::endl;
00178     
00179     for (i=0;i<m;i++) {
00180       r[i] = energies[i];
00181       for (j=0;j<n;j++)
00182         r[i]-=Acopy[i][j]*solution[j];
00183     }
00184 
00185     // compute next correction vector
00186     solve(m,n,A,alpha,pivot,r,e);
00187 
00188     norme0=norme1;
00189     norme1=0.;
00190     for (i=0;i<n;i++)
00191       norme1+=e[i]*e[i];
00192 
00193     // terminate iteration if the norm of the new correction failed to decrease
00194     // significantly compared to the norm of the previous correction
00195     if (norme1>(0.0625*norme0))
00196       break;
00197 
00198     // apply correction vector
00199     for (i=0;i<n;i++)
00200       solution[i]+=e[i];
00201   }
00202 
00203 return solution;
00204 }
00205 
00206 
00207 bool GenericHouseholder::decompose(const int m, const int n, std::vector<std::vector<float> >& qr,  std::vector<float>& alpha, std::vector<int>& pivot)
00208 {
00209   int i,j,jbar,k;
00210   float beta,sigma,alphak,qrkk;
00211   std::vector<float> y(n);
00212   std::vector<float> sum(n);
00213 
00214   std::cout << "Householder::decompose() started" << std::endl;
00215   
00216   for (j=0;j<n;j++) {
00217     // jth column sum
00218     
00219     sum[j]=0.;
00220     for (i=0;i<m;i++)
00221 //      std::cout << "0: qr[i][j]" << qr[i][j] << " i = " << i << " j = " << j << std::endl;
00222       sum[j]+=qr[i][j]*qr[i][j];
00223 
00224     pivot[j] = j;
00225   }
00226   
00227   for (k=0;k<n;k++) {
00228     // kth Householder transformation
00229     
00230     sigma = sum[k];
00231     jbar = k;
00232     
00233     for (j=k+1;j<n;j++) {
00234       if (sigma < sum[j]) {
00235         sigma = sum[j];
00236         jbar=j;
00237       }
00238     }
00239 
00240     if (jbar != k) {
00241       // column interchange
00242       i = pivot[k];
00243       pivot[k]=pivot[jbar];
00244       pivot[jbar]=i;
00245       sum[jbar]=sum[k];
00246       sum[k]=sigma;
00247 
00248       for (i=0;i<m;i++) {
00249         sigma=qr[i][k];
00250         qr[i][k]=qr[i][jbar];
00251 //      std::cout << "A: qr[i][k]" << qr[i][k] << " i = " << i << " k = " << k << std::endl;
00252         qr[i][jbar]=sigma;
00253 //      std::cout << "B: qr[i][jbar]" << qr[i][k] << " i = " << i << " jbar = " << jbar << std::endl;
00254       }
00255     } // end column interchange
00256 
00257     sigma=0.;
00258     for (i=k;i<m;i++){
00259       sigma+=qr[i][k]*qr[i][k];
00260 //      std::cout << "C: qr[i][k]" << qr[i][k] << " i = " << i << " k = " << k << std::endl;
00261 }
00262 
00263     if (sigma == 0.) {
00264       std::cout << "Householder::decompose() failed" << std::endl;
00265       return false;
00266     }
00267 
00268     qrkk = qr[k][k];
00269 
00270     if (qrkk < 0.) 
00271       alpha[k] = sqrt(sigma);
00272     else
00273       alpha[k] = sqrt(sigma) * (-1.);
00274     alphak = alpha[k];
00275 
00276     beta = 1/(sigma-qrkk*alphak);
00277     qr[k][k]=qrkk-alphak;
00278 
00279     for (j=k+1;j<n;j++) {
00280       y[j]=0.;
00281       for (i=k;i<m;i++)
00282         y[j]+=qr[i][k]*qr[i][j];
00283       y[j]*=beta;
00284     }
00285 
00286     for (j=k+1;j<n;j++) {
00287       
00288       for (i=k;i<m;i++) {
00289         qr[i][j]-=qr[i][k]*y[j];
00290         sum[j]-=qr[k][j]*qr[k][j];
00291       }
00292     }
00293   } // end of kth householder transformation
00294 
00295   std::cout << "Householder::decompose() finished" << std::endl;
00296   
00297   return true;
00298 }
00299 
00300 
00301 void GenericHouseholder::solve(int m, int n, const std::vector<std::vector<float> > &qr, const std::vector<float> &alpha, const std::vector<int> &pivot, 
00302                                      std::vector<float> &r, std::vector<float> &y)
00303 {
00304   std::vector<float> z(n,0.);
00305 
00306   float gamma;
00307   int i,j;
00308 
00309   std::cout << "Householder::solve() begin" << std::endl;
00310 
00311   for (j=0;j<n;j++) {
00312     // apply jth transformation to the right hand side
00313     gamma=0.;
00314     for (i=j;i<m;i++)
00315       gamma+=qr[i][j]*r[i];
00316     gamma/=(alpha[j]*qr[j][j]);
00317 
00318     for (i=j;i<m;i++)
00319       r[i]+=gamma*qr[i][j];
00320   }
00321 
00322   //  std::cout<<"OK1:"<<std::endl;
00323   z[n-1]=r[n-1]/alpha[n-1];
00324   //  std::cout<<"OK2:"<<std::endl;  
00325 
00326   for (i=n-2;i>=0;i--) {
00327     z[i]= r[i];
00328     for (j=i+1;j<n;j++)
00329       z[i]-=qr[i][j]*z[j];
00330     z[i]/=alpha[i];
00331   }
00332   //  std::cout<<"OK3:"<<std::endl;
00333 
00334   for (i=0;i<n;i++)
00335     y[pivot[i]]=z[i];
00336 
00337   std::cout << "Householder::solve() finished." << std::endl;
00338 
00339 }