CMS 3D CMS Logo

HouseholderDecomposition.cc
Go to the documentation of this file.
1 
8 #include <cfloat>
9 #include <cmath>
10 #include <cstdlib>
11 
12 HouseholderDecomposition::HouseholderDecomposition(int squareMode_, int mineta_, int maxeta_, int minphi_, int maxphi_)
13  : squareMode(squareMode_), countEvents(0), mineta(mineta_), maxeta(maxeta_), minphi(minphi_), maxphi(maxphi_) {
14  Neta = maxeta - mineta + 1;
15  if (mineta * maxeta < 0)
16  Neta--; // there's no eta index = 0
17  Nphi = maxphi - minphi + 1;
18  if (Nphi < 0)
19  Nphi += 360;
20 
21  Nchannels = Neta * Nphi; // no. of channels, get it from edges of the region
22 
23  Nxtals = squareMode * squareMode; // no. of xtals in one event
24 
25  sigmaReplacement = 0.00001; // the sum of columns is replaced by this value in case it is zero (e.g. dead crystal)
26 }
27 
29 
30 std::vector<float> HouseholderDecomposition::runRegional(const std::vector<std::vector<float> >& eventMatrix,
31  const std::vector<int>& VmaxCeta,
32  const std::vector<int>& VmaxCphi,
33  const std::vector<float>& energyVector,
34  const int& nIter,
35  const int& regLength) {
36  // make regions
37  makeRegions(regLength);
38 
39  Nevents = eventMatrix.size(); // Number of events to calibrate with
40 
41  std::vector<float> totalSolution(Nchannels, 1.);
42  std::vector<float> iterSolution(Nchannels, 1.);
43  std::vector<std::vector<float> > myEventMatrix(eventMatrix);
44 
45  // loop over nIter
46  for (int iter = 1; iter <= nIter; iter++) {
47  // loop over regions
48  for (unsigned int ireg = 0; ireg < regMinEta.size(); ireg++) {
49  std::vector<float> regIterSolution, regEnergyVector;
50  std::vector<int> regVmaxCeta, regVmaxCphi;
51  std::vector<std::vector<float> > regEventMatrix;
52 
53  // initialize new instance with regional min,max indices
54  HouseholderDecomposition regionalHH(
55  squareMode, regMinEta[ireg], regMaxEta[ireg], regMinPhi[ireg], regMaxPhi[ireg]);
56 
57  // copy all events in region into new eventmatrix, energyvector, VmaxCeta, VmaxCphi
58  for (unsigned int ia = 0; ia < VmaxCeta.size(); ia++) {
59  if ((VmaxCeta[ia] >= regMinEta[ireg]) && (VmaxCeta[ia] <= regMaxEta[ireg]) &&
60  (VmaxCphi[ia] >= regMinPhi[ireg]) && (VmaxCphi[ia] <= regMaxPhi[ireg])) {
61  // save event, calculate new eventmatrix(truncated) and energy
62  regVmaxCeta.push_back(VmaxCeta[ia]);
63  regVmaxCphi.push_back(VmaxCphi[ia]);
64 
65  std::vector<float> regEvent = myEventMatrix[ia];
66  float regEnergy = energyVector[ia];
67  for (int i2 = 0; i2 < Nxtals; i2++) {
68  int iFullReg = regionalHH.indexSqr2Reg(i2, VmaxCeta[ia], VmaxCphi[ia]);
69  if (iFullReg < 0) // crystal outside
70  {
71  regEnergy -= regEvent[i2];
72  regEvent[i2] = 0.;
73  }
74  }
75  regEventMatrix.push_back(regEvent);
76  regEnergyVector.push_back(regEnergy);
77  }
78  }
79 
80  // calibrate
81  // std::cout << "HouseholderDecomposition::runRegional - Starting calibration of region " << ireg << ": eta "
82  // << regMinEta[ireg] << " to " << regMaxEta[ireg] << ", phi " << regMinPhi[ireg] << " to " << regMaxPhi[ireg] << std::endl;
83  regIterSolution = regionalHH.iterate(regEventMatrix, regVmaxCeta, regVmaxCphi, regEnergyVector);
84  // std::cout << "HouseholderDecomposition::runRegional - calibration of region finished. " << std::endl;
85 
86  // save solution into global iterSolution
87  // don't forget to delete the ones that are on the border !
88  for (unsigned int i1 = 0; i1 < regIterSolution.size(); i1++) {
89  int regFrame = regLength / 2;
90  int currRegPhiRange = regMaxPhi[ireg] - regMinPhi[ireg] + 1;
91  int currRegEta = i1 / currRegPhiRange + regMinEta[ireg];
92  int currRegPhi = i1 % currRegPhiRange + regMinPhi[ireg];
93  int newindex = -100;
94  // if crystal well inside:
95  if ((currRegEta >= (regMinEta[ireg] + regFrame * (!(regMinEta[ireg] == mineta)))) &&
96  (currRegEta <= (regMaxEta[ireg] - regFrame * (!(regMaxEta[ireg] == maxeta)))) &&
97  (currRegPhi >= (regMinPhi[ireg] + regFrame * (!(regMinPhi[ireg] == minphi)))) &&
98  (currRegPhi <= (regMaxPhi[ireg] - regFrame * (!(regMaxPhi[ireg] == maxphi))))) {
99  newindex = (currRegEta - mineta) * Nphi + currRegPhi - minphi;
100  iterSolution[newindex] = regIterSolution[i1];
101  }
102  }
103  } // end loop over regions
104 
105  if (iterSolution.empty())
106  return iterSolution;
107 
108  // re-calibrate eventMatrix with solution
109  for (int ievent = 0; ievent < Nevents; ievent++) {
110  myEventMatrix[ievent] = recalibrateEvent(myEventMatrix[ievent], VmaxCeta[ievent], VmaxCphi[ievent], iterSolution);
111  }
112 
113  // save solution into theCalibVector
114  for (int i = 0; i < Nchannels; i++) {
115  totalSolution[i] *= iterSolution[i];
116  }
117 
118  } // end loop over nIter
119 
120  return totalSolution;
121 }
122 
123 std::vector<float> HouseholderDecomposition::iterate(const std::vector<std::vector<float> >& eventMatrix,
124  const std::vector<int>& VmaxCeta,
125  const std::vector<int>& VmaxCphi,
126  const std::vector<float>& energyVector,
127  const int& nIter,
128  const bool& normalizeFlag) {
129  Nevents = eventMatrix.size(); // Number of events to calibrate with
130 
131  std::vector<float> totalSolution(Nchannels, 1.);
132  std::vector<float> iterSolution;
133  std::vector<std::vector<float> > myEventMatrix(eventMatrix);
134  std::vector<float> myEnergyVector(energyVector);
135 
136  int i, j;
137 
138  // Iterate the correction
139  for (int iter = 1; iter <= nIter; iter++) {
140  // if normalization flag is set, normalize energies
141  float sumOverEnergy;
142  if (normalizeFlag) {
143  float scale = 0.;
144 
145  for (i = 0; i < Nevents; i++) {
146  sumOverEnergy = 0.;
147  for (j = 0; j < Nxtals; j++) {
148  sumOverEnergy += myEventMatrix[i][j];
149  }
150  sumOverEnergy /= myEnergyVector[i];
151  scale += sumOverEnergy;
152  }
153  scale /= Nevents;
154 
155  for (i = 0; i < Nevents; i++) {
156  myEnergyVector[i] *= scale;
157  }
158  } // end normalize energies
159 
160  // now the real work starts:
161  iterSolution = iterate(myEventMatrix, VmaxCeta, VmaxCphi, myEnergyVector);
162 
163  if (iterSolution.empty())
164  return iterSolution;
165 
166  // re-calibrate eventMatrix with solution
167  for (int ievent = 0; ievent < Nevents; ievent++) {
168  myEventMatrix[ievent] = recalibrateEvent(myEventMatrix[ievent], VmaxCeta[ievent], VmaxCphi[ievent], iterSolution);
169  }
170 
171  for (int i = 0; i < Nchannels; i++) {
172  // save solution into theCalibVector
173  totalSolution[i] *= iterSolution[i];
174  }
175 
176  } // end iterate correction
177 
178  return totalSolution;
179 }
180 
181 std::vector<float> HouseholderDecomposition::iterate(const std::vector<std::vector<float> >& eventMatrix,
182  const std::vector<int>& VmaxCeta,
183  const std::vector<int>& VmaxCphi,
184  const std::vector<float>& energyVectorOrig) {
185  std::vector<float> solution;
186 
187  Nevents = eventMatrix.size(); // Number of events to calibrate with
188 
189  if (Nchannels > Nevents) {
190  std::cout << "Householder::runIter(): more channels to calibrate than events available. " << std::endl;
191  std::cout << " Nchannels=" << Nchannels << std::endl;
192  std::cout << " Nevents=" << Nevents << std::endl;
193  std::cout << " ****************** ERROR *********************" << std::endl;
194  return solution; // empty vector
195  }
196 
197  // input: eventMatrixOrig - the unzipped matrix
198  eventMatrixOrig = unzipMatrix(eventMatrix, VmaxCeta, VmaxCphi);
199 
200  if (eventMatrixOrig.size() != energyVectorOrig.size()) {
201  std::cout << "Householder::runIter(): matrix dimensions non-conformant. " << std::endl;
202  std::cout << " energyVectorOrig.size()=" << energyVectorOrig.size() << std::endl;
203  std::cout << " eventMatrixOrig.size()=" << eventMatrixOrig.size() << std::endl;
204  std::cout << " ****************** ERROR *********************" << std::endl;
205  return solution; // empty vector
206  }
207 
208  int i, j;
210  energyVectorProc = energyVectorOrig; // copy energyVectorOrig vector
211  std::vector<float> e(Nchannels);
212  alpha.assign(Nchannels, 0.);
213  pivot.assign(Nchannels, 0);
214 
215  //--------------------
216  bool decomposeSuccess = decompose();
217 
218  if (!decomposeSuccess) {
219  std::cout << "Householder::runIter(): Failed: Singular condition in decomposition." << std::endl;
220  std::cout << "***************** PROBLEM in DECOMPOSITION *************************" << std::endl;
221  return solution; // empty vector
222  }
223 
224  /* DBL_EPSILON: Difference between 1.0 and the minimum float greater than 1.0 */
225  float mydbleps = 2.22045e-16; //DBL_EPSILON;
226  float etasqr = mydbleps * mydbleps;
227  // std::cout << "LOOK at DBL_EPSILON :" << mydbleps <<std::endl;
228 
229  //--------------------
230  // apply transformations to rhs - find solution vector
231  solution.assign(Nchannels, 0.);
232  solve(solution);
233 
234  // compute residual vector energyVectorProc
235  for (i = 0; i < Nevents; i++) {
236  energyVectorProc[i] = energyVectorOrig[i];
237  for (j = 0; j < Nchannels; j++) {
238  energyVectorProc[i] -= eventMatrixOrig[i][j] * solution[j];
239  }
240  }
241 
242  //--------------------
243  // compute first correction vector e
244  solve(e);
245 
246  float normy0 = 0.;
247  float norme1 = 0.;
248  float norme0;
249 
250  for (i = 0; i < Nchannels; i++) {
251  normy0 += solution[i] * solution[i];
252  norme1 += e[i] * e[i];
253  }
254 
255  // std::cout << "Householder::runIter(): applying first correction";
256  // std::cout << " normy0 = " << normy0;
257  // std::cout << " norme1 = " << norme1 << std::endl;
258 
259  // not attempt at obtaining the solution is made unless the norm of the first
260  // correction is significantly smaller than the norm of the initial solution
261  if (norme1 > (0.0625 * normy0)) {
262  // std::cout << "Householder::runIter(): first correction is too large. Failed." << std::endl;
263  }
264 
265  // improve the solution
266  for (i = 0; i < Nchannels; i++) {
267  solution[i] += e[i];
268  }
269 
270  // std::cout << "Householder::runIter(): improving solution...." << std::endl;
271 
272  //--------------------
273  // only continue iteration if the correction was significant
274  while (norme1 > (etasqr * normy0)) {
275  // std::cout << "Householder::runIter(): norme1 = " << norme1 << std::endl;
276 
277  for (i = 0; i < Nevents; i++) {
278  energyVectorProc[i] = energyVectorOrig[i];
279  for (j = 0; j < Nchannels; j++) {
280  energyVectorProc[i] -= eventMatrixOrig[i][j] * solution[j];
281  }
282  }
283 
284  // compute next correction vector
285  solve(e);
286 
287  norme0 = norme1;
288  norme1 = 0.;
289 
290  for (i = 0; i < Nchannels; i++) {
291  norme1 += e[i] * e[i];
292  }
293 
294  // terminate iteration if the norm of the new correction failed to decrease
295  // significantly compared to the norm of the previous correction
296  if (norme1 > (0.0625 * norme0))
297  break;
298 
299  // apply correction vector
300  for (i = 0; i < Nchannels; i++) {
301  solution[i] += e[i];
302  }
303  }
304 
305  //clean up
306  eventMatrixOrig.clear();
307  eventMatrixProc.clear();
308  energyVectorProc.clear();
309  alpha.clear();
310  pivot.clear();
311 
312  return solution;
313 }
314 
316  int i, j, jbar, k;
317  float beta, sigma, alphak, eventMatrixkk;
318  std::vector<float> y(Nchannels);
319  std::vector<float> sum(Nchannels);
320 
321  // std::cout << "Householder::decompose() started" << std::endl;
322 
323  for (j = 0; j < Nchannels; j++) {
324  // jth column sum: squared sum for each crystal
325  sum[j] = 0.;
326  for (i = 0; i < Nevents; i++)
327  sum[j] += eventMatrixProc[i][j] * eventMatrixProc[i][j];
328 
329  // bookkeeping vector
330  pivot[j] = j;
331  }
332 
333  for (k = 0; k < Nchannels; k++) {
334  // kth Householder transformation
335  sigma = sum[k];
336  jbar = k;
337 
338  // go through all following columns
339  // find the largest sumSquared in the following columns
340  for (j = k + 1; j < Nchannels; j++) {
341  if (sum[j] > sigma) {
342  sigma = sum[j];
343  jbar = j;
344  }
345  }
346 
347  if (jbar != k) {
348  // column interchange:
349  // interchange within: bookkeeping vector, squaredSum, eventMatrixProc
350 
351  i = pivot[k];
352  pivot[k] = pivot[jbar];
353  pivot[jbar] = i;
354 
355  sum[jbar] = sum[k];
356  sum[k] = sigma;
357 
358  for (i = 0; i < Nevents; i++) {
359  sigma = eventMatrixProc[i][k];
360  eventMatrixProc[i][k] = eventMatrixProc[i][jbar];
361  eventMatrixProc[i][jbar] = sigma;
362  }
363  } // end column interchange
364 
365  // now store in sigma the squared sum of the readoutEnergies for this column(crystal)
366  sigma = 0.;
367  for (i = k; i < Nevents; i++) {
368  sigma += eventMatrixProc[i][k] * eventMatrixProc[i][k];
369  }
370 
371  // found a zero-column, bail out
372  if (sigma == 0.) {
373  // std::cout << "Householder::decompose() failed" << std::endl;
374  // return false;
375  // rof 14.12.2006: workaround to avoid failure of algorithm because of dead crystals:
376  sigma = sigmaReplacement;
377  // std::cout << "Householder::decompose - found zero column " << jbar << ", replacing sum of column elements by " << sigma << std::endl;
378  }
379 
380  // the following paragraph acts only on the diagonal element:
381  // if element=0, then calculate alpha & beta
382 
383  // take the diagonal element
384  eventMatrixkk = eventMatrixProc[k][k];
385 
386  if (eventMatrixkk < 0.)
387  alpha[k] = sqrt(sigma);
388  else
389  alpha[k] = sqrt(sigma) * (-1.);
390 
391  alphak = alpha[k];
392 
393  beta = 1 / (sigma - eventMatrixkk * alphak);
394  // replace it
395  eventMatrixProc[k][k] = eventMatrixkk - alphak;
396 
397  for (j = k + 1; j < Nchannels; j++) {
398  y[j] = 0.;
399 
400  for (i = k; i < Nevents; i++) {
401  y[j] += eventMatrixProc[i][k] * eventMatrixProc[i][j];
402  }
403 
404  y[j] *= beta;
405  }
406 
407  for (j = k + 1; j < Nchannels; j++) {
408  for (i = k; i < Nevents; i++) {
409  eventMatrixProc[i][j] -= eventMatrixProc[i][k] * y[j];
410  sum[j] -= eventMatrixProc[k][j] * eventMatrixProc[k][j];
411  }
412  }
413  } // end of kth householder transformation
414 
415  // std::cout << "Householder::decompose() finished" << std::endl;
416 
417  return true;
418 }
419 
420 void HouseholderDecomposition::solve(std::vector<float>& y) {
421  std::vector<float> z(Nchannels, 0.);
422 
423  float gamma;
424  int i, j;
425 
426  // std::cout << "Householder::solve() begin" << std::endl;
427 
428  for (j = 0; j < Nchannels; j++) {
429  // apply jth transformation to the right hand side
430  gamma = 0.;
431  for (i = j; i < Nevents; i++) {
433  }
434  gamma /= (alpha[j] * eventMatrixProc[j][j]);
435 
436  for (i = j; i < Nevents; i++) {
438  }
439  }
440 
442 
443  for (i = Nchannels - 2; i >= 0; i--) {
444  z[i] = energyVectorProc[i];
445  for (j = i + 1; j < Nchannels; j++) {
446  z[i] -= eventMatrixProc[i][j] * z[j];
447  }
448  z[i] /= alpha[i];
449  }
450 
451  for (i = 0; i < Nchannels; i++) {
452  y[pivot[i]] = z[i];
453  }
454 
455  // std::cout << "Householder::solve() finished." << std::endl;
456 }
457 
458 std::vector<float> HouseholderDecomposition::recalibrateEvent(const std::vector<float>& eventSquare,
459  const int& maxCeta,
460  const int& maxCphi,
461  const std::vector<float>& recalibrateVector) {
462  std::vector<float> newEventSquare(eventSquare);
463  int iFull;
464 
465  for (int i = 0; i < Nxtals; i++) {
466  iFull = indexSqr2Reg(i, maxCeta, maxCphi);
467  if (iFull >= 0)
468  newEventSquare[i] *= recalibrateVector[iFull];
469  }
470  return newEventSquare;
471 }
472 
473 int HouseholderDecomposition::indexSqr2Reg(const int& sqrIndex, const int& maxCeta, const int& maxCphi) {
474  int regionIndex;
475 
476  // get the current eta, phi indices
477  int curr_eta = maxCeta - squareMode / 2 + sqrIndex % squareMode;
478  if (curr_eta * maxCeta <= 0) {
479  if (maxCeta > 0)
480  curr_eta--;
481  else
482  curr_eta++;
483  } // JUMP over 0
484 
485  int curr_phi = maxCphi - squareMode / 2 + sqrIndex / squareMode;
486  if (curr_phi < 1)
487  curr_phi += 360;
488  if (curr_phi > 360)
489  curr_phi -= 360;
490 
491  bool negPhiDirection = (maxphi < minphi);
492  int iFullphi;
493 
494  regionIndex = -1;
495 
496  if (curr_eta >= mineta && curr_eta <= maxeta)
497  if ((!negPhiDirection && (curr_phi >= minphi && curr_phi <= maxphi)) ||
498  (negPhiDirection && !(curr_phi >= minphi && curr_phi <= maxphi))) {
499  iFullphi = curr_phi - minphi;
500  if (iFullphi < 0)
501  iFullphi += 360;
502  regionIndex = (curr_eta - mineta) * (maxphi - minphi + 1 + 360 * negPhiDirection) + iFullphi;
503  }
504 
505  return regionIndex;
506 }
507 
508 std::vector<std::vector<float> > HouseholderDecomposition::unzipMatrix(
509  const std::vector<std::vector<float> >& eventMatrix,
510  const std::vector<int>& VmaxCeta,
511  const std::vector<int>& VmaxCphi) {
512  std::vector<std::vector<float> > fullMatrix;
513 
514  int iFull;
515 
516  for (int i = 0; i < Nevents; i++) {
517  std::vector<float> foo(Nchannels, 0.);
518  for (int k = 0; k < Nxtals; k++) {
519  iFull = indexSqr2Reg(k, VmaxCeta[i], VmaxCphi[i]);
520  if (iFull >= 0)
521  foo[iFull] = eventMatrix[i][k];
522  }
523  fullMatrix.push_back(foo);
524  }
525 
526  return fullMatrix;
527 }
528 
529 void HouseholderDecomposition::makeRegions(const int& regLength) {
530  // int regFrame = regLength/2;
531  int regFrame = squareMode / 2;
532  // first eta:
533  int remEta = Neta % regLength;
534  if (remEta > regLength / 2)
535  remEta -= regLength;
536  int numSubRegEta = Neta / regLength + (remEta < 0) * 1;
537 
538  int addtoEta = remEta / numSubRegEta;
539  int addtomoreEta =
540  remEta % numSubRegEta; // add "addtomore" number of times (addto+1), remaining times add just (addto)
541 
542  // then phi:
543  int remPhi = Nphi % regLength;
544  if (remPhi > regLength / 2)
545  remPhi -= regLength;
546  int numSubRegPhi = Nphi / regLength + (remPhi < 0) * 1;
547 
548  int addtoPhi = remPhi / numSubRegPhi;
549  int addtomorePhi =
550  remPhi % numSubRegPhi; // add "addtomore" number of times (addto+-1), remaining times add just (addto)
551 
552  // now put it all together
553  int startIndexEta = mineta;
554  int startIndexPhi;
555  int endIndexEta;
556  int endIndexPhi;
557  for (int i = 0; i < numSubRegEta; i++) {
558  int addedLengthEta = regLength + addtoEta + addtomoreEta / abs(addtomoreEta) * (i < abs(addtomoreEta));
559  endIndexEta = startIndexEta + addedLengthEta - 1;
560 
561  startIndexPhi = minphi;
562  for (int j = 0; j < numSubRegPhi; j++) {
563  int addedLengthPhi = regLength + addtoPhi + addtomorePhi / abs(addtomorePhi) * (j < abs(addtomorePhi));
564  endIndexPhi = startIndexPhi + addedLengthPhi - 1;
565 
566  regMinPhi.push_back(startIndexPhi - regFrame * (j != 0));
567  regMaxPhi.push_back(endIndexPhi + regFrame * (j != (numSubRegPhi - 1)));
568  regMinEta.push_back(startIndexEta - regFrame * (i != 0));
569  regMaxEta.push_back(endIndexEta + regFrame * (i != (numSubRegEta - 1)));
570 
571  startIndexPhi = endIndexPhi + 1;
572  }
573  startIndexEta = endIndexEta + 1;
574  }
575 
576  // // print it all
577  // std::cout << "Householder::makeRegions created the following regions for calibration:" << std::endl;
578  // for (int i=0; i<regMinEta.size(); i++)
579  // std::cout << "Region " << i << ": eta = " << regMinEta[i] << " to " << regMaxEta[i] << ", phi = " << regMinPhi[i] << " to " << regMaxPhi[i] << std::endl;
580 }
void solve(std::vector< float > &y)
std::vector< std::vector< float > > eventMatrixProc
std::vector< float > recalibrateEvent(const std::vector< float > &eventSquare, const int &maxCeta, const int &maxCphi, const std::vector< float > &recalibrateVector)
Recalibrate before next iteration: give previous solution vector as argument.
void makeRegions(const int &regLength)
std::vector< float > iterate(const std::vector< std::vector< float > > &eventMatrix, const std::vector< int > &VmaxCeta, const std::vector< int > &VmaxCphi, const std::vector< float > &energyVector, const int &nIter, const bool &normalizeFlag=false)
T sqrt(T t)
Definition: SSEVec.h:19
int indexSqr2Reg(const int &sqrIndex, const int &maxCeta, const int &maxCphi)
Method to translate from square indices to region indices.
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::vector< float > energyVectorProc
std::vector< float > runRegional(const std::vector< std::vector< float > > &eventMatrix, const std::vector< int > &VmaxCeta, const std::vector< int > &VmaxCphi, const std::vector< float > &energyVector, const int &nIter, const int &regLength=5)
std::vector< std::vector< float > > unzipMatrix(const std::vector< std::vector< float > > &eventMatrix, const std::vector< int > &VmaxCeta, const std::vector< int > &VmaxCphi)
Unzips the skimmed matrix into a full matrix.
HouseholderDecomposition(int squareMode_=5, int mineta_=1, int maxeta_=85, int minphi_=1, int maxphi_=20)
Default constructor.
std::vector< std::vector< float > > eventMatrixOrig