Belle II Software  release-06-01-15
ECLLeakagePosition.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 //..ECL
10 #include <ecl/geometry/ECLLeakagePosition.h>
11 #include <ecl/dbobjects/ECLCrystalCalib.h>
12 #include <ecl/geometry/ECLNeighbours.h>
13 
14 //..Other
15 #include <iostream>
16 #include <TMath.h>
17 
18 using namespace Belle2;
19 using namespace ECL;
20 
21 //..Constructor.
23  m_ECLCrystalThetaEdge("ECLCrystalThetaEdge"),
24  m_ECLCrystalPhiEdge("ECLCrystalPhiEdge"),
25  m_ECLCrystalThetaWidth("ECLCrystalThetaWidth"),
26  m_ECLCrystalPhiWidth("ECLCrystalPhiWidth")
27 {
28 
29  //..Obtain the vectors of crystal edges and widths from the database
30  if (m_ECLCrystalThetaEdge.hasChanged()) {
31  thetaEdge = m_ECLCrystalThetaEdge->getCalibVector();
32  }
33  if (m_ECLCrystalPhiEdge.hasChanged()) {
34  phiEdge = m_ECLCrystalPhiEdge->getCalibVector();
35  }
36  if (m_ECLCrystalThetaWidth.hasChanged()) {
37  thetaWidth = m_ECLCrystalThetaWidth->getCalibVector();
38  }
39  if (m_ECLCrystalPhiWidth.hasChanged()) {
40  phiWidth = m_ECLCrystalPhiWidth->getCalibVector();
41  }
42 
43  //..Eight nearest neighbours, plus crystal itself. Uses cellID, 1--8736
44  neighbours = new ECLNeighbours("N", 1);
45 
46  //..Record the thetaID and phiID of each cellID
47  for (int thID = 0; thID < 69; thID++) {
48  for (int phID = 0; phID < neighbours->getCrystalsPerRing(thID); phID++) {
49  thetaIDofCrysID.push_back(thID);
50  phiIDofCrysID.push_back(phID);
51  }
52  }
53 
54  //..Crystals between mechanical structure for each thetaID
55  for (int thID = 0; thID < firstBarrelThetaID; thID++) {
56  int nCrys = neighbours->getCrystalsPerRing(thID) / 16;
57  crysBetweenMech.push_back(nCrys);
58  }
59  for (int thID = firstBarrelThetaID; thID <= lastBarrelThetaID; thID++) {
60  crysBetweenMech.push_back(2);
61  }
62  for (int thID = lastBarrelThetaID + 1; thID < 69; thID++) {
63  int nCrys = neighbours->getCrystalsPerRing(thID) / 16;
64  crysBetweenMech.push_back(nCrys);
65  }
66 }
67 
69 {
70 }
71 
72 std::vector<int> ECLLeakagePosition::getLeakagePosition(const int cellIDFromEnergy, const float theta, const float phi,
73  const int nPositions)
74 {
75 
76  //..Start by checking if the crystal with the most energy is the correct one
77  int crysID = cellIDFromEnergy - 1;
78  int iStatus = -1;
79 
80  //..theta and phi need to be within the crystal
81  float dTheta = theta - thetaEdge[crysID];
82  float dPhi = phi - phiEdge[crysID];
83  if (dPhi > TMath::Pi()) {dPhi -= 2.*TMath::Pi();}
84  if (dPhi < -TMath::Pi()) {dPhi += 2.*TMath::Pi();}
85  if (dTheta >= 0 and dTheta <= thetaWidth[crysID] and dPhi >= 0 and dPhi <= phiWidth[crysID]) {
86  iStatus = 0;
87  }
88 
89  //..Theta and phi are not located in the maximum energy crystal. Check the
90  // eight nearest neighbours.
91  if (iStatus == -1) {
92 
93  //..Nearest neighbours (plus the central crystal)
94  for (const auto& tempCellID : neighbours->getNeighbours(cellIDFromEnergy)) {
95  int tempCrysID = tempCellID - 1;
96  dTheta = theta - thetaEdge[tempCrysID];
97  dPhi = phi - phiEdge[tempCrysID];
98  if (dPhi > TMath::Pi()) {dPhi -= 2.*TMath::Pi();}
99  if (dPhi < -TMath::Pi()) {dPhi += 2.*TMath::Pi();}
100 
101  //..This one is correct
102  if (dTheta >= 0 and dTheta <= thetaWidth[tempCrysID] and dPhi >= 0 and dPhi <= phiWidth[tempCrysID]) {
103  iStatus = 1;
104  crysID = tempCrysID;
105  break;
106  }
107  }
108  }
109 
110  //..Need to do this one by brute force
111  if (iStatus == -1) {
112 
113  //..Start at the last crystal and work backwards
114  for (int crys = 8735; crys >= 0; crys--) {
115  dTheta = theta - thetaEdge[crys];
116  dPhi = phi - phiEdge[crys];
117  if (dPhi > TMath::Pi()) {dPhi -= 2.*TMath::Pi();}
118  if (dPhi < -TMath::Pi()) {dPhi += 2.*TMath::Pi();}
119  if (dPhi >= 0 and dPhi <= phiWidth[crys] and dTheta >= 0) {
120  iStatus = 2;
121  crysID = crys;
122  break;
123  }
124  }
125  }
126 
127  //..Above should cover all cases, but set sensible values if we missed something
128  if (iStatus == -1) {
129  iStatus = 3;
130  crysID = cellIDFromEnergy - 1;
131  dTheta = 0.5;
132  dPhi = 0.5;
133  }
134 
135  //..Return values
136  int cellID = crysID + 1;
137  int thetaID = thetaIDofCrysID[crysID];
138  int iRegion = 0;
139  if (thetaID >= firstBarrelThetaID and thetaID <= lastBarrelThetaID) {iRegion = 1;}
140  if (thetaID > lastBarrelThetaID) {iRegion = 2;}
141 
142  //..Mechanical structure is on lower edge of phiID 0, and every 2 (barrel) or n (endcap)
143  // crystals thereafter
144  int iPhiMech = phiIDofCrysID[crysID] % crysBetweenMech[thetaID];
145  bool reversePhi;
146 
147  //..Mechanical structure on lower edge
148  if ((iPhiMech == 0 and iRegion != 1) or (iPhiMech == crysBetweenMech[thetaID] - 1 and iRegion == 1)) {
149  iPhiMech = 0;
150  reversePhi = false;
151 
152  //..Mechanical structure on upper edge
153  } else if ((iPhiMech == crysBetweenMech[thetaID] - 1 and iRegion != 1) or (iPhiMech == 0 and iRegion == 1)) {
154  iPhiMech = 0;
155  reversePhi = true;
156 
157  //..No mechanical structure adjacent
158  } else {
159  iPhiMech = 1;
160  reversePhi = false;
161  }
162 
163  //..Divide crystal into nPositions in width, starting from lower edge
164  int iLocalTheta = (int)(nPositions * dTheta / thetaWidth[crysID]);
165  if (iLocalTheta < 0) {iLocalTheta = 0;}
166  if (iLocalTheta >= nPositions) {iLocalTheta = nPositions - 1;}
167 
168  int iLocalPhi = (int)(nPositions * dPhi / phiWidth[crysID]);
169  if (iLocalPhi < 0) {iLocalPhi = 0;}
170  if (iLocalPhi >= nPositions) {iLocalPhi = nPositions - 1;}
171 
172  //..iLocalPhi is measured from edge with mechanical structure, if present,
173  // so reverse order of iLocalPhi if mech structure is on the upper edge
174  if (reversePhi) {iLocalPhi = nPositions - iLocalPhi - 1;}
175 
176  //..Return as a std::vector
177  std::vector<int> position;
178  position.push_back(cellID);
179  position.push_back(thetaID);
180  position.push_back(iRegion);
181  position.push_back(iLocalTheta);
182  position.push_back(iLocalPhi);
183  position.push_back(iPhiMech);
184  position.push_back(iStatus);
185  return position;
186 }
DBObjPtr< ECLCrystalCalib > m_ECLCrystalPhiEdge
lower edges of crystals, phi
std::vector< float > thetaEdge
lower theta edges from DB object
std::vector< int > crysBetweenMech
crystals between phi mechanical structure per thetaID
std::vector< float > phiEdge
lower phi edges from DB object
ECL::ECLNeighbours * neighbours
8 nearest neighbours to crystal
std::vector< int > thetaIDofCrysID
thetaID of each crystal ID
const int firstBarrelThetaID
first barrel thetaID
DBObjPtr< ECLCrystalCalib > m_ECLCrystalThetaWidth
width in theta
DBObjPtr< ECLCrystalCalib > m_ECLCrystalPhiWidth
width in phi
std::vector< int > getLeakagePosition(const int cellIDFromEnergy, const float theta, const float phi, const int nPositions)
Return postion.
std::vector< float > phiWidth
crystal phi widths from DB object
const int lastBarrelThetaID
last barrel thetaID
DBObjPtr< ECLCrystalCalib > m_ECLCrystalThetaEdge
Required geometry payloads.
std::vector< float > thetaWidth
crystal theta widths from DB object
std::vector< int > phiIDofCrysID
phiID of each crystal ID
Class to get the neighbours for a given cell id.
Definition: ECLNeighbours.h:23
const std::vector< short int > & getNeighbours(short int cid) const
Return the neighbours for a given cell ID.
short int getCrystalsPerRing(const short int thetaid) const
return number of crystals in a given theta ring
Definition: ECLNeighbours.h:37
Abstract base class for different kinds of events.