Belle II Software  release-05-01-25
ECLNeighbours.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2016 - Belle II Collaboration *
4  * *
5  * Returns the list of neighbours for a given cell ID. *
6  * *
7  * Author: The Belle II Collaboration *
8  * Contributors: Torben Ferber (ferber@physics.ubc.ca) *
9  * *
10  * This software is provided "as is" without any warranty. *
11  **************************************************************************/
12 
13 // ECL GEOMETRY
14 #include <ecl/geometry/ECLNeighbours.h>
15 #include <ecl/geometry/ECLGeometryPar.h> // for geometry
16 
17 // FRAMEWORK
18 #include <framework/logging/Logger.h>
19 #include <framework/gearbox/Unit.h>
20 
21 // OTHER
22 #include "TMath.h"
23 #include "TVector3.h"
24 
25 using namespace Belle2;
26 using namespace ECL;
27 
28 // Constructor.
29 ECLNeighbours::ECLNeighbours(const std::string& neighbourDef, const double par)
30 {
31  // resize the vector
32  std::vector<short int> fakeneighbours;
33  fakeneighbours.push_back(0); // insert one fake to avoid the "0" entry
34  m_neighbourMap.push_back(fakeneighbours);
35 
36  int parToInt = int(par);
37 
38  // fixed number of neighbours:
39  if (neighbourDef == "N") {
40  B2DEBUG(150, "ECLNeighbours::ECLNeighbours: initialize " << neighbourDef << ", n x n: " << parToInt * 2 + 1 << " x " << parToInt * 2
41  + 1);
42  if ((parToInt >= 0) and (parToInt < 6)) initializeN(parToInt);
43  else B2FATAL("ECLNeighbours::ECLNeighbours: " << parToInt << " is an invalid parameter (must be between 0 and 5)!");
44  } else if (neighbourDef == "NC") {
45  B2DEBUG(150, "ECLNeighbours::ECLNeighbours: initialize " << neighbourDef << ", n x n (minus corners): " << parToInt * 2 + 1 << " x "
46  <<
47  parToInt * 2 + 1);
48  if ((parToInt >= 0) and (parToInt < 6)) initializeNC(parToInt, 1);
49  else B2FATAL("ECLNeighbours::ECLNeighbours: " << parToInt << " is an invalid parameter (must be between 0 and 5)!");
50  } else if (neighbourDef == "N2C") {
51  B2DEBUG(150, "ECLNeighbours::ECLNeighbours: initialize " << neighbourDef << ", n x n (minus 2 corners): " << parToInt * 2 + 1 <<
52  " x " <<
53  parToInt * 2 + 1);
54  if ((parToInt >= 0) and (parToInt < 6)) initializeNC(parToInt, 2);
55  else B2FATAL("ECLNeighbours::ECLNeighbours: " << parToInt << " is an invalid parameter (must be between 0 and 5)!");
56  }
57  // or neighbours depend on the distance:
58  else if (neighbourDef == "R") {
59  B2DEBUG(150, "ECLNeighbours::ECLNeighbours: initialize " << neighbourDef << ", radius: " << par << " cm");
60  if ((par > 0.0) and (par < 30.0 * Belle2::Unit::cm)) initializeR(par);
61  else B2FATAL("ECLNeighbours::ECLNeighbours: " << par << " is an invalid parameter (must be between 0 cm and 30 cm)!");
62  }
63  // or neighbours that form a cross, user defined coverage of up to 100% in neighbouring ring:
64  else if (neighbourDef == "F") {
65  double parChecked = par;
66  if (parChecked > 1.0) parChecked = 1.0;
67  else if (parChecked < 0.1) parChecked = 0.1;
68  B2DEBUG(150, "ECLNeighbours::ECLNeighbours: initialize " << neighbourDef << ", fraction: " << parChecked);
69  initializeF(parChecked);
70  }
71  // or wrong type:
72  else {
73  B2FATAL("ECLNeighbours::ECLNeighbours (constructor via std::string): Invalid option: " << neighbourDef <<
74  " (valid: N, NC, NC2, R ( with R<30 cm), F (with 0.1<f<1)");
75  }
76 
77 }
78 
80 {
81  ;
82 }
83 
84 void ECLNeighbours::initializeR(double radius)
85 {
86  // resize the vector
87  std::vector<short int> fakeneighbours;
88  fakeneighbours.push_back(0); // insert one fake to avoid the "0" entry
89  m_neighbourMapTemp.push_back(fakeneighbours);
90 
91  // distance calculations take a "long" time, so reduce the number of candidates first:
92  initializeN(6);
93 
94  // ECL geometry
96 
97  for (int i = 0; i < 8736; i++) {
98  // get the central one
99  TVector3 direction = geom->GetCrystalVec(i);
100  TVector3 position = geom->GetCrystalPos(i);
101 
102  // get all nearby crystals
103  std::vector<short int> neighbours = getNeighbours(i + 1);
104  std::vector<short int> neighboursTemp;
105 
106  // ... and calculate the shortest distance between the central one and all possible neighbours (of the reduced set)
107  for (auto const& id : neighbours) {
108  const TVector3& directionNeighbour = geom->GetCrystalVec(id - 1);
109  const double alpha = direction.Angle(directionNeighbour);
110  const double R = position.Mag();
111  const double distance = getDistance(alpha, R);
112 
113  if (distance <= radius) neighboursTemp.push_back(id);
114  }
115 
116  m_neighbourMapTemp.push_back(neighboursTemp);
117  }
118 
119  // all done, reoplace the original map
121 
122 }
123 
124 void ECLNeighbours::initializeF(double frac)
125 {
126  // ECL geometry
128 
129  for (int i = 0; i < 8736; i++) {
130  // this vector will hold all neighbours for the i-th crystal
131  std::vector<short int> neighbours;
132 
133  // phi and theta coordinates of the central crystal
134  geom->Mapping(i);
135  const short tid = geom->GetThetaID();
136  const short pid = geom->GetPhiID();
137 
138  // add the two in the same theta ring
139  const short int phiInc = increasePhiId(pid, tid, 1);
140  const short int phiDec = decreasePhiId(pid, tid, 1);
141  neighbours.push_back(geom->GetCellID(tid , pid) + 1);
142  neighbours.push_back(geom->GetCellID(tid , phiInc) + 1);
143  neighbours.push_back(geom->GetCellID(tid , phiDec) + 1);
144 
145  double fracPos = (pid + 0.5) / m_crystalsPerRing[tid];
146 
147  // find the two closest crystals in the inner theta ring
148  short int tidinner = tid - 1;
149  if (tidinner >= 0) {
150 
151  short int n1 = -1;
152  double dist1 = 999.;
153  short int pid1 = -1;
154  short int n2 = -1;
155  double dist2 = 999.;
156 
157  for (short int inner = 0; inner < m_crystalsPerRing[tidinner]; ++inner) {
158  const double f = (inner + 0.5) / m_crystalsPerRing[tidinner];
159  const double dist = fabs(fracPos - f);
160  if (dist < dist1) {
161  dist2 = dist1;
162  dist1 = dist;
163  n2 = n1;
164  n1 = geom->GetCellID(tidinner, inner);
165  pid1 = inner;
166  } else if (dist < dist2) {
167  dist2 = dist;
168  n2 = geom->GetCellID(tidinner, inner);
169  }
170  }
171 
172  // check coverage
173  double cov = TMath::Min(((double) pid + 1) / m_crystalsPerRing[tid],
174  ((double) pid1 + 1) / m_crystalsPerRing[tidinner]) - TMath::Max(((double) pid) / m_crystalsPerRing[tid],
175  ((double) pid1) / m_crystalsPerRing[tidinner]);
176  cov = cov / (1. / m_crystalsPerRing[tid]);
177 
178  neighbours.push_back(n1 + 1);
179  if (cov < frac - 1e-4) neighbours.push_back(n2 + 1);
180  }
181 
182  // find the two closest crystals in the outer theta ring
183  short int tidouter = tid + 1;
184  if (tidouter <= 68) {
185  short int no1 = -1;
186  double disto1 = 999.;
187  short int pido1 = -1;
188  short int no2 = -1;
189  double disto2 = 999.;
190 
191  for (short int outer = 0; outer < m_crystalsPerRing[tidouter]; ++outer) {
192  const double f = (outer + 0.5) / m_crystalsPerRing[tidouter];
193  const double dist = fabs(fracPos - f);
194  if (dist < disto1) {
195  disto2 = disto1;
196  disto1 = dist;
197  no2 = no1;
198  no1 = geom->GetCellID(tidouter, outer);
199  pido1 = outer;
200  } else if (dist < disto2) {
201  disto2 = dist;
202  no2 = geom->GetCellID(tidouter, outer);
203  }
204  }
205  // check coverage
206  double cov = TMath::Min(((double) pid + 1) / m_crystalsPerRing[tid],
207  ((double) pido1 + 1) / m_crystalsPerRing[tidouter]) - TMath::Max(((double) pid) / m_crystalsPerRing[tid],
208  ((double) pido1) / m_crystalsPerRing[tidouter]);
209  cov = cov / (1. / m_crystalsPerRing[tid]);
210 
211  neighbours.push_back(no1 + 1);
212  if (cov < frac - 1e-4) {
213  neighbours.push_back(no2 + 1);
214  }
215  }
216 
217  // push back the final vector of IDs
218  m_neighbourMap.push_back(neighbours);
219  }
220 
221 }
222 
224 {
225  // ECL geometry
227 
228  // This is the "NxN-edges" case (in the barrel)
229  // in the endcaps we project the neighbours to the outer and inner rings.
230  for (int i = 0; i < 8736; i++) {
231 
232  // this vector will hold all neighbours for the i-th crystal
233  std::vector<short int> neighbours;
234 
235  // phi and theta coordinates of the central crystal
236  geom->Mapping(i);
237  const short tid = geom->GetThetaID();
238  const short pid = geom->GetPhiID();
239 
240  // 'left' and 'right' extremal neighbours in the same theta ring
241  const short int phiInc = increasePhiId(pid, tid, n);
242  const short int phiDec = decreasePhiId(pid, tid, n);
243  const double fractionalPhiInc = static_cast < double >(phiInc) / m_crystalsPerRing [ tid ];
244  const double fractionalPhiDec = static_cast < double >(phiDec) / m_crystalsPerRing [ tid ];
245 
246  // loop over all possible theta rings and add neighbours
247  for (int theta = tid - n; theta <= tid + n; theta++) {
248  if ((theta > 68) || (theta < 0)) continue; // valid theta ids are 0..68 (69 in total)
249 
250  short int thisPhiInc = std::lround(fractionalPhiInc * m_crystalsPerRing [ theta ]);
251 
252  short int thisPhiDec = std::lround(fractionalPhiDec * m_crystalsPerRing [ theta ]);
253  if (thisPhiDec == m_crystalsPerRing [ theta ]) thisPhiDec = 0;
254 
255  const std::vector<short int> phiList = getPhiIdsInBetween(thisPhiInc, thisPhiDec, theta);
256 
257  for (unsigned int k = 0; k < phiList.size(); ++k) {
258  neighbours.push_back(geom->GetCellID(theta , phiList.at(k)) + 1);
259  }
260  }
261 
262  // push back the final vector of IDs
263  m_neighbourMap.push_back(neighbours);
264 
265  }
266 }
267 
268 
269 void ECLNeighbours::initializeNC(const int n, const int corners)
270 {
271  // ECL geometry
273 
274  // This is the "NxN-edges" minus edges case (in the barrel)
275  // in the endcaps we project the neighbours to the outer and inner rings.
276  for (int i = 0; i < 8736; i++) {
277 
278  // this vector will hold all neighbours for the i-th crystal
279  std::vector<short int> neighbours;
280 
281  // phi and theta coordinates of the central crystal
282  geom->Mapping(i);
283  const short tid = geom->GetThetaID();
284  const short pid = geom->GetPhiID();
285 
286  // 'left' and 'right' extremal neighbours in the same theta ring
287  const short int phiInc = increasePhiId(pid, tid, n);
288  const short int phiDec = decreasePhiId(pid, tid, n);
289  const double fractionalPhiInc = static_cast < double >(phiInc) / m_crystalsPerRing [ tid ];
290  const double fractionalPhiDec = static_cast < double >(phiDec) / m_crystalsPerRing [ tid ];
291 
292  // loop over all possible theta rings and add neighbours
293  for (int theta = tid - n; theta <= tid + n; theta++) {
294  if ((theta > 68) || (theta < 0)) continue; // valid theta ids are 0..68 (69 in total)
295 
296  short int thisPhiInc = std::lround(fractionalPhiInc * m_crystalsPerRing [ theta ]);
297 
298  short int thisPhiDec = std::lround(fractionalPhiDec * m_crystalsPerRing [ theta ]);
299  if (thisPhiDec == m_crystalsPerRing [ theta ]) thisPhiDec = 0;
300 
301  std::vector<short int> phiList;
302  if ((theta == tid - n) or (theta == tid + n)) phiList = getPhiIdsInBetweenC(thisPhiInc, thisPhiDec, theta, corners);
303  else if (corners == 2 and ((theta == tid - n + 1)
304  or (theta == tid + n - 1))) phiList = getPhiIdsInBetweenC(thisPhiInc, thisPhiDec, theta, 1);
305  else phiList = getPhiIdsInBetween(thisPhiInc, thisPhiDec, theta);
306 
307  for (unsigned int k = 0; k < phiList.size(); ++k) {
308  neighbours.push_back(geom->GetCellID(theta , phiList.at(k)) + 1);
309  }
310  }
311 
312  // push back the final vector of IDs
313  m_neighbourMap.push_back(neighbours);
314 
315  }
316 }
317 
318 const std::vector<short int>& ECLNeighbours::getNeighbours(const short int cid) const
319 {
320  return m_neighbourMap.at(cid);
321 }
322 
323 // decrease the phi id by "n" integers numbers (valid ids range from 0 to m_crystalsPerRing[thetaid] - 1)
324 short int ECLNeighbours::decreasePhiId(const short int phiid, const short int thetaid, const short int n)
325 {
326  short int previousPhiId = ((phiid - n < 0) ? m_crystalsPerRing[thetaid] + phiid - n : phiid - n); // "underflow"
327  return previousPhiId;
328 }
329 
330 // increase the phi id by "n" integers numbers (valid ids range from 0 to m_crystalsPerRing[thetaid] - 1)
331 short int ECLNeighbours::increasePhiId(const short int phiid, const short int thetaid, const short int n)
332 {
333  short int nextPhiId = (((phiid + n) > (m_crystalsPerRing[thetaid] - 1)) ? phiid + n - m_crystalsPerRing[thetaid] : phiid +
334  n); // "overflow"
335  return nextPhiId;
336 }
337 
338 std::vector<short int> ECLNeighbours::getPhiIdsInBetween(const short int phi0, const short int phi1, const short int theta)
339 {
340  std::vector<short int> phiList;
341  short int loop = phi0;
342 
343  while (1) {
344  phiList.push_back(loop);
345  if (loop == phi1) break;
346  loop = decreasePhiId(loop, theta, 1);
347  }
348 
349  return phiList;
350 }
351 
352 std::vector<short int> ECLNeighbours::getPhiIdsInBetweenC(const short int phi0, const short int phi1, const short int theta,
353  const int corners)
354 {
355  std::vector<short int> phiList;
356  if (phi0 == phi1) return phiList; // could be that there is only one crystal in this theta ring definition
357 
358  short int loop = decreasePhiId(phi0, theta, corners); // start at -n corners
359  if (loop == phi1) return phiList; // there will be no neighbours left in this phi ring after removing the first corners
360 
361  short int stop = increasePhiId(phi1, theta, corners); //stop at +n corners
362 
363  while (1) {
364  phiList.push_back(loop);
365  if (loop == stop) break;
366  loop = decreasePhiId(loop, theta, 1);
367  }
368 
369  return phiList;
370 }
371 
372 double ECLNeighbours::getDistance(const double alpha, const double R)
373 {
374  return 2.0 * R * TMath::Sin(alpha / 2.0);
375 }
376 
Belle2::Unit::cm
static const double cm
Standard units with the value = 1.
Definition: Unit.h:57
Belle2::ECL::ECLNeighbours::getPhiIdsInBetweenC
std::vector< short int > getPhiIdsInBetweenC(const short int phiInc, const short int phiDec, const short int theta, const int corners)
return a list of phi ids between two phi ids minus edges
Definition: ECLNeighbours.cc:352
Belle2::ECL::ECLNeighbours::initializeNC
void initializeNC(const int nneighbours, const int corners)
initialize the mask neighbour list, remove corners.
Definition: ECLNeighbours.cc:269
Belle2::ECL::ECLNeighbours::decreasePhiId
short int decreasePhiId(const short int phiid, const short int thetaid, const short int n)
return the previous phi id.
Definition: ECLNeighbours.cc:324
Belle2::ECL::ECLNeighbours::getDistance
double getDistance(const double alpha, const double R)
return the chord length between cells
Definition: ECLNeighbours.cc:372
Belle2::ECL::ECLGeometryPar::Instance
static ECLGeometryPar * Instance()
Static method to get a reference to the ECLGeometryPar instance.
Definition: ECLGeometryPar.cc:151
Belle2::ECL::ECLNeighbours::ECLNeighbours
ECLNeighbours(const std::string &neighbourDef, const double par)
Constructor: Fix number of neighbours ("N") in the seed theta ring, fraction cross ("F"),...
Definition: ECLNeighbours.cc:29
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ECL::ECLNeighbours::~ECLNeighbours
~ECLNeighbours()
Destructor.
Definition: ECLNeighbours.cc:79
Belle2::ECL::ECLNeighbours::m_neighbourMapTemp
std::vector< std::vector< short int > > m_neighbourMapTemp
temporary list of list of neighbour cids.
Definition: ECLNeighbours.h:59
Belle2::ECL::ECLNeighbours::initializeF
void initializeF(const double fraction)
initialize the fractional cross neighbour list.
Definition: ECLNeighbours.cc:124
Belle2::ECL::ECLNeighbours::initializeN
void initializeN(const int nneighbours)
initialize the mask neighbour list.
Definition: ECLNeighbours.cc:223
Belle2::ECL::ECLNeighbours::increasePhiId
short int increasePhiId(const short int phiid, const short int thetaid, const short int n)
return the next phi id.
Definition: ECLNeighbours.cc:331
Belle2::ECL::ECLNeighbours::m_crystalsPerRing
const short m_crystalsPerRing[69]
Number of crystals in each theta ring.
Definition: ECLNeighbours.h:62
Belle2::ECL::ECLGeometryPar
The Class for ECL Geometry Parameters.
Definition: ECLGeometryPar.h:45
Belle2::ECL::ECLNeighbours::m_neighbourMap
std::vector< std::vector< short int > > m_neighbourMap
list of list of neighbour cids.
Definition: ECLNeighbours.h:56
Belle2::ECL::ECLNeighbours::getNeighbours
const std::vector< short int > & getNeighbours(short int cid) const
Return the neighbours for a given cell ID.
Definition: ECLNeighbours.cc:318
Belle2::ECL::ECLNeighbours::getPhiIdsInBetween
std::vector< short int > getPhiIdsInBetween(const short int phiInc, const short int phiDec, const short int theta)
return a list of phi ids between two phi ids
Definition: ECLNeighbours.cc:338
Belle2::ECL::ECLNeighbours::initializeR
void initializeR(const double radius)
initialize the radius neighbour list.
Definition: ECLNeighbours.cc:84