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