Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-10 10:18:05

0001 #pragma once
0002 
0003 #include <vector>
0004 #include <map>
0005 
0006 #include <TRef.h>
0007 #include <TString.h>
0008 
0009 #include "CherenkovPhotonDetector.h"
0010 class CherenkovMirrorGroup;
0011 class OpticalBoundary;
0012 class G4LogicalVolume;
0013 
0014 namespace IRT2 {
0015 
0016 class CherenkovDetector: public TObject {
0017  public:
0018  CherenkovDetector(const char *name = 0): /*m_ContainerVolume(0),*/ m_Name(name ? name : ""), 
0019                       m_ReadoutCellMask(0x0), m_SectorCount(0), m_SectorPhase(0.0)
0020                       /*, m_SectorBoundaryOffset(0.0)*/ {};
0021   ~CherenkovDetector() {};
0022 
0023   enum ud {Upstream, Downstream};
0024 
0025   void AddOpticalBoundary(CherenkovDetector::ud where, unsigned sector, OpticalBoundary *boundary) {
0026     m_OpticalBoundaries[where][sector].push_back(boundary);
0027   };
0028 
0029   void AddRadiator(const char *name, CherenkovRadiator *radiator) { 
0030     _m_Radiators[name] = radiator; 
0031   };
0032 
0033   void SetSectorCount(unsigned count) { m_SectorCount = count; };
0034   void SetSectorPhase(double phase)   {m_SectorPhase = phase; };
0035   
0036   // FIXME: "sector" is in fact *some* index rather than an azimuthal segmentation index;
0037   void AddPhotonDetector(CherenkovPhotonDetector *pd) { 
0038     m_PhotonDetectors.push_back(pd); 
0039   };
0040   void CreatePhotonDetectorInstance(unsigned sector, CherenkovPhotonDetector *pd, 
0041                     uint64_t icopy, ParametricSurface *surface) {
0042     auto irt = pd->AllocateIRT(sector, icopy);
0043 
0044     for(unsigned ud=0; ud<2; ud++)
0045       if (m_OpticalBoundaries[ud].find(sector) != m_OpticalBoundaries[ud].end())
0046     for(auto boundary: m_OpticalBoundaries[ud][sector])
0047       irt->AddOpticalBoundary(boundary);
0048  
0049     pd->AddItselfToOpticalBoundaries(irt, surface);
0050   };
0051 
0052   //unsigned GetRadiatorCount( void ) const { return m_Radiators.size(); };
0053   // FIXME: this kind of denies 'private' access;
0054   std::map<TString, CherenkovRadiator*> &Radiators( void ) { return _m_Radiators; };
0055 
0056   std::map<unsigned, std::vector<OpticalBoundary*>> m_OpticalBoundaries[2];
0057   std::vector<CherenkovPhotonDetector*> m_PhotonDetectors; 
0058 
0059   //void SetContainerVolume(const G4LogicalVolume *lv) { m_ContainerVolume = lv; };
0060   //const G4LogicalVolume *m_ContainerVolume; //!
0061   void SetContainerVolume(CherenkovRadiator *radiator) { m_ContainerVolume = radiator; };
0062   CherenkovRadiator *GetContainerVolume( void ) const { 
0063     return dynamic_cast<CherenkovRadiator*>(m_ContainerVolume.GetObject()); };
0064   TRef m_ContainerVolume; 
0065 
0066   const char *GetName( void ) const { return m_Name.Data(); };
0067 
0068   CherenkovRadiator *GetRadiator(const char *name) {
0069     if (_m_Radiators.find(name) == _m_Radiators.end()) return 0;
0070 
0071     return _m_Radiators[name];
0072   };
0073   bool RadiatorRegistered(const CherenkovRadiator *radiator) {
0074     for(auto &ptr: _m_Radiators)
0075       if (ptr.second == radiator)
0076     return true;
0077 
0078     return false;
0079   };
0080   // FIXME: create a lookup table;
0081   const char *GetRadiatorName(const CherenkovRadiator *radiator) {
0082     for(auto &ptr: _m_Radiators)
0083       if (ptr.second == radiator)
0084     return ptr.first.Data();
0085 
0086     return 0;
0087   };
0088 
0089   void SetReadoutCellMask(uint64_t mask) { m_ReadoutCellMask = mask; };
0090   inline uint64_t GetReadoutCellMask( void ) const { return m_ReadoutCellMask; };
0091 
0092   unsigned GetSector(const TVector3 &pt) {
0093     // Either a single "sector" or sector structure not defined yet -> return 0;
0094     if (m_SectorCount <= 1) return 0;
0095 
0096     double bin = 2*M_PI/m_SectorCount;
0097     
0098     return (unsigned)floor((pt.Phi() + 4*M_PI - m_SectorPhase)/bin) % m_SectorCount;
0099   };
0100 
0101   // FIXME: get rid of the second argument here;
0102   CherenkovRadiator *GuessRadiator(const TVector3 &x0, const TVector3 &n0) {
0103     // Determine sector (in EIC DRICH terminology);
0104     unsigned isec = GetSector(x0);
0105     
0106     // FIXME: may want to do a better check; 
0107     if (m_OpticalBoundaries[CherenkovDetector::Upstream][isec].empty()) return 0;
0108 
0109     // Now loop through all radiators, and check boundaries in this sector;
0110     for(auto rptr: _m_Radiators) {
0111       const auto radiator = rptr.second;
0112       
0113       // Front and rear surfaces for this particular sector;
0114       auto s1 = radiator->GetFrontSide(isec);
0115       auto s2 = radiator->GetRearSide (isec);
0116 
0117       TVector3 from, to;
0118       // Go backwards and ignore surface orientation mismatch;
0119       bool b1 = s1->GetCrossing(x0, -1*n0, &from, false);
0120       bool b2 = s2->GetCrossing(x0,    n0, &to);
0121       if (!b1 || !b2) continue;
0122 
0123       if ((x0 - from).Dot(to - x0) > 0.0) return radiator;
0124     } //for radiator
0125     
0126     // Seemingly this 3D point does not belong to any radiator;
0127     return 0;
0128   };
0129 
0130   void StoreOpticalBoundary(OpticalBoundary *boundary) {
0131     m_OpticalBoundaryStorage.push_back(boundary);
0132   };
0133 
0134   // readout ID -> pixel position converter (for external usage)
0135   std::function<TVector3(long long int)> m_ReadoutIDToPosition; //!
0136 
0137  private:  
0138   TString m_Name;
0139   // This is needed for dd4hep cell index decoding;
0140   uint64_t m_ReadoutCellMask;
0141 
0142   // IRT has a TRef by (unfortunate) design -> need a serialized storage buffer to refer to;
0143   std::vector<OpticalBoundary*> m_OpticalBoundaryStorage;
0144 
0145   // These are needed to calculate to which detector sector (think of a dRICH) a
0146   // particular 3D point belongs; a respective call is used in two different cases:
0147   //  (1) to define to which radiator a photon production vertex belongs
0148   //  (2) to define to which sector a particular sensor hit belongs
0149   //
0150   // In principle a photon can be produced in one sector, but be detected in a different
0151   // one, but this seemingly does not cause any confusion since each radiator is treated
0152   // "globally", so effectively case #1 is only about using a proper section of a spherical
0153   // mirror in case of dRICH to define whether a photon vertex was inside or outside of
0154   // the gas volume;
0155   unsigned m_SectorCount;
0156   double m_SectorPhase;
0157   
0158   std::map<TString, CherenkovRadiator*> _m_Radiators;
0159 
0160 #ifndef DISABLE_ROOT_IO
0161   ClassDef(CherenkovDetector, 7);
0162 #endif
0163 };
0164 
0165 } // namespace IRT2