Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:52:15

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 
0014 #define DD4HEP_MUST_USE_DETECTORIMP_H 1
0015 
0016 // Framework include files
0017 #include <DD4hep/Plugins.h>
0018 #include <DD4hep/Printout.h>
0019 #include <DD4hep/GeoHandler.h>
0020 #include <DD4hep/DetectorHelper.h>
0021 #include <DD4hep/DetectorTools.h>
0022 
0023 #include <DD4hep/InstanceCount.h>
0024 #include <DD4hep/detail/ObjectsInterna.h>
0025 #include <DD4hep/detail/DetectorInterna.h>
0026 #include <DD4hep/detail/VolumeManagerInterna.h>
0027 #include <DD4hep/detail/OpticalSurfaceManagerInterna.h>
0028 #include <DD4hep/DetectorImp.h>
0029 #include <DD4hep/DD4hepUnits.h>
0030 
0031 // C/C++ include files
0032 #include <iostream>
0033 #include <stdexcept>
0034 #include <cerrno>
0035 #include <mutex>
0036 
0037 // ROOT inlcude files
0038 #include <TGeoSystemOfUnits.h>
0039 #include <TGeoCompositeShape.h>
0040 #include <TGeoBoolNode.h>
0041 #include <TGeoManager.h>
0042 #include <TGeoMatrix.h>
0043 #include <TGeoVolume.h>
0044 #include <TGeoShape.h>
0045 #include <TClass.h>
0046 
0047 #include <XML/DocumentHandler.h>
0048 
0049 #ifndef __TIXML__
0050 #include <xercesc/dom/DOMException.hpp>
0051 namespace dd4hep {
0052   namespace xml {
0053     typedef xercesc::DOMException XmlException;
0054   }
0055 }
0056 #endif
0057 
0058 using namespace dd4hep;
0059 
0060 ClassImp(DetectorImp)
0061 
0062 namespace {
0063 
0064   std::recursive_mutex  s_detector_apply_lock;
0065 
0066   struct TypePreserve {
0067     DetectorBuildType& m_t;
0068     TypePreserve(DetectorBuildType& t)
0069       : m_t(t) {
0070     }
0071     ~TypePreserve() {
0072       m_t = BUILD_NONE;
0073     }
0074   };
0075 
0076   struct Instances  {
0077     std::recursive_mutex  lock;
0078     std::map<std::string, Detector*> detectors;
0079     Instances() = default;
0080     ~Instances()  {
0081     }
0082     Detector* get(const std::string& name)   {
0083       auto i = detectors.find(name);
0084       return i == detectors.end() ? 0 : (*i).second;
0085     }
0086     void insert(const std::string& name, Detector* detector)   {
0087       auto i = detectors.find(name);
0088       if ( i == detectors.end() )   {
0089         detectors.emplace(name,detector);
0090         return;
0091       }
0092       except("DD4hep","Cannot insert detector instance %s [Already present]",name.c_str());
0093     }
0094     Detector* remove(const std::string& name)   {
0095       auto i = detectors.find(name);
0096       if ( i != detectors.end() )  {
0097         Detector* det = (*i).second;
0098         detectors.erase(i);
0099         return det;
0100       }
0101       return 0;
0102     }
0103   };
0104   
0105   class DetectorGuard  final  {
0106   protected:
0107     static std::pair<std::recursive_mutex, std::map<DetectorImp*, TGeoManager*> >& detector_lock()   {
0108       static std::pair<std::recursive_mutex, std::map<DetectorImp*, TGeoManager*> > s_inst;
0109       return s_inst;
0110     }
0111     DetectorImp* detector {nullptr};
0112   public:
0113     DetectorGuard(DetectorImp* imp) : detector(imp) {}
0114     ~DetectorGuard() = default;
0115     void lock(TGeoManager* mgr)   const  {
0116       auto& lock = detector_lock();
0117       lock.first.lock();
0118       lock.second[detector] = mgr;
0119     }
0120     TGeoManager* unlock()  const  {
0121       TGeoManager* mgr = nullptr;
0122       auto& lock = detector_lock();
0123       auto i = lock.second.find(detector);
0124       if ( i != lock.second.end() )   {
0125         mgr = (*i).second;
0126         lock.second.erase(i);
0127       }
0128       lock.first.unlock();
0129       return mgr;
0130     }
0131   };
0132   
0133   Instances& detector_instances()    {
0134     static Instances s_inst;
0135     return s_inst;
0136   }
0137 }
0138 
0139 std::string dd4hep::versionString(){
0140   char vsn[32];
0141   std::snprintf(vsn, sizeof(vsn), "v%2.2d-%2.2d", DD4HEP_MAJOR_VERSION, DD4HEP_MINOR_VERSION);
0142   return { vsn };
0143 }
0144 
0145 std::unique_ptr<Detector> Detector::make_unique(const std::string& name)   {
0146   Detector* description = new DetectorImp(name);
0147   return std::unique_ptr<Detector>(description);
0148 }
0149 
0150 Detector& Detector::getInstance(const std::string& name)   {
0151   std::lock_guard<std::recursive_mutex> lock(detector_instances().lock);
0152   Detector* description = detector_instances().get(name);
0153   if ( 0 == description )   {
0154     gGeoManager = 0;
0155     description = new DetectorImp(name);
0156     detector_instances().insert(name,description);
0157   }
0158   return *description;
0159 }
0160 
0161 /// Destroy the instance
0162 void Detector::destroyInstance(const std::string& name) {
0163   std::lock_guard<std::recursive_mutex> lock(detector_instances().lock);
0164   Detector* description = detector_instances().remove(name);
0165   if (description)
0166     delete description;
0167 }
0168 
0169 /// Default constructor used by ROOT I/O
0170 DetectorImp::DetectorImp()
0171   : TNamed(), DetectorData(), DetectorLoad(this), m_buildType(BUILD_NONE)
0172 {
0173   m_surfaceManager = new detail::OpticalSurfaceManagerObject(*this);
0174   m_std_conditions.convention  = STD_Conditions::NTP;
0175   m_std_conditions.pressure    = Pressure_NTP;
0176   m_std_conditions.temperature = Temperature_NTP;
0177 }
0178 
0179 /// Initializing constructor
0180 DetectorImp::DetectorImp(const std::string& name)
0181   : TNamed(), DetectorData(), DetectorLoad(this), m_buildType(BUILD_NONE)
0182 {
0183 #if defined(DD4HEP_USE_GEANT4_UNITS)
0184   printout(INFO,"DD4hep","++ Using globally Geant4 unit system (mm,ns,MeV)");
0185   if ( TGeoManager::GetDefaultUnits() != TGeoManager::kG4Units )  {
0186     TGeoManager::LockDefaultUnits(kFALSE);
0187     TGeoManager::SetDefaultUnits(TGeoManager::kG4Units);
0188     TGeoManager::LockDefaultUnits(kTRUE);
0189   }
0190 #else
0191   if ( TGeoManager::GetDefaultUnits() != TGeoManager::kRootUnits )  {
0192     TGeoManager::LockDefaultUnits(kFALSE);
0193     TGeoManager::SetDefaultUnits(TGeoManager::kRootUnits);
0194     TGeoManager::LockDefaultUnits(kTRUE);
0195   }
0196 #endif
0197 
0198   SetName(name.c_str());
0199   SetTitle("DD4hep detector description object");
0200   //DetectorGuard(this).lock(gGeoManager);
0201   gGeoManager = nullptr;
0202   InstanceCount::increment(this);
0203   m_manager = new TGeoManager(name.c_str(), "Detector Geometry");
0204   {
0205     m_manager->AddNavigator();
0206     m_manager->SetCurrentNavigator(0);
0207     gGeoManager = m_manager;
0208 #if 1 //FIXME: eventually this should be set to 1 - needs fixes in examples ...
0209     TGeoElementTable* table = m_manager->GetElementTable();
0210     table->TGeoElementTable::~TGeoElementTable();
0211     new(table) TGeoElementTable();
0212     // This will initialize the table without filling:
0213     table->AddElement("VACUUM","VACUUM", 1, 1, 1e-15);
0214 #endif
0215   }
0216   if ( 0 == gGeoIdentity )
0217   {
0218     gGeoIdentity = new TGeoIdentity();
0219   }
0220   m_surfaceManager = new detail::OpticalSurfaceManagerObject(*this);
0221   m_std_conditions.convention  = STD_Conditions::NTP;
0222   m_std_conditions.pressure    = Pressure_NTP;
0223   m_std_conditions.temperature = Temperature_NTP;
0224   
0225   VisAttr attr("invisible");
0226   attr.setColor(1.0, 0.5, 0.5, 0.5);
0227   attr.setLineStyle(VisAttr::SOLID);
0228   attr.setDrawingStyle(VisAttr::SOLID);
0229   attr.setVisible(false);
0230   attr.setShowDaughters(true);
0231   addVisAttribute(attr);
0232   m_invisibleVis = attr;
0233 }
0234 
0235 /// Standard destructor
0236 DetectorImp::~DetectorImp() {
0237   DetectorGuard(this).lock(gGeoManager);
0238   if ( m_manager )  {
0239     std::lock_guard<std::recursive_mutex> lock(detector_instances().lock);
0240     if ( m_manager == gGeoManager ) gGeoManager = 0;
0241     Detector* description = detector_instances().get(GetName());
0242     if ( 0 != description )   {
0243       detector_instances().remove(m_manager->GetName());
0244     }
0245   }
0246   if ( m_surfaceManager )   {
0247     delete m_surfaceManager;
0248     m_surfaceManager = nullptr;
0249   }
0250   destroyData(false);
0251   m_extensions.clear();
0252   m_detectorTypes.clear();
0253   InstanceCount::decrement(this);
0254   DetectorGuard(this).unlock();
0255 }
0256 
0257 /// ROOT I/O call
0258 Int_t DetectorImp::saveObject(const char *name, Int_t option, Int_t bufsize) const   {
0259   Int_t nbytes = 0;
0260   try  {
0261     DetectorData::patchRootStreamer(TGeoVolume::Class());
0262     DetectorData::patchRootStreamer(TGeoNode::Class());
0263     nbytes = TNamed::Write(name, option, bufsize);
0264     DetectorData::unpatchRootStreamer(TGeoVolume::Class());
0265     DetectorData::unpatchRootStreamer(TGeoNode::Class());
0266     return nbytes;
0267   }
0268   catch (const std::exception& e) {
0269     DetectorData::unpatchRootStreamer(TGeoVolume::Class());
0270     DetectorData::unpatchRootStreamer(TGeoNode::Class());
0271     except("Detector","Exception %s while saving dd4hep::Detector object", e.what());
0272   }
0273   catch (...) {
0274     DetectorData::unpatchRootStreamer(TGeoVolume::Class());
0275     DetectorData::unpatchRootStreamer(TGeoNode::Class());
0276     except("Detector","UNKNOWN exception while saving dd4hep::Detector object.");
0277   }
0278   return nbytes;
0279 }
0280 
0281 // Load volume manager
0282 void DetectorImp::imp_loadVolumeManager()   {
0283   detail::destroyHandle(m_volManager);
0284   m_volManager = VolumeManager(*this, "World", world(), Readout(), VolumeManager::TREE);
0285 }
0286 
0287 /// Add an extension object to the Detector instance
0288 void* DetectorImp::addUserExtension(unsigned long long int key, ExtensionEntry* entry) {
0289   return m_extensions.addExtension(key,entry);
0290 }
0291 
0292 /// Remove an existing extension object from the Detector instance
0293 void* DetectorImp::removeUserExtension(unsigned long long int key, bool destroy)  {
0294   return m_extensions.removeExtension(key,destroy);
0295 }
0296 
0297 /// Access an existing extension object from the Detector instance
0298 void* DetectorImp::userExtension(unsigned long long int key, bool alert) const {
0299   return m_extensions.extension(key,alert);
0300 }
0301 
0302 /// Access flag to steer the detail of building of the geometry/detector description
0303 DetectorBuildType DetectorImp::buildType() const {
0304   std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0305   DetectorBuildType temp = m_buildType;
0306   return temp;
0307 }
0308 
0309 /// Register new mother volume using the detector name.
0310 void DetectorImp::declareParent(const std::string& detector_name, const DetElement& parent)  {
0311   if ( !detector_name.empty() )  {
0312     if ( parent.isValid() )  {
0313       auto i = m_detectorParents.find(detector_name);
0314       if (i == m_detectorParents.end())   {
0315         Volume parent_volume = parent.placement().volume();
0316         if ( parent_volume.isValid() )   {
0317           m_detectorParents.emplace(detector_name,parent);
0318           return;
0319         }
0320         except("DD4hep","+++ Failed to access valid parent volume of %s from %s",
0321                detector_name.c_str(), parent.name());
0322       }
0323       except("DD4hep",
0324              "+++ A parent to the detector %s was already registered.",
0325              detector_name.c_str());
0326     }
0327     except("DD4hep",
0328            "+++ Attempt to register invalid parent for detector: %s [Invalid-Handle].",
0329            detector_name.c_str());
0330   }
0331   except("DD4hep",
0332          "+++ Attempt to register parent to invalid detector [Invalid-detector-name].");
0333 }
0334 
0335 /// Access mother volume by detector element
0336 Volume DetectorImp::pickMotherVolume(const DetElement& de) const {
0337   if ( de.isValid() )   {
0338     std::string de_name = de.name();
0339     auto i = m_detectorParents.find(de_name);
0340     if (i == m_detectorParents.end())   {
0341       if ( m_worldVol.isValid() )  {
0342         return m_worldVol;
0343       }
0344       except("DD4hep",
0345              "+++ The world volume is not (yet) valid. "
0346              "Are you correctly building detector %s?",
0347              de.name());
0348     }
0349     if ( (*i).second.isValid() )  {
0350       Volume vol = (*i).second.volume();
0351       if ( vol.isValid() )  {
0352         return vol;
0353       }
0354     }
0355     except("DD4hep",
0356            "+++ The mother volume of %s is not valid. "
0357            "Are you correctly building detectors?",
0358            de.name());
0359   }
0360   except("DD4hep","Detector: Attempt access mother volume of invalid detector [Invalid-handle]");
0361   return 0;
0362 }
0363 
0364 /// Access default conditions (temperature and pressure
0365 const STD_Conditions& DetectorImp::stdConditions()   const   {
0366   if ( (m_std_conditions.convention&STD_Conditions::USER_SET) == 0 &&
0367        (m_std_conditions.convention&STD_Conditions::USER_NOTIFIED) == 0 )
0368   {
0369     printout(WARNING,"DD4hep","++ STD conditions NOT defined by client. NTP defaults taken.");
0370     m_std_conditions.convention |= STD_Conditions::USER_NOTIFIED;
0371   }
0372   return m_std_conditions;
0373 }
0374 /// Set the STD temperature and pressure
0375 void DetectorImp::setStdConditions(double temp, double pressure)  {
0376   m_std_conditions.temperature = temp;
0377   m_std_conditions.pressure = pressure;
0378   m_std_conditions.convention = STD_Conditions::USER_SET;
0379   if      ( std::abs(temp-Temperature_NTP) < 1e-10 && std::abs(pressure-Pressure_NTP) < 1e-10 )
0380     m_std_conditions.convention |= STD_Conditions::NTP;
0381   else if ( std::abs(temp-Temperature_STP) < 1e-10 && std::abs(pressure-Pressure_STP) < 1e-10 )
0382     m_std_conditions.convention |= STD_Conditions::STP;
0383   else
0384     m_std_conditions.convention |= STD_Conditions::USER;
0385 }
0386 
0387 /// Set the STD conditions according to defined types (STP or NTP)
0388 void DetectorImp::setStdConditions(const std::string& type)   {
0389   if ( type == "STP" )   {
0390     m_std_conditions.temperature = Temperature_STP;
0391     m_std_conditions.pressure    = Pressure_STP;
0392     m_std_conditions.convention  = STD_Conditions::STP|STD_Conditions::USER_SET;
0393   }
0394   else if ( type == "NTP" )   {
0395     m_std_conditions.temperature = Temperature_NTP;
0396     m_std_conditions.pressure    = Pressure_NTP;
0397     m_std_conditions.convention  = STD_Conditions::NTP|STD_Conditions::USER_SET;
0398   }
0399   else   {
0400     except("DD4hep",
0401            "++ Attempt to set standard conditions to "
0402            "unknown conventions (Only STP and NTP allowed).");
0403   }
0404 }
0405 
0406 /// Retrieve a subdetector element by its name from the detector description
0407 DetElement DetectorImp::detector(const std::string& name) const  {
0408   HandleMap::const_iterator i = m_detectors.find(name);
0409   if (i != m_detectors.end()) {
0410     return (*i).second;
0411   }
0412   DetElement de = detail::tools::findElement(*this,name);
0413   return de;
0414 }
0415 
0416 Detector& DetectorImp::addDetector(const Handle<NamedObject>& ref_det) {
0417   DetElement     det_element(ref_det);
0418   DetectorHelper helper(this);
0419   DetElement     existing_det = helper.detectorByID(det_element.id());
0420 
0421   if ( existing_det.isValid() )   {
0422     SensitiveDetector sd = helper.sensitiveDetector(existing_det);
0423     if ( sd.isValid() )   {
0424       std::stringstream str;
0425       str << "Detector: The sensitive sub-detectors " << det_element.name() << " and "
0426           << existing_det.name() << " have the identical ID:" << det_element.id() << ".";
0427       except("DD4hep",str.str());
0428     }
0429   }
0430   m_detectors.append(ref_det);
0431   det_element->flag |= DetElement::Object::IS_TOP_LEVEL_DETECTOR;
0432   PlacedVolume pv = det_element.placement();
0433   if ( !pv.isValid() )   {
0434     std::stringstream str;
0435     str << "Detector: Adding subdetectors with no valid placement is not allowed: "
0436         << det_element.name() << " ID:" << det_element.id() << ".";
0437     except("DD4hep",str.str());
0438   }
0439   Volume volume = pv->GetMotherVolume();
0440   if ( volume == m_worldVol )  {
0441     printout(DEBUG,"DD4hep","+++ Detector: Added detector %s to the world instance.",
0442              det_element.name());
0443     m_world.add(det_element);
0444     return *this;
0445   }
0446   /// Check if the parent is part of the compounds
0447   auto ipar = m_detectorParents.find(det_element.name());
0448   if (ipar != m_detectorParents.end())   {
0449     DetElement parent = (*ipar).second;
0450     parent.add(det_element);
0451     printout(DEBUG,"DD4hep","+++ Detector: Added detector %s to parent %s.",
0452              det_element.name(), parent.name());
0453     return *this;
0454   }
0455 
0456   // The detector's placement must be one of the existing detectors
0457   for(HandleMap::iterator idet = m_detectors.begin(); idet != m_detectors.end(); ++idet)  {
0458     DetElement parent((*idet).second);
0459     Volume     vol = parent.placement().volume();
0460     if ( vol == volume )  {
0461       printout(INFO,"DD4hep","+++ Detector: Added detector %s to the parent:%s.",
0462                det_element.name(),parent.name());
0463       parent.add(det_element);
0464       return *this;
0465     }
0466   }
0467   except("DD4hep","+++ Detector: The detector %s has no known parent.", det_element.name());
0468   throw std::runtime_error("Detector-Error"); // Never called....
0469 }
0470 
0471 /// Add a new constant by named reference to the detector description
0472 Detector& DetectorImp::addConstant(const Handle<NamedObject>& x) {
0473   if ( strcmp(x.name(),"Detector_InhibitConstants") == 0 )   {
0474     const char* title = x->GetTitle();
0475     char c = ::toupper(title[0]);
0476     m_inhibitConstants = (c=='Y' || c=='T' || c=='1');
0477   }
0478   m_define.append(x, false);
0479   return *this;
0480 }
0481 
0482 /// Retrieve a constant by its name from the detector description
0483 Constant DetectorImp::constant(const std::string& name) const {
0484   if ( !m_inhibitConstants )   {
0485     return getRefChild(m_define, name);
0486   }
0487   throw std::runtime_error("Detector:constant("+name+"): Access to global constants is inhibited.");
0488 }
0489 
0490 /// Typed access to constants: access string values
0491 std::string DetectorImp::constantAsString(const std::string& name) const {
0492   if ( !m_inhibitConstants )   {
0493     Handle<NamedObject> c = constant(name);
0494     if (c.isValid())
0495       return c->GetTitle();
0496     throw std::runtime_error("Detector:constantAsString: The constant " + name + " is not known to the system.");
0497   }
0498   throw std::runtime_error("Detector:constantAsString("+name+"):: Access to global constants is inhibited.");
0499 }
0500 
0501 /// Typed access to constants: long values
0502 long DetectorImp::constantAsLong(const std::string& name) const {
0503   if ( !m_inhibitConstants )   {
0504     return _toLong(constantAsString(name));
0505   }
0506   throw std::runtime_error("Detector:constantAsLong("+name+"): Access to global constants is inhibited.");
0507 }
0508 
0509 /// Typed access to constants: double values
0510 double DetectorImp::constantAsDouble(const std::string& name) const {
0511   if ( !m_inhibitConstants )   {
0512     return _toDouble(constantAsString(name));
0513   }
0514   throw std::runtime_error("Detector:constantAsDouble("+name+"): Access to global constants is inhibited.");
0515 }
0516 
0517 /// Add a field component by named reference to the detector description
0518 Detector& DetectorImp::addField(const Handle<NamedObject>& x) {
0519   m_field.add(x);
0520   m_fields.append(x);
0521   return *this;
0522 }
0523 
0524 /// Retrieve a matrial by its name from the detector description
0525 Material DetectorImp::material(const std::string& name) const {
0526   TGeoMedium* mat = m_manager->GetMedium(name.c_str());
0527   if (mat) {
0528     return Material(mat);
0529   }
0530   throw std::runtime_error("Cannot find a material referenced by name:" + name);
0531 }
0532 
0533 /// Internal helper to map detector types once the geometry is closed
0534 void DetectorImp::mapDetectorTypes()  {
0535   m_detectorTypes[""] = {};
0536   for( const auto& i : m_detectors )   {
0537     DetElement det(i.second);
0538     if ( det.parent().isValid() )  { // Exclude 'world'
0539       HandleMap::const_iterator j=m_sensitive.find(det.name());
0540       if ( j != m_sensitive.end() )  {
0541         SensitiveDetector sd((*j).second);
0542         m_detectorTypes[sd.type()].emplace_back(det);
0543       }
0544       else if ( det.type() == "compound" )  {
0545         m_detectorTypes[det.type()].emplace_back(det);      
0546       }
0547       else  {
0548         m_detectorTypes["passive"].emplace_back(det);      
0549       }
0550     }
0551   }
0552 }
0553 
0554 /// Access the availible detector types
0555 std::vector<std::string> DetectorImp::detectorTypes() const  {
0556   if ( m_manager->IsClosed() ) {
0557     std::vector<std::string> v;
0558     v.reserve(m_detectorTypes.size());
0559     for(const auto& t : m_detectorTypes )
0560       v.emplace_back(t.first);
0561     return v;
0562   }
0563   throw std::runtime_error("detectorTypes: Call only available once the geometry is closed!");
0564 }
0565 
0566 /// Access a set of subdetectors according to the sensitive type.
0567 const std::vector<DetElement>& DetectorImp::detectors(const std::string& type, bool throw_exc) const {
0568   if ( m_manager->IsClosed() ) {
0569     DetectorTypeMap::const_iterator i=m_detectorTypes.find(type);
0570     if ( i != m_detectorTypes.end() ) return (*i).second;
0571     if ( throw_exc )  {
0572       throw std::runtime_error("detectors("+type+"): Detectors of this type do not exist in the current setup!");
0573     }
0574     // return empty vector instead of exception
0575     return m_detectorTypes.at("") ;
0576   }
0577   throw std::runtime_error("detectors("+type+"): Detectors can only selected by type once the geometry is closed!");
0578 }
0579 
0580 std::vector<DetElement> DetectorImp::detectors(unsigned int includeFlag, unsigned int excludeFlag ) const  {
0581   if( ! m_manager->IsClosed() ) {
0582     throw std::runtime_error("detectors(typeFlag): Detectors can only selected by typeFlag once the geometry is closed!");
0583   }
0584   std::vector<DetElement> dets ;
0585   dets.reserve( m_detectors.size() ) ;
0586   
0587   for(HandleMap::const_iterator i=m_detectors.begin(); i!=m_detectors.end(); ++i)   {
0588     DetElement det((*i).second);
0589     if ( det.parent().isValid() )  { // Exclude 'world'
0590       
0591       //fixme: what to do with compounds - add their daughters  ?
0592       // ...
0593 
0594       if( ( det.typeFlag() &  includeFlag ) == includeFlag &&
0595           ( det.typeFlag() &  excludeFlag ) ==  0 )
0596         dets.emplace_back( det ) ;
0597     }
0598   }
0599   return dets ;
0600 }
0601 
0602 /// Access a set of subdetectors according to several sensitive types.
0603 std::vector<DetElement> DetectorImp::detectors(const std::string& type1,
0604                                                const std::string& type2,
0605                                                const std::string& type3,
0606                                                const std::string& type4,
0607                                                const std::string& type5 )  {
0608   if ( m_manager->IsClosed() ) {
0609     std::vector<DetElement> v;
0610     DetectorTypeMap::const_iterator i, end=m_detectorTypes.end();
0611     if ( !type1.empty() && (i=m_detectorTypes.find(type1)) != end )
0612       v.insert(v.end(),(*i).second.begin(),(*i).second.end());
0613     if ( !type2.empty() && (i=m_detectorTypes.find(type2)) != end )
0614       v.insert(v.end(),(*i).second.begin(),(*i).second.end());
0615     if ( !type3.empty() && (i=m_detectorTypes.find(type3)) != end )
0616       v.insert(v.end(),(*i).second.begin(),(*i).second.end());
0617     if ( !type4.empty() && (i=m_detectorTypes.find(type4)) != end )
0618       v.insert(v.end(),(*i).second.begin(),(*i).second.end());
0619     if ( !type5.empty() && (i=m_detectorTypes.find(type5)) != end ) 
0620       v.insert(v.end(),(*i).second.begin(),(*i).second.end());
0621     return v;
0622   }
0623   throw std::runtime_error("detectors("+type1+","+type2+",...): Detectors can only selected by type once the geometry is closed!");
0624 }
0625 
0626 Handle<NamedObject> DetectorImp::getRefChild(const HandleMap& e, const std::string& name, bool do_throw) const {
0627   HandleMap::const_iterator it = e.find(name);
0628   if (it != e.end()) {
0629     return it->second;
0630   }
0631   if (do_throw) {
0632     union ptr {
0633       const ObjectHandleMap* omap;
0634       const char* c;
0635       const void* other;
0636       ptr(const void* p) { other = p; }
0637     };
0638     std::string nam = "";
0639     ptr mptr(&e), ref(this);
0640     if ( ref.c > mptr.c && mptr.c < ref.c+sizeof(*this) )  {
0641       nam = mptr.omap->name;
0642     }
0643     std::stringstream err;
0644     err << "getRefChild: Failed to find child with name: " << name
0645         << " Map " << nam << " contains " << e.size() << " elements: {";
0646     for (it = e.begin(); it != e.end(); ++it) {
0647       if (it != e.begin()) {
0648         err << ", ";
0649       }
0650       err << it->first;
0651     }
0652     err << "}";
0653     throw std::runtime_error(err.str());
0654   }
0655   return 0;
0656 }
0657 
0658 namespace {
0659   struct ShapePatcher: public detail::GeoScan {
0660     VolumeManager m_volManager;
0661     DetElement m_world;
0662     ShapePatcher(VolumeManager m, DetElement e)
0663       : detail::GeoScan(e), m_volManager(m), m_world(e) {
0664     }
0665     void patchShapes() {
0666       auto&  data = *m_data;
0667       char   text[32];
0668       std::string nam;
0669       printout(INFO,"Detector","+++ Patching names of anonymous shapes....");
0670       for (auto i = data.rbegin(); i != data.rend(); ++i) {
0671         for( const TGeoNode* n : (*i).second )  {
0672           TGeoVolume* vol = n->GetVolume();
0673           TGeoShape*  s   = vol->GetShape();
0674           const char* sn  = s->GetName();
0675           ::snprintf(text,sizeof(text),"_shape_%p",(void*)s);
0676           if (0 == sn || 0 == ::strlen(sn)) {
0677             nam = vol->GetName();
0678             nam += text;
0679             s->SetName(nam.c_str());
0680           }
0681           else if (0 == ::strcmp(sn, s->IsA()->GetName())) {
0682             nam = vol->GetName();
0683             nam += text;
0684             s->SetName(nam.c_str());
0685           }
0686           else {
0687             nam = sn;
0688             if (nam.find("_shape") == std::string::npos)
0689               nam += text;
0690             s->SetName(nam.c_str());
0691           }
0692           if (s->IsA() == TGeoCompositeShape::Class()) {
0693             TGeoCompositeShape* c = (TGeoCompositeShape*) s;
0694             const TGeoBoolNode* boolean = c->GetBoolNode();
0695             s = boolean->GetLeftShape();
0696             sn = s->GetName();
0697             if (0 == sn || 0 == ::strlen(sn)) {
0698               s->SetName((nam + "_left").c_str());
0699             }
0700             else if (0 == ::strcmp(sn, s->IsA()->GetName())) {
0701               s->SetName((nam + "_left").c_str());
0702             }
0703             s = boolean->GetRightShape();
0704             sn = s->GetName();
0705             if (0 == sn || 0 == ::strlen(sn)) {
0706               s->SetName((nam + "_right").c_str());
0707             }
0708             else if (0 == ::strcmp(s->GetName(), s->IsA()->GetName())) {
0709               s->SetName((nam + "_right").c_str());
0710             }
0711           }
0712         }
0713       }
0714     }
0715   };
0716 }
0717 
0718 /// Finalize/close the geometry
0719 void DetectorImp::endDocument(bool close_geometry)    {
0720   TGeoManager* mgr = m_manager;
0721   std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0722   if ( close_geometry && !mgr->IsClosed() )  {
0723 #if 0
0724     Region trackingRegion("TrackingRegion");
0725     trackingRegion.setThreshold(1);
0726     trackingRegion.setStoreSecondaries(true);
0727     add(trackingRegion);
0728     m_trackingVol.setRegion(trackingRegion);
0729     // Set the tracking volume to invisible.
0730     VisAttr trackingVis("TrackingVis");
0731     trackingVis.setVisible(false);
0732     m_trackingVol.setVisAttributes(trackingVis);
0733     add(trackingVis);
0734 #endif
0735     m_worldVol.solid()->ComputeBBox();
0736     // Propagating reflections: This is useless now and unused!!!!
0737     // Since we allow now for anonymous shapes,
0738     // we will rename them to use the name of the volume they are assigned to
0739     mgr->CloseGeometry();
0740     PlacedVolume pv = mgr->GetTopNode();
0741     auto* extension = pv->GetUserExtension();
0742     if ( nullptr == extension )   {
0743       extension = new PlacedVolume::Object();
0744       pv->SetUserExtension(extension);
0745     }
0746     m_world.setPlacement(pv);
0747   }
0748   // Patching shape names of anaonymous shapes
0749   ShapePatcher patcher(m_volManager, m_world);
0750   patcher.patchShapes();
0751   mapDetectorTypes();
0752   m_state = READY;
0753   //DetectorGuard(this).unlock();
0754 }
0755 
0756 /// Initialize the geometry and set the bounding box of the world volume
0757 void DetectorImp::init() {
0758   if (!m_world.isValid()) {
0759     TGeoManager* mgr = m_manager;
0760     std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0761     Constant     air_const = getRefChild(m_define, "Air", false);
0762     Constant     vac_const = getRefChild(m_define, "Vacuum", false);
0763     Box          worldSolid;
0764     
0765     m_materialVacuum = material(vac_const.isValid() ? vac_const->GetTitle() : "Vacuum");
0766 
0767     m_worldVol = m_manager->GetTopVolume();
0768     if ( m_worldVol.isValid() )   {
0769       worldSolid    = m_worldVol.solid();
0770       m_materialAir = m_worldVol.material();
0771       printout(INFO,"Detector", "*********** Use Top Node from manager as "
0772                "world volume [%s].  Material: %s BBox: %4.0f %4.0f %4.0f",
0773                worldSolid->IsA()->GetName(), m_materialAir.name(),
0774                worldSolid->GetDX(), worldSolid->GetDY(), worldSolid->GetDZ());
0775     }
0776     else   {
0777       /// Construct the top level world element
0778       Solid parallelWorldSolid = Box("world_x", "world_y", "world_z");
0779       worldSolid    = Box("world_x", "world_y", "world_z");
0780       m_materialAir = material(air_const.isValid() ? air_const->GetTitle() : "Air");
0781       m_worldVol    = Volume("world_volume", worldSolid, m_materialAir);
0782       parallelWorldSolid->SetName("parallel_world_solid");
0783       printout(INFO,"Detector","*********** Created World volume with size: %4.0f %4.0f %4.0f",
0784                worldSolid->GetDX(), worldSolid->GetDY(), worldSolid->GetDZ());
0785     }
0786     m_world = DetElement(new WorldObject(*this,"world"));
0787     /// Set the world volume to invisible.
0788     VisAttr worldVis = visAttributes("WorldVis");
0789     if ( !worldVis.isValid() )  {
0790       worldVis = VisAttr("WorldVis");
0791       worldVis.setVisible(false);
0792       worldVis.setShowDaughters(true);
0793       worldVis.setColor(1., 1., 1., 1.);
0794       worldVis.setLineStyle(VisAttr::SOLID);
0795       worldVis.setDrawingStyle(VisAttr::WIREFRAME);
0796       //m_worldVol.setVisAttributes(worldVis);
0797       m_worldVol->SetVisibility(kFALSE);
0798       m_worldVol->SetVisDaughters(kTRUE);
0799       m_worldVol->SetVisContainers(kTRUE);
0800       add(worldVis);
0801     }
0802     m_worldVol.setVisAttributes(worldVis);
0803     m_manager->SetTopVolume(m_worldVol.ptr());
0804 
0805     /// Set the top level volume to the TGeomanager
0806     m_detectors.append(m_world);
0807     m_world.setPlacement(mgr->GetTopNode());
0808 
0809     /// Construct the parallel world
0810     m_parallelWorldVol = Volume("parallel_world_volume", worldSolid, m_materialAir);
0811 
0812     /// Construct the field envelope
0813     m_field = OverlayedField("global");
0814     m_state = LOADING;
0815   }
0816 }
0817 
0818 /// Read any geometry description or alignment file
0819 void DetectorImp::fromXML(const std::string& xmlfile, DetectorBuildType build_type) {
0820   std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0821   m_buildType = build_type;
0822   processXML(xmlfile, 0);
0823 }
0824 
0825 /// Read any geometry description or alignment file with external XML entity resolution
0826 void DetectorImp::fromXML(const std::string& fname, xml::UriReader* entity_resolver, DetectorBuildType build_type)  {
0827   std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0828   m_buildType = build_type;
0829   processXML(fname, entity_resolver);
0830 }
0831 
0832 void DetectorImp::dump() const {
0833   TGeoManager* mgr = m_manager;
0834   mgr->SetVisLevel(4);
0835   mgr->SetVisOption(1);
0836   m_worldVol->Draw("ogl");
0837 }
0838 
0839 /// Manipulate geometry using facroy converter
0840 long DetectorImp::apply(const char* factory_type, int argc, char** argv)   const   {
0841   std::lock_guard<std::recursive_mutex> lock(s_detector_apply_lock);
0842   std::string fac = factory_type;
0843   try {
0844     Detector* thisPtr = const_cast<DetectorImp*>(this);
0845     long result = PluginService::Create<long>(fac, thisPtr, argc, argv);
0846     if (0 == result) {
0847       PluginDebug dbg;
0848       result = PluginService::Create<long>(fac, thisPtr, argc, argv);
0849       if ( 0 == result )  {
0850         throw std::runtime_error("dd4hep: apply-plugin: Failed to locate plugin " +
0851                                  fac + ". " + dbg.missingFactory(fac));
0852       }
0853     }
0854     result = *(long*) result;
0855     if (result != 1) {
0856       throw std::runtime_error("dd4hep: apply-plugin: Failed to execute plugin " + fac);
0857     }
0858     return result;
0859   }
0860   catch (const xml::XmlException& e) {
0861     throw std::runtime_error(xml::_toString(e.msg) + "\ndd4hep: XML-DOM Exception with plugin:" + fac);
0862   }
0863   catch (const std::exception& e) {
0864     throw std::runtime_error(std::string(e.what()) + "\ndd4hep: with plugin:" + fac);
0865   }
0866   catch (...) {
0867     throw std::runtime_error("UNKNOWN exception from plugin:" + fac);
0868   }
0869   return EINVAL;
0870 }