Belle II Software  release-06-01-15
ECLGeometryPar.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 #include <ecl/geometry/ECLGeometryPar.h>
10 #include <framework/logging/Logger.h>
11 
12 #include <G4VTouchable.hh>
13 #include <G4PhysicalVolumeStore.hh>
14 #include <G4NavigationHistory.hh>
15 #include <G4Transform3D.hh>
16 #include <G4Point3D.hh>
17 #include <G4Vector3D.hh>
18 #include <iomanip>
19 
20 using namespace std;
21 using namespace Belle2;
22 using namespace ECL;
23 
24 ECLGeometryPar* ECLGeometryPar::m_B4ECLGeometryParDB = 0;
25 
26 class Mapping_t {
27 public:
28  static void Mapping(int id, int& ThetaId, int& PhiId)
29  {
30  ThetaId = m_Theta[((unsigned int)id) >> 4];
31  PhiId = id - m_dTheta[ThetaId] * 16 - ThetaId * 128;
32  }
33 
34  static void Mapping(int id, int& ThetaId, int& PhiId, int& nrep, int& indx)
35  {
36  Mapping(id, ThetaId, PhiId);
37 
38  int off = m_offsets[ThetaId];
39  int i = m_tbl[ThetaId];
40 
41  int r = m_recip[i];
42  int d = m_denom[i];
43 
44  nrep = (PhiId * r) >> m_RECIPROCAL_SHIFT;
45  indx = off + (PhiId - nrep * d);
46  }
47 
48  static int CellID(int ThetaId, int PhiId)
49  {
50  return PhiId + m_dTheta[ThetaId] * 16 + ThetaId * 128;
51  }
52 
53  static int Offset(int ThetaId)
54  {
55  return m_dTheta[ThetaId] + ThetaId * 8;
56  }
57 
58  static int Indx2ThetaId(int indx)
59  {
60  return m_Theta[indx];
61  }
62 
63  static int ThetaId2NCry(int ThetaId) // Theta Id to the number of crystals @ this Id
64  {
65  return m_denom[m_tbl[ThetaId]];
66  }
67 
68 private:
69  static const char m_dTheta[69];
70  static const unsigned char m_Theta[546], m_tbl[69], m_offsets[69];
71 
72  static const unsigned char m_RECIPROCAL_SHIFT = 16;
73  static const unsigned int m_recip[5], m_denom[5];
74 };
75 
76 const unsigned char Mapping_t::m_Theta[546] = {
77  0, 0, 0, 1, 1, 1,
78  2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
79  5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
80  8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
81  11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12,
82 
83  13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15,
84  16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18,
85  19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21,
86  22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24,
87  25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
88  28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30,
89  31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, 33,
90  34, 34, 34, 34, 34, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 36,
91  37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39,
92  40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42,
93  43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45,
94  46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48,
95  49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51,
96  52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54,
97  55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57,
98  58, 58, 58, 58, 58, 58, 58, 58, 58,
99 
100  59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60,
101  61, 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62,
102  63, 63, 63, 63, 63, 63, 64, 64, 64, 64, 64, 64,
103  65, 65, 65, 65, 65, 65,
104  66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68
105 };
106 
107 const char Mapping_t::m_dTheta[69] = {
108  0, -5, -10, -14, -18, -22, -24, -26, -28, -30, -32, -34, -33, // forward
109 
110  -32, -31, -30, -29, -28, -27, -26, -25, -24,
111  -23, -22, -21, -20, -19, -18, -17, -16, -15,
112  -14, -13, -12, -11, -10, -9, -8, -7, -6,
113  -5, -4, -3, -2, -1, 0, 1, 2, 3,
114  4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
115 
116  14, 15, 16, 14, 12, 10, 8, 6, 2, -2 // backward
117 };
118 
119 const unsigned char Mapping_t::m_tbl[69] = { // pointer to the denominator/reciprocal arrays or how many crystals in a phi sector
120  1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, // forward
121 
122  0, 0, 0, 0, 0, 0, 0, 0, 0,
123  0, 0, 0, 0, 0, 0, 0, 0, 0,
124  0, 0, 0, 0, 0, 0, 0, 0, 0,
125  0, 0, 0, 0, 0, 0, 0, 0, 0,
126  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127 
128  4, 4, 3, 3, 3, 3, 3, 2, 2, 2 // backward
129 };
130 
131 const unsigned char Mapping_t::m_offsets[69] = {
132  0, 3, 6, 10, 14, 18, 24, 30, 36, 42, 48, 54, 63, // forward
133 
134  132, 134, 136, 138, 140, 142, 144, 146, 148,
135  150, 152, 154, 156, 158, 160, 162, 164, 166,
136  168, 170, 172, 174, 176, 178, 180, 182, 184,
137  186, 188, 190, 192, 194, 196, 198, 200, 202,
138  204, 206, 208, 210, 212, 214, 216, 218, 220, 222,
139 
140  72, 81, 90, 96, 102, 108, 114, 120, 124, 128 // backward
141 };
142 
143 #define pack(x) ((1<<Mapping_t::m_RECIPROCAL_SHIFT)/x+1)
144 const unsigned int Mapping_t::m_recip[] = {pack(2), pack(3), pack(4), pack(6), pack(9)};
145 const unsigned int Mapping_t::m_denom[] = { (2), (3), (4), (6), (9)};
146 #undef pack
147 
148 
149 ECLGeometryPar* ECLGeometryPar::Instance()
150 {
151  if (!m_B4ECLGeometryParDB) m_B4ECLGeometryParDB = new ECLGeometryPar();
152  return m_B4ECLGeometryParDB;
153 }
154 
155 ECLGeometryPar::ECLGeometryPar()
156 {
157  clear();
158  // delay crystal positions fetching to a moment when it actually needed and geometry is already built
159  // read();
160 }
161 
162 ECLGeometryPar::~ECLGeometryPar()
163 {
164  if (m_B4ECLGeometryParDB) {
165  delete m_B4ECLGeometryParDB;
166  B2DEBUG(150, "m_B4ECLGeometryParDB deleted ");
167  }
168  if (m_ECLForwardGlobalT) delete m_ECLForwardGlobalT;
169  if (m_ECLBarrelGlobalT) delete m_ECLBarrelGlobalT;
170  if (m_ECLBackwardGlobalT) delete m_ECLBackwardGlobalT;
171 }
172 
173 void ECLGeometryPar::clear()
174 {
175  m_ini_cid = -1;
176  mPar_cellID = 0;
177  mPar_thetaID = 0;
178  mPar_phiID = 0;
179 }
180 
181 // There is no way to get world coordinates of a local point of a physical volume in Geant.
182 // The only way to check geometry is to trace particle and check volumes it crosses.
183 // Here particle gun parameters are produced to check crystal positions with the center @ r0 and direction n
184 void ParticleGunParameters(const G4String& comment, const G4ThreeVector& n, const G4ThreeVector& r0, double dphi)
185 {
186  cout << comment << endl;
187  cout << "Center position = " << r0 << ", Direction = " << n << endl;
188  // closest point to z-axis
189  double t = -(n.z() * r0.z() - n * r0) / (n.z() * n.z() - n * n);
190  G4ThreeVector r = n * t + r0;
191  cout << "Closest point to z-axis = " << r << endl; // at the moment I do not see tilt in phi
192  const double r2d = 180 / M_PI;
193  double th = r2d * n.theta();
194  double phi = r2d * n.phi();
195  double z = r.z();
196  dphi *= r2d;
197  cout << " 'thetaParams': [" << th << ", " << th << "]," << endl;
198  cout << " 'phiParams': [" << phi << "+0*" << dphi << ", " << phi << "+0*" << dphi << "]," << endl;
199  cout << " 'zVertexParams': [" << z << ", " << z << "]" << endl;
200 }
201 
202 G4Transform3D getT(const G4VPhysicalVolume& v)
203 {
204  return G4Transform3D(v.GetObjectRotationValue(), v.GetObjectTranslation());
205 }
206 
207 G4Transform3D getT(const G4String& n)
208 {
209  G4PhysicalVolumeStore* store = G4PhysicalVolumeStore::GetInstance();
210  // int N = store->size();
211  // cout<<N<<endl;
212  // for(int i=0;i<N;i++){
213  // G4VPhysicalVolume *vv = (*store)[i];
214  // if(vv->GetName()==n){
215  // cout<<i<<" "<<vv->GetName()<<" "<<vv->GetMultiplicity()<<" "<<vv->GetCopyNo()<<endl;
216  // G4PVReplica *r = dynamic_cast<G4PVReplica*>(vv);
217  // if(r) cout<<"Instance = "<<r->GetInstanceID()<<endl;
218  // }
219  // }
220 
221  G4VPhysicalVolume* v = store->GetVolume(n);
222  return getT(*v);
223 }
224 
225 void print_trans(const G4Transform3D& t)
226 {
227  for (int i = 0; i < 4; i++) {
228  for (int j = 0; j < 3; j++)
229  cout << t(j, i) << " ";
230  cout << endl;
231  }
232 }
233 
234 void ECLGeometryPar::read()
235 {
236  m_crystals.clear();
237  m_crystals.reserve(46 * 2 + 132); // 10752 bytes
238 
239  // Endcap sectors are rotated since behaviour of G4Replica class. It
240  // requires a physical volume during phi replication to be symmetric
241  // around phi=0. So we need to rotate it by -((2*pi)/16)/2 angle at the
242  // geometry description are return back here.
243 
244  G4Point3D p0(0, 0, 0); G4Vector3D v0(0, 0, 1);
245 
246  {
247  m_ECLForwardGlobalT = new G4Transform3D(getT("ECLForwardPhysical"));
248  G4Transform3D T = getT("ECLForwardCrystalSectorPhysical_1");
249  G4String tnamef("ECLForwardWrappedCrystal_Physical_");
250  for (int i = 0; i < 72; i++) {
251  G4String vname(tnamef); vname += to_string(i);
252  G4Transform3D cT = T * getT(vname);
253  CrystalGeom_t c = {cT * p0, cT * v0};
254  m_crystals.push_back(c);
255  // G4cout << i << " " << c.pos << " " << c.dir << G4endl;
256  }
257  }
258 
259  {
260  m_ECLBackwardGlobalT = new G4Transform3D(getT("ECLBackwardPhysical"));
261  G4Transform3D T = getT("ECLBackwardCrystalSectorPhysical_0");
262  G4String tnamef("ECLBackwardWrappedCrystal_Physical_");
263  for (int i = 0; i < 60; i++) {
264  G4String vname(tnamef); vname += to_string(i);
265  G4Transform3D cT = T * getT(vname);
266  CrystalGeom_t c = {cT * p0, cT * v0};
267  m_crystals.push_back(c);
268  // G4cout << i << " " << c.pos << " " << c.dir << G4endl;
269  }
270  }
271 
272  {
273  // get barrel sector (between two septums) transformation
274 
275  // extract global barrel movements assuming we know transformation of the sector in axial symmetric situation
276  m_ECLBarrelGlobalT = new G4Transform3D(getT("ECLBarrelSectorPhysical_0") * G4RotateZ3D(M_PI / 2));
277  G4Transform3D Ts = G4RotateZ3D(-M_PI / 2);
278  // since barrel sector is symmetric around phi=0 we need to
279  // translate crystal with negative phi back to positive rotating
280  // crystal position by (2*M_PI/72) angle
281  G4Transform3D Ts1 = G4RotateZ3D(M_PI / 36) * Ts;
282 
283  G4String tname("ECLBarrelWrappedCrystal_Physical_");
284  for (int i = 0; i < 2 * 46; i++) {
285  G4String vname(tname); vname += to_string(i);
286  G4Transform3D cT = ((i % 2) ? Ts1 : Ts) * getT(vname);
287  CrystalGeom_t c = {cT * p0, cT * v0};
288  m_crystals.push_back(c);
289  // G4cout << i << " " << c.pos << " " <<c.dir<<G4endl;
290  }
291  }
292 
293  B2DEBUG(150, "ECLGeometryPar::read() initialized with " << m_crystals.size() << " crystals.");
294 }
295 
296 template <int n>
297 void sincos(const double* ss, int iphi, double& s, double& c)
298 {
299  int n4 = n / 4;
300  int iq = iphi / n4; // quadrant
301  int is = iphi % n4;
302  int ic = n4 - is;
303  if (iq & 1) {int t = is; is = ic; ic = t;}
304  double ls = ss[is];
305  double lc = ss[ic];
306  // check quadrant and assign sign bit accordingly
307  if ((((0 << 0) + (0 << 1) + (1 << 2) + (1 << 3)) >> iq) & 1) ls = -ls;
308  if ((((0 << 0) + (1 << 1) + (1 << 2) + (0 << 3)) >> iq) & 1) lc = -lc;
309  s = ls;
310  c = lc;
311 }
312 
313 const double ss72[] = {
314  0.0000000000000000000000,
315  0.0871557427476581735581,
316  0.1736481776669303488517,
317  0.2588190451025207623489,
318  0.3420201433256687330441,
319  0.4226182617406994361870,
320  0.5000000000000000000000,
321  0.5735764363510460961080,
322  0.6427876096865393263226,
323  0.7071067811865475244008,
324  0.7660444431189780352024,
325  0.8191520442889917896845,
326  0.8660254037844386467637,
327  0.9063077870366499632426,
328  0.9396926207859083840541,
329  0.9659258262890682867497,
330  0.9848077530122080593667,
331  0.9961946980917455322950,
332  1.0000000000000000000000
333 };
334 
335 const double ss16[] = {
336  0.0000000000000000000000,
337  0.3826834323650897717285,
338  0.7071067811865475244008,
339  0.9238795325112867561282,
340  1.0000000000000000000000
341 };
342 
343 void ECLGeometryPar::InitCrystal(int cid)
344 {
345  if (m_crystals.size() == 0) read();
346  int thetaid, phiid, nreplica, indx;
347  Mapping_t::Mapping(cid, thetaid, phiid, nreplica, indx);
348  // cout<<cid<<" "<<thetaid<<" "<<phiid<<" "<<nreplica<<" "<<indx<<endl;
349  const CrystalGeom_t& t = m_crystals[indx];
350  double s, c;
351  if (indx > 131)
352  sincos<72>(ss72, nreplica, s, c);
353  else
354  sincos<16>(ss16, nreplica, s, c);
355 
356  G4Transform3D* T;
357  if (cid < 1152) {
358  T = m_ECLForwardGlobalT;
359  } else if (cid < 7776) {
360  T = m_ECLBarrelGlobalT;
361  } else {
362  T = m_ECLBackwardGlobalT;
363  c = -c;
364  }
365  double xp = c * t.pos.x() - s * t.pos.y();
366  double yp = s * t.pos.x() + c * t.pos.y();
367  // m_current_crystal.pos.set(xp, yp, t.pos.z());
368 
369  double xv = c * t.dir.x() - s * t.dir.y();
370  double yv = s * t.dir.x() + c * t.dir.y();
371  // m_current_crystal.dir.set(xv, yv, t.dir.z());
372 
373  m_current_crystal.pos = (1 / CLHEP::cm) * (*T * G4Point3D(xp, yp, t.pos.z()));
374  m_current_crystal.dir = *T * G4Vector3D(xv, yv, t.dir.z());
375 
376  // cout<<t.pos<<" "<<t.dir<<" "<<m_current_crystal.pos<<" "<<m_current_crystal.dir<<endl;
377  m_ini_cid = cid;
378 }
379 
380 int ECLGeometryPar::GetCellID(int ThetaId, int PhiId)
381 {
382  return Mapping_t::CellID(ThetaId, PhiId);
383 }
384 
385 void ECLGeometryPar::Mapping(int cid)
386 {
387  mPar_cellID = cid;
388  Mapping_t::Mapping(mPar_cellID, mPar_thetaID, mPar_phiID);
389 }
390 
391 int ECLGeometryPar::TouchableDiodeToCellID(const G4VTouchable* touch)
392 {
393  return TouchableToCellID(touch);
394 }
395 
396 int ECLGeometryPar::TouchableToCellID(const G4VTouchable* touch)
397 {
398  // touch->GetCopyNumber() is a virtual call, avoid it by using
399  // directly G4NavigationHistory so we will have only one virtual
400  // call instead of three here
401  const G4NavigationHistory* h = touch->GetHistory();
402  int hd = h->GetDepth();
403  int i1 = h->GetReplicaNo(hd - 1); // index of each volume is set at physical volume creation
404  int i2 = h->GetReplicaNo(hd - 2); // go up in volume hierarchy
405 
406  int ThetaId = Mapping_t::Indx2ThetaId(i1);
407  int NCryst = Mapping_t::ThetaId2NCry(ThetaId); // the number of crystals in a sector at given ThetaId
408  int Offset = Mapping_t::Offset(ThetaId);
409 
410  int ik = i1 - Offset;
411  int PhiId;
412  if (NCryst == 2) {
413  PhiId = (i2 - (ik % 2)) * NCryst + ik;
414  if (PhiId < 0) PhiId += 144;
415  } else {
416  int i3 = h->GetReplicaNo(hd - 3); // go up in volume hierarchy
417  if (ThetaId < 13)
418  PhiId = (i2 + 2 * i3) * NCryst + ik;
419  else {
420  // int tt[] = {3,2,1,0,7,6,5,4};
421  // if(i3r!=tt[i3]){
422  // cout<<i3<<" "<<i3<<" "<<tt[i3]<<endl;
423  // exit(0);
424  // }
425  int i3r = (3 - (i3 % 4)) + 4 * (i3 / 4);
426  PhiId = (2 * i3r + (1 - i2)) * NCryst + ik;
427  }
428  }
429 
430  int cellID = Offset * 16 + PhiId;
431  // cout<<"ECLGeometryPar::TouchableToCellID "<<h->GetVolume(hd-1)->GetName()<<" "<<i1<<" "<<i2<<" "<<h->GetReplicaNo(hd - 3)<<" "<<ThetaId<<" "<<NCryst<<" "<<Offset<<" "<<PhiId<<endl;
432 
433  // test of the position and direction of crystal
434  if (0) {
435  G4AffineTransform t = h->GetTopTransform();
436  G4ThreeVector o(0, 0, 0), n(0, 0, 1);
437  G4ThreeVector ro = t.Inverse().TransformPoint(o);
438  G4ThreeVector rn = t.Inverse().TransformAxis(n);
439 
440  InitCrystal(cellID);
441  ro *= 1 / CLHEP::cm;
442 
443  G4ThreeVector dr = m_current_crystal.pos - ro, dn = m_current_crystal.dir - rn;
444  if (dr.mag() > 1e-10 || dn.mag() > 1e-10) {
445  cout << "Missmatch " << h->GetVolume(hd - 1)->GetName() << " " << cellID << " " << ThetaId << " " << PhiId << " " << NCryst << " "
446  << hd << " " << i2 << " " << i1 << " " << m_current_crystal.pos << " " << ro << " " << rn << " " << dr << " " << dn << endl;
447 
448  for (int i = 0; i < 144; i++) {
449  int ci = Mapping_t::CellID(ThetaId, i);
450  InitCrystal(ci);
451  dr = m_current_crystal.pos - ro;
452  if (dr.mag() < 1e-10) cout << "best PhiId = " << i << endl;
453  }
454  }
455  }
456  return cellID;
457 }
458 
459 int ECLGeometryPar::ECLVolumeToCellID(const G4VTouchable* touch)
460 {
461  int depth = touch->GetHistoryDepth();
462  if ((depth != 3) && (depth != 5)) {
463  B2WARNING("ECLGeometryPar::ECLVolumeToCellID: History depth = " << depth << " is out of range: should be 3 or 5.");
464  return -1;
465  }
466  const G4String& vname = touch->GetVolume()->GetName();
467  std::size_t pos0 = vname.find("lv_forward_crystal_");
468  std::size_t pos1 = vname.find("lv_barrel_crystal_");
469  std::size_t pos2 = vname.find("lv_backward_crystal_");
470  if (pos0 == string::npos && pos1 == string::npos && pos2 == string::npos) {
471  B2WARNING("ECLGeometryPar::ECLVolumeToCellID: Volume name does not match pattern. NAME=" << vname);
472  return -1;
473  }
474  return TouchableToCellID(touch);
475 }
476 
477 double ECLGeometryPar::time2sensor(int cid, const G4ThreeVector& hit_pos)
478 {
479  if (cid != m_ini_cid) InitCrystal(cid);
480  double z = 15. - (hit_pos - m_current_crystal.pos) * m_current_crystal.dir; // position along the vector of crystal axis
481  double dt = 6.05 + z * (0.0749 - z * 0.00112); // flight time to diode sensor in nanoseconds
482  return dt;
483 }
484 
485 EclNbr::EclNbr() :
486  m_nbrs(*new std::vector< Identifier >)
487 {
488  mNbr_cellID = 0;
489  mNbr_thetaID = 0;
490  mNbr_phiID = 0;
491 }
492 
493 EclNbr::EclNbr(const EclNbr& aNbr) :
494  m_nbrs(*new std::vector< Identifier > (aNbr.m_nbrs)) ,
495  m_nearSize(aNbr.m_nearSize)
496 {
497  mNbr_cellID = 0;
498  mNbr_thetaID = 0;
499  mNbr_phiID = 0;
500 }
501 
503  const std::vector< Identifier >& aNbrs ,
504  const std::vector< Identifier >::size_type aNearSize
505 ) :
506  m_nbrs(*new std::vector< Identifier > (aNbrs)) ,
507  m_nearSize(aNearSize)
508 {
509  // sort vector separately for near, nxt-near nbrs
510  std::sort(m_nbrs.begin() , m_nbrs.begin() + aNearSize , std::less< Identifier >()) ;
511  std::sort(m_nbrs.begin() + aNearSize , m_nbrs.end() , std::less< Identifier >()) ;
512 }
513 
515 {
516  delete &m_nbrs ;
517 }
518 std::ostream& operator<<(std::ostream& os, const EclNbr& aNbr)
519 {
520  os << "N(" ;
521  unsigned short i(0) ;
522  for (std::vector< EclNbr::Identifier >::const_iterator
523  iNbr(aNbr.nbrs().begin()) ;
524  iNbr != aNbr.nbrs().end() ; ++iNbr) {
525  ++i;
526  if (iNbr != aNbr.nbrs().begin() && i != aNbr.nearSize() + 1) os << "," ;
527  if (i == aNbr.nearSize() + 1) os << "|" ;
528  os << std::setw(4) << (*iNbr) ;
529  }
530  os << ")" ;
531  return os ;
532 }
533 
534 
536 {
537  unsigned short Nri(0) ;
538  cout << "(";
539  for (std::vector< EclNbr::Identifier >::const_iterator
540  iNbr(m_nbrs.begin()) ;
541  iNbr != m_nbrs.end() ; ++iNbr) {
542  ++Nri;
543  if (iNbr != m_nbrs.begin() && Nri != m_nearSize + 1) cout << "," ;
544  if (Nri == m_nearSize + 1) cout << "|" ;
545  cout << std::setw(4) << (*iNbr) ;
546  }
547  cout << ")" << endl;
548 }
549 //
550 // assignment operators
551 
552 
554 {
555  if (this != &aNbr) {
556  mNbr_cellID = aNbr.mNbr_cellID;
557  mNbr_thetaID = aNbr.mNbr_thetaID;
558  mNbr_phiID = aNbr.mNbr_phiID;
559 
560  m_nbrs = aNbr.m_nbrs ;
561  m_nearSize = aNbr.m_nearSize ;
562  }
563  return *this ;
564 }
565 
566 //
567 // member functions
568 //
569 
570 //
571 // const member functions
572 //
573 
574 const std::vector< EclNbr::Identifier >&
576 {
577  return m_nbrs ;
578 }
579 
580 const std::vector< EclNbr::Identifier >::const_iterator
582 {
583  return m_nbrs.begin() ;
584 }
585 
586 const std::vector< EclNbr::Identifier >::const_iterator
588 {
589  return m_nbrs.begin() + m_nearSize ;
590 }
591 
592 const std::vector< EclNbr::Identifier >::const_iterator
594 {
595  return m_nbrs.begin() + m_nearSize ;
596 }
597 
598 const std::vector< EclNbr::Identifier >::const_iterator
600 {
601  return m_nbrs.end() ;
602 }
603 
604 std::vector< EclNbr::Identifier >::size_type
606 {
607  return m_nearSize ;
608 }
609 
610 std::vector< EclNbr::Identifier >::size_type
612 {
613  return (m_nbrs.size() - m_nearSize) ;
614 }
615 
616 
617 int EclNbr::GetCellID(int ThetaId, int PhiId)
618 {
619  mNbr_cellID = Mapping_t::CellID(ThetaId, PhiId);
620  mNbr_thetaID = ThetaId;
621  mNbr_phiID = PhiId ;
622  return mNbr_cellID;
623 }
624 
625 void EclNbr::Mapping(int cid)
626 {
627  mNbr_cellID = cid;
628  Mapping_t::Mapping(mNbr_cellID, mNbr_thetaID, mNbr_phiID);
629 }
630 
631 EclNbr
633 {
634  // generate nbr lists. always easier here to work with theta-phi
635 
636  const int cellID = aCellId;
637  Mapping(cellID);
638  const int thetaId = GetThetaID();
639  const int phiId = GetPhiID();
640  std::vector< EclNbr::Identifier >::size_type nearSize(0);
641  std::vector< EclNbr::Identifier > vNbr;
642 
643  vNbr.reserve(24) ; // except for extreme endcaps, always 24
644 
645  int t00 = thetaId;
646  int tm1 = thetaId - 1;
647  int tm2 = thetaId - 2;
648  int tp1 = thetaId + 1;
649  int tp2 = thetaId + 2;
650 
651  if (aCellId > 1151 && aCellId < 7776) {
652  // barrel
653  //
654  // 12 13 14 15 16 ^ theta
655  // 11 2 3 4 17 |
656  // 10 1 0 5 18 +--> phi X--+ view from inside
657  // 9 8 7 6 19 | (foot pointing e- dir)
658  // 24 23 22 21 20 Z
659  int f00 = phiId;
660  int fm1 = (phiId + 143) % 144;
661  int fp1 = (phiId + 1) % 144;
662  int fm2 = (phiId + 142) % 144;
663  int fp2 = (phiId + 2) % 144;
664 
665  vNbr.push_back(GetCellID(t00 , fm1));
666  vNbr.push_back(GetCellID(tp1 , fm1));
667  vNbr.push_back(GetCellID(tp1 , f00));
668  vNbr.push_back(GetCellID(tp1 , fp1));
669  vNbr.push_back(GetCellID(t00 , fp1));
670  vNbr.push_back(GetCellID(tm1 , fp1));
671  vNbr.push_back(GetCellID(tm1 , f00));
672  vNbr.push_back(GetCellID(tm1 , fm1));
673 
674  nearSize = vNbr.size();
675 
676  vNbr.push_back(GetCellID(tm1 , fm2));
677  vNbr.push_back(GetCellID(t00 , fm2));
678  vNbr.push_back(GetCellID(tp1 , fm2));
679  vNbr.push_back(GetCellID(tp2 , fm2));
680  vNbr.push_back(GetCellID(tp2 , fm1));
681  vNbr.push_back(GetCellID(tp2 , f00));
682  vNbr.push_back(GetCellID(tp2 , fp1));
683  vNbr.push_back(GetCellID(tp2 , fp2));
684  vNbr.push_back(GetCellID(tp1 , fp2));
685  vNbr.push_back(GetCellID(t00 , fp2));
686  vNbr.push_back(GetCellID(tm1 , fp2));
687  vNbr.push_back(GetCellID(tm2 , fp2));
688  vNbr.push_back(GetCellID(tm2 , fp1));
689  vNbr.push_back(GetCellID(tm2 , f00));
690  vNbr.push_back(GetCellID(tm2 , fm1));
691  vNbr.push_back(GetCellID(tm2 , fm2));
692  }//if( aCellId > 1152 && aCellId < 7777 )
693  else {
694  // endcap -- not always 24!
695  int n00 = 1000;
696  int np1 = 1000;
697  int np2 = 1000;
698  int nm1 = 1000;
699  int nm2 = 1000;
700  if (aCellId < 1153) { // forward
701  const EclIdentifier mPerRingForward[]
702  = { 48, 48, 64, 64, 64, 96, 96, 96, 96, 96, 96, 144, 144, 144, 144 };
703  if (thetaId > 1) nm2 = mPerRingForward[ thetaId - 2 ];
704  if (thetaId > 0) nm1 = mPerRingForward[ thetaId - 1 ];
705  n00 = mPerRingForward[ thetaId ];
706  np1 = mPerRingForward[ thetaId + 1 ];
707  np2 = mPerRingForward[ thetaId + 2 ];
708  } else { // backward
709  const EclIdentifier mPerRingBackward[]
710  = { 64, 64, 64, 96, 96, 96, 96, 96, 144, 144, 144, 144 };
711  if (thetaId < 67) np2 = mPerRingBackward[ 66 - thetaId ];
712  if (thetaId < 68) np1 = mPerRingBackward[ 67 - thetaId ];
713  n00 = mPerRingBackward[ 68 - thetaId ];
714  nm1 = mPerRingBackward[ 69 - thetaId ];
715  nm2 = mPerRingBackward[ 70 - thetaId ];
716  }
717  // f-- are phi's, t-- are thetas
718  // all calculations should be integer arith - pcs
719  // f(th,phi)
720  // criterion: center -> next bin
721  int f0000 = phiId;
722  int fp100 = (f0000 * np1 + np1 / 2) / n00;
723  int fp200 = (f0000 * np2 + np2 / 2) / n00;
724  int fm100 = (f0000 * nm1 + nm1 / 2) / n00;
725  int fm200 = (f0000 * nm2 + nm2 / 2) / n00;
726 
727  int f00m1 = (f0000 + n00 - 1) % n00; // should be exact
728  int f00m2 = (f0000 + n00 - 2) % n00;
729  int f00p1 = (f0000 + 1) % n00;
730  int f00p2 = (f0000 + 2) % n00;
731 
732  int fp1m1 = (fp100 + np1 - 1) % np1;
733  int fp1m2 = (fp100 + np1 - 2) % np1;
734  int fp1p1 = (fp100 + 1) % np1;
735  int fp1p2 = (fp100 + 2) % np1;
736 
737  int fm1m1 = (fm100 + nm1 - 1) % nm1;
738  int fm1m2 = (fm100 + nm1 - 2) % nm1;
739  int fm1p1 = (fm100 + 1) % nm1;
740  int fm1p2 = (fm100 + 2) % nm1;
741 
742  int fp2m1 = (fp200 + np2 - 1) % np2;
743  int fp2m2 = (fp200 + np2 - 2) % np2;
744  int fp2p1 = (fp200 + 1) % np2;
745  int fp2p2 = (fp200 + 2) % np2;
746 
747  int fm2m1 = (fm200 + nm2 - 1) % nm2;
748  int fm2m2 = (fm200 + nm2 - 2) % nm2;
749  int fm2p1 = (fm200 + 1) % nm2;
750  int fm2p2 = (fm200 + 2) % nm2;
751  int delta = n00 / 16;
752 // int sector = phiId/delta; // 0..15
753  int nth = phiId % delta;
754 
755  switch (thetaId) {
756  case 0:
757  if (nth == 1)
758  fp2p2 = 1000;
759  break;
760  case 1:
761  if (nth == 1) {
762  fp2p2 = 1000;
763  fp1p2 = fp1p1;
764  fp1p1 = 1000;
765  }
766  break;
767  case 2:
768  if ((nth == 0) || (nth == 1)) {
769  fm2p2 = 1000;
770  fm1p2 = fm1p1;
771  fm1p1 = 1000;
772  } else if ((nth == 2) || (nth == 3)) {
773  fm2m2 = 1000;
774  fm1m2 = fm1m1;
775  fm1m1 = 1000;
776  }
777  break;
778  case 3:
779  if ((nth == 0) || (nth == 3)) {
780  fm2p2 = fm2m2 = 1000;
781  } else if (nth == 1) {
782  fm2p2 = 1000;
783  } else if (nth == 2) {
784  fm2m2 = 1000;
785  }
786  break;
787  case 5:
788  if ((nth == 2) || (nth == 5)) {
789  fm2m2 = 1000;
790  fm1m2 = fm1m1;
791  fm1m1 = 1000;
792  } else {
793  fm2p2 = 1000;
794  fm1p2 = fm1p1;
795  fm1p1 = 1000;
796  }
797  break;
798  case 6:
799  fm2p2 = 1000;
800  if ((nth == 0) || (nth == 2) || (nth == 3) || (nth == 5)) {
801  fm2m2 = 1000;
802  }
803  break;
804  case 11:
805  if ((nth == 2) || (nth == 5) || (nth == 8)) {
806  fm2m2 = 1000;
807  fm1m2 = fm1m1;
808  fm1m1 = 1000;
809  } else {
810  fm2p2 = 1000;
811  fm1p2 = fm1p1;
812  fm1p1 = 1000;
813  }
814  break;
815  case 12:
816  fm2p2 = 1000;
817  if ((nth == 0) || (nth == 2) || (nth == 3)
818  || (nth == 5) || (nth == 6) || (nth == 8))
819  fm2m2 = 1000;
820  break;
821  case 65:
822  if ((nth == 2) || (nth == 5)) {
823  fp2m2 = 1000;
824  fp1m2 = fp1m1;
825  fp1m1 = 1000;
826  } else {
827  fp2p2 = 1000;
828  fp1p2 = fp1p1;
829  fp1p1 = 1000;
830  }
831  break;
832  case 64:
833  fp2p2 = 1000;
834  if ((nth == 0) || (nth == 2) || (nth == 3) || (nth == 5))
835  fp2m2 = 1000;
836  break;
837  case 60:
838  if ((nth == 2) || (nth == 5) || (nth == 8)) {
839  fp2m2 = 1000;
840  fp1m2 = fp1m1;
841  fp1m1 = 1000;
842  } else {
843  fp2p2 = 1000;
844  fp1p2 = fp1p1;
845  fp1p1 = 1000;
846  }
847  break;
848  case 59:
849  fp2p2 = 1000;
850  if ((nth == 0) || (nth == 2) || (nth == 3) || (nth == 5)
851  || (nth == 6) || (nth == 8))
852  fp2m2 = 1000;
853  break;
854  }//switch
855 
856  // insert near-nbrs
857  vNbr.push_back(GetCellID(t00, f00m1));
858  vNbr.push_back(GetCellID(t00, f00p1));
859  if (nm1 < 999) {
860  vNbr.push_back(GetCellID(tm1 , fm100));
861  if (fm1m1 < 999)
862  vNbr.push_back(GetCellID(tm1 , fm1m1));
863  if (fm1p1 < 999)
864  vNbr.push_back(GetCellID(tm1 , fm1p1));
865  }
866  if (np1 < 999) {
867  vNbr.push_back(GetCellID(tp1 , fp100));
868  if (fp1m1 < 999)
869  vNbr.push_back(GetCellID(tp1 , fp1m1));
870  if (fp1p1 < 999)
871  vNbr.push_back(GetCellID(tp1 , fp1p1));
872  }
873  nearSize = vNbr.size() ;
874 
875  // now on to next-near neighbors
876  if (nm2 < 999) {
877  vNbr.push_back(GetCellID(tm2 , fm200));
878  if (fm2m1 < 999)
879  vNbr.push_back(GetCellID(tm2 , fm2m1));
880  if (fm2p1 < 999)
881  vNbr.push_back(GetCellID(tm2 , fm2p1));
882  if (fm2m2 < 999)
883  vNbr.push_back(GetCellID(tm2 , fm2m2));
884  if (fm2p2 < 999)
885  vNbr.push_back(GetCellID(tm2 , fm2p2));
886  }
887  if (nm1 < 999) {
888  if (fm1m2 < 999)
889  vNbr.push_back(GetCellID(tm1 , fm1m2));
890  if (fm1p2 < 999)
891  vNbr.push_back(GetCellID(tm1 , fm1p2));
892  }
893  vNbr.push_back(GetCellID(t00 , f00m2));
894  vNbr.push_back(GetCellID(t00 , f00p2));
895  if (np1 < 999) {
896  if (fp1m2 < 999)
897  vNbr.push_back(GetCellID(tp1, fp1m2));
898  if (fp1p2 < 999)
899  vNbr.push_back(GetCellID(tp1, fp1p2));
900  }
901  if (np2 < 999) {
902  vNbr.push_back(GetCellID(tp2, fp200));
903  if (fp2m1 < 999)
904  vNbr.push_back(GetCellID(tp2, fp2m1));
905  if (fp2p1 < 999)
906  vNbr.push_back(GetCellID(tp2, fp2p1));
907  if (fp2m2 < 999)
908  vNbr.push_back(GetCellID(tp2, fp2m2));
909  if (fp2p2 < 999)
910  vNbr.push_back(GetCellID(tp2, fp2p2));
911  }
912  }//else( aCellId > 1152 && aCellId < 7777 )
913  return
914  EclNbr(vNbr, nearSize);
915 }
The Class for ECL Geometry Parameters.
std::vector< Identifier >::size_type nextSize() const
get crystals nextSize
const std::vector< Identifier >::const_iterator nextEnd() const
get crystals nextEnd
EclNbr getNbr(const Identifier aCellId)
get crystals nbr
int GetPhiID()
Get Theta Id.
EclNbr()
Constructors and destructor.
int mNbr_thetaID
The Theta ID information.
std::vector< Identifier >::size_type m_nearSize
size of near brs
virtual ~EclNbr()
destructor
const std::vector< Identifier > & nbrs() const
get crystals nbrs
int mNbr_cellID
Get Phi Id.
const std::vector< Identifier >::const_iterator nearEnd() const
get crystals nearEnd
int mNbr_phiID
The Phi ID information.
void printNbr()
print crystals nbrs
void Mapping(int cid)
Mapping theta, phi Id.
int GetCellID(int ThetaId, int PhiId)
Get Cell Id.
const std::vector< Identifier >::const_iterator nearBegin() const
get crystals nearBegin
const std::vector< Identifier >::const_iterator nextBegin() const
get crystals nextBegin
EclIdentifier Identifier
constants, enums and typedefs
std::vector< Identifier >::size_type nearSize() const
get crystals nearSize
std::vector< Identifier > & m_nbrs
id of m_brs
int GetThetaID()
Get Cell Id.
EclNbr & operator=(const EclNbr &aNbr)
assignment operator(s)
std::ostream & operator<<(std::ostream &output, const IntervalOfValidity &iov)
TString rn()
Get random string.
Definition: tools.h:38
Abstract base class for different kinds of events.