Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-03-28 08:35:16

0001 #pragma once
0002 
0003 #include <map>
0004 
0005 class G4LogicalVolume;
0006 class G4RadiatorMaterial;
0007 class G4OpticalSurface;
0008 
0009 class CherenkovMirror;
0010 class CherenkovPhotonDetector;
0011 
0012 #include "BitMask.h"
0013 #include "CherenkovDetector.h"
0014 
0015 #define _STORE_ORPHAN_PHOTONS_    (0x00000001)
0016 #define _STORE_REFLECTION_POINTS_ (0x00000002)
0017 #define _STORE_REFRACTION_POINTS_ (0x00000003)
0018 
0019 namespace IRT2 {
0020 
0021 class CherenkovDetectorCollection: public BitMask {
0022  public:
0023   CherenkovDetectorCollection();
0024   // FIXME: populate the dtor, for completeness;
0025   ~CherenkovDetectorCollection() {};
0026 
0027   static CherenkovDetectorCollection *m_Instance;              //!
0028   static CherenkovDetectorCollection *Instance() {
0029     return m_Instance ? m_Instance : new CherenkovDetectorCollection();
0030   };
0031   
0032   CherenkovDetector *AddNewDetector(const char *name) {
0033     auto det = new CherenkovDetector(name);
0034     m_Detectors[det->GetName()] = det;
0035 
0036     return det;
0037   };
0038 
0039   CherenkovRadiator *FindOrAddRadiator(CherenkovDetector *det, const char *name, const G4LogicalVolume *volume, 
0040                  const G4RadiatorMaterial *material) {
0041     auto radiator = FindRadiator(volume);
0042     // FIXME: check consistency;
0043     if (!radiator) {
0044       radiator = new CherenkovRadiator(volume, material);
0045       det->AddRadiator(name, radiator);
0046 
0047       m_RadiatorLookup[volume] = radiator;
0048     } //if
0049 
0050     return radiator;
0051   };
0052   CherenkovRadiator *AddFlatRadiator(CherenkovDetector *det, const char *name, CherenkovDetector::ud where, unsigned path, 
0053                      const G4LogicalVolume *volume, 
0054                      const G4RadiatorMaterial *material, const FlatSurface *surface, 
0055                      double thickness) {
0056     auto radiator = FindOrAddRadiator(det, name, volume, material);
0057 
0058     // Make a pair of local copies; they are stored in their respective class instances, 
0059     // therefore need two separate ones;
0060     {
0061       auto boundary = surface->_Clone(0.0, TVector3(0,0,1));
0062       boundary->Shift(( thickness/2)*surface->GetNormal());
0063       det->AddOpticalBoundary(where, path, new OpticalBoundary(radiator,                  boundary, true));
0064       radiator->m_Borders[path].first = boundary;
0065 
0066       // FIXME (?): in case of dRICH (and FRICH) this boundary is assigned by hand (a spherical
0067       // mirror surface), so it should kind of work;
0068       if (where == CherenkovDetector::Downstream && !det->GetContainerVolume()->GetRearSide(path))
0069     det->GetContainerVolume()->m_Borders[path].second = boundary;
0070     }
0071     {
0072       auto boundary = surface->_Clone(0.0, TVector3(0,0,1));
0073       boundary->Shift((-thickness/2)*surface->GetNormal());
0074       det->AddOpticalBoundary(where, path, new OpticalBoundary(det->GetContainerVolume(), boundary, true));
0075       radiator->m_Borders[path].second = boundary;
0076 
0077       // This will most likely be a temporary assignment; only "upstream" boundaries are of interest 
0078       // here since the "downstream" ones are essentially a sensor-side description;
0079       if (where == CherenkovDetector::Upstream) det->GetContainerVolume()->m_Borders[path].first = boundary;
0080     }    
0081 
0082     return radiator;
0083   };
0084   void AddRadiatorLogicalVolume(CherenkovRadiator *radiator, const G4LogicalVolume *lv) {
0085     radiator->AddLogicalVolume(lv);
0086     m_RadiatorLookup[lv] = radiator;
0087   };
0088 
0089   //inline void AddOrphanPhoton(OpticalPhoton *photon) { m_OrphanPhotons.push_back(photon); };
0090 
0091   void AddPhotonDetector(CherenkovDetector *det, const G4LogicalVolume *lv, 
0092              CherenkovPhotonDetector *pd) {
0093     // FIXME: a consistency check!;
0094     if (FindPhotonDetector(lv)) return;
0095 
0096     det->AddPhotonDetector(pd);
0097 
0098     m_PhotonDetectorLookup[lv] = pd;
0099   };
0100 
0101   //inline unsigned GetDetectorCount( void ) const { return m_Detectors.size(); };
0102 
0103   inline CherenkovRadiator *FindRadiator(const G4LogicalVolume *lv) {
0104     return (m_RadiatorLookup.find(lv) == m_RadiatorLookup.end() ? 0 : m_RadiatorLookup[lv]);
0105   };
0106   inline CherenkovMirror *FindMirror(const G4LogicalVolume *lv) {
0107     return (m_MirrorLookup.find(lv) == m_MirrorLookup.end() ? 0 : m_MirrorLookup[lv]);
0108   };
0109   inline void AddMirrorLookupEntry(const G4LogicalVolume *lv, CherenkovMirror *mirror) {
0110     m_MirrorLookup[lv] = mirror;
0111   };
0112   inline void AddPhotonDetectorLookupEntry(const G4LogicalVolume *lv, CherenkovPhotonDetector *pd) {
0113     m_PhotonDetectorLookup[lv] = pd;
0114   };
0115   inline CherenkovPhotonDetector *FindPhotonDetector(const G4LogicalVolume *lv) {
0116     return (m_PhotonDetectorLookup.find(lv) == m_PhotonDetectorLookup.end() ? 0 : m_PhotonDetectorLookup[lv]);
0117   };
0118 
0119   CherenkovRadiator *SetContainerVolume(CherenkovDetector *det, const char *name, unsigned path, 
0120                     const G4LogicalVolume *lv, 
0121                     const G4RadiatorMaterial *material, 
0122                     /*const*/ ParametricSurface *surface) { 
0123     auto radiator = FindOrAddRadiator(det, name, lv, material);
0124     // This is most likely a temporary assignment;
0125     radiator->m_Borders[path].first = surface;
0126 
0127     det->AddOpticalBoundary(CherenkovDetector::Upstream, path, new OpticalBoundary(FindRadiator(lv), surface, true));
0128     //det->SetContainerVolume(lv);
0129     det->SetContainerVolume(radiator);
0130 
0131     return radiator;
0132   };
0133 
0134   // FIXME: do it more efficient later;
0135   CherenkovDetector *GetDetectorByRadiator(const CherenkovRadiator *radiator) {
0136     for(auto detector: m_Detectors)
0137       for(auto ptr: detector.second->Radiators())
0138     if (ptr.second == radiator)
0139       return detector.second;
0140       
0141     return 0;
0142   };
0143   CherenkovDetector *GetDetector(const char *name) {
0144     if (m_Detectors.find(name) == m_Detectors.end()) return 0;
0145 
0146     return m_Detectors[name];
0147   };
0148   const std::map<TString, CherenkovDetector*> &GetDetectors( void ) const {
0149     return m_Detectors;
0150   }; 
0151 
0152   // The lookup tables are global of course since the same particle can hit radiators
0153   // in more than one detector;
0154  private:
0155   std::map<const G4LogicalVolume*, CherenkovRadiator*>       m_RadiatorLookup;         //!
0156   std::map<const G4LogicalVolume*, CherenkovMirror*>         m_MirrorLookup;           //!
0157   std::map<const G4LogicalVolume*, CherenkovPhotonDetector*> m_PhotonDetectorLookup;   //!
0158 
0159   std::map<TString, CherenkovDetector*> m_Detectors;
0160   
0161   //std::vector<OpticalPhoton*> m_OrphanPhotons; 
0162 
0163 #ifndef DISABLE_ROOT_IO
0164   ClassDef(CherenkovDetectorCollection, 3);
0165 #endif
0166 };
0167 
0168 } // namespace IRT2