diff --git a/DDCore/python/dd4hepFactories.py b/DDCore/python/dd4hepFactories.py new file mode 100755 index 0000000000000000000000000000000000000000..04a413f0f83e15084d34beb1bc86e073eb7d390c --- /dev/null +++ b/DDCore/python/dd4hepFactories.py @@ -0,0 +1,169 @@ +#!/bin/python +#========================================================================== +# AIDA Detector description implementation +#-------------------------------------------------------------------------- +# Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +# All rights reserved. +# +# For the licensing terms see $DD4hepINSTALL/LICENSE. +# For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +# +#========================================================================== + +import os, sys, optparse, logging + +class ComponentDumper: + def __init__(self): + os.environ['DD4HEP_TRACE']='ON' + self.all_components = [] + + def scanPath(self): + ldp = os.environ['LD_LIBRARY_PATH'].split(':') + for p in ldp: + if len(p): + logging.info('+== Search component directory: '+p) + files = os.listdir(p) + for f in files: + fname = p+os.sep+f + ext = os.path.splitext(fname)[-1].lower() + if ext == '.components': + self.readComponents(fname) + elif ext == '.rootmap': + self.dumpDictionaries(fname) + + def readComponents(self,fname): + logging.info('+== Search component file: '+fname) + file = open(fname,"r") + lines = file.readlines() + dirname = os.path.dirname(fname) + for l in lines: + l = l[:-1] + if len(l)>2 and (l[0:2] == '//' or l[0] == '#'): + continue + lib, comp = l.split(':') + self.all_components.append([dirname+os.sep+lib,comp]) + file.close() + + def searchDuplicates(self, summary_only=False): + entries = {} + component_count = 0 + duplicate_count = 0 + for lib, comp in self.all_components: + if entries.has_key(comp): + dupl = entries[comp] + if dupl[1] == 0: + if not summary_only: + logging.info('+'+('==='*40)) + logging.info('| Component entry: '+comp+' in library: '+dupl[0]) + entries[comp][1] = 1 + if not summary_only: + logging.info('| --> Duplicate factory declaration in: '+ lib) + duplicate_count = duplicate_count + 1 + continue + entries[comp] = [lib,0] + component_count = component_count + 1 + logging.info('+'+('==='*40)) + logging.info('| Found %d dd4hep factory entries and %d DUPLICATES in component files.'%(component_count,duplicate_count,)) + logging.info('+'+('==='*40)) + + def dumpInventory(self, summary_only=False, dump=True, load=False, interactive=True): + entries = {} + do_load = load + library_count = 0 + component_count = 0 + for lib, comp in self.all_components: + if not entries.has_key(lib): + entries[lib] = [comp] + library_count = library_count + 1 + component_count = component_count + 1 + continue + entries[lib].append(comp) + component_count = component_count + 1 + if not summary_only: + for lib, comp in entries.items(): + if dump: + logging.info('+== Component library: '+lib) + count = 0 + for c in comp: + count = count + 1 + if dump: + logging.info('| %-3d Component: %s'%(count,c,)) + if do_load: + ret = 'D' + if interactive: + try: + ret = raw_input("<CR> to DUMP the list of components \n"+ + "<Q> to QUIT \n"+ + "<D> to DUMP the list of components \n"+ + "<S> to SKIP this particular library\n"+ + "<L> to no longer LOAD libraries \n") + except Exception,X: + ret = 'D' + if not len(ret): + ret = 'D' + if ret[0].upper() == 'Q': + sys.exit(0) + elif ret[0].upper() == 'D': + gSystem.Load(lib) + elif ret[0].upper() == 'L': + do_load = False + logging.info('+'+('==='*40)) + logging.info('| Found %d dd4hep factory libraries with %d components.'%(library_count,component_count,)) + logging.info('+'+('==='*40) ) + + def dumpDictionaries(self,fname): + pass + + +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG) +parser = optparse.OptionParser() +parser.description = "DD4hep factory checks." +parser.formatter.width = 132 +parser.add_option("-c", "--check", + action="store_true", dest="check", default=False, + help="Check the components file in the LD_LIBRARY_PATH for duplicates", + metavar="<boolean>") + +parser.add_option("-d","--dump", + action="store_true", dest="dump", default=False, + help="Dump the content of the components files", + metavar="<boolean>") + +parser.add_option("-l","--load", + action="store_true", dest="load", default=False, + help="Load all libraries indicated in the component files", + metavar="<boolean>") + +parser.add_option("-n","--no-interactive", + action="store_false", dest="interactive", default=True, + help="Always load. Do NOT inquire if a library should be loaded or not", + metavar="<boolean>") + +(opts, args) = parser.parse_args() + +if not (opts.check or opts.dump or opts.load): + logging.info(" %s",parser.format_help()) + sys.exit(0) + +try: + import ROOT + from ROOT import gROOT + from ROOT import gSystem + gROOT.SetBatch(1) +except ImportError,X: + logging.error('PyROOT interface not accessible: %s',str(X)) + sys.exit(errno.ENOENT) + +try: + import dd4hep +except ImportError,X: + logging.error('dd4hep python interface not accessible: %s',str(X)) + sys.exit(errno.ENOENT) + +dmp = ComponentDumper() +dmp.scanPath() +if opts.check: + dmp.searchDuplicates() +if opts.dump or opts.load: + dmp.dumpInventory(dump=opts.dump,load=opts.load,interactive=opts.interactive) +sys.exit(0) diff --git a/DDG4/include/DDG4/Geant4Kernel.h b/DDG4/include/DDG4/Geant4Kernel.h index 09a342ecd2d2546405e666795563317fd267a91b..7495aade654915bf35e74c12a3e7c9d989bef3d8 100644 --- a/DDG4/include/DDG4/Geant4Kernel.h +++ b/DDG4/include/DDG4/Geant4Kernel.h @@ -79,6 +79,10 @@ namespace dd4hep { std::string m_uiName; /// Property: Name of the G4 run manager factory to be used. Default: Geant4RunManager std::string m_runManagerType; + /// Property: Name of the default factory to create G4VSensitiveDetector instances + std::string m_dfltSensitiveDetectorType; + /// Property: Names with specialized factories to create G4VSensitiveDetector instances + std::map<std::string, std::string> m_sensitiveDetectorTypes; /// Property: Number of events to be executed in batch mode long m_numEvent; /// Property: Output level @@ -171,6 +175,15 @@ namespace dd4hep { template <typename T> void setUserFramework(T* object) { m_userFramework = UserFramework(object,&typeid(T)); } + /// Property access: Name of the default factory to create G4VSensitiveDetector instances + const std::string defaultSensitiveDetectorType() const { + return m_dfltSensitiveDetectorType; + } + /// Property access: Names with specialized factories to create G4VSensitiveDetector instances + const std::map<std::string, std::string>& sensitiveDetectorTypes() const { + return m_sensitiveDetectorTypes; + } + /** Property access */ /// Access to the properties of the object PropertyManager& properties() { return m_properties; } diff --git a/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp index afd3c54dbd1f62d0c513a19562d03ca9437b621f..69fced892b63f160e8ba82e7a54ff1727e53787a 100644 --- a/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp +++ b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp @@ -52,6 +52,7 @@ namespace dd4hep { #include "DD4hep/Detector.h" #include "DDG4/Geant4Mapping.h" +#include "DDG4/Geant4Kernel.h" #include "DDG4/Factories.h" // ROOT include files @@ -82,25 +83,30 @@ Geant4DetectorSensitivesConstruction::~Geant4DetectorSensitivesConstruction() { /// Sensitive detector construction callback. Called at "ConstructSDandField()" void Geant4DetectorSensitivesConstruction::constructSensitives(Geant4DetectorConstructionContext* ctxt) { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); + const Geant4Kernel& kernel = context()->kernel(); + const auto& types = kernel.sensitiveDetectorTypes(); + const string& dflt = kernel.defaultSensitiveDetectorType(); for(const auto& iv : p->sensitives ) { SensitiveDetector sd = iv.first; - string typ = sd.type(), nam = sd.name(); + string nam = sd.name(); + auto iter = types.find(nam); + string typ = (iter != types.end()) ? (*iter).second : dflt; G4VSensitiveDetector* g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->description); - if (!g4sd) { - string tmp = typ; - tmp[0] = ::toupper(tmp[0]); - typ = "Geant4" + tmp; + if (g4sd) { + print("Geant4SDConstruction", "+++ Subdetector: %-32s type: %-16s factory: %s.", + nam.c_str(), sd.type().c_str(), typ.c_str()); + } + else { + PluginDebug dbg; g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->description); - if ( !g4sd ) { - PluginDebug dbg; - g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->description); - if ( !g4sd ) { - throw runtime_error("ConstructSDandField: FATAL Failed to " - "create Geant4 sensitive detector " + nam + - " of type " + typ + "."); - } + if ( !g4sd ) { + throw runtime_error("ConstructSDandField: FATAL Failed to " + "create Geant4 sensitive detector " + nam + + " (" + sd.type() + ") of type " + typ + "."); } + print("Geant4SDConstruction", "+++ Subdetector: %-32s type: %-16s factory: %s.", + nam.c_str(), sd.type().c_str(), typ.c_str()); } g4sd->Activate(true); G4SDManager::GetSDMpointer()->AddNewDetector(g4sd); @@ -113,5 +119,5 @@ void Geant4DetectorSensitivesConstruction::constructSensitives(Geant4DetectorCon ctxt->setSensitiveDetector(g4v,g4sd); } } - print("Geant4Converter", "++ Handled %ld sensitive detectors.",p->sensitives.size()); + print("Geant4SDConstruction", "+++ Handled %ld sensitive detectors.",p->sensitives.size()); } diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py index aeedfff1c51beeebf7a86d6e041252b601a6701f..e98a70fbf8e0c49eec468d4f968cde0cfdbf2df7 100644 --- a/DDG4/python/DDG4.py +++ b/DDG4/python/DDG4.py @@ -577,13 +577,13 @@ class Geant4: def setupCalorimeter(self,name,type=None,collections=None): sd = self.description.sensitiveDetector(name) - sd.setType('calorimeter') + ### sd.setType('calorimeter') if type is None: type = self.sensitive_types['calorimeter'] return self.setupDetector(name,type,collections) def setupTracker(self,name,type=None,collections=None): sd = self.description.sensitiveDetector(name) - sd.setType('tracker') + ### sd.setType('tracker') if type is None: type = self.sensitive_types['tracker'] return self.setupDetector(name,type,collections) diff --git a/DDG4/src/Geant4Kernel.cpp b/DDG4/src/Geant4Kernel.cpp index 103f9961354964ad3e68089089435ce8d992eae6..15aa3db6f34b0c1d53f3ef8a5b079a0b417cb631 100644 --- a/DDG4/src/Geant4Kernel.cpp +++ b/DDG4/src/Geant4Kernel.cpp @@ -83,6 +83,8 @@ Geant4Kernel::Geant4Kernel(Detector& description_ref) declareProperty("NumEvents", m_numEvent = 10); declareProperty("OutputLevels", m_clientLevels); declareProperty("NumberOfThreads", m_numThreads); + declareProperty("DefaultSensitiveType", m_dfltSensitiveDetectorType = "Geant4SensDet"); + declareProperty("SensitiveTypes", m_sensitiveDetectorTypes); declareProperty("RunManagerType", m_runManagerType = "G4RunManager"); m_controlName = "/ddg4/"; m_control = new G4UIdirectory(m_controlName.c_str()); @@ -103,6 +105,8 @@ Geant4Kernel::Geant4Kernel(Geant4Kernel* m, unsigned long ident) m_ident = m_master->m_workers.size(); m_numEvent = m_master->m_numEvent; m_runManagerType = m_master->m_runManagerType; + m_sensitiveDetectorTypes = m_master->m_sensitiveDetectorTypes; + m_dfltSensitiveDetectorType = m_master->m_dfltSensitiveDetectorType; declareProperty("UI",m_uiName = m_master->m_uiName); declareProperty("OutputLevel", m_outputLevel = m_master->m_outputLevel); declareProperty("OutputLevels",m_clientLevels = m_master->m_clientLevels); diff --git a/DDG4/src/Geant4SensDetAction.cpp b/DDG4/src/Geant4SensDetAction.cpp index 37086187dbc87e24831968a341da0ecacf3a6cc3..a2fb4b5461a3a45ae749389bea2a9cd72582448f 100644 --- a/DDG4/src/Geant4SensDetAction.cpp +++ b/DDG4/src/Geant4SensDetAction.cpp @@ -246,7 +246,6 @@ Geant4SensDetActionSequence::Geant4SensDetActionSequence(Geant4Context* ctxt, co /// Update the sensitive detector type, so that the proper instance is created m_sensitive = context()->detectorDescription().sensitiveDetector(nam); m_sensitiveType = m_sensitive.type(); - m_sensitive.setType("Geant4SensDet"); InstanceCount::increment(this); }