Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:19:48

0001 // Name: BEmcRec.h
0002 // Author: A. Bazilevsky, Apr 2012
0003 // Modified from EmcSectorRec.cxx and EmcScSectorRec.cxx
0004 
0005 // BEmcRec -- base class for sPHENIX EMCal
0006 
0007 // ///////////////////////////////////////////////////////////////////////////
0008 
0009 #include "BEmcRec.h"
0010 #include "BEmcCluster.h"
0011 #include "BEmcProfile.h"
0012 
0013 #include <TMath.h>
0014 
0015 #include <cmath>
0016 #include <cstdlib>
0017 #include <fstream>
0018 #include <iostream>
0019 #include <utility>
0020 
0021 // ///////////////////////////////////////////////////////////////////////////
0022 // BEmcRec member functions
0023 
0024 BEmcRec::BEmcRec() : fModules(new std::vector<EmcModule>), fClusters(new std::vector<EmcCluster>)
0025 {
0026   fTowerGeom.clear();
0027 }
0028 
0029 // ///////////////////////////////////////////////////////////////////////////
0030 
0031 BEmcRec::~BEmcRec()
0032 {
0033   if (fModules)
0034   {
0035     fModules->clear();
0036     delete fModules;
0037   }
0038 
0039   if (fClusters)
0040   {
0041     fClusters->clear();
0042     delete fClusters;
0043   }
0044 
0045   delete _emcprof;
0046 }
0047 
0048 // ///////////////////////////////////////////////////////////////////////////
0049 
0050 void BEmcRec::LoadProfile(const std::string& /*fname*/)
0051 {
0052   std::cout << "Warning from BEmcRec::LoadProfile(): No acton defined for shower profile evaluation; should be defined in a detector specific module " << Name() << std::endl;
0053 }
0054 
0055 void BEmcRec::PrintTowerGeometry(const std::string& fname)
0056 {
0057   std::ofstream outfile(fname);
0058   if (!outfile.is_open())
0059   {
0060     std::cout << "Error in BEmcRec::PrintTowerGeometry(): Failed to open file "
0061               << fname << std::endl;
0062     return;
0063   }
0064   outfile << "Number of bins:" << std::endl;
0065   outfile << fNx << " " << fNy << std::endl;
0066   outfile << "ix iy x y z dx0 dy0 dz0 dx1 dy1 dz1" << std::endl;
0067   int ich;
0068   TowerGeom geom;
0069   std::map<int, TowerGeom>::iterator it;
0070   for (int iy = 0; iy < fNy; iy++)
0071   {
0072     for (int ix = 0; ix < fNx; ix++)
0073     {
0074       ich = iy * fNx + ix;
0075       it = fTowerGeom.find(ich);
0076       if (it != fTowerGeom.end())
0077       {
0078         geom = it->second;
0079         outfile << ix << " " << iy << " " << geom.Xcenter << " "
0080                 << geom.Ycenter << " " << geom.Zcenter << " " << geom.dX[0] << " "
0081                 << geom.dY[0] << " " << geom.dZ[0] << " " << geom.dX[1] << " "
0082                 << geom.dY[1] << " " << geom.dZ[1] << std::endl;
0083         //  std::cout << "Z0: " << geom.dZ[0] << " || Z1: " << geom.dZ[1] << std::endl;
0084       }
0085     }
0086   }
0087   outfile.close();
0088 }
0089 
0090 void BEmcRec::PrintTowerGeometryDetailed(const std::string& fname)
0091 {
0092   std::ofstream outfile(fname);
0093   if (!outfile.is_open())
0094   {
0095     std::cout << "Error in BEmcRec::PrintTowerGeometry(): Failed to open file "
0096               << fname << std::endl;
0097     return;
0098   }
0099   outfile << "Number of bins:" << std::endl;
0100   outfile << fNx << " " << fNy << std::endl;
0101   outfile << "ieta iphi vtx_1_x vtx_1_y vtx_1_z vtx_2_x vtx_2_y vtx_2_z vtx_3_x vtx_3_y vtx_3_z vtx_4_x vtx_4_y vtx_4_z vtx_5_x vtx_5_y vtx_5_z vtx_6_x vtx_6_y vtx_6_z vtx_7_x vtx_7_y vtx_7_z vtx_8_x vtx_8_y vtx_8_z\n";
0102   int ich;
0103   RawTowerGeom *geom;
0104   std::map<int, RawTowerGeom*>::iterator it;
0105   for (int iy = 0; iy < fNy; iy++)
0106   {
0107     for (int ix = 0; ix < fNx; ix++)
0108     {
0109       ich = iy * fNx + ix;
0110       it = fTowerGeomDetailed.find(ich);
0111       if (it != fTowerGeomDetailed.end())
0112       {
0113         geom = it->second;
0114         outfile << ix << " " << iy << " ";
0115         for (int ivtx = 0; ivtx < 8; ivtx++) {
0116           outfile << geom->get_vertex_x(ivtx) << " " << geom->get_vertex_y(ivtx) << " " << geom->get_vertex_z(ivtx) << " ";
0117         }
0118         outfile << "\n";
0119       }
0120     }
0121   }
0122   outfile.close();
0123 }
0124 
0125 void BEmcRec::ClearInitialDetailedGeometry()
0126 {
0127   // Contrary to the fTowerGeom node,
0128   // fTowerGeomDetailed is only used optionally for PrintTowerGeomDetailed()
0129   // Memory should be released once it becomes irrelevant.
0130 
0131   for (auto & ich : fTowerGeomDetailed)
0132   {
0133     delete ich.second;
0134   }
0135   fTowerGeomDetailed.clear();
0136 }
0137 
0138 bool BEmcRec::GetTowerGeometry(int ix, int iy, TowerGeom& geom)
0139 {
0140   if (ix < 0 || ix >= fNx || iy < 0 || iy >= fNy)
0141   {
0142     return false;
0143   }
0144 
0145   int ich = (iy * fNx) + ix;
0146   std::map<int, TowerGeom>::iterator it = fTowerGeom.find(ich);
0147   if (it == fTowerGeom.end())
0148   {
0149     return false;
0150   }
0151 
0152   geom = it->second;
0153   return true;
0154 }
0155 
0156 bool BEmcRec::SetTowerGeometry(int ix, int iy, const RawTowerGeom& raw_geom0)
0157 {
0158   if (ix < 0 || ix >= fNx || iy < 0 || iy >= fNy)
0159   {
0160     return false;
0161   }
0162 
0163   TowerGeom geom; // (intermediate geometry used for S-corrections)
0164   geom.Xcenter = raw_geom0.get_center_x();
0165   geom.Ycenter = raw_geom0.get_center_y();
0166   geom.Zcenter = raw_geom0.get_center_z();
0167 
0168   if (m_UseDetailedGeometry)
0169   {
0170     geom.rotX = raw_geom0.get_rotx();
0171     geom.rotY = raw_geom0.get_roty();
0172     geom.rotZ = raw_geom0.get_rotz();
0173 
0174     // Describe the eta and phi direction within the tower
0175     geom.dX[0] = raw_geom0.get_center_high_phi_x() - raw_geom0.get_center_low_phi_x();
0176     geom.dY[0] = raw_geom0.get_center_high_phi_y() - raw_geom0.get_center_low_phi_y();
0177     geom.dZ[0] = raw_geom0.get_center_high_phi_z() - raw_geom0.get_center_low_phi_z();
0178     geom.dX[1] = raw_geom0.get_center_high_eta_x() - raw_geom0.get_center_low_eta_x();
0179     geom.dY[1] = raw_geom0.get_center_high_eta_y() - raw_geom0.get_center_low_eta_y();
0180     geom.dZ[1] = raw_geom0.get_center_high_eta_z() - raw_geom0.get_center_low_eta_z();
0181   }
0182   else
0183   {
0184     // By default, an approximate value for the tower rotation will be given
0185     geom.rotX = 0;
0186     geom.rotY = 0;
0187     geom.rotZ = 0;
0188 
0189     // The tower eta and phi directions should be computed 
0190     // in the CompleteTowerGeometry method afterwards
0191     geom.dX[0] = geom.dX[1] = 0;
0192     geom.dY[0] = geom.dY[1] = 0;
0193     geom.dZ[0] = geom.dZ[1] = 0;
0194   }
0195 
0196   int ich = (iy * fNx) + ix;
0197   fTowerGeom[ich] = geom;
0198   
0199   if (m_UseDetailedGeometry)
0200   {
0201     // copy the input geometry inside fTowerGeomDetailed (only for print)
0202     RawTowerGeomv5 *geom_detailed = new RawTowerGeomv5(raw_geom0); 
0203     fTowerGeomDetailed[ich] = geom_detailed;
0204   }
0205 
0206   return true;
0207 }
0208 
0209 bool BEmcRec::CompleteTowerGeometry()
0210 // Calculates tower front size from coordinates of tower center coordinates
0211 {
0212   if (fTowerGeom.empty() || fNx <= 0)
0213   {
0214     std::cout << "Error in BEmcRec::CalculateTowerSize(): Tower geometry not well setup (NX = "
0215               << fNx << ")" << std::endl;
0216     return false;
0217   }
0218 
0219   const int nb = 8;
0220   int idx[nb] = {0, 1, 0, -1, -1, 1, 1, -1};
0221   int idy[nb] = {-1, 0, 1, 0, -1, -1, 1, 1};
0222 
0223   std::map<int, TowerGeom>::iterator it;
0224 
0225   for (it = fTowerGeom.begin(); it != fTowerGeom.end(); ++it)
0226   {
0227     int ich = it->first;
0228     TowerGeom geom0 = it->second;
0229     int ix = ich % fNx;
0230     int iy = ich / fNx;
0231 
0232     TowerGeom geomx;
0233     int inx = 0;
0234 
0235     while (inx < nb && (idx[inx] == 0 || !GetTowerGeometry(ix + idx[inx], iy + idy[inx], geomx)))
0236     {
0237       inx++;
0238     }
0239     if (inx >= nb)
0240     {
0241       std::cout << "Error in BEmcRec::CompleteTowerGeometry(): Error when locating neighbour for (ix,iy)=("
0242                 << ix << "," << iy << ")" << std::endl;
0243       return false;
0244     }
0245 
0246     TowerGeom geomy;
0247     int iny = 0;
0248 
0249     while (iny < nb && (idy[iny] == 0 || !GetTowerGeometry(ix + idx[iny], iy + idy[iny], geomy)))
0250     {
0251       iny++;
0252     }
0253     if (iny >= nb)
0254     {
0255       std::cout << "Error in BEmcRec::CompleteTowerGeometry(): Error when locating neighbour for (ix,iy)=("
0256                 << ix << "," << iy << ")" << std::endl;
0257       return false;
0258     }
0259 
0260     geom0.dX[0] = (geomx.Xcenter - geom0.Xcenter) / float(idx[inx]);
0261     geom0.dY[0] = (geomx.Ycenter - geom0.Ycenter) / float(idx[inx]);
0262     geom0.dZ[0] = (geomx.Zcenter - geom0.Zcenter) / float(idx[inx]);
0263     geom0.dX[1] = (geomy.Xcenter - geom0.Xcenter) / float(idy[iny]);
0264     geom0.dY[1] = (geomy.Ycenter - geom0.Ycenter) / float(idy[iny]);
0265     geom0.dZ[1] = (geomy.Zcenter - geom0.Zcenter) / float(idy[iny]);
0266 
0267     it->second = geom0;
0268 
0269   }  // it = fTowerGeom.begin()
0270 
0271   return true;
0272 }
0273 
0274 void BEmcRec::Tower2Global(float E, float xC, float yC,
0275                            float& xA, float& yA, float& zA)
0276 // xC and yC are local position in tower units
0277 // For CYL geometry (xC,yC) is actually (phiC,zC)
0278 {
0279 
0280   
0281   bool flagDoSD =  true;
0282   if (xA < -999)
0283   {
0284     flagDoSD = false;
0285   }
0286   
0287   xA = 0;
0288   yA = 0;
0289   zA = 0;
0290 
0291 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0292   int ix = xC + 0.5;  // tower #
0293   if (ix < 0 || ix >= fNx)
0294   {
0295     std::cout << m_ThisName << " Error in BEmcRec::Tower2Global: wrong input x: " << ix << std::endl;
0296     return;
0297   }
0298 
0299 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0300   int iy = yC + 0.5;  // tower #
0301   if (iy < 0 || iy >= fNy)
0302   {
0303     std::cout << "Error in BEmcRec::Tower2Global: wrong input y: " << iy << std::endl;
0304     return;
0305   }
0306 
0307   // Get tower where the shower is positioned
0308   TowerGeom geom0;
0309 
0310   if (!GetTowerGeometry(ix, iy, geom0))
0311   {
0312     // Weird case: cluster center of gravity outside the EMCal, take geometry from the neighbouring tower
0313     const int idx[4] = {1, 0, -1, 0};
0314     const int idy[4] = {0, 1, 0, -1};
0315     int ii = 0;
0316     while (ii < 4 && !GetTowerGeometry(ix + idx[ii], iy + idy[ii], geom0))
0317     {
0318       ii++;
0319     }
0320     if (ii >= 4)
0321     {
0322       std::cout << "Error in BEmcRec::Tower2Global: can not identify neighbour for tower ("
0323                 << ix << "," << iy << ")" << std::endl;
0324       return;
0325     }
0326     float Xc = geom0.Xcenter - (idx[ii] * geom0.dX[0]) - (idy[ii] * geom0.dX[1]);
0327     float Yc = geom0.Ycenter - (idx[ii] * geom0.dY[0]) - (idy[ii] * geom0.dY[1]);
0328     float Zc = geom0.Zcenter - (idx[ii] * geom0.dZ[0]) - (idy[ii] * geom0.dZ[1]);
0329     geom0.Xcenter = Xc;
0330     geom0.Ycenter = Yc;
0331     geom0.Zcenter = Zc;
0332   }
0333 
0334   float xt = geom0.Xcenter + ((xC - ix) * geom0.dX[0]) + ((yC - iy) * geom0.dX[1]);
0335   float yt = geom0.Ycenter + ((xC - ix) * geom0.dY[0]) + ((yC - iy) * geom0.dY[1]);
0336   float zt = geom0.Zcenter + ((xC - ix) * geom0.dZ[0]) + ((yC - iy) * geom0.dZ[1]);
0337 
0338   if (flagDoSD)
0339   {
0340     CorrectShowerDepth(ix, iy, E, xt, yt, zt, xA, yA, zA);
0341   }
0342   else 
0343   {
0344     // If zvtx is not used (m_UseAltZvtx = 2 in RawClusterBuilderTemplate)
0345     // then there is no correction of z_cluster
0346     float savzt = zt;
0347     CorrectShowerDepth(ix, iy, E, xt, yt, zt, xA, yA, zA);
0348     zA = savzt; 
0349   }
0350 }
0351 
0352 // ///////////////////////////////////////////////////////////////////////////
0353 
0354 int BEmcRec::iTowerDist(int ix1, int ix2) const
0355 // Distrance in tower units
0356 {
0357   int idist = ix2 - ix1;
0358   if (bCYL)
0359   {
0360     int idistr = fNx - abs(idist);  // Always >0
0361     if (idistr < abs(idist))
0362     {  // Then count in opposite direction
0363       if (idist < 0)
0364       {
0365         idist = idistr;
0366       }
0367       else
0368       {
0369         idist = -idistr;
0370       }
0371     }
0372   }
0373   //  std::cout << "Dist " << ix1 << " " << ix2 << ": " << idist << std::endl;
0374   return idist;
0375 }
0376 
0377 float BEmcRec::fTowerDist(float x1, float x2) const
0378 {
0379   float dist = x2 - x1;
0380   if (bCYL)
0381   {
0382     float distr = fNx - std::fabs(dist);  // Always >0
0383     if (distr < std::abs(dist))
0384     {  // Then count in opposite direction
0385       if (dist < 0)
0386       {
0387         dist = distr;
0388       }
0389       else
0390       {
0391         dist = -distr;
0392       }
0393     }
0394   }
0395   return dist;
0396 }
0397 
0398 // ///////////////////////////////////
0399 
0400 int BEmcRec::FindClusters()
0401 // Cluster search algorithm based on Lednev's one developed for GAMS.
0402 // Returns number of clusters found
0403 {
0404   int nhit;
0405   int nCl;
0406   //  int LenCl[fgMaxLen];
0407   int* LenCl;
0408   int next;
0409   int ib;
0410   int ie;
0411   int iab;
0412   int iae;
0413   int last;
0414   int LastCl;
0415   int leng;
0416   int ich;
0417   int ia = 0;
0418 
0419   EmcModule* vv;
0420   EmcModule *vhit;
0421   EmcModule *vt;
0422   EmcCluster Clt(this);
0423   std::vector<EmcModule>::iterator ph;
0424   std::vector<EmcModule> hl;
0425 
0426   (*fClusters).clear();
0427   nhit = (*fModules).size();
0428 
0429   if (nhit <= 0)
0430   {
0431     return 0;
0432   }
0433   if (nhit == 1)
0434   {
0435     Clt.ReInitialize((*fModules));
0436     fClusters->push_back(Clt);
0437     return 1;
0438   }
0439 
0440   int MaxLen = fgMaxLen;
0441   LenCl = new int[MaxLen];
0442   ZeroVector(LenCl, MaxLen);
0443 
0444   vt = new EmcModule[nhit];
0445   vhit = new EmcModule[nhit];
0446 
0447   ph = (*fModules).begin();
0448   vv = vhit;
0449   while (ph != (*fModules).end())
0450   {
0451     *vv++ = *ph++;// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0452   }
0453 
0454   qsort(vhit, nhit, sizeof(EmcModule), HitNCompare);
0455 
0456   nCl = 0;
0457   next = 0;
0458   for (ich = 1; ich < nhit + 1; ich++)
0459   {
0460     if (ich < nhit)
0461     {
0462       ia = vhit[ich].ich; // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0463     }
0464 
0465     // New subcluster
0466     // NOLINTNEXTLINE(bugprone-pointer-arithmetic-on-polymorphic-object)
0467     if ((ia - vhit[ich - 1].ich > 1)  // the beginning of new subcluster
0468         || (ich >= nhit)              // just finish defining last sub-cluster
0469         || (ia - ia / fNx * fNx == 0))
0470     {  // new raw -> new subcluster
0471 
0472       ib = next;
0473       ie = ich - 1;
0474       next = ich;
0475       if (nCl >= MaxLen)
0476       {
0477         //        delete[] vhit;
0478         //        delete[] vt;
0479         //        return -1;
0480         int* LenCltmp = new int[MaxLen];
0481         CopyVector(LenCl, LenCltmp, MaxLen);
0482         delete[] LenCl;
0483 // NOLINTNEXTLINE(bugprone-implicit-widening-of-multiplication-result)
0484         LenCl = new int[MaxLen * 2];
0485         ZeroVector(LenCl, MaxLen * 2);
0486         CopyVector(LenCltmp, LenCl, MaxLen);
0487         delete[] LenCltmp;
0488         MaxLen *= 2;
0489         //  std::cout << "Extend array size to " << MaxLen << std::endl;
0490       }
0491       nCl++;
0492       LenCl[nCl - 1] = next - ib;
0493       if (nCl > 1)
0494       {
0495         // Job to glue the subclusters with common edge
0496         //
0497         iab = vhit[ib].ich;  // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) // The last subcl begin
0498         iae = vhit[ie].ich;  // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) // The last subcl end
0499         last = ib - 1;       // The prelast subcl end
0500         LastCl = nCl - 2;
0501         for (int iCl = LastCl; iCl >= 0; iCl--)
0502         {
0503           leng = LenCl[iCl];
0504 
0505           if (iab - vhit[last].ich > fNx)// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0506           {
0507             goto new_ich;
0508           }
0509           for (int ichc = last; ichc >= last - leng + 1; ichc--)
0510           {
0511             //      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
0512 
0513             //      if( iae-vhit[ichc].ich >= fNx // From PHENIX version
0514         // NOLINTNEXTLINE(bugprone-pointer-arithmetic-on-polymorphic-object)
0515             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 !!!!
0516             )
0517             {
0518               // 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
0519               CopyVector(&vhit[last + 1 - leng], vt, leng);// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0520               CopyVector(&vhit[last + 1], &vhit[last + 1 - leng], ib - 1 - last);// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0521               CopyVector(vt, &vhit[ib - leng], leng);// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0522 
0523               // Now the number of clusters is reduced by 1 and the length of the last one increased by iCl-cluster length "leng"
0524               for (int i = iCl; i < nCl - 2; i++)
0525               {
0526                 LenCl[i] = LenCl[i + 1];
0527               }
0528               ib -= leng;
0529               LenCl[nCl - 2] = LenCl[nCl - 1] + leng;
0530               nCl--;
0531               goto new_icl;
0532             }
0533           }  // for( int ichc=last
0534 
0535         new_icl:
0536           last = last - leng;
0537         }  // for( int iCl=LastCl
0538 
0539       }  // if( nCl > 1
0540 
0541     }  // if( (ia-vhit
0542 
0543   new_ich:
0544     continue;
0545   }  //  for( ich=1
0546 
0547   if (nCl > 0)
0548   {
0549     ib = 0;
0550     for (int iCl = 0; iCl < nCl; iCl++)
0551     {
0552       leng = LenCl[iCl];
0553       hl.clear();
0554       for (ich = 0; ich < leng; ich++)
0555       {
0556         hl.push_back(vhit[ib + ich]);// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
0557       }
0558       Clt.ReInitialize(hl);
0559       ib += LenCl[iCl];
0560       fClusters->push_back(Clt);
0561     }
0562   }
0563   delete[] LenCl;
0564   delete[] vhit;
0565   delete[] vt;
0566 
0567   return nCl;
0568 }
0569 
0570 // ///////////////////////////////////////////////////////////////////////////
0571 
0572 void BEmcRec::Momenta(std::vector<EmcModule>* phit, float& pe, float& px,
0573                       float& py, float& pxx, float& pyy, float& pyx, 
0574                       float thresh) const
0575 {
0576   // First and second momenta calculation
0577 
0578   float a;
0579   float x;
0580   float y;
0581   float e;
0582   float xx;
0583   float yy;
0584   float yx;
0585   std::vector<EmcModule>::iterator ph;
0586 
0587   pe = 0;
0588   px = 0;
0589   py = 0;
0590   pxx = 0;
0591   pyy = 0;
0592   pyx = 0;
0593   if (phit->empty())
0594   {
0595     return;
0596   }
0597 
0598   // Find max energy tower
0599   //
0600   ph = phit->begin();
0601   float emax = 0;
0602   int ichmax = 0;
0603 
0604   while (ph != phit->end())
0605   {
0606     a = ph->amp;
0607     if (a > emax)
0608     {
0609       emax = a;
0610       ichmax = ph->ich;
0611     }
0612     ++ph;
0613   }  
0614 
0615   if (emax <= 0)
0616   {
0617     return;
0618   }
0619 
0620   int iymax = ichmax / fNx;
0621   int ixmax = ichmax - iymax * fNx;
0622 
0623   // Calculate CG relative to max energy tower
0624 
0625   x = 0;
0626   y = 0;
0627   e = 0;
0628   xx = 0;
0629   yy = 0;
0630   yx = 0;
0631   ph = phit->begin();
0632 
0633   while (ph != phit->end())
0634   {
0635     a = ph->amp;
0636     if (a > thresh)
0637     {
0638       int iy = ph->ich / fNx;
0639       int ix = ph->ich - (iy * fNx);
0640       int idx = iTowerDist(ixmax, ix);
0641       int idy = iy - iymax;
0642       e += a;
0643       x += idx * a;
0644       y += idy * a;
0645       xx += a * idx * idx;
0646       yy += a * idy * idy;
0647       yx += a * idx * idy;
0648     }
0649     ++ph;
0650   }
0651 
0652   pe = e;
0653 
0654   if (e > 0)
0655   {
0656     x /= e;
0657     y /= e;
0658     xx = xx / e - x * x;
0659     yy = yy / e - y * y;
0660     yx = yx / e - y * x;
0661 
0662     x += ixmax;
0663     y += iymax;
0664 
0665     while (x < -0.5)
0666     {
0667       x += float(fNx);
0668     }
0669     while (x >= fNx - 0.5)
0670     {
0671       x -= float(fNx);
0672     }
0673 
0674     px = x;
0675     py = y;
0676     pxx = xx;
0677     pyy = yy;
0678     pyx = yx;
0679   }
0680 }
0681 
0682 // ///////////////////////////////////////////////////////////////////////////
0683 
0684 float BEmcRec::PredictEnergy(float en, float xcg, float ycg, int ix, int iy)
0685 {
0686   if (_emcprof != nullptr && bProfileProb)
0687   {
0688     return PredictEnergyProb(en, xcg, ycg, ix, iy);
0689   }
0690 
0691   float dx = std::fabs(fTowerDist(float(ix), xcg));
0692   float dy = ycg - iy;
0693   return PredictEnergyParam(en, dx, dy);
0694 }
0695 
0696 float BEmcRec::PredictEnergyParam(float /*en*/, float xc, float yc)
0697 {
0698   // Calculates the energy deposited in the tower, the distance between
0699   // its center and shower Center of Gravity being (xc,yc)
0700   // en - shower energy
0701 
0702   float dx;
0703   float dy;
0704   float r1;
0705   float r2;
0706   float r3;
0707   float fPpar1;
0708   float fPpar2;
0709   float fPpar3;
0710   float fPpar4;
0711 
0712   float fPshiftx = 0;  // !!!!! Untill tuned ... may not be necessary
0713   float fPshifty = 0;  // !!!!! Untill tuned ... may not be necessary
0714 
0715   /*
0716   float lgE;
0717   if (en <= 1.e-10)
0718     lgE = 0;
0719   else
0720     lgE = log(en);
0721   fPpar1=0.59-(1.45+0.13*lgE)*sin2a;
0722   fPpar2=0.265+(0.80+0.32*lgE)*sin2a;
0723   fPpar3=0.25+(0.45-0.036*lgE)*sin2a;
0724   fPpar4=0.42;
0725   */
0726   fPpar1 = 0.549;
0727   fPpar2 = 0.304;
0728   fPpar3 = 0.389;
0729   fPpar4 = 0.326;
0730   /*
0731   fPpar1 = 0.486;
0732   fPpar2 = 0.302;
0733   fPpar3 = 0.354;
0734   fPpar4 = 0.407;
0735   */
0736   /*
0737   fPpar1 = 0.343;
0738   fPpar2 = 0.509;
0739   fPpar3 = 0.199;
0740   fPpar4 = 0.548;
0741   */
0742 
0743   //  if (en > 0) SetProfileParameters(-1, en, xc, yc);
0744 
0745   dx = std::fabs(xc - fPshiftx);
0746   dy = std::fabs(yc - fPshifty);
0747   r2 = dx * dx + dy * dy;
0748   r1 = std::sqrt(r2);
0749   r3 = r2 * r1;
0750   double e = (fPpar1 * std::exp(-r3 / fPpar2)) + (fPpar3 * std::exp(-r1 / fPpar4));
0751 
0752   return e;
0753 }
0754 
0755 float BEmcRec::PredictEnergyProb(float en, float xcg, float ycg, int ix, int iy)
0756 // Predict tower energy from profiles used in GetProb()
0757 // This is expected to be used in BEmcCluster::GetSubClusters
0758 {
0759   if (_emcprof == nullptr)
0760   {
0761     return -1;
0762   }
0763 
0764   while (xcg < -0.5)
0765   {
0766     xcg += float(fNx);
0767   }
0768   while (xcg >= fNx - 0.5)
0769   {
0770     xcg -= float(fNx);
0771   }
0772 
0773 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0774   int ixcg = int(xcg + 0.5);
0775 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0776   int iycg = int(ycg + 0.5);
0777   float ddx = std::fabs(xcg - ixcg);
0778   float ddy = std::fabs(ycg - iycg);
0779 
0780   float xg=0;
0781   float yg=0;
0782   float zg=0;
0783   Tower2Global(en, xcg, ycg, xg, yg, zg);
0784 
0785   float theta;
0786   float phi;
0787   GetImpactThetaPhi(xg, yg, zg, theta, phi);
0788 
0789   int isx = 1;
0790   if (xcg - ixcg < 0)
0791   {
0792     isx = -1;
0793   }
0794   int isy = 1;
0795   if (ycg - iycg < 0)
0796   {
0797     isy = -1;
0798   }
0799 
0800   int idx = iTowerDist(ixcg, ix) * isx;
0801   int idy = (iy - iycg) * isy;
0802 
0803   int id = -1;
0804   if (idx == 0 && idy == 0)
0805   {
0806     id = 0;
0807   }
0808   else if (idx == 1 && idy == 0)
0809   {
0810     id = 1;
0811   }
0812   else if (idx == 1 && idy == 1)
0813   {
0814     id = 2;
0815   }
0816   else if (idx == 0 && idy == 1)
0817   {
0818     id = 3;
0819   }
0820 
0821   if (id < 0)
0822   {
0823     float dx = std::fabs(fTowerDist(xcg, float(ix)));
0824     float dy = std::fabs(iy - ycg);
0825     float rr = std::sqrt((dx * dx) + (dy * dy));
0826     //    return PredictEnergyParam(en, dx, dy);
0827     return _emcprof->PredictEnergyR(en, theta, phi, rr);
0828   }
0829 
0830   float ep[4];
0831   float err[4];
0832   for (int ip = 0; ip < 4; ip++)
0833   {
0834     _emcprof->PredictEnergy(ip, en, theta, phi, ddx, ddy, ep[ip], err[ip]);
0835   }
0836 
0837   float eout;
0838 
0839   if (id == 0)
0840   {
0841     eout = (ep[1] + ep[2]) / 2. + ep[3];
0842   }
0843   else if (id == 1)
0844   {
0845     eout = (ep[0] - ep[2]) / 2. - ep[3];
0846   }
0847   else if (id == 3)
0848   {
0849     eout = (ep[0] - ep[1]) / 2. - ep[3];
0850   }
0851   else
0852   {
0853     eout = ep[3];
0854   }
0855 
0856   //  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);
0857   if (eout < 0)
0858   {
0859     eout = 1e-6;
0860   }
0861 
0862   return eout;
0863 }
0864 
0865 // ///////////////////////////////////////////////////////////////////////////
0866 
0867 float BEmcRec::GetTowerEnergy(int iy, int iz, std::vector<EmcModule>* plist) const
0868 {
0869   int nn = plist->size();
0870   if (nn <= 0)
0871   {
0872     return 0;
0873   }
0874 
0875   for (int i = 0; i < nn; i++)
0876   {
0877     int ich = (*plist)[i].ich;
0878     int iyt = ich / fNx;
0879     int izt = ich % fNx;
0880     if (iy == iyt && iz == izt)
0881     {
0882       return (*plist)[i].amp;
0883     }
0884   }
0885   return 0;
0886 }
0887 
0888 // !!!!! Change here to a ponter to HitList
0889 float BEmcRec::GetProb(std::vector<EmcModule> HitList, float en, float xg, float yg, float zg, float& chi2, int& ndf)
0890 // Do nothing; should be defined in a detector specific module BEmcRec{Name}
0891 {
0892   //  float enoise = 0.01;  // 10 MeV per tower
0893   float enoise = GetProbNoiseParam();
0894   //  float thresh = 0.01;
0895   float thresh = GetTowerThreshold();
0896 
0897   chi2 = 0;
0898   ndf = 0;
0899   if (_emcprof == nullptr)
0900   {
0901     return -1;
0902   }
0903 
0904   if (!(_emcprof->IsLoaded()))
0905   {
0906     return -1;
0907   }
0908 
0909   int nn = HitList.size();
0910   if (nn <= 0)
0911   {
0912     return -1;
0913   }
0914 
0915   float theta;
0916   float phi;
0917   GetImpactThetaPhi(xg, yg, zg, theta, phi);
0918 
0919   // z coordinate below means x coordinate
0920 
0921   float etot;
0922   float zcg;
0923   float ycg;
0924   float zz;
0925   float yy;
0926   float yz;
0927   Momenta(&HitList, etot, zcg, ycg, zz, yy, yz, thresh);
0928 
0929 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0930   int iz0cg = int(zcg + 0.5);
0931 // NOLINTNEXTLINE(bugprone-incorrect-roundings)
0932   int iy0cg = int(ycg + 0.5);
0933   float ddz = std::fabs(zcg - iz0cg);
0934   float ddy = std::fabs(ycg - iy0cg);
0935 
0936   int isz = 1;
0937   if (zcg - iz0cg < 0)
0938   {
0939     isz = -1;
0940   }
0941   int isy = 1;
0942   if (ycg - iy0cg < 0)
0943   {
0944     isy = -1;
0945   }
0946 
0947   // 4 central towers: 43
0948   //                   12
0949   // Tower 1 - central one
0950   float e1;
0951   float e2;
0952   float e3;
0953   float e4;
0954   e1 = GetTowerEnergy(iy0cg, iz0cg, &HitList);
0955   e2 = GetTowerEnergy(iy0cg, iz0cg + isz, &HitList);
0956   e3 = GetTowerEnergy(iy0cg + isy, iz0cg + isz, &HitList);
0957   e4 = GetTowerEnergy(iy0cg + isy, iz0cg, &HitList);
0958 
0959   if (e1 < thresh)
0960   {
0961     e1 = 0;
0962   }
0963   if (e2 < thresh)
0964   {
0965     e2 = 0;
0966   }
0967   if (e3 < thresh)
0968   {
0969     e3 = 0;
0970   }
0971   if (e4 < thresh)
0972   {
0973     e4 = 0;
0974   }
0975 
0976   float e1t = (e1 + e2 + e3 + e4) / etot;
0977   float e2t = (e1 + e2 - e3 - e4) / etot;
0978   float e3t = (e1 - e2 - e3 + e4) / etot;
0979   float e4t = (e3) / etot;
0980   //  float rr = sqrt((0.5-ddz)*(0.5-ddz)+(0.5-ddy)*(0.5-ddy));
0981 
0982   // Predicted values
0983   const int NP = 4;  // From BEmcProfile
0984   float ep[NP];
0985   float err[NP];
0986   for (int ip = 0; ip < NP; ip++)
0987   {
0988     _emcprof->PredictEnergy(ip, en, theta, phi, ddz, ddy, ep[ip], err[ip]);
0989     if (ep[ip] < 0)
0990     {
0991       return -1;
0992     }
0993     if (ip < 3)
0994     {
0995       err[ip] = std::sqrt((err[ip] * err[ip]) + (4 * enoise * enoise / etot / etot));
0996     }
0997     else
0998     {
0999       err[ip] = std::sqrt((err[ip] * err[ip]) + (1 * enoise * enoise / etot / etot));
1000     }
1001   }
1002 
1003   chi2 = 0.;
1004   chi2 += (ep[0] - e1t) * (ep[0] - e1t) / err[0] / err[0];
1005   chi2 += (ep[1] - e2t) * (ep[1] - e2t) / err[1] / err[1];
1006   chi2 += (ep[2] - e3t) * (ep[2] - e3t) / err[2] / err[2];
1007   chi2 += (ep[3] - e4t) * (ep[3] - e4t) / err[3] / err[3];
1008   ndf = 4;
1009 
1010   chi2 /= 1.5;
1011 
1012   float prob = TMath::Prob(chi2, ndf);
1013 
1014   return prob;
1015 }
1016 
1017 // ///////////////////////////////////////////////////////////////////////////
1018 // Static functions
1019 
1020 int BEmcRec::HitNCompare(const void* h1, const void* h2)
1021 {
1022   return (static_cast<const EmcModule*>(h1)->ich - static_cast<const EmcModule*>(h2)->ich);
1023 }
1024 
1025 // ///////////////////////////////////////////////////////////////////////////
1026 
1027 int BEmcRec::HitACompare(const void* h1, const void* h2)
1028 {
1029   float amp1 = static_cast<const EmcModule*>(h1)->amp;
1030   float amp2 = static_cast<const EmcModule*>(h2)->amp;
1031   return (amp1 < amp2) ? 1 : (amp1 > amp2) ? -1 : 0; // NOLINT(readability-avoid-nested-conditional-operator)
1032 }
1033 
1034 // ///////////////////////////////////////////////////////////////////////////
1035 
1036 void BEmcRec::ZeroVector(int* v, int N)
1037 {
1038   int* p = v;
1039   for (int i = 0; i < N; i++)
1040   {
1041     *p++ = 0;
1042   }
1043 }
1044 
1045 // ///////////////////////////////////////////////////////////////////////////
1046 
1047 void BEmcRec::ZeroVector(float* v, int N)
1048 {
1049   float* p = v;
1050   for (int i = 0; i < N; i++)
1051   {
1052     *p++ = 0;
1053   }
1054 }
1055 
1056 // ///////////////////////////////////////////////////////////////////////////
1057 
1058 void BEmcRec::ZeroVector(EmcModule* v, int N)
1059 {
1060   //  memset(v, 0, N*sizeof(EmcModule));
1061   for (int i = 0; i < N; i++)
1062   {
1063     v[i].ich = 0;// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
1064     v[i].amp = 0;// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
1065     v[i].tof = 0;// NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
1066   }
1067 }
1068 
1069 // ///////////////////////////////////////////////////////////////////////////
1070 
1071 void BEmcRec::CopyVector(const int* from, int* to, int N)
1072 {
1073   if (N <= 0)
1074   {
1075     return;
1076   }
1077   for (int i = 0; i < N; i++)
1078   {
1079     to[i] = from[i];
1080   }
1081 }
1082 
1083 // ///////////////////////////////////////////////////////////////////////////
1084 
1085 void BEmcRec::CopyVector(const EmcModule* from, EmcModule* to, int N)
1086 {
1087   if (N <= 0)
1088   {
1089     return;
1090   }
1091   for (int i = 0; i < N; i++)
1092   {
1093     to[i] = from[i]; // NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object)
1094   }
1095 }
1096 
1097 // ///////////////////////////////////////////////////////////////////////////
1098 
1099 /* Future improvements:
1100 
1101 1. FindClusters(): to ensure that all EmcModules are above energy threshold
1102 set by SetThreshold routine (or default one)
1103 
1104 */
1105 
1106 // ///////////////////////////////////////////////////////////////////////////
1107 // EOF