Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BEmcRec.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file BEmcRec.cc
1 // Name: BEmcRec.h
2 // Author: A. Bazilevsky, Apr 2012
3 // Modified from EmcSectorRec.cxx and EmcScSectorRec.cxx
4 
5 // BEmcRec -- base class for sPHENIX EMCal
6 
7 // ///////////////////////////////////////////////////////////////////////////
8 
9 #include "BEmcRec.h"
10 #include "BEmcCluster.h"
11 #include "BEmcProfile.h"
12 
13 #include <TMath.h>
14 
15 #include <cstdlib>
16 #include <fstream>
17 #include <iostream>
18 #include <utility>
19 
20 // ///////////////////////////////////////////////////////////////////////////
21 // BEmcRec member functions
22 
24 {
25  fTowerGeom.clear();
26  fModules = new std::vector<EmcModule>;
27  fClusters = new std::vector<EmcCluster>;
28 }
29 
30 // ///////////////////////////////////////////////////////////////////////////
31 
33 {
34  if (fModules)
35  {
36  fModules->clear();
37  delete fModules;
38  }
39 
40  if (fClusters)
41  {
42  fClusters->clear();
43  delete fClusters;
44  }
45 
46  delete _emcprof;
47 }
48 
49 // ///////////////////////////////////////////////////////////////////////////
50 
51 void BEmcRec::LoadProfile(const std::string& /*fname*/)
52 {
53  std::cout << "Warning from BEmcRec::LoadProfile(): No acton defined for shower profile evaluation; should be defined in a detector specific module " << Name() << std::endl;
54 }
55 
57 {
58  std::ofstream outfile(fname);
59  if (!outfile.is_open())
60  {
61  std::cout << "Error in BEmcRec::PrintTowerGeometry(): Failed to open file "
62  << fname << std::endl;
63  return;
64  }
65  outfile << "Number of bins:" << std::endl;
66  outfile << fNx << " " << fNy << std::endl;
67  outfile << "ix iy x y z dx0 dy0 dz0 dx1 dy1 dz1" << std::endl;
68  int ich;
69  TowerGeom geom;
70  std::map<int, TowerGeom>::iterator it;
71  for (int iy = 0; iy < fNy; iy++)
72  {
73  for (int ix = 0; ix < fNx; ix++)
74  {
75  ich = iy * fNx + ix;
76  it = fTowerGeom.find(ich);
77  if (it != fTowerGeom.end())
78  {
79  geom = it->second;
80  outfile << ix << " " << iy << " " << geom.Xcenter << " "
81  << geom.Ycenter << " " << geom.Zcenter << " " << geom.dX[0] << " "
82  << geom.dY[0] << " " << geom.dZ[0] << " " << geom.dX[1] << " "
83  << geom.dY[1] << " " << geom.dZ[1] << std::endl;
84  // std::cout << "Z0: " << geom.dZ[0] << " || Z1: " << geom.dZ[1] << std::endl;
85  }
86  }
87  }
88 }
89 
90 bool BEmcRec::GetTowerGeometry(int ix, int iy, TowerGeom& geom)
91 {
92  if (ix < 0 || ix >= fNx || iy < 0 || iy >= fNy)
93  {
94  return false;
95  }
96 
97  int ich = iy * fNx + ix;
98  std::map<int, TowerGeom>::iterator it = fTowerGeom.find(ich);
99  if (it == fTowerGeom.end())
100  {
101  return false;
102  }
103 
104  geom = it->second;
105  return true;
106 }
107 
108 bool BEmcRec::SetTowerGeometry(int ix, int iy, float xx, float yy, float zz)
109 {
110  if (ix < 0 || ix >= fNx || iy < 0 || iy >= fNy)
111  {
112  return false;
113  }
114 
115  TowerGeom geom;
116  geom.Xcenter = xx;
117  geom.Ycenter = yy;
118  geom.Zcenter = zz;
119  geom.dX[0] = geom.dX[1] = 0; // These should be calculated by CompleteTowerGeometry()
120  geom.dY[0] = geom.dY[1] = 0;
121  geom.dZ[0] = geom.dZ[1] = 0;
122 
123  int ich = iy * fNx + ix;
124  fTowerGeom[ich] = geom;
125  return true;
126 }
127 
129 // Calculates tower front size from coordinates of tower center coordinates
130 {
131  if (fTowerGeom.empty() || fNx <= 0)
132  {
133  std::cout << "Error in BEmcRec::CalculateTowerSize(): Tower geometry not well setup (NX = "
134  << fNx << ")" << std::endl;
135  return false;
136  }
137 
138  const int nb = 8;
139  int idx[nb] = {0, 1, 0, -1, -1, 1, 1, -1};
140  int idy[nb] = {-1, 0, 1, 0, -1, -1, 1, 1};
141 
142  std::map<int, TowerGeom>::iterator it;
143 
144  for (it = fTowerGeom.begin(); it != fTowerGeom.end(); ++it)
145  {
146  int ich = it->first;
147  TowerGeom geom0 = it->second;
148  int ix = ich % fNx;
149  int iy = ich / fNx;
150 
151  TowerGeom geomx;
152  int inx = 0;
153 
154  while (inx < nb && (idx[inx] == 0 || !GetTowerGeometry(ix + idx[inx], iy + idy[inx], geomx)))
155  {
156  inx++;
157  }
158  if (inx >= nb)
159  {
160  std::cout << "Error in BEmcRec::CompleteTowerGeometry(): Error when locating neighbour for (ix,iy)=("
161  << ix << "," << iy << ")" << std::endl;
162  return false;
163  }
164 
165  TowerGeom geomy;
166  int iny = 0;
167 
168  while (iny < nb && (idy[iny] == 0 || !GetTowerGeometry(ix + idx[iny], iy + idy[iny], geomy)))
169  {
170  iny++;
171  }
172  if (iny >= nb)
173  {
174  std::cout << "Error in BEmcRec::CompleteTowerGeometry(): Error when locating neighbour for (ix,iy)=("
175  << ix << "," << iy << ")" << std::endl;
176  return false;
177  }
178 
179  geom0.dX[0] = (geomx.Xcenter - geom0.Xcenter) / float(idx[inx]);
180  geom0.dY[0] = (geomx.Ycenter - geom0.Ycenter) / float(idx[inx]);
181  geom0.dZ[0] = (geomx.Zcenter - geom0.Zcenter) / float(idx[inx]);
182  geom0.dX[1] = (geomy.Xcenter - geom0.Xcenter) / float(idy[iny]);
183  geom0.dY[1] = (geomy.Ycenter - geom0.Ycenter) / float(idy[iny]);
184  geom0.dZ[1] = (geomy.Zcenter - geom0.Zcenter) / float(idy[iny]);
185 
186  it->second = geom0;
187 
188  } // it = fTowerGeom.begin()
189 
190  return true;
191 }
192 
193 void BEmcRec::Tower2Global(float E, float xC, float yC,
194  float& xA, float& yA, float& zA)
195 // xC and yC are local position in tower units
196 // For CYL geometry (xC,yC) is actually (phiC,zC)
197 {
198 
199 
200  bool flagDoSD = true;
201  if (xA < -999)
202  flagDoSD = false;
203 
204  xA = 0;
205  yA = 0;
206  zA = 0;
207 
208  int ix = xC + 0.5; // tower #
209  if (ix < 0 || ix >= fNx)
210  {
211  std::cout << m_ThisName << " Error in BEmcRec::Tower2Global: wrong input x: " << ix << std::endl;
212  return;
213  }
214 
215  int iy = yC + 0.5; // tower #
216  if (iy < 0 || iy >= fNy)
217  {
218  std::cout << "Error in BEmcRec::Tower2Global: wrong input y: " << iy << std::endl;
219  return;
220  }
221 
222  // Get tower where the shower is positioned
223  TowerGeom geom0;
224 
225  if (!GetTowerGeometry(ix, iy, geom0))
226  {
227  // Weird case: cluster center of gravity outside the EMCal, take geometry from the neighbouring tower
228  const int idx[4] = {1, 0, -1, 0};
229  const int idy[4] = {0, 1, 0, -1};
230  int ii = 0;
231  while (ii < 4 && !GetTowerGeometry(ix + idx[ii], iy + idy[ii], geom0))
232  {
233  ii++;
234  }
235  if (ii >= 4)
236  {
237  std::cout << "Error in BEmcRec::Tower2Global: can not identify neighbour for tower ("
238  << ix << "," << iy << ")" << std::endl;
239  return;
240  }
241  float Xc = geom0.Xcenter - idx[ii] * geom0.dX[0] - idy[ii] * geom0.dX[1];
242  float Yc = geom0.Ycenter - idx[ii] * geom0.dY[0] - idy[ii] * geom0.dY[1];
243  float Zc = geom0.Zcenter - idx[ii] * geom0.dZ[0] - idy[ii] * geom0.dZ[1];
244  geom0.Xcenter = Xc;
245  geom0.Ycenter = Yc;
246  geom0.Zcenter = Zc;
247  }
248 
249  float xt = geom0.Xcenter + (xC - ix) * geom0.dX[0] + (yC - iy) * geom0.dX[1];
250  float yt = geom0.Ycenter + (xC - ix) * geom0.dY[0] + (yC - iy) * geom0.dY[1];
251  float zt = geom0.Zcenter + (xC - ix) * geom0.dZ[0] + (yC - iy) * geom0.dZ[1];
252 
253  if (flagDoSD)
254  {
255  CorrectShowerDepth(E, xt, yt, zt, xA, yA, zA);
256  }
257  else
258  {
259  float savzt = zt;
260  CorrectShowerDepth(E,xt,yt, zt, xA, yA, zA);
261  zA = savzt;
262  }
263  // rA = sqrt(xA*xA+yA*yA);
264  // phiA = atan2(yA, xA);
265 }
266 
267 // ///////////////////////////////////////////////////////////////////////////
268 
269 int BEmcRec::iTowerDist(int ix1, int ix2)
270 // Distrance in tower units
271 {
272  int idist = ix2 - ix1;
273  if (bCYL)
274  {
275  int idistr = fNx - abs(idist); // Always >0
276  if (idistr < abs(idist))
277  { // Then count in opposite direction
278  if (idist < 0)
279  {
280  idist = idistr;
281  }
282  else
283  {
284  idist = -idistr;
285  }
286  }
287  }
288  // std::cout << "Dist " << ix1 << " " << ix2 << ": " << idist << std::endl;
289  return idist;
290 }
291 
292 float BEmcRec::fTowerDist(float x1, float x2)
293 {
294  float dist = x2 - x1;
295  if (bCYL)
296  {
297  float distr = fNx - fabs(dist); // Always >0
298  if (distr < abs(dist))
299  { // Then count in opposite direction
300  if (dist < 0)
301  {
302  dist = distr;
303  }
304  else
305  {
306  dist = -distr;
307  }
308  }
309  }
310  return dist;
311 }
312 
313 // ///////////////////////////////////
314 
316 // Cluster search algorithm based on Lednev's one developed for GAMS.
317 // Returns number of clusters found
318 {
319  int nhit, nCl;
320  // int LenCl[fgMaxLen];
321  int* LenCl;
322  int next, ib, ie, iab, iae, last, LastCl, leng, ich;
323  int ia = 0;
324 
325  EmcModule* vv;
326  EmcModule *vhit, *vt;
327  EmcCluster Clt(this);
328  std::vector<EmcModule>::iterator ph;
329  std::vector<EmcModule> hl;
330 
331  (*fClusters).clear();
332  nhit = (*fModules).size();
333 
334  if (nhit <= 0)
335  {
336  return 0;
337  }
338  if (nhit == 1)
339  {
340  Clt.ReInitialize((*fModules));
341  fClusters->push_back(Clt);
342  return 1;
343  }
344 
345  int MaxLen = fgMaxLen;
346  LenCl = new int[MaxLen];
347  ZeroVector(LenCl, MaxLen);
348 
349  vt = new EmcModule[nhit];
350  vhit = new EmcModule[nhit];
351 
352  ph = (*fModules).begin();
353  vv = vhit;
354  while (ph != (*fModules).end())
355  {
356  *vv++ = *ph++;
357  }
358 
359  qsort(vhit, nhit, sizeof(EmcModule), HitNCompare);
360 
361  nCl = 0;
362  next = 0;
363  for (ich = 1; ich < nhit + 1; ich++)
364  {
365  if (ich < nhit)
366  {
367  ia = vhit[ich].ich;
368  }
369 
370  // New subcluster
371  //
372  if ((ia - vhit[ich - 1].ich > 1) // the beginning of new subcluster
373  || (ich >= nhit) // just finish defining last sub-cluster
374  || (ia - ia / fNx * fNx == 0))
375  { // new raw -> new subcluster
376 
377  ib = next;
378  ie = ich - 1;
379  next = ich;
380  if (nCl >= MaxLen)
381  {
382  // delete[] vhit;
383  // delete[] vt;
384  // return -1;
385  int* LenCltmp = new int[MaxLen];
386  CopyVector(LenCl, LenCltmp, MaxLen);
387  delete[] LenCl;
388  LenCl = new int[MaxLen * 2];
389  ZeroVector(LenCl, MaxLen * 2);
390  CopyVector(LenCltmp, LenCl, MaxLen);
391  delete[] LenCltmp;
392  MaxLen *= 2;
393  // std::cout << "Extend array size to " << MaxLen << std::endl;
394  }
395  nCl++;
396  LenCl[nCl - 1] = next - ib;
397  if (nCl > 1)
398  {
399  // Job to glue the subclusters with common edge
400  //
401  iab = vhit[ib].ich; // The last subcl begin
402  iae = vhit[ie].ich; // The last subcl end
403  last = ib - 1; // The prelast subcl end
404  LastCl = nCl - 2;
405  for (int iCl = LastCl; iCl >= 0; iCl--)
406  {
407  leng = LenCl[iCl];
408 
409  if (iab - vhit[last].ich > fNx)
410  {
411  goto new_ich;
412  }
413  for (int ichc = last; ichc >= last - leng + 1; ichc--)
414  {
415  // if( iab-vhit[ichc].ich > fNx ) goto new_icl; // From PHENIX version !!! This may be not right for complicated clusters, where tower ordering is not conserved
416 
417  // if( iae-vhit[ichc].ich >= fNx // From PHENIX version
418  if ((vhit[ichc].ich + fNx <= iae && vhit[ichc].ich + fNx >= iab) || (bCYL && (iae % fNx == fNx - 1) && (iae - vhit[ichc].ich == fNx - 1)) // Only for CYLinder geom !!!!
419  )
420  {
421  // Swap iCl-cluster towers (of length "leng") with whatever was between it and the last subcluster (of length "ib-1-last") - to make it adjecent to the last subcluster
422  CopyVector(&vhit[last + 1 - leng], vt, leng);
423  CopyVector(&vhit[last + 1], &vhit[last + 1 - leng], ib - 1 - last);
424  CopyVector(vt, &vhit[ib - leng], leng);
425 
426  // Now the number of clusters is reduced by 1 and the length of the last one increased by iCl-cluster length "leng"
427  for (int i = iCl; i < nCl - 2; i++)
428  {
429  LenCl[i] = LenCl[i + 1];
430  }
431  ib -= leng;
432  LenCl[nCl - 2] = LenCl[nCl - 1] + leng;
433  nCl--;
434  goto new_icl;
435  }
436  } // for( int ichc=last
437 
438  new_icl:
439  last = last - leng;
440  } // for( int iCl=LastCl
441 
442  } // if( nCl > 1
443 
444  } // if( (ia-vhit
445 
446  new_ich:
447  continue;
448  } // for( ich=1
449 
450  if (nCl > 0)
451  {
452  ib = 0;
453  for (int iCl = 0; iCl < nCl; iCl++)
454  {
455  leng = LenCl[iCl];
456  hl.clear();
457  for (ich = 0; ich < leng; ich++)
458  {
459  hl.push_back(vhit[ib + ich]);
460  }
461  Clt.ReInitialize(hl);
462  ib += LenCl[iCl];
463  fClusters->push_back(Clt);
464  }
465  }
466  delete[] LenCl;
467  delete[] vhit;
468  delete[] vt;
469 
470  return nCl;
471 }
472 
473 // ///////////////////////////////////////////////////////////////////////////
474 
475 void BEmcRec::Momenta(std::vector<EmcModule>* phit, float& pe, float& px,
476  float& py, float& pxx, float& pyy, float& pyx,
477  float thresh)
478 {
479  // First and second momenta calculation
480 
481  float a, x, y, e, xx, yy, yx;
482  std::vector<EmcModule>::iterator ph;
483 
484  pe = 0;
485  px = 0;
486  py = 0;
487  pxx = 0;
488  pyy = 0;
489  pyx = 0;
490  if (phit->empty())
491  {
492  return;
493  }
494 
495  // Find max energy tower
496  //
497  ph = phit->begin();
498  float emax = 0;
499  int ichmax = 0;
500 
501  while (ph != phit->end())
502  {
503  a = ph->amp;
504  if (a > emax)
505  {
506  emax = a;
507  ichmax = ph->ich;
508  }
509  ++ph;
510  }
511 
512  if (emax <= 0)
513  {
514  return;
515  }
516 
517  int iymax = ichmax / fNx;
518  int ixmax = ichmax - iymax * fNx;
519 
520  // Calculate CG relative to max energy tower
521 
522  x = 0;
523  y = 0;
524  e = 0;
525  xx = 0;
526  yy = 0;
527  yx = 0;
528  ph = phit->begin();
529 
530  while (ph != phit->end())
531  {
532  a = ph->amp;
533  if (a > thresh)
534  {
535  int iy = ph->ich / fNx;
536  int ix = ph->ich - iy * fNx;
537  int idx = iTowerDist(ixmax, ix);
538  int idy = iy - iymax;
539  e += a;
540  x += idx * a;
541  y += idy * a;
542  xx += a * idx * idx;
543  yy += a * idy * idy;
544  yx += a * idx * idy;
545  }
546  ++ph;
547  }
548 
549  pe = e;
550 
551  if (e > 0)
552  {
553  x /= e;
554  y /= e;
555  xx = xx / e - x * x;
556  yy = yy / e - y * y;
557  yx = yx / e - y * x;
558 
559  x += ixmax;
560  y += iymax;
561 
562  while (x < -0.5)
563  {
564  x += float(fNx);
565  }
566  while (x >= fNx - 0.5)
567  {
568  x -= float(fNx);
569  }
570 
571  px = x;
572  py = y;
573  pxx = xx;
574  pyy = yy;
575  pyx = yx;
576  }
577 }
578 
579 // ///////////////////////////////////////////////////////////////////////////
580 
581 float BEmcRec::PredictEnergy(float en, float xcg, float ycg, int ix, int iy)
582 {
583  if (_emcprof != nullptr && bProfileProb)
584  {
585  return PredictEnergyProb(en, xcg, ycg, ix, iy);
586  }
587 
588  float dx = fabs(fTowerDist(float(ix), xcg));
589  float dy = ycg - iy;
590  return PredictEnergyParam(en, dx, dy);
591 }
592 
593 float BEmcRec::PredictEnergyParam(float /*en*/, float xc, float yc)
594 {
595  // Calculates the energy deposited in the tower, the distance between
596  // its center and shower Center of Gravity being (xc,yc)
597  // en - shower energy
598 
599  float dx, dy, r1, r2, r3;
600  float fPpar1, fPpar2, fPpar3, fPpar4;
601 
602  float fPshiftx = 0; // !!!!! Untill tuned ... may not be necessary
603  float fPshifty = 0; // !!!!! Untill tuned ... may not be necessary
604 
605  /*
606  float lgE;
607  if (en <= 1.e-10)
608  lgE = 0;
609  else
610  lgE = log(en);
611  fPpar1=0.59-(1.45+0.13*lgE)*sin2a;
612  fPpar2=0.265+(0.80+0.32*lgE)*sin2a;
613  fPpar3=0.25+(0.45-0.036*lgE)*sin2a;
614  fPpar4=0.42;
615  */
616  fPpar1 = 0.549;
617  fPpar2 = 0.304;
618  fPpar3 = 0.389;
619  fPpar4 = 0.326;
620  /*
621  fPpar1 = 0.486;
622  fPpar2 = 0.302;
623  fPpar3 = 0.354;
624  fPpar4 = 0.407;
625  */
626  /*
627  fPpar1 = 0.343;
628  fPpar2 = 0.509;
629  fPpar3 = 0.199;
630  fPpar4 = 0.548;
631  */
632 
633  // if (en > 0) SetProfileParameters(-1, en, xc, yc);
634 
635  dx = fabs(xc - fPshiftx);
636  dy = fabs(yc - fPshifty);
637  r2 = dx * dx + dy * dy;
638  r1 = sqrt(r2);
639  r3 = r2 * r1;
640  double e = fPpar1 * exp(-r3 / fPpar2) + fPpar3 * exp(-r1 / fPpar4);
641 
642  return e;
643 }
644 
645 float BEmcRec::PredictEnergyProb(float en, float xcg, float ycg, int ix, int iy)
646 // Predict tower energy from profiles used in GetProb()
647 // This is expected to be used in BEmcCluster::GetSubClusters
648 {
649  if (_emcprof == nullptr)
650  {
651  return -1;
652  }
653 
654  while (xcg < -0.5)
655  {
656  xcg += float(fNx);
657  }
658  while (xcg >= fNx - 0.5)
659  {
660  xcg -= float(fNx);
661  }
662 
663  int ixcg = int(xcg + 0.5);
664  int iycg = int(ycg + 0.5);
665  float ddx = fabs(xcg - ixcg);
666  float ddy = fabs(ycg - iycg);
667 
668  float xg=0, yg=0, zg=0;
669  Tower2Global(en, xcg, ycg, xg, yg, zg);
670 
671  float theta, phi;
672  GetImpactThetaPhi(xg, yg, zg, theta, phi);
673 
674  int isx = 1;
675  if (xcg - ixcg < 0)
676  {
677  isx = -1;
678  }
679  int isy = 1;
680  if (ycg - iycg < 0)
681  {
682  isy = -1;
683  }
684 
685  int idx = iTowerDist(ixcg, ix) * isx;
686  int idy = (iy - iycg) * isy;
687 
688  int id = -1;
689  if (idx == 0 && idy == 0)
690  {
691  id = 0;
692  }
693  else if (idx == 1 && idy == 0)
694  {
695  id = 1;
696  }
697  else if (idx == 1 && idy == 1)
698  {
699  id = 2;
700  }
701  else if (idx == 0 && idy == 1)
702  {
703  id = 3;
704  }
705 
706  if (id < 0)
707  {
708  float dx = fabs(fTowerDist(xcg, float(ix)));
709  float dy = fabs(iy - ycg);
710  float rr = sqrt(dx * dx + dy * dy);
711  // return PredictEnergyParam(en, dx, dy);
712  return _emcprof->PredictEnergyR(en, theta, phi, rr);
713  }
714 
715  float ep[4], err[4];
716  for (int ip = 0; ip < 4; ip++)
717  {
718  _emcprof->PredictEnergy(ip, en, theta, phi, ddx, ddy, ep[ip], err[ip]);
719  }
720 
721  float eout;
722 
723  if (id == 0)
724  {
725  eout = (ep[1] + ep[2]) / 2. + ep[3];
726  }
727  else if (id == 1)
728  {
729  eout = (ep[0] - ep[2]) / 2. - ep[3];
730  }
731  else if (id == 3)
732  {
733  eout = (ep[0] - ep[1]) / 2. - ep[3];
734  }
735  else
736  {
737  eout = ep[3];
738  }
739 
740  // if( eout<0 ) printf("id=%d eout=%f: ep= %f %f %f %f Input: E=%f xcg=%f ycg=%f\n",id,eout,ep[0],ep[1],ep[2],ep[3],en,xcg,ycg);
741  if (eout < 0)
742  {
743  eout = 1e-6;
744  }
745 
746  return eout;
747 }
748 
749 // ///////////////////////////////////////////////////////////////////////////
750 
751 float BEmcRec::GetTowerEnergy(int iy, int iz, std::vector<EmcModule>* plist)
752 {
753  int nn = plist->size();
754  if (nn <= 0)
755  {
756  return 0;
757  }
758 
759  for (int i = 0; i < nn; i++)
760  {
761  int ich = (*plist)[i].ich;
762  int iyt = ich / fNx;
763  int izt = ich % fNx;
764  if (iy == iyt && iz == izt)
765  {
766  return (*plist)[i].amp;
767  }
768  }
769  return 0;
770 }
771 
772 // !!!!! Change here to a ponter to HitList
773 float BEmcRec::GetProb(std::vector<EmcModule> HitList, float en, float xg, float yg, float zg, float& chi2, int& ndf)
774 // Do nothing; should be defined in a detector specific module BEmcRec{Name}
775 {
776  // float enoise = 0.01; // 10 MeV per tower
777  float enoise = GetProbNoiseParam();
778  // float thresh = 0.01;
779  float thresh = GetTowerThreshold();
780 
781  chi2 = 0;
782  ndf = 0;
783  if (_emcprof == nullptr)
784  {
785  return -1;
786  }
787 
788  if (!(_emcprof->IsLoaded()))
789  {
790  return -1;
791  }
792 
793  int nn = HitList.size();
794  if (nn <= 0)
795  {
796  return -1;
797  }
798 
799  float theta, phi;
800  GetImpactThetaPhi(xg, yg, zg, theta, phi);
801 
802  // z coordinate below means x coordinate
803 
804  float etot;
805  float zcg, ycg;
806  float zz, yy, yz;
807  Momenta(&HitList, etot, zcg, ycg, zz, yy, yz, thresh);
808 
809  int iz0cg = int(zcg + 0.5);
810  int iy0cg = int(ycg + 0.5);
811  float ddz = fabs(zcg - iz0cg);
812  float ddy = fabs(ycg - iy0cg);
813 
814  int isz = 1;
815  if (zcg - iz0cg < 0)
816  {
817  isz = -1;
818  }
819  int isy = 1;
820  if (ycg - iy0cg < 0)
821  {
822  isy = -1;
823  }
824 
825  // 4 central towers: 43
826  // 12
827  // Tower 1 - central one
828  float e1, e2, e3, e4;
829  e1 = GetTowerEnergy(iy0cg, iz0cg, &HitList);
830  e2 = GetTowerEnergy(iy0cg, iz0cg + isz, &HitList);
831  e3 = GetTowerEnergy(iy0cg + isy, iz0cg + isz, &HitList);
832  e4 = GetTowerEnergy(iy0cg + isy, iz0cg, &HitList);
833 
834  if (e1 < thresh)
835  {
836  e1 = 0;
837  }
838  if (e2 < thresh)
839  {
840  e2 = 0;
841  }
842  if (e3 < thresh)
843  {
844  e3 = 0;
845  }
846  if (e4 < thresh)
847  {
848  e4 = 0;
849  }
850 
851  float e1t = (e1 + e2 + e3 + e4) / etot;
852  float e2t = (e1 + e2 - e3 - e4) / etot;
853  float e3t = (e1 - e2 - e3 + e4) / etot;
854  float e4t = (e3) / etot;
855  // float rr = sqrt((0.5-ddz)*(0.5-ddz)+(0.5-ddy)*(0.5-ddy));
856 
857  // Predicted values
858  const int NP = 4; // From BEmcProfile
859  float ep[NP];
860  float err[NP];
861  for (int ip = 0; ip < NP; ip++)
862  {
863  _emcprof->PredictEnergy(ip, en, theta, phi, ddz, ddy, ep[ip], err[ip]);
864  if (ep[ip] < 0)
865  {
866  return -1;
867  }
868  if (ip < 3)
869  {
870  err[ip] = sqrt(err[ip] * err[ip] + 4 * enoise * enoise / etot / etot);
871  }
872  else
873  {
874  err[ip] = sqrt(err[ip] * err[ip] + 1 * enoise * enoise / etot / etot);
875  }
876  }
877 
878  chi2 = 0.;
879  chi2 += (ep[0] - e1t) * (ep[0] - e1t) / err[0] / err[0];
880  chi2 += (ep[1] - e2t) * (ep[1] - e2t) / err[1] / err[1];
881  chi2 += (ep[2] - e3t) * (ep[2] - e3t) / err[2] / err[2];
882  chi2 += (ep[3] - e4t) * (ep[3] - e4t) / err[3] / err[3];
883  ndf = 4;
884 
885  chi2 /= 1.5;
886 
887  float prob = TMath::Prob(chi2, ndf);
888 
889  return prob;
890 }
891 
892 // ///////////////////////////////////////////////////////////////////////////
893 // Static functions
894 
895 int BEmcRec::HitNCompare(const void* h1, const void* h2)
896 {
897  return (static_cast<const EmcModule*>(h1)->ich - static_cast<const EmcModule*>(h2)->ich);
898 }
899 
900 // ///////////////////////////////////////////////////////////////////////////
901 
902 int BEmcRec::HitACompare(const void* h1, const void* h2)
903 {
904  float amp1 = static_cast<const EmcModule*>(h1)->amp;
905  float amp2 = static_cast<const EmcModule*>(h2)->amp;
906  return (amp1 < amp2) ? 1 : (amp1 > amp2) ? -1
907  : 0;
908 }
909 
910 // ///////////////////////////////////////////////////////////////////////////
911 
912 void BEmcRec::ZeroVector(int* v, int N)
913 {
914  int* p = v;
915  for (int i = 0; i < N; i++)
916  {
917  *p++ = 0;
918  }
919 }
920 
921 // ///////////////////////////////////////////////////////////////////////////
922 
923 void BEmcRec::ZeroVector(float* v, int N)
924 {
925  float* p = v;
926  for (int i = 0; i < N; i++)
927  {
928  *p++ = 0;
929  }
930 }
931 
932 // ///////////////////////////////////////////////////////////////////////////
933 
935 {
936  // memset(v, 0, N*sizeof(EmcModule));
937  for (int i = 0; i < N; i++)
938  {
939  v[i].ich = 0;
940  v[i].amp = 0;
941  v[i].tof = 0;
942  }
943 }
944 
945 // ///////////////////////////////////////////////////////////////////////////
946 
947 void BEmcRec::CopyVector(const int* from, int* to, int N)
948 {
949  if (N <= 0)
950  {
951  return;
952  }
953  for (int i = 0; i < N; i++)
954  {
955  to[i] = from[i];
956  }
957 }
958 
959 // ///////////////////////////////////////////////////////////////////////////
960 
961 void BEmcRec::CopyVector(const EmcModule* from, EmcModule* to, int N)
962 {
963  if (N <= 0)
964  {
965  return;
966  }
967  for (int i = 0; i < N; i++)
968  {
969  to[i] = from[i];
970  }
971 }
972 
973 // ///////////////////////////////////////////////////////////////////////////
974 
975 /* Future improvements:
976 
977 1. FindClusters(): to ensure that all EmcModules are above energy threshold
978 set by SetThreshold routine (or default one)
979 
980 */
981 
982 // ///////////////////////////////////////////////////////////////////////////
983 // EOF