Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:16:46

0001 //==========================================================================
0002 //  AIDA Detector description implementation 
0003 //--------------------------------------------------------------------------
0004 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0005 // All rights reserved.
0006 //
0007 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0008 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0009 //
0010 // Author     : M.Frank
0011 //
0012 //==========================================================================
0013 #ifndef DD4HEP_DETELEMENTVOLUMEIDS_H
0014 #define DD4HEP_DETELEMENTVOLUMEIDS_H
0015 
0016 // Framework include files
0017 #include <DD4hep/DetElement.h>
0018 #include <DD4hep/Volumes.h>
0019 
0020 // C/C++ includes
0021 
0022 /// Namespace for the AIDA detector description toolkit
0023 namespace dd4hep {
0024 
0025   /// Forward declarations
0026   class Detector;
0027 
0028   /// Actor class to assign volume identifiers to DetElements in a subdetector tree
0029   /**
0030    *  During the tree traversal the encoding information is also accumulated
0031    *  in a map indexed by the DetElement.
0032    *
0033    *  \author  M.Frank
0034    *  \version 1.0
0035    */
0036   class DetElementVolumeIDs   {
0037   private:
0038     /// Reference to the Detector instance
0039     const Detector& m_detDesc;
0040 
0041   public:
0042     /// Node counter
0043     std::size_t     numberOfNodes  { 0 };
0044     /// Encoding/mask for sensitive volumes
0045     struct Encoding  {
0046       VolumeID identifier;
0047       VolumeID mask;
0048     };
0049     /// Set of already added entries
0050     std::map<DetElement, std::vector<Encoding> > entries;
0051 
0052   private:
0053     using PlacementPath = std::vector<PlacedVolume>;
0054    
0055     /// Scan a single physical volume and look for sensitive elements below
0056     std::size_t scanPhysicalVolume(DetElement&        parent,
0057                                    DetElement         e,
0058                                    PlacedVolume       pv, 
0059                                    Encoding           parent_encoding,
0060                                    SensitiveDetector& sd,
0061                                    PlacementPath&     chain);
0062   public:
0063     /// Default constructor
0064     DetElementVolumeIDs(const Detector& description);
0065     /// Populate the Volume manager
0066     std::size_t populate(DetElement e);
0067   };
0068 }      /* End namespace dd4hep                */
0069 #endif // DD4HEP_DETELEMENTVOLUMEIDS_H
0070 //==========================================================================
0071 //  AIDA Detector description implementation 
0072 //--------------------------------------------------------------------------
0073 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
0074 // All rights reserved.
0075 //
0076 // For the licensing terms see $DD4hepINSTALL/LICENSE.
0077 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
0078 //
0079 // Author     : M.Frank
0080 //
0081 //==========================================================================
0082 
0083 // Framework include files
0084 #include <DD4hep/Printout.h>
0085 #include <DD4hep/Factories.h>
0086 #include <DD4hep/Detector.h>
0087 #include <DD4hep/DetectorTools.h>
0088 #include <DD4hep/detail/DetectorInterna.h>
0089 
0090 /// Namespace for the AIDA detector description toolkit
0091 using namespace dd4hep;
0092 
0093 namespace  {
0094 
0095   /// Basic entry point to assign volume identifiers to detector elements
0096   /**
0097    *  Factory: DD4hep_DetElementVolumeIDs
0098    *
0099    *  \author  M.Frank
0100    *  \version 1.0
0101    *  \date    01/04/2014
0102    */
0103   long assign_de_volumeIDs(Detector& description, int argc, char** argv) {
0104     std::string detector = "/world";
0105     for(int i = 0; i < argc && argv[i]; ++i)  {
0106       if ( 0 == ::strncmp("-detector",argv[i],4) )
0107         detector = argv[++i];
0108       else  {
0109         std::cout <<
0110           "Usage: -plugin DD4hep_DetElementVolumeIDs  -arg [-arg]               \n\n"
0111           "     -detector <string> Top level DetElement path. Default: '/world' \n"
0112           "     -help              Print this help output                       \n"
0113           "     Arguments given: " << arguments(argc,argv) << std::endl << std::flush;
0114         ::exit(EINVAL);
0115       }
0116     }
0117     DetElement element = description.world();
0118     if ( detector != "/world" )   {
0119       element = detail::tools::findElement(description,detector);
0120       if ( !element.isValid() )  {
0121         except("DD4hep_DetElementVolumeIDs","+++ Invalid DetElement path: %s",detector.c_str());
0122       }
0123     }
0124     DetElementVolumeIDs mgr(description);
0125     auto count = mgr.populate(element);
0126     if ( count == 0 )   {
0127       except("DD4hep_DetElementVolumeIDs",
0128              "+++ NO volume identifiers assigned to DetElement %s. %s",
0129              "Something went wrong!",detector.c_str());
0130     }
0131     return count > 0 ? 1 : 0;
0132   }
0133 }
0134 DECLARE_APPLY(DD4hep_DetElementVolumeIDs,assign_de_volumeIDs)
0135 
0136 using Encoding = DetElementVolumeIDs::Encoding;
0137 using VolIDs   = PlacedVolume::VolIDs;
0138 
0139 namespace  {
0140 
0141   /// Compute the encoding for a set of VolIDs within a readout descriptor
0142   Encoding update_encoding(const IDDescriptor iddesc, const VolIDs& ids, const Encoding& initial)  {
0143     VolumeID volume_id = initial.identifier, mask = initial.mask;
0144     for (VolIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) {
0145       const auto& id = (*i);
0146       const BitFieldElement* f = iddesc.field(id.first);
0147       VolumeID msk = f->mask();
0148       int      off = f->offset();
0149       VolumeID val = id.second;    // Necessary to extend volume IDs > 32 bit
0150       volume_id   |= ((f->value(val << off) << off)&msk);
0151       mask        |= msk;
0152     }
0153     return { volume_id, mask };
0154   }
0155 }
0156 
0157 /// Default constructor
0158 DetElementVolumeIDs::DetElementVolumeIDs(const Detector& description)
0159   : m_detDesc(description)
0160 {
0161 }
0162 
0163 /// Populate the Volume manager
0164 std::size_t DetElementVolumeIDs::populate(DetElement det) {
0165   std::size_t  count = 0UL;
0166   Encoding     encoding { 0, 0 };
0167   PlacedVolume pv = det.placement();
0168 
0169   entries.clear();
0170   if ( !pv.isValid() )   {
0171     except("DetElementVolumeIDs",
0172            "+++ Top level DetElement %s has no valid placement. %s",
0173            "[Something awfully wrong]", det.path().c_str());
0174   }
0175   if ( det == m_detDesc.world() )   {
0176     for (const auto& i : det.children() )  {
0177       DetElement   de = i.second;
0178       pv = de.placement();
0179       if (pv.isValid()) {
0180         PlacementPath     chain;
0181         Encoding          coding { 0, 0 };
0182         SensitiveDetector sd (0);
0183         count += scanPhysicalVolume(de, de, pv, coding, sd, chain);
0184         continue;
0185       }
0186       printout(WARNING, "DetElementVolumeIDs", "++ Detector element %s of type %s has no placement.", 
0187                de.name(), de.type().c_str());
0188     }
0189     printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count); 
0190     return count;
0191   }
0192   SensitiveDetector sd = m_detDesc.sensitiveDetector(det.name());
0193   if ( !pv.volIDs().empty() && !sd.isValid() )   {
0194     except("DetElementVolumeIDs",
0195            "+++ No sensitive detector available for top level DetElement %s.",
0196            det.path().c_str());
0197   }
0198   PlacementPath chain;
0199   count += scanPhysicalVolume(det, det, pv, encoding, sd, chain);
0200   printout(INFO, "DetElementVolumeIDs", "++ Assigned %ld volume identifiers to DetElements.", count); 
0201   return count;
0202 }
0203 
0204 /// Scan a single physical volume and look for sensitive elements below
0205 std::size_t
0206 DetElementVolumeIDs::scanPhysicalVolume(DetElement&        parent,
0207                                         DetElement         e,
0208                                         PlacedVolume       pv, 
0209                                         Encoding           parent_encoding,
0210                                         SensitiveDetector& sd,
0211                                         PlacementPath&     chain)
0212 {
0213   TGeoNode* node = pv.ptr();
0214   std::size_t count = 0;
0215   if (node) {
0216     Volume vol = pv.volume();
0217     const VolIDs& pv_ids   = pv.volIDs();
0218     Encoding vol_encoding  = parent_encoding;
0219     bool     is_sensitive  = vol.isSensitive();
0220     bool     have_encoding = pv_ids.empty();
0221     bool     compound      = e.type() == "compound";
0222 
0223     if ( compound )  {
0224       sd = SensitiveDetector(0);
0225       vol_encoding = Encoding();
0226     }
0227     else if ( !sd.isValid() )  {
0228       if ( is_sensitive )
0229         sd = vol.sensitiveDetector();
0230       else if ( (parent->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0231         sd = m_detDesc.sensitiveDetector(parent.name());
0232       else if ( (e->flag&DetElement::Object::HAVE_SENSITIVE_DETECTOR) )
0233         sd = m_detDesc.sensitiveDetector(e.name());
0234     }
0235     chain.emplace_back(node);
0236     if ( sd.isValid() && !pv_ids.empty() )   {
0237       Readout ro = sd.readout();
0238       if ( ro.isValid() )   {
0239         vol_encoding  = update_encoding(ro.idSpec(), pv_ids, parent_encoding);
0240         have_encoding = true;
0241       }
0242       else {
0243         printout(WARNING, "DetElementVolumeIDs",
0244                  "%s: Strange constellation volume %s is sensitive, but has no readout! sd:%p",
0245                  parent.name(), pv.volume().name(), sd.ptr());
0246       }
0247     }
0248     for (int idau = 0, ndau = node->GetNdaughters(); idau < ndau; ++idau) {
0249       TGeoNode*    daughter = node->GetDaughter(idau);
0250       PlacedVolume place_dau(daughter);
0251       if ( place_dau.data() ) {
0252         DetElement   de_dau;
0253         /// Check if this particular volume is the placement of one of the
0254         /// children of this detector element. If the daughter placement is also
0255         /// a detector child, then we must reset the node chain.
0256         for( const auto& de : e.children() )  {
0257           if ( de.second.placement().ptr() == daughter )  {
0258             de_dau = de.second;
0259             break;
0260           }
0261         }
0262         if ( de_dau.isValid() ) {
0263           PlacementPath dau_chain;
0264           count += scanPhysicalVolume(parent, de_dau, place_dau, vol_encoding, sd, dau_chain);
0265         }
0266         else { // there may be several layers of volumes between mother-child of DE
0267           count += scanPhysicalVolume(parent, e, place_dau, vol_encoding, sd, chain);
0268         }
0269       }
0270       else  {
0271         except("DetElementVolumeIDs",
0272                "Invalid not instrumented placement: %s %s", daughter->GetName(),
0273                " [Internal error -- bad detector constructor]");
0274       }
0275       /// For compounds the upper level sensitive detector does not exist,
0276       /// because there are multiple at lower layers
0277       if ( compound )  {
0278         sd = SensitiveDetector(0);
0279       }
0280     }
0281     if ( sd.isValid() )   {
0282       if ( !have_encoding && !compound )   {
0283         printout(ERROR, "DetElementVolumeIDs",
0284                  "Element %s: Missing SD encoding. Volume manager won't work!",
0285                  e.path().c_str());
0286       }
0287       if ( is_sensitive || count > 0 )  {
0288         // Either this layer is sensitive of a layer below.
0289         if ( node == e.placement().ptr() )  {
0290           // These here are placement nodes, which at the same time are DetElement placements
0291           // 1) We recuperate volumes from lower levels by reusing the subdetector
0292           //    This only works if there is exactly one sensitive detector per subdetector!
0293           // 2) DetElements in the upper hierarchy of the sensitive also get a volume id,
0294           //    and the volume is registered. (to be discussed)
0295           //
0296           e.object<DetElement::Object>().volumeID = vol_encoding.identifier;
0297         }
0298         // Collect all sensitive volumes, which belong to the next DetElement
0299         if ( entries.find(e) == entries.end()) {
0300           entries[e].emplace_back(vol_encoding);
0301           ++numberOfNodes;
0302         }
0303         ++count;
0304       }
0305     }
0306     chain.pop_back();
0307   }
0308   return count;
0309 }