EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
EicGeoParData.h
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file EicGeoParData.h
1 //
2 // AYK (ayk@bnl.gov), 2013/06/13
3 //
4 // EIC geometry mapping classes;
5 //
6 
7 #include <stdlib.h>
8 #include <assert.h>
9 
10 #include <set>
11 
12 #include <TString.h>
13 #include <TObject.h>
14 #include <TFile.h>
15 #include <TGeoManager.h>
16 #include <TTimeStamp.h>
17 #include <TVector3.h>
18 
19 #include <FairGeoLoader.h>
20 #include <FairGeoInterface.h>
21 #include <FairGeoMedia.h>
22 #include <FairGeoMedium.h>
23 #include <FairGeoBuilder.h>
24 
25 #include <EicDetName.h>
26 #include <EicNamePatternHub.h>
27 #include <EicGeoMap.h>
28 
29 #ifndef _EIC_GEO_PAR_DATA_
30 #define _EIC_GEO_PAR_DATA_
31 
32 // Prefer to decouple from EicGeoMapLevel (even that in principle could
33 // allow inheritance);
35 {
36  // No sense to complicate access for the master class;
37  friend class EicGeoParData;
38 
39  public:
41  LogicalVolumeGroupProjection(unsigned maxEntryNum):
42  mMaxEntryNum(maxEntryNum), mCircular(false) {
43  // NB: in fact maxEntryNum is guaranteed not to be 0 in the calling routine;
44  mBitMask = maxEntryNum ? new EicBitMask<ULogicalIndex_t>(maxEntryNum) : 0;
45  };
47 
48  private:
49  ULogicalIndex_t mMaxEntryNum; // max number of volume copies on this level
50 
51  EicBitMask<ULogicalIndex_t> *mBitMask; //-> bit mask parameters associated with this level
52 
53  Bool_t mCircular; // "true" if respective dimension is of "barrel" type
54 
56 };
57 
58 // Well, do not need more that XYZ-projections in EicRoot logical volume groups;
59 // in fact may live with just XY, but who cares;
60 #define _LOGICAL_VOLUME_GROUP_COORD_NUM_ 3
61 
62 // No reason to make them bound to whatever class;
63 TVector3 LocalToMaster (const TGeoMatrix *mtx, const TVector3& local);
64 TVector3 LocalToMasterVect(const TGeoMatrix *mtx, const TVector3& local);
65 TVector3 MasterToLocal (const TGeoMatrix *mtx, const TVector3& master);
66 TVector3 MasterToLocalVect(const TGeoMatrix *mtx, const TVector3& master);
67 
69 {
70  public:
73 
74  // NB: this whole class is transient stuff -> does not bother ROOT streamer;
75  TGeoNode *mGeoNode;
76  TGeoHMatrix *mGeoMtx;
77 
78  TString mVolumePath;
79 
81 };
82 
84 {
85  // No sense to complicate access for the master class;
86  friend class EicGeoParData;
87 
88  public:
90  mLookup = 0;
91 
92  mDim3D = 0;
93  for(unsigned iq=0; iq<_LOGICAL_VOLUME_GROUP_COORD_NUM_; iq++)
94  mRealDim[iq] = 0;
95  };
97 
98  private:
99  std::vector<LogicalVolumeGroupProjection*> mProjections;
100 
101  // These variables are initialized and used upon EicGeoParData import from
102  // a geometry file (so they are not present in the mapping file);
106 
108 };
109 
110 class SourceFile {
111  public:
112  SourceFile(const char *fileName = 0);
114 
115  const TString &GetFileName() const { return mFileName; };
116  bool IsOk() const { return mOkFlag; };
117 
118  void Print();
119 
120  private:
121  Bool_t mOkFlag; // flag indicating whether file was imported or not
122  TString mFileName; // file name
123  UInt_t mFileSize; // file size (I guess 32 bits suffices? :-)
124  UChar_t *mFileContent; //[mFileSize] file content
125 
126  ClassDef(SourceFile,3);
127 };
128 
129 //
130 // In principle one may want to define certain type of ID for each level
131 // of every map (say declare who is sensitive and who is absorber in
132 // femcFiberCore->femcFiber->femcTower sequence); or perhaps declare whole
133 // maps as either sensitive or absorber ones; in practice this yields more
134 // confusion that help, because 1) one still can not always pack levels
135 // in a single map (say fiber core and cladding may be on the same level
136 // in geometry tree), 2) structure becomes much less intuitively clear;
137 // so the logic of presently implemented code looks like this:
138 //
139 // - detector may have as many logical maps as needed; actually if a given volume
140 // type (name) is expected to act as GEANT sensitive one, this *requires*
141 // creation of a separate map in respective *.C script; even if two maps
142 // overlap in all levels but the top one(s);
143 //
144 // - maps are distinguished by the 0-th - top - level which 1) can be
145 // sensitive volume in GEANT terms, 2) can be either active or dead
146 // (absorber) volume in terms of digitization & reconstruction;
147 //
148 // - maps may have the same top-level volumes (say 2x2 and 1x2 towers
149 // may have the same crystals as building blocks);
150 //
151 // - one can de-activate part of the top-level volume types at a time
152 // when simulation starts (so that eg. hits are not produced in absorber
153 // material; saves greatly CPU time); all top-level volumes are declared
154 // GEANT-sensitive ones per default (check on that!);
155 //
156 // - during digitization one can *select* out of the whole set of GEANT-sensitive
157 // volumes which produced hits a subset of "digitization-sensitive" volume types;
158 // say it should be possible to digitize and find clusters assuming only fiber
159 // core volumes to be sensitive or core+cladding or core+cladding+absorber and just
160 // change light yield, threshold, etc accordingly; energy deposit for *all* types
161 // of volumes associated with a given cell will be recorded separately if needed,
162 // and besides this separately for each primary mother particle; only energy deposit
163 // in volumes declared as "digitization-sensitive" will be used for photon
164 // generation, clustering, etc; indeed a situation with transparent and scintillating
165 // fibers in one tower is not covered within this logic, since only a single
166 // reconstructed energy per cell is calculated; but at present we have no such detectors
167 // in EIC; logic can be expanded later at a price of yet another complication, so why
168 // bother now?;
169 //
170 
171 class EicGeoParData: public TObject
172 {
173  public:
174  EicGeoParData(const char *detName = 0, int version = -1, int subVersion = 0);
176 
177  void ResetVars();
178 
180 
181  //
182  // Mapping file creation part and matching access methods
183  //
184 
185  void SetGeometryType(GeometryType gType) { mGeometryType = gType; };
187 
188  // Default file name will look like 'vst-test.root' in this case;
189  void SetTestGeometryFlag(bool flag = true) { mTestGeometryFlag = flag; };
190  bool IsTestGeometry() const { return mTestGeometryFlag; };
191 
192  int GetVersion() const { return mVersion; };
193  int GetSubVersion() const { return mSubVersion; };
194 
195  // Default file name like 'vst-v00.0.root' will be composed using detector name,
196  // version and subversion; one may want to excplicitely overrid this behaviour
197  // either proving a fixed name via SetFileName() or a format string like
198  // 'bemc-v02%d-%d-pr.root' where version and subversion will be used; in the latter
199  // case user is responsible for sanity control;
200  void SetFileName(const char *fileName) { if (fileName) mFileName = fileName; };
201  void SetFileNameFormat(const char *fileNameFormat) {
202  if (fileNameFormat) mFileNameFormat = fileNameFormat;
203  };
204 
205  void SetComment(const char *comment) { if (comment) mComment = comment; };
206 
207  int AttachSourceFile(const char *fileName);
208  void PrintAttachedSourceFile(const char *fileName);
209 
211 
212  private:
213  int SetCircularCore(unsigned group, unsigned what);
214  public:
215  int SetCircularX( unsigned group = 0) { return SetCircularCore(group, IDX); };
216  int SetCircularY( unsigned group = 0) { return SetCircularCore(group, IDY); };
217  int SetCircularZ( unsigned group = 0) { return SetCircularCore(group, IDZ); };
218 
219  private:
220  bool GetCircularCore(unsigned group, unsigned what) const;
221  public:
222  bool GetCircularX( unsigned group = 0) const { return GetCircularCore(group, IDX); };
223  bool GetCircularY( unsigned group = 0) const { return GetCircularCore(group, IDY); };
224  bool GetCircularZ( unsigned group = 0) const { return GetCircularCore(group, IDZ); };
225  bool GetCircular ( unsigned group, unsigned what) const { return GetCircularCore(group, what);};
226 
227  int SetMappingTableEntry(EicGeoMap *map, const unsigned geant[], unsigned group, unsigned logical[]);
228 
229  // GEANT hierarchy can be any and may have several levels; logical tables are less
230  // demanding; allow at most 256 groups of XYZ indices and avoid further complications;
231  int AddLogicalVolumeGroup(unsigned dimX = 0, unsigned dimY = 0, unsigned dimZ = 0);
232 
233  // FIXME: no double-counting check, whetsoever?;
234  void AddBlackHoleVolume(const char *vName) {
235  if (vName) mBlackHoleVolumes.insert(TString(vName));
236  };
237  void AddStepEnforcedVolume(const char *vName) {
238  if (vName) mStepEnforcedVolumes.insert(TString(vName));
239  };
240  void AddStepEnforcedVolumeLookupEntry(int volumeID, double step) {
241  mStepEnforcedVolumesLookup.insert(std::pair<int, double>(volumeID, step));
242  };
243 
244  // A wrapper to gGeoMan->GetMedium();
245  const TGeoMedium *GetMedium(const char *medium);
246 
247  void SetTopVolumeTransformation(TGeoMatrix *transformation) {
248  mTopVolumeTransformation = transformation;
249  };
250  const TGeoMatrix* GetTopVolumeTransformation() const { return mTopVolumeTransformation; };
251 
252  //private:
253  TString GetGeometryFileName(bool root = true) const;
254 
255  public:
256  // NB: yes, these methods can not be protected, otherwise CINT complains like
257  // "Error: ConstructGeometry() declared but no dictionary for the base class";
258  // public here and public in derived classes works; what a *hit!;
259  virtual void Print(const char *option = 0) const;
260 
261  // In fact every derived class is supposed to have its own ConstructGeometry() call
262  // unless everything happens in .C script up to the final FinalizeOutput() call;
263  virtual int ConstructGeometry(bool root = true, bool gdml = false, bool check = false) { return 0; };
264 
265  // NB: this is not really the top volume in ROOT TGeo sense (see mRootGeoManager->SetTopVolume()
266  // call in EicGeoParData::EicGeoParData() -> there is another wrapper volume on top of it);
267  // but it is indeed a top meaning volume of the detector hierarchy;
268  TGeoVolume *GetTopVolume() const { return mTopVolume; };
269  TGeoManager *GetRootGeoManager() { return mRootGeoManager; };
270 
271  // Yes, prefer to put all output operations in one user call;
272  void FinalizeOutput(bool root = true, bool gdml = false, bool check = false);// const;
273 
274  //
275  // simulation/digitization/reconstruction code calls
276  //
277 
278  enum IDXYZ {IDX=0, IDY, IDZ};
279 
280  UInt_t GetMapNum() const { return mGeantVolumeMaps.size(); };
281  // (Perhaps write) access to map pointers;
282  EicGeoMap *GetMapPtrViaMapID(unsigned mapId) const {
283  return mapId < mGeantVolumeMaps.size() ? mGeantVolumeMaps[mapId] : 0;
284  };
285  const EicGeoMap *GetMapPtrViaHitMultiIndex(ULong64_t multi) const {
286  return GetMapPtrViaMapID(unsigned((multi >> _GEANT_INDEX_BIT_NUM_) & _SERVICE_BIT_MASK_));
287  };
288 
290 
291  unsigned GetMaxVolumeLevelNum() const { return mMaxVolumeLevelNum;};
292 
293  ULogicalIndex_t GeantMultiToLogicalIndex(ULong64_t multi) const;
294 
295  private:
296  unsigned GetDimCore(unsigned group, unsigned what) const;
297  public:
298  unsigned GetDimX (unsigned group = 0) const { return GetDimCore(group, IDX); };
299  unsigned GetDimY (unsigned group = 0) const { return GetDimCore(group, IDY); };
300  unsigned GetDimZ (unsigned group = 0) const { return GetDimCore(group, IDZ); };
301  unsigned GetDim (unsigned group, unsigned what) const { return GetDimCore(group, what);};
302 
303  unsigned GetGroup(ULogicalIndex_t logicalID) const {
304  return ((logicalID >> _LOGICAL_XYZ_BIT_NUM_) & _LOGICAL_GROUP_MASK_);
305  };
306 
307  private:
308  unsigned GetLogicalCoordCore(unsigned what, ULogicalIndex_t logicalID) const;
309  public:
310  unsigned GetX ( ULogicalIndex_t logicalID) const {
311  return GetLogicalCoordCore( IDX, logicalID);
312  };
313  unsigned GetY ( ULogicalIndex_t logicalID) const {
314  return GetLogicalCoordCore( IDY, logicalID);
315  };
316  unsigned GetZ ( ULogicalIndex_t logicalID) const {
317  return GetLogicalCoordCore( IDZ, logicalID);
318  };
319  unsigned GetCoord(unsigned what, ULogicalIndex_t logicalID) const {
320  return GetLogicalCoordCore(what, logicalID);
321  };
322 
323  bool IsBlackHoleVolume(const char *vName) const {
324  // In this case no need to do further steps like char* -> TString conversion;
325  if (!mBlackHoleVolumes.size()) return false;
326 
327  return (mBlackHoleVolumes.find(TString(vName)) != mBlackHoleVolumes.end());
328  };
329  const std::set<TString> &GetBlackHoleVolumes() const { return mBlackHoleVolumes; };
330 
331  // Not exactly the most efficient call I guess;
332  double GetEnforcedStep(int volumeID) {
333  if (mStepEnforcedVolumesLookup.find(volumeID) == mStepEnforcedVolumesLookup.end())
334  return 0.0;
335 
336  return mStepEnforcedVolumesLookup[volumeID];
337  };
338  const std::set<TString> &GetStepEnforcedVolumes() const { return mStepEnforcedVolumes; };
339 
340  // Need an extra routine to initialize lookup tables since in the constructor call
341  // during ROOT streamer import eg mLogicalVolumeGroups.size() is = 0 (in other words
342  // nothing is imported yet);
343  void InitializeLookupTables();
344 
346  LogicalVolumeLookupTableEntry *GetLookupTableNode(const TGeoNode *node) const;
347 
348  // Yes, prefer to allow direct access to this (and below) pointer rather than
349  // creating 4 different access routines (prefix, ..., pattern);
352 
353  return mColorRequests;
354  };
357 
358  return mTransparencyRequests;
359  };
360 
361  // Provide a reasonable default routine; also may want to apply different distance limits
362  // for different dimensions; default distance limits are "natural" ones (3x3 square in 2D
363  // case and 3x3x3 cube in 3D case); maxChebyshevDist=0 explicitely indicates this limit is
364  // of no use per default;
365  virtual bool AreNeighbours(ULogicalIndex_t l1, ULogicalIndex_t l2, unsigned maxLinearDist = 1,
366  unsigned maxChebyshevDist = 0) const;
367 
368  const EicDetName *GetDetName() const { return mDetName; };
369 
370  void AddWantedParticle(const char *vName, int pdg) {
371  mWantedParticles.insert(std::pair<TString, Int_t>(TString(vName), pdg));
372  };
373  bool IsWantedParticle(const char *vName, int pdg) const {
374  return (mWantedParticles.find(std::pair<TString, Int_t>(TString(vName), pdg)) !=
375  mWantedParticles.end());
376  };
377 
378  protected:
379  GeometryType mGeometryType; // geometry type (no structure / simple / full)
380  Bool_t mTestGeometryFlag; // "test type" geometry (no "fs/ss/ns" suffix will be used)
381 
382  private:
383  Int_t mVersion; // optional version ID
384  Int_t mSubVersion; // optional subversion ID
385 
386  TString mFileName;
387  TString mFileNameFormat;
388 
389  TString mAuthor; // author in a way user@hostname
390  TString mComment; // optional comment
391 
392  std::vector<SourceFile*> mSourceFiles; // attached source (or whatever other) files
393 
394  TTimeStamp mTimeStamp; // creation time stamp
395 
396  // FIXME: there should be a way to modify this from simulation.C if needed;
397  TGeoMatrix *mTopVolumeTransformation; //
398 
399  // Collection of maps for this detector;
400  std::vector<EicGeoMap*> mGeantVolumeMaps; // vector with detector maps
401 
402  // Well, can not make these variables persistent, because 'mMaxVolumeLevelNum'
403  // is not really defined in C-scripts without an extra call at the end;
405 
406  // Well, nothing is wrong to add some extra functionality right in this class,
407  // without creating an extra layer; if multi-index has a meaning of encrypted set of
408  // NXYZ-indices (or perhaps just 1- or 2-dimensional ones), one can consider to implement
409  // neighbour check routines; they should not necessarily be the most efficient
410  // ones, but rather generic enough to be useable by various EicRoot detectors;
411  std::vector <LogicalVolumeGroup*> mLogicalVolumeGroups;// table describing GEANT->Logical conversion
412 
413  // Well, eg for ideal calorimeter clustering algorithm I want to collect separately
414  // hits from all "mother" particles; just in order to simplify things before the actual
415  // cluster finding algorithm is operational; the question is how to define who is "mother particle";
416  // the convention is: as soon as a particle enters one of such "black hole volumes" its
417  // daughters can NOT be mother particles for shower energy deposit hits; a typical scenario is:
418  //
419  // - "FemcTowerShell" is defined as one of such *experiment-wide* (so global) volumes;
420  // - primary electron produces a bremsstrahlung photon in the TPC inner field cage;
421  // - this photon eventually reaches FEMC calorimeter and produces a shower; NB: it enters
422  // "FemcTowerShell" volume first;
423  //
424  // --> hits from all shower particles in FEMC will be assigned bremsstrahlung photon
425  // as a mother particle even that it is neither a primary particle nor it differs
426  // essentially from all other photons in e/m shower inside the calorimeter;
427  //
428  // This way one can get two separate e/m clusters in the calorimeter (one from electron
429  // and the other one from photon); besides this, the logic is arranged such, that list of
430  // "black hole" volumes is NOT detector-specific (so it is a *global* one); eg if one of the
431  // shower electrons escapes FEMC and produces a cluster in FHAC, mother particle for this
432  // FHAC cluster will NOT be escaped electron, but the original bremsstrahlung photon, even
433  // that FHAC may define say "FhacTower" as it's own "black hole volume";
434  //
435  // The limitation: there should not be any overlap between black hole and sensitive volume names!;
436  //
437  std::set<TString> mBlackHoleVolumes; // after entering such a volume particle becomes "secondary mother"
438 
439  std::set<std::pair<TString, Int_t> > mWantedParticles;
440 
441  // Well, for whatever reason I can not make use of max step limit as given in media.geo
442  // file; this is however essential for TPC tracking; just enforce this setting
443  // in EicDetector::ProcessHits() via explicit call to gMC->SetMaxStep(); yes, it is
444  // inefficient I guess;
445  std::set<TString> mStepEnforcedVolumes; // max step will be set explicitely in G4 mode in these volumes
446  std::map<int, double> mStepEnforcedVolumesLookup;
447 
448  protected:
449  // Detector name class;
451 
452  private:
453  // This stuff is specifically put here (see implementation as well) to hide most
454  // of the FairRoot geometry- and media-related calls in scripts like femc.C;
455  TGeoManager* mRootGeoManager;
456  TGeoVolume *mWrapperVolume;
457  TGeoVolume *mTopVolume;
458 
461 
464 
465  // Just need to store the names in order to make sure, that geobuild->createMedium()
466  // was performed for all the media requested by GetMedium() calls;
467  std::set<const char *> mMediaCache;
468 
469  std::map<const TGeoNode*, LogicalVolumeLookupTableEntry*> mGeantToLogicalLookupTable;
470 
471  // I think there is no need to propagate this information further?;
474 
476 };
477 
478 #endif