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