EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicGeoMap.h
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicGeoMap.h
1 //
2 // AYK (ayk@bnl.gov), 2014/08/20
3 //
4 // EIC basic geometry map class;
5 //
6 
7 #include <TString.h>
8 #include <TObject.h>
9 
10 #ifndef _EIC_GEO_MAP_
11 #define _EIC_GEO_MAP_
12 
13 //
14 // It looks like ROOT streaming does not allow to save arrays 'arr[DIM]' where
15 // 'DIM' is a 64-bit variable (in other words '<typedef> *arr; //[DIM]' syntax
16 // assumes that 'DIM' is at most of UInt_t type); Ok, fine; not really needed
17 // for EicRoot implementation; so consider a mixed scheme:
18 //
19 // - packed GEANT hierarchy tree node indices are encoded as 32-bit;
20 // - internally routines pass 64-bit index where higher 32 bits are
21 // reserved for a map ID (which is an overkill, clear);
22 // - all the code however is written in such a way, that changing
23 // UGeantIndex_t to ULong64_t should in principle work (provided the above
24 // mentioned ROOT feature is fixed); NB: of course 32-bit mapping tables
25 // (and MC files produced using them) will not be backwards compatible;
26 // - if UGeantIndex_t ever becomes ULong64_t, one has a freedom to set
27 // _GEANT_INDEX_BIT_NUM_ to any number up to 63 (at least one bit is needed
28 // to encode MAP ID); for now _GEANT_INDEX_BIT_NUM_ is set to its max
29 // possible value: 32;
30 //
31 // - logical indices (group of 3D volumes, each of which can have XYZ mapping)
32 // have no this limitation and as of 2014/08/20 'mMappingTable' is converted
33 // to ULogicalIndex_t* (so 64 bit);
34 //
35 // - it is implicitely assumed, that single dimension indices (say X) can not
36 // exceed a 32-bit unsigned value; FIXME: may want to verify this;
37 //
38 
39 // So: 32-bit GEANT indices ...
40 typedef UInt_t UGeantIndex_t;
41 
42 // ... and 64-bit logical ones (packed together: group ID and XYZ);
43 typedef ULong64_t ULogicalIndex_t;
44 
45 // NB: once again, as long as mentioned above ROOT restriction is valid,
46 // _GEANT_INDEX_BIT_NUM_ '32';
47 #define _GEANT_INDEX_BIT_NUM_ 32
48 #define _GEANT_INDEX_BIT_MASK_ ((ULong64_t(0x1) << _GEANT_INDEX_BIT_NUM_) - 1)
49 // Bits remaining to encode map ID (so 32+32 split in internal routine arguments);
50 #define _SERVICE_BIT_NUM_ ((sizeof(ULong64_t) << 3) - _GEANT_INDEX_BIT_NUM_)
51 // Well, want this mask to be applied to values shifted to bit #0;
52 #define _SERVICE_BIT_MASK_ ((ULong64_t(0x1) << _SERVICE_BIT_NUM_) - 1)
53 
54 // Well, voluntary consider to allocate 16 highest bits for logical group encoding
55 // and remaining 48 bits for XYZ encoding; NB: in a few places in the code assume
56 // implicitely, that 1) _LOGICAL_GROUP_BIT_NUM_ and _LOGICAL_XYZ_BIT_NUM_ sum up to
57 // the bit count of UGeo_t, 2) group 8 bits are the highest ones (24..31);
58 #define _LOGICAL_GROUP_BIT_NUM_ 16
59 #define _LOGICAL_XYZ_BIT_NUM_ ((sizeof(ULogicalIndex_t) << 3) - _LOGICAL_GROUP_BIT_NUM_)
60 #define _LOGICAL_GROUP_NUM_MAX_ (ULogicalIndex_t(0x1) << (_LOGICAL_GROUP_BIT_NUM_))
61 // Again, want it to be applied to values shifted to bit #0;
62 #define _LOGICAL_GROUP_MASK_ (_LOGICAL_GROUP_NUM_MAX_-1)
63 
64 // Encountered in a few places -> create a separate #define;
65 #define _LOGICAL_INDEX_INVALID_ (~ULogicalIndex_t(0))
66 
67 template <typename T>
68 class EicBitMask: public TObject
69 {
70  public:
72  EicBitMask(unsigned maxEntryNum) {
73  ResetVars();
74 
75  // Well, the idea is that level entry may be skipped alltogether and will not
76  // contribute to the mapping table size; so 'mBitNum' and 'mBitMask' will stay 0;
77  if (!maxEntryNum) return;
78 
79  // Looks strange, but works; in principle could save a bit for maxEntryNum=1;
80  // do not mind to overcomplicate things though;
81  mBitNum = 1;
82  for(T value = maxEntryNum-1; value>>1; value >>= 1)
83  mBitNum++;
84 
85  SetMask();
86  };
88 
89  void ResetVars() { mBitNum = mShift = 0; mMask = 0; };
90 
91  void SetShift(unsigned shift) { mShift = shift;};
92  void SetBitNum(unsigned bitNum) { mBitNum = bitNum; SetMask(); };
93 
94  unsigned GetBitNum() const { return mBitNum;};
95  unsigned GetShift() const { return mShift; };
96  T GetBitMask() const { return mMask; };
97 
98  T GetMaskedBits(T value) const { return ((value >> mShift) & mMask); };
99 
100  private:
101  UInt_t mBitNum; // number of bits in this mask
102  UInt_t mShift; // shift of this level bit mask in the UGeantIndex_t-wide bit index
103  T mMask; // bit mask itself (bits [0..mBitNum-1], so offset to #0 bit
104 
105  void SetMask() { mMask = (T(0x1) << mBitNum) - 1;};
106 
108 };
109 
111 {
112  // Yes, no sense to complicate access for the master classes;
113  friend class EicGeoMap;
114  friend class EicGeoParData;
115 
116  public:
118  ~GeantVolumeLevel() { if (mBitMask) delete mBitMask; };
119 
120  const TString& GetVolumeName() const { return mVolumeName; };
123 
125  return mBitMask ? mBitMask->GetMaskedBits(value) : 0;
126  };
127 
128  private:
129  UGeantIndex_t mMaxEntryNum; // max number of identical volume copies on this level
130  TString mVolumeName; // GEANT volume name
131 
132  UInt_t mVolumeID;
133 
134  EicBitMask<UGeantIndex_t> *mBitMask; //-> bit mask parameters associated with this level
135 
137 };
138 
139 class EicGeoMap: public TObject
140 {
141  // Yes, simplify access for the master class and also hide few methods
142  // from the outside world;
143  friend class EicGeoParData;
144 
145  public:
147  mBirkConstant(0.0) {};
149 
150  unsigned GetGeantVolumeLevelNum() const { return mGeantVolumeLevels.size();};
151  const GeantVolumeLevel *GetGeantVolumeLevelPtr(unsigned volumeID) const {
152  return volumeID < mGeantVolumeLevels.size() ? mGeantVolumeLevels[volumeID] : 0;
153  };
154 
155  // Initialize next volume level;
156  int AddGeantVolumeLevel(const TString &volumeName, UGeantIndex_t maxEntryNum);
157 
158  bool IsMySignature(const unsigned lvIDs[]) const;
159 
160  const TString* GetBaseVolumePath() const { return &mBaseVolumePath; }
161  void AssignBaseVolumePath(const char *baseVolumePath) { mBaseVolumePath = baseVolumePath;};
162 
163  void SetSensitivityFlag(double birkConstant = 0.0) {
164  mBirkConstant = birkConstant;
165  mSensitivityFlag = true;
166  };
167  bool IsSensitive() const { return mSensitivityFlag; };
168 
169  // FIXME: consistency check is done in EicDigiHitProducer::ExtraInit() only;
170  // may want to implement it earlier (check volume existence with such name);
171  void SetSingleSensorContainerVolume(const char *singleSensorContainerVolumeName) {
172  mSingleSensorContainerVolumeName = TString(singleSensorContainerVolumeName);
173  };
174  const TString& GetSingleSensorContainerVolumeName() const {
176  };
177 
178  const TString* GetInnermostVolumeName() const {
179  return mGeantVolumeLevels.size() ? &GetGeantVolumeLevelPtr(0)->GetVolumeName() : 0;
180  };
181 
183  const ULogicalIndex_t *GetMappingTable() const { return mMappingTable; };
184 
185  double GetBirkConstant() const { return mBirkConstant; };
186 
187  private:
188  // Digitization procedure declares maps as sensitive based on their top-level
189  // volume name; may also want to assign Kb constant by hand;
190  bool mSensitivityFlag;
191  // Well, it is convenient to have a transient variable right in the mapping table;
192  double mBirkConstant;
193 
194  // TGeoVolume levels (including current - sensitive volume - level!)
195  // which uniquely characterize elementary sensitive node location in the geometry
196  // tree; for instance for endcap backward EMC (crystals) the sequence will be
197  // BemcQuadrant -> BemcTower -> BemcCrystal;
198  std::vector <GeantVolumeLevel*> mGeantVolumeLevels; // volume names and other service info
199 
200  // Calculates 'mBitNum' and 'mBitShift' values on all levels; also 'mMappingTableDim';
201  int CalculateBitPattern();
202 
203  // Overall dimension of the mapping table (2**N, where N is the minimum
204  // number of bits needed to pack all level indices);
205  UGeantIndex_t mMappingTableDim; // number of entries in the mapping table
206  ULogicalIndex_t *mMappingTable; //[mMappingTableDim] mapping table array
207 
208  // Well, it is assumed of course that this path is unique for all elements
209  // of this map; does it make sense?;
210  TString mBaseVolumePath; // exact mother volume path (like "/cave_1/CEMC_0");
211 
212  // Well, for the FakeMoCa logic one needs to decide whether 3D point of a fake hit
213  // is inside some cell or not; check is done on all TGeoNode nodes with full path
214  // names ending with this volume name (like /cave_1/CEMC_0/cemcSector_11/cemcTower_3);
215  //
216  // As of July'2014 this information and respective look-up table are also used
217  // for standard digitization (got rid of fGeoH pointer and point->volumePath);
218  TString mSingleSensorContainerVolumeName; // volume which is an "elementary cell" for this map
219 
220  // Write access to mapping table for initialization;
221  int SetMappingTableEntry(const unsigned geo[], ULogicalIndex_t logical);
222 
223  // Calculate actual multi-dim volume index for the "global" geometry tree;
224  // depends on the sequence in which detectors were put into geometry, etc;
226 
227  // Remaps 32-bit GEANT hierarchy tree geographic multi-index into 64-bit
228  // logical map index (say encoded XY-indices for the endcap calorimeter matrix);
230  return (mMappingTable && geant < mMappingTableDim) ?
232  };
233 
234  ClassDef(EicGeoMap,16);
235 };
236 
237 #endif